@bongos/core 1.20.48 → 1.20.50
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 +84 -54
- package/.claude/skills/new-project/SKILL.md +5 -0
- package/clients/bongos-client/index.d.ts +1 -1
- package/docs/api/openapi.json +3 -0
- package/docs/api-reference.md +1 -1
- package/docs/copy-inventory.md +434 -400
- package/docs/copy-registry.json +816 -508
- package/docs/module-api-changelog.md +4 -0
- package/docs/page-inventory.json +11 -2
- package/docs/page-readings.json +733 -690
- package/modules/hall-ui/public/criterion-uat-ui.js +280 -0
- package/modules/hall-ui/public/goal-map.html +5 -3
- package/modules/hall-ui/public/goals-page.js +23 -44
- package/modules/hall-ui/public/goals-render.js +24 -15
- package/modules/hall-ui/public/goals.css +45 -0
- package/modules/hall-ui/public/goals.html +5 -2
- package/modules/hall-ui/public/goals.states.json +38 -0
- package/modules/hall-ui/public/sky-data.js +9 -1
- package/modules/hall-ui/public/sky-interaction.js +1 -1
- package/modules/hall-ui/public/sky-panel.js +1 -1
- package/modules/hall-ui/public/thinking.html +5 -3
- package/modules/lifecycle/done-when.js +3 -1
- package/modules/lifecycle/sky.js +23 -8
- package/modules/platform-identity/routes/sso.js +5 -0
- package/modules/provisioning/migrations/provisioning_033_terms_ack.sql +33 -0
- package/modules/provisioning/onboard-plan.js +5 -0
- package/modules/provisioning/provisioning.js +7 -4
- package/modules/provisioning/routes/provisioning.js +3 -3
- package/modules/provisioning/terms-ack.js +36 -0
- package/modules/public-landing/public/projects.html +226 -77
- package/modules/public-landing/public/projects.probes.json +8 -2
- package/modules/public-landing/public/projects.states.json +16 -12
- package/modules/ui-design/kit/serve.js +6 -0
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/release-notes.json +12 -0
- package/scripts/hall-preview/server.js +2 -0
- package/src/module-api.js +1 -1
- package/tests/claim_action.mjs +6 -1
- package/tests/criterion_uat_ui.mjs +113 -0
- package/tests/goal_criterion_confirm_ui.mjs +188 -91
- package/tests/goal_map_page.mjs +2 -1
- package/tests/hall_sky.mjs +16 -0
- package/tests/helpers.mjs +3 -1
- package/tests/projects_hub.mjs +4 -2
- package/tests/projects_hub_app_status.mjs +1 -1
- package/tests/projects_hub_app_step.mjs +9 -9
- package/tests/projects_hub_module_picker.mjs +7 -7
- package/tests/projects_hub_pre_uat.mjs +4 -1
- package/tests/provisioning_terms_ack.mjs +216 -0
- package/tests/sky_read.mjs +7 -1
- package/tests/wizard_draft_resume.mjs +4 -4
- package/tests/wizard_front_door.mjs +271 -0
- package/tests/wizard_intent_resume.mjs +31 -19
|
@@ -15,12 +15,13 @@
|
|
|
15
15
|
// ruled out the task's other option (drop the record at a terminal state).
|
|
16
16
|
//
|
|
17
17
|
// The reset fires only when there is a SECOND DRAFT to lose, and the draft's own step is
|
|
18
|
-
// what says so. A landed create clears DRAFT_KEY — but show(
|
|
18
|
+
// what says so. A landed create clears DRAFT_KEY — but show(11) then persists the done
|
|
19
19
|
// panel's position straight back into it, so a plain "is there a draft?" test is always
|
|
20
20
|
// yes and would skip the reset forever, leaving the finished project's name sitting in
|
|
21
21
|
// the fresh form. (That is exactly what the first cut of this change shipped into a
|
|
22
22
|
// render: "still watching Mercury" above a name field still reading "Mercury".) Only
|
|
23
|
-
// steps 1-
|
|
23
|
+
// steps 1-10 are wizard steps (1-8 before task 1004417's front door took 1 and 2);
|
|
24
|
+
// anything else is the done panel's own bookkeeping.
|
|
24
25
|
//
|
|
25
26
|
// Harness: there is no jsdom in this repo, so this follows tests/wizard_draft_resume.mjs
|
|
26
27
|
// and tests/project_door_ui.mjs — slice the real region out of the page's INLINE script
|
|
@@ -57,8 +58,8 @@ test('both slices are still findable (a rename must fail loudly, not silently pa
|
|
|
57
58
|
assert.ok(offerSlice, 'paintResumeOffer() was not found in projects.html');
|
|
58
59
|
assert.match(enterSlice, /if \(focus && !resumeIntent\) \{/, 'the intent branch is part of the slice');
|
|
59
60
|
assert.match(enterSlice, /startProgress\(created\.id\);/, 'so is the resume branch it guards');
|
|
60
|
-
assert.match(enterSlice, /draft\.step >= 1 && draft\.step <=
|
|
61
|
-
'the STORED draft\'s step decides, not state.step — state.step is
|
|
61
|
+
assert.match(enterSlice, /draft\.step >= 1 && draft\.step <= 10/,
|
|
62
|
+
'the STORED draft\'s step decides, not state.step — state.step is 11 for the whole life of a finished standup');
|
|
62
63
|
assert.match(SCRIPT, /if \(created && created\.id\) \{ enterCreated\(created, !!focus\); return; \}/,
|
|
63
64
|
'enter() still hands the created record straight to it');
|
|
64
65
|
});
|
|
@@ -72,7 +73,7 @@ function runEnter({ focus, resumeIntent = false, draft = null, record }) {
|
|
|
72
73
|
const calls = { show: [], resets: 0, offer: [], done: 0, progress: [], polls: 0, focused: 0 };
|
|
73
74
|
// state.step is the DONE step for the whole life of a finished standup — the value
|
|
74
75
|
// a draft-blind reading would have trusted
|
|
75
|
-
const state = { step: draft ? draft.step :
|
|
76
|
+
const state = { step: draft ? draft.step : 11, name: 'Mercury', slug: 'mercury', domain: '', mode: 'greenfield', noAddress: false, modules: null };
|
|
76
77
|
const sandbox = {
|
|
77
78
|
record, focus, resumeIntent, state,
|
|
78
79
|
DRAFT_KEY: 'draft',
|
|
@@ -98,7 +99,7 @@ const REC = { id: 'inst-1', name: 'Acme', slug: 'acme', domain: 'acme.example',
|
|
|
98
99
|
|
|
99
100
|
test('a reload / Back / identity settle (focus false) still resumes the done panel, watch and all', () => {
|
|
100
101
|
const { calls, state } = runEnter({ focus: false, record: REC });
|
|
101
|
-
assert.deepEqual(calls.show, [[
|
|
102
|
+
assert.deepEqual(calls.show, [[11, false]], 'the done panel, and no focus steal on a non-deliberate arrival');
|
|
102
103
|
assert.equal(calls.resets, 0, 'nothing is reset — this is the same standup continuing');
|
|
103
104
|
assert.equal(calls.done, 1, 'the checklist is re-rendered');
|
|
104
105
|
assert.deepEqual(calls.progress, ['inst-1'], 'the progress watch is restarted from the record');
|
|
@@ -113,7 +114,7 @@ test('a deliberate "New project" click after a finished standup opens a FRESH st
|
|
|
113
114
|
assert.equal(calls.progress.length, 0, 'and its watch is not restarted');
|
|
114
115
|
assert.equal(calls.resets, 1, 'with no second draft to lose, the wizard forgets the finished project');
|
|
115
116
|
assert.deepEqual(calls.show, [[1, false]], 'step 1, and step 1 does not take the heading focus');
|
|
116
|
-
assert.equal(calls.focused, 1, 'the
|
|
117
|
+
assert.equal(calls.focused, 1, 'its one control, the terms tick, does — the deliberate-nav rule enter() already applies');
|
|
117
118
|
assert.equal(state.name, '', 'the old name is gone from the form');
|
|
118
119
|
});
|
|
119
120
|
|
|
@@ -126,7 +127,7 @@ test('…and the standup stays one click away, named, on the resume link', () =>
|
|
|
126
127
|
|
|
127
128
|
test('the resume link gets the done panel back — the record was never cleared', () => {
|
|
128
129
|
const { calls, sandbox } = runEnter({ focus: true, resumeIntent: true, record: REC });
|
|
129
|
-
assert.deepEqual(calls.show, [[
|
|
130
|
+
assert.deepEqual(calls.show, [[11, true]], 'a deliberate resume moves focus to the done panel');
|
|
130
131
|
assert.deepEqual(calls.progress, ['inst-1'], 'the watch comes back with it');
|
|
131
132
|
assert.equal(sandbox.resumeIntent, false, 'the flag is ONE-SHOT — the next plain nav click must mean "new" again');
|
|
132
133
|
assert.deepEqual(calls.offer, [null], 'and the offer comes down behind it');
|
|
@@ -144,20 +145,20 @@ test('a second draft already under way is NOT wiped by navigating back to the wi
|
|
|
144
145
|
});
|
|
145
146
|
|
|
146
147
|
test('the done panel\'s own saved step is NOT a second draft — it must not block the reset', () => {
|
|
147
|
-
// Caught in a render, not in a unit test: show(
|
|
148
|
+
// Caught in a render, not in a unit test: show(11) calls saveDraft(), so DRAFT_KEY is
|
|
148
149
|
// non-empty again the moment a create lands. Reading "is there a draft?" left the
|
|
149
150
|
// finished project's name in the fresh form, under a line offering to resume it.
|
|
150
|
-
const { calls, state } = runEnter({ focus: true, record: REC, draft: { step:
|
|
151
|
+
const { calls, state } = runEnter({ focus: true, record: REC, draft: { step: 11, name: 'Mercury' } });
|
|
151
152
|
assert.equal(calls.resets, 1, 'the done step is bookkeeping, not a project being typed');
|
|
152
|
-
assert.deepEqual(calls.show, [[1, false]], 'out-of-range steps land on the
|
|
153
|
+
assert.deepEqual(calls.show, [[1, false]], 'out-of-range steps land on step 1, the front door');
|
|
153
154
|
assert.equal(state.name, '', 'and the finished project\'s name does not survive into it');
|
|
154
155
|
assert.equal(calls.done, 0, 'never back onto the done panel');
|
|
155
156
|
});
|
|
156
157
|
|
|
157
158
|
test('a draft on the app step or the review is live too — the last two numbered steps (task 1004351)', () => {
|
|
158
|
-
// The app step moved the review from 7 to 8
|
|
159
|
-
// project sitting on its review, silently wiping it.
|
|
160
|
-
for (const step of [
|
|
159
|
+
// The app step moved the review from 7 to 8, and the front door (task 1004417) to 10. A
|
|
160
|
+
// guard left behind would reset a second project sitting on its review, silently wiping it.
|
|
161
|
+
for (const step of [9, 10]) {
|
|
161
162
|
const { calls, state } = runEnter({ focus: true, record: REC, draft: { step } });
|
|
162
163
|
assert.equal(calls.resets, 0, `step ${step} is a live draft`);
|
|
163
164
|
assert.deepEqual(calls.show, [[step, true]]);
|
|
@@ -165,8 +166,16 @@ test('a draft on the app step or the review is live too — the last two numbere
|
|
|
165
166
|
}
|
|
166
167
|
});
|
|
167
168
|
|
|
168
|
-
test('a draft
|
|
169
|
-
for (const
|
|
169
|
+
test('a draft on the front door is live too — a founder part-way through it keeps their place (task 1004417)', () => {
|
|
170
|
+
for (const step of [1, 2]) {
|
|
171
|
+
const { calls, state } = runEnter({ focus: true, record: REC, draft: { step } });
|
|
172
|
+
assert.equal(calls.resets, 0, `step ${step} is a live draft`);
|
|
173
|
+
assert.equal(state.step, step);
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
test('a draft whose step is missing or junk resets too — only 1-10 preserves anything', () => {
|
|
178
|
+
for (const draft of [{ step: 0 }, { step: 11 }, { name: 'half-typed' }]) {
|
|
170
179
|
const { calls } = runEnter({ focus: true, record: REC, draft });
|
|
171
180
|
assert.equal(calls.resets, 1, `step ${JSON.stringify(draft.step)} is not a wizard step`);
|
|
172
181
|
assert.deepEqual(calls.show, [[1, false]]);
|
|
@@ -191,11 +200,14 @@ test('paintResumeOffer names the project by textContent and hides on null (no li
|
|
|
191
200
|
});
|
|
192
201
|
|
|
193
202
|
test('the offer ships as real markup inside step 1, hidden until there is something to resume', () => {
|
|
194
|
-
|
|
203
|
+
// step 1 is the front door's terms screen since task 1004417 — the offer moved with it
|
|
204
|
+
const panel = HUB.slice(HUB.indexOf('id="panel-terms"'), HUB.indexOf('id="panel-fork"'));
|
|
195
205
|
assert.match(panel, /<p class="resumeOffer" id="wizResume" hidden>still watching <strong id="wizResumeName">your project<\/strong> — <a href="#" id="wizResumeGo">resume it<\/a><\/p>/,
|
|
196
206
|
'baked into the panel (C7), carrying its own hidden state');
|
|
197
|
-
assert.ok(panel.indexOf('id="wizResume"') < panel.indexOf('<form
|
|
198
|
-
'it sits above the
|
|
207
|
+
assert.ok(panel.indexOf('id="wizResume"') < panel.indexOf('<form data-next="2">'),
|
|
208
|
+
'it sits above the terms form, where a visitor reads it before anything else');
|
|
209
|
+
assert.doesNotMatch(HUB.slice(HUB.indexOf('id="panel-name"'), HUB.indexOf('id="panel-type"')), /id="wizResume"/,
|
|
210
|
+
'and only once — a second copy would be a duplicate id');
|
|
199
211
|
assert.match(SCRIPT, /\$\('wizResumeGo'\)\.addEventListener\('click', function \(ev\) \{\n\s*ev\.preventDefault\(\);\n\s*resumeIntent = true;\n\s*enter\(true\);/,
|
|
200
212
|
'the link raises the one-shot intent and re-enters, rather than href-navigating');
|
|
201
213
|
});
|