@north-light/cli 0.3.437 → 0.3.438

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.
@@ -0,0 +1,58 @@
1
+ # CI runners and the double-run gate
2
+
3
+ Crouter's suite runs on macOS (see the header of `.github/workflows/test.yml`). GitHub-hosted `macos-latest` is billed per minute and a full run is ~50 billed minutes, so the suite can run on a self-hosted Mac instead, and the push to `main` does not re-run it for a tree that already passed.
4
+
5
+ ## Where the macOS jobs run: `CRTR_CI_RUNNER`
6
+
7
+ Repository variable `CRTR_CI_RUNNER` selects `runs-on` for the `build`, `build-output` and `lane` jobs of `test.yml`:
8
+
9
+ | Value | Runs on |
10
+ | --- | --- |
11
+ | unset, or anything other than `self-hosted` | GitHub-hosted `macos-latest` (billed) |
12
+ | `self-hosted` | runners labelled `[self-hosted, macOS, crouter]` (the Mac mini) |
13
+
14
+ ```bash
15
+ gh variable set CRTR_CI_RUNNER --body self-hosted -R Northlight-Systems/crouter # use the mini
16
+ gh variable delete CRTR_CI_RUNNER -R Northlight-Systems/crouter # fall back to macos-latest
17
+ ```
18
+
19
+ It takes effect on the next run; no commit is needed. **If the mini is offline, jobs queue until it returns (they do not fall back by themselves) — delete the variable.** Cancel and re-run anything already queued. The variable also changes the shard matrix: `self-hosted` uses 2 unit + 3 integration + 3 seam shards (8 lane jobs, 3 runner instances), hosted uses 3 + 6 + 6 (15).
20
+
21
+ A pull request from a fork always runs on `macos-latest`, whatever the variable says: a self-hosted runner must never execute fork code. The repository is private and forking is disabled today, so this only guards a later change.
22
+
23
+ ## The Mac mini runners
24
+
25
+ `scripts/ci-runner/install.sh` installs N runner instances (default 3). The mini has 10 cores and 16 GB; a lane job runs up to 8 test files at once, each with a broker and tmux, so three concurrent jobs is the ceiling before the seam lane's timeouts become the failure.
26
+
27
+ Isolation, per instance `~/ci-runners/crouter-N/`:
28
+
29
+ - its own runner directory and `_work` checkout;
30
+ - its own `HOME` (`~/ci-runners/crouter-N/home`), never the account's. The suite refuses to start if `$HOME/.crouter` exists, so the account's own crouter install (`~/.crouter`, the selected runtime, `~/.local/bin/crtr`, any running `crtrd`) is neither read nor written;
31
+ - a minimal `PATH` (Homebrew + system) that does not include the account's crtr or npm globals;
32
+ - `hook-job-started.sh` / `hook-job-completed.sh` (`ACTIONS_RUNNER_HOOK_JOB_*`), which kill every process whose environment or command line points into that instance's directory (brokers, `crtrd`, test tmux servers, orphaned node processes) and wipe `home/.crouter*` and `_temp`. They match only that instance's path, so one instance's cleanup cannot touch another's job or the account's processes.
33
+
34
+ The tests bind unix sockets under per-test temp dirs and tmux servers under the per-test `HOME`, with no fixed TCP ports, so instances do not collide.
35
+
36
+ ### Service
37
+
38
+ Each instance is a boot-time LaunchDaemon (survives reboot and logout, runs as `silasrhyneer`): `ai.northlight.ci-runner.crouter-1` … `-3`.
39
+
40
+ ```bash
41
+ sudo launchctl kickstart -k system/ai.northlight.ci-runner.crouter-1 # restart one
42
+ sudo launchctl print system/ai.northlight.ci-runner.crouter-1 | head # state
43
+ tail -f ~/ci-runners/crouter-1/runner.log # log
44
+ gh api repos/Northlight-Systems/crouter/actions/runners --jq '.runners[]|[.name,.status,.busy]|@tsv'
45
+ ```
46
+
47
+ Installing and upgrading: get a registration token (`gh api -X POST repos/Northlight-Systems/crouter/actions/runners/registration-token --jq .token`), run `RUNNER_TOKEN=… scripts/ci-runner/install.sh 3` on the mini, then run the `sudo launchctl bootstrap` lines it prints. Prerequisites on the mini: `tmux`, `uv`, `git` (Homebrew); Node comes from `actions/setup-node`.
48
+
49
+ ## No double run on `main`
50
+
51
+ `publish.yml` starts with a `gate` job. It reads the pushed commit's **git tree** and looks for a workflow artifact named `tested-tree-<tree>`. `test.yml`'s final `tested` job creates that artifact only after `build`, `build-output` and every `lane` shard pass, on every pull request run and on every run of Publish's own `tests` job.
52
+
53
+ - Rebase-merging a PR whose tested merge ref has the same tree as the resulting `main` commit → artifact found → `tests` is skipped and `publish` proceeds.
54
+ - A direct push to `main`, or a merge after `main` moved (a different tree from the one the PR run tested) → no artifact → the full suite runs exactly as before. A release commit (`chore: release …`, pushed by Publish itself) changes the tree, so a PR not updated since before the latest release runs the suite once on merge; update the branch to avoid it.
55
+ - The gate can only skip; if the lookup errors it runs the suite. `publish` runs only when `tests` passed, or was skipped *because* the gate found a record. A failed or cancelled suite never publishes.
56
+ - Branch protection is not enabled on `main` and the gate does not depend on it: the proof is the tree, not a required check. Artifacts are kept 30 days; older trees are simply re-tested.
57
+
58
+ The OIDC constraint at the top of `publish.yml` is unchanged: every publishing job is still in that file.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@north-light/cli",
3
- "version": "0.3.437",
3
+ "version": "0.3.438",
4
4
  "description": "crtr — agent runtime with memory, plugins, and marketplaces",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -137,7 +137,7 @@
