@bongos/core 1.19.140 → 1.19.141

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.140",
6
- "core_contract": "1.19.140",
7
- "source_commit": "10935aeebedec72d8090e9be8f6d261d3b44d787",
5
+ "core_version": "1.19.141",
6
+ "core_contract": "1.19.141",
7
+ "source_commit": "b945e540f7d2e847172a7d529a393ef7ed3cd181",
8
8
  "source_ref": "HEAD",
9
- "built_at": "2026-08-15T15:07:34.061Z",
9
+ "built_at": "2026-08-15T15:22:10.867Z",
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": "bff52e93502be3347f11913b68eb9807f14d6181c7e9f85788de9f4d21fa9c64",
20
+ "tree_sha256": "ebfb642cad8b628d4485648012f4b179c33923d35f37dd4f4be28e87245f99b9",
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": "9a8f370c9664f4d95d9030a91829796d447c7bd2e0e5f19d7be9f34ee4f9e305"
4180
+ "sha256": "e2dbef1b10a02d42af480300fa0be08f86312d8be984a64e1f0522f5f70b1152"
4181
4181
  },
4182
4182
  {
4183
4183
  "path": "package.json",
4184
4184
  "mode": "0000644",
4185
- "sha256": "3dab4531988ec5a8632934a63ca42c7872e899c878ffd75a85ba4ef9e0bbf806"
4185
+ "sha256": "624eb72a1cc5d8f63b33038e823818c93159c0f92351f011c88202618c2aff45"
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": "1c7cb3f54e177325c60a713a3f9219ce4349be229a3638f67319484f11cfef07"
4440
+ "sha256": "1823d08908672433c4ef47c9320598fd1e6c949836daf8f874b5b802fc43f9c5"
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": "ce6bcfa96110ae47a5098b08b574d9f8d015acfca354db31cd438c68362b3027"
5770
+ "sha256": "851121766a8f979a937d436e38efa09f77dae45687c464d7a5a8185373a0fcbe"
5771
5771
  },
5772
5772
  {
5773
5773
  "path": "src/module-loader/catalog.js",
@@ -7352,7 +7352,7 @@
7352
7352
  {
7353
7353
  "path": "tests/public_landing_projects.mjs",
7354
7354
  "mode": "0000644",
7355
- "sha256": "5760a59ccce395dbc3ac7bb49df58db3acac2954ab83b345b557233bb3381e12"
7355
+ "sha256": "d7998f770254f2c0179a6269d408f571c8757a97defd2543462b8496cb5f3e23"
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.140",
3
+ "version": "1.19.141",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@bongos/core",
9
- "version": "1.19.140",
9
+ "version": "1.19.141",
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.140",
3
+ "version": "1.19.141",
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",
@@ -159,6 +159,10 @@ h1[tabindex="-1"]:focus{outline:none;}
159
159
  }
160
160
  .humanSteps b{font-size:15px;}
161
161
  .humanSteps p{font-size:13.5px;font-weight:500;color:var(--ink-soft);line-height:1.55;margin-top:4px;}
162
+ /* a repo the platform already handled is named as a plain inline link (task 1002855) —
163
+ the .ghbtn treatment reads as an action to take, and there is nothing here to do */
164
+ .humanSteps p a{color:var(--accent-deep);font-weight:700;text-decoration:none;}
165
+ .humanSteps p a:hover{text-decoration:underline;}
162
166
  /* live checklist states (task 1002694): a step the platform has verified done, and a
163
167
  step that can't be performed yet (its prerequisite — usually the domain — is missing) */
164
168
  .humanSteps>li.sdone{border-color:color-mix(in srgb,var(--ok) 30%,var(--bg-card));background:linear-gradient(180deg,color-mix(in srgb,var(--ok) 8%,var(--bg-card)) 0%,var(--bg-card) 100%);}
@@ -2154,6 +2158,19 @@ h1[tabindex="-1"]:focus{outline:none;}
2154
2158
  if (owner) u.searchParams.set('owner', owner);
2155
2159
  return u.toString();
2156
2160
  }
