@kontextmind/kxm 0.7.169 → 0.7.171
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 +18 -0
- package/docs/adr/ADR-0005-obscura-default-playwright.md +2 -2
- package/docs/architecture/hosted-direction.md +7 -7
- package/docs/contributing/assignment-runner.md +6 -5
- package/docs/contributing/decisions.md +1 -1
- package/docs/contributing/learnings.md +9 -4
- package/docs/reference/cli-reference.md +27 -4
- package/package.json +1 -1
- package/plugins/kxm/.claude-plugin/plugin.json +1 -1
- package/plugins/kxm/dist/cli.js +596 -269
- package/plugins/kxm/dist/mcp-server.js +1 -1
- package/plugins/kxm/package.json +1 -1
- package/plugins/kxm/skills/kxm-runs/SKILL.md +10 -0
- package/plugins/kxm/src/cli/supervise.ts +167 -0
- package/plugins/kxm/src/cli.ts +32 -0
- package/plugins/kxm/src/mcp-server.ts +1 -1
- package/plugins/kxm/src/supervise-state.ts +232 -0
- package/scripts/pr-land.mjs +115 -17
package/CHANGELOG.md
CHANGED
|
@@ -617,6 +617,24 @@ All notable user-facing changes are documented here. The project follows [Semant
|
|
|
617
617
|
|
|
618
618
|
### Fixed
|
|
619
619
|
|
|
620
|
+
- **`kxm supervise` keeps supervisor state across a restart.**
|
|
621
|
+
`status`, `record`, and `tick` store in-flight lanes, the last-seen pull
|
|
622
|
+
request and CI state, and backoff timers in `.kxm/state/supervisor.json`.
|
|
623
|
+
A later process reads that file. `tick` clears a backoff whose deadline
|
|
624
|
+
has passed and appends `.kxm/logs/supervisor.log`. An unknown schema is
|
|
625
|
+
refused and left unchanged. See the
|
|
626
|
+
[CLI reference](docs/reference/cli-reference.md#kxm-supervise).
|
|
627
|
+
|
|
628
|
+
- **`kxm land` names a verify failure and refuses an UNKNOWN merge state.**
|
|
629
|
+
A failed `verify` records the exit code, the failing step, and a short
|
|
630
|
+
excerpt on the stage line and in `.kxm/logs/land-verify-<tree>.json`, and
|
|
631
|
+
writes the full output to `.kxm/logs/land-verify-<tree>.log`. The rebase
|
|
632
|
+
and merge stages poll `mergeStateStatus` while it is `UNKNOWN` and refuse
|
|
633
|
+
`land_merge_state_unknown` if it does not resolve. `CLEAN` and `HAS_HOOKS`
|
|
634
|
+
proceed; `BEHIND` and `DIRTY` still rebase; any other known state refuses
|
|
635
|
+
`land_merge_not_ready`. See the
|
|
636
|
+
[CLI reference](docs/reference/cli-reference.md#kxm-land).
|
|
637
|
+
|
|
620
638
|
- **`kxm hub view` and `kxm hub bind` require a kxm hub body.** HTTP 200 HTML
|
|
621
639
|
(an Authentik login page) and 30x redirects are not healthy. The JSON
|
|
622
640
|
`health` field is `{ "error": "auth_proxy" }`, not the page. Bind refuses
|
|
@@ -7,7 +7,7 @@ project: "kxm"
|
|
|
7
7
|
status: "accepted"
|
|
8
8
|
owner: "@operator"
|
|
9
9
|
created: "2026-09-27"
|
|
10
|
-
updated: "2026-09-
|
|
10
|
+
updated: "2026-09-28"
|
|
11
11
|
authority: "decision"
|
|
12
12
|
confidence: "verified"
|
|
13
13
|
summary: "Playwright testing and verification connect to pinned Obscura v0.2.3 over CDP. Steel stays the browser for human takeover, MFA, and the live session viewer."
|
|
@@ -74,7 +74,7 @@ Obscura v0.2.3 is a headless Chromium build that speaks the Chrome DevTools Prot
|
|
|
74
74
|
|
|
75
75
|
- Playwright tests and verification use Obscura unless the operator sets `KXM_BROWSER=steel`.
|
|
76
76
|
- Steel session create, release, takeover, and the session viewer are unchanged.
|
|
77
|
-
- CI for this smoke test is `.github/workflows/e2e.yml` on `ubuntu-latest`.
|
|
77
|
+
- CI for this smoke test is `.github/workflows/e2e.yml` on `ubuntu-latest`. The `CI` workflow is on, and `CI / required` is a required check in `protect-main`. `Nightly` and `Real Pi smoke` stay disabled. This ADR does not enable them.
|
|
78
78
|
- The `node --test` globs do not collect `test/e2e/`.
|
|
79
79
|
|
|
80
80
|
## Related
|
|
@@ -4,9 +4,9 @@ Target. This page is a direction, not a live deployment.
|
|
|
4
4
|
|
|
5
5
|
Read from `plans/plan-per-tenant-hosting.md`.
|
|
6
6
|
`plans/plan-greenfield-infra.md` is in this checkout as a `kxm.doc.v1`
|
|
7
|
-
stub (status draft, authority instruction)
|
|
8
|
-
|
|
9
|
-
implementation-plan greenfield bullets.
|
|
7
|
+
stub committed in #373 (status draft, authority instruction). The
|
|
8
|
+
long-form proposal is not in this repository. The canonical facts below
|
|
9
|
+
come from the implementation-plan greenfield bullets.
|
|
10
10
|
|
|
11
11
|
```mermaid
|
|
12
12
|
flowchart LR
|
|
@@ -47,10 +47,10 @@ roadmap question. The tracker wins.
|
|
|
47
47
|
|
|
48
48
|
## Greenfield infra plan
|
|
49
49
|
|
|
50
|
-
`plans/plan-greenfield-infra.md` is
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
scheduled there.
|
|
50
|
+
`plans/plan-greenfield-infra.md` is a `kxm.doc.v1` stub committed in #373
|
|
51
|
+
(status draft, authority instruction, updated 2026-09-28). The long-form
|
|
52
|
+
proposal is not in this repository. Its delivery position is unchanged:
|
|
53
|
+
none of the delivery is scheduled there.
|
|
54
54
|
|
|
55
55
|
The tracker names that file. The sentences that can be repeated without a
|
|
56
56
|
hostname, an account name, or a secret are: a first move is recorded as
|
|
@@ -402,20 +402,21 @@ regenerates documentation (`docs`), then runs the GitHub stages: `push`,
|
|
|
402
402
|
|
|
403
403
|
| Stage | Role |
|
|
404
404
|
|---|---|
|
|
405
|
-
| `verify` | Clean tree, then `npm run verify`, skipped when
|
|
405
|
+
| `verify` | Clean tree, then `npm run verify`, skipped when an `ok: true` receipt for this tree is younger than 30 minutes. A failure names the exit code, the failing step, and a short excerpt, and writes the full log |
|
|
406
406
|
| `docs` | Regenerate the roadmap after verify and before the merge. Absent generator: pass, skipped |
|
|
407
407
|
| `push` | `git push -u origin <branch>`, with `--force-with-lease` after a rebase in this run |
|
|
408
408
|
| `pr` | Reuse the open pull request, or create one from `--body-file` |
|
|
409
|
-
| `rebase` |
|
|
409
|
+
| `rebase` | Polls `UNKNOWN` until it resolves. `CLEAN` and `HAS_HOOKS` proceed. `BEHIND` and `DIRTY` rebase, up to five rounds onto `origin/main`. Only the dist rebuild, the CHANGELOG Unreleased union, and the tracker "Landed in this tree" union are resolved automatically. Any other known state blocks |
|
|
410
410
|
| `unblock` | Rerun one failed check. A required review is reported |
|
|
411
|
-
| `merge` | Squash only
|
|
411
|
+
| `merge` | Squash only after `CLEAN` or `HAS_HOOKS`. Poll until `MERGED`, up to 20 minutes. `UNKNOWN` does not merge |
|
|
412
412
|
| `release` | Auto-release tag, Release workflow, then npm for 10 minutes. Prints `PUBLISHED <version>` |
|
|
413
413
|
| `milestone` | Report `deep_review_required` when a phase completes or the body has a `Milestone:` line. Does not run the review |
|
|
414
414
|
|
|
415
415
|
Refusals (exit 1): `land_dirty_tree`, `land_verify_failed`, `land_docs_failed`,
|
|
416
416
|
`land_push_rejected`, `land_pr_body_missing`, `land_conflict_manual`,
|
|
417
|
-
`
|
|
418
|
-
`
|
|
417
|
+
`land_merge_state_unknown`, `land_merge_not_ready`, `land_blocked`,
|
|
418
|
+
`land_merge_failed`, `land_release_failed`, `land_publish_timeout`,
|
|
419
|
+
`land_milestone_failed`. Usage errors exit 2.
|
|
419
420
|
`--stage <name>` runs one stage. `--dry-run` prints the plan and does not mutate.
|
|
420
421
|
|
|
421
422
|
The same stages are command gates in `.kxm/gates.yaml` (`land-verify`,
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
title: "Decisions"
|
|
3
3
|
description: "Decisions of medium significance or higher made by automated KXM work in this repository. One entry per decision: the options evaluated with their weights, and why the selected option won. Recorded the turn the decision is taken."
|
|
4
4
|
audience: "agents and maintainers"
|
|
5
|
-
updated: "2026-09-
|
|
5
|
+
updated: "2026-09-28"
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# Decisions
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
title: "Learnings"
|
|
3
3
|
description: "Durable lessons from running the writer, critic, and landing loop on this repository. One entry per lesson, with the evidence and where it applies. Pruned when a lesson stops being true."
|
|
4
4
|
audience: "agents and maintainers"
|
|
5
|
-
updated: "2026-09-
|
|
5
|
+
updated: "2026-09-28"
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# Learnings
|
|
@@ -97,9 +97,14 @@ entry whose fix has landed is deleted, not archived.
|
|
|
97
97
|
|
|
98
98
|
- **Auto-merge cannot be enabled on a PR that is already `CLEAN`**; the
|
|
99
99
|
mutation answers "clean status" and the REST squash merge is the path.
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
100
|
+
`CI` is on and `CI / required` is a required check in `protect-main`, so
|
|
101
|
+
a pull request is not clean until that check passes.
|
|
102
|
+
- **A verify failure inside `kxm land` names the exit code, the failing
|
|
103
|
+
step, and a short excerpt, and keeps the full output in
|
|
104
|
+
`.kxm/logs/land-verify-<tree>.log`.** The receipt
|
|
105
|
+
`.kxm/logs/land-verify-<tree>.json` records the same fields with
|
|
106
|
+
`ok: false`. `mergeStateStatus: UNKNOWN` is polled and refused at the
|
|
107
|
+
bound; it is not treated as ready to merge.
|
|
103
108
|
|
|
104
109
|
## Reviews
|
|
105
110
|
|
|
@@ -160,6 +160,7 @@ Exit 2 covers an unknown command or option, a missing argument or required optio
|
|
|
160
160
|
| Create and drive a run | [`kxm run`](#kxm-run), [`kxm runs drive`](#kxm-runs-drive), [`kxm runtime status`](#kxm-runtime-status) |
|
|
161
161
|
| Work in an isolated checkout | [`kxm lane`](#kxm-lane), [`kxm run --lane`](#kxm-run) |
|
|
162
162
|
| Land the current branch | [`kxm land`](#kxm-land) |
|
|
163
|
+
| Resume the roadmap supervisor | [`kxm supervise`](#kxm-supervise) |
|
|
163
164
|
| Delegate and accept a developer assignment | [`kxm assign`](#kxm-assign) |
|
|
164
165
|
| Inspect runs | [`kxm runs list`](#kxm-runs-list), [`kxm runs status`](#kxm-runs-status), [`kxm runs receipt`](#kxm-runs-receipt), [`kxm tenant status`](#kxm-tenant-status), [`kxm workflow list`](#kxm-workflow-list) |
|
|
165
166
|
| Message peers | [`kxm peer list`](#kxm-peer-list), [`kxm peer send`](#kxm-peer-send), [`kxm peer await`](#kxm-peer-await), [`kxm peer fanout`](#kxm-peer-fanout) |
|
|
@@ -1454,20 +1455,42 @@ Outside a KXM project the command refuses `project_required` (exit 1). Unknown a
|
|
|
1454
1455
|
|
|
1455
1456
|
| Stage | What it does |
|
|
1456
1457
|
|---|---|
|
|
1457
|
-
| `verify` | Refuses `land_dirty_tree` unless `git status --porcelain` is empty. Skips when `.kxm/logs/land-verify-<tree>.json` for `HEAD^{tree}` is younger than 30 minutes
|
|
1458
|
+
| `verify` | Refuses `land_dirty_tree` unless `git status --porcelain` is empty. Skips when `.kxm/logs/land-verify-<tree>.json` for `HEAD^{tree}` is younger than 30 minutes and records `ok: true`. Otherwise runs `npm run verify` and writes that receipt. A failure writes the full output to `.kxm/logs/land-verify-<tree>.log` and a receipt with `ok: false`, the exit code, the failing step, and a short excerpt. The stage line names that exit code, the failing lines, and the log path. |
|
|
1458
1459
|
| `docs` | Runs `plans/kxm-roadmap/update-dashboard.mjs` when that file exists. Commits changes under `docs/roadmap/`, `plans/kxm-roadmap/`, or `docs/architecture/` as `docs(roadmap): regenerate after verify`. Any other path, including `state.json`, is `land_docs_failed`. When the generator is absent the stage passes with `docs: skipped (generator absent)`. |
|
|
1459
1460
|
| `push` | `git push -u origin <branch>`. After a rebase in this run, the push uses `--force-with-lease`. |
|
|
1460
1461
|
| `pr` | Reuses the branch's open pull request, or creates one with `gh pr create --body-file`. The title is `--title` when that option is set; otherwise it is the subject of the first commit (`git log --reverse --format=%s origin/main..HEAD`). `--dry-run` prints that title. |
|
|
1461
|
-
| `rebase` |
|
|
1462
|
+
| `rebase` | Polls `mergeStateStatus` while it is `UNKNOWN`, with bounded backoff (`KXM_LAND_MERGE_STATE_POLL_MS`, default 1 second, doubling up to 30 seconds, for at most `KXM_LAND_MERGE_STATE_WAIT_MS`, default 2 minutes). `UNKNOWN` at that bound is `land_merge_state_unknown` and is never treated as ready. `CLEAN` and `HAS_HOOKS` proceed. `BEHIND` and `DIRTY` fetch and rebase onto `origin/main`, resolving only three conflicts (take `plugins/kxm/dist` from main and rebuild; union CHANGELOG Unreleased bullets, ours first; union the tracker "Landed in this tree" list, newest first). Any other known state, including `BLOCKED`, is `land_merge_not_ready`. Runs `docs` again when the tree changed, re-verifies unless `git merge-tree --write-tree origin/main HEAD` was clean, and pushes with the lease. Five rounds, then `land_conflict_manual`. |
|
|
1462
1463
|
| `unblock` | Reads `statusCheckRollup` and `reviewDecision`. Reruns one failed check with `gh run rerun --failed`. A second failure or `REVIEW_REQUIRED` is `land_blocked`. |
|
|
1463
|
-
| `merge` |
|
|
1464
|
+
| `merge` | Refuses `land_merge_state_unknown` when `mergeStateStatus` stays `UNKNOWN`, and `land_merge_not_ready` for any known state other than `CLEAN` or `HAS_HOOKS`. Otherwise enables auto-merge with `enablePullRequestAutoMerge` and `mergeMethod: SQUASH`. When the response contains "clean status", squash-merges with `PUT /repos/{owner}/{repo}/pulls/{n}/merge` and commit title `<title> (#n)`. Polls `gh pr view --json state` every 30 seconds for up to 20 minutes. |
|
|
1464
1465
|
| `release` | Records the newest `v*` tag before the merge, waits for the Auto-Release run whose title contains the pull request title, requires a newer tag from `git ls-remote --tags origin`, then waits for the first `release.yml` run whose `createdAt` is after that Auto-Release run, with no title filter. Both run ids are written to `.kxm/logs/land-release-context.json` and printed in the stage detail (`PUBLISHED <version> auto-release <id> release <id>`). Each wait prints one JSON line every 2 minutes (`waiting auto-release.yml 4m`). The npm poll is `npm view @kontextmind/kxm@<version> version` every 30 seconds for 10 minutes. |
|
|
1465
1466
|
| `milestone` | Compares `plans/kxm-roadmap/state.json` from before and after `docs`. When a phase goes from an open task to all tasks `done`, or the pull request body contains a `Milestone:` line, prints `deep_review_required: true` and exits 0. The review is the `/reanalyze-roadmap` skill, not this command. An absent state file passes with skipped. |
|
|
1466
1467
|
|
|
1467
|
-
Refusals (exit 1): `project_required`, `land_dirty_tree`, `land_verify_failed`, `land_docs_failed`, `land_push_rejected`, `land_pr_body_missing`, `land_pr_title_missing`, `land_conflict_manual`, `land_blocked`, `land_merge_failed`, `land_release_failed`, `land_publish_timeout`, `land_milestone_failed`.
|
|
1468
|
+
Refusals (exit 1): `project_required`, `land_dirty_tree`, `land_verify_failed`, `land_docs_failed`, `land_push_rejected`, `land_pr_body_missing`, `land_pr_title_missing`, `land_conflict_manual`, `land_merge_state_unknown`, `land_merge_not_ready`, `land_blocked`, `land_merge_failed`, `land_release_failed`, `land_publish_timeout`, `land_milestone_failed`.
|
|
1468
1469
|
|
|
1469
1470
|
`land_pr_title_missing`: the `pr` stage was not given `--title`, and the first commit subject on `origin/main..HEAD` is empty.
|
|
1470
1471
|
|
|
1472
|
+
`land_verify_failed`: `npm run verify` exited non-zero. The stage line and `.kxm/logs/land-verify-<tree>.json` include `exitCode`, the failing step when the output names one, a short excerpt of the failing lines, and `log` (the full output).
|
|
1473
|
+
|
|
1474
|
+
`land_merge_state_unknown`: `mergeStateStatus` stayed `UNKNOWN` until the wait bound. The stage does not pass and does not merge.
|
|
1475
|
+
|
|
1476
|
+
`land_merge_not_ready`: GitHub reported a known merge state that is not `CLEAN` or `HAS_HOOKS`, and the rebase stage is not going to rebase it (`BLOCKED`, and on the merge stage also `BEHIND` or `DIRTY`). The detail names the status.
|
|
1477
|
+
|
|
1478
|
+
## `kxm supervise`
|
|
1479
|
+
|
|
1480
|
+
Persist the roadmap supervisor's memory in `.kxm/state/supervisor.json` (`kxm.supervisor.v1`, mode `0600`). The file holds in-flight lanes, the last-seen pull request number and merge state, the last-seen CI status and conclusion, and backoff timers. A missing file is empty. A malformed file or any other schema is refused and left unchanged. A later process reads the same file and continues.
|
|
1481
|
+
|
|
1482
|
+
```text
|
|
1483
|
+
kxm supervise status
|
|
1484
|
+
kxm supervise record --lane <unit> [--pr <n> --merge-state <status>] [--ci-status <status> --ci-conclusion <conclusion>] [--backoff-ms <n>] [--settled]
|
|
1485
|
+
kxm supervise tick
|
|
1486
|
+
```
|
|
1487
|
+
|
|
1488
|
+
`record` updates one lane and keeps fields that this call does not set. `--settled` marks the lane not in flight. `--backoff-ms 0` clears the timer. `tick` clears backoff timers whose deadline has passed, leaves the lane in flight with its last-seen pull request and CI state, and appends one line to `.kxm/logs/supervisor.log`. A timer still in the future is unchanged. `--dry-run` prints the writes and does not change the file or the log. `KXM_SUPERVISE_NOW` overrides the clock with an ISO-8601 UTC timestamp.
|
|
1489
|
+
|
|
1490
|
+
Outside a KXM project the command refuses `project_required` (exit 1).
|
|
1491
|
+
|
|
1492
|
+
Refusals (exit 1): `project_required`, `supervisor_unreadable`, `supervisor_schema_unsupported`, `supervisor_clock_invalid`, `lane_unit_invalid`, `supervisor_pr_invalid`, `supervisor_ci_invalid`, `supervisor_backoff_invalid`.
|
|
1493
|
+
|
|
1471
1494
|
## `kxm assign`
|
|
1472
1495
|
|
|
1473
1496
|
`kxm assign` is the entry to this repository's developer assignment runner. Each verb spawns `node scripts/assignment-run.mjs <verb> ...` from the project root with that argument list, `stdio: "inherit"`, and the process environment unchanged. The command returns the child's exit code. It does not load a `.env` file, resolve paths, or repeat any runner check. Every validation rule, refusal code, and file the runner writes stays in [`scripts/assignment-run.mjs`](../../scripts/assignment-run.mjs). The loop, the records, and those codes are documented in [Assignment runner](../contributing/assignment-runner.md).
|
package/package.json
CHANGED
|
@@ -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.
|
|
5
|
+
"version": "0.7.171",
|
|
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",
|