@bongos/core 1.24.25 → 1.24.27
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 +173 -108
- package/docs/adr/0307-autobongos-a-deterministic-supervisor-and-agentic-workers.md +12 -0
- package/docs/copy-inventory.md +280 -256
- package/docs/copy-registry.json +572 -306
- package/docs/module-api-changelog.md +4 -0
- package/docs/page-inventory.json +10 -4
- package/docs/page-readings.json +4337 -4313
- package/docs/recipes/ui-look-before-you-ship.md +1 -0
- package/modules/autonomy/fence.js +16 -1
- package/modules/government/protected-surfaces.json +2 -0
- package/modules/hall-ui/public/ai-studio.html +2 -2
- package/modules/hall-ui/public/atlas.html +1 -1
- package/modules/hall-ui/public/blockers.html +2 -2
- package/modules/hall-ui/public/blockers.js +3 -1
- package/modules/hall-ui/public/board-room.html +3 -1
- package/modules/hall-ui/public/city.html +1 -1
- package/modules/hall-ui/public/collab.html +4 -4
- package/modules/hall-ui/public/collab.js +4 -0
- package/modules/hall-ui/public/commands.html +3 -3
- package/modules/hall-ui/public/copy-desk.html +3 -3
- package/modules/hall-ui/public/core-move-notice.js +9 -6
- package/modules/hall-ui/public/criterion-uat-ui.js +1 -1
- package/modules/hall-ui/public/deploy-handoff.js +203 -0
- package/modules/hall-ui/public/deploy.html +6 -2
- package/modules/hall-ui/public/deploy.js +7 -1
- package/modules/hall-ui/public/diagrams.html +1 -1
- package/modules/hall-ui/public/drachmae.html +2 -2
- package/modules/hall-ui/public/fleet.html +3 -1
- package/modules/hall-ui/public/gate.html +3 -1
- package/modules/hall-ui/public/goal-map.html +1 -1
- package/modules/hall-ui/public/goals-page.js +1 -1
- package/modules/hall-ui/public/goals.css +3 -2
- package/modules/hall-ui/public/goals.html +3 -3
- package/modules/hall-ui/public/goals.js +1 -1
- package/modules/hall-ui/public/government.html +3 -1
- package/modules/hall-ui/public/hall-widgets.js +9 -9
- package/modules/hall-ui/public/idea.html +1 -1
- package/modules/hall-ui/public/ideas.html +3 -3
- package/modules/hall-ui/public/index.html +3 -1
- package/modules/hall-ui/public/lightbulb.js +1 -1
- package/modules/hall-ui/public/market-watch-item.html +2 -2
- package/modules/hall-ui/public/market-watch-rules.html +2 -2
- package/modules/hall-ui/public/market-watch-settings.html +3 -1
- package/modules/hall-ui/public/market-watch.html +2 -2
- package/modules/hall-ui/public/modules.html +2 -2
- package/modules/hall-ui/public/my-agents.html +3 -3
- package/modules/hall-ui/public/primer.html +2 -2
- package/modules/hall-ui/public/profile.html +6 -6
- package/modules/hall-ui/public/project-settings.html +3 -1
- package/modules/hall-ui/public/ranks.html +4 -4
- package/modules/hall-ui/public/roadmap.html +2 -2
- package/modules/hall-ui/public/roster.html +2 -2
- package/modules/hall-ui/public/sessions.html +3 -1
- package/modules/hall-ui/public/settings-software-update.js +23 -9
- package/modules/hall-ui/public/settings-specialities.js +1 -1
- package/modules/hall-ui/public/settings.html +10 -6
- package/modules/hall-ui/public/settings.js +3 -0
- package/modules/hall-ui/public/shell.js +25 -73
- package/modules/hall-ui/public/street.html +1 -1
- package/modules/hall-ui/public/studio.html +1 -1
- package/modules/hall-ui/public/studio.js +3 -3
- package/modules/hall-ui/public/style.css +209 -40
- package/modules/hall-ui/public/task-detail.js +2 -2
- package/modules/hall-ui/public/task.html +1 -1
- package/modules/hall-ui/public/thinking.html +1 -1
- package/modules/hall-ui/public/tweak-editor.html +2 -2
- package/modules/hall-ui/public/update-pill.js +623 -0
- package/modules/hall-ui/public/watch.html +3 -1
- package/modules/hall-ui/public/watch.js +1 -1
- package/modules/hall-ui/public/work.html +4 -4
- package/modules/hall-ui/records/loader.md +35 -0
- package/modules/hall-ui/records/update-pill.md +12 -0
- package/modules/lifecycle/github-push.js +1 -0
- package/modules/lifecycle/routes/tasks.js +2 -2
- package/modules/lifecycle/runner-self-guard.js +122 -0
- package/modules/lifecycle/runner-self.js +154 -0
- package/modules/public-landing/public/account.html +3 -3
- package/modules/public-landing/public/assets/cosmos.css +45 -0
- package/modules/public-landing/public/community.html +4 -4
- package/modules/public-landing/public/connections.html +1 -1
- package/modules/public-landing/public/guild.html +1 -1
- package/modules/public-landing/public/invitations.html +4 -4
- package/modules/public-landing/public/projects.html +26 -26
- package/modules/status-ui/public/index.html +2 -2
- package/modules/status-ui/public/index.states.json +12 -0
- package/modules/status-ui/public/status.js +10 -2
- package/modules/status-ui/public/style.css +57 -0
- package/modules/ui-design/kit/README.md +1 -1
- package/modules/ui-design/kit/serve.js +8 -1
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/release-notes.json +24 -0
- package/scripts/bongos/autobongos-loop.js +4 -0
- package/scripts/bongos/autobongos-run.js +21 -4
- package/scripts/bongos/autobongos-tweak-lane.js +5 -3
- package/scripts/bongos/ship-flow.js +20 -0
- package/scripts/hall-preview/README.md +1 -0
- package/scripts/hall-preview/server.js +9 -0
- package/src/bongos/apex-hall-redirects.js +53 -0
- package/src/bongos/serve-internal.js +3 -18
- package/src/module-api.js +1 -1
- package/tests/autobongos_host_access.mjs +5 -3
- package/tests/autobongos_self_modification.mjs +420 -0
- package/tests/core_update_banner.mjs +6 -92
- package/tests/core_upgrade_owner_door.mjs +4 -56
- package/tests/deploy_handoff.mjs +206 -0
- package/tests/government_protected_surfaces.mjs +15 -0
- package/tests/hall_loading.mjs +153 -0
- package/tests/hub_connections_page.mjs +1 -1
- package/tests/hub_invitations_page.mjs +1 -1
- package/tests/loading_mark.mjs +203 -0
- package/tests/nav_permission_atoms.mjs +3 -2
- package/tests/software_update.mjs +39 -2
- package/tests/update_pill.mjs +431 -0
|
@@ -7,11 +7,12 @@
|
|
|
7
7
|
// update channel lets it take; what each version in between brings — and, for the people
|
|
8
8
|
// the upgrade door lets through, an Update button.
|
|
9
9
|
//
|
|
10
|
-
// THE BUTTON
|
|
11
|
-
//
|
|
12
|
-
//
|
|
13
|
-
//
|
|
14
|
-
//
|
|
10
|
+
// THE BUTTON RUNS THE PILL'S FLOW; IT IS NOT A SECOND DOOR. Taking an update is the deploy
|
|
11
|
+
// door's act, with its health check and auto-rollback (ADR 0293), and on a hosted project that
|
|
12
|
+
// door is on the hub (ADR 0339 D3). Since task 1005041 the button hands this panel's reading to
|
|
13
|
+
// update-pill.js, which takes the update in place (this page names the version; the door moves
|
|
14
|
+
// it), so there is one copy of that flow, not two. The server still names the door (`door`),
|
|
15
|
+
// and the button's href is that door, for a page whose pill script did not load.
|
|
15
16
|
//
|
|
16
17
|
// THE PAGE KNOWS NOTHING (deploy.js's rule, kept). Every version here is the server's reading
|
|
17
18
|
// with the time it was taken. "Up to date" is drawn only from an ok reading with nothing
|
|
@@ -125,11 +126,14 @@
|
|
|
125
126
|
if (!sameOrigin && !/^https?:\/\/[^\s"'<>]+$/i.test(url)) return '';
|
|
126
127
|
let where = '';
|
|
127
128
|
if (!sameOrigin) {
|
|
128
|
-
try { where =
|
|
129
|
+
try { where = new URL(url).host; } catch (e) { return ''; }
|
|
129
130
|
}
|
|
131
|
+
// IN PLACE (task 1005041): the button runs the Update pill's flow (update-pill.js) and the
|
|
132
|
+
// page stays put; the pill in the top bar shows the progress. The href stays the door's,
|
|
133
|
+
// so a page whose pill script did not load still reaches the update the old way.
|
|
130
134
|
return `<div class="row-end su-door">
|
|
131
|
-
<a class="pbtn pbtn--save" id="su-update" href="${escapeHtml(url)}">Update to ${escapeHtml(offered)}
|
|
132
|
-
<span class="panel-hint">
|
|
135
|
+
<a class="pbtn pbtn--save" id="su-update" href="${escapeHtml(url)}">Update to ${escapeHtml(offered)}</a>
|
|
136
|
+
<span class="panel-hint">Takes a few minutes. The project restarts once, checks itself, and goes back to the version it runs now if it does not come back healthy.${where ? ` A small window from ${escapeHtml(where)} opens for a moment to start it.` : ''}</span>
|
|
133
137
|
</div>${door.kind === 'hub' && ask.available ? askHtml(ask, offered, { lead: false }) : ''}`;
|
|
134
138
|
}
|
|
135
139
|
|
|
@@ -236,6 +240,16 @@
|
|
|
236
240
|
const askBtn = byId('su-ask');
|
|
237
241
|
if (askBtn) askBtn.addEventListener('click', () => askForUpgrade(data, askBtn));
|
|
238
242
|
|
|
243
|
+
// The same press as the pill's Update now; only when it took the update in place is the
|
|
244
|
+
// link's own navigation stopped.
|
|
245
|
+
const updateBtn = byId('su-update');
|
|
246
|
+
if (updateBtn) {
|
|
247
|
+
updateBtn.addEventListener('click', (e) => {
|
|
248
|
+
const pill = window.OTBUpdatePill;
|
|
249
|
+
if (pill && pill.updateNow(data, { api })) e.preventDefault();
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
|
|
239
253
|
const more = byId('su-more');
|
|
240
254
|
if (more) {
|
|
241
255
|
more.addEventListener('click', () => {
|
|
@@ -275,7 +289,7 @@
|
|
|
275
289
|
if (asked) return;
|
|
276
290
|
asked = true;
|
|
277
291
|
const body = byId('su-body');
|
|
278
|
-
if (body) body.innerHTML = '<p class="
|
|
292
|
+
if (body) body.innerHTML = '<p class="hall-loading hall-loading--inline" role="status">Checking for a newer version…</p>';
|
|
279
293
|
try {
|
|
280
294
|
const res = await api.request('GET', `${API}/software-update`);
|
|
281
295
|
if (res.status === 401) { window.location.assign(`${API}/auth/web/start`); return; }
|
|
@@ -276,7 +276,7 @@
|
|
|
276
276
|
return `
|
|
277
277
|
<form class="speciality-offer" data-id="${escapeHtml(String(s.id))}">
|
|
278
278
|
<h4 class="speciality-create__h">What ${escapeHtml(s.name)} offers</h4>
|
|
279
|
-
<div class="speciality-offer__choices">${state.offerChoices || '<p class="
|
|
279
|
+
<div class="speciality-offer__choices">${state.offerChoices || '<p class="hall-loading hall-loading--inline" role="status">Loading this project’s skills…</p>'}</div>
|
|
280
280
|
<div class="speciality-actions">
|
|
281
281
|
<button type="submit" class="btn" ${state.offerChoices ? '' : 'disabled'}>Save what it offers</button>
|
|
282
282
|
</div>
|
|
@@ -54,6 +54,8 @@
|
|
|
54
54
|
<nav class="section-rail" id="settings-rail" aria-label="Settings sections"></nav>
|
|
55
55
|
|
|
56
56
|
<div class="settings-groups" id="settings-groups" data-active="account">
|
|
57
|
+
<!-- task 1005043: the panel loader, until settings.js has read who is viewing (hideLayout). -->
|
|
58
|
+
<p class="hall-loading hall-loading--page" id="settings-loading" role="status">Loading…</p>
|
|
57
59
|
|
|
58
60
|
<!-- ============ group: account ============ -->
|
|
59
61
|
|
|
@@ -344,7 +346,7 @@
|
|
|
344
346
|
</label>
|
|
345
347
|
<details id="speciality-create-offer" class="speciality-offer-box">
|
|
346
348
|
<summary>Skills it offers <small>(optional)</small></summary>
|
|
347
|
-
<div id="speciality-create-skills"><p class="
|
|
349
|
+
<div id="speciality-create-skills"><p class="hall-loading hall-loading--inline" role="status">Loading this project’s skills…</p></div>
|
|
348
350
|
</details>
|
|
349
351
|
<div class="speciality-actions">
|
|
350
352
|
<button type="submit" class="btn">Create speciality</button>
|
|
@@ -473,9 +475,9 @@
|
|
|
473
475
|
<!-- SOFTWARE UPDATE — this project's version, the newest release its update
|
|
474
476
|
channel allows, and what the versions between them carry (task 1004296).
|
|
475
477
|
Like a phone's Software Update screen: every builder reads it; the Update
|
|
476
|
-
button is drawn only for those the upgrade door lets through, and it
|
|
477
|
-
|
|
478
|
-
|
|
478
|
+
button is drawn only for those the upgrade door lets through, and it runs
|
|
479
|
+
the Update pill's in-place flow (update-pill.js, task 1005041): the act is
|
|
480
|
+
still the door's, with its auto-rollback (ADR 0293). Rendered by settings-software-update.js
|
|
479
481
|
from GET /api/bongos/software-update, read only when this group opens:
|
|
480
482
|
an update's notes come out of a package download. -->
|
|
481
483
|
<section class="scroll" id="software-update-scroll" aria-labelledby="software-update-h" data-group="update" hidden>
|
|
@@ -512,7 +514,7 @@
|
|
|
512
514
|
<script src="/builders/dom-utils.js?v=2026-10-25-escape"></script>
|
|
513
515
|
<script src="/builders/shell-trail.js?v=2026-10-08-city-tab"></script>
|
|
514
516
|
<script src="/builders/craft-mode.js?v=2026-10-30-market-watch"></script>
|
|
515
|
-
<script src="/builders/shell.js?v=2026-
|
|
517
|
+
<script src="/builders/shell.js?v=2026-11-03-update-pill"></script>
|
|
516
518
|
<!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
|
|
517
519
|
<script src="/builders/palette.js" defer></script>
|
|
518
520
|
<!-- shared component kit (window.OTBKit) — section rail (task 2166). -->
|
|
@@ -538,7 +540,9 @@
|
|
|
538
540
|
settings.js is against the 1500-line ratchet. -->
|
|
539
541
|
<script src="/builders/settings-render.js?v=2026-09-16-render-levels"></script>
|
|
540
542
|
<!-- task 1004296: Settings → Software update. Own file on the same precedent. -->
|
|
541
|
-
|
|
543
|
+
<!-- the Update pill's flow, which the panel's Update button runs in place (task 1005041) -->
|
|
544
|
+
<script src="/builders/update-pill.js?v=2026-11-03-pill"></script>
|
|
545
|
+
<script src="/builders/settings-software-update.js?v=2026-11-03-pill"></script>
|
|
542
546
|
<!-- task 1004501: Settings → Your Autobongos runner. Own file on the same precedent. -->
|
|
543
547
|
<script src="/builders/settings-autobongos.js?v=2026-10-01-autobongos"></script>
|
|
544
548
|
<!-- task 1003793: Settings → Module install reports. Own file on the same precedent. -->
|
|
@@ -1186,6 +1186,9 @@
|
|
|
1186
1186
|
function hideLayout(hide) {
|
|
1187
1187
|
const layout = document.getElementById('settings-layout');
|
|
1188
1188
|
if (layout) layout.hidden = !!hide;
|
|
1189
|
+
// Every path past /me decides the layout here, so the page loader stops here too (task 1005043).
|
|
1190
|
+
const loading = document.getElementById('settings-loading');
|
|
1191
|
+
if (loading) loading.hidden = true;
|
|
1189
1192
|
}
|
|
1190
1193
|
|
|
1191
1194
|
// ---- bootstrap -----------------------------------------------------------
|
|
@@ -751,8 +751,11 @@
|
|
|
751
751
|
history.replaceState(null, '', window.location.pathname + rest + window.location.hash);
|
|
752
752
|
}
|
|
753
753
|
|
|
754
|
-
// task 1004045 — the
|
|
755
|
-
//
|
|
754
|
+
// task 1004045 → task 1005041 — the Update pill. The owner's first ask was a banner at the top
|
|
755
|
+
// of every owner's hall when a core update is released; the second (2026-11-03) was that it
|
|
756
|
+
// was "way too obstructing and not obvious what to do", and should feel like the Claude
|
|
757
|
+
// app's "restart to update". So the news is a quiet pill in the top bar now, and the
|
|
758
|
+
// update is taken in place from it: update-pill.js owns all of it, this only asks.
|
|
756
759
|
//
|
|
757
760
|
// WHY THE SERVER IS ASKED RATHER THAN TOLD. The version this box runs is known
|
|
758
761
|
// here, but what is PUBLISHED is not, and the fact lives behind an outbound
|
|
@@ -764,6 +767,11 @@
|
|
|
764
767
|
// ASKED ONCE PER PAGE LOAD. applyAccess runs on every settle (the /me probe, a
|
|
765
768
|
// page's own report), and re-firing a network call on each would be a request per
|
|
766
769
|
// nav interaction for a fact with a six-hour life on the server.
|
|
770
|
+
//
|
|
771
|
+
// SAID FROM AN ANSWER, OR FROM AN UPDATE ALREADY UNDER WAY. The pill script loads only
|
|
772
|
+
// when the answer has something to say (behind, held, or just moved), or when this
|
|
773
|
+
// browser remembers an update it started: mid-restart the read itself may fail, and the
|
|
774
|
+
// pill must still follow the owner from page to page.
|
|
767
775
|
var coreUpdateAsked = false;
|
|
768
776
|
function maybeRenderCoreUpdate() {
|
|
769
777
|
if (coreUpdateAsked) return;
|
|
@@ -771,10 +779,20 @@
|
|
|
771
779
|
if (!perms || perms['core.pin.move'] !== true) return;
|
|
772
780
|
coreUpdateAsked = true;
|
|
773
781
|
api.request('GET', '/api/bongos/core-update').then(function (res) {
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
782
|
+
mountUpdatePill(res && res.status === 200 && res.data ? res.data : null);
|
|
783
|
+
}, function () { mountUpdatePill(null); });
|
|
784
|
+
}
|
|
785
|
+
function updateUnderWay() {
|
|
786
|
+
try { return !!(window.localStorage && window.localStorage.getItem('bongos.update.run')); } catch (e) { return false; }
|
|
787
|
+
}
|
|
788
|
+
function mountUpdatePill(data) {
|
|
789
|
+
var u = data && data.update;
|
|
790
|
+
var news = !!(u && u.reading === 'ok' && u.behind) || !!(data && data.held);
|
|
791
|
+
if (news || updateUnderWay()) {
|
|
792
|
+
var go = function () { if (window.OTBUpdatePill) window.OTBUpdatePill.mount(data, { api: api }); };
|
|
793
|
+
if (window.OTBUpdatePill) go(); else loadHallScript('update-pill.js', go);
|
|
794
|
+
}
|
|
795
|
+
if (data && data.moved) renderCoreMoveNotice(data.moved); // task 1004731: loads core-move-notice.js, which draws it
|
|
778
796
|
}
|
|
779
797
|
// One hall script on demand, stamped with the shell's own ?v= (task 1004996 made it one helper).
|
|
780
798
|
function loadHallScript(file, onload, onerror) {
|
|
@@ -785,7 +803,7 @@
|
|
|
785
803
|
head.appendChild(tag);
|
|
786
804
|
}
|
|
787
805
|
function renderCoreMoveNotice(moved) {
|
|
788
|
-
loadHallScript('core-move-notice.js', function () { if (window.CoreMoveNotice) window.CoreMoveNotice.render(moved, { api: api, href:
|
|
806
|
+
loadHallScript('core-move-notice.js', function () { if (window.CoreMoveNotice) window.CoreMoveNotice.render(moved, { api: api, href: '/settings#software-update' }); });
|
|
789
807
|
}
|
|
790
808
|
var githubChipAsked = false; // task 1004996: the Link GitHub chip (github-chip.js), asked once a page
|
|
791
809
|
function loadGithubChip(builder) {
|
|
@@ -795,72 +813,6 @@
|
|
|
795
813
|
loadHallScript('github-chip.js', function () { if (window.OTBGithubChip) window.OTBGithubChip.mount({ api: api, builder: builder, hub: hub }); });
|
|
796
814
|
}
|
|
797
815
|
|
|
798
|
-
// Where the banner's Upgrade goes (task 1004296). The platform's hall runs the deploy
|
|
799
|
-
// door itself, so there it is /deploy. Every other hall — a hosted project, a
|
|
800
|
-
// self-hosted instance — takes its update from Settings → Software update, which says
|
|
801
|
-
// what the update carries and, on a hosted project, hands the owner to the hub's door
|
|
802
|
-
// for this project (ADR 0339 D3). The banner no longer links off-site itself.
|
|
803
|
-
var SOFTWARE_UPDATE_HREF = '/settings#software-update';
|
|
804
|
-
|
|
805
|
-
// SAY NOTHING WHEN THERE IS NOTHING TO SAY. `behind` is false both when the box
|
|
806
|
-
// is current AND when the registry could not be read; `reading` separates them,
|
|
807
|
-
// and neither renders. A banner is a claim about being out of date, and a wrong
|
|
808
|
-
// one on a project that is actually current is worse than silence.
|
|
809
|
-
function renderCoreUpdateBanner(update, held) {
|
|
810
|
-
if (!update || update.reading !== 'ok' || !update.behind || !update.latest) return;
|
|
811
|
-
// A dismissal is remembered PER VERSION, not forever: the next release is new
|
|
812
|
-
// news and must re-announce itself, or the surface is dead after one click.
|
|
813
|
-
// localStorage throws in a private window and is absent in the unit tests' bare
|
|
814
|
-
// vm context, so every touch is guarded and its loss only costs the memory.
|
|
815
|
-
try {
|
|
816
|
-
var seen = window.localStorage && window.localStorage.getItem('bongos.coreUpdate.dismissed');
|
|
817
|
-
if (seen && seen === update.latest) return;
|
|
818
|
-
} catch (e) { /* no storage: always show */ }
|
|
819
|
-
var topbar = document.getElementById('app-topbar');
|
|
820
|
-
if (!topbar) return;
|
|
821
|
-
var el = document.createElement('div');
|
|
822
|
-
el.className = 'core-update-notice';
|
|
823
|
-
el.id = 'core-update-notice';
|
|
824
|
-
el.setAttribute('role', 'status');
|
|
825
|
-
// The action goes where the update can actually be taken. The deploy door is the
|
|
826
|
-
// provisioning module's, and a hosted project does NOT run that module (probed:
|
|
827
|
-
// /api/bongos/provisioning/health is 404 on a tenant, 200 on the platform) — so on
|
|
828
|
-
// those it goes to Settings → Software update (SOFTWARE_UPDATE_HREF above).
|
|
829
|
-
// NOT A LINK TO THE PAGE YOU ARE ALREADY ON (task 1004145). This reads as the action
|
|
830
|
-
// button — it is labelled with the verb and styled like one — but it is a plain
|
|
831
|
-
// navigation to /deploy. On /deploy itself that is a no-op, and the owner who
|
|
832
|
-
// pressed it there reasonably reported "I clicked update, but I didn't see anything
|
|
833
|
-
// happen": nothing had, and nothing had been asked for. The control is on that page
|
|
834
|
-
// already, so on it the banner informs and points, and does not pretend to act.
|
|
835
|
-
// The same rule on Settings → Software update: that panel IS the control there.
|
|
836
|
-
var here = window.location ? String(window.location.pathname || '').replace(/\/+$/, '') : '';
|
|
837
|
-
var onDeploy = here === '/deploy';
|
|
838
|
-
var onUpdatePanel = here === '/settings' && String(window.location.hash || '') === '#software-update';
|
|
839
|
-
var action = moduleOn('provisioning')
|
|
840
|
-
? (onDeploy
|
|
841
|
-
? '<span class="core-update-notice__hint">Use the control below to take it.</span>'
|
|
842
|
-
: '<a class="core-update-notice__action" href="/deploy">Upgrade</a>')
|
|
843
|
-
: (onUpdatePanel
|
|
844
|
-
? '<span class="core-update-notice__hint">Its details are below.</span>'
|
|
845
|
-
: '<a class="core-update-notice__action" href="' + SOFTWARE_UPDATE_HREF + '">Upgrade</a>');
|
|
846
|
-
// task 1004730: the newest version already failed here and was rolled back. Say so, never
|
|
847
|
-
// "available" with a button to take it again; Software update carries the full sentence.
|
|
848
|
-
var hold = held && held.version === update.latest ? held : null;
|
|
849
|
-
el.innerHTML = (hold
|
|
850
|
-
? '<span>Core <strong>' + esc(hold.version) + '</strong> was tried on this project and rolled back. It is still on ' +
|
|
851
|
-
esc(hold.still_on) + ' and working.</span><a class="core-update-notice__action" href="' + SOFTWARE_UPDATE_HREF + '">Details</a>'
|
|
852
|
-
: '<span>Core <strong>' + esc(update.latest) + '</strong> is available — this project runs ' +
|
|
853
|
-
esc(update.running || 'an unknown version') + '.</span>' + action) +
|
|
854
|
-
'<button type="button" class="core-update-notice__close" aria-label="Dismiss">×</button>';
|
|
855
|
-
el.querySelector('.core-update-notice__close').addEventListener('click', function () {
|
|
856
|
-
try {
|
|
857
|
-
if (window.localStorage) window.localStorage.setItem('bongos.coreUpdate.dismissed', update.latest);
|
|
858
|
-
} catch (e) { /* dismissal is best-effort */ }
|
|
859
|
-
el.remove();
|
|
860
|
-
});
|
|
861
|
-
topbar.insertAdjacentElement('afterend', el);
|
|
862
|
-
}
|
|
863
|
-
|
|
864
816
|
// task 1003303: the skip link, rendered once here rather than pasted into 27
|
|
865
817
|
// heads. The hall had none, which is a platform floor (DESIGN.md
|
|
866
818
|
// §Accessibility Floors) and, with the sidebar first in the DOM, meant a
|
|
@@ -231,7 +231,7 @@
|
|
|
231
231
|
<script src="/builders/dom-utils.js?v=2026-10-25-escape"></script>
|
|
232
232
|
<script src="/builders/shell-trail.js?v=2026-10-08-city-tab"></script>
|
|
233
233
|
<script src="/builders/craft-mode.js?v=2026-10-30-market-watch"></script>
|
|
234
|
-
<script src="/builders/shell.js?v=2026-
|
|
234
|
+
<script src="/builders/shell.js?v=2026-11-03-update-pill"></script>
|
|
235
235
|
<script src="/builders/palette.js" defer></script>
|
|
236
236
|
<script src="/builders/gov-living.js?v=2026-10-09-positions1"></script>
|
|
237
237
|
<script src="/builders/gov-feeds.js?v=2026-10-09-living3"></script>
|
|
@@ -219,7 +219,7 @@
|
|
|
219
219
|
<script src="/builders/dom-utils.js?v=2026-10-25-escape"></script>
|
|
220
220
|
<script src="/builders/shell-trail.js?v=2026-10-08-city-tab"></script>
|
|
221
221
|
<script src="/builders/craft-mode.js?v=2026-10-30-market-watch"></script>
|
|
222
|
-
<script src="/builders/shell.js?v=2026-
|
|
222
|
+
<script src="/builders/shell.js?v=2026-11-03-update-pill"></script>
|
|
223
223
|
<script src="/builders/palette.js" defer></script>
|
|
224
224
|
<!-- The kit, for its ONE renderer: the full-size ship-time visual figure
|
|
225
225
|
(task 1003829), which the older reviews still show. -->
|
|
@@ -755,7 +755,7 @@
|
|
|
755
755
|
|
|
756
756
|
function statusHtml() {
|
|
757
757
|
if (!home.pages) {
|
|
758
|
-
return
|
|
758
|
+
return home.pagesFailed ? '<p class="st-panel__line">The pages could not be read just now. Try again in a moment.</p>' : '<p class="hall-loading" role="status">Reading the pages…</p>';
|
|
759
759
|
}
|
|
760
760
|
const rows = lib.surfaceRows(home.pages, lib.landingHost(byId('hall-main') && byId('hall-main').getAttribute('data-apex'), window.location && window.location.host)).map((s) => `
|
|
761
761
|
<li class="st-surface">
|
|
@@ -804,7 +804,7 @@
|
|
|
804
804
|
|
|
805
805
|
function siteHtml() {
|
|
806
806
|
if (!home.site) {
|
|
807
|
-
return `<p class="st-panel__line">${
|
|
807
|
+
return home.siteFailed ? `<p class="st-panel__line">${SITE_FAILED}</p>` : '<p class="hall-loading" role="status">Reading the reviews…</p>';
|
|
808
808
|
}
|
|
809
809
|
if (!home.site.length) return `<p class="st-panel__line">${SITE_NONE}</p>`;
|
|
810
810
|
const rows = home.site.map((r) => `
|
|
@@ -1178,7 +1178,7 @@
|
|
|
1178
1178
|
}
|
|
1179
1179
|
|
|
1180
1180
|
function siteListPage() {
|
|
1181
|
-
if (!home.site) return `<p class="st-panel__line">${
|
|
1181
|
+
if (!home.site) return home.siteFailed ? `<p class="st-panel__line">${SITE_FAILED}</p>` : '<p class="hall-loading" role="status">Reading the reviews…</p>';
|
|
1182
1182
|
if (!home.site.length) return `<p class="st-panel__line">${SITE_NONE}</p>`;
|
|
1183
1183
|
return `<ul class="st-doc-list">${home.site.map((r) => `<li><a class="st-doc-list__row" href="${escapeHtml(siteHref(r.link))}">
|
|
1184
1184
|
<span class="st-doc-list__page">${escapeHtml(r.page_title || r.page_path || r.page_id)}</span>
|
|
@@ -1038,54 +1038,134 @@ html[data-theme="dark"] .gplate__light { display: none; }
|
|
|
1038
1038
|
line-height: 1;
|
|
1039
1039
|
cursor: pointer;
|
|
1040
1040
|
}
|
|
1041
|
-
/*
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1041
|
+
/* ---------- the Update pill and its card (task 1005041, update-pill.js) ----------
|
|
1042
|
+
The owner: the full-width update banners were "way too obstructing"; it should feel
|
|
1043
|
+
like the Claude app's "restart to update". So the news is a quiet pill in the top bar
|
|
1044
|
+
(the Link GitHub chip's shape, one step louder: the accent dot), and everything else
|
|
1045
|
+
lives in a small card under it. The same card carries the one-time "Bongos is updated"
|
|
1046
|
+
note (core-move-notice.js), pinned to the same corner. */
|
|
1047
|
+
.upd-pill {
|
|
1048
|
+
display: inline-flex;
|
|
1049
|
+
align-items: center;
|
|
1050
|
+
gap: 6px;
|
|
1051
|
+
min-height: 28px;
|
|
1052
|
+
min-width: 28px;
|
|
1053
|
+
padding: 0 11px 0 9px;
|
|
1054
|
+
border: 1px solid var(--rule);
|
|
1055
|
+
border-radius: var(--radius-pill);
|
|
1056
|
+
background: var(--bg-card);
|
|
1057
|
+
color: var(--ink);
|
|
1058
|
+
font: inherit;
|
|
1059
|
+
font-size: 12px;
|
|
1060
|
+
font-weight: 500;
|
|
1061
|
+
line-height: 1;
|
|
1062
|
+
white-space: nowrap;
|
|
1063
|
+
flex-shrink: 0;
|
|
1064
|
+
cursor: pointer;
|
|
1053
1065
|
}
|
|
1054
|
-
.
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1066
|
+
.upd-pill:hover { border-color: var(--ink-faint); }
|
|
1067
|
+
.upd-pill:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
|
|
1068
|
+
.upd-pill__dot { width: 7px; height: 7px; border-radius: 50%; background: var(--accent); flex-shrink: 0; }
|
|
1069
|
+
.upd-pill[data-face="held"] .upd-pill__dot { background: var(--ink-faint); }
|
|
1070
|
+
.upd-pill[data-face="done"] { background: var(--accent); border-color: var(--accent); color: var(--accent-on); }
|
|
1071
|
+
.upd-pill[data-face="done"] .upd-pill__dot { background: var(--accent-on); }
|
|
1072
|
+
.upd-pill[data-face="done"]:hover { background: var(--accent-lift); border-color: var(--accent-lift); }
|
|
1073
|
+
/* The running face turns a ring. The Kill Switch stops it, and the label still says
|
|
1074
|
+
"Updating…", so the rest frame is the whole message. */
|
|
1075
|
+
.upd-pill__spin {
|
|
1076
|
+
width: 10px; height: 10px;
|
|
1077
|
+
border: 1.5px solid var(--rule);
|
|
1078
|
+
border-top-color: var(--accent);
|
|
1079
|
+
border-radius: 50%;
|
|
1080
|
+
flex-shrink: 0;
|
|
1081
|
+
animation: upd-turn 0.9s linear infinite;
|
|
1058
1082
|
}
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
.
|
|
1062
|
-
|
|
1063
|
-
|
|
1083
|
+
@keyframes upd-turn { to { transform: rotate(360deg); } }
|
|
1084
|
+
|
|
1085
|
+
.upd-card {
|
|
1086
|
+
position: fixed;
|
|
1087
|
+
top: 64px;
|
|
1088
|
+
right: 16px;
|
|
1089
|
+
z-index: calc(var(--z-sidebar) + 5);
|
|
1090
|
+
width: min(360px, calc(100vw - 32px));
|
|
1091
|
+
max-height: calc(100vh - 96px);
|
|
1092
|
+
overflow-y: auto;
|
|
1093
|
+
padding: 16px 18px 18px;
|
|
1094
|
+
border: 1px solid var(--rule-soft);
|
|
1095
|
+
border-radius: var(--radius);
|
|
1096
|
+
background: var(--bg-card);
|
|
1097
|
+
color: var(--ink);
|
|
1098
|
+
box-shadow: var(--shadow-pop);
|
|
1099
|
+
font-size: 13px;
|
|
1100
|
+
line-height: 1.5;
|
|
1064
1101
|
}
|
|
1065
|
-
.
|
|
1066
|
-
|
|
1067
|
-
|
|
1102
|
+
.upd-card[hidden] { display: none; }
|
|
1103
|
+
.upd-card p { margin: 0 0 8px; }
|
|
1104
|
+
.upd-card__h { margin: 0 32px 8px 0; font-size: 15px; font-weight: 600; line-height: 1.3; }
|
|
1105
|
+
.upd-card__close {
|
|
1106
|
+
position: absolute;
|
|
1107
|
+
top: 10px; right: 10px;
|
|
1108
|
+
width: 28px; height: 28px;
|
|
1068
1109
|
border: 0;
|
|
1110
|
+
border-radius: var(--radius-pill);
|
|
1069
1111
|
background: none;
|
|
1070
|
-
color:
|
|
1071
|
-
font-size:
|
|
1112
|
+
color: var(--ink-soft);
|
|
1113
|
+
font-size: 18px;
|
|
1072
1114
|
line-height: 1;
|
|
1073
1115
|
cursor: pointer;
|
|
1074
1116
|
}
|
|
1075
|
-
|
|
1076
|
-
.
|
|
1077
|
-
.
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
.
|
|
1081
|
-
.
|
|
1082
|
-
.
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1117
|
+
.upd-card__close:hover { background: var(--glass-strong); color: var(--ink); }
|
|
1118
|
+
.upd-card__list { margin: 0 0 10px; padding-left: 1.1rem; color: var(--ink-soft); }
|
|
1119
|
+
.upd-card__list li + li { margin-top: 4px; }
|
|
1120
|
+
.upd-card__note { color: var(--ink-soft); }
|
|
1121
|
+
.upd-card__ver { color: var(--ink-faint); font-size: 12px; }
|
|
1122
|
+
.upd-card__err { color: var(--danger); }
|
|
1123
|
+
.upd-ver { font-family: var(--font-mono); font-size: 12px; }
|
|
1124
|
+
.upd-card__actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; }
|
|
1125
|
+
.upd-btn {
|
|
1126
|
+
display: inline-flex;
|
|
1127
|
+
align-items: center;
|
|
1128
|
+
justify-content: center;
|
|
1129
|
+
min-height: 36px;
|
|
1130
|
+
padding: 0 14px;
|
|
1131
|
+
border: 1px solid var(--glass-edge);
|
|
1132
|
+
border-radius: var(--radius-pill);
|
|
1133
|
+
background: transparent;
|
|
1134
|
+
color: var(--ink);
|
|
1135
|
+
font: inherit;
|
|
1136
|
+
font-size: 13px;
|
|
1137
|
+
text-decoration: none;
|
|
1138
|
+
cursor: pointer;
|
|
1087
1139
|
}
|
|
1088
|
-
.
|
|
1140
|
+
.upd-btn:hover { background: var(--glass-strong); text-decoration: none; }
|
|
1141
|
+
.upd-btn:focus-visible, .upd-card__close:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
|
|
1142
|
+
.upd-btn--go { background: var(--accent); border-color: var(--accent); color: var(--accent-on); font-weight: 500; }
|
|
1143
|
+
.upd-btn--go:hover { background: var(--accent-lift); border-color: var(--accent-lift); }
|
|
1144
|
+
.upd-btn:disabled { opacity: 1; color: var(--ink-faint); background: var(--glass); border-color: var(--glass-edge); cursor: default; }
|
|
1145
|
+
/* An indeterminate bar: how long an upgrade takes is not known here, so it never fills. */
|
|
1146
|
+
.upd-track { position: relative; height: 4px; margin: 4px 0 10px; border-radius: 2px; background: var(--glass-strong); overflow: hidden; }
|
|
1147
|
+
.upd-track span {
|
|
1148
|
+
position: absolute; top: 0; bottom: 0; left: 0;
|
|
1149
|
+
width: 40%;
|
|
1150
|
+
border-radius: 2px;
|
|
1151
|
+
background: var(--accent);
|
|
1152
|
+
animation: upd-slide 1.6s ease-in-out infinite;
|
|
1153
|
+
}
|
|
1154
|
+
@keyframes upd-slide { 0% { transform: translateX(-100%); } 100% { transform: translateX(250%); } }
|
|
1155
|
+
/* The one-time note sits under the top bar's right end too, on every page that loads it. */
|
|
1156
|
+
.upd-card--note { top: 64px; }
|
|
1157
|
+
@media (max-width: 640px) {
|
|
1158
|
+
.upd-card { right: 16px; left: 16px; width: auto; }
|
|
1159
|
+
}
|
|
1160
|
+
/* The hub's handoff window (deploy-handoff.js): a small popup with nothing in it but the card.
|
|
1161
|
+
The shell still runs (it signs the viewer in), so its chrome is hidden, not removed. */
|
|
1162
|
+
html[data-handoff="on"] .app-sidebar,
|
|
1163
|
+
html[data-handoff="on"] .app-topbar,
|
|
1164
|
+
html[data-handoff="on"] .app-foot,
|
|
1165
|
+
html[data-handoff="on"] .upd-pill,
|
|
1166
|
+
html[data-handoff="on"] .core-move-notice { display: none; }
|
|
1167
|
+
html[data-handoff="on"] .app-content { padding: 0; }
|
|
1168
|
+
.upd-card--handoff { position: static; width: auto; max-width: 420px; max-height: none; margin: 24px auto; box-shadow: none; }
|
|
1089
1169
|
.topbar-menu {
|
|
1090
1170
|
display: none;
|
|
1091
1171
|
align-items: center;
|
|
@@ -4317,7 +4397,8 @@ main [id] { scroll-margin-top: calc(var(--topbar-h) + 16px); }
|
|
|
4317
4397
|
.empty-state__action { display: inline-block; margin-top: 6px; font-size: 13px; }
|
|
4318
4398
|
|
|
4319
4399
|
/* skeleton shimmer — standard-height placeholder rows while data loads, so
|
|
4320
|
-
cards don't jump; derives from the ink/bg tokens like everything else
|
|
4400
|
+
cards don't jump; derives from the ink/bg tokens like everything else. It
|
|
4401
|
+
breathes in the loader's beat (task 1005043; the keyframes sit with it). */
|
|
4321
4402
|
.kit-skel {
|
|
4322
4403
|
display: inline-block;
|
|
4323
4404
|
width: 60%;
|
|
@@ -4325,9 +4406,97 @@ main [id] { scroll-margin-top: calc(var(--topbar-h) + 16px); }
|
|
|
4325
4406
|
height: 12px;
|
|
4326
4407
|
border-radius: 2px;
|
|
4327
4408
|
background: var(--skeleton);
|
|
4409
|
+
animation: hall-loading-breathe .8s ease-in-out infinite alternate-reverse;
|
|
4328
4410
|
}
|
|
4329
4411
|
.kit-skel-row td { border-bottom: 1px solid var(--rule-soft); }
|
|
4330
4412
|
|
|
4413
|
+
/* ---- the loader (task 1005043) ----------------------------------------------
|
|
4414
|
+
One loader for everything a hall page waits on, drawn from the Bongos mark
|
|
4415
|
+
(shell.js's brand-mark SVG: the ring, the core and the accent dot). A page
|
|
4416
|
+
opts in by giving its existing placeholder the class; its own words stay as
|
|
4417
|
+
the caption, so no page gains markup. The ring and the dot turn together round
|
|
4418
|
+
the still core and the ink breathes, after the Vibe skeleton the owner pointed
|
|
4419
|
+
at (vibe.monday.com: 0.4 to 1 and back, 0.8s). Three sizes: the default for a
|
|
4420
|
+
panel, --page for a page's main area, --inline for a line in a list or card.
|
|
4421
|
+
|
|
4422
|
+
DESIGN.md holds it: CSS only, transform and filter only (the breath and the
|
|
4423
|
+
arrival are filter: opacity(), not opacity), every colour a var() or a mix of
|
|
4424
|
+
one; the black in the two masks is alpha, not paint. The 20s floor is for the
|
|
4425
|
+
ambient plates: a loader is the live thing on the page, so it keeps a loader's
|
|
4426
|
+
tempo and the dot spends the accent. Each turn eases out of and back into the
|
|
4427
|
+
logo's own pose, so the mark lands on the logo once per beat. It arrives after
|
|
4428
|
+
240ms, so a read that answers faster never shows it. Under the Kill Switch
|
|
4429
|
+
nothing moves and the rest frame is the logo itself. ---- */
|
|
4430
|
+
.hall-loading {
|
|
4431
|
+
--hl-size: 40px;
|
|
4432
|
+
--hl-pad: 28px;
|
|
4433
|
+
--hl-beat: 1.6s;
|
|
4434
|
+
position: relative;
|
|
4435
|
+
display: flex;
|
|
4436
|
+
flex-direction: column;
|
|
4437
|
+
align-items: center;
|
|
4438
|
+
gap: 12px;
|
|
4439
|
+
margin: 0;
|
|
4440
|
+
padding: var(--hl-pad) 0;
|
|
4441
|
+
font-size: 13.5px;
|
|
4442
|
+
color: var(--ink-faint);
|
|
4443
|
+
text-align: center;
|
|
4444
|
+
animation: hall-loading-arrive 500ms cubic-bezier(.16, 1, .3, 1) 240ms both;
|
|
4445
|
+
}
|
|
4446
|
+
.hall-loading::before,
|
|
4447
|
+
.hall-loading::after {
|
|
4448
|
+
content: "";
|
|
4449
|
+
display: block;
|
|
4450
|
+
flex: none;
|
|
4451
|
+
width: var(--hl-size);
|
|
4452
|
+
height: var(--hl-size);
|
|
4453
|
+
-webkit-mask: var(--hl-shape) center / contain no-repeat;
|
|
4454
|
+
mask: var(--hl-shape) center / contain no-repeat;
|
|
4455
|
+
animation: hall-loading-turn var(--hl-beat) cubic-bezier(.45, .05, .55, .95) infinite;
|
|
4456
|
+
}
|
|
4457
|
+
/* the ring and the core: one ink, breathing */
|
|
4458
|
+
.hall-loading::before {
|
|
4459
|
+
--hl-shape: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 200 200'%3E%3Cpath d='M137 31 A78 78 0 1 0 170 66' fill='none' stroke='black' stroke-width='15' stroke-linecap='round'/%3E%3Ccircle cx='100' cy='100' r='55'/%3E%3C/svg%3E");
|
|
4460
|
+
background: color-mix(in srgb, var(--ink) 30%, var(--bg-card));
|
|
4461
|
+
animation:
|
|
4462
|
+
hall-loading-turn var(--hl-beat) cubic-bezier(.45, .05, .55, .95) infinite,
|
|
4463
|
+
hall-loading-breathe calc(var(--hl-beat) / 2) ease-in-out infinite alternate-reverse;
|
|
4464
|
+
}
|
|
4465
|
+
/* the dot: the accent, laid exactly over the mark and turning with it */
|
|
4466
|
+
.hall-loading::after {
|
|
4467
|
+
--hl-shape: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 200 200'%3E%3Ccircle cx='156' cy='46' r='12'/%3E%3C/svg%3E");
|
|
4468
|
+
position: absolute;
|
|
4469
|
+
top: var(--hl-pad);
|
|
4470
|
+
left: calc(50% - var(--hl-size) / 2);
|
|
4471
|
+
background: var(--accent);
|
|
4472
|
+
}
|
|
4473
|
+
.hall-loading--page { --hl-size: 64px; --hl-pad: 72px; gap: 16px; }
|
|
4474
|
+
.hall-loading--inline {
|
|
4475
|
+
--hl-size: 16px;
|
|
4476
|
+
--hl-pad: 0px;
|
|
4477
|
+
display: inline-flex;
|
|
4478
|
+
flex-direction: row;
|
|
4479
|
+
gap: 8px;
|
|
4480
|
+
text-align: left;
|
|
4481
|
+
}
|
|
4482
|
+
.hall-loading--inline::after { top: calc(50% - var(--hl-size) / 2); left: 0; }
|
|
4483
|
+
/* --wait: a page whose every section stays [hidden] until it knows who is
|
|
4484
|
+
reading (the sealed/body pairs) puts one loader FIRST in its <main>. It shows
|
|
4485
|
+
only while nothing after it is showing, and steps aside the moment the page
|
|
4486
|
+
reveals anything (the body, the sealed notice, an error), so no page script
|
|
4487
|
+
has to remember to hide it. Without :has() it never shows: today's page. */
|
|
4488
|
+
/* --zones: the same, for a view made of always-present, empty zones that cards
|
|
4489
|
+
mount into (Home, Watch's panes): it shows while no showing zone after it
|
|
4490
|
+
holds a showing child. */
|
|
4491
|
+
.hall-loading--wait, .hall-loading--zones { display: none; }
|
|
4492
|
+
@supports selector(:has(a)) {
|
|
4493
|
+
.hall-loading--wait:not(:has(~ :not([hidden], script, template, style))) { display: flex; }
|
|
4494
|
+
.hall-loading--zones:not(:has(~ :not([hidden]) > :not([hidden], script, template, style))) { display: flex; }
|
|
4495
|
+
}
|
|
4496
|
+
@keyframes hall-loading-arrive { from { filter: opacity(0); transform: translateY(6px); } }
|
|
4497
|
+
@keyframes hall-loading-turn { to { transform: rotate(1turn); } }
|
|
4498
|
+
@keyframes hall-loading-breathe { from { filter: opacity(.45); } }
|
|
4499
|
+
|
|
4331
4500
|
/* collapsible card body — the Work-backlog <details> idiom, generalized */
|
|
4332
4501
|
.kit-collapse__summary {
|
|
4333
4502
|
cursor: pointer;
|
|
@@ -413,7 +413,7 @@
|
|
|
413
413
|
}
|
|
414
414
|
|
|
415
415
|
async function renderPromote() {
|
|
416
|
-
box.innerHTML = '<p class="
|
|
416
|
+
box.innerHTML = '<p class="hall-loading hall-loading--inline" role="status">Loading versions…</p>';
|
|
417
417
|
// Both dead ends offer the way back through the same delegated [data-go]
|
|
418
418
|
// handler the forms use — a builder must never be stranded mid-panel.
|
|
419
419
|
function bail(message) {
|
|
@@ -658,7 +658,7 @@
|
|
|
658
658
|
function bodyFor(state) {
|
|
659
659
|
var nodes = [];
|
|
660
660
|
var label = '#' + state.id;
|
|
661
|
-
if (state.loading) { nodes.push(h('p', '
|
|
661
|
+
if (state.loading) { nodes.push(h('p', 'hall-loading', 'Loading ' + label + '…')); return nodes; }
|
|
662
662
|
if (state.needsAuth) {
|
|
663
663
|
nodes.push(h('p', 'deeplink-card__title', label));
|
|
664
664
|
nodes.push(h('p', 'deeplink-card__note', 'Sign in to the Builders’ Hall to view this record.'));
|
|
@@ -59,7 +59,7 @@
|
|
|
59
59
|
<script src="/builders/dom-utils.js?v=2026-10-25-escape"></script>
|
|
60
60
|
<script src="/builders/shell-trail.js?v=2026-10-08-city-tab"></script>
|
|
61
61
|
<script src="/builders/craft-mode.js?v=2026-10-30-market-watch"></script>
|
|
62
|
-
<script src="/builders/shell.js?v=2026-
|
|
62
|
+
<script src="/builders/shell.js?v=2026-11-03-update-pill"></script>
|
|
63
63
|
<!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
|
|
64
64
|
<script src="/builders/palette.js" defer></script>
|
|
65
65
|
<!-- task-detail.js still owns the #/idea/N and #/blocker/N deep-link overlay
|