diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7abe8bed..3b331b02 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -109,7 +109,7 @@ jobs: run: pnpm run build - name: Run slow CLI tests - run: pnpm --filter @ktx/cli run test:slow + run: pnpm --filter @kaelio/ktx run test:slow cli-smoke-tests: name: CLI smoke tests diff --git a/AGENTS.md b/AGENTS.md index 83659a07..52ddd87d 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -89,7 +89,7 @@ pnpm run type-check pnpm run test pnpm run check pnpm run dead-code -pnpm --filter @ktx/cli run smoke +pnpm --filter @kaelio/ktx run smoke pnpm --filter './packages/*' run build pnpm --filter './packages/*' run test pnpm --filter './packages/*' run type-check diff --git a/docs-site/content/docs/community/contributing.mdx b/docs-site/content/docs/community/contributing.mdx index 8002a5cc..70c390ec 100644 --- a/docs-site/content/docs/community/contributing.mdx +++ b/docs-site/content/docs/community/contributing.mdx @@ -63,7 +63,7 @@ pnpm run build This builds the TypeScript package. You can also build the package directly: ```bash -pnpm --filter @ktx/cli run build +pnpm --filter @kaelio/ktx run build ``` ### Link the CLI for local testing @@ -110,16 +110,16 @@ resolution. The Python projects use `pyproject.toml` for dependency management. pnpm run test # Run tests for the TypeScript package -pnpm --filter @ktx/cli run test +pnpm --filter @kaelio/ktx run test # Type-check all packages pnpm run type-check # Type-check the TypeScript package -pnpm --filter @ktx/cli run type-check +pnpm --filter @kaelio/ktx run type-check # CLI smoke test -pnpm --filter @ktx/cli run smoke +pnpm --filter @kaelio/ktx run smoke ``` ### Python @@ -204,9 +204,9 @@ it. Keep runtime loading dynamic when the driver is optional. ### Step 5: Test ```bash -pnpm --filter @ktx/cli run build -pnpm --filter @ktx/cli run type-check -pnpm --filter @ktx/cli run test +pnpm --filter @kaelio/ktx run build +pnpm --filter @kaelio/ktx run type-check +pnpm --filter @kaelio/ktx run test ``` Use `packages/cli/src/connectors/sqlite/` as a minimal reference and diff --git a/examples/postgres-historic/README.md b/examples/postgres-historic/README.md index 30dcfde5..64fc2593 100644 --- a/examples/postgres-historic/README.md +++ b/examples/postgres-historic/README.md @@ -58,7 +58,7 @@ Create a project and enable query history: ```bash export WAREHOUSE_DATABASE_URL=postgresql://ktx_reader:ktx_reader@127.0.0.1:55432/analytics # pragma: allowlist secret -pnpm --filter @ktx/cli run build +pnpm --filter @kaelio/ktx run build node packages/cli/dist/bin.js --project-dir /tmp/ktx-postgres-historic setup \ --new \ --skip-agents \ diff --git a/examples/postgres-historic/scripts/smoke.sh b/examples/postgres-historic/scripts/smoke.sh index 1fe10b70..947eeb88 100755 --- a/examples/postgres-historic/scripts/smoke.sh +++ b/examples/postgres-historic/scripts/smoke.sh @@ -198,8 +198,7 @@ NODE } cd "$KTX_ROOT" -pnpm --filter @ktx/context run build -pnpm --filter @ktx/cli run build +pnpm --filter @kaelio/ktx run build docker compose -f "$COMPOSE_FILE" up -d --wait "$EXAMPLE_DIR/scripts/generate-workload.sh" base diff --git a/package.json b/package.json index 968c566b..9fcd583a 100644 --- a/package.json +++ b/package.json @@ -40,12 +40,12 @@ "semantic-release": "semantic-release", "semantic-release:debug": "semantic-release --dry-run --debug", "semantic-release:dry-run": "semantic-release --dry-run --no-ci", - "smoke": "pnpm run build && pnpm --filter @ktx/cli run smoke", + "smoke": "pnpm run build && pnpm --filter @kaelio/ktx run smoke", "test": "node --test scripts/*.test.mjs && pnpm --filter './packages/*' run test", "test:coverage": "pnpm run test:coverage:ts && pnpm run test:coverage:py", "test:coverage:py": "uv run pytest --cov=python/ktx-sl/semantic_layer --cov=python/ktx-daemon/src/ktx_daemon --cov-report=xml:coverage/python.xml --cov-report=term", "test:coverage:ts": "pnpm --filter './packages/*' run build && pnpm --filter './packages/*' run test --coverage --coverage.reporter=lcov --coverage.exclude='dist/**' && node scripts/normalize-lcov-paths.mjs packages/*/coverage/lcov.info", - "test:slow": "pnpm --filter @ktx/cli run test:slow", + "test:slow": "pnpm --filter @kaelio/ktx run test:slow", "type-check": "pnpm --filter './packages/*' run type-check" }, "devDependencies": { diff --git a/packages/cli/package.json b/packages/cli/package.json index ba51f1ab..84acf6f2 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,8 +1,7 @@ { - "name": "@ktx/cli", + "name": "@kaelio/ktx", "version": "0.4.1", - "description": "Standalone ktx context layer CLI", - "private": true, + "description": "Standalone ktx context layer for database agents", "type": "module", "engines": { "node": ">=22.0.0" @@ -24,6 +23,10 @@ "dist", "assets" ], + "publishConfig": { + "access": "public", + "provenance": true + }, "scripts": { "assets:demo": "node scripts/build-demo-assets.mjs", "build": "tsc -p tsconfig.json && node scripts/copy-runtime-assets.mjs && node ../../scripts/prepare-cli-bin.mjs", @@ -89,11 +92,11 @@ "license": "Apache-2.0", "repository": { "type": "git", - "url": "git+https://github.com/kaelio/ktx.git", + "url": "https://github.com/Kaelio/ktx", "directory": "packages/cli" }, "bugs": { - "url": "https://github.com/kaelio/ktx/issues" + "url": "https://github.com/Kaelio/ktx/issues" }, - "homepage": "https://github.com/kaelio/ktx#readme" + "homepage": "https://github.com/Kaelio/ktx#readme" } diff --git a/packages/cli/src/admin-reindex.test.ts b/packages/cli/src/admin-reindex.test.ts index 0802746a..dace420f 100644 --- a/packages/cli/src/admin-reindex.test.ts +++ b/packages/cli/src/admin-reindex.test.ts @@ -5,7 +5,7 @@ import { describe, expect, it, vi } from 'vitest'; import { renderReindexJson, renderReindexPlain, reindexHasErrors } from './admin-reindex.js'; import { runKtxCli } from './index.js'; -const cliVersion = (createRequire(import.meta.url)('@ktx/cli/package.json') as { version: string }) +const cliVersion = (createRequire(import.meta.url)('@kaelio/ktx/package.json') as { version: string }) .version; function makeIo(options: { stdoutIsTTY?: boolean } = {}) { diff --git a/packages/cli/src/cli-program.test.ts b/packages/cli/src/cli-program.test.ts index 6b9ffd8f..565a5d56 100644 --- a/packages/cli/src/cli-program.test.ts +++ b/packages/cli/src/cli-program.test.ts @@ -12,7 +12,7 @@ function stubIo(): KtxCliIo { function stubPackageInfo(): KtxCliPackageInfo { return { - name: '@ktx/cli', + name: '@kaelio/ktx', version: '0.0.0-test', }; } diff --git a/packages/cli/src/commands/mcp-commands.test.ts b/packages/cli/src/commands/mcp-commands.test.ts index 0d31b8d4..dfcd1946 100644 --- a/packages/cli/src/commands/mcp-commands.test.ts +++ b/packages/cli/src/commands/mcp-commands.test.ts @@ -11,7 +11,7 @@ function makeContext(overrides: Partial = {}): KtxCliComma stderr: { write: vi.fn() }, }, deps: {}, - packageInfo: { name: '@ktx/cli', version: '0.0.0-test' }, + packageInfo: { name: '@kaelio/ktx', version: '0.0.0-test' }, setExitCode: (code) => { exitCode = code; }, diff --git a/packages/cli/src/commands/sql-commands.test.ts b/packages/cli/src/commands/sql-commands.test.ts index a24450fc..4f2c0277 100644 --- a/packages/cli/src/commands/sql-commands.test.ts +++ b/packages/cli/src/commands/sql-commands.test.ts @@ -11,7 +11,7 @@ function makeContext(overrides: Partial = {}): KtxCliComma stderr: { write: vi.fn() }, }, deps: {}, - packageInfo: { name: '@ktx/cli', version: '0.0.0-test' }, + packageInfo: { name: '@kaelio/ktx', version: '0.0.0-test' }, setExitCode: (code) => { exitCode = code; }, diff --git a/packages/cli/src/doctor.test.ts b/packages/cli/src/doctor.test.ts index a6bfbff6..b483ea20 100644 --- a/packages/cli/src/doctor.test.ts +++ b/packages/cli/src/doctor.test.ts @@ -106,7 +106,7 @@ describe('runSetupDoctorChecks', () => { if (command === 'pnpm' && args[0] === '--version') return '10.28.0'; if (command === 'corepack' && args[0] === '--version') return '0.32.0'; if (command === 'uv' && args[0] === '--version') return 'uv 0.9.5'; - if (command === process.execPath && args.includes('--version')) return '@ktx/cli 0.0.0-private'; + if (command === process.execPath && args.includes('--version')) return '@kaelio/ktx 0.0.0-private'; throw new Error(`${command} ${args.join(' ')}`); }, pathExists: async () => true, @@ -163,7 +163,7 @@ describe('runSetupDoctorChecks', () => { if (command === 'pnpm' && args[0] === '--version') return '10.28.0'; if (command === 'corepack' && args[0] === '--version') throw new Error('spawn corepack ENOENT'); if (command === 'uv' && args[0] === '--version') return 'uv 0.9.5'; - if (command === process.execPath && args.includes('--version')) return '@ktx/cli 0.0.0-private'; + if (command === process.execPath && args.includes('--version')) return '@kaelio/ktx 0.0.0-private'; throw new Error(`${command} ${args.join(' ')}`); }, pathExists: async () => true, diff --git a/packages/cli/src/index.test.ts b/packages/cli/src/index.test.ts index 473b5002..4cc6c1e9 100644 --- a/packages/cli/src/index.test.ts +++ b/packages/cli/src/index.test.ts @@ -19,7 +19,7 @@ import { const require = createRequire(import.meta.url); -const cliPackageJson = require('@ktx/cli/package.json') as { name: string; version: string }; +const cliPackageJson = require('@kaelio/ktx/package.json') as { name: string; version: string }; const cliVersion = cliPackageJson.version; function makeIo(options: { stdoutIsTty?: boolean } = {}) { @@ -47,16 +47,16 @@ function makeIo(options: { stdoutIsTty?: boolean } = {}) { describe('getKtxCliPackageInfo', () => { it('identifies the CLI package', () => { expect(getKtxCliPackageInfo()).toEqual({ - name: '@ktx/cli', + name: '@kaelio/ktx', version: cliVersion, }); }); it('exports package metadata for package managers and runtime diagnostics', () => { - const packageJson = require('@ktx/cli/package.json') as { name: string; version: string }; + const packageJson = require('@kaelio/ktx/package.json') as { name: string; version: string }; expect(packageJson).toMatchObject({ - name: '@ktx/cli', + name: '@kaelio/ktx', version: cliVersion, }); expect(cliVersion).toMatch(/^\d+\.\d+\.\d+/); @@ -116,7 +116,7 @@ describe('runKtxCli', () => { await expect(runKtxCli(['--version'], testIo.io)).resolves.toBe(0); - expect(testIo.stdout()).toBe(`@ktx/cli ${cliVersion}\n`); + expect(testIo.stdout()).toBe(`@kaelio/ktx ${cliVersion}\n`); expect(testIo.stderr()).toBe(''); }); diff --git a/packages/cli/src/print-command-tree.ts b/packages/cli/src/print-command-tree.ts index 7a2c9d83..cc304d8a 100644 --- a/packages/cli/src/print-command-tree.ts +++ b/packages/cli/src/print-command-tree.ts @@ -12,7 +12,7 @@ function silentIo(): KtxCliIo { function stubPackageInfo(): KtxCliPackageInfo { return { - name: '@ktx/cli', + name: '@kaelio/ktx', version: '0.0.0-docs', }; } diff --git a/python/ktx-daemon/README.md b/python/ktx-daemon/README.md index bb429c5e..95a3ffbf 100644 --- a/python/ktx-daemon/README.md +++ b/python/ktx-daemon/README.md @@ -4,7 +4,7 @@ It supports portable compute in two modes: -- One-shot commands, used by default by `@ktx/context`. +- One-shot commands, used by default by the `@kaelio/ktx` CLI. - An explicit HTTP server for long-running local MCP sessions. ## One-shot semantic query diff --git a/scripts/build-public-npm-package.mjs b/scripts/build-public-npm-package.mjs deleted file mode 100644 index 04ac7682..00000000 --- a/scripts/build-public-npm-package.mjs +++ /dev/null @@ -1,156 +0,0 @@ -#!/usr/bin/env node - -import { execFile } from 'node:child_process'; -import { cp, mkdir, readFile, rm, writeFile } from 'node:fs/promises'; -import { dirname, join, resolve } from 'node:path'; -import { fileURLToPath, pathToFileURL } from 'node:url'; -import { promisify } from 'node:util'; - -import { - PUBLIC_NPM_PACKAGE_NAME, - publicNpmPackageVersion, -} from './public-npm-release-metadata.mjs'; - -const execFileAsync = promisify(execFile); - -export const PUBLIC_NPM_PACKAGE_VERSION = publicNpmPackageVersion(); -export { PUBLIC_NPM_PACKAGE_NAME }; - -export function publicNpmPackageTarballName(version = PUBLIC_NPM_PACKAGE_VERSION) { - return `kaelio-ktx-${version}.tgz`; -} - -function scriptRootDir() { - return resolve(dirname(fileURLToPath(import.meta.url)), '..'); -} - -export function publicNpmPackageLayout(rootDir = scriptRootDir(), version = PUBLIC_NPM_PACKAGE_VERSION) { - return { - rootDir, - packageVersion: version, - cliPackageRoot: join(rootDir, 'packages', 'cli'), - packRoot: join(rootDir, 'dist', 'public-npm-package'), - npmDir: join(rootDir, 'dist', 'artifacts', 'npm'), - tarballPath: join(rootDir, 'dist', 'artifacts', 'npm', publicNpmPackageTarballName(version)), - }; -} - -async function readJson(path) { - return JSON.parse(await readFile(path, 'utf8')); -} - -async function writeJson(path, value) { - await writeFile(path, `${JSON.stringify(value, null, 2)}\n`); -} - -function sortedObject(entries) { - return Object.fromEntries([...entries].sort(([left], [right]) => left.localeCompare(right))); -} - -function isWorkspacePackageName(name) { - return name.startsWith('@ktx/'); -} - -export function collectPublicDependencies(cliPackageJson) { - return sortedObject( - Object.entries(cliPackageJson.dependencies ?? {}).filter(([name]) => !isWorkspacePackageName(name)), - ); -} - -export function publicNpmPackageJson(cliPackageJson, dependencies, version = PUBLIC_NPM_PACKAGE_VERSION) { - return { - name: PUBLIC_NPM_PACKAGE_NAME, - version, - description: 'Standalone KTX context layer for database agents', - private: false, - type: 'module', - engines: cliPackageJson.engines ?? { node: '>=22.0.0' }, - bin: { ktx: './dist/bin.js' }, - main: cliPackageJson.main ?? 'dist/index.js', - types: cliPackageJson.types ?? 'dist/index.d.ts', - exports: cliPackageJson.exports ?? { - '.': { - types: './dist/index.d.ts', - import: './dist/index.js', - default: './dist/index.js', - }, - './package.json': './package.json', - }, - files: ['dist', 'assets'], - dependencies, - license: cliPackageJson.license ?? 'Apache-2.0', - repository: { - type: 'git', - url: 'https://github.com/Kaelio/ktx', - }, - bugs: { - url: 'https://github.com/Kaelio/ktx/issues', - }, - homepage: 'https://github.com/Kaelio/ktx#readme', - }; -} - -async function copyPackageFileEntries(sourceRoot, targetRoot, packageJson) { - for (const entry of packageJson.files ?? ['dist']) { - await cp(join(sourceRoot, entry), join(targetRoot, entry), { - recursive: true, - force: true, - }); - } -} - -async function copyCliPackage(layout, cliPackageJson, dependencies) { - await copyPackageFileEntries(layout.cliPackageRoot, layout.packRoot, cliPackageJson); - await writeJson( - join(layout.packRoot, 'package.json'), - publicNpmPackageJson(cliPackageJson, dependencies, layout.packageVersion), - ); -} - -export async function createPublicNpmPackageTree(layout = publicNpmPackageLayout()) { - const cliPackageJson = await readJson(join(layout.cliPackageRoot, 'package.json')); - const dependencies = collectPublicDependencies(cliPackageJson); - - await rm(layout.packRoot, { recursive: true, force: true }); - await mkdir(layout.packRoot, { recursive: true }); - await mkdir(layout.npmDir, { recursive: true }); - await copyCliPackage(layout, cliPackageJson, dependencies); - - return { - layout, - packageJson: publicNpmPackageJson(cliPackageJson, dependencies, layout.packageVersion), - }; -} - -export function publicNpmPackCommand(layout = publicNpmPackageLayout()) { - return { - command: 'pnpm', - args: ['--config.node-linker=hoisted', 'pack', '--out', layout.tarballPath], - cwd: layout.packRoot, - }; -} - -export async function buildPublicNpmPackage(layout = publicNpmPackageLayout()) { - await createPublicNpmPackageTree(layout); - const pack = publicNpmPackCommand(layout); - await execFileAsync(pack.command, pack.args, { - cwd: pack.cwd, - encoding: 'utf8', - maxBuffer: 10 * 1024 * 1024, - }); - return layout.tarballPath; -} - -async function main() { - const tarball = await buildPublicNpmPackage(); - process.stdout.write(`Built ${PUBLIC_NPM_PACKAGE_NAME} package: ${tarball}\n`); -} - -if (import.meta.url === pathToFileURL(process.argv[1] ?? '').href) { - try { - await main(); - } catch (error) { - process.stderr.write(`${error instanceof Error ? error.stack : String(error)}\n`); - process.exitCode = 1; - } -} diff --git a/scripts/build-public-npm-package.test.mjs b/scripts/build-public-npm-package.test.mjs deleted file mode 100644 index dc218df8..00000000 --- a/scripts/build-public-npm-package.test.mjs +++ /dev/null @@ -1,187 +0,0 @@ -import assert from 'node:assert/strict'; -import { mkdir, mkdtemp, readFile, rm, writeFile } from 'node:fs/promises'; -import { tmpdir } from 'node:os'; -import { join } from 'node:path'; -import { describe, it } from 'node:test'; - -import { - PUBLIC_NPM_PACKAGE_NAME, - PUBLIC_NPM_PACKAGE_VERSION, - collectPublicDependencies, - createPublicNpmPackageTree, - publicNpmPackageJson, - publicNpmPackageLayout, - publicNpmPackageTarballName, - publicNpmPackCommand, -} from './build-public-npm-package.mjs'; - -async function writeJson(path, value) { - await writeFile(path, `${JSON.stringify(value, null, 2)}\n`); -} - -async function writePackage(root, packageRoot, packageJson, files = {}) { - const absoluteRoot = join(root, packageRoot); - await mkdir(absoluteRoot, { recursive: true }); - await writeJson(join(absoluteRoot, 'package.json'), packageJson); - - for (const [relativePath, contents] of Object.entries(files)) { - const target = join(absoluteRoot, relativePath); - await mkdir(join(target, '..'), { recursive: true }); - await writeFile(target, contents); - } -} - -async function writeWorkspaceFixture(root) { - await writePackage( - root, - 'packages/cli', - { - name: '@ktx/cli', - version: '0.0.0-private', - description: 'CLI wrapper for KTX', - type: 'module', - engines: { node: '>=22.0.0' }, - bin: { ktx: './dist/bin.js' }, - main: 'dist/index.js', - types: 'dist/index.d.ts', - exports: { - '.': { - types: './dist/index.d.ts', - import: './dist/index.js', - default: './dist/index.js', - }, - './package.json': './package.json', - }, - files: ['dist', 'assets'], - dependencies: { - '@clack/prompts': '1.3.0', - ai: '^6.0.168', - commander: '14.0.3', - yaml: '^2.8.2', - }, - license: 'Apache-2.0', - repository: { - type: 'git', - url: 'git+https://github.com/kaelio/ktx.git', - directory: 'packages/cli', - }, - }, - { - 'dist/bin.js': '#!/usr/bin/env node\n', - 'dist/index.js': 'export const cli = true;\n', - 'dist/index.d.ts': 'export declare const cli: true;\n', - 'assets/python/manifest.json': '{"schemaVersion":1}\n', - }, - ); - -} - -describe('publicNpmPackageLayout', () => { - it('uses the public npm release version for the tarball name', () => { - const layout = publicNpmPackageLayout('/repo/ktx'); - - assert.match(PUBLIC_NPM_PACKAGE_VERSION, /^\d+\.\d+\.\d+/); - assert.equal(publicNpmPackageTarballName(), `kaelio-ktx-${PUBLIC_NPM_PACKAGE_VERSION}.tgz`); - assert.equal( - layout.tarballPath, - `/repo/ktx/dist/artifacts/npm/kaelio-ktx-${PUBLIC_NPM_PACKAGE_VERSION}.tgz`, - ); - }); -}); - -describe('collectPublicDependencies', () => { - it('returns CLI external runtime dependencies and omits workspace packages', () => { - assert.deepEqual( - collectPublicDependencies({ - name: '@ktx/cli', - dependencies: { - '@ktx/internal-only': 'workspace:*', - commander: '14.0.3', - zod: '^4.4.3', - }, - }), - { - commander: '14.0.3', - zod: '^4.4.3', - }, - ); - }); -}); - -describe('publicNpmPackageJson', () => { - - it('describes the public @kaelio/ktx binary package', () => { - const packageJson = publicNpmPackageJson( - { - name: '@ktx/cli', - version: '0.0.0-private', - engines: { node: '>=22.0.0' }, - bin: { ktx: './dist/bin.js' }, - main: 'dist/index.js', - types: 'dist/index.d.ts', - exports: { '.': './dist/index.js', './package.json': './package.json' }, - license: 'Apache-2.0', - }, - { commander: '14.0.3' }, - ); - - assert.equal(packageJson.name, PUBLIC_NPM_PACKAGE_NAME); - assert.equal(packageJson.version, PUBLIC_NPM_PACKAGE_VERSION); - assert.equal(packageJson.private, false); - assert.deepEqual(packageJson.bin, { ktx: './dist/bin.js' }); - assert.deepEqual(packageJson.dependencies, { commander: '14.0.3' }); - assert.deepEqual(packageJson.files, ['dist', 'assets']); - assert.deepEqual(packageJson.repository, { - type: 'git', - url: 'https://github.com/Kaelio/ktx', - }); - assert.deepEqual(packageJson.bugs, { - url: 'https://github.com/Kaelio/ktx/issues', - }); - assert.equal(packageJson.homepage, 'https://github.com/Kaelio/ktx#readme'); - }); -}); - -describe('createPublicNpmPackageTree', () => { - it('copies CLI files and assets without bundled internal workspace packages', async () => { - const root = await mkdtemp(join(tmpdir(), 'ktx-public-npm-test-')); - try { - await writeWorkspaceFixture(root); - const layout = publicNpmPackageLayout(root); - - const result = await createPublicNpmPackageTree(layout); - - assert.equal(result.packageJson.name, '@kaelio/ktx'); - assert.equal(result.packageJson.dependencies.commander, '14.0.3'); - assert.equal(result.packageJson.dependencies.yaml, '^2.8.2'); - assert.equal(result.packageJson.dependencies.ai, '^6.0.168'); - assert.equal( - await readFile(join(layout.packRoot, 'assets', 'python', 'manifest.json'), 'utf8'), - '{"schemaVersion":1}\n', - ); - await assert.rejects( - () => readFile(join(layout.packRoot, 'node_modules', '@ktx', 'context', 'package.json'), 'utf8'), - /ENOENT/, - ); - } finally { - await rm(root, { recursive: true, force: true }); - } - }); -}); - -describe('publicNpmPackCommand', () => { - it('packs the assembled public package with pnpm', () => { - const layout = publicNpmPackageLayout('/repo/ktx'); - - assert.deepEqual(publicNpmPackCommand(layout), { - command: 'pnpm', - args: [ - '--config.node-linker=hoisted', - 'pack', - '--out', - `/repo/ktx/dist/artifacts/npm/kaelio-ktx-${PUBLIC_NPM_PACKAGE_VERSION}.tgz`, - ], - cwd: '/repo/ktx/dist/public-npm-package', - }); - }); -}); diff --git a/scripts/check-boundaries.mjs b/scripts/check-boundaries.mjs index c3161704..5766ac78 100644 --- a/scripts/check-boundaries.mjs +++ b/scripts/check-boundaries.mjs @@ -10,7 +10,7 @@ const identifierSkipPrefixes = ['docs/', 'docs-site/', 'examples/', 'python/ktx- const identifierAllowPatterns = [ /^packages\/cli\/src\/(?:index|managed-local-embeddings|managed-python-command|managed-python-daemon|managed-python-runtime|release-version|runtime)(?:\.test)?\.ts$/, /^python\/ktx-daemon\/src\/ktx_daemon\/__init__\.py$/, - /^scripts\/(?:build-public-npm-package|build-python-runtime-wheel|local-embeddings-runtime-smoke|package-artifacts|public-npm-release-metadata|published-package-smoke|release-readiness)(?:\.test)?\.mjs$/, + /^scripts\/(?:build-python-runtime-wheel|local-embeddings-runtime-smoke|package-artifacts|public-npm-release-metadata|published-package-smoke|release-readiness)(?:\.test)?\.mjs$/, /^scripts\/semantic-release-config\.cjs$/, ]; const forbiddenIdentifierTerms = ['kae' + 'lio', 'Kae' + 'lio', 'KAE' + 'LIO_']; diff --git a/scripts/link-dev-cli.test.mjs b/scripts/link-dev-cli.test.mjs index db4f9f4e..c3268541 100644 --- a/scripts/link-dev-cli.test.mjs +++ b/scripts/link-dev-cli.test.mjs @@ -13,7 +13,7 @@ test('linkDevCli writes a ktx-dev launcher by default', async () => { execText: async (command, args) => { assert.equal(command, 'ktx-dev'); assert.deepEqual(args, ['--version']); - return '@ktx/cli 0.0.0-private'; + return '@kaelio/ktx 0.0.0-private'; }, writeFile: async (path, content) => writes.push({ path, content }), chmod: async (path, mode) => chmods.push({ path, mode }), @@ -34,7 +34,7 @@ test('linkDevCli can explicitly write ktx when requested', async () => { binaryName: 'ktx', globalBin: '/pnpm/bin', binPath: '/workspace/ktx/packages/cli/dist/bin.js', - execText: async () => '@ktx/cli 0.0.0-private', + execText: async () => '@kaelio/ktx 0.0.0-private', writeFile: async (path, content) => writes.push({ path, content }), chmod: async () => undefined, access: async () => undefined, diff --git a/scripts/local-embeddings-runtime-smoke.mjs b/scripts/local-embeddings-runtime-smoke.mjs index c6d98178..539eaa60 100644 --- a/scripts/local-embeddings-runtime-smoke.mjs +++ b/scripts/local-embeddings-runtime-smoke.mjs @@ -8,7 +8,7 @@ import { promisify } from 'node:util'; import { PUBLIC_NPM_PACKAGE_NAME, PUBLIC_NPM_PACKAGE_VERSION, -} from './build-public-npm-package.mjs'; +} from './public-npm-release-metadata.mjs'; import { npmSmokePnpmWorkspaceYaml } from './package-artifacts.mjs'; const execFileAsync = promisify(execFile); diff --git a/scripts/local-embeddings-runtime-smoke.test.mjs b/scripts/local-embeddings-runtime-smoke.test.mjs index a445ef48..5fcd75c6 100644 --- a/scripts/local-embeddings-runtime-smoke.test.mjs +++ b/scripts/local-embeddings-runtime-smoke.test.mjs @@ -2,7 +2,7 @@ import assert from 'node:assert/strict'; import { readFile } from 'node:fs/promises'; import { describe, it } from 'node:test'; -import { PUBLIC_NPM_PACKAGE_VERSION } from './build-public-npm-package.mjs'; +import { PUBLIC_NPM_PACKAGE_VERSION } from './public-npm-release-metadata.mjs'; import { buildLocalEmbeddingsSmokeEnv, expectedPublicKtxVersionPattern, diff --git a/scripts/package-artifacts.mjs b/scripts/package-artifacts.mjs index 2049ff24..627850b4 100644 --- a/scripts/package-artifacts.mjs +++ b/scripts/package-artifacts.mjs @@ -15,8 +15,8 @@ import { import { PUBLIC_NPM_PACKAGE_NAME, publicNpmPackageTarballName, -} from './build-public-npm-package.mjs'; -import { publicNpmPackageVersion } from './public-npm-release-metadata.mjs'; + publicNpmPackageVersion, +} from './public-npm-release-metadata.mjs'; export { RUNTIME_WHEEL_DISTRIBUTION_NAME, @@ -24,10 +24,6 @@ export { RUNTIME_WHEEL_PACKAGE_VERSION, }; -export const INTERNAL_NPM_WORKSPACE_PACKAGES = [ - { name: '@ktx/cli', packageRoot: 'packages/cli' }, -]; - export const NPM_ARTIFACT_PACKAGES = [{ name: PUBLIC_NPM_PACKAGE_NAME, packageRoot: 'packages/cli' }]; export const CLI_PYTHON_ASSET_MANIFEST = 'manifest.json'; @@ -72,30 +68,22 @@ export function packageArtifactLayout(rootDir = scriptRootDir(), version = publi } export function buildArtifactCommands(layout) { - const npmBuildCommand = { - command: 'pnpm', - args: [ - '--filter', - '@ktx/cli', - 'run', - 'build', - ], - cwd: layout.rootDir, - }; - const publicPackageCommand = { - command: process.execPath, - args: ['scripts/build-public-npm-package.mjs'], - cwd: layout.rootDir, - }; - return [ - npmBuildCommand, + { + command: 'pnpm', + args: ['--filter', PUBLIC_NPM_PACKAGE_NAME, 'run', 'build'], + cwd: layout.rootDir, + }, { command: process.execPath, args: ['scripts/build-python-runtime-wheel.mjs'], cwd: layout.rootDir, }, - publicPackageCommand, + { + command: 'pnpm', + args: ['pack', '--out', layout.cliTarball], + cwd: join(layout.rootDir, 'packages', 'cli'), + }, ]; } @@ -163,19 +151,17 @@ function releaseMetadataEntry({ ecosystem, packageName, packageRoot, packageVers async function readNpmPackageMetadata(rootDir, packageInfo, version) { const packageJson = await readJson(join(rootDir, packageInfo.packageRoot, 'package.json')); - const expectedSourceName = packageInfo.name === PUBLIC_NPM_PACKAGE_NAME ? '@ktx/cli' : packageInfo.name; - if (packageJson.name !== expectedSourceName) { + if (packageJson.name !== packageInfo.name) { throw new Error( - `Unexpected package name in ${packageInfo.packageRoot}/package.json: expected ${expectedSourceName}, got ${packageJson.name}`, + `Unexpected package name in ${packageInfo.packageRoot}/package.json: expected ${packageInfo.name}, got ${packageJson.name}`, ); } - const isPublicKtxPackage = packageInfo.name === PUBLIC_NPM_PACKAGE_NAME; return releaseMetadataEntry({ ecosystem: 'npm', packageName: packageInfo.name, packageRoot: packageInfo.packageRoot, - packageVersion: isPublicKtxPackage ? version : packageJson.version, - privatePackage: isPublicKtxPackage ? false : packageJson.private === true, + packageVersion: version, + privatePackage: false, }); } @@ -922,13 +908,13 @@ async function buildArtifacts(layout) { await mkdir(layout.npmDir, { recursive: true }); await mkdir(layout.pythonDir, { recursive: true }); - const [npmBuildCommand, wheelCommand, publicPackageCommand] = buildArtifactCommands(layout); + const [npmBuildCommand, wheelCommand, packCommand] = buildArtifactCommands(layout); await runCommand(npmBuildCommand.command, npmBuildCommand.args, { cwd: npmBuildCommand.cwd }); await runCommand(wheelCommand.command, wheelCommand.args, { cwd: wheelCommand.cwd }); const pythonArtifacts = await findPythonArtifacts(layout.pythonDir); await copyRuntimeWheelAssets(layout, pythonArtifacts); - await runCommand(publicPackageCommand.command, publicPackageCommand.args, { cwd: publicPackageCommand.cwd }); + await runCommand(packCommand.command, packCommand.args, { cwd: packCommand.cwd }); for (const packageInfo of NPM_ARTIFACT_PACKAGES) { await assertPathExists(layout.npmTarballs[packageInfo.name], `${packageInfo.name} tarball`); diff --git a/scripts/package-artifacts.test.mjs b/scripts/package-artifacts.test.mjs index 45eb697f..6a3b5d72 100644 --- a/scripts/package-artifacts.test.mjs +++ b/scripts/package-artifacts.test.mjs @@ -5,10 +5,9 @@ import { tmpdir } from 'node:os'; import { join } from 'node:path'; import { describe, it } from 'node:test'; -import { PUBLIC_NPM_PACKAGE_VERSION } from './build-public-npm-package.mjs'; +import { PUBLIC_NPM_PACKAGE_VERSION } from './public-npm-release-metadata.mjs'; import { CLI_PYTHON_ASSET_MANIFEST, - INTERNAL_NPM_WORKSPACE_PACKAGES, RUNTIME_WHEEL_DISTRIBUTION_NAME, RUNTIME_WHEEL_NORMALIZED_NAME, RUNTIME_WHEEL_PACKAGE_VERSION, @@ -62,12 +61,11 @@ async function writeReleaseMetadataInputs(root) { requiredBeforePublishing: ['Choose public release version.'], }); - for (const packageInfo of INTERNAL_NPM_WORKSPACE_PACKAGES) { + for (const packageInfo of NPM_ARTIFACT_PACKAGES) { await mkdir(join(root, packageInfo.packageRoot), { recursive: true }); await writeJson(join(root, packageInfo.packageRoot, 'package.json'), { name: packageInfo.name, - version: '0.0.0-private', - private: true, + version: PUBLIC_NPM_PACKAGE_VERSION, }); } } @@ -112,16 +110,20 @@ describe('packageArtifactLayout', () => { }); describe('buildArtifactCommands', () => { - it('builds the CLI package, then the runtime wheel, then packs npm artifacts', () => { + it('builds the CLI package, then the runtime wheel, then packs the npm tarball directly', () => { const layout = packageArtifactLayout('/repo/ktx', PUBLIC_NPM_PACKAGE_VERSION); const commands = buildArtifactCommands(layout); assert.deepEqual( - commands.map((command) => [command.command, command.args]), + commands.map((command) => [command.command, command.args, command.cwd]), [ - ['pnpm', ['--filter', '@ktx/cli', 'run', 'build']], - [process.execPath, ['scripts/build-python-runtime-wheel.mjs']], - [process.execPath, ['scripts/build-public-npm-package.mjs']], + ['pnpm', ['--filter', '@kaelio/ktx', 'run', 'build'], '/repo/ktx'], + [process.execPath, ['scripts/build-python-runtime-wheel.mjs'], '/repo/ktx'], + [ + 'pnpm', + ['pack', '--out', `/repo/ktx/dist/artifacts/npm/kaelio-ktx-${PUBLIC_NPM_PACKAGE_VERSION}.tgz`], + '/repo/ktx/packages/cli', + ], ], ); }); diff --git a/scripts/public-npm-release-metadata.mjs b/scripts/public-npm-release-metadata.mjs index 6aeba682..ec671b82 100644 --- a/scripts/public-npm-release-metadata.mjs +++ b/scripts/public-npm-release-metadata.mjs @@ -8,6 +8,10 @@ export const PUBLIC_NPM_PACKAGE_NAME = '@kaelio/ktx'; export const PUBLIC_NPM_RELEASE_TAGS = new Set(['latest', 'next']); export const PUBLIC_NPM_BRANCH_RELEASE_TAG_PATTERN = /^branch-[a-z0-9]+(?:-[a-z0-9]+)*$/; +export function publicNpmPackageTarballName(version) { + return `kaelio-ktx-${version}.tgz`; +} + const SEMVER_PATTERN = /^(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-]+)*)?$/; const SEMVER_PARTS_PATTERN = @@ -82,6 +86,8 @@ export function publicNpmPackageVersion(rootDir = scriptRootDir()) { return readPublicNpmReleaseMetadata(rootDir).version; } +export const PUBLIC_NPM_PACKAGE_VERSION = publicNpmPackageVersion(); + export function publicPythonRuntimePackageVersion(rootDir = scriptRootDir()) { return publicNpmPackageVersionToPythonVersion(publicNpmPackageVersion(rootDir)); } diff --git a/scripts/published-package-smoke.test.mjs b/scripts/published-package-smoke.test.mjs index 719eed2a..09c54934 100644 --- a/scripts/published-package-smoke.test.mjs +++ b/scripts/published-package-smoke.test.mjs @@ -105,7 +105,7 @@ describe('published package smoke config', () => { /Invalid KTX_PUBLISHED_KTX_PACKAGE/, ); assert.throws( - () => readPublishedPackageSmokeConfig({ KTX_PUBLISHED_KTX_PACKAGE: '@ktx/cli public' }, []), + () => readPublishedPackageSmokeConfig({ KTX_PUBLISHED_KTX_PACKAGE: '@kaelio/ktx public' }, []), /Invalid KTX_PUBLISHED_KTX_PACKAGE/, ); assert.throws( @@ -114,7 +114,7 @@ describe('published package smoke config', () => { {}, [], { - packageName: '@ktx/cli public', + packageName: '@kaelio/ktx public', version: 'latest', registry: null, }, diff --git a/scripts/release-readiness.mjs b/scripts/release-readiness.mjs index bcb66dc8..ffd22ab5 100644 --- a/scripts/release-readiness.mjs +++ b/scripts/release-readiness.mjs @@ -228,20 +228,17 @@ function assertNonPublishingArtifactPolicy(policy, metadata, publicPackageVersio if (entry.releaseMode !== CI_ARTIFACT_ONLY_RELEASE_MODE) { throw new Error(`Package ${entry.packageName} releaseMode must remain ci-artifact-only`); } - if (entry.ecosystem === 'npm') { - const isPublicKtxPackage = entry.packageName === '@kaelio/ktx'; - if (isPublicKtxPackage) { - if (entry.private !== false) { - throw new Error(`${policyLabel} npm package @kaelio/ktx must be publishable when npm.publish is false`); - } - if (entry.packageVersion !== publicPackageVersion) { - throw new Error(`${policyLabel} npm package @kaelio/ktx must use public version ${publicPackageVersion}`); - } - } else if (entry.private !== true) { - throw new Error(`${policyLabel} npm package ${entry.packageName} must remain private`); - } else if (!entry.packageVersion.endsWith('-private')) { - throw new Error(`${policyLabel} npm package ${entry.packageName} must use a private version suffix`); - } + if (entry.ecosystem !== 'npm') { + continue; + } + if (entry.packageName !== '@kaelio/ktx') { + throw new Error(`${policyLabel} unexpected npm package ${entry.packageName}`); + } + if (entry.private !== false) { + throw new Error(`${policyLabel} npm package @kaelio/ktx must be publishable when npm.publish is false`); + } + if (entry.packageVersion !== publicPackageVersion) { + throw new Error(`${policyLabel} npm package @kaelio/ktx must use public version ${publicPackageVersion}`); } } } diff --git a/scripts/release-readiness.test.mjs b/scripts/release-readiness.test.mjs index cfe4235c..7cf5d498 100644 --- a/scripts/release-readiness.test.mjs +++ b/scripts/release-readiness.test.mjs @@ -5,12 +5,11 @@ import { join } from 'node:path'; import { describe, it } from 'node:test'; import { - INTERNAL_NPM_WORKSPACE_PACKAGES, NPM_ARTIFACT_PACKAGES, packageArtifactLayout, writeArtifactManifest, } from './package-artifacts.mjs'; -import { PUBLIC_NPM_PACKAGE_VERSION } from './build-public-npm-package.mjs'; +import { PUBLIC_NPM_PACKAGE_VERSION } from './public-npm-release-metadata.mjs'; import { RUNTIME_WHEEL_PACKAGE_VERSION } from './build-python-runtime-wheel.mjs'; import { readReleasePolicy, releasePolicyPath, releaseReadinessReport } from './release-readiness.mjs'; @@ -19,12 +18,11 @@ async function writeJson(path, value) { } async function writeReleaseMetadataInputs(root) { - for (const packageInfo of INTERNAL_NPM_WORKSPACE_PACKAGES) { + for (const packageInfo of NPM_ARTIFACT_PACKAGES) { await mkdir(join(root, packageInfo.packageRoot), { recursive: true }); await writeJson(join(root, packageInfo.packageRoot, 'package.json'), { name: packageInfo.name, - version: '0.0.0-private', - private: true, + version: PUBLIC_NPM_PACKAGE_VERSION, }); } } @@ -528,7 +526,7 @@ describe('release readiness policy', () => { await writeReadyFixture(root, { policy: releasePolicy({ publishedPackageSmoke: { - packageName: '@ktx/cli public', + packageName: '@kaelio/ktx public', version: 'latest', registry: null, }, diff --git a/scripts/run-ktx.test.mjs b/scripts/run-ktx.test.mjs index 98035aef..65ca4797 100644 --- a/scripts/run-ktx.test.mjs +++ b/scripts/run-ktx.test.mjs @@ -40,7 +40,7 @@ test('runWorkspaceKtx runs the built CLI when it already exists', async () => { readdir: fs.readdir, execFile: async (command, args, options) => { calls.push({ command, args, cwd: options.cwd }); - return { stdout: '@ktx/cli 0.0.0-private\n', stderr: '' }; + return { stdout: '@kaelio/ktx 0.0.0-private\n', stderr: '' }; }, stdout: { write: (chunk) => logs.push(['stdout', chunk]) }, stderr: { write: (chunk) => logs.push(['stderr', chunk]) }, @@ -54,7 +54,7 @@ test('runWorkspaceKtx runs the built CLI when it already exists', async () => { cwd: '/workspace/ktx', }, ]); - assert.deepEqual(logs, [['stdout', '@ktx/cli 0.0.0-private\n']]); + assert.deepEqual(logs, [['stdout', '@kaelio/ktx 0.0.0-private\n']]); }); test('runWorkspaceKtx forwards a caller-provided environment to buffered commands', async () => { @@ -69,7 +69,7 @@ test('runWorkspaceKtx forwards a caller-provided environment to buffered command env: { PATH: '/bin', GIT_CEILING_DIRECTORIES: '/workspace/ktx/examples' }, execFile: async (command, args, options) => { calls.push({ command, args, cwd: options.cwd, env: options.env }); - return { stdout: '@ktx/cli 0.0.0-private\n', stderr: '' }; + return { stdout: '@kaelio/ktx 0.0.0-private\n', stderr: '' }; }, stdout: { write: () => undefined }, stderr: { write: () => undefined }, diff --git a/scripts/standalone-ci-workflow.test.mjs b/scripts/standalone-ci-workflow.test.mjs index 4824c494..103d61d7 100644 --- a/scripts/standalone-ci-workflow.test.mjs +++ b/scripts/standalone-ci-workflow.test.mjs @@ -40,7 +40,7 @@ describe('standalone KTX CI workflow', () => { 'pnpm install --frozen-lockfile', 'pnpm run check', 'pnpm run build', - 'pnpm --filter @ktx/cli run test:slow', + 'pnpm --filter @kaelio/ktx run test:slow', 'pnpm run smoke', 'actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405', 'python-version: "3.13"', diff --git a/scripts/test-tiering.test.mjs b/scripts/test-tiering.test.mjs index ddf31735..bd43ce71 100644 --- a/scripts/test-tiering.test.mjs +++ b/scripts/test-tiering.test.mjs @@ -60,7 +60,7 @@ describe('test tiering', () => { it('provides explicit slow package test scripts for CI', async () => { const rootPackage = await readJson('../package.json'); const cliPackage = await readJson('../packages/cli/package.json'); - assert.equal(rootPackage.scripts['test:slow'], 'pnpm --filter @ktx/cli run test:slow'); + assert.equal(rootPackage.scripts['test:slow'], 'pnpm --filter @kaelio/ktx run test:slow'); assertScriptContainsAll(cliPackage.scripts['test:slow'], cliSlowTests); assertScriptContainsAll(cliPackage.scripts['test:slow'], contextSlowTests); assert.doesNotMatch(cliPackage.scripts['test:slow'], /relationship-benchmarks\.test\.ts/); diff --git a/scripts/update-public-release-version.test.mjs b/scripts/update-public-release-version.test.mjs index 3ddd67f2..cfe8b67b 100644 --- a/scripts/update-public-release-version.test.mjs +++ b/scripts/update-public-release-version.test.mjs @@ -22,9 +22,8 @@ async function writeReleaseFixture(root) { private: true, }); await writeJson(join(root, 'packages', 'cli', 'package.json'), { - name: '@ktx/cli', + name: '@kaelio/ktx', version: '0.0.0-private', - private: true, }); await writeJson(join(root, 'release-policy.json'), { schemaVersion: 1,