@kaelio/ktx 0.1.1 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/python/{kaelio_ktx-0.1.1-py3-none-any.whl → kaelio_ktx-0.3.0-py3-none-any.whl} +0 -0
- package/assets/python/manifest.json +4 -4
- package/dist/admin-reindex.d.ts +15 -0
- package/dist/admin-reindex.js +161 -0
- package/dist/admin-reindex.test.js +116 -0
- package/dist/{dev.d.ts → admin.d.ts} +1 -1
- package/dist/{dev.js → admin.js} +14 -12
- package/dist/{dev.test.js → admin.test.js} +36 -31
- package/dist/cli-program.js +7 -7
- package/dist/cli-program.test.js +1 -3
- package/dist/cli-project.d.ts +18 -0
- package/dist/cli-project.js +52 -0
- package/dist/cli-project.test.d.ts +1 -0
- package/dist/cli-project.test.js +149 -0
- package/dist/cli-runtime.d.ts +2 -2
- package/dist/cli-runtime.js +2 -8
- package/dist/commands/connection-commands.js +11 -10
- package/dist/commands/connection-selection.d.ts +11 -0
- package/dist/commands/connection-selection.js +9 -0
- package/dist/commands/ingest-commands.js +32 -26
- package/dist/commands/knowledge-commands.js +17 -28
- package/dist/commands/mcp-commands.js +17 -11
- package/dist/commands/runtime-commands.js +2 -2
- package/dist/commands/sl-commands.js +27 -32
- package/dist/context-build-view.js +1 -1
- package/dist/doctor.test.js +4 -4
- package/dist/example-smoke.test.js +3 -3
- package/dist/index.test.js +97 -85
- package/dist/ingest.js +9 -2
- package/dist/ingest.test.js +27 -3
- package/dist/io/print-list.test.js +4 -4
- package/dist/knowledge.js +1 -1
- package/dist/managed-local-embeddings.d.ts +0 -2
- package/dist/managed-local-embeddings.js +2 -5
- package/dist/managed-local-embeddings.test.js +5 -8
- package/dist/managed-python-command.js +2 -2
- package/dist/managed-python-command.test.js +3 -3
- package/dist/managed-python-daemon.js +2 -2
- package/dist/managed-python-daemon.test.js +1 -1
- package/dist/managed-python-http.js +3 -3
- package/dist/managed-python-http.test.js +6 -6
- package/dist/managed-python-runtime.d.ts +1 -1
- package/dist/managed-python-runtime.js +3 -3
- package/dist/managed-python-runtime.test.js +2 -2
- package/dist/memory-flow-tui.test.js +2 -2
- package/dist/next-steps.d.ts +6 -6
- package/dist/next-steps.js +4 -4
- package/dist/next-steps.test.js +5 -5
- package/dist/print-command-tree.js +0 -2
- package/dist/print-command-tree.test.js +1 -1
- package/dist/public-ingest.d.ts +4 -2
- package/dist/public-ingest.js +12 -8
- package/dist/public-ingest.test.js +7 -3
- package/dist/release-version.d.ts +1 -5
- package/dist/release-version.js +2 -39
- package/dist/runtime-requirements.js +1 -1
- package/dist/runtime.js +6 -6
- package/dist/runtime.test.js +8 -8
- package/dist/scan.js +7 -2
- package/dist/scan.test.js +3 -3
- package/dist/setup-agents.js +3 -3
- package/dist/setup-agents.test.js +1 -1
- package/dist/setup-embeddings.js +2 -2
- package/dist/setup-embeddings.test.js +5 -5
- package/dist/setup-runtime.test.js +3 -3
- package/dist/sl.js +1 -1
- package/dist/standalone-smoke.test.js +6 -2
- package/node_modules/@ktx/context/dist/core/git.service.d.ts +1 -0
- package/node_modules/@ktx/context/dist/core/git.service.js +12 -0
- package/node_modules/@ktx/context/dist/index-sync/index.d.ts +2 -0
- package/node_modules/@ktx/context/dist/index-sync/index.js +1 -0
- package/node_modules/@ktx/context/dist/index-sync/reindex.d.ts +20 -0
- package/node_modules/@ktx/context/dist/index-sync/reindex.js +141 -0
- package/node_modules/@ktx/context/dist/index-sync/reindex.test.d.ts +1 -0
- package/node_modules/@ktx/context/dist/index-sync/reindex.test.js +139 -0
- package/node_modules/@ktx/context/dist/index-sync/types.d.ts +29 -0
- package/node_modules/@ktx/context/dist/index-sync/types.js +1 -0
- package/node_modules/@ktx/context/dist/index.d.ts +1 -0
- package/node_modules/@ktx/context/dist/index.js +1 -0
- package/node_modules/@ktx/context/dist/ingest/adapters/historic-sql/historic-sql.adapter.d.ts +2 -1
- package/node_modules/@ktx/context/dist/ingest/adapters/historic-sql/historic-sql.adapter.js +18 -0
- package/node_modules/@ktx/context/dist/ingest/adapters/historic-sql/local-ingest-acceptance.test.js +6 -6
- package/node_modules/@ktx/context/dist/ingest/adapters/historic-sql/projection.d.ts +5 -0
- package/node_modules/@ktx/context/dist/ingest/adapters/historic-sql/projection.js +48 -0
- package/node_modules/@ktx/context/dist/ingest/adapters/historic-sql/projection.test.js +83 -0
- package/node_modules/@ktx/context/dist/ingest/adapters/live-database/daemon-introspection.js +4 -1
- package/node_modules/@ktx/context/dist/ingest/adapters/live-database/daemon-introspection.test.js +32 -0
- package/node_modules/@ktx/context/dist/ingest/finalization-scope.d.ts +22 -0
- package/node_modules/@ktx/context/dist/ingest/finalization-scope.js +95 -0
- package/node_modules/@ktx/context/dist/ingest/finalization-scope.test.d.ts +1 -0
- package/node_modules/@ktx/context/dist/ingest/finalization-scope.test.js +114 -0
- package/node_modules/@ktx/context/dist/ingest/index.d.ts +1 -2
- package/node_modules/@ktx/context/dist/ingest/index.js +0 -1
- package/node_modules/@ktx/context/dist/ingest/ingest-bundle.runner.d.ts +2 -0
- package/node_modules/@ktx/context/dist/ingest/ingest-bundle.runner.isolated-diff.test.js +166 -0
- package/node_modules/@ktx/context/dist/ingest/ingest-bundle.runner.js +235 -45
- package/node_modules/@ktx/context/dist/ingest/ingest-bundle.runner.test.js +193 -38
- package/node_modules/@ktx/context/dist/ingest/local-bundle-ingest.test.js +22 -3
- package/node_modules/@ktx/context/dist/ingest/local-bundle-runtime.js +3 -4
- package/node_modules/@ktx/context/dist/ingest/local-ingest.js +0 -7
- package/node_modules/@ktx/context/dist/ingest/local-stage-ingest.js +15 -5
- package/node_modules/@ktx/context/dist/ingest/local-stage-ingest.test.js +29 -0
- package/node_modules/@ktx/context/dist/ingest/memory-flow/schema.d.ts +4 -4
- package/node_modules/@ktx/context/dist/ingest/memory-flow/schema.js +1 -1
- package/node_modules/@ktx/context/dist/ingest/memory-flow/types.d.ts +1 -1
- package/node_modules/@ktx/context/dist/ingest/ports.d.ts +1 -20
- package/node_modules/@ktx/context/dist/ingest/report-snapshot.d.ts +73 -2
- package/node_modules/@ktx/context/dist/ingest/report-snapshot.js +27 -0
- package/node_modules/@ktx/context/dist/ingest/reports.d.ts +23 -5
- package/node_modules/@ktx/context/dist/ingest/reports.js +7 -24
- package/node_modules/@ktx/context/dist/ingest/types.d.ts +33 -0
- package/node_modules/@ktx/context/dist/llm/index.d.ts +1 -1
- package/node_modules/@ktx/context/dist/llm/index.js +1 -1
- package/node_modules/@ktx/context/dist/llm/local-config.d.ts +0 -1
- package/node_modules/@ktx/context/dist/llm/local-config.js +2 -12
- package/node_modules/@ktx/context/dist/llm/local-config.test.js +2 -23
- package/node_modules/@ktx/context/dist/memory/local-memory.js +9 -3
- package/node_modules/@ktx/context/dist/package-exports.test.js +2 -2
- package/node_modules/@ktx/context/dist/project/config.d.ts +16 -0
- package/node_modules/@ktx/context/dist/project/driver-schemas.d.ts +8 -0
- package/node_modules/@ktx/context/dist/project/driver-schemas.js +4 -0
- package/node_modules/@ktx/context/dist/scan/enabled-tables.d.ts +3 -0
- package/node_modules/@ktx/context/dist/scan/enabled-tables.js +15 -0
- package/node_modules/@ktx/context/dist/scan/local-scan.d.ts +2 -4
- package/node_modules/@ktx/context/dist/scan/local-scan.js +2 -15
- package/node_modules/@ktx/context/dist/sl/ports.d.ts +3 -3
- package/node_modules/@ktx/context/dist/sl/sl-search.service.d.ts +3 -2
- package/node_modules/@ktx/context/dist/sl/sl-search.service.js +47 -45
- package/node_modules/@ktx/context/dist/sl/sl-search.service.test.js +61 -0
- package/node_modules/@ktx/context/dist/sl/sqlite-sl-sources-index.d.ts +4 -3
- package/node_modules/@ktx/context/dist/sl/sqlite-sl-sources-index.js +15 -5
- package/node_modules/@ktx/context/dist/sl/sqlite-sl-sources-index.test.js +24 -0
- package/node_modules/@ktx/context/dist/wiki/knowledge-wiki.service.d.ts +3 -2
- package/node_modules/@ktx/context/dist/wiki/knowledge-wiki.service.js +62 -51
- package/node_modules/@ktx/context/dist/wiki/knowledge-wiki.service.test.js +59 -3
- package/node_modules/@ktx/context/dist/wiki/ports.d.ts +3 -3
- package/node_modules/@ktx/context/dist/wiki/sqlite-knowledge-index.d.ts +33 -0
- package/node_modules/@ktx/context/dist/wiki/sqlite-knowledge-index.js +155 -2
- package/node_modules/@ktx/context/dist/wiki/sqlite-knowledge-index.test.js +26 -0
- package/node_modules/@ktx/context/package.json +5 -0
- package/package.json +1 -1
- package/node_modules/@ktx/context/dist/ingest/adapters/historic-sql/post-processor.d.ts +0 -4
- package/node_modules/@ktx/context/dist/ingest/adapters/historic-sql/post-processor.js +0 -38
- package/node_modules/@ktx/context/dist/ingest/adapters/historic-sql/post-processor.test.js +0 -63
- /package/dist/{dev.test.d.ts → admin-reindex.test.d.ts} +0 -0
- /package/{node_modules/@ktx/context/dist/ingest/adapters/historic-sql/post-processor.test.d.ts → dist/admin.test.d.ts} +0 -0
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
2
|
+
import { MANAGED_SENTENCE_TRANSFORMERS_BASE_URL } from '@ktx/context';
|
|
3
|
+
import { buildDefaultKtxProjectConfig } from '@ktx/context/project';
|
|
4
|
+
import { loadKtxCliProject, projectNeedsManagedLocalEmbeddings, substituteManagedLocalEmbeddingsUrl, } from './cli-project.js';
|
|
5
|
+
const RESOLVED_BASE_URL = 'http://127.0.0.1:51234';
|
|
6
|
+
function makeIo() {
|
|
7
|
+
let stderr = '';
|
|
8
|
+
return {
|
|
9
|
+
io: {
|
|
10
|
+
stdout: { write: (_chunk) => { } },
|
|
11
|
+
stderr: {
|
|
12
|
+
write: (chunk) => {
|
|
13
|
+
stderr += chunk;
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
stderr: () => stderr,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
function projectWithConfig(config) {
|
|
21
|
+
return {
|
|
22
|
+
projectDir: '/work/proj',
|
|
23
|
+
configPath: '/work/proj/ktx.yaml',
|
|
24
|
+
config,
|
|
25
|
+
coreConfig: {},
|
|
26
|
+
git: {},
|
|
27
|
+
fileStore: {},
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
function withManagedIngestEmbedding(config) {
|
|
31
|
+
return {
|
|
32
|
+
...config,
|
|
33
|
+
ingest: {
|
|
34
|
+
...config.ingest,
|
|
35
|
+
embeddings: {
|
|
36
|
+
backend: 'sentence-transformers',
|
|
37
|
+
model: 'all-MiniLM-L6-v2',
|
|
38
|
+
dimensions: 384,
|
|
39
|
+
sentenceTransformers: { base_url: MANAGED_SENTENCE_TRANSFORMERS_BASE_URL, pathPrefix: '' },
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
function withManagedScanEnrichmentEmbedding(config) {
|
|
45
|
+
return {
|
|
46
|
+
...config,
|
|
47
|
+
scan: {
|
|
48
|
+
...config.scan,
|
|
49
|
+
enrichment: {
|
|
50
|
+
...config.scan.enrichment,
|
|
51
|
+
embeddings: {
|
|
52
|
+
backend: 'sentence-transformers',
|
|
53
|
+
model: 'all-MiniLM-L6-v2',
|
|
54
|
+
dimensions: 384,
|
|
55
|
+
sentenceTransformers: { base_url: MANAGED_SENTENCE_TRANSFORMERS_BASE_URL, pathPrefix: '' },
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
const fakeDaemon = {
|
|
62
|
+
baseUrl: RESOLVED_BASE_URL,
|
|
63
|
+
stdoutLog: '/work/proj/.ktx/runtime/daemon.stdout.log',
|
|
64
|
+
stderrLog: '/work/proj/.ktx/runtime/daemon.stderr.log',
|
|
65
|
+
};
|
|
66
|
+
describe('projectNeedsManagedLocalEmbeddings', () => {
|
|
67
|
+
it('returns false when neither ingest nor scan embeddings reference the managed sentinel', () => {
|
|
68
|
+
expect(projectNeedsManagedLocalEmbeddings(buildDefaultKtxProjectConfig())).toBe(false);
|
|
69
|
+
});
|
|
70
|
+
it('returns true when ingest.embeddings uses the managed sentinel', () => {
|
|
71
|
+
expect(projectNeedsManagedLocalEmbeddings(withManagedIngestEmbedding(buildDefaultKtxProjectConfig()))).toBe(true);
|
|
72
|
+
});
|
|
73
|
+
it('returns true when scan.enrichment.embeddings uses the managed sentinel', () => {
|
|
74
|
+
expect(projectNeedsManagedLocalEmbeddings(withManagedScanEnrichmentEmbedding(buildDefaultKtxProjectConfig()))).toBe(true);
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
describe('substituteManagedLocalEmbeddingsUrl', () => {
|
|
78
|
+
it('rewrites the managed sentinel in both ingest.embeddings and scan.enrichment.embeddings', () => {
|
|
79
|
+
const config = withManagedScanEnrichmentEmbedding(withManagedIngestEmbedding(buildDefaultKtxProjectConfig()));
|
|
80
|
+
const resolved = substituteManagedLocalEmbeddingsUrl(config, RESOLVED_BASE_URL);
|
|
81
|
+
expect(resolved.ingest.embeddings.sentenceTransformers?.base_url).toBe(RESOLVED_BASE_URL);
|
|
82
|
+
expect(resolved.scan.enrichment.embeddings?.sentenceTransformers?.base_url).toBe(RESOLVED_BASE_URL);
|
|
83
|
+
});
|
|
84
|
+
it('returns the input unchanged when no sentinel is present', () => {
|
|
85
|
+
const config = buildDefaultKtxProjectConfig();
|
|
86
|
+
const resolved = substituteManagedLocalEmbeddingsUrl(config, RESOLVED_BASE_URL);
|
|
87
|
+
expect(resolved.ingest.embeddings).toEqual(config.ingest.embeddings);
|
|
88
|
+
expect(resolved.scan.enrichment.embeddings).toEqual(config.scan.enrichment.embeddings);
|
|
89
|
+
});
|
|
90
|
+
it('does not touch non-sentinel sentence-transformers URLs', () => {
|
|
91
|
+
const config = {
|
|
92
|
+
...buildDefaultKtxProjectConfig(),
|
|
93
|
+
ingest: {
|
|
94
|
+
...buildDefaultKtxProjectConfig().ingest,
|
|
95
|
+
embeddings: {
|
|
96
|
+
backend: 'sentence-transformers',
|
|
97
|
+
model: 'all-MiniLM-L6-v2',
|
|
98
|
+
dimensions: 384,
|
|
99
|
+
sentenceTransformers: { base_url: 'http://localhost:9999', pathPrefix: '' },
|
|
100
|
+
},
|
|
101
|
+
},
|
|
102
|
+
};
|
|
103
|
+
const resolved = substituteManagedLocalEmbeddingsUrl(config, RESOLVED_BASE_URL);
|
|
104
|
+
expect(resolved.ingest.embeddings.sentenceTransformers?.base_url).toBe('http://localhost:9999');
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
describe('loadKtxCliProject', () => {
|
|
108
|
+
it('returns the project unchanged and does not start the daemon when no sentinel is present', async () => {
|
|
109
|
+
const io = makeIo();
|
|
110
|
+
const project = projectWithConfig(buildDefaultKtxProjectConfig());
|
|
111
|
+
const loadProject = vi.fn(async () => project);
|
|
112
|
+
const ensureLocalEmbeddings = vi.fn(async () => fakeDaemon);
|
|
113
|
+
const result = await loadKtxCliProject({ projectDir: '/work/proj', cliVersion: '0.2.0', installPolicy: 'never', io: io.io }, { loadProject, ensureLocalEmbeddings });
|
|
114
|
+
expect(result).toBe(project);
|
|
115
|
+
expect(ensureLocalEmbeddings).not.toHaveBeenCalled();
|
|
116
|
+
});
|
|
117
|
+
it('starts the daemon and substitutes the resolved URL when ingest.embeddings uses the sentinel', async () => {
|
|
118
|
+
const io = makeIo();
|
|
119
|
+
const project = projectWithConfig(withManagedIngestEmbedding(buildDefaultKtxProjectConfig()));
|
|
120
|
+
const loadProject = vi.fn(async () => project);
|
|
121
|
+
const ensureLocalEmbeddings = vi.fn(async () => fakeDaemon);
|
|
122
|
+
const result = await loadKtxCliProject({ projectDir: '/work/proj', cliVersion: '0.2.0', installPolicy: 'never', io: io.io }, { loadProject, ensureLocalEmbeddings });
|
|
123
|
+
expect(ensureLocalEmbeddings).toHaveBeenCalledWith({
|
|
124
|
+
cliVersion: '0.2.0',
|
|
125
|
+
projectDir: '/work/proj',
|
|
126
|
+
installPolicy: 'never',
|
|
127
|
+
io: io.io,
|
|
128
|
+
});
|
|
129
|
+
expect(result.config.ingest.embeddings.sentenceTransformers?.base_url).toBe(RESOLVED_BASE_URL);
|
|
130
|
+
});
|
|
131
|
+
it('does not mutate process.env', async () => {
|
|
132
|
+
const io = makeIo();
|
|
133
|
+
const before = process.env.KTX_MANAGED_SENTENCE_TRANSFORMERS_BASE_URL;
|
|
134
|
+
delete process.env.KTX_MANAGED_SENTENCE_TRANSFORMERS_BASE_URL;
|
|
135
|
+
try {
|
|
136
|
+
const project = projectWithConfig(withManagedIngestEmbedding(buildDefaultKtxProjectConfig()));
|
|
137
|
+
await loadKtxCliProject({ projectDir: '/work/proj', cliVersion: '0.2.0', installPolicy: 'never', io: io.io }, { loadProject: vi.fn(async () => project), ensureLocalEmbeddings: vi.fn(async () => fakeDaemon) });
|
|
138
|
+
expect(process.env.KTX_MANAGED_SENTENCE_TRANSFORMERS_BASE_URL).toBeUndefined();
|
|
139
|
+
}
|
|
140
|
+
finally {
|
|
141
|
+
if (before === undefined) {
|
|
142
|
+
delete process.env.KTX_MANAGED_SENTENCE_TRANSFORMERS_BASE_URL;
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
process.env.KTX_MANAGED_SENTENCE_TRANSFORMERS_BASE_URL = before;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
});
|
package/dist/cli-runtime.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { KtxConnectionArgs } from './connection.js';
|
|
2
|
+
import type { KtxAdminReindexArgs } from './admin-reindex.js';
|
|
2
3
|
import type { KtxDoctorArgs } from './doctor.js';
|
|
3
4
|
import type { KtxKnowledgeArgs } from './knowledge.js';
|
|
4
5
|
import type { KtxPublicIngestArgs } from './public-ingest.js';
|
|
@@ -10,8 +11,6 @@ import type { KtxTextIngestArgs } from './text-ingest.js';
|
|
|
10
11
|
export interface KtxCliPackageInfo {
|
|
11
12
|
name: string;
|
|
12
13
|
version: string;
|
|
13
|
-
packageVersion: string;
|
|
14
|
-
runtimeVersion: string;
|
|
15
14
|
contextPackageName: '@ktx/context';
|
|
16
15
|
}
|
|
17
16
|
export interface KtxCliIo {
|
|
@@ -25,6 +24,7 @@ export interface KtxCliIo {
|
|
|
25
24
|
};
|
|
26
25
|
}
|
|
27
26
|
export interface KtxCliDeps {
|
|
27
|
+
adminReindex?: (args: KtxAdminReindexArgs, io: KtxCliIo) => Promise<number>;
|
|
28
28
|
setup?: (args: KtxSetupArgs, io: KtxCliIo) => Promise<number>;
|
|
29
29
|
connection?: (args: KtxConnectionArgs, io: KtxCliIo) => Promise<number>;
|
|
30
30
|
doctor?: (args: KtxDoctorArgs, io: KtxCliIo) => Promise<number>;
|
package/dist/cli-runtime.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createRequire } from 'node:module';
|
|
2
2
|
import { profileMark, profileSpan } from './startup-profile.js';
|
|
3
|
-
import {
|
|
3
|
+
import { assertCliVersion } from './release-version.js';
|
|
4
4
|
profileMark('module:cli-runtime');
|
|
5
5
|
const requirePackageJson = createRequire(import.meta.url);
|
|
6
6
|
export function getKtxCliPackageInfo() {
|
|
@@ -15,15 +15,9 @@ export function packageInfoFromJson(packageJson) {
|
|
|
15
15
|
typeof packageJson.version !== 'string') {
|
|
16
16
|
throw new Error('Invalid KTX CLI package metadata');
|
|
17
17
|
}
|
|
18
|
-
const runtimeVersion = resolveKtxRuntimeVersion({
|
|
19
|
-
packageName: packageJson.name,
|
|
20
|
-
packageVersion: packageJson.version,
|
|
21
|
-
});
|
|
22
18
|
return {
|
|
23
19
|
name: packageJson.name,
|
|
24
|
-
version:
|
|
25
|
-
packageVersion: packageJson.version,
|
|
26
|
-
runtimeVersion,
|
|
20
|
+
version: assertCliVersion(packageJson.version, `${packageJson.name}/package.json`),
|
|
27
21
|
contextPackageName: '@ktx/context',
|
|
28
22
|
};
|
|
29
23
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { resolveCommandProjectDir } from '../cli-program.js';
|
|
2
2
|
import { profileMark } from '../startup-profile.js';
|
|
3
|
+
import { resolveConnectionSelection } from './connection-selection.js';
|
|
3
4
|
profileMark('module:commands/connection-commands');
|
|
4
5
|
async function runConnectionArgs(context, args) {
|
|
5
6
|
const runner = context.deps.connection ?? (await import('../connection.js')).runKtxConnection;
|
|
@@ -10,7 +11,10 @@ export function registerConnectionCommands(program, context, commandName = 'conn
|
|
|
10
11
|
.command(commandName)
|
|
11
12
|
.description('List and test configured connections')
|
|
12
13
|
.showHelpAfterError()
|
|
13
|
-
.addHelpText('after', '\nProject directory defaults to KTX_PROJECT_DIR when set, otherwise the nearest ktx.yaml or current working directory.\n')
|
|
14
|
+
.addHelpText('after', '\nProject directory defaults to KTX_PROJECT_DIR when set, otherwise the nearest ktx.yaml or current working directory.\n')
|
|
15
|
+
.action(async (_options, command) => {
|
|
16
|
+
await runConnectionArgs(context, { command: 'list', projectDir: resolveCommandProjectDir(command) });
|
|
17
|
+
});
|
|
14
18
|
connection.hook('preAction', (_thisCommand, actionCommand) => {
|
|
15
19
|
context.writeDebug?.(commandName, actionCommand);
|
|
16
20
|
});
|
|
@@ -22,25 +26,22 @@ export function registerConnectionCommands(program, context, commandName = 'conn
|
|
|
22
26
|
});
|
|
23
27
|
connection
|
|
24
28
|
.command('test')
|
|
25
|
-
.description('Test
|
|
26
|
-
.argument('[connectionId]', 'KTX connection id (omit
|
|
29
|
+
.description('Test one or all configured connections (default: all)')
|
|
30
|
+
.argument('[connectionId]', 'KTX connection id to test (omit to test all)')
|
|
27
31
|
.option('--all', 'Test every configured connection and print a summary list')
|
|
28
32
|
.action(async (connectionId, options, command) => {
|
|
29
|
-
|
|
30
|
-
if (all && connectionId !== undefined) {
|
|
33
|
+
if (options.all === true && connectionId !== undefined) {
|
|
31
34
|
command.error('error: --all cannot be combined with a connection id argument');
|
|
32
35
|
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
}
|
|
36
|
-
if (all) {
|
|
36
|
+
const selection = resolveConnectionSelection({ connectionId, all: options.all === true });
|
|
37
|
+
if (selection.kind === 'all') {
|
|
37
38
|
await runConnectionArgs(context, { command: 'test-all', projectDir: resolveCommandProjectDir(command) });
|
|
38
39
|
return;
|
|
39
40
|
}
|
|
40
41
|
await runConnectionArgs(context, {
|
|
41
42
|
command: 'test',
|
|
42
43
|
projectDir: resolveCommandProjectDir(command),
|
|
43
|
-
connectionId: connectionId,
|
|
44
|
+
connectionId: selection.connectionId,
|
|
44
45
|
});
|
|
45
46
|
});
|
|
46
47
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export type ConnectionSelection = {
|
|
2
|
+
kind: 'all';
|
|
3
|
+
} | {
|
|
4
|
+
kind: 'single';
|
|
5
|
+
connectionId: string;
|
|
6
|
+
};
|
|
7
|
+
export interface ResolveConnectionSelectionInput {
|
|
8
|
+
connectionId?: string | undefined;
|
|
9
|
+
all: boolean;
|
|
10
|
+
}
|
|
11
|
+
export declare function resolveConnectionSelection(input: ResolveConnectionSelectionInput): ConnectionSelection;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export function resolveConnectionSelection(input) {
|
|
2
|
+
if (input.all && input.connectionId !== undefined) {
|
|
3
|
+
throw new Error('--all cannot be combined with a connection id argument');
|
|
4
|
+
}
|
|
5
|
+
if (input.connectionId !== undefined) {
|
|
6
|
+
return { kind: 'single', connectionId: input.connectionId };
|
|
7
|
+
}
|
|
8
|
+
return { kind: 'all' };
|
|
9
|
+
}
|
|
@@ -2,32 +2,59 @@ import { Option } from '@commander-js/extra-typings';
|
|
|
2
2
|
import { collectOption, parsePositiveIntegerOption, resolveCommandProjectDir, } from '../cli-program.js';
|
|
3
3
|
import { runtimeInstallPolicyFromFlags } from '../managed-python-command.js';
|
|
4
4
|
import { profileMark } from '../startup-profile.js';
|
|
5
|
+
import { resolveConnectionSelection } from './connection-selection.js';
|
|
5
6
|
profileMark('module:commands/ingest-commands');
|
|
6
7
|
export function registerIngestCommands(program, context, commandOptions) {
|
|
7
8
|
const ingest = program
|
|
8
9
|
.command('ingest')
|
|
9
|
-
.description('Build or inspect KTX context')
|
|
10
|
+
.description('Build or inspect KTX context, or capture text into memory')
|
|
10
11
|
.usage('[options] [connectionId]')
|
|
11
|
-
.argument('[connectionId]', 'Configured connection id to ingest')
|
|
12
|
+
.argument('[connectionId]', 'Configured connection id to ingest (omit to ingest all)')
|
|
12
13
|
.option('--all', 'Ingest all configured connections', false)
|
|
13
14
|
.addOption(new Option('--fast', 'Use deterministic database schema ingest').conflicts('deep'))
|
|
14
15
|
.addOption(new Option('--deep', 'Use AI-enriched database ingest').conflicts('fast'))
|
|
15
16
|
.addOption(new Option('--query-history', 'Include database query-history usage patterns').conflicts('noQueryHistory'))
|
|
16
17
|
.addOption(new Option('--no-query-history', 'Skip database query-history usage patterns'))
|
|
17
18
|
.option('--query-history-window-days <days>', 'Query-history lookback window for this run', parsePositiveIntegerOption)
|
|
19
|
+
.option('--text <content>', 'Capture inline text into KTX memory; repeatable', collectOption, [])
|
|
20
|
+
.option('--file <path>', 'Capture a text file into KTX memory; use - for stdin; repeatable', collectOption, [])
|
|
21
|
+
.option('--connection-id <connectionId>', 'KTX connection id to tag captured text/file notes')
|
|
22
|
+
.option('--user-id <id>', 'Memory user id for text/file capture attribution', 'local-cli')
|
|
23
|
+
.option('--fail-fast', 'Stop after the first failed text/file item', false)
|
|
18
24
|
.addOption(new Option('--plain', 'Print plain text output').conflicts(['json']))
|
|
19
25
|
.addOption(new Option('--json', 'Print JSON output').conflicts(['plain']))
|
|
20
26
|
.option('--yes', 'Install required managed runtime features without prompting')
|
|
21
27
|
.option('--no-input', 'Disable interactive terminal input')
|
|
22
28
|
.showHelpAfterError();
|
|
23
29
|
ingest.action(async (connectionId, options, command) => {
|
|
30
|
+
const projectDir = resolveCommandProjectDir(command);
|
|
31
|
+
const hasTextCapture = options.text.length > 0 || options.file.length > 0;
|
|
32
|
+
if (hasTextCapture) {
|
|
33
|
+
if (connectionId !== undefined) {
|
|
34
|
+
command.error('error: --text/--file does not accept a positional connection id; use --connection-id <id> to tag captured notes');
|
|
35
|
+
}
|
|
36
|
+
if (options.all === true) {
|
|
37
|
+
command.error('error: --all cannot be combined with --text or --file');
|
|
38
|
+
}
|
|
39
|
+
context.setExitCode(await commandOptions.runTextIngest({
|
|
40
|
+
projectDir,
|
|
41
|
+
texts: options.text,
|
|
42
|
+
files: options.file,
|
|
43
|
+
...(options.connectionId ? { connectionId: options.connectionId } : {}),
|
|
44
|
+
userId: options.userId,
|
|
45
|
+
json: options.json === true,
|
|
46
|
+
failFast: options.failFast === true,
|
|
47
|
+
}, context.io, context.deps));
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
const selection = resolveConnectionSelection({ connectionId, all: options.all === true });
|
|
24
51
|
const { runKtxPublicIngest } = await import('../public-ingest.js');
|
|
25
52
|
const queryHistory = options.queryHistory === true ? 'enabled' : options.queryHistory === false ? 'disabled' : 'default';
|
|
26
53
|
const args = {
|
|
27
54
|
command: 'run',
|
|
28
|
-
projectDir
|
|
29
|
-
...(
|
|
30
|
-
all:
|
|
55
|
+
projectDir,
|
|
56
|
+
...(selection.kind === 'single' ? { targetConnectionId: selection.connectionId } : {}),
|
|
57
|
+
all: selection.kind === 'all',
|
|
31
58
|
json: options.json === true,
|
|
32
59
|
inputMode: options.input === false ? 'disabled' : 'auto',
|
|
33
60
|
...(options.fast === true ? { depth: 'fast' } : {}),
|
|
@@ -42,25 +69,4 @@ export function registerIngestCommands(program, context, commandOptions) {
|
|
|
42
69
|
ingest.hook('preAction', (_thisCommand, actionCommand) => {
|
|
43
70
|
context.writeDebug?.('ingest', actionCommand);
|
|
44
71
|
});
|
|
45
|
-
ingest
|
|
46
|
-
.command('text')
|
|
47
|
-
.description('Ingest free-form text artifacts into KTX memory')
|
|
48
|
-
.argument('[files...]', 'Files to ingest; use - to read one item from stdin')
|
|
49
|
-
.option('--text <content>', 'Text content to ingest; repeat for a batch', collectOption, [])
|
|
50
|
-
.option('--connection-id <connectionId>', 'Optional KTX connection id for semantic-layer capture')
|
|
51
|
-
.option('--user-id <id>', 'Memory user id for capture attribution', 'local-cli')
|
|
52
|
-
.option('--json', 'Print JSON output')
|
|
53
|
-
.option('--fail-fast', 'Stop after the first failed text item', false)
|
|
54
|
-
.action(async (files, options, command) => {
|
|
55
|
-
const parentOptions = command.parent?.opts();
|
|
56
|
-
context.setExitCode(await commandOptions.runTextIngest({
|
|
57
|
-
projectDir: resolveCommandProjectDir(command),
|
|
58
|
-
texts: options.text,
|
|
59
|
-
files,
|
|
60
|
-
...(options.connectionId ? { connectionId: options.connectionId } : {}),
|
|
61
|
-
userId: options.userId,
|
|
62
|
-
json: options.json === true || parentOptions?.json === true,
|
|
63
|
-
failFast: options.failFast === true,
|
|
64
|
-
}, context.io, context.deps));
|
|
65
|
-
});
|
|
66
72
|
}
|
|
@@ -11,47 +11,36 @@ function isDebugEnabled(command) {
|
|
|
11
11
|
return options.debug === true;
|
|
12
12
|
}
|
|
13
13
|
export function registerWikiCommands(program, context) {
|
|
14
|
-
|
|
14
|
+
program
|
|
15
15
|
.command('wiki')
|
|
16
16
|
.description('List or search local wiki pages')
|
|
17
|
-
.
|
|
18
|
-
.
|
|
19
|
-
wiki
|
|
20
|
-
.command('list')
|
|
21
|
-
.description('List local wiki pages')
|
|
22
|
-
.option('--user-id <id>', 'Local user id', 'local')
|
|
23
|
-
.addOption(new Option('--output <mode>', 'Output mode: pretty (default in TTY), plain (TSV), or json').choices([
|
|
24
|
-
'pretty',
|
|
25
|
-
'plain',
|
|
26
|
-
'json',
|
|
27
|
-
]))
|
|
28
|
-
.option('--json', 'Shortcut for --output=json (overrides --output)', false)
|
|
29
|
-
.action(async (options, command) => {
|
|
30
|
-
await runKnowledgeArgs(context, {
|
|
31
|
-
command: 'list',
|
|
32
|
-
projectDir: resolveCommandProjectDir(command),
|
|
33
|
-
userId: options.userId,
|
|
34
|
-
output: options.output,
|
|
35
|
-
json: options.json,
|
|
36
|
-
});
|
|
37
|
-
});
|
|
38
|
-
wiki
|
|
39
|
-
.command('search')
|
|
40
|
-
.description('Search local wiki pages')
|
|
41
|
-
.argument('<query>', 'Search query')
|
|
17
|
+
.usage('[options] [query...]')
|
|
18
|
+
.argument('[query...]', 'Search query; omit to list all pages')
|
|
42
19
|
.option('--user-id <id>', 'Local user id', 'local')
|
|
43
|
-
.option('--limit <number>', 'Maximum search results', parsePositiveIntegerOption)
|
|
20
|
+
.option('--limit <number>', 'Maximum search results (search mode only)', parsePositiveIntegerOption)
|
|
44
21
|
.addOption(new Option('--output <mode>', 'Output mode: pretty (default in TTY), plain (TSV), or json').choices([
|
|
45
22
|
'pretty',
|
|
46
23
|
'plain',
|
|
47
24
|
'json',
|
|
48
25
|
]))
|
|
49
26
|
.option('--json', 'Shortcut for --output=json (overrides --output)', false)
|
|
27
|
+
.showHelpAfterError()
|
|
28
|
+
.addHelpText('after', '\nProject directory defaults to KTX_PROJECT_DIR when set, otherwise the current working directory.\n')
|
|
50
29
|
.action(async (query, options, command) => {
|
|
30
|
+
if (query.length === 0) {
|
|
31
|
+
await runKnowledgeArgs(context, {
|
|
32
|
+
command: 'list',
|
|
33
|
+
projectDir: resolveCommandProjectDir(command),
|
|
34
|
+
userId: options.userId,
|
|
35
|
+
output: options.output,
|
|
36
|
+
json: options.json,
|
|
37
|
+
});
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
51
40
|
await runKnowledgeArgs(context, {
|
|
52
41
|
command: 'search',
|
|
53
42
|
projectDir: resolveCommandProjectDir(command),
|
|
54
|
-
query,
|
|
43
|
+
query: query.join(' '),
|
|
55
44
|
userId: options.userId,
|
|
56
45
|
output: options.output,
|
|
57
46
|
json: options.json,
|
|
@@ -21,8 +21,23 @@ function formatMcpStartResultMessage(input) {
|
|
|
21
21
|
'',
|
|
22
22
|
].join('\n');
|
|
23
23
|
}
|
|
24
|
+
async function printMcpStatus(context, projectDir) {
|
|
25
|
+
const status = await (context.deps.mcp?.readStatus ?? readKtxMcpDaemonStatus)({ projectDir });
|
|
26
|
+
context.io.stdout.write(`${status.detail}\n`);
|
|
27
|
+
if (status.kind === 'running') {
|
|
28
|
+
context.io.stdout.write(`URL: ${status.url}\n`);
|
|
29
|
+
context.io.stdout.write(`PID: ${status.state.pid}\n`);
|
|
30
|
+
context.io.stdout.write(`Token auth: ${status.state.tokenAuth ? 'enabled' : 'disabled'}\n`);
|
|
31
|
+
context.io.stdout.write(`Project: ${status.state.projectDir}\n`);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
24
34
|
export function registerMcpCommands(program, context) {
|
|
25
|
-
const mcp = program
|
|
35
|
+
const mcp = program
|
|
36
|
+
.command('mcp')
|
|
37
|
+
.description('Manage the KTX MCP HTTP server (bare command: show status)')
|
|
38
|
+
.action(async (_options, command) => {
|
|
39
|
+
await printMcpStatus(context, resolveCommandProjectDir(command));
|
|
40
|
+
});
|
|
26
41
|
mcp
|
|
27
42
|
.command('stdio')
|
|
28
43
|
.description('Run the KTX MCP server over stdio')
|
|
@@ -91,16 +106,7 @@ export function registerMcpCommands(program, context) {
|
|
|
91
106
|
.command('status')
|
|
92
107
|
.description('Show KTX MCP daemon status')
|
|
93
108
|
.action(async (_options, command) => {
|
|
94
|
-
|
|
95
|
-
projectDir: resolveCommandProjectDir(command),
|
|
96
|
-
});
|
|
97
|
-
context.io.stdout.write(`${status.detail}\n`);
|
|
98
|
-
if (status.kind === 'running') {
|
|
99
|
-
context.io.stdout.write(`URL: ${status.url}\n`);
|
|
100
|
-
context.io.stdout.write(`PID: ${status.state.pid}\n`);
|
|
101
|
-
context.io.stdout.write(`Token auth: ${status.state.tokenAuth ? 'enabled' : 'disabled'}\n`);
|
|
102
|
-
context.io.stdout.write(`Project: ${status.state.projectDir}\n`);
|
|
103
|
-
}
|
|
109
|
+
await printMcpStatus(context, resolveCommandProjectDir(command));
|
|
104
110
|
});
|
|
105
111
|
mcp
|
|
106
112
|
.command('logs')
|
|
@@ -30,7 +30,7 @@ export function registerRuntimeCommands(program, context) {
|
|
|
30
30
|
});
|
|
31
31
|
runtime
|
|
32
32
|
.command('start')
|
|
33
|
-
.description('Start the KTX
|
|
33
|
+
.description('Start the KTX daemon')
|
|
34
34
|
.addOption(createRuntimeFeatureOption())
|
|
35
35
|
.option('--force', 'Restart even when a matching daemon is already running', false)
|
|
36
36
|
.action(async (options, command) => {
|
|
@@ -44,7 +44,7 @@ export function registerRuntimeCommands(program, context) {
|
|
|
44
44
|
});
|
|
45
45
|
runtime
|
|
46
46
|
.command('stop')
|
|
47
|
-
.description('Stop the KTX
|
|
47
|
+
.description('Stop the KTX daemon')
|
|
48
48
|
.option('--all', 'Stop all KTX daemon processes recorded or discoverable on this machine', false)
|
|
49
49
|
.action(async (options, command) => {
|
|
50
50
|
await runRuntimeArgs(context, {
|
|
@@ -28,63 +28,57 @@ export function registerSlCommands(program, context, commandName = 'sl') {
|
|
|
28
28
|
const sl = program
|
|
29
29
|
.command(commandName)
|
|
30
30
|
.description('List, search, validate, or query local semantic-layer sources')
|
|
31
|
-
.
|
|
32
|
-
.
|
|
33
|
-
sl.command('list')
|
|
34
|
-
.description('List semantic-layer sources')
|
|
35
|
-
.option('--connection-id <id>', 'KTX connection id')
|
|
36
|
-
.addOption(new Option('--output <mode>', 'Output mode: pretty (default in TTY), plain (TSV), or json').choices([
|
|
37
|
-
'pretty',
|
|
38
|
-
'plain',
|
|
39
|
-
'json',
|
|
40
|
-
]))
|
|
41
|
-
.option('--json', 'Shortcut for --output=json (overrides --output)', false)
|
|
42
|
-
.action(async (options, command) => {
|
|
43
|
-
await runSlArgs(context, {
|
|
44
|
-
command: 'list',
|
|
45
|
-
projectDir: resolveCommandProjectDir(command),
|
|
46
|
-
connectionId: options.connectionId,
|
|
47
|
-
output: options.output,
|
|
48
|
-
json: options.json,
|
|
49
|
-
});
|
|
50
|
-
});
|
|
51
|
-
sl.command('search')
|
|
52
|
-
.description('Search semantic-layer sources')
|
|
53
|
-
.argument('<query>', 'Search query')
|
|
31
|
+
.usage('[options] [query...]')
|
|
32
|
+
.argument('[query...]', 'Search query; omit to list all sources')
|
|
54
33
|
.option('--connection-id <id>', 'KTX connection id')
|
|
55
|
-
.option('--limit <number>', 'Maximum search results', parsePositiveIntegerOption)
|
|
34
|
+
.option('--limit <number>', 'Maximum search results (search mode only)', parsePositiveIntegerOption)
|
|
56
35
|
.addOption(new Option('--output <mode>', 'Output mode: pretty (default in TTY), plain (TSV), or json').choices([
|
|
57
36
|
'pretty',
|
|
58
37
|
'plain',
|
|
59
38
|
'json',
|
|
60
39
|
]))
|
|
61
40
|
.option('--json', 'Shortcut for --output=json (overrides --output)', false)
|
|
41
|
+
.showHelpAfterError()
|
|
42
|
+
.addHelpText('after', '\nProject directory defaults to KTX_PROJECT_DIR when set, otherwise the current working directory.\n')
|
|
62
43
|
.action(async (query, options, command) => {
|
|
44
|
+
if (query.length === 0) {
|
|
45
|
+
await runSlArgs(context, {
|
|
46
|
+
command: 'list',
|
|
47
|
+
projectDir: resolveCommandProjectDir(command),
|
|
48
|
+
connectionId: options.connectionId,
|
|
49
|
+
output: options.output,
|
|
50
|
+
json: options.json,
|
|
51
|
+
});
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
63
54
|
await runSlArgs(context, {
|
|
64
55
|
command: 'search',
|
|
65
56
|
projectDir: resolveCommandProjectDir(command),
|
|
66
57
|
connectionId: options.connectionId,
|
|
67
|
-
query,
|
|
58
|
+
query: query.join(' '),
|
|
68
59
|
...(options.limit !== undefined ? { limit: options.limit } : {}),
|
|
69
60
|
output: options.output,
|
|
70
61
|
json: options.json,
|
|
71
62
|
});
|
|
72
63
|
});
|
|
73
64
|
sl.command('validate')
|
|
74
|
-
.description('Validate a semantic-layer source')
|
|
65
|
+
.description('Validate a semantic-layer source (set --connection-id on `ktx sl`)')
|
|
75
66
|
.argument('<sourceName>', 'Semantic-layer source name')
|
|
76
|
-
.
|
|
77
|
-
|
|
67
|
+
.action(async (sourceName, _options, command) => {
|
|
68
|
+
const parentOpts = command.parent?.opts();
|
|
69
|
+
const connectionId = parentOpts?.connectionId;
|
|
70
|
+
if (connectionId === undefined) {
|
|
71
|
+
command.error("error: required option '--connection-id <id>' not specified");
|
|
72
|
+
}
|
|
78
73
|
await runSlArgs(context, {
|
|
79
74
|
command: 'validate',
|
|
80
75
|
projectDir: resolveCommandProjectDir(command),
|
|
81
|
-
connectionId:
|
|
76
|
+
connectionId: connectionId,
|
|
82
77
|
sourceName,
|
|
83
78
|
});
|
|
84
79
|
});
|
|
85
80
|
sl.command('query')
|
|
86
|
-
.description('Compile or execute a semantic-layer query')
|
|
87
|
-
.option('--connection-id <id>', 'KTX connection id')
|
|
81
|
+
.description('Compile or execute a semantic-layer query (set --connection-id on `ktx sl`)')
|
|
88
82
|
.option('--query-file <path>', 'JSON semantic-layer query file')
|
|
89
83
|
.option('--measure <measure>', 'Measure to query; repeatable', collectOption, [])
|
|
90
84
|
.option('--dimension <dimension>', 'Dimension to include; repeatable', collectOption, [])
|
|
@@ -102,10 +96,11 @@ export function registerSlCommands(program, context, commandName = 'sl') {
|
|
|
102
96
|
if (options.measure.length === 0 && !options.queryFile) {
|
|
103
97
|
throw new Error('sl query requires at least one --measure');
|
|
104
98
|
}
|
|
99
|
+
const parentOpts = command.parent?.opts();
|
|
105
100
|
const args = slQueryCommandSchema.parse({
|
|
106
101
|
command: 'query',
|
|
107
102
|
projectDir: resolveCommandProjectDir(command),
|
|
108
|
-
connectionId:
|
|
103
|
+
connectionId: parentOpts?.connectionId,
|
|
109
104
|
...(options.queryFile
|
|
110
105
|
? { queryFile: options.queryFile }
|
|
111
106
|
: {
|
|
@@ -532,7 +532,7 @@ function failedStepDetail(result) {
|
|
|
532
532
|
return result.steps.find((step) => step.status === 'failed')?.detail ?? null;
|
|
533
533
|
}
|
|
534
534
|
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*/;
|
|
535
|
-
const ACTIONABLE_FAILURE_LINE_RE = /^(Missing bundled Python runtime manifest|KTX Python runtime is required|KTX
|
|
535
|
+
const ACTIONABLE_FAILURE_LINE_RE = /^(Missing bundled Python runtime manifest|KTX Python runtime is required|KTX daemon HTTP|Error:|Failed\b|Could not\b|Cannot\b)/;
|
|
536
536
|
function trimErrorPrefix(line) {
|
|
537
537
|
return line.replace(/^Error:\s*/, '');
|
|
538
538
|
}
|
package/dist/doctor.test.js
CHANGED
|
@@ -55,8 +55,8 @@ describe('formatDoctorReport', () => {
|
|
|
55
55
|
expect(output).not.toContain('v22.16.0');
|
|
56
56
|
expect(output).toContain('Everything ready.');
|
|
57
57
|
expect(output).toContain('ktx status --json');
|
|
58
|
-
expect(output).toContain('ktx sl
|
|
59
|
-
expect(output).toContain('ktx wiki
|
|
58
|
+
expect(output).toContain('ktx sl');
|
|
59
|
+
expect(output).toContain('ktx wiki');
|
|
60
60
|
expect(output).not.toContain('ktx scan');
|
|
61
61
|
expect(output).not.toContain('ktx sl ask');
|
|
62
62
|
});
|
|
@@ -412,8 +412,8 @@ describe('runKtxDoctor', () => {
|
|
|
412
412
|
expect(out).toContain('info: pg_stat_statements.max is 1000');
|
|
413
413
|
expect(out).not.toContain('Update the Postgres parameter group or config');
|
|
414
414
|
expect(out).toContain('ktx status --json');
|
|
415
|
-
expect(out).toContain('ktx sl
|
|
416
|
-
expect(out).toContain('ktx wiki
|
|
415
|
+
expect(out).toContain('ktx sl');
|
|
416
|
+
expect(out).toContain('ktx wiki');
|
|
417
417
|
expect(out).not.toContain('ktx scan');
|
|
418
418
|
expect(out).not.toContain('ktx sl ask');
|
|
419
419
|
delete process.env.ANTHROPIC_API_KEY;
|
|
@@ -51,10 +51,10 @@ describe('standalone local warehouse example', () => {
|
|
|
51
51
|
});
|
|
52
52
|
it('runs local CLI commands against the copied example project', async () => {
|
|
53
53
|
const projectDir = await copyExampleProject(tempDir);
|
|
54
|
-
const knowledgeList = await runBuiltCli(['wiki', '
|
|
54
|
+
const knowledgeList = await runBuiltCli(['wiki', 'revenue', '--json', '--project-dir', projectDir]);
|
|
55
55
|
expect(knowledgeList).toMatchObject({ code: 0, stderr: '' });
|
|
56
56
|
expect(parseJsonOutput(knowledgeList.stdout).data.items).toContainEqual(expect.objectContaining({ key: 'revenue', summary: 'Paid order value after refunds' }));
|
|
57
|
-
const slList = await runBuiltCli(['sl', '
|
|
57
|
+
const slList = await runBuiltCli(['sl', '--json', '--project-dir', projectDir, '--connection-id', 'warehouse']);
|
|
58
58
|
expect(slList).toMatchObject({ code: 0, stderr: '' });
|
|
59
59
|
expect(parseJsonOutput(slList.stdout).data.items).toContainEqual(expect.objectContaining({ connectionId: 'warehouse', name: 'orders', columnCount: 3 }));
|
|
60
60
|
const slSearch = await runBuiltCli([
|
|
@@ -78,6 +78,6 @@ describe('standalone local warehouse example', () => {
|
|
|
78
78
|
'fake',
|
|
79
79
|
]);
|
|
80
80
|
expect(ingest).toMatchObject({ code: 1, stdout: '' });
|
|
81
|
-
expect(ingest.stderr).toContain("unknown option '--
|
|
81
|
+
expect(ingest.stderr).toContain("unknown option '--adapter'");
|
|
82
82
|
}, 30_000);
|
|
83
83
|
});
|