@apex-actions/cli 0.95.2 → 0.97.0

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/README.md +13 -13
  2. package/THIRD-PARTY-NOTICES.md +3 -3
  3. package/dist/cli/environment/main.js +1 -1
  4. package/dist/cli/grant/main.js +1 -1
  5. package/dist/cli/login/device.js +1 -1
  6. package/dist/cli/login/main.js +6 -6
  7. package/dist/cli/logout/main.js +2 -2
  8. package/dist/cli/migrate/main.js +1 -1
  9. package/dist/cli/notify/main.js +1 -1
  10. package/dist/cli/reference.js +6 -6
  11. package/dist/cli/secret/shared.js +1 -1
  12. package/dist/cli/tenant/main.js +4 -4
  13. package/dist/cli/token/main.js +3 -3
  14. package/dist/cli/whoami/main.js +1 -1
  15. package/dist/src/application/authenticate.js +3 -3
  16. package/dist/src/application/manage-departures.js +1 -1
  17. package/dist/src/application/manage-secrets.js +1 -1
  18. package/dist/src/application/manage-terms.js +1 -1
  19. package/dist/src/domain/accounts.js +1 -1
  20. package/dist/src/domain/credentials.js +7 -7
  21. package/dist/src/domain/fleet-history.js +1 -1
  22. package/dist/src/domain/grants.js +2 -2
  23. package/dist/src/domain/insight.js +1 -1
  24. package/dist/src/domain/logsearch.js +1 -1
  25. package/dist/src/domain/notify.js +4 -4
  26. package/dist/src/domain/provenance.js +1 -1
  27. package/dist/src/domain/runs.js +1 -1
  28. package/dist/src/domain/spend.js +1 -1
  29. package/dist/src/domain/supplychain.js +1 -1
  30. package/dist/src/infrastructure/binary-install.js +1 -1
  31. package/dist/src/infrastructure/control-plane-http.js +20 -20
  32. package/dist/src/infrastructure/credentials.js +4 -4
  33. package/dist/src/infrastructure/device-login.js +1 -1
  34. package/dist/src/infrastructure/loopback-login.js +1 -1
  35. package/package.json +3 -7
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  `apex` developer and operator CLI (TypeScript, commander).
4
4
 
5
- Part of the [Apex Actions](../) superproject. Conventions, architecture, and agent context live in the `context` repository.
5
+ A workspace of the [Apex Actions](../../README.md) repository. What it is inside: [`docs/architecture/components/cli.md`](../../docs/architecture/components/cli.md); the conventions: [`docs/conventions/`](../../docs/conventions/README.md).
6
6
 
7
7
  ## Commands
8
8
 
@@ -20,12 +20,12 @@ Part of the [Apex Actions](../) superproject. Conventions, architecture, and age
20
20
  | `apex secret` · `apex variable` | the control-plane REST API | a customer token with `secrets:*` / `variables:*` (`APEX_TOKEN` or `apex login`) |
21
21
  | `apex login --console` · `logout --console` | the Admin Console in the browser, and the control-plane REST API | an operator signed in to the Admin Console, who approves it |
22
22
  | `apex grant list` · `apex tenant installations` | the control-plane admin API | the operator token (`apex login --console`), or the machine token |
23
- | `apex grant create` · `update` · `revoke` | the control-plane admin API | the operator token (`apex login --console`) — never the machine token (control-plane ADR-0056, ADR-0079) |
23
+ | `apex grant create` · `update` · `revoke` | the control-plane admin API | the operator token (`apex login --console`) — never the machine token (`api` ADR-0056, `api` ADR-0079) |
24
24
 
25
25
  Every other customer command in `cli/reference.ts` names the permission it needs; the public reference shows it.
26
26
 
