refactor(release): drop release-policy.json runtime dep and next branch (#180)

* chore: standardize daemon naming on "KTX daemon"

Replace inconsistent names ("KTX Python daemon", "KTX local embeddings
daemon", "KTX managed daemon", "Python daemon") with the single name
"KTX daemon" in CLI output, errors, command descriptions, test
assertions, smoke scripts, docs, AGENTS.md, issue templates, and
codecov flags. The daemon is a portable compute server with endpoints
for SQL analysis, semantic layer, LookML, database introspection, and
embeddings; the previous labels misrepresented it as embeddings-only or
exposed implementation details ("Python", "managed").

The "KTX Python runtime" concept (installed interpreter + packages) is
deliberately left as-is — it is a separate concept from the daemon
process.

* refactor(release): drop release-policy.json runtime dep and next branch

Strips the release-policy.json fallback from release-version.ts so the CLI
reads its version straight from packages/cli/package.json. dev → 0.0.0-private,
installed @kaelio/ktx → the real semver baked into the published package.json.
KtxCliPackageInfo collapses to { name, version, contextPackageName }; /health
no longer depends on version files surviving past a CI run.

Replaces the dual-branch (main + next) semantic-release model with a single-
branch model on main. rcs and stables interleave on the same branch via
{ name: 'main', prerelease: 'rc', channel: 'next' } / ['main']. Drops
@semantic-release/git and @semantic-release/changelog (nothing is committed
back to the repo on any channel) and the workflow's "Prepare next prerelease
branch" step plus the KTX_PRERELEASE_BRANCH plumbing. The git tag plus the
published npm artifact carry the version forward.

Updates docs/release.md, removes the two now-unused devDeps, regenerates
pnpm-lock.yaml. 611/611 @ktx/cli tests, 173/173 script tests, type-check,
biome, knip all clean.

* fix(release): don't throw on non-main branches at config-load time

knip loads .releaserc.cjs on every PR run, where GITHUB_REF_NAME is the
merge ref (e.g. 180/merge). The previous version of releaseBranches threw
immediately when the branch wasn't main, which made knip fail to evaluate
the config and then mis-flag @semantic-release/exec as an unused dep.

semantic-release already refuses to publish when the current branch doesn't
match a configured release branch, so the explicit throw was redundant.
Drop it (and the unused currentBranch helper) and replace the
"rejects releases from non-main" assertion with one that exercises a CI-
shaped GITHUB_REF_NAME and confirms the config loads.
This commit is contained in:
Andrey Avtomonov 2026-05-20 13:53:14 +02:00 committed by GitHub
parent da6d05ed55
commit a11b9e9757
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
43 changed files with 142 additions and 387 deletions

View file

@ -137,7 +137,7 @@ describe('admin reindex Commander routing', () => {
force: true,
json: true,
output: 'plain',
cliVersion: '0.1.0-rc.1',
cliVersion: '0.0.0-private',
},
io.io,
);

View file

@ -14,8 +14,6 @@ function stubPackageInfo(): KtxCliPackageInfo {
return {
name: '@ktx/cli',
version: '0.0.0-test',
packageVersion: '0.0.0-private',
runtimeVersion: '0.0.0-test',
contextPackageName: '@ktx/context',
};
}

View file

@ -11,7 +11,7 @@ import type { KtxSlArgs } from './sl.js';
import type { KtxSqlArgs } from './sql.js';
import { profileMark, profileSpan } from './startup-profile.js';
import type { KtxTextIngestArgs } from './text-ingest.js';
import { resolveKtxRuntimeVersion } from './release-version.js';
import { assertCliVersion } from './release-version.js';
profileMark('module:cli-runtime');
@ -20,8 +20,6 @@ const requirePackageJson = createRequire(import.meta.url);
export interface KtxCliPackageInfo {
name: string;
version: string;
packageVersion: string;
runtimeVersion: string;
contextPackageName: '@ktx/context';
}
@ -66,16 +64,9 @@ export function packageInfoFromJson(packageJson: unknown): KtxCliPackageInfo {
throw new Error('Invalid KTX CLI package metadata');
}
const runtimeVersion = resolveKtxRuntimeVersion({
packageName: packageJson.name,
packageVersion: packageJson.version,
});
return {
name: packageJson.name,
version: runtimeVersion,
packageVersion: packageJson.version,
runtimeVersion,
version: assertCliVersion(packageJson.version, `${packageJson.name}/package.json`),
contextPackageName: '@ktx/context',
};
}

View file

@ -38,7 +38,7 @@ export function registerRuntimeCommands(program: Command, context: KtxCliCommand
runtime
.command('start')
.description('Start the KTX-managed Python HTTP daemon')
.description('Start the KTX daemon')
.addOption(createRuntimeFeatureOption())
.option('--force', 'Restart even when a matching daemon is already running', false)
.action(async (options: { feature: RuntimeFeature; force?: boolean }, command: CommandWithGlobalOptions) => {
@ -53,7 +53,7 @@ export function registerRuntimeCommands(program: Command, context: KtxCliCommand
runtime
.command('stop')
.description('Stop the KTX-managed Python HTTP daemon')
.description('Stop the KTX daemon')
.option('--all', 'Stop all KTX daemon processes recorded or discoverable on this machine', false)
.action(async (options: { all?: boolean }, command: CommandWithGlobalOptions) => {
await runRuntimeArgs(context, {

View file

@ -706,7 +706,7 @@ function failedStepDetail(result: KtxPublicIngestTargetResult): string | null {
const INTERNAL_FAILURE_LINE_RE =
/^(Report|Run|Job|Status|Adapter|Connection|Sync|Mode|Dry run|Diff|Tasks|Work units|Failed tasks|Saved memory|Provenance rows):\s*/;
const ACTIONABLE_FAILURE_LINE_RE =
/^(Missing bundled Python runtime manifest|KTX Python runtime is required|KTX managed daemon|Error:|Failed\b|Could not\b|Cannot\b)/;
/^(Missing bundled Python runtime manifest|KTX Python runtime is required|KTX daemon HTTP|Error:|Failed\b|Could not\b|Cannot\b)/;
function trimErrorPrefix(line: string): string {
return line.replace(/^Error:\s*/, '');

View file

@ -45,9 +45,7 @@ describe('getKtxCliPackageInfo', () => {
it('identifies the CLI package and its context dependency', () => {
expect(getKtxCliPackageInfo()).toEqual({
name: '@ktx/cli',
version: '0.1.0-rc.1',
packageVersion: '0.0.0-private',
runtimeVersion: '0.1.0-rc.1',
version: '0.0.0-private',
contextPackageName: '@ktx/context',
});
});
@ -70,8 +68,6 @@ describe('getKtxCliPackageInfo', () => {
).toEqual({
name: '@kaelio/ktx',
version: '0.1.0',
packageVersion: '0.1.0',
runtimeVersion: '0.1.0',
contextPackageName: '@ktx/context',
});
});
@ -118,7 +114,7 @@ describe('runKtxCli', () => {
await expect(runKtxCli(['--version'], testIo.io)).resolves.toBe(0);
expect(testIo.stdout()).toBe('@ktx/cli 0.1.0-rc.1\n');
expect(testIo.stdout()).toBe('@ktx/cli 0.0.0-private\n');
expect(testIo.stderr()).toBe('');
});
@ -282,7 +278,7 @@ describe('runKtxCli', () => {
expect(unknownIo.stderr()).toContain("unknown option '--query'");
});
it('routes runtime management commands with the release runtime version', async () => {
it('routes runtime management commands with the CLI package version', async () => {
const runtime = vi.fn(async () => 0);
const installIo = makeIo();
const startIo = makeIo();
@ -308,7 +304,7 @@ describe('runKtxCli', () => {
1,
{
command: 'install',
cliVersion: '0.1.0-rc.1',
cliVersion: '0.0.0-private',
feature: 'local-embeddings',
force: true,
},
@ -318,7 +314,7 @@ describe('runKtxCli', () => {
2,
{
command: 'start',
cliVersion: '0.1.0-rc.1',
cliVersion: '0.0.0-private',
projectDir: expect.any(String),
feature: 'local-embeddings',
force: true,
@ -329,7 +325,7 @@ describe('runKtxCli', () => {
3,
{
command: 'stop',
cliVersion: '0.1.0-rc.1',
cliVersion: '0.0.0-private',
projectDir: expect.any(String),
all: false,
},
@ -339,7 +335,7 @@ describe('runKtxCli', () => {
4,
{
command: 'stop',
cliVersion: '0.1.0-rc.1',
cliVersion: '0.0.0-private',
projectDir: expect.any(String),
all: true,
},
@ -349,7 +345,7 @@ describe('runKtxCli', () => {
5,
{
command: 'status',
cliVersion: '0.1.0-rc.1',
cliVersion: '0.0.0-private',
json: true,
},
statusIo.io,
@ -422,7 +418,7 @@ describe('runKtxCli', () => {
expect.objectContaining({
command: 'query',
projectDir: tempDir,
cliVersion: '0.1.0-rc.1',
cliVersion: '0.0.0-private',
runtimeInstallPolicy: 'prompt',
query: expect.objectContaining({ measures: ['orders.order_count'], dimensions: [] }),
}),
@ -437,7 +433,7 @@ describe('runKtxCli', () => {
).resolves.toBe(0);
expect(sl).toHaveBeenLastCalledWith(
expect.objectContaining({
cliVersion: '0.1.0-rc.1',
cliVersion: '0.0.0-private',
runtimeInstallPolicy: 'auto',
}),
autoIo.io,
@ -453,7 +449,7 @@ describe('runKtxCli', () => {
).resolves.toBe(0);
expect(sl).toHaveBeenLastCalledWith(
expect.objectContaining({
cliVersion: '0.1.0-rc.1',
cliVersion: '0.0.0-private',
runtimeInstallPolicy: 'never',
}),
noInputIo.io,
@ -589,7 +585,7 @@ describe('runKtxCli', () => {
skipAgents: false,
inputMode: 'auto',
yes: false,
cliVersion: '0.1.0-rc.1',
cliVersion: '0.0.0-private',
skipLlm: false,
skipEmbeddings: false,
databaseSchemas: [],
@ -719,7 +715,7 @@ describe('runKtxCli', () => {
inputMode: 'disabled',
depth: 'fast',
queryHistory: 'default',
cliVersion: '0.1.0-rc.1',
cliVersion: '0.0.0-private',
runtimeInstallPolicy: 'never',
},
testIo.io,
@ -746,7 +742,7 @@ describe('runKtxCli', () => {
inputMode: 'auto',
depth: 'deep',
queryHistory: 'default',
cliVersion: '0.1.0-rc.1',
cliVersion: '0.0.0-private',
runtimeInstallPolicy: 'prompt',
},
testIo.io,
@ -823,7 +819,7 @@ describe('runKtxCli', () => {
json: false,
inputMode: 'disabled',
queryHistory: 'default',
cliVersion: '0.1.0-rc.1',
cliVersion: '0.0.0-private',
runtimeInstallPolicy: 'never',
},
testIo.io,
@ -1128,7 +1124,7 @@ describe('runKtxCli', () => {
command: 'run',
projectDir: tempDir,
inputMode: 'disabled',
cliVersion: '0.1.0-rc.1',
cliVersion: '0.0.0-private',
anthropicApiKeyEnv: 'ANTHROPIC_API_KEY', // pragma: allowlist secret
llmModel: 'claude-sonnet-4-6',
skipLlm: false,
@ -1167,7 +1163,7 @@ describe('runKtxCli', () => {
command: 'run',
projectDir: tempDir,
inputMode: 'disabled',
cliVersion: '0.1.0-rc.1',
cliVersion: '0.0.0-private',
llmBackend: 'vertex',
vertexProject: 'local-gcp-project',
vertexLocation: 'us-east5',
@ -1204,7 +1200,7 @@ describe('runKtxCli', () => {
command: 'run',
projectDir: tempDir,
inputMode: 'disabled',
cliVersion: '0.1.0-rc.1',
cliVersion: '0.0.0-private',
llmBackend: 'claude-code',
llmModel: 'opus',
skipLlm: false,
@ -1312,7 +1308,7 @@ describe('runKtxCli', () => {
projectDir: '/tmp/project',
inputMode: 'disabled',
yes: true,
cliVersion: '0.1.0-rc.1',
cliVersion: '0.0.0-private',
skipLlm: true,
skipEmbeddings: true,
databaseDrivers: ['postgres'],
@ -1653,7 +1649,7 @@ describe('runKtxCli', () => {
queryFile: '/tmp/query.json',
execute: false,
format: 'json',
cliVersion: '0.1.0-rc.1',
cliVersion: '0.0.0-private',
runtimeInstallPolicy: 'auto',
},
autoIo.io,
@ -1667,7 +1663,7 @@ describe('runKtxCli', () => {
queryFile: '/tmp/query.json',
execute: false,
format: 'json',
cliVersion: '0.1.0-rc.1',
cliVersion: '0.0.0-private',
runtimeInstallPolicy: 'never',
},
neverIo.io,

View file

@ -1334,7 +1334,7 @@ describe('runKtxIngest', () => {
);
});
it('passes managed daemon options to adapters and pull-config options when no explicit daemon URL is set', async () => {
it('passes KTX daemon options to adapters and pull-config options when no explicit daemon URL is set', async () => {
const projectDir = join(tempDir, 'managed-daemon-ingest-project');
await initKtxProject({ projectDir });
await writeWarehouseConfig(projectDir);

View file

@ -117,7 +117,7 @@ describe('managedLocalEmbeddingProjectConfig', () => {
});
describe('managedLocalEmbeddingHealthConfig', () => {
it('uses the active managed daemon URL for the immediate health check', () => {
it('uses the active KTX daemon URL for the immediate health check', () => {
expect(
managedLocalEmbeddingHealthConfig({
baseUrl: 'http://127.0.0.1:61234',
@ -134,7 +134,7 @@ describe('managedLocalEmbeddingHealthConfig', () => {
});
describe('ensureManagedLocalEmbeddingsDaemon', () => {
it('ensures the local-embeddings feature and starts the managed daemon', async () => {
it('ensures the local-embeddings feature and starts the KTX daemon', async () => {
const io = makeIo();
const ensureRuntime = vi.fn(async () => runtime());
const startDaemon = vi.fn(async () => daemonResult('started'));
@ -169,7 +169,7 @@ describe('ensureManagedLocalEmbeddingsDaemon', () => {
features: ['local-embeddings'],
force: false,
});
expect(io.stderr()).toContain('Started KTX local embeddings daemon: http://127.0.0.1:61234');
expect(io.stderr()).toContain('Started KTX daemon: http://127.0.0.1:61234');
});
it('reuses an already running daemon without reporting a new start', async () => {
@ -184,6 +184,6 @@ describe('ensureManagedLocalEmbeddingsDaemon', () => {
startDaemon: vi.fn(async () => daemonResult('reused')),
});
expect(io.stderr()).toContain('Using KTX local embeddings daemon: http://127.0.0.1:61234');
expect(io.stderr()).toContain('Using KTX daemon: http://127.0.0.1:61234');
});
});

View file

@ -89,7 +89,7 @@ export async function ensureManagedLocalEmbeddingsDaemon(
});
const verb = daemon.status === 'started' ? 'Started' : 'Using';
options.io.stderr.write(`${verb} KTX local embeddings daemon: ${daemon.baseUrl}\n`);
options.io.stderr.write(`${verb} KTX daemon: ${daemon.baseUrl}\n`);
return {
baseUrl: daemon.baseUrl,

View file

@ -125,7 +125,7 @@ function daemonOptionsBase(root: string) {
} as const;
}
describe('managed Python daemon lifecycle', () => {
describe('KTX daemon lifecycle', () => {
let tempDir: string;
beforeEach(async () => {

View file

@ -325,7 +325,7 @@ async function waitForHealth(input: {
return;
}
lastDetail = finalHealth.detail;
throw new Error(`KTX Python daemon failed to start: ${lastDetail}. stderr: ${input.state.stderrLog}`);
throw new Error(`KTX daemon failed to start: ${lastDetail}. stderr: ${input.state.stderrLog}`);
}
async function removeState(layout: ManagedPythonDaemonLayout): Promise<void> {
@ -705,7 +705,7 @@ export async function startManagedPythonDaemon(
);
child.unref();
if (!child.pid) {
throw new Error(`KTX Python daemon did not report a pid. stderr: ${layout.daemonStderrPath}`);
throw new Error(`KTX daemon did not report a pid. stderr: ${layout.daemonStderrPath}`);
}
const state: ManagedPythonDaemonState = {
schemaVersion: 1,

View file

@ -57,7 +57,7 @@ describe('createManagedPythonDaemonBaseUrlResolver', () => {
features: ['core'],
force: false,
});
expect(testIo.stderr()).toContain('Started KTX Python daemon: http://127.0.0.1:61234');
expect(testIo.stderr()).toContain('Started KTX daemon: http://127.0.0.1:61234');
});
it('reports daemon reuse without reinstalling after the first resolved URL', async () => {
@ -86,7 +86,7 @@ describe('createManagedPythonDaemonBaseUrlResolver', () => {
expect(ensureRuntime).toHaveBeenCalledTimes(1);
expect(startDaemon).toHaveBeenCalledTimes(1);
expect(testIo.stderr()).toContain('Using existing KTX Python daemon: http://127.0.0.1:61234');
expect(testIo.stderr()).toContain('Using existing KTX daemon: http://127.0.0.1:61234');
});
});
@ -104,8 +104,8 @@ describe('createManagedDaemonHttpJsonRunner', () => {
});
});
describe('managed daemon ingest ports', () => {
it('creates a Looker table parser backed by the managed daemon runner', async () => {
describe('KTX daemon ingest ports', () => {
it('creates a Looker table parser backed by the KTX daemon runner', async () => {
const requestJson = vi.fn(async () => ({
results: {
'model.explore': {
@ -135,7 +135,7 @@ describe('managed daemon ingest ports', () => {
});
});
it('creates a SQL analysis port backed by the managed daemon runner', async () => {
it('creates a SQL analysis port backed by the KTX daemon runner', async () => {
const requestJson = vi.fn(async () => ({
fingerprint: 'select-orders',
normalized_sql: 'SELECT * FROM public.orders WHERE id = ?',
@ -157,7 +157,7 @@ describe('managed daemon ingest ports', () => {
});
});
it('routes SQL batch analysis through the managed daemon runner', async () => {
it('routes SQL batch analysis through the KTX daemon runner', async () => {
const requestJson = vi.fn(async () => ({
results: {
orders: {

View file

@ -70,7 +70,7 @@ function normalizedBaseUrl(baseUrl: string): string {
function parseJsonObject(raw: string, path: string): Record<string, unknown> {
const parsed = JSON.parse(raw) as unknown;
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
throw new Error(`KTX managed daemon HTTP ${path} returned non-object JSON`);
throw new Error(`KTX daemon HTTP ${path} returned non-object JSON`);
}
return parsed as Record<string, unknown>;
}
@ -101,7 +101,7 @@ export async function postManagedDaemonJson(
const text = Buffer.concat(chunks).toString('utf8');
const statusCode = response.statusCode ?? 0;
if (statusCode < 200 || statusCode >= 300) {
reject(new Error(`KTX managed daemon HTTP ${path} failed with ${statusCode}: ${text}`));
reject(new Error(`KTX daemon HTTP ${path} failed with ${statusCode}: ${text}`));
return;
}
try {
@ -142,7 +142,7 @@ export function createManagedPythonDaemonBaseUrlResolver(
force: false,
});
const verb = daemon.status === 'started' ? 'Started' : 'Using existing';
options.io.stderr.write(`${verb} KTX Python daemon: ${daemon.baseUrl}\n`);
options.io.stderr.write(`${verb} KTX daemon: ${daemon.baseUrl}\n`);
cachedBaseUrl = daemon.baseUrl;
return cachedBaseUrl;
};

View file

@ -14,8 +14,6 @@ function stubPackageInfo(): KtxCliPackageInfo {
return {
name: '@ktx/cli',
version: '0.0.0-docs',
packageVersion: '0.0.0-private',
runtimeVersion: '0.0.0-docs',
contextPackageName: '@ktx/context',
};
}

View file

@ -679,7 +679,7 @@ function createCapturedPublicIngestIo(): CapturedPublicIngestIo {
const INTERNAL_STATUS_LINE_RE =
/^(Report|Run|Job|Status|Adapter|Connection|Sync|Diff|Tasks|Work units|Failed tasks|Saved memory|Provenance rows):\s*/;
const ACTIONABLE_FAILURE_LINE_RE =
/^(Missing bundled Python runtime manifest|KTX Python runtime is required|KTX managed daemon|Error:|Failed\b|Could not\b|Cannot\b)/;
/^(Missing bundled Python runtime manifest|KTX Python runtime is required|KTX daemon HTTP|Error:|Failed\b|Could not\b|Cannot\b)/;
const RUNTIME_BACKED_RETRY_LINE_RE = /^Then retry the runtime-backed KTX command\.?$/;
function trimErrorPrefix(line: string): string {

View file

@ -1,55 +1,9 @@
import { existsSync, readFileSync } from 'node:fs';
import { dirname, join, parse } from 'node:path';
import { fileURLToPath } from 'node:url';
const semverPattern =
/^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/;
function isPlainObject(value: unknown): value is Record<string, unknown> {
return typeof value === 'object' && value !== null && !Array.isArray(value);
}
function assertReleaseVersion(value: unknown, source: string): string {
export function assertCliVersion(value: unknown, source: string): string {
if (typeof value !== 'string' || !semverPattern.test(value)) {
throw new Error(`Invalid KTX release version in ${source}`);
throw new Error(`Invalid KTX CLI version in ${source}`);
}
return value;
}
function findReleasePolicyPath(startDir: string): string | undefined {
let current = startDir;
const root = parse(current).root;
while (true) {
const candidate = join(current, 'release-policy.json');
if (existsSync(candidate)) {
return candidate;
}
if (current === root) {
return undefined;
}
current = dirname(current);
}
}
function readSourceReleaseVersion(startDir = dirname(fileURLToPath(import.meta.url))): string | undefined {
const policyPath = findReleasePolicyPath(startDir);
if (!policyPath) {
return undefined;
}
const policy = JSON.parse(readFileSync(policyPath, 'utf8')) as unknown;
if (!isPlainObject(policy)) {
throw new Error(`Invalid KTX release policy: ${policyPath}`);
}
return assertReleaseVersion(policy.publicNpmPackageVersion, policyPath);
}
export function resolveKtxRuntimeVersion(input: {
packageName: string;
packageVersion: string;
startDir?: string;
}): string {
if (input.packageName === '@kaelio/ktx') {
return assertReleaseVersion(input.packageVersion, `${input.packageName}/package.json`);
}
return readSourceReleaseVersion(input.startDir) ?? input.packageVersion;
}

View file

@ -94,7 +94,7 @@ export function resolveProjectRuntimeRequirements(
requirements.push({
feature: 'core',
reason: 'database-introspection',
detail: 'Database introspection fallback uses the Python daemon.',
detail: 'Database introspection fallback uses the KTX daemon.',
});
}

View file

@ -109,7 +109,7 @@ describe('runKtxRuntime', () => {
expect(io.stderr()).toBe('');
});
it('starts the managed Python daemon and prints the base URL', async () => {
it('starts the KTX daemon and prints the base URL', async () => {
const io = makeIo();
const deps: KtxRuntimeDeps = {
startDaemon: vi.fn(async (): Promise<ManagedPythonDaemonStartResult> => ({
@ -160,14 +160,14 @@ describe('runKtxRuntime', () => {
features: ['local-embeddings'],
force: true,
});
expect(io.stdout()).toContain('Started KTX Python daemon');
expect(io.stdout()).toContain('Started KTX daemon');
expect(io.stdout()).toContain('url: http://127.0.0.1:61234');
expect(io.stdout()).toContain('pid: 4242');
expect(io.stdout()).toContain('features: core, local-embeddings');
expect(io.stdout()).toContain('stderr: /work/proj/.ktx/runtime/daemon.stderr.log');
});
it('stops the managed Python daemon', async () => {
it('stops the KTX daemon', async () => {
const io = makeIo();
const deps: KtxRuntimeDeps = {
stopDaemon: vi.fn(async (): Promise<ManagedPythonDaemonStopResult> => ({
@ -208,11 +208,11 @@ describe('runKtxRuntime', () => {
).resolves.toBe(0);
expect(deps.stopDaemon).toHaveBeenCalledWith({ cliVersion: '0.2.0', projectDir: '/work/proj' });
expect(io.stdout()).toContain('Stopped KTX Python daemon');
expect(io.stdout()).toContain('Stopped KTX daemon');
expect(io.stdout()).toContain('pid: 4242');
});
it('stops all discovered Python daemons and reports the summary', async () => {
it('stops all discovered KTX daemons and reports the summary', async () => {
const io = makeIo();
const deps: KtxRuntimeDeps = {
stopAllDaemons: vi.fn(async (): Promise<ManagedPythonDaemonStopAllResult> => ({
@ -231,7 +231,7 @@ describe('runKtxRuntime', () => {
).resolves.toBe(0);
expect(deps.stopAllDaemons).toHaveBeenCalledWith({ cliVersion: '0.2.0', projectDir: '/work/proj' });
expect(io.stdout()).toContain('Stopped 2 KTX Python daemons');
expect(io.stdout()).toContain('Stopped 2 KTX daemons');
expect(io.stdout()).toContain('pid: 4242 source: state url: http://127.0.0.1:61234');
expect(io.stdout()).toContain('pid: 5252 source: process url: http://127.0.0.1:8765');
});
@ -259,7 +259,7 @@ describe('runKtxRuntime', () => {
runKtxRuntime({ command: 'stop', cliVersion: '0.2.0', projectDir: '/work/proj', all: true }, io.io, deps),
).resolves.toBe(1);
expect(io.stderr()).toContain('Stopped 0 KTX Python daemons; failed 1');
expect(io.stderr()).toContain('Stopped 0 KTX daemons; failed 1');
expect(io.stderr()).toContain('pid: 4242 source: state url: http://127.0.0.1:61234');
expect(io.stderr()).toContain('process scan: ps failed');
});

View file

@ -56,7 +56,7 @@ function writeInstallResult(io: KtxCliIo, result: ManagedPythonRuntimeInstallRes
function writeDaemonStart(io: KtxCliIo, result: ManagedPythonDaemonStartResult): void {
const verb = result.status === 'reused' ? 'Using existing' : 'Started';
io.stdout.write(`${verb} KTX Python daemon\n`);
io.stdout.write(`${verb} KTX daemon\n`);
io.stdout.write(`url: ${result.baseUrl}\n`);
io.stdout.write(`pid: ${result.state.pid}\n`);
io.stdout.write(`version: ${result.state.version}\n`);
@ -68,10 +68,10 @@ function writeDaemonStart(io: KtxCliIo, result: ManagedPythonDaemonStartResult):
function writeDaemonStop(io: KtxCliIo, result: ManagedPythonDaemonStopResult): void {
if (result.status === 'already-stopped') {
io.stdout.write('KTX Python daemon already stopped\n');
io.stdout.write('KTX daemon already stopped\n');
return;
}
io.stdout.write('Stopped KTX Python daemon\n');
io.stdout.write('Stopped KTX daemon\n');
io.stdout.write(`pid: ${result.state?.pid ?? 'unknown'}\n`);
io.stdout.write(`state: ${result.layout.daemonStatePath}\n`);
}
@ -94,11 +94,11 @@ function writeDaemonStopAll(io: KtxCliIo, result: ManagedPythonDaemonStopAllResu
result.failed.length === 0 &&
result.scanErrors.length === 0
) {
io.stdout.write('No KTX Python daemons found\n');
io.stdout.write('No KTX daemons found\n');
return 0;
}
if (failed === 0) {
io.stdout.write(`Stopped ${result.stopped.length} KTX Python daemons\n`);
io.stdout.write(`Stopped ${result.stopped.length} KTX daemons\n`);
if (result.stale.length > 0) {
io.stdout.write(`Cleaned ${result.stale.length} stale daemon states\n`);
}
@ -111,7 +111,7 @@ function writeDaemonStopAll(io: KtxCliIo, result: ManagedPythonDaemonStopAllResu
return 0;
}
io.stderr.write(
`Stopped ${result.stopped.length} KTX Python daemons; failed ${result.failed.length}${
`Stopped ${result.stopped.length} KTX daemons; failed ${result.failed.length}${
result.stale.length > 0 ? `; cleaned stale ${result.stale.length}` : ''
}\n`,
);

View file

@ -376,7 +376,7 @@ describe('runKtxScan', () => {
expect(io.stdout()).not.toContain('/~');
});
it('passes managed daemon options to local ingest adapters when no explicit daemon URL is set', async () => {
it('passes KTX daemon options to local ingest adapters when no explicit daemon URL is set', async () => {
await initKtxProject({ projectDir: tempDir });
const createLocalIngestAdapters = vi.fn(() => []);
const runLocalScan = vi.fn(

View file

@ -361,7 +361,7 @@ describe('setup embeddings step', () => {
);
expect(result.status).toBe('failed');
expect(io.stderr()).toContain('Recent local embeddings daemon stderr:');
expect(io.stderr()).toContain('Recent KTX daemon stderr:');
expect(io.stderr()).toContain('daemon traceback line 6');
expect(io.stderr()).toContain('daemon traceback line 45');
expect(io.stderr()).not.toContain('daemon traceback line 5');
@ -391,7 +391,7 @@ describe('setup embeddings step', () => {
);
expect(result.status).toBe('failed');
expect(io.stderr()).not.toContain('Recent local embeddings daemon stderr:');
expect(io.stderr()).not.toContain('Recent KTX daemon stderr:');
});
it('uses fixed OpenAI defaults and only asks for credentials when OpenAI is selected', async () => {

View file

@ -312,7 +312,7 @@ function localEmbeddingSetupMessage(message: string, stderrTail: string[] = []):
'The first run may download Python packages and the all-MiniLM-L6-v2 model.',
];
if (stderrTail.length > 0) {
lines.push('Recent local embeddings daemon stderr:', ...stderrTail);
lines.push('Recent KTX daemon stderr:', ...stderrTail);
}
return lines.join('\n');
}

View file

@ -97,7 +97,7 @@ describe('runKtxSetupRuntimeStep', () => {
expect(io.stderr()).toContain('ktx admin runtime install --yes');
});
it('starts the managed local embeddings daemon for configured sentence-transformers embeddings', async () => {
it('starts the KTX daemon for configured sentence-transformers embeddings', async () => {
const io = makeIo();
const ensureLocalEmbeddings = vi.fn(async () => ({
baseUrl: 'http://127.0.0.1:61234',