@bongos/core 1.24.51 → 1.24.52
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 +95 -85
- package/docs/copy-inventory.md +199 -215
- package/docs/copy-registry.json +230 -395
- package/docs/file-map.md +1 -1
- package/docs/module-api-changelog.md +2 -0
- package/docs/page-inventory.json +33 -0
- package/docs/page-readings.json +450 -463
- package/modules/hall-ui/public/ai-studio.html +1 -0
- package/modules/hall-ui/public/approval-queue.css +3 -11
- package/modules/hall-ui/public/approval-queue.js +13 -20
- package/modules/hall-ui/public/atlas.html +1 -0
- package/modules/hall-ui/public/blockers.html +1 -0
- package/modules/hall-ui/public/board-room.html +1 -0
- package/modules/hall-ui/public/bulk-toolbar.js +5 -1
- package/modules/hall-ui/public/city.html +1 -0
- package/modules/hall-ui/public/collab.html +1 -0
- package/modules/hall-ui/public/commands.html +1 -0
- package/modules/hall-ui/public/controls.css +100 -0
- package/modules/hall-ui/public/copy-desk.css +7 -11
- package/modules/hall-ui/public/copy-desk.html +17 -16
- package/modules/hall-ui/public/copy-desk.js +13 -9
- package/modules/hall-ui/public/deploy.html +1 -0
- package/modules/hall-ui/public/goal-inbox.js +32 -17
- package/modules/hall-ui/public/goal-map.html +1 -0
- package/modules/hall-ui/public/goals-page.js +7 -1
- package/modules/hall-ui/public/goals.html +1 -0
- package/modules/hall-ui/public/government.html +1 -0
- package/modules/hall-ui/public/government.js +10 -2
- package/modules/hall-ui/public/hall-dialog.js +255 -0
- package/modules/hall-ui/public/hall-kit.js +9 -2
- package/modules/hall-ui/public/idea.html +1 -0
- package/modules/hall-ui/public/ideas.html +1 -0
- package/modules/hall-ui/public/index.html +1 -0
- package/modules/hall-ui/public/market-watch-item.html +2 -1
- package/modules/hall-ui/public/market-watch-lib.js +16 -9
- package/modules/hall-ui/public/market-watch-rules.html +1 -0
- package/modules/hall-ui/public/market-watch.css +2 -3
- package/modules/hall-ui/public/market-watch.html +2 -1
- package/modules/hall-ui/public/modules.html +1 -0
- package/modules/hall-ui/public/money.html +1 -0
- package/modules/hall-ui/public/my-agents.html +1 -0
- package/modules/hall-ui/public/oversight.css +3 -33
- package/modules/hall-ui/public/primer.html +1 -0
- package/modules/hall-ui/public/profile.html +1 -0
- package/modules/hall-ui/public/project-settings.html +1 -0
- package/modules/hall-ui/public/roster.html +1 -0
- package/modules/hall-ui/public/settings-ai-keys.js +5 -1
- package/modules/hall-ui/public/settings-passkeys.js +5 -1
- package/modules/hall-ui/public/settings-sessions.js +10 -2
- package/modules/hall-ui/public/settings.html +1 -0
- package/modules/hall-ui/public/settings.js +5 -1
- package/modules/hall-ui/public/street.html +1 -0
- package/modules/hall-ui/public/studio.css +6 -32
- package/modules/hall-ui/public/studio.html +4 -3
- package/modules/hall-ui/public/studio.js +40 -35
- package/modules/hall-ui/public/style.css +2 -8
- package/modules/hall-ui/public/task.html +1 -0
- package/modules/hall-ui/public/task.js +26 -12
- package/modules/hall-ui/public/thinking.html +1 -0
- package/modules/hall-ui/public/tweak-editor.html +1 -0
- package/modules/hall-ui/public/watch.html +1 -0
- package/modules/hall-ui/public/work.html +1 -0
- package/modules/hall-ui/public/work.js +7 -1
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/release-notes.json +6 -0
- package/src/module-api.js +1 -1
- package/tests/bulk_toolbar.mjs +1 -1
- package/tests/hall_approval_queue.mjs +8 -2
- package/tests/hall_audit.mjs +1 -1
- package/tests/hall_city.mjs +1 -1
- package/tests/hall_collab_world.mjs +9 -6
- package/tests/hall_dialog.mjs +401 -0
- package/tests/hall_error_envelope.mjs +1 -1
- package/tests/hall_oversight_world.mjs +9 -7
- package/tests/hall_record_world.mjs +1 -1
- package/tests/hall_street.mjs +1 -1
- package/tests/hall_studio_home.mjs +1 -1
- package/tests/home_attention_cards.mjs +2 -0
- package/tests/kind_axis_unset.mjs +1 -1
- package/tests/market_watch_pages.mjs +3 -1
|
@@ -395,6 +395,7 @@
|
|
|
395
395
|
<script src="/builders/shell-trail.js?v=2026-11-05-numbers"></script>
|
|
396
396
|
<script src="/builders/craft-mode.js?v=2026-11-05-goals"></script>
|
|
397
397
|
<script src="/builders/shell.js?v=2026-11-07-brand-mark"></script>
|
|
398
|
+
<script src="/builders/hall-dialog.js"></script>
|
|
398
399
|
<!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
|
|
399
400
|
<script src="/builders/palette.js" defer></script>
|
|
400
401
|
<!-- shared component kit (window.OTBKit) — section rail (task 2166). -->
|
|
@@ -814,7 +814,11 @@
|
|
|
814
814
|
|
|
815
815
|
async function removeArtKey() {
|
|
816
816
|
const status = $('#artkey-status');
|
|
817
|
-
if (!window.confirm(
|
|
817
|
+
if (!(await window.OTBDialog.confirm({
|
|
818
|
+
title: 'Remove your image-generation key?',
|
|
819
|
+
body: 'Art generation will stop until you add one again.',
|
|
820
|
+
confirmLabel: 'Remove key', danger: true,
|
|
821
|
+
}))) return;
|
|
818
822
|
if (status) status.textContent = 'Removing…';
|
|
819
823
|
try {
|
|
820
824
|
const res = await api.request('DELETE', `${API}/me/art-key/own`);
|
|
@@ -232,6 +232,7 @@
|
|
|
232
232
|
<script src="/builders/shell-trail.js?v=2026-11-05-numbers"></script>
|
|
233
233
|
<script src="/builders/craft-mode.js?v=2026-11-05-goals"></script>
|
|
234
234
|
<script src="/builders/shell.js?v=2026-11-07-brand-mark"></script>
|
|
235
|
+
<script src="/builders/hall-dialog.js"></script>
|
|
235
236
|
<script src="/builders/palette.js" defer></script>
|
|
236
237
|
<script src="/builders/gov-living.js?v=2026-10-09-positions1"></script>
|
|
237
238
|
<script src="/builders/gov-feeds.js?v=2026-10-09-living3"></script>
|
|
@@ -73,7 +73,6 @@ body[data-page="studio"] {
|
|
|
73
73
|
--st-panel: rgba(255, 255, 255, .075);
|
|
74
74
|
--st-panel-edge: rgba(255, 255, 255, .18);
|
|
75
75
|
--st-panel-rim: rgba(255, 255, 255, .22);
|
|
76
|
-
--st-panel-drop: rgba(0, 0, 0, .55);
|
|
77
76
|
--st-close: rgba(255, 255, 255, .08);
|
|
78
77
|
--st-chip-edge: rgba(255, 255, 255, .16);
|
|
79
78
|
--st-track: rgba(255, 255, 255, .1);
|
|
@@ -126,7 +125,6 @@ body[data-page="studio"][data-sky="day"] {
|
|
|
126
125
|
--st-panel: rgba(255, 255, 255, .75);
|
|
127
126
|
--st-panel-edge: rgba(60, 40, 20, .16);
|
|
128
127
|
--st-panel-rim: rgba(255, 255, 255, .9);
|
|
129
|
-
--st-panel-drop: rgba(60, 40, 20, .18);
|
|
130
128
|
--st-close: rgba(60, 40, 20, .08);
|
|
131
129
|
--st-chip-edge: rgba(60, 40, 20, .2);
|
|
132
130
|
--st-track: rgba(60, 40, 20, .12);
|
|
@@ -150,7 +148,6 @@ body[data-page="studio"][data-sky="day"] .aq-overlay {
|
|
|
150
148
|
--aq-glass: rgba(255, 255, 255, .75);
|
|
151
149
|
--aq-glass-edge: rgba(60, 40, 20, .16);
|
|
152
150
|
--aq-glass-rim: rgba(255, 255, 255, .9);
|
|
153
|
-
--aq-drop: rgba(60, 40, 20, .18);
|
|
154
151
|
--aq-ink: #1b1a1d;
|
|
155
152
|
--aq-ink-soft: #4d4c52;
|
|
156
153
|
--aq-ink-faint: #5a595f;
|
|
@@ -597,20 +594,13 @@ html.st-reading .st-glance { display: none; }
|
|
|
597
594
|
page), and .88 on a phone.
|
|
598
595
|
--------------------------------------------------------------------------- */
|
|
599
596
|
.st-overlay {
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
z-index: var(--z-modal, 160);
|
|
603
|
-
display: flex;
|
|
604
|
-
align-items: center;
|
|
605
|
-
justify-content: center;
|
|
606
|
-
padding: 24px;
|
|
607
|
-
box-sizing: border-box;
|
|
597
|
+
/* the layer, the placement and the gutter are the shared .hall-scrim's
|
|
598
|
+
(controls.css, task 1005085); only the sky's tint is its own */
|
|
608
599
|
background: var(--st-scrim);
|
|
609
600
|
color: var(--st-ink);
|
|
610
601
|
font-family: var(--st-face);
|
|
611
602
|
color-scheme: dark;
|
|
612
603
|
}
|
|
613
|
-
.st-overlay[hidden] { display: none; }
|
|
614
604
|
html[data-theme="dark"] body[data-page="studio"] { --st-scrim: rgba(4, 5, 9, .42); }
|
|
615
605
|
@media (prefers-color-scheme: dark) {
|
|
616
606
|
html:not([data-theme]) body[data-page="studio"] { --st-scrim: rgba(4, 5, 9, .42); }
|
|
@@ -627,7 +617,7 @@ html.st-open { overflow: hidden; }
|
|
|
627
617
|
border: 1px solid var(--st-panel-edge);
|
|
628
618
|
backdrop-filter: blur(30px) saturate(160%);
|
|
629
619
|
-webkit-backdrop-filter: blur(30px) saturate(160%);
|
|
630
|
-
box-shadow: inset 0 1px 0 var(--st-panel-rim),
|
|
620
|
+
box-shadow: inset 0 1px 0 var(--st-panel-rim), var(--ds-shadow-pop);
|
|
631
621
|
display: flex;
|
|
632
622
|
flex-direction: column;
|
|
633
623
|
gap: 22px;
|
|
@@ -797,28 +787,12 @@ html.st-open { overflow: hidden; }
|
|
|
797
787
|
tokens, in a dialog that opens from the quiet door above.
|
|
798
788
|
=========================================================================== */
|
|
799
789
|
.st-reviews {
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
z-index: var(--z-modal, 160);
|
|
803
|
-
display: flex;
|
|
804
|
-
align-items: center;
|
|
805
|
-
justify-content: center;
|
|
806
|
-
padding: 24px;
|
|
807
|
-
box-sizing: border-box;
|
|
808
|
-
background: var(--scrim);
|
|
790
|
+
/* the shared .hall-scrim (controls.css, task 1005085) is the layer and the
|
|
791
|
+
scrim; the panel inside is the shared .hall-dialog */
|
|
809
792
|
color: var(--ink);
|
|
810
793
|
font-family: var(--font-body);
|
|
811
794
|
}
|
|
812
|
-
.st-
|
|
813
|
-
.st-reviews__dialog {
|
|
814
|
-
width: min(780px, 100%);
|
|
815
|
-
max-height: 100%;
|
|
816
|
-
overflow-y: auto;
|
|
817
|
-
box-sizing: border-box;
|
|
818
|
-
padding: clamp(18px, 3vw, 28px);
|
|
819
|
-
border-radius: var(--radius);
|
|
820
|
-
background: var(--bg);
|
|
821
|
-
}
|
|
795
|
+
.st-reviews__dialog { width: min(780px, 100%); }
|
|
822
796
|
.st-reviews__head { display: flex; align-items: center; gap: 12px; margin-bottom: 6px; }
|
|
823
797
|
.st-reviews__head .btn-ghost { margin-left: auto; }
|
|
824
798
|
.st-reviews__title {
|
|
@@ -177,7 +177,7 @@
|
|
|
177
177
|
<!-- The two small glass panels: the Tweak/CopyWrite Flow and Artist
|
|
178
178
|
Review Status. The Approval queue is its own component
|
|
179
179
|
(approval-queue.js), mounted by studio.js. -->
|
|
180
|
-
<div class="st-overlay" id="st-panel" hidden>
|
|
180
|
+
<div class="hall-scrim st-overlay" id="st-panel" hidden>
|
|
181
181
|
<div class="st-dialog" role="dialog" aria-modal="true" aria-labelledby="st-panel-title">
|
|
182
182
|
<div class="st-dialog__head">
|
|
183
183
|
<h2 class="st-dialog__title" id="st-panel-title" tabindex="-1">Work through tweaks</h2>
|
|
@@ -189,8 +189,8 @@
|
|
|
189
189
|
|
|
190
190
|
<!-- The reviews filed before Tweak Mode (R04, retired in TW14): the
|
|
191
191
|
garden, one piece at a time, answered here until none remain. -->
|
|
192
|
-
<div class="st-reviews" id="st-reviews" hidden>
|
|
193
|
-
<div class="st-reviews__dialog" role="dialog" aria-modal="true" aria-labelledby="st-reviews-title">
|
|
192
|
+
<div class="hall-scrim st-reviews" id="st-reviews" hidden>
|
|
193
|
+
<div class="hall-dialog hall-dialog--wide st-reviews__dialog" role="dialog" aria-modal="true" aria-labelledby="st-reviews-title">
|
|
194
194
|
<div class="st-reviews__head">
|
|
195
195
|
<h2 class="st-reviews__title" id="st-reviews-title" tabindex="-1">Reviews from before Tweak Mode</h2>
|
|
196
196
|
<button type="button" class="btn-ghost" data-close-reviews>close</button>
|
|
@@ -226,6 +226,7 @@
|
|
|
226
226
|
<script src="/builders/shell-trail.js?v=2026-11-05-numbers"></script>
|
|
227
227
|
<script src="/builders/craft-mode.js?v=2026-11-05-goals"></script>
|
|
228
228
|
<script src="/builders/shell.js?v=2026-11-07-brand-mark"></script>
|
|
229
|
+
<script src="/builders/hall-dialog.js"></script>
|
|
229
230
|
<script src="/builders/palette.js" defer></script>
|
|
230
231
|
<!-- The kit, for its ONE renderer: the full-size ship-time visual figure
|
|
231
232
|
(task 1003829), which the older reviews still show. -->
|
|
@@ -821,27 +821,33 @@
|
|
|
821
821
|
body.innerHTML = home.panel === 'flow' ? flowHtml() : home.panel === 'site' ? siteHtml() : statusHtml();
|
|
822
822
|
}
|
|
823
823
|
|
|
824
|
-
|
|
824
|
+
// The two panels run on the hall's one dialog behaviour (hall-dialog.js, task
|
|
825
|
+
// 1005085): Escape closes the top one only, Tab stays inside, a click on the
|
|
826
|
+
// scrim closes, the scroll locks, and focus goes back to the door that opened it.
|
|
827
|
+
function panelModal() {
|
|
825
828
|
const overlay = byId('st-panel');
|
|
826
|
-
if (!overlay
|
|
829
|
+
if (!overlay) return null;
|
|
830
|
+
return window.OTBDialog.bind(overlay, {
|
|
831
|
+
panel: overlay.querySelector('[role="dialog"]'),
|
|
832
|
+
lockClass: 'st-open',
|
|
833
|
+
initialFocus: () => byId('st-panel-title'),
|
|
834
|
+
onClose: () => { home.panel = null; },
|
|
835
|
+
});
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
function openPanel(kind, opener) {
|
|
839
|
+
const m = panelModal();
|
|
840
|
+
if (!m || !TITLES[kind]) return;
|
|
827
841
|
home.panel = kind;
|
|
828
|
-
home.opener = opener || null;
|
|
829
842
|
home.picking = false;
|
|
830
843
|
setText('st-panel-title', TITLES[kind]);
|
|
831
844
|
paintPanel();
|
|
832
|
-
|
|
833
|
-
document.documentElement.classList.add('st-open');
|
|
834
|
-
const title = byId('st-panel-title');
|
|
835
|
-
if (title) title.focus();
|
|
845
|
+
m.open(opener || null);
|
|
836
846
|
}
|
|
837
847
|
|
|
838
848
|
function closePanel() {
|
|
839
|
-
const
|
|
840
|
-
if (
|
|
841
|
-
overlay.hidden = true;
|
|
842
|
-
home.panel = null;
|
|
843
|
-
document.documentElement.classList.remove('st-open');
|
|
844
|
-
if (home.opener && home.opener.focus) home.opener.focus();
|
|
849
|
+
const m = panelModal();
|
|
850
|
+
if (m) m.close();
|
|
845
851
|
}
|
|
846
852
|
|
|
847
853
|
// Release a round the reads cannot name (task 1004837). One line of why is
|
|
@@ -875,24 +881,29 @@
|
|
|
875
881
|
|
|
876
882
|
// ---- the older reviews' dialog --------------------------------------------
|
|
877
883
|
|
|
878
|
-
function
|
|
884
|
+
function reviewsModal() {
|
|
879
885
|
const box = byId('st-reviews');
|
|
880
|
-
if (!box) return;
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
+
if (!box) return null;
|
|
887
|
+
return window.OTBDialog.bind(box, {
|
|
888
|
+
panel: box.querySelector('[role="dialog"]'),
|
|
889
|
+
lockClass: 'st-open',
|
|
890
|
+
initialFocus: () => byId('st-reviews-title'),
|
|
891
|
+
// the door hides once the last review is answered: fall back to the flow door
|
|
892
|
+
returnFocus: (opener) => {
|
|
893
|
+
const door = byId('st-older');
|
|
894
|
+
return opener && !opener.hidden ? opener : (door && !door.hidden ? door : byId('st-flow'));
|
|
895
|
+
},
|
|
896
|
+
});
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
function openReviews(opener) {
|
|
900
|
+
const m = reviewsModal();
|
|
901
|
+
if (m) m.open(opener || null);
|
|
886
902
|
}
|
|
887
903
|
|
|
888
904
|
function closeReviews() {
|
|
889
|
-
const
|
|
890
|
-
if (
|
|
891
|
-
box.hidden = true;
|
|
892
|
-
document.documentElement.classList.remove('st-open');
|
|
893
|
-
const door = byId('st-older');
|
|
894
|
-
const back = home.opener && !home.opener.hidden ? home.opener : (door && !door.hidden ? door : byId('st-flow'));
|
|
895
|
-
if (back && back.focus) back.focus();
|
|
905
|
+
const m = reviewsModal();
|
|
906
|
+
if (m) m.close();
|
|
896
907
|
}
|
|
897
908
|
|
|
898
909
|
// ---- the studio's own words, typed over in place ---------------------------
|
|
@@ -1072,7 +1083,7 @@
|
|
|
1072
1083
|
const overlay = byId('st-panel');
|
|
1073
1084
|
if (overlay) {
|
|
1074
1085
|
overlay.addEventListener('click', (ev) => {
|
|
1075
|
-
if (ev.target
|
|
1086
|
+
if (ev.target.closest('[data-close-panel]')) { closePanel(); return; }
|
|
1076
1087
|
const review = ev.target.closest('[data-review-page]');
|
|
1077
1088
|
if (review && approvals) { ev.preventDefault(); const id = review.getAttribute('data-review-page'); closePanel(); approvals.open(id); return; }
|
|
1078
1089
|
const rel = ev.target.closest('[data-release-page]');
|
|
@@ -1087,15 +1098,9 @@
|
|
|
1087
1098
|
const reviews = byId('st-reviews');
|
|
1088
1099
|
if (reviews) {
|
|
1089
1100
|
reviews.addEventListener('click', (ev) => {
|
|
1090
|
-
if (ev.target
|
|
1101
|
+
if (ev.target.closest('[data-close-reviews]')) closeReviews();
|
|
1091
1102
|
});
|
|
1092
1103
|
}
|
|
1093
|
-
document.addEventListener('keydown', (ev) => {
|
|
1094
|
-
if (ev.key !== 'Escape') return;
|
|
1095
|
-
if (home.panel) { closePanel(); return; }
|
|
1096
|
-
const box = byId('st-reviews');
|
|
1097
|
-
if (box && !box.hidden) closeReviews();
|
|
1098
|
-
});
|
|
1099
1104
|
|
|
1100
1105
|
const hint = byId('st-hint');
|
|
1101
1106
|
if (hint) hint.addEventListener('click', () => beginWords(null));
|
|
@@ -4604,14 +4604,8 @@ body[data-page="home"] #home-stats .stat-row { border-bottom-left-radius: 0; bor
|
|
|
4604
4604
|
.attn-card__n { font-family: var(--font-display); font-size: 30px; font-weight: 300; line-height: 1; font-variant-numeric: tabular-nums; }
|
|
4605
4605
|
.attn-card__t { font-weight: 600; }
|
|
4606
4606
|
.attn-card__s { margin-top: auto; font-size: 12px; color: var(--ink-soft); }
|
|
4607
|
-
.
|
|
4608
|
-
|
|
4609
|
-
background: var(--bg-card); color: var(--ink); border: 0; border-radius: var(--radius);
|
|
4610
|
-
}
|
|
4611
|
-
.attn-dialog::backdrop { background: var(--scrim); }
|
|
4612
|
-
.attn-dialog__head { display: flex; align-items: center; gap: 12px; margin-bottom: 8px; }
|
|
4613
|
-
.attn-dialog__h { flex: 1; margin: 0; font-family: var(--font-display); font-weight: 500; font-size: 20px; }
|
|
4614
|
-
.attn-dialog__x { min-width: 32px; min-height: 32px; background: none; border: 0; color: var(--ink-soft); font-size: 22px; cursor: pointer; }
|
|
4607
|
+
/* The window a card opens is the hall's one dialog (controls.css .hall-dialog,
|
|
4608
|
+
task 1005085); the slice's own heading is the dialog's title, so it hides. */
|
|
4615
4609
|
.attn-dialog__body .ginbox__sec-h { display: none; }
|
|
4616
4610
|
|
|
4617
4611
|
.home-split { display: grid; grid-template-columns: 1fr 1fr; gap: 24px; align-items: start; }
|
|
@@ -60,6 +60,7 @@
|
|
|
60
60
|
<script src="/builders/shell-trail.js?v=2026-11-05-numbers"></script>
|
|
61
61
|
<script src="/builders/craft-mode.js?v=2026-11-05-goals"></script>
|
|
62
62
|
<script src="/builders/shell.js?v=2026-11-07-brand-mark"></script>
|
|
63
|
+
<script src="/builders/hall-dialog.js"></script>
|
|
63
64
|
<!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
|
|
64
65
|
<script src="/builders/palette.js" defer></script>
|
|
65
66
|
<!-- task-detail.js still owns the #/idea/N and #/blocker/N deep-link overlay
|
|
@@ -173,6 +173,19 @@
|
|
|
173
173
|
}
|
|
174
174
|
}
|
|
175
175
|
|
|
176
|
+
// Confirm a task. A verify-kind task's confirm attests the verification
|
|
177
|
+
// actually passed (the server requires { verified: true }), so the Archon
|
|
178
|
+
// affirms it in the hall's own confirm first (task 1005085).
|
|
179
|
+
async function confirmTask(t, btn) {
|
|
180
|
+
if (t.kind === 'verify' && !(await window.OTBDialog.confirm({
|
|
181
|
+
title: `Confirm that verification for #${t.id} actually passed?`,
|
|
182
|
+
body: 'The task is recorded as confirmed, with your word that its verification passed.',
|
|
183
|
+
confirmLabel: 'It passed', trigger: btn,
|
|
184
|
+
}))) return;
|
|
185
|
+
const body = t.kind === 'verify' ? { verified: true } : {};
|
|
186
|
+
runLifecycle(btn, `${API}/tasks/${encodeURIComponent(t.id)}/confirm`, body, `#${t.id} confirmed.`);
|
|
187
|
+
}
|
|
188
|
+
|
|
176
189
|
// The two lifecycle DECISIONS (ship, confirm) as the city's ask card
|
|
177
190
|
// (hall-ask.js; task 1004822, criterion wa6-hall-reads-like-home). Only a
|
|
178
191
|
// decision the page waits on gets the card — claim, copy and retire stay plain
|
|
@@ -898,13 +911,7 @@
|
|
|
898
911
|
}
|
|
899
912
|
const confirmBtn = $('#confirm-btn');
|
|
900
913
|
if (confirmBtn) {
|
|
901
|
-
confirmBtn.addEventListener('click', () =>
|
|
902
|
-
// A verify-kind task's confirm attests the verification actually passed
|
|
903
|
-
// (the server requires { verified: true }); make the Archon affirm it.
|
|
904
|
-
if (t.kind === 'verify' && !window.confirm(`Confirm that verification for #${t.id} actually passed?`)) return;
|
|
905
|
-
const body = t.kind === 'verify' ? { verified: true } : {};
|
|
906
|
-
runLifecycle(confirmBtn, `${API}/tasks/${encodeURIComponent(t.id)}/confirm`, body, `#${t.id} confirmed.`);
|
|
907
|
-
});
|
|
914
|
+
confirmBtn.addEventListener('click', () => confirmTask(t, confirmBtn));
|
|
908
915
|
}
|
|
909
916
|
|
|
910
917
|
// task 1003063 (R10): PATCH goal_id, then a full reload so the goal line, the
|
|
@@ -995,13 +1002,20 @@
|
|
|
995
1002
|
// reason is the record noting that someone did this and declining to say
|
|
996
1003
|
// why. Asking costs one line.
|
|
997
1004
|
if (!reason) { toast('Say why it is being retired — the reason goes in the record.'); return; }
|
|
998
|
-
|
|
999
|
-
abandonOpen = false;
|
|
1000
|
-
runWrite(abandonBtn,
|
|
1001
|
-
() => postJSON(`${API}/tasks/${encodeURIComponent(t.id)}/abandon`, { reason }),
|
|
1002
|
-
`Task ${t.id} retired. Promote restores it to the backlog.`);
|
|
1005
|
+
retireTask(t, abandonBtn, reason);
|
|
1003
1006
|
});
|
|
1004
1007
|
}
|
|
1008
|
+
async function retireTask(task, btn, reason) {
|
|
1009
|
+
if (!(await window.OTBDialog.confirm({
|
|
1010
|
+
title: `Retire task ${task.id}?`,
|
|
1011
|
+
body: 'It leaves the claimable queue. Promote restores it to the backlog.',
|
|
1012
|
+
confirmLabel: 'Retire task', danger: true, trigger: btn,
|
|
1013
|
+
}))) return;
|
|
1014
|
+
abandonOpen = false;
|
|
1015
|
+
runWrite(btn,
|
|
1016
|
+
() => postJSON(`${API}/tasks/${encodeURIComponent(task.id)}/abandon`, { reason }),
|
|
1017
|
+
`Task ${task.id} retired. Promote restores it to the backlog.`);
|
|
1018
|
+
}
|
|
1005
1019
|
|
|
1006
1020
|
const moveGoalBtn = $('#move-goal-btn');
|
|
1007
1021
|
if (moveGoalBtn) {
|
|
@@ -142,6 +142,7 @@
|
|
|
142
142
|
<script src="/builders/shell-trail.js?v=2026-11-05-numbers"></script>
|
|
143
143
|
<script src="/builders/craft-mode.js?v=2026-11-05-goals"></script>
|
|
144
144
|
<script src="/builders/shell.js?v=2026-11-07-brand-mark"></script>
|
|
145
|
+
<script src="/builders/hall-dialog.js"></script>
|
|
145
146
|
<script src="/builders/palette.js" defer></script>
|
|
146
147
|
|
|
147
148
|
<script src="/builders/idea-objects.js?v=2026-09-27-split"></script>
|
|
@@ -146,6 +146,7 @@
|
|
|
146
146
|
<script src="/builders/shell-trail.js?v=2026-11-05-numbers"></script>
|
|
147
147
|
<script src="/builders/craft-mode.js?v=2026-11-05-goals"></script>
|
|
148
148
|
<script src="/builders/shell.js?v=2026-11-07-brand-mark"></script>
|
|
149
|
+
<script src="/builders/hall-dialog.js"></script>
|
|
149
150
|
<script src="/builders/palette.js" defer></script>
|
|
150
151
|
<script src="/builders/brand-holes.js?v=2026-09-29-aqfix"></script>
|
|
151
152
|
<script src="/builders/tweak-editor-lib.js?v=2026-09-29-tw27"></script>
|
|
@@ -272,6 +272,7 @@
|
|
|
272
272
|
<script src="/builders/shell-trail.js?v=2026-11-05-numbers"></script>
|
|
273
273
|
<script src="/builders/craft-mode.js?v=2026-11-05-goals"></script>
|
|
274
274
|
<script src="/builders/shell.js?v=2026-11-07-brand-mark"></script>
|
|
275
|
+
<script src="/builders/hall-dialog.js"></script>
|
|
275
276
|
<!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
|
|
276
277
|
<script src="/builders/palette.js" defer></script>
|
|
277
278
|
<!-- shared component kit (window.OTBKit) — tabs, ledger, pager (task 2166). -->
|
|
@@ -175,6 +175,7 @@
|
|
|
175
175
|
<script src="/builders/shell-trail.js?v=2026-11-05-numbers"></script>
|
|
176
176
|
<script src="/builders/craft-mode.js?v=2026-11-05-goals"></script>
|
|
177
177
|
<script src="/builders/shell.js?v=2026-11-07-brand-mark"></script>
|
|
178
|
+
<script src="/builders/hall-dialog.js"></script>
|
|
178
179
|
<!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
|
|
179
180
|
<script src="/builders/palette.js" defer></script>
|
|
180
181
|
<!-- task 1004727: the ONE karma vote control every task/idea list renders -->
|
|
@@ -759,8 +759,14 @@
|
|
|
759
759
|
async function doRelease(claimId, taskId, btn) {
|
|
760
760
|
const key = `release:${claimId}`;
|
|
761
761
|
if (pending.has(key)) return;
|
|
762
|
-
|
|
762
|
+
// Held while the confirm is open too, so a second click cannot stack a second dialog.
|
|
763
763
|
pending.add(key);
|
|
764
|
+
const yes = await window.OTBDialog.confirm({
|
|
765
|
+
title: `Release your claim on #${taskId}?`,
|
|
766
|
+
body: `It returns to the queue and no ${curLabel()} are earned.`,
|
|
767
|
+
confirmLabel: 'Release', danger: true, trigger: btn,
|
|
768
|
+
});
|
|
769
|
+
if (!yes) { pending.delete(key); return; }
|
|
764
770
|
if (btn) { btn.disabled = true; btn.textContent = 'Releasing…'; }
|
|
765
771
|
try {
|
|
766
772
|
const out = await claimAction.release(claimId, taskId);
|
package/package-lock.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bongos/core",
|
|
3
|
-
"version": "1.24.
|
|
3
|
+
"version": "1.24.52",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@bongos/core",
|
|
9
|
-
"version": "1.24.
|
|
9
|
+
"version": "1.24.52",
|
|
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.24.
|
|
3
|
+
"version": "1.24.52",
|
|
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",
|
package/release-notes.json
CHANGED
|
@@ -11277,5 +11277,11 @@
|
|
|
11277
11277
|
"id": "1005090",
|
|
11278
11278
|
"text": "The public status page now talks plainly: 'Top builders', 'Recently shipped', 'Spending' instead of the old ancient-city words, and costs show in dollars."
|
|
11279
11279
|
}
|
|
11280
|
+
],
|
|
11281
|
+
"1.24.52": [
|
|
11282
|
+
{
|
|
11283
|
+
"id": "1005085",
|
|
11284
|
+
"text": "The hall's pop-up questions now use one Cloud Bongos dialog instead of the browser's grey box: every 'are you sure?' says plainly what will happen, and the six home-made pop-ups on different pages now share one look and the sa"
|
|
11285
|
+
}
|
|
11280
11286
|
]
|
|
11281
11287
|
}
|
package/src/module-api.js
CHANGED
|
@@ -81,7 +81,7 @@ const { sleep } = require('./sleep');
|
|
|
81
81
|
// MAJOR (see allowBoxScope below): passes the request through untouched.
|
|
82
82
|
function deprecatedNoopMiddleware(_req, _res, next) { next(); }
|
|
83
83
|
|
|
84
|
-
const CORE_VERSION = '1.24.
|
|
84
|
+
const CORE_VERSION = '1.24.52'; // CI auto-patch carrier (ADR 0161); changelog: docs/module-api-changelog.md
|
|
85
85
|
|
|
86
86
|
// A namespaced logger so a module's log lines are attributable + consistent.
|
|
87
87
|
// Usage: const log = api.logger('discord'); log.info('mounted');
|
package/tests/bulk_toolbar.mjs
CHANGED
|
@@ -46,7 +46,7 @@ function stubPage(present) {
|
|
|
46
46
|
const els = {};
|
|
47
47
|
for (const id of present) els[id] = { hidden: true, disabled: false, textContent: '', title: '', listeners: {}, addEventListener(t, fn) { this.listeners[t] = fn; } };
|
|
48
48
|
globalThis.document = { getElementById: (id) => els[id] || null };
|
|
49
|
-
globalThis.window = { confirm: () => true };
|
|
49
|
+
globalThis.window = { OTBDialog: { confirm: async () => true } }; // the branded confirm (task 1005085)
|
|
50
50
|
globalThis.location = loc;
|
|
51
51
|
return els;
|
|
52
52
|
}
|
|
@@ -90,6 +90,9 @@ function bootPanel({ answers = {}, writes = null, mode = 'light' } = {}) {
|
|
|
90
90
|
getElementById: byId,
|
|
91
91
|
createElement: (tag) => augment(makeEl(tag, {})),
|
|
92
92
|
get activeElement() { return boot.focused || null; },
|
|
93
|
+
// the shared dialog (hall-dialog.js, task 1005085) hears its keys on the document
|
|
94
|
+
listeners: {},
|
|
95
|
+
addEventListener(type, fn) { (this.listeners[type] = this.listeners[type] || []).push(fn); },
|
|
93
96
|
};
|
|
94
97
|
const api = {
|
|
95
98
|
// The REAL client's shape: request(method, path, { body }). This fake once
|
|
@@ -110,6 +113,7 @@ function bootPanel({ answers = {}, writes = null, mode = 'light' } = {}) {
|
|
|
110
113
|
win.window = win;
|
|
111
114
|
vm.runInContext(read('brand-holes.js'), ctx, { filename: 'brand-holes.js' });
|
|
112
115
|
vm.runInContext(read('approval-queue-lib.js'), ctx, { filename: 'approval-queue-lib.js' });
|
|
116
|
+
vm.runInContext(read('hall-dialog.js'), ctx, { filename: 'hall-dialog.js' }); // the shared dialog behaviour (task 1005085)
|
|
113
117
|
vm.runInContext(read('approval-queue.js'), ctx, { filename: 'approval-queue.js' });
|
|
114
118
|
const panel = win.OTBApprovalQueue.mount({
|
|
115
119
|
api,
|
|
@@ -124,7 +128,9 @@ function bootPanel({ answers = {}, writes = null, mode = 'light' } = {}) {
|
|
|
124
128
|
const q = (sel) => scrim.querySelector(sel);
|
|
125
129
|
const qa = (sel) => scrim.querySelectorAll(sel);
|
|
126
130
|
const click = async (el) => { assert.ok(el, 'the control exists'); scrim.fire('click', { target: el }); await settle(); await settle(); };
|
|
127
|
-
boot = { body, scrim, q, qa, click, requests, counts, panel, classes, win, focused: null
|
|
131
|
+
boot = { body, scrim, q, qa, click, requests, counts, panel, classes, win, focused: null,
|
|
132
|
+
// a key pressed anywhere in the page reaches the document, where the shared dialog listens
|
|
133
|
+
key: (ev) => (documentObj.listeners.keydown || []).forEach((fn) => fn({ preventDefault() {}, stopPropagation() {}, ...ev })) };
|
|
128
134
|
return boot;
|
|
129
135
|
}
|
|
130
136
|
|
|
@@ -330,7 +336,7 @@ await test('empty, closed with Escape, and focus goes back where it was', async
|
|
|
330
336
|
await b.panel.open(); await settle();
|
|
331
337
|
assert.equal(text(b.q('.aq-title')), 'Nothing waiting');
|
|
332
338
|
assert.match(text(b.q('.aq-frame__note')), /Nothing is waiting for you/);
|
|
333
|
-
b.
|
|
339
|
+
b.key({ key: 'Escape', target: b.scrim });
|
|
334
340
|
assert.equal(b.scrim.hidden, true);
|
|
335
341
|
assert.equal(b.focused, opener);
|
|
336
342
|
assert.ok(!b.classes.has('aq-open'));
|
package/tests/hall_audit.mjs
CHANGED
|
@@ -510,7 +510,7 @@ test('the verdict classes and the scrim exist in the token tier, in both modes',
|
|
|
510
510
|
assert.match(css, /\.ledger__verdict--danger\s*\{[^}]*var\(--danger\)/, 'fell short → --danger');
|
|
511
511
|
assert.match(css, /\.ledger__verdict--none\s*\{[^}]*var\(--ink-soft\)/, 'not graded → --ink-soft');
|
|
512
512
|
assert.match(css, /--scrim:/, 'the modal scrim is a token, not a sheet-local literal');
|
|
513
|
-
assert.match(read('
|
|
513
|
+
assert.match(read('controls.css'), /\.hall-dialog::backdrop \{ background: var\(--scrim\); \}/, 'the one dialog backdrop takes it (task 1005085)');
|
|
514
514
|
});
|
|
515
515
|
|
|
516
516
|
// ---- 10. an outline: none always names its replacement (task 1003496) -----
|
package/tests/hall_city.mjs
CHANGED
|
@@ -288,7 +288,7 @@ test('the city sits in the hall chrome, behind the shell\'s full-screen switch',
|
|
|
288
288
|
// task 1004685 (the living city): gov-living.js, the model under the drawing, and
|
|
289
289
|
// gov-feeds.js, its one reader per page (shared with the shell's tally), load before it
|
|
290
290
|
// task 1004702: the card answers its first ask in place, so the deck's card and sender (and the desk rows under them) load before the page
|
|
291
|
-
assert.deepEqual(scripts, ['dom-utils', 'shell-trail', 'craft-mode', 'shell', 'palette', 'gov-living', 'gov-feeds', 'city-draw', 'hall-kit', 'street-draw', 'street-card', 'street-inside', 'street-desk', 'street-deck', 'city-decide', 'city-switchboard', 'city'], 'the shell first, as on every hall page');
|
|
291
|
+
assert.deepEqual(scripts, ['dom-utils', 'shell-trail', 'craft-mode', 'shell', 'hall-dialog', 'palette', 'gov-living', 'gov-feeds', 'city-draw', 'hall-kit', 'street-draw', 'street-card', 'street-inside', 'street-desk', 'street-deck', 'city-decide', 'city-switchboard', 'city'], 'the shell first, then the shared dialog (task 1005085), as on every hall page');
|
|
292
292
|
// task 1004925: every script but dom-utils.js is deferred, so none holds up the
|
|
293
293
|
// parser; defer runs them in document order, which is why the order above still
|
|
294
294
|
// holds. dom-utils.js stays synchronous: the one-escaper guard
|
|
@@ -53,7 +53,9 @@ test('the page sheets spend only the fifteen, in px, and never opacity', () => {
|
|
|
53
53
|
const cd = read('copy-desk.css');
|
|
54
54
|
const literals = cd.match(/rgba?\([^)]*\)/g) || [];
|
|
55
55
|
assert.deepEqual(literals, [], 'not even the scrim is a literal here any more');
|
|
56
|
-
|
|
56
|
+
// task 1005085: the dialogs are the hall's one dialog, whose backdrop lives in controls.css
|
|
57
|
+
assert.doesNotMatch(cd, /::backdrop/, 'no backdrop of its own');
|
|
58
|
+
assert.match(read('controls.css'), /\.hall-dialog::backdrop \{ background: var\(--scrim\); \}/, 'the shared backdrop spends the token');
|
|
57
59
|
});
|
|
58
60
|
|
|
59
61
|
test('every list is the family\'s row, and the card-in-a-card is gone', () => {
|
|
@@ -335,15 +337,16 @@ test('the filters and the search are the kit\'s bar; the duplicates are paged th
|
|
|
335
337
|
assert.match(read('copy-desk.html'), /src="\/builders\/hall-kit\.js/, 'the page loads the kit');
|
|
336
338
|
});
|
|
337
339
|
|
|
338
|
-
test('the three dialogs are the
|
|
340
|
+
test('the three dialogs are the hall\'s one dialog on a native <dialog>, with the number input in a field', () => {
|
|
339
341
|
const html = read('copy-desk.html');
|
|
340
|
-
// Three since task 1003114 (R03): flag, close, and the proposal composer
|
|
341
|
-
|
|
342
|
+
// Three since task 1003114 (R03): flag, close, and the proposal composer; the
|
|
343
|
+
// shared .hall-dialog since task 1005085, each named by its own title.
|
|
344
|
+
assert.equal((html.match(/<dialog id="cd-(close-dialog|dialog|propose-dialog)" class="hall-dialog cd-dialog" aria-labelledby="cd-(close|dialog|propose)-h">/g) || []).length, 3);
|
|
342
345
|
assert.match(html, /<div class="ov-field ov-field--wide">\s*<label class="ov-field__l" for="cd-close-task">[^<]*<\/label>\s*<input type="number" id="cd-close-task"/, 'the number input sits in the family field, which restates the 30px pill');
|
|
343
346
|
assert.ok(!/<label[^>]*>[^<]*<span class="cd-dialog__hint"/.test(html), 'no hint lives inside a label (the label voice would uppercase it)');
|
|
344
347
|
assert.equal((html.match(/class="ov-form__why"/g) || []).length, 4, 'the four hints are the form\'s own explainer line');
|
|
345
|
-
assert.match(html, /class="btn
|
|
346
|
-
assert.match(html, /class="btn
|
|
348
|
+
assert.match(html, /class="btn" id="cd-submit"/, 'the accent door files the flag');
|
|
349
|
+
assert.match(html, /class="btn" id="cd-propose-submit"/, 'and the proposal composer has its own');
|
|
347
350
|
});
|
|
348
351
|
|
|
349
352
|
test('the proposal composer is prefilled, and says what filing it does and does not do', () => {
|