@bongos/core 1.20.80 → 1.20.81
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.bongos-core.json +53 -33
- package/clients/bongos-client/README.md +1 -1
- package/clients/bongos-client/bongos-client.global.js +6 -0
- package/clients/bongos-client/index.cjs +6 -0
- package/clients/bongos-client/index.d.ts +10 -0
- package/clients/bongos-client/index.mjs +6 -0
- package/docs/api/openapi.json +200 -4
- package/docs/api-reference.md +5 -2
- package/docs/copy-inventory.md +59 -53
- package/docs/copy-registry.json +120 -66
- package/docs/module-api-changelog.md +2 -0
- package/docs/page-inventory.json +2 -1
- package/docs/page-readings.json +86 -81
- package/modules/autonomy/cadence.js +3 -0
- package/modules/autonomy/db.js +136 -0
- package/modules/autonomy/fence.js +88 -3
- package/modules/autonomy/migrations/autonomy_005_builder_scope.sql +55 -0
- package/modules/autonomy/routes/autonomy.js +123 -3
- package/modules/government/catalog.js +9 -1
- package/modules/government/migrations/government_022_autonomy_run.sql +38 -0
- package/modules/hall-ui/public/gate.html +5 -2
- package/modules/hall-ui/public/gate.js +73 -4
- package/modules/hall-ui/public/settings-autobongos.js +156 -0
- package/modules/hall-ui/public/settings.html +19 -0
- package/modules/hall-ui/public/settings.js +1 -0
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/release-notes.json +6 -0
- package/src/module-api.js +1 -1
- package/tests/autonomy_builder_scope.mjs +474 -0
- package/tests/autonomy_fence_priority.mjs +3 -1
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
// modules/hall-ui/public/settings-autobongos.js — the "Your Autobongos runner"
|
|
2
|
+
// panel on /builders/settings (task 1004501).
|
|
3
|
+
//
|
|
4
|
+
// WHY THE PANEL EXISTS. The fence used to be one switch and one goal list for
|
|
5
|
+
// every runner on the instance. Owner ruling, 2026-10-01: each builder says which
|
|
6
|
+
// work THEIR runner takes, and a builder who has said nothing gets no autonomous
|
|
7
|
+
// work. This is where they say it.
|
|
8
|
+
//
|
|
9
|
+
// WHAT IT READS. GET /autonomy/fence answers with the caller's EFFECTIVE fence: the
|
|
10
|
+
// project allowlist narrowed to their picks, plus `scope` (what they picked, whether
|
|
11
|
+
// they may run a runner, whether the owner paused them) and `project` (the
|
|
12
|
+
// unnarrowed allowlist they choose from). One read, so the panel cannot disagree
|
|
13
|
+
// with what the builder's runner is told. The server decides every one of those
|
|
14
|
+
// facts; this page only draws them.
|
|
15
|
+
//
|
|
16
|
+
// WHAT IT WRITES. PUT /autonomy/me/goals with the whole list, on Save. The route
|
|
17
|
+
// refuses a goal that is not allowlisted (409), and it is behind `autonomy.run`, so
|
|
18
|
+
// a builder who may not run a runner is told so here instead of shown a form that
|
|
19
|
+
// would fail.
|
|
20
|
+
//
|
|
21
|
+
// Its own file on the settings-interaction.js precedent: settings.js sits against
|
|
22
|
+
// the 1500-line ratchet, and this panel shares nothing with the rest of the page.
|
|
23
|
+
|
|
24
|
+
(() => {
|
|
25
|
+
'use strict';
|
|
26
|
+
|
|
27
|
+
const API = '/api/bongos';
|
|
28
|
+
const { escapeHtml, $ } = window.OTB;
|
|
29
|
+
const { emptyStateHtml } = window.OTBKit;
|
|
30
|
+
const toast = (msg) => window.OTB.toast(msg);
|
|
31
|
+
const api = window.BongosClient.createClient({ baseUrl: '', credentials: 'same-origin', throwOnError: false });
|
|
32
|
+
|
|
33
|
+
const toAuth = () => window.location.assign(`${API}/auth/web/start`);
|
|
34
|
+
|
|
35
|
+
// The lines above the form: each one says why the runner might be idle, in the
|
|
36
|
+
// order the server checks them, so the first line a builder reads is the reason.
|
|
37
|
+
function noticesHtml(fence) {
|
|
38
|
+
const project = fence.project || {};
|
|
39
|
+
const scope = fence.scope || {};
|
|
40
|
+
const out = [];
|
|
41
|
+
if (project.enabled !== true) {
|
|
42
|
+
out.push(`The project's runner switch is off right now${project.paused_reason ? `: ${escapeHtml(project.paused_reason)}` : ''}. Your choices are kept and apply when it is back on.`);
|
|
43
|
+
}
|
|
44
|
+
if (scope.owner_paused) {
|
|
45
|
+
out.push(`The owner paused your runner${scope.owner_paused_reason ? `: ${escapeHtml(scope.owner_paused_reason)}` : ''}. Only the owner can resume it.`);
|
|
46
|
+
}
|
|
47
|
+
return out.map((t) => `<p class="prow__hint">${t}</p>`).join('');
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Goal names, by id. The fence carries only ids and the owner's note, so the
|
|
51
|
+
// names come from GET /goals — the list the Goals page draws for this same
|
|
52
|
+
// builder, so it names only goals they can already see. Best-effort: a failed
|
|
53
|
+
// read leaves the map empty and a row falls back to its number.
|
|
54
|
+
let goalNames = new Map();
|
|
55
|
+
async function loadGoalNames() {
|
|
56
|
+
try {
|
|
57
|
+
const res = await api.request('GET', `${API}/goals`);
|
|
58
|
+
if (res.ok && res.data && Array.isArray(res.data.goals)) {
|
|
59
|
+
goalNames = new Map(res.data.goals.map((g) => [Number(g.id), g.title]));
|
|
60
|
+
}
|
|
61
|
+
} catch (_) { /* names are a nicety; the picker works without them */ }
|
|
62
|
+
}
|
|
63
|
+
const goalLabel = (id) => goalNames.get(Number(id)) || `Goal ${id}`;
|
|
64
|
+
|
|
65
|
+
function render(fence) {
|
|
66
|
+
const body = $('#autobongos-body');
|
|
67
|
+
if (!body) return;
|
|
68
|
+
const scope = fence.scope || {};
|
|
69
|
+
if (scope.may_run !== true) {
|
|
70
|
+
body.innerHTML = emptyStateHtml('Your rank cannot run an Autobongos runner on this project. Ask the owner if you need one.');
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
const goals = (fence.project && Array.isArray(fence.project.goals)) ? fence.project.goals : [];
|
|
74
|
+
if (!goals.length) {
|
|
75
|
+
body.innerHTML = noticesHtml(fence) + emptyStateHtml('The project has not allowed any goals for runners yet, so there is nothing to choose from.');
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
const picked = new Set((scope.goals || []).map(Number));
|
|
79
|
+
body.innerHTML = `${noticesHtml(fence)}
|
|
80
|
+
<form id="autobongos-form">
|
|
81
|
+
<div class="prows">
|
|
82
|
+
${goals.map((g) => {
|
|
83
|
+
const id = `autobongos-goal-${escapeHtml(String(g.goal_id))}`;
|
|
84
|
+
return `<label class="prow prow--pick" for="${id}">
|
|
85
|
+
<input type="checkbox" id="${id}" name="autobongos-goal" value="${escapeHtml(String(g.goal_id))}"${picked.has(Number(g.goal_id)) ? ' checked' : ''}>
|
|
86
|
+
<span class="prow__main">
|
|
87
|
+
<span class="prow__label">${escapeHtml(goalLabel(g.goal_id))}</span>
|
|
88
|
+
<span class="prow__desc">${escapeHtml([goalNames.has(Number(g.goal_id)) ? `goal ${g.goal_id}` : '', g.note || ''].filter(Boolean).join(' · '))}</span>
|
|
89
|
+
</span>
|
|
90
|
+
</label>`;
|
|
91
|
+
}).join('')}
|
|
92
|
+
</div>
|
|
93
|
+
<div class="settings-card">
|
|
94
|
+
<button type="submit" class="settings-btn" id="autobongos-save">Save</button>
|
|
95
|
+
<span class="settings-card__hint">${picked.size ? `Your runner works ${picked.size} goal${picked.size === 1 ? '' : 's'}.` : 'Your runner takes no work until you choose at least one goal.'}</span>
|
|
96
|
+
</div>
|
|
97
|
+
</form>`;
|
|
98
|
+
$('#autobongos-form').addEventListener('submit', (e) => {
|
|
99
|
+
e.preventDefault();
|
|
100
|
+
const ids = [...e.target.querySelectorAll('input[name="autobongos-goal"]:checked')].map((i) => Number(i.value));
|
|
101
|
+
save(ids);
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
async function load() {
|
|
106
|
+
const res = await api.request('GET', `${API}/autonomy/fence`);
|
|
107
|
+
if (res.status === 401) { toAuth(); return null; }
|
|
108
|
+
if (!res.ok) throw new Error(`fence GET → ${res.status}`);
|
|
109
|
+
return res.data;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
async function save(goalIds) {
|
|
113
|
+
const status = $('#autobongos-status');
|
|
114
|
+
const btn = $('#autobongos-save');
|
|
115
|
+
if (status) status.textContent = 'Saving…';
|
|
116
|
+
if (btn) btn.disabled = true;
|
|
117
|
+
try {
|
|
118
|
+
const res = await api.request('PUT', `${API}/autonomy/me/goals`, { body: { goal_ids: goalIds } });
|
|
119
|
+
if (res.status === 401) { toAuth(); return; }
|
|
120
|
+
if (!res.ok) {
|
|
121
|
+
const env = res.data && res.data.error;
|
|
122
|
+
throw new Error((env && env.message) || `could not save (${res.status})`);
|
|
123
|
+
}
|
|
124
|
+
const msg = goalIds.length ? `Saved — your runner works ${goalIds.length} goal${goalIds.length === 1 ? '' : 's'}.` : 'Saved — your runner takes no work.';
|
|
125
|
+
if (status) status.textContent = msg;
|
|
126
|
+
toast(msg);
|
|
127
|
+
const fence = await load();
|
|
128
|
+
if (fence) render(fence);
|
|
129
|
+
} catch (err) {
|
|
130
|
+
console.error('[settings] save autobongos goals failed', err);
|
|
131
|
+
if (status) status.textContent = `Could not save: ${err.message}`;
|
|
132
|
+
toast('Could not save your runner’s goals. Try again.');
|
|
133
|
+
if (btn) btn.disabled = false;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
async function setup() {
|
|
138
|
+
const section = $('#autobongos-scroll');
|
|
139
|
+
if (!section) return;
|
|
140
|
+
try {
|
|
141
|
+
const [fence] = await Promise.all([load(), loadGoalNames()]);
|
|
142
|
+
if (!fence) return;
|
|
143
|
+
render(fence);
|
|
144
|
+
section.hidden = false;
|
|
145
|
+
} catch (err) {
|
|
146
|
+
// Its own try/catch, like every other panel: a failing read shows this
|
|
147
|
+
// panel's own error rather than taking the settings page down with it.
|
|
148
|
+
console.error('[settings] failed to load autobongos scope', err);
|
|
149
|
+
section.hidden = false;
|
|
150
|
+
$('#autobongos-body').innerHTML =
|
|
151
|
+
'<p class="voices-empty">Your runner settings could not be loaded. Reload the page to try again.</p>';
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
setup();
|
|
156
|
+
})();
|
|
@@ -163,6 +163,23 @@
|
|
|
163
163
|
<p class="section-note">Ending a session takes effect immediately; the token stops working on its very next request.</p>
|
|
164
164
|
</section>
|
|
165
165
|
|
|
166
|
+
<!-- YOUR AUTOBONGOS RUNNER — which goals your own unattended runner
|
|
167
|
+
works (task 1004501). Rendered by settings-autobongos.js against
|
|
168
|
+
GET /autonomy/fence (your effective fence) and PUT
|
|
169
|
+
/autonomy/me/goals. Picking nothing means your runner takes no
|
|
170
|
+
work. The project allowlist and the master switch stay the
|
|
171
|
+
owner's, on the Gate page. -->
|
|
172
|
+
<section class="scroll" id="autobongos-scroll" aria-labelledby="autobongos-h" data-group="access" hidden>
|
|
173
|
+
<h2 id="autobongos-h" class="scroll__h">Your Autobongos runner</h2>
|
|
174
|
+
<p class="scroll__lede">
|
|
175
|
+
Choose which goals your own runner works while you are away. You can
|
|
176
|
+
only choose from the goals the project allows. If you choose none, your
|
|
177
|
+
runner takes no work.
|
|
178
|
+
</p>
|
|
179
|
+
<div id="autobongos-body" aria-live="polite"></div>
|
|
180
|
+
<p class="settings-status" id="autobongos-status" role="status" aria-live="polite"></p>
|
|
181
|
+
</section>
|
|
182
|
+
|
|
166
183
|
<!-- IMAGE KEY — per-builder Gemini key (task 1013 / ADR 0073).
|
|
167
184
|
GET/PUT/DELETE /api/bongos/me/art-key/own. Write-only (set/replace/
|
|
168
185
|
remove); the full key is never shown again after save (masked,
|
|
@@ -425,5 +442,7 @@
|
|
|
425
442
|
<script src="/builders/settings-render.js?v=2026-09-16-render-levels"></script>
|
|
426
443
|
<!-- task 1004296: Settings → Software update. Own file on the same precedent. -->
|
|
427
444
|
<script src="/builders/settings-software-update.js?v=2026-09-26-update"></script>
|
|
445
|
+
<!-- task 1004501: Settings → Your Autobongos runner. Own file on the same precedent. -->
|
|
446
|
+
<script src="/builders/settings-autobongos.js?v=2026-10-01-autobongos"></script>
|
|
428
447
|
</body>
|
|
429
448
|
</html>
|
|
@@ -1066,6 +1066,7 @@
|
|
|
1066
1066
|
'privacy': 'account-hub-scroll',
|
|
1067
1067
|
'disciplines': 'craft-scroll',
|
|
1068
1068
|
'cli': 'cli-scroll',
|
|
1069
|
+
'autobongos': 'autobongos-scroll',
|
|
1069
1070
|
'art-key': 'art-key',
|
|
1070
1071
|
'interaction': 'interaction-scroll',
|
|
1071
1072
|
'wandering': 'wandering-scroll',
|
package/package-lock.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bongos/core",
|
|
3
|
-
"version": "1.20.
|
|
3
|
+
"version": "1.20.81",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@bongos/core",
|
|
9
|
-
"version": "1.20.
|
|
9
|
+
"version": "1.20.81",
|
|
10
10
|
"license": "AGPL-3.0-or-later",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"express": "^4.21.2",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bongos/core",
|
|
3
|
-
"version": "1.20.
|
|
3
|
+
"version": "1.20.81",
|
|
4
4
|
"description": "Cloud Bongos — the AI-first build platform core (GDS + platform surfaces + module system), installed as a versioned dependency (ADR 0108).",
|
|
5
5
|
"license": "AGPL-3.0-or-later",
|
|
6
6
|
"main": "src/platform-server.js",
|
package/release-notes.json
CHANGED
|
@@ -8625,5 +8625,11 @@
|
|
|
8625
8625
|
"id": "1003907",
|
|
8626
8626
|
"text": "Autobongos has now been proven against the live project: it shipped work by itself with nobody watching, refused every kind of work it is not allowed to touch, and recovered from restarts and network failures on its own. The o"
|
|
8627
8627
|
}
|
|
8628
|
+
],
|
|
8629
|
+
"1.20.81": [
|
|
8630
|
+
{
|
|
8631
|
+
"id": "1004501",
|
|
8632
|
+
"text": "Each builder now chooses which goals their own Autobongos runner works, in Settings, from the goals the project allows. A builder who chooses nothing gets no unattended work. Who may run a runner at all is now a project permis"
|
|
8633
|
+
}
|
|
8628
8634
|
]
|
|
8629
8635
|
}
|
package/src/module-api.js
CHANGED
|
@@ -75,7 +75,7 @@ const { responsibilityFor, ROLE_RESPONSIBILITIES } = require('./role-responsibil
|
|
|
75
75
|
// MAJOR (see allowBoxScope below): passes the request through untouched.
|
|
76
76
|
function deprecatedNoopMiddleware(_req, _res, next) { next(); }
|
|
77
77
|
|
|
78
|
-
const CORE_VERSION = '1.20.
|
|
78
|
+
const CORE_VERSION = '1.20.81'; // CI auto-patch carrier (ADR 0161); changelog: docs/module-api-changelog.md
|
|
79
79
|
|
|
80
80
|
// A namespaced logger so a module's log lines are attributable + consistent.
|
|
81
81
|
// Usage: const log = api.logger('discord'); log.info('mounted');
|