@yemi33/minions 0.1.2273 → 0.1.2274

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.
@@ -124,6 +124,17 @@
124
124
  </div>
125
125
  </div>
126
126
  </div>
127
+ <!-- Pending work items sub-section: lists work items with
128
+ status === 'pending'. Populated by renderPendingWorkItems() in
129
+ status.js from the /api/work-items poll slice; hidden via the
130
+ `hidden` attribute when there are zero pending items. -->
131
+ <div class="pending-section" id="pending-section" hidden>
132
+ <div class="pending-head">
133
+ Pending Work Items
134
+ <span class="pending-count" id="pending-count"></span>
135
+ </div>
136
+ <div class="pending-list" id="pending-list"></div>
137
+ </div>
127
138
  </div>
128
139
  </div>
129
140
 
@@ -514,6 +514,7 @@
514
514
  _slimSettle('/api/pull-requests', prev.pullRequests),
515
515
  _slimSettle('/api/pinned', prev.pinned),
516
516
  _slimSettle('/state/engine/watches.json', prev.watches),
517
+ _slimSettle('/api/work-items', prev.workItems),
517
518
  ]);
518
519
  var data = results[0] || {};
519
520
  data.dispatch = (results[1] && typeof results[1] === 'object') ? results[1] : {};
@@ -521,6 +522,7 @@
521
522
  data.pullRequests = Array.isArray(results[3]) ? results[3] : [];
522
523
  data.pinned = Array.isArray(results[4]) ? results[4] : [];
523
524
  data.watches = Array.isArray(results[5]) ? results[5] : [];
525
+ data.workItems = Array.isArray(results[6]) ? results[6] : [];
524
526
  applyStatus(data);
525
527
  } catch (e) {
526
528
  // Soft failure — leave previous values, surface in stamp
@@ -165,6 +165,11 @@
165
165
  // ── Team member cards ──────────────────────────────────────
166
166
  renderMembers(Array.isArray(data.agents) ? data.agents : []);
167
167
 
168
+ // ── Pending work items section ─────────────────────────────
169
+ // Surfaces WIs with status === 'pending' (W-mqtx516q). Sourced from the
170
+ // /api/work-items slice merged in by the slim poll (history.js).
171
+ renderPendingWorkItems(Array.isArray(data.workItems) ? data.workItems : []);
172
+
168
173
  // ── Stamps + history ───────────────────────────────────────
169
174
  var stamp = document.getElementById('cockpit-stamp');
170
175
  if (stamp) stamp.textContent = 'updated ' + relTime(data.timestamp || Date.now());
@@ -174,3 +179,94 @@
174
179
  if (hStamp) hStamp.textContent = relTime(data.timestamp || Date.now());
175
180
  }
176
181
 
