@yemi33/minions 0.1.2370 β†’ 0.1.2371

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.
Files changed (71) hide show
  1. package/bin/minions.js +38 -11
  2. package/dashboard/js/render-other.js +2 -30
  3. package/dashboard/js/render-work-items.js +0 -34
  4. package/dashboard/js/settings.js +12 -27
  5. package/dashboard/pages/tools.html +1 -1
  6. package/dashboard.js +80 -257
  7. package/docs/README.md +2 -3
  8. package/docs/architecture.excalidraw +2 -2
  9. package/docs/auto-discovery.md +3 -3
  10. package/docs/completion-reports.md +0 -121
  11. package/docs/copilot-cli-schema.md +9 -17
  12. package/docs/deprecated.json +0 -51
  13. package/docs/design-state-storage.md +4 -4
  14. package/docs/harness-propagation.md +33 -263
  15. package/docs/human-vs-automated.md +1 -1
  16. package/docs/named-agents.md +0 -2
  17. package/docs/plan-lifecycle.md +5 -6
  18. package/docs/qa-runbook-lifecycle.md +10 -25
  19. package/docs/shared-lifecycle-module-map.md +2 -10
  20. package/engine/ado-comment.js +5 -11
  21. package/engine/ado.js +10 -5
  22. package/engine/cleanup.js +16 -36
  23. package/engine/cli.js +13 -175
  24. package/engine/comment-format.js +8 -182
  25. package/engine/db/index.js +60 -10
  26. package/engine/db/migrations/018-sql-only-cutover.js +56 -0
  27. package/engine/dispatch-store.js +0 -114
  28. package/engine/dispatch.js +1 -6
  29. package/engine/gh-comment.js +2 -10
  30. package/engine/github.js +8 -6
  31. package/engine/lifecycle.js +58 -173
  32. package/engine/llm.js +9 -11
  33. package/engine/managed-spawn.js +1 -6
  34. package/engine/memory-store.js +8 -6
  35. package/engine/metrics-store.js +4 -128
  36. package/engine/pipeline.js +4 -7
  37. package/engine/playbook.js +8 -196
  38. package/engine/prd-store.js +115 -141
  39. package/engine/preflight.js +8 -55
  40. package/engine/projects.js +34 -41
  41. package/engine/pull-requests-store.js +9 -234
  42. package/engine/qa-runs.js +4 -15
  43. package/engine/qa-sessions.js +5 -17
  44. package/engine/queries.js +23 -103
  45. package/engine/routing.js +1 -1
  46. package/engine/runtimes/claude.js +1 -2
  47. package/engine/runtimes/codex.js +0 -2
  48. package/engine/runtimes/copilot.js +1 -4
  49. package/engine/shared-branch-pr-reconcile.js +2 -5
  50. package/engine/shared.js +174 -533
  51. package/engine/small-state-store.js +12 -647
  52. package/engine/spawn-agent.js +5 -96
  53. package/engine/state-operations.js +166 -0
  54. package/engine/supervisor.js +0 -1
  55. package/engine/watch-actions.js +2 -3
  56. package/engine/watches-store.js +2 -128
  57. package/engine/work-items-store.js +3 -254
  58. package/engine.js +102 -334
  59. package/package.json +2 -2
  60. package/playbooks/build-fix-complex.md +0 -4
  61. package/playbooks/fix.md +0 -4
  62. package/playbooks/implement-shared.md +0 -4
  63. package/playbooks/implement.md +0 -4
  64. package/playbooks/plan-to-prd.md +16 -11
  65. package/playbooks/plan.md +0 -4
  66. package/playbooks/review.md +0 -6
  67. package/playbooks/shared-rules.md +0 -65
  68. package/docs/harness-transparency.md +0 -199
  69. package/docs/project-skills.md +0 -193
  70. package/engine/discover-project-skills.js +0 -673
  71. package/engine/playbook-intents.js +0 -76
