@bongos/core 1.24.26 → 1.24.28
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 +164 -109
- package/docs/adr/0307-autobongos-a-deterministic-supervisor-and-agentic-workers.md +12 -0
- package/docs/copy-inventory.md +242 -223
- package/docs/copy-registry.json +559 -358
- package/docs/module-api-changelog.md +4 -0
- package/docs/page-inventory.json +18 -6
- package/docs/page-readings.json +4399 -4315
- package/docs/recipes/ui-look-before-you-ship.md +1 -0
- package/modules/autonomy/fence.js +16 -1
- package/modules/government/protected-surfaces.json +2 -0
- package/modules/hall-ui/public/ai-studio.html +1 -1
- package/modules/hall-ui/public/atlas.html +1 -1
- package/modules/hall-ui/public/blockers.html +1 -1
- package/modules/hall-ui/public/board-room.html +1 -1
- package/modules/hall-ui/public/city.html +1 -1
- package/modules/hall-ui/public/collab.html +1 -1
- package/modules/hall-ui/public/commands.html +1 -1
- package/modules/hall-ui/public/copy-desk.html +1 -1
- package/modules/hall-ui/public/core-move-notice.js +9 -6
- package/modules/hall-ui/public/deploy-handoff.js +203 -0
- package/modules/hall-ui/public/deploy.html +4 -2
- package/modules/hall-ui/public/deploy.js +7 -1
- package/modules/hall-ui/public/diagrams.html +1 -1
- package/modules/hall-ui/public/drachmae.html +1 -1
- package/modules/hall-ui/public/fleet.html +1 -1
- package/modules/hall-ui/public/gate.html +1 -1
- package/modules/hall-ui/public/goal-map.html +1 -1
- package/modules/hall-ui/public/goals.html +1 -1
- package/modules/hall-ui/public/government.html +1 -1
- package/modules/hall-ui/public/idea.html +1 -1
- package/modules/hall-ui/public/ideas.html +1 -1
- package/modules/hall-ui/public/index.html +1 -1
- package/modules/hall-ui/public/market-watch-item.html +1 -1
- package/modules/hall-ui/public/market-watch-rules.html +1 -1
- package/modules/hall-ui/public/market-watch-settings.html +1 -1
- package/modules/hall-ui/public/market-watch.html +1 -1
- package/modules/hall-ui/public/modules.html +1 -1
- package/modules/hall-ui/public/my-agents.css +72 -1
- package/modules/hall-ui/public/my-agents.html +31 -7
- package/modules/hall-ui/public/my-agents.js +63 -54
- package/modules/hall-ui/public/my-agents.states.json +18 -0
- package/modules/hall-ui/public/primer.html +1 -1
- package/modules/hall-ui/public/profile.html +1 -1
- package/modules/hall-ui/public/project-settings.html +1 -1
- package/modules/hall-ui/public/ranks.html +1 -1
- package/modules/hall-ui/public/roadmap.html +1 -1
- package/modules/hall-ui/public/roster.html +1 -1
- package/modules/hall-ui/public/sessions.html +1 -1
- package/modules/hall-ui/public/settings-software-update.js +22 -8
- package/modules/hall-ui/public/settings.css +2 -132
- package/modules/hall-ui/public/settings.html +15 -53
- package/modules/hall-ui/public/shell.js +25 -73
- package/modules/hall-ui/public/speciality-tools.css +140 -0
- package/modules/hall-ui/public/{settings-specialities.js → speciality-tools.js} +83 -6
- package/modules/hall-ui/public/street.html +1 -1
- package/modules/hall-ui/public/studio.html +1 -1
- package/modules/hall-ui/public/style.css +119 -39
- package/modules/hall-ui/public/task.html +1 -1
- package/modules/hall-ui/public/thinking.html +1 -1
- package/modules/hall-ui/public/tweak-editor.html +1 -1
- package/modules/hall-ui/public/update-pill.js +623 -0
- package/modules/hall-ui/public/watch.html +1 -1
- package/modules/hall-ui/public/work.html +1 -1
- package/modules/hall-ui/records/my-agents.md +4 -2
- package/modules/hall-ui/records/panel-family.md +2 -0
- package/modules/hall-ui/records/update-pill.md +12 -0
- package/modules/lifecycle/github-push.js +1 -0
- package/modules/lifecycle/routes/tasks.js +2 -2
- package/modules/lifecycle/runner-self-guard.js +122 -0
- package/modules/lifecycle/runner-self.js +154 -0
- package/modules/public-landing/public/account.html +3 -3
- package/modules/public-landing/public/assets/cosmos.css +45 -0
- package/modules/public-landing/public/community.html +4 -4
- package/modules/public-landing/public/connections.html +1 -1
- package/modules/public-landing/public/guild.html +1 -1
- package/modules/public-landing/public/invitations.html +4 -4
- package/modules/public-landing/public/projects.html +26 -26
- package/modules/status-ui/public/index.html +2 -2
- package/modules/status-ui/public/index.states.json +12 -0
- package/modules/status-ui/public/status.js +10 -2
- package/modules/status-ui/public/style.css +57 -0
- package/modules/ui-design/kit/README.md +1 -1
- package/modules/ui-design/kit/serve.js +8 -1
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/release-notes.json +20 -0
- package/scripts/bongos/autobongos-loop.js +4 -0
- package/scripts/bongos/autobongos-run.js +21 -4
- package/scripts/bongos/autobongos-tweak-lane.js +5 -3
- package/scripts/bongos/ship-flow.js +20 -0
- package/scripts/hall-preview/server.js +4 -0
- package/src/module-api.js +1 -1
- package/tests/autobongos_host_access.mjs +5 -3
- package/tests/autobongos_self_modification.mjs +420 -0
- package/tests/core_update_banner.mjs +6 -92
- package/tests/core_upgrade_owner_door.mjs +4 -56
- package/tests/deploy_handoff.mjs +206 -0
- package/tests/government_protected_surfaces.mjs +15 -0
- package/tests/hall_loading.mjs +3 -1
- package/tests/hall_my_agents.mjs +104 -2
- package/tests/helpers.mjs +161 -0
- package/tests/hub_connections_page.mjs +1 -1
- package/tests/hub_invitations_page.mjs +1 -1
- package/tests/loading_mark.mjs +203 -0
- package/tests/nav_permission_atoms.mjs +3 -2
- package/tests/software_update.mjs +6 -2
- package/tests/speciality_offer_ui.mjs +182 -149
- package/tests/speciality_walkthrough_ui.mjs +180 -161
- package/tests/update_pill.mjs +431 -0
|
@@ -157,138 +157,8 @@ select.voices__select { min-width: 140px; }
|
|
|
157
157
|
.settings-btn--discord { background: #5865F2; border-color: #4853c4; color: #ffffff; }
|
|
158
158
|
.settings-btn--discord:hover:not(:disabled) { background: #4853c4; border-color: #4853c4; color: #ffffff; }
|
|
159
159
|
|
|
160
|
-
/*
|
|
161
|
-
|
|
162
|
-
create form. Tokens only — no literal colours, so light/dark follow the page. */
|
|
163
|
-
.speciality-craft {
|
|
164
|
-
font-size: 0.78rem;
|
|
165
|
-
text-transform: lowercase;
|
|
166
|
-
opacity: 0.72;
|
|
167
|
-
margin-left: 0.4rem;
|
|
168
|
-
}
|
|
169
|
-
.speciality-badge {
|
|
170
|
-
font-size: 0.7rem;
|
|
171
|
-
padding: 0.05rem 0.4rem;
|
|
172
|
-
border-radius: 0.5rem;
|
|
173
|
-
margin-left: 0.4rem;
|
|
174
|
-
border: 1px solid currentColor;
|
|
175
|
-
}
|
|
176
|
-
.speciality-counts { opacity: 0.82; }
|
|
177
|
-
.speciality-card { flex-wrap: wrap; }
|
|
178
|
-
.speciality-train,
|
|
179
|
-
.speciality-create {
|
|
180
|
-
flex-basis: 100%;
|
|
181
|
-
margin-top: 0.75rem;
|
|
182
|
-
padding-top: 0.75rem;
|
|
183
|
-
border-top: 1px solid var(--rule, rgba(128, 128, 128, 0.25));
|
|
184
|
-
display: flex;
|
|
185
|
-
flex-direction: column;
|
|
186
|
-
gap: 0.6rem;
|
|
187
|
-
}
|
|
188
|
-
.speciality-create__h { margin: 0; font-size: 0.95rem; }
|
|
189
|
-
.speciality-field { display: flex; flex-direction: column; gap: 0.25rem; }
|
|
190
|
-
.speciality-field > span { font-size: 0.85rem; }
|
|
191
|
-
.speciality-field small { display: block; opacity: 0.7; font-weight: normal; }
|
|
192
|
-
.speciality-field input[type='text'],
|
|
193
|
-
.speciality-field select,
|
|
194
|
-
.speciality-field textarea {
|
|
195
|
-
width: 100%;
|
|
196
|
-
box-sizing: border-box;
|
|
197
|
-
}
|
|
198
|
-
/* The checkbox row reads as one sentence, so it runs inline rather than stacked. */
|
|
199
|
-
.speciality-field--check { flex-direction: row; align-items: flex-start; gap: 0.5rem; }
|
|
200
|
-
.speciality-field--check input { margin-top: 0.2rem; }
|
|
201
|
-
.speciality-actions { display: flex; gap: 0.5rem; }
|
|
202
|
-
/* What a speciality OFFERS (task 1004404): the owner's pick-list of this
|
|
203
|
-
instance's skills, each with its plain line. Sixty-odd rows, so the list
|
|
204
|
-
scrolls inside its own box rather than pushing the form's buttons off-screen;
|
|
205
|
-
the reading lines keep the measure. */
|
|
206
|
-
.speciality-field input[type='search'] { width: 100%; box-sizing: border-box; }
|
|
207
|
-
.speciality-offer,
|
|
208
|
-
.speciality-offer-box { flex-basis: 100%; display: flex; flex-direction: column; gap: 0.6rem; }
|
|
209
|
-
.speciality-offer { margin-top: 0.75rem; padding-top: 0.75rem; border-top: 1px solid var(--rule); }
|
|
210
|
-
.speciality-offer > *, .speciality-offer-box > * { max-width: var(--measure); }
|
|
211
|
-
.speciality-offer-box > summary { cursor: pointer; font-size: 0.85rem; min-height: 24px; padding-block: 2px; box-sizing: border-box; }
|
|
212
|
-
.speciality-offer-box > summary small { opacity: 0.7; }
|
|
213
|
-
.speciality-offer__choices, #speciality-create-skills { display: flex; flex-direction: column; gap: 0.6rem; }
|
|
214
|
-
.speciality-offer__list {
|
|
215
|
-
list-style: none;
|
|
216
|
-
margin: 0;
|
|
217
|
-
padding: 0 0.25rem 0 0;
|
|
218
|
-
display: flex;
|
|
219
|
-
flex-direction: column;
|
|
220
|
-
gap: 0.5rem;
|
|
221
|
-
max-height: 24rem;
|
|
222
|
-
overflow-y: auto;
|
|
223
|
-
overflow-x: hidden;
|
|
224
|
-
}
|
|
225
|
-
.speciality-offer__list li[hidden] { display: none; }
|
|
226
|
-
.speciality-offer__list strong { font-family: var(--font-mono); font-weight: 600; }
|
|
227
|
-
.speciality-offer__list .speciality-field--check > span { font-size: 0.85rem; line-height: 1.45; }
|
|
228
|
-
/* The adopted contract, shown in full before "Use this" — another builder's prose
|
|
229
|
-
reaching your sessions is the one thing here that must never be folded away. */
|
|
230
|
-
.speciality-contract { flex-basis: 100%; margin-top: 0.5rem; font-size: 0.85rem; }
|
|
231
|
-
/* 24px tall: the panel was never revealed until task 1004073, so the kit had
|
|
232
|
-
never measured this toggle; it came back 21px. */
|
|
233
|
-
.speciality-contract > summary { cursor: pointer; opacity: 0.85; min-height: 24px; padding-block: 2px; box-sizing: border-box; }
|
|
234
|
-
.speciality-contract__body {
|
|
235
|
-
white-space: pre-wrap;
|
|
236
|
-
margin: 0.4rem 0 0;
|
|
237
|
-
padding: 0.5rem 0.65rem;
|
|
238
|
-
border-left: 2px solid var(--rule, rgba(128, 128, 128, 0.35));
|
|
239
|
-
border-radius: 0;
|
|
240
|
-
font-family: inherit;
|
|
241
|
-
opacity: 0.92;
|
|
242
|
-
}
|
|
243
|
-
/* The skills walkthrough (task 1004073, ADR 0310 §3): one offered skill at a
|
|
244
|
-
time, three answers as a definition list, then a decision. It sits inside the
|
|
245
|
-
card like the train form, so it inherits the card's ground in both modes. */
|
|
246
|
-
.skill-walk {
|
|
247
|
-
flex-basis: 100%;
|
|
248
|
-
margin-top: 0.75rem;
|
|
249
|
-
padding-top: 0.75rem;
|
|
250
|
-
border-top: 1px solid var(--rule);
|
|
251
|
-
display: flex;
|
|
252
|
-
flex-direction: column;
|
|
253
|
-
gap: 0.6rem;
|
|
254
|
-
}
|
|
255
|
-
/* The measure caps the reading lines, never the section: a capped flex-basis
|
|
256
|
-
lets the section fit beside the card's actions instead of wrapping under them. */
|
|
257
|
-
.skill-walk > * { max-width: var(--measure); }
|
|
258
|
-
.skill-walk__progress { margin: 0; font-size: 0.8rem; color: var(--ink-soft); }
|
|
259
|
-
.skill-walk__name { margin: 0; font-family: var(--font-mono); font-size: 1rem; color: var(--ink); }
|
|
260
|
-
.skill-walk__facts { margin: 0; display: grid; gap: 0.2rem 0; }
|
|
261
|
-
.skill-walk__facts dt { font-size: 0.8rem; color: var(--ink-soft); margin-top: 0.4rem; }
|
|
262
|
-
.skill-walk__facts dt:first-child { margin-top: 0; }
|
|
263
|
-
.skill-walk__facts dd { margin: 0; color: var(--ink); line-height: 1.5; }
|
|
264
|
-
.skill-walk__note { font-size: 0.8rem; }
|
|
265
|
-
/* "Leave it off" and "Turn it on" are the panel family's plain pill at EQUAL
|
|
266
|
-
weight: the default is off, so the page must not lean on the reader toward on.
|
|
267
|
-
Only "Save my choices" takes the accent. A decision already made reads through
|
|
268
|
-
aria-pressed when the person steps Back to it. */
|
|
269
|
-
.skill-walk__actions { flex-wrap: wrap; }
|
|
270
|
-
.skill-walk__actions .pbtn[aria-pressed="true"] { border-color: var(--ink-soft); }
|
|
271
|
-
.skill-walk__recap { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0.5rem; }
|
|
272
|
-
.skill-walk__recap li { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0 0.4rem; }
|
|
273
|
-
.skill-walk__recap .prow__hint { flex-basis: 100%; margin: 0; }
|
|
274
|
-
.skill-walk__recap strong { font-family: var(--font-mono); font-weight: 600; }
|
|
275
|
-
/* "Finish later" is a way out, not a choice about a skill, so it reads as a quiet
|
|
276
|
-
link below the decision rather than a third button beside it. */
|
|
277
|
-
.skill-walk__later {
|
|
278
|
-
align-self: flex-start;
|
|
279
|
-
background: none;
|
|
280
|
-
border: 0;
|
|
281
|
-
padding: 0 0.25rem;
|
|
282
|
-
margin-inline-start: -0.25rem;
|
|
283
|
-
min-height: 24px;
|
|
284
|
-
font: inherit;
|
|
285
|
-
font-size: 0.8rem;
|
|
286
|
-
color: var(--ink-soft);
|
|
287
|
-
text-decoration: underline;
|
|
288
|
-
text-underline-offset: 3px;
|
|
289
|
-
cursor: pointer;
|
|
290
|
-
}
|
|
291
|
-
.skill-walk__later:hover { color: var(--ink); }
|
|
160
|
+
/* The specialities panel's rules moved to speciality-tools.css (task 1005052),
|
|
161
|
+
which Settings links right after this sheet and My agents links too. */
|
|
292
162
|
|
|
293
163
|
/* ---- Software update (task 1004296) -------------------------------------- */
|
|
294
164
|
/* A version is read digit by digit and compared against another, so it takes the mono
|
|
@@ -18,6 +18,8 @@
|
|
|
18
18
|
has — the rail layout, the group head, the token ladder, the voices grid. -->
|
|
19
19
|
<link rel="stylesheet" href="/builders/panel.css">
|
|
20
20
|
<link rel="stylesheet" href="/builders/settings.css">
|
|
21
|
+
<!-- the speciality tools sheet (task 1005052), shared with My agents -->
|
|
22
|
+
<link rel="stylesheet" href="/builders/speciality-tools.css">
|
|
21
23
|
</head>
|
|
22
24
|
<body data-page="settings" data-page-title="Settings">
|
|
23
25
|
|
|
@@ -305,53 +307,9 @@
|
|
|
305
307
|
<div id="speciality-suggestions"></div>
|
|
306
308
|
<ul class="prows" id="specialities-rows"></ul>
|
|
307
309
|
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
<span>Name</span>
|
|
312
|
-
<input type="text" name="name" maxlength="80" required placeholder="Economics" />
|
|
313
|
-
</label>
|
|
314
|
-
<label class="speciality-field">
|
|
315
|
-
<span>Role it sits under</span>
|
|
316
|
-
<select name="discipline" required>
|
|
317
|
-
<option value="">Pick one…</option>
|
|
318
|
-
<option value="engineer">Engineer</option>
|
|
319
|
-
<option value="ideator">Ideator</option>
|
|
320
|
-
<option value="artist">Artist</option>
|
|
321
|
-
<option value="ui">UI design</option>
|
|
322
|
-
</select>
|
|
323
|
-
</label>
|
|
324
|
-
<label class="speciality-field">
|
|
325
|
-
<span>Summary <small>(optional)</small></span>
|
|
326
|
-
<input type="text" name="summary" maxlength="500" placeholder="Markets, incentives, and how to price them." />
|
|
327
|
-
</label>
|
|
328
|
-
<label class="speciality-field">
|
|
329
|
-
<span>How Claude should engage you in it <small>(optional)</small></span>
|
|
330
|
-
<textarea name="contract_md" rows="4" maxlength="4000" placeholder="Argue from mechanism, not vibes. Always name the assumption a number rests on."></textarea>
|
|
331
|
-
</label>
|
|
332
|
-
<label class="speciality-field">
|
|
333
|
-
<span>Who can use it</span>
|
|
334
|
-
<select name="visibility">
|
|
335
|
-
<option value="private">Only me</option>
|
|
336
|
-
<option value="project">Anyone in the owning project</option>
|
|
337
|
-
<option value="public">Anyone on this instance</option>
|
|
338
|
-
</select>
|
|
339
|
-
</label>
|
|
340
|
-
<label class="speciality-field speciality-field--check">
|
|
341
|
-
<input type="checkbox" name="sellable" />
|
|
342
|
-
<span>
|
|
343
|
-
May be offered for sale later
|
|
344
|
-
<small>Records your decision only — there is no marketplace yet, and nothing is listed anywhere.</small>
|
|
345
|
-
</span>
|
|
346
|
-
</label>
|
|
347
|
-
<details id="speciality-create-offer" class="speciality-offer-box">
|
|
348
|
-
<summary>Skills it offers <small>(optional)</small></summary>
|
|
349
|
-
<div id="speciality-create-skills"><p class="hall-loading hall-loading--inline" role="status">Loading this project’s skills…</p></div>
|
|
350
|
-
</details>
|
|
351
|
-
<div class="speciality-actions">
|
|
352
|
-
<button type="submit" class="btn">Create speciality</button>
|
|
353
|
-
</div>
|
|
354
|
-
</form>
|
|
310
|
+
<!-- The create form is rendered by speciality-tools.js (task 1005052), the
|
|
311
|
+
one copy Settings and My agents share; this is only its host. -->
|
|
312
|
+
<form id="speciality-create" class="speciality-create"></form>
|
|
355
313
|
|
|
356
314
|
<p class="settings-status" id="specialities-status" role="status" aria-live="polite"></p>
|
|
357
315
|
</section>
|
|
@@ -475,9 +433,9 @@
|
|
|
475
433
|
<!-- SOFTWARE UPDATE — this project's version, the newest release its update
|
|
476
434
|
channel allows, and what the versions between them carry (task 1004296).
|
|
477
435
|
Like a phone's Software Update screen: every builder reads it; the Update
|
|
478
|
-
button is drawn only for those the upgrade door lets through, and it
|
|
479
|
-
|
|
480
|
-
|
|
436
|
+
button is drawn only for those the upgrade door lets through, and it runs
|
|
437
|
+
the Update pill's in-place flow (update-pill.js, task 1005041): the act is
|
|
438
|
+
still the door's, with its auto-rollback (ADR 0293). Rendered by settings-software-update.js
|
|
481
439
|
from GET /api/bongos/software-update, read only when this group opens:
|
|
482
440
|
an update's notes come out of a package download. -->
|
|
483
441
|
<section class="scroll" id="software-update-scroll" aria-labelledby="software-update-h" data-group="update" hidden>
|
|
@@ -514,7 +472,7 @@
|
|
|
514
472
|
<script src="/builders/dom-utils.js?v=2026-10-25-escape"></script>
|
|
515
473
|
<script src="/builders/shell-trail.js?v=2026-10-08-city-tab"></script>
|
|
516
474
|
<script src="/builders/craft-mode.js?v=2026-10-30-market-watch"></script>
|
|
517
|
-
<script src="/builders/shell.js?v=2026-
|
|
475
|
+
<script src="/builders/shell.js?v=2026-11-03-update-pill"></script>
|
|
518
476
|
<!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
|
|
519
477
|
<script src="/builders/palette.js" defer></script>
|
|
520
478
|
<!-- shared component kit (window.OTBKit) — section rail (task 2166). -->
|
|
@@ -534,13 +492,17 @@
|
|
|
534
492
|
the same precedent and for the same reason — settings.js is against the
|
|
535
493
|
1500-line ratchet, and this panel shares nothing with the rest of the page. -->
|
|
536
494
|
<script src="/builders/settings-interaction.js?v=2026-10-17-laws"></script>
|
|
537
|
-
|
|
495
|
+
<!-- task 1005052: the speciality tools are ONE component Settings and My agents
|
|
496
|
+
both mount (it was settings-specialities.js). Task 1005044 removes this mount. -->
|
|
497
|
+
<script src="/builders/speciality-tools.js?v=2026-11-03-shared"></script>
|
|
538
498
|
<!-- task 1002518: the card-richness ladder. Own file on the same precedent —
|
|
539
499
|
the panel grew from one switch to a rung picker with a derived default, and
|
|
540
500
|
settings.js is against the 1500-line ratchet. -->
|
|
541
501
|
<script src="/builders/settings-render.js?v=2026-09-16-render-levels"></script>
|
|
542
502
|
<!-- task 1004296: Settings → Software update. Own file on the same precedent. -->
|
|
543
|
-
|
|
503
|
+
<!-- the Update pill's flow, which the panel's Update button runs in place (task 1005041) -->
|
|
504
|
+
<script src="/builders/update-pill.js?v=2026-11-03-pill"></script>
|
|
505
|
+
<script src="/builders/settings-software-update.js?v=2026-11-03-pill"></script>
|
|
544
506
|
<!-- task 1004501: Settings → Your Autobongos runner. Own file on the same precedent. -->
|
|
545
507
|
<script src="/builders/settings-autobongos.js?v=2026-10-01-autobongos"></script>
|
|
546
508
|
<!-- task 1003793: Settings → Module install reports. Own file on the same precedent. -->
|
|
@@ -751,8 +751,11 @@
|
|
|
751
751
|
history.replaceState(null, '', window.location.pathname + rest + window.location.hash);
|
|
752
752
|
}
|
|
753
753
|
|
|
754
|
-
// task 1004045 — the
|
|
755
|
-
//
|
|
754
|
+
// task 1004045 → task 1005041 — the Update pill. The owner's first ask was a banner at the top
|
|
755
|
+
// of every owner's hall when a core update is released; the second (2026-11-03) was that it
|
|
756
|
+
// was "way too obstructing and not obvious what to do", and should feel like the Claude
|
|
757
|
+
// app's "restart to update". So the news is a quiet pill in the top bar now, and the
|
|
758
|
+
// update is taken in place from it: update-pill.js owns all of it, this only asks.
|
|
756
759
|
//
|
|
757
760
|
// WHY THE SERVER IS ASKED RATHER THAN TOLD. The version this box runs is known
|
|
758
761
|
// here, but what is PUBLISHED is not, and the fact lives behind an outbound
|
|
@@ -764,6 +767,11 @@
|
|
|
764
767
|
// ASKED ONCE PER PAGE LOAD. applyAccess runs on every settle (the /me probe, a
|
|
765
768
|
// page's own report), and re-firing a network call on each would be a request per
|
|
766
769
|
// nav interaction for a fact with a six-hour life on the server.
|
|
770
|
+
//
|
|
771
|
+
// SAID FROM AN ANSWER, OR FROM AN UPDATE ALREADY UNDER WAY. The pill script loads only
|
|
772
|
+
// when the answer has something to say (behind, held, or just moved), or when this
|
|
773
|
+
// browser remembers an update it started: mid-restart the read itself may fail, and the
|
|
774
|
+
// pill must still follow the owner from page to page.
|
|
767
775
|
var coreUpdateAsked = false;
|
|
768
776
|
function maybeRenderCoreUpdate() {
|
|
769
777
|
if (coreUpdateAsked) return;
|
|
@@ -771,10 +779,20 @@
|
|
|
771
779
|
if (!perms || perms['core.pin.move'] !== true) return;
|
|
772
780
|
coreUpdateAsked = true;
|
|
773
781
|
api.request('GET', '/api/bongos/core-update').then(function (res) {
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
782
|
+
mountUpdatePill(res && res.status === 200 && res.data ? res.data : null);
|
|
783
|
+
}, function () { mountUpdatePill(null); });
|
|
784
|
+
}
|
|
785
|
+
function updateUnderWay() {
|
|
786
|
+
try { return !!(window.localStorage && window.localStorage.getItem('bongos.update.run')); } catch (e) { return false; }
|
|
787
|
+
}
|
|
788
|
+
function mountUpdatePill(data) {
|
|
789
|
+
var u = data && data.update;
|
|
790
|
+
var news = !!(u && u.reading === 'ok' && u.behind) || !!(data && data.held);
|
|
791
|
+
if (news || updateUnderWay()) {
|
|
792
|
+
var go = function () { if (window.OTBUpdatePill) window.OTBUpdatePill.mount(data, { api: api }); };
|
|
793
|
+
if (window.OTBUpdatePill) go(); else loadHallScript('update-pill.js', go);
|
|
794
|
+
}
|
|
795
|
+
if (data && data.moved) renderCoreMoveNotice(data.moved); // task 1004731: loads core-move-notice.js, which draws it
|
|
778
796
|
}
|
|
779
797
|
// One hall script on demand, stamped with the shell's own ?v= (task 1004996 made it one helper).
|
|
780
798
|
function loadHallScript(file, onload, onerror) {
|
|
@@ -785,7 +803,7 @@
|
|
|
785
803
|
head.appendChild(tag);
|
|
786
804
|
}
|
|
787
805
|
function renderCoreMoveNotice(moved) {
|
|
788
|
-
loadHallScript('core-move-notice.js', function () { if (window.CoreMoveNotice) window.CoreMoveNotice.render(moved, { api: api, href:
|
|
806
|
+
loadHallScript('core-move-notice.js', function () { if (window.CoreMoveNotice) window.CoreMoveNotice.render(moved, { api: api, href: '/settings#software-update' }); });
|
|
789
807
|
}
|
|
790
808
|
var githubChipAsked = false; // task 1004996: the Link GitHub chip (github-chip.js), asked once a page
|
|
791
809
|
function loadGithubChip(builder) {
|
|
@@ -795,72 +813,6 @@
|
|
|
795
813
|
loadHallScript('github-chip.js', function () { if (window.OTBGithubChip) window.OTBGithubChip.mount({ api: api, builder: builder, hub: hub }); });
|
|
796
814
|
}
|
|
797
815
|
|
|
798
|
-
// Where the banner's Upgrade goes (task 1004296). The platform's hall runs the deploy
|
|
799
|
-
// door itself, so there it is /deploy. Every other hall — a hosted project, a
|
|
800
|
-
// self-hosted instance — takes its update from Settings → Software update, which says
|
|
801
|
-
// what the update carries and, on a hosted project, hands the owner to the hub's door
|
|
802
|
-
// for this project (ADR 0339 D3). The banner no longer links off-site itself.
|
|
803
|
-
var SOFTWARE_UPDATE_HREF = '/settings#software-update';
|
|
804
|
-
|
|
805
|
-
// SAY NOTHING WHEN THERE IS NOTHING TO SAY. `behind` is false both when the box
|
|
806
|
-
// is current AND when the registry could not be read; `reading` separates them,
|
|
807
|
-
// and neither renders. A banner is a claim about being out of date, and a wrong
|
|
808
|
-
// one on a project that is actually current is worse than silence.
|
|
809
|
-
function renderCoreUpdateBanner(update, held) {
|
|
810
|
-
if (!update || update.reading !== 'ok' || !update.behind || !update.latest) return;
|
|
811
|
-
// A dismissal is remembered PER VERSION, not forever: the next release is new
|
|
812
|
-
// news and must re-announce itself, or the surface is dead after one click.
|
|
813
|
-
// localStorage throws in a private window and is absent in the unit tests' bare
|
|
814
|
-
// vm context, so every touch is guarded and its loss only costs the memory.
|
|
815
|
-
try {
|
|
816
|
-
var seen = window.localStorage && window.localStorage.getItem('bongos.coreUpdate.dismissed');
|
|
817
|
-
if (seen && seen === update.latest) return;
|
|
818
|
-
} catch (e) { /* no storage: always show */ }
|
|
819
|
-
var topbar = document.getElementById('app-topbar');
|
|
820
|
-
if (!topbar) return;
|
|
821
|
-
var el = document.createElement('div');
|
|
822
|
-
el.className = 'core-update-notice';
|
|
823
|
-
el.id = 'core-update-notice';
|
|
824
|
-
el.setAttribute('role', 'status');
|
|
825
|
-
// The action goes where the update can actually be taken. The deploy door is the
|
|
826
|
-
// provisioning module's, and a hosted project does NOT run that module (probed:
|
|
827
|
-
// /api/bongos/provisioning/health is 404 on a tenant, 200 on the platform) — so on
|
|
828
|
-
// those it goes to Settings → Software update (SOFTWARE_UPDATE_HREF above).
|
|
829
|
-
// NOT A LINK TO THE PAGE YOU ARE ALREADY ON (task 1004145). This reads as the action
|
|
830
|
-
// button — it is labelled with the verb and styled like one — but it is a plain
|
|
831
|
-
// navigation to /deploy. On /deploy itself that is a no-op, and the owner who
|
|
832
|
-
// pressed it there reasonably reported "I clicked update, but I didn't see anything
|
|
833
|
-
// happen": nothing had, and nothing had been asked for. The control is on that page
|
|
834
|
-
// already, so on it the banner informs and points, and does not pretend to act.
|
|
835
|
-
// The same rule on Settings → Software update: that panel IS the control there.
|
|
836
|
-
var here = window.location ? String(window.location.pathname || '').replace(/\/+$/, '') : '';
|
|
837
|
-
var onDeploy = here === '/deploy';
|
|
838
|
-
var onUpdatePanel = here === '/settings' && String(window.location.hash || '') === '#software-update';
|
|
839
|
-
var action = moduleOn('provisioning')
|
|
840
|
-
? (onDeploy
|
|
841
|
-
? '<span class="core-update-notice__hint">Use the control below to take it.</span>'
|
|
842
|
-
: '<a class="core-update-notice__action" href="/deploy">Upgrade</a>')
|
|
843
|
-
: (onUpdatePanel
|
|
844
|
-
? '<span class="core-update-notice__hint">Its details are below.</span>'
|
|
845
|
-
: '<a class="core-update-notice__action" href="' + SOFTWARE_UPDATE_HREF + '">Upgrade</a>');
|
|
846
|
-
// task 1004730: the newest version already failed here and was rolled back. Say so, never
|
|
847
|
-
// "available" with a button to take it again; Software update carries the full sentence.
|
|
848
|
-
var hold = held && held.version === update.latest ? held : null;
|
|
849
|
-
el.innerHTML = (hold
|
|
850
|
-
? '<span>Core <strong>' + esc(hold.version) + '</strong> was tried on this project and rolled back. It is still on ' +
|
|
851
|
-
esc(hold.still_on) + ' and working.</span><a class="core-update-notice__action" href="' + SOFTWARE_UPDATE_HREF + '">Details</a>'
|
|
852
|
-
: '<span>Core <strong>' + esc(update.latest) + '</strong> is available — this project runs ' +
|
|
853
|
-
esc(update.running || 'an unknown version') + '.</span>' + action) +
|
|
854
|
-
'<button type="button" class="core-update-notice__close" aria-label="Dismiss">×</button>';
|
|
855
|
-
el.querySelector('.core-update-notice__close').addEventListener('click', function () {
|
|
856
|
-
try {
|
|
857
|
-
if (window.localStorage) window.localStorage.setItem('bongos.coreUpdate.dismissed', update.latest);
|
|
858
|
-
} catch (e) { /* dismissal is best-effort */ }
|
|
859
|
-
el.remove();
|
|
860
|
-
});
|
|
861
|
-
topbar.insertAdjacentElement('afterend', el);
|
|
862
|
-
}
|
|
863
|
-
|
|
864
816
|
// task 1003303: the skip link, rendered once here rather than pasted into 27
|
|
865
817
|
// heads. The hall had none, which is a platform floor (DESIGN.md
|
|
866
818
|
// §Accessibility Floors) and, with the sidebar first in the DOM, meant a
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/* speciality-tools.css — the SPECIALITY TOOLS sheet (task 1005052): the structural
|
|
2
|
+
rules of the one component Settings and My agents both mount
|
|
3
|
+
(speciality-tools.js) — the card, the train, offer and create forms, the
|
|
4
|
+
instructions block and the skills walkthrough. Moved out of settings.css
|
|
5
|
+
verbatim, so Settings draws exactly as it did; each page sheet adds its own
|
|
6
|
+
look on top (Settings: panel.css, linked before this; My agents: the `.ma-know`
|
|
7
|
+
skin in my-agents.css, linked after). */
|
|
8
|
+
|
|
9
|
+
/* Specialities panel (task 1003855, ADR 0296). A speciality is a named bundle of
|
|
10
|
+
knowledge and terms under a craft; this styles the list, the train form and the
|
|
11
|
+
create form. Tokens only — no literal colours, so light/dark follow the page. */
|
|
12
|
+
.speciality-craft {
|
|
13
|
+
font-size: 0.78rem;
|
|
14
|
+
text-transform: lowercase;
|
|
15
|
+
opacity: 0.72;
|
|
16
|
+
margin-left: 0.4rem;
|
|
17
|
+
}
|
|
18
|
+
.speciality-badge {
|
|
19
|
+
font-size: 0.7rem;
|
|
20
|
+
padding: 0.05rem 0.4rem;
|
|
21
|
+
border-radius: 0.5rem;
|
|
22
|
+
margin-left: 0.4rem;
|
|
23
|
+
border: 1px solid currentColor;
|
|
24
|
+
}
|
|
25
|
+
.speciality-counts { opacity: 0.82; }
|
|
26
|
+
.speciality-card { flex-wrap: wrap; }
|
|
27
|
+
.speciality-train,
|
|
28
|
+
.speciality-create {
|
|
29
|
+
flex-basis: 100%;
|
|
30
|
+
margin-top: 0.75rem;
|
|
31
|
+
padding-top: 0.75rem;
|
|
32
|
+
border-top: 1px solid var(--rule, rgba(128, 128, 128, 0.25));
|
|
33
|
+
display: flex;
|
|
34
|
+
flex-direction: column;
|
|
35
|
+
gap: 0.6rem;
|
|
36
|
+
}
|
|
37
|
+
.speciality-create__h { margin: 0; font-size: 0.95rem; }
|
|
38
|
+
.speciality-field { display: flex; flex-direction: column; gap: 0.25rem; }
|
|
39
|
+
.speciality-field > span { font-size: 0.85rem; }
|
|
40
|
+
.speciality-field small { display: block; opacity: 0.7; font-weight: normal; }
|
|
41
|
+
.speciality-field input[type='text'],
|
|
42
|
+
.speciality-field select,
|
|
43
|
+
.speciality-field textarea {
|
|
44
|
+
width: 100%;
|
|
45
|
+
box-sizing: border-box;
|
|
46
|
+
}
|
|
47
|
+
/* The checkbox row reads as one sentence, so it runs inline rather than stacked. */
|
|
48
|
+
.speciality-field--check { flex-direction: row; align-items: flex-start; gap: 0.5rem; }
|
|
49
|
+
.speciality-field--check input { margin-top: 0.2rem; }
|
|
50
|
+
.speciality-actions { display: flex; gap: 0.5rem; }
|
|
51
|
+
/* What a speciality OFFERS (task 1004404): the owner's pick-list of this
|
|
52
|
+
instance's skills, each with its plain line. Sixty-odd rows, so the list
|
|
53
|
+
scrolls inside its own box rather than pushing the form's buttons off-screen;
|
|
54
|
+
the reading lines keep the measure. */
|
|
55
|
+
.speciality-field input[type='search'] { width: 100%; box-sizing: border-box; }
|
|
56
|
+
.speciality-offer,
|
|
57
|
+
.speciality-offer-box { flex-basis: 100%; display: flex; flex-direction: column; gap: 0.6rem; }
|
|
58
|
+
.speciality-offer { margin-top: 0.75rem; padding-top: 0.75rem; border-top: 1px solid var(--rule); }
|
|
59
|
+
.speciality-offer > *, .speciality-offer-box > * { max-width: var(--measure); }
|
|
60
|
+
.speciality-offer-box > summary { cursor: pointer; font-size: 0.85rem; min-height: 24px; padding-block: 2px; box-sizing: border-box; }
|
|
61
|
+
.speciality-offer-box > summary small { opacity: 0.7; }
|
|
62
|
+
.speciality-offer__choices, #speciality-create-skills { display: flex; flex-direction: column; gap: 0.6rem; }
|
|
63
|
+
.speciality-offer__list {
|
|
64
|
+
list-style: none;
|
|
65
|
+
margin: 0;
|
|
66
|
+
padding: 0 0.25rem 0 0;
|
|
67
|
+
display: flex;
|
|
68
|
+
flex-direction: column;
|
|
69
|
+
gap: 0.5rem;
|
|
70
|
+
max-height: 24rem;
|
|
71
|
+
overflow-y: auto;
|
|
72
|
+
overflow-x: hidden;
|
|
73
|
+
}
|
|
74
|
+
.speciality-offer__list li[hidden] { display: none; }
|
|
75
|
+
.speciality-offer__list strong { font-family: var(--font-mono); font-weight: 600; }
|
|
76
|
+
.speciality-offer__list .speciality-field--check > span { font-size: 0.85rem; line-height: 1.45; }
|
|
77
|
+
/* The adopted contract, shown in full before "Use this" — another builder's prose
|
|
78
|
+
reaching your sessions is the one thing here that must never be folded away. */
|
|
79
|
+
.speciality-contract { flex-basis: 100%; margin-top: 0.5rem; font-size: 0.85rem; }
|
|
80
|
+
/* 24px tall: the panel was never revealed until task 1004073, so the kit had
|
|
81
|
+
never measured this toggle; it came back 21px. */
|
|
82
|
+
.speciality-contract > summary { cursor: pointer; opacity: 0.85; min-height: 24px; padding-block: 2px; box-sizing: border-box; }
|
|
83
|
+
.speciality-contract__body {
|
|
84
|
+
white-space: pre-wrap;
|
|
85
|
+
margin: 0.4rem 0 0;
|
|
86
|
+
padding: 0.5rem 0.65rem;
|
|
87
|
+
border-left: 2px solid var(--rule, rgba(128, 128, 128, 0.35));
|
|
88
|
+
border-radius: 0;
|
|
89
|
+
font-family: inherit;
|
|
90
|
+
opacity: 0.92;
|
|
91
|
+
}
|
|
92
|
+
/* The skills walkthrough (task 1004073, ADR 0310 §3): one offered skill at a
|
|
93
|
+
time, three answers as a definition list, then a decision. It sits inside the
|
|
94
|
+
card like the train form, so it inherits the card's ground in both modes. */
|
|
95
|
+
.skill-walk {
|
|
96
|
+
flex-basis: 100%;
|
|
97
|
+
margin-top: 0.75rem;
|
|
98
|
+
padding-top: 0.75rem;
|
|
99
|
+
border-top: 1px solid var(--rule);
|
|
100
|
+
display: flex;
|
|
101
|
+
flex-direction: column;
|
|
102
|
+
gap: 0.6rem;
|
|
103
|
+
}
|
|
104
|
+
/* The measure caps the reading lines, never the section: a capped flex-basis
|
|
105
|
+
lets the section fit beside the card's actions instead of wrapping under them. */
|
|
106
|
+
.skill-walk > * { max-width: var(--measure); }
|
|
107
|
+
.skill-walk__progress { margin: 0; font-size: 0.8rem; color: var(--ink-soft); }
|
|
108
|
+
.skill-walk__name { margin: 0; font-family: var(--font-mono); font-size: 1rem; color: var(--ink); }
|
|
109
|
+
.skill-walk__facts { margin: 0; display: grid; gap: 0.2rem 0; }
|
|
110
|
+
.skill-walk__facts dt { font-size: 0.8rem; color: var(--ink-soft); margin-top: 0.4rem; }
|
|
111
|
+
.skill-walk__facts dt:first-child { margin-top: 0; }
|
|
112
|
+
.skill-walk__facts dd { margin: 0; color: var(--ink); line-height: 1.5; }
|
|
113
|
+
.skill-walk__note { font-size: 0.8rem; }
|
|
114
|
+
/* "Leave it off" and "Turn it on" are the panel family's plain pill at EQUAL
|
|
115
|
+
weight: the default is off, so the page must not lean on the reader toward on.
|
|
116
|
+
Only "Save my choices" takes the accent. A decision already made reads through
|
|
117
|
+
aria-pressed when the person steps Back to it. */
|
|
118
|
+
.skill-walk__actions { flex-wrap: wrap; }
|
|
119
|
+
.skill-walk__actions .pbtn[aria-pressed="true"] { border-color: var(--ink-soft); }
|
|
120
|
+
.skill-walk__recap { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0.5rem; }
|
|
121
|
+
.skill-walk__recap li { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0 0.4rem; }
|
|
122
|
+
.skill-walk__recap .prow__hint { flex-basis: 100%; margin: 0; }
|
|
123
|
+
.skill-walk__recap strong { font-family: var(--font-mono); font-weight: 600; }
|
|
124
|
+
/* "Finish later" is a way out, not a choice about a skill, so it reads as a quiet
|
|
125
|
+
link below the decision rather than a third button beside it. */
|
|
126
|
+
.skill-walk__later {
|
|
127
|
+
align-self: flex-start;
|
|
128
|
+
background: none;
|
|
129
|
+
border: 0;
|
|
130
|
+
padding: 0 0.25rem;
|
|
131
|
+
margin-inline-start: -0.25rem;
|
|
132
|
+
min-height: 24px;
|
|
133
|
+
font: inherit;
|
|
134
|
+
font-size: 0.8rem;
|
|
135
|
+
color: var(--ink-soft);
|
|
136
|
+
text-decoration: underline;
|
|
137
|
+
text-underline-offset: 3px;
|
|
138
|
+
cursor: pointer;
|
|
139
|
+
}
|
|
140
|
+
.skill-walk__later:hover { color: var(--ink); }
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
// modules/hall-ui/public/
|
|
2
|
-
//
|
|
1
|
+
// modules/hall-ui/public/speciality-tools.js — THE SPECIALITY TOOLS, one component
|
|
2
|
+
// mounted by two pages: Settings' "Your specialities" panel (task 1003855; ADR
|
|
3
|
+
// 0296) and My agents' "What it knows" section (task 1005052).
|
|
3
4
|
//
|
|
4
5
|
// WHAT A SPECIALITY IS, for anyone reading this file first: a craft says HOW you
|
|
5
6
|
// work (engineer / ideator / artist / ui); a speciality says what you work ON and
|
|
@@ -7,10 +8,21 @@
|
|
|
7
8
|
// contract you write here is injected into every session where you hold a claim
|
|
8
9
|
// in that craft.
|
|
9
10
|
//
|
|
10
|
-
//
|
|
11
|
-
//
|
|
12
|
-
//
|
|
13
|
-
//
|
|
11
|
+
// ONE COMPONENT, TWO MOUNTS (task 1005052). This was settings-specialities.js;
|
|
12
|
+
// it was carved out so My agents gets every tool Settings has without a second
|
|
13
|
+
// copy. A page mounts it by carrying the hosts, by id, inside one section:
|
|
14
|
+
// #specialities-scroll the section (ships `hidden`; revealed by load())
|
|
15
|
+
// #speciality-suggestions what the project suggests
|
|
16
|
+
// #specialities-rows the catalogue, one card per speciality (a <ul>)
|
|
17
|
+
// #speciality-create an EMPTY <form>: createFormHtml() below fills it,
|
|
18
|
+
// so the create form's markup exists once, here
|
|
19
|
+
// #specialities-status the status line
|
|
20
|
+
// Nothing else is page-specific: each page's own sheet draws the same markup in
|
|
21
|
+
// its own look (Settings through panel.css, My agents through my-agents.css's
|
|
22
|
+
// `.ma-know` skin; the structural rules are speciality-tools.css). Task 1005044
|
|
23
|
+
// removes the Settings mount (its section and this file's script tag); the code
|
|
24
|
+
// stays. Self-contained — it shares nothing with either page but `window.OTB`,
|
|
25
|
+
// loaded before it, and one DOM event it dispatches (changed(), below).
|
|
14
26
|
//
|
|
15
27
|
// TRAINING IS TWO-FOLD, and only half of it is visible here. Documents you add are
|
|
16
28
|
// the half you drive; the other half accumulates on its own from learnings captured
|
|
@@ -33,6 +45,13 @@
|
|
|
33
45
|
const el = (id) => document.getElementById(id);
|
|
34
46
|
const statusLine = (msg) => { const s = el('specialities-status'); if (s) s.textContent = msg || ''; };
|
|
35
47
|
|
|
48
|
+
// What a session is sent just moved (an adopt, a stop, a skills save): say so,
|
|
49
|
+
// so a page that shows it can read it again. My agents' "What your agent reads
|
|
50
|
+
// first" listens (task 1005052); Settings does not, and nothing here waits on it.
|
|
51
|
+
function changed() {
|
|
52
|
+
if (typeof CustomEvent === 'function' && document.dispatchEvent) document.dispatchEvent(new CustomEvent('otb:specialities-changed'));
|
|
53
|
+
}
|
|
54
|
+
|
|
36
55
|
async function call(method, path, body) {
|
|
37
56
|
const res = await fetch(`${API}${path}`, {
|
|
38
57
|
method,
|
|
@@ -203,6 +222,7 @@
|
|
|
203
222
|
state.walk = null;
|
|
204
223
|
toast(`Saved — ${enabled.length} of ${steps.length} skill${steps.length === 1 ? '' : 's'} on.`);
|
|
205
224
|
await load();
|
|
225
|
+
changed();
|
|
206
226
|
return;
|
|
207
227
|
} catch (err) {
|
|
208
228
|
w.saving = false;
|
|
@@ -458,6 +478,7 @@
|
|
|
458
478
|
if (state.walk && state.walk.id === String(id)) state.walk = null;
|
|
459
479
|
}
|
|
460
480
|
await load();
|
|
481
|
+
if (action === 'adopt' || action === 'abandon') changed();
|
|
461
482
|
// Adopting is the moment the ruling is about: a speciality that offers
|
|
462
483
|
// skills opens straight into the walkthrough, with every one still off.
|
|
463
484
|
if (action === 'adopt') {
|
|
@@ -585,8 +606,64 @@
|
|
|
585
606
|
});
|
|
586
607
|
}
|
|
587
608
|
|
|
609
|
+
// THE CREATE FORM, rendered into the page's empty `<form id="speciality-create">`
|
|
610
|
+
// (task 1005052). It lived in settings.html until a second page mounted these
|
|
611
|
+
// tools; here it is one copy both pages share, filled before wire() reads its
|
|
612
|
+
// fields. The markup is the one settings.html carried, unchanged.
|
|
613
|
+
function createFormHtml() {
|
|
614
|
+
return `
|
|
615
|
+
<h3 class="speciality-create__h">Create one</h3>
|
|
616
|
+
<label class="speciality-field">
|
|
617
|
+
<span>Name</span>
|
|
618
|
+
<input type="text" name="name" maxlength="80" required placeholder="Economics" />
|
|
619
|
+
</label>
|
|
620
|
+
<label class="speciality-field">
|
|
621
|
+
<span>Role it sits under</span>
|
|
622
|
+
<select name="discipline" required>
|
|
623
|
+
<option value="">Pick one…</option>
|
|
624
|
+
<option value="engineer">Engineer</option>
|
|
625
|
+
<option value="ideator">Ideator</option>
|
|
626
|
+
<option value="artist">Artist</option>
|
|
627
|
+
<option value="ui">UI design</option>
|
|
628
|
+
</select>
|
|
629
|
+
</label>
|
|
630
|
+
<label class="speciality-field">
|
|
631
|
+
<span>Summary <small>(optional)</small></span>
|
|
632
|
+
<input type="text" name="summary" maxlength="500" placeholder="Markets, incentives, and how to price them." />
|
|
633
|
+
</label>
|
|
634
|
+
<label class="speciality-field">
|
|
635
|
+
<span>How Claude should engage you in it <small>(optional)</small></span>
|
|
636
|
+
<textarea name="contract_md" rows="4" maxlength="4000" placeholder="Argue from mechanism, not vibes. Always name the assumption a number rests on."></textarea>
|
|
637
|
+
</label>
|
|
638
|
+
<label class="speciality-field">
|
|
639
|
+
<span>Who can use it</span>
|
|
640
|
+
<select name="visibility">
|
|
641
|
+
<option value="private">Only me</option>
|
|
642
|
+
<option value="project">Anyone in the owning project</option>
|
|
643
|
+
<option value="public">Anyone on this instance</option>
|
|
644
|
+
</select>
|
|
645
|
+
</label>
|
|
646
|
+
<label class="speciality-field speciality-field--check">
|
|
647
|
+
<input type="checkbox" name="sellable" />
|
|
648
|
+
<span>
|
|
649
|
+
May be offered for sale later
|
|
650
|
+
<small>Records your decision only — there is no marketplace yet, and nothing is listed anywhere.</small>
|
|
651
|
+
</span>
|
|
652
|
+
</label>
|
|
653
|
+
<details id="speciality-create-offer" class="speciality-offer-box">
|
|
654
|
+
<summary>Skills it offers <small>(optional)</small></summary>
|
|
655
|
+
<div id="speciality-create-skills"><p class="hall-loading hall-loading--inline" role="status">Loading this project’s skills…</p></div>
|
|
656
|
+
</details>
|
|
657
|
+
<div class="speciality-actions">
|
|
658
|
+
<button type="submit" class="btn">Create speciality</button>
|
|
659
|
+
</div>
|
|
660
|
+
`;
|
|
661
|
+
}
|
|
662
|
+
|
|
588
663
|
function boot() {
|
|
589
664
|
if (!el('specialities-rows')) return; // panel not on this page
|
|
665
|
+
const create = el('speciality-create');
|
|
666
|
+
if (create) create.innerHTML = createFormHtml();
|
|
590
667
|
wire();
|
|
591
668
|
load();
|
|
592
669
|
}
|