@yemi33/minions 0.1.984 → 0.1.985

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/CHANGELOG.md CHANGED
@@ -1,8 +1,9 @@
1
1
  # Changelog
2
2
 
3
- ## 0.1.984 (2026-04-15)
3
+ ## 0.1.985 (2026-04-15)
4
4
 
5
5
  ### Features
6
+ - complete watches management — new conditions, CC actions, PROJECTS fix (#1103)
6
7
  - fix misleading poll frequency field labels in settings modal (#1099)
7
8
  - add Auto-complete PRs toggle to settings modal (#1095)
8
9
  - gate build failure auto-fix behind autoFixBuilds flag
@@ -22,7 +23,6 @@
22
23
  - Update command-center.js to capture tool inputs and use formatted summaries
23
24
  - certificate-based auth for Teams integration (#1027)
24
25
  - Create render-utils.js with shared formatting helpers
25
- - add adoPollEnabled/ghPollEnabled engine settings
26
26
 
27
27
  ### Fixes
28
28
  - fix syncPrsFromOutput skipping tool_result lines where PR URLs live (#1100)
@@ -22,6 +22,8 @@ const _WATCH_CONDITION_LABELS = {
22
22
  failed: 'Failed',
23
23
  'status-change': 'Status Change',
24
24
  any: 'Any Change',
25
+ 'new-comments': 'New Comments',
26
+ 'vote-change': 'Vote Change',
25
27
  };
26
28
 
27
29
  function _intervalToHuman(ms) {
@@ -222,6 +224,8 @@ function _watchFormHtml() {
222
224
  { value: 'failed', label: 'Failed' },
223
225
  { value: 'status-change', label: 'Status Change' },
224
226
  { value: 'any', label: 'Any Change' },
227
+ { value: 'new-comments', label: 'New Comments' },
228
+ { value: 'vote-change', label: 'Vote Change' },
225
229
  ];
226
230
  var ttOpts = targetTypes.map(function(t) { return '<option value="' + t.value + '">' + t.label + '</option>'; }).join('');
227
231
  var condOpts = conditions.map(function(c) { return '<option value="' + c.value + '">' + c.label + '</option>'; }).join('');
package/dashboard.js CHANGED
@@ -709,6 +709,24 @@ async function executeCCActions(actions) {
709
709
  results.push({ type: 'create-watch', id: watch.id, ok: true });
710
710
  break;
711
711
  }
712
+ case 'delete-watch': {
713
+ const deleted = watchesMod.deleteWatch(action.id);
714
+ if (deleted) invalidateStatusCache();
715
+ results.push({ type: 'delete-watch', id: action.id, ok: deleted });
716
+ break;
717
+ }
718
+ case 'pause-watch': {
719
+ const paused = watchesMod.updateWatch(action.id, { status: shared.WATCH_STATUS.PAUSED });
720
+ if (paused) invalidateStatusCache();
721
+ results.push({ type: 'pause-watch', id: action.id, ok: !!paused });
722
+ break;
723
+ }
724
+ case 'resume-watch': {
725
+ const resumed = watchesMod.updateWatch(action.id, { status: shared.WATCH_STATUS.ACTIVE });
726
+ if (resumed) invalidateStatusCache();
727
+ results.push({ type: 'resume-watch', id: action.id, ok: !!resumed });
728
+ break;
729
+ }
712
730
  default:
713
731
  // Server didn't handle — frontend must execute
714
732
  results.push({ type: action.type });
package/engine/shared.js CHANGED
@@ -620,7 +620,7 @@ const PR_POLLABLE_STATUSES = new Set([PR_STATUS.ACTIVE, PR_STATUS.LINKED]);
620
620
  // Watch statuses — engine-level persistent watches that survive restarts
621
621
  const WATCH_STATUS = { ACTIVE: 'active', PAUSED: 'paused', TRIGGERED: 'triggered', EXPIRED: 'expired' };
622
622
  const WATCH_TARGET_TYPE = { PR: 'pr', WORK_ITEM: 'work-item' };
623
- const WATCH_CONDITION = { MERGED: 'merged', BUILD_FAIL: 'build-fail', BUILD_PASS: 'build-pass', COMPLETED: 'completed', FAILED: 'failed', STATUS_CHANGE: 'status-change', ANY: 'any' };
623
+ const WATCH_CONDITION = { MERGED: 'merged', BUILD_FAIL: 'build-fail', BUILD_PASS: 'build-pass', COMPLETED: 'completed', FAILED: 'failed', STATUS_CHANGE: 'status-change', ANY: 'any', NEW_COMMENTS: 'new-comments', VOTE_CHANGE: 'vote-change' };
624
624
  // Absolute conditions auto-expire on first trigger when stopAfter=0 (fire-once semantics).
625
625
  // Change-based conditions (status-change, any) run forever when stopAfter=0.
626
626
  const WATCH_ABSOLUTE_CONDITIONS = new Set([
package/engine/watches.js CHANGED
@@ -158,6 +158,16 @@ function evaluateWatch(watch, state) {
158
158
  );
159
159
  return { triggered: anyChanged, message: anyChanged ? `PR ${target} changed` : '' };
160
160
  }
161
+ case WATCH_CONDITION.NEW_COMMENTS: {
162
+ const lastCommentDate = pr.humanFeedback?.lastProcessedCommentDate || null;
163
+ const prevCommentDate = prevState.lastCommentDate || null;
164
+ const hasNew = lastCommentDate && lastCommentDate !== prevCommentDate;
165
+ return { triggered: !!hasNew, message: hasNew ? `PR ${target} has a new comment (${lastCommentDate})` : '' };
166
+ }
167
+ case WATCH_CONDITION.VOTE_CHANGE: {
168
+ const changed = prevState.reviewStatus !== undefined && prevState.reviewStatus !== pr.reviewStatus;
169
+ return { triggered: changed, message: changed ? `PR ${target} vote changed: ${prevState.reviewStatus} → ${pr.reviewStatus}` : '' };
170
+ }
161
171
  default:
162
172
  return { triggered: false, message: `Unknown condition: ${condition}` };
163
173
  }
@@ -280,7 +290,7 @@ function _captureState(watch, state) {
280
290
  const pr = (state.pullRequests || []).find(p =>
281
291
  String(p.prNumber) === String(watch.target) || p.id === watch.target
282
292
  );
283
- if (pr) return { status: pr.status, buildStatus: pr.buildStatus, reviewStatus: pr.reviewStatus };
293
+ if (pr) return { status: pr.status, buildStatus: pr.buildStatus, reviewStatus: pr.reviewStatus, lastCommentDate: pr.humanFeedback?.lastProcessedCommentDate || null };
284
294
  }
285
295
  if (watch.targetType === WATCH_TARGET_TYPE.WORK_ITEM) {
286
296
  const wi = (state.workItems || []).find(w => w.id === watch.target);
package/engine.js CHANGED
@@ -3188,11 +3188,12 @@ async function tickInner() {
3188
3188
  if (tickCount % 3 === 0) {
3189
3189
  safe('checkWatches', () => {
3190
3190
  const { checkWatches } = require('./engine/watches');
3191
- const pullRequests = PROJECTS.flatMap(p => {
3191
+ const projects = getProjects(config);
3192
+ const pullRequests = projects.flatMap(p => {
3192
3193
  const prPath = path.join(MINIONS_DIR, 'projects', p.name, 'pull-requests.json');
3193
3194
  return safeJson(prPath) || [];
3194
3195
  });
3195
- const workItems = PROJECTS.flatMap(p => {
3196
+ const workItems = projects.flatMap(p => {
3196
3197
  const wiPath = path.join(MINIONS_DIR, 'projects', p.name, 'work-items.json');
3197
3198
  return safeJson(wiPath) || [];
3198
3199
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yemi33/minions",
3
- "version": "0.1.984",
3
+ "version": "0.1.985",
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"
@@ -82,9 +82,15 @@ Additional actions (all take `id` or `file` as primary key):
82
82
  - Meetings: add-meeting-note (id, note), advance-meeting (id), end-meeting (id), archive-meeting (id), unarchive-meeting (id), delete-meeting (id)
83
83
  - Work item ops: delete-work-item (id, source), archive-work-item (id), work-item-feedback (id, rating: up/down, comment), reopen-work-item (id, project[, description] — reopen a done/failed item back to pending)
84
84
  - PRD ops: edit-prd-item, remove-prd-item, reopen-prd-item (id, file — re-dispatches on existing branch)
85
- - **create-watch**: target, targetType (pr/work-item/branch), condition (merged/build-fail/build-pass/completed/failed/status-change/any), interval ("15m", "1h", "30s" — default "5m"), owner (agent id or "human"), description, project, stopAfter (0=run forever, 1=expire on first match, N=expire after N matches), onNotMet (null=do nothing, "notify"=write to inbox each poll while condition not met)
85
+ - **create-watch**: target, targetType (pr/work-item), condition (merged/build-fail/build-pass/completed/failed/status-change/any/new-comments/vote-change), interval ("15m", "1h", "30s" — default "5m"), owner (agent id or "human"), description, project, stopAfter (0=run forever, 1=expire on first match, N=expire after N matches), onNotMet (null=do nothing, "notify"=write to inbox each poll while condition not met)
86
86
  Example: user says "check PR 1065 build every 15 min until green" → `{"type":"create-watch","target":"1065","targetType":"pr","condition":"build-pass","interval":"15m","stopAfter":1,"description":"Watch PR 1065 build until green"}`
87
87
  Example: user says "ping me every 15 min while build is still failing" → `{"type":"create-watch","target":"1065","targetType":"pr","condition":"build-pass","interval":"15m","stopAfter":1,"onNotMet":"notify","description":"Watch PR 1065 build — notify each poll"}`
88
+ - **delete-watch**: id — remove a watch permanently
89
+ Example: user says "stop watching PR 1065" → `{"type":"delete-watch","id":"watch-abc123"}`
90
+ - **pause-watch**: id — pause a watch without deleting it (can be resumed later)
91
+ Example: user says "pause the PR 1065 watch" → `{"type":"pause-watch","id":"watch-abc123"}`
92
+ - **resume-watch**: id — resume a paused watch
93
+ Example: user says "resume watching PR 1065" → `{"type":"resume-watch","id":"watch-abc123"}`
88
94
  - KB/Inbox: promote-to-kb (file, category), kb-sweep, toggle-kb-pin (key)
89
95
  - Plan lifecycle: revise-plan (file, feedback — dispatches agent to revise)
90
96
  - Pipeline: continue-pipeline (id — resume past wait stage)