@yemi33/minions 0.1.2306 → 0.1.2307

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/bin/minions.js CHANGED
@@ -1580,6 +1580,7 @@ ${fs.existsSync(path.join(PKG_ROOT, '.git')) ? `
1580
1580
  isPortListening,
1581
1581
  confirmPortUp: tcpPortAccepts,
1582
1582
  isStopIntentSet: shared.isStopIntentSet || (() => false),
1583
+ recordRespawn: shared.recordEngineRespawn,
1583
1584
  }).then(result => {
1584
1585
  // ALWAYS exit 0 — the scheduler must never see a failure for the
1585
1586
  // recovery we're trying to make boring. The `result` is logged by tick
@@ -289,6 +289,23 @@ async function openSettings() {
289
289
  '⚠ Live mode: dispatches run directly in this repo\'s checkout. Only one mutating dispatch runs at a time. Dirty working trees block dispatch — commit or stash before running.' +
290
290
  '</div>' +
291
291
  '</div>';
292
+ // W-mqtvnnj1000357fa — per-project live-checkout auto-stash override.
293
+ // Tri-state: "" (use fleet default → engine.liveCheckoutAutoStash), "on"
294
+ // (force stash), "off" (force fail-on-dirty). Only an explicit on/off
295
+ // overrides the fleet setting; the default option leaves p.liveCheckoutAutoStash
296
+ // unset so resolveLiveCheckoutAutoStash falls back to engine.
297
+ var autoStashRaw = (p.liveCheckoutAutoStash === true) ? 'on' : (p.liveCheckoutAutoStash === false) ? 'off' : '';
298
+ var autoStashSearch = 'live checkout auto-stash dirty tree stash dispatch';
299
+ var autoStashBlock =
300
+ '<div data-search="' + escHtml(autoStashSearch) + '" style="margin-bottom:6px">' +
301
+ '<label style="font-size:var(--text-sm);color:var(--muted);display:block;margin-bottom:2px">Live-checkout auto-stash</label>' +
302
+ '<select id="set-liveCheckoutAutoStash-' + escHtml(p.name) + '" style="width:100%;padding:4px 6px;background:var(--surface);border:1px solid var(--border);border-radius:4px;color:var(--text);font-size:var(--text-md)">' +
303
+ '<option value=""' + (autoStashRaw === '' ? ' selected' : '') + '>Use fleet default</option>' +
304
+ '<option value="on"' + (autoStashRaw === 'on' ? ' selected' : '') + '>On — auto-stash dirty tree</option>' +
305
+ '<option value="off"' + (autoStashRaw === 'off' ? ' selected' : '') + '>Off — fail on dirty tree</option>' +
306
+ '</select>' +
307
+ '<div style="font-size:var(--text-xs);color:var(--muted);margin-top:2px;line-height:1.4">Live mode only. On = `git stash push --include-untracked` a dirty tree before dispatch instead of failing; the engine never pops the stash (run `git stash pop` manually). Overrides the fleet-wide setting under Worktrees.</div>' +
308
+ '</div>';
292
309
  return '<div data-settings-project="' + escHtml(p.name) + '" data-search="project ' + escHtml(p.name.toLowerCase()) + '" style="border:1px solid var(--border);border-radius:6px;padding:10px 12px;margin-bottom:12px">' +
293
310
  '<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:8px">' +
294
311
  '<div style="font-size:var(--text-md);font-weight:600">' + escHtml(p.name) + '</div>' +
@@ -297,6 +314,7 @@ async function openSettings() {
297
314
  pathRow +
298
315
  branchGrid +
299
316
  worktreeModeBlock +
317
+ autoStashBlock +
300
318
  driftNote +
301
319
  '<div style="display:flex;flex-direction:column;gap:6px;margin-top:8px">' +
302
320
  settingsToggle('Discover from PRs', 'set-ws-prs-' + p.name, p.workSources.pullRequests.enabled, 'Discovery gate: scan repo for open PRs and surface them as review tasks. Independent of ADO/GitHub polling — does not affect already-tracked PRs.') +
@@ -1050,6 +1068,7 @@ async function saveSettings() {
1050
1068
  autoCompletePrs: document.getElementById('set-autoCompletePrs').checked,
1051
1069
  ccUseWorkerPool: !!document.getElementById('set-ccUseWorkerPool')?.checked,
1052
1070
  autoReapOrphanWorktreeHolders: !!document.getElementById('set-autoReapOrphanWorktreeHolders')?.checked,
1071
+ liveCheckoutAutoStash: !!document.getElementById('set-liveCheckoutAutoStash')?.checked,
1053
1072
  liveCheckoutAutoReset: !!document.getElementById('set-liveCheckoutAutoReset')?.checked,
1054
1073
  orphanHolderScanTimeoutMs: document.getElementById('set-orphanHolderScanTimeoutMs')?.value,
1055
1074
  statusProbeKillTimeoutMs: document.getElementById('set-statusProbeKillTimeoutMs')?.value,
@@ -1155,10 +1174,18 @@ async function saveSettings() {
1155
1174
  // values.
1156
1175
  const wtModeInput = document.getElementById('set-checkoutMode-' + p.name);
1157
1176
  const wtModeValue = (wtModeInput && wtModeInput.value === 'live') ? 'live' : 'worktree';
1177
+ // W-mqtvnnj1000357fa — per-project live-checkout auto-stash override.
1178
+ // '' → null (clear override, fall back to engine fleet setting); 'on' →
1179
+ // true; 'off' → false. The server deletes the field on null and validates
1180
+ // booleans.
1181
+ const autoStashInput = document.getElementById('set-liveCheckoutAutoStash-' + p.name);
1182
+ const autoStashRaw = autoStashInput ? autoStashInput.value : '';
1183
+ const autoStashValue = autoStashRaw === 'on' ? true : autoStashRaw === 'off' ? false : null;
1158
1184
  return {
1159
1185
  name: p.name,
1160
1186
  mainBranch: mainBranchValue || null,
1161
1187
  checkoutMode: wtModeValue,
1188
+ liveCheckoutAutoStash: autoStashValue,
1162
1189
  workSources: {
1163
1190
  pullRequests: { enabled: document.getElementById('set-ws-prs-' + p.name)?.checked ?? true },
1164
1191
  workItems: { enabled: document.getElementById('set-ws-wi-' + p.name)?.checked ?? true }
@@ -226,28 +226,12 @@
226
226
  </div>
227
227
  </div>
228
228
 
229
- <!-- Plans + PRD control panel — opened from the "Plans" status tile. Two tabs:
230
- Plans (.md plan drafts) and PRD (materialized PRDs). Each tab is rendered
231
- lazily by dashboard/slim/js/plans.js into #slim-plans-body. Backed by the
232
- existing endpoints (no new server routes):
233
- Plans /api/plans (list), /api/plans/:file (read), and the lifecycle
234
- POSTs (/api/plans/{approve,execute,reject,pause,regenerate,
235
- archive,delete,unarchive}).
236
- PRD — the .json entries from /api/plans plus /api/prd and the
237
- read-only subset of /api/prd-items. -->
238
- <div class="modal-bg" id="slim-plans-modal">
239
- <div class="modal slim-plans-modal-inner">
240
- <div class="modal-header">
241
- <h3>Plans</h3>
242
- <div class="kn-tabs" id="slim-plans-tabs" role="tablist">
243
- <button class="kn-tab active" id="slim-plans-tab-plans" data-plans-tab="plans" type="button" role="tab" aria-selected="true" aria-controls="slim-plans-body">Plans</button>
244
- <button class="kn-tab" id="slim-plans-tab-prd" data-plans-tab="prd" type="button" role="tab" aria-selected="false" aria-controls="slim-plans-body">PRD</button>
245
- </div>
246
- <button id="slim-plans-close" class="icon-btn" title="Close" style="margin-left:auto">&times;</button>
247
- </div>
248
- <div class="modal-body" id="slim-plans-body" role="tabpanel" tabindex="0" aria-labelledby="slim-plans-tab-plans"></div>
249
- </div>
250
- </div>
229
+ <!-- Plans + PRD control panel — the "Plans" cockpit tile opens the LITERAL
230
+ classic /plans screen in a chrome-off iframe (/plans?embed=1), routed through
231
+ the standard TILE_VIEWS path in modals-tiles.js#renderPlansBody. There is no
232
+ slim-specific Plans/PRD flyout markup anymore (W-mr28ko750010199f / "reuse,
233
+ don't fork"): the classic /plans screen is the single source of truth for the
234
+ Plans + PRD tabs and every lifecycle action. -->
251
235
 
252
236
  <!-- Pin editor — create (Pin Content action / "+ Pin") or edit an existing
253
237
  note. Submits to POST /api/pinned (create) or /api/pinned/update (edit). -->
@@ -17,7 +17,6 @@
17
17
  bindModalClose('slim-agent-modal', 'slim-agent-close', _stopAgentDetailRuntime);
18
18
  bindModalClose('slim-tools-modal', 'slim-tools-close');
19
19
  bindModalClose('slim-tile-modal', 'slim-tile-close');
20
- bindModalClose('slim-plans-modal', 'slim-plans-close');
21
20
 
22
21
  function tileEmpty(body, text) {
23
22
  var d = document.createElement('div');
@@ -142,6 +141,25 @@
142
141
  body.appendChild(frame);
143
142
  }
144
143
 
144
+ // Plans tile body — reuses the LITERAL classic dashboard /plans screen instead
145
+ // of a slim-specific tabbed Plans/PRD flyout, so there is one Plans/PRD UI, not
146
+ // two (W-mr28ko750010199f / "reuse, don't fork" — mirrors renderQueuedWorkBody
147
+ // for the Work tile). Slim and classic are two separate IIFE bundles with no
148
+ // shared scope, so we embed the real /plans screen in an iframe with the
149
+ // chrome-off ?embed=1 mode. The iframed page IS the classic screen — the full
150
+ // Plans + PRD tabbed UI with every lifecycle action (approve/execute/reject/
151
+ // pause/regenerate/unarchive/archive/delete), backed by the same /api/plans +
152
+ // /api/prd data + endpoints — with zero duplicated rendering logic. Classic is
153
+ // reachable at /plans even with slim-ux ON (only / is taken over). Built with
154
+ // createElement (no innerHTML) to satisfy the dashboard no-unsanitized lint gate.
155
+ function renderPlansBody(body) {
156
+ var frame = document.createElement('iframe');
157
+ frame.className = 'slim-plans-embed';
158
+ frame.src = '/plans?embed=1';
159
+ frame.title = 'Plans';
160
+ body.appendChild(frame);
161
+ }
162
+
145
163
  function renderPrTileBody(body, data) {
146
164
  // Emoji glyphs make build/review status scannable at a glance; the
147
165
  // accompanying label keeps the row readable when the glyph alone is
@@ -264,6 +282,7 @@
264
282
  engine: { title: 'Engine', render: renderEngineTileBody },
265
283
  dispatches: { title: 'Active dispatches', render: function(body, data) { renderDispatchTileBody(body, data, true); } },
266
284
  queued: { title: 'Queued work', render: function(body) { renderQueuedWorkBody(body); } },
285
+ plans: { title: 'Plans', render: function(body) { renderPlansBody(body); } },
267
286
  prs: { title: 'Pull requests', render: renderPrTileBody },
268
287
  watches: { title: 'Watches', render: renderWatchTileBody },
269
288
  };
@@ -274,9 +293,6 @@
274
293
  // The Knowledge tile opens the unified Knowledge control panel (Pinned
275
294
  // Context + Notes + KB tabs) rather than the read-only tile detail view.
276
295
  if (key === 'knowledge') { openKnowledgeModal(); return; }
277
- // The Plans tile opens the tabbed Plans/PRD control panel (rendered by
278
- // dashboard/slim/js/plans.js) rather than the read-only tile detail view.
279
- if (key === 'plans') { openPlansModal(); return; }
280
296
  var view = TILE_VIEWS[key];
281
297
  if (!view) return;
282
298
  var modal = document.getElementById('slim-tile-modal');
@@ -288,9 +304,11 @@
288
304
  // The "+ Link PR" header chip only applies to the PR list.
289
305
  var headerChip = document.getElementById('slim-tile-modal-linkpr');
290
306
  if (headerChip) headerChip.style.display = (key === 'prs') ? '' : 'none';
291
- // The queued tile embeds the full classic /work screen in an iframe — widen
292
- // the modal + drop the body padding so the embedded table gets real estate.
307
+ // The queued + plans tiles embed a full classic screen (/work, /plans) in an
308
+ // iframe — widen the modal + drop the body padding so the embedded screen
309
+ // gets real estate. Both reuse the shared wide-modal treatment.
293
310
  modal.classList.toggle('tile-modal--work', key === 'queued');
311
+ modal.classList.toggle('tile-modal--plans', key === 'plans');
294
312
  view.render(body, lastStatusData || {});
295
313
  modal.classList.add('open');
296
314
  }
@@ -316,22 +334,14 @@
316
334
  }
317
335
  })();
318
336
 
319
- // ── Plans control-panel wiring ─────────────────────────────────────
320
- // The Plans tile opens #slim-plans-modal (routed in openTileModal above).
321
- // plans.js is the renderer only; the tab-switch + lazy tile-count wiring
322
- // lives here, mirroring knowledge.js#bindKnowledgeUi. The plan/PRD count is
323
- // not part of the /api/status poll, so it is fetched lazily from /api/plans
324
- // shortly after first paint (and refreshed on each modal open by the renderer).
325
- (function bindPlansUi() {
326
- var tabBar = document.getElementById('slim-plans-tabs');
327
- if (tabBar) {
328
- tabBar.addEventListener('click', function(ev) {
329
- var btn = ev.target && ev.target.closest ? ev.target.closest('.kn-tab') : null;
330
- if (!btn) return;
331
- var tab = btn.getAttribute('data-plans-tab');
332
- if (tab && typeof setPlansTab === 'function') setPlansTab(tab);
333
- });
334
- }
337
+ // ── Plans tile wiring ──────────────────────────────────────────────
338
+ // The Plans tile opens the classic /plans screen in an iframe (routed through
339
+ // the standard TILE_VIEWS path in openTileModal above) there is no
340
+ // slim-specific Plans/PRD flyout to wire. The cockpit tile's at-a-glance count
341
+ // is still slim-owned (the plan/PRD count is not part of the /api/status poll),
342
+ // so it is fetched lazily from /api/plans shortly after first paint, mirroring
343
+ // knowledge.js#loadKnowledgeCounts. See dashboard/slim/js/plans.js.
344
+ (function bindPlansTileCount() {
335
345
  if (typeof loadPlansCounts === 'function') setTimeout(loadPlansCounts, 1500);
336
346
  })();
337
347