2161
+ /* github.com address of the repo this draft points at, or '' when we can't name one
2162
+ honestly. Adopt: owner/repo IS the address the owner picked. Auto-create: the
2163
+ html_url the create call returned — a draft predating task 1002855 has none, and
2164
+ gets no link rather than a guess that could 404. The scheme is hard-coded and both
2165
+ segments are encoded, so nothing here can become an off-site or javascript: href. */
2166
+ function repoLinkFor() {
2167
+ if (!state.owner || !state.repo) return '';
2168
+ if (state.mode === 'adopt') {
2169
+ return 'https://github.com/' + encodeURIComponent(state.owner) + '/' + encodeURIComponent(state.repo);
2170
+ }
2171
+ var stored = String(state.repoUrl || '');
2172
+ return stored.indexOf('https://github.com/') === 0 ? stored : '';
2173
+ }
2157
2174
  function saveDraft() {
2158
2175
  try { sessionStorage.setItem(DRAFT_KEY, JSON.stringify(state)); } catch (e) {}
2159
2176
  }
@@ -2554,6 +2571,10 @@ h1[tabindex="-1"]:focus{outline:none;}
2554
2571
  state.owner = full.slice(0, full.indexOf('/'));
2555
2572
  state.repo = full.slice(full.indexOf('/') + 1);
2556
2573
  }
2574
+ /* Keep GitHub's own html_url so the done panel can link the repo it made
2575
+ (task 1002855). It rides saveDraft(), so a resumed draft keeps the link. */
2576
+ var made = data.repo && data.repo.html_url;
2577
+ if (typeof made === 'string' && made.indexOf('https://github.com/') === 0) state.repoUrl = made;
2557
2578
  state.repoAutoCreated = true; saveDraft();
2558
2579
  });
2559
2580
  });
