@yemi33/minions 0.1.2047 → 0.1.2049

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/engine/queries.js CHANGED
@@ -531,6 +531,11 @@ function getAgents(config) {
531
531
  // → engine.defaultCli → 'copilot'. Surfaced so the dashboard can show a
532
532
  // runtime tag next to the agent name.
533
533
  const runtime = shared.resolveAgentCli(a, config.engine || {});
534
+ // Resolve the model alongside the runtime so the dashboard can render a
535
+ // sibling chip (W-mpmwxk4y00053271). `resolveAgentModel` returns
536
+ // `undefined` when neither the per-agent override nor `engine.defaultModel`
537
+ // is set, which the renderer treats as "runtime default" and omits.
538
+ const model = shared.resolveAgentModel(a, config.engine || {}) || null;
534
539
  const inboxFiles = allInboxFiles.filter(f => f.includes(a.id));
535
540
  let steeringInboxFiles = [];
536
541
  try { steeringInboxFiles = steering.listUnreadSteeringMessages(a.id); } catch { steeringInboxFiles = []; }
@@ -552,7 +557,7 @@ function getAgents(config) {
552
557
  const chartered = fs.existsSync(path.join(AGENTS_DIR, a.id, 'charter.md'));
553
558
  if (lastAction.length > 120) lastAction = lastAction.slice(0, 120) + '...';
554
559
  return {
555
- ...a, runtime, status: s.status, lastAction,
560
+ ...a, runtime, model, status: s.status, lastAction,
556
561
  currentTask: (s.task || '').slice(0, 200),
557
562
  // P-w2c8d1e7 — Phase 1.2: surface the active dispatch id so watch
558
563
  // captureState can snapshot it for currentDispatchId-aware predicates.
@@ -1236,8 +1241,16 @@ function getWorkItems(config) {
1236
1241
  }
1237
1242
  }
1238
1243
  if (!item._pr) {
1239
- // Derive from PR.prdItems (single source of truth)
1240
- const linkedPr = allPrs.find(p => (p.prdItems || []).includes(item.id));
1244
+ // Derive from PR.prdItems (single source of truth), then fall back to
1245
+ // branch identity. The branch fallback heals decomposed-child WIs whose
1246
+ // PR-opening agent only stamped the parent id into prdItems — branch
1247
+ // names (`work/<wi-id>`) are unique per WI within a project, so a
1248
+ // branch hit is as authoritative as a prdItems hit. Scoped to the same
1249
+ // project so cross-repo branch collisions don't false-link.
1250
+ // (W-mpn0b76200044eed)
1251
+ const itemProject = item.project || item._source;
1252
+ const linkedPr = allPrs.find(p => (p.prdItems || []).includes(item.id))
1253
+ || (item.branch && allPrs.find(p => p.branch === item.branch && p._project === itemProject));
1241
1254
  if (linkedPr) {
1242
1255
  item._pr = linkedPr.id;
1243
1256
  item._prUrl = linkedPr.url;
@@ -1925,6 +1938,10 @@ function getProjectGitStatus(localPath, configuredMainBranch = null) {
1925
1938
  const key = _projectGitStatusCacheKey(localPath, configuredMainBranch);
1926
1939
  const now = Date.now();
1927
1940
  const cached = _projectGitStatusCache.get(key);
1941
+ // Compute ref-mtime freshness once. Used twice below: to gate the TTL
1942
+ // fast-path AND to decide whether the stale-while-revalidate return
1943
+ // should null out the known-stale ahead/behind counters (#2848).
1944
+ const refsAdvanced = !!(cached && _projectGitRefsAdvancedSince(localPath, configuredMainBranch, cached.refMtimes));
1928
1945
  // Within TTL: short-circuit ONLY when no tracked git ref has advanced
1929
1946
  // past cached.ts. Without the mtime gate, a freshly-pulled repo serves
1930
1947
  // the pre-pull ahead/behind counts for up to 15s + one SPA poll (~19s
@@ -1939,7 +1956,7 @@ function getProjectGitStatus(localPath, configuredMainBranch = null) {
1939
1956
  if (cachedIsMissing && fs.existsSync(localPath)) {
1940
1957
  // Path came back — fall through to schedule a fresh probe.
1941
1958
  } else if (cached && cached.ts && (now - cached.ts) < PROJECT_GIT_STATUS_TTL
1942
- && !_projectGitRefsAdvancedSince(localPath, configuredMainBranch, cached.refMtimes)) {
1959
+ && !refsAdvanced) {
1943
1960
  return cached.value;
1944
1961
  }
1945
1962
  // Cheap synchronous existsSync — short-circuits a path that just disappeared
@@ -1955,7 +1972,22 @@ function getProjectGitStatus(localPath, configuredMainBranch = null) {
1955
1972
  // previous value (or pending placeholder on the very first call). The next
1956
1973
  // /api/status response after the refresh settles will have fresh data.
1957
1974
  _scheduleProjectGitStatusRefresh(localPath, key, configuredMainBranch);
1958
- return cached ? cached.value : PROJECT_GIT_STATUS_PENDING;
1975
+ if (!cached) return PROJECT_GIT_STATUS_PENDING;
1976
+ // When tracked git refs have advanced past the cached snapshot, the
1977
+ // cached ahead/behind counts are known to be stale (e.g. user just ran
1978
+ // `git pull` / `git fetch` and the local checkout is now current).
1979
+ // Returning the cached value as-is would briefly display a misleading
1980
+ // "behind: 8" after the user has already pulled to current — see
1981
+ // yemi33/minions#2848. Null those specific counters so the dashboard
1982
+ // shows a pending state for ahead/behind until the background probe
1983
+ // settles; branch and dirty flags stay valid enough on the cached
1984
+ // value (and update on the next poll once the probe lands). TTL-expiry
1985
+ // fall-throughs (refsAdvanced=false) still return the prior counters
1986
+ // because nothing local has actually changed there.
1987
+ if (refsAdvanced) {
1988
+ return { ...cached.value, ahead: null, behind: null };
1989
+ }
1990
+ return cached.value;
1959
1991
  }
1960
1992
 
1961
1993
  // Force a refresh now and wait for completion. Called from dashboard boot
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yemi33/minions",
3
- "version": "0.1.2047",
3
+ "version": "0.1.2049",
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"
@@ -23,7 +23,8 @@
23
23
  "test:perf": "node test/perf/managed-spawn-load.test.js",
24
24
  "test:e2e:accept": "node test/playwright/accept-baseline.js",
25
25
  "test:e2e:accept-force": "node test/playwright/accept-baseline.js --force",
26
- "test:setup": "npx playwright install chromium"
26
+ "test:setup": "npx playwright install chromium",
27
+ "lint": "eslint dashboard/"
27
28
  },
28
29
  "keywords": [
29
30
  "ai",
@@ -65,7 +66,9 @@
65
66
  "@azure-devops/mcp": "2.7.0"
66
67
  },
67
68
  "devDependencies": {
68
- "@playwright/test": "^1.58.2"
69
+ "@playwright/test": "^1.58.2",
70
+ "eslint": "^9.39.4",
71
+ "eslint-plugin-no-unsanitized": "^4.1.5"
69
72
  },
70
73
  "publishConfig": {
71
74
  "access": "public"
package/playbooks/fix.md CHANGED
@@ -93,11 +93,21 @@ Do NOT remove the worktree — the engine handles cleanup automatically.
93
93
 
94
94
  ## Resolve Review Comments
95
95
 
96
- After pushing, respond to each review comment/thread:
97
- - **If you fixed it**: Reply confirming the fix, then resolve the thread
98
- - **If the comment was invalid, stale, already addressed, out of scope, or harmful**: Reply with the evidence-backed rationale explaining why no code change was made — leave the thread open for the reviewer to decide
99
- - **GitHub**: Reply to each review comment, resolve conversations you've fixed
100
- - **ADO**: Use `az` CLI first to reply to each thread and update status when supported; use ADO MCP only as a fallback when `az` is unavailable or insufficient. Set status to `fixed` or `closed` for fixes; leave `active` for rationale replies
96
+ After pushing, respond to each review comment/thread. **Every disposition requires a reply before you resolve, close, or mark-fixed the thread — no exceptions.** Resolving a thread silently is a process violation (see "Resolving Review Threads — No Silent Closures" in `shared-rules.md`).
97
+
98
+ Pick the disposition that matches the finding and post the matching reply, then act on the thread:
99
+
100
+ - **Fixed** Reply confirming the fix with commit SHA or `file:line` of the change, then resolve the thread.
101
+ - **Satisfied elsewhere** (addressed by another chunk / sibling PR / existing wiring the reviewer missed) → Reply citing the exact PR number, commit SHA, or `file:line` that satisfies it, then resolve. Example: `Satisfied by chunk 6 (PR 5216079) — ArtifactsMainScreen.kt:305 re-fires start() via LaunchedEffect on every screen enter.`
102
+ - **Deferred** (non-blocking nit you accept but choose not to act on now) → Reply starting with `Deferred:` and a one-line reason, then resolve. Example: `Deferred: default-off rollout switch makes this acceptable for v1; revisit if telemetry shows otherwise.`
103
+ - **Tracked as follow-up** → Reply with `Tracked as follow-up: W-…` and the WI link, then resolve (see `## Follow-up Dispatch` below).
104
+ - **Won't fix / disagree** (comment is invalid, stale, already addressed, out of scope, or harmful) → Reply with the evidence-backed rationale explaining why no code change was made. Leave the thread **active** for the reviewer to decide; do NOT resolve unilaterally.
105
+
106
+ Host-specific mechanics:
107
+ - **GitHub**: Reply to each review comment, then resolve the conversation for the four resolve-eligible dispositions above. Leave Won't-fix threads unresolved.
108
+ - **ADO**: Use `az` CLI first to reply to each thread and update status when supported; use ADO MCP only as a fallback when `az` is unavailable or insufficient. Set status to `fixed` for Fixed/Satisfied-elsewhere/Tracked-as-follow-up and `closed` for Deferred; leave `active` for Won't-fix rationale replies.
109
+
110
+ Hard rule: never resolve, close, or mark-fixed a thread without first posting a reply that explains the disposition. The chunk-5 / Caleb-Tseng / MaiLibraryViewModel thread (ADO 5215549 thread 65692221) is the canonical bad example — closed silently with no audit trail.
101
111
 
102
112
  ## Follow-up Dispatch
103
113
 
@@ -140,6 +140,35 @@ Concretely:
140
140
  - If you skipped local validation, say so in the completion JSON (e.g. `tests: skipped — relying on PR pipeline`) and still exit.
141
141
  - Holding a slot to watch a pipeline is wasted capacity; the engine has its own pipeline-monitoring path.
142
142
 
143
+ ## Resolving Review Threads — No Silent Closures
144
+
145
+ Whenever you resolve, close, or mark-fixed any PR review thread (GitHub
146
+ conversation or ADO thread), you MUST first post a reply on that thread
147
+ explaining the disposition. This is non-negotiable across every playbook
148
+ (`fix`, `review`, `implement`, follow-up dispatch, anything that touches
149
+ a review thread).
150
+
151
+ Allowed dispositions and what the reply MUST contain:
152
+ - **Fixed** → reply with commit SHA or file:line of the change, then resolve.
153
+ - **Satisfied elsewhere** (addressed by another chunk / sibling PR / existing
154
+ wiring the reviewer missed) → reply citing the exact PR number, commit
155
+ SHA, or `file:line` that satisfies it, then resolve. Example:
156
+ `Satisfied by chunk 6 (PR 5216079) — ArtifactsMainScreen.kt:305
157
+ re-fires start() via LaunchedEffect on every screen enter.`
158
+ - **Deferred** (non-blocking nit you accept but choose not to act on now)
159
+ → reply starting with `Deferred:` and a one-line reason, then resolve.
160
+ Example: `Deferred: default-off rollout switch makes this acceptable
161
+ for v1; revisit if telemetry shows otherwise.`
162
+ - **Tracked as follow-up** → reply with `Tracked as follow-up: W-…` and
163
+ the WI link, then resolve (see follow-up dispatch template).
164
+ - **Won't fix / disagree** → reply with the evidence-backed rationale;
165
+ leave the thread **active** for the reviewer to decide. Do NOT resolve
166
+ unilaterally.
167
+
168
+ Hard rule: resolving a thread with no reply comment is a process violation.
169
+ The chunk-5 / Caleb-Tseng / MaiLibraryViewModel thread (ADO 5215549 thread
170
+ 65692221) is the canonical bad example — closed silently with no audit trail.
171
+
143
172
  {{#github_shared_rules}}
144
173
  ## Checking PR and Build Status
145
174