182
+ // ── Pending work items renderer ────────────────────────────────
183
+ // Lists every work item with status === 'pending' in a dedicated section
184
+ // under the cockpit (W-mqtx516q). The section is hidden via the `hidden`
185
+ // attribute when there are zero pending items. Each row shows id, title,
186
+ // project, type, and the engine's _pendingReason as a small badge when set.
187
+ // Everything goes through textContent (no innerHTML) to keep the SEC-03
188
+ // baseline clean. A JSON fingerprint of the visible fields skips the DOM
189
+ // rebuild when nothing changed between 5s polls.
190
+ var _lastPendingJson = null;
191
+
192
+ function renderPendingWorkItems(items) {
193
+ var section = document.getElementById('pending-section');
194
+ var list = document.getElementById('pending-list');
195
+ if (!section || !list) return;
196
+
197
+ var pending = (Array.isArray(items) ? items : []).filter(function(w) {
198
+ return w && w.status === 'pending';
199
+ });
200
+
201
+ var fingerprint = JSON.stringify(pending.map(function(w) {
202
+ return [w.id, w.title, w.project || w._source, w.type, w._pendingReason];
203
+ }));
204
+ if (fingerprint === _lastPendingJson) return;
205
+ _lastPendingJson = fingerprint;
206
+
207
+ if (!pending.length) {
208
+ section.setAttribute('hidden', '');
209
+ list.textContent = '';
210
+ return;
211
+ }
212
+ section.removeAttribute('hidden');
213
+
214
+ var countEl = document.getElementById('pending-count');
215
+ if (countEl) countEl.textContent = String(pending.length);
216
+
217
+ list.textContent = '';
218
+ var frag = document.createDocumentFragment();
219
+ pending.forEach(function(w) {
220
+ var row = document.createElement('div');
221
+ row.className = 'pending-row';
222
+
223
+ // Top line: title + optional pending-reason badge.
224
+ var main = document.createElement('div');
225
+ main.className = 'pending-row-main';
226
+
227
+ var title = document.createElement('span');
228
+ title.className = 'pending-title';
229
+ title.textContent = w.title || w.id || '(untitled)';
230
+ title.title = (w.title || w.id || '') + (w.id ? ' (' + w.id + ')' : '');
231
+ main.appendChild(title);
232
+
233
+ if (w._pendingReason) {
234
+ var badge = document.createElement('span');
235
+ badge.className = 'pending-reason-badge';
236
+ badge.textContent = String(w._pendingReason).replace(/_/g, ' ');
237
+ badge.title = 'Pending reason: ' + w._pendingReason;
238
+ main.appendChild(badge);
239
+ }
240
+ row.appendChild(main);
241
+
242
+ // Meta line: id + project + type chips.
243
+ var meta = document.createElement('div');
244
+ meta.className = 'pending-row-meta';
245
+
246
+ var idEl = document.createElement('span');
247
+ idEl.className = 'pending-meta-id';
248
+ idEl.textContent = w.id || '';
249
+ meta.appendChild(idEl);
250
+
251
+ var project = w.project || w._source;
252
+ if (project) {
253
+ var projEl = document.createElement('span');
254
+ projEl.className = 'pending-meta-chip';
255
+ projEl.textContent = project;
256
+ meta.appendChild(projEl);
257
+ }
258
+
259
+ if (w.type) {
260
+ var typeEl = document.createElement('span');
261
+ typeEl.className = 'pending-meta-chip pending-meta-type';
262
+ typeEl.textContent = w.type;
263
+ meta.appendChild(typeEl);
264
+ }
265
+ row.appendChild(meta);
266
+
267
+ frag.appendChild(row);
268
+ });
269
+ list.appendChild(frag);
270
+ }
271
+
272
+
@@ -1139,6 +1139,93 @@
1139
1139
  .team-section { margin-bottom: 14px; }
1140
1140
  .cockpit-section { padding-top: 14px; border-top: 1px solid var(--border); }
1141
1141
 
