@bongos/core 1.21.67 → 1.21.68

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.21.67",
6
- "core_contract": "1.21.67",
7
- "source_commit": "d47aad0e873a78904c981b809062792003207822",
5
+ "core_version": "1.21.68",
6
+ "core_contract": "1.21.68",
7
+ "source_commit": "905d458be330f20adcb3a7d845df43fee7eff689",
8
8
  "source_ref": "HEAD",
9
- "built_at": "2026-10-06T17:54:50.385Z",
9
+ "built_at": "2026-10-06T18:26:22.762Z",
10
10
  "redaction": {
11
11
  "model": "docs-redacted+functional-verbatim",
12
12
  "docs_redacted": 587,
@@ -17,7 +17,7 @@
17
17
  "gate": "passed"
18
18
  },
19
19
  "file_count": 3583,
20
- "tree_sha256": "9e5acb92e763d8ffaa8cb3f51ed15d92cc5da78a0db387f5660313ef3f59f675",
20
+ "tree_sha256": "a902270fa53256d93862bf90030c31725f778c4a86e45b3e7ab48660dbb1a34f",
21
21
  "files": [
22
22
  {
23
23
  "path": ".claude/skills/ask-for-help/SKILL.md",
@@ -2847,7 +2847,7 @@
2847
2847
  {
2848
2848
  "path": "docs/module-api-changelog.md",
2849
2849
  "mode": "0000644",
2850
- "sha256": "3a8483f3b1bfeee5129f0b3120d559517d2379e729932680dbf370acb53c909f"
2850
+ "sha256": "fd5870bc0ed7adb62a63d1339b2922163ef6dcd5e38d183b2902c7767782b5bd"
2851
2851
  },
2852
2852
  {
2853
2853
  "path": "docs/modules-contract.md",
@@ -2937,7 +2937,7 @@
2937
2937
  {
2938
2938
  "path": "docs/page-readings.json",
2939
2939
  "mode": "0000644",
2940
- "sha256": "4475500bd02e0c2e381609268b87fdc939d932112e9b9e1f0a3ff31488ff2c57"
2940
+ "sha256": "7e8658d86ed640ea55dad973f0f39b124d6f8960d87c7dab17981c0365f64436"
2941
2941
  },
2942
2942
  {
2943
2943
  "path": "docs/project-context.template.md",
@@ -9212,7 +9212,7 @@
9212
9212
  {
9213
9213
  "path": "modules/public-landing/public/invitations.html",
9214
9214
  "mode": "0000644",
9215
- "sha256": "6775f25bdae0f80419e6523e4b368b62812040f5cfb34c1ae23b42b55c468be3"
9215
+ "sha256": "5b0b779c53f00f20d298c168e680b0f95334d6919869b4b4560e2dab534f4bdd"
9216
9216
  },
9217
9217
  {
9218
9218
  "path": "modules/public-landing/public/invitations.probes.json",
@@ -10037,12 +10037,12 @@
10037
10037
  {
10038
10038
  "path": "package-lock.json",
10039
10039
  "mode": "0000644",
10040
- "sha256": "debdf805f0e43fa453b07b17ff192faa8d15d81ba6795dd1299aad6f2b4f7349"
10040
+ "sha256": "9bf9f4221d7b278a8bc8220046fea675373e383d3588e644f0727b2ac942ddb5"
10041
10041
  },
10042
10042
  {
10043
10043
  "path": "package.json",
10044
10044
  "mode": "0000644",
10045
- "sha256": "c9398b668bd9a5ecc85766696dd81915f885e31084452ffe85098135e106f082"
10045
+ "sha256": "36e78f9f5af0899ec6d026bc20abdce4e5a467130e639d432238d677cac0aa36"
10046
10046
  },
10047
10047
  {
10048
10048
  "path": "public-docs/index.html",
@@ -10062,7 +10062,7 @@
10062
10062
  {
10063
10063
  "path": "release-notes.json",
10064
10064
  "mode": "0000644",
10065
- "sha256": "a688b82430fa5d9dd691f76bea6f7e5429d82b9151189093f2c3d167aa7c5449"
10065
+ "sha256": "125ba1b20b6eb21664bccbfa277c61a65a58920b48a7a26126a4782d7e48ad26"
10066
10066
  },
10067
10067
  {
10068
10068
  "path": "scripts/cron/style_guide_audit.sh",
@@ -12282,7 +12282,7 @@
12282
12282
  {
12283
12283
  "path": "src/module-api.js",
12284
12284
  "mode": "0000644",
12285
- "sha256": "b36016a91228286215541459f863b968e74aa6d83e58d6ca024392c7793ac8d2"
12285
+ "sha256": "46c686b3ad977c0ebf004d351746e3fa5491de0d2898c873c4604c9edfce5f5c"
12286
12286
  },
12287
12287
  {
12288
12288
  "path": "src/module-loader/catalog.js",
@@ -14852,7 +14852,7 @@
14852
14852
  {
14853
14853
  "path": "tests/hub_invitations_page.mjs",
14854
14854
  "mode": "0000644",
14855
- "sha256": "f8da457dce58c17c623a976cf650a0abfd31fafb516ddc0c0c074d45871458a2"
14855
+ "sha256": "7ac7c55c05086c04759d80aa70011cf51b3574bcb97801922b38e127f16e044b"
14856
14856
  },
14857
14857
  {
14858
14858
  "path": "tests/hub_invite_notices.mjs",
@@ -2966,5 +2966,7 @@ is load-bearing: the script throws rather than guess if it is missing, and
2966
2966
  landed since 1.21.65 with no explicit bump. run 37486828045. (task 1002620)
2967
2967
  1.21.67 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
2968
2968
  landed since 1.21.66 with no explicit bump. run 37507134428. (task 1002620)
2969
+ 1.21.68 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
2970
+ landed since 1.21.67 with no explicit bump. run 37511231885. (task 1002620)
2969
2971
  ---------------------------------------------------------------------------
2970
2972
  ```
@@ -4423,7 +4423,7 @@
4423
4423
  "surface": "landing",
4424
4424
  "title": "{{productName}} — Invitations",
4425
4425
  "states_read": ["out","in","in-join-applied","in-profile","in-engagements","in-engagement-note","in-engagement-applied","in-guild-cards","in-guild-count-off","in-guild-joined","in-empty","in-pick-open","in-pick-typed","in-pick-chosen"],
4426
- "files_hash": "f47d2b458c7d82fe",
4426
+ "files_hash": "8c3aa9ca65130b98",
4427
4427
  "reading_hash": "9306d59204f55cc2",
4428
4428
  "counts": {"lines":60,"placed":14,"shared":10,"unplaced":36},
4429
4429
  "omitted": {"data":14},
@@ -197,6 +197,12 @@
197
197
  return (u.protocol === 'https:' || u.protocol === 'http:') ? u.href : '';
198
198
  } catch (e) { return ''; }
199
199
  }
200
+ /* hostOf is for DISPLAY: it tolerates a bare or half-typed address and drops
201
+ a leading www, so a row reads "example.com". pickHost (the join picker,
202
+ below) is for MATCHING: new URL().host keeps www and any port, so it agrees
203
+ exactly with the origins the server stores, and the picker's mine/applied
204
+ maps and the "Applied" echo key on that. Folding one into the other would
205
+ either mislabel rows or miss matches. */
200
206
  function hostOf(origin) {
201
207
  return String(origin || '').replace(/^https?:\/\//, '').replace(/^www\./, '').replace(/\/.*$/, '').toLowerCase();
202
208
  }
@@ -222,16 +228,16 @@
222
228
  return row;
223
229
  }
224
230
 
225
- /* the leave/decline shape: disable, POST, drop the row on success, restore
226
- the button on failure. `onRemoved` carries whatever else the caller needs
227
- after the row is gone (the empty-line flip). */
228
- function postThenRemoveRow(url, row, btn, idleLabel, onRemoved) {
231
+ /* the decline shape: disable, POST, drop the row on success, re-enable the
232
+ button on failure. `onRemoved` carries whatever else the caller needs after
233
+ the row is gone (the empty-line flip). The busy/idle label swap the /projects
234
+ copy carries is for its Leave button, which never moved here. */
235
+ function postThenRemoveRow(url, row, btn, onRemoved) {
229
236
  btn.disabled = true;
230
- if (idleLabel) btn.textContent = idleLabel.busy;
231
237
  fetch(url, { method: 'POST', credentials: 'same-origin' })
232
238
  .then(function (r) { return r.ok ? r.json() : Promise.reject(); })
233
239
  .then(function () { row.remove(); if (onRemoved) onRemoved(); })
234
- .catch(function () { btn.disabled = false; if (idleLabel) btn.textContent = idleLabel.idle; });
240
+ .catch(function () { btn.disabled = false; });
235
241
  }
236
242
 
237
243
  /* Each invitation renders as a way IN, never an Accept button: the hub's own
@@ -266,7 +272,7 @@
266
272
  decline.textContent = 'Decline';
267
273
  decline.addEventListener('click', function () {
268
274
  postThenRemoveRow(
269
- API + '/my-projects/invites/' + encodeURIComponent(inv.client_id) + '/decline', row, decline, null,
275
+ API + '/my-projects/invites/' + encodeURIComponent(inv.client_id) + '/decline', row, decline,
270
276
  paintInvitesSection
271
277
  );
272
278
  });
@@ -856,8 +862,11 @@
856
862
  list.hidden = false;
857
863
  input.setAttribute('aria-expanded', 'true');
858
864
  }
865
+ /* once the feed is cached a keystroke renders once; only the first open
866
+ paints "Loading projects…" and then re-renders when the reads settle */
859
867
  function openPicker() {
860
868
  renderPicker();
869
+ if (picker.projects) return;
861
870
  loadPicker().then(function () {
862
871
  if (document.activeElement === $('joinOrigin')) renderPicker();
863
872
  });
package/package-lock.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@bongos/core",
3
- "version": "1.21.67",
3
+ "version": "1.21.68",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@bongos/core",
9
- "version": "1.21.67",
9
+ "version": "1.21.68",
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.21.67",
3
+ "version": "1.21.68",
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",
@@ -9182,5 +9182,11 @@
9182
9182
  "id": "1004257",
9183
9183
  "text": "The cloudbongos.com landing page now has a \"Download the CLI\" button in its closing section. It picks the right download for the visitor's computer and lists the others. It stays hidden until a CLI release is published, so not"
9184
9184
  }
9185
+ ],
9186
+ "1.21.68": [
9187
+ {
9188
+ "id": "1004589",
9189
+ "text": "The /invitations project picker now draws its list once per keystroke instead of twice. Nothing looks different."
9190
+ }
9185
9191
  ]
9186
9192
  }
package/src/module-api.js CHANGED
@@ -75,7 +75,7 @@ const { responsibilityFor, ROLE_RESPONSIBILITIES } = require('./role-responsibil
75
75
  // MAJOR (see allowBoxScope below): passes the request through untouched.
76
76
  function deprecatedNoopMiddleware(_req, _res, next) { next(); }
77
77
 
78
- const CORE_VERSION = '1.21.67'; // CI auto-patch carrier (ADR 0161); changelog: docs/module-api-changelog.md
78
+ const CORE_VERSION = '1.21.68'; // CI auto-patch carrier (ADR 0161); changelog: docs/module-api-changelog.md
79
79
 
80
80
  // A namespaced logger so a module's log lines are attributable + consistent.
81
81
  // Usage: const log = api.logger('discord'); log.info('mounted');
@@ -253,6 +253,21 @@ test('the picker lists the map minus the hub, an anonymous row and your own proj
253
253
  assert.equal(ui.$('joinOrigin').value, '', 'an Applied row cannot be picked again');
254
254
  });
255
255
 
256
+ test('the picker: once the map is cached, a keystroke renders the list once (task 1004589)', async () => {
257
+ const ui = await boot({ me: { github_login: 'octocat' }, reads: { '/projects/featured': FEED, '/my-projects': MINE } });
258
+ const input = ui.$('joinOrigin');
259
+ let renders = 0;
260
+ const set = input.setAttribute;
261
+ input.setAttribute = (k, v) => { if (k === 'aria-expanded' && v === 'true') renders++; return set(k, v); };
262
+ await ui.fire(input, 'focus');
263
+ assert.equal(renders, 2, 'the first open paints "Loading projects…", then the list when the reads settle');
264
+ renders = 0;
265
+ input.value = 'grove';
266
+ await ui.fire(input, 'input');
267
+ assert.equal(renders, 1, 'not a second time when the already-settled read resolves again');
268
+ assert.deepEqual(optionsOf(ui).map((o) => o.children[0].textContent), ['The Grove']);
269
+ });
270
+
256
271
  test('the picker narrows by name or address, and the keyboard picks: arrows skip an Applied row, Enter fills the address, Escape closes', async () => {
257
272
  const ui = await boot({ me: { github_login: 'octocat' }, reads: { '/projects/featured': FEED, '/my-projects': MINE } });
258
273
  const input = ui.$('joinOrigin');