@kontextmind/kxm 0.7.176 → 0.7.178

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.
@@ -11,7 +11,7 @@
11
11
  "name": "kxm",
12
12
  "source": "./plugins/kxm",
13
13
  "description": "Durable workflows, peer agents, and kxm tui",
14
- "version": "0.7.176",
14
+ "version": "0.7.178",
15
15
  "category": "development",
16
16
  "tags": ["kxm", "multi-agent", "workflows", "mcp"]
17
17
  }
package/CHANGELOG.md CHANGED
@@ -6,6 +6,16 @@ All notable user-facing changes are documented here. The project follows [Semant
6
6
 
7
7
  ### Added
8
8
 
9
+ - **KXM configuration now has one owner-validated terminal editor.**
10
+ `kxm config edit --scope project|user` and OMP/Pi `/kxm config` publish the
11
+ same `kxm.config.v1` surface. Accepted writes are saved and re-read; rejected
12
+ values leave file bytes unchanged; clear removes only the selected scope's
13
+ override. Non-TTY and dry-run calls render one plain frame without writing.
14
+ The editor excludes endpoints, key references, credentials, arrays, dynamic
15
+ maps, roster, routes, gates, roles, and workflow definitions. Pi/OMP package
16
+ discovery now loads the tracked extension bundle, so the private TUI
17
+ workspace is bundled rather than becoming an unresolved runtime dependency.
18
+
9
19
  - **Hub project identity and its access key live in `.kxm/config.yaml`.**
10
20
  `hub.local` and `hub.cloud` hold the URL, the project id to present, and a
11
21
  key reference (`key.op` is an `op://` reference, `key.env` is an environment
@@ -2,7 +2,8 @@
2
2
 
3
3
  Read from `plans/kxm-roadmap/state.json` and the pages linked below.
4
4
 
5
- Verified date: null. A review pass has not set `architecture.verified`.
5
+ Verified date: 2026-10-11. The roadmap review checked every page listed here
6
+ against the current checkout.
6
7
 
7
8
  | Page | What it covers |
8
9
  | --- | --- |
@@ -1,15 +1,17 @@
1
1
  # Surfaces
2
2
 
3
- Read from `plugins/kxm/src/cli.ts`, `scripts/kxm-hub.mjs`, `plugins/kxm/src/hub.ts`,
4
- `plugins/kxm/src/runtime-supervisor.ts`, `plugins/kxm/src/runtime-paths.ts`,
5
- `plugins/kxm/src/mcp-server.ts`, `plugins/kxm/src/oneshot-producer.ts`,
6
- `plugins/kxm/src/studio-layout.ts`, `plugins/kxm/src/cli/types.ts`
7
- (`workspaceDirs`), `plugins/kxm/src/local-snapshot.ts`, and
8
- `scripts/kxm-worker.mjs`.
3
+ Read from `plugins/kxm/src/cli.ts`, `plugins/kxm/src/config-editor.ts`,
4
+ `plugins/kxm/src/extension.ts`, `scripts/kxm-hub.mjs`,
5
+ `plugins/kxm/src/hub.ts`, `plugins/kxm/src/runtime-supervisor.ts`,
6
+ `plugins/kxm/src/runtime-paths.ts`, `plugins/kxm/src/mcp-server.ts`,
7
+ `plugins/kxm/src/oneshot-producer.ts`, `plugins/kxm/src/studio-layout.ts`,
8
+ `plugins/kxm/src/cli/types.ts` (`workspaceDirs`),
9
+ `plugins/kxm/src/local-snapshot.ts`, and `scripts/kxm-worker.mjs`.
9
10
 
10
11
  | Surface | Started by | Listener or path | Store it owns | Defining file |
11
12
  | --- | --- | --- | --- | --- |
12
13
  | `kxm` CLI | `node scripts/kxm.mjs` or the installed bin | no listener | none | `plugins/kxm/src/cli.ts` |
14
+ | Configuration editor | `kxm config edit --scope project\|user`; OMP/Pi `/kxm config` uses project scope | `.kxm/config.yaml` or the user `config.yaml` | the selected config file; only bounded non-secret scalar fields | `plugins/kxm/src/config-editor.ts` |
13
15
  | Hub | `kxm hub start` via `scripts/kxm-hub.mjs` | `127.0.0.1:7331` | `.kxm/state/kxm.db` under the workspace state dir | `plugins/kxm/src/hub.ts` |
14
16
  | Hub credentials | written when the hub starts | `hub-env.json` under the user state root | that JSON file, not SQLite | `plugins/kxm/src/hub-env.ts` |
15
17
  | Hub cloud binding | `kxm hub bind <url> --cloud --token-env/--token-command` | no listener; writes the binding record and never stores the token | binding record; token stays in the named env or command | `plugins/kxm/src/cli/hub.ts` |
@@ -170,8 +170,10 @@ see the [plugin README](../../plugins/kxm/README.md).
170
170
  ### Pi package
171
171
 
172
172
  The root `package.json` carries the `pi-package` keyword and a `pi` block:
173
- `pi.extensions` lists `./plugins/kxm/src/extension.ts` and `pi.skills` lists
174
- `./plugins/kxm/skills`. Pi loads the TypeScript source itself.
173
+ `pi.extensions` lists the tracked `./plugins/kxm/dist/extension.js` bundle and
174
+ `pi.skills` lists `./plugins/kxm/skills`. Development can still load
175
+ `plugins/kxm/src/extension.ts` explicitly; published installs use the bundle so
176
+ private workspace packages are never unresolved runtime dependencies.
175
177
 
176
178
  ### Agent Skills
177
179
 
@@ -135,6 +135,7 @@ The context suites in detail:
135
135
  |---|---|
136
136
  | `init`, `validate`, `export` and `watch` in isolated workspaces | `cli.test.ts`, `github-watch.test.ts` |
137
137
  | Every mutating command under `--dry-run` leaves the workspace, state root and hub untouched | `cli-experience.test.ts` ("every mutating command under --dry-run leaves the workspace, state root, and hub untouched") |
138
+ | Owner-validated config editor: persisted writes, exact-byte refusals, scope inheritance, scalar-only publication, CLI frames, and OMP/Pi lifecycle | `config-editor.test.ts` |
138
139
  | Hub auto-start reuses a healthy or claimed hub, persists one admin key, and fails closed on bad claims | `hub-autostart.test.ts` |
139
140
  | Hub-local session brief from SQLite without message bodies; `hub bind` reports on, off or unknown | `session-work.test.ts`, `cli.test.ts` |
140
141
  | Session manifests, fail-closed rosters, worker and result envelopes, hub-owned envelope fields | `session.test.ts`, `cli.test.ts`, `envelope.test.ts`, `envelope-contract.test.ts` |
@@ -8,10 +8,10 @@ The kit is the workspace package
8
8
  [`packages/core/tui`](../../packages/core/tui) (`@kontextmind/tui`), also
9
9
  published on the product as `@kontextmind/kxm/tui`. It is one declarative
10
10
  surface model, one renderer, one input decoder, one contribution registry, and
11
- thin host adapters. Today `kxm dash` uses only its ANSI theme; the panel,
12
- registry and adapters are exported for integrators, and no shipped `kxm` command
13
- draws a panel yet. See [Packages and workspaces](packages.md) for the layout
14
- convention it follows.
11
+ thin host adapters. `kxm config edit --scope project|user` and OMP/Pi
12
+ `/kxm config` ship the first production panel on this kit. `kxm dash` uses its
13
+ ANSI theme but keeps its existing hub and SSE loop. See
14
+ [Packages and workspaces](packages.md) for the layout convention the kit follows.
15
15
 
16
16
  ## Package layout
17
17
 
@@ -99,6 +99,24 @@ The reducer is pure
99
99
  effects; the component layer runs them. That is the same contract that keeps
100
100
  `kxm dash` navigation testable, and it is why no key handling needs a terminal.
101
101
 
102
+ ## Shipped configuration editor
103
+
104
+ The `kxm/config` contribution in
105
+ [`config-editor.ts`](../../plugins/kxm/src/config-editor.ts) owns the supported
106
+ `kxm.config.v1` fields. Both `kxm config edit` and `/kxm config` register that
107
+ same contribution; the CLI uses the standalone adapter, while the OMP/Pi
108
+ extension uses the generic Pi custom panel.
109
+
110
+ Project scope shows built-in, user, then project values. User scope deliberately
111
+ shows only built-in and user values, so a project override cannot make a
112
+ successful user edit look unchanged. Clear deletes the selected scope's key;
113
+ the registry then re-reads the inherited value from disk.
114
+
115
+ The descriptor exposes only bounded scalar preferences. It does not expose hub
116
+ URLs, key references, credentials, arrays, dynamic maps, roster, routes, gates,
117
+ roles, or workflow definitions. Unknown section/field pairs and invalid values
118
+ are rejected before the config writer runs.
119
+
102
120
  ## Adding a surface
103
121
 
104
122
  1. Write the descriptor table. Each row is one setting: id, key path, label,
@@ -101,7 +101,7 @@ kxm -V
101
101
  `--dry-run` changes nothing: no file is written, deleted, or moved, no request that changes hub or Runtime state is sent, no process is started, and no remote command runs. A command that cannot say what it would do without doing some of it refuses the flag instead of acting.
102
102
 
103
103
  - Plan with `planned`: `backup`, `restore`, `config set`, `role add|remove|modify|resume`, `workflow add|remove|modify`, `goal create`, `task create|run|sync`, `memory note|sync`, `skills evaluate|promote|reject`, `context promote`, `context wiki-compile --out`, `auth token`, `session token`, `session brief`, and `ssh run|file|close`. Each prints its normal result plus `dryRun: true` and `planned`, a list of `{action, target}` entries whose `action` is `write`, `delete`, `move`, `request`, or `ssh`. Text mode prints `dry run: <summary>` and one indented `would <action> <target>` line per entry (`session brief` appends `dry run: would write <file>` lines to the brief instead).
104
- - Plan in their own shape (described in each section): `init`, `run`, `runs drive|cancel`, `docs build|serve`, `runtime start|stop|sync-retry`, `hub start|stop|bind|unbind`, `session start|stop`, `agent worker`, `dash`, `studio serve`, `models inventory-refresh`, `routes admit|disable`, `update`, `completion install`, `workflow start|signal|export|checkpoint|record|wait`, every `peer` subcommand, `gate degrade|signal`, `skills create`, and `improve report`. `gate github watch --dry-run` still polls GitHub but does not post the signal.
104
+ - Plan in their own shape (described in each section): `init`, `run`, `runs drive|cancel`, `docs build|serve`, `runtime start|stop|sync-retry`, `hub start|stop|bind|unbind`, `session start|stop`, `agent worker`, `dash`, `studio serve`, `models inventory-refresh`, `routes admit|disable`, `update`, `completion install`, `workflow start|signal|export|checkpoint|record|wait`, every `peer` subcommand, `gate degrade|signal`, `skills create`, `improve report`, and `config edit`. `config edit --dry-run` prints one plain frame and writes nothing. `gate github watch --dry-run` still polls GitHub but does not post the signal.
105
105
  - Read-only commands run as usual, without leaving a trace: a local SQLite store is opened without creating `-wal` or `-shm` files, and `runs status|list|receipt` only attach to a running Runtime supervisor. With no supervisor running they exit 2 with `dry_run_unsupported` instead of starting one. `context wiki-compile --dry-run` still asks the hub to compile, which is a read.
106
106
  - Refused: `kxm models` (the interactive screen) and `kxm prices acknowledge` exit 2 with `dry_run_unsupported`. The CLI keeps one list of the commands that answer `--dry-run` and refuses every other command the same way before it runs, so a command added without dry-run support fails closed.
107
107
 
@@ -339,6 +339,34 @@ Stop harness extensions from starting a hub (Not run):
339
339
  kxm config set hub.autoStart off --scope user
340
340
  ```
341
341
 
342
+ ### `kxm config edit`
343
+
344
+ ```text
345
+ kxm config edit --scope project|user
346
+ ```
347
+
348
+ Opens the terminal editor for one fixed list of scalar `kxm.config.v1` preferences. The same editor is `/kxm config` inside the OMP/Pi TUI, and that command mounts only when the session mode is `tui`.
349
+
350
+ | Option | Argument | Default | Description |
351
+ |---|---|---|---|
352
+ | `--scope` | `project` or `user` | none | Which file a write or clear changes. Required |
353
+
354
+ - `--scope project` writes `.kxm/config.yaml` and shows built-in, then user, then project. `--scope user` writes `$KXM_USER_CONFIG_DIR/config.yaml` (default `~/.config/kxm/config.yaml`) and shows built-in, then user. The project file does not mask the user view.
355
+ - A write checks the section and field together, then checks the value. A refusal leaves that file's bytes unchanged. Clear deletes only that scope's key.
356
+ - The editor accepts workflow and harness ids that contain `@`. Whitespace and control characters are refused.
357
+ - A stored scalar whose runtime type does not match the field is shown with `stored type does not match this field`. The text `true` is not a boolean.
358
+ - It does not edit hub URLs, key references, credentials, arrays, dynamic maps, roster, routes, gates, roles, or workflow YAML. `kxm config get`, `set`, and `list` are unchanged and still accept keys this editor does not.
359
+ - No TTY, and `--dry-run`, each print one plain frame and write nothing. `--json`, or a scope other than `project` or `user`, exits 2 and writes nothing.
360
+
361
+ ```bash
362
+ kxm config edit --scope project --dry-run
363
+ ```
364
+
365
+ ```text
366
+ KXM configuration
367
+ ...
368
+ ```
369
+
342
370
  ## `kxm completion`
343
371
 
344
372
  ```text
@@ -1315,6 +1315,14 @@ every reader found in `plugins/kxm/src`, `scripts/`, and `packages/`; the
1315
1315
  | `telemetry.anonymize` | Boolean | `true` | Not read by any code path yet |
1316
1316
  | `telemetry.userTelemetryDir` | Path | none | Not read by any code path yet |
1317
1317
 
1318
+ The terminal editor exposes a fixed non-secret scalar subset of this table:
1319
+ theme and token budget; default workflow and harness; dashboard settings;
1320
+ default tracker; hub auto-start; improvement policy and thresholds; shadow
1321
+ execution and circuit-breaker scalars; and federated/anonymized telemetry
1322
+ flags. It deliberately excludes arrays, dynamic maps, paths, sync-provider
1323
+ details, hub endpoints and key references, credentials, and trusted roster,
1324
+ route, gate, role, or workflow-definition files.
1325
+
1318
1326
  Under `auto_threshold`, `minRuns`, `minPassRate` and `minCostSavings` are the
1319
1327
  distinct runs, the accepted share, and the mean recorded cost per attempt a
1320
1328
  candidate needs before `kxm improve` reports it ready for review. A group with
@@ -1376,9 +1384,15 @@ Commands:
1376
1384
  - `kxm config list` prints `user`, `defaults`, `dash`, `sync`, and
1377
1385
  `loadedFrom`; `--json` prints every section. An empty `loadedFrom` means no
1378
1386
  file was found.
1379
-
1380
- There is no `kxm config unset`. Delete the key from the file to fall back to
1381
- the next layer; setting `null` stores `null`.
1387
+ - `kxm config edit --scope project|user` opens the owner-validated terminal
1388
+ editor. Project scope shows Base → User → Project; user scope shows Base →
1389
+ User so a project override cannot mask the edit. Clear deletes that scope's
1390
+ leaf and re-reads the inherited value. Non-TTY and `--dry-run` calls print one
1391
+ plain frame without writing. Invalid scope and `--json` are refused.
1392
+
1393
+ There is no standalone `kxm config unset` command. The editor's clear action
1394
+ deletes its supported key from the selected scope; for other keys, delete the
1395
+ key from the file. Setting `null` stores `null` and does not mean inherit.
1382
1396
 
1383
1397
  ### Configuration layers
1384
1398
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kontextmind/kxm",
3
- "version": "0.7.176",
3
+ "version": "0.7.178",
4
4
  "description": "KXM local-first multi-agent orchestration and operator dashboard",
5
5
  "type": "module",
6
6
  "author": "KontextMind",
@@ -70,7 +70,7 @@
70
70
  },
71
71
  "pi": {
72
72
  "extensions": [
73
- "./plugins/kxm/src/extension.ts"
73
+ "./plugins/kxm/dist/extension.js"
74
74
  ],
75
75
  "skills": [
76
76
  "./plugins/kxm/skills"
@@ -78,7 +78,7 @@
78
78
  },
79
79
  "dependencies": {
80
80
  "@anthropic-ai/claude-agent-sdk": "0.3.289",
81
- "@earendil-works/pi-tui": "0.87.1",
81
+ "@earendil-works/pi-tui": "1.0.2",
82
82
  "@modelcontextprotocol/sdk": "1.32.0",
83
83
  "yaml": "^2.9.0"
84
84
  },
@@ -95,7 +95,7 @@
95
95
  }
96
96
  },
