@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
|
@@ -21,6 +21,7 @@ SURFACE=hall-ui PREFIX=/builders/ node modules/ui-design/kit/serve.js
|
|
|
21
21
|
CHILD=1 node modules/ui-design/kit/serve.js # the child-instance shape (apex-only regions stripped)
|
|
22
22
|
LIVE=1 node modules/ui-design/kit/serve.js # public feeds proxied to the pack's public origin
|
|
23
23
|
FAIL=featured,progress node modules/ui-design/kit/serve.js # those feeds answer 500
|
|
24
|
+
LATENCY=4000 node modules/ui-design/kit/serve.js # every /api/ read held 4s, to look at a page's waiting state (the loader; task 1005053)
|
|
24
25
|
STYLE=grove node modules/ui-design/kit/serve.js # under a look from the style library (modules/ui-design/styles/; task 1003323)
|
|
25
26
|
```
|
|
26
27
|
|
|
@@ -48,6 +48,7 @@ const REFUSALS = {
|
|
|
48
48
|
no_allowlist: 'no goal is allowlisted, so there is nothing this runner may work on',
|
|
49
49
|
goal_not_allowlisted: 'that goal is not on the allowlist',
|
|
50
50
|
protected_path: 'the task declares work on a permission, migration, infrastructure or deploy-pipeline surface',
|
|
51
|
+
self_modification: "the task declares work on the runner's own supervisor, safety checks or kill switch",
|
|
51
52
|
needs_host_access: 'the work needs shell access to a live host (SSH, root, systemd) that the runner machine does not have',
|
|
52
53
|
grader_unavailable: 'the grader is bypassed, and it is the only review between an unattended worker and main',
|
|
53
54
|
not_permitted: 'your rank does not hold autonomy.run, so your runner may not work on this project',
|
|
@@ -332,7 +333,13 @@ function needsHostAccess(task) {
|
|
|
332
333
|
// in core and a module reaches core only through the doorway. Passing the hits in
|
|
333
334
|
// also means the caller decides WHAT to match, which is what lets a future caller
|
|
334
335
|
// run the same decision over a real diff instead of a declaration.
|
|
335
|
-
|
|
336
|
+
//
|
|
337
|
+
// `selfHits` is the same idea for the runner's OWN files (task 1004546): the output
|
|
338
|
+
// of modules/lifecycle/runner-self.js matchRunnerSelf over the same touches[]. The
|
|
339
|
+
// owner's rule is that the runner never edits its own supervisor, safety checks or
|
|
340
|
+
// kill switch, and none of those are on the ADR 0043 registry. Declared touches are
|
|
341
|
+
// a claim, so the ship-time check and the server's publish check read the real diff.
|
|
342
|
+
function decideTask({ task, goals = [], protectedHits = [], selfHits = [] } = {}) {
|
|
336
343
|
if (!task || task.id === undefined || task.id === null) {
|
|
337
344
|
return { go: false, code: 'fence_unreadable', reason: 'no task to decide about' };
|
|
338
345
|
}
|
|
@@ -351,6 +358,14 @@ function decideTask({ task, goals = [], protectedHits = [] } = {}) {
|
|
|
351
358
|
globs,
|
|
352
359
|
};
|
|
353
360
|
}
|
|
361
|
+
if (Array.isArray(selfHits) && selfHits.length) {
|
|
362
|
+
const files = [...new Set(selfHits.map((h) => h && h.file).filter(Boolean))];
|
|
363
|
+
return {
|
|
364
|
+
go: false, code: 'self_modification',
|
|
365
|
+
reason: `${REFUSALS.self_modification}${files.length ? ` (${files.join(', ')})` : ''}`,
|
|
366
|
+
files,
|
|
367
|
+
};
|
|
368
|
+
}
|
|
354
369
|
const host = needsHostAccess(task);
|
|
355
370
|
if (host.needs) {
|
|
356
371
|
return {
|
|
@@ -109,6 +109,8 @@
|
|
|
109
109
|
{ "glob": "modules/lifecycle/github-push.js", "group": "pipeline", "why": "BV1.R86: the server-mediated branch publish (ADR 0055)" },
|
|
110
110
|
{ "glob": "modules/lifecycle/conflict-resolve.js", "group": "pipeline", "why": "BV1.R86: self-heals generated-file conflicts at land time" },
|
|
111
111
|
{ "glob": "modules/lifecycle/publish-reconciler.js", "group": "pipeline", "why": "BV1.R86: lands confirmed merges" },
|
|
112
|
+
{ "glob": "modules/lifecycle/runner-self.js", "group": "pipeline", "why": "task 1004546: the one list of files an Autobongos runner may never change, and the shape of a runner's claim" },
|
|
113
|
+
{ "glob": "modules/lifecycle/runner-self-guard.js", "group": "pipeline", "why": "task 1004546: the server refuses to publish a runner's change to its own supervisor, safety checks or kill switch" },
|
|
112
114
|
{ "glob": "migrations/", "group": "schema", "why": "schema migrations are never newcomer work" },
|
|
113
115
|
{ "glob": "infra/", "group": "substrate", "why": "the deploy substrate" },
|
|
114
116
|
{ "glob": ".github/", "group": "substrate", "why": "CI workflows (deploy-prod.yml, grade gate, secrets-scan) are the pipeline" },
|
|
@@ -73,7 +73,7 @@
|
|
|
73
73
|
<!-- The view, painted by ai-studio.js. The page's one <h1> is each
|
|
74
74
|
view's own question or figure. -->
|
|
75
75
|
<div class="ais-page" id="ais-page">
|
|
76
|
-
<p class="
|
|
76
|
+
<p class="hall-loading hall-loading--page" role="status">Opening…</p>
|
|
77
77
|
</div>
|
|
78
78
|
<input type="file" id="ais-file" class="ais-file" multiple accept="image/png,image/jpeg,image/gif,image/webp,application/pdf" tabindex="-1" aria-hidden="true">
|
|
79
79
|
<input type="file" id="ais-camera-file" class="ais-file" accept="image/*" capture="environment" tabindex="-1" aria-hidden="true">
|
|
@@ -89,7 +89,7 @@
|
|
|
89
89
|
<script src="/builders/dom-utils.js?v=2026-10-25-escape"></script>
|
|
90
90
|
<script src="/builders/shell-trail.js?v=2026-10-08-city-tab"></script>
|
|
91
91
|
<script src="/builders/craft-mode.js?v=2026-10-30-market-watch"></script>
|
|
92
|
-
<script src="/builders/shell.js?v=2026-
|
|
92
|
+
<script src="/builders/shell.js?v=2026-11-03-update-pill"></script>
|
|
93
93
|
<script src="/builders/palette.js" defer></script>
|
|
94
94
|
<script src="/builders/tweak-editor-lib.js?v=2026-09-28-tw23"></script>
|
|
95
95
|
<script src="/builders/studio-lib.js?v=2026-10-09-day"></script>
|
|
@@ -92,7 +92,7 @@
|
|
|
92
92
|
<script src="/builders/dom-utils.js?v=2026-10-25-escape"></script>
|
|
93
93
|
<script src="/builders/shell-trail.js?v=2026-10-08-city-tab"></script>
|
|
94
94
|
<script src="/builders/craft-mode.js?v=2026-10-30-market-watch"></script>
|
|
95
|
-
<script src="/builders/shell.js?v=2026-
|
|
95
|
+
<script src="/builders/shell.js?v=2026-11-03-update-pill"></script>
|
|
96
96
|
<!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
|
|
97
97
|
<script src="/builders/palette.js" defer></script>
|
|
98
98
|
<script src="/builders/atlas.js?v=2026-09-02-index" defer></script>
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
<h2 id="blockers-h" class="scroll__h">Requires project owner fix<span class="count-pill" id="blockers-count" hidden></span></h2>
|
|
45
45
|
<div id="blockers-file-area"></div>
|
|
46
46
|
<div id="blockers-body">
|
|
47
|
-
<p class="
|
|
47
|
+
<p class="hall-loading hall-loading--page" role="status">Loading…</p>
|
|
48
48
|
</div>
|
|
49
49
|
</section>
|
|
50
50
|
</main>
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
<script src="/builders/dom-utils.js?v=2026-10-25-escape"></script>
|
|
62
62
|
<script src="/builders/shell-trail.js?v=2026-10-08-city-tab"></script>
|
|
63
63
|
<script src="/builders/craft-mode.js?v=2026-10-30-market-watch"></script>
|
|
64
|
-
<script src="/builders/shell.js?v=2026-
|
|
64
|
+
<script src="/builders/shell.js?v=2026-11-03-update-pill"></script>
|
|
65
65
|
<!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
|
|
66
66
|
<script src="/builders/palette.js" defer></script>
|
|
67
67
|
<!-- the branding pack's currency label, loaded BEFORE blockers.js. -->
|
|
@@ -297,7 +297,9 @@
|
|
|
297
297
|
}
|
|
298
298
|
|
|
299
299
|
function mountShell() {
|
|
300
|
-
|
|
300
|
+
// The loader holds the list until renderList's first paint replaces it (task 1005043).
|
|
301
|
+
body.innerHTML = '<ul class="ov-rows" id="blockers-list"><li class="hall-loading hall-loading--page" role="status">Loading…</li></ul>'
|
|
302
|
+
+ kit.pagerBarHtml(pager.prefix, { label: 'blockers' });
|
|
301
303
|
kit.wirePager(pager, function () { fetchPage(); });
|
|
302
304
|
}
|
|
303
305
|
|
|
@@ -32,6 +32,8 @@
|
|
|
32
32
|
</div>
|
|
33
33
|
|
|
34
34
|
<main id="hall-main">
|
|
35
|
+
<!-- task 1005043: the page loader, shown until any section below is revealed. -->
|
|
36
|
+
<p class="hall-loading hall-loading--page hall-loading--wait" role="status">Loading…</p>
|
|
35
37
|
<!-- task 1003469: the sealed state is a panel with a heading, not a bare
|
|
36
38
|
line on the ground. board-room.js writes the floor into the lede from
|
|
37
39
|
the pack's rank label, so the copy cannot drift. Unlike its
|
|
@@ -61,7 +63,7 @@
|
|
|
61
63
|
<script src="/builders/dom-utils.js?v=2026-10-25-escape"></script>
|
|
62
64
|
<script src="/builders/shell-trail.js?v=2026-10-08-city-tab"></script>
|
|
63
65
|
<script src="/builders/craft-mode.js?v=2026-10-30-market-watch"></script>
|
|
64
|
-
<script src="/builders/shell.js?v=2026-
|
|
66
|
+
<script src="/builders/shell.js?v=2026-11-03-update-pill"></script>
|
|
65
67
|
<!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
|
|
66
68
|
<script src="/builders/palette.js" defer></script>
|
|
67
69
|
<script src="/builders/hall-kit.js"></script>
|
|
@@ -108,7 +108,7 @@
|
|
|
108
108
|
<script src="/builders/dom-utils.js?v=2026-10-25-escape"></script>
|
|
109
109
|
<script src="/builders/shell-trail.js?v=2026-10-08-city-tab" defer></script>
|
|
110
110
|
<script src="/builders/craft-mode.js?v=2026-10-30-market-watch" defer></script>
|
|
111
|
-
<script src="/builders/shell.js?v=2026-
|
|
111
|
+
<script src="/builders/shell.js?v=2026-11-03-update-pill" defer></script>
|
|
112
112
|
<script src="/builders/palette.js" defer></script>
|
|
113
113
|
<script src="/builders/gov-living.js?v=2026-10-09-positions1" defer></script>
|
|
114
114
|
<script src="/builders/gov-feeds.js?v=2026-10-09-living3" defer></script>
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
<span class="cb-block__age" id="cb-for-me-age" hidden></span>
|
|
50
50
|
<span class="cb-faces" id="cb-for-me-faces" aria-hidden="true"></span>
|
|
51
51
|
</div>
|
|
52
|
-
<ul class="ov-rows" id="cb-for-me"></ul>
|
|
52
|
+
<ul class="ov-rows" id="cb-for-me"><li class="hall-loading" role="status">Loading…</li></ul>
|
|
53
53
|
<div class="empty-state cb-empty" id="cb-for-me-empty" hidden>
|
|
54
54
|
<p>Nobody is waiting on you. Requests reach you by role —
|
|
55
55
|
<a href="/builders/settings">set yours in Settings</a>.</p>
|
|
@@ -79,7 +79,7 @@
|
|
|
79
79
|
<h2 class="scroll__h" id="cb-mine-h">Your asks <span class="cb-block__n" id="cb-mine-n"></span></h2>
|
|
80
80
|
<span class="cb-block__age" id="cb-mine-age" hidden></span>
|
|
81
81
|
</div>
|
|
82
|
-
<ul class="ov-rows" id="cb-mine"></ul>
|
|
82
|
+
<ul class="ov-rows" id="cb-mine"><li class="hall-loading" role="status">Loading…</li></ul>
|
|
83
83
|
<div class="empty-state cb-empty" id="cb-mine-empty" hidden><p>You have no open asks.</p></div>
|
|
84
84
|
<button class="btn-ghost cb-more" id="cb-mine-more" type="button" aria-expanded="false" aria-controls="cb-mine" hidden></button>
|
|
85
85
|
</section>
|
|
@@ -91,7 +91,7 @@
|
|
|
91
91
|
<span class="cb-block__age" id="cb-all-age" hidden></span>
|
|
92
92
|
<span class="cb-faces" id="cb-all-faces" aria-hidden="true"></span>
|
|
93
93
|
</div>
|
|
94
|
-
<ul class="ov-rows" id="cb-all"></ul>
|
|
94
|
+
<ul class="ov-rows" id="cb-all"><li class="hall-loading" role="status">Loading…</li></ul>
|
|
95
95
|
<div class="empty-state cb-empty" id="cb-all-empty" hidden><p>Nobody has an open ask right now.</p></div>
|
|
96
96
|
<button class="btn-ghost cb-more" id="cb-all-more" type="button" aria-expanded="false" aria-controls="cb-all" hidden></button>
|
|
97
97
|
</section>
|
|
@@ -162,7 +162,7 @@
|
|
|
162
162
|
<script src="/builders/dom-utils.js?v=2026-10-25-escape"></script>
|
|
163
163
|
<script src="/builders/shell-trail.js?v=2026-10-08-city-tab"></script>
|
|
164
164
|
<script src="/builders/craft-mode.js?v=2026-10-30-market-watch"></script>
|
|
165
|
-
<script src="/builders/shell.js?v=2026-
|
|
165
|
+
<script src="/builders/shell.js?v=2026-11-03-update-pill"></script>
|
|
166
166
|
<script src="/builders/palette.js" defer></script>
|
|
167
167
|
<script src="/builders/collab-lib.js?v=2026-09-24-archive"></script>
|
|
168
168
|
<script src="/builders/collab.js?v=2026-09-24-archive"></script>
|
|
@@ -843,5 +843,9 @@
|
|
|
843
843
|
const sub = $('#cb-sub');
|
|
844
844
|
// V6: a message that stops someone points at the next move in the same breath.
|
|
845
845
|
if (sub) sub.textContent = 'Could not load requests — reload to try again.';
|
|
846
|
+
// task 1005043: the loaders stop, and the same words stand where the asks would have.
|
|
847
|
+
['for-me', 'mine', 'all'].forEach((k) => { const host = $(`#cb-${k}`); if (host) host.innerHTML = ''; });
|
|
848
|
+
const first = $('#cb-for-me');
|
|
849
|
+
if (first) first.innerHTML = '<li class="empty-state"><p>Could not load requests — reload to try again.</p></li>';
|
|
846
850
|
});
|
|
847
851
|
})();
|
|
@@ -33,14 +33,14 @@
|
|
|
33
33
|
<span><span class="fact-pill fact-pill--info">Shown to Claude</span> Claude can start it when you ask in plain words.</span>
|
|
34
34
|
<span><span class="fact-pill cmd-how--typed">Type it yourself</span> Kept out of Claude's menu to save room; type <code>/name</code> to run it.</span>
|
|
35
35
|
</div>
|
|
36
|
-
<div id="skills-body" aria-live="polite"><p class="
|
|
36
|
+
<div id="skills-body" aria-live="polite"><p class="hall-loading" role="status">Loading the slash commands…</p></div>
|
|
37
37
|
<p class="cmd-note">Some commands refuse below a certain rank.</p>
|
|
38
38
|
</section>
|
|
39
39
|
|
|
40
40
|
<section class="scroll" id="cli-scroll" aria-labelledby="cli-h">
|
|
41
41
|
<h2 id="cli-h" class="scroll__h">Terminal commands (bongos)</h2>
|
|
42
42
|
<p class="scroll__lede">The same work from any terminal. <code>bongos help</code> lists them there.</p>
|
|
43
|
-
<div id="cli-body" aria-live="polite"><p class="
|
|
43
|
+
<div id="cli-body" aria-live="polite"><p class="hall-loading" role="status">Loading the terminal commands…</p></div>
|
|
44
44
|
</section>
|
|
45
45
|
</main>
|
|
46
46
|
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
<script src="/builders/dom-utils.js?v=2026-10-25-escape"></script>
|
|
55
55
|
<script src="/builders/shell-trail.js?v=2026-10-08-city-tab"></script>
|
|
56
56
|
<script src="/builders/craft-mode.js?v=2026-10-30-market-watch"></script>
|
|
57
|
-
<script src="/builders/shell.js?v=2026-
|
|
57
|
+
<script src="/builders/shell.js?v=2026-11-03-update-pill"></script>
|
|
58
58
|
<!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
|
|
59
59
|
<script src="/builders/palette.js" defer></script>
|
|
60
60
|
<script src="/builders/hall-kit.js"></script>
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
<h2 id="cd-flags-h" class="scroll__h">Flagged</h2>
|
|
47
47
|
<p class="scroll__lede">Copy someone has judged as needing attention, with their reason. Anyone can file one; closing it needs the <span id="cd-close-rank">Metic</span> rank or above, or that it is your own.</p>
|
|
48
48
|
<div id="cd-filters"></div>
|
|
49
|
-
<div id="cd-flags"><div class="empty-state"><p>Loading…</p></div></div>
|
|
49
|
+
<div id="cd-flags"><div class="empty-state"><p class="hall-loading" role="status">Loading…</p></div></div>
|
|
50
50
|
</section>
|
|
51
51
|
|
|
52
52
|
<!-- The one signal a machine can compute with no judgement layer at all
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
<section class="scroll" id="cd-dupes-scroll" aria-labelledby="cd-dupes-h">
|
|
56
56
|
<h2 id="cd-dupes-h" class="scroll__h">Said more than once</h2>
|
|
57
57
|
<p class="scroll__lede">The same sentence, in several places. Sometimes that is right and the answer is to dismiss it; sometimes it is seven copies of an error message that should have been one. Nobody has looked at the ones marked untouched.</p>
|
|
58
|
-
<div id="cd-dupes"><div class="empty-state"><p>Loading…</p></div></div>
|
|
58
|
+
<div id="cd-dupes"><div class="empty-state"><p class="hall-loading" role="status">Loading…</p></div></div>
|
|
59
59
|
</section>
|
|
60
60
|
|
|
61
61
|
<!-- Find any string in the product and flag it. Without this the queue
|
|
@@ -180,7 +180,7 @@
|
|
|
180
180
|
<script src="/builders/dom-utils.js?v=2026-10-25-escape"></script>
|
|
181
181
|
<script src="/builders/shell-trail.js?v=2026-10-08-city-tab"></script>
|
|
182
182
|
<script src="/builders/craft-mode.js?v=2026-10-30-market-watch"></script>
|
|
183
|
-
<script src="/builders/shell.js?v=2026-
|
|
183
|
+
<script src="/builders/shell.js?v=2026-11-03-update-pill"></script>
|
|
184
184
|
<script src="/builders/palette.js" defer></script>
|
|
185
185
|
<script src="/builders/hall-kit.js"></script>
|
|
186
186
|
<script src="/builders/copy-desk.js?v=2026-09-01-redesign"></script>
|
|
@@ -32,19 +32,22 @@
|
|
|
32
32
|
}
|
|
33
33
|
var topbar = document.getElementById('app-topbar');
|
|
34
34
|
if (!topbar) return;
|
|
35
|
+
// A small card in the top-right corner, the Update pill's own (task 1005041): the owner
|
|
36
|
+
// called the full-width strips "way too obstructing". It still sits after the top bar in
|
|
37
|
+
// the document, so a screen reader meets it where the strip was.
|
|
35
38
|
var el = document.createElement('div');
|
|
36
|
-
el.className = '
|
|
39
|
+
el.className = 'upd-card upd-card--note core-move-notice';
|
|
37
40
|
el.id = 'core-move-notice';
|
|
38
41
|
el.setAttribute('role', 'status');
|
|
39
42
|
var entries = Array.isArray(moved.entries) ? moved.entries : [];
|
|
40
43
|
var list = entries.length
|
|
41
|
-
? '<ul class="core-move-notice__list">' + entries.map(function (e) { return '<li>' + esc(e && e.text) + '</li>'; }).join('') +
|
|
44
|
+
? '<ul class="upd-card__list core-move-notice__list">' + entries.map(function (e) { return '<li>' + esc(e && e.text) + '</li>'; }).join('') +
|
|
42
45
|
(moved.more > 0 ? '<li>…and ' + esc(String(moved.more)) + ' more.</li>' : '') + '</ul>'
|
|
43
46
|
: '';
|
|
44
|
-
el.innerHTML = '<
|
|
45
|
-
|
|
46
|
-
'<
|
|
47
|
-
'<
|
|
47
|
+
el.innerHTML = '<button type="button" class="upd-card__close core-move-notice__close" aria-label="Dismiss">×</button>' +
|
|
48
|
+
'<h2 class="upd-card__h">Bongos is updated</h2>' +
|
|
49
|
+
'<p>' + esc(moved.message) + (entries.length ? ' What changed:' : '') + '</p>' + list +
|
|
50
|
+
'<div class="upd-card__actions"><a class="upd-btn core-move-notice__more" href="' + esc((opts && opts.href) || '/settings#software-update') + '">Update history</a></div>';
|
|
48
51
|
function markSeen() {
|
|
49
52
|
try {
|
|
50
53
|
if (window.localStorage) window.localStorage.setItem(SEEN_KEY, String(moved.id));
|
|
@@ -195,7 +195,7 @@
|
|
|
195
195
|
if (existing) { existing.remove(); btn.setAttribute('aria-expanded', 'false'); return; }
|
|
196
196
|
const panel = document.createElement('div');
|
|
197
197
|
panel.className = 'uat-panel';
|
|
198
|
-
panel.
|
|
198
|
+
panel.innerHTML = '<p class="hall-loading hall-loading--inline" role="status">Loading…</p>';
|
|
199
199
|
row.appendChild(panel);
|
|
200
200
|
btn.setAttribute('aria-expanded', 'true');
|
|
201
201
|
try {
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
// deploy-handoff.js — the hub's half of the in-place update (task 1005041).
|
|
2
|
+
//
|
|
3
|
+
// A hosted project's owner presses Update now in their own hall (update-pill.js). The act
|
|
4
|
+
// has to happen HERE, on the hub, with the owner's hub session: the project's own server
|
|
5
|
+
// may never move its own pin (ADR 0293 D1, ADR 0339 D3). So the hall opens this page in a
|
|
6
|
+
// small window as /deploy?project=<slug>&handoff=1, and the two windows say four things:
|
|
7
|
+
// hub → hall { tag, step: 'ready' } "I am loaded; which version?"
|
|
8
|
+
// hall → hub { tag, step: 'go', to } the version the owner was shown
|
|
9
|
+
// hub → hall { tag, step: 'started', to } the move is queued; the window closes
|
|
10
|
+
// hub → hall { tag, step: 'refused', message } the server's own sentence
|
|
11
|
+
//
|
|
12
|
+
// WHAT IS CHECKED BEFORE ANYTHING MOVES (judgeGo). The message must come from the window
|
|
13
|
+
// that opened this one, from that project's own registered address (provisioning's
|
|
14
|
+
// `domain`, which is where its hall is served), and name exactly the version this hub's
|
|
15
|
+
// own preview would move it to. Anything else moves nothing: a page that opens this
|
|
16
|
+
// window from elsewhere is talking to a window that will not listen, and a version this
|
|
17
|
+
// hub would not offer is shown to the owner instead of sent. The move itself is the same
|
|
18
|
+
// POST the deploy door makes, gated server-side exactly as before (owner or core.pin.move).
|
|
19
|
+
//
|
|
20
|
+
// ONE PRESS, NEVER ZERO, WHEN IT CANNOT HEAR. If no word comes from the hall (a browser
|
|
21
|
+
// that cuts the tie between the two windows, or this page opened by hand), it shows one
|
|
22
|
+
// button naming the version, the door's own confirm. It never moves on load by itself.
|
|
23
|
+
//
|
|
24
|
+
// Loaded by deploy.html; deploy.js hands over to run() when ?handoff=1 is present.
|
|
25
|
+
// Node-require-safe, so the tests run judgeGo and projectOrigin without a page.
|
|
26
|
+
(function (root) {
|
|
27
|
+
'use strict';
|
|
28
|
+
|
|
29
|
+
var MSG = 'bongos-update'; // update-pill.js's tag
|
|
30
|
+
var VERSION_RE = /^\d+\.\d+\.\d+$/;
|
|
31
|
+
var HOST_RE = /^(?=.{1,253}$)[a-z0-9](?:[a-z0-9-]*[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]*[a-z0-9])?)+(?::\d{1,5})?$/;
|
|
32
|
+
var API = '/api/bongos';
|
|
33
|
+
// How long the window waits for the hall to say which version, before it offers the press.
|
|
34
|
+
var HEAR_MS = typeof root !== 'undefined' && root && typeof root.__handoffHearMs === 'number' ? root.__handoffHearMs : 5000;
|
|
35
|
+
|
|
36
|
+
/** Is this page the handoff window? Read defensively, as deploy.js reads its scope. */
|
|
37
|
+
function wanted(loc) {
|
|
38
|
+
try { return /[?&]handoff=1(?:&|$)/.test(String((loc && loc.search) || '')); } catch (e) { return false; }
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** The one origin allowed to ask for this project's move: its registered address, on the
|
|
42
|
+
* scheme this hub is served on (https in production; http only on a local harness). */
|
|
43
|
+
function projectOrigin(inst, protocol) {
|
|
44
|
+
var host = inst && typeof inst.domain === 'string' ? inst.domain.trim().toLowerCase() : '';
|
|
45
|
+
if (!host || !HOST_RE.test(host)) return null;
|
|
46
|
+
return (protocol === 'http:' ? 'http://' : 'https://') + host;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** Why a message may NOT start the move, or null when it may. Each refusal names itself. */
|
|
50
|
+
function judgeGo(o) {
|
|
51
|
+
var data = o && o.data;
|
|
52
|
+
if (!data || data.tag !== MSG || data.step !== 'go') return 'not_go';
|
|
53
|
+
if (!o.opener || o.source !== o.opener) return 'not_opener';
|
|
54
|
+
if (!o.allowed || o.origin !== o.allowed) return 'wrong_origin';
|
|
55
|
+
var p = o.preview;
|
|
56
|
+
if (!p || p.reading !== 'ok' || !p.behind || !VERSION_RE.test(String(p.recommended_version || ''))) return 'nothing_to_move';
|
|
57
|
+
if (p.viewer_may_move === false) return 'not_allowed';
|
|
58
|
+
if (typeof data.to !== 'string' || data.to !== p.recommended_version) return 'wrong_version';
|
|
59
|
+
if (p.open_intent) return 'busy';
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// ---------- the page ----------
|
|
64
|
+
|
|
65
|
+
function esc(s) { return root.OTB.escapeHtml(String(s == null ? '' : s)); }
|
|
66
|
+
|
|
67
|
+
function run(opts) {
|
|
68
|
+
var d = root.document;
|
|
69
|
+
var api = opts.api;
|
|
70
|
+
var main = d.getElementById('hall-main');
|
|
71
|
+
if (!main) return;
|
|
72
|
+
d.documentElement.setAttribute('data-handoff', 'on');
|
|
73
|
+
main.innerHTML = '<section class="upd-card upd-card--handoff" aria-labelledby="ho-h"><div id="ho-body"><p class="upd-card__note" role="status">Opening this project\'s update…</p></div></section>';
|
|
74
|
+
var body = d.getElementById('ho-body');
|
|
75
|
+
var slug = scopeSlug(root.location);
|
|
76
|
+
var opener = null;
|
|
77
|
+
try { opener = root.opener || null; } catch (e) { opener = null; }
|
|
78
|
+
var inst = null;
|
|
79
|
+
var preview = null;
|
|
80
|
+
var allowed = null;
|
|
81
|
+
var heard = false;
|
|
82
|
+
var moving = false;
|
|
83
|
+
|
|
84
|
+
function draw(html) { body.innerHTML = html; }
|
|
85
|
+
function title(t) { return '<h1 class="upd-card__h" id="ho-h">' + esc(t) + '</h1>'; }
|
|
86
|
+
function tell(msg) {
|
|
87
|
+
if (!opener || !allowed) return;
|
|
88
|
+
try { opener.postMessage(Object.assign({ tag: MSG }, msg), allowed); } catch (e) { /* the hall watches its own version anyway */ }
|
|
89
|
+
}
|
|
90
|
+
function refuse(message) {
|
|
91
|
+
tell({ step: 'refused', message: message });
|
|
92
|
+
draw(title('The update did not start') + '<p class="upd-card__err" role="alert">' + esc(message) + '</p>' +
|
|
93
|
+
'<div class="upd-card__actions"><button type="button" class="upd-btn" id="ho-close">Close</button></div>');
|
|
94
|
+
wireClose();
|
|
95
|
+
}
|
|
96
|
+
function wireClose() {
|
|
97
|
+
var c = d.getElementById('ho-close');
|
|
98
|
+
if (c) c.addEventListener('click', function () { root.close(); });
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// The one press, naming the version THIS hub would move to: the door's own confirm.
|
|
102
|
+
function offerPress(note) {
|
|
103
|
+
if (moving) return;
|
|
104
|
+
var to = preview.recommended_version;
|
|
105
|
+
draw(title('Update ' + (slug || 'this project')) +
|
|
106
|
+
(note ? '<p class="upd-card__note">' + esc(note) + '</p>' : '') +
|
|
107
|
+
'<p>Moves it to version <span class="upd-ver">' + esc(to) + '</span>. It restarts once, and goes back to the version it runs now on its own if the new one is not healthy.</p>' +
|
|
108
|
+
'<div class="upd-card__actions"><button type="button" class="upd-btn upd-btn--go" id="ho-go">Update to ' + esc(to) + '</button>' +
|
|
109
|
+
'<button type="button" class="upd-btn" id="ho-close">Cancel</button></div>');
|
|
110
|
+
d.getElementById('ho-go').addEventListener('click', function () { move(to); });
|
|
111
|
+
wireClose();
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function move(to) {
|
|
115
|
+
if (moving) return;
|
|
116
|
+
moving = true;
|
|
117
|
+
draw(title('Starting the update') + '<p class="upd-card__note" role="status">Asking the server to move ' + esc(slug) + ' to ' + esc(to) + '…</p>');
|
|
118
|
+
api.request('POST', API + '/provisioning/instances/' + encodeURIComponent(inst.id) + '/core-upgrade', { body: { to: to } }).then(function (res) {
|
|
119
|
+
if (res && res.status === 401) { signIn(); return; }
|
|
120
|
+
if (!res || !res.ok) {
|
|
121
|
+
moving = false;
|
|
122
|
+
var err = (res && res.data && res.data.error) || {};
|
|
123
|
+
refuse(err.message && err.message !== err.code ? err.message : 'The server refused the update (' + (res ? res.status : 'no answer') + ').');
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
tell({ step: 'started', to: to });
|
|
127
|
+
draw(title('The update has started') +
|
|
128
|
+
'<p role="status">You can close this window. ' + (opener ? 'Your project\'s hall shows how it is going.' : 'Open your project\'s hall to see how it is going.') + '</p>' +
|
|
129
|
+
'<div class="upd-card__actions"><button type="button" class="upd-btn" id="ho-close">Close</button></div>');
|
|
130
|
+
wireClose();
|
|
131
|
+
if (opener) root.setTimeout(function () { root.close(); }, 1200);
|
|
132
|
+
}, function () { moving = false; refuse('The server did not answer. Nothing was changed.'); });
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function onMessage(e) {
|
|
136
|
+
if (!e || !e.data || e.data.tag !== MSG) return;
|
|
137
|
+
var why = judgeGo({ data: e.data, source: e.source, opener: opener, origin: e.origin, allowed: allowed, preview: preview });
|
|
138
|
+
if (why === 'not_go' || why === 'not_opener' || why === 'wrong_origin') return; // not ours to answer
|
|
139
|
+
heard = true;
|
|
140
|
+
if (!why) { move(e.data.to); return; }
|
|
141
|
+
if (why === 'wrong_version') { offerPress('A different version is ready than the one your hall showed. Check it before updating.'); return; }
|
|
142
|
+
if (why === 'busy') { refuse('Another change is already running for this project. Try again once it settles.'); return; }
|
|
143
|
+
if (why === 'not_allowed') { refuse('Only the project\'s owner can update it.'); return; }
|
|
144
|
+
refuse('This project already runs the newest version it can take.');
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function signIn() {
|
|
148
|
+
var back = String(root.location.pathname || '/deploy') + String(root.location.search || '');
|
|
149
|
+
root.location.assign(API + '/auth/web/start?return=' + encodeURIComponent(back));
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function read(path) {
|
|
153
|
+
return api.request('GET', API + path).then(function (res) {
|
|
154
|
+
if (res && res.status === 401) { signIn(); throw { kind: '401' }; }
|
|
155
|
+
if (!res || !res.ok) {
|
|
156
|
+
var err = (res && res.data && res.data.error) || {};
|
|
157
|
+
var e = new Error(err.message && err.message !== err.code ? err.message : (err.code || path + ' → ' + (res && res.status)));
|
|
158
|
+
e.status = res && res.status;
|
|
159
|
+
throw e;
|
|
160
|
+
}
|
|
161
|
+
return res.data;
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// The project by name: the whole roster where the viewer may read it, else their own
|
|
166
|
+
// projects (deploy.js findBySlug's order). A lookup, never a listing.
|
|
167
|
+
read('/provisioning/fleet').then(function (d) { return d.instances || []; }, function (e) {
|
|
168
|
+
if (e && e.status === 403) return read('/provisioning/instances').then(function (d) { return d.instances || []; });
|
|
169
|
+
throw e;
|
|
170
|
+
}).then(function (rows) {
|
|
171
|
+
for (var i = 0; i < rows.length; i++) if (rows[i] && String(rows[i].slug) === slug) inst = rows[i];
|
|
172
|
+
if (!inst) throw new Error('No project called ' + slug + ' is hosted here under your account.');
|
|
173
|
+
allowed = projectOrigin(inst, root.location.protocol);
|
|
174
|
+
return read('/provisioning/instances/' + encodeURIComponent(inst.id) + '/core-upgrade');
|
|
175
|
+
}).then(function (d) {
|
|
176
|
+
preview = d.preview || null;
|
|
177
|
+
if (!preview || preview.reading !== 'ok' || !preview.behind) {
|
|
178
|
+
refuse(preview && preview.reading === 'ok' ? 'This project already runs the newest version it can take.' : 'This project\'s version could not be read just now. Nothing was changed.');
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
if (preview.open_intent) { refuse('Another change is already running for this project. Try again once it settles.'); return; }
|
|
182
|
+
if (!opener || !allowed) { offerPress(); return; }
|
|
183
|
+
root.addEventListener('message', onMessage);
|
|
184
|
+
tell({ step: 'ready' });
|
|
185
|
+
draw(title('Updating ' + slug) + '<p class="upd-card__note" role="status">Waiting for your hall…</p>');
|
|
186
|
+
root.setTimeout(function () { if (!heard && !moving) offerPress(); }, HEAR_MS);
|
|
187
|
+
}).then(null, function (e) {
|
|
188
|
+
if (e && e.kind === '401') return;
|
|
189
|
+
refuse(String((e && e.message) || 'This project\'s update could not be opened.'));
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
function scopeSlug(loc) {
|
|
194
|
+
try {
|
|
195
|
+
var m = /[?&]project=([^&#]+)/.exec(String((loc && loc.search) || ''));
|
|
196
|
+
return m ? decodeURIComponent(m[1]) : null;
|
|
197
|
+
} catch (e) { return null; }
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
var api = { wanted: wanted, run: run, judgeGo: judgeGo, projectOrigin: projectOrigin, MSG: MSG };
|
|
201
|
+
if (typeof module !== 'undefined' && module.exports) module.exports = api;
|
|
202
|
+
if (root) root.OTBDeployHandoff = api;
|
|
203
|
+
})(typeof window !== 'undefined' ? window : null);
|
|
@@ -28,6 +28,8 @@
|
|
|
28
28
|
</div>
|
|
29
29
|
|
|
30
30
|
<main id="hall-main">
|
|
31
|
+
<!-- task 1005043: the page loader, shown until any section below is revealed. -->
|
|
32
|
+
<p class="hall-loading hall-loading--page hall-loading--wait" role="status">Loading…</p>
|
|
31
33
|
<section class="scroll" id="dp-sealed" aria-labelledby="dp-sealed-h" hidden>
|
|
32
34
|
<h2 class="scroll__h" id="dp-sealed-h">Restricted</h2>
|
|
33
35
|
<p class="scroll__lede" id="dp-sealed-body">This page opens at a higher rank.</p>
|
|
@@ -79,11 +81,13 @@
|
|
|
79
81
|
<script src="/builders/dom-utils.js?v=2026-10-25-escape"></script>
|
|
80
82
|
<script src="/builders/shell-trail.js?v=2026-10-08-city-tab"></script>
|
|
81
83
|
<script src="/builders/craft-mode.js?v=2026-10-30-market-watch"></script>
|
|
82
|
-
<script src="/builders/shell.js?v=2026-
|
|
84
|
+
<script src="/builders/shell.js?v=2026-11-03-update-pill"></script>
|
|
83
85
|
<script src="/builders/palette.js" defer></script>
|
|
84
86
|
<script src="/builders/hall-kit.js"></script>
|
|
85
87
|
<!-- the shared ask card the move is drawn with (task 1004829) -->
|
|
86
88
|
<script src="/builders/hall-ask.js"></script>
|
|
87
|
-
|
|
89
|
+
<!-- the in-place update window a hosted project's hall opens (task 1005041) -->
|
|
90
|
+
<script src="/builders/deploy-handoff.js?v=2026-11-03-handoff"></script>
|
|
91
|
+
<script src="/builders/deploy.js?v=2026-11-03-handoff"></script>
|
|
88
92
|
</body>
|
|
89
93
|
</html>
|
|
@@ -906,5 +906,11 @@
|
|
|
906
906
|
}
|
|
907
907
|
}
|
|
908
908
|
|
|
909
|
-
document.addEventListener('DOMContentLoaded', () => {
|
|
909
|
+
document.addEventListener('DOMContentLoaded', () => {
|
|
910
|
+
// task 1005041: the small window a hosted project's hall opens to update in place. It is
|
|
911
|
+
// this door, asked from the project's own site, and deploy-handoff.js draws it instead.
|
|
912
|
+
const handoff = window.OTBDeployHandoff;
|
|
913
|
+
if (handoff && handoff.wanted(window.location)) { handoff.run({ api }); return; }
|
|
914
|
+
load(); loadModuleSections();
|
|
915
|
+
});
|
|
910
916
|
})();
|
|
@@ -97,7 +97,7 @@
|
|
|
97
97
|
<script src="/builders/dom-utils.js?v=2026-10-25-escape"></script>
|
|
98
98
|
<script src="/builders/shell-trail.js?v=2026-10-08-city-tab"></script>
|
|
99
99
|
<script src="/builders/craft-mode.js?v=2026-10-30-market-watch"></script>
|
|
100
|
-
<script src="/builders/shell.js?v=2026-
|
|
100
|
+
<script src="/builders/shell.js?v=2026-11-03-update-pill"></script>
|
|
101
101
|
<!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
|
|
102
102
|
<script src="/builders/palette.js" defer></script>
|
|
103
103
|
<script src="/builders/diagram-viewer.js?v=2026-06-14-diagviewer-1" defer></script>
|
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
<nav class="primer-toc__inner">
|
|
52
52
|
<p class="primer-toc__heading" id="primer-toc-heading">On this page</p>
|
|
53
53
|
<ol class="primer-toc__list" id="primer-toc-list" aria-labelledby="primer-toc-heading">
|
|
54
|
-
<li class="
|
|
54
|
+
<li class="hall-loading hall-loading--inline" role="status">Loading…</li>
|
|
55
55
|
</ol>
|
|
56
56
|
</nav>
|
|
57
57
|
</aside>
|
|
@@ -97,7 +97,7 @@
|
|
|
97
97
|
<script src="/builders/dom-utils.js?v=2026-10-25-escape"></script>
|
|
98
98
|
<script src="/builders/shell-trail.js?v=2026-10-08-city-tab"></script>
|
|
99
99
|
<script src="/builders/craft-mode.js?v=2026-10-30-market-watch"></script>
|
|
100
|
-
<script src="/builders/shell.js?v=2026-
|
|
100
|
+
<script src="/builders/shell.js?v=2026-11-03-update-pill"></script>
|
|
101
101
|
<!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
|
|
102
102
|
<script src="/builders/palette.js" defer></script>
|
|
103
103
|
<script src="/builders/md-reader.js?v=2026-09-02-mdreader-2"></script>
|
|
@@ -27,6 +27,8 @@
|
|
|
27
27
|
</div>
|
|
28
28
|
|
|
29
29
|
<main id="hall-main">
|
|
30
|
+
<!-- task 1005043: the page loader, shown until any section below is revealed. -->
|
|
31
|
+
<p class="hall-loading hall-loading--page hall-loading--wait" role="status">Loading…</p>
|
|
30
32
|
<section class="scroll" id="fl-sealed" aria-labelledby="fl-sealed-h" hidden>
|
|
31
33
|
<h2 class="scroll__h" id="fl-sealed-h">Restricted</h2>
|
|
32
34
|
<p class="scroll__lede">This page opens at a higher rank.</p>
|
|
@@ -58,7 +60,7 @@
|
|
|
58
60
|
<script src="/builders/dom-utils.js?v=2026-10-25-escape"></script>
|
|
59
61
|
<script src="/builders/shell-trail.js?v=2026-10-08-city-tab"></script>
|
|
60
62
|
<script src="/builders/craft-mode.js?v=2026-10-30-market-watch"></script>
|
|
61
|
-
<script src="/builders/shell.js?v=2026-
|
|
63
|
+
<script src="/builders/shell.js?v=2026-11-03-update-pill"></script>
|
|
62
64
|
<script src="/builders/palette.js" defer></script>
|
|
63
65
|
<script src="/builders/hall-kit.js"></script>
|
|
64
66
|
<script src="/builders/fleet-costs.js"></script>
|
|
@@ -27,6 +27,8 @@
|
|
|
27
27
|
</div>
|
|
28
28
|
|
|
29
29
|
<main id="hall-main">
|
|
30
|
+
<!-- task 1005043: the page loader, shown until any section below is revealed. -->
|
|
31
|
+
<p class="hall-loading hall-loading--page hall-loading--wait" role="status">Loading…</p>
|
|
30
32
|
<!-- task 1003469: the sealed state is a panel with a heading, not a bare
|
|
31
33
|
line on the ground. gate.js writes the real floor into the lede from
|
|
32
34
|
the pack's rank label, so the copy cannot drift from ADR 0157. -->
|
|
@@ -65,7 +67,7 @@
|
|
|
65
67
|
<script src="/builders/dom-utils.js?v=2026-10-25-escape"></script>
|
|
66
68
|
<script src="/builders/shell-trail.js?v=2026-10-08-city-tab"></script>
|
|
67
69
|
<script src="/builders/craft-mode.js?v=2026-10-30-market-watch"></script>
|
|
68
|
-
<script src="/builders/shell.js?v=2026-
|
|
70
|
+
<script src="/builders/shell.js?v=2026-11-03-update-pill"></script>
|
|
69
71
|
<!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
|
|
70
72
|
<script src="/builders/palette.js" defer></script>
|
|
71
73
|
<script src="/builders/hall-kit.js"></script>
|