@yemi33/minions 0.1.2010 → 0.1.2012

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 CHANGED
@@ -1919,7 +1919,7 @@ async function _handleStatusRequest(req, res) {
1919
1919
  }
1920
1920
  }
1921
1921
 
1922
- // Periodic push for engine-driven changes (dispatch.json, control.json) that bypass invalidateStatusCache
1922
+ // Periodic push for engine-driven changes (dispatch.json, work-items.json, pull-requests.json) that bypass invalidateStatusCache
1923
1923
  setInterval(() => {
1924
1924
  if (_statusStreamClients.size === 0) return;
1925
1925
  const data = getStatusJson();
@@ -8098,6 +8098,11 @@ What would you like to discuss or change? When you're happy, say "approve" and I
8098
8098
  async function handleEngineRestart(req, res) {
8099
8099
  try {
8100
8100
  const newPid = restartEngine();
8101
+ // control.json is no longer in the mtime-tracked list (W-mpg8aapw001d7e0c)
8102
+ // because heartbeat noise dominated legitimate state changes and defeated
8103
+ // the /api/status ETag short-circuit. Explicit invalidation here keeps the
8104
+ // restart visible on the next poll without re-tracking control.json.
8105
+ invalidateStatusCache();
8101
8106
  return jsonReply(res, 200, { ok: true, pid: newPid });
8102
8107
  } catch (e) { return jsonReply(res, e.statusCode || 500, { error: e.message }); }
8103
8108
  }
@@ -1963,8 +1963,19 @@ function recordPrNoOpFixAttempt(target, cause, source, dispatchItem, branchChang
1963
1963
  ).slice(0, 500);
1964
1964
  target._lastDispatchByCause = target._lastDispatchByCause
1965
1965
  && typeof target._lastDispatchByCause === 'object' ? target._lastDispatchByCause : {};
1966
+ // W-mpg6wptq0011cc68: distinguish indeterminate noops (detection could not
1967
+ // prove the branch advanced — fetch failed, worktree gone, missing baseline)
1968
+ // from confirmed noops (remote head was verified to equal beforeHead). The
1969
+ // same-head guard in engine.js MUST NOT permanently suppress on indeterminate
1970
+ // records, otherwise a single failed detection locks out future fix
1971
+ // dispatches on that head+comment until the SHA moves — and the SHA cannot
1972
+ // move unless the suppressed fix runs. The `_noOpFixes[cause].count` +
1973
+ // `prNoOpFixPauseAttempts` (default 3) safety valve still applies; only the
1974
+ // same-head guard is relaxed.
1975
+ const indeterminate = !!branchChange && branchChange.changed === null;
1966
1976
  target._lastDispatchByCause[cause] = {
1967
1977
  outcome: 'noop',
1978
+ indeterminate,
1968
1979
  headSha,
1969
1980
  reason: reasonText,
1970
1981
  dispatchedAt: now,
@@ -1032,7 +1032,17 @@ function selectPlaybook(workType, item) {
1032
1032
 
1033
1033
  function buildPrDispatch(agentId, config, project, pr, type, extraVars, taskLabel, meta) {
1034
1034
  const dispatchId = `${agentId || 'unassigned'}-${type}-${shared.uid()}`;
1035
- const vars = { ...buildBaseVars(agentId, config, project), ...extraVars, task_id: dispatchId };
1035
+ // W-mpg6wptq0011cc68: PR-context dispatches (review/fix/build-and-test) all
1036
+ // operate on the PR's branch, so default `branch_name` to `pr_branch` here
1037
+ // so shared-rules.md's `{{branch_name}}` reference resolves. Without this,
1038
+ // every PR fix/review render emits a recurring `unresolved template
1039
+ // variables: branch_name` warn. Callers may still override explicitly.
1040
+ const vars = {
1041
+ ...buildBaseVars(agentId, config, project),
1042
+ branch_name: extraVars?.pr_branch || '',
1043
+ ...extraVars,
1044
+ task_id: dispatchId,
1045
+ };
1036
1046
  const playbookName = type === 'test' ? 'build-and-test' : (type === 'review' ? 'review' : 'fix');
1037
1047
  const prompt = renderPlaybook(playbookName, vars);
1038
1048
  if (!prompt) return null;
package/engine/queries.js CHANGED
@@ -1822,6 +1822,19 @@ function resetProjectGitStatusCache() {
1822
1822
  * automatically.
1823
1823
  *
1824
1824
  * Files intentionally NOT tracked:
1825
+ * - `engine/log.json` — append-only log written many times per tick
1826
+ * (PR polls, dispatch transitions, heartbeat). Its mtime advances
1827
+ * every few seconds in steady state, which by itself was enough to
1828
+ * bust the ETag cache on every poll and reduce the /api/status 304
1829
+ * short-circuit to 0% hit rate (W-mpg8aapw001d7e0c). Log tail is
1830
+ * surfaced by `getEngineLog()` and accepts the 10 s `FAST_STATE_TTL`
1831
+ * backstop — log entries are not UX-blocking.
1832
+ * - `engine/control.json` — heartbeat writes advance mtime every tick
1833
+ * (~60 s) plus on any control-side mutation, dominating legitimate
1834
+ * state changes. Engine state (running/paused/stopped) is surfaced
1835
+ * by `getEngineState()`; the dashboard-side mutating handlers
1836
+ * (`handleEngineRestart` etc.) call `invalidateStatusCache()`
1837
+ * directly, and the 10 s TTL covers CLI-driven control-file edits.
1825
1838
  * - `engine/state.json` — surfaced via `getEngineState()` but changes
1826
1839
  * only on engine startup / reconcile. Negligible benefit.
1827
1840
  * - `engine/cooldowns.json`, `engine/pr-links.json`, `engine/pending-
@@ -1841,11 +1854,10 @@ function resetProjectGitStatusCache() {
1841
1854
  function getStatusFastStateMtimePaths(config) {
1842
1855
  const projects = getProjects(config || getConfig());
1843
1856
  const files = [
1844
- // Engine-level state surfaced by getDispatchQueue / inline engine block /
1845
- // getEngineLog / getMetrics.
1857
+ // Engine-level state surfaced by getDispatchQueue / getMetrics.
1858
+ // `control.json` and `log.json` are intentionally omitted — see the
1859
+ // "Files intentionally NOT tracked" section above (W-mpg8aapw001d7e0c).
1846
1860
  DISPATCH_PATH,
1847
- CONTROL_PATH,
1848
- LOG_PATH,
1849
1861
  path.join(ENGINE_DIR, 'metrics.json'),
1850
1862
  // Watches surfaced by watchesMod.getWatches() (W-mpftp7na000td0f4 fix).
1851
1863
  path.join(ENGINE_DIR, 'watches.json'),
package/engine.js CHANGED
@@ -4252,6 +4252,13 @@ async function discoverFromPrs(config, project) {
4252
4252
  // queued). Skip only the human-feedback dispatch path; leave
4253
4253
  // `fixDispatched=false` so downstream causes are still evaluated.
4254
4254
  const skipHumanFeedback = !!(lastHumanDispatch?.outcome === 'noop'
4255
+ // W-mpg6wptq0011cc68: indeterminate noops (detection could not verify
4256
+ // branch advance — fetch failed, worktree gone) must NOT permanently
4257
+ // suppress re-dispatch. lifecycle.js:2043-2048 explicitly comments
4258
+ // that a future tick with working detection must be free to re-fire.
4259
+ // The `_noOpFixes` count + `prNoOpFixPauseAttempts` (default 3) safety
4260
+ // valve still triggers pause if detection keeps failing.
4261
+ && !lastHumanDispatch.indeterminate
4255
4262
  && lastHumanDispatch.headSha
4256
4263
  && currentHeadSha
4257
4264
  && lastHumanDispatch.headSha === currentHeadSha
@@ -4436,6 +4443,12 @@ async function discoverFromPrs(config, project) {
4436
4443
  // below — symmetric to the human-feedback bug. Skip only the build-fix
4437
4444
  // dispatch path; downstream merge-conflict resolution must still run.
4438
4445
  const skipBuildFix = !!(lastBuildDispatch?.outcome === 'noop'
4446
+ // W-mpg6wptq0011cc68: symmetric protection — indeterminate noops here
4447
+ // (detection couldn't verify branch advance) must NOT permanently
4448
+ // suppress build-fix either. Same rationale as the human-feedback
4449
+ // guard above; the per-cause `_noOpFixes` count + pause-after-N valve
4450
+ // still applies.
4451
+ && !lastBuildDispatch.indeterminate
4439
4452
  && lastBuildDispatch.headSha
4440
4453
  && currentHeadSha
4441
4454
  && lastBuildDispatch.headSha === currentHeadSha);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yemi33/minions",
3
- "version": "0.1.2010",
3
+ "version": "0.1.2012",
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"