@yemi33/minions 0.1.2036 → 0.1.2037
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 +18 -9
- package/dashboard/js/state.js +7 -4
- package/dashboard.js +26 -2
- package/engine/queries.js +68 -14
- package/package.json +1 -1
package/dashboard/js/refresh.js
CHANGED
|
@@ -122,7 +122,7 @@ function _formatCcDrawerLabel(autoMode) {
|
|
|
122
122
|
|
|
123
123
|
function _processStatusUpdate(data) {
|
|
124
124
|
// Detect fresh install — clear stale browser state AND reload so module-scoped
|
|
125
|
-
// JS caches (_sectionCache, _prevCounts,
|
|
125
|
+
// JS caches (_sectionCache, _prevCounts, _managedProcessesLastItems,
|
|
126
126
|
// _pipelinePollHash, _meetingPollHash, etc.) reinitialise against the new install's
|
|
127
127
|
// data shape. localStorage.clear() alone leaves those caches stale after a
|
|
128
128
|
// MINIONS_HOME swap that doesn't restart the dashboard (F11 / W-mpgcijjo000ce878).
|
|
@@ -252,16 +252,25 @@ function _processStatusUpdate(data) {
|
|
|
252
252
|
if (swi) swi.textContent = (data.workItems || []).length || '';
|
|
253
253
|
const spr = document.getElementById('sidebar-pr');
|
|
254
254
|
if (spr) spr.textContent = (data.pullRequests || []).length || '';
|
|
255
|
-
// Refresh KB and plans
|
|
256
|
-
|
|
257
|
-
|
|
255
|
+
// Refresh KB and plans every status cycle (~4s) so plan status flips
|
|
256
|
+
// (approve/archive/complete) and KB additions surface within the SPA's
|
|
257
|
+
// 4s poll target. Server-side caches keep this cheap:
|
|
258
|
+
// - /api/plans: 5s in-memory TTL + invalidation on every mutating endpoint
|
|
259
|
+
// (dashboard.js _plansCache / invalidatePlansCache) — back-to-back polls
|
|
260
|
+
// hit the cache; external file edits surface within 5s.
|
|
261
|
+
// - /api/knowledge: 30s in-memory TTL + invalidation on POST /api/knowledge
|
|
262
|
+
// and after every kb-sweep (engine/queries.js _kbCache / kb-sweep.js).
|
|
263
|
+
// Previously throttled to every 3rd cycle (~12s) — see W-mphfb6ss000a3b9e
|
|
264
|
+
// for the cadence audit + Playwright coverage.
|
|
265
|
+
refreshKnowledgeBase();
|
|
266
|
+
refreshPlans();
|
|
258
267
|
|
|
259
268
|
// Cross-slice render triggers (F1/F3, W-mpgb0xbh000e3b86): renderPrs reads
|
|
260
269
|
// window._lastWorkItems for the +N follow-up chip count and derivePlanStatus
|
|
261
270
|
// reads window._lastStatus.pullRequests for verify-follow-up reconciliation.
|
|
262
271
|
// When workItems OR pullRequests change, re-render the dependents against the
|
|
263
|
-
// freshest cached data — without waiting
|
|
264
|
-
//
|
|
272
|
+
// freshest cached data — without waiting for the next refreshPlans cycle (F3)
|
|
273
|
+
// or for a PR object to mutate (F1). Runs after the window._last*
|
|
265
274
|
// assignments above so the cached globals these renderers consult are fresh.
|
|
266
275
|
if (_workItemsChanged && !_prsChanged) {
|
|
267
276
|
// F1: only the work-item slice moved this tick — renderPrs wasn't called
|
|
@@ -271,9 +280,9 @@ function _processStatusUpdate(data) {
|
|
|
271
280
|
}
|
|
272
281
|
if ((_workItemsChanged || _prsChanged) && Array.isArray(window._lastPlans) && typeof renderPlans === 'function') {
|
|
273
282
|
// F3: derivePlanStatus + _renderVerifyBadge derive from pullRequests +
|
|
274
|
-
// workItems. Re-render against
|
|
275
|
-
//
|
|
276
|
-
//
|
|
283
|
+
// workItems. Re-render against cached plans so plan status flips within
|
|
284
|
+
// one /api/status tick (~4s) instead of one refreshPlans poll. No-op
|
|
285
|
+
// until _lastPlans is populated.
|
|
277
286
|
renderPlans(window._lastPlans);
|
|
278
287
|
}
|
|
279
288
|
|
package/dashboard/js/state.js
CHANGED
|
@@ -27,10 +27,13 @@ let currentPage = getPageFromUrl();
|
|
|
27
27
|
|
|
28
28
|
// W-mpgb0xa7000d90d4 (dashboard-refresh-audit.md F5) — switchPage previously
|
|
29
29
|
// only cleaned intervals and flipped CSS; tabs like /plans and /inbox waited
|
|
30
|
-
//
|
|
31
|
-
//
|
|
32
|
-
//
|
|
33
|
-
//
|
|
30
|
+
// for refresh.js's next slow-cycle (refreshKnowledgeBase + refreshPlans) before
|
|
31
|
+
// showing fresh data. The QA tab worked around this with its own switchPage
|
|
32
|
+
// monkey-patch in qa.js (__qaWrapped) — that per-tab pattern is now generalized
|
|
33
|
+
// into one canonical lifecycle below. (As of W-mphfb6ss000a3b9e the slow-cycle
|
|
34
|
+
// modulo was dropped, so refreshPlans/refreshKnowledgeBase now run every 4s
|
|
35
|
+
// status tick — but the page-enter loader still wins on tab-switch because it
|
|
36
|
+
// fires synchronously without waiting for the next interval boundary.)
|
|
34
37
|
//
|
|
35
38
|
// PAGE_LAZY_LOADERS: functions to invoke when ENTERING a page (resolved by
|
|
36
39
|
// name through window so the function body can live alongside its tab UI).
|
package/dashboard.js
CHANGED
|
@@ -1628,6 +1628,20 @@ function _getSlowMtimes() {
|
|
|
1628
1628
|
return result;
|
|
1629
1629
|
}
|
|
1630
1630
|
|
|
1631
|
+
// Reset the per-source caches that outlive the slow-state TTL when a tracked
|
|
1632
|
+
// source file changes (W-mphfdgwv000bf549). The slow-state mtime tracker now
|
|
1633
|
+
// covers skill discovery dirs and MCP config files, but
|
|
1634
|
+
// `queries._skillsCache` (30 s) and the local `_mcpServersCache` (5 min)
|
|
1635
|
+
// would still serve stale data into `_buildStatusSlowState()` — defeating
|
|
1636
|
+
// the <4 s freshness goal. Only call this when an mtime delta is detected;
|
|
1637
|
+
// TTL-driven rebuilds keep using the inner caches so we don't pay disk-scan
|
|
1638
|
+
// cost on every 60 s slow-state rollover.
|
|
1639
|
+
function _invalidateSlowInnerCachesForMtimeChange() {
|
|
1640
|
+
try { queries.invalidateSkillsCache(); } catch { /* optional */ }
|
|
1641
|
+
_mcpServersCache = null;
|
|
1642
|
+
_mcpServersCacheTs = 0;
|
|
1643
|
+
}
|
|
1644
|
+
|
|
1631
1645
|
function _mtimesChanged(prev, curr) {
|
|
1632
1646
|
for (const fp of Object.keys(curr)) {
|
|
1633
1647
|
if (prev[fp] !== curr[fp]) return true;
|
|
@@ -1838,9 +1852,13 @@ function getStatus() {
|
|
|
1838
1852
|
// so changes surface within one SPA poll (~4 s) instead of waiting up to
|
|
1839
1853
|
// 60 s for TTL. Same pre-build snapshot semantics as fast-state below.
|
|
1840
1854
|
let slowStale = !_slowState || (now - _slowStateTs) >= SLOW_STATE_TTL;
|
|
1855
|
+
let slowMtimeChanged = false;
|
|
1841
1856
|
if (!slowStale) {
|
|
1842
1857
|
const currSlowMtimes = _getSlowMtimes();
|
|
1843
|
-
if (_mtimesChanged(_lastSlowMtimes, currSlowMtimes))
|
|
1858
|
+
if (_mtimesChanged(_lastSlowMtimes, currSlowMtimes)) {
|
|
1859
|
+
slowStale = true;
|
|
1860
|
+
slowMtimeChanged = true;
|
|
1861
|
+
}
|
|
1844
1862
|
}
|
|
1845
1863
|
|
|
1846
1864
|
// If nothing stale, return cached merged result
|
|
@@ -1867,6 +1885,7 @@ function getStatus() {
|
|
|
1867
1885
|
// Same pre-build snapshot pattern as fast-state — capture mtimes BEFORE
|
|
1868
1886
|
// disk reads so any write landing mid-build busts the next poll.
|
|
1869
1887
|
if (slowStale) {
|
|
1888
|
+
if (slowMtimeChanged) _invalidateSlowInnerCachesForMtimeChange();
|
|
1870
1889
|
const preBuildSlowMtimes = _getSlowMtimes();
|
|
1871
1890
|
_slowState = _buildStatusSlowState();
|
|
1872
1891
|
_slowStateTs = now;
|
|
@@ -1912,9 +1931,13 @@ function refreshStatusAsync() {
|
|
|
1912
1931
|
if (_mtimesChanged(_lastMtimes, currMtimes)) fastStale = true;
|
|
1913
1932
|
}
|
|
1914
1933
|
let slowStale = !_slowState || (now - _slowStateTs) >= SLOW_STATE_TTL;
|
|
1934
|
+
let slowMtimeChanged = false;
|
|
1915
1935
|
if (!slowStale) {
|
|
1916
1936
|
const currSlowMtimes = _getSlowMtimes();
|
|
1917
|
-
if (_mtimesChanged(_lastSlowMtimes, currSlowMtimes))
|
|
1937
|
+
if (_mtimesChanged(_lastSlowMtimes, currSlowMtimes)) {
|
|
1938
|
+
slowStale = true;
|
|
1939
|
+
slowMtimeChanged = true;
|
|
1940
|
+
}
|
|
1918
1941
|
}
|
|
1919
1942
|
|
|
1920
1943
|
if (!fastStale && !slowStale && _statusCache) return _statusCache;
|
|
@@ -1944,6 +1967,7 @@ function refreshStatusAsync() {
|
|
|
1944
1967
|
let slow = _slowState;
|
|
1945
1968
|
let preBuildSlowMtimes = null;
|
|
1946
1969
|
if (slowStale) {
|
|
1970
|
+
if (slowMtimeChanged) _invalidateSlowInnerCachesForMtimeChange();
|
|
1947
1971
|
preBuildSlowMtimes = _getSlowMtimes();
|
|
1948
1972
|
slow = _buildStatusSlowState();
|
|
1949
1973
|
}
|
package/engine/queries.js
CHANGED
|
@@ -2079,25 +2079,43 @@ function getStatusFastStateMtimePaths(config) {
|
|
|
2079
2079
|
* - Per-project paths must use `shared.project*` so newly-added projects
|
|
2080
2080
|
* are picked up without registry edits.
|
|
2081
2081
|
*
|
|
2082
|
+
* Skill and MCP source paths (W-mphfdgwv000bf549):
|
|
2083
|
+
* - Skill discovery roots (`~/.claude/skills`, `~/.copilot/skills`,
|
|
2084
|
+
* `~/.agents/skills`, `<project>/.claude/skills`, `<project>/.github/skills`,
|
|
2085
|
+
* `<project>/.agents/skills`) plus plugin registries are tracked here
|
|
2086
|
+
* because manual `SKILL.md` drops bypass the agent-close
|
|
2087
|
+
* `invalidateStatusCache({includeSlow:true})` path that previously
|
|
2088
|
+
* covered the agent-extraction case. Directory mtime advances reliably
|
|
2089
|
+
* on Windows NTFS when a subdirectory is added/removed (verified via
|
|
2090
|
+
* INBOX_DIR). Tracking the user-home dirs means non-Minions skill
|
|
2091
|
+
* installs on this machine also bust the fleet's slow-state — but skill
|
|
2092
|
+
* dirs only mutate on rare events (install / manual edit), not on every
|
|
2093
|
+
* CLI command, so the steady-state noise is negligible.
|
|
2094
|
+
* - MCP config files (`~/.claude.json`, `~/.copilot/mcp-config.json`,
|
|
2095
|
+
* `<project>/.mcp.json`) feed `getMcpServers()`. `~/.claude.json`
|
|
2096
|
+
* stores more than `mcpServers`, but it only flips on intentional
|
|
2097
|
+
* Claude CLI mutations (mcp add/remove, settings edits), not on every
|
|
2098
|
+
* prompt, so whole-file tracking is acceptable.
|
|
2099
|
+
*
|
|
2082
2100
|
* Files intentionally NOT tracked here:
|
|
2083
|
-
* -
|
|
2084
|
-
*
|
|
2085
|
-
* 60 s TTL.
|
|
2086
|
-
* - `~/.claude/skills/`, `~/.copilot/skills/`, `<project>/.claude/skills/`,
|
|
2087
|
-
* `<project>/.github/skills/` — `extractSkillsFromOutput` writes here
|
|
2088
|
-
* from the agent-close path, which already calls
|
|
2089
|
-
* `invalidateStatusCache({includeSlow: true})` directly. Tracking the
|
|
2090
|
-
* user-home dir is additionally harmful because it's shared with every
|
|
2091
|
-
* Claude Code session on the machine; non-Minions activity would
|
|
2092
|
-
* otherwise bust this fleet's dashboard cache.
|
|
2101
|
+
* - version, autoMode, installId — change only on human/CLI edits, which
|
|
2102
|
+
* already pop the slow-state via reloadConfig + the 60 s TTL.
|
|
2093
2103
|
* - project git state — already invalidated via the
|
|
2094
2104
|
* `_setOnProjectGitStatusChanged` callback into `invalidateStatusCache`
|
|
2095
2105
|
* (W-mpgrk5cy fix); also tracked in fast-state via `.git/logs/HEAD`.
|
|
2106
|
+
*
|
|
2107
|
+
* NOTE: Detecting a change here busts the dashboard's slow-state cache, but
|
|
2108
|
+
* the inner per-source caches (`queries._skillsCache` 30 s, dashboard's
|
|
2109
|
+
* `_mcpServersCache` 5 min) survive across `_buildStatusSlowState()` calls.
|
|
2110
|
+
* dashboard.js calls `queries.invalidateSkillsCache()` and resets
|
|
2111
|
+
* `_mcpServersCache` whenever this tracker fires, so the rebuild reads
|
|
2112
|
+
* fresh disk state. Keep that invalidation wired up if you add new sources.
|
|
2096
2113
|
*/
|
|
2097
|
-
function getStatusSlowStateMtimePaths(
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2114
|
+
function getStatusSlowStateMtimePaths(config) {
|
|
2115
|
+
config = config || getConfig();
|
|
2116
|
+
const projects = getProjects(config);
|
|
2117
|
+
const homeDir = os.homedir();
|
|
2118
|
+
const files = [
|
|
2101
2119
|
// prd/*.json (surfaced by getPrdInfo) — engine writes via syncPrdFromPrs,
|
|
2102
2120
|
// the materializer, and plan-to-prd outputs.
|
|
2103
2121
|
PRD_DIR,
|
|
@@ -2117,6 +2135,42 @@ function getStatusSlowStateMtimePaths(_config) {
|
|
|
2117
2135
|
// CLI/editor edit that bypasses the API.
|
|
2118
2136
|
path.join(MINIONS_DIR, 'pinned.md'),
|
|
2119
2137
|
];
|
|
2138
|
+
|
|
2139
|
+
// Skill discovery roots (surfaced by _buildStatusSlowState → getSkills).
|
|
2140
|
+
// Mirrors collectSkillFiles' source enumeration so adding a new runtime
|
|
2141
|
+
// adapter automatically extends the tracker. ENOENT is tolerated by
|
|
2142
|
+
// dashboard._statMtimeMs (returns 0), so absent dirs cost nothing.
|
|
2143
|
+
try {
|
|
2144
|
+
const { listRuntimes, resolveRuntime } = require('./runtimes');
|
|
2145
|
+
for (const runtimeName of listRuntimes()) {
|
|
2146
|
+
const runtime = resolveRuntime(runtimeName);
|
|
2147
|
+
if (typeof runtime.getSkillRoots !== 'function') continue;
|
|
2148
|
+
for (const root of runtime.getSkillRoots({ homeDir })) {
|
|
2149
|
+
if (root && root.dir) files.push(root.dir);
|
|
2150
|
+
}
|
|
2151
|
+
for (const project of projects) {
|
|
2152
|
+
if (!project || !project.localPath) continue;
|
|
2153
|
+
for (const root of runtime.getSkillRoots({ homeDir, project })) {
|
|
2154
|
+
if (root && root.dir) files.push(root.dir);
|
|
2155
|
+
}
|
|
2156
|
+
}
|
|
2157
|
+
}
|
|
2158
|
+
} catch { /* runtime registry optional in partial installs */ }
|
|
2159
|
+
|
|
2160
|
+
// Plugin skill registries (also feed collectSkillFiles).
|
|
2161
|
+
files.push(path.join(homeDir, '.claude', 'plugins', 'installed_plugins.json'));
|
|
2162
|
+
files.push(path.join(homeDir, '.copilot', 'installed-plugins'));
|
|
2163
|
+
|
|
2164
|
+
// MCP server config files (surfaced by _buildStatusSlowState → getMcpServers).
|
|
2165
|
+
files.push(path.join(homeDir, '.claude.json'));
|
|
2166
|
+
files.push(path.join(homeDir, '.copilot', 'mcp-config.json'));
|
|
2167
|
+
for (const project of projects) {
|
|
2168
|
+
if (project && project.localPath) {
|
|
2169
|
+
files.push(path.join(project.localPath, '.mcp.json'));
|
|
2170
|
+
}
|
|
2171
|
+
}
|
|
2172
|
+
|
|
2173
|
+
return files;
|
|
2120
2174
|
}
|
|
2121
2175
|
|
|
2122
2176
|
// ── Exports ─────────────────────────────────────────────────────────────────
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yemi33/minions",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2037",
|
|
4
4
|
"description": "Multi-agent AI dev team that runs from ~/.minions/ — five autonomous agents share a single engine, dashboard, and knowledge base",
|
|
5
5
|
"bin": {
|
|
6
6
|
"minions": "bin/minions.js"
|