@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 +1 -0
- package/dashboard/js/settings.js +27 -0
- package/dashboard/slim/body.html +6 -22
- package/dashboard/slim/js/modals-tiles.js +32 -22
- package/dashboard/slim/js/plans.js +24 -516
- package/dashboard/slim/styles.css +10 -7
- package/dashboard.js +34 -0
- package/docs/completion-reports.md +2 -2
- package/docs/harness-transparency.md +18 -0
- package/docs/live-checkout-mode.md +53 -6
- package/engine/ado-comment.js +5 -2
- package/engine/cli.js +58 -3
- package/engine/comment-format.js +82 -2
- package/engine/discover-project-skills.js +4 -0
- package/engine/dispatch.js +36 -1
- package/engine/gh-comment.js +8 -3
- package/engine/lifecycle.js +92 -25
- package/engine/live-checkout.js +207 -0
- package/engine/pre-dispatch-eval.js +54 -5
- package/engine/shared.js +90 -1
- package/engine/supervisor.js +13 -0
- package/engine/watchdog.js +10 -0
- package/engine.js +208 -3
- package/package.json +1 -1
- package/playbooks/review.md +2 -0
- package/playbooks/shared-rules.md +9 -0
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
|
package/dashboard/js/settings.js
CHANGED
|
@@ -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 }
|
package/dashboard/slim/body.html
CHANGED
|
@@ -226,28 +226,12 @@
|
|
|
226
226
|
</div>
|
|
227
227
|
</div>
|
|
228
228
|
|
|
229
|
-
<!-- Plans + PRD control panel —
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
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">×</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
|
|
292
|
-
// the modal + drop the body padding so the embedded
|
|
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
|
|
320
|
-
// The Plans tile opens
|
|
321
|
-
//
|
|
322
|
-
//
|
|
323
|
-
//
|
|
324
|
-
//
|
|
325
|
-
|
|
326
|
-
|
|
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
|
|