27
- Generated reference: `docs/feature-docs/cli-commands.md` (`pnpm docs:cli` from `packages/release`), and
28
- the structured one the public site renders, `docs/feature-docs/cli-reference.json` (`pnpm docs:reference`;
27
+ Generated reference: `docs/features/cli-commands.md` (`pnpm docs:cli` from `packages/tooling`), and
28
+ the structured one the public site renders, `apps/cli/cli-reference.json` (`pnpm docs:reference`;
29
29
  customer commands only, classified in `cli/reference.ts`).
30
30
 
31
31
  ```bash
@@ -38,7 +38,7 @@ apex logs '#42' --job test # one job, clean enough to pipe
38
38
  ```
39
39
 
40
40
  `apex migrate scan` answers "will my workflows run" before anything has moved. Every verdict comes
41
- out of the engine's conformance corpus with the fixture that proves it (ADR-0002, engine ADR-0013) —
41
+ out of the engine's conformance corpus with the fixture that proves it (`cli` ADR-0002, `engine` ADR-0013) —
42
42
  nothing here holds a second opinion about compatibility. It imports secret and variable **names** and
43
43
  never values, and `--path` scans a checkout on this machine with no token and no network:
44
44
 
@@ -49,8 +49,8 @@ apex migrate scan acme --repo acme/api --json # one repository of an organizat
49
49
 
50
50
  ### Credentials
51
51
 
52
- The CLI resolves one credential, in this order (control-plane ADR-0064, amended by
53
- [ADR-0005](docs/adr/0005-an-exported-token-outranks-a-saved-login.md)) — **the environment outranks
52
+ The CLI resolves one credential, in this order (`api` ADR-0064, amended by
53
+ [ADR-0005](../../docs/adrs/cli/0005-an-exported-token-outranks-a-saved-login.md)) — **the environment outranks
54
54
  the file**:
55
55
 
56
56
  1. `APEX_TOKEN` — a token minted on the dashboard (`/settings/tokens`), for CI and scripts;
@@ -66,7 +66,7 @@ the file**:
66
66
  **Operator commands** — `apex grant` and `apex tenant installations` — look first for the **operator
67
67
  token** `apex login --console` saved in `$XDG_CONFIG_HOME/apex/console-credentials` (same mode rules), when
68
68
  it is unexpired and was minted by the control plane `APEX_API_URL` names, and otherwise use the order above
69
- (control-plane ADR-0079). The operator token is approved on the Admin Console (`APEX_CONSOLE_URL`, or the
69
+ (`api` ADR-0079). The operator token is approved on the Admin Console (`APEX_CONSOLE_URL`, or the
70
70
  API's `app.` host read as `admin.`) by an operator, by loopback only; it lives a week at most and reaches
71
71
  only the grant routes and the installation list, and every grant it writes names its operator. The machine
72
72
  token can list grants and is refused every write. `apex logout --console` revokes and forgets it.
@@ -75,7 +75,7 @@ token can list grants and is refused every write. `apex logout --console` revoke
75
75
  only ever sent to the control plane that issued it. `apex login` opens the consent page on the web
76
76
  app — `APEX_WEB_URL`, or the API's origin — and listens on `127.0.0.1` for the loopback callback
77
77
  (RFC 8252, PKCE); once the code is redeemed it hands the tab back to the web app's bare `/cli/done`
78
- page (control-plane ADR-0075). Where no browser can open on this machine — an SSH session
78
+ page (`api` ADR-0075). Where no browser can open on this machine — an SSH session
79
79
  (`SSH_CONNECTION`/`SSH_TTY`), a Codespace, a dev container, `/.dockerenv`, or Linux with neither `DISPLAY`
80
80
  nor `WAYLAND_DISPLAY` — or with `--device` (or `--no-browser`), it uses the **device flow** instead (RFC 8628,
81
81
  run by Apex): it prints a code and `…/cli/device`, the person enters the code on any device, a phone included,
@@ -83,7 +83,7 @@ and the CLI polls — honouring `interval` and `slow_down` — until the approva
83
83
  minutes end. `--browser` insists on the loopback. `apex token create` and a widening `apex token edit` take
84
84
  the same three flags. A customer token carries **permissions** (`resource:read|write`, write implying
85
85
  read; resources `actions`, `approvals`, `deployments`, `secrets`, `variables`, `environments`, `notifications`,
86
- `administration`) and belongs to **one Account** (control-plane ADR-0071). It reaches the repository routes its
86
+ `administration`) and belongs to **one Account** (`api` ADR-0071). It reaches the repository routes its
87
87
  grants cover, within its person's role and the Account owner's token policy; `apex login` takes the policy's
88
88
  defaults for the person's role (the Owner's: everything), in the Account `--account` names when there is more than
89
89
  one. A route it lacks the grant for answers 403 `this token needs <permission>`, which the CLI completes with the
@@ -103,7 +103,7 @@ apex secret list --repo acme/api --json # names only
103
103
  ```
104
104
 
105
105
  A pipeline gets its own token. It is approved in the browser like a login, printed once to stdout,
106
- and never saved (control-plane ADR-0064: a token never mints a token):
106
+ and never saved (`api` ADR-0064: a token never mints a token):
107
107
 
108
108
  ```bash
109
109
  apex token create ci-deploy --permission actions:write --permission secrets:write \
@@ -124,8 +124,8 @@ refused · 2 usage or configuration · 3 not found on `delete`.
124
124
  - `src/domain/` — pure decisions: run and job selection, input parsing, exit codes
125
125
  - `src/application/` — use cases over ports
126
126
  - `src/infrastructure/` — adapters: the engine and runner binaries, the REST API
127
- - `docs/` — general docs (`*.md`), `adr/`, `feature-docs/`, `run-book/`
128
- - `VERSION` — lockstep version, managed by the `release` library; do not edit by hand
127
+ - Documentation is the root's: decisions in `docs/adrs/cli/`, the rest by category in `docs/` (TASK-0526)
128
+ - `VERSION` — the release version, which `version:sync` writes from the root (ADR-0048); never edited by hand
129
129
 
130
130
  ## Licence
131
131
 
@@ -1,6 +1,6 @@
1
1
  # Third-party notices
2
2
 
3
- **Generated — do not edit.** `pnpm notices` from `packages/release`, for `cli`.
3
+ **Generated — do not edit.** `pnpm notices` from `packages/tooling`, for `cli`.
4
4
 
5
5
  Production npm dependencies, as resolved by pnpm. 40 packages: 0BSD, Apache-2.0, ISC, MIT.
6
6
 
@@ -489,7 +489,7 @@ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
489
489
  OTHER DEALINGS IN THE SOFTWARE.
490
490
  ```
491
491
 
492
- ## @types/node 24.13.3
492
+ ## @types/node 24.19.2
493
493
 
494
494
  - License: MIT
495
495
  - Homepage: https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/node
@@ -1162,7 +1162,7 @@ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
1162
1162
  PERFORMANCE OF THIS SOFTWARE.
1163
1163
  ```
1164
1164
 
1165
- ## undici-types 7.18.2
1165
+ ## undici-types 7.24.6
1166
1166
 
1167
1167
  - License: MIT
1168
1168
  - Homepage: https://undici.nodejs.org
@@ -127,7 +127,7 @@ const deleteCommand = new Command('delete')
127
127
  return;
128
128
  case 'deleted':
129
129
  // Anything already waiting stays waiting: it was gated by rules that
130
- // existed when it was gated (control-plane ADR-0018).
130
+ // existed when it was gated (api ADR-0018).
131
131
  console.log(`${chalk.green('✔')} ${name} is no longer protected`);
132
132
  console.log(chalk.dim('Deployments already waiting stay waiting; approve or reject them.'));
133
133
  }
@@ -4,7 +4,7 @@ import { createGrant, listGrants, revokeGrant, updateGrant } from '../../src/app
4
4
  import { createGrantBody, createdLine, grantLine, revokedLine, updateGrantBody } from '../../src/domain/grants.js';
5
5
  import { HttpControlPlane, NotConfiguredError } from '../../src/infrastructure/control-plane-http.js';
6
6
  /**
7
- * `apex grant`: complimentary access from the terminal (control-plane ADR-0056 as amended by ADR-0079,
7
+ * `apex grant`: complimentary access from the terminal (api ADR-0056 as amended by api ADR-0079,
8
8
  * TASK-0199). The admin API's own shapes, unchanged. Every write needs a person: the operator token
9
9
  * `apex login --console` saved, whose operator the grant row and the audit log name. The machine token
10
10
  * (`APEX_ADMIN_TOKEN`) can list and is refused every write, so a leaked one cannot make a free tenant.
@@ -3,7 +3,7 @@ import { chooseFlow, deviceInstructions } from '../../src/domain/credentials.js'
3
3
  import { HttpDeviceExchange, detectHeadless, machineReport, sleep } from '../../src/infrastructure/device-login.js';
4
4
  /**
5
5
  * How `apex login`, `apex token create` and a widening `apex token edit` get their approval back
6
- * (control-plane ADR-0075): the loopback redirect where a browser opens on this machine, a device code
6
+ * (api ADR-0075): the loopback redirect where a browser opens on this machine, a device code
7
7
  * typed on any device where one cannot. One set of flags for the three commands.
8
8
  */
9
9
  export const withFlowOptions = (command) => command
@@ -8,20 +8,20 @@ import { HttpLoginExchange, listenForCallback, newPkcePair, openInBrowser } from
8
8
  import { approvalFlow, withFlowOptions } from './device.js';
9
9
  /**
10
10
  * `apex login`: sign the CLI in with the browser a person already uses
11
- * (control-plane ADR-0064, RFC 8252 + PKCE). The token it mints is the same
11
+ * (api ADR-0064, RFC 8252 + PKCE). The token it mints is the same
12
12
  * one the dashboard mints, saved `0600` for this user alone.
13
13
  *
14
14
  * It opens a browser only because it was asked to — this command is the
15
15
  * asking — and prints the URL either way. Where no browser can open on this
16
16
  * machine (SSH, a container, a Codespace, a Linux box with no display), or
17
17
  * with `--device`, it prints a code to enter on any device instead
18
- * (control-plane ADR-0075); `--browser` insists on the browser here.
18
+ * (api ADR-0075); `--browser` insists on the browser here.
19
19
  *
20
20
  * The token carries the Account token policy's defaults for the person's role
21
21
  * there (the Owner's: everything), and belongs to that one Account — named with
22
- * `--account` when the person is in more than one (control-plane ADR-0071).
22
+ * `--account` when the person is in more than one (api ADR-0071).
23
23
  *
24
- * `--console` is the operator's sign-in (control-plane ADR-0079): approved on the
24
+ * `--console` is the operator's sign-in (api ADR-0079): approved on the
25
25
  * Admin Console by an operator, it saves an **operator token** beside the Account
26
26
  * login — a week at most, reaching only complimentary access (`apex grant`).
27
27
  */