137
137
  },
138
138
  "license": "UNLICENSED",
139
139
  "dependencies": {
140
- "@north-light/identity": "0.3.437",
140
+ "@north-light/identity": "0.3.438",
141
141
  "@earendil-works/pi-agent-core": "1.1.0",
142
142
  "@earendil-works/pi-ai": "1.1.0",
143
143
  "@earendil-works/pi-coding-agent": "1.1.0",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@north-light/identity",
3
- "version": "0.3.437",
3
+ "version": "0.3.438",
4
4
  "description": "Northlight access-token verification and scope rules",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
package/runtime.lock.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@north-light/cli",
3
- "version": "0.3.437",
3
+ "version": "0.3.438",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@north-light/cli",
9
- "version": "0.3.437",
9
+ "version": "0.3.438",
10
10
  "hasInstallScript": true,
11
11
  "license": "UNLICENSED",
12
12
  "workspaces": [
@@ -18,7 +18,7 @@
18
18
  "@earendil-works/pi-ai": "1.1.0",
19
19
  "@earendil-works/pi-coding-agent": "1.1.0",
20
20
  "@earendil-works/pi-tui": "1.1.0",
21
- "@north-light/identity": "0.3.437",
21
+ "@north-light/identity": "0.3.438",
22
22
  "cron-parser": "^5.6.0",
23
23
  "esbuild": "^0.27.7",
24
24
  "jose": "^6.2.12",
@@ -12095,17 +12095,17 @@
12095
12095
  },
12096
12096
  "packages/crouter-api": {
12097
12097
  "name": "@north-light/api",
12098
- "version": "0.3.437",
12098
+ "version": "0.3.438",
12099
12099
  "license": "UNLICENSED"
12100
12100
  },
12101
12101
  "packages/crouter-env-docker": {
12102
12102
  "name": "@north-light/env-docker",
12103
- "version": "0.3.437",
12103
+ "version": "0.3.438",
12104
12104
  "license": "UNLICENSED"
12105
12105
  },
12106
12106
  "packages/crouter-identity": {
12107
12107
  "name": "@north-light/identity",
12108
- "version": "0.3.437",
12108
+ "version": "0.3.438",
12109
12109
  "license": "UNLICENSED",
12110
12110
  "dependencies": {
12111
12111
  "jose": "^6.2.1"
@@ -12113,20 +12113,20 @@
12113
12113
  },
12114
12114
  "packages/crouter-plugin": {
12115
12115
  "name": "@north-light/plugin",
12116
- "version": "0.3.437",
12116
+ "version": "0.3.438",
12117
12117
  "license": "UNLICENSED",
12118
12118
  "dependencies": {
12119
- "@north-light/api": "0.3.437",
12120
- "@north-light/identity": "0.3.437"
12119
+ "@north-light/api": "0.3.438",
12120
+ "@north-light/identity": "0.3.438"
12121
12121
  }
12122
12122
  },
12123
12123
  "packages/crouter-sdk": {
12124
12124
  "name": "@north-light/sdk",
12125
- "version": "0.3.437",
12125
+ "version": "0.3.438",
12126
12126
  "license": "UNLICENSED",
12127
12127
  "dependencies": {
12128
- "@north-light/api": "0.3.437",
12129
- "@north-light/identity": "0.3.437",
12128
+ "@north-light/api": "0.3.438",
12129
+ "@north-light/identity": "0.3.438",
12130
12130
  "jose": "^6.2.1"
12131
12131
  },
12132
12132
  "bin": {