@bongos/core 1.24.73 → 1.24.74
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 +67 -57
- package/docs/copy-inventory.md +1 -1
- package/docs/copy-registry.json +1 -1
- package/docs/module-api-changelog.md +2 -0
- package/docs/page-inventory.json +33 -0
- package/docs/page-readings.json +36 -36
- package/modules/hall-ui/public/ai-studio.html +2 -1
- package/modules/hall-ui/public/atlas.html +2 -1
- package/modules/hall-ui/public/blockers.html +2 -1
- package/modules/hall-ui/public/board-room.html +2 -1
- package/modules/hall-ui/public/city.html +2 -1
- package/modules/hall-ui/public/collab.html +2 -1
- package/modules/hall-ui/public/commands.html +2 -1
- package/modules/hall-ui/public/copy-desk.html +2 -1
- package/modules/hall-ui/public/deploy.html +2 -1
- package/modules/hall-ui/public/goal-map.html +2 -1
- package/modules/hall-ui/public/goals.html +2 -1
- package/modules/hall-ui/public/government.html +2 -1
- package/modules/hall-ui/public/idea.html +2 -1
- package/modules/hall-ui/public/ideas.html +2 -1
- package/modules/hall-ui/public/index.html +2 -1
- package/modules/hall-ui/public/market-watch-item.html +2 -1
- package/modules/hall-ui/public/market-watch-rules.html +2 -1
- package/modules/hall-ui/public/market-watch.html +2 -1
- package/modules/hall-ui/public/modules.html +2 -1
- package/modules/hall-ui/public/money.html +2 -1
- package/modules/hall-ui/public/my-agents.html +2 -1
- package/modules/hall-ui/public/primer.html +2 -1
- package/modules/hall-ui/public/profile.html +2 -1
- package/modules/hall-ui/public/project-settings.html +2 -1
- package/modules/hall-ui/public/roster.html +2 -1
- package/modules/hall-ui/public/settings.html +2 -1
- package/modules/hall-ui/public/shell-game.js +50 -0
- package/modules/hall-ui/public/shell.js +11 -11
- package/modules/hall-ui/public/street.html +2 -1
- package/modules/hall-ui/public/studio.html +2 -1
- package/modules/hall-ui/public/task.html +2 -1
- package/modules/hall-ui/public/thinking.html +2 -1
- package/modules/hall-ui/public/tweak-editor.html +2 -1
- package/modules/hall-ui/public/watch.html +2 -1
- package/modules/hall-ui/public/work.html +2 -1
- package/modules/hall-ui/records/game-mode.md +20 -0
- 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/goal_map_page.mjs +2 -2
- package/tests/hall_city.mjs +1 -1
- package/tests/hall_fullscreen.mjs +101 -0
- package/tests/hall_my_agents.mjs +1 -1
- package/tests/hall_street.mjs +1 -1
- package/tests/nav_permission_atoms.mjs +1 -1
|
@@ -25,6 +25,8 @@ const HALL = path.join(ROOT, 'modules/hall-ui/public');
|
|
|
25
25
|
const SHELL = fs.readFileSync(path.join(HALL, 'shell.js'), 'utf8');
|
|
26
26
|
// task 1004492: the way back lives in shell-trail.js, which every page loads first.
|
|
27
27
|
const TRAIL = fs.readFileSync(path.join(HALL, 'shell-trail.js'), 'utf8');
|
|
28
|
+
// task 1005142: game mode, the hall-wide half of the switch; every page loads it before the shell.
|
|
29
|
+
const GAME = fs.readFileSync(path.join(HALL, 'shell-game.js'), 'utf8');
|
|
28
30
|
const read = (f) => fs.readFileSync(path.join(HALL, f), 'utf8');
|
|
29
31
|
|
|
30
32
|
// Boot the shell once — one page load. `store` is the browser's localStorage and
|
|
@@ -125,11 +127,16 @@ function boot({ page = 'thinking', optIn = true, store = {}, storageThrows = fal
|
|
|
125
127
|
};
|
|
126
128
|
sandbox.globalThis = sandbox;
|
|
127
129
|
vm.createContext(sandbox);
|
|
130
|
+
vm.runInContext(GAME, sandbox, { filename: 'shell-game.js' });
|
|
128
131
|
vm.runInContext(TRAIL, sandbox, { filename: 'shell-trail.js' });
|
|
129
132
|
vm.runInContext(SHELL, sandbox, { filename: 'shell.js' });
|
|
130
133
|
const root = documentObj.documentElement;
|
|
131
134
|
return {
|
|
132
135
|
store,
|
|
136
|
+
game: () => windowObj.OTBShellGame,
|
|
137
|
+
gameStamp: () => root.dataset.game === 'on',
|
|
138
|
+
// The "how to leave" line: showing = the shell created it and it is not hidden.
|
|
139
|
+
hintShowing: () => els.has('fullscreen-hint') && els.get('fullscreen-hint').hidden === false,
|
|
133
140
|
button: () => getElementById('fullscreen-toggle'),
|
|
134
141
|
on: () => root.dataset.fullscreen === 'on',
|
|
135
142
|
plain: () => root.dataset.fullscreenPlain === 'on',
|
|
@@ -477,3 +484,97 @@ test('source: full screen hides the sidebar and foot, and collapses the top bar
|
|
|
477
484
|
assert.match(css, /html\[data-fullscreen="on"\] \.topbar-side > :not\(\.fullscreen-toggle\)/);
|
|
478
485
|
assert.doesNotMatch(css, /html\[data-fullscreen="on"\] \.app-topbar \{ display: none/);
|
|
479
486
|
});
|
|
487
|
+
|
|
488
|
+
// GAME MODE (task 1005142, BONGOS-V3 R02). The spec's done-when: no page shows the
|
|
489
|
+
// sidebar in game mode. Game mode is hall-wide — one key, read by the SAME switch
|
|
490
|
+
// — so these drive the real shell-game.js + shell.js the way a reader moves
|
|
491
|
+
// through the hall: page after page over one browser store.
|
|
492
|
+
test('game mode: EVERY page opens without its bars — plain, laid-out, and one that remembers "off"', () => {
|
|
493
|
+
const store = { 'hall-game': 'on', 'hall-fullscreen:goals': 'off' };
|
|
494
|
+
for (const [page, optIn] of [['goals', false], ['work', false], ['thinking', true], ['city', true]]) {
|
|
495
|
+
const p = boot({ page, optIn, store });
|
|
496
|
+
assert.equal(p.on(), true, `${page} opens in full screen`);
|
|
497
|
+
assert.equal(p.gameStamp(), true, `${page}: html[data-game="on"]`);
|
|
498
|
+
assert.equal(p.plain(), optIn === false, `${page}: the plain mark still follows the page`);
|
|
499
|
+
}
|
|
500
|
+
assert.equal(boot({ page: 'goals', optIn: false, store: {} }).on(), false, 'and outside game mode nothing changed');
|
|
501
|
+
});
|
|
502
|
+
|
|
503
|
+
test('game mode: every hall page carries the switch — none opts out, and each loads shell-game.js before the shell', () => {
|
|
504
|
+
const pages = fs.readdirSync(HALL).filter((f) => f.endsWith('.html'));
|
|
505
|
+
assert.ok(pages.length >= 30, `found ${pages.length} hall pages`);
|
|
506
|
+
for (const f of pages) {
|
|
507
|
+
const html = read(f);
|
|
508
|
+
assert.doesNotMatch(html, /data-fullscreen-switch="off"/, `${f} must not opt out: it would keep its sidebar in game mode`);
|
|
509
|
+
assert.match(html, /id="app-topbar"/, `${f}: the top bar is where the shell renders the switch`);
|
|
510
|
+
const tags = [...html.matchAll(/<script src="\/builders\/([a-z-]+)\.js[^"]*"( defer)?><\/script>/g)].map((m) => [m[1], !!m[2]]);
|
|
511
|
+
const game = tags.findIndex((t) => t[0] === 'shell-game');
|
|
512
|
+
const shell = tags.findIndex((t) => t[0] === 'shell');
|
|
513
|
+
assert.ok(game >= 0 && game < shell, `${f} loads shell-game.js before shell.js`);
|
|
514
|
+
assert.equal(tags[game][1], tags[shell][1], `${f}: both load the same way, so the order holds`);
|
|
515
|
+
}
|
|
516
|
+
});
|
|
517
|
+
|
|
518
|
+
test('game mode: leaving brings the bars back for THIS page only, and never rewrites a page\'s own memory', () => {
|
|
519
|
+
const store = { 'hall-game': 'on', 'hall-fullscreen:thinking': 'on' };
|
|
520
|
+
const goals = boot({ page: 'goals', optIn: false, store });
|
|
521
|
+
goals.press('Escape');
|
|
522
|
+
assert.equal(goals.on(), false, 'Escape still leaves');
|
|
523
|
+
assert.equal(store['hall-fullscreen:goals'], undefined, 'nothing remembered for the page');
|
|
524
|
+
assert.equal(boot({ page: 'goals', optIn: false, store }).on(), true, 'the next load opens without bars again');
|
|
525
|
+
const sky = boot({ page: 'thinking', store });
|
|
526
|
+
sky.button().click();
|
|
527
|
+
assert.equal(sky.on(), false, 'the corner button leaves too');
|
|
528
|
+
assert.equal(store['hall-fullscreen:thinking'], 'on', 'the sky\'s own choice survives game mode');
|
|
529
|
+
});
|
|
530
|
+
|
|
531
|
+
test('game mode: the Escape hand-off is unchanged — a press the page used, or one in a field, does not leave', () => {
|
|
532
|
+
const p = boot({ page: 'goals', optIn: false, store: { 'hall-game': 'on' } });
|
|
533
|
+
p.press('Escape', { pageUses: true });
|
|
534
|
+
assert.equal(p.on(), true, 'a page listener that called preventDefault keeps the press');
|
|
535
|
+
p.press('Escape', { target: { tagName: 'TEXTAREA' } });
|
|
536
|
+
assert.equal(p.on(), true);
|
|
537
|
+
});
|
|
538
|
+
|
|
539
|
+
test('game mode: set() switches the page live, and turning it off hands each page back its own memory', () => {
|
|
540
|
+
const store = { 'hall-fullscreen:thinking': 'on' };
|
|
541
|
+
const goals = boot({ page: 'goals', optIn: false, store });
|
|
542
|
+
goals.game().set(true);
|
|
543
|
+
assert.equal(store['hall-game'], 'on');
|
|
544
|
+
assert.equal(goals.on(), true, 'on at once, no reload');
|
|
545
|
+
assert.ok(goals.resizes() >= 1, 'a page that sizes to its box is told to re-measure');
|
|
546
|
+
goals.game().set(false);
|
|
547
|
+
assert.equal(goals.on(), false, 'goals remembered nothing, so its bars return');
|
|
548
|
+
assert.equal(goals.gameStamp(), false);
|
|
549
|
+
assert.equal(store['hall-fullscreen:goals'], undefined, 'and switching the mode wrote nothing for the page');
|
|
550
|
+
const sky = boot({ page: 'thinking', store: Object.assign(store, { 'hall-game': 'on' }) });
|
|
551
|
+
sky.game().set(false);
|
|
552
|
+
assert.equal(sky.on(), true, 'the sky had chosen full screen itself, and keeps it');
|
|
553
|
+
});
|
|
554
|
+
|
|
555
|
+
test('game mode: ?game=on / ?game=off set it from the URL; anything else is ignored', () => {
|
|
556
|
+
const store = {};
|
|
557
|
+
assert.equal(boot({ page: 'work', optIn: false, store, search: '?game=on' }).on(), true);
|
|
558
|
+
assert.equal(store['hall-game'], 'on');
|
|
559
|
+
assert.equal(boot({ page: 'goals', optIn: false, store }).on(), true, 'and it holds on the next page');
|
|
560
|
+
assert.equal(boot({ page: 'work', optIn: false, store, search: '?game=off' }).on(), false);
|
|
561
|
+
boot({ page: 'work', optIn: false, store, search: '?game=%22%3E%3Cimg%3E' });
|
|
562
|
+
assert.equal(store['hall-game'], 'off', 'a value that is not on/off is not stored');
|
|
563
|
+
});
|
|
564
|
+
|
|
565
|
+
test('game mode: how to leave is said once per tab, not on every page; outside it the shell\'s rule stands', () => {
|
|
566
|
+
const store = { 'hall-game': 'on' };
|
|
567
|
+
const session = {};
|
|
568
|
+
assert.equal(boot({ page: 'goals', optIn: false, store, session }).hintShowing(), true, 'the first page says it');
|
|
569
|
+
assert.equal(boot({ page: 'work', optIn: false, store, session }).hintShowing(), false, 'the next does not repeat it');
|
|
570
|
+
const own = { 'hall-fullscreen:thinking': 'on' };
|
|
571
|
+
assert.equal(boot({ page: 'thinking', store: own, session: {} }).hintShowing(), true);
|
|
572
|
+
assert.equal(boot({ page: 'thinking', store: own, session: {} }).hintShowing(), true, 'a remembered page says it on every open, as before');
|
|
573
|
+
});
|
|
574
|
+
|
|
575
|
+
test('game mode: storage that throws leaves the hall out of game mode, with the switch working', () => {
|
|
576
|
+
const p = boot({ page: 'goals', optIn: false, storageThrows: true, search: '?game=on' });
|
|
577
|
+
assert.equal(p.on(), false);
|
|
578
|
+
p.button().click();
|
|
579
|
+
assert.equal(p.on(), true);
|
|
580
|
+
});
|
package/tests/hall_my_agents.mjs
CHANGED
|
@@ -443,7 +443,7 @@ test('PAGE: in the hall family, with no prototype key', () => {
|
|
|
443
443
|
assert.deepEqual(sheets, ['style.css', 'oversight.css', 'speciality-tools.css', 'my-agents.css'],
|
|
444
444
|
'rides the oversight archetype; the shared speciality sheet (task 1005052) before its own, so the page skin wins');
|
|
445
445
|
const scripts = [...html.matchAll(/src="\/builders\/([a-z-]+)\.js/g)].map((m) => m[1]);
|
|
446
|
-
assert.deepEqual(scripts.slice(0,
|
|
446
|
+
assert.deepEqual(scripts.slice(0, 5), ['dom-utils', 'shell-game', 'shell-trail', 'craft-mode', 'shell']); // dom-utils first: the shell escapes through it (task 1004876)
|
|
447
447
|
for (const s of ['gov-living', 'gov-positions', 'my-agents', 'speciality-tools']) assert.ok(scripts.includes(s), `loads ${s}.js`);
|
|
448
448
|
assert.doesNotMatch(html, /ma-key|data-proto|Prototype data/, 'nothing on the page is prototype data, so there is no key');
|
|
449
449
|
assert.doesNotMatch(read('my-agents.js'), /governor-overlay/, 'and it reads no overlay');
|
package/tests/hall_street.mjs
CHANGED
|
@@ -490,7 +490,7 @@ test('the page holds the prototype\'s header, the street, the readings and the c
|
|
|
490
490
|
assert.match(html, /<a class="street-mark" id="streetHome" href="\/builders\/city"[^>]*>\{\{productName\}\}</);
|
|
491
491
|
for (const id of ['hudNeeds', 'hudMoving', 'hudShare', 'streetMode', 'streetSigns', 'streetPins', 'streetDoors', 'streetCard']) assert.match(html, new RegExp(`id="${id}"`), id);
|
|
492
492
|
const scripts = [...html.matchAll(/<script src="\/builders\/([a-z-]+)\.js/g)].map((m) => m[1]);
|
|
493
|
-
assert.deepEqual(scripts.filter((s) => !/^street-(deck|office)$/.test(s)), ['dom-utils', 'shell-trail', 'craft-mode', 'shell', 'hall-dialog', 'palette', 'gov-living', 'gov-feeds', 'city-draw', 'street-draw', 'street-card', 'street-inside', 'street-depth', 'street-desk', 'street-amend', 'street'], 'the hall shell (task 1004544), the living model and its one reader (task 1004685: city-draw.js counts with it, so it loads first), the shared kit, then the card (task 1004528), the interiors (task 1004526), the living street\'s exterior (street-depth.js), the floor desk (task 1004558) and the drafted amendment (task 1004530); the deck rides beside them');
|
|
493
|
+
assert.deepEqual(scripts.filter((s) => !/^street-(deck|office)$/.test(s)), ['dom-utils', 'shell-game', 'shell-trail', 'craft-mode', 'shell', 'hall-dialog', 'palette', 'gov-living', 'gov-feeds', 'city-draw', 'street-draw', 'street-card', 'street-inside', 'street-depth', 'street-desk', 'street-amend', 'street'], 'the hall shell (task 1004544), the living model and its one reader (task 1004685: city-draw.js counts with it, so it loads first), the shared kit, then the card (task 1004528), the interiors (task 1004526), the living street\'s exterior (street-depth.js), the floor desk (task 1004558) and the drafted amendment (task 1004530); the deck rides beside them');
|
|
494
494
|
assert.equal(City.STREET_HREF, '/builders/street', 'the city\'s door is this page');
|
|
495
495
|
});
|
|
496
496
|
|
|
@@ -102,7 +102,7 @@ test('the hall-preview fixture carries every atom /me resolves', () => {
|
|
|
102
102
|
// task 1005051: Roadmap left it (folded into Goals; /roadmap redirects).
|
|
103
103
|
// task 1005070: the remembered nav (the rail paints before /me).
|
|
104
104
|
// task 1005088: the sidebar mark is drawn by reference to the one brand mark.
|
|
105
|
-
const SHELL_SHA = '
|
|
105
|
+
const SHELL_SHA = 'e9c13c142bcd2a95';
|
|
106
106
|
|
|
107
107
|
test('shell.js has not changed without its cache-bust being bumped', () => {
|
|
108
108
|
const actual = crypto.createHash('sha256').update(SHELL).digest('hex').slice(0, 16);
|