1142
+ /* Pending work items section (W-mqtx516q). Sits under the cockpit tiles;
1143
+ hidden via the `hidden` attribute when there are no pending WIs. */
1144
+ .pending-section {
1145
+ padding-top: 14px;
1146
+ margin-top: 14px;
1147
+ border-top: 1px solid var(--border);
1148
+ }
1149
+ .pending-section[hidden] { display: none; }
1150
+ .pending-head {
1151
+ font-size: var(--text-sm);
1152
+ font-weight: 600;
1153
+ color: var(--text);
1154
+ letter-spacing: 0.02em;
1155
+ text-transform: uppercase;
1156
+ margin-bottom: 8px;
1157
+ display: flex;
1158
+ align-items: center;
1159
+ gap: 6px;
1160
+ }
1161
+ .pending-count {
1162
+ font-size: var(--text-xs);
1163
+ font-weight: 600;
1164
+ color: var(--orange);
1165
+ background: rgba(214, 153, 34, 0.14);
1166
+ border-radius: 9px;
1167
+ padding: 0 7px;
1168
+ line-height: 16px;
1169
+ }
1170
+ .pending-list {
1171
+ display: flex;
1172
+ flex-direction: column;
1173
+ gap: 6px;
1174
+ }
1175
+ .pending-row {
1176
+ background: var(--surface2);
1177
+ border: 1px solid var(--border);
1178
+ border-left: 3px solid var(--orange);
1179
+ border-radius: var(--radius);
1180
+ padding: 7px 9px;
1181
+ }
1182
+ .pending-row-main {
1183
+ display: flex;
1184
+ align-items: center;
1185
+ gap: 6px;
1186
+ }
1187
+ .pending-title {
1188
+ font-size: var(--text-md);
1189
+ color: var(--text);
1190
+ overflow: hidden;
1191
+ text-overflow: ellipsis;
1192
+ white-space: nowrap;
1193
+ min-width: 0;
1194
+ flex: 1;
1195
+ }
1196
+ .pending-reason-badge {
1197
+ flex: none;
1198
+ font-size: var(--text-xs);
1199
+ color: var(--orange);
1200
+ border: 1px solid rgba(214, 153, 34, 0.5);
1201
+ border-radius: 6px;
1202
+ padding: 0 5px;
1203
+ line-height: 15px;
1204
+ white-space: nowrap;
1205
+ }
1206
+ .pending-row-meta {
1207
+ display: flex;
1208
+ align-items: center;
1209
+ flex-wrap: wrap;
1210
+ gap: 6px;
1211
+ margin-top: 4px;
1212
+ }
1213
+ .pending-meta-id {
1214
+ font-size: var(--text-xs);
1215
+ color: var(--muted);
1216
+ font-family: var(--mono, monospace);
1217
+ }
1218
+ .pending-meta-chip {
1219
+ font-size: var(--text-xs);
1220
+ color: var(--muted);
1221
+ background: var(--surface);
1222
+ border: 1px solid var(--border);
1223
+ border-radius: 6px;
1224
+ padding: 0 6px;
1225
+ line-height: 15px;
1226
+ }
1227
+ .pending-meta-type { color: var(--blue); }
1228
+
1142
1229
  /* Square member cards. Auto-fill so the column count adapts to the
1143
1230
  panel width; aspect-ratio keeps each card square regardless. */
1144
1231
  .member-grid {
@@ -168,14 +168,19 @@ async function validateAcceptanceCriteria(workItem, opts = {}) {
168
168
  model: _resolveModel(opts),
169
169
  maxTurns: 1,
170
170
  direct: true,
171
- // Direct callLLM spawns the runtime CLI with cwd=MINIONS_DIR (engine/llm.js
172
- // _spawnProcess). Without an allowedTools clamp the validator has full
173
- // Edit/Write/Bash access to D:\squad and can leak partial implementations
174
- // outside any worktree confirmed in P-b5e2a481 (2026-06-01 23:44 UTC):
175
- // the validator "previewed" the work by editing dashboard/js/refresh.js
176
- // in MINIONS_DIR before the actual implement agent ran in its worktree.
177
- // Read-only tools only the eval is a JSON-decision call.
178
- allowedTools: 'Read,Grep,Glob',
171
+ // No tools at all. Direct callLLM spawns the runtime CLI with
172
+ // cwd=MINIONS_DIR (engine/llm.js _spawnProcess). P-b5e2a481 (2026-06-01
173
+ // 23:44 UTC) removed write access (Edit/Write/Bash) after the validator
174
+ // "previewed" work by editing dashboard/js/refresh.js in MINIONS_DIR, but
175
+ // left Read/Grep/Glob in place. Those read tools made the model search the
176
+ // MINIONS_DIR codebase to "verify" whether the described code exists — but
177
+ // the cwd is always MINIONS_DIR, never the target project, so work items
178
+ // targeting other repos (e.g. Android in office/src) were searched against
179
+ // this Node.js codebase, found nothing, and were wrongly marked invalid.
180
+ // The pre-dispatch eval is a pure text-reasoning call ("is this clear,
181
+ // actionable, and testable?") and needs no filesystem access. Passing no
182
+ // allowedTools makes the runtime omit --allowedTools entirely so the model
183
+ // reasons only over the prompt text.
179
184
  engineConfig: opts.engineConfig,
180
185
  });
181
186
  } catch (e) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yemi33/minions",
3
- "version": "0.1.2273",
3
+ "version": "0.1.2274",
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"