@bongos/core 1.19.1052 → 1.19.1053
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 +26 -26
- package/docs/copy-inventory.md +100 -114
- package/docs/copy-registry.json +163 -401
- package/docs/module-api-changelog.md +2 -0
- package/modules/hall-ui/public/goal-map.html +18 -24
- package/modules/hall-ui/public/goal-map.states.json +2 -2
- package/modules/hall-ui/public/sky-data.js +22 -18
- package/modules/hall-ui/public/sky-interaction.js +23 -22
- package/modules/hall-ui/public/sky-layout.js +5 -5
- package/modules/hall-ui/public/sky-panel.js +3 -2
- package/modules/hall-ui/public/sky-tour.js +37 -26
- package/modules/hall-ui/public/thinking.css +2 -0
- package/modules/hall-ui/public/thinking.html +16 -25
- package/modules/hall-ui/public/thinking.states.json +1 -1
- package/modules/hall-ui/records/sky.md +11 -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 +49 -25
- package/tests/hall_sky.mjs +49 -12
- package/tests/helpers.mjs +2 -1
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
(tests/hall_tokens.mjs: no hall page hardcodes a web-font stylesheet).
|
|
14
14
|
The template carried its own Google Fonts link for the same two faces. -->
|
|
15
15
|
<link rel="stylesheet" href="/builders/style.css?v=2026-07-02-shell1">
|
|
16
|
-
<link rel="stylesheet" href="/builders/thinking.css?v=2026-09-
|
|
16
|
+
<link rel="stylesheet" href="/builders/thinking.css?v=2026-09-27-split">
|
|
17
17
|
</head>
|
|
18
18
|
<!-- THE SKY (task 1004231 / sky part 3 of 5, goal 1000095; ADR 0331, ADR 0227
|
|
19
19
|
§11). This page is docs/design/mocks/sky/sky.template.html — the prototype
|
|
@@ -41,12 +41,13 @@
|
|
|
41
41
|
<header>: the shell's top bar is the page's one <header>, and in full
|
|
42
42
|
screen it stays in the document as the way back.
|
|
43
43
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
"
|
|
49
|
-
|
|
44
|
+
ONLY YOUR THINKING (task 1004328, owner decision 2026-09-27). The sheet,
|
|
45
|
+
the seven scripts and the drawing are shared with THE PROJECT SKY at
|
|
46
|
+
/goal-map; the lenses and the tools are not. This page's switcher is
|
|
47
|
+
"simple" and "your thinking" and nothing else. "The whole project", the
|
|
48
|
+
"my ideas" overlay, explore and its start dialog are the project map's
|
|
49
|
+
and live only in goal-map.html, and nothing here leaves for that page as
|
|
50
|
+
a lens. -->
|
|
50
51
|
<body data-page="thinking" data-page-title="Your thinking" data-fullscreen-switch>
|
|
51
52
|
|
|
52
53
|
<div class="app">
|
|
@@ -74,15 +75,12 @@
|
|
|
74
75
|
<div class="lens" role="group" aria-label="Filter" id="lensGroup">
|
|
75
76
|
<button type="button" id="lensSimple" aria-pressed="false">simple</button>
|
|
76
77
|
<button type="button" id="lensMine" aria-pressed="true">your thinking</button>
|
|
77
|
-
<button type="button" id="lensAll" aria-pressed="false">the whole project</button>
|
|
78
78
|
</div>
|
|
79
79
|
<div class="tools" id="tools">
|
|
80
80
|
<button type="button" class="pill" id="roomBtn" aria-pressed="false" title="The same sky, as a list (L)">list</button>
|
|
81
81
|
<button type="button" class="pill" id="recentBtn" aria-pressed="false" hidden title="Only the thoughts of the last thirty days.">recent</button>
|
|
82
82
|
<button type="button" class="pill" id="claudeBtn" aria-pressed="false" title="Show the thoughts a session filed under your name. Off by default: only what a person filed.">claude layer</button>
|
|
83
83
|
<button type="button" class="pill" id="influenceBtn" aria-pressed="false" title="Only the goals your thoughts touched — everything else fades.">my influence</button>
|
|
84
|
-
<button type="button" class="pill" id="exploreBtn" aria-pressed="true" hidden title="Explore: the sky reveals itself as you follow routes from where you begin.">explore</button>
|
|
85
|
-
<button type="button" class="pill" id="ideasBtn" aria-pressed="false" hidden title="Lay your thoughts over the project map.">my ideas</button>
|
|
86
84
|
<button type="button" class="pill" id="rehearse" aria-pressed="false" title="What if: invents removals, dimming and nods — none has happened in the ledger yet — so you can see how the dead would read. Sizes are never invented.">what if</button>
|
|
87
85
|
<button type="button" class="pill icon" id="clockBtn" title="Show or hide the clock" aria-label="Show or hide the clock">◷</button>
|
|
88
86
|
<button type="button" class="pill icon" id="tourBtn" title="How to read the sky (?)" aria-label="How to read the sky">?</button>
|
|
@@ -117,13 +115,6 @@
|
|
|
117
115
|
|
|
118
116
|
<aside class="panel" id="panel" hidden aria-live="polite"></aside>
|
|
119
117
|
|
|
120
|
-
<div class="start glass" id="start" hidden role="dialog" aria-label="Where do you begin?">
|
|
121
|
-
<span class="lbl">explore</span>
|
|
122
|
-
<h3>Where do you begin?</h3>
|
|
123
|
-
<p>The sky reveals itself as you go. Pick a well to start in; every route you chart brings the goal at its far end into view.</p>
|
|
124
|
-
<div class="opts" id="startOpts"></div>
|
|
125
|
-
</div>
|
|
126
|
-
|
|
127
118
|
<div class="tour glass" id="tour" hidden role="dialog" aria-label="How to read the sky">
|
|
128
119
|
<div class="step"><span class="lbl" id="tourN"></span><span class="dots" id="tourDots"></span></div>
|
|
129
120
|
<h3 id="tourH"></h3>
|
|
@@ -150,13 +141,13 @@
|
|
|
150
141
|
<script src="/builders/shell.js?v=2026-09-27-fullscreen"></script>
|
|
151
142
|
<script src="/builders/palette.js" defer></script>
|
|
152
143
|
|
|
153
|
-
<script src="/builders/idea-objects.js?v=2026-09-
|
|
154
|
-
<script src="/builders/sky-data.js?v=2026-09-
|
|
155
|
-
<script src="/builders/sky-layout.js?v=2026-09-
|
|
156
|
-
<script src="/builders/sky-draw.js?v=2026-09-
|
|
157
|
-
<script src="/builders/sky-interaction.js?v=2026-09-
|
|
158
|
-
<script src="/builders/sky-panel.js?v=2026-09-
|
|
159
|
-
<script src="/builders/sky-composer.js?v=2026-09-
|
|
160
|
-
<script src="/builders/sky-tour.js?v=2026-09-
|
|
144
|
+
<script src="/builders/idea-objects.js?v=2026-09-27-split"></script>
|
|
145
|
+
<script src="/builders/sky-data.js?v=2026-09-27-split"></script>
|
|
146
|
+
<script src="/builders/sky-layout.js?v=2026-09-27-split"></script>
|
|
147
|
+
<script src="/builders/sky-draw.js?v=2026-09-27-split"></script>
|
|
148
|
+
<script src="/builders/sky-interaction.js?v=2026-09-27-split"></script>
|
|
149
|
+
<script src="/builders/sky-panel.js?v=2026-09-27-split"></script>
|
|
150
|
+
<script src="/builders/sky-composer.js?v=2026-09-27-split"></script>
|
|
151
|
+
<script src="/builders/sky-tour.js?v=2026-09-27-split"></script>
|
|
161
152
|
</body>
|
|
162
153
|
</html>
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
},
|
|
16
16
|
"sky": {
|
|
17
17
|
"auth": true,
|
|
18
|
-
"_": "The 'your thinking' lens, bare: composer, lenses, tools, legend and the clock.",
|
|
18
|
+
"_": "The 'your thinking' lens, bare: composer, the two lenses (simple, your thinking), tools, legend and the clock.",
|
|
19
19
|
"actions": [["wait", 1200], ["clickIfVisible", "#tourSkip"], ["wait", 300]],
|
|
20
20
|
"expect": { "visible": ["#sky", "#composerWrap"] }
|
|
21
21
|
},
|
|
@@ -30,3 +30,14 @@ Pinned by `tests/hall_sky.mjs` (31 cases: the reads, the five objects, the two c
|
|
|
30
30
|
- **The sky is drawn on a STAGE.** Everything the sky owns lives in `main.sky-stage`, fixed under the top bar and beside the 64px rail (the whole window in full screen, no rail under 768). `contain: layout paint` makes the stage the containing block of every fixed layer, so the template's fixed layout is untouched and simply measures from the stage; its four viewport units became `%` of that box (the same number on `/goal-map`). `SKY.viewport()` gives the canvas its size and the pointer its offset (`S.OX` / `S.OY`), and a `ResizeObserver` re-measures when the switch changes the box without the window resizing.
|
|
31
31
|
- **The sky's palette lives on the stage, not the body, on `/thinking`** — so the chrome around it keeps the hall's own light and dark. `style.css` now loads under `thinking.css`, and the handful of hall rules whose names the template also uses (`.skip`, `.filters`, `.foot`, `:focus-visible`, text inputs, `* { box-sizing }`) are reset under `:where(.sky-stage)` at the same specificity, before the sky's own rules. The sky's global rules are `:where()`-scoped for the same reason, which leaves `/goal-map` byte-for-byte in its old cascade.
|
|
32
32
|
- **Both pages render in both modes now.** The chrome follows the hall theme; the sky's stage is the void in both. The `full` and `full-back` states in both states files (and `full-list` in the sky's) press the switch.
|
|
33
|
+
|
|
34
|
+
## Two skies, one renderer (task 1004328, BV2.TW21)
|
|
35
|
+
|
|
36
|
+
**Owner decision 2026-09-27: "Your thinking is only your thinking."** Part 4's "one page, two doors" above is SUPERSEDED: the two pages share the renderer and nothing else. The owner confirmed that "the your projects tab" means the whole-project lens, its switch and the project-map features. What this settled:
|
|
37
|
+
- **The lens and the features separate; the drawing does not.** `thinking.css`, the seven `sky-*.js` files and every draw path stay shared. What each page may be in is `S.lenses` (set once in `sky-data.js` from `data-sky-lens`): `['simple', 'mine']` on `/thinking`, `['all']` on `/goal-map`. `setLens` clamps to it, so nothing — a button, the tour, a jump, the panel's "descend" — can take a page into a lens it lacks, and no button leaves for the other page (`location.assign` is gone from `sky-interaction.js`).
|
|
38
|
+
- **Absent, not hidden.** `/thinking` carries no "the whole project" button, no "my ideas", no "explore" and no "where do you begin" dialog; `/goal-map` carries no switcher at all and none of the ideator's pills (recent, claude layer, my influence). The scripts touch a one-page control through `SKY.hide` / `SKY.press` / `SKY.on`, which do nothing when the element is not there. `thinking.css` gained one rule, `.brand + .tools { margin-left: auto; }`, so `/goal-map`'s tools keep the switcher's push to the right and its top strip reads as before.
|
|
39
|
+
- **Two tours from one list.** Every step in `ALL_STEPS` says which sky it belongs to; `/thinking` walks nine of the template's thirteen (the ideator's steps, the wells and rings, the clock, the composer, simple), `/goal-map` walks eight — the wells, rings, life, routes, settled systems, the clock and explore — opened by one new step, "This is the whole project.", because the template's first step is "This is your sky." and belongs to `/thinking`. The project tour turns explore off for its length and gives it back. Each tour has its own seen key (S.tourKey: sky-tour-seen here, sky-map-tour-seen on the map), so one does not silence the other.
|
|
40
|
+
- **"Descend into the well" stays in its sky.** On `/goal-map` it only flies; on `/thinking` it steps "simple" up to "your thinking" (the one lens there that zooms). The legend drops "unexplored" on `/thinking`, which has no explore.
|
|
41
|
+
- **Kept on both:** the list drawer (the room on `/thinking`, the ledger on `/goal-map`), the clock, the composer, "what if", the panel. Filing a thought from the project map still works; the owner's decision names the lens and the overlay, not the composer.
|
|
42
|
+
|
|
43
|
+
Pinned by `tests/hall_sky.mjs` (absence of every project-map control, every path into a lens, the nine-step tour never entering "all") and `tests/goal_map_page.mjs` (no switcher, setLens clamped, the eight-step tour with explore off and given back).
|
package/package-lock.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bongos/core",
|
|
3
|
-
"version": "1.19.
|
|
3
|
+
"version": "1.19.1053",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@bongos/core",
|
|
9
|
-
"version": "1.19.
|
|
9
|
+
"version": "1.19.1053",
|
|
10
10
|
"license": "AGPL-3.0-or-later",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"express": "^4.21.2",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bongos/core",
|
|
3
|
-
"version": "1.19.
|
|
3
|
+
"version": "1.19.1053",
|
|
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
|
@@ -7613,5 +7613,11 @@
|
|
|
7613
7613
|
"id": "1004327",
|
|
7614
7614
|
"text": "The studio and Your thinking now sit inside the builders hall like every other page, with the sidebar and the top bar around them. Each has one new button in the top-right corner that goes full screen: the sidebar and top bar"
|
|
7615
7615
|
}
|
|
7616
|
+
],
|
|
7617
|
+
"1.19.1053": [
|
|
7618
|
+
{
|
|
7619
|
+
"id": "1004328",
|
|
7620
|
+
"text": "Your thinking and the project map are now two separate pages that share only their drawing. Your thinking keeps just your own views, simple and your thinking, with your own tools: the list, recent, claude layer, my influence,"
|
|
7621
|
+
}
|
|
7616
7622
|
]
|
|
7617
7623
|
}
|
package/src/module-api.js
CHANGED
|
@@ -71,7 +71,7 @@ const { responsibilityFor, ROLE_RESPONSIBILITIES } = require('./role-responsibil
|
|
|
71
71
|
// there. scripts/gds/bump-version.js still rewrites the literal below; it appends
|
|
72
72
|
// the entry to that file. Look for a version's history there, not here.
|
|
73
73
|
// ---------------------------------------------------------------------------
|
|
74
|
-
const CORE_VERSION = '1.19.
|
|
74
|
+
const CORE_VERSION = '1.19.1053'; // CI auto-patch carrier (ADR 0161); changelog: docs/module-api-changelog.md
|
|
75
75
|
|
|
76
76
|
// A namespaced logger so a module's log lines are attributable + consistent.
|
|
77
77
|
// Usage: const log = api.logger('dev-box'); log.info('mounted');
|
package/tests/goal_map_page.mjs
CHANGED
|
@@ -20,7 +20,13 @@
|
|
|
20
20
|
// The REAL goal-map.html markup and the REAL seven sky-*.js files boot in a vm
|
|
21
21
|
// through bootSkyPage (tests/helpers.mjs) — the same helper tests/hall_sky.mjs
|
|
22
22
|
// uses for /thinking, pointed at this page's own file, so a button lost from
|
|
23
|
-
// either
|
|
23
|
+
// either page fails its own suite.
|
|
24
|
+
//
|
|
25
|
+
// TWO SKIES, ONE RENDERER (task 1004328, owner decision 2026-09-27). The
|
|
26
|
+
// project sky is the ONLY home of the whole-project lens and its features —
|
|
27
|
+
// explore, "my ideas", the ledger of goals — and it offers no other lens: no
|
|
28
|
+
// switcher, no "simple", no "your thinking", and the ideator's pills
|
|
29
|
+
// (recent, claude layer, my influence) are /thinking's alone.
|
|
24
30
|
//
|
|
25
31
|
// Run: node tests/goal_map_page.mjs
|
|
26
32
|
import assert from 'node:assert/strict';
|
|
@@ -85,45 +91,45 @@ const goal = (p, id) => p.S().goalById.get(String(id));
|
|
|
85
91
|
|
|
86
92
|
// ═══ the lens is home ════════════════════════════════════════════════════════
|
|
87
93
|
|
|
88
|
-
await test('it opens in "the whole project": the brand line, the
|
|
94
|
+
await test('it opens in "the whole project": the brand line, the tools and the figures are the project sky\'s', async () => {
|
|
89
95
|
const p = await boot({ sky: FOUR(), versions: versions(), mine: mine([star()]) });
|
|
90
96
|
assert.ok(p.ready(), 'the page booted');
|
|
91
97
|
const S = p.S();
|
|
92
98
|
assert.equal(S.home, 'all', 'the body says which lens is home');
|
|
93
99
|
assert.equal(S.lens, 'all');
|
|
94
|
-
assert.equal(p.el('lensAll').getAttribute('aria-pressed'), 'true');
|
|
95
|
-
assert.equal(p.el('lensMine').getAttribute('aria-pressed'), 'false');
|
|
96
100
|
assert.equal(p.el('lensWord').textContent, '— the whole project');
|
|
97
101
|
assert.equal(p.el('lensWord').parentNode.textContent, 'the sky — the whole project', 'the h1 is the project sky\'s');
|
|
98
102
|
assert.equal(p.el('roomTitle').textContent, 'the ledger');
|
|
99
103
|
assert.equal(p.el('exploreBtn').hidden, false, 'explore is a tool here');
|
|
100
104
|
assert.equal(p.el('ideasBtn').hidden, false, 'so is "my ideas"');
|
|
101
|
-
assert.equal(p.el(
|
|
102
|
-
assert.equal(p.el('influenceBtn').hidden, true);
|
|
105
|
+
for (const id of ['claudeBtn', 'influenceBtn', 'recentBtn']) assert.equal(p.el(id), null, `the ideator's #${id} is not on this page at all`);
|
|
103
106
|
assert.match(p.stats(), /<b>4<\/b> goals · <b>1<\/b> alive · <b>2<\/b> wells · <b>1<\/b> settled · <b>1<\/b> collapsed · <b>1<\/b> routes · <b>13<\/b> tasks/, 'the figures line is the goals\' line');
|
|
104
107
|
const urls = p.requests.map((r) => r.url);
|
|
105
108
|
for (const want of ['/api/bongos/sky', '/api/bongos/sky/mine', '/api/bongos/me', '/api/bongos/inbox/template']) assert.ok(urls.includes(want), `reads ${want}`);
|
|
106
109
|
assert.ok(!urls.some((u) => /goals\/graph/.test(u)), 'the goal map\'s aggregate read is gone — the sky\'s own reads carry the routes');
|
|
107
110
|
});
|
|
108
111
|
|
|
109
|
-
await test('the same seven files open /thinking in "your thinking" — one
|
|
112
|
+
await test('the same seven files open /thinking in "your thinking" — one renderer, two skies', async () => {
|
|
110
113
|
const p = bootSkyPage({ page: 'thinking', sky: FOUR(), versions: versions() }); await drain();
|
|
111
114
|
assert.equal(p.S().home, 'mine');
|
|
112
115
|
assert.equal(p.S().lens, 'mine');
|
|
113
116
|
assert.equal(p.el('lensWord').parentNode.textContent, 'your sky — your thinking');
|
|
114
117
|
});
|
|
115
118
|
|
|
116
|
-
await test('
|
|
117
|
-
const
|
|
118
|
-
|
|
119
|
-
assert.
|
|
120
|
-
const
|
|
121
|
-
|
|
122
|
-
assert.equal(
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
assert.equal(
|
|
126
|
-
|
|
119
|
+
await test('THE WHOLE PROJECT ONLY: no switcher, no "simple", no "your thinking" — and no lens this page lacks is ever entered', async () => {
|
|
120
|
+
const p = await boot({ sky: FOUR(), versions: versions(), mine: mine([star()]) });
|
|
121
|
+
const S = p.S(); const SKY = p.SKY();
|
|
122
|
+
assert.deepEqual(JSON.parse(JSON.stringify(S.lenses)), ['all']);
|
|
123
|
+
for (const id of ['lensGroup', 'lensSimple', 'lensMine', 'lensAll']) assert.equal(p.el(id), null, `#${id} is not on this page`);
|
|
124
|
+
const html = read('goal-map.html').replace(/<!--[\s\S]*?-->/g, '');
|
|
125
|
+
assert.equal(/your thinking|>simple</.test(html), false, 'the page offers neither lens in its markup');
|
|
126
|
+
assert.equal(/href="[^"]*\/thinking"/.test(html), false, 'and never links to /thinking (the shared sheet is thinking.css, which is not a link to the page)');
|
|
127
|
+
for (const l of ['mine', 'simple']) { SKY.setLens(l, true); assert.equal(S.lens, 'all', `setLens('${l}') stays in the whole project`); }
|
|
128
|
+
assert.equal(p.el('lensWord').parentNode.textContent, 'the sky — the whole project');
|
|
129
|
+
SKY.pick({ kind: 'goal', ref: goal(p, '7') }, false); p.click('descendBtn');
|
|
130
|
+
assert.equal(S.lens, 'all', 'descending stays on the project map');
|
|
131
|
+
assert.equal(p.navigated, null, 'nothing leaves for /thinking');
|
|
132
|
+
assert.ok(/\.brand \+ \.tools \{ margin-left: auto; \}/.test(read('thinking.css')), 'the tools take the switcher\'s push to the right, so the top strip reads as before');
|
|
127
133
|
});
|
|
128
134
|
|
|
129
135
|
// ═══ the wells ═══════════════════════════════════════════════════════════════
|
|
@@ -339,19 +345,37 @@ await test('a band is a version, and clicking one fills the screen with it', asy
|
|
|
339
345
|
|
|
340
346
|
// ═══ the tour ════════════════════════════════════════════════════════════════
|
|
341
347
|
|
|
342
|
-
await test('the tour
|
|
343
|
-
const p = await boot({ sky: FOUR(), versions: versions() });
|
|
348
|
+
await test('the tour is the project map\'s own eight steps, all in the whole project, with explore off while it runs and given back after', async () => {
|
|
349
|
+
const p = await boot({ sky: FOUR(), versions: versions(), storage: {} });
|
|
350
|
+
const S = p.S();
|
|
351
|
+
assert.deepEqual(S.explore.on, true, 'explore is on before the tour');
|
|
352
|
+
assert.deepEqual(JSON.parse(JSON.stringify(p.SKY().STEPS.map((s) => s.h))), [
|
|
353
|
+
'This is the whole project.', 'A goal is a gravity well.', 'A ring is a criterion.', 'An alive well glows.',
|
|
354
|
+
'Routes run between goals that wait on each other.', 'A settled system is a goal that finished.', 'The sky has a clock.', 'By default, you explore.',
|
|
355
|
+
]);
|
|
344
356
|
p.key('?');
|
|
345
357
|
assert.equal(p.el('tour').hidden, false);
|
|
346
|
-
assert.equal(p.
|
|
347
|
-
|
|
348
|
-
assert.equal(
|
|
358
|
+
assert.equal(p.el('tourN').textContent, 'how to read the sky · 1 of 8');
|
|
359
|
+
assert.equal(S.lens, 'all', 'step one is the whole project');
|
|
360
|
+
assert.equal(S.explore.on, false, 'and the tour sees every well');
|
|
361
|
+
assert.equal(p.el('start').hidden, true, 'so "where do you begin" waits');
|
|
362
|
+
const lenses = new Set([S.lens]);
|
|
363
|
+
for (let n = 0; n < 7; n++) { p.click('tourNext'); lenses.add(S.lens); }
|
|
364
|
+
assert.deepEqual([...lenses], ['all'], 'no step of this tour leaves the whole project');
|
|
365
|
+
assert.equal(p.el('tourN').textContent, 'how to read the sky · 8 of 8');
|
|
349
366
|
p.key('Escape');
|
|
350
367
|
assert.equal(p.el('tour').hidden, true);
|
|
351
|
-
assert.equal(
|
|
352
|
-
assert.equal(
|
|
368
|
+
assert.equal(S.lens, 'all', 'back to the whole project');
|
|
369
|
+
assert.equal(S.explore.on, true, 'explore is given back');
|
|
370
|
+
assert.equal(p.el('exploreBtn').getAttribute('aria-pressed'), 'true');
|
|
353
371
|
const first = await boot({ sky: FOUR(), tourSeen: false });
|
|
354
372
|
assert.equal(first.timers.pending(), 1, 'a first visit schedules the tour here as well');
|
|
373
|
+
// The two tours differ, so each keeps its own seen key (task 1004328).
|
|
374
|
+
const afterThinking = await boot({ sky: FOUR(), tourSeen: false, storage: { 'sky-explore': 'off', 'sky-tour-seen': '4' } });
|
|
375
|
+
assert.equal(afterThinking.timers.pending(), 1, 'having seen /thinking\'s tour does not mark this one seen');
|
|
376
|
+
assert.equal(afterThinking.S().tourKey, 'sky-map-tour-seen');
|
|
377
|
+
const seenHere = await boot({ sky: FOUR(), tourSeen: false, storage: { 'sky-explore': 'off', 'sky-map-tour-seen': '4' } });
|
|
378
|
+
assert.equal(seenHere.timers.pending(), 0, 'and this one, once seen, stays seen');
|
|
355
379
|
});
|
|
356
380
|
|
|
357
381
|
// ═══ born of a thought (part 5) ══════════════════════════════════════════════
|
package/tests/hall_sky.mjs
CHANGED
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
// tests/hall_thinking_room.mjs.
|
|
21
21
|
|
|
22
22
|
import assert from 'node:assert/strict';
|
|
23
|
+
import * as FS from 'node:fs';
|
|
23
24
|
import { makeRunner, settle, bootSkyPage } from './helpers.mjs';
|
|
24
25
|
|
|
25
26
|
const { test, summary } = makeRunner();
|
|
@@ -367,11 +368,38 @@ await test('the bands come from the versions read: building at the centre, shipp
|
|
|
367
368
|
for (const f of src) assert.doesNotMatch(fs.readFileSync(path.join('modules/hall-ui/public', f), 'utf8'), /BONGOS-V\d|GDS-V\d|PMS-V\d|CB-V\d/, `${f} names no instance version`);
|
|
368
369
|
});
|
|
369
370
|
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
371
|
+
// ═══ only your thinking (task 1004328, owner decision 2026-09-27) ═══════════
|
|
372
|
+
// The whole-project lens and the project map's features live only on
|
|
373
|
+
// /goal-map (tests/goal_map_page.mjs). Here they are ABSENT from the markup,
|
|
374
|
+
// not merely hidden, and nothing — a button, the tour, a jump, the panel —
|
|
375
|
+
// takes this sky into "the whole project" or leaves for that page.
|
|
376
|
+
|
|
377
|
+
await test('ONLY YOUR THINKING: no "the whole project" lens, no "my ideas", no explore — absent from the page, not hidden', async () => {
|
|
378
|
+
const p = await boot({ mine: mine(FIVE()), sky: sky([well()]), versions: versions() });
|
|
379
|
+
same(p.S().lenses, ['simple', 'mine']);
|
|
380
|
+
for (const id of ['lensAll', 'ideasBtn', 'exploreBtn', 'start', 'startOpts']) assert.equal(p.el(id), null, `#${id} is the project map's, not this page's`);
|
|
381
|
+
for (const id of ['lensSimple', 'lensMine', 'recentBtn', 'claudeBtn', 'influenceBtn', 'rehearse']) assert.ok(p.el(id), `#${id} is your thinking's own tool`);
|
|
382
|
+
// The markup a person meets — the header comments may explain the split, and do.
|
|
383
|
+
const html = FS.readFileSync('modules/hall-ui/public/thinking.html', 'utf8').replace(/<!--[\s\S]*?-->/g, '');
|
|
384
|
+
assert.doesNotMatch(html, /the whole project/, 'the words are gone from the markup too');
|
|
385
|
+
assert.doesNotMatch(html, /goal-map/, 'and this page never names the project map');
|
|
386
|
+
assert.doesNotMatch(p.el('legend').innerHTML, /unexplored/, 'the legend does not teach explore, which this sky does not have');
|
|
387
|
+
});
|
|
388
|
+
|
|
389
|
+
await test('nothing takes /thinking into the whole project: setLens, the panel and the switcher all stay in your sky', async () => {
|
|
390
|
+
const p = await boot({ mine: mine(FIVE()), sky: sky([well()]), versions: versions() });
|
|
391
|
+
p.SKY().setLens('all', true);
|
|
392
|
+
assert.equal(p.S().lens, 'mine', 'a lens this page does not have is never entered');
|
|
393
|
+
p.click('lensSimple'); assert.equal(p.S().lens, 'simple');
|
|
394
|
+
p.click('lensMine'); assert.equal(p.S().lens, 'mine');
|
|
395
|
+
assert.equal(p.navigated, null, 'no lens leaves for another page');
|
|
396
|
+
p.SKY().pick({ kind: 'goal', ref: p.S().goals[0] }, false);
|
|
397
|
+
p.click('descendBtn');
|
|
398
|
+
assert.equal(p.S().lens, 'mine', 'descending into a well stays in your thinking');
|
|
399
|
+
p.click('lensSimple'); p.SKY().pick({ kind: 'goal', ref: p.S().goals[0] }, false); p.click('descendBtn');
|
|
400
|
+
assert.equal(p.S().lens, 'mine', 'from "simple", descending steps up to your thinking — the one lens here that zooms');
|
|
401
|
+
const src = FS.readFileSync('modules/hall-ui/public/sky-interaction.js', 'utf8');
|
|
402
|
+
assert.doesNotMatch(src, /location\.assign|'\/goal-map'|'\/thinking'/, 'the switcher has no door to the other page');
|
|
375
403
|
});
|
|
376
404
|
|
|
377
405
|
// ═══ the words are never markup ══════════════════════════════════════════════
|
|
@@ -392,25 +420,34 @@ await test('a title never becomes markup — in the drawer, the panel and the ho
|
|
|
392
420
|
|
|
393
421
|
// ═══ the tour, the lenses and the keys ═══════════════════════════════════════
|
|
394
422
|
|
|
395
|
-
await test('the tour is the template\'s thirteen steps — ? opens it, Escape closes it', async () => {
|
|
423
|
+
await test('the tour is your thinking\'s nine of the template\'s thirteen steps, in order and never in the whole project — ? opens it, Escape closes it', async () => {
|
|
396
424
|
const p = await boot({ mine: mine(FIVE()), sky: sky([well()]), versions: versions() });
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
same(STEPS.map((s) => s.h), [
|
|
425
|
+
// The template's thirteen are all still in the list; the four the project map owns are /goal-map's (task 1004328).
|
|
426
|
+
const template = [
|
|
400
427
|
'This is your sky.', 'A goal is a gravity well.', 'A ring is a criterion.', 'A burning thought is a star.', 'Some thoughts became the structure.',
|
|
401
428
|
'Unclaimed thoughts drift.', 'An alive well glows.', 'Routes run between goals that wait on each other.', 'A settled system is a goal that finished.',
|
|
402
429
|
'The sky has a clock.', 'By default, you explore.', 'Release a thought here.', 'When it is too much, go simple.',
|
|
430
|
+
];
|
|
431
|
+
same(p.SKY().ALL_STEPS.map((s) => s.h).filter((h) => template.includes(h)), template, 'every template step survives, in its order');
|
|
432
|
+
const STEPS = p.SKY().STEPS;
|
|
433
|
+
assert.equal(STEPS.length, 9);
|
|
434
|
+
same(STEPS.map((s) => s.h), [
|
|
435
|
+
'This is your sky.', 'A goal is a gravity well.', 'A ring is a criterion.', 'A burning thought is a star.', 'Some thoughts became the structure.',
|
|
436
|
+
'Unclaimed thoughts drift.', 'The sky has a clock.', 'Release a thought here.', 'When it is too much, go simple.',
|
|
403
437
|
]);
|
|
404
438
|
assert.equal(p.el('tour').hidden, true);
|
|
405
439
|
p.key('?');
|
|
406
440
|
assert.equal(p.el('tour').hidden, false);
|
|
407
|
-
assert.equal(p.el('tourN').textContent, 'how to read the sky · 1 of
|
|
408
|
-
|
|
409
|
-
|
|
441
|
+
assert.equal(p.el('tourN').textContent, 'how to read the sky · 1 of 9');
|
|
442
|
+
const lenses = new Set([p.S().lens]);
|
|
443
|
+
for (let n = 0; n < 8; n++) { p.click('tourNext'); lenses.add(p.S().lens); }
|
|
444
|
+
assert.equal(lenses.has('all'), false, 'no step of this tour enters the whole project');
|
|
445
|
+
assert.equal(p.el('tourN').textContent, 'how to read the sky · 9 of 9');
|
|
410
446
|
assert.equal(p.el('tourNext').textContent, 'start reading');
|
|
411
447
|
p.key('Escape');
|
|
412
448
|
assert.equal(p.el('tour').hidden, true);
|
|
413
449
|
assert.equal(p.S().lens, 'mine', 'the tour hands the sky back to your thinking');
|
|
450
|
+
assert.equal(p.navigated, null);
|
|
414
451
|
});
|
|
415
452
|
|
|
416
453
|
await test('the tour opens by itself on a first visit, and only then', async () => {
|
package/tests/helpers.mjs
CHANGED
|
@@ -904,7 +904,8 @@ export function bootSkyPage({
|
|
|
904
904
|
};
|
|
905
905
|
|
|
906
906
|
// ── the window ───────────────────────────────────────────────────────────
|
|
907
|
-
|
|
907
|
+
// Each page keeps its own tour-seen key (task 1004328); tourSeen marks both.
|
|
908
|
+
const store = { ...(tourSeen ? { 'sky-tour-seen': '4', 'sky-map-tour-seen': '4' } : {}), ...storage };
|
|
908
909
|
let raf = null;
|
|
909
910
|
const windowObj = {
|
|
910
911
|
__BRANDING__: {}, __MODULES__: { enabled: {} },
|