@north-light/cli 0.3.487 → 0.3.488

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.
Files changed (35) hide show
  1. package/dist/api/contract.d.ts +1 -1
  2. package/dist/api/contract.js +1 -1
  3. package/dist/api/index.d.ts +2 -1
  4. package/dist/build-root.js +1 -1
  5. package/dist/builtin-memory/crouter-sdk/release-notes.md +17 -0
  6. package/dist/builtin-memory/crouter-sdk/resources.md +2 -1
  7. package/dist/builtin-memory/northlight-apps/cli.md +20 -6
  8. package/dist/builtin-memory/northlight-apps/coding-agents.md +9 -7
  9. package/dist/builtin-memory/northlight-apps/guides/manage-your-app.md +1 -0
  10. package/dist/builtin-memory/northlight-apps/quickstart.md +5 -3
  11. package/dist/clients/attach/viewer.js +505 -505
  12. package/dist/core/canvas/recovery.d.ts +5 -0
  13. package/dist/core/canvas/recovery.js +2 -2
  14. package/dist/core/command-plugins/endpoint.js +1 -1
  15. package/dist/core/human/page-errors.d.ts +4 -0
  16. package/dist/core/human/page-errors.js +1 -1
  17. package/dist/core/human/page.d.ts +10 -3
  18. package/dist/core/human/page.js +1 -1
  19. package/dist/core/peer/ingest.js +1 -1
  20. package/dist/core/peer/stubs.d.ts +4 -0
  21. package/dist/core/peer/stubs.js +1 -1
  22. package/dist/core/peer/version.d.ts +2 -2
  23. package/dist/core/peer/version.js +1 -1
  24. package/dist/core/runtime/revive.js +2 -2
  25. package/dist/daemon/api/handlers/human-requests.js +1 -1
  26. package/docs/apps/cli.md +20 -6
  27. package/docs/apps/coding-agents.md +9 -7
  28. package/docs/apps/guides/manage-your-app.md +1 -0
  29. package/docs/apps/quickstart.md +5 -3
  30. package/docs/ci-runner.md +2 -1
  31. package/docs/sdk/release-notes.md +17 -0
  32. package/docs/sdk/resources.md +2 -1
  33. package/package.json +3 -3
  34. package/packages/crouter-identity/package.json +1 -1
  35. package/runtime.lock.json +12 -12
@@ -89,7 +89,9 @@ and "Done. Go back to your terminal." in the browser. The name, id and dates are
89
89
 
90
90
  The login is saved outside your project, in `~/.config/northlight/credentials.json` (mode `0600`). Never commit, paste or print it.
91
91
 
