@yemi33/minions 0.1.2390 → 0.1.2392
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/js/refresh.js +1 -1
- package/dashboard/js/render-work-items.js +4 -9
- package/dashboard/js/settings.js +46 -10
- package/docs/deprecated.json +6 -6
- package/docs/slim-ux/concepts.md +739 -586
- package/package.json +1 -1
package/dashboard/js/refresh.js
CHANGED
|
@@ -155,7 +155,7 @@ const RENDER_VERSIONS = {
|
|
|
155
155
|
// chip row into its own non-interactive "Branch" field (W-mr2qjr3b0002522f).
|
|
156
156
|
// Bumped 8→9 for paused pre-dispatch evaluation guidance.
|
|
157
157
|
// Bumped 9→10: row actions now preserve work-item source scope when IDs collide.
|
|
158
|
-
workItems:
|
|
158
|
+
workItems: 11,
|
|
159
159
|
skills: 1,
|
|
160
160
|
commands: 1,
|
|
161
161
|
mcpServers: 1,
|
|
@@ -179,13 +179,9 @@ function wiRow(item) {
|
|
|
179
179
|
: (item.branchStrategy === 'shared-branch' && item.status === 'done')
|
|
180
180
|
? '<span style="font-size:var(--text-xs);color:var(--muted)" title="Part of shared branch — aggregate PR created at verify stage">shared branch</span>'
|
|
181
181
|
: '<span style="color:var(--muted)">—</span>';
|
|
182
|
-
// W-mqrdn6qq
|
|
183
|
-
//
|
|
184
|
-
//
|
|
185
|
-
// demotion (engine/dispatch.js writeDispatchResult / force-demote path).
|
|
186
|
-
var isNonRetryableFail = !!item._failureClass
|
|
187
|
-
|| /^Non-retryable failure:/i.test(item.failReason || '')
|
|
188
|
-
|| /^Project "[^"]+" not found\./i.test(item.failReason || '');
|
|
182
|
+
// W-mqrdn6qq / W-mrkqc0pl — ALL failure/error snippets (retryable AND
|
|
183
|
+
// non-retryable) surface their red failReason snippet in the PR column,
|
|
184
|
+
// never the Agent column.
|
|
189
185
|
var failSnippet = item.failReason
|
|
190
186
|
? '<span style="display:block;font-size:var(--text-xs);color:var(--red)" title="' + escapeHtml(item.failReason) + '">' + escapeHtml(item.failReason.slice(0, 30)) + '</span>'
|
|
191
187
|
: '';
|
|
@@ -234,9 +230,8 @@ function wiRow(item) {
|
|
|
234
230
|
(item.completedAgents && item.completedAgents.length > 0
|
|
235
231
|
? '<span class="pr-agent">' + escapeHtml(item.completedAgents.join(', ')) + '</span>'
|
|
236
232
|
: '<span class="pr-agent">' + escapeHtml(item.dispatched_to || item.agent || '—') + '</span>') +
|
|
237
|
-
(failSnippet && !isNonRetryableFail ? failSnippet : '') +
|
|
238
233
|
'</td>' +
|
|
239
|
-
'<td>' + prLink + (failSnippet
|
|
234
|
+
'<td>' + prLink + (failSnippet ? failSnippet : '') + '</td>' +
|
|
240
235
|
'<td><span class="pr-date">' + escapeHtml((item.created || '').slice(0, 16).replace('T', ' ')) + '</span></td>' +
|
|
241
236
|
'<td style="white-space:nowrap;font-size:var(--text-xs);color:var(--muted)">' +
|
|
242
237
|
(function() {
|
package/dashboard/js/settings.js
CHANGED
|
@@ -33,6 +33,38 @@ function _isCurrentModelLoad(scope, key, token) {
|
|
|
33
33
|
return _modelLoadEpochs[scope][key] === token;
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
+
// Per-open dedup cache for /api/runtimes/<name>/models payloads.
|
|
37
|
+
// initRuntimeFleetUI() fans out one model fetch per agent PLUS default + CC.
|
|
38
|
+
// When the whole fleet shares a runtime (the common case) those are
|
|
39
|
+
// byte-identical requests, and each one makes the server reloadConfig() from
|
|
40
|
+
// disk + re-run model discovery. Collapsing them to one request per distinct
|
|
41
|
+
// runtime per Settings open removes the N+2 → 1 duplicate round-trips (measured
|
|
42
|
+
// 10 → 1 for an 8-agent single-runtime fleet). forceRefresh (the ↻ button)
|
|
43
|
+
// bypasses the cache and repopulates it with the fresh list. Transient
|
|
44
|
+
// failures are NOT cached so a blip can't poison every agent cell for the open.
|
|
45
|
+
let _modelFetchCache = new Map();
|
|
46
|
+
function _resetModelFetchCache() { _modelFetchCache = new Map(); }
|
|
47
|
+
function _fetchRuntimeModelsPayload(runtimeName, forceRefresh) {
|
|
48
|
+
if (!runtimeName) return Promise.resolve({ models: null });
|
|
49
|
+
if (!forceRefresh) {
|
|
50
|
+
const cached = _modelFetchCache.get(runtimeName);
|
|
51
|
+
if (cached) return cached;
|
|
52
|
+
}
|
|
53
|
+
const suffix = forceRefresh ? '/models/refresh' : '/models';
|
|
54
|
+
const p = fetch('/api/runtimes/' + encodeURIComponent(runtimeName) + suffix, forceRefresh ? { method: 'POST' } : undefined)
|
|
55
|
+
.then(res => (res.ok ? res.json() : null))
|
|
56
|
+
.catch(() => null)
|
|
57
|
+
.then(payload => {
|
|
58
|
+
if (!payload || !Array.isArray(payload.models)) {
|
|
59
|
+
if (_modelFetchCache.get(runtimeName) === p) _modelFetchCache.delete(runtimeName);
|
|
60
|
+
return payload || { models: null };
|
|
61
|
+
}
|
|
62
|
+
return payload;
|
|
63
|
+
});
|
|
64
|
+
_modelFetchCache.set(runtimeName, p);
|
|
65
|
+
return p;
|
|
66
|
+
}
|
|
67
|
+
|
|
36
68
|
async function openSettings() {
|
|
37
69
|
document.getElementById('modal-title').textContent = 'Settings';
|
|
38
70
|
document.getElementById('modal-body').innerHTML = '<p style="color:var(--muted)">Loading...</p>';
|
|
@@ -719,8 +751,16 @@ async function openSettings() {
|
|
|
719
751
|
// hides unmatched rows so operators can see results without tab-hopping.
|
|
720
752
|
const searchInput = document.getElementById('settings-search');
|
|
721
753
|
if (searchInput) {
|
|
754
|
+
// Debounce the filter: _applySettingsSearch runs several full-DOM
|
|
755
|
+
// querySelectorAll scans and reads textContent of every [data-search] row
|
|
756
|
+
// (a forced reflow). Firing that per-keystroke made typing janky on the
|
|
757
|
+
// large Settings DOM. The field itself stays instant; only the filter
|
|
758
|
+
// computation is coalesced to the last keystroke in a ~120ms window.
|
|
759
|
+
let _searchDebounce = null;
|
|
722
760
|
searchInput.addEventListener('input', function() {
|
|
723
|
-
|
|
761
|
+
const val = searchInput.value || '';
|
|
762
|
+
if (_searchDebounce) clearTimeout(_searchDebounce);
|
|
763
|
+
_searchDebounce = setTimeout(function() { _applySettingsSearch(val); }, 120);
|
|
724
764
|
});
|
|
725
765
|
}
|
|
726
766
|
|
|
@@ -822,6 +862,9 @@ async function initRuntimeFleetUI(engineCfg, agentsCfg) {
|
|
|
822
862
|
const ccCliSelect = document.getElementById('set-ccCli');
|
|
823
863
|
if (!cliSelect || !ccCliSelect) return;
|
|
824
864
|
|
|
865
|
+
// Fresh cache per Settings open so a config change between opens is picked up.
|
|
866
|
+
_resetModelFetchCache();
|
|
867
|
+
|
|
825
868
|
// Fetch the registry; render an empty fallback on failure so the rest of the
|
|
826
869
|
// settings panel still works.
|
|
827
870
|
let runtimes = [];
|
|
@@ -917,11 +960,7 @@ async function loadModelsForRuntime(runtimeName, inputId, currentValue, forceRef
|
|
|
917
960
|
return;
|
|
918
961
|
}
|
|
919
962
|
let payload = { models: null };
|
|
920
|
-
|
|
921
|
-
const suffix = forceRefresh ? '/models/refresh' : '/models';
|
|
922
|
-
const res = await fetch('/api/runtimes/' + encodeURIComponent(runtimeName) + suffix, forceRefresh ? { method: 'POST' } : undefined);
|
|
923
|
-
if (res.ok) payload = await res.json();
|
|
924
|
-
} catch { /* fall through to free-text */ }
|
|
963
|
+
payload = await _fetchRuntimeModelsPayload(runtimeName, forceRefresh);
|
|
925
964
|
|
|
926
965
|
if (!_isCurrentModelLoad('runtime', inputId, token)) return;
|
|
927
966
|
const models = Array.isArray(payload.models) ? payload.models : null;
|
|
@@ -962,10 +1001,7 @@ async function loadModelsForAgent(agentId, runtimeName, currentValue) {
|
|
|
962
1001
|
return;
|
|
963
1002
|
}
|
|
964
1003
|
let payload = { models: null };
|
|
965
|
-
|
|
966
|
-
const res = await fetch('/api/runtimes/' + encodeURIComponent(runtimeName) + '/models');
|
|
967
|
-
if (res.ok) payload = await res.json();
|
|
968
|
-
} catch { /* fall through to free-text */ }
|
|
1004
|
+
payload = await _fetchRuntimeModelsPayload(runtimeName, false);
|
|
969
1005
|
|
|
970
1006
|
if (!_isCurrentModelLoad('agent', agentId, token)) return;
|
|
971
1007
|
const models = Array.isArray(payload.models) ? payload.models : null;
|
package/docs/deprecated.json
CHANGED
|
@@ -1,32 +1,32 @@
|
|
|
1
1
|
[
|
|
2
2
|
{
|
|
3
3
|
"id": "agent-config-skills-field",
|
|
4
|
-
"description": "Legacy per-agent descriptive-metadata array `agents.<id>.skills` in config.json, renamed to `agents.<id>.expertise` to remove the name collision with executable runtime/harness skills (SKILL.md). The
|
|
4
|
+
"description": "Legacy per-agent descriptive-metadata array `agents.<id>.skills` in config.json, renamed to `agents.<id>.expertise` to remove the name collision with executable runtime/harness skills (SKILL.md). The tags appear in the agent identity prompt and provide a soft preference to `pickReReviewAgentHints` when selecting a re-reviewer; they are not hard routing constraints. A read-compat shim honors the old key so operator configs still carrying `skills` (and no `expertise`) keep working.",
|
|
5
5
|
"code": [
|
|
6
6
|
{
|
|
7
7
|
"file": "engine/playbook.js",
|
|
8
|
-
"lines": "
|
|
8
|
+
"lines": "1094",
|
|
9
9
|
"note": "buildSystemPrompt reads `agent.expertise ?? agent.skills ?? []` for the `Expertise:` identity line"
|
|
10
10
|
},
|
|
11
11
|
{
|
|
12
12
|
"file": "engine/lifecycle.js",
|
|
13
|
-
"lines": "
|
|
13
|
+
"lines": "5317-5321",
|
|
14
14
|
"note": "pickReReviewAgentHints reads `agent.expertise` with an `agent.skills` array fallback"
|
|
15
15
|
},
|
|
16
16
|
{
|
|
17
17
|
"file": "engine/queries.js",
|
|
18
|
-
"lines": "
|
|
18
|
+
"lines": "830-832",
|
|
19
19
|
"note": "getAgents normalizes `expertise: a.expertise ?? a.skills ?? []` so the dashboard/settings UI always receives `expertise`"
|
|
20
20
|
},
|
|
21
21
|
{
|
|
22
22
|
"file": "dashboard.js",
|
|
23
|
-
"lines": "
|
|
23
|
+
"lines": "11245-11252",
|
|
24
24
|
"note": "settings POST accepts a legacy `updates.skills` key, persists as `config.agents[id].expertise`, and deletes the old `skills` key"
|
|
25
25
|
}
|
|
26
26
|
],
|
|
27
27
|
"removalGate": "Telemetry / a config sweep across all known engines must show no persisted `config.agents.<id>.skills` key (only `expertise`) for >=30 consecutive days, confirming every operator config has been re-saved through the dashboard (which drops the legacy key) or hand-migrated.",
|
|
28
28
|
"targetRemovalDate": "2026-09-17",
|
|
29
|
-
"notes": "Safe to remove on or after 2026-09-17 (~3 release windows) once the removal gate clears. Removal scope: drop the `?? agent.skills` / `?? a.skills` fallbacks in engine/playbook.js:
|
|
29
|
+
"notes": "Safe to remove on or after 2026-09-17 (~3 release windows) once the removal gate clears. Removal scope: drop the `?? agent.skills` / `?? a.skills` fallbacks in engine/playbook.js:1094, engine/lifecycle.js:5317-5319, and engine/queries.js:832; drop the `updates.skills` legacy branch + `delete config.agents[id].skills` in dashboard.js:11245-11252; and update docs/named-agents.md to stop mentioning the legacy key. Does NOT touch the unrelated executable-skills system (queries.js harnesses, runtime adapters, dashboard renderSkills, SKILL.md tooling)."
|
|
30
30
|
},
|
|
31
31
|
{
|
|
32
32
|
"id": "config-poll-key-migration",
|