@bongos/core 1.19.138 → 1.19.140

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.138",
6
- "core_contract": "1.19.138",
7
- "source_commit": "c881ff7b166e960c529748049090f53ad17276c8",
5
+ "core_version": "1.19.140",
6
+ "core_contract": "1.19.140",
7
+ "source_commit": "10935aeebedec72d8090e9be8f6d261d3b44d787",
8
8
  "source_ref": "HEAD",
9
- "built_at": "2026-08-15T14:53:14.334Z",
9
+ "built_at": "2026-08-15T15:07:34.061Z",
10
10
  "redaction": {
11
11
  "model": "docs-redacted+functional-verbatim",
12
12
  "docs_redacted": 303,
@@ -17,7 +17,7 @@
17
17
  "gate": "passed"
18
18
  },
19
19
  "file_count": 1574,
20
- "tree_sha256": "09b573285811157440bc46ef823f8ae2adf4735d9a0d559e656a7a68793a0bdf",
20
+ "tree_sha256": "bff52e93502be3347f11913b68eb9807f14d6181c7e9f85788de9f4d21fa9c64",
21
21
  "files": [
22
22
  {
23
23
  "path": ".claude/skills/blocker-review/SKILL.md",
@@ -4177,12 +4177,12 @@
4177
4177
  {
4178
4178
  "path": "package-lock.json",
4179
4179
  "mode": "0000644",
4180
- "sha256": "b3bd34c7f961631c76f810499e202ecf7ff7b28beb3933da63fd89be5b684e6b"
4180
+ "sha256": "9a8f370c9664f4d95d9030a91829796d447c7bd2e0e5f19d7be9f34ee4f9e305"
4181
4181
  },
4182
4182
  {
4183
4183
  "path": "package.json",
4184
4184
  "mode": "0000644",
4185
- "sha256": "470274822238a12b1ad33021c5c9fc233f69beefdb30730fc7208257e01a11ef"
4185
+ "sha256": "3dab4531988ec5a8632934a63ca42c7872e899c878ffd75a85ba4ef9e0bbf806"
4186
4186
  },
4187
4187
  {
4188
4188
  "path": "public-docs/index.html",
@@ -4437,7 +4437,7 @@
4437
4437
  {
4438
4438
  "path": "public-landing/projects.html",
4439
4439
  "mode": "0000644",
4440
- "sha256": "060cfd1249c09576e634c7c84c8470207cf55b93cb0719cc89821c8c59aa2a17"
4440
+ "sha256": "1c7cb3f54e177325c60a713a3f9219ce4349be229a3638f67319484f11cfef07"
4441
4441
  },
4442
4442
  {
4443
4443
  "path": "public-landing/world/assets/clouds/cloud-island-large.png",
@@ -5767,7 +5767,7 @@
5767
5767
  {
5768
5768
  "path": "src/module-api.js",
5769
5769
  "mode": "0000644",
5770
- "sha256": "b5bbd063bab04b41b5fa8769f2c8de1e0919c28be09bcdf45345ff9440558205"
5770
+ "sha256": "ce6bcfa96110ae47a5098b08b574d9f8d015acfca354db31cd438c68362b3027"
5771
5771
  },
5772
5772
  {
5773
5773
  "path": "src/module-loader/catalog.js",
@@ -7312,7 +7312,7 @@
7312
7312
  {
7313
7313
  "path": "tests/projects_hub.mjs",
7314
7314
  "mode": "0000644",
7315
- "sha256": "ee5c944f9e3bd3d618c977e76d4e2ba3e663ce59bf7833f9427a0191717ba57d"
7315
+ "sha256": "5a3f724b4e84324d7560254517612b45fd4e4e31e57ebbb0b35a4021d712df6b"
7316
7316
  },
7317
7317
  {
7318
7318
  "path": "tests/provision.mjs",
@@ -7352,7 +7352,7 @@
7352
7352
  {
7353
7353
  "path": "tests/public_landing_projects.mjs",
7354
7354
  "mode": "0000644",
7355
- "sha256": "d0907a08d6b932d25df7b143e82c94d64a15eab66a7bd1df86ba85b1729661b7"
7355
+ "sha256": "5760a59ccce395dbc3ac7bb49df58db3acac2954ab83b345b557233bb3381e12"
7356
7356
  },
7357
7357
  {
7358
7358
  "path": "tests/public_mirror_export.mjs",
package/package-lock.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@bongos/core",
3
- "version": "1.19.138",
3
+ "version": "1.19.140",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@bongos/core",
9
- "version": "1.19.138",
9
+ "version": "1.19.140",
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.138",
3
+ "version": "1.19.140",
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",
@@ -1438,9 +1438,16 @@ h1[tabindex="-1"]:focus{outline:none;}
1438
1438
  setView('mine');
1439
1439
  tryAnchor(); /* the list may already be rendered from an earlier visit */
1440
1440
  }
1441
+ /* Card-shell lookup by instance id. CSS.escape, not esc(): the data-inst
1442
+ attribute holds the DECODED value, so an HTML-escaped id would never match
1443
+ — and raw interpolation is selector injection. esc() stays correct for
1444
+ RENDERING data-inst into markup; this is the only selector path. */
1445
+ function liFor(id) {
1446
+ return document.querySelector('li[data-inst="' + CSS.escape(String(id == null ? '' : id)) + '"]');
1447
+ }
1441
1448
  function tryAnchor() {
1442
1449
  if (!pendingAnchor) return;
1443
- var li = document.querySelector('li[data-inst="' + pendingAnchor + '"]');
1450
+ var li = liFor(pendingAnchor);
1444
1451
  if (!li) return;
1445
1452
  pendingAnchor = null;
1446
1453
  /* a search or state filter that hides the target would turn the anchor
@@ -2925,11 +2932,36 @@ h1[tabindex="-1"]:focus{outline:none;}
2925
2932
  : 'Raising the server, database, and address — nothing needed from you.',
2926
2933
  '', revive ? 'revive' : 'standup');
2927
2934
  } else if (s === 'active') {
2935
+ /* Live lights on a VERIFIED answer, not on script completion (direction
2936
+ §7): the strip keys on the same last_verified_* overlay the manage
2937
+ list's chips read. null is deliberately distinct from false — a fresh
2938
+ standup stays unprobed for up to a sweep interval and must not read
2939
+ as a failure. */
2928
2940
  var addr = inst.domain ? 'https://' + inst.domain : null;
2929
- el.innerHTML = progressMarkup(-1, 3,
2930
- 'Your project is up' + (addr ? ' — <a href="' + esc(addr) + '" target="_blank" rel="noopener">' + esc(inst.domain) + '</a>' : '') +
2931
- '. Finish the steps below and the hall is yours.', 'isLive');
2932
- return true;
2941
+ var link = addr ? '<a href="' + esc(addr) + '" target="_blank" rel="noopener">' + esc(inst.domain) + '</a>' : null;
2942
+ var flow = revive ? 'revive' : 'standup';
2943
+ if (!addr) {
2944
+ /* domainless instances are never probed — there is no address to
2945
+ answer at, so a verified answer can never arrive; say what IS true
2946
+ instead of promising the hall (sign-in stays locked without one) */
2947
+ el.innerHTML = progressMarkup(-1, 3,
2948
+ 'The build finished — your project is standing, but it has no address yet, so sign-in can’t be wired up. Attach a domain any time from <a href="?view=mine">your projects page</a>; the steps below that need one unlock then.', 'isLive', flow);
2949
+ return true;
2950
+ }
2951
+ if (inst.last_verified_up === false) {
2952
+ el.innerHTML = progressMarkup(2, 2,
2953
+ 'The build finished, but ' + link + ' isn’t answering right now — this panel keeps checking.', '', flow);
2954
+ return false;
2955
+ }
2956
+ if (inst.last_verified_up) {
2957
+ el.innerHTML = progressMarkup(-1, 3,
2958
+ 'Your project is answering at ' + link + '. Finish the steps below and the hall is yours.', 'isLive', flow);
2959
+ return true;
2960
+ }
2961
+ /* null: standing, not checked yet — keep watching until the first probe */
2962
+ el.innerHTML = progressMarkup(2, 2,
2963
+ 'The build finished — checking that ' + link + ' answers…', '', flow);
2964
+ return false;
2933
2965
  } else if (s === 'error') {
2934
2966
  /* the honest snag (direction §5 / F19): no raw stderr as the headline, no
2935
2967
  false "keeps retrying" — retries stop, and the retry door is the mine view */
@@ -3112,7 +3144,7 @@ h1[tabindex="-1"]:focus{outline:none;}
3112
3144
  var shown = 0;
3113
3145
  Object.keys(byId).forEach(function (id) {
3114
3146
  var inst = byId[id];
3115
- var li = document.querySelector('[data-inst="' + esc(String(id)) + '"]');
3147
+ var li = liFor(id);
3116
3148
  if (!li) return;
3117
3149
  var keep = (mineFilter === 'all' || groupFor(inst) === mineFilter) &&
3118
3150
  (!q || findText(inst).indexOf(q) !== -1);
@@ -3379,10 +3411,11 @@ h1[tabindex="-1"]:focus{outline:none;}
3379
3411
  }
3380
3412
 
3381
3413
  function renderCard(inst) {
3382
- /* ids are server-generated, but escape anyway — every interpolated field in
3383
- this file goes through esc(), no exceptions (the grader's rule is right) */
3414
+ /* iid is for MARKUP interpolation only (esc() = HTML escape); the DOM
3415
+ lookup goes through liFor(), which CSS-escapes — the two escapes are
3416
+ not interchangeable */
3384
3417
  var iid = esc(String(inst.id));
3385
- var li = document.querySelector('[data-inst="' + iid + '"]');
3418
+ var li = liFor(inst.id);
3386
3419
  if (!li) return;
3387
3420
  var gone = inst.status === 'torn_down';
3388
3421
  li.className = 'proj' + (gone ? ' gone' : '');
package/src/module-api.js CHANGED
@@ -703,8 +703,12 @@ const { validateOrRespond, LIMITS, parseId, asyncHandler, corsPublicGet, parsePa
703
703
  // landed since 1.19.136 with no explicit bump. run 31890033301. (task 1002620)
704
704
  // 1.19.138 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
705
705
  // landed since 1.19.137 with no explicit bump. run 31891128524. (task 1002620)
706
+ // 1.19.139 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
707
+ // landed since 1.19.138 with no explicit bump. run 31891461224. (task 1002620)
708
+ // 1.19.140 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
709
+ // landed since 1.19.139 with no explicit bump. run 31891805999. (task 1002620)
706
710
  // ---------------------------------------------------------------------------
707
- const CORE_VERSION = '1.19.138'; // CI auto-patch carrier (ADR 0161); see changelog above
711
+ const CORE_VERSION = '1.19.140'; // CI auto-patch carrier (ADR 0161); see changelog above
708
712
 
709
713
  // A namespaced logger so a module's log lines are attributable + consistent.
710
714
  // Usage: const log = api.logger('dev-box'); log.info('mounted');
@@ -765,6 +765,23 @@ test('an owned orb\'s job is manage, not the public site', () => {
765
765
  'the orb route key must not collide with the manage list\'s card identity');
766
766
  });
767
767
 
768
+ test('the card-shell lookup CSS-escapes the id — HTML-escape never reaches a selector (task 1002893)', () => {
769
+ const fn = (SCRIPT.match(/function liFor\(([\s\S]*?)\n \}/) || [, ''])[1];
770
+ assert.ok(fn, 'liFor() must be extractable');
771
+ assert.match(fn, /CSS\.escape\(/, 'the selector path escapes with CSS.escape, not esc()');
772
+ // liFor is the ONLY data-inst selector site — esc() belongs to markup
773
+ // rendering, where it stays; a second selector site could quietly restore
774
+ // the esc()-in-selector (or no-escape) shape this test exists to kill
775
+ const sel = SCRIPT.match(/\[data-inst="' \+/g) || [];
776
+ assert.equal(sel.length, 1, 'exactly one data-inst selector concatenation (inside liFor)');
777
+ assert.match(SCRIPT, /\[data-inst="' \+ CSS\.escape\(/, 'and that one site CSS-escapes');
778
+ // the two prior wrong shapes, by name
779
+ assert.doesNotMatch(SCRIPT, /\[data-inst="' \+ esc\(/,
780
+ 'an HTML-escaped id must never be interpolated into a selector');
781
+ assert.doesNotMatch(SCRIPT, /\[data-inst="' \+ pendingAnchor/,
782
+ 'raw interpolation into a selector is the injection-shaped site');
783
+ });
784
+
768
785
  test('the orb chip is the manage list\'s truth, never a second story (C6)', () => {
769
786
  const orbs = (SCRIPT.match(/function renderOrbs\(([\s\S]*?)\n \}/) || [, ''])[1];
770
787
  // exactly ONE chip site, and it defers to chipFor() — a second site could
@@ -160,6 +160,22 @@ test('the done panel reads the open intent — a queued revive is never told to
160
160
  assert.match(body, /\.prog\.flowDown/, 'the .prog strip has the teardown palette (transcribed from .strip.flowDown)');
161
161
  });
162
162
 
163
+ test('the done panel lights Live on a verified answer, never on status alone (task 1002895)', async () => {
164
+ const { body } = await request('/projects', 'game.test.local');
165
+ const fn = (body.match(/function renderProgress\(inst\)\s*\{([\s\S]*?)\n \}/) || [, ''])[1];
166
+ assert.ok(fn, 'renderProgress() must be extractable');
167
+ assert.match(fn, /last_verified_up/, 'the strip reads the verification overlay, not status alone');
168
+ // the three honest rungs: verified, failed probe, and never-probed —
169
+ // null is deliberately distinct from false and must not read as a failure
170
+ assert.match(fn, /answering at/i, 'verified speaks the list view\'s language');
171
+ assert.match(fn, /isn’t answering right now/, 'a failed probe is spoken, never painted green');
172
+ assert.match(fn, /checking that/, 'the never-probed instance gets its own calm rung');
173
+ // gap row 8: domainless is never probed at all — it states its truth instead
174
+ // of promising the hall (sign-in stays locked without an address)
175
+ assert.match(fn, /no address yet/, 'the domainless path cannot fall into an unverified hole');
176
+ assert.doesNotMatch(fn, /Your project is up/, 'the status-alone headline is dead');
177
+ });
178
+
163
179
  test('the address row surfaces the manual-DNS note the runner recorded (F16)', async () => {
164
180
  const { body } = await request('/projects', 'game.test.local');
165
181
  assert.match(body, /inst\.dns_note/, 'the card reads the dns_note the runner writes');