@kontextmind/kxm 0.7.180 → 0.7.182
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/.claude-plugin/marketplace.json +1 -1
- package/CHANGELOG.md +23 -0
- package/docs/architecture/authentication.md +11 -2
- package/docs/architecture/hosted-direction.md +7 -5
- package/docs/architecture/inventory.md +5 -3
- package/docs/architecture/platform.md +18 -4
- package/docs/contributing/ci-and-release.md +18 -9
- package/docs/contributing/decisions.md +31 -0
- package/docs/contributing/development.md +39 -1
- package/docs/contributing/test-matrix.md +2 -1
- package/docs/reference/cli-reference.md +9 -9
- package/docs/reference/configuration.md +22 -0
- package/package.json +1 -1
- package/plugins/kxm/.claude-plugin/plugin.json +1 -1
- package/plugins/kxm/dist/cli.js +148 -42
- package/plugins/kxm/dist/mcp-server.js +1 -1
- package/plugins/kxm/package.json +1 -1
- package/plugins/kxm/src/improve-sources.ts +99 -13
- package/plugins/kxm/src/mcp-server.ts +1 -1
- package/plugins/kxm/src/studio-layout.ts +50 -0
- package/scripts/ci-postgres-17.sh +144 -0
|
@@ -290,6 +290,7 @@ export interface StudioServerOptions {
|
|
|
290
290
|
planProvider?: (() => KxmCompiledPlan | undefined) | undefined;
|
|
291
291
|
stateProvider?: (() => KxmRunState | undefined) | undefined;
|
|
292
292
|
onMutation?: ((command: string, args: Record<string, unknown>) => Promise<{ ok: boolean; result?: unknown; error?: string }> | { ok: boolean; result?: unknown; error?: string }) | undefined;
|
|
293
|
+
controlUrl?: string | undefined;
|
|
293
294
|
}
|
|
294
295
|
|
|
295
296
|
export interface StudioServerHandle {
|
|
@@ -299,6 +300,15 @@ export interface StudioServerHandle {
|
|
|
299
300
|
close: () => Promise<void>;
|
|
300
301
|
}
|
|
301
302
|
|
|
303
|
+
function isKxmdAccountView(value: unknown): boolean {
|
|
304
|
+
if (typeof value !== "object" || value === null) return false;
|
|
305
|
+
const account = value as Record<string, unknown>;
|
|
306
|
+
return account.account === "kxmd"
|
|
307
|
+
&& account.database === "kxmd"
|
|
308
|
+
&& account.namespace === "kxmd"
|
|
309
|
+
&& account.role === "kxmd";
|
|
310
|
+
}
|
|
311
|
+
|
|
302
312
|
/**
|
|
303
313
|
* Embedded Web Studio Local Server (Decision Q8 & D14).
|
|
304
314
|
* Serves the visual DAG, form stepper, and Temporal swimlane dashboards on http://localhost:4242.
|
|
@@ -328,6 +338,46 @@ export function createStudioServer(options: StudioServerOptions = {}): StudioSer
|
|
|
328
338
|
return;
|
|
329
339
|
}
|
|
330
340
|
|
|
341
|
+
if (url.pathname === "/api/control/account" && req.method === "GET") {
|
|
342
|
+
const base = options.controlUrl ?? process.env.KXM_CONTROL_URL;
|
|
343
|
+
if (!base) {
|
|
344
|
+
res.writeHead(503, { "Content-Type": "application/json" });
|
|
345
|
+
res.end(JSON.stringify({ ok: false, error: "control_unconfigured" }));
|
|
346
|
+
return;
|
|
347
|
+
}
|
|
348
|
+
let upstream: Response;
|
|
349
|
+
try {
|
|
350
|
+
upstream = await fetch(new URL("/v1/account", base), {
|
|
351
|
+
signal: AbortSignal.timeout(3_000),
|
|
352
|
+
});
|
|
353
|
+
} catch {
|
|
354
|
+
res.writeHead(502, { "Content-Type": "application/json" });
|
|
355
|
+
res.end(JSON.stringify({ ok: false, error: "control_unreachable" }));
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
358
|
+
const contentType = upstream.headers.get("content-type");
|
|
359
|
+
if (!contentType?.toLowerCase().startsWith("application/json")) {
|
|
360
|
+
res.writeHead(502, { "Content-Type": "application/json" });
|
|
361
|
+
res.end(JSON.stringify({ ok: false, error: "control_response_invalid" }));
|
|
362
|
+
return;
|
|
363
|
+
}
|
|
364
|
+
let body: unknown;
|
|
365
|
+
try {
|
|
366
|
+
body = await upstream.json();
|
|
367
|
+
} catch {
|
|
368
|
+
res.writeHead(502, { "Content-Type": "application/json" });
|
|
369
|
+
res.end(JSON.stringify({ ok: false, error: "control_response_invalid" }));
|
|
370
|
+
return;
|
|
371
|
+
}
|
|
372
|
+
if (upstream.ok && !isKxmdAccountView(body)) {
|
|
373
|
+
res.writeHead(502, { "Content-Type": "application/json" });
|
|
374
|
+
res.end(JSON.stringify({ ok: false, error: "control_response_invalid" }));
|
|
375
|
+
return;
|
|
376
|
+
}
|
|
377
|
+
res.writeHead(upstream.status, { "Content-Type": "application/json" });
|
|
378
|
+
res.end(JSON.stringify(body));
|
|
379
|
+
return;
|
|
380
|
+
}
|
|
331
381
|
if (url.pathname === "/api/layout" && req.method === "GET") {
|
|
332
382
|
const plan = options.planProvider?.();
|
|
333
383
|
if (!plan) {
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Start PostgreSQL 17 on 127.0.0.1:5432 for the Python MG1 lane.
|
|
3
|
+
# The kontextmind-doks scale set has a client binary and no engine socket, so
|
|
4
|
+
# this job provisions the server from a pinned archive instead of a workflow
|
|
5
|
+
# service. A second call in the same job returns once that server is ready.
|
|
6
|
+
|
|
7
|
+
set -euo pipefail
|
|
8
|
+
|
|
9
|
+
version=17.11.0
|
|
10
|
+
triple=x86_64-unknown-linux-gnu
|
|
11
|
+
sha256=b7a1ba6bae6499d8296e3e81b0171eecfd1766ca9aaa0057e41ad3e844e5e2e0
|
|
12
|
+
archive_name="postgresql-${version}-${triple}.tar.gz"
|
|
13
|
+
url="https://github.com/theseus-rs/postgresql-binaries/releases/download/${version}/${archive_name}"
|
|
14
|
+
|
|
15
|
+
if [[ "$(uname -s)" != "Linux" || "$(uname -m)" != "x86_64" ]]; then
|
|
16
|
+
echo "PostgreSQL 17 CI archive is linux/x86_64 only (got $(uname -s)/$(uname -m))" >&2
|
|
17
|
+
exit 1
|
|
18
|
+
fi
|
|
19
|
+
|
|
20
|
+
work="${RUNNER_TEMP:-${TMPDIR:-/tmp}}/kxm-mg1-postgres"
|
|
21
|
+
prefix="${work}/postgresql-${version}-${triple}"
|
|
22
|
+
pgdata="${work}/data"
|
|
23
|
+
pglog="${work}/postgres.log"
|
|
24
|
+
pwfile="${work}/pwfile"
|
|
25
|
+
mkdir -p "$work"
|
|
26
|
+
|
|
27
|
+
package_for_library() {
|
|
28
|
+
case "$1" in
|
|
29
|
+
libzstd.so.*) echo libzstd1 ;;
|
|
30
|
+
liblz4.so.*) echo liblz4-1 ;;
|
|
31
|
+
libxml2.so.*) echo libxml2 ;;
|
|
32
|
+
liblzma.so.*) echo liblzma5 ;;
|
|
33
|
+
libssl.so.3 | libcrypto.so.3) echo libssl3 ;;
|
|
34
|
+
libicuuc.so.74 | libicui18n.so.74 | libicudata.so.74) echo libicu74 ;;
|
|
35
|
+
libgssapi_krb5.so.*) echo libgssapi-krb5-2 ;;
|
|
36
|
+
libkrb5.so.* | libk5crypto.so.* | libkrb5support.so.*) echo libkrb5-3 ;;
|
|
37
|
+
libcom_err.so.*) echo libcom-err2 ;;
|
|
38
|
+
libkeyutils.so.*) echo libkeyutils1 ;;
|
|
39
|
+
libstdc++.so.*) echo libstdc++6 ;;
|
|
40
|
+
libgcc_s.so.*) echo libgcc-s1 ;;
|
|
41
|
+
libz.so.*) echo zlib1g ;;
|
|
42
|
+
*) return 1 ;;
|
|
43
|
+
esac
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
server_version_num() {
|
|
47
|
+
PGPASSWORD=postgres "${prefix}/bin/psql" \
|
|
48
|
+
-h 127.0.0.1 -p 5432 -U postgres -d postgres \
|
|
49
|
+
-Atqc "SHOW server_version_num"
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
postgres_17_ready() {
|
|
53
|
+
[[ -x "${prefix}/bin/pg_isready" ]] || return 1
|
|
54
|
+
"${prefix}/bin/pg_isready" -h 127.0.0.1 -p 5432 -U postgres >/dev/null 2>&1 || return 1
|
|
55
|
+
local num
|
|
56
|
+
num="$(server_version_num 2>/dev/null)" || return 1
|
|
57
|
+
[[ "$num" -ge 170000 && "$num" -lt 180000 ]]
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
install_missing_libraries() {
|
|
61
|
+
local -a missing=()
|
|
62
|
+
local line
|
|
63
|
+
while IFS= read -r line; do
|
|
64
|
+
[[ -n "$line" ]] && missing+=("$line")
|
|
65
|
+
done < <(ldd "${prefix}/bin/postgres" | awk '/not found$/ { print $1 }')
|
|
66
|
+
if [[ ${#missing[@]} -eq 0 ]]; then
|
|
67
|
+
return 0
|
|
68
|
+
fi
|
|
69
|
+
|
|
70
|
+
local -a packages=()
|
|
71
|
+
local lib pkg
|
|
72
|
+
for lib in "${missing[@]}"; do
|
|
73
|
+
if ! pkg="$(package_for_library "$lib")"; then
|
|
74
|
+
echo "PostgreSQL 17 needs ${lib}, which has no package mapping on this runner" >&2
|
|
75
|
+
ldd "${prefix}/bin/postgres" >&2 || true
|
|
76
|
+
exit 1
|
|
77
|
+
fi
|
|
78
|
+
packages+=("$pkg")
|
|
79
|
+
done
|
|
80
|
+
mapfile -t packages < <(printf '%s\n' "${packages[@]}" | awk '!seen[$0]++')
|
|
81
|
+
echo "Installing shared libraries for PostgreSQL 17: ${packages[*]}"
|
|
82
|
+
sudo -n apt-get update
|
|
83
|
+
sudo -n DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends "${packages[@]}"
|
|
84
|
+
|
|
85
|
+
local -a still=()
|
|
86
|
+
while IFS= read -r line; do
|
|
87
|
+
[[ -n "$line" ]] && still+=("$line")
|
|
88
|
+
done < <(ldd "${prefix}/bin/postgres" | awk '/not found$/ { print $1 }')
|
|
89
|
+
if [[ ${#still[@]} -gt 0 ]]; then
|
|
90
|
+
echo "PostgreSQL 17 still needs: ${still[*]}" >&2
|
|
91
|
+
exit 1
|
|
92
|
+
fi
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if postgres_17_ready; then
|
|
96
|
+
echo "PostgreSQL 17 already ready on 127.0.0.1:5432 (server_version_num=$(server_version_num))"
|
|
97
|
+
exit 0
|
|
98
|
+
fi
|
|
99
|
+
|
|
100
|
+
if [[ ! -x "${prefix}/bin/postgres" ]]; then
|
|
101
|
+
echo "Downloading PostgreSQL ${version}"
|
|
102
|
+
curl --fail --silent --show-error --location --retry 5 --retry-delay 2 \
|
|
103
|
+
--output "${work}/${archive_name}" \
|
|
104
|
+
"$url"
|
|
105
|
+
echo "${sha256} ${work}/${archive_name}" | sha256sum -c -
|
|
106
|
+
tar -xzf "${work}/${archive_name}" -C "$work"
|
|
107
|
+
fi
|
|
108
|
+
install_missing_libraries
|
|
109
|
+
|
|
110
|
+
if [[ ! -s "${pgdata}/PG_VERSION" ]]; then
|
|
111
|
+
printf '%s\n' postgres >"$pwfile"
|
|
112
|
+
chmod 600 "$pwfile"
|
|
113
|
+
"${prefix}/bin/initdb" \
|
|
114
|
+
--username=postgres \
|
|
115
|
+
--pwfile="$pwfile" \
|
|
116
|
+
--auth-host=scram-sha-256 \
|
|
117
|
+
--auth-local=trust \
|
|
118
|
+
--encoding=UTF8 \
|
|
119
|
+
--locale=C \
|
|
120
|
+
--set listen_addresses=127.0.0.1 \
|
|
121
|
+
--set port=5432 \
|
|
122
|
+
--set shared_buffers=16MB \
|
|
123
|
+
--set max_connections=20 \
|
|
124
|
+
--set shared_memory_type=mmap \
|
|
125
|
+
--set dynamic_shared_memory_type=mmap \
|
|
126
|
+
--set huge_pages=off \
|
|
127
|
+
--set fsync=off \
|
|
128
|
+
--set synchronous_commit=off \
|
|
129
|
+
--set full_page_writes=off \
|
|
130
|
+
--pgdata="$pgdata"
|
|
131
|
+
fi
|
|
132
|
+
|
|
133
|
+
if ! "${prefix}/bin/pg_ctl" -D "$pgdata" -l "$pglog" -w -t 30 start; then
|
|
134
|
+
echo "PostgreSQL 17 failed to start" >&2
|
|
135
|
+
cat "$pglog" >&2 || true
|
|
136
|
+
exit 1
|
|
137
|
+
fi
|
|
138
|
+
|
|
139
|
+
num="$(server_version_num)"
|
|
140
|
+
if [[ "$num" -lt 170000 || "$num" -ge 180000 ]]; then
|
|
141
|
+
echo "PostgreSQL 17 required, server_version_num=${num}" >&2
|
|
142
|
+
exit 1
|
|
143
|
+
fi
|
|
144
|
+
echo "PostgreSQL 17 ready on 127.0.0.1:5432 (server_version_num=${num})"
|