@@ -77,7 +77,7 @@ export default withFlowOptions(new Command('login')
77
77
  console.log(` permissions: ${describeGrants(outcome.permissions)}${outcome.accountId === undefined ? '' : ` · Account ${outcome.accountId}`}`);
78
78
  }
79
79
  console.log(chalk.dim(`Saved to ${outcome.location}. Revoke it any time at ${webBase}${TOKENS_PAGE}.`));
80
- // The environment outranks the saved login (ADR-0005): say so, or the login looks like it did nothing.
80
+ // The environment outranks the saved login (cli ADR-0005): say so, or the login looks like it did nothing.
81
81
  for (const name of [TOKEN_ENV, ADMIN_TOKEN_ENV]) {
82
82
  if (process.env[name])
83
83
  console.log(chalk.yellow(`${name} is set in this shell and is used before the saved login; unset it to use the login.`));
@@ -107,7 +107,7 @@ const reportFailure = (outcome, command) => {
107
107
  }
108
108
  };
109
109
  /**
110
- * `apex login --console` (control-plane ADR-0079): the loopback approval on the Admin Console, saving the
110
+ * `apex login --console` (api ADR-0079): the loopback approval on the Admin Console, saving the
111
111
  * operator token to its own file. No device flow — `--device` is refused rather than silently ignored.
112
112
  */
113
113
  const consoleSignIn = async (opts) => {
@@ -9,12 +9,12 @@ import { ADMIN_TOKEN_ENV, CONSOLE_URL_ENV, FileCredentialStore, TOKEN_ENV, WEB_U
9
9
  *
10
10
  * The token is revoked at the control plane that minted it — never at whatever
11
11
  * `APEX_API_URL` says now — with `DELETE /api/v1/me/token`, the one thing a
12
- * token may do to itself (control-plane ADR-0064). The file goes whether or not
12
+ * token may do to itself (api ADR-0064). The file goes whether or not
13
13
  * the server could be reached; when it could not, the command says the token
14
14
  * may still be valid and where to revoke it, rather than implying it is dead.
15
15
  *
16
16
  * `--console` does the same to the operator token `apex login --console` saved
17
- * (control-plane ADR-0079), which may revoke itself and nothing else.
17
+ * (api ADR-0079), which may revoke itself and nothing else.
18
18
  */
19
19
  export default new Command('logout')
20
20
  .description('Revoke the token `apex login` saved, and forget it')
@@ -194,7 +194,7 @@ const ScanCommand = new Command('scan')
194
194
  * coexistence **on** first — from that moment Apex plans nothing here — then add
195
195
  * workflows as you gain confidence in them. Doing it the other way round leaves
196
196
  * a window in which everything runs on both, which is how a publishing workflow
197
- * nearly pushed the same images twice (control-plane ADR-0046).
197
+ * nearly pushed the same images twice (api ADR-0046).
198
198
  */
199
199
  const CoexistCommand = new Command('coexist')
200
200
  .description('Run Apex beside GitHub Actions on one repository, opting workflows in one at a time')
@@ -42,7 +42,7 @@ const printDelivery = (d) => {
42
42
  const status = `${d.status}${d.httpStatus === undefined ? '' : ` ${String(d.httpStatus)}`}`;
43
43
  console.log(` ${chalk.dim(d.createdAt)} ${d.ruleName.padEnd(18)} ${d.trigger.padEnd(10)} ${colour(status.padEnd(12))} ${d.attempts > 1 ? chalk.dim(`${String(d.attempts)} attempts`) : ''}`);
44
44
  // Somebody else's server's words, so they are printed as data and never
45
- // interpreted (control-plane ADR-0029).
45
+ // interpreted (api ADR-0029).
46
46
  if (d.detail !== undefined && d.detail !== '')
47
47
  console.log(chalk.dim(` ${d.detail}`));
48
48
  };
@@ -3,7 +3,7 @@
3
3
  * sits in, who it is for, and a few examples a person can copy.
4
4
  *
5
5
  * `test/cli-reference.test.ts` walks `buildProgram` and writes
6
- * `docs/feature-docs/cli-reference.json` from the tree plus this table; the
6
+ * `apps/cli/cli-reference.json` from the tree plus this table; the
7
7
  * marketing site renders that file. A top-level command missing from here
8
8
  * fails the test, so nothing reaches the site — or escapes it — unclassified.
9
9
  *
@@ -11,7 +11,7 @@
11
11
  * for.** A customer's credential is an API token carrying the permissions its
12
12
  * person chose (`resource:read|write`, write implying read), within one
13
13
  * Account, their role there and the Account's token policy (control-plane
14
- * ADR-0071). A token reaches the control plane's repository routes its grants
14
+ * api ADR-0071). A token reaches the control plane's repository routes its grants
15
15
  * cover, plus its own identity and tokens; every other route — the fleet, the
16
16
  * operator's organisation, tenants, billing — answers it 403. So a command is
17
17
  * `customer` exactly when every route it calls is a repository or self route in
@@ -49,7 +49,7 @@ export const REFERENCE = {
49
49
  },
50
50
  { command: 'apex login --browser', description: 'Open a browser on this machine even where the CLI would choose a code.' },
51
51
  ],
52
- // The operator's sign-in, approved on the Admin Console (control-plane ADR-0079).
52
+ // The operator's sign-in, approved on the Admin Console (api ADR-0079).
53
53
  operatorOptions: ['--console'],
54
54
  },
55
55
  logout: {
@@ -126,7 +126,7 @@ export const REFERENCE = {
126
126
  secret: {
127
127
  group: 'config',
128
128
  audience: 'customer',
129
- // `--org <organization>` asks for organization:read|write in that Organization instead (control-plane ADR-0084).
129
+ // `--org <organization>` asks for organization:read|write in that Organization instead (api ADR-0084).
130
130
  subcommandPermissions: { list: 'secrets:read', set: 'secrets:write', delete: 'secrets:write' },
131
131
  examples: [
132
132
  { command: 'printf %s "$NPM_TOKEN" | apex secret set NPM_TOKEN --repo acme/web', description: 'Set a secret from a pipe; a value never goes on the command line.' },
@@ -266,7 +266,7 @@ export const REFERENCE = {
266
266
  actions: {
267
267
  group: 'config',
268
268
  audience: 'customer',
269
- // An organisation's action policy asks for organization:* in that Organization (control-plane ADR-0084, TASK-0279).
269
+ // An organisation's action policy asks for organization:* in that Organization (api ADR-0084, TASK-0279).
270
270
  subcommandPermissions: { list: 'actions:read', pin: 'administration:write', policy: 'organization:read' },
271
271
  examples: [
272
272
  { command: 'apex actions list acme/web', description: 'Every action a repository pulls in, least fixed first.' },
@@ -312,6 +312,6 @@ export const REFERENCE = {
312
312
  runner: { group: 'runners', audience: OPERATOR },
313
313
  terms: { group: 'billing', audience: OPERATOR },
314
314
  tenant: { group: 'billing', audience: OPERATOR },
315
- // Complimentary access: the operator token `apex login --console` saves writes; no Account token reaches it (control-plane ADR-0079).
315
+ // Complimentary access: the operator token `apex login --console` saves writes; no Account token reaches it (api ADR-0079).
316
316
  grant: { group: 'billing', audience: OPERATOR },
317
317
  };
@@ -6,7 +6,7 @@ import { nameProblem, reachFrom, secretAppFrom } from '../../src/domain/secrets.
6
6
  import { HttpControlPlane, NotConfiguredError } from '../../src/infrastructure/control-plane-http.js';
7
7
  /** What `--org` says in every subcommand's help. */
8
8
  export const ORG_OPTION = ['--org [organization]', 'an organization’s scope, by its GitHub login (bare: the operator organization)'];
9
- /** `gh secret --app`'s spelling (context TASK-0394): Dependabot's store is handed only to a run Dependabot started. */
9
+ /** `gh secret --app`'s spelling (TASK-0394): Dependabot's store is handed only to a run Dependabot started. */
10
10
  export const APP_OPTION = ['--app <app>', 'which store: actions (default) or dependabot, handed only to runs Dependabot started'];
11
11
  export const collect = (value, previous) => [...previous, value];
12
12
  export const usage = (message) => {
@@ -20,7 +20,7 @@ const api = () => {
20
20
  };
21
21
  const departuresCommand = new Command('departures')
22
22
  .description('Every tenant that uninstalled, newest first, and when its data is deleted')
23
- .option('--repositories', 'repositories removed from an installation that stays, instead (ADR-0069 amendment)')
23
+ .option('--repositories', 'repositories removed from an installation that stays, instead (api ADR-0069 amendment)')
24
24
  .option('--json', 'machine-readable output')
25
25
  .action(async (opts) => {
26
26
  const client = api();
@@ -62,7 +62,7 @@ const departuresCommand = new Command('departures')
62
62
  for (const d of outcome.value)
63
63
  console.log(` ${departureLine(d)}`);
64
64
  });
65
- /** `apex tenant purge --repository <repoId>` (context TASK-0331). */
65
+ /** `apex tenant purge --repository <repoId>` (TASK-0331). */
66
66
  const purgeRemovedRepository = async (raw, opts) => {
67
67
  const repoId = Number(raw);
68
68
  if (!Number.isSafeInteger(repoId) || repoId <= 0) {
@@ -98,7 +98,7 @@ const purgeRemovedRepository = async (raw, opts) => {
98
98
  const purgeCommand = new Command('purge')
99
99
  .description("Delete one departed tenant's data now, whatever its window — a dry run unless --apply")
100
100
  .argument('[installationId]', 'the installation that left')
101
- .option('--repository <repoId>', 'a repository removed from an installation that stays, instead (ADR-0069 amendment)')
101
+ .option('--repository <repoId>', 'a repository removed from an installation that stays, instead (api ADR-0069 amendment)')
102
102
  .option('--apply', 'delete it (default: report what would be deleted)')
103
103
  .option('--json', 'machine-readable output')
104
104
  .action(async (raw, opts) => {
@@ -227,7 +227,7 @@ const installationsCommand = new Command('installations')
227
227
  .option('--fresh', 'only installations that never ran, paid or were granted')
228
228
  .option('--json', 'machine-readable output')
229
229
  .action(async (opts) => {
230
- // The operator token `apex login --console` saved reaches this route too (control-plane ADR-0079).
230
+ // The operator token `apex login --console` saved reaches this route too (api ADR-0079).
231
231
  let client;
232
232
  try {
233
233
  client = new HttpControlPlane({ operator: true });
@@ -8,14 +8,14 @@ import { api, collect, usage } from '../secret/shared.js';
8
8
  import { approvalFlow, withFlowOptions } from '../login/device.js';
9
9
  /**
10
10
  * `apex token`: the person's API tokens from the terminal (control-plane
11
- * ADR-0064, amended 2026-09-27).
11
+ * api ADR-0064, amended 2026-09-27).
12
12
  *
13
13
  * `create` asks for the person's approval in the browser, exactly as `apex
14
14
  * login` does, and prints the token once — the token alone on stdout, so
15
15
  * `$(apex token create …)` captures it, and everything a person reads on
16
16
  * stderr. It is never saved, and the CLI's own login is left as it was.
17
17
  * A token carries the permissions asked for with `--permission` and belongs
18
- * to one Account (control-plane ADR-0071).
18
+ * to one Account (api ADR-0071).
19
19
  * `edit` narrows a token at once with whichever credential the CLI has, and
20
20
  * widens one only through the same browser approval.
21
21
  * `list` and `revoke` use whichever credential the CLI already has.
@@ -25,7 +25,7 @@ import { approvalFlow, withFlowOptions } from '../login/device.js';
25
25
  const PERMISSION_HELP = `resource:read or resource:write (write implies read); resource is one of ${TOKEN_RESOURCES.join(', ')}`;
26
26
  /**
27
27
  * The approval half `create` and a widening `edit` share — the loopback on this machine, or a device code
28
- * (control-plane ADR-0075). Everything a person reads goes to stderr: stdout is the token's alone.
28
+ * (api ADR-0075). Everything a person reads goes to stderr: stdout is the token's alone.
29
29
  */
30
30
  const approvalDeps = (flags, what) => {
31
31
  const apiUrl = apiUrlFrom();
@@ -24,7 +24,7 @@ const credentialLine = (credential) => {
24
24
  * credential got it there. The answer is the server's (`GET /api/v1/me`), not
25
25
  * a guess from the local file; the credential itself is never printed.
26
26
  *
27
- * It also names any credential that was present and lost (ADR-0005: the
27
+ * It also names any credential that was present and lost (cli ADR-0005: the
28
28
  * environment outranks the saved login), because the surprise this command
29
29
  * exists to prevent is acting as somebody other than the one you meant.
30
30
  *
@@ -35,7 +35,7 @@ export const approveInBrowser = async (deps, token, accountId) => {
35
35
  /** RFC 8628 §3.2's default when a server names no interval. */
36
36
  const DEFAULT_INTERVAL_SECONDS = 5;
37
37
  /**
38
- * The device flow (control-plane ADR-0075, RFC 8628 run by Apex): ask for a request, show the code, and
38
+ * The device flow (api ADR-0075, RFC 8628 run by Apex): ask for a request, show the code, and
39
39
  * poll with the device code — which never leaves this process — every `interval` seconds, slowing down
40
40
  * when told, until the person approves or denies on any device, or the code's ten minutes pass.
41
41
  */
@@ -113,7 +113,7 @@ export const login = async (deps) => {
113
113
  };
114
114
  };
115
115
  /**
116
- * `apex login --console` (control-plane ADR-0079): the same loopback + PKCE approval, opened on the Admin
116
+ * `apex login --console` (api ADR-0079): the same loopback + PKCE approval, opened on the Admin
117
117
  * Console's bare page rather than the app's — `deps.webBase` is the Console's — and redeemed at the same
118
118
  * control plane, for an **operator token**. Only the loopback: an operator approves in the Console's own
119
119
  * browser session. What comes back must be an operator token, or nothing is saved.
@@ -132,7 +132,7 @@ export const consoleLogin = async (deps) => {
132
132
  };
133
133
  /**
134
134
  * Revoke the saved token at the control plane that minted it, then forget it
135
- * (control-plane ADR-0064: a token may revoke itself and nothing else). The file
135
+ * (api ADR-0064: a token may revoke itself and nothing else). The file
136
136
  * goes either way — keeping a credential because the network was down would be
137
137
  * the wrong failure — and a revocation that did not happen is reported as such,
138
138
  * never implied.
@@ -16,7 +16,7 @@ export const listDepartures = async (api) => await attempt(() => api.departures(
16
16
  * left to ask.
17
17
  */
18
18
  export const purgeDeparture = async (api, installationId, apply) => await attempt(() => api.purgeDeparture(installationId, apply));
19
- /** Every repository the App was removed from, newest first (control-plane ADR-0069 amendment). */
19
+ /** Every repository the App was removed from, newest first (api ADR-0069 amendment). */
20
20
  export const listRepositoryDepartures = async (api) => await attempt(() => api.repositoryDepartures());
21
21
  /** Purge one removed repository's data now, whatever its window — a dry run unless `apply`; machine token only. */
22
22
  export const purgeRepositoryDeparture = async (api, repoId, apply) => await attempt(() => api.purgeRepositoryDeparture(repoId, apply));
@@ -2,7 +2,7 @@
2
2
  import { targetLabel } from '../domain/secrets.js';
3
3
  /**
4
4
  * Why the unnamed organisation scope refused: it is the operator organisation's
5
- * (BUG-0112). A customer names theirs — `--org <login>` (ADR-0084) — and that
5
+ * (BUG-0112). A customer names theirs — `--org <login>` (api ADR-0084) — and that
6
6
  * route's refusal explains itself, so it is relayed as worded.
7
7
  */
8
8
  export const ORG_SCOPE_REFUSAL = 'the bare --org scope is the operator organisation’s — name yours: --org <your-organization>';
@@ -12,7 +12,7 @@ const attempt = async (fn) => {
12
12
  * The API answers what *this caller* may act for; the CLI authenticates as the
13
13
  * machine principal, which administers every account, so an operator sees the
14
14
  * whole list. Nothing is classified here — outstanding is the control plane's
15
- * judgement (control-plane ADR-0039 amendment 1) and a second one would be a
15
+ * judgement (api ADR-0039 amendment 1) and a second one would be a
16
16
  * second answer to a question that must have one.
17
17
  */
18
18
  export const readTermsStanding = async (api) => await attempt(() => api.termsStanding());
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * The Accounts backfill as the control plane reports it (control-plane
3
- * `POST /api/v1/console/accounts/backfill`, TASK-0195), and how a person reads it.
3
+ * `POST /api/v1/office/accounts/backfill`, TASK-0195), and how a person reads it.
4
4
  */
5
5
  const ORG_VERB = {
6
6
  connect: ['would join', 'joined'],
@@ -1,7 +1,7 @@
1
1
  // domain layer — see ../../../../docs/conventions/clean-architecture.md §1
2
2
  /**
3
3
  * A customer's terminal credential, and the browser login that mints one
4
- * (control-plane ADR-0064).
4
+ * (api ADR-0064).
5
5
  *
6
6
  * Pure decisions only: where the consent page is, whether a loopback callback
7
7
  * is the one this login asked for, whether a file mode is private enough to
@@ -24,10 +24,10 @@ export const describeSource = (source) => {
24
24
  return 'the operator token `apex login --console` saved';
25
25
  }
26
26
  };
27
- /** An operator token's prefix (control-plane ADR-0079); an Account token's is `apex_pat_`. */
27
+ /** An operator token's prefix (api ADR-0079); an Account token's is `apex_pat_`. */
28
28
  export const OPERATOR_TOKEN_PREFIX = 'apex_opt_';
29
29
  /**
30
- * The Admin Console's base URL, where `apex login --console` is approved (control-plane ADR-0079):
30
+ * The Admin Console's base URL, where `apex login --console` is approved (api ADR-0079):
31
31
  * `APEX_CONSOLE_URL` when set, else the API's host with `app.` read as `admin.` — the hosted service's
32
32
  * pair — else `undefined`, and the command asks for `APEX_CONSOLE_URL`.
33
33
  */
@@ -116,19 +116,19 @@ export const authorizeUrl = (webBase, request) => {
116
116
  return `${normaliseUrl(webBase)}/cli/authorize?${query.toString()}`;
117
117
  };
118
118
  /**
119
- * Where the loopback callback sends the browser once the code is redeemed (control-plane ADR-0075): the
119
+ * Where the loopback callback sends the browser once the code is redeemed (api ADR-0075): the
120
120
  * web app's bare `/cli/done`, so the tab ends on our domain rather than on this process's `127.0.0.1`.
121
121
  * The page is copy only and confirms nothing server-side, so it carries only the outcome and the purpose
122
122
  * — never the code, the state or anything else the callback held.
123
123
  */
124
124
  export const doneUrl = (webBase, outcome, purpose) => `${normaliseUrl(webBase)}/cli/done?${new URLSearchParams({ outcome, purpose }).toString()}`;
125
- /** A token's lifetime bounds (control-plane ADR-0064): every token expires, 90 days at most. */
125
+ /** A token's lifetime bounds (api ADR-0064): every token expires, 90 days at most. */
126
126
  export const MAX_TOKEN_DAYS = 90;
127
127
  /** Repositories one token may be held to. */
128
128
  export const MAX_TOKEN_REPOS = 100;
129
129
  const REPO = /^[A-Za-z0-9-]+\/[A-Za-z0-9._-]+$/;
130
130
  /**
131
- * What a token may be granted (context ADR-0038): `resource:read|write`, write implying read. The control plane's
131
+ * What a token may be granted (ADR-0038): `resource:read|write`, write implying read. The control plane's
132
132
  * `RepoPermission`, in the order a person reads them.
133
133
  */
134
134
  export const TOKEN_RESOURCES = ['actions', 'approvals', 'deployments', 'secrets', 'variables', 'environments', 'notifications', 'administration', 'organization'];
@@ -235,7 +235,7 @@ export const judgeCallback = (params, expectedState) => {
235
235
  const set = (v) => v !== undefined && v !== '';
236
236
  /**
237
237
  * Why no browser can open on this machine, in words for the terminal — or `undefined` when one can.
238
- * ADR-0075's list: an SSH session, a Codespace, a dev container, a container, or Linux with no display.
238
+ * api ADR-0075's list: an SSH session, a Codespace, a dev container, a container, or Linux with no display.
239
239
  */
240
240
  export const headlessReason = ({ env, platform, dockerenv }) => {
241
241
  if (set(env['SSH_CONNECTION']) || set(env['SSH_TTY']))
@@ -3,7 +3,7 @@
3
3
  // How big was the fleet, and when was it nothing?
4
4
  //
5
5
  // The control plane serves runner *lifetimes* — `registeredAt` to `lastSeenAt`,
6
- // departed runners included (control-plane ADR-0041). Everything below is the
6
+ // departed runners included (api ADR-0041). Everything below is the
7
7
  // pure arithmetic that turns a pile of intervals into the two answers a capacity
8
8
  // question actually wants: the peak, and the time at zero. It is here rather
9
9
  // than in the control plane so that it can be tested without a server, and so
@@ -1,7 +1,7 @@
1
1
  // domain layer — see ../../../../docs/conventions/clean-architecture.md §1
2
2
  /**
3
- * Complimentary access from the terminal (control-plane ADR-0056 as amended by
4
- * ADR-0079, TASK-0199): the grant and installation shapes the admin API
3
+ * Complimentary access from the terminal (api ADR-0056 as amended by
4
+ * api ADR-0079, TASK-0199): the grant and installation shapes the admin API
5
5
  * answers with, the checks `apex grant` makes before a round trip — the
6
6
  * control plane makes them again — and how each reads as a line.
7
7
  */
@@ -1,6 +1,6 @@
1
1
  // domain layer — see ../../../../docs/conventions/clean-architecture.md §1
2
2
  // The REST shapes for "what got slower" and "what is flaky", mirroring
3
- // control-plane/contracts/openapi.yaml, plus the pure decisions the CLI makes
3
+ // packages/contracts/openapi/openapi.yaml, plus the pure decisions the CLI makes
4
4
  // about presenting them.
5
5
  /**
6
6
  * A duration a person can compare at a glance.
@@ -1,6 +1,6 @@
1
1
  // domain layer — see ../../../../docs/conventions/clean-architecture.md §1
2
2
  // The REST shapes for a log search and a structured log view, mirroring
3
- // control-plane/contracts/openapi.yaml, plus the pure decisions the CLI makes
3
+ // packages/contracts/openapi/openapi.yaml, plus the pure decisions the CLI makes
4
4
  // about presenting them.
5
5
  /**
6
6
  * `ci.yml #12 · build` — how a result names the job it found.
@@ -1,10 +1,10 @@
1
1
  // domain layer — see ../../../../docs/conventions/clean-architecture.md §1
2
2
  // The REST shapes for notification routing, mirroring
3
- // control-plane/contracts/openapi.yaml, plus the pure presentation decisions
3
+ // packages/contracts/openapi/openapi.yaml, plus the pure presentation decisions
4
4
  // the CLI makes about them.
5
5
  //
6
6
  // There is no destination URL in any of these types, and that is not an
7
- // oversight: the control plane never returns one (control-plane ADR-0029), so
7
+ // oversight: the control plane never returns one (api ADR-0029), so
8
8
  // a field for it here would be a field that is always empty and would invite
9
9
  // somebody to try to fill it.
10
10
  export const TRIGGERS = ['broke', 'recovered', 'failed', 'succeeded'];
@@ -38,7 +38,7 @@ export const lastAttemptLine = (rule) => {
38
38
  * all is neither, and calling it a rejection points the reader at the
39
39
  * destination when the fault is on this side of the socket. It read as Slack
40
40
  * turning us away while the real cause was a `TypeError` in our own resolver
41
- * (control-plane ADR-0036), which is a day of somebody's time in the wrong
41
+ * (api ADR-0036), which is a day of somebody's time in the wrong
42
42
  * logs.
43
43
  */
44
44
  export const sendOutcomeLine = (outcome) => {
@@ -53,7 +53,7 @@ export const sendOutcomeLine = (outcome) => {
53
53
  *
54
54
  * Written out because the default subscription is the thing people misread:
55
55
  * "broke, recovered" looks like it might mean *every* failure, and it does not
56
- * (control-plane ADR-0028).
56
+ * (api ADR-0028).
57
57
  */
58
58
  export const subscriptionLine = (rule) => {
59
59
  const transitions = rule.on.filter((t) => t === 'broke' || t === 'recovered');
@@ -1,6 +1,6 @@
1
1
  // domain layer — see ../../../../docs/conventions/clean-architecture.md §1
2
2
  // The REST shapes for "why did this run" and "how do I run it here", mirroring
3
- // control-plane/contracts/openapi.yaml, plus the pure decisions the CLI makes
3
+ // packages/contracts/openapi/openapi.yaml, plus the pure decisions the CLI makes
4
4
  // about presenting them.
5
5
  /**
6
6
  * The retry note for one job, or `undefined` when it ran first time.
@@ -1,6 +1,6 @@
1
1
  // domain layer — see ../../../../docs/conventions/clean-architecture.md §1
2
2
  // What the CLI knows about runs and jobs, and the pure decisions it makes
3
- // about them. The REST shapes come from control-plane/contracts/openapi.
3
+ // about them. The REST shapes come from packages/contracts/openapi.
4
4
  /** The run's action-policy findings as `apex logs --summary` prints them: where, which job, the policy's sentence. */
5
5
  export const policyLines = (run) => (run.policyFindings ?? []).map((f) => `${f.workflowPath}${f.line === undefined || f.line <= 0 ? '' : `:${String(f.line)}`} (job ${f.jobId}): ${f.reason}`);
6
6
  /** A run is worth following while anything can still change. */
@@ -1,5 +1,5 @@
1
1
  // domain layer — see ../../../../docs/conventions/clean-architecture.md §1
2
- // The REST shapes for a spend report, mirroring control-plane/contracts/openapi.yaml,
2
+ // The REST shapes for a spend report, mirroring packages/contracts/openapi/openapi.yaml,
3
3
  // plus the pure decisions the CLI makes about presenting money.
4
4
  /**
5
5
  * Money, at a precision that does not pretend.
@@ -1,6 +1,6 @@
1
1
  // domain layer — see ../../../../docs/conventions/clean-architecture.md §1
2
2
  // The REST shapes for the action supply chain, mirroring
3
- // control-plane/contracts/openapi.yaml, plus the pure decisions the CLI makes
3
+ // packages/contracts/openapi/openapi.yaml, plus the pure decisions the CLI makes
4
4
  // about presenting them. No judgement lives here: whether a reference is
5
5
  // allowed is the control plane's answer, and a second implementation would be
6
6
  // a second answer.
@@ -8,7 +8,7 @@ import { homedir } from 'node:os';
8
8
  import { delimiter, dirname, join } from 'node:path';
9
9
  import { promisify } from 'node:util';
10
10
  /**
11
- * Where `engine` and `runner` publish their binaries on a release tag (context ADR-0040): one archive per
11
+ * Where `engine` and `runner` publish their binaries on a release tag (ADR-0040): one archive per
12
12
  * platform and a SHA256SUMS file per command, under the lockstep version.
13
13
  */
14
14
  export const DIST_BASE = 'https://apexactions.com/dl';
@@ -14,7 +14,7 @@ export class HttpError extends Error {
14
14
  this.status = status;
15
15
  }
16
16
  }
17
- /** A named Organization's reach, as the API takes it (control-plane ADR-0084); nothing for any other scope. */
17
+ /** A named Organization's reach, as the API takes it (api ADR-0084); nothing for any other scope. */
18
18
  /** Dependabot's store is named; the Actions store is the routes' default, so its paths are unchanged (TASK-0394). */
19
19
  const appQuery = (target) => (target.app === 'dependabot' ? '?app=dependabot' : '');
20
20
  const reachBody = (target, reach) => target.kind === 'org' && target.org !== undefined && reach !== undefined
@@ -23,13 +23,13 @@ const reachBody = (target, reach) => target.kind === 'org' && target.org !== und
23
23
  /**
24
24
  * Adapter: the control-plane REST API over the platform's `fetch`.
25
25
  *
26
- * The credential is resolved in control-plane ADR-0064's order as this repo's
27
- * ADR-0005 amends it (see `credentials.ts`): a customer's `APEX_TOKEN`, then
26
+ * The credential is resolved in api ADR-0064's order as this repo's
27
+ * cli ADR-0005 amends it (see `credentials.ts`): a customer's `APEX_TOKEN`, then
28
28
  * the operator's `APEX_ADMIN_TOKEN` — the machine principal, which keeps
29
29
  * scripts and boot paths working when GitHub is unreachable (ADR-0006) — then
30
30
  * the token `apex login` saved. The environment outranks the file.
31
31
  * A customer token reaches the repository routes its permissions cover, in its
32
- * Account (control-plane ADR-0071); a route it lacks the grant for answers 403
32
+ * Account (api ADR-0071); a route it lacks the grant for answers 403
33
33
  * `this token needs <permission>`, which this client extends with the edit
34
34
  * that would add it.
35
35
  *
@@ -69,7 +69,7 @@ export class HttpControlPlane {
69
69
  async whoami() {
70
70
  return await this.#json('GET', '/api/v1/me');
71
71
  }
72
- // ── the person's tokens: read and revoke, never mint (ADR-0064, amended 2026-09-27) ──
72
+ // ── the person's tokens: read and revoke, never mint (api ADR-0064, amended 2026-09-27) ──
73
73
  async listTokens() {
74
74
  const body = await this.#json('GET', '/api/v1/me/tokens');
75
75
  if (!Array.isArray(body.tokens))
@@ -235,7 +235,7 @@ export class HttpControlPlane {
235
235
  * The terms in force and who owes an acceptance, read from `/me`.
236
236
  *
237
237
  * It rides on `/me` in the API because the remedy is at somebody's next
238
- * sign-in and that is the call every screen makes (control-plane ADR-0039
238
+ * sign-in and that is the call every screen makes (api ADR-0039
239
239
  * amendment 1); here it means one request answers both halves.
240
240
  */
241
241
  async termsStanding() {
@@ -247,23 +247,23 @@ export class HttpControlPlane {
247
247
  return body.accepted;
248
248
  }
249
249
  async departures() {
250
- return (await this.#json('GET', '/api/v1/console/departures')).departures;
250
+ return (await this.#json('GET', '/api/v1/office/departures')).departures;
251
251
  }
252
252
  async purgeDeparture(installationId, apply) {
253
253
  return await this.#json('POST', `/api/v1/departures/${installationId}/purge${apply ? '?apply=true' : ''}`);
254
254
  }
255
255
  async repositoryDepartures() {
256
- return (await this.#json('GET', '/api/v1/console/repository-departures')).departures;
256
+ return (await this.#json('GET', '/api/v1/office/repository-departures')).departures;
257
257
  }
258
258
  async purgeRepositoryDeparture(repoId, apply) {
259
259
  return await this.#json('POST', `/api/v1/repository-departures/${repoId}/purge${apply ? '?apply=true' : ''}`);
260
260
  }
261
261
  async accountsBackfill(input, apply) {
262
- return await this.#json('POST', `/api/v1/console/accounts/backfill${apply ? '?apply=true' : ''}`, input);
262
+ return await this.#json('POST', `/api/v1/office/accounts/backfill${apply ? '?apply=true' : ''}`, input);
263
263
  }
264
- // ── complimentary access (control-plane ADR-0056, ADR-0079): the admin API's shapes, unchanged ──
264
+ // ── complimentary access (api ADR-0056, api ADR-0079): the admin API's shapes, unchanged ──
265
265
  /**
266
- * Every grant. The list is paged since context TASK-0241 (control-plane ADR-0081), so this follows `page.nextCursor`
266
+ * Every grant. The list is paged since TASK-0241 (api ADR-0081), so this follows `page.nextCursor`
267
267
  * to the end; a control plane from before the grammar answers everything and no `page`, which ends the loop at once.
268
268
  */
269
269
  async listGrants() {
@@ -273,7 +273,7 @@ export class HttpControlPlane {
273
273
  const query = new URLSearchParams({ limit: '200' });
274
274
  if (cursor !== undefined)
275
275
  query.set('cursor', cursor);
276
- const body = await this.#json('GET', `/api/v1/console/grants?${query.toString()}`);
276
+ const body = await this.#json('GET', `/api/v1/office/grants?${query.toString()}`);
277
277
  all.push(...body.grants);
278
278
  cursor = body.page?.nextCursor;
279
279
  if (cursor === undefined)
@@ -282,22 +282,22 @@ export class HttpControlPlane {
282
282
  return all;
283
283
  }
284
284
  async createGrant(body) {
285
- return await this.#json('POST', '/api/v1/console/grants', body);
285
+ return await this.#json('POST', '/api/v1/office/grants', body);
286
286
  }
287
287
  async updateGrant(id, body) {
288
- return (await this.#json('PATCH', `/api/v1/console/grants/${encodeURIComponent(id)}`, body)).grant;
288
+ return (await this.#json('PATCH', `/api/v1/office/grants/${encodeURIComponent(id)}`, body)).grant;
289
289
  }
290
290
  async revokeGrant(id) {
291
- return await this.#json('DELETE', `/api/v1/console/grants/${encodeURIComponent(id)}`);
291
+ return await this.#json('DELETE', `/api/v1/office/grants/${encodeURIComponent(id)}`);
292
292
  }
293
293
  async listInstallations() {
294
- return (await this.#json('GET', '/api/v1/console/installations')).installations;
294
+ return (await this.#json('GET', '/api/v1/office/installations')).installations;
295
295
  }
296
296
  async accountsUnconnected() {
297
- return (await this.#json('GET', '/api/v1/console/accounts/unconnected')).installations;
297
+ return (await this.#json('GET', '/api/v1/office/accounts/unconnected')).installations;
298
298
  }
299
299
  async accountsConnect(input) {
300
- return await this.#json('POST', '/api/v1/console/accounts/connect', input);
300
+ return await this.#json('POST', '/api/v1/office/accounts/connect', input);
301
301
  }
302
302
  async actionPolicy(owner) {
303
303
  return await this.#json('GET', `/api/v1/orgs/${encodeURIComponent(owner)}/action-policy`);
@@ -382,7 +382,7 @@ export class HttpControlPlane {
382
382
  return await this.#json('GET', `/api/v1/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/coexistence/diff?${q.toString()}`);
383
383
  }
384
384
  /**
385
- * Every live runner. The list is paged since control-plane ADR-0081, so this follows `page.nextCursor` to the end —
385
+ * Every live runner. The list is paged since api ADR-0081, so this follows `page.nextCursor` to the end —
386
386
  * `apex runner list` means all of them, and the fleet alone can hold more than one page. A control plane from before
387
387
  * the grammar answers everything and no `page`, which ends the loop at once.
388
388
  */
@@ -434,7 +434,7 @@ export class HttpControlPlane {
434
434
  return await this.#json('GET', `/api/v1/runs/${encodeURIComponent(runId)}/artifacts`);
435
435
  }
436
436
  /**
437
- * Every artifact a repository holds. The list is paged since control-plane ADR-0081 (context TASK-0228), so this
437
+ * Every artifact a repository holds. The list is paged since api ADR-0081 (TASK-0228), so this
438
438
  * follows `page.nextCursor` to the end; before, the list stopped at 200 without saying so. The total is the API's,
439
439
  * over every artifact. A control plane from before the grammar answers one page and no `page`, which ends the loop.
440
440
  */
@@ -38,7 +38,7 @@ export class InsecureCredentialsError extends NotConfiguredError {
38
38
  export const credentialsPath = (env = process.env) => join(set(env['XDG_CONFIG_HOME']) ? env['XDG_CONFIG_HOME'] : join(homedir(), '.config'), 'apex', 'credentials');
39
39
  /**
40
40
  * `$XDG_CONFIG_HOME/apex/console-credentials`: where `apex login --console` keeps the operator token
41
- * (control-plane ADR-0079) — beside the Account login, never in place of it.
41
+ * (api ADR-0079) — beside the Account login, never in place of it.
42
42
  */
43
43
  export const consoleCredentialsPath = (env = process.env) => join(dirname(credentialsPath(env)), 'console-credentials');
44
44
  /**
@@ -105,8 +105,8 @@ export class FileCredentialStore {
105
105
  }
106
106
  }
107
107
  /**
108
- * Which credential the CLI uses (control-plane ADR-0064's order, amended by
109
- * this repo's ADR-0005 — the environment outranks the file):
108
+ * Which credential the CLI uses (api ADR-0064's order, amended by
109
+ * cli ADR-0005 — the environment outranks the file):
110
110
  *
111
111
  * 1. `APEX_TOKEN` — a dashboard token, for CI and scripts;
112
112
  * 2. `APEX_ADMIN_TOKEN` — the operator's. An explicitly exported variable is
@@ -162,7 +162,7 @@ export const resolveCredential = (env = process.env, store = new FileCredentialS
162
162
  };
163
163
  /**
164
164
  * Which credential an operator command — `apex grant`, `apex tenant installations` — uses (control-plane
165
- * ADR-0079): the operator token `apex login --console` saved, when it is private, unexpired and was minted by
165
+ * api ADR-0079): the operator token `apex login --console` saved, when it is private, unexpired and was minted by
166
166
  * the control plane `APEX_API_URL` names; otherwise the ordinary order ({@link resolveCredential}), in which
167
167
  * the machine token can read grants and is refused every write. An expired operator token is skipped, and
168
168
  * the refusal that follows says to sign in again.
@@ -4,7 +4,7 @@ import { hostname, platform, release, type } from 'node:os';
4
4
  import { headlessReason, isDevicePollError, normaliseUrl } from '../domain/credentials.js';
5
5
  import { redeemedFrom } from './loopback-login.js';
6
6
  /**
7
- * The device flow's adapters (control-plane ADR-0075): the two calls, what this machine says about
7
+ * The device flow's adapters (api ADR-0075): the two calls, what this machine says about
8
8
  * itself, and whether a browser can open here at all.
9
9
  */
10
10
  /** Why no browser can open here, read from this process's environment; `undefined` when one can. */
@@ -5,7 +5,7 @@ import { createServer } from 'node:http';
5
5
  import { judgeCallback, normaliseUrl } from '../domain/credentials.js';
6
6
  /**
7
7
  * Adapters for `apex login`: the PKCE pair, the loopback listener, the
8
- * browser, and the code exchange (RFC 8252, RFC 7636; control-plane ADR-0064).
8
+ * browser, and the code exchange (RFC 8252, RFC 7636; api ADR-0064).
9
9
  */
10
10
  /** base64url(sha256(verifier)) — RFC 7636's S256. */
11
11
  export const s256 = (verifier) => createHash('sha256').update(verifier, 'ascii').digest('base64url');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@apex-actions/cli",
3
- "version": "0.95.2",
3
+ "version": "0.97.0",
4
4
  "license": "SEE LICENSE IN LICENSE",
5
5
  "//files": "Without this npm ships src, test and the CI config alongside the binary a user installs.",
6
6
  "files": [
@@ -13,7 +13,8 @@
13
13
  },
14
14
  "repository": {
15
15
  "type": "git",
16
- "url": "git+https://github.com/Apex-Actions/cli.git"
16
+ "url": "git+https://github.com/Apex-Actions/apex-actions.git",
17
+ "directory": "apps/cli"
17
18
  },
18
19
  "description": "apex — developer and operator CLI for Apex Actions",
19
20
  "type": "module",
@@ -33,16 +34,11 @@
33
34
  "@types/node": "^24.0.0",
34
35
  "dependency-cruiser": "^16.10.0",
35
36
  "eslint": "^9.28.0",
36
- "husky": "^9.1.7",
37
- "lint-staged": "^16.1.0",
38
37
  "tsx": "^4.19.4",
39
38
  "typescript": "^5.8.3",
40
39
  "typescript-eslint": "^8.67.0",
41
40
  "vitest": "^3.2.0"
42
41
  },
43
- "lint-staged": {
44
- "*.ts": "eslint --max-warnings=0"
45
- },
46
42
  "scripts": {
47
43
  "build": "tsc -p tsconfig.build.json",
48
44
  "typecheck": "tsc -p tsconfig.json --noEmit",