@yemi33/minions 0.1.2314 → 0.1.2315

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.
@@ -12,6 +12,7 @@ The engine runs a tick every 10 seconds (configurable via `config.json` → `eng
12
12
  tick()
13
13
  1. checkTimeouts() Enforce runtime limits and stale-orphan cleanup
14
14
  1a. checkSteering() Drain steering messages queued by the dashboard
15
+ 1a2 checkSpawnPhaseStalls() Watchdog for agents stuck before their first heartbeat
15
16
  1b. checkIdleThreshold() Notify on excessive agent idleness
16
17
  1c. meetingTimeouts() Advance round-based meetings whose timer fired
17
18
  2. consolidateInbox() Merge learnings into notes.md (Haiku-powered)
@@ -31,6 +32,8 @@ tick()
31
32
  3a. pruneStalePrDispatches() Clear pending PR dispatches whose underlying PRs no longer warrant action
32
33
  3. discoverWork() Scan ALL linked projects for new tasks
33
34
  4. updateSnapshot() Write identity/now.md
35
+ 4a. memoryBaseline() Sample RSS/heap/GC every memoryBaselineEveryTicks ticks (default 6 ≈ 60s)
36
+ 4b. heapSnapshotRequest() Serve a pending guard-token heap-snapshot request, if any
34
37
  5. dispatch Spawn agents for pending items (up to maxConcurrent)
35
38
  ```
36
39
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  > Author: Rebecca (Architect) | Date: 2026-04-07 | Status: **Accepted — implementation in progress**
4
4
 
5
- > **Implementation status (as of 2026-06):** The `node:sqlite` recommendation in §3 has been adopted ahead of schedule. Phases 0–10 have shipped (events, dispatches, work_items, pull_requests, logs, metrics, watches, schedule_runs + pipeline_runs + managed_processes + worktree_pool, qa_runs + qa_sessions, pr_links, cooldowns + pending_rebases + cc_sessions + doc_sessions, and steering_deliveries (Phases 0–9); plans + prds + prd_items + prd_verify_prs (Phase 10, migration `015-plans-prds.js`) — see `CHANGELOG.md` and `engine/db/migrations/`). The SQLite schema lives under `engine/db/migrations/` and the singleton opens `engine/state.db` in WAL mode. Phase 8 added the first opt-out toggle for the JSON sidecars (`engine.qaDualWriteJson`, default true). Phase 9.4 went further and deleted the silent SQL-unavailable JSON fallbacks in the engine — SQL is now the only reader/writer for everything migrated; the JSON mirror layer is dual-written as a passive mirror and slated for deletion in Phase 9.5. Phase 10 dual-writes PRD state to SQL (`engine/prd-store.js`) and flips reads to SQL when the `prdReadsFromSql` feature flag is ON (default ON reversible). The "Phase 2: estimated Node 26 LTS" timeline in §3 is now historical context; treat sections 1–3 as design rationale rather than a forward plan.
5
+ > **Implementation status (as of 2026-06):** The `node:sqlite` recommendation in §3 has been adopted ahead of schedule. Phases 0–10 have shipped (events, dispatches, work_items, pull_requests, logs, metrics, watches, schedule_runs + pipeline_runs + managed_processes + worktree_pool, qa_runs + qa_sessions, pr_links, cooldowns + pending_rebases + cc_sessions + doc_sessions, and steering_deliveries (Phases 0–9); plans + prds + prd_items + prd_verify_prs (Phase 10, migration `015-plans-prds.js`) — see `CHANGELOG.md` and `engine/db/migrations/`). The SQLite schema lives under `engine/db/migrations/` and the singleton opens `engine/state.db` in WAL mode. Phase 8 added the first opt-out toggle for the JSON sidecars (`engine.qaDualWriteJson`, default true). Phase 9.4 went further and deleted the silent SQL-unavailable JSON fallbacks in the engine — SQL is now the only reader/writer for everything migrated; the JSON mirror layer is dual-written as a passive mirror and slated for deletion in Phase 9.5. Phase 10 dual-writes PRD state to SQL (`engine/prd-store.js`); the `prdReadsFromSql` read-flip flag was removed after soaking (default had been ON since 0.1.2090) — SQL is now the unconditional PRD read path in `engine/queries.js`, with SQL errors propagating instead of silently falling back to a disk scan. Phase 10 step 4.3 added a second, still-flagged toggle, `prdJoinFromFk`: it resolves the dashboard WI↔PRD-item join via the SQL FK (`work_items.prd_item_id` → `prd_items.id`) instead of the legacy feature-id string match, with a fallback to the string match when the flag is OFF or the FK is unstamped/NULL (default ON, reversible, expires 2026-12-01). The "Phase 2: estimated Node 26 LTS" timeline in §3 is now historical context; treat sections 1–3 as design rationale rather than a forward plan.
6
6
 
7
7
  ## Executive Summary
8
8
 
@@ -81,6 +81,10 @@ A paused cause **suppresses further auto-dispatch for that cause** until cleared
81
81
 
82
82
  The exported `recordPrNoOpFixAttempt` / `clearPrNoOpFixAttempt` / `sweepStalePrNoOpFixes` helpers in `engine/lifecycle.js` are the only sanctioned entry points. The dispatch evaluator gates re-dispatch on `shared.isPrNoOpFixCausePaused(pr, cause)` (which re-validates the fingerprint per call), the dashboard chip surface uses `shared.getPrPausedCauses(pr)` (same gate), and the `pollPrStatus` callback in `engine/ado.js` + `engine/github.js` calls `sweepStalePrNoOpFixes(pr)` each tick to GC records whose fingerprint no longer matches the live PR.
83
83
 
84
+ #### E2. Build-fix-ineffective tracker (`pr._buildFixIneffective`, issue #639)
85
+
86
+ A "branch unchanged" no-op report for a `BUILD_FAILURE`-cause fix used to be conflated with the generic `_noOpFixes[BUILD_FAILURE]` counter even when the build was still genuinely red on the unchanged head — silently masking a stuck failure as "handled". `checkBuildStillFailingLive()` re-polls host-specific live CI (`checkLiveBuildAndConflict` in `engine/github.js` / `engine/ado.js`) right after `detectPrFixBranchChange()` reports no branch change for a build-failure fix. If the build is still failing, `recordBuildFixIneffective()` tracks a **separate**, `headSha`-keyed counter (`pr._buildFixIneffective`) instead of bumping `_noOpFixes[BUILD_FAILURE]`, pausing after `prNoOpFixPauseAttempts` on the same head and writing a distinct `build-fix-ineffective-<pr>` inbox alert; `shared.isBuildFixIneffectivePaused()` re-validates the stored `headSha` against the live PR before honoring the pause (same fingerprint-revalidation pattern as `isPrNoOpFixCausePaused`), and `engine.js` wires `isBuildFixIneffectiveSuppressed()` into the `BUILD_FAILURE` dispatch gate alongside the existing no-op check. A real branch-changing fix clears the stale record. The dashboard PR list (`dashboard/js/render-prs.js`) renders a separate, non-interactive "infra issue suspected" chip for a paused `_buildFixIneffective` record (tooltip shows `reason`/`count`/`headSha`/`liveBuildStatus`) alongside the existing `_pausedCauses` chips.
87
+
84
88
  ## 5. Fix completes
85
89
 
86
90
  - `updatePrAfterFix()` (lifecycle.js) sets `reviewStatus = 'waiting'` + `fixedAt = ts()`
@@ -163,3 +167,4 @@ The exported `recordPrNoOpFixAttempt` / `clearPrNoOpFixAttempt` / `sweepStalePrN
163
167
  - Builds use the merge commit hash as `sourceVersion`, not the source branch commit — compare against `lastMergeCommit.commitId`
164
168
  - `partiallySucceeded` counts as passing (warnings, not failures)
165
169
  - A stale but passing build is still valid — don't re-trigger builds that already passed
170
+ - ADO never auto-clears a reviewer's numeric vote when new commits land, so a hard-reject `-10` vote stays live forever unless the reviewer explicitly re-votes. Both `pollPrStatus()` and the pre-dispatch `checkLiveReviewStatus()` treat a `-10` as **stale/superseded** (resolving to `waiting` instead of `changes-requested`) via `isStaleAdoRejectVote()` once a fix has completed after the vote's last review (`fixedAt > lastReviewedAt`) with no push since (`lastPushedAt <= fixedAt`) — otherwise the auto re-review-after-fix flow can never fire for that PR (issue #633).
@@ -48,6 +48,8 @@ Filenames follow the `YYYY-MM-DD-<agent>-<slug>.md` convention so chronological
48
48
 
49
49
  Agents read `knowledge/` directly with grep/glob/view. They **do not** write to it. See [Sweep-write-only constraint](#sweep-write-only-constraint) below.
50
50
 
51
+ **Full-body copies vs. condensed stubs.** When `engine/consolidation.js#classifyToKnowledgeBase` promotes an inbox note into `knowledge/`, it only copies the full body when the note is routed to `conventions/` or its content carries a reusable-knowledge section header (`## Patterns`, `## Conventions`, `## Gotchas`, `## Dependencies`, `## Best Practices`, etc.). Narrowly-scoped, one-off notes (a single PR review, a task status update) instead get a deterministic, LLM-free condensed stub — title + first-paragraph abstract + a link back to the archived inbox note — to avoid duplicating disk usage and prompt-token cost on every future dispatch. Every promoted entry's frontmatter gains a `reusable: true|false` field so this can be audited (issue #604).
52
+
51
53
  ### 3. `notes.md` — consolidated team notes
52
54
 
53
55
  `notes.md` is the rolling team notebook. The consolidation sweep periodically merges high-signal findings from the inbox into dated `### YYYY-MM-DD` sections at the top of `notes.md`, with links back to the underlying KB entries.
package/docs/watches.md CHANGED
@@ -169,7 +169,7 @@ I/O happens **outside the lock**: notifications via `writeToInbox`, follow-up ac
169
169
  | `dispatch-work-item` | Append a new WI to the project (or central) `work-items.json` with `createdBy: "watch:<id>"` |
170
170
  | `run-skill` | Wrapper around `dispatch-work-item` that asks the agent to run a specific `.claude` skill |
171
171
  | `webhook` | `http`/`https` request to an arbitrary URL (10s safety timeout, JSON or string body) |
172
- | `minions-api` | Loopback call to the in-process dashboard at `http://127.0.0.1:${MINIONS_PORT \|\| 7331}` — `endpoint` must start with `/api/`; sets `X-Minions-Internal: 1`; returns `{ok, status, summary, response}` for chain-step templating |
172
+ | `minions-api` | Loopback call to the in-process dashboard at `http://127.0.0.1:${shared.readDashboardPortFile(MINIONS_DIR)?.port \|\| 7331}` (reads the bound-port beacon file, not the `MINIONS_PORT` env, so it still resolves after an `EADDRINUSE` port scan) — `endpoint` must start with `/api/`; sets `X-Minions-Internal: 1`; returns `{ok, status, summary, response}` for chain-step templating |
173
173
  | `cancel-work-item` | Flip a WI to `WI_STATUS.CANCELLED` across all known work-items files |
174
174
  | `trigger-pipeline` | Start a new pipeline run (skipped if the pipeline already has an active run) |
175
175
  | `archive-plan` | Set PRD `status="archived"` + `archivedAt` |
package/engine/cleanup.js CHANGED
@@ -740,10 +740,22 @@ async function runCleanup(config, verbose = false) {
740
740
  shared._writeWorktreeSkipLiveInboxNote(full, 'cleanup.orphanWorktreeDirSweep', blockingInfo);
741
741
  continue;
742
742
  }
743
+ // W-mr2zu0hb000f20c7 — route through shared.removeWorktree instead of a
744
+ // raw fs.rmSync so this path gets the same retry-with-backoff (transient
745
+ // Windows EBUSY/locked-file handling) and real-repo-refusal safety net
746
+ // that every other worktree removal in this file uses. This dir already
747
+ // isn't registered in `git worktree list`, so the primary
748
+ // `git worktree remove --force` inside removeWorktree is expected to
749
+ // fail and fall through to its fs.rmSync + retry logic — that's fine,
750
+ // the safety checks (ownership marker already verified above; real-repo
751
+ // and live-dispatch refusals re-checked inside removeWorktree) still apply.
743
752
  try {
744
- fs.rmSync(full, { recursive: true, force: true });
745
- cleaned.orphanWorktreeDirs++;
746
- log('info', `Cleanup: removed orphan worktree dir ${full} (not registered in git)`);
753
+ if (shared.removeWorktree(full, root, wtRoot)) {
754
+ cleaned.orphanWorktreeDirs++;
755
+ log('info', `Cleanup: removed orphan worktree dir ${full} (not registered in git)`);
756
+ } else {
757
+ log('warn', `orphan worktree dir ${full}: removeWorktree declined (see prior log line for reason)`);
758
+ }
747
759
  } catch (err) {
748
760
  log('warn', `orphan worktree dir ${full}: ${err.message}`);
749
761
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yemi33/minions",
3
- "version": "0.1.2314",
3
+ "version": "0.1.2315",
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"