@@ -2664,15 +2685,23 @@ h1[tabindex="-1"]:focus{outline:none;}
2664
2685
  function renderStepGithubRepo() {
2665
2686
  var landed = live.instStatus === 'active';
2666
2687
  var repoLabel = state.owner && state.repo ? '<strong>' + esc(state.owner + '/' + state.repo) + '</strong>' : 'your new repository';
2688
+ /* Naming a repo without linking it stranded the owner on exactly the path where the
2689
+ platform did the work (task 1002855). Adopt links the repo the owner picked;
2690
+ auto-create links the html_url GitHub itself returned. A draft written before this
2691
+ change carries no stored URL and degrades to the bare name — never a guessed link.
2692
+ Only these two branches link: the manual branch below still has a real .ghbtn
2693
+ action, and nesting an <a> inside it would be malformed. */
2694
+ var repoUrl = repoLinkFor();
2695
+ var repoLink = repoUrl ? '<a href="' + esc(repoUrl) + '" target="_blank" rel="noopener">' + repoLabel + '</a>' : repoLabel;
2667
2696
  if (state.mode === 'adopt') {
2668
2697
  return landed
2669
- ? '<li class="sdone" data-onboard-step="github-repo"><b>Your repo carries the platform</b><p>The build layered the platform onto ' + repoLabel + ' — existing files, history, and backlog kept. Pull to see it.</p></li>'
2670
- : '<li data-onboard-step="github-repo"><b>Your existing repo</b><p>The build clones ' + repoLabel + ' and layers the platform onto its existing history — nothing is created or emptied, and your backlog is imported. Nothing for you to do here.</p></li>';
2698
+ ? '<li class="sdone" data-onboard-step="github-repo"><b>Your repo carries the platform</b><p>The build layered the platform onto ' + repoLink + ' — existing files, history, and backlog kept. Pull to see it.</p></li>'
2699
+ : '<li data-onboard-step="github-repo"><b>Your existing repo</b><p>The build clones ' + repoLink + ' and layers the platform onto its existing history — nothing is created or emptied, and your backlog is imported. Nothing for you to do here.</p></li>';
2671
2700
  }
2672
2701
  if (state.repoAutoCreated) {
2673
2702
  return landed
2674
- ? '<li class="sdone" data-onboard-step="github-repo"><b>Repo ready — scaffold landed</b><p>We created ' + repoLabel + ' (public, by design) and the build pushed your project’s starting files to it.</p></li>'
2675
- : '<li data-onboard-step="github-repo"><b>Your empty repo is ready</b><p>We created ' + repoLabel + ' on GitHub for you — public (projects here are open by design), empty, and waiting. The scaffold lands there when the build runs; nothing for you to do here.</p></li>';
2703
+ ? '<li class="sdone" data-onboard-step="github-repo"><b>Repo ready — scaffold landed</b><p>We created ' + repoLink + ' (public, by design) and the build pushed your project’s starting files to it.</p></li>'
2704
+ : '<li data-onboard-step="github-repo"><b>Your empty repo is ready</b><p>We created ' + repoLink + ' on GitHub for you — public (projects here are open by design), empty, and waiting. The scaffold lands there when the build runs; nothing for you to do here.</p></li>';
2676
2705
  }
2677
2706
  var ghNewUrl = githubNewRepoUrl(state.owner, state.repo);
2678
2707
  return '<li' + (landed ? ' class="sdone"' : '') + ' data-onboard-step="github-repo"><b>Create the empty GitHub repo</b><p>Do this first — the build needs the repo to exist. Click below (GitHub opens with the owner and name already filled in), press <strong>Create repository</strong>, and leave it completely empty. It must land at exactly ' + repoLabel + ' — leave GitHub’s Owner box as prefilled (your personal account), because the build watches that exact address; a repo created under a different owner (an organization, say) is never found. GitHub will ask public or private — your choice; both work here, and we never change it. Seeing “repository not found” above? That just means the repo isn’t created yet — make it here.</p>' +
package/src/module-api.js CHANGED
@@ -707,8 +707,10 @@ const { validateOrRespond, LIMITS, parseId, asyncHandler, corsPublicGet, parsePa
707
707
  // landed since 1.19.138 with no explicit bump. run 31891461224. (task 1002620)
708
708
  // 1.19.140 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
709
709
  // landed since 1.19.139 with no explicit bump. run 31891805999. (task 1002620)
710
+ // 1.19.141 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
711
+ // landed since 1.19.140 with no explicit bump. run 31892484952. (task 1002620)
710
712
  // ---------------------------------------------------------------------------
711
- const CORE_VERSION = '1.19.140'; // CI auto-patch carrier (ADR 0161); see changelog above
713
+ const CORE_VERSION = '1.19.141'; // CI auto-patch carrier (ADR 0161); see changelog above
712
714
 
713
715
  // A namespaced logger so a module's log lines are attributable + consistent.
714
716
  // Usage: const log = api.logger('dev-box'); log.info('mounted');
@@ -176,6 +176,81 @@ test('the done panel lights Live on a verified answer, never on status alone (ta
176
176
  assert.doesNotMatch(fn, /Your project is up/, 'the status-alone headline is dead');
177
177
  });
178
178
 
179
+ /* ── The done panel's GitHub step (task 1002855) ─────────────────────────────
180
+ 'We created <repo> on GitHub for you' named a repo and handed the owner nothing
181
+ to click, while the manual-create branch right below it rendered a full button:
182
+ the one path where the PLATFORM did the work was the one that stranded them
183
+ (owner-reported during the task 1002697 walk). Adopt named a repo unlinked too. ── */
184
+
185
+ test('the auto-created repo is linked in the done panel, not merely named', async () => {
186
+ const { body } = await request('/projects', 'game.test.local');
187
+ const fn = (body.match(/function renderStepGithubRepo\(\)\s*\{([\s\S]*?)\n \}/) || [, ''])[1];
188
+ assert.ok(fn, 'renderStepGithubRepo() must be extractable');
189
+ const auto = (fn.match(/if \(state\.repoAutoCreated\) \{([\s\S]*?)\n \}/) || [, ''])[1];
190
+ assert.ok(auto, 'the auto-created branch must be extractable');
191
+ assert.match(auto, /We created/, 'this is the copy the owner reported');
192
+ // BOTH copies — scaffold landed and not yet landed — carry the link
193
+ assert.equal((auto.match(/repoLink/g) || []).length, 2,
194
+ 'the landed and pre-landed copies must both link the repo');
195
+ assert.doesNotMatch(auto, /repoLabel/,
196
+ 'no auto-created copy may still name the repo without linking it');
197
+ });
198
+
199
+ test('the adopt branch links the repo it names', async () => {
200
+ const { body } = await request('/projects', 'game.test.local');
201
+ const fn = (body.match(/function renderStepGithubRepo\(\)\s*\{([\s\S]*?)\n \}/) || [, ''])[1];
202
+ const adopt = (fn.match(/if \(state\.mode === 'adopt'\) \{([\s\S]*?)\n \}/) || [, ''])[1];
203
+ assert.ok(adopt, 'the adopt branch must be extractable');
204
+ assert.equal((adopt.match(/repoLink/g) || []).length, 2,
205
+ 'both adopt copies must link the repo the owner picked');
206
+ assert.doesNotMatch(adopt, /repoLabel/, 'adopt may not name a repo unlinked either');
207
+ });
208
+
209
+ test('the auto-created link is a plain inline link, never the .ghbtn call to action', async () => {
210
+ const { body } = await request('/projects', 'game.test.local');
211
+ const fn = (body.match(/function renderStepGithubRepo\(\)\s*\{([\s\S]*?)\n \}/) || [, ''])[1];
212
+ const decl = (fn.match(/var repoLink = [^\n]*/) || [''])[0];
213
+ assert.match(decl, /<a href="/, 'the link is built as an anchor');
214
+ assert.match(decl, /esc\(repoUrl\)/, 'the href goes through the page escaper');
215
+ assert.match(decl, /rel="noopener"/, 'a target=_blank link carries rel=noopener');
216
+ assert.doesNotMatch(decl, /ghbtn/, 'there is nothing to DO here — no button treatment');
217
+ // the manual-create branch keeps its real .ghbtn action, and an anchor nested
218
+ // inside that anchor would be malformed — so only the two done branches link
219
+ assert.match(fn, /class="ghbtn"/, 'the manual-create button survives untouched');
220
+ // and the plain link needs a style, or it falls back to the browser's blue
221
+ assert.match(body, /\.humanSteps p a\{/, 'the inline link is styled with the page palette');
222
+ });
223
+
224
+ test('a draft with no stored repo URL renders no link — never a guessed one', async () => {
225
+ const { body } = await request('/projects', 'game.test.local');
226
+ const src = (body.match(/(function repoLinkFor\(\)\s*\{[\s\S]*?\n \})/) || [, ''])[1];
227
+ assert.ok(src, 'repoLinkFor() must be extractable');
228
+ const urlFor = (state) => new Function('state', `${src}\nreturn repoLinkFor();`)(state);
229
+
230
+ // the real auto-created path: GitHub's own html_url, kept on the draft
231
+ assert.equal(
232
+ urlFor({ mode: 'greenfield', owner: 'someone', repo: 'thing', repoAutoCreated: true, repoUrl: 'https://github.com/someone/thing' }),
233
+ 'https://github.com/someone/thing');
234
+ // a draft written before task 1002855 has no stored URL — it degrades to none
235
+ assert.equal(
236
+ urlFor({ mode: 'greenfield', owner: 'someone', repo: 'thing', repoAutoCreated: true }), '');
237
+ // adopt has no server-supplied URL: the repo the owner picked IS the address
238
+ assert.equal(urlFor({ mode: 'adopt', owner: 'someone', repo: 'thing' }), 'https://github.com/someone/thing');
239
+ // nothing named yet, and anything that isn't a github.com URL, link to nothing
240
+ assert.equal(urlFor({ mode: 'adopt', owner: '', repo: '' }), '');
241
+ assert.equal(urlFor({ mode: 'greenfield', owner: 'a', repo: 'b', repoUrl: 'javascript:alert(1)' }), '');
242
+ assert.equal(urlFor({ mode: 'greenfield', owner: 'a', repo: 'b', repoUrl: 'https://evil.example/x' }), '');
243
+ });
244
+
245
+ test('the create-repo response keeps the html_url it already returned', async () => {
246
+ const { body } = await request('/projects', 'game.test.local');
247
+ const fn = (body.match(/function ensureFreshRepo\(\)\s*\{([\s\S]*?)\n \}/) || [, ''])[1];
248
+ assert.ok(fn, 'ensureFreshRepo() must be extractable');
249
+ assert.match(fn, /data\.repo && data\.repo\.html_url/, 'the URL is read off the response, not dropped');
250
+ assert.match(fn, /state\.repoUrl = made/, 'and stored on the draft so a resume keeps it');
251
+ assert.match(fn, /saveDraft\(\)/, 'the draft is persisted after the URL lands on state');
252
+ });
253
+
179
254
  test('the address row surfaces the manual-DNS note the runner recorded (F16)', async () => {
180
255
  const { body } = await request('/projects', 'game.test.local');
181
256
  assert.match(body, /inst\.dns_note/, 'the card reads the dns_note the runner writes');