instar 1.3.493 → 1.3.495
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/dashboard/index.html +6 -0
- package/dashboard/mandates.js +147 -3
- package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
- package/dist/core/PostUpdateMigrator.js +18 -0
- package/dist/core/PostUpdateMigrator.js.map +1 -1
- package/dist/messaging/slack/SocketModeClient.d.ts +10 -0
- package/dist/messaging/slack/SocketModeClient.d.ts.map +1 -1
- package/dist/messaging/slack/SocketModeClient.js +77 -49
- package/dist/messaging/slack/SocketModeClient.js.map +1 -1
- package/dist/scaffold/templates.d.ts.map +1 -1
- package/dist/scaffold/templates.js +1 -0
- package/dist/scaffold/templates.js.map +1 -1
- package/dist/server/CapabilityIndex.d.ts.map +1 -1
- package/dist/server/CapabilityIndex.js +2 -1
- package/dist/server/CapabilityIndex.js.map +1 -1
- package/dist/server/routes.d.ts.map +1 -1
- package/dist/server/routes.js +25 -0
- package/dist/server/routes.js.map +1 -1
- package/package.json +1 -1
- package/src/data/builtin-manifest.json +63 -63
- package/src/scaffold/templates.ts +1 -0
- package/upgrades/1.3.494.md +27 -0
- package/upgrades/1.3.495.md +29 -0
- package/upgrades/side-effects/mandate-grant-form.md +79 -0
- package/upgrades/side-effects/socketmode-ws-leak-fix.md +74 -0
package/dashboard/index.html
CHANGED
|
@@ -809,6 +809,12 @@
|
|
|
809
809
|
.mnd-btn { padding: 6px 14px; cursor: pointer; }
|
|
810
810
|
.mnd-btn-danger { color: #f85149; }
|
|
811
811
|
.mnd-dead-note { font-size: 13px; color: var(--text-dim); font-style: italic; }
|
|
812
|
+
.mnd-grants-head { font-size: 13px; color: var(--text-dim); }
|
|
813
|
+
.mnd-grants { margin: 0; padding-left: 18px; font-size: 13px; line-height: 1.7; }
|
|
814
|
+
.mnd-grant-details { font-size: 13px; }
|
|
815
|
+
.mnd-grant-summary { cursor: pointer; color: var(--text-dim); }
|
|
816
|
+
.mnd-grant-row { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; margin: 8px 0 4px; }
|
|
817
|
+
.mnd-grant-field { min-width: 130px; max-width: 100%; padding: 6px 8px; }
|
|
812
818
|
.mnd-notice { min-height: 20px; font-size: 14px; color: #3fb950; }
|
|
813
819
|
.mnd-issue-form { display: flex; flex-direction: column; gap: 14px; max-width: 640px; padding: 12px 0; }
|
|
814
820
|
.mnd-issue-form label { display: flex; flex-direction: column; gap: 4px; font-size: 15px; color: var(--text-bright); }
|
package/dashboard/mandates.js
CHANGED
|
@@ -20,6 +20,28 @@ const AUTHORITIES_TEMPLATE = JSON.stringify([
|
|
|
20
20
|
{ action: 'sign-code-review', bounds: { artifact: 'migration-port', mutual: true } },
|
|
21
21
|
], null, 2);
|
|
22
22
|
|
|
23
|
+
// Mirrors FLOOR_ACTIONS in src/permissions/RolePolicy.ts — the enumerated
|
|
24
|
+
// never-discretionary actions a user grant can lift. Kept in sync by the
|
|
25
|
+
// dashboard-mandatesTab test, which compares this list against the source enum.
|
|
26
|
+
const FLOOR_ACTIONS = [
|
|
27
|
+
'money-movement',
|
|
28
|
+
'prod-deploy',
|
|
29
|
+
'credential-access',
|
|
30
|
+
'destructive-data',
|
|
31
|
+
'external-send',
|
|
32
|
+
'grant-authority',
|
|
33
|
+
];
|
|
34
|
+
|
|
35
|
+
// Mobile-first: the operator picks a duration, never types a timestamp.
|
|
36
|
+
// The submit handler clamps to the mandate's own expiry (a grant can never
|
|
37
|
+
// outlive the mandate that carries it — the server enforces the same rule).
|
|
38
|
+
const GRANT_DURATIONS = [
|
|
39
|
+
{ label: '15 minutes', minutes: 15 },
|
|
40
|
+
{ label: '1 hour', minutes: 60 },
|
|
41
|
+
{ label: '4 hours', minutes: 240 },
|
|
42
|
+
{ label: '24 hours', minutes: 1440 },
|
|
43
|
+
];
|
|
44
|
+
|
|
23
45
|
function esc(s) {
|
|
24
46
|
return String(s ?? '').replace(/[&<>"']/g, (c) => ({
|
|
25
47
|
'&': '&', '<': '<', '>': '>', '"': '"', "'": ''',
|
|
@@ -39,7 +61,57 @@ function fmtWhen(iso) {
|
|
|
39
61
|
} catch { return String(iso); }
|
|
40
62
|
}
|
|
41
63
|
|
|
42
|
-
|
|
64
|
+
function userLabel(slackUserId, slackUsers) {
|
|
65
|
+
const u = (slackUsers || []).find((x) => x.slackUserId === slackUserId);
|
|
66
|
+
return u ? `${u.name} (${slackUserId})` : slackUserId;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** The grants a mandate already carries, in operator language. */
|
|
70
|
+
export function renderGrants(m, slackUsers) {
|
|
71
|
+
const grants = Array.isArray(m.grants) ? m.grants : [];
|
|
72
|
+
if (grants.length === 0) return '';
|
|
73
|
+
const rows = grants.map((g) => {
|
|
74
|
+
const expired = Date.parse(g.expiresAt) < Date.now();
|
|
75
|
+
const badge = expired
|
|
76
|
+
? '<span class="mnd-badge mnd-dead">expired</span>'
|
|
77
|
+
: '<span class="mnd-badge mnd-ok">active</span>';
|
|
78
|
+
return `<li>${badge} <strong>${esc(userLabel(g.grantedTo, slackUsers))}</strong> may <code>${esc(g.floorAction)}</code> until ${fmtWhen(g.expiresAt)} — authorized by ${esc(g.authorizedBy)}</li>`;
|
|
79
|
+
}).join('');
|
|
80
|
+
return `<div class="mnd-grants-head">User grants this mandate carries:</div><ul class="mnd-grants">${rows}</ul>`;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* The add-grant form for an ACTIVE mandate. Mobile-first by design (the
|
|
85
|
+
* 2026-06-12 lesson, instar#1080): the operator PICKS a person and a duration —
|
|
86
|
+
* the only thing typed is the PIN. A free-text Slack-id input appears only
|
|
87
|
+
* when the user registry has nobody to offer.
|
|
88
|
+
*/
|
|
89
|
+
export function renderGrantForm(m, slackUsers) {
|
|
90
|
+
const users = (slackUsers || []).filter((u) => u.slackUserId);
|
|
91
|
+
const granteeField = users.length > 0
|
|
92
|
+
? `<select class="mnd-grant-field" data-grant-user="${esc(m.id)}">${
|
|
93
|
+
users.map((u) => `<option value="${esc(u.slackUserId)}">${esc(u.name)}${u.orgRole ? ` — ${esc(u.orgRole)}` : ''}</option>`).join('')
|
|
94
|
+
}</select>`
|
|
95
|
+
: `<input type="text" class="mnd-grant-field" data-grant-user="${esc(m.id)}" placeholder="Slack user id (e.g. U0…)" />`;
|
|
96
|
+
const actionField = `<select class="mnd-grant-field" data-grant-action="${esc(m.id)}">${
|
|
97
|
+
FLOOR_ACTIONS.map((a) => `<option value="${a}"${a === 'prod-deploy' ? ' selected' : ''}>${a}</option>`).join('')
|
|
98
|
+
}</select>`;
|
|
99
|
+
const durationField = `<select class="mnd-grant-field" data-grant-duration="${esc(m.id)}">${
|
|
100
|
+
GRANT_DURATIONS.map((d) => `<option value="${d.minutes}"${d.minutes === 60 ? ' selected' : ''}>${d.label}</option>`).join('')
|
|
101
|
+
}</select>`;
|
|
102
|
+
return `<details class="mnd-grant-details"><summary class="mnd-grant-summary">Grant a user a floor action (PIN required)</summary>
|
|
103
|
+
<div class="mnd-grant-row">
|
|
104
|
+
${granteeField}
|
|
105
|
+
${actionField}
|
|
106
|
+
${durationField}
|
|
107
|
+
<input type="password" class="mnd-pin" data-grant-pin="${esc(m.id)}" placeholder="PIN" autocomplete="off" />
|
|
108
|
+
<button class="mnd-btn" data-grant="${esc(m.id)}">Grant</button>
|
|
109
|
+
</div>
|
|
110
|
+
<span class="mnd-hint">Lifts the picked person to ONE floor action for the picked window. Signed into this mandate by your PIN — revoking the mandate voids it; it can never outlive the mandate.</span>
|
|
111
|
+
</details>`;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export function renderMandates(list, slackUsers = []) {
|
|
43
115
|
if (!Array.isArray(list) || list.length === 0) {
|
|
44
116
|
return '<div class="mnd-empty">No mandates issued. The gate is deny-by-default: every delegated agent action refuses until you issue one.</div>';
|
|
45
117
|
}
|
|
@@ -60,6 +132,7 @@ export function renderMandates(list) {
|
|
|
60
132
|
<button class="mnd-btn mnd-btn-danger" data-revoke="${esc(m.id)}">Revoke</button>
|
|
61
133
|
</div>`
|
|
62
134
|
: `<div class="mnd-dead-note">${m.revoked ? `revoked ${fmtWhen(m.revoked.at)} — ${esc(m.revoked.reason)}` : `expired ${fmtWhen(m.expiresAt)}`}</div>`;
|
|
135
|
+
const grantUi = state === 'active' ? renderGrantForm(m, slackUsers) : '';
|
|
63
136
|
return `<div class="mnd-card">
|
|
64
137
|
<div class="mnd-card-head">
|
|
65
138
|
<span class="mnd-scope">${esc(m.scope)}</span>
|
|
@@ -68,6 +141,8 @@ export function renderMandates(list) {
|
|
|
68
141
|
</div>
|
|
69
142
|
<div class="mnd-meta">id <code>${esc(m.id)}</code> · agents <code>${esc(shortFp(m.agents?.[0]))}</code> + <code>${esc(shortFp(m.agents?.[1]))}</code> · by ${esc(m.author)} · expires ${fmtWhen(m.expiresAt)}</div>
|
|
70
143
|
<ul class="mnd-authorities">${authorities}</ul>
|
|
144
|
+
${renderGrants(m, slackUsers)}
|
|
145
|
+
${grantUi}
|
|
71
146
|
${revokeUi}
|
|
72
147
|
</div>`;
|
|
73
148
|
}).join('');
|
|
@@ -129,12 +204,18 @@ export function createController({ doc, els, fetchImpl }) {
|
|
|
129
204
|
|
|
130
205
|
let refreshErrorShown = false;
|
|
131
206
|
let autoOpenedIssueForm = false;
|
|
207
|
+
// Last-fetched state the grant submit handler needs: the mandate list (for
|
|
208
|
+
// the expiry clamp) — kept here, never re-derived from the DOM.
|
|
209
|
+
let lastMandates = [];
|
|
132
210
|
|
|
133
211
|
async function refresh() {
|
|
134
212
|
try {
|
|
135
|
-
const [mand, audit] = await Promise.all([
|
|
213
|
+
const [mand, audit, users] = await Promise.all([
|
|
136
214
|
fetchJson('/mandate'),
|
|
137
215
|
fetchJson('/mandate/audit?limit=200'),
|
|
216
|
+
// Registered Slack users feed the grant form's person picker. A failure
|
|
217
|
+
// here must never take down the tab — the form degrades to a text input.
|
|
218
|
+
fetchJson('/permissions/users').catch(() => ({ status: 0, body: null })),
|
|
138
219
|
]);
|
|
139
220
|
if (mand.status === 503) {
|
|
140
221
|
els.list.innerHTML = '<div class="mnd-empty">Mandate engine unavailable on this server (older version or init failure).</div>';
|
|
@@ -143,7 +224,9 @@ export function createController({ doc, els, fetchImpl }) {
|
|
|
143
224
|
return;
|
|
144
225
|
}
|
|
145
226
|
const mandates = mand.body?.mandates;
|
|
146
|
-
|
|
227
|
+
lastMandates = Array.isArray(mandates) ? mandates : [];
|
|
228
|
+
const slackUsers = users.status === 200 && Array.isArray(users.body?.users) ? users.body.users : [];
|
|
229
|
+
els.list.innerHTML = renderMandates(mandates, slackUsers);
|
|
147
230
|
els.audit.innerHTML = renderAudit(audit.body);
|
|
148
231
|
if (els.stamp) els.stamp.textContent = 'updated ' + new Date().toLocaleTimeString();
|
|
149
232
|
// Nothing issued yet → the issue form IS the page's call to action;
|
|
@@ -155,6 +238,7 @@ export function createController({ doc, els, fetchImpl }) {
|
|
|
155
238
|
// A persistent refresh error from a server restart-gap heals itself.
|
|
156
239
|
if (refreshErrorShown) { clearNote(); refreshErrorShown = false; }
|
|
157
240
|
wireRevokeButtons();
|
|
241
|
+
wireGrantButtons();
|
|
158
242
|
} catch (e) {
|
|
159
243
|
refreshErrorShown = true;
|
|
160
244
|
note('refresh failed: ' + (e?.message ?? e) + ' — retrying automatically.', 'error');
|
|
@@ -184,6 +268,66 @@ export function createController({ doc, els, fetchImpl }) {
|
|
|
184
268
|
});
|
|
185
269
|
}
|
|
186
270
|
|
|
271
|
+
function wireGrantButtons() {
|
|
272
|
+
els.list.querySelectorAll('[data-grant]').forEach((btn) => {
|
|
273
|
+
btn.onclick = async () => {
|
|
274
|
+
const id = btn.getAttribute('data-grant');
|
|
275
|
+
const userEl = els.list.querySelector(`[data-grant-user="${id}"]`);
|
|
276
|
+
const actionEl = els.list.querySelector(`[data-grant-action="${id}"]`);
|
|
277
|
+
const durEl = els.list.querySelector(`[data-grant-duration="${id}"]`);
|
|
278
|
+
const pinEl = els.list.querySelector(`[data-grant-pin="${id}"]`);
|
|
279
|
+
const grantedTo = (userEl?.value ?? '').trim();
|
|
280
|
+
const floorAction = actionEl?.value ?? 'prod-deploy';
|
|
281
|
+
const pin = pinEl?.value ?? '';
|
|
282
|
+
const problems = [];
|
|
283
|
+
if (!grantedTo) problems.push('• Pick (or type) who the grant is for.');
|
|
284
|
+
if (!pin) problems.push('• Type your dashboard PIN — granting a floor action is a human action; agent credentials are refused.');
|
|
285
|
+
if (problems.length > 0) {
|
|
286
|
+
note('Not granted — fix the following first:\n' + problems.join('\n'), 'error');
|
|
287
|
+
return;
|
|
288
|
+
}
|
|
289
|
+
// A grant can never outlive its mandate — clamp client-side so the
|
|
290
|
+
// operator's pick always succeeds (the server enforces the same rule
|
|
291
|
+
// by rejection; rejection is a worse experience than a shorter window).
|
|
292
|
+
const minutes = Number(durEl?.value ?? 60) || 60;
|
|
293
|
+
const mandate = lastMandates.find((m) => m.id === id);
|
|
294
|
+
const mandateExpiryMs = mandate ? Date.parse(mandate.expiresAt) : NaN;
|
|
295
|
+
let expiryMs = Date.now() + minutes * 60_000;
|
|
296
|
+
let clamped = false;
|
|
297
|
+
if (!isNaN(mandateExpiryMs) && expiryMs > mandateExpiryMs) { expiryMs = mandateExpiryMs; clamped = true; }
|
|
298
|
+
btn.disabled = true;
|
|
299
|
+
try {
|
|
300
|
+
const { status, body } = await fetchJson(`/mandate/${encodeURIComponent(id)}/grants`, {
|
|
301
|
+
method: 'POST',
|
|
302
|
+
headers: { 'Content-Type': 'application/json' },
|
|
303
|
+
body: JSON.stringify({
|
|
304
|
+
pin,
|
|
305
|
+
grants: [{
|
|
306
|
+
floorAction,
|
|
307
|
+
grantedTo,
|
|
308
|
+
authorizedBy: 'operator (dashboard PIN)',
|
|
309
|
+
expiresAt: new Date(expiryMs).toISOString(),
|
|
310
|
+
}],
|
|
311
|
+
}),
|
|
312
|
+
});
|
|
313
|
+
if (status === 201) {
|
|
314
|
+
note(`✓ Grant signed — ${grantedTo} may ${floorAction} until ${fmtWhen(new Date(expiryMs).toISOString())}${clamped ? ' (shortened to the mandate’s own expiry — a grant can never outlive its mandate)' : ''}.`, 'success');
|
|
315
|
+
await refresh();
|
|
316
|
+
} else {
|
|
317
|
+
note(`Not granted — the server refused: ${body?.error ?? `HTTP ${status}`}`, 'error');
|
|
318
|
+
}
|
|
319
|
+
} catch (e) {
|
|
320
|
+
// A network failure must neither strand the typed PIN (cleared in
|
|
321
|
+
// finally) nor fail silently.
|
|
322
|
+
note(`Not granted — request failed: ${e?.message ?? e}. Nothing was signed; try again.`, 'error');
|
|
323
|
+
} finally {
|
|
324
|
+
if (pinEl) pinEl.value = ''; // never retain the PIN — on ANY path
|
|
325
|
+
btn.disabled = false;
|
|
326
|
+
}
|
|
327
|
+
};
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
|
|
187
331
|
// Validate EVERYTHING client-side and report every problem at once —
|
|
188
332
|
// never POST a request we know the server will refuse, and never let the
|
|
189
333
|
// operator discover a missing field one transient error at a time.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PostUpdateMigrator.d.ts","sourceRoot":"","sources":["../../src/core/PostUpdateMigrator.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"PostUpdateMigrator.d.ts","sourceRoot":"","sources":["../../src/core/PostUpdateMigrator.ts"],"names":[],"mappings":"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"}
|
|
@@ -5027,6 +5027,24 @@ Create worktrees for collaborator repos with \`instar worktree create <branch>\`
|
|
|
5027
5027
|
patched = true;
|
|
5028
5028
|
result.upgraded.push('CLAUDE.md: added Coordination Mandate awareness section');
|
|
5029
5029
|
}
|
|
5030
|
+
// Phone-first floor grants (Mobile-Complete Operator Actions, instar#1080)
|
|
5031
|
+
// — agents that already carry the Coordination Mandate section must learn
|
|
5032
|
+
// to point operators at the Mandates-tab grant form, never at a terminal
|
|
5033
|
+
// command. Content-sniffed on the bullet's distinctive lead; inserted
|
|
5034
|
+
// inside the existing section when its anchor line is intact, appended
|
|
5035
|
+
// otherwise so a hand-edited section still gains the guidance.
|
|
5036
|
+
if (content.includes('/mandate/evaluate') && !content.includes('User floor-action grants are phone-first')) {
|
|
5037
|
+
const grantBullet = `- **User floor-action grants are phone-first.** When the operator needs to grant a USER a floor action (e.g. "let Mia prod-deploy for an hour"), the Mandates tab carries a grant form on every active mandate: pick the person (from the registered-user list), pick the action and duration, type the PIN, tap Grant. Send them the dashboard link — NEVER a terminal command or a hand-built API call (Mobile-Complete Operator Actions). The grant is signed into the mandate, clamped to the mandate's expiry, and voided by revoking the mandate.`;
|
|
5038
|
+
const grantAnchor = 'point them at the dashboard **Mandates tab** (issue/revoke forms + the decision audit live there).';
|
|
5039
|
+
if (content.includes(grantAnchor)) {
|
|
5040
|
+
content = content.replace(grantAnchor, grantAnchor + '\n' + grantBullet);
|
|
5041
|
+
}
|
|
5042
|
+
else {
|
|
5043
|
+
content += '\n' + grantBullet + '\n';
|
|
5044
|
+
}
|
|
5045
|
+
patched = true;
|
|
5046
|
+
result.upgraded.push('CLAUDE.md: added phone-first floor-grant guidance to the Coordination Mandate section');
|
|
5047
|
+
}
|
|
5030
5048
|
// ReviewExchange protocol (coordination-mandate spec §7 G2.3) — Agent
|
|
5031
5049
|
// Awareness backfill. Content-sniffed on the distinctive route prefix.
|
|
5032
5050
|
if (!content.includes('/review-exchange')) {
|