@bongos/core 1.21.105 → 1.21.106
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 +53 -43
- package/docs/copy-inventory.md +368 -366
- package/docs/copy-registry.json +475 -457
- package/docs/design/project-startup-direction.md +14 -0
- package/docs/module-api-changelog.md +2 -0
- package/docs/page-inventory.json +10 -3
- package/docs/page-readings.json +1023 -977
- package/modules/public-landing/public/projects-hall-live.states.json +3 -2
- package/modules/public-landing/public/projects-setup.states.json +91 -0
- package/modules/public-landing/public/projects.html +535 -804
- package/modules/public-landing/public/projects.probes.json +3 -3
- package/modules/public-landing/public/projects.states.json +1 -1
- package/modules/ui-design/kit/fixtures/provisioning-instances-hall-live.json +22 -2
- package/modules/ui-design/kit/fixtures/provisioning-instances-setup.json +195 -0
- package/modules/ui-design/kit/serve.js +22 -4
- 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/cosmos_token_contrast.mjs +10 -18
- package/tests/github_handback_any_device.mjs +4 -3
- package/tests/github_one_trip.mjs +45 -47
- package/tests/github_org_account.mjs +2 -2
- package/tests/github_pick_up.mjs +40 -29
- package/tests/onboard.mjs +13 -7
- package/tests/project_invite_ui.mjs +6 -3
- package/tests/project_modules_ui.mjs +3 -3
- package/tests/projects_hub.mjs +8 -9
- package/tests/projects_hub_cloud_hop.mjs +77 -125
- package/tests/projects_hub_dns_ready.mjs +42 -51
- package/tests/projects_hub_pre_uat.mjs +68 -69
- package/tests/public_landing_projects.mjs +45 -102
- package/tests/setup_status_facts.mjs +400 -0
- package/tests/wizard_github_feedback.mjs +90 -87
- package/tests/wizard_one_page.mjs +11 -9
- package/tests/wizard_auto_open.mjs +0 -94
|
@@ -167,12 +167,12 @@
|
|
|
167
167
|
{ "name": "part 02 (task 1004648): Change opens a row in place and reads Done, opening another closes it, and nothing needs confirming", "auth": true, "width": 1440, "url": "/projects?view=new",
|
|
168
168
|
"steps": [["wait",600],["fill","#newName","Mercury"],["click","#typeCards .tpill[data-type=\"game\"]"],["fill","#f-desc","A co-op farming game where the seasons never repeat."],["select","#physCountry","US"],["wait",100],["click","[data-phys=\"builder_geography\"][data-val=\"global\"]"],["click","[data-phys=\"minors_on_board\"][data-val=\"false\"]"],["click","[data-phys=\"entity\"][data-val=\"intent-solo\"]"],["wait",300],["click","#reviewRows .setRow[data-row=\"team\"] [data-row-chg]"],["wait",200],["click","[data-phys-solo=\"many\"]"],["wait",600],["click","#reviewRows .setRow[data-row=\"run\"] [data-row-chg]"],["wait",300]],
|
|
169
169
|
"expect": {"visible":["#reviewRows .setRow[data-row=\"rewards\"]","#reviewRows .setRow.open[data-row=\"run\"] .opts"],"hidden":["#reviewRows .setRow[data-row=\"team\"] .opts"],"text":[["#reviewRows .setRow[data-row=\"run\"] [data-row-chg]","Done"],["#reviewRows .setRow[data-row=\"team\"] [data-row-chg]","Change"]]} },
|
|
170
|
-
{ "name": "the wizard driver (task 1004648): part 01, the checks, the address row (the dotless stub host takes a domain the founder owns), the tick, then Create — part 03 goes live
|
|
170
|
+
{ "name": "the wizard driver (task 1004648): part 01, the checks, the address row (the dotless stub host takes a domain the founder owns), the tick, then Create — part 03 goes live as Getting <name> ready: one sentence, the checked facts, and the cloud hop behind its link", "auth": true, "width": 1440, "url": "/projects?view=new",
|
|
171
171
|
"steps": [["wait",600],["fill","#newName","Mercury"],["click","#typeCards .tpill[data-type=\"game\"]"],["fill","#f-desc","A co-op farming game where the seasons never repeat."],["select","#physCountry","US"],["wait",100],["click","[data-phys=\"builder_geography\"][data-val=\"global\"]"],["click","[data-phys=\"minors_on_board\"][data-val=\"false\"]"],["click","[data-phys=\"entity\"][data-val=\"intent-solo\"]"],["wait",300],["click","#reviewRows .setRow[data-row=\"address\"] [data-row-chg]"],["wait",200],["fill","#f-slug","mercury"],["wait",900],["fill","#f-domain","mercury.example.com"],["wait",200],["click","#reviewRows .setRow[data-row=\"address\"] [data-row-chg]"],["wait",200],["click","#termsAck"],["wait",100],["click","#doCreate"],["wait",1500]],
|
|
172
|
-
"expect": {"visible":["#panel-done","#
|
|
172
|
+
"expect": {"visible":["#panel-done","#setupNow","#homeFacts","#ghFacts","#hopLink"],"hidden":["#wizParts","#hop","#doneAlive"],"text":[["#donePartT","Getting Mercury ready"]]} },
|
|
173
173
|
{ "name": "the wizard driver at 320 (narrower than a 375 phone): the page stacks, nothing scrolls sideways, and the walk still reaches part 03", "auth": true, "width": 320, "url": "/projects?view=new",
|
|
174
174
|
"steps": [["wait",600],["fill","#newName","Mercury"],["click","#typeCards .tpill[data-type=\"game\"]"],["fill","#f-desc","A co-op farming game where the seasons never repeat."],["select","#physCountry","US"],["wait",100],["click","[data-phys=\"builder_geography\"][data-val=\"global\"]"],["click","[data-phys=\"minors_on_board\"][data-val=\"false\"]"],["click","[data-phys=\"entity\"][data-val=\"intent-solo\"]"],["wait",300],["click","#reviewRows .setRow[data-row=\"address\"] [data-row-chg]"],["wait",200],["fill","#f-slug","mercury"],["wait",900],["fill","#f-domain","mercury.example.com"],["wait",200],["click","#reviewRows .setRow[data-row=\"address\"] [data-row-chg]"],["wait",200],["click","#termsAck"],["wait",100],["click","#doCreate"],["wait",1500]],
|
|
175
|
-
"expect": {"noOverflow":true,"visible":["#panel-done","#
|
|
175
|
+
"expect": {"noOverflow":true,"visible":["#panel-done","#homeFacts","#ghFacts"],"hidden":["#wizParts"]} },
|
|
176
176
|
{ "name": "invite a guild (task 1002303, R27): a /g/ address gives one pending line per member on its public page, each a link to the hall", "auth": true, "width": 1440, "url": "/projects?view=manage&id=101",
|
|
177
177
|
"steps": [["wait",900],["fill","#mInviteGuild","/g/forge-crew"],["click","#mInvite [data-invite-guild]"],["wait",400]],
|
|
178
178
|
"expect": { "count": [["#mInviteList li", 4]], "value": [["#mInviteGuild", ""]],
|
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
"in-new-look": {"auth":true,"url":"/projects?view=new","actions":[["wait",600],["fill","#newName","Mercury"],["click","#typeCards .tpill[data-type=\"game\"]"],["fill","#f-desc","A co-op farming game where the seasons never repeat."],["select","#physCountry","US"],["wait",100],["click","[data-phys=\"builder_geography\"][data-val=\"global\"]"],["click","[data-phys=\"minors_on_board\"][data-val=\"false\"]"],["click","[data-phys=\"entity\"][data-val=\"intent-solo\"]"],["wait",300],["click","#reviewRows .setRow[data-row=\"look\"] [data-row-chg]"],["wait",400]],"expect":{"visible":["#reviewRows .setRow.open[data-row=\"look\"] .opts","#wizLook"]}},
|
|
57
57
|
"in-new-look-custom": {"auth":true,"url":"/projects?view=new","actions":[["wait",600],["fill","#newName","Mercury"],["click","#typeCards .tpill[data-type=\"game\"]"],["fill","#f-desc","A co-op farming game where the seasons never repeat."],["select","#physCountry","US"],["wait",100],["click","[data-phys=\"builder_geography\"][data-val=\"global\"]"],["click","[data-phys=\"minors_on_board\"][data-val=\"false\"]"],["click","[data-phys=\"entity\"][data-val=\"intent-solo\"]"],["wait",300],["click","#reviewRows .setRow[data-row=\"look\"] [data-row-chg]"],["wait",400],["click","#wizLook-custom"],["wait",200]],"expect":{"visible":["#reviewRows .setRow.open[data-row=\"look\"] .opts","#wizLook","#wizAccent","#wizAccentNote"]}},
|
|
58
58
|
"in-new-create-blocked": {"auth":true,"url":"/projects?view=new","actions":[["wait",600],["fill","#newName","Mercury"],["click","#typeCards .tpill[data-type=\"game\"]"],["fill","#f-desc","A co-op farming game where the seasons never repeat."],["click","#termsAck"],["wait",100],["click","#doCreate"],["wait",400]],"expect":{"visible":["#reviewRows .setRow.open[data-row=\"address\"] .opts","#h-domain"],"hidden":["#doneBody"],"text":[["#createWhy","Fix the row that’s open, then create."]]}},
|
|
59
|
-
"in-new-done": {"auth":true,"url":"/projects?view=new","actions":[["wait",600],["fill","#newName","Mercury"],["click","#typeCards .tpill[data-type=\"game\"]"],["fill","#f-desc","A co-op farming game where the seasons never repeat."],["select","#physCountry","US"],["wait",100],["click","[data-phys=\"builder_geography\"][data-val=\"global\"]"],["click","[data-phys=\"minors_on_board\"][data-val=\"false\"]"],["click","[data-phys=\"entity\"][data-val=\"intent-solo\"]"],["wait",300],["click","#reviewRows .setRow[data-row=\"address\"] [data-row-chg]"],["wait",200],["fill","#f-slug","mercury"],["wait",900],["fill","#f-domain","mercury.example.com"],["wait",200],["click","#reviewRows .setRow[data-row=\"address\"] [data-row-chg]"],["wait",200],["click","#termsAck"],["wait",100],["click","#doCreate"],["wait",1500]],"expect":{"visible":["#panel-done","#doneBody","#
|
|
59
|
+
"in-new-done": {"auth":true,"url":"/projects?view=new","actions":[["wait",600],["fill","#newName","Mercury"],["click","#typeCards .tpill[data-type=\"game\"]"],["fill","#f-desc","A co-op farming game where the seasons never repeat."],["select","#physCountry","US"],["wait",100],["click","[data-phys=\"builder_geography\"][data-val=\"global\"]"],["click","[data-phys=\"minors_on_board\"][data-val=\"false\"]"],["click","[data-phys=\"entity\"][data-val=\"intent-solo\"]"],["wait",300],["click","#reviewRows .setRow[data-row=\"address\"] [data-row-chg]"],["wait",200],["fill","#f-slug","mercury"],["wait",900],["fill","#f-domain","mercury.example.com"],["wait",200],["click","#reviewRows .setRow[data-row=\"address\"] [data-row-chg]"],["wait",200],["click","#termsAck"],["wait",100],["click","#doCreate"],["wait",1500]],"expect":{"visible":["#panel-done","#doneBody","#setupNow","#homeFacts","#ghFacts","#hopLink","#wizRecap"],"hidden":["#wizParts","#qWrap","#wizInvite","#hop","#doneAlive"],"attr":[["#doCreate","disabled",""],["#wizRoom","data-screen","done"]],"text":[["#donePartT","Getting Mercury ready"],["#doCreate","Created"]]}},
|
|
60
60
|
"in-new-resume-offer": {"auth":true,"url":"/projects?view=new","actions":[["wait",600],["fill","#newName","Mercury"],["click","#typeCards .tpill[data-type=\"game\"]"],["fill","#f-desc","A co-op farming game where the seasons never repeat."],["select","#physCountry","US"],["wait",100],["click","[data-phys=\"builder_geography\"][data-val=\"global\"]"],["click","[data-phys=\"minors_on_board\"][data-val=\"false\"]"],["click","[data-phys=\"entity\"][data-val=\"intent-solo\"]"],["wait",300],["click","#reviewRows .setRow[data-row=\"address\"] [data-row-chg]"],["wait",200],["fill","#f-slug","mercury"],["wait",900],["fill","#f-domain","mercury.example.com"],["wait",200],["click","#reviewRows .setRow[data-row=\"address\"] [data-row-chg]"],["wait",200],["click","#termsAck"],["wait",100],["click","#doCreate"],["wait",1500],["click","#projTrig"],["wait",350],["click","#menuProjects [data-nav=\"new\"]"],["wait",500]],"expect":{"visible":["#panel-page","#wizResume","#wizResumeGo","#wizParts"],"hidden":["#doneBody"],"text":[["#wizResumeName","Mercury"]]}},
|
|
61
61
|
"out-new": {"auth":false,"url":"/projects?view=new","expect":{"visible":["#panel-gate","#wizSignin"],"hidden":["#qWrap","#panel-page"]}},
|
|
62
62
|
"out-map-projects": { "auth": false, "actions": [["click", "#projTrig"], ["wait", 350]], "expect": { "expanded": true, "hidden": ["#menuProjects [data-nav=\"mine\"]"] } },
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"_": "The owner's projects for the kit (task 1003345): four states the mine list and the manage page render — live, standing up, snagged, torn down. Timestamps written \"$now-3m\" / \"$now-1d\" are resolved by the stub at request time so \"checked 3m ago\" stays true. Mooring (task 1003345, the grade's finding): live but unreachable since its last probe, so the restart door renders and the restart probe has a row to drive.",
|
|
2
|
+
"_": "The owner's projects for the kit (task 1003345): four states the mine list and the manage page render — live, standing up, snagged, torn down. Timestamps written \"$now-3m\" / \"$now-1d\" are resolved by the stub at request time so \"checked 3m ago\" stays true. Mooring (task 1003345, the grade's finding): live but unreachable since its last probe, so the restart door renders and the restart probe has a row to drive. Mercury (102) also carries the owner read's GitHub halves (github_app, github_setup), produced by the REAL projections with the app approved, installed and signed in, so part 03 reaches every required fact done (task 1004683).",
|
|
3
3
|
"instances": [
|
|
4
4
|
{
|
|
5
5
|
"id": 101,
|
|
@@ -44,7 +44,27 @@
|
|
|
44
44
|
"state": "running",
|
|
45
45
|
"created_at": "$now-6m"
|
|
46
46
|
},
|
|
47
|
-
"dns_resolves": true
|
|
47
|
+
"dns_resolves": true,
|
|
48
|
+
"github_app": {
|
|
49
|
+
"status": "done",
|
|
50
|
+
"app_slug": "mercury-cloudbongos-com",
|
|
51
|
+
"failure": null,
|
|
52
|
+
"started_at": "2026-10-09T12:52:53.145Z"
|
|
53
|
+
},
|
|
54
|
+
"github_setup": {
|
|
55
|
+
"checklist": {
|
|
56
|
+
"approve": "done",
|
|
57
|
+
"install": "done",
|
|
58
|
+
"sign_in": "done",
|
|
59
|
+
"device_flow": "later",
|
|
60
|
+
"connected": true
|
|
61
|
+
},
|
|
62
|
+
"install_url": null,
|
|
63
|
+
"repo": "builder/mercury",
|
|
64
|
+
"verifying": true,
|
|
65
|
+
"pick_up": null,
|
|
66
|
+
"app_org": null
|
|
67
|
+
}
|
|
48
68
|
},
|
|
49
69
|
{
|
|
50
70
|
"id": 103,
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
{
|
|
2
|
+
"_": "Part 03 after Create, one project per scenario of the design of record docs/design/mocks/day-night-rooms/setup-status.html (task 1004683): 201 just created, 202 waiting on GitHub, 203 installing, 204 stopped (the install never confirmed, the checking window over), 205 all done. Each row carries the github_app and github_setup halves of the owner's instance read, produced by the REAL projections (manifest-truth publicGithubApp, github-setup githubSetupRead); serve.js hands them out beside the instance on the single read. Regenerate the GitHub halves rather than hand-editing them.",
|
|
3
|
+
"instances": [
|
|
4
|
+
{
|
|
5
|
+
"id": 201,
|
|
6
|
+
"slug": "kestrel",
|
|
7
|
+
"domain": "kestrel.cloudbongos.com",
|
|
8
|
+
"target_ref": "founder/kestrel",
|
|
9
|
+
"hosting_shape": "cloud-host",
|
|
10
|
+
"onboard_mode": "greenfield",
|
|
11
|
+
"error_note": null,
|
|
12
|
+
"dns_note": null,
|
|
13
|
+
"torn_down_at": null,
|
|
14
|
+
"open_intent": null,
|
|
15
|
+
"status": "provisioning",
|
|
16
|
+
"created_at": "$now-1m",
|
|
17
|
+
"provisioned_at": null,
|
|
18
|
+
"updated_at": "$now-1m",
|
|
19
|
+
"last_verified_at": null,
|
|
20
|
+
"last_verified_up": null,
|
|
21
|
+
"dns_resolves": false,
|
|
22
|
+
"github_app": null,
|
|
23
|
+
"github_setup": {
|
|
24
|
+
"checklist": {
|
|
25
|
+
"approve": "todo",
|
|
26
|
+
"install": "todo",
|
|
27
|
+
"sign_in": "todo",
|
|
28
|
+
"device_flow": "todo",
|
|
29
|
+
"connected": false
|
|
30
|
+
},
|
|
31
|
+
"install_url": null,
|
|
32
|
+
"repo": "founder/kestrel",
|
|
33
|
+
"verifying": false,
|
|
34
|
+
"app_org": null,
|
|
35
|
+
"pick_up": null
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
"id": 202,
|
|
40
|
+
"slug": "heron",
|
|
41
|
+
"domain": "heron.cloudbongos.com",
|
|
42
|
+
"target_ref": "founder/heron",
|
|
43
|
+
"hosting_shape": "cloud-host",
|
|
44
|
+
"onboard_mode": "greenfield",
|
|
45
|
+
"error_note": null,
|
|
46
|
+
"dns_note": null,
|
|
47
|
+
"torn_down_at": null,
|
|
48
|
+
"open_intent": null,
|
|
49
|
+
"status": "active",
|
|
50
|
+
"created_at": "$now-9m",
|
|
51
|
+
"provisioned_at": "$now-6m",
|
|
52
|
+
"updated_at": "$now-6m",
|
|
53
|
+
"last_verified_at": null,
|
|
54
|
+
"last_verified_up": null,
|
|
55
|
+
"dns_resolves": false,
|
|
56
|
+
"github_app": {
|
|
57
|
+
"status": "pending",
|
|
58
|
+
"app_slug": null,
|
|
59
|
+
"failure": null,
|
|
60
|
+
"started_at": "2026-10-09T12:48:57.326Z"
|
|
61
|
+
},
|
|
62
|
+
"github_setup": {
|
|
63
|
+
"checklist": {
|
|
64
|
+
"approve": "now",
|
|
65
|
+
"install": "todo",
|
|
66
|
+
"sign_in": "todo",
|
|
67
|
+
"device_flow": "todo",
|
|
68
|
+
"connected": false
|
|
69
|
+
},
|
|
70
|
+
"install_url": null,
|
|
71
|
+
"repo": "founder/heron",
|
|
72
|
+
"verifying": false,
|
|
73
|
+
"pick_up": "reopen",
|
|
74
|
+
"app_org": null
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
"id": 203,
|
|
79
|
+
"slug": "plover",
|
|
80
|
+
"domain": "plover.cloudbongos.com",
|
|
81
|
+
"target_ref": "founder/plover",
|
|
82
|
+
"hosting_shape": "cloud-host",
|
|
83
|
+
"onboard_mode": "greenfield",
|
|
84
|
+
"error_note": null,
|
|
85
|
+
"dns_note": null,
|
|
86
|
+
"torn_down_at": null,
|
|
87
|
+
"open_intent": null,
|
|
88
|
+
"status": "active",
|
|
89
|
+
"created_at": "$now-14m",
|
|
90
|
+
"provisioned_at": "$now-11m",
|
|
91
|
+
"updated_at": "$now-11m",
|
|
92
|
+
"last_verified_at": "$now-9s",
|
|
93
|
+
"last_verified_up": true,
|
|
94
|
+
"dns_resolves": true,
|
|
95
|
+
"github_app": {
|
|
96
|
+
"status": "converting",
|
|
97
|
+
"app_slug": "plover-cloudbongos-com",
|
|
98
|
+
"failure": null,
|
|
99
|
+
"started_at": "2026-10-09T12:45:57.326Z"
|
|
100
|
+
},
|
|
101
|
+
"github_setup": {
|
|
102
|
+
"checklist": {
|
|
103
|
+
"approve": "done",
|
|
104
|
+
"install": "now",
|
|
105
|
+
"sign_in": "now",
|
|
106
|
+
"device_flow": "todo",
|
|
107
|
+
"connected": false
|
|
108
|
+
},
|
|
109
|
+
"install_url": "https://github.com/apps/plover-cloudbongos-com/installations/new",
|
|
110
|
+
"repo": "founder/plover",
|
|
111
|
+
"verifying": true,
|
|
112
|
+
"pick_up": null,
|
|
113
|
+
"app_org": null
|
|
114
|
+
}
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
"id": 204,
|
|
118
|
+
"slug": "tern",
|
|
119
|
+
"domain": "tern.cloudbongos.com",
|
|
120
|
+
"target_ref": "founder/tern",
|
|
121
|
+
"hosting_shape": "cloud-host",
|
|
122
|
+
"onboard_mode": "greenfield",
|
|
123
|
+
"error_note": null,
|
|
124
|
+
"dns_note": null,
|
|
125
|
+
"torn_down_at": null,
|
|
126
|
+
"open_intent": null,
|
|
127
|
+
"status": "active",
|
|
128
|
+
"created_at": "$now-4h",
|
|
129
|
+
"provisioned_at": "$now-235m",
|
|
130
|
+
"updated_at": "$now-235m",
|
|
131
|
+
"last_verified_at": "$now-9s",
|
|
132
|
+
"last_verified_up": true,
|
|
133
|
+
"dns_resolves": true,
|
|
134
|
+
"github_app": {
|
|
135
|
+
"status": "done",
|
|
136
|
+
"app_slug": "tern-cloudbongos-com",
|
|
137
|
+
"failure": null,
|
|
138
|
+
"started_at": "2026-10-09T08:59:57.326Z"
|
|
139
|
+
},
|
|
140
|
+
"github_setup": {
|
|
141
|
+
"checklist": {
|
|
142
|
+
"approve": "done",
|
|
143
|
+
"install": "now",
|
|
144
|
+
"sign_in": "done",
|
|
145
|
+
"device_flow": "later",
|
|
146
|
+
"connected": false
|
|
147
|
+
},
|
|
148
|
+
"install_url": "https://github.com/apps/tern-cloudbongos-com/installations/new",
|
|
149
|
+
"repo": "founder/tern",
|
|
150
|
+
"verifying": false,
|
|
151
|
+
"pick_up": "check",
|
|
152
|
+
"app_org": null
|
|
153
|
+
}
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
"id": 205,
|
|
157
|
+
"slug": "wren",
|
|
158
|
+
"domain": "wren.cloudbongos.com",
|
|
159
|
+
"target_ref": "founder/wren",
|
|
160
|
+
"hosting_shape": "cloud-host",
|
|
161
|
+
"onboard_mode": "greenfield",
|
|
162
|
+
"error_note": null,
|
|
163
|
+
"dns_note": null,
|
|
164
|
+
"torn_down_at": null,
|
|
165
|
+
"open_intent": null,
|
|
166
|
+
"status": "active",
|
|
167
|
+
"created_at": "$now-30m",
|
|
168
|
+
"provisioned_at": "$now-27m",
|
|
169
|
+
"updated_at": "$now-27m",
|
|
170
|
+
"last_verified_at": "$now-3s",
|
|
171
|
+
"last_verified_up": true,
|
|
172
|
+
"dns_resolves": true,
|
|
173
|
+
"github_app": {
|
|
174
|
+
"status": "done",
|
|
175
|
+
"app_slug": "wren-cloudbongos-com",
|
|
176
|
+
"failure": null,
|
|
177
|
+
"started_at": "2026-10-09T12:25:57.326Z"
|
|
178
|
+
},
|
|
179
|
+
"github_setup": {
|
|
180
|
+
"checklist": {
|
|
181
|
+
"approve": "done",
|
|
182
|
+
"install": "done",
|
|
183
|
+
"sign_in": "done",
|
|
184
|
+
"device_flow": "later",
|
|
185
|
+
"connected": true
|
|
186
|
+
},
|
|
187
|
+
"install_url": null,
|
|
188
|
+
"repo": "founder/wren",
|
|
189
|
+
"verifying": true,
|
|
190
|
+
"pick_up": null,
|
|
191
|
+
"app_org": null
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
]
|
|
195
|
+
}
|
|
@@ -309,12 +309,27 @@ function instances(res, id, settings) {
|
|
|
309
309
|
if (FAIL.has(name)) return json(res, 500, { error: { code: 'stub_failure', message: `FAIL=${name}` } });
|
|
310
310
|
const file = path.join(FIXTURES, (ALIAS[name] || name) + '.json');
|
|
311
311
|
if (!fs.existsSync(file)) return json(res, 404, { error: { code: 'no_fixture', message: name } });
|
|
312
|
-
|
|
312
|
+
// a fixture row may carry the owner read's two GitHub halves (github_app, github_setup —
|
|
313
|
+
// the shapes modules/provisioning/routes/provisioning.js adds, task 1004683); they ride
|
|
314
|
+
// the single read beside the instance, never inside it, and never the list
|
|
315
|
+
const rows = stamp((JSON.parse(fs.readFileSync(file, 'utf8')).instances || []).map(withAsk).map(withPlanet));
|
|
316
|
+
const bare = (i) => { const { github_app, github_setup, ...rest } = i; return rest; };
|
|
317
|
+
const list = rows.map(bare);
|
|
313
318
|
if (id === null) return json(res, 200, { instances: list });
|
|
314
|
-
const
|
|
315
|
-
if (!
|
|
319
|
+
const row = rows.find((i) => String(i.id) === String(id));
|
|
320
|
+
if (!row) return json(res, 404, { error: { code: 'not_found', message: 'no such instance' } });
|
|
321
|
+
const inst = bare(row);
|
|
316
322
|
if (settings) return json(res, 200, { settings: { platform_visibility: 'public', joinability: 'open', visibility: 'public' }, planet: PLANETS.get(String(id)) || NO_PLANET, options: { platform_visibility: ['public', 'gated'], joinability: ['open', 'apply', 'invite_only'], visibility: ['public', 'private', 'stealth'] } });
|
|
317
|
-
return json(res, 200, { instance: inst, open_intent: inst.open_intent || null });
|
|
323
|
+
return json(res, 200, { instance: inst, open_intent: inst.open_intent || null, github_app: row.github_app || null, github_setup: row.github_setup || null });
|
|
324
|
+
}
|
|
325
|
+
// GET /provisioning/github-app/resume?id=N — the route's resume record (routes/github-setup.js
|
|
326
|
+
// resumeRecord) for a fixture project, so a render can open part 03 on it by URL alone
|
|
327
|
+
function resumeAnswer(res, id) {
|
|
328
|
+
const file = path.join(FIXTURES, (ALIAS['provisioning-instances'] || 'provisioning-instances') + '.json');
|
|
329
|
+
const rows = fs.existsSync(file) ? (JSON.parse(fs.readFileSync(file, 'utf8')).instances || []) : [];
|
|
330
|
+
const inst = id ? rows.find((i) => String(i.id) === String(id)) : null;
|
|
331
|
+
const repo = inst && /^[A-Za-z0-9][A-Za-z0-9-]{0,38}\/[A-Za-z0-9._-]{1,100}$/.test(String(inst.target_ref || '')) ? inst.target_ref : null;
|
|
332
|
+
return json(res, 200, { ok: true, project: inst ? { id: inst.id, slug: inst.slug, domain: inst.domain || null, onboard_mode: inst.onboard_mode || 'greenfield', repo } : null });
|
|
318
333
|
}
|
|
319
334
|
// A project's art in the featured fixture may be root-relative (the surface's
|
|
320
335
|
// own /assets/…, served by this stub) — the page accepts only an http(s) art
|
|
@@ -644,6 +659,9 @@ const server = http.createServer((req, res) => {
|
|
|
644
659
|
if (/^\/provisioning\/instances\/\d+\/invite-suggestions$/.test(rest) && req.method === 'GET') {
|
|
645
660
|
return AUTH ? json(res, 200, { suggested: [], seeking: null, reason: null }) : json(res, 401, UNAUTH);
|
|
646
661
|
}
|
|
662
|
+
if (rest === '/provisioning/github-app/resume' && req.method === 'GET') {
|
|
663
|
+
return AUTH ? resumeAnswer(res, u.searchParams.get('id')) : json(res, 401, UNAUTH);
|
|
664
|
+
}
|
|
647
665
|
const one = rest.match(/^\/provisioning\/instances\/(\d+)(\/settings)?$/);
|
|
648
666
|
if (one && req.method === 'GET') return AUTH ? instances(res, one[1], !!one[2]) : json(res, 401, UNAUTH);
|
|
649
667
|
// the hub's own cross-project surface (task 1003774): the requested/leave/
|
package/package-lock.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bongos/core",
|
|
3
|
-
"version": "1.21.
|
|
3
|
+
"version": "1.21.106",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@bongos/core",
|
|
9
|
-
"version": "1.21.
|
|
9
|
+
"version": "1.21.106",
|
|
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.21.
|
|
3
|
+
"version": "1.21.106",
|
|
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
|
@@ -9476,5 +9476,11 @@
|
|
|
9476
9476
|
"id": "1004666",
|
|
9477
9477
|
"text": "A check that is still running is no longer reported as a failed one. Before, a project whose test service posts a \"still working\" status would see its change called broken and trigger a pointless repair attempt; now it is corr"
|
|
9478
9478
|
}
|
|
9479
|
+
],
|
|
9480
|
+
"1.21.106": [
|
|
9481
|
+
{
|
|
9482
|
+
"id": "1004683",
|
|
9483
|
+
"text": "After pressing Create, a founder now sees \"Getting <name> ready\" with a plain count (\"4 of 6 done\", or \"ready\" with a tick) and one sentence saying what is happening and whether it is their turn. Below it are two short lists,"
|
|
9484
|
+
}
|
|
9479
9485
|
]
|
|
9480
9486
|
}
|
package/src/module-api.js
CHANGED
|
@@ -75,7 +75,7 @@ const { responsibilityFor, ROLE_RESPONSIBILITIES } = require('./role-responsibil
|
|
|
75
75
|
// MAJOR (see allowBoxScope below): passes the request through untouched.
|
|
76
76
|
function deprecatedNoopMiddleware(_req, _res, next) { next(); }
|
|
77
77
|
|
|
78
|
-
const CORE_VERSION = '1.21.
|
|
78
|
+
const CORE_VERSION = '1.21.106'; // CI auto-patch carrier (ADR 0161); changelog: docs/module-api-changelog.md
|
|
79
79
|
|
|
80
80
|
// A namespaced logger so a module's log lines are attributable + consistent.
|
|
81
81
|
// Usage: const log = api.logger('discord'); log.info('mounted');
|
|
@@ -515,24 +515,16 @@ test('text is never dimmed by subtree opacity', () => {
|
|
|
515
515
|
assert.deepEqual(offenders, [], `\n ${offenders.join('\n ')}\n`);
|
|
516
516
|
});
|
|
517
517
|
|
|
518
|
-
test('
|
|
519
|
-
//
|
|
520
|
-
//
|
|
521
|
-
//
|
|
522
|
-
//
|
|
523
|
-
//
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
const body = m[1];
|
|
529
|
-
if (/(?:border(?:-\w+)?|background)\s*:\s*var\(\s*--sea\s*\)/.test(body)) {
|
|
530
|
-
bad.push(`raw --sea state mark: ${m[0].slice(0, 80)}`);
|
|
531
|
-
}
|
|
532
|
-
if (/border-(?:left|bottom)\s*:[^;]*#fff\b/i.test(body)) {
|
|
533
|
-
bad.push(`hardcoded #fff tick: ${m[0].slice(0, 80)}`);
|
|
534
|
-
}
|
|
535
|
-
}
|
|
518
|
+
test('part 03 draws no stage strip, and its fact marks use the status inks, never raw --sea or #fff (task 1004683)', () => {
|
|
519
|
+
// The done panel's page-local .prog strip (a mirror of cosmos's .strip) left with the
|
|
520
|
+
// stage dots: part 03 is one list of checked facts now. The mine and manage views keep
|
|
521
|
+
// cosmos's own .strip. A fact's mark carries its state in the --ok / --err / --accent
|
|
522
|
+
// inks (which the day room re-points through --wz-*); raw --sea or a literal white
|
|
523
|
+
// would be the 1.74:1 dark tick this test was first written for.
|
|
524
|
+
assert.equal([...pageSrc.matchAll(/\.prog[^{}]*\{([^}]*)\}/g)].length, 0, 'no .prog rules are left in projects.html');
|
|
525
|
+
const marks = [...pageSrc.matchAll(/\.setFact\.(done|bad|now|you) \.d\{([^}]*)\}/g)];
|
|
526
|
+
assert.ok(marks.length >= 4, 'the four marked fact states are found');
|
|
527
|
+
const bad = marks.filter((m) => /var\(\s*--sea\s*\)|#fff\b/i.test(m[2])).map((m) => m[0].slice(0, 80));
|
|
536
528
|
assert.deepEqual(bad, [], `\n ${bad.join('\n ')}\n`);
|
|
537
529
|
});
|
|
538
530
|
|
|
@@ -82,8 +82,8 @@ function region(startMark, endMark) {
|
|
|
82
82
|
const e = s < 0 ? -1 : SCRIPT.indexOf(endMark, s);
|
|
83
83
|
return s > 0 && e > s ? SCRIPT.slice(s, e) : null;
|
|
84
84
|
}
|
|
85
|
-
const POLLS = region(" /* ── C8: the wizard's polls run only while the create view is on stage",
|
|
86
|
-
const WATCH_VARS = region(' var pollTimer = null;',
|
|
85
|
+
const POLLS = region(" /* ── C8: the wizard's polls run only while the create view is on stage", " /* ── the owner's instance read (task 2083)");
|
|
86
|
+
const WATCH_VARS = region(' var pollTimer = null;', ' function startProgress(id) {');
|
|
87
87
|
const START_PROGRESS = (SCRIPT.match(/ {4}function startProgress\(id\) \{[\s\S]*?\n {4}\}/) || [null])[0];
|
|
88
88
|
const DOORS = region(" /* ── the hub's three doors ── */", ' return { enter: enter, leave: leave, onAuth: onAuth };');
|
|
89
89
|
|
|
@@ -136,7 +136,8 @@ function page({ url, who, storage = 'empty', name = '', hidden = false, instance
|
|
|
136
136
|
renderDone() { log.rendered += 1; }, renderSteps() { log.rendered += 1; },
|
|
137
137
|
resetForNewProject() { log.resets += 1; },
|
|
138
138
|
saveDraft() {},
|
|
139
|
-
|
|
139
|
+
// part 03's facts (task 1004683) are tests/setup_status_facts.mjs; here they only have to exist
|
|
140
|
+
paintFacts() {}, homeFacts: () => [], ghFacts: () => [], setupReady: () => false, hostOk: () => true, addressReady: () => true,
|
|
140
141
|
};
|
|
141
142
|
sandbox.globalThis = sandbox;
|
|
142
143
|
vm.createContext(sandbox);
|
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
// app's OWN key: the creds read back out of a REAL webEnvBody, a JWT that verifies,
|
|
9
9
|
// installed / not installed / cannot tell, device flow on / off / cannot tell, and the
|
|
10
10
|
// tick recording only what GitHub confirmed — never a secret in a log line.
|
|
11
|
-
// 3. the REAL projection (githubSetupRead) run into the REAL page
|
|
12
|
-
// the vm-slice idiom): each server state draws the
|
|
11
|
+
// 3. the REAL projection (githubSetupRead) run into the REAL page facts (projects.html,
|
|
12
|
+
// ghFacts, the vm-slice idiom; task 1004683): each server state draws the fact the founder should see.
|
|
13
13
|
// 4. the device-flow finding is written down where the next builder will look.
|
|
14
14
|
//
|
|
15
15
|
// Run: node --test tests/github_one_trip.mjs
|
|
@@ -185,38 +185,35 @@ test('the window query takes each project\'s LATEST attempt, past placement, sti
|
|
|
185
185
|
assert.match(fs.readFileSync(path.join(ROOT, 'scripts', 'gds', 'provision.js'), 'utf8'), /require\('\.\/provision-github-setup\.js'\)\.verifyGithubAppSetups\(deps\)/, 'it runs on every runner tick, after the conversions');
|
|
186
186
|
});
|
|
187
187
|
|
|
188
|
-
// ── 3. the real projection into the real
|
|
188
|
+
// ── 3. the real projection into the real page facts ─────────────────────────
|
|
189
|
+
// Since task 1004683 part 03 draws FACTS, not checklist markup: ghFacts() is pure over
|
|
190
|
+
// what the reads said, and paintFacts draws it from nodes (tests/setup_status_facts.mjs
|
|
191
|
+
// runs the whole route-to-DOM path). Here: the GitHub half, fed by the real projection.
|
|
189
192
|
|
|
190
|
-
const
|
|
191
|
-
const
|
|
193
|
+
const FS = SCRIPT.indexOf(' function ghStep(key) {');
|
|
194
|
+
const FE = SCRIPT.indexOf(' /* ── drawing it: nodes and textContent only', FS);
|
|
192
195
|
const SS = SCRIPT.indexOf(' /* the checklist the server derived (task 1004649)');
|
|
193
196
|
const SE = SCRIPT.indexOf(' function pollManifest(stateToken) {', SS);
|
|
194
|
-
const PS = SCRIPT.indexOf(' function stepsPaint() {');
|
|
195
|
-
const PE = SCRIPT.indexOf(' (function hopInput()', PS);
|
|
196
197
|
|
|
197
198
|
test('the regions are findable (a rename must fail loudly)', () => {
|
|
198
|
-
assert.ok(
|
|
199
|
+
assert.ok(FS > 0 && FE > FS && SS > 0 && SE > SS);
|
|
200
|
+
assert.match(SCRIPT.slice(FS, FE), /function ghFacts\(now\)/);
|
|
199
201
|
});
|
|
200
202
|
|
|
201
203
|
function page({ manifest, appSlug = null }) {
|
|
202
204
|
const sandbox = {
|
|
203
|
-
live: { manifest, manifestMsg: '', manifestCode: '', manifestFailure: null, appSlug, setup: null, installUrl: null, instStatus: 'active', addrReady: true },
|
|
205
|
+
live: { manifest, manifestMsg: '', manifestCode: '', manifestFailure: null, appSlug, appOrg: null, setup: null, installUrl: null, pickUp: null, verifying: false, askedPlatform: false, instStatus: 'active', addrReady: true, inst: null, readAt: 0, gone: '', repo: null },
|
|
204
206
|
state: { name: 'Mer<cury', slug: 'mercury', owner: 'acme', repo: 'mercury', step: 2 },
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
esc: (x) => String(x).replace(/[&<>"']/g, (c) => ({ '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }[c])),
|
|
208
|
-
GH_ICON: '', manualOauthDetails: () => '', projectPageLink: (t) => t, autoOpenTick: () => '',
|
|
209
|
-
progressMarkup: (a, b, note) => `<prog>${note}</prog>`, encodeURIComponent, JSON, Array,
|
|
207
|
+
resolvedDomain: () => 'mercury.example.com', apexBase: () => 'example.com', addressReady: () => true,
|
|
208
|
+
document: { hidden: false, hasFocus: () => true },
|
|
210
209
|
};
|
|
211
210
|
vm.createContext(sandbox);
|
|
212
|
-
vm.runInContext(`${SCRIPT.slice(
|
|
211
|
+
vm.runInContext(`${SCRIPT.slice(FS, FE)}\n${SCRIPT.slice(SS, SE)}`, sandbox);
|
|
213
212
|
return sandbox;
|
|
214
213
|
}
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
}
|
|
219
|
-
function cls(li) { return ((li.match(/^<li(?: class="([^"]*)")?/) || [])[1] || '').split(/\s+/).filter(Boolean); }
|
|
214
|
+
// vm-born values compared through JSON
|
|
215
|
+
const draw = (sb) => JSON.parse(JSON.stringify(vm.runInContext('ghFacts(Date.now())', sb)));
|
|
216
|
+
const states = (rows) => rows.map((r) => r.state);
|
|
220
217
|
|
|
221
218
|
async function serverSays(status, appSlug, eventRows) {
|
|
222
219
|
const db = { query: async () => ({ rows: eventRows }) };
|
|
@@ -224,55 +221,50 @@ async function serverSays(status, appSlug, eventRows) {
|
|
|
224
221
|
return GS.githubSetupRead(db, { target_ref: 'acme/mercury' }, row, status);
|
|
225
222
|
}
|
|
226
223
|
|
|
227
|
-
test('the mockup\'s four
|
|
228
|
-
const
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
assert.
|
|
232
|
-
assert.
|
|
233
|
-
assert.equal(
|
|
224
|
+
test('the mockup\'s four facts, in its words and order; the typed name is text, never markup', () => {
|
|
225
|
+
const rows = draw(page({ manifest: null }));
|
|
226
|
+
assert.deepEqual(rows.map((r) => r.title), ['Approve the Mer<cury app on GitHub', 'Install it on your repo', 'Builders can sign in', 'Command-line sign-in']);
|
|
227
|
+
assert.deepEqual(rows.map((r) => r.key), ['approve', 'install', 'sign_in', 'device_flow']);
|
|
228
|
+
assert.equal(rows[0].act, 'connect', 'one click starts the one trip, from inside the Approve fact');
|
|
229
|
+
assert.equal(rows[0].state, 'you', 'it is the founder\'s turn');
|
|
230
|
+
assert.equal(rows[3].opt, true, 'command-line sign-in is optional');
|
|
231
|
+
assert.doesNotMatch(SCRIPT.slice(FS, FE), /esc\(|innerHTML/, 'the facts carry text; the painter writes nodes');
|
|
234
232
|
});
|
|
235
233
|
|
|
236
|
-
test('each server state draws the
|
|
234
|
+
test('each server state draws the facts the founder should see — from the REAL projection', async () => {
|
|
237
235
|
// keys placed, nothing verified on GitHub yet
|
|
238
236
|
let sb = page({ manifest: 'converting', appSlug: 'mercury-app' });
|
|
239
237
|
let d = await serverSays('converting', 'mercury-app', []);
|
|
240
|
-
vm.runInContext(`seedSetup(${JSON.stringify(d.checklist)}, ${JSON.stringify(d.install_url)})`, sb);
|
|
238
|
+
vm.runInContext(`seedSetup(${JSON.stringify(d.checklist)}, ${JSON.stringify(d.install_url)}, ${JSON.stringify(d)})`, sb);
|
|
241
239
|
let rows = draw(sb);
|
|
242
|
-
assert.deepEqual(rows
|
|
243
|
-
assert.
|
|
244
|
-
assert.equal(
|
|
240
|
+
assert.deepEqual(states(rows), ['done', 'you', 'now', 'todo']);
|
|
241
|
+
assert.equal(rows[1].href, 'https://github.com/apps/mercury-app/installations/new?state=S1', 'the way back to the install, with the attempt');
|
|
242
|
+
assert.equal(rows[1].sub, 'acme/mercury', 'the repo the server says it installs on');
|
|
243
|
+
assert.equal(rows[1].right, 'not yet seen');
|
|
245
244
|
|
|
246
245
|
// sign-in verified, install still unconfirmed: NOT connected
|
|
247
246
|
sb = page({ manifest: 'done', appSlug: 'mercury-app' });
|
|
248
247
|
d = await serverSays('done', 'mercury-app', []);
|
|
249
|
-
vm.runInContext(`seedSetup(${JSON.stringify(d.checklist)}, ${JSON.stringify(d.install_url)})`, sb);
|
|
248
|
+
vm.runInContext(`seedSetup(${JSON.stringify(d.checklist)}, ${JSON.stringify(d.install_url)}, ${JSON.stringify(d)})`, sb);
|
|
250
249
|
rows = draw(sb);
|
|
251
|
-
assert.deepEqual(rows
|
|
252
|
-
assert.
|
|
250
|
+
assert.deepEqual(states(rows), ['done', 'you', 'done', 'todo']);
|
|
251
|
+
assert.equal(JSON.stringify(rows[3].sub), JSON.stringify(['Turn it on later in ', { t: 'the app settings', href: 'https://github.com/settings/apps/mercury-app' }, '.']));
|
|
253
252
|
assert.equal(vm.runInContext('setupOpen()', sb), true, 'the page keeps watching for the install');
|
|
254
253
|
|
|
255
254
|
// GitHub confirmed the install to the runner: connected, device flow still optional
|
|
256
255
|
sb = page({ manifest: 'done', appSlug: 'mercury-app' });
|
|
257
256
|
d = await serverSays('done', 'mercury-app', [{ event: 'github-app-installed', at: '2026-10-08T10:00:00Z' }]);
|
|
258
|
-
vm.runInContext(`seedSetup(${JSON.stringify(d.checklist)}, ${JSON.stringify(d.install_url)})`, sb);
|
|
257
|
+
vm.runInContext(`seedSetup(${JSON.stringify(d.checklist)}, ${JSON.stringify(d.install_url)}, ${JSON.stringify(d)})`, sb);
|
|
259
258
|
rows = draw(sb);
|
|
260
|
-
assert.deepEqual(rows
|
|
261
|
-
assert.match(rows[1], /The app is on acme\/mercury/);
|
|
259
|
+
assert.deepEqual(states(rows), ['done', 'done', 'done', 'todo']);
|
|
262
260
|
assert.equal(vm.runInContext('setupOpen()', sb), false);
|
|
263
|
-
|
|
264
|
-
const items = rows.map((li) => ({ classList: { contains: (c) => cls(li).includes(c) } }));
|
|
265
|
-
const ghState = { textContent: '' };
|
|
266
|
-
sb.$ = (id) => (id === 'humanSteps' ? { children: items } : id === 'ghState' ? ghState : null);
|
|
267
|
-
sb.manifestInFlight = () => false;
|
|
268
|
-
vm.runInContext('stepsPaint()', sb);
|
|
269
|
-
assert.equal(ghState.textContent, 'connected ✓');
|
|
261
|
+
assert.equal(vm.runInContext('setupCount([], ghFacts(Date.now()))', sb), 'ready ✓', 'the optional fact does not hold the count back');
|
|
270
262
|
|
|
271
263
|
// and once GitHub has device flow on, the fourth ticks too
|
|
272
264
|
sb = page({ manifest: 'done', appSlug: 'mercury-app' });
|
|
273
265
|
d = await serverSays('done', 'mercury-app', [{ event: 'github-app-installed', at: '2026-10-08T10:00:00Z' }, { event: 'github-app-device-flow', at: '2026-10-08T10:05:00Z' }]);
|
|
274
|
-
vm.runInContext(`seedSetup(${JSON.stringify(d.checklist)}, ${JSON.stringify(d.install_url)})`, sb);
|
|
275
|
-
assert.
|
|
266
|
+
vm.runInContext(`seedSetup(${JSON.stringify(d.checklist)}, ${JSON.stringify(d.install_url)}, ${JSON.stringify(d)})`, sb);
|
|
267
|
+
assert.equal(draw(sb)[3].state, 'done');
|
|
276
268
|
});
|
|
277
269
|
|
|
278
270
|
test('seedSetup is change-only, and an install link must be GitHub\'s', () => {
|
|
@@ -286,6 +278,12 @@ test('seedSetup is change-only, and an install link must be GitHub\'s', () => {
|
|
|
286
278
|
vm.runInContext(`seedSetup(${c}, 'javascript:alert(1)')`, sb2);
|
|
287
279
|
assert.equal(vm.runInContext('live.installUrl', sb2), null);
|
|
288
280
|
assert.equal(vm.runInContext('seedSetup(null, null)', sb2), false);
|
|
281
|
+
// the repo it installs on rides the read, strict
|
|
282
|
+
const sb3 = page({ manifest: 'done', appSlug: 'a' });
|
|
283
|
+
vm.runInContext(`seedSetup(${c}, null, { repo: 'acme/mer cury' })`, sb3);
|
|
284
|
+
assert.equal(vm.runInContext('live.repo', sb3), null, 'a malformed repo never reaches the page');
|
|
285
|
+
vm.runInContext(`seedSetup(${c}, null, { repo: 'acme/mercury' })`, sb3);
|
|
286
|
+
assert.equal(vm.runInContext('live.repo', sb3), 'acme/mercury');
|
|
289
287
|
});
|
|
290
288
|
|
|
291
289
|
// ── 4. the finding is written down ──────────────────────────────────────────
|
|
@@ -113,7 +113,7 @@ const PICKER = region(" /* ── whose GitHub account: mine or an organisati
|
|
|
113
113
|
const ENSURE_REPO = region(' function ensureFreshRepo() {', " $('doCreate').addEventListener('click'");
|
|
114
114
|
const NOTE_ORG = region(" /* the organisation the server says this attempt's app is on: change-only */", ' function startManifest(btn) {');
|
|
115
115
|
const START = region(' function startManifest(btn) {', ' /* the "start again" offer once a wait has clearly gone wrong');
|
|
116
|
-
const SETTINGS = region(' /* the organisation that owns the app, when the founder made it on one (task 1004651) */', ' /*
|
|
116
|
+
const SETTINGS = region(' /* the organisation that owns the app, when the founder made it on one (task 1004651) */', ' /* When a fact was seen, said plainly');
|
|
117
117
|
|
|
118
118
|
test('the page regions are still findable (a rename must fail loudly, not test nothing)', () => {
|
|
119
119
|
for (const [name, r] of Object.entries({ PICKER, ENSURE_REPO, NOTE_ORG, START, SETTINGS })) assert.ok(r, `${name} region not found`);
|
|
@@ -165,7 +165,7 @@ function page({ state = {}, live = {} } = {}) {
|
|
|
165
165
|
live: { manifest: null, manifestMsg: '', manifestFailure: null, appSlug: null, appOrg: null, setup: null, installUrl: null, ...live },
|
|
166
166
|
repoAccess: true, instanceId: 42, me: { github_login: 'founder' },
|
|
167
167
|
hopForRepoAccess: () => false, syncHome() {}, saveDraft() {},
|
|
168
|
-
rememberManifest() {},
|
|
168
|
+
rememberManifest() {}, paintFacts() {}, repaintFacts() {}, pollManifest() {}, watchGhTab() {},
|
|
169
169
|
};
|
|
170
170
|
sandbox.manifestStartedAt = 0;
|
|
171
171
|
vm.createContext(sandbox);
|