mirror of
https://github.com/Kaelio/ktx.git
synced 2026-06-10 08:05:14 +02:00
Merge origin/main into dead-ts-code-tools
This commit is contained in:
commit
0e2dcc9658
89 changed files with 1015 additions and 5955 deletions
|
|
@ -152,14 +152,12 @@ describe('standalone example docs', () => {
|
|||
const servingAgents = await readText('docs-site/content/docs/guides/serving-agents.mdx');
|
||||
|
||||
for (const command of [
|
||||
'ktx agent tools --json',
|
||||
'ktx agent context --json',
|
||||
'ktx agent sl list --json',
|
||||
'ktx agent sl read orders --json',
|
||||
'ktx agent sl query --json',
|
||||
'ktx agent wiki search "revenue recognition" --json',
|
||||
'ktx agent wiki read order-status-definitions --json',
|
||||
'ktx agent sql execute --json',
|
||||
'ktx status --json',
|
||||
'ktx sl list --json',
|
||||
'ktx sl read orders --json',
|
||||
'ktx sl query --json',
|
||||
'ktx wiki search "revenue recognition" --json',
|
||||
'ktx wiki read order-status-definitions --json',
|
||||
]) {
|
||||
assert.match(servingAgents, new RegExp(command.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')));
|
||||
}
|
||||
|
|
@ -184,12 +182,11 @@ describe('standalone example docs', () => {
|
|||
assert.match(quickstart, publicPackagePattern('npm install -g {package}'));
|
||||
assert.match(quickstart, /ktx dev runtime install --feature local-embeddings --yes/);
|
||||
assert.match(quickstart, /ktx dev runtime start --feature local-embeddings/);
|
||||
assert.match(quickstart, /Install `uv`, run `ktx dev runtime doctor`/);
|
||||
assert.match(quickstart, /Install `uv`, run `ktx dev runtime status`/);
|
||||
assert.match(packageArtifacts, /requires `uv` on `PATH`/);
|
||||
assert.match(packageArtifacts, /ktx dev runtime status/);
|
||||
assert.match(packageArtifacts, /ktx dev runtime doctor/);
|
||||
assert.match(packageArtifacts, /ktx dev runtime prune --dry-run/);
|
||||
assert.match(packageArtifacts, /ktx dev runtime prune --yes/);
|
||||
assert.match(packageArtifacts, /ktx dev runtime status/);
|
||||
assert.doesNotMatch(packageArtifacts, /ktx dev runtime prune/);
|
||||
assert.match(
|
||||
packageArtifacts,
|
||||
new RegExp(
|
||||
|
|
@ -221,9 +218,8 @@ describe('standalone example docs', () => {
|
|||
assert.doesNotMatch(readme, /installs the Python artifacts directly/);
|
||||
assert.match(readme, /requires `uv` on `PATH`/);
|
||||
assert.match(readme, /ktx dev runtime status/);
|
||||
assert.match(readme, /ktx dev runtime doctor/);
|
||||
assert.match(readme, /ktx dev runtime prune --dry-run/);
|
||||
assert.match(readme, /ktx dev runtime prune --yes/);
|
||||
assert.match(readme, /ktx dev runtime status/);
|
||||
assert.doesNotMatch(readme, /ktx dev runtime prune/);
|
||||
assert.doesNotMatch(readme, /@ktx\/context/);
|
||||
assert.doesNotMatch(readme, /@ktx\/cli/);
|
||||
assert.doesNotMatch(readme, /python -m ktx_daemon semantic-validate/);
|
||||
|
|
@ -234,14 +230,15 @@ describe('standalone example docs', () => {
|
|||
const buildingContext = await readText('docs-site/content/docs/guides/building-context.mdx');
|
||||
const scanReference = await readText('docs-site/content/docs/cli-reference/ktx-scan.mdx');
|
||||
|
||||
assert.match(buildingContext, /ktx dev scan <connection-id>/);
|
||||
assert.match(buildingContext, /ktx dev scan status <run-id>/);
|
||||
assert.match(buildingContext, /ktx dev scan report <run-id>/);
|
||||
assert.match(scanReference, /ktx dev scan <connectionId> \[options\]/);
|
||||
assert.match(buildingContext, /ktx scan <connection-id>/);
|
||||
assert.match(buildingContext, /ktx status/);
|
||||
assert.doesNotMatch(buildingContext, /ktx scan status <run-id>/);
|
||||
assert.doesNotMatch(buildingContext, /ktx scan report <run-id>/);
|
||||
assert.match(scanReference, /ktx scan <connectionId> \[options\]/);
|
||||
assert.match(rootReadme, /raw-sources\//);
|
||||
assert.match(rootReadme, /live-database\//);
|
||||
assert.doesNotMatch(rootReadme, /Run a local ingest smoke test/);
|
||||
assert.doesNotMatch(rootReadme, /ktx dev ingest run --project-dir/);
|
||||
assert.doesNotMatch(rootReadme, /ktx ingest run --project-dir/);
|
||||
assert.doesNotMatch(rootReadme, /ktx ingest status --project-dir/);
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -107,7 +107,6 @@ export function buildLiveDatabaseIngestArgs(projectDir, databaseIntrospectionUrl
|
|||
return [
|
||||
'exec',
|
||||
'ktx',
|
||||
'dev',
|
||||
'ingest',
|
||||
'run',
|
||||
'--project-dir',
|
||||
|
|
@ -325,12 +324,12 @@ async function main() {
|
|||
env: managedRuntimeEnv(cleanInstallDir),
|
||||
timeout: 120_000,
|
||||
});
|
||||
requireSuccess('ktx dev ingest run live-database', ingestRun);
|
||||
requireOutput('ktx dev ingest run live-database', ingestRun, /Status: done/);
|
||||
requireOutput('ktx dev ingest run live-database', ingestRun, /Adapter: live-database/);
|
||||
requireOutput('ktx dev ingest run live-database', ingestRun, /Diff: \+4\/~0\/-0\/=0/);
|
||||
requireOutput('ktx dev ingest run live-database', ingestRun, /Raw files: 4/);
|
||||
requireOutput('ktx dev ingest run live-database', ingestRun, /Work units: 2/);
|
||||
requireSuccess('ktx ingest run live-database', ingestRun);
|
||||
requireOutput('ktx ingest run live-database', ingestRun, /Status: done/);
|
||||
requireOutput('ktx ingest run live-database', ingestRun, /Adapter: live-database/);
|
||||
requireOutput('ktx ingest run live-database', ingestRun, /Diff: \+4\/~0\/-0\/=0/);
|
||||
requireOutput('ktx ingest run live-database', ingestRun, /Raw files: 4/);
|
||||
requireOutput('ktx ingest run live-database', ingestRun, /Work units: 2/);
|
||||
|
||||
const runId = getRunId(ingestRun.stdout);
|
||||
const ingestStatus = await run('pnpm', buildLiveDatabaseStatusArgs(projectDir, runId), {
|
||||
|
|
|
|||
|
|
@ -102,7 +102,6 @@ describe('installed live-database artifact smoke helpers', () => {
|
|||
assert.deepEqual(buildLiveDatabaseIngestArgs('/tmp/project', 'http://127.0.0.1:8765'), [
|
||||
'exec',
|
||||
'ktx',
|
||||
'dev',
|
||||
'ingest',
|
||||
'run',
|
||||
'--project-dir',
|
||||
|
|
|
|||
|
|
@ -205,6 +205,17 @@ function parseJsonStdout(label, result) {
|
|||
}
|
||||
}
|
||||
|
||||
function parseJsonStdoutWithExitCode(label, result, expectedCode) {
|
||||
if (result.code !== expectedCode) {
|
||||
throw new Error(`${label} failed with code ${result.code}\nstdout:\n${result.stdout}\nstderr:\n${result.stderr}`);
|
||||
}
|
||||
try {
|
||||
return JSON.parse(result.stdout);
|
||||
} catch (error) {
|
||||
throw new Error(`${label} did not write JSON stdout: ${error.message}\nstdout:\n${result.stdout}`);
|
||||
}
|
||||
}
|
||||
|
||||
function requireOutput(label, result, pattern) {
|
||||
if (!pattern.test(result.stdout)) {
|
||||
throw new Error(`${label} stdout did not match ${pattern}\nstdout:\n${result.stdout}`);
|
||||
|
|
@ -283,13 +294,14 @@ export async function runLocalEmbeddingsRuntimeSmoke(options = {}) {
|
|||
requireSuccess(commands[0].label, version);
|
||||
requireOutput(commands[0].label, version, expectedPublicKtxVersionPattern());
|
||||
|
||||
const missingStatus = parseJsonStdout(
|
||||
const missingStatus = parseJsonStdoutWithExitCode(
|
||||
commands[1].label,
|
||||
await run(commands[1].command, commands[1].args, {
|
||||
cwd: installDir,
|
||||
env: smokeEnv,
|
||||
timeoutMs: commands[1].timeoutMs,
|
||||
}),
|
||||
1,
|
||||
);
|
||||
if (missingStatus.kind !== 'missing') {
|
||||
throw new Error(`Expected missing runtime before install, got ${JSON.stringify(missingStatus)}`);
|
||||
|
|
|
|||
|
|
@ -548,10 +548,13 @@ function parseJsonResult(label, result) {
|
|||
return JSON.parse(result.stdout);
|
||||
}
|
||||
|
||||
function parseJsonFailure(label, result) {
|
||||
assert.equal(result.code, 1, label + ' should fail with exit code 1');
|
||||
assert.equal(result.stdout, '', label + ' should not write stdout when failing');
|
||||
return JSON.parse(result.stderr);
|
||||
function parseJsonResultWithExitCode(label, result, expectedCode) {
|
||||
assert.equal(
|
||||
result.code,
|
||||
expectedCode,
|
||||
label + ' failed with code ' + result.code + '\\nstdout:\\n' + result.stdout + '\\nstderr:\\n' + result.stderr,
|
||||
);
|
||||
return JSON.parse(result.stdout);
|
||||
}
|
||||
|
||||
function requireIncludes(values, expected, label) {
|
||||
|
|
@ -594,38 +597,15 @@ try {
|
|||
requireSuccess('ktx public package version', version);
|
||||
requireOutput('ktx public package version', version, /@kaelio\\/ktx 0\\.1\\.0/);
|
||||
|
||||
const runtimeStatusBefore = parseJsonResult(
|
||||
const runtimeStatusBefore = parseJsonResultWithExitCode(
|
||||
'ktx dev runtime status missing',
|
||||
await run('pnpm', ['exec', 'ktx', 'dev', 'runtime', 'status', '--json']),
|
||||
1,
|
||||
);
|
||||
assert.equal(runtimeStatusBefore.kind, 'missing');
|
||||
assert.equal(runtimeStatusBefore.layout.runtimeRoot, process.env.KTX_RUNTIME_ROOT);
|
||||
process.stdout.write('ktx managed runtime starts missing in isolated root\\n');
|
||||
|
||||
const missingProjectDir = join(root, 'missing-project');
|
||||
await mkdir(missingProjectDir, { recursive: true });
|
||||
const missingProjectSearch = await run('pnpm', [
|
||||
'exec',
|
||||
'ktx',
|
||||
'agent',
|
||||
'sl',
|
||||
'list',
|
||||
'--json',
|
||||
'--query',
|
||||
'revenue',
|
||||
'--project-dir',
|
||||
missingProjectDir,
|
||||
]);
|
||||
const missingProjectError = parseJsonFailure('ktx agent sl list missing project', missingProjectSearch);
|
||||
assert.equal(missingProjectError.error.code, 'agent_sl_search_missing_project');
|
||||
assert.deepEqual(missingProjectError.error.nextSteps, [
|
||||
'ktx setup --project-dir ' + missingProjectDir,
|
||||
'ktx status --project-dir ' + missingProjectDir,
|
||||
'ktx ingest <connection>',
|
||||
'ktx agent sl list --json --query "revenue" --project-dir ' + missingProjectDir,
|
||||
]);
|
||||
process.stdout.write('ktx agent sl list missing project guidance verified\\n');
|
||||
|
||||
const init = await run('pnpm', [
|
||||
'exec',
|
||||
'ktx',
|
||||
|
|
@ -661,28 +641,6 @@ try {
|
|||
'--skip-agents',
|
||||
]);
|
||||
requireProjectStderr('ktx setup empty project', emptyInit, emptyProjectDir);
|
||||
const emptySearch = await run('pnpm', [
|
||||
'exec',
|
||||
'ktx',
|
||||
'agent',
|
||||
'sl',
|
||||
'list',
|
||||
'--json',
|
||||
'--query',
|
||||
'revenue',
|
||||
'--project-dir',
|
||||
emptyProjectDir,
|
||||
]);
|
||||
const emptySearchError = parseJsonFailure('ktx agent sl list no connections', emptySearch);
|
||||
assert.equal(emptySearchError.error.code, 'agent_sl_search_no_connections');
|
||||
assert.deepEqual(emptySearchError.error.nextSteps, [
|
||||
'ktx setup --project-dir ' + emptyProjectDir,
|
||||
'ktx status --project-dir ' + emptyProjectDir,
|
||||
'ktx ingest <connection>',
|
||||
'ktx agent sl list --json --query "revenue" --project-dir ' + emptyProjectDir,
|
||||
]);
|
||||
process.stdout.write('ktx agent sl list no connections guidance verified\\n');
|
||||
|
||||
await writeFile(
|
||||
join(projectDir, 'ktx.yaml'),
|
||||
[
|
||||
|
|
@ -727,10 +685,9 @@ try {
|
|||
'utf-8',
|
||||
);
|
||||
|
||||
const agentWikiSearch = await run('pnpm', [
|
||||
const wikiSearch = await run('pnpm', [
|
||||
'exec',
|
||||
'ktx',
|
||||
'agent',
|
||||
'wiki',
|
||||
'search',
|
||||
'revenue',
|
||||
|
|
@ -740,40 +697,17 @@ try {
|
|||
'--project-dir',
|
||||
projectDir,
|
||||
]);
|
||||
const agentWikiSearchJson = parseJsonResult('ktx agent wiki search', agentWikiSearch);
|
||||
assert.equal(agentWikiSearchJson.totalFound, 1);
|
||||
assert.equal(agentWikiSearchJson.results[0].key, 'revenue');
|
||||
assert.equal(agentWikiSearchJson.results[0].path, 'knowledge/global/revenue.md');
|
||||
assert.equal(typeof agentWikiSearchJson.results[0].score, 'number');
|
||||
requireIncludes(agentWikiSearchJson.results[0].matchReasons, 'lexical', 'agent wiki search match reasons');
|
||||
process.stdout.write('ktx agent wiki search hybrid metadata verified\\n');
|
||||
const wikiSearchJson = parseJsonResult('ktx wiki search', wikiSearch);
|
||||
assert.equal(wikiSearchJson.kind, 'list');
|
||||
assert.equal(wikiSearchJson.data.items.length, 1);
|
||||
assert.equal(wikiSearchJson.data.items[0].key, 'revenue');
|
||||
assert.equal(wikiSearchJson.data.items[0].path, 'knowledge/global/revenue.md');
|
||||
assert.equal(typeof wikiSearchJson.data.items[0].score, 'number');
|
||||
requireIncludes(wikiSearchJson.data.items[0].matchReasons, 'lexical', 'wiki search match reasons');
|
||||
process.stdout.write('ktx wiki search hybrid metadata verified\\n');
|
||||
await access(join(projectDir, '.ktx', 'db.sqlite'));
|
||||
process.stdout.write('SQLite knowledge index: ' + join(projectDir, '.ktx', 'db.sqlite') + '\\n');
|
||||
|
||||
const noSourceSearch = await run('pnpm', [
|
||||
'exec',
|
||||
'ktx',
|
||||
'agent',
|
||||
'sl',
|
||||
'list',
|
||||
'--json',
|
||||
'--connection-id',
|
||||
'warehouse',
|
||||
'--query',
|
||||
'revenue',
|
||||
'--project-dir',
|
||||
projectDir,
|
||||
]);
|
||||
const noSourceSearchError = parseJsonFailure('ktx agent sl list no indexed sources', noSourceSearch);
|
||||
assert.equal(noSourceSearchError.error.code, 'agent_sl_search_no_indexed_sources');
|
||||
assert.deepEqual(noSourceSearchError.error.nextSteps, [
|
||||
'ktx setup --project-dir ' + projectDir,
|
||||
'ktx status --project-dir ' + projectDir,
|
||||
'ktx ingest <connection>',
|
||||
'ktx agent sl list --json --query "revenue" --project-dir ' + projectDir,
|
||||
]);
|
||||
process.stdout.write('ktx agent sl list no indexed sources guidance verified\\n');
|
||||
|
||||
const slYaml = [
|
||||
'name: orders',
|
||||
'table: orders',
|
||||
|
|
@ -794,10 +728,9 @@ try {
|
|||
await mkdir(join(projectDir, 'semantic-layer', 'warehouse'), { recursive: true });
|
||||
await writeFile(join(projectDir, 'semantic-layer', 'warehouse', 'orders.yaml'), slYaml, 'utf-8');
|
||||
|
||||
const agentSlSearch = await run('pnpm', [
|
||||
const slSearch = await run('pnpm', [
|
||||
'exec',
|
||||
'ktx',
|
||||
'agent',
|
||||
'sl',
|
||||
'list',
|
||||
'--json',
|
||||
|
|
@ -808,13 +741,14 @@ try {
|
|||
'--project-dir',
|
||||
projectDir,
|
||||
]);
|
||||
const agentSlSearchJson = parseJsonResult('ktx agent sl list', agentSlSearch);
|
||||
assert.equal(agentSlSearchJson.totalSources, 1);
|
||||
assert.equal(agentSlSearchJson.sources[0].connectionId, 'warehouse');
|
||||
assert.equal(agentSlSearchJson.sources[0].name, 'orders');
|
||||
assert.equal(typeof agentSlSearchJson.sources[0].score, 'number');
|
||||
requireIncludes(agentSlSearchJson.sources[0].matchReasons, 'lexical', 'agent sl search match reasons');
|
||||
process.stdout.write('ktx agent sl list hybrid metadata verified\\n');
|
||||
const slSearchJson = parseJsonResult('ktx sl list', slSearch);
|
||||
assert.equal(slSearchJson.kind, 'list');
|
||||
assert.equal(slSearchJson.data.items.length, 1);
|
||||
assert.equal(slSearchJson.data.items[0].connectionId, 'warehouse');
|
||||
assert.equal(slSearchJson.data.items[0].name, 'orders');
|
||||
assert.equal(typeof slSearchJson.data.items[0].score, 'number');
|
||||
requireIncludes(slSearchJson.data.items[0].matchReasons, 'lexical', 'sl search match reasons');
|
||||
process.stdout.write('ktx sl list hybrid metadata verified\\n');
|
||||
|
||||
const slQuery = await run('pnpm', ['exec', 'ktx', 'sl', 'query',
|
||||
'--connection-id',
|
||||
|
|
@ -865,12 +799,11 @@ try {
|
|||
requireOutput('ktx sl query sqlite execute', sqliteSlQuery, /"rows": \\[\\s*\\[\\s*3\\s*\\]\\s*\\]/);
|
||||
process.stdout.write('ktx sl query sqlite execute verified\\n');
|
||||
|
||||
const runtimeDoctor = await run('pnpm', ['exec', 'ktx', 'dev', 'runtime', 'doctor']);
|
||||
requireSuccess('ktx dev runtime doctor', runtimeDoctor);
|
||||
requireOutput('ktx dev runtime doctor', runtimeDoctor, /PASS uv/);
|
||||
requireOutput('ktx dev runtime doctor', runtimeDoctor, /PASS Bundled Python wheel/);
|
||||
requireOutput('ktx dev runtime doctor', runtimeDoctor, /PASS Managed Python runtime/);
|
||||
process.stdout.write('ktx dev runtime doctor verified\\n');
|
||||
const runtimeDoctor = await run('pnpm', ['exec', 'ktx', 'dev', 'runtime', 'status']);
|
||||
requireSuccess('ktx dev runtime status', runtimeDoctor);
|
||||
requireOutput('ktx dev runtime status', runtimeDoctor, /KTX Python runtime/);
|
||||
requireOutput('ktx dev runtime status', runtimeDoctor, /status: ready/);
|
||||
process.stdout.write('ktx dev runtime status verified\\n');
|
||||
|
||||
const runtimeStart = await run('pnpm', ['exec', 'ktx', 'dev', 'runtime', 'start']);
|
||||
requireSuccess('ktx dev runtime start', runtimeStart);
|
||||
|
|
@ -890,28 +823,7 @@ try {
|
|||
requireOutput('ktx dev runtime stop', runtimeStop, /Stopped KTX Python daemon/);
|
||||
process.stdout.write('ktx dev runtime daemon lifecycle verified\\n');
|
||||
|
||||
const staleRuntimeDir = join(process.env.KTX_RUNTIME_ROOT, '0.0.0');
|
||||
await mkdir(staleRuntimeDir, { recursive: true });
|
||||
|
||||
const runtimePruneDryRun = await run('pnpm', ['exec', 'ktx', 'dev', 'runtime', 'prune', '--dry-run']);
|
||||
requireSuccess('ktx dev runtime prune dry run', runtimePruneDryRun);
|
||||
requireOutput('ktx dev runtime prune dry run', runtimePruneDryRun, /Stale KTX Python runtimes/);
|
||||
requireOutput('ktx dev runtime prune dry run', runtimePruneDryRun, /0\\.0\\.0/);
|
||||
await access(staleRuntimeDir);
|
||||
|
||||
const runtimePruneNeedsConfirmation = await run('pnpm', ['exec', 'ktx', 'dev', 'runtime', 'prune']);
|
||||
assert.equal(runtimePruneNeedsConfirmation.code, 1, 'ktx dev runtime prune needs confirmation');
|
||||
assert.equal(runtimePruneNeedsConfirmation.stdout, '', 'ktx dev runtime prune needs confirmation wrote stdout');
|
||||
assert.match(runtimePruneNeedsConfirmation.stderr, /Refusing to prune without --yes/);
|
||||
|
||||
const runtimePruneConfirmed = await run('pnpm', ['exec', 'ktx', 'dev', 'runtime', 'prune', '--yes']);
|
||||
requireSuccess('ktx dev runtime prune confirmed', runtimePruneConfirmed);
|
||||
requireOutput('ktx dev runtime prune confirmed', runtimePruneConfirmed, /Removed stale KTX Python runtimes/);
|
||||
requireOutput('ktx dev runtime prune confirmed', runtimePruneConfirmed, /0\\.0\\.0/);
|
||||
await assert.rejects(() => access(staleRuntimeDir));
|
||||
process.stdout.write('ktx dev runtime prune verified\\n');
|
||||
|
||||
const structuralScan = await run('pnpm', ['exec', 'ktx', 'dev', 'scan', 'warehouse',
|
||||
const structuralScan = await run('pnpm', ['exec', 'ktx', 'scan', 'warehouse',
|
||||
'--project-dir',
|
||||
projectDir,
|
||||
]);
|
||||
|
|
@ -920,34 +832,10 @@ try {
|
|||
requireOutput('ktx scan structural', structuralScan, /Mode: structural/);
|
||||
requireOutput('ktx scan structural', structuralScan, /Needs attention\\s+None/);
|
||||
const structuralScanRunId = getRunId(structuralScan.stdout);
|
||||
|
||||
const scanStatus = await run('pnpm', ['exec', 'ktx', 'dev', 'scan', 'status',
|
||||
'--project-dir',
|
||||
projectDir,
|
||||
structuralScanRunId,
|
||||
]);
|
||||
requireProjectStderr('ktx scan status', scanStatus, projectDir);
|
||||
requireOutput('ktx scan status', scanStatus, new RegExp('Run: ' + structuralScanRunId));
|
||||
requireOutput('ktx scan status', scanStatus, /Status: done/);
|
||||
requireOutput('ktx scan status', scanStatus, /Mode: structural/);
|
||||
|
||||
const scanReport = await run('pnpm', ['exec', 'ktx', 'dev', 'scan', 'report',
|
||||
'--project-dir',
|
||||
projectDir,
|
||||
'--json',
|
||||
structuralScanRunId,
|
||||
]);
|
||||
requireSuccess('ktx scan report', scanReport);
|
||||
const scanReportJson = JSON.parse(scanReport.stdout);
|
||||
assert.equal(scanReportJson.mode, 'structural');
|
||||
assert.equal(scanReportJson.connectionId, 'warehouse');
|
||||
assert.equal(scanReportJson.manifestShardsWritten, 1);
|
||||
assert.deepEqual(scanReportJson.artifactPaths.enrichmentArtifacts, []);
|
||||
assert.deepEqual(scanReportJson.artifactPaths.manifestShards, ['semantic-layer/warehouse/_schema/public.yaml']);
|
||||
await access(join(projectDir, 'semantic-layer', 'warehouse', '_schema', 'public.yaml'));
|
||||
process.stdout.write('ktx scan structural verified: ' + structuralScanRunId + '\\n');
|
||||
|
||||
const enrichedScan = await run('pnpm', ['exec', 'ktx', 'dev', 'scan', 'warehouse',
|
||||
const enrichedScan = await run('pnpm', ['exec', 'ktx', 'scan', 'warehouse',
|
||||
'--project-dir',
|
||||
projectDir,
|
||||
'--mode',
|
||||
|
|
@ -956,24 +844,14 @@ try {
|
|||
requireProjectStderr('ktx scan enriched', enrichedScan, projectDir);
|
||||
requireOutput('ktx scan enriched', enrichedScan, /Status: done/);
|
||||
requireOutput('ktx scan enriched', enrichedScan, /Mode: enriched/);
|
||||
requireOutput('ktx scan enriched', enrichedScan, /Enrichment artifacts:/);
|
||||
const enrichedScanRunId = getRunId(enrichedScan.stdout);
|
||||
const enrichedScanReport = await run('pnpm', ['exec', 'ktx', 'dev', 'scan', 'report',
|
||||
'--project-dir',
|
||||
projectDir,
|
||||
'--json',
|
||||
enrichedScanRunId,
|
||||
]);
|
||||
requireSuccess('ktx scan enriched report', enrichedScanReport);
|
||||
const enrichedScanReportJson = JSON.parse(enrichedScanReport.stdout);
|
||||
assert.equal(enrichedScanReportJson.mode, 'enriched');
|
||||
assert.ok(enrichedScanReportJson.artifactPaths.enrichmentArtifacts.length > 0);
|
||||
assert.deepEqual(enrichedScanReportJson.artifactPaths.manifestShards, ['semantic-layer/warehouse/_schema/public.yaml']);
|
||||
process.stdout.write('ktx scan enriched verified: ' + enrichedScanRunId + '\\n');
|
||||
|
||||
await mkdir(join(sourceDir, 'orders'), { recursive: true });
|
||||
await writeFile(join(sourceDir, 'orders', 'orders.json'), '{"name":"orders"}\\n', 'utf-8');
|
||||
|
||||
const ingestRun = await run('pnpm', ['exec', 'ktx', 'dev', 'ingest', 'run',
|
||||
const ingestRun = await run('pnpm', ['exec', 'ktx', 'ingest', 'run',
|
||||
'--project-dir',
|
||||
projectDir,
|
||||
'--connection-id',
|
||||
|
|
@ -983,14 +861,14 @@ try {
|
|||
'--source-dir',
|
||||
sourceDir,
|
||||
]);
|
||||
assert.equal(ingestRun.code, 1, 'ktx dev ingest run without an LLM provider must fail');
|
||||
assert.equal(ingestRun.code, 1, 'ktx ingest run without an LLM provider must fail');
|
||||
assert.match(
|
||||
ingestRun.stderr,
|
||||
/ktx dev ingest run requires llm\\.provider\\.backend: anthropic, vertex, or gateway, or an injected agentRunner/,
|
||||
/ktx ingest run requires llm\\.provider\\.backend: anthropic, vertex, or gateway, or an injected agentRunner/,
|
||||
);
|
||||
|
||||
await access(join(projectDir, '.ktx', 'db.sqlite'));
|
||||
process.stdout.write('ktx dev ingest provider guard verified\\n');
|
||||
process.stdout.write('ktx ingest provider guard verified\\n');
|
||||
} finally {
|
||||
if (daemonStarted) {
|
||||
await run('pnpm', ['exec', 'ktx', 'dev', 'runtime', 'stop']);
|
||||
|
|
|
|||
|
|
@ -459,9 +459,9 @@ describe('verification snippets', () => {
|
|||
assert.doesNotMatch(source, /startSemanticDaemon/);
|
||||
assert.match(source, /run\('pnpm', \[\s*'exec',\s*'ktx',\s*'setup'/);
|
||||
assert.match(source, /knowledge', 'global', 'revenue\.md'/);
|
||||
assert.match(source, /run\('pnpm', \[\s*'exec',\s*'ktx',\s*'agent',\s*'wiki',\s*'search'/);
|
||||
assert.match(source, /run\('pnpm', \[\s*'exec',\s*'ktx',\s*'wiki',\s*'search'/);
|
||||
assert.match(source, /semantic-layer', 'warehouse', 'orders\.yaml'/);
|
||||
assert.match(source, /run\('pnpm', \[\s*'exec',\s*'ktx',\s*'agent',\s*'sl',\s*'list'/);
|
||||
assert.match(source, /run\('pnpm', \[\s*'exec',\s*'ktx',\s*'sl',\s*'list'/);
|
||||
assert.match(source, /orders\.order_count/);
|
||||
assert.match(source, /sqlite3/);
|
||||
assert.match(source, /driver: sqlite/);
|
||||
|
|
@ -482,33 +482,26 @@ describe('verification snippets', () => {
|
|||
assert.match(source, /ktx dev runtime status ready/);
|
||||
assert.match(source, /runtimeStatusAfter\.kind, 'ready'/);
|
||||
assert.match(source, /runtimeStatusAfter\.manifest\.features/);
|
||||
assert.match(source, /ktx dev runtime doctor/);
|
||||
assert.match(source, /PASS Managed Python runtime/);
|
||||
assert.match(source, /ktx dev runtime status/);
|
||||
assert.match(source, /status: ready/);
|
||||
assert.match(source, /ktx dev runtime start/);
|
||||
assert.match(source, /ktx dev runtime start reuse/);
|
||||
assert.match(source, /Using existing KTX Python daemon/);
|
||||
assert.match(source, /ktx dev runtime stop/);
|
||||
assert.match(source, /ktx dev runtime prune dry run/);
|
||||
assert.match(source, /0\.0\.0/);
|
||||
assert.match(source, /ktx dev runtime prune needs confirmation/);
|
||||
assert.match(source, /Refusing to prune without --yes/);
|
||||
assert.match(source, /ktx dev runtime prune confirmed/);
|
||||
assert.match(source, /Removed stale KTX Python runtimes/);
|
||||
assert.match(source, /assert\.rejects\(\(\) => access\(staleRuntimeDir\)\)/);
|
||||
assert.match(source, /run\('pnpm', \[\s*'exec',\s*'ktx',\s*'dev',\s*'scan',\s*'warehouse'/);
|
||||
assert.doesNotMatch(source, /ktx dev runtime prune/);
|
||||
assert.doesNotMatch(source, /staleRuntimeDir/);
|
||||
assert.match(source, /run\('pnpm', \[\s*'exec',\s*'ktx',\s*'scan',\s*'warehouse'/);
|
||||
assert.match(source, /'--mode',\s*'enriched'/);
|
||||
assert.doesNotMatch(source, /'--enrich'/);
|
||||
assert.match(source, /ktx scan structural verified/);
|
||||
assert.match(source, /ktx scan enriched verified/);
|
||||
assert.match(source, /scanReportJson\.artifactPaths\.manifestShards/);
|
||||
assert.match(source, /scanReportJson\.artifactPaths\.enrichmentArtifacts/);
|
||||
assert.match(source, /enrichment:/);
|
||||
assert.match(source, /mode: deterministic/);
|
||||
assert.match(source, /run\('pnpm', \['exec', 'ktx', 'dev', 'ingest', 'run'/);
|
||||
assert.match(source, /run\('pnpm', \['exec', 'ktx', 'ingest', 'run'/);
|
||||
assert.match(source, /access\(join\(projectDir, '\.ktx', 'db\.sqlite'\)\)/);
|
||||
assert.match(source, /SQLite knowledge index/);
|
||||
assert.match(source, /ktx dev ingest run requires llm\\.provider\\.backend: anthropic, vertex, or gateway/);
|
||||
assert.match(source, /ktx dev ingest provider guard verified/);
|
||||
assert.match(source, /ktx ingest run requires llm\\.provider\\.backend: anthropic, vertex, or gateway/);
|
||||
assert.match(source, /ktx ingest provider guard verified/);
|
||||
});
|
||||
|
||||
describe('npmCliSmokeSource', () => {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
import { mkdir as fsMkdir, writeFile as fsWriteFile } from 'node:fs/promises';
|
||||
import { mkdir as fsMkdir, readFile as fsReadFile, writeFile as fsWriteFile } from 'node:fs/promises';
|
||||
import { execFile as childExecFile } from 'node:child_process';
|
||||
import { dirname, resolve } from 'node:path';
|
||||
import { fileURLToPath, pathToFileURL } from 'node:url';
|
||||
|
|
@ -89,11 +89,7 @@ function parseArgs(argv) {
|
|||
}
|
||||
|
||||
export function buildOrbitScanArgv(input) {
|
||||
return ['dev', 'scan', input.connectionId, '--enrich', '--project-dir', input.projectDir];
|
||||
}
|
||||
|
||||
export function buildOrbitReportArgv(input) {
|
||||
return ['dev', 'scan', 'report', '--json', '--project-dir', input.projectDir, input.runId];
|
||||
return ['scan', input.connectionId, '--mode', 'relationships', '--project-dir', input.projectDir];
|
||||
}
|
||||
|
||||
export function extractRunId(stdout) {
|
||||
|
|
@ -101,6 +97,11 @@ export function extractRunId(stdout) {
|
|||
return match?.[1] ?? null;
|
||||
}
|
||||
|
||||
export function extractReportPath(stdout) {
|
||||
const match = stdout.match(/^\s*Report:\s*(\S+)/m);
|
||||
return match?.[1] ?? null;
|
||||
}
|
||||
|
||||
function listLines(values) {
|
||||
if (!values || values.length === 0) {
|
||||
return ['- none'];
|
||||
|
|
@ -203,11 +204,9 @@ export function formatOrbitVerificationMarkdown(result) {
|
|||
|
||||
if (result.status === 'success') {
|
||||
lines.push(
|
||||
'## JSON Report Command',
|
||||
'## Scan Report Artifact',
|
||||
'',
|
||||
'```bash',
|
||||
result.reportCommand,
|
||||
'```',
|
||||
`- ${result.reportPath}`,
|
||||
'',
|
||||
...formatSuccess(result),
|
||||
);
|
||||
|
|
@ -249,6 +248,7 @@ export async function runOrbitVerification(options = {}) {
|
|||
const now = options.now ?? (() => new Date());
|
||||
const mkdir = options.mkdir ?? fsMkdir;
|
||||
const writeFile = options.writeFile ?? fsWriteFile;
|
||||
const readFile = options.readFile ?? fsReadFile;
|
||||
const date = dateOnly(now());
|
||||
const env = options.env ?? orbitVerificationEnv(projectDir);
|
||||
const runWithEnv = (argv, runnerOptions) => runner(argv, { ...runnerOptions, env });
|
||||
|
|
@ -284,33 +284,32 @@ export async function runOrbitVerification(options = {}) {
|
|||
scanStderr: scan.stderr,
|
||||
};
|
||||
} else {
|
||||
const reportArgv = buildOrbitReportArgv({ projectDir, runId });
|
||||
const reportOutput = await runBufferedWorkspaceKtx(runWithEnv, reportArgv, rootDir, execFile);
|
||||
if (reportOutput.exitCode !== 0) {
|
||||
const scanReportPath = extractReportPath(scan.stdout);
|
||||
if (!scanReportPath) {
|
||||
result = {
|
||||
status: 'blocked',
|
||||
date,
|
||||
connectionId,
|
||||
projectDir,
|
||||
scanCommand: shellCommand(scanArgv),
|
||||
scanExitCode: reportOutput.exitCode,
|
||||
blocker: firstNonEmptyLine(reportOutput.stderr, reportOutput.stdout),
|
||||
scanStdout: `${scan.stdout}\n${reportOutput.stdout}`.trim(),
|
||||
scanStderr: `${scan.stderr}\n${reportOutput.stderr}`.trim(),
|
||||
scanExitCode: scan.exitCode,
|
||||
blocker: 'KTX scan completed without printing a report artifact path',
|
||||
scanStdout: scan.stdout,
|
||||
scanStderr: scan.stderr,
|
||||
};
|
||||
} else {
|
||||
const fullScanReportPath = resolve(projectDir, scanReportPath);
|
||||
result = {
|
||||
status: 'success',
|
||||
date,
|
||||
connectionId,
|
||||
projectDir,
|
||||
scanCommand: shellCommand(scanArgv),
|
||||
reportCommand: shellCommand(reportArgv),
|
||||
reportPath: fullScanReportPath,
|
||||
scanExitCode: scan.exitCode,
|
||||
reportExitCode: reportOutput.exitCode,
|
||||
scanStdout: scan.stdout,
|
||||
scanStderr: scan.stderr,
|
||||
report: JSON.parse(reportOutput.stdout),
|
||||
report: JSON.parse(await readFile(fullScanReportPath, 'utf8')),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,9 +3,9 @@ import { readFile } from 'node:fs/promises';
|
|||
import { dirname } from 'node:path';
|
||||
import { describe, it } from 'node:test';
|
||||
import {
|
||||
buildOrbitReportArgv,
|
||||
buildOrbitScanArgv,
|
||||
defaultOrbitVerificationProjectDir,
|
||||
extractReportPath,
|
||||
extractRunId,
|
||||
formatOrbitVerificationMarkdown,
|
||||
runOrbitVerification,
|
||||
|
|
@ -59,24 +59,15 @@ describe('relationship Orbit verification helper', () => {
|
|||
);
|
||||
});
|
||||
|
||||
it('builds the current KTX launcher arguments for scan and JSON report commands', () => {
|
||||
it('builds the current KTX launcher arguments for scan commands', () => {
|
||||
assert.deepEqual(buildOrbitScanArgv({ connectionId: 'orbit', projectDir: '/tmp/orbit-project' }), [
|
||||
'dev',
|
||||
'scan',
|
||||
'orbit',
|
||||
'--enrich',
|
||||
'--mode',
|
||||
'relationships',
|
||||
'--project-dir',
|
||||
'/tmp/orbit-project',
|
||||
]);
|
||||
assert.deepEqual(buildOrbitReportArgv({ projectDir: '/tmp/orbit-project', runId: 'scan-orbit-1' }), [
|
||||
'dev',
|
||||
'scan',
|
||||
'report',
|
||||
'--json',
|
||||
'--project-dir',
|
||||
'/tmp/orbit-project',
|
||||
'scan-orbit-1',
|
||||
]);
|
||||
});
|
||||
|
||||
it('uses the checked-in Orbit verification project by default', async () => {
|
||||
|
|
@ -95,22 +86,17 @@ describe('relationship Orbit verification helper', () => {
|
|||
runWorkspaceKtx: async (argv, options) => {
|
||||
calls.push(argv);
|
||||
envs.push(options.env);
|
||||
if (argv[2] === 'report') {
|
||||
options.stdout.write(successReportJson());
|
||||
return 0;
|
||||
}
|
||||
options.stdout.write('KTX scan completed\nRun: scan-orbit-1\nConnection: orbit\n');
|
||||
options.stdout.write('KTX scan completed\nRun: scan-orbit-1\nConnection: orbit\n Report: reports/scan-report.json\n');
|
||||
return 0;
|
||||
},
|
||||
readFile: async () => successReportJson(),
|
||||
});
|
||||
|
||||
assert.equal(result.status, 'success');
|
||||
assert.deepEqual(calls, [
|
||||
['dev', 'scan', 'orbit', '--enrich', '--project-dir', defaultProjectDir],
|
||||
['dev', 'scan', 'report', '--json', '--project-dir', defaultProjectDir, 'scan-orbit-1'],
|
||||
['scan', 'orbit', '--mode', 'relationships', '--project-dir', defaultProjectDir],
|
||||
]);
|
||||
assert.equal(envs[0].GIT_CEILING_DIRECTORIES, dirname(defaultProjectDir));
|
||||
assert.equal(envs[1].GIT_CEILING_DIRECTORIES, dirname(defaultProjectDir));
|
||||
assert.equal(writes.length, 1);
|
||||
assert.match(writes[0].content, new RegExp(defaultProjectDir.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')));
|
||||
});
|
||||
|
|
@ -129,19 +115,15 @@ describe('relationship Orbit verification helper', () => {
|
|||
writeFile: async () => {},
|
||||
runWorkspaceKtx: async (argv, options) => {
|
||||
calls.push(argv);
|
||||
if (argv[2] === 'report') {
|
||||
options.stdout.write(successReportJson());
|
||||
return 0;
|
||||
}
|
||||
options.stdout.write('KTX scan completed\nRun: scan-orbit-1\nConnection: orbit\n');
|
||||
options.stdout.write('KTX scan completed\nRun: scan-orbit-1\nConnection: orbit\n Report: reports/scan-report.json\n');
|
||||
return 0;
|
||||
},
|
||||
readFile: async () => successReportJson(),
|
||||
});
|
||||
|
||||
assert.equal(result.projectDir, '/tmp/orbit-project-from-env');
|
||||
assert.deepEqual(calls, [
|
||||
['dev', 'scan', 'orbit', '--enrich', '--project-dir', '/tmp/orbit-project-from-env'],
|
||||
['dev', 'scan', 'report', '--json', '--project-dir', '/tmp/orbit-project-from-env', 'scan-orbit-1'],
|
||||
['scan', 'orbit', '--mode', 'relationships', '--project-dir', '/tmp/orbit-project-from-env'],
|
||||
]);
|
||||
} finally {
|
||||
if (previousProjectDir === undefined) {
|
||||
|
|
@ -155,6 +137,7 @@ describe('relationship Orbit verification helper', () => {
|
|||
it('extracts the run id from human scan output', () => {
|
||||
assert.equal(extractRunId(`KTX scan completed\nStatus: done\nRun: scan-orbit-1\nConnection: orbit\n`), 'scan-orbit-1');
|
||||
assert.equal(extractRunId('KTX scan completed without a run line\n'), null);
|
||||
assert.equal(extractReportPath('Artifacts\n Report: reports/scan-report.json\n'), 'reports/scan-report.json');
|
||||
});
|
||||
|
||||
it('formats successful Orbit verification evidence from the JSON report', () => {
|
||||
|
|
@ -163,10 +146,9 @@ describe('relationship Orbit verification helper', () => {
|
|||
date: '2026-05-07',
|
||||
connectionId: 'orbit',
|
||||
projectDir: '/tmp/orbit-project',
|
||||
scanCommand: 'pnpm run ktx -- dev scan orbit --enrich --project-dir /tmp/orbit-project',
|
||||
reportCommand: 'pnpm run ktx -- dev scan report --json --project-dir /tmp/orbit-project scan-orbit-1',
|
||||
scanCommand: 'pnpm run ktx -- scan orbit --mode relationships --project-dir /tmp/orbit-project',
|
||||
reportPath: '/tmp/orbit-project/reports/scan-report.json',
|
||||
scanExitCode: 0,
|
||||
reportExitCode: 0,
|
||||
scanStdout: 'KTX scan completed\nRun: scan-orbit-1\n',
|
||||
scanStderr: '',
|
||||
report: JSON.parse(successReportJson()),
|
||||
|
|
@ -189,7 +171,7 @@ describe('relationship Orbit verification helper', () => {
|
|||
date: '2026-05-07',
|
||||
connectionId: 'orbit',
|
||||
projectDir: '/tmp/orbit-project',
|
||||
scanCommand: 'pnpm run ktx -- dev scan orbit --enrich --project-dir /tmp/orbit-project',
|
||||
scanCommand: 'pnpm run ktx -- scan orbit --mode relationships --project-dir /tmp/orbit-project',
|
||||
scanExitCode: 1,
|
||||
blocker: 'Connection "orbit" was not found',
|
||||
scanStdout: '',
|
||||
|
|
@ -202,7 +184,7 @@ describe('relationship Orbit verification helper', () => {
|
|||
assert.doesNotMatch(markdown, /scan\.enrichment\.mode is required/);
|
||||
});
|
||||
|
||||
it('runs scan then JSON report and writes success Markdown', async () => {
|
||||
it('runs scan then reads the report artifact and writes success Markdown', async () => {
|
||||
const calls = [];
|
||||
const writes = [];
|
||||
const result = await runOrbitVerification({
|
||||
|
|
@ -216,19 +198,15 @@ describe('relationship Orbit verification helper', () => {
|
|||
},
|
||||
runWorkspaceKtx: async (argv, options) => {
|
||||
calls.push(argv);
|
||||
if (argv[2] === 'report') {
|
||||
options.stdout.write(successReportJson());
|
||||
return 0;
|
||||
}
|
||||
options.stdout.write('KTX scan completed\nRun: scan-orbit-1\nConnection: orbit\n');
|
||||
options.stdout.write('KTX scan completed\nRun: scan-orbit-1\nConnection: orbit\n Report: reports/scan-report.json\n');
|
||||
return 0;
|
||||
},
|
||||
readFile: async () => successReportJson(),
|
||||
});
|
||||
|
||||
assert.equal(result.status, 'success');
|
||||
assert.deepEqual(calls, [
|
||||
['dev', 'scan', 'orbit', '--enrich', '--project-dir', '/tmp/orbit-project'],
|
||||
['dev', 'scan', 'report', '--json', '--project-dir', '/tmp/orbit-project', 'scan-orbit-1'],
|
||||
['scan', 'orbit', '--mode', 'relationships', '--project-dir', '/tmp/orbit-project'],
|
||||
]);
|
||||
assert.equal(writes.length, 1);
|
||||
assert.equal(writes[0].path, '/tmp/orbit-report.md');
|
||||
|
|
|
|||
|
|
@ -83,10 +83,6 @@ async function isBuildStale(rootDir, binPath, fs) {
|
|||
return false;
|
||||
}
|
||||
|
||||
function isShellCompletionRequest(argv) {
|
||||
return argv[0] === '__complete' || (argv[0] === 'dev' && argv[1] === '__complete');
|
||||
}
|
||||
|
||||
async function runBuffered(execFile, stdout, stderr, command, args, options) {
|
||||
try {
|
||||
const result = await execFile(command, args, { cwd: options.cwd, env: options.env, maxBuffer: 1024 * 1024 * 16 });
|
||||
|
|
@ -150,8 +146,7 @@ export async function runWorkspaceKtx(argv, options = {}) {
|
|||
const commandEnv = options.env;
|
||||
|
||||
const binExists = await fileExists(binPath, access);
|
||||
const skipStaleBuildCheck = binExists && isShellCompletionRequest(cliArgv);
|
||||
const needsBuild = !binExists || (!skipStaleBuildCheck && (await isBuildStale(rootDir, binPath, fs)));
|
||||
const needsBuild = !binExists || (await isBuildStale(rootDir, binPath, fs));
|
||||
if (needsBuild) {
|
||||
stderr.write(
|
||||
binExists
|
||||
|
|
|
|||
|
|
@ -105,53 +105,6 @@ test('runWorkspaceKtx drops a leading npm argument separator', async () => {
|
|||
]);
|
||||
});
|
||||
|
||||
test('runWorkspaceKtx skips stale-build checks for shell completion when dist exists', async () => {
|
||||
const calls = [];
|
||||
let statCalls = 0;
|
||||
|
||||
const exitCode = await runWorkspaceKtx(['dev', '__complete', '--shell', 'zsh', '--position', '2', '--', 'ktx', ''], {
|
||||
rootDir: '/workspace/ktx',
|
||||
access: async () => undefined,
|
||||
stat: async (path) => {
|
||||
statCalls += 1;
|
||||
return {
|
||||
mtimeMs: path.endsWith('/packages/cli/dist/bin.js') ? 2000 : 3000,
|
||||
isDirectory: () => path.endsWith('/src') || path.endsWith('/packages'),
|
||||
};
|
||||
},
|
||||
readdir: async () => {
|
||||
throw new Error('completion should not scan source directories');
|
||||
},
|
||||
execFile: async (command, args, options) => {
|
||||
calls.push({ command, args, cwd: options.cwd });
|
||||
return { stdout: 'connect:Add, list, test, and map data sources\n', stderr: '' };
|
||||
},
|
||||
stdout: { write: () => undefined },
|
||||
stderr: { write: () => undefined },
|
||||
});
|
||||
|
||||
assert.equal(exitCode, 0);
|
||||
assert.equal(statCalls, 0);
|
||||
assert.deepEqual(calls, [
|
||||
{
|
||||
command: process.execPath,
|
||||
args: [
|
||||
'/workspace/ktx/packages/cli/dist/bin.js',
|
||||
'dev',
|
||||
'__complete',
|
||||
'--shell',
|
||||
'zsh',
|
||||
'--position',
|
||||
'2',
|
||||
'--',
|
||||
'ktx',
|
||||
'',
|
||||
],
|
||||
cwd: '/workspace/ktx',
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
test('runWorkspaceKtx builds the workspace CLI before running it when dist is missing', async () => {
|
||||
const calls = [];
|
||||
const logs = [];
|
||||
|
|
@ -199,7 +152,7 @@ test('runWorkspaceKtx rebuilds before running when workspace sources are newer t
|
|||
const logs = [];
|
||||
let sourceMtimeMs = 3000;
|
||||
|
||||
const exitCode = await runWorkspaceKtx(['dev', 'scan', 'orbit', '--enrich'], {
|
||||
const exitCode = await runWorkspaceKtx(['scan', 'orbit', '--mode', 'relationships'], {
|
||||
rootDir: '/workspace/ktx',
|
||||
access: async () => undefined,
|
||||
stat: async (path) => ({
|
||||
|
|
@ -232,7 +185,7 @@ test('runWorkspaceKtx rebuilds before running when workspace sources are newer t
|
|||
calls.map((call) => [call.command, call.args]),
|
||||
[
|
||||
['pnpm', ['run', 'build']],
|
||||
[process.execPath, ['/workspace/ktx/packages/cli/dist/bin.js', 'dev', 'scan', 'orbit', '--enrich']],
|
||||
[process.execPath, ['/workspace/ktx/packages/cli/dist/bin.js', 'scan', 'orbit', '--mode', 'relationships']],
|
||||
],
|
||||
);
|
||||
assert.deepEqual(logs, [
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue