@bongos/core 1.19.792 → 1.19.794

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/.bongos-core.json CHANGED
@@ -2,11 +2,11 @@
2
2
  "artifact": "bongos-core",
3
3
  "manifest_schema": 1,
4
4
  "generator": "scripts/gds/package-core.js",
5
- "core_version": "1.19.792",
6
- "core_contract": "1.19.792",
7
- "source_commit": "7d0308f082bb516dafaf779e6e8955df07aac1f0",
5
+ "core_version": "1.19.794",
6
+ "core_contract": "1.19.794",
7
+ "source_commit": "58b6a9cb74826c4f1f72ca3cede882e22cd7a692",
8
8
  "source_ref": "HEAD",
9
- "built_at": "2026-09-17T00:25:50.991Z",
9
+ "built_at": "2026-09-17T00:45:35.726Z",
10
10
  "redaction": {
11
11
  "model": "docs-redacted+functional-verbatim",
12
12
  "docs_redacted": 486,
@@ -17,7 +17,7 @@
17
17
  "gate": "passed"
18
18
  },
19
19
  "file_count": 2690,
20
- "tree_sha256": "82a4277b3d647e6c4e975f1a9b4c6316a2177aa583ebaba8a37aab51a552694e",
20
+ "tree_sha256": "d3110e81291c49d143518eb1ef7e4e7a9d98ecbc08b176a4da98f589a27fd00d",
21
21
  "files": [
22
22
  {
23
23
  "path": ".claude/skills/ask-for-help/SKILL.md",
@@ -77,7 +77,7 @@
77
77
  {
78
78
  "path": ".claude/skills/builder-reauth/SKILL.md",
79
79
  "mode": "0000644",
80
- "sha256": "41527df350a69c001dd9a1a2d07767338fa216af58bea5a2019c2261d2b69aaa"
80
+ "sha256": "f54f3355d1f034fe99735a73ce62936d7d1582e751754bbe12023a4bf8a2d17c"
81
81
  },
82
82
  {
83
83
  "path": ".claude/skills/builder-redteam/SKILL.md",
@@ -342,7 +342,7 @@
342
342
  {
343
343
  "path": "bin/bongos.js",
344
344
  "mode": "0000644",
345
- "sha256": "d585fc874c0a45f5d02d5753025d4761ca9b817ae9e5c556891b5c5c444cffde"
345
+ "sha256": "36d11612cace3d69bd2e98c8f7b5b7d737d8bba5fd8fe1a0554a85e3cb1973ca"
346
346
  },
347
347
  {
348
348
  "path": "clients/bongos-client/README.md",
@@ -1972,7 +1972,7 @@
1972
1972
  {
1973
1973
  "path": "docs/api/openapi.json",
1974
1974
  "mode": "0000644",
1975
- "sha256": "00f6e4757e5337e7f7cf3ae1d0afeccfcabe9ef1896304004b855931f8b9c423"
1975
+ "sha256": "1442772c691bb7447cb13e4e63b062dd41913d8bb06555cee814069434556ae5"
1976
1976
  },
1977
1977
  {
1978
1978
  "path": "docs/architecture.md",
@@ -2527,7 +2527,7 @@
2527
2527
  {
2528
2528
  "path": "docs/module-api-changelog.md",
2529
2529
  "mode": "0000644",
2530
- "sha256": "a0c0e1aafc81738b39d52423b76ebbc23bfecd478ddee519c341d25a265a1e93"
2530
+ "sha256": "72aa54d05b8b21077bb6616513d99cb5f4c15ff3134c015024609d265a73efee"
2531
2531
  },
2532
2532
  {
2533
2533
  "path": "docs/modules-contract.md",
@@ -7692,12 +7692,12 @@
7692
7692
  {
7693
7693
  "path": "package-lock.json",
7694
7694
  "mode": "0000644",
7695
- "sha256": "a4f7542d3fd24e6d64fc20658f5339458a3ec0e38cccb5b12959b40babedf580"
7695
+ "sha256": "a8e7ddfcf220286f226ac9f1dd0f32247942c46b5518630a3610c68f47d541a2"
7696
7696
  },
7697
7697
  {
7698
7698
  "path": "package.json",
7699
7699
  "mode": "0000644",
7700
- "sha256": "fbda0210622f719253cab72cd3ab108ef90efa5d1357c4df20afa076e15add1f"
7700
+ "sha256": "2439337546b7731e96d15362371d002a51fd2d7112f6aa09abf53c05a88549ca"
7701
7701
  },
7702
7702
  {
7703
7703
  "path": "public-docs/index.html",
@@ -8532,7 +8532,7 @@
8532
8532
  {
8533
8533
  "path": "scripts/gds/paste-token.js",
8534
8534
  "mode": "0000644",
8535
- "sha256": "7f112d061f459781559778639c0c11b9fbc2a5acc06d87464a40def06c3e4cf7"
8535
+ "sha256": "423b356f7ff60913af72ce2042fb8dd2fcefa26375864dbb428cb4e3b527bb82"
8536
8536
  },
8537
8537
  {
8538
8538
  "path": "scripts/gds/portability-smoke-art.sh",
@@ -8637,7 +8637,7 @@
8637
8637
  {
8638
8638
  "path": "scripts/gds/reauth.js",
8639
8639
  "mode": "0000644",
8640
- "sha256": "5368ed9a43034b060451e54f21f885c216fab17cf731d7981d2681aeae890507"
8640
+ "sha256": "ce20f84be283f2a97df7d410b56b40d1e0cd14be8349acc418aa645d702f4f45"
8641
8641
  },
8642
8642
  {
8643
8643
  "path": "scripts/gds/recall.js",
@@ -9467,7 +9467,7 @@
9467
9467
  {
9468
9468
  "path": "src/bongos/routes/auth.js",
9469
9469
  "mode": "0000644",
9470
- "sha256": "4723bdcca92e442d73517df92463f58d16f0773d4167d8661a75fd9a7a61392d"
9470
+ "sha256": "a45868b46ab96fdedab3e7359259527e2d75e65b86a916865e5fff358f88a3b3"
9471
9471
  },
9472
9472
  {
9473
9473
  "path": "src/bongos/routes/backup.js",
@@ -9577,7 +9577,7 @@
9577
9577
  {
9578
9578
  "path": "src/module-api.js",
9579
9579
  "mode": "0000644",
9580
- "sha256": "51bcfd1a4eb31a189085c07cdcc46dd1b9d923c9335021ea3dcb54c6c55e01c6"
9580
+ "sha256": "9d386b35a316f8ab344ad96e48ed473560ada963d7b33699576b1325afe6be03"
9581
9581
  },
9582
9582
  {
9583
9583
  "path": "src/module-loader/catalog.js",
@@ -10012,7 +10012,7 @@
10012
10012
  {
10013
10013
  "path": "tests/bongos_cli.mjs",
10014
10014
  "mode": "0000644",
10015
- "sha256": "20d7d86da8e03ede2004bdc3dda589670977fca0240d56cd3677fc08fbb2de03"
10015
+ "sha256": "ef01af16d62c55325a3b12cc7968a9d797994d2f46364149668bf4e2839cb0e0"
10016
10016
  },
10017
10017
  {
10018
10018
  "path": "tests/bongos_dispatch.mjs",
@@ -10292,7 +10292,7 @@
10292
10292
  {
10293
10293
  "path": "tests/cli_token_reissue.mjs",
10294
10294
  "mode": "0000644",
10295
- "sha256": "66717847c1f67d4bedd9a2d9d5ed989e238039118e439eb2a3c67d43079172a4"
10295
+ "sha256": "a82544c109464d884e44731cbdd73e9e141d31d8e18a9241222d6a26223e19c2"
10296
10296
  },
10297
10297
  {
10298
10298
  "path": "tests/client_baseurl_guard.mjs",
@@ -25,10 +25,10 @@ What actually bounds a leaked token is **revocation**, and it is faster than any
25
25
  2. **Relay the click-path verbatim.** The helper prints the exact steps; pass them to the user clearly (don't paraphrase the URL):
26
26
  - Open `https://example.com/builders/settings` (the helper tries to open it automatically; if not, give them the link).
27
27
  - They are already signed in there via the browser cookie. Under the **"CLI Access"** section, click **"Re-issue CLI token"**.
28
- - Click **"Copy"** — it copies a one-line command of the form `node scripts/gds/paste-token.js <token>`.
28
+ - Click **"Copy"** — it copies a one-line command of the form `bongos paste-token <token>`.
29
29
  - Ask them to **paste that one line back into the chat**.
30
30
 
31
- 3. **Run the pasted command.** When the user pastes `node scripts/gds/paste-token.js <token>`, run it exactly as given. `paste-token.js` verifies the token against `/api/gds/me` **before** touching the session file (a bad paste leaves the existing session intact) and preserves any `gemini_api_key`. On success it prints the builder login, rank, and confirms the session file was written.
31
+ 3. **Run the pasted command.** When the user pastes `bongos paste-token <token>`, run it exactly as given. `paste-token.js` verifies the token against `/api/gds/me` **before** touching the session file (a bad paste leaves the existing session intact) and preserves any `gemini_api_key`. On success it prints the builder login, rank, and confirms the session file was written.
32
32
 
33
33
  4. **Confirm.** Relay the authenticated identity + rank back to the user, and tell them they can now re-run whatever `/builder-*` command they were trying.
34
34
 
@@ -41,13 +41,13 @@ What actually bounds a leaked token is **revocation**, and it is faster than any
41
41
 
42
42
  ## Constraints
43
43
 
44
- - **The token briefly transits the chat — that's the known cost of guided-paste.** The user pastes `node scripts/gds/paste-token.js <token>` into the conversation, so the bearer appears in the chat (and any log/context that captures it). That's the accepted trade-off Lars chose; the deferred zero-paste loopback flow removes it. So: treat the session log as sensitive, **never echo the token beyond running that one pasted command**, and never write it to any file other than `~/.config/otb/gds-session.json` (`paste-token.js` is the only thing that should write it — let it do the write). The token rotates whenever the builder clicks Re-issue again, so re-running this flow invalidates an exposed paste's usefulness for an attacker who lacks the browser cookie.
44
+ - **The token briefly transits the chat — that's the known cost of guided-paste.** The user pastes `bongos paste-token <token>` into the conversation, so the bearer appears in the chat (and any log/context that captures it). That's the accepted trade-off Lars chose; the deferred zero-paste loopback flow removes it. So: treat the session log as sensitive, **never echo the token beyond running that one pasted command**, and never write it to any file other than `~/.config/otb/gds-session.json` (`paste-token.js` is the only thing that should write it — let it do the write). The token rotates whenever the builder clicks Re-issue again, so re-running this flow invalidates an exposed paste's usefulness for an attacker who lacks the browser cookie.
45
45
  - **Don't re-auth a valid session.** If `reauth.js` exits 0, stop.
46
46
  - **`GDS_API_BASE`** overrides the endpoint (default `https://example.com`); for local dev `GDS_API_BASE=http://localhost:3000`.
47
47
 
48
48
  ## Files this skill touches
49
49
 
50
50
  - Runs: `node scripts/gds/reauth.js` (detect + open browser + print click-path)
51
- - Runs: `node scripts/gds/paste-token.js <token>` (verify + write the new session)
51
+ - Runs: `bongos paste-token <token>` (verify + write the new session)
52
52
  - Reads/Writes (via paste-token.js): `~/.config/otb/gds-session.json`
53
53
  - Calls: `GET /api/gds/me`; the Settings page (CLI Access) calls `POST /api/gds/auth/cli-token/issue`
package/bin/bongos.js CHANGED
@@ -47,6 +47,10 @@ const BUNDLED_RUNNERS = {
47
47
  'login.js': () => require('../scripts/gds/login.js'),
48
48
  'setup.js': () => require('../scripts/gds/setup.js'),
49
49
  'reauth.js': () => require('../scripts/gds/reauth.js'),
50
+ // Bundled for the same reason as reauth: they are two halves of one on-ramp
51
+ // (mint the token, then store it), and a builder recovering a dead session on a
52
+ // bare laptop has the standalone binary and nothing else (task 1003961).
53
+ 'paste-token.js': () => require('../scripts/gds/paste-token.js'),
50
54
  'api.js': () => require('../scripts/gds/api.js'),
51
55
  'shell.js': () => require('../scripts/gds/shell.js'),
52
56
  'code.js': () => require('../scripts/gds/code.js'),
@@ -84,6 +88,13 @@ const VERBS = {
84
88
  login: { script: 'login.js', group: 'account', summary: 'Sign in to an instance (bongos login <url> — browser click, no paste)' },
85
89
  setup: { script: 'setup.js', group: 'account', summary: 'Full builder setup on this instance (art key, disciplines, consent)' },
86
90
  reauth: { script: 'reauth.js', group: 'account', summary: 'Refresh your session' },
91
+ // The second half of `reauth`: the hall mints a token, this stores it. A VERB
92
+ // rather than a path because the string is emitted by the SERVER and pasted on
93
+ // an INSTANCE, where `scripts/gds/` does not exist — the core is a dependency
94
+ // there, so the old `node scripts/gds/paste-token.js <token>` named a file the
95
+ // builder did not have (task 1003961). A verb also makes it allow-listable by
96
+ // name, the way claim/ship/release already are (ADR 0104).
97
+ 'paste-token': { script: 'paste-token.js', group: 'account', summary: 'Finish re-auth: store the token copied from Settings (bongos paste-token <token>)' },
87
98
  doctor: { script: 'doctor.js', group: 'account', summary: 'Check your local toolchain + session' },
88
99
  box: { script: 'api.js', prefixArgs: ['POST', '/api/gds/box/ensure'], group: 'account', summary: 'Turn on / wake your cloud dev box' },
89
100
  shell: { script: 'shell.js', group: 'account', summary: 'Open a terminal on your dev box (--local for a local clone)' },
@@ -239,7 +250,7 @@ function runBundled(verb, def, forwarded) {
239
250
  ` bongos code open VS Code on your cloud dev box (has everything)\n` +
240
251
  ` bongos shell open a terminal on your cloud dev box\n` +
241
252
  ` bongos init scaffold a new instance here\n\n` +
242
- `The standalone binary covers the on-ramp: login, box, shell, code, init, reauth.\n`
253
+ `The standalone binary covers the on-ramp: login, box, shell, code, init, reauth, paste-token.\n`
243
254
  );
244
255
  return 2;
245
256
  }
@@ -1329,7 +1329,7 @@
1329
1329
  "auth"
1330
1330
  ],
1331
1331
  "summary": "POST /auth/cli-token/issue",
1332
- "description": "POST /auth/cli-token/issue — V3.R91 / task 401. Issue a fresh CLI bearer for the requesting builder, gated on a WEB COOKIE session (not a bearer). The browser already proves identity via the gds_session cookie; this endpoint mints a separate cli-source session row the builder can paste into ~/.config/otb/gds-session.json via scripts/gds/paste-token.js. Replaces the ~30-60s Device Flow when the CLI bearer has expired. rank: any-builder (own identity only) — no rank gate. auth source restriction: cookie ONLY. A bearer cannot mint a new bearer (a leaked CLI token shouldn't be able to extend its own lifetime; the httpOnly browser cookie is the harder-to-steal credential).\n\n**Rank:** `any-builder` — Any authenticated builder (row-level ownership enforced in-handler).",
1332
+ "description": "POST /auth/cli-token/issue — V3.R91 / task 401. Issue a fresh CLI bearer for the requesting builder, gated on a WEB COOKIE session (not a bearer). The browser already proves identity via the gds_session cookie; this endpoint mints a separate cli-source session row the builder can paste into ~/.config/otb/gds-session.json via `bongos paste-token`. Replaces the ~30-60s Device Flow when the CLI bearer has expired. rank: any-builder (own identity only) — no rank gate. auth source restriction: cookie ONLY. A bearer cannot mint a new bearer (a leaked CLI token shouldn't be able to extend its own lifetime; the httpOnly browser cookie is the harder-to-steal credential).\n\n**Rank:** `any-builder` — Any authenticated builder (row-level ownership enforced in-handler).",
1333
1333
  "x-rank": "any-builder",
1334
1334
  "x-source": "src/bongos/routes/auth.js",
1335
1335
  "responses": {
@@ -2058,5 +2058,9 @@ is load-bearing: the script throws rather than guess if it is missing, and
2058
2058
  landed since 1.19.790 with no explicit bump. run 35165066743. (task 1002620)
2059
2059
  1.19.792 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
2060
2060
  landed since 1.19.791 with no explicit bump. run 35166486577. (task 1002620)
2061
+ 1.19.793 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
2062
+ landed since 1.19.792 with no explicit bump. run 35167484049. (task 1002620)
2063
+ 1.19.794 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
2064
+ landed since 1.19.793 with no explicit bump. run 35167814500. (task 1002620)
2061
2065
  ---------------------------------------------------------------------------
2062
2066
  ```
package/package-lock.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@bongos/core",
3
- "version": "1.19.792",
3
+ "version": "1.19.794",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@bongos/core",
9
- "version": "1.19.792",
9
+ "version": "1.19.794",
10
10
  "license": "AGPL-3.0-or-later",
11
11
  "dependencies": {
12
12
  "express": "^4.21.2",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bongos/core",
3
- "version": "1.19.792",
3
+ "version": "1.19.794",
4
4
  "description": "Cloud Bongos — the AI-first build platform core (GDS + platform surfaces + module system), installed as a versioned dependency (ADR 0108).",
5
5
  "license": "AGPL-3.0-or-later",
6
6
  "main": "src/platform-server.js",
@@ -7,7 +7,8 @@
7
7
  // paste never silently un-registers a builder's Gemini key.
8
8
  //
9
9
  // Usage:
10
- // node scripts/gds/paste-token.js <token>
10
+ // bongos paste-token <token> # what the hall hands you (task 1003961)
11
+ // node scripts/gds/paste-token.js <token> # equivalent, inside a core checkout
11
12
  //
12
13
  // The portal returns the exact invocation as the "paste_command" field, so a
13
14
  // builder can copy + paste a single line.
@@ -42,7 +43,8 @@ const API_BASE = ic.resolveApiBase();
42
43
  function usage(extra) {
43
44
  if (extra) console.error(extra);
44
45
  console.error('');
45
- console.error('Usage: node scripts/gds/paste-token.js <token>');
46
+ console.error('Usage: bongos paste-token <token>');
47
+ console.error(' (inside a core checkout: node scripts/gds/paste-token.js <token>)');
46
48
  console.error('');
47
49
  console.error('Get a token on your Settings page: ' + API_BASE + '/builders/settings');
48
50
  console.error('— under "CLI Access" click "Re-issue CLI token" (you must be signed in).');
@@ -17,7 +17,7 @@
17
17
  // 2. Guide — open the builder's Settings page in the default browser (where
18
18
  // the builder is already signed in via the httpOnly cookie) and print the
19
19
  // exact click-path: Settings → CLI Access → Re-issue CLI token → Copy.
20
- // The page hands back a one-liner: `node scripts/gds/paste-token.js
20
+ // The page hands back a one-liner: `bongos paste-token
21
21
  // <token>`. The builder pastes that one line back into Claude; the
22
22
  // /builder-reauth skill runs it (paste-token.js verifies + writes safely).
23
23
  //
@@ -96,7 +96,7 @@ function printGuidance({ opened }) {
96
96
  console.log(" you're already signed in there via your browser cookie)");
97
97
  console.log(' 2. Under the "CLI Access" section, click "Re-issue CLI token".');
98
98
  console.log(' 3. Click "Copy" — it copies a one-line command that looks like:');
99
- console.log(' node scripts/gds/paste-token.js <token>');
99
+ console.log(' bongos paste-token <token>');
100
100
  console.log(' 4. Paste that one line back to Claude. It will run it for you,');
101
101
  console.log(' verify the token, and write your new session.');
102
102
  console.log('');
@@ -1025,7 +1025,7 @@ module.exports = function buildAuthRouter() {
1025
1025
  // the requesting builder, gated on a WEB COOKIE session (not a bearer). The
1026
1026
  // browser already proves identity via the gds_session cookie; this endpoint
1027
1027
  // mints a separate cli-source session row the builder can paste into
1028
- // ~/.config/otb/gds-session.json via scripts/gds/paste-token.js. Replaces
1028
+ // ~/.config/otb/gds-session.json via `bongos paste-token`. Replaces
1029
1029
  // the ~30-60s Device Flow when the CLI bearer has expired.
1030
1030
  //
1031
1031
  // rank: any-builder (own identity only) — no rank gate.
@@ -1058,7 +1058,15 @@ module.exports = function buildAuthRouter() {
1058
1058
  token,
1059
1059
  expires_at: row.expires_at,
1060
1060
  builder_login: req.builder.github_login,
1061
- paste_command: `node scripts/gds/paste-token.js ${token}`,
1061
+ // A VERB, never a path (task 1003961). This string is composed HERE and run
1062
+ // THERE — on an instance, where the core is an installed dependency and
1063
+ // `scripts/gds/` does not exist, so the previous
1064
+ // `node scripts/gds/paste-token.js <token>` named a file the builder did not
1065
+ // have and the copy button handed out a command that could not run. `bongos`
1066
+ // is on PATH in any installed instance, so the verb form is layout- and
1067
+ // directory-independent. Same discipline as configuredOAuthOrigin() above:
1068
+ // nothing about the RECIPIENT's filesystem may be assumed here.
1069
+ paste_command: `bongos paste-token ${token}`,
1062
1070
  });
1063
1071
  } catch (err) {
1064
1072
  log.error('[gds] POST /auth/cli-token/issue', err);
package/src/module-api.js CHANGED
@@ -71,7 +71,7 @@ const { responsibilityFor, ROLE_RESPONSIBILITIES } = require('./role-responsibil
71
71
  // there. scripts/gds/bump-version.js still rewrites the literal below; it appends
72
72
  // the entry to that file. Look for a version's history there, not here.
73
73
  // ---------------------------------------------------------------------------
74
- const CORE_VERSION = '1.19.792'; // CI auto-patch carrier (ADR 0161); changelog: docs/module-api-changelog.md
74
+ const CORE_VERSION = '1.19.794'; // CI auto-patch carrier (ADR 0161); changelog: docs/module-api-changelog.md
75
75
 
76
76
  // A namespaced logger so a module's log lines are attributable + consistent.
77
77
  // Usage: const log = api.logger('dev-box'); log.info('mounted');
@@ -13,6 +13,7 @@
13
13
  import { strict as assert } from 'node:assert';
14
14
  import { createRequire } from 'node:module';
15
15
  import { spawnSync } from 'node:child_process';
16
+ import { readFileSync } from 'node:fs';
16
17
  import { fileURLToPath } from 'node:url';
17
18
  import { dirname, join } from 'node:path';
18
19
 
@@ -43,6 +44,33 @@ test('verbHelpText: names the verb, its summary, and the full-help pointer', ()
43
44
  assert.match(out, /bongos help/);
44
45
  });
45
46
 
47
+ // task 1003961 — the hall's re-auth copy button emits `bongos paste-token <token>`.
48
+ // That string is composed by the SERVER and run on an INSTANCE, so the verb has to
49
+ // exist here or the one-click path dead-ends on "unknown command". Pinned against
50
+ // the routes file so the two halves cannot drift apart.
51
+ test('paste-token is a registered verb wired to paste-token.js', () => {
52
+ const def = cli.VERBS['paste-token'];
53
+ assert.ok(def, 'bongos paste-token must be a registered verb');
54
+ assert.equal(def.script, 'paste-token.js');
55
+ assert.equal(def.group, 'account', 'it belongs with the other session verbs');
56
+ });
57
+
58
+ test('paste-token is bundled into the standalone binary, like reauth', () => {
59
+ // Two halves of one on-ramp: reauth mints the token, paste-token stores it.
60
+ // A builder recovering a dead session on a bare laptop has only the binary.
61
+ assert.ok(cli.BUNDLED_RUNNERS['paste-token.js'],
62
+ 'paste-token.js must be in BUNDLED_RUNNERS or the compiled binary refuses the verb');
63
+ assert.ok(cli.BUNDLED_RUNNERS['reauth.js'], 'reauth is the sibling this mirrors');
64
+ });
65
+
66
+ test('the server emits exactly the verb the CLI registers', () => {
67
+ const routes = readFileSync(join(dirname(fileURLToPath(import.meta.url)), '..', 'src', 'bongos', 'routes', 'auth.js'), 'utf8');
68
+ const m = routes.match(/paste_command:\s*`([^`]+)`/);
69
+ assert.ok(m, 'auth.js should emit a paste_command template literal');
70
+ const verb = m[1].split(' ')[1];
71
+ assert.ok(cli.VERBS[verb], `server emits "bongos ${verb}" but the CLI has no such verb`);
72
+ });
73
+
46
74
  test('VERBS: selfHelp is only claimed by scripts that really print their own usage', () => {
47
75
  // Verified by reading each script (they all branch on --help/-h to a usage()
48
76
  // printer). If a verb is added here, verify its script first — a wrong
@@ -119,16 +119,23 @@ const issueBlock = (() => {
119
119
  return routeSrc.slice(start, start + 3000);
120
120
  })();
121
121
 
122
- t("the issue handler reads SESSION_COOKIE (not just Authorization)", () => {
123
- assert.ok(issueBlock.includes('parseCookie(req, SESSION_COOKIE)'),
124
- 'handler must use parseCookie(req, SESSION_COOKIE)');
122
+ // Refreshed for the current handler (task 1003961). These two assertions named
123
+ // `parseCookie(req, SESSION_COOKIE)` and `res.status(403)`, the shape BEFORE the
124
+ // handler moved to the `sessionCookieToken` helper and the `res.fail` envelope.
125
+ // They had been red on main ever since — invisible, because this file is in the
126
+ // runner's INTEGRATION set and self-skips in CI's DB-free lane. Left alone they
127
+ // would have masked the new assertions below: a file that is already red cannot
128
+ // tell you whether the test you just added passes.
129
+ t("the issue handler reads the session COOKIE (not just Authorization)", () => {
130
+ assert.ok(issueBlock.includes('sessionCookieToken(req)'),
131
+ 'handler must resolve the browser cookie via sessionCookieToken(req)');
125
132
  });
126
133
 
127
134
  t('the issue handler rejects bearer-only callers with cookie_required', () => {
128
135
  assert.ok(issueBlock.includes("cookie_required"),
129
136
  "error code 'cookie_required' missing");
130
- assert.ok(/status\(403\)/.test(issueBlock),
131
- 'must respond with 403 when cookie is missing');
137
+ assert.ok(/status:\s*403/.test(issueBlock),
138
+ 'must respond 403 when the cookie is missing (res.fail envelope carries `status: 403`)');
132
139
  });
133
140
 
134
141
  t("mints a session with source='cli' (CHECK constraint compliant)", () => {
@@ -141,6 +148,23 @@ t('returns a paste_command field the portal can show verbatim', () => {
141
148
  'response should include paste_command for one-click UX');
142
149
  });
143
150
 
151
+ // The regression this pins (task 1003961): paste_command is composed on the SERVER
152
+ // and run on an INSTANCE, where the core is an installed dependency and there is no
153
+ // `scripts/gds/` directory. Emitting a repo-relative script path handed every
154
+ // instance builder a command naming a file they did not have. A verb has no such
155
+ // coupling — `bongos` is on PATH wherever the core is installed.
156
+ t('paste_command names a CLI VERB, never a filesystem path', () => {
157
+ const m = issueBlock.match(/paste_command:\s*`([^`]+)`/);
158
+ assert.ok(m, 'paste_command should be a template literal the test can read');
159
+ const cmd = m[1];
160
+ assert.ok(/^bongos paste-token /.test(cmd),
161
+ `paste_command must start with the verb form, got: ${cmd}`);
162
+ assert.ok(!cmd.includes('/'),
163
+ `paste_command must contain no path separator — it runs where the layout differs. Got: ${cmd}`);
164
+ assert.ok(!/\bnode\b/.test(cmd),
165
+ `paste_command must not invoke node directly (that assumes a script on disk). Got: ${cmd}`);
166
+ });
167
+
144
168
  // ---------------------------------------------------------------------------
145
169
 
146
170
  console.log(`\n${passed} passed, ${failed} failed`);