97
97
  "devDependencies": {
98
- "@earendil-works/pi-coding-agent": "0.87.1",
98
+ "@earendil-works/pi-coding-agent": "1.0.2",
99
99
  "@modelcontextprotocol/sdk": "1.32.0",
100
100
  "@playwright/test": "1.63.0",
101
101
  "@types/node": "26.6.4",
@@ -2,7 +2,7 @@
2
2
  "$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json",
3
3
  "name": "kxm",
4
4
  "displayName": "KXM",
5
- "version": "0.7.176",
5
+ "version": "0.7.178",
6
6
  "description": "Headless multi-agent orchestration, durable workflows, and a live operator dashboard for Pi and Claude Code",
7
7
  "author": {
8
8
  "name": "KontextMind",
@@ -1275,7 +1275,7 @@ function sessionBriefPickerEnabled(input) {
1275
1275
  function parseKxmSlashArgs(args) {
1276
1276
  const raw = String(args ?? "").trim().toLowerCase();
1277
1277
  if (raw === "" || raw === "brief") return "brief";
1278
- if (raw === "status" || raw === "hub" || raw === "memory" || raw === "progress" || raw === "workflow" || raw === "help") return raw;
1278
+ if (raw === "status" || raw === "hub" || raw === "memory" || raw === "progress" || raw === "workflow" || raw === "config" || raw === "help") return raw;
1279
1279
  return "help";
1280
1280
  }
1281
1281
  function kxmSlashCompletions(prefix) {
@@ -1295,7 +1295,7 @@ var init_session_work = __esm({
1295
1295
  MAX_SESSION_BRIEF_PLANS = 5;
1296
1296
  SESSION_BRIEF_SCHEMA = "kxm.session-brief.v1";
1297
1297
  DEFAULT_SESSION_BRIEF_STALE_SECONDS = 5;
1298
- KXM_SLASH_SUBCOMMANDS = ["status", "hub", "memory", "progress", "workflow", "help"];
1298
+ KXM_SLASH_SUBCOMMANDS = ["status", "hub", "memory", "progress", "workflow", "config", "help"];
1299
1299
  }
1300
1300
  });
1301
1301
 
@@ -9182,6 +9182,7 @@ function loadKxmConfig(repoRoot = process.cwd(), options = {}) {
9182
9182
  const userConfigFile = join6(userDir, "config.yaml");
9183
9183
  const repoDir = repoConfigDirectory(repoRoot);
9184
9184
  const repoConfigFile = join6(repoDir, "config.yaml");
9185
+ const includeProject = options.layers !== "user";
9185
9186
  let userRaw = {};
9186
9187
  let userLoadedPath;
9187
9188
  if (existsSync7(userConfigFile)) {
@@ -9195,7 +9196,7 @@ function loadKxmConfig(repoRoot = process.cwd(), options = {}) {
9195
9196
  }
9196
9197
  let repoRaw = {};
9197
9198
  let repoLoadedPath;
9198
- if (existsSync7(repoConfigFile)) {
9199
+ if (includeProject && existsSync7(repoConfigFile)) {
9199
9200
  try {
9200
9201
  const text = readFileSync7(repoConfigFile, "utf8");
9201
9202
  repoRaw = (0, import_yaml2.parse)(text) ?? {};