@yemi33/minions 0.1.2026 → 0.1.2027
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 -0
- package/dashboard.js +50 -5
- package/engine/queries.js +95 -3
- package/package.json +1 -1
package/dashboard/js/refresh.js
CHANGED
|
@@ -13,6 +13,7 @@ const _pageCounters = {
|
|
|
13
13
|
pipelines: function(d) { return (d.pipelines || []).length + '|' + (d.pipelines || []).reduce(function(s, p) { return s + (p.runs || []).length; }, 0); },
|
|
14
14
|
schedule: function(d) { return (d.schedules || []).length; },
|
|
15
15
|
engine: function(d) { return (d.dispatch?.completed || []).filter(function(c) { return c.result === 'error'; }).length; },
|
|
16
|
+
qa: function(d) { return (d.qaRuns?.total || 0) + '|' + (d.qaRuns?.sig || ''); },
|
|
16
17
|
};
|
|
17
18
|
let _prevCounts = {};
|
|
18
19
|
function _detectPageChanges(data) {
|
package/dashboard.js
CHANGED
|
@@ -1589,7 +1589,9 @@ function _ifNoneMatchHasEtag(headerValue, currentEtag) {
|
|
|
1589
1589
|
// delegate so any module that contributes to `_buildStatusFastState()` can
|
|
1590
1590
|
// register its mtime inputs in one place.
|
|
1591
1591
|
const _mtimeTrackedFiles = () => queries.getStatusFastStateMtimePaths(CONFIG);
|
|
1592
|
-
|
|
1592
|
+
const _slowMtimeTrackedFiles = () => queries.getStatusSlowStateMtimePaths(CONFIG);
|
|
1593
|
+
let _lastMtimes = {}; // { filePath: mtimeMs } — fast-state baseline
|
|
1594
|
+
let _lastSlowMtimes = {}; // { filePath: mtimeMs } — slow-state baseline
|
|
1593
1595
|
|
|
1594
1596
|
function _getMtimes() {
|
|
1595
1597
|
const result = {};
|
|
@@ -1599,6 +1601,14 @@ function _getMtimes() {
|
|
|
1599
1601
|
return result;
|
|
1600
1602
|
}
|
|
1601
1603
|
|
|
1604
|
+
function _getSlowMtimes() {
|
|
1605
|
+
const result = {};
|
|
1606
|
+
for (const fp of _slowMtimeTrackedFiles()) {
|
|
1607
|
+
try { result[fp] = fs.statSync(fp).mtimeMs; } catch { result[fp] = 0; }
|
|
1608
|
+
}
|
|
1609
|
+
return result;
|
|
1610
|
+
}
|
|
1611
|
+
|
|
1602
1612
|
function _mtimesChanged(prev, curr) {
|
|
1603
1613
|
for (const fp of Object.keys(curr)) {
|
|
1604
1614
|
if (prev[fp] !== curr[fp]) return true;
|
|
@@ -1668,6 +1678,21 @@ function _buildStatusFastState() {
|
|
|
1668
1678
|
workItems: getWorkItems(),
|
|
1669
1679
|
watches: watchesMod.getWatches(),
|
|
1670
1680
|
meetings: (() => { try { return require('./engine/meeting').getMeetings(); } catch { return []; } })(),
|
|
1681
|
+
// QA runs — surfaced for the sidebar activity-dot counter and any future
|
|
1682
|
+
// CC/aggregate view. Tab-level rendering keeps its own /api/qa/runs poll
|
|
1683
|
+
// (5 s while the QA page is mounted). qa-runs.json is in the mtime tracker
|
|
1684
|
+
// so a new run lights the dot within one /api/status poll cycle (~4 s).
|
|
1685
|
+
qaRuns: (() => {
|
|
1686
|
+
try {
|
|
1687
|
+
const runs = require('./engine/qa-runs').listRuns({ limit: 50 }) || [];
|
|
1688
|
+
return {
|
|
1689
|
+
total: runs.length,
|
|
1690
|
+
// Signature of (id, status) for the most recent 20 runs so the
|
|
1691
|
+
// sidebar counter advances on status flips AND on new entries.
|
|
1692
|
+
sig: runs.slice(0, 20).map(r => (r && r.id || '') + ':' + (r && r.status || '')).join(','),
|
|
1693
|
+
};
|
|
1694
|
+
} catch { return { total: 0, sig: '' }; }
|
|
1695
|
+
})(),
|
|
1671
1696
|
};
|
|
1672
1697
|
}
|
|
1673
1698
|
|
|
@@ -1772,8 +1797,16 @@ function getStatus() {
|
|
|
1772
1797
|
if (_mtimesChanged(_lastMtimes, currMtimes)) fastStale = true;
|
|
1773
1798
|
}
|
|
1774
1799
|
|
|
1775
|
-
// Slow state: 60s TTL
|
|
1776
|
-
|
|
1800
|
+
// Slow state: 60s TTL with mtime-based validation for early bust.
|
|
1801
|
+
// The mtime tracker covers engine-driven slow-state writes (PRD updates,
|
|
1802
|
+
// pipeline-runs.json, schedule-runs.json, verify guides, project skills)
|
|
1803
|
+
// so changes surface within one SPA poll (~4 s) instead of waiting up to
|
|
1804
|
+
// 60 s for TTL. Same pre-build snapshot semantics as fast-state below.
|
|
1805
|
+
let slowStale = !_slowState || (now - _slowStateTs) >= SLOW_STATE_TTL;
|
|
1806
|
+
if (!slowStale) {
|
|
1807
|
+
const currSlowMtimes = _getSlowMtimes();
|
|
1808
|
+
if (_mtimesChanged(_lastSlowMtimes, currSlowMtimes)) slowStale = true;
|
|
1809
|
+
}
|
|
1777
1810
|
|
|
1778
1811
|
// If nothing stale, return cached merged result
|
|
1779
1812
|
if (!fastStale && !slowStale && _statusCache) return _statusCache;
|
|
@@ -1795,10 +1828,14 @@ function getStatus() {
|
|
|
1795
1828
|
_lastMtimes = preBuildMtimes;
|
|
1796
1829
|
}
|
|
1797
1830
|
|
|
1798
|
-
// Rebuild slow state (rarely-changing data: ~8-15 reads, 60s TTL)
|
|
1831
|
+
// Rebuild slow state (rarely-changing data: ~8-15 reads, 60s TTL).
|
|
1832
|
+
// Same pre-build snapshot pattern as fast-state — capture mtimes BEFORE
|
|
1833
|
+
// disk reads so any write landing mid-build busts the next poll.
|
|
1799
1834
|
if (slowStale) {
|
|
1835
|
+
const preBuildSlowMtimes = _getSlowMtimes();
|
|
1800
1836
|
_slowState = _buildStatusSlowState();
|
|
1801
1837
|
_slowStateTs = now;
|
|
1838
|
+
_lastSlowMtimes = preBuildSlowMtimes;
|
|
1802
1839
|
}
|
|
1803
1840
|
|
|
1804
1841
|
// Merge both tiers — no API contract change
|
|
@@ -1839,7 +1876,11 @@ function refreshStatusAsync() {
|
|
|
1839
1876
|
const currMtimes = _getMtimes();
|
|
1840
1877
|
if (_mtimesChanged(_lastMtimes, currMtimes)) fastStale = true;
|
|
1841
1878
|
}
|
|
1842
|
-
|
|
1879
|
+
let slowStale = !_slowState || (now - _slowStateTs) >= SLOW_STATE_TTL;
|
|
1880
|
+
if (!slowStale) {
|
|
1881
|
+
const currSlowMtimes = _getSlowMtimes();
|
|
1882
|
+
if (_mtimesChanged(_lastSlowMtimes, currSlowMtimes)) slowStale = true;
|
|
1883
|
+
}
|
|
1843
1884
|
|
|
1844
1885
|
if (!fastStale && !slowStale && _statusCache) return _statusCache;
|
|
1845
1886
|
|
|
@@ -1866,7 +1907,9 @@ function refreshStatusAsync() {
|
|
|
1866
1907
|
}
|
|
1867
1908
|
|
|
1868
1909
|
let slow = _slowState;
|
|
1910
|
+
let preBuildSlowMtimes = null;
|
|
1869
1911
|
if (slowStale) {
|
|
1912
|
+
preBuildSlowMtimes = _getSlowMtimes();
|
|
1870
1913
|
slow = _buildStatusSlowState();
|
|
1871
1914
|
}
|
|
1872
1915
|
|
|
@@ -1887,6 +1930,7 @@ function refreshStatusAsync() {
|
|
|
1887
1930
|
if (slowStale) {
|
|
1888
1931
|
_slowState = slow;
|
|
1889
1932
|
_slowStateTs = now;
|
|
1933
|
+
_lastSlowMtimes = preBuildSlowMtimes;
|
|
1890
1934
|
}
|
|
1891
1935
|
_statusCache = { ..._fastState, ..._slowState, timestamp: new Date().toISOString() };
|
|
1892
1936
|
_markStatusCacheBuilt();
|
|
@@ -1921,6 +1965,7 @@ function _resetStatusCacheForTesting() {
|
|
|
1921
1965
|
_statusInvalidationGeneration = 0;
|
|
1922
1966
|
_statusRefreshHook = null;
|
|
1923
1967
|
_lastMtimes = {};
|
|
1968
|
+
_lastSlowMtimes = {};
|
|
1924
1969
|
}
|
|
1925
1970
|
|
|
1926
1971
|
/** Return cached JSON string of status — single stringify, reused by SSE and /api/status */
|
package/engine/queries.js
CHANGED
|
@@ -1918,11 +1918,29 @@ function getStatusFastStateMtimePaths(config) {
|
|
|
1918
1918
|
// entry-add/remove signal even on Windows NTFS. Without it, PR-comment
|
|
1919
1919
|
// notifications, agent-failure summaries, follow-up build alerts, and
|
|
1920
1920
|
// meeting-transcript dumps all lagged up to 10 s before appearing on
|
|
1921
|
-
// the dashboard's inbox view.
|
|
1922
|
-
// (see "Files intentionally NOT tracked") because round transitions
|
|
1923
|
-
// edit existing files in-place, which dir mtime can't detect.
|
|
1921
|
+
// the dashboard's inbox view.
|
|
1924
1922
|
INBOX_DIR,
|
|
1923
|
+
// engine/qa-runs.json (surfaced by listRuns via fast-state qaRuns slice)
|
|
1924
|
+
// — new QA runs and status flips need to light the sidebar activity dot
|
|
1925
|
+
// within one SPA poll cycle. Single file, mtime advances on each write.
|
|
1926
|
+
path.join(ENGINE_DIR, 'qa-runs.json'),
|
|
1925
1927
|
];
|
|
1928
|
+
// meetings/<id>.json (surfaced by meeting.getMeetings) — round transitions
|
|
1929
|
+
// edit each file in-place via mutateMeeting, so the parent dir's mtime
|
|
1930
|
+
// does NOT advance on Windows. Tracking each file individually catches
|
|
1931
|
+
// in-file edits. Bounded by meeting count (typically <50 active); a 50-
|
|
1932
|
+
// meeting fleet adds ~50 statSync calls per cache miss — still cheap.
|
|
1933
|
+
// Filter `.backup` sidecars (from safe-write tempfile pattern) and
|
|
1934
|
+
// non-*.json entries so corrupted state can't pollute the registry.
|
|
1935
|
+
try {
|
|
1936
|
+
const meetingsDir = path.join(MINIONS_DIR, 'meetings');
|
|
1937
|
+
const entries = fs.readdirSync(meetingsDir);
|
|
1938
|
+
for (const f of entries) {
|
|
1939
|
+
if (f.endsWith('.json') && !f.endsWith('.backup.json')) {
|
|
1940
|
+
files.push(path.join(meetingsDir, f));
|
|
1941
|
+
}
|
|
1942
|
+
}
|
|
1943
|
+
} catch { /* meetings dir absent → no meetings to track */ }
|
|
1926
1944
|
// Per-project work-items (surfaced by getWorkItems) and pull-requests
|
|
1927
1945
|
// (surfaced by getPullRequests). The PR file was the biggest miss in the
|
|
1928
1946
|
// original tracked list — PR status flips (running → passing, waiting →
|
|
@@ -1947,6 +1965,79 @@ function getStatusFastStateMtimePaths(config) {
|
|
|
1947
1965
|
return files;
|
|
1948
1966
|
}
|
|
1949
1967
|
|
|
1968
|
+
/**
|
|
1969
|
+
* Slow-state mtime tracker — symmetric with the fast-state registry above.
|
|
1970
|
+
*
|
|
1971
|
+
* Slow-state slices (`prdProgress`, `prd`, `verifyGuides`, `archivedPrds`,
|
|
1972
|
+
* `skills`, `mcpServers`, `schedules`, `pipelines`, `pinned`, `projects`,
|
|
1973
|
+
* `version`, etc.) live behind a 60 s TTL in `dashboard.js`. Without mtime
|
|
1974
|
+
* tracking, engine-driven writes to `prd/*.json`, `engine/schedule-runs.json`,
|
|
1975
|
+
* `engine/pipeline-runs.json`, or `prd/guides/*.md` waited up to the full
|
|
1976
|
+
* 60 s before surfacing in the dashboard — which produced the visible
|
|
1977
|
+
* "plan status doesn't update, pipelines never advance" symptom.
|
|
1978
|
+
*
|
|
1979
|
+
* The same conventions as fast-state apply:
|
|
1980
|
+
* - Entries must back something `_buildStatusSlowState()` reads; otherwise
|
|
1981
|
+
* the rebuild silently no-ops on detected change.
|
|
1982
|
+
* - Files mutated through a `mutate*` helper are reliable (`safeWrite`
|
|
1983
|
+
* rename advances mtime). Append-only logs reset the cache often but
|
|
1984
|
+
* are not relevant here.
|
|
1985
|
+
* - Per-project paths must use `shared.project*` so newly-added projects
|
|
1986
|
+
* are picked up without registry edits.
|
|
1987
|
+
*
|
|
1988
|
+
* Files intentionally NOT tracked here:
|
|
1989
|
+
* - `mcpServers`, version, autoMode, installId — change only on human/
|
|
1990
|
+
* CLI edits, which already pop the slow-state via reloadConfig + the
|
|
1991
|
+
* 60 s TTL.
|
|
1992
|
+
* - `~/.claude/skills/`, `~/.copilot/skills/` — user-home dirs that
|
|
1993
|
+
* `extractSkillsFromOutput` writes to from the agent-close path,
|
|
1994
|
+
* which already calls `invalidateStatusCache()` directly.
|
|
1995
|
+
* - project git state — already invalidated via the
|
|
1996
|
+
* `_setOnProjectGitStatusChanged` callback into `invalidateStatusCache`
|
|
1997
|
+
* (W-mpgrk5cy fix); also tracked in fast-state via `.git/logs/HEAD`.
|
|
1998
|
+
*/
|
|
1999
|
+
function getStatusSlowStateMtimePaths(config) {
|
|
2000
|
+
const projects = getProjects(config || getConfig());
|
|
2001
|
+
const files = [
|
|
2002
|
+
// prd/*.json (surfaced by getPrdInfo) — engine writes via syncPrdFromPrs,
|
|
2003
|
+
// the materializer, and plan-to-prd outputs. Dir mtime advances on entry
|
|
2004
|
+
// add/remove; in-file edits use getPrdInfo's own per-file mtime cache so
|
|
2005
|
+
// small-content flips still surface via the 10 s TTL backstop, but the
|
|
2006
|
+
// big "new PRD created" event surfaces immediately.
|
|
2007
|
+
PRD_DIR,
|
|
2008
|
+
// prd/archive/*.json — manual archive moves PRDs here; dir mtime catches
|
|
2009
|
+
// the move.
|
|
2010
|
+
path.join(PRD_DIR, 'archive'),
|
|
2011
|
+
// prd/guides/*.md — verify agent writes new files here on E2E completion.
|
|
2012
|
+
path.join(MINIONS_DIR, 'prd', 'guides'),
|
|
2013
|
+
// engine/schedule-runs.json — scheduler rewrites this on every cron fire.
|
|
2014
|
+
path.join(ENGINE_DIR, 'schedule-runs.json'),
|
|
2015
|
+
// engine/pipeline-runs.json — pipeline executor rewrites this on each
|
|
2016
|
+
// stage transition (the most user-visible slow-state lag pre-fix).
|
|
2017
|
+
path.join(ENGINE_DIR, 'pipeline-runs.json'),
|
|
2018
|
+
// pipelines/*.json — pipeline definitions, edited by humans + plan agents.
|
|
2019
|
+
// Dir mtime is fine because pipeline edits are wholesale file replacements
|
|
2020
|
+
// (no in-place tweaks once a pipeline is authored).
|
|
2021
|
+
path.join(MINIONS_DIR, 'pipelines'),
|
|
2022
|
+
// pinned.md — single file, dashboard-side writes already call
|
|
2023
|
+
// invalidateStatusCache({includeSlow:true}); tracker entry catches any
|
|
2024
|
+
// CLI/editor edit that bypasses the API.
|
|
2025
|
+
path.join(MINIONS_DIR, 'pinned.md'),
|
|
2026
|
+
// engine/skill-states/ — engine writes when agents extract new skills.
|
|
2027
|
+
// Dir mtime catches new skill files. Skips per-skill in-place edits which
|
|
2028
|
+
// the agent-close invalidate already covers.
|
|
2029
|
+
SKILLS_DIR,
|
|
2030
|
+
];
|
|
2031
|
+
// Per-project local skill dirs — agents extract project-scoped skills here.
|
|
2032
|
+
for (const p of projects) {
|
|
2033
|
+
if (p && p.localPath) {
|
|
2034
|
+
files.push(path.join(p.localPath, '.claude', 'skills'));
|
|
2035
|
+
files.push(path.join(p.localPath, '.github', 'skills'));
|
|
2036
|
+
}
|
|
2037
|
+
}
|
|
2038
|
+
return files;
|
|
2039
|
+
}
|
|
2040
|
+
|
|
1950
2041
|
// ── Exports ─────────────────────────────────────────────────────────────────
|
|
1951
2042
|
|
|
1952
2043
|
module.exports = {
|
|
@@ -1967,6 +2058,7 @@ module.exports = {
|
|
|
1967
2058
|
_setOnProjectGitStatusChanged,
|
|
1968
2059
|
// W-mpftp7na000td0f4 — engine→dashboard cache-invalidation registry
|
|
1969
2060
|
getStatusFastStateMtimePaths,
|
|
2061
|
+
getStatusSlowStateMtimePaths,
|
|
1970
2062
|
|
|
1971
2063
|
// Core state
|
|
1972
2064
|
getConfig, getControl, getDispatch, getDispatchQueue, getDispatchCompletionReport, invalidateDispatchCache,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yemi33/minions",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2027",
|
|
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"
|