package/bin/minions.js CHANGED
@@ -10,7 +10,7 @@
10
10
  * minions list List linked projects
11
11
  * minions update [--no-wait] Update to latest version (--no-wait backgrounds the post-update restart)
12
12
  * minions version Show installed and package versions
13
- * minions doctor [--harness] Check prerequisites and runtime health (--harness: print harness propagation diagnostic)
13
+ * minions doctor [--harness] Check prerequisites and runtime health (--harness: print runtime harness inventory)
14
14
  * minions restart [--open] Stop + start engine + dashboard (--open forces a new browser tab)
15
15
  * minions start [--open] Start engine + dashboard if not already running (no-op when up)
16
16
  * minions stop Stop the engine
@@ -29,7 +29,7 @@
29
29
  * minions config set-cli <R> [--model M] Persist default runtime/model
30
30
  * minions bridge <subcmd> Constellation bridge: status|health|enable|disable
31
31
  * minions plan <file|text> [proj] Run a plan
32
- * minions mcp-sync Print harness propagation diagnostic (read-only; same source as `doctor --harness`)
32
+ * minions mcp-sync Print runtime harness inventory (read-only; same source as `doctor --harness`)
33
33
  * minions nuke --confirm Factory reset runtime state/config
34
34
  * minions uninstall --confirm Remove Minions and uninstall package
35
35
  */
@@ -44,7 +44,6 @@
44
44
  if (!Number.isFinite(major) || major < 22 || major >= 24) return;
45
45
  const opts = String(process.env.NODE_OPTIONS || '');
46
46
  if (opts.includes('--experimental-sqlite')) return;
47
- if (process.env.MINIONS_FORCE_JSON === '1') return; // explicit opt-out
48
47
  const { spawnSync } = require('child_process');
49
48
  const nextOpts = (opts + ' --experimental-sqlite').trim();
