@kontextmind/kxm 0.7.128 → 0.7.130

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.128",
14
+ "version": "0.7.130",
15
15
  "category": "development",
16
16
  "tags": ["kxm", "multi-agent", "workflows", "mcp"]
17
17
  }
package/CHANGELOG.md CHANGED
@@ -425,6 +425,26 @@ All notable user-facing changes are documented here. The project follows [Semant
425
425
 
426
426
  ### Fixed
427
427
 
428
+ - **The test suite no longer passes `--test-timeout`.** Under `node --test` that flag bounds each file, so coverage on CI timed out `test/core/engine.test.ts` at three minutes. The wall clock in `scripts/run-bounded.mjs` still bounds each script.
429
+ - **A git worktree lane registers under its project.** The Runtime registry
430
+ keeps the home row and adds the lane as its own control root and event
431
+ store, with the same project id and home runtime (`lane_of` on the lane
432
+ row). A foreign clone with that id is still `project_home_conflict`. A
433
+ registered root whose directory is gone is replaced, and that replacement
434
+ logs one `project_registration_replaced` event. `kxm lane drop` unregisters
435
+ the lane root when the Runtime is running, and still drops the worktree
436
+ when the Runtime is stopped. `kxm runs status` and `kxm lane status` print
437
+ the root they read. On the first read-write open, the registry table is
438
+ rebuilt and the registry advances from schema 1 to 2, copying every row
439
+ forward with `lane_of` empty. `kxm lane drop` refuses `lane_run_open` and names every
440
+ unsettled run in that lane's event store unless `--force` is set. Unregister
441
+ answers 409 `runtime_project_busy` or `runtime_project_has_lanes` unless the
442
+ body sets `force`.
443
+ - **`npm test` exits when the suite finishes.** The script passes
444
+ `--test-force-exit`, so a green run does not sit in the event loop and a
445
+ red run still prints its failures. Two full runs of the suite without the
446
+ flag also exited once the files finished; the handle that kept an earlier
447
+ run alive was not reproduced in this tree.
428
448
  - **`kxm land` names the pull request from the first commit subject and matches the Release run by time.**
429
449
  `--title` sets the title; otherwise the subject of the first commit on the
430
450
  branch is used, and a missing subject refuses `land_pr_title_missing`. The
@@ -13,7 +13,7 @@ Read from `plugins/kxm/src/cli.ts`, `scripts/kxm-hub.mjs`, `plugins/kxm/src/hub.
13
13
  | 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
14
  | 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
15
  | Runtime supervisor | `kxm runtime` / `scripts/kxm-runtime-supervisor.mjs` | `127.0.0.1` and the requested port, or ephemeral | registry and event stores below | `plugins/kxm/src/runtime-supervisor.ts` |
16
- | Runtime registry | opened by the supervisor | `runtime/registry.db` under the user state root | `registry.db` | `plugins/kxm/src/runtime-paths.ts` |
16
+ | Runtime registry | opened by the supervisor | `runtime/registry.db` under the user state root | `registry.db`. A lane worktree registers under its project: same project id, its own control root, `lane_of` set. A registering root is the primary worktree when its git common dir is `<root>/.git`; if that primary registers while the live home row is not primary, the primary becomes the home row and every other live row of that repository becomes its lane. | `plugins/kxm/src/runtime-paths.ts` |
17
17
  | Runtime event store | opened by the supervisor | `runtime/projects/<key>/run-events.db` | `run-events.db` | `plugins/kxm/src/runtime-paths.ts` |
18
18
  | MCP server | Claude plugin or stdio launch | stdio | none | `plugins/kxm/src/mcp-server.ts` |
19
19
  | One-shot harness | supervisor producer | child process, no listener | none | `plugins/kxm/src/oneshot-producer.ts` |
@@ -162,7 +162,7 @@ Each database records its schema version in SQLite's `user_version`. When a proc
162
162
  - an older store fails with `runtime_schema_outdated`;
163
163
  - a store with tables but no version fails with `runtime_schema_shape_invalid`.
164
164
 
165
- KXM never upgrades a store in place, because the code would otherwise have to keep working against schema shapes it no longer tests. To cross a store version, stop the owner, back up if you need the history, delete the store with its `-wal` and `-shm` files, and let the owner recreate it: `kxm hub start` for `kxm.db`, and the Runtime for the registry and event stores. `kxm init` rebuilds no database. Legacy `.kxm/config/*.json` files are refused the same way.
165
+ KXM does not upgrade hub stores or Runtime event stores in place, because the code would otherwise have to keep working against schema shapes it no longer tests. To cross one of those versions, stop the owner, back up if you need the history, delete the store with its `-wal` and `-shm` files, and let the owner recreate it: `kxm hub start` for `kxm.db`, and the Runtime for event stores. The Runtime registry is the exception: schema 1 opens as schema 2, and each existing row keeps its root with `lane_of` left empty. `kxm init` rebuilds no database. Legacy `.kxm/config/*.json` files are refused the same way.
166
166
 
167
167
  Every store opens in WAL mode with a 5-second busy timeout, `synchronous=NORMAL`, and foreign keys on. A database or sidecar that is a symbolic link is refused. [ADR-0003](../adr/ADR-0003-sqlite-only-store.md) records why SQLite is the only store.
168
168
 
@@ -17,7 +17,7 @@
17
17
  | [Synchronization](synchronization.md) | Implemented for the default policy; custom policies and on-demand content transfer are not |
18
18
  | [Routing](routing.md) | Implemented: routing records, the dated price catalog, `kxm routing report` and `kxm improve` |
19
19
  | [Validation](validation.md) | Largely implemented: the restricted YAML loader, schema, reference and semantic checks, and permission diffs |
20
- | [Migration](migration.md) | Decided: there is no migration path and no `kxm migrate` command; legacy state is refused |
20
+ | [Migration](migration.md) | Decided: no `kxm migrate` command; legacy state is refused. The Runtime registry schema 1 to 2 copy is the one in-place step |
21
21
 
22
22
  KXM is a convention-over-configuration, local-first orchestration and
23
23
  context platform. One local Runtime owns execution; an optional multi-project
@@ -14,7 +14,7 @@ one re-adds a compatibility lane by inference.
14
14
  | Project tree with legacy `.kxm/config` JSON | `loadKxmProject` fails closed with `legacy_state_unsupported`, one issue per legacy file. No receipt, plan, flag, or environment variable unlocks it. |
15
15
  | `kxm init` on such a tree | Reports `mode: "legacy"`, lists `legacyInputs`, performs **no writes**. Recovery is a fresh project directory plus the YAML definitions worth keeping. |
16
16
  | `kxm migrate` | Unknown command. It existed as `plan` / `apply` / `verify` for pre-KXM JSON and was deleted with this decision. |
17
- | SQLite store stamped with an older `user_version` | Refused with `runtime_schema_outdated`; the refusal never advances `user_version`, so the store stays identifiably old. Delete the state file and let the process that owns it recreate the store (`kxm hub start` for hub state, the Runtime for registry/event stores). `kxm init` is **project-only** and rebuilds no database. Forward-only stamping is prohibited — it turns a clean failure into a later query against a column that does not exist. |
17
+ | SQLite store stamped with an older `user_version` | Hub stores and Runtime event stores are refused with `runtime_schema_outdated`. That refusal never advances `user_version`. Delete the state file and let the process that owns it recreate the store (`kxm hub start` for hub state, the Runtime for event stores). `kxm init` is **project-only** and rebuilds no database. The Runtime registry is the exception: schema 1 is copied to schema 2 in place, existing rows stay, and `lane_of` is null on those rows. Forward-only stamping of any other store is prohibited, because it turns a clean failure into a later query against a column that does not exist. |
18
18
  | Retired product and command names | Rejected by fail-closed brakes (lint + readiness tests), not aliased. |
19
19
  | Shared/off-scope Pi history | Never imported into a narrower run scope. A new physical session starts clean; durable facts come from Git, workflow evidence, artifacts, or promoted context. |
20
20
  | Historical run records | Never fabricated. Events whose real ordering was not observed stay absent rather than reconstructed into a finer-grained model. |
@@ -31,15 +31,19 @@ does exist:
31
31
  [Back up and restore KXM](../operations/backup-and-restore.md); a single `kxm.db`
32
32
  copy is not a backup.
33
33
  - **Out-of-range versions refuse without touching the file.** The stamp is read
34
- before anything that can modify the store, so a database this build refuses —
35
- older or newer — comes back byte-identical: neither its schema nor its
34
+ before anything that can modify the store, so a database this build refuses,
35
+ older or newer, comes back byte-identical: neither its schema nor its
36
36
  `user_version` changes, and it is not converted to WAL as a side effect of being
37
- rejected. A store ahead of this build is refused without downgrade.
38
- - **Schema changes are additive-and-replace, not in-place.** Land the new
37
+ rejected. A store ahead of this build is refused without downgrade. The
38
+ registry schema 1 to 2 copy is not a refusal: that file is rewritten, and
39
+ every other older store is still refused untouched.
40
+ - **Schema changes are additive-and-replace, not in-place,** except the
41
+ Runtime registry's `lane_of` column. For every other store, land the new
39
42
  definition, delete the local state, and let the process that owns each store
40
- recreate it — `kxm hub start` for hub state, the Runtime for registry and
41
- event stores. `kxm init` is project-only and rebuilds no database.
42
- Nothing in the runtime may rewrite an existing store's shape.
43
+ recreate it. `kxm hub start` recreates hub state. The Runtime recreates event
44
+ stores. `kxm init` is project-only and rebuilds no database. Nothing else in
45
+ the runtime may rewrite an existing store's shape. Opening a schema 1
46
+ registry copies its rows into schema 2 and leaves `lane_of` null.
43
47
 
44
48
  ## If this ever changes
45
49
 
@@ -235,10 +235,12 @@ It runs three scripts in order:
235
235
 
236
236
  | Step | Script | What it checks |
237
237
  |---|---|---|
238
- | 1 | `npm test` | Build, then `test/core/*.test.ts` and `packages/core/*/tests/unit/*.test.ts` |
238
+ | 1 | `npm test` | Build, then `test/core/*.test.ts` and `packages/core/*/tests/unit/*.test.ts`. The script passes `--test-force-exit` so a finished run leaves the process even if a handle is still open; a failing test is still reported before that exit |
239
239
  | 2 | `npm run check` | `tsc --noEmit`, `markdownlint-cli2`, and version surfaces |
240
240
  | 3 | `npm run check:generated` | Generated artifacts are tracked and match the staged copy |
241
241
 
242
+ Every suite script passes `--test-force-exit`, and `scripts/run-bounded.mjs` stops the run if the suite is still going after its wall-clock limit (20 minutes, or 40 for the complete and coverage suites). The bound is that wall clock per script. A per-test timeout is not used because under `node --test` each file is itself a test, so a per-test timeout also bounds each file.
243
+
242
244
  Other scripts you will use:
243
245
 
244
246
  | Script | Use it for |
@@ -237,14 +237,14 @@ It restores the registry and every project's event store and sidecar. Every chec
237
237
 
238
238
  ### Restore ceilings
239
239
 
240
- A backup newer than this build is refused with `runtime_schema_newer` before any file changes. KXM has no migrations: an older backup restores, but its store then refuses to open with `runtime_schema_outdated`. Restore an older backup with the release that wrote it; see [Upgrade KXM](upgrade.md#understand-schema-changes).
240
+ A backup newer than this build is refused with `runtime_schema_newer` before any file changes. Hub and event stores are not migrated: an older backup of those restores, then the store refuses to open with `runtime_schema_outdated`. A registry backup at schema 1 opens in place: existing rows stay, and each gains an empty `lane_of` column. Restore any other older backup with the release that wrote it; see [Upgrade KXM](upgrade.md#understand-schema-changes).
241
241
 
242
242
  The ceilings come from `KXM_BACKUP_CEILINGS` in `plugins/kxm/src/database.ts` and match each store's own schema version:
243
243
 
244
244
  | Store id | Highest schema version restored |
245
245
  |---|---|
246
246
  | `hub-store` | 5 |
247
- | `registry` | 1 |
247
+ | `registry` | 2 |
248
248
  | `events:<key>` | 7 |
249
249
  | `binding-store` | 1 (no current store uses it) |
250
250
 
@@ -280,7 +280,7 @@ Test a full restore on a spare machine before you rely on it, and repeat the tes
280
280
  | `backup_no_stores` | No `.kxm/state/kxm.db` under the checkout (or it was moved with `KXM_STATE_DIR` or `KXM_DATA_PATH`) and no event store for this checkout under the user state root | Run inside the checkout; copy a relocated database with the stopped-state procedure |
281
281
  | `Backup is incomplete (<n> omitted); not ok:`, exit 1 | A store or sidecar could not be copied, or appeared while the backup ran | Fix the source named after `omitted`, then run `kxm backup` again |
282
282
  | `restore_incomplete` | The manifest records `complete: false` | Restore a complete backup; the partial one is not restorable |
283
- | Runs are missing, or the Runtime refuses the project with `project_home_conflict`, after a restore | The checkout moved to another absolute path, and the registry still binds the project to the old one | Keep the checkout at its original path and restore there |
283
+ | Runs are missing, or the Runtime refuses the project with `project_home_conflict`, after a restore | The checkout moved, and a live registration still points at the old directory. A missing directory is replaced on the next registration. A second live checkout that is not a worktree of the registered repository is still refused | Keep a live checkout at its original path. A worktree of that repository registers as a lane |
284
284
  | `restore_requires_all_projects` | The backup holds the Runtime registry or another project's event store: it was taken with `--all-projects`, or by a build from before backups were scoped | Pass `--all-projects` if rolling back every project is what you want; otherwise restore a backup taken without it |
285
285
  | `restore_runtime_running` | The Runtime supervisor is running | Run `kxm runtime stop`, pause whatever restarts it, then restore |
286
286
  | `restore_runtime_unverified` | `$S/runtime/registry.db` cannot be read, so restore cannot tell whether the supervisor is running | Stop the Runtime, move the registry aside, then restore; an `--all-projects` backup brings the registry back |
@@ -84,7 +84,7 @@ kxm update pi --models # refresh Pi model catalogs
84
84
 
85
85
  ## Understand schema changes
86
86
 
87
- Each store records a schema version, and KXM never upgrades a store in place.
87
+ Each store records a schema version. Hub stores and Runtime event stores are never upgraded in place. The Runtime registry copies schema 1 forward to schema 2 and keeps every existing row.
88
88
 
89
89
  | Store | Location | Created by |
90
90
  |---|---|---|
@@ -93,7 +93,7 @@ Each store records a schema version, and KXM never upgrades a store in place.
93
93
  | Run event store | `runtime/projects/<key>/run-events.db` under the user state root | The Runtime supervisor |
94
94
 
95
95
  - A store **newer** than the running release refuses to open (`runtime_schema_newer`). Do not delete it; run the release that created it, or upgrade.
96
- - A store **older** than the running release also refuses to open (`runtime_schema_outdated`), and the error names the store. There is no migration.
96
+ - A hub store or event store **older** than the running release also refuses to open (`runtime_schema_outdated`), and the error names the store. There is no migration for those stores. A registry at schema 1 opens, and its rows stay.
97
97
 
98
98
  When a release changes a schema, either stay on the old release, or accept a fresh store: stop the owner, move the old file aside (keep it with your backup), and start the owner, which re-creates it. `kxm init` rebuilds no database. A fresh hub store loses message and workflow history; a fresh Runtime store loses local run history. Check the changelog for schema changes before you upgrade.
99
99
 
@@ -1345,7 +1345,7 @@ dry run: resume workflow run wf_dry_run (stage: review)
1345
1345
 
1346
1346
  ## `kxm lane`
1347
1347
 
1348
- One lane is one git worktree, one branch named the unit, and one recorded base sha. The record lives in the control checkout's state directory, `.kxm/state/lanes.json` (`kxm.lanes.v1`, mode 0600). The worktree path is `../<control-dir-basename>-<unit>`, next to the control checkout. Creating a lane resolves the base ref to a sha and does not fetch. There is no push, merge, pull request, or branch delete. Selecting a lane sets the discovery cwd to that lane's path and rebuilds workspace directories from it; `KXM_WORKDIR` still selects the workspace root when it is set, so the lane path is the workspace root only when `KXM_WORKDIR` is unset.
1348
+ One lane is one git worktree, one branch named the unit, and one recorded base sha. The record lives in the control checkout's state directory, `.kxm/state/lanes.json` (`kxm.lanes.v1`, mode 0600). The worktree path is `../<control-dir-basename>-<unit>`, next to the control checkout. Creating a lane resolves the base ref to a sha and does not fetch. There is no push, merge, pull request, or branch delete. Selecting a lane sets the discovery cwd to that lane's path and rebuilds workspace directories from it; `KXM_WORKDIR` still selects the workspace root when it is set, so the lane path is the workspace root only when `KXM_WORKDIR` is unset. A lane worktree of an already registered repository registers in the Runtime registry under that project: the same project id, its own control root and event store, and the same home runtime. A foreign clone with the same id is refused with `project_home_conflict`.
1349
1349
 
1350
1350
  ```text
1351
1351
  kxm lane create <unit> [--base <ref>]
@@ -1375,15 +1375,19 @@ Prints one line per lane: unit, branch, base sha, `dirty` (porcelain line count)
1375
1375
 
1376
1376
  ### `kxm lane status`
1377
1377
 
1378
- The list row for one unit, plus `status` of `lastRunId` when the Runtime supervisor is already running and answers. Otherwise `status=unknown`. `kxm lane status` never starts the Runtime supervisor.
1378
+ The list row for one unit, plus `status` of `lastRunId` when the Runtime supervisor is already running and answers. Otherwise `status=unknown`. The text ends with `root=<path>`, the lane root that status read. JSON includes the same path as `root`. `kxm lane status` never starts the Runtime supervisor.
1379
1379
 
1380
1380
  Refusals (exit 1): `lane_missing`, `lane_unit_invalid`, `lanes_unreadable`.
1381
1381
 
1382
1382
  ### `kxm lane drop`
1383
1383
 
1384
- Removes the worktree and the record. Refuses `lane_dirty` when porcelain is nonempty, and `lane_run_open` when `lastRunId` is set and that run is not `completed`, `failed`, or `cancelled`. `--force` overrides both. `git worktree remove --force` is used only with `--force`. The branch is not deleted; the text says so (`branchDeleted: false`). Unless `--force` is set, drop may start the Runtime supervisor to check whether the lane's last run is still open; `--dry-run` only attaches to a supervisor that is already running. `kxm lane status` never starts the supervisor.
1384
+ Removes the worktree and the record, and unregisters that lane root from the Runtime registry. When the supervisor is running, drop calls `POST /v1/projects/unregister`. A stopped supervisor is not an error: drop takes the registry write lock, deletes the row when that transaction still sees no live supervisor, and continues when the registry is absent. If the lock finds a live supervisor, drop uses the unregister route instead of editing the file. The route answers 409 `runtime_project_busy` when that root has an unsettled run, and 409 `runtime_project_has_lanes` when the root is the home row and other lanes are still registered, unless the body sets `force` to true. Refuses `lane_dirty` when porcelain is nonempty. Refuses `lane_run_open` when any run in the lane event store is not `completed`, `failed`, or `cancelled`. The text names each unsettled run id, and JSON includes `runIds`. That list is the same read as `kxm runs list` when the supervisor is running, and a direct read of the lane event store when the supervisor is stopped. A lane with no event store keeps the earlier check: `lane_run_open` when `lastRunId` is set and that run is not settled. `--force` overrides both refusals and sends `force: true` on the unregister request. `git worktree remove --force` is used only with `--force`. The branch is not deleted; the text says so (`branchDeleted: false`). Unless `--force` is set, the `lastRunId` check may start the Runtime supervisor. The event-store list only attaches to a supervisor that is already running. `--dry-run` only attaches and does not unregister. `kxm lane status` never starts the supervisor.
1385
1385
 
1386
- Refusals (exit 1): `lane_missing`, `lane_dirty`, `lane_run_open`, `lane_git_failed`.
1386
+ `lane_run_open` also uses the detail `lane <unit> runs could not be read: <detail>` when the lane's project or store could not be read, so the drop fails closed and does not remove the worktree. `<detail>` is the error message, cut to 200 characters, or `run list failed` when the thrown value is not an `Error`. The unsettled-run details stay `lane <unit> run <ids> is unsettled` (with `runIds`) and `lane <unit> run <lastRunId> is <status>`.
1387
+
1388
+ `lane_unregister_failed` uses the detail `lane <unit> could not be unregistered: <detail>`. `<detail>` is cut to 300 characters. It appears when a live supervisor refused the unregister or the request failed: the error message, `lane root could not be unregistered` when the failure is not an `Error`, or `runtime supervisor is live but could not be reached` when the registry lock finds a live supervisor that drop cannot attach to.
1389
+
1390
+ Refusals (exit 1): `lane_missing`, `lane_dirty`, `lane_run_open`, `lane_git_failed`, `lane_unregister_failed`.
1387
1391
 
1388
1392
  ### `kxm lane run`
1389
1393
 
@@ -1638,8 +1642,8 @@ kxm runs status <runId> [--lane <unit>]
1638
1642
  Show the projected status of a run, including durable drive receipt state (open / receipt verified / unsettled / orphaned).
1639
1643
 
1640
1644
  - Arguments: `<runId>`, Run id. `--lane <unit>` discovers the project from that lane's worktree (`lane_missing` when the record or path is absent, `lane_unit_invalid` when the unit is not a KXM identifier, `lanes_unreadable` when the record cannot be read). Reads run state, but starts the supervisor if needed (not under `--dry-run`).
1641
- - Text: `run <id>: <status> (workflow <id>, updated <time>)`, plus a drive line such as `drive <id>: open`, `completed (receipt verified)`, `unsettled <reason>`, `handoff`, `cancelled (<reason>)`, or `no receipt (orphaned)`.
1642
- - JSON keys: `run` (`runId`, `status`, `workflowId`, `configRevision`, `updatedAt`, ...), `drive` (`driveId`, `mode`, `openedAt`, `receipt`, `verified`, `divergence`).
1645
+ - Text: `run <id>: <status> (workflow <id>, updated <time>)`, then `root <path>` (the checkout the status read, which is the lane worktree when `--lane` is set), plus a drive line such as `drive <id>: open`, `completed (receipt verified)`, `unsettled <reason>`, `handoff`, `cancelled (<reason>)`, or `no receipt (orphaned)`.
1646
+ - JSON keys: `projectRoot` (that same checkout), `run` (`runId`, `status`, `workflowId`, `configRevision`, `updatedAt`, ...), `drive` (`driveId`, `mode`, `openedAt`, `receipt`, `verified`, `divergence`).
1643
1647
  - Errors: `project_required`, `run_status_failed`, `run_status_io_failed` (exit 1).
1644
1648
 
1645
1649
  ```bash
@@ -1648,6 +1652,7 @@ kxm runs status run_a80e84c98f514299b82f0157f4537ea3
1648
1652
 
1649
1653
  ```text
1650
1654
  run run_a80e84c98f514299b82f0157f4537ea3: preparing (workflow default, updated 2026-09-23T17:47:29.682Z)
1655
+ root /work/proj
1651
1656
  ```
1652
1657
 
1653
1658
  With no supervisor running:
@@ -166,8 +166,11 @@ makes a directory a KXM project. Parser: `loadKxmProject` in
166
166
  | `limits.maxAgentTimeMs` | Integer, 0 to 31,536,000,000 | Optional | Runtime refuses to drive any run while it is set (`limit_unsupported`); leave it out |
167
167
  | `limits.agentStepTimeoutMs` | Integer, 60,000 to 31,536,000,000 | Optional, 3,600,000 | Wall clock for one live agent or moa step when the step omits `timeoutMs`. The supervisor passes it to the one-shot producer. A step `timeoutMs` narrower than this wins; a wider step value is refused (`step_unsupported`, field `timeoutMs`) |
168
168
 
169
- The Runtime binds one project `id` to one control root per state root, so a
170
- second checkout with the same ID is refused with `project_home_conflict`.
169
+ The Runtime binds a project `id` to one repository. A git worktree of that
170
+ repository registers as a lane: the same id, its own control root, and the
171
+ same home runtime. A foreign clone with the same id is refused with
172
+ `project_home_conflict`. A registered root whose directory is gone is replaced
173
+ when a new root for that id registers.
171
174
 
172
175
  Example (validated with `kxm init --json`, including a nested member checkout
173
176
  at `repositories/api`):
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kontextmind/kxm",
3
- "version": "0.7.128",
3
+ "version": "0.7.130",
4
4
  "description": "KXM local-first multi-agent orchestration and operator dashboard",
5
5
  "type": "module",
6
6
  "author": "KontextMind",
@@ -34,12 +34,12 @@
34
34
  "build:runtime": "node scripts/build-runtime.mjs",
35
35
  "build": "npm run build:mcp && npm run build:runtime && npm run build:packages",
36
36
  "check:generated": "npm run build && node scripts/check-generated.mjs",
37
- "test:core": "npm run build && node --disable-warning=ExperimentalWarning --experimental-strip-types --test --test-concurrency=4 test/core/*.test.ts",
38
- "test:simulations": "npm run build && node --disable-warning=ExperimentalWarning --experimental-strip-types --test --test-concurrency=4 test/simulations/*.test.ts",
39
- "test:complete": "npm run build && node --disable-warning=ExperimentalWarning --experimental-strip-types --test --test-concurrency=4 test/core/*.test.ts test/simulations/*.test.ts",
40
- "test": "npm run build && node --disable-warning=ExperimentalWarning --experimental-strip-types --test --test-concurrency=4 test/core/*.test.ts packages/core/*/tests/unit/*.test.ts",
41
- "test:coverage:core": "npm run build && node --disable-warning=ExperimentalWarning --experimental-strip-types --test --test-concurrency=4 --experimental-test-coverage --test-coverage-lines=91 --test-coverage-branches=80 --test-coverage-functions=92 --test-coverage-include=plugins/kxm/src/**/*.ts --test-coverage-exclude=plugins/kxm/src/server.ts --test-coverage-exclude=plugins/kxm/src/mcp-server.ts --test-coverage-exclude=plugins/kxm/src/runtime-supervisor.ts --test-coverage-include=packages/core/*/src/**/*.ts test/core/*.test.ts packages/core/*/tests/unit/*.test.ts",
42
- "test:coverage:complete": "npm run build && node --disable-warning=ExperimentalWarning --experimental-strip-types --test --test-concurrency=4 --experimental-test-coverage --test-coverage-lines=93 --test-coverage-branches=80 --test-coverage-functions=93 --test-coverage-include=plugins/kxm/src/**/*.ts --test-coverage-exclude=plugins/kxm/src/server.ts --test-coverage-exclude=plugins/kxm/src/mcp-server.ts --test-coverage-exclude=plugins/kxm/src/runtime-supervisor.ts --test-coverage-include=packages/core/*/src/**/*.ts test/core/*.test.ts test/simulations/*.test.ts packages/core/*/tests/unit/*.test.ts",
37
+ "test:core": "npm run build && node scripts/run-bounded.mjs 1200000 node --disable-warning=ExperimentalWarning --experimental-strip-types --test --test-force-exit --test-concurrency=4 test/core/*.test.ts",
38
+ "test:simulations": "npm run build && node scripts/run-bounded.mjs 1200000 node --disable-warning=ExperimentalWarning --experimental-strip-types --test --test-force-exit --test-concurrency=4 test/simulations/*.test.ts",
39
+ "test:complete": "npm run build && node scripts/run-bounded.mjs 2400000 node --disable-warning=ExperimentalWarning --experimental-strip-types --test --test-force-exit --test-concurrency=4 test/core/*.test.ts test/simulations/*.test.ts",
40
+ "test": "npm run build && node scripts/run-bounded.mjs 1200000 node --disable-warning=ExperimentalWarning --experimental-strip-types --test --test-force-exit --test-concurrency=4 test/core/*.test.ts packages/core/*/tests/unit/*.test.ts",
41
+ "test:coverage:core": "npm run build && node scripts/run-bounded.mjs 2400000 node --disable-warning=ExperimentalWarning --experimental-strip-types --test --test-force-exit --test-concurrency=4 --experimental-test-coverage --test-coverage-lines=91 --test-coverage-branches=80 --test-coverage-functions=92 --test-coverage-include=plugins/kxm/src/**/*.ts --test-coverage-exclude=plugins/kxm/src/server.ts --test-coverage-exclude=plugins/kxm/src/mcp-server.ts --test-coverage-exclude=plugins/kxm/src/runtime-supervisor.ts --test-coverage-include=packages/core/*/src/**/*.ts test/core/*.test.ts packages/core/*/tests/unit/*.test.ts",
42
+ "test:coverage:complete": "npm run build && node scripts/run-bounded.mjs 2400000 node --disable-warning=ExperimentalWarning --experimental-strip-types --test --test-force-exit --test-concurrency=4 --experimental-test-coverage --test-coverage-lines=93 --test-coverage-branches=80 --test-coverage-functions=93 --test-coverage-include=plugins/kxm/src/**/*.ts --test-coverage-exclude=plugins/kxm/src/server.ts --test-coverage-exclude=plugins/kxm/src/mcp-server.ts --test-coverage-exclude=plugins/kxm/src/runtime-supervisor.ts --test-coverage-include=packages/core/*/src/**/*.ts test/core/*.test.ts test/simulations/*.test.ts packages/core/*/tests/unit/*.test.ts",
43
43
  "test:coverage": "npm run test:coverage:core",
44
44
  "typecheck": "tsc --noEmit",
45
45
  "lint:docs": "markdownlint-cli2",
@@ -48,7 +48,7 @@
48
48
  "verify": "npm test && npm run check && npm run check:generated",
49
49
  "validate:claude": "claude plugin validate . --strict && claude plugin validate plugins/kxm --strict",
50
50
  "validate:ci": "npm run test:coverage && npm run check && npm pack --dry-run",
51
- "validate:pr": "npm run build && npm run typecheck && node --disable-warning=ExperimentalWarning --experimental-strip-types --test --test-concurrency=4 test/core/artifacts-exist.test.ts test/core/ci-contract.test.ts test/core/envelope.test.ts test/core/envelope-contract.test.ts test/core/protocol.test.ts test/core/repo-root.test.ts test/core/routes-count.test.ts test/core/smoke.test.ts test/core/version-surfaces.test.ts && npm run check:versions && node scripts/check-generated.mjs",
51
+ "validate:pr": "npm run build && npm run typecheck && node scripts/run-bounded.mjs 1200000 node --disable-warning=ExperimentalWarning --experimental-strip-types --test --test-force-exit --test-concurrency=4 test/core/artifacts-exist.test.ts test/core/ci-contract.test.ts test/core/envelope.test.ts test/core/envelope-contract.test.ts test/core/protocol.test.ts test/core/repo-root.test.ts test/core/routes-count.test.ts test/core/smoke.test.ts test/core/version-surfaces.test.ts && npm run check:versions && node scripts/check-generated.mjs",
52
52
  "validate": "npm run validate:ci && npm run validate:claude",
53
53
  "test:packages": "npx nx run-many -t test --output-style=static",
54
54
  "check:packages": "npx nx run-many -t build,test:coverage,typecheck --output-style=static",
@@ -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.128",
5
+ "version": "0.7.130",
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",