92
- Not yet checked on production: this whole step, including the confirm page and its wording (not yet checked on production). The command, its output and its files are checked against a fake directory in the package's tests.
92
+ Checked on production: this whole step, including the confirm page and its wording. The confirm page reads "Let a coding agent manage your Northlight apps?", shows the code, the computer's name and platform and the address it asked from ("The computer named itself; Northlight did not check it"), and lists what the login can and can't do. After **Allow** the page reads "Done / Go back to your terminal." and the terminal prints the output above.
93
+
94
+ If you run `login` again, it does not start over. While a code is pending it prints "Still waiting for the login started at HH:MM." with the same link and code. Once you are logged in it prints "Already logged in as …" and exits 0. If the code expired unapproved it exits 1 and says so: run it again for a new code. See [the CLI reference](/docs/cli#login-logout-whoami).
93
95
 
94
96
  If `login` cannot reach `account.northlight.ai`, or you would rather use the browser, skip to [Register in the browser instead](#register-in-the-browser-instead).
95
97
 
@@ -99,7 +101,7 @@ If `login` cannot reach `account.northlight.ai`, or you would rather use the bro
99
101
  npx @north-light/sdk register --scope sms:send
100
102
  ```
101
103
 
102
- Run it in the folder `init` made. It registers the app with the public key from `local/app-key.json`, the name from `package.json`, the origin from `local/app.env` and the redirect URI `<origin>/auth/callback`, then adds `sms:send` to what the app asks for. A new app starts asking for `crtr:llm` and `crtr:act`. The server in this guide also asks for `sms:send`, so it needs the `--scope`. Take scope strings from `npx @north-light/sdk apps asks` or from `providers.tools`. Do not invent them. See [Scopes and grants](/docs/concepts/scopes-and-grants).
104
+ Run it in the folder `init` made. With no dependencies installed, `npx` downloads the newest published release of the SDK, not the version your `package.json` pins, so run `npm i` first if the pinned version should run. It registers the app with the public key from `local/app-key.json`, the name from `package.json`, the origin from `local/app.env` and the redirect URI `<origin>/auth/callback`, then adds `sms:send` to what the app asks for. A new app starts asking for `crtr:llm` and `crtr:act`. The server in this guide also asks for `sms:send`, so it needs the `--scope`. Take scope strings from `npx @north-light/sdk apps asks` or from `providers.tools`. Do not invent them. See [Scopes and grants](/docs/concepts/scopes-and-grants).
103
105
 
104
106
  You should see:
105
107
 
@@ -116,7 +118,7 @@ Next: npm i && npm start, then open http://localhost:3000/auth/login
116
118
 
117
119
  `local/app.env` now has all four settings. The name, client ID and key ID are examples. Change the defaults with `--name`, `--logo`, `--justification` and `--redirect-uri`; the default logo is a placeholder, `https://sdk.docs.northlight.ai/app-logo.png`. `register` refuses when `CROUTER_CLIENT_ID` is already set. A login can register at most 10 apps a day.
118
120
 
119
- Not yet checked on production: this step, including that the directory accepts the default logo (not yet checked on production). Its output and its effect on `local/app.env` are checked against a fake directory in the package's tests.
121
+ Checked on production: this step, including that the directory accepts the default logo.
120
122
 
121
123
  ## 5. Run it
122
124
 
package/docs/ci-runner.md CHANGED
@@ -108,7 +108,7 @@ The hourly `17 * * * *` schedule and the `promote`, `api_ref`, `env_docker_ref`
108
108
 
109
109
  | Event | ubuntu `checks` + `select` | ubuntu `linux` (container) | `macos` (laptop-only tests) |
110
110
  | --- | --- | --- | --- |
111
- | pull request push | yes | the selected files, sharded to ~4 min; none for a docs-only change | the selected files that carry `laptopOnly` tags, if any |
111
+ | pull request push | yes | the selected files (narrowed by Preflight's pick when there is one), sharded to ~4 min; none for a docs-only change | the selected files that carry `laptopOnly` tags, if any |
112
112
  | pull request with the `full-ci` label, or a change whose path forces it | yes | all of it | all of it |
113
113
  | merge queue run (`merge_group`; inert until a queue ruleset exists) | yes | all of it | all of it |
114
114
  | `workflow_dispatch` (`gh workflow run test.yml --ref <branch>`) | yes | all of it | all of it |
@@ -129,4 +129,5 @@ On a pull request push the selector turns the diff against the merge base into p
129
129
  - **Path rules** are in `classify()`; anything not named there under `src/` or `packages/` that is not TypeScript, and any unrecognized path, forces `full`. A no-test rule never beats evidence that a test reads the path: a file in some test's or the CLI's import graph selects the tests that reach it even under `scripts/` (e.g. `scripts/proof/stub-provider/*.ts`, reached through the plugin test fixture); a script whose path or file name a test mentions forces `full`; and a `bin/**` shim selects the CLI closure and its spawners plus every test that names the shim (`spawn-env.test.ts` runs `./bin/runtime-generation-manifest.mjs`).
130
130
  - **Shard sizing** uses `scripts/ci-select/timing.json`: per-file local work in seconds from one measured local run, times a per-lane factor that scales it to the Linux test-step totals, targeting 240 s per shard. A committed table, not a runtime measurement, because it must exist before the first selected run and cannot come from a run that is being skipped; a file missing from the table (a new test) costs its lane's median, which only skews shard balance. Selection never reads it.
131
131
  - `node scripts/ci-select.mjs --replay scripts/ci-select/replay-prs.json` replays the 44 merged PRs #1–#65 through the selector as shipped, path rules included: this is the projection to quote. Over those PRs it runs a Linux lane on 34/44 (full suite: 44/44), at 26.0 billed ubuntu minutes per PR (full suite 39), 3.0 macOS-equivalent cost including the 4 minutes of `checks` (full suite 4.3), 564 s of laptop-only local work on the minis (759), 9.6 hosted-fallback macOS minutes (13); 8 PRs are docs-only and select no lane.
132
+ - **Preflight's test pick can narrow a selected run.** Preflight's triage run (the `tests` block of `.github/preflight.yml`) publishes the check run `Preflight test pick` on the PR head commit, written by Preflight's GitHub App (app id 5351829, so a workflow cannot forge it). After selecting, and only on a `pull_request` in mode `selected` (no `full-ci` or `no-test-pick` label, not a fork), `ci-select.mjs` polls that check run for `github.event.pull_request.head.sha` (not the merge ref) with the job's `GITHUB_TOKEN` (the repo's default token permissions are the restricted set without `checks`, which answers HTTP 403, so the `select` job declares `contents: read` and `checks: read`, and publish.yml's `tests` job grants `checks: read` too because a called workflow cannot exceed its caller). It waits at most 120 s for a completed pick, gives up after 45 s when no such check run exists, and stops at once on `outcome: none`. A valid pick keeps `(selected ∩ pick) ∪ (selected test files the PR changed)`, re-plans the shards from them, and gives mode `none` when nothing is left. It never adds a file and never touches `checks`. Any HTTP error, bad JSON, unknown schema, wrong head SHA or timeout keeps the script's set, and the log says so (e.g. `no Preflight test pick for <sha> after 45 s; using the script's set`). Mode `full` stays `full`, a narrowed run stays `selected` (so it never records a tested tree and the release `gate` still needs a full-suite record), and merge_group, push, schedule, dispatch and Publish's call never consult it. Opt a PR out with `gh pr edit <n> --add-label no-test-pick`. Evidence: the `select` step summary opens with `Preflight test pick: used|not used`, and `selection.json` (artifact `selection`) has a `pick` object with `used`, `why`, `before` and `after` file counts per lane (linux and macOS), `billed` estimated minutes before and after, and `dropped`, the files the pick removed. The logic and its tests are `scripts/ci-test-pick-lib.mjs` and `scripts/ci-test-pick.test.mjs` (in `test:contract`).
132
133
  - `--static-only` is a **counterfactual**, not the selector: it drops every path rule, so a workflow, manifest, helper or unrecognized path selects nothing instead of `full`. It exists only to compare with the design's replay figures, which used the import-graph-plus-spawner model alone (30/44 PRs, 21.9 ubuntu minutes). Do not read its numbers as what the selector does.
@@ -7,6 +7,23 @@ description: Behavior changes in @north-light/sdk that an app must act on, newes
7
7
 
8
8
  Changes to `@north-light/sdk` that can change what an existing app sees. Newest first.
9
9
 
10
+ ## 0.3.488
11
+
12
+ ### Developer CLI: `--help` exits 0, `login` is safe to re-run (CLI only, no app change)
13
+
14
+ - `npx @north-light/sdk <command> --help` and `-h` print the command's usage and exit 0 for every command. A bad flag still exits 1.
15
+ - `login` run again while this computer is logged in prints `Already logged in as …` and exits 0 instead of starting a second login (`--new` still does). A failed poll (a dropped connection, a sleeping laptop) is retried for up to 3 minutes; if the directory is still unreachable, `login` exits 1 and says the code is still saved and to run `login` again. It no longer ends on the first failed poll with a console fallback message.
16
+ - `init` writes `"allowScripts": {"esbuild": false}` into a new app's `package.json`, so npm 11.20+ no longer warns that esbuild's postinstall script is not allowed.
17
+ - `apps set-logo --file <path>` uploads a logo image (PNG, JPEG, WebP or SVG, square, at least 256x256, at most 512 KB) and `apps set-brand-color --color <#rrggbb or none>` sets or clears the brand colour. Both work on testing and verified apps. The directory side must be live first: until it is, they answer with the directory's refusal.
18
+ - `apps set-listing`, `set-spend-cap` and `set-allows` refuse with the same plain wording as the docs. They still make no request.
19
+
20
+ ### `docs`: an app writes, reads and edits documents it owns (additive, no app change)
21
+
22
+ - `docs.write({name, body, preview, kind?, rules?, privacy?, summary?})` creates a document owned by your app and returns its canonical `name` (`<app>/<name>`). `kind: 'preference'` with `rules: [{on: 'boot', deliver: 'content'}]` puts the body into the context of every node at boot. A name already taken throws `ConflictError` (`name_taken`).
23
+ - `docs.get(name)` returns `{body, revision, base, rules, kind, owner, needsMerge, …}`; no such document throws `NotFoundError`.
24
+ - `docs.edit(name, {body | replace, rationale, base?, …})` changes it in place and returns the new `revision`. Pass the `base` from `docs.get`; a base that is no longer current throws `ConflictError` (`stale_revision`) and writes nothing.
25
+ - Served on the app listener, so `oauth.client(userId)` offers it. An app can write only as itself (`owner: 'app'`, the default), and needs no scope for documents it owns.
26
+
10
27
  ## 0.3.487
11
28
 
12
29
  ### Run notices and the app listener verify one call-token shape (additive, no app change)
@@ -28,6 +28,7 @@ Every namespace exported by the client. Namespaces are camelCase. Verbs are `cre
28
28
  | `models.config` | `update` | `PUT /v1/model-config` |
29
29
  | `customObjects` | `register`, `publish`, `unregister`, `ack`, `receive` | `/v1/custom-objects…` |
30
30
  | `memory` | `list`, `listAll`, `get` | `GET /v1/memory`, `GET /v1/memory/document` |
31
+ | `docs` | `write`, `edit`, `get` | `POST /v1/docs`, `PATCH /v1/docs/:ref`, `GET /v1/objects/:ref?fields=1` |
31
32
  | `runs` | `start`, `get`, `list`, `listAll`, `message`, `interrupt`, `cancel`, `delete`, `rename`, `trace`, `events`, `reply`, `stream`, `wait`, `parse` | `/v1/runs…` |
32
33
  | `uploads` | `create` | `POST /v1/uploads` |
33
34
  | `attachments` | `link` | `GET /v1/attachments/link` |
@@ -37,7 +38,7 @@ Every namespace exported by the client. Namespaces are camelCase. Verbs are `cre
37
38
  | `grant` | `get` (`wait`, `since`: hold until `version` changes) | `GET /v1/grant` |
38
39
  | `health` | `get` | `GET /v1/health` |
39
40
 
40
- `runs`, `uploads`, `attachments`, `shares`, `questions` and the app side of `grant` and `providers` are the application-facing API an app reaches through the app listener; `oauth.client(userId)` returns a client typed to exactly that set (`AppClient`); `nodes`, `bash`, `canvas`, `crons`, `human`, `models`, `customObjects`, `structuredRequests`, `system`, `auth`, `files.read/write/list` and `profiles.ensure/retrieve` are the owner's own daemon and are not served to an app. An app schedules work with its own timer calling `runs.start`, or a run's agent runs `crtr cron add` under `crtr:schedule`. See [Apps on Northlight](./guides/apps-on-northlight.md) and [Apps with many users](./guides/apps-with-many-users.md). `memory` is the person's `public` documents ([Memory](./memory.md)). `system.health` (`/healthz`) is the daemon's liveness check; `health.get` is the app listener's.
41
+ `runs`, `uploads`, `attachments`, `shares`, `questions`, `docs` and the app side of `grant` and `providers` are the application-facing API an app reaches through the app listener; `oauth.client(userId)` returns a client typed to exactly that set (`AppClient`); `nodes`, `bash`, `canvas`, `crons`, `human`, `models`, `customObjects`, `structuredRequests`, `system`, `auth`, `files.read/write/list` and `profiles.ensure/retrieve` are the owner's own daemon and are not served to an app. An app schedules work with its own timer calling `runs.start`, or a run's agent runs `crtr cron add` under `crtr:schedule`. See [Apps on Northlight](./guides/apps-on-northlight.md) and [Apps with many users](./guides/apps-with-many-users.md). `memory` is the person's `public` documents ([Memory](./memory.md)). `docs` writes, reads and edits documents the calling app owns: `docs.write({name, body, preview, kind?, rules?})` returns the canonical `name`; `docs.get(name)` returns `body`, `revision`, `rules` and the edit `base`; `docs.edit(name, {body, rationale, base?})` changes it in place and refuses a stale `base` with `ConflictError` (`stale_revision`). To keep one document current, `get` it (catch `NotFoundError` on first run to `write`), compare `body` to your text, and `edit` only when they differ. `system.health` (`/healthz`) is the daemon's liveness check; `health.get` is the app listener's.
41
42
 
42
43
  Action methods keep the product's literal name (`fork`, `revive`, `promote`, `yield`) rather than being renamed into a generic verb. Every request-capable method takes `RequestOptions` as its final argument after its path, body, or query arguments. `RequestOptions` is `{ headers?, signal?, timeout?, maxRetries? }`; stream event options exclude `timeout` and add `after`.
43
44
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@north-light/cli",
3
- "version": "0.3.487",
3
+ "version": "0.3.488",
4
4
  "description": "crtr — agent runtime with memory, plugins, and marketplaces",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -99,7 +99,7 @@
99
99
  "test:runtime-packaging": "node --test scripts/runtime-smoke.test.mjs scripts/pack-args.test.mjs scripts/ensure-native-linux.test.mjs scripts/release-version.test.mjs",
100
100
  "contract:check": "node scripts/contract.mjs check",
101
101
  "contract:surface": "node scripts/contract.mjs generate",
102
- "test:contract": "node --conditions=crtr-src --import tsx/esm --test scripts/contract.test.mjs scripts/promote-sdk.test.mjs scripts/release-version.test.mjs scripts/sdk-docs-commands.test.mjs scripts/ci-image.test.mjs scripts/ci-miss-triage.test.mjs",
102
+ "test:contract": "node --conditions=crtr-src --import tsx/esm --test scripts/contract.test.mjs scripts/promote-sdk.test.mjs scripts/release-version.test.mjs scripts/sdk-docs-commands.test.mjs scripts/ci-image.test.mjs scripts/ci-miss-triage.test.mjs scripts/ci-test-pick.test.mjs",
103
103
  "test:build-output": "node scripts/build-concurrency-test.mjs",
104
104
  "check:cli-no-canvas": "node scripts/check-cli-no-canvas.mjs",
105
105
  "check:cli-cold-start": "node scripts/check-cli-cold-start.mjs",
@@ -137,7 +137,7 @@
137
137
  },
138
138
  "license": "UNLICENSED",
139
139
  "dependencies": {
140
- "@north-light/identity": "0.3.487",
140
+ "@north-light/identity": "0.3.488",
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.487",
3
+ "version": "0.3.488",
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.487",
3
+ "version": "0.3.488",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@north-light/cli",
9
- "version": "0.3.487",
9
+ "version": "0.3.488",
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.487",
21
+ "@north-light/identity": "0.3.488",
22
22
  "cron-parser": "^5.6.0",
23
23
  "esbuild": "^0.27.7",
24
24
  "jose": "^6.2.12",
@@ -12116,17 +12116,17 @@
12116
12116
  },
12117
12117
  "packages/crouter-api": {
12118
12118
  "name": "@north-light/api",
12119
- "version": "0.3.487",
12119
+ "version": "0.3.488",
12120
12120
  "license": "UNLICENSED"
12121
12121
  },
12122
12122
  "packages/crouter-env-docker": {
12123
12123
  "name": "@north-light/env-docker",
12124
- "version": "0.3.487",
12124
+ "version": "0.3.488",
12125
12125
  "license": "UNLICENSED"
12126
12126
  },
12127
12127
  "packages/crouter-identity": {
12128
12128
  "name": "@north-light/identity",
12129
- "version": "0.3.487",
12129
+ "version": "0.3.488",
12130
12130
  "license": "UNLICENSED",
12131
12131
  "dependencies": {
12132
12132
  "jose": "^6.2.1"
@@ -12134,20 +12134,20 @@
12134
12134
  },
12135
12135
  "packages/crouter-plugin": {
12136
12136
  "name": "@north-light/plugin",
12137
- "version": "0.3.487",
12137
+ "version": "0.3.488",
12138
12138
  "license": "UNLICENSED",
12139
12139
  "dependencies": {
12140
- "@north-light/api": "0.3.487",
12141
- "@north-light/identity": "0.3.487"
12140
+ "@north-light/api": "0.3.488",
12141
+ "@north-light/identity": "0.3.488"
12142
12142
  }
12143
12143
  },
12144
12144
  "packages/crouter-sdk": {
12145
12145
  "name": "@north-light/sdk",
12146
- "version": "0.3.487",
12146
+ "version": "0.3.488",
12147
12147
  "license": "UNLICENSED",
12148
12148
  "dependencies": {
12149
- "@north-light/api": "0.3.487",
12150
- "@north-light/identity": "0.3.487",
12149
+ "@north-light/api": "0.3.488",
12150
+ "@north-light/identity": "0.3.488",
12151
12151
  "jose": "^6.2.1"
12152
12152
  },
12153
12153
  "bin": {