50
49
  const res = spawnSync(
@@ -319,12 +318,9 @@ function _openStdioLog(name) {
319
318
  * /api/work-items returns [] from the aggregate reader because the
320
319
  * Phase-9-canonical SQL path is unreachable.
321
320
  *
322
- * Honors NODE_OPTIONS / MINIONS_FORCE_JSON: if the caller already has the
323
- * flag set (via NODE_OPTIONS) or has opted out of SQL entirely
324
- * (MINIONS_FORCE_JSON=1), we add nothing β€” the child inherits the env.
321
+ * Honors NODE_OPTIONS: if the caller already has the flag, we add nothing.
325
322
  */
326
323
  function _sqliteSpawnFlags() {
327
- if (process.env.MINIONS_FORCE_JSON === '1') return [];
328
324
  const major = parseInt(String(process.versions.node).split('.')[0], 10);
329
325
  if (!Number.isFinite(major) || major < 22 || major >= 24) return [];
330
326
  const nodeOpts = String(process.env.NODE_OPTIONS || '');
@@ -1212,7 +1208,7 @@ if (!cmd || cmd === 'help' || cmd === '--help' || cmd === '-h') {
1212
1208
  minions init Bootstrap ~/.minions/ (first time)
1213
1209
  minions update [--no-wait] Update to latest version (--no-wait backgrounds the restart)
1214
1210
  minions version Show installed vs package version
1215
- minions doctor [--harness] Check prerequisites and runtime health (--harness: print harness propagation diagnostic)
1211
+ minions doctor [--harness] Check prerequisites and runtime health (--harness: print runtime harness inventory)
1216
1212
  minions add <project-dir> Link a project (interactive)
1217
1213
  minions remove <project-dir> Unlink a project
1218
1214
  minions list List linked projects
@@ -1235,11 +1231,10 @@ if (!cmd || cmd === 'help' || cmd === '--help' || cmd === '-h') {
1235
1231
  minions config set-cli <R> [--model M]
1236
1232
  Persist default runtime/model without starting
1237
1233
  minions bridge <subcmd> Constellation bridge: status|health|enable|disable
1238
- minions mcp-sync Print harness propagation diagnostic (read-only; same source as 'doctor --harness')
1234
+ minions mcp-sync Print runtime harness inventory (read-only; same source as 'doctor --harness')
1239
1235
  minions cleanup Clean temp files, worktrees, zombies
1240
1236
  minions pr comment <repo> <n> Post a marker-prepended PR comment via gh
1241
1237
  --agent <id> --kind <k> [--wi <id>] (--body-file <f> | --body <text>)
1242
- [--harness-file <f> | --harness-json <j>] folds in a "Harnesses used" section
1243
1238
  minions nuke --confirm Factory reset (delete state, reset config to defaults)
1244
1239
  minions uninstall --confirm Remove everything + uninstall npm package
1245
1240
 
@@ -1610,11 +1605,43 @@ ${fs.existsSync(path.join(PKG_ROOT, '.git')) ? `
1610
1605
  console.log('\n Minions uninstalled. Your project repos were not touched.');
1611
1606
  console.log('\n To re-install later, run:');
1612
1607
  console.log(' npm install -g @yemi33/minions && minions init\n');
1608
+ } else if (cmd === 'state') {
1609
+ ensureInstalled();
1610
+ const operations = require(path.join(MINIONS_HOME, 'engine', 'state-operations'));
1611
+ const sub = rest[0];
1612
+ try {
1613
+ let result;
1614
+ if (sub === 'check') result = operations.checkState();
1615
+ else if (sub === 'backup') result = operations.backupState(rest[1]);
1616
+ else if (sub === 'export') result = operations.exportState(rest[1]);
1617
+ else if (sub === 'import-legacy-json') {
1618
+ if (!rest.includes('--confirm')) throw new Error('legacy import requires --confirm');
1619
+ const enginePid = readEnginePid(MINIONS_HOME);
1620
+ if (enginePid) {
1621
+ try {
1622
+ process.kill(enginePid, 0);
1623
+ throw new Error(`engine PID ${enginePid} is running; stop Minions before importing`);
1624
+ } catch (e) {
1625
+ if (!e.code) throw e;
1626
+ }
1627
+ }
1628
+ result = operations.importLegacyJson(rest[1]);
1629
+ }
1630
+ else {
1631
+ console.error('\n Usage: minions state (check|backup <file>|export <file>|import-legacy-json <dir> --confirm)\n');
1632
+ process.exit(2);
1633
+ }
1634
+ console.log(JSON.stringify(result, null, 2));
1635
+ process.exit(result.ok === false ? 1 : 0);
1636
+ } catch (e) {
1637
+ console.error(`\n State ${sub || 'operation'} failed: ${e.message}\n`);
1638
+ process.exit(1);
1639
+ }
1613
1640
  } else if (cmd === 'doctor') {
1614
1641
  ensureInstalled();
1615
1642
  const { doctor, runHarnessDoctor } = require(path.join(MINIONS_HOME, 'engine', 'preflight'));
1616
1643
  if (rest.includes('--harness')) {
1617
- // P-a3f9b2c1 β€” print the harness propagation diagnostic and exit. The
1644
+ // Print the read-only runtime harness inventory and exit. The
1618
1645
  // legacy `minions doctor` still runs the full preflight + runtime fleet
1619
1646
  // sweep; `--harness` is a one-shot survey of the asset-propagation
1620
1647
  // surfaces only (see docs/harness-propagation.md).
@@ -1024,12 +1024,12 @@ function renderHarnessDiagnostics(diag) {
1024
1024
  return;
1025
1025
  }
1026
1026
  const parts = [];
1027
- parts.push('<div style="font-size:var(--text-sm);color:var(--muted);margin-bottom:8px">Fleet-default runtime: <code style="color:var(--blue)">' + escHtml(diag.fleetDefaultCli || '?') + '</code></div>');
1027
+ parts.push('<div style="font-size:var(--text-sm);color:var(--muted);margin-bottom:8px">Fleet-default runtime: <code style="color:var(--blue)">' + escHtml(diag.fleetDefaultCli || '?') + '</code>. Adapter inventory only: each CLI performs native discovery from its cwd and user configuration.</div>');
1028
1028
 
1029
1029
  // Per-runtime adapter rows
1030
1030
  for (const r of diag.runtimes || []) {
1031
1031
  parts.push('<details data-hkey="rt:' + escHtml(r.name) + '" style="margin:6px 0;border:1px solid var(--border);border-radius:6px;padding:8px 10px;background:var(--surface2)"><summary style="font-weight:600;cursor:pointer">Runtime: ' + escHtml(r.name) + '</summary>' +
1032
- _harnessRowsBlock('User asset dirs (--add-dir)', r.userAssetDirs) +
1032
+ _harnessRowsBlock('User asset dirs (adapter inventory)', r.userAssetDirs) +
1033
1033
  _harnessRowsBlock('Skill roots (CLI native discovery)', r.skillRoots) +
1034
1034
  _harnessRowsBlock('Skill write targets', r.skillWriteTargets) +
1035
1035
  _harnessRowsBlock('Slash command roots', r.commandRoots) +
@@ -1037,17 +1037,6 @@ function renderHarnessDiagnostics(diag) {
1037
1037
  '</details>');
1038
1038
  }
1039
1039
 
1040
- // --add-dir snapshot for fleet default
1041
- const snap = diag.addDirSnapshot || [];
1042
- parts.push('<details data-hkey="addDirSnapshot" open style="margin:6px 0;border:1px solid var(--border);border-radius:6px;padding:8px 10px;background:var(--surface2)"><summary style="font-weight:600;cursor:pointer">--add-dir snapshot for ' + escHtml(diag.fleetDefaultCli || 'fleet default') + ' <span style="color:var(--muted);font-weight:400">(' + snap.length + ' dir' + (snap.length === 1 ? '' : 's') + ')</span></summary>' +
1043
- (snap.length === 0
1044
- ? '<div style="font-size:var(--text-sm);color:var(--muted);margin:6px 0 0 12px"><em>(no dirs attached β€” engine/spawn-agent.js unavailable or adapter has no asset dirs)</em></div>'
1045
- : snap.map(d =>
1046
- '<div style="font-family:monospace;font-size:var(--text-sm);margin-left:18px;display:flex;gap:8px;align-items:baseline"><span style="color:var(--green)">βœ“</span> <span>' + escHtml(d.path) + '</span> <span style="color:var(--muted)">[' + escHtml(d.scope) + ']</span></div>'
1047
- ).join('')
1048
- ) +
1049
- '</details>');
1050
-
1051
1040
  // Suppressed assets
1052
1041
  const suppressed = diag.suppressed || [];
1053
1042
  if (suppressed.length > 0) {
@@ -1059,22 +1048,6 @@ function renderHarnessDiagnostics(diag) {
1059
1048
  '</details>');
1060
1049
  }
1061
1050
 
1062
- // Project-local-on-main footgun
1063
- const footgun = (diag.projectLocalOnMain || []).filter(e => e && e.uncommittedAssets && e.uncommittedAssets.length > 0);
1064
- if (footgun.length > 0) {
1065
- parts.push('<details data-hkey="footgun" open style="margin:6px 0;border:1px solid var(--orange);border-radius:6px;padding:8px 10px;background:var(--surface2)"><summary style="font-weight:600;cursor:pointer;color:var(--orange)">⚠ Project-local assets on main checkout (won\'t propagate to worktree)</summary>' +
1066
- footgun.map(entry =>
1067
- '<div style="margin:8px 0 0 12px">' +
1068
- '<div style="font-weight:600">' + escHtml(entry.project) + ' <span style="font-family:monospace;color:var(--muted);font-weight:400">' + escHtml(entry.localPath) + '</span></div>' +
1069
- '<div style="font-size:var(--text-sm);color:var(--muted);margin:4px 0 6px">' + escHtml(entry.footgunWarning || '') + '</div>' +
1070
- entry.uncommittedAssets.map(a =>
1071
- '<div style="font-family:monospace;font-size:var(--text-sm);margin-left:12px;display:flex;gap:8px;align-items:baseline"><span style="color:var(--orange)">⚠</span> <span>' + escHtml(a.file) + '</span> <span style="color:var(--muted)">[' + escHtml(a.kind) + ']</span></div>'
1072
- ).join('') +
1073
- '</div>'
1074
- ).join('') +
1075
- '</details>');
1076
- }
1077
-
1078
1051
  // Missing dirs summary (aggregate)
1079
1052
  const missing = diag.missingDirs || [];
1080
1053
  if (missing.length > 0) {
@@ -1257,4 +1230,3 @@ async function killKeepPid(agentId, pid) {
1257
1230
  }
1258
1231
 
1259
1232
  window.MinionsKeepProcesses = { renderKeepProcesses, killKeepPid, mountKeepProcessesPanel, unmountKeepProcessesPanel };
1260
-
@@ -921,40 +921,6 @@ function _wiRenderDetail(item) {
921
921
  // a dead artifact link).
922
922
  if (arts.branch) html += field('Branch', '🌿 <code style="font-size:var(--text-sm);background:var(--surface2);padding:2px 6px;border-radius:var(--radius-sm)">' + escapeHtml(arts.branch) + '</code>');
923
923
 
924
- // P-d5a6f7c4 (Harness Transparency, Stage 3 β€” surface). Render the harness
925
- // usage the agent self-reported. Shape:
926
- // { skills:[{name,source,path}], mcpServers:[{name,scope}],
927
- // commands:[{name,scope}], docs:[{path,why}] }. Every entry renders as a
928
- // plain solid pill; the engine's internal grounding flag is not surfaced.
929
- (function() {
930
- var hu = item._harnessUsed;
931
- if (!hu || typeof hu !== 'object') return;
932
- var kinds = [
933
- { key: 'skills', icon: '🧩', label: 'Skill', primary: 'name', secondary: 'source' },
934
- { key: 'mcpServers', icon: 'πŸ”Œ', label: 'MCP', primary: 'name', secondary: 'scope' },
935
- { key: 'commands', icon: '⌘', label: 'Command', primary: 'name', secondary: 'scope' },
936
- { key: 'docs', icon: 'πŸ“„', label: 'Doc', primary: 'path', secondary: 'why' },
937
- ];
938
- var pills = '';
939
- var pStyle = 'display:inline-flex;align-items:center;gap:4px;padding:2px 8px;border-radius:10px;font-size:var(--text-sm);background:var(--surface2);border:1px solid var(--border);color:var(--text)';
940
- kinds.forEach(function(k) {
941
- var entries = Array.isArray(hu[k.key]) ? hu[k.key] : [];
942
- entries.forEach(function(e) {
943
- if (!e || typeof e !== 'object') return;
944
- var primary = e[k.primary];
945
- if (typeof primary !== 'string' || !primary) return;
946
- var secondary = (typeof e[k.secondary] === 'string') ? e[k.secondary] : '';
947
- var title = k.label + (secondary ? ' (' + secondary + ')' : '');
948
- pills += '<span style="' + pStyle + '" title="' + escapeHtml(title) + '">'
949
- + k.icon + ' ' + escapeHtml(primary)
950
- + (secondary ? ' <span style="color:var(--muted);font-size:var(--text-xs)">' + escapeHtml(secondary) + '</span>' : '')
951
- + '</span> ';
952
- });
953
- });
954
- if (!pills) return;
955
- html += field('Repo harnesses used', '<div style="display:flex;flex-wrap:wrap;gap:4px">' + pills + '</div>');
956
- })();
957
-
958
924
  // P-34fa5d79 β€” Mentions: notes whose YAML frontmatter cites this WI
959
925
  // (work_item: / wi: / sourceItem:). Slim string[] field set by
960
926
  // engine/queries.js#getWorkItems from _buildNotesByWiMap. Each entry is
@@ -473,7 +473,6 @@ async function openSettings() {
473
473
  // Tooltip on copilotDisableBuiltinMcps MUST warn about the split-brain risk
474
474
  settingsToggle('Copilot: disable built-in MCPs', 'set-copilotDisableBuiltinMcps', e.copilotDisableBuiltinMcps !== false,
475
475
  '⚠ When OFF, Copilot agents can autonomously create PRs/labels/comments via the github-mcp-server, bypassing pull-requests.json tracking β€” Minions and Copilot end up with split views of the same PR. Keep ON unless you understand the risk.') +
476
- settingsToggle('Copilot: suppress AGENTS.md', 'set-copilotSuppressAgentsMd', e.copilotSuppressAgentsMd !== false, '--no-custom-instructions: stops AGENTS.md auto-load from fighting Minions playbook prompts') +
477
476
  settingsToggle('Copilot: reasoning summaries', 'set-copilotReasoningSummaries', !!e.copilotReasoningSummaries, '--enable-reasoning-summaries (Anthropic-family models only)') +
478
477
  '</div>' +
479
478
  '<div class="settings-grid-2">' +
@@ -485,13 +484,13 @@ async function openSettings() {
485
484
  '</select>' +
486
485
  '</div>' +
487
486
  settingsField('Copilot fallback model', 'set-copilotFallbackModel', e.copilotFallbackModel || '', 'e.g. gpt-5.4', 'Copilot has no --fallback-model flag. On a MODEL_UNAVAILABLE (overloaded/503) retry, the engine OVERRIDES --model with this value (Copilot only).') +
488
- '</div>' +
489
- '<div class="settings-stack" style="margin-top:12px">' +
490
- settingsField('Copilot: disable agent MCP servers', 'set-copilotAgentDisabledMcpServers',
491
- Array.isArray(e.copilotAgentDisabledMcpServers) ? e.copilotAgentDisabledMcpServers.join(', ') : (e.copilotAgentDisabledMcpServers || ''),
492
- 'e.g. playwright, maestro, loop',
493
- 'Comma-separated MCP server names (from ~/.copilot/mcp-config.json) the engine disables for autonomous Copilot agent dispatches via --disable-mcp-server. Copilot loads your user MCP config on every spawn regardless of --add-dir/hermeticHarness; list the noisy local/UI servers (e.g. playwright, maestro) to keep them out of agents. Empty = inherit all.') +
494
- '</div>';
487
+ '</div>' +
488
+ '<div class="settings-stack" style="margin-top:12px">' +
489
+ settingsField('Copilot: disable agent MCP servers', 'set-copilotAgentDisabledMcpServers',
490
+ Array.isArray(e.copilotAgentDisabledMcpServers) ? e.copilotAgentDisabledMcpServers.join(', ') : (e.copilotAgentDisabledMcpServers || ''),
491
+ 'e.g. playwright, maestro, loop',
492
+ 'Comma-separated MCP server names (from ~/.copilot/mcp-config.json) the engine disables for autonomous Copilot agent dispatches by filtering them out of the agent-only COPILOT_HOME. Copilot loads your user MCP config on every spawn regardless of --add-dir; list the noisy/auth-popping servers (e.g. playwright, maestro) to keep them out of agents. Empty = inherit all.') +
493
+ '</div>';
495
494
 
496
495
  const paneClaude =
497
496
  '<h3>Claude Tuning</h3>' +
@@ -509,20 +508,12 @@ async function openSettings() {
509
508
  'Permission bypass is runtime-owned: Claude agents use <code>--dangerously-skip-permissions</code>; Copilot agents use <code>--autopilot --allow-all --no-ask-user</code>. There is no dashboard permission-mode setting.' +
510
509
  '</div>';
511
510
 
512
- // Harness propagation knobs (PL-seamless-harness-invocation, P-2bd84e91).
513
- // All three flags govern what the spawned agent inherits from the operator's
514
- // local CLI harness (user-scope skills/commands/MCPs, project-local-on-main
515
- // assets, Claude workspace .mcp.json pre-approval). See docs/harness-propagation.md.
516
511
  const paneHarness =
517
- '<h3>Harness Propagation</h3>' +
518
- '<div class="settings-pane-sub">Controls what the spawned agent sees from your local CLI harness (skills, commands, MCPs). Defaults match the docs/harness-propagation.md contract β€” flip these only if you understand the tradeoff. The Tools tab\'s Harness diagnostics view shows the live propagated surface.</div>' +
512
+ '<h3>Native Runtime Integration</h3>' +
513
+ '<div class="settings-pane-sub">Repository instructions, skills, commands, and MCPs are discovered by the selected CLI in the dispatched checkout. Minions does not inject or suppress them.</div>' +
519
514
  '<div class="settings-stack" style="margin-bottom:12px">' +
520
- settingsToggle('Propagate project-local harness on main', 'set-harnessPropagateProjectLocal', e.harnessPropagateProjectLocal !== false,
521
- 'P-08b62d49: surface uncommitted <repo>/.claude/skills, <repo>/.copilot/commands, etc. into the worktree dispatch via extra --add-dir entries. Default ON closes the worktree-uncommitted footgun. Turn OFF to fall back to the legacy "only committed assets are visible" behavior.') +
522
515
  settingsToggle('Claude: pre-approve workspace .mcp.json', 'set-claudePreApproveWorkspaceMcps', e.claudePreApproveWorkspaceMcps !== false,
523
- 'P-7d31a06b: pre-warms ~/.claude.json projects.<worktree>.enabledMcpjsonServers on every Claude spawn so the first invocation in a brand-new worktree skips the "trust this server?" prompt β€” which would otherwise be invisible behind --dangerously-skip-permissions and silently drop workspace MCPs. Claude-only (no-op on Copilot/Codex). Best-effort: failures never block dispatch.') +
524
- settingsToggle('Hermetic harness (drop user-scope assets)', 'set-hermeticHarness', !!e.hermeticHarness,
525
- '⚠ P-49e1c8b7 fleet-wide opt-out: when ON, --add-dir is exactly [minionsDir] (user-scope skill/command/MCP roots dropped), project-local propagation skipped, and Claude workspace .mcp.json pre-approval skipped. Use when you want a known-empty harness surface (reproducible CI runs, debugging "works in my CLI" bugs). Per-agent override available via agent.hermeticHarness. Default OFF.') +
516
+ 'Pre-warms Claude workspace MCP trust so headless dispatch does not block on an invisible prompt. This enables the repository-native .mcp.json; it does not alter discovery.') +
526
517
  '</div>';
527
518
 
528
519
  const paneBudget =
@@ -614,7 +605,6 @@ async function openSettings() {
614
605
  '<div class="settings-stack">' +
615
606
  settingsToggle('Allow Temp Agents', 'set-allowTempAgents', !!e.allowTempAgents, 'Spawn ephemeral agents when all permanent agents are busy') +
616
607
  settingsToggle('Disable model discovery', 'set-disableModelDiscovery', !!e.disableModelDiscovery, 'Skip /api/runtimes/<name>/models REST calls fleet-wide. Settings UI falls back to free-text.') +
617
- settingsToggle('QA: dual-write JSON sidecars', 'set-qaDualWriteJson', e.qaDualWriteJson !== false, 'Keep mirroring qa-runs.json and qa-sessions.json on every mutation alongside the SQLite source of truth. Default ON. Disable only once external tooling has been migrated off the JSON files β€” disabling drops the rollback path back to the JSON store.') +
618
608
  '</div>' +
619
609
  // W-mqk2s8q1 β€” dashboard refresh diagnostics, relocated here from the
620
610
  // floating bottom-left "diag" chip so it sits alongside the other
@@ -644,7 +634,7 @@ async function openSettings() {
644
634
  { id: 'worktree', label: 'Worker Pool & Worktrees', html: paneWorktree },
645
635
  { id: 'copilot', label: 'Copilot Tuning', html: paneCopilot },
646
636
  { id: 'claude', label: 'Claude Tuning', html: paneClaude },
647
- { id: 'harness', label: 'Harness Propagation', html: paneHarness },
637
+ { id: 'harness', label: 'Runtime Harness', html: paneHarness },
648
638
  { id: 'budget', label: 'Budget', html: paneBudget },
649
639
  { id: 'maxturns', label: 'Max Turns', html: paneMaxTurns },
650
640
  { id: 'features', label: 'Feature Flags', html: paneFeatures },
@@ -1197,16 +1187,11 @@ async function saveSettings() {
1197
1187
  claudeBareMode: !!document.getElementById('set-claudeBareMode')?.checked,
1198
1188
  claudeFallbackModel: (document.getElementById('set-claudeFallbackModel')?.value ?? '').trim(),
1199
1189
  copilotFallbackModel: (document.getElementById('set-copilotFallbackModel')?.value ?? '').trim(),
1190
+ copilotAgentDisabledMcpServers: (document.getElementById('set-copilotAgentDisabledMcpServers')?.value ?? '').trim(),
1200
1191
  copilotDisableBuiltinMcps: !!document.getElementById('set-copilotDisableBuiltinMcps')?.checked,
1201
- copilotSuppressAgentsMd: !!document.getElementById('set-copilotSuppressAgentsMd')?.checked,
1202
1192
  copilotStreamMode: document.getElementById('set-copilotStreamMode')?.value || 'on',
1203
1193
  copilotReasoningSummaries: !!document.getElementById('set-copilotReasoningSummaries')?.checked,
1204
- // Harness propagation knobs (P-2bd84e91). Booleans round-trip through
1205
- // handleSettingsUpdate's auto boolean-fields loop because all three live
1206
- // in ENGINE_DEFAULTS as booleans.
1207
- harnessPropagateProjectLocal: !!document.getElementById('set-harnessPropagateProjectLocal')?.checked,
1208
1194
  claudePreApproveWorkspaceMcps: !!document.getElementById('set-claudePreApproveWorkspaceMcps')?.checked,
1209
- hermeticHarness: !!document.getElementById('set-hermeticHarness')?.checked,
1210
1195
  maxBudgetUsd: (document.getElementById('set-maxBudgetUsd')?.value ?? '').trim(),
1211
1196
  disableModelDiscovery: !!document.getElementById('set-disableModelDiscovery')?.checked,
1212
1197
  qaDualWriteJson: !!document.getElementById('set-qaDualWriteJson')?.checked,
@@ -11,6 +11,6 @@
11
11
  <div id="mcp-list"><p class="empty">No MCP servers synced.</p></div>
12
12
  </section>
13
13
  <section>
14
- <h2>Harness Propagation <span class="qa-section-subtitle">what each runtime sees, what's attached via --add-dir, and which assets won't propagate to a fresh worktree</span></h2>
14
+ <h2>Runtime Harness Inventory <span class="qa-section-subtitle">native locations declared by each runtime adapter; inventory only, not proof of loading or use</span></h2>
15
15
  <div id="harness-diag"><p class="empty">Loading harness diagnostics…</p></div>
16
16
  </section>