@bongos/core 1.21.113 → 1.21.115
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 +608 -188
- package/.claude/skills/ask-for-help/SKILL.md +1 -1
- package/.claude/skills/bongos-feedback/SKILL.md +1 -1
- package/.claude/skills/builder-sequence/SKILL.md +1 -1
- package/.claude/skills/builder-ship/SKILL.md +1 -0
- package/GOVERNMENT.md +128 -11
- package/clients/bongos-client/README.md +1 -1
- package/clients/bongos-client/bongos-client.global.js +28 -0
- package/clients/bongos-client/index.cjs +28 -0
- package/clients/bongos-client/index.d.ts +45 -2
- package/clients/bongos-client/index.mjs +28 -0
- package/docs/adr/0372-an-ask-is-stored-per-docket-matter-and-the-server-refuses-slop.md +33 -0
- package/docs/adr/0373-an-ai-session-files-a-blocker-with-an-ask.md +31 -0
- package/docs/adr/0374-a-building-lead-is-a-held-position-appointed-by-a-people-matter.md +30 -0
- package/docs/adr/0375-who-may-build-without-a-vote-comes-from-the-form-of-government.md +38 -0
- package/docs/adr/0376-every-ask-is-routed-to-a-real-seat-on-the-server.md +30 -0
- package/docs/adr/0377-governance-is-a-held-position-read-on-me.md +24 -0
- package/docs/adr/0378-a-leads-build-outs-are-rows-built-at-once-or-by-a-passed-vote.md +33 -0
- package/docs/adr/0379-the-treasury-is-pots-per-goal-a-reserve-and-borrowing-over-real-spend.md +32 -0
- package/docs/adr/0380-a-strictness-preset-is-a-bundle-of-laws-switched-by-one-laws-vote.md +26 -0
- package/docs/adr/README.md +10 -1
- package/docs/api/openapi.json +989 -87
- package/docs/api-reference.md +18 -4
- package/docs/copy-inventory.md +709 -626
- package/docs/copy-registry.json +1673 -858
- package/docs/file-map.md +2 -1
- package/docs/module-api-changelog.md +4 -0
- package/docs/packs/engineer.md +2 -1
- package/docs/page-inventory.json +91 -6
- package/docs/page-readings.json +4875 -4748
- package/modules/builder-settings/law-locks.js +202 -0
- package/modules/builder-settings/routes/settings.js +66 -6
- package/modules/builder-settings/settings.js +7 -0
- package/modules/discord/ship-broadcast.js +22 -13
- package/modules/government/asks-db.js +54 -0
- package/modules/government/asks.js +269 -0
- package/modules/government/board-idea-reads.js +68 -0
- package/modules/government/board.js +21 -57
- package/modules/government/build-rights.js +148 -0
- package/modules/government/buildouts.js +160 -0
- package/modules/government/counts.js +81 -0
- package/modules/government/db.js +242 -0
- package/modules/government/decision-board.js +234 -8
- package/modules/government/decision-rules.js +2 -0
- package/modules/government/docket.js +114 -6
- package/modules/government/law-board.js +131 -0
- package/modules/government/laws.js +241 -0
- package/modules/government/leads.js +170 -0
- package/modules/government/migrations/government_027_laws.sql +143 -0
- package/modules/government/migrations/government_028_asks.sql +57 -0
- package/modules/government/migrations/government_029_leads.sql +135 -0
- package/modules/government/migrations/government_030_buildouts.sql +111 -0
- package/modules/government/migrations/government_031_treasury.sql +107 -0
- package/modules/government/module.json +2 -1
- package/modules/government/pollers/treasury-borrow.js +62 -0
- package/modules/government/positions.js +107 -0
- package/modules/government/presets.js +149 -0
- package/modules/government/routes/government.js +425 -2
- package/modules/government/routing.js +154 -0
- package/modules/government/treasury-db.js +166 -0
- package/modules/government/treasury.js +241 -0
- package/modules/hall-ui/public/atlas.html +2 -2
- package/modules/hall-ui/public/blockers.html +2 -2
- package/modules/hall-ui/public/board-room.html +2 -2
- package/modules/hall-ui/public/board-room.js +2 -0
- package/modules/hall-ui/public/city-draw.js +604 -11
- package/modules/hall-ui/public/city.css +157 -1
- package/modules/hall-ui/public/city.html +37 -7
- package/modules/hall-ui/public/city.js +441 -21
- package/modules/hall-ui/public/city.states.json +110 -5
- package/modules/hall-ui/public/collab.html +2 -2
- package/modules/hall-ui/public/commands.html +2 -2
- package/modules/hall-ui/public/copy-desk.html +2 -2
- package/modules/hall-ui/public/craft-mode.js +112 -29
- package/modules/hall-ui/public/deploy.html +2 -2
- package/modules/hall-ui/public/diagram-viewer.css +12 -0
- package/modules/hall-ui/public/diagram-viewer.js +4 -0
- package/modules/hall-ui/public/diagrams.html +2 -2
- package/modules/hall-ui/public/drachmae.html +2 -2
- package/modules/hall-ui/public/fleet.html +2 -2
- package/modules/hall-ui/public/gate.html +2 -2
- package/modules/hall-ui/public/goal-map.html +2 -2
- package/modules/hall-ui/public/goals.html +2 -2
- package/modules/hall-ui/public/gov-feeds.js +141 -0
- package/modules/hall-ui/public/gov-living.js +1002 -0
- package/modules/hall-ui/public/gov-positions.js +97 -0
- package/modules/hall-ui/public/government.html +2 -2
- package/modules/hall-ui/public/hall-render.js +3 -0
- package/modules/hall-ui/public/idea.html +2 -2
- package/modules/hall-ui/public/ideas.html +2 -2
- package/modules/hall-ui/public/index.html +3 -3
- package/modules/hall-ui/public/modules.html +2 -2
- package/modules/hall-ui/public/my-agents.css +334 -0
- package/modules/hall-ui/public/my-agents.html +72 -0
- package/modules/hall-ui/public/my-agents.js +603 -0
- package/modules/hall-ui/public/my-agents.states.json +37 -0
- package/modules/hall-ui/public/primer.html +2 -2
- package/modules/hall-ui/public/profile-connections.js +40 -28
- package/modules/hall-ui/public/profile.html +2 -2
- package/modules/hall-ui/public/project-settings.html +2 -2
- package/modules/hall-ui/public/ranks.html +2 -2
- package/modules/hall-ui/public/roadmap.html +2 -2
- package/modules/hall-ui/public/room.css +8 -0
- package/modules/hall-ui/public/roster.html +2 -2
- package/modules/hall-ui/public/sessions.html +2 -2
- package/modules/hall-ui/public/settings.html +2 -2
- package/modules/hall-ui/public/shell.js +116 -16
- package/modules/hall-ui/public/street-card.js +18 -1
- package/modules/hall-ui/public/street-deck.css +299 -0
- package/modules/hall-ui/public/street-deck.js +1145 -0
- package/modules/hall-ui/public/street-depth.js +712 -0
- package/modules/hall-ui/public/street-desk.js +5 -2
- package/modules/hall-ui/public/street-draw.js +109 -16
- package/modules/hall-ui/public/street-inside.js +137 -22
- package/modules/hall-ui/public/street-office.js +705 -0
- package/modules/hall-ui/public/street.css +161 -11
- package/modules/hall-ui/public/street.html +41 -11
- package/modules/hall-ui/public/street.js +78 -66
- package/modules/hall-ui/public/street.states.json +129 -21
- package/modules/hall-ui/public/studio.html +2 -2
- package/modules/hall-ui/public/style.css +5 -1
- package/modules/hall-ui/public/task.html +2 -2
- package/modules/hall-ui/public/thinking.html +2 -2
- package/modules/hall-ui/public/tweak-editor.html +2 -2
- package/modules/hall-ui/public/watch.html +2 -2
- package/modules/hall-ui/public/watch.js +14 -1
- package/modules/hall-ui/public/work.html +2 -2
- package/modules/hall-ui/records/living-city.md +57 -0
- package/modules/hall-ui/records/my-agents.md +21 -0
- package/modules/hall-ui/records/oversight-family.md +1 -0
- package/modules/hall-ui/records/profile-connections.md +10 -0
- package/modules/hall-ui/records/reading-rooms.md +2 -0
- package/modules/ideas/routes/blockers.js +92 -3
- package/modules/lifecycle/module.json +2 -1
- package/modules/lifecycle/moving.js +17 -1
- package/modules/lifecycle/routes/moving.js +6 -0
- package/modules/lifecycle/routes/project-settings.js +23 -0
- package/modules/onboarding/approval-broadcast.js +8 -0
- package/modules/onboarding/routes/access-requests.js +16 -6
- package/modules/platform-identity/connections.js +13 -2
- package/modules/platform-identity/routes/connections.js +7 -1
- package/modules/public-landing/public/account-private.states.json +2 -2
- package/modules/public-landing/public/account.html +65 -5
- package/modules/public-landing/public/account.states.json +3 -3
- package/modules/public-landing/public/assets/world/r2-bongos-chrome-b.jpg.json +1 -1
- package/modules/public-landing/public/assets/world/r2-bongos-chrome-b.webp +0 -0
- package/modules/public-landing/public/assets/world/r2-bongos-chrome-b.webp.json +13 -0
- package/modules/public-landing/public/assets/world/r2-chrome-blob-one.jpg.json +1 -1
- package/modules/public-landing/public/assets/world/r2-chrome-blob-one.webp +0 -0
- package/modules/public-landing/public/assets/world/r2-chrome-blob-one.webp.json +13 -0
- package/modules/public-landing/public/assets/world/r2-chrome-blobs-set.jpg.json +1 -1
- package/modules/public-landing/public/assets/world/r2-chrome-blobs-set.webp +0 -0
- package/modules/public-landing/public/assets/world/r2-chrome-blobs-set.webp.json +13 -0
- package/modules/public-landing/public/assets/world.css +4 -4
- package/modules/public-landing/public/connections-empty.states.json +14 -0
- package/modules/public-landing/public/connections-inactive.states.json +14 -0
- package/modules/public-landing/public/connections.html +450 -0
- package/modules/public-landing/public/connections.probes.json +414 -0
- package/modules/public-landing/public/connections.states.json +17 -0
- package/modules/public-landing/public/contact.html +2 -2
- package/modules/public-landing/public/guild.html +2 -2
- package/modules/public-landing/public/index.html +2 -2
- package/modules/public-landing/public/invitations.html +2 -2
- package/modules/public-landing/public/privacy.html +2 -2
- package/modules/public-landing/public/projects-hall-live.states.json +0 -5
- package/modules/public-landing/public/projects.html +169 -6
- package/modules/public-landing/public/projects.probes.json +10 -6
- package/modules/public-landing/public/projects.states.json +13 -13
- package/modules/public-landing/public/terms.html +2 -2
- package/modules/ui-design/kit/fixtures/connections-empty.json +12 -0
- package/modules/ui-design/kit/fixtures/connections-inactive.json +7 -0
- package/modules/ui-design/kit/fixtures/connections.json +22 -0
- package/modules/ui-design/kit/serve.js +95 -0
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/release-notes.json +128 -0
- package/scripts/discord/README.md +8 -5
- package/scripts/discord/post.js +12 -1
- package/scripts/gds/artifact-audit.js +20 -3
- package/scripts/gds/ask.js +164 -0
- package/scripts/gds/autobongos-verify.js +21 -2
- package/scripts/gds/government-walk.js +638 -4
- package/scripts/gds/pulse.js +9 -6
- package/scripts/gds/ship-escalation.js +22 -3
- package/scripts/gds/ship-finish.js +5 -4
- package/scripts/gds/ship-merge-gate.js +18 -6
- package/scripts/hall-preview/README.md +41 -1
- package/scripts/hall-preview/pref-writes.js +140 -0
- package/scripts/hall-preview/refresh-fixtures.js +101 -7
- package/scripts/hall-preview/scrub-identity.js +366 -7
- package/scripts/hall-preview/server.js +27 -1
- package/scripts/render-diagrams.sh +4 -2
- package/src/bongos/auth-idp.js +6 -1
- package/src/bongos/project-settings.js +41 -0
- package/src/bongos/route-rank-check.js +27 -0
- package/src/bongos/routes/me.js +68 -7
- package/src/bongos/serve-internal.js +5 -1
- package/src/module-api.js +7 -1
- package/src/platform-server.js +10 -0
- package/tests/application_lifecycle.mjs +47 -5
- package/tests/conductor_main_e2e.mjs +21 -0
- package/tests/connections_api.mjs +18 -0
- package/tests/craft_mode_nav.mjs +5 -3
- package/tests/craft_mode_tallies.mjs +52 -16
- package/tests/discord_approvals.mjs +11 -0
- package/tests/discord_channels.mjs +20 -0
- package/tests/fixtures/gov-seated.mjs +64 -0
- package/tests/fixtures/government-ask-cards.json +1284 -0
- package/tests/government_act_alone_buildings.mjs +1 -0
- package/tests/government_agent_asks.mjs +322 -0
- package/tests/government_asks.mjs +408 -0
- package/tests/government_build_rights.mjs +253 -0
- package/tests/government_buildouts.mjs +382 -0
- package/tests/government_counts.mjs +143 -0
- package/tests/government_decision_rules.mjs +5 -1
- package/tests/government_laws.mjs +488 -0
- package/tests/government_laws_session.mjs +321 -0
- package/tests/government_leads.mjs +375 -0
- package/tests/government_positions.mjs +127 -0
- package/tests/government_presets.mjs +215 -0
- package/tests/government_routes.mjs +8 -1
- package/tests/government_routing.mjs +118 -0
- package/tests/government_seed.mjs +5 -0
- package/tests/government_treasury.mjs +394 -0
- package/tests/governor_docket.mjs +26 -2
- package/tests/hall_buildouts.mjs +208 -0
- package/tests/hall_city.mjs +14 -6
- package/tests/hall_city_living.mjs +617 -0
- package/tests/hall_gov_counts.mjs +336 -0
- package/tests/hall_gov_living.mjs +636 -0
- package/tests/hall_gov_real_site.mjs +655 -0
- package/tests/hall_matter_card.mjs +6 -1
- package/tests/hall_my_agents.mjs +481 -0
- package/tests/hall_nav.mjs +107 -4
- package/tests/hall_page_gate_map.mjs +4 -0
- package/tests/hall_preview_governor_fixtures.mjs +30 -3
- package/tests/hall_preview_scrub.mjs +59 -1
- package/tests/hall_preview_security.mjs +169 -0
- package/tests/hall_reading_world.mjs +44 -0
- package/tests/hall_roster_world.mjs +6 -2
- package/tests/hall_street.mjs +18 -2
- package/tests/hall_street_amend.mjs +1 -1
- package/tests/hall_street_deck.mjs +609 -0
- package/tests/hall_street_depth.mjs +559 -0
- package/tests/hall_street_desk.mjs +1 -1
- package/tests/hall_street_inside.mjs +29 -5
- package/tests/hall_tweak_editor.mjs +4 -1
- package/tests/hub_account_page.mjs +94 -3
- package/tests/hub_connections_page.mjs +507 -0
- package/tests/hub_invite_badge.mjs +1 -1
- package/tests/idp_device_exchange.mjs +18 -0
- package/tests/landing_legal_pages.mjs +8 -5
- package/tests/landing_page.mjs +23 -4
- package/tests/nav_permission_atoms.mjs +4 -1
- package/tests/profile_connections_ui.mjs +88 -25
- package/tests/projects_hub.mjs +15 -0
- package/tests/projects_hub_pre_uat.mjs +4 -2
- package/tests/render_check.mjs +2 -2
- package/tests/ship_broadcast_routing.mjs +57 -16
- package/tests/ship_broadcast_server.mjs +40 -7
- package/tests/ship_merge_gate.mjs +19 -0
- package/tests/ui_design_kit.mjs +2 -2
- package/tests/watch_applications_queue.mjs +23 -0
- package/tests/wizard_physics.mjs +1 -1
- package/tests/wizard_physics_more.mjs +133 -0
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"_": "MY AGENTS (task 1004685, the living-city prototype) through modules/ui-design/kit/render.js. Every row is filled from GET /me and its prefs, so the floors run against the hall-preview harness, which serves those reads and records the pref writes (scripts/hall-preview/pref-writes.js):\n\n node scripts/hall-preview/server.js --port 4614 --fixture-me --rank archon\n node modules/ui-design/kit/render.js --states modules/hall-ui/public/my-agents.states.json --base-in http://builders.localhost:4614 --base-out http://builders.localhost:4614\n\nAgainst the kit's own stub the reads 404 and the page shows its sign-in line. The 'nobody' state is the same page as a builder who holds no seat (?as=nobody, read by the prototype only).",
|
|
3
|
+
"page": "/my-agents",
|
|
4
|
+
"surface": "hall-ui",
|
|
5
|
+
"stub": { "prefix": "/builders/" },
|
|
6
|
+
"modeQuery": false,
|
|
7
|
+
"ignoreRequests": ["/api/(gds|bongos)/"],
|
|
8
|
+
"ignoreConsole": ["/api/(gds|bongos)/", "\\b401\\b", "\\b403\\b", "\\b404\\b", "\\b501\\b", "Unauthorized", "Forbidden", "Not Found", "load failed"],
|
|
9
|
+
"states": {
|
|
10
|
+
"desk": {
|
|
11
|
+
"auth": true,
|
|
12
|
+
"_": "Every setting as one real line (task 1004714: only a real law locks a row, and the hub has none), the real preset strip (no preset in force on the hub; what each would lock), Make it a law, and what the agent reads first.",
|
|
13
|
+
"actions": [["wait", 900], ["clickIfVisible", "[data-craft-close]"], ["wait", 300]],
|
|
14
|
+
"expect": { "visible": ["#ma-strict", "#ma-desk", "#ma-reads", ".ma-chip", "[data-group=\"habits\"] [data-propose]"] }
|
|
15
|
+
},
|
|
16
|
+
"factory": {
|
|
17
|
+
"auth": true,
|
|
18
|
+
"_": "Previewing Factory: the strip says it would lock off-task and the three model slots (a preview only: no row locks), offers to put it to a vote, and the way back.",
|
|
19
|
+
"actions": [["wait", 900], ["clickIfVisible", "[data-craft-close]"], ["wait", 300], ["click", "button[data-preset=\"factory\"]"], ["wait", 400]],
|
|
20
|
+
"expect": { "visible": [".ma-back", ".ma-pip[data-on]"] }
|
|
21
|
+
},
|
|
22
|
+
"saved": {
|
|
23
|
+
"auth": true,
|
|
24
|
+
"_": "A choice saved through the real route (the harness records it): reply length flipped to the value not chosen, the row's tick lit. Clicking the UNCHOSEN chip keeps the state repeatable, since the recorder remembers the last run's choice.",
|
|
25
|
+
"actions": [["wait", 900], ["clickIfVisible", "[data-craft-close]"], ["wait", 300], ["click", "button[data-set=\"verbosity\"][aria-pressed=\"false\"]"], ["wait", 400]],
|
|
26
|
+
"expect": { "visible": [".ma-row[data-saved] .ma-tick"] }
|
|
27
|
+
},
|
|
28
|
+
"nobody": {
|
|
29
|
+
"auth": true,
|
|
30
|
+
"url": "/my-agents?as=nobody",
|
|
31
|
+
"_": "As a builder with no seat: no governing tabs, no Governing mode, the same laws.",
|
|
32
|
+
"actions": [["wait", 900], ["clickIfVisible", "[data-craft-close]"], ["wait", 300]],
|
|
33
|
+
"expect": { "visible": ["#ma-as", "#ma-desk"] }
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
"reducedMotion": { "auth": true, "actions": [["wait", 900]] }
|
|
37
|
+
}
|
|
@@ -116,8 +116,8 @@
|
|
|
116
116
|
<div id="toast" class="toast" role="status" aria-live="polite" data-visible="0"></div>
|
|
117
117
|
|
|
118
118
|
<script src="/builders/shell-trail.js?v=2026-10-08-city-tab"></script>
|
|
119
|
-
<script src="/builders/craft-mode.js?v=2026-10-
|
|
120
|
-
<script src="/builders/shell.js?v=2026-10-
|
|
119
|
+
<script src="/builders/craft-mode.js?v=2026-10-09-living3"></script>
|
|
120
|
+
<script src="/builders/shell.js?v=2026-10-10-hall-keys1"></script>
|
|
121
121
|
<!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
|
|
122
122
|
<script src="/builders/palette.js" defer></script>
|
|
123
123
|
<!-- the shared markdown reader (window.OTBMdReader) — primer.js renders through
|
|
@@ -3,12 +3,21 @@
|
|
|
3
3
|
// task 1002296 / goal 1000045 criterion C6; ADR 0202, ADR 0207).
|
|
4
4
|
//
|
|
5
5
|
// WHAT IT RENDERS, and to whom:
|
|
6
|
-
// * on YOUR OWN profile —
|
|
7
|
-
//
|
|
8
|
-
//
|
|
6
|
+
// * on YOUR OWN profile — your accepted connections who also build on THIS
|
|
7
|
+
// project (`GET /connections?here=1`), each 1st degree by definition, each
|
|
8
|
+
// removable; a link to the hub's /connections page for everything else; and
|
|
9
|
+
// "builders you may know" (below).
|
|
9
10
|
// * on ANOTHER builder's profile — the viewer-relative degree label, the
|
|
10
11
|
// mutual connections it was computed from, and the connect affordance.
|
|
11
12
|
//
|
|
13
|
+
// THE HUB IS CONNECTIONS' HOME, THIS TAB IS ITS IN-PROJECT CUT (ADR 0337 D5.4,
|
|
14
|
+
// task 1004279). Your connections on other projects, and the request queues in
|
|
15
|
+
// both directions, live on the hub's /connections page (task 1004278), and this
|
|
16
|
+
// tab links there rather than drawing a second copy. It does not even READ the
|
|
17
|
+
// requests: GET /connections/requests stamps `seen_at` on the incoming rows it
|
|
18
|
+
// returns, which means "delivered", so a read this tab did not render would mark
|
|
19
|
+
// a request seen that nobody saw.
|
|
20
|
+
//
|
|
12
21
|
// HUB-ONLY, AND IT DEGRADES TO NOTHING. Connections are account-to-account on
|
|
13
22
|
// the platform hub (modules/platform-identity); on an instance without that
|
|
14
23
|
// module every route here is absent, every call 404s, and the section never
|
|
@@ -40,7 +49,9 @@
|
|
|
40
49
|
// viewer was actually handed — never a total carried beside a filtered list,
|
|
41
50
|
// which is a leak by subtraction (ADR 0171 D4 / ADR 0202 D4).
|
|
42
51
|
//
|
|
43
|
-
// "BUILDERS YOU MAY KNOW" (R21, task 1002297; ADR 0202 D5)
|
|
52
|
+
// "BUILDERS YOU MAY KNOW" (R21, task 1002297; ADR 0202 D5) STAYS in the hall
|
|
53
|
+
// (decided with task 1004279): ADR 0337 D4.2 puts it on both sides, and D5.4
|
|
54
|
+
// moved only the connections and their requests to the hub. It renders on YOUR
|
|
44
55
|
// OWN profile only, under your connections — never on someone else's, which
|
|
45
56
|
// is what makes it own-scope: the candidate pool is the session's own
|
|
46
57
|
// frontier. The server already picked the reason; this file renders it
|
|
@@ -135,17 +146,6 @@
|
|
|
135
146
|
</tr>`;
|
|
136
147
|
}
|
|
137
148
|
|
|
138
|
-
function requestsHtml(incoming, outgoing) {
|
|
139
|
-
const inbox = incoming.map((r) => `<li class="conn-req">${personHtml(r)}`
|
|
140
|
-
+ (r.note ? `<p class="conn-req__note">${escapeHtml(r.note)}</p>` : '')
|
|
141
|
-
+ `<span class="conn-req__acts">${btn('accept', r.id, 'Accept')}${btn('decline', r.id, 'Decline')}</span></li>`).join('');
|
|
142
|
-
const outbox = outgoing.map((r) => `<li class="conn-req">${personHtml(r)}`
|
|
143
|
-
+ '<span class="conn-req__state">Request sent</span>'
|
|
144
|
-
+ `<span class="conn-req__acts">${btn('withdraw', r.id, 'Withdraw')}</span></li>`).join('');
|
|
145
|
-
return (incoming.length ? `<h3 class="conn-sub">${escapeHtml(plural(incoming.length, 'builder'))} asking to connect</h3><ul class="conn-reqs">${inbox}</ul>` : '')
|
|
146
|
-
+ (outgoing.length ? `<h3 class="conn-sub">${escapeHtml(plural(outgoing.length, 'request'))} you have sent</h3><ul class="conn-reqs">${outbox}</ul>` : '');
|
|
147
|
-
}
|
|
148
|
-
|
|
149
149
|
// "Builders you may know" (R21, task 1002297; ADR 0202 D5) — mutual
|
|
150
150
|
// connections + shared projects, each explained in one line by the server.
|
|
151
151
|
// Empty when the server has nothing to say, same as every other honest
|
|
@@ -166,24 +166,37 @@
|
|
|
166
166
|
return `<button class="btn-ghost" type="button" data-act="suggest-connect" data-handle="${escapeHtml(handle)}">Connect</button>`;
|
|
167
167
|
}
|
|
168
168
|
|
|
169
|
-
//
|
|
170
|
-
|
|
171
|
-
|
|
169
|
+
// How many of your connections build here — the length of the list beside it.
|
|
170
|
+
function hereLede(n) {
|
|
171
|
+
if (!n) return 'None of your connections build on this project yet.';
|
|
172
|
+
return n === 1 ? '1 of your connections builds on this project.' : `${n} of your connections build on this project.`;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// The way out to the hub's /connections page, where the rest of your
|
|
176
|
+
// connections and both request queues live. No hub origin, no link — the
|
|
177
|
+
// OTB.hubOrigin() contract every hall link to the hub keeps.
|
|
178
|
+
function hubLinkHtml() {
|
|
179
|
+
const hub = window.OTB.hubOrigin ? window.OTB.hubOrigin() : null;
|
|
180
|
+
if (!hub) return '';
|
|
181
|
+
return '<p class="scroll__lede">Requests, and your connections on other projects, are on your Connections page.</p>'
|
|
182
|
+
+ `<div class="row-end"><a class="pbtn" id="conn-hub-link" href="${escapeHtml(`${hub}/connections`)}">Open your Connections page</a></div>`;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// Your own connections on this project + the link to the rest + "builders you
|
|
186
|
+
// may know". Returns false when the hub routes are absent or the session is
|
|
187
|
+
// gone, so the caller leaves the section hidden rather than rendering an empty
|
|
172
188
|
// shell.
|
|
173
189
|
async function renderOwn(body) {
|
|
174
|
-
const [list,
|
|
175
|
-
api.request('GET', `${API}/connections`),
|
|
176
|
-
api.request('GET', `${API}/connections/requests`),
|
|
190
|
+
const [list, suggestions] = await Promise.all([
|
|
191
|
+
api.request('GET', `${API}/connections?here=1`),
|
|
177
192
|
api.request('GET', `${API}/connections/suggestions`),
|
|
178
193
|
]);
|
|
179
|
-
if (!list.ok
|
|
194
|
+
if (!list.ok) return false;
|
|
180
195
|
const connections = arr(list.data && list.data.connections);
|
|
181
|
-
const incoming = arr(reqs.data && reqs.data.incoming);
|
|
182
|
-
const outgoing = arr(reqs.data && reqs.data.outgoing);
|
|
183
196
|
const suggested = suggestions.ok ? arr(suggestions.data && suggestions.data.suggestions) : [];
|
|
184
|
-
body.innerHTML =
|
|
185
|
-
+ `<p class="scroll__lede">${escapeHtml(plural(connections.length, 'connection'))}.</p>`
|
|
197
|
+
body.innerHTML = `<p class="scroll__lede">${escapeHtml(hereLede(connections.length))}</p>`
|
|
186
198
|
+ '<div id="conn-ledger"></div>'
|
|
199
|
+
+ hubLinkHtml()
|
|
187
200
|
+ suggestionsHtml(suggested);
|
|
188
201
|
const mount = $('#conn-ledger');
|
|
189
202
|
if (mount) {
|
|
@@ -192,7 +205,7 @@
|
|
|
192
205
|
mount,
|
|
193
206
|
columns: ['Builder', 'Degree', { label: 'Connected', class: 'ledger__date' }, ''],
|
|
194
207
|
rowHtml: connectionRow,
|
|
195
|
-
emptyMsg: '
|
|
208
|
+
emptyMsg: 'When someone you are connected with joins this project, they show up here.',
|
|
196
209
|
pager,
|
|
197
210
|
}).render(connections);
|
|
198
211
|
}
|
|
@@ -280,7 +293,6 @@
|
|
|
280
293
|
accept: { call: (id) => api.request('POST', `${API}/connections/${encodeURIComponent(id)}/accept`), message: 'Connected.' },
|
|
281
294
|
decline: { call: (id) => api.request('POST', `${API}/connections/${encodeURIComponent(id)}/decline`), message: 'Declined.' },
|
|
282
295
|
remove: { call: (id) => api.request('DELETE', `${API}/connections/${encodeURIComponent(id)}`), message: 'Connection removed.' },
|
|
283
|
-
withdraw: { call: (id) => api.request('DELETE', `${API}/connections/${encodeURIComponent(id)}`), message: 'Request withdrawn.' },
|
|
284
296
|
};
|
|
285
297
|
|
|
286
298
|
async function onClick(ev) {
|
|
@@ -208,8 +208,8 @@
|
|
|
208
208
|
<!-- The app shell (sidebar + top bar). Dependency-free; loaded FIRST so the
|
|
209
209
|
chrome exists before the page script runs. -->
|
|
210
210
|
<script src="/builders/shell-trail.js?v=2026-10-08-city-tab"></script>
|
|
211
|
-
<script src="/builders/craft-mode.js?v=2026-10-
|
|
212
|
-
<script src="/builders/shell.js?v=2026-10-
|
|
211
|
+
<script src="/builders/craft-mode.js?v=2026-10-09-living3"></script>
|
|
212
|
+
<script src="/builders/shell.js?v=2026-10-10-hall-keys1"></script>
|
|
213
213
|
<!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
|
|
214
214
|
<script src="/builders/palette.js" defer></script>
|
|
215
215
|
<!-- shared frontend toolkit (window.OTB) — loaded before profile.js, which pulls from it. -->
|
|
@@ -71,8 +71,8 @@
|
|
|
71
71
|
<div id="toast" class="toast" role="status" aria-live="polite" data-visible="0"></div>
|
|
72
72
|
|
|
73
73
|
<script src="/builders/shell-trail.js?v=2026-10-08-city-tab"></script>
|
|
74
|
-
<script src="/builders/craft-mode.js?v=2026-10-
|
|
75
|
-
<script src="/builders/shell.js?v=2026-10-
|
|
74
|
+
<script src="/builders/craft-mode.js?v=2026-10-09-living3"></script>
|
|
75
|
+
<script src="/builders/shell.js?v=2026-10-10-hall-keys1"></script>
|
|
76
76
|
<!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
|
|
77
77
|
<script src="/builders/palette.js" defer></script>
|
|
78
78
|
<script src="/builders/dom-utils.js?v=2026-06-16-gate"></script>
|
|
@@ -78,8 +78,8 @@
|
|
|
78
78
|
<!-- The app shell (sidebar + top bar). Dependency-free; loaded FIRST so the
|
|
79
79
|
chrome exists before the page script runs. -->
|
|
80
80
|
<script src="/builders/shell-trail.js?v=2026-10-08-city-tab"></script>
|
|
81
|
-
<script src="/builders/craft-mode.js?v=2026-10-
|
|
82
|
-
<script src="/builders/shell.js?v=2026-10-
|
|
81
|
+
<script src="/builders/craft-mode.js?v=2026-10-09-living3"></script>
|
|
82
|
+
<script src="/builders/shell.js?v=2026-10-10-hall-keys1"></script>
|
|
83
83
|
<!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
|
|
84
84
|
<script src="/builders/palette.js" defer></script>
|
|
85
85
|
<!-- shared frontend toolkit (window.OTB) — loaded before ranks.js, which pulls from it. -->
|
|
@@ -42,8 +42,8 @@
|
|
|
42
42
|
<div id="toast" class="toast" role="status" aria-live="polite" data-visible="0"></div>
|
|
43
43
|
|
|
44
44
|
<script src="/builders/shell-trail.js?v=2026-10-08-city-tab"></script>
|
|
45
|
-
<script src="/builders/craft-mode.js?v=2026-10-
|
|
46
|
-
<script src="/builders/shell.js?v=2026-10-
|
|
45
|
+
<script src="/builders/craft-mode.js?v=2026-10-09-living3"></script>
|
|
46
|
+
<script src="/builders/shell.js?v=2026-10-10-hall-keys1"></script>
|
|
47
47
|
<!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
|
|
48
48
|
<script src="/builders/palette.js" defer></script>
|
|
49
49
|
<script src="/builders/dom-utils.js?v=2026-06-14-domutils"></script>
|
|
@@ -371,6 +371,14 @@ body.room .page-head { max-width: var(--room-max); }
|
|
|
371
371
|
max-width: 100%;
|
|
372
372
|
height: auto;
|
|
373
373
|
}
|
|
374
|
+
/* The PNG the canvas replaces is a light render too, and it is what shows
|
|
375
|
+
before the SVG arrives and whenever it cannot. Dark turns it the way
|
|
376
|
+
diagram-viewer.css turns the canvas (task 1003639), so a dark reader never
|
|
377
|
+
gets a white flash; the PNG keeps its baked ground, which inverts to black. */
|
|
378
|
+
html[data-theme="dark"] .primer-figure img, html[data-theme="dark"] figure.diagram img { filter: invert(1) hue-rotate(180deg); }
|
|
379
|
+
@media (prefers-color-scheme: dark) {
|
|
380
|
+
html:not([data-theme]) .primer-figure img, html:not([data-theme]) figure.diagram img { filter: invert(1) hue-rotate(180deg); }
|
|
381
|
+
}
|
|
374
382
|
/* diagram-viewer.js inserts its canvas INSIDE the figure and hides the <img>,
|
|
375
383
|
so the frame has to belong to exactly one of them or the diagram ends up in
|
|
376
384
|
two nested boxes. The figure keeps it; the canvas gives its own up. (Its
|
|
@@ -54,8 +54,8 @@
|
|
|
54
54
|
<!-- The app shell (sidebar + top bar). Dependency-free; loaded FIRST so the
|
|
55
55
|
chrome exists before the page script runs. -->
|
|
56
56
|
<script src="/builders/shell-trail.js?v=2026-10-08-city-tab"></script>
|
|
57
|
-
<script src="/builders/craft-mode.js?v=2026-10-
|
|
58
|
-
<script src="/builders/shell.js?v=2026-10-
|
|
57
|
+
<script src="/builders/craft-mode.js?v=2026-10-09-living3"></script>
|
|
58
|
+
<script src="/builders/shell.js?v=2026-10-10-hall-keys1"></script>
|
|
59
59
|
<!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
|
|
60
60
|
<script src="/builders/palette.js" defer></script>
|
|
61
61
|
<!-- shared frontend toolkit (window.OTB — rank labels, number formats) + the
|
|
@@ -112,8 +112,8 @@
|
|
|
112
112
|
<!-- The app shell (sidebar + top bar). Dependency-free; loaded FIRST so the
|
|
113
113
|
chrome exists before the page script runs. -->
|
|
114
114
|
<script src="/builders/shell-trail.js?v=2026-10-08-city-tab"></script>
|
|
115
|
-
<script src="/builders/craft-mode.js?v=2026-10-
|
|
116
|
-
<script src="/builders/shell.js?v=2026-10-
|
|
115
|
+
<script src="/builders/craft-mode.js?v=2026-10-09-living3"></script>
|
|
116
|
+
<script src="/builders/shell.js?v=2026-10-10-hall-keys1"></script>
|
|
117
117
|
<!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
|
|
118
118
|
<script src="/builders/palette.js" defer></script>
|
|
119
119
|
<!-- shared frontend toolkit (window.OTB) — loaded BEFORE sessions.js so it can pull from it. -->
|
|
@@ -452,8 +452,8 @@
|
|
|
452
452
|
<!-- The app shell (sidebar + top bar). Dependency-free; loaded FIRST so the
|
|
453
453
|
chrome exists before the page scripts run. -->
|
|
454
454
|
<script src="/builders/shell-trail.js?v=2026-10-08-city-tab"></script>
|
|
455
|
-
<script src="/builders/craft-mode.js?v=2026-10-
|
|
456
|
-
<script src="/builders/shell.js?v=2026-10-
|
|
455
|
+
<script src="/builders/craft-mode.js?v=2026-10-09-living3"></script>
|
|
456
|
+
<script src="/builders/shell.js?v=2026-10-10-hall-keys1"></script>
|
|
457
457
|
<!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
|
|
458
458
|
<script src="/builders/palette.js" defer></script>
|
|
459
459
|
<!-- shared frontend toolkit (window.OTB) — loaded before consuming IIFEs. -->
|
|
@@ -108,6 +108,8 @@
|
|
|
108
108
|
// You
|
|
109
109
|
standing: '<circle cx="9" cy="6" r="3"/><path d="M3.5 15.5c.6-2.9 2.9-4.5 5.5-4.5s4.9 1.6 5.5 4.5"/>',
|
|
110
110
|
profile: '<rect x="2.5" y="4" width="13" height="10" rx="1.5"/><circle cx="6.3" cy="8" r="1.6"/><path d="M4.1 12c.3-1.1 1.1-1.7 2.2-1.7s1.9.6 2.2 1.7"/><path d="M10.4 7.5h3M10.4 10.3h3"/>',
|
|
111
|
+
// task 1004685 (prototype): My agents — a helper's head on an antenna, not a person.
|
|
112
|
+
agents: '<rect x="4" y="6" width="10" height="8.5" rx="2.5"/><path d="M9 6V3.6"/><circle cx="9" cy="2.7" r="0.9"/><path d="M7 10.2v0.6M11 10.2v0.6"/><path d="M1.8 9v3M16.2 9v3"/>',
|
|
111
113
|
// Community
|
|
112
114
|
collab: '<path d="M2.5 4a1 1 0 0 1 1-1h7a1 1 0 0 1 1 1v4.5a1 1 0 0 1-1 1H6.5L4 11.5v-2h-.5a1 1 0 0 1-1-1V4Z"/><path d="M11.5 6.5h3a1 1 0 0 1 1 1V12a1 1 0 0 1-1 1H14v2l-2.5-2H8.5a1 1 0 0 1-1-1V9.5"/>',
|
|
113
115
|
roster: '<circle cx="6.5" cy="6.3" r="2.3"/><path d="M2.5 15c.4-2.3 1.9-3.7 4-3.7s3.6 1.4 4 3.7"/><circle cx="12.5" cy="5.8" r="2"/><path d="M11.4 10.5c.4-.1.7-.2 1.1-.2 1.9 0 3.3 1.3 3.7 3.5"/>',
|
|
@@ -243,14 +245,15 @@
|
|
|
243
245
|
// /me (boardVotesNeed), pre-filtered to what the vote route would accept —
|
|
244
246
|
// so the badge counts ballots this viewer can actually cast, never "items
|
|
245
247
|
// open somewhere".
|
|
246
|
-
|
|
248
|
+
// task 1004685: `position: true` narrows the gate to seat holders (GOVERNING IS A POSITION).
|
|
249
|
+
{ id: 'board-room', label: 'Board Room', icon: 'boardroom', href: '/board-room', gate: 'perm:board.vote.cast', count: 'board_votes', position: true },
|
|
247
250
|
// The governor city (task 1004524): the owner put it on the sidebar on
|
|
248
251
|
// 2026-10-08, reversing "leave it off". It is the Governing mode's lead tab
|
|
249
252
|
// (craft-mode.js folds that mode's other tabs into a dropdown under it).
|
|
250
253
|
// Gated on the atom its page is (requireBoardVotePage), and it sits in this
|
|
251
254
|
// head-less group for the reason the Board Room does: the atom floors below
|
|
252
255
|
// any rank head. Cosmetic only (ADR 0016).
|
|
253
|
-
{ id: 'city', label: 'City', icon: 'city', href: '/city', gate: 'perm:board.vote.cast' },
|
|
256
|
+
{ id: 'city', label: 'City', icon: 'city', href: '/city', gate: 'perm:board.vote.cast', position: true },
|
|
254
257
|
// task 1004326 (BV2.TW15 of goal 1000095): the Ideas board (/ideas, task
|
|
255
258
|
// 1002928) and the Copy desk (/copy-desk, task 1003113) are ARCHIVED — off
|
|
256
259
|
// the nav on the owner's call of 2026-09-27, NOT deleted. Both pages and
|
|
@@ -292,6 +295,9 @@
|
|
|
292
295
|
// /profile?id=N from the leaderboard); 'signed' just means "show this 'my
|
|
293
296
|
// profile' shortcut once you're signed in".
|
|
294
297
|
{ id: 'profile', label: 'Profile', icon: 'profile', href: '/profile', gate: 'signed' },
|
|
298
|
+
// task 1004685 (prototype, board 6): MY AGENTS — how your own Claude works for you
|
|
299
|
+
// and which settings the project's laws lock. 'signed' is its page's real floor.
|
|
300
|
+
{ id: 'my-agents', label: 'My agents', icon: 'agents', href: '/my-agents', gate: 'signed' },
|
|
295
301
|
] },
|
|
296
302
|
// task 1003442 (goal 1000075): Community is Collab + Builders, and NEITHER
|
|
297
303
|
// carries a rank flag any more. Both items and this head read 'member'
|
|
@@ -357,18 +363,19 @@
|
|
|
357
363
|
// Relabeled 'Archon' → 'Governance' in ADR 0157, then → 'Government' by ADR 0174: these pages are no longer
|
|
358
364
|
// Archon-only, so a group header reading "Archon" over items a Metic can open
|
|
359
365
|
// would misdescribe the ladder to the builders most likely to be learning it.
|
|
360
|
-
|
|
366
|
+
// task 1004685: a governing surface throughout, so head and items carry `position`.
|
|
367
|
+
{ group: 'Government', gate: 'government', position: true, items: [
|
|
361
368
|
// The Board Room was FIRST here from the ADR 0266 carve until task 1003744
|
|
362
369
|
// moved it into the project group — its wall is an ATOM (`board.vote.cast`,
|
|
363
370
|
// xenos floor) rather than this group's rank, and a group whose audience is
|
|
364
371
|
// Metic+ oversight could not honestly hold it. Everything below IS a rank
|
|
365
372
|
// surface, so this group's gate and audience are unchanged.
|
|
366
|
-
{ id: 'watch', label: 'Watch', icon: 'watch', href: '/watch', gate: 'government' },
|
|
367
|
-
{ id: 'gate', label: 'Gate', icon: 'gate', href: '/gate', gate: 'government' },
|
|
368
|
-
{ id: 'sessions', label: 'Sessions', icon: 'sessions', href: '/sessions', gate: 'government' },
|
|
373
|
+
{ id: 'watch', label: 'Watch', icon: 'watch', href: '/watch', gate: 'government', position: true },
|
|
374
|
+
{ id: 'gate', label: 'Gate', icon: 'gate', href: '/gate', gate: 'government', position: true },
|
|
375
|
+
{ id: 'sessions', label: 'Sessions', icon: 'sessions', href: '/sessions', gate: 'government', position: true },
|
|
369
376
|
// The project's own fundamentals (task 1003280, goal 1000072). Mirrors the
|
|
370
377
|
// server's requireGovernmentPage floor; cosmetic only, as every item here is.
|
|
371
|
-
{ id: 'project-settings', label: 'Project settings', icon: 'settings', href: '/project-settings', gate: 'government' },
|
|
378
|
+
{ id: 'project-settings', label: 'Project settings', icon: 'settings', href: '/project-settings', gate: 'government', position: true },
|
|
372
379
|
// The deploy door (task 1003159, ADR 0293). Gated 'archon' here to mirror the
|
|
373
380
|
// `core.pin.move` atom its page and both its routes check — cosmetic only, as
|
|
374
381
|
// every item in this list is; the wall is server-side.
|
|
@@ -378,18 +385,18 @@
|
|
|
378
385
|
// dropped where the module is off — and since task 1004296 it STAYS dropped: /deploy
|
|
379
386
|
// is the platform hall's page alone, and every other hall takes its update from
|
|
380
387
|
// Settings → Software update, whose Update button carries the hub hand-off.
|
|
381
|
-
{ id: 'deploy', label: 'Deploy', icon: 'deploy', href: '/deploy', gate: 'archon', module: 'provisioning render-deploy' },
|
|
388
|
+
{ id: 'deploy', label: 'Deploy', icon: 'deploy', href: '/deploy', gate: 'archon', module: 'provisioning render-deploy', position: true },
|
|
382
389
|
// task 1001949: what each hosted project costs. 'government' mirrors the metic floor
|
|
383
390
|
// of `provisioning.fleet.manage`, the atom its page and its one read check (the
|
|
384
391
|
// Deploy precedent above); dropped where the provisioning module is not enabled.
|
|
385
|
-
{ id: 'fleet', label: 'Fleet costs', icon: 'fleet', href: '/fleet', gate: 'government', module: 'provisioning' },
|
|
392
|
+
{ id: 'fleet', label: 'Fleet costs', icon: 'fleet', href: '/fleet', gate: 'government', module: 'provisioning', position: true },
|
|
386
393
|
// BV1.R113: the roles-and-permissions tab (ADR 0151). The one genuinely
|
|
387
394
|
// Archon-only item the 'government' gate comment anticipated — cosmetic
|
|
388
395
|
// only. The wall is the `government.manage` atom checked on each of the
|
|
389
396
|
// tab's nine data routes (route-rank-check.js); the page SHELL itself is
|
|
390
397
|
// metic+, because R16 made /government three rooms and only this one is
|
|
391
398
|
// the archon surface.
|
|
392
|
-
{ id: 'government', label: 'Permissions', icon: 'permissions', href: '/government', gate: 'archon' } // NOT 'Ranks': /ranks is the signed-in ladder explainer and two nav items
|
|
399
|
+
{ id: 'government', label: 'Permissions', icon: 'permissions', href: '/government', gate: 'archon', position: true } // NOT 'Ranks': /ranks is the signed-in ladder explainer and two nav items
|
|
393
400
|
// reading 'Ranks' is the confusion this rename exists to remove. This tab
|
|
394
401
|
// is where a rank's permissions are granted, so it says what it does.,
|
|
395
402
|
] },
|
|
@@ -443,6 +450,7 @@
|
|
|
443
450
|
(it.external ? ' target="_blank" rel="noopener"' : '') +
|
|
444
451
|
(it.view ? ' data-view="' + it.view + '"' : '') +
|
|
445
452
|
' data-gate="' + it.gate + '"' + (it.module ? ' data-module="' + it.module + '"' : '') +
|
|
453
|
+
(it.position ? ' data-position="1"' : '') +
|
|
446
454
|
(it.count ? ' data-count="' + esc(it.count) + '"' : '') +
|
|
447
455
|
' title="' + esc(it.label) + '" hidden>' + icon(it.icon) +
|
|
448
456
|
'<span class="nav-item__label">' + esc(it.label) + '</span>' +
|
|
@@ -470,7 +478,7 @@
|
|
|
470
478
|
// string to find groups and a matching wrapper would parse as a phantom
|
|
471
479
|
// one. `data-gate` stays immediately after the class for the same reason.
|
|
472
480
|
var head = g.group
|
|
473
|
-
? '<button type="button" class="nav-group__head" data-gate="' + (g.gate || 'always') + '" data-group="' + esc(groupId) + '" aria-expanded="' + (collapsed ? 'false' : 'true') + '" aria-controls="nav-items-' + esc(groupId) + '" hidden>' +
|
|
481
|
+
? '<button type="button" class="nav-group__head" data-gate="' + (g.gate || 'always') + '"' + (g.position ? ' data-position="1"' : '') + ' data-group="' + esc(groupId) + '" aria-expanded="' + (collapsed ? 'false' : 'true') + '" aria-controls="nav-items-' + esc(groupId) + '" hidden>' +
|
|
474
482
|
'<span class="nav-group__head-label">' + esc(g.group) + '</span>' + chevronIcon() +
|
|
475
483
|
'</button>'
|
|
476
484
|
: '';
|
|
@@ -870,11 +878,14 @@
|
|
|
870
878
|
// not establish authority. null is NOT "holds nothing that matters": it is
|
|
871
879
|
// unreadable, and unreadable hides the link, the same call gateAllows()'s
|
|
872
880
|
// `default: false` and the social mode's OFF-is-the-fallback rule make.
|
|
873
|
-
|
|
881
|
+
// task 1004685: `positions` (seats held, null while unknown), `simRank` (?as=nobody's).
|
|
882
|
+
var access = { authed: null, rank: null, graduated: false, showWork: false, permissions: null, needs: null, founding: null, positions: null, simRank: null };
|
|
874
883
|
|
|
875
884
|
function gateAllows(gate) {
|
|
876
885
|
var authed = access.authed === true;
|
|
877
|
-
|
|
886
|
+
// ?as=nobody's stand-in rank only ever sits BELOW the real one (gov-positions.js).
|
|
887
|
+
var rank = access.simRank || access.rank;
|
|
888
|
+
var member = authed && rank !== 'xenos';
|
|
878
889
|
// task 1003744: the one gate key that is not a rank. `perm:<atom>` asks whether
|
|
879
890
|
// the viewer HOLDS that permission, reading the answer the SERVER resolved —
|
|
880
891
|
// never re-derived here from rank or anything else, the social-mode precedent:
|
|
@@ -889,11 +900,11 @@
|
|
|
889
900
|
case 'signed': return authed;
|
|
890
901
|
case 'member': return member;
|
|
891
902
|
case 'work': return authed && (member || access.showWork);
|
|
892
|
-
case 'archon': return authed &&
|
|
903
|
+
case 'archon': return authed && rank === 'archon';
|
|
893
904
|
// ADR 0157: the monitoring/ops pages sit at the `page.view.government` floor,
|
|
894
905
|
// which is metic. Kept as its own key rather than widening 'archon', so a
|
|
895
906
|
// genuinely Archon-only nav item can still be added later.
|
|
896
|
-
case 'government': return authed && (
|
|
907
|
+
case 'government': return authed && (rank === 'metic' || rank === 'archon');
|
|
897
908
|
default: return false;
|
|
898
909
|
}
|
|
899
910
|
}
|
|
@@ -995,6 +1006,81 @@
|
|
|
995
1006
|
'<a class="founding-band__link" href="/">What\u2019s this?</a>';
|
|
996
1007
|
}
|
|
997
1008
|
|
|
1009
|
+
// ---------- GOVERNING IS A POSITION (task 1004685 drew it; task 1004713 made it real) ----------
|
|
1010
|
+
// Owner ruling: you pick a craft, but you HOLD a seat or you don't. `position: true`
|
|
1011
|
+
// items (City, Board Room, Government) show only to a seat holder — the owner, a
|
|
1012
|
+
// Lead, a seat on a building's sitting, a board member — and craft-mode.js names
|
|
1013
|
+
// Governing by the seat. The seats are /me's `positions` block, resolved by the
|
|
1014
|
+
// SERVER (modules/government/positions.js); gov-positions.js (loaded lazily) only
|
|
1015
|
+
// reads it. COSMETIC NAV ONLY: page gates stay server-side, and a seat only takes
|
|
1016
|
+
// a link away. UNKNOWN IS TODAY'S NAV (a /me with no positions block: null).
|
|
1017
|
+
// ?as=nobody views the hall with no seat (session-sticky; ?as=me clears). It only hides.
|
|
1018
|
+
var POSITIONS_KEY = 'hall-positions';
|
|
1019
|
+
var AS_KEY = 'hall-as';
|
|
1020
|
+
var POSITIONS_TTL = 10 * 60 * 1000;
|
|
1021
|
+
var positionsAsked = null;
|
|
1022
|
+
var SHELL_V = (function () {
|
|
1023
|
+
var s = document.currentScript && document.currentScript.src;
|
|
1024
|
+
var m = s && /[?&]v=([^&#]+)/.exec(s);
|
|
1025
|
+
return m ? m[1] : '';
|
|
1026
|
+
})();
|
|
1027
|
+
function protoAs() {
|
|
1028
|
+
var m = /[?&]as=([a-z]+)/.exec((window.location && window.location.search) || '');
|
|
1029
|
+
try {
|
|
1030
|
+
if (m && m[1] === 'nobody') window.sessionStorage.setItem(AS_KEY, 'nobody');
|
|
1031
|
+
else if (m && m[1] === 'me') window.sessionStorage.removeItem(AS_KEY);
|
|
1032
|
+
return window.sessionStorage.getItem(AS_KEY) === 'nobody' ? 'nobody' : null;
|
|
1033
|
+
} catch (_) { return m && m[1] === 'nobody' ? 'nobody' : null; }
|
|
1034
|
+
}
|
|
1035
|
+
// id null = whoever was last asked about (the boot paint, before /me lands).
|
|
1036
|
+
function cachedPositions(id, as) {
|
|
1037
|
+
try {
|
|
1038
|
+
var c = JSON.parse(window.sessionStorage.getItem(POSITIONS_KEY) || 'null');
|
|
1039
|
+
if (c && (id == null || c.id === id) && c.as === as && Date.now() - c.at < POSITIONS_TTL) return c.value;
|
|
1040
|
+
} catch (_) { /* no storage: ask again */ }
|
|
1041
|
+
return null;
|
|
1042
|
+
}
|
|
1043
|
+
function settlePositions(p) {
|
|
1044
|
+
access.positions = p && p.known === true ? p : null;
|
|
1045
|
+
access.simRank = access.positions && access.positions.sim_rank ? access.positions.sim_rank : null;
|
|
1046
|
+
if (CRAFT && CRAFT.setPositions) CRAFT.setPositions(access.positions);
|
|
1047
|
+
}
|
|
1048
|
+
// READS A PAGE SHARES (task 1004685): /me is asked once a page; gov-feeds.js adopts
|
|
1049
|
+
// window.__hallReads. The seats ride /me itself (task 1004713), so no read of their own.
|
|
1050
|
+
var HALL_READS = window.__hallReads = window.__hallReads || {};
|
|
1051
|
+
var positionsLibAsk = null;
|
|
1052
|
+
function positionsLib() {
|
|
1053
|
+
if (window.GovPositions) return Promise.resolve(window.GovPositions);
|
|
1054
|
+
if (!positionsLibAsk) {
|
|
1055
|
+
positionsLibAsk = new Promise(function (resolve) {
|
|
1056
|
+
var head = document.head;
|
|
1057
|
+
if (!head || !head.appendChild || !document.createElement) { resolve(null); return; }
|
|
1058
|
+
var tag = document.createElement('script');
|
|
1059
|
+
tag.src = '/builders/gov-positions.js' + (SHELL_V ? '?v=' + SHELL_V : '');
|
|
1060
|
+
tag.onload = function () { resolve(window.GovPositions || null); };
|
|
1061
|
+
tag.onerror = function () { resolve(null); };
|
|
1062
|
+
head.appendChild(tag);
|
|
1063
|
+
});
|
|
1064
|
+
}
|
|
1065
|
+
return positionsLibAsk;
|
|
1066
|
+
}
|
|
1067
|
+
// `sent` is /me's `positions` block as the server resolved it (undefined: not told).
|
|
1068
|
+
function loadPositions(builder, sent) {
|
|
1069
|
+
var id = builder && builder.id != null ? String(builder.id) : null;
|
|
1070
|
+
if (!id) return;
|
|
1071
|
+
var as = protoAs();
|
|
1072
|
+
var key = id + '|' + JSON.stringify(sent === undefined ? null : sent);
|
|
1073
|
+
if (positionsAsked === key) return;
|
|
1074
|
+
positionsAsked = key;
|
|
1075
|
+
positionsLib().then(function (lib) {
|
|
1076
|
+
if (!lib || positionsAsked !== key) return;
|
|
1077
|
+
var p = lib.positionsFor({ me: { builder: builder, positions: sent }, as: as });
|
|
1078
|
+
try { window.sessionStorage.setItem(POSITIONS_KEY, JSON.stringify({ id: id, as: as, at: Date.now(), value: p })); } catch (_) { /* private mode */ }
|
|
1079
|
+
settlePositions(p);
|
|
1080
|
+
applyAccess();
|
|
1081
|
+
}, function () { /* cosmetic: unknown stays today's nav */ });
|
|
1082
|
+
}
|
|
1083
|
+
|
|
998
1084
|
// task 1003117 (R06 of goal 1000074): EMPHASISE the Studio nav entry for a
|
|
999
1085
|
// builder whose craft includes artist — the "emphasized entry for artist-craft
|
|
1000
1086
|
// builders" half of artist mode. Cosmetic only (the page is open to every rank,
|
|
@@ -1077,12 +1163,17 @@
|
|
|
1077
1163
|
access.founding = (state.founding && typeof state.founding === 'object') ? state.founding : null;
|
|
1078
1164
|
}
|
|
1079
1165
|
if (state.builder) { renderUser(state.builder); applyCraftEmphasis(state.builder); }
|
|
1166
|
+
// task 1004713: which seats this builder holds — /me's server-resolved block.
|
|
1167
|
+
if (state.builder && access.authed === true) loadPositions(state.builder, state.positions);
|
|
1080
1168
|
}
|
|
1081
1169
|
document.querySelectorAll('#app-sidebar [data-gate]').forEach(function (el) {
|
|
1082
1170
|
var ok = gateAllows(el.dataset.gate);
|
|
1083
1171
|
// A space-separated list is any-of: the Deploy item is the provisioning door's on the
|
|
1084
1172
|
// platform hall and the render-deploy module's on a Render project's hall (task 1004270).
|
|
1085
1173
|
if (ok && el.dataset.module && !el.dataset.module.split(' ').some(moduleOn)) ok = false;
|
|
1174
|
+
// task 1004713: a governing surface also needs a held seat — once the seats are
|
|
1175
|
+
// KNOWN (/me's server-resolved positions). Unknown (null) is today's nav.
|
|
1176
|
+
if (ok && el.dataset.position && access.positions && !access.positions.has_position) ok = false;
|
|
1086
1177
|
el.hidden = !ok;
|
|
1087
1178
|
});
|
|
1088
1179
|
// task 1004493: the craft mode then takes away the tabs its craft does not need.
|
|
@@ -1311,7 +1402,10 @@
|
|
|
1311
1402
|
});
|
|
1312
1403
|
}
|
|
1313
1404
|
function probeMe(otherProfile) {
|
|
1314
|
-
api.request('GET', '/api/bongos/me')
|
|
1405
|
+
var meRead = api.request('GET', '/api/bongos/me');
|
|
1406
|
+
// the governor pages' living model reads /me too: it takes this answer (gov-feeds.js)
|
|
1407
|
+
HALL_READS['/me'] = meRead.then(function (res) { return res && res.ok ? res.data : (res && res.status === 403 ? false : null); }, function () { return null; });
|
|
1408
|
+
meRead.then(function (res) {
|
|
1315
1409
|
if (res.status === 401) { applyAccess({ authed: false }); return null; }
|
|
1316
1410
|
if (!res.ok) return null;
|
|
1317
1411
|
return res.data;
|
|
@@ -1336,6 +1430,8 @@
|
|
|
1336
1430
|
needs: me.needs || null,
|
|
1337
1431
|
// task 1004422: project founding mode, for the band and the asleep rooms.
|
|
1338
1432
|
founding: me.founding_mode || null,
|
|
1433
|
+
// task 1004713: the government positions this builder holds (server-resolved).
|
|
1434
|
+
positions: me.positions || null,
|
|
1339
1435
|
builder: me.builder,
|
|
1340
1436
|
});
|
|
1341
1437
|
}).catch(function () { /* cosmetic only */ });
|
|
@@ -1343,6 +1439,8 @@
|
|
|
1343
1439
|
|
|
1344
1440
|
// ---------- boot (defer = DOM parsed; render synchronously) ----------
|
|
1345
1441
|
|
|
1442
|
+
// task 1004685: the seats last seen this session, so the first paint is right.
|
|
1443
|
+
settlePositions(cachedPositions(null, protoAs()));
|
|
1346
1444
|
renderSkipLink();
|
|
1347
1445
|
renderSidebar();
|
|
1348
1446
|
renderTopbar();
|
|
@@ -1383,5 +1481,7 @@
|
|
|
1383
1481
|
applyTheme: applyTheme,
|
|
1384
1482
|
// task 1004477: a page that renders an exit after boot asks the shell to fill it.
|
|
1385
1483
|
fillExits: TRAIL.fillExits,
|
|
1484
|
+
// task 1004713: the seats this viewer holds (null while unknown).
|
|
1485
|
+
positions: function () { return access.positions; },
|
|
1386
1486
|
};
|
|
1387
1487
|
})();
|
|
@@ -194,6 +194,7 @@
|
|
|
194
194
|
if (item.subject_type === 'genesis_stage') return 'genesis';
|
|
195
195
|
if (areaOf(item)) return 'matter';
|
|
196
196
|
if (item.subject && item.subject.kind === 'decision_rules') return 'rules';
|
|
197
|
+
if (item.subject && item.subject.kind === 'laws') return 'law';
|
|
197
198
|
return 'amendment';
|
|
198
199
|
}
|
|
199
200
|
// The proposer's own words for a sitting.
|
|
@@ -201,7 +202,7 @@
|
|
|
201
202
|
var s = item && item.subject;
|
|
202
203
|
if (!s) return '';
|
|
203
204
|
var k = subjectKind(item);
|
|
204
|
-
if (k === 'amendment' || k === 'rules') return firstPara(s.rationale_md);
|
|
205
|
+
if (k === 'amendment' || k === 'rules' || k === 'law') return firstPara(s.rationale_md);
|
|
205
206
|
if (k === 'matter') return firstPara(s.detail_md);
|
|
206
207
|
if (k === 'idea') {
|
|
207
208
|
var f = s.field_values || {};
|
|
@@ -232,6 +233,13 @@
|
|
|
232
233
|
});
|
|
233
234
|
return rows.length ? { rows: rows } : null;
|
|
234
235
|
}
|
|
236
|
+
if (k === 'law') {
|
|
237
|
+
// task 1004706: each law it enacts is inserted; each it repeals, struck
|
|
238
|
+
var lp = s.proposed && s.proposed.laws ? s.proposed.laws : {};
|
|
239
|
+
var lrows = (Array.isArray(lp.enact) ? lp.enact : []).map(function (l) { return { label: 'law', struck: '', inserted: str(l.text) }; })
|
|
240
|
+
.concat((Array.isArray(lp.repeal) ? lp.repeal : []).map(function (id) { return { label: 'repeal', struck: 'law ' + str(id), inserted: '' }; }));
|
|
241
|
+
return lrows.length ? { rows: lrows } : null;
|
|
242
|
+
}
|
|
235
243
|
if (k === 'amendment') {
|
|
236
244
|
var live = constitution && constitution.board ? constitution.board : null;
|
|
237
245
|
var p = s.proposed || {};
|
|
@@ -687,6 +695,11 @@
|
|
|
687
695
|
ACT_ROUTES.builder_budget = {
|
|
688
696
|
budget: function (id, inp) { return inp.option ? call('PATCH', '/builders/' + id + '/budget', { monthly_budget_usd: inp.option === 'none' ? null : Number(inp.option) }) : null; },
|
|
689
697
|
};
|
|
698
|
+
// task 1004712: a dry pot's borrow from the reserve, answered by its seat
|
|
699
|
+
// (POST /government/treasury/borrows/:id/answer; the chip's key is lend, half or no).
|
|
700
|
+
ACT_ROUTES.treasury_spending = {
|
|
701
|
+
answer: function (id, inp) { return inp.option ? post('/government/treasury/borrows/' + id + '/answer', { key: str(inp.option) }) : null; },
|
|
702
|
+
};
|
|
690
703
|
ACT_ROUTES.signed_criterion = { unsign: function (id, inp) { return post('/done-when/' + id + '/unsatisfy', { reason: str(inp.label) || 'undone on the floor desk' }); } };
|
|
691
704
|
// The same acts at a building a sitting decides (task 1004561): filed as the
|
|
692
705
|
// building's matter, which carries the act out once it passes. Each returns
|
|
@@ -743,6 +756,10 @@
|
|
|
743
756
|
var text = str(inp.text).trim();
|
|
744
757
|
if (s.kind === 'amendment') return post('/government/board/items', { subject_type: 'constitutional_amendment', proposal: s.proposed, rationale_md: text });
|
|
745
758
|
if (s.kind === 'rules') return post('/government/board/decision-rules', { rules: (s.proposed && s.proposed.decision_rules) || [], rationale_md: text });
|
|
759
|
+
if (s.kind === 'law') {
|
|
760
|
+
var lw = (s.proposed && s.proposed.laws) || {};
|
|
761
|
+
return post('/government/board/laws', { enact: lw.enact || [], repeal: lw.repeal || [], rationale_md: text });
|
|
762
|
+
}
|
|
746
763
|
if (s.kind === 'matter') {
|
|
747
764
|
var body = { area: s.area, title: s.title || cv.title, detail_md: text };
|
|
748
765
|
if (s.action) body.action = s.action;
|