@yemi33/minions 0.1.2424 → 0.1.2426
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/install-internal-minions.js +1209 -0
- package/bin/minions.js +75 -9
- package/dashboard/docs/typography.md +27 -12
- package/dashboard/js/command-center.js +13 -11
- package/dashboard/js/live-stream.js +1 -1
- package/dashboard/js/memory-search.js +388 -43
- package/dashboard/js/modal-qa.js +5 -5
- package/dashboard/js/qa.js +39 -26
- package/dashboard/js/refresh.js +37 -18
- package/dashboard/js/render-agents.js +14 -18
- package/dashboard/js/render-dispatch.js +14 -74
- package/dashboard/js/render-inbox.js +3 -3
- package/dashboard/js/render-meetings.js +8 -8
- package/dashboard/js/render-other.js +45 -20
- package/dashboard/js/render-pipelines.js +6 -6
- package/dashboard/js/render-plans.js +14 -14
- package/dashboard/js/render-prd.js +46 -46
- package/dashboard/js/render-prs.js +9 -65
- package/dashboard/js/render-schedules.js +5 -5
- package/dashboard/js/render-skills.js +6 -6
- package/dashboard/js/render-utils.js +4 -4
- package/dashboard/js/render-watches.js +4 -16
- package/dashboard/js/render-work-items.js +95 -107
- package/dashboard/js/settings.js +175 -74
- package/dashboard/layout.html +3 -2
- package/dashboard/pages/inbox.html +1 -1
- package/dashboard/pages/work.html +1 -1
- package/dashboard/shared/model-display.js +9 -0
- package/dashboard/shared/watches-source.js +43 -0
- package/dashboard/shared/welcome-popup.js +259 -0
- package/dashboard/slim/body.html +6 -6
- package/dashboard/slim/js/chat.js +4 -2
- package/dashboard/slim/js/history.js +10 -3
- package/dashboard/slim/js/modals-tiles.js +85 -16
- package/dashboard/slim/js/status.js +12 -16
- package/dashboard/slim/styles.css +24 -4
- package/dashboard/styles.css +62 -27
- package/dashboard-build.js +8 -2
- package/dashboard.js +3854 -2514
- package/docs/README.md +7 -5
- package/docs/api-errors.md +144 -0
- package/docs/auto-discovery.md +83 -61
- package/docs/capture-demos.js +173 -30
- package/docs/command-center.md +5 -1
- package/docs/completion-reports.md +127 -11
- package/docs/constants.md +15 -3
- package/docs/constellation-style-telemetry.md +2 -2
- package/docs/copilot-cli-schema.md +32 -22
- package/docs/cross-repo-plans.md +30 -30
- package/docs/demo/memory-system.html +1 -1
- package/docs/deprecated.json +132 -18
- package/docs/diagnostics-memory.md +8 -4
- package/docs/human-vs-automated.md +2 -2
- package/docs/index.html +9 -2
- package/docs/internal-install.md +212 -0
- package/docs/kb-pr3223-cascade-archiving.md +16 -0
- package/docs/kb-pr696-merge-conflict-docs.md +23 -0
- package/docs/kb-sweep.md +2 -2
- package/docs/keep-processes.md +8 -1
- package/docs/live-checkout-mode.md +1 -1
- package/docs/managed-spawn.md +21 -3
- package/docs/named-agents.md +3 -2
- package/docs/onboarding.md +26 -0
- package/docs/plan-lifecycle.md +32 -32
- package/docs/pr-screenshots/pr-899/worker-pool-worktrees-AFTER.png +0 -0
- package/docs/pr-screenshots/pr-899/worker-pool-worktrees-BEFORE.png +0 -0
- package/docs/pr-screenshots/pr-979/auto-fix-pane-AFTER.png +0 -0
- package/docs/pr-screenshots/pr-979/auto-fix-pane-BEFORE.png +0 -0
- package/docs/pr-screenshots/pr-985/pr-column-em-dash-AFTER.png +0 -0
- package/docs/pr-screenshots/pr-985/pr-column-em-dash-BEFORE.png +0 -0
- package/docs/qa-runbook-lifecycle.md +67 -51
- package/docs/qa-runbooks.md +2 -2
- package/docs/runtime-adapters.md +101 -50
- package/docs/security.md +28 -0
- package/docs/self-improvement.md +47 -13
- package/docs/skills.md +29 -0
- package/docs/slim-ux/concepts.md +2 -2
- package/docs/specs/agent-configurability.md +43 -41
- package/docs/specs/agent-rename.md +13 -13
- package/docs/team-memory.md +283 -14
- package/docs/tutorials/01-install-and-connect.md +23 -0
- package/docs/tutorials/03-plan-driven-feature.md +3 -3
- package/docs/tutorials/04-runtimes-and-harness.md +18 -21
- package/docs/tutorials/08-operations-and-recovery.md +3 -2
- package/docs/tutorials/README.md +4 -3
- package/docs/visual-evidence-ci.md +103 -0
- package/docs/watches.md +35 -30
- package/docs/worktree-lifecycle.md +151 -13
- package/engine/acp-transport.js +1 -0
- package/engine/ado.js +80 -33
- package/engine/agent-api-validation.js +571 -0
- package/engine/agent-worker-pool.js +7 -6
- package/engine/api-contracts/agent-content.js +761 -0
- package/engine/api-contracts/cc-ops.js +219 -0
- package/engine/api-contracts/config-runtime.js +419 -0
- package/engine/api-contracts/core.js +138 -0
- package/engine/api-contracts/index.js +506 -0
- package/engine/api-contracts/orchestration.js +602 -0
- package/engine/api-contracts/pull-requests.js +323 -0
- package/engine/api-contracts/qa-process.js +764 -0
- package/engine/api-contracts/work-plan-prd.js +494 -0
- package/engine/api-validation.js +543 -0
- package/engine/cc-api-validation.js +586 -0
- package/engine/cc-worker-pool.js +9 -1
- package/engine/cleanup.js +393 -271
- package/engine/cli.js +65 -7
- package/engine/comment-classifier.js +70 -5
- package/engine/consolidation.js +123 -5
- package/engine/content-api-validation.js +606 -0
- package/engine/create-pr-worktree.js +22 -1
- package/engine/db/migrations/027-review-learning-lifecycle.js +162 -0
- package/engine/dispatch.js +33 -0
- package/engine/distribution.js +189 -0
- package/engine/execution-model.js +59 -0
- package/engine/features.js +12 -0
- package/engine/github.js +67 -25
- package/engine/harness-context.js +313 -0
- package/engine/inbox-store.js +1 -1
- package/engine/kb-sweep.js +161 -38
- package/engine/keep-process-sweep.js +43 -3
- package/engine/lifecycle.js +1066 -165
- package/engine/llm.js +4 -0
- package/engine/managed-spawn.js +463 -48
- package/engine/meeting.js +197 -34
- package/engine/memory-retrieval.js +280 -0
- package/engine/memory-store.js +821 -38
- package/engine/model-discovery.js +17 -3
- package/engine/pipeline.js +802 -14
- package/engine/plan-prd-validation.js +745 -0
- package/engine/playbook.js +206 -17
- package/engine/pooled-agent-process.js +6 -1
- package/engine/pr-action.js +1 -1
- package/engine/pr-issue-validation.js +653 -0
- package/engine/pr-resolve.js +75 -13
- package/engine/prd-store.js +39 -6
- package/engine/preflight.js +7 -2
- package/engine/process-utils.js +79 -31
- package/engine/projects.js +198 -12
- package/engine/promotion.js +371 -0
- package/engine/qa-from-prd.js +3 -0
- package/engine/qa-process-validation.js +572 -0
- package/engine/qa-runbooks.js +41 -37
- package/engine/qa-runners/maestro.js +11 -7
- package/engine/qa-runners/playwright.js +37 -14
- package/engine/qa-runners.js +9 -10
- package/engine/qa-runs.js +124 -11
- package/engine/qa-sessions.js +139 -40
- package/engine/quarantine-refs.js +81 -11
- package/engine/queries.js +163 -9
- package/engine/review-learning-backfill.js +482 -0
- package/engine/review-learning.js +1236 -0
- package/engine/runtimes/claude.js +60 -2
- package/engine/runtimes/codex.js +57 -16
- package/engine/runtimes/contract.js +21 -0
- package/engine/runtimes/copilot.js +51 -3
- package/engine/runtimes/index.js +1 -0
- package/engine/scheduler.js +201 -32
- package/engine/settings-validation.js +909 -0
- package/engine/shared.js +705 -208
- package/engine/spawn-agent.js +48 -21
- package/engine/steering-constraints.js +31 -0
- package/engine/steering-store.js +10 -2
- package/engine/steering.js +14 -2
- package/engine/timeout.js +404 -111
- package/engine/untrusted-fence.js +24 -10
- package/engine/watch-actions.js +7 -2
- package/engine/watches.js +353 -51
- package/engine/work-item-validation.js +561 -0
- package/engine/work-items-store.js +61 -1
- package/engine/worktree-gc.js +656 -37
- package/engine/worktree-preflight.js +154 -0
- package/engine.js +2068 -342
- package/package.json +1 -1
- package/playbooks/_pr-description-audit.md +88 -41
- package/playbooks/build-fix-complex.md +3 -3
- package/playbooks/docs.md +2 -2
- package/playbooks/fix.md +18 -18
- package/playbooks/implement.md +18 -18
- package/playbooks/qa-session-draft.md +10 -12
- package/playbooks/qa-session-execute.md +16 -12
- package/playbooks/qa-validate.md +8 -7
- package/playbooks/shared-rules.md +45 -0
- package/playbooks/test.md +4 -0
- package/prompts/cc-system.md +1 -1
- package/skills/check-self-authored-review-comment/SKILL.md +2 -2
package/dashboard/js/settings.js
CHANGED
|
@@ -97,7 +97,10 @@ async function openSettings() {
|
|
|
97
97
|
// muted text — operators see exactly what each agent will resolve to without
|
|
98
98
|
// chasing config files. Empty input clears the override → re-inherit fleet.
|
|
99
99
|
const fleetCliLabel = e.defaultCli || 'copilot';
|
|
100
|
-
const
|
|
100
|
+
const statusAutoMode = window._lastStatus?.autoMode || {};
|
|
101
|
+
const fleetModelLabel = MinionsModelDisplay.label(
|
|
102
|
+
e.defaultModel || statusAutoMode.defaultModelDisplay
|
|
103
|
+
);
|
|
101
104
|
const agentRows = Object.entries(agents).map(function([id, a]) {
|
|
102
105
|
return '<tr>' +
|
|
103
106
|
'<td style="font-weight:600">' + escHtml(a.emoji || '') + ' ' + escHtml(a.name || id) + '</td>' +
|
|
@@ -140,18 +143,18 @@ async function openSettings() {
|
|
|
140
143
|
'<select id="set-defaultCli" 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)">' +
|
|
141
144
|
'<option value="">Loading…</option>' +
|
|
142
145
|
'</select>' +
|
|
143
|
-
'<div style="font-size:var(--text-
|
|
146
|
+
'<div style="font-size:var(--text-sm);color:var(--muted);margin-top:1px">Fleet-wide runtime — registered adapters from <code>/api/runtimes</code></div>' +
|
|
144
147
|
'</div>' +
|
|
145
148
|
'<div data-search="default model fleet">' +
|
|
146
149
|
'<label style="font-size:var(--text-sm);color:var(--muted);display:block;margin-bottom:2px">Default Model</label>' +
|
|
147
150
|
'<div id="set-defaultModel-wrap"><input id="set-defaultModel" value="' + escHtml(e.defaultModel || '') + '" placeholder="Default (CLI chooses)" style="' + MODEL_FIELD_INPUT_STYLE + '"></div>' +
|
|
148
|
-
'<div style="font-size:var(--text-
|
|
151
|
+
'<div style="font-size:var(--text-sm);color:var(--muted);margin-top:1px">Empty = let the runtime pick its own default</div>' +
|
|
149
152
|
'</div>' +
|
|
150
153
|
'</div>' +
|
|
151
154
|
// CC overrides — collapsed by default
|
|
152
155
|
'<details id="set-cc-overrides-details"' + ((e.ccCli || e.ccModel) ? ' open' : '') + ' style="margin-top:8px;border-top:1px solid var(--border);padding-top:8px">' +
|
|
153
156
|
'<summary style="cursor:pointer;font-size:var(--text-base);color:var(--text);user-select:none">Customize CC separately ' +
|
|
154
|
-
'<span style="font-size:var(--text-
|
|
157
|
+
'<span style="font-size:var(--text-sm);color:var(--muted)">(Command Center + doc-chat use the fleet defaults unless overridden)</span>' +
|
|
155
158
|
'</summary>' +
|
|
156
159
|
'<div style="display:grid;grid-template-columns:1fr 2fr 1fr;gap:8px;margin-top:8px">' +
|
|
157
160
|
'<div data-search="cc cli command center runtime">' +
|
|
@@ -159,7 +162,7 @@ async function openSettings() {
|
|
|
159
162
|
'<select id="set-ccCli" 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)">' +
|
|
160
163
|
'<option value="">Loading…</option>' +
|
|
161
164
|
'</select>' +
|
|
162
|
-
'<div style="font-size:var(--text-
|
|
165
|
+
'<div style="font-size:var(--text-sm);color:var(--muted);margin-top:1px">Empty = inherit Default CLI</div>' +
|
|
163
166
|
'</div>' +
|
|
164
167
|
'<div data-search="cc model command center">' +
|
|
165
168
|
'<label style="font-size:var(--text-sm);color:var(--muted);display:block;margin-bottom:2px">CC Model</label>' +
|
|
@@ -169,7 +172,7 @@ async function openSettings() {
|
|
|
169
172
|
// and the hint below, breaking vertical alignment with the
|
|
170
173
|
// sibling CC CLI / Effort columns.
|
|
171
174
|
'<div id="set-ccModel-wrap"><input id="set-ccModel" value="' + escHtml(e.ccModel || '') + '" placeholder="(inherits Default Model)" style="' + MODEL_FIELD_INPUT_STYLE + '"></div>' +
|
|
172
|
-
'<div style="font-size:var(--text-
|
|
175
|
+
'<div style="font-size:var(--text-sm);color:var(--muted);margin-top:1px">Empty = inherit Default Model</div>' +
|
|
173
176
|
'</div>' +
|
|
174
177
|
'<div data-search="cc effort reasoning">' +
|
|
175
178
|
'<label style="font-size:var(--text-sm);color:var(--muted);display:block;margin-bottom:2px">Effort</label>' +
|
|
@@ -179,13 +182,13 @@ async function openSettings() {
|
|
|
179
182
|
'<option value="medium"' + (e.ccEffort === 'medium' ? ' selected' : '') + '>Medium</option>' +
|
|
180
183
|
'<option value="high"' + (e.ccEffort === 'high' ? ' selected' : '') + '>High</option>' +
|
|
181
184
|
'</select>' +
|
|
182
|
-
'<div style="font-size:var(--text-
|
|
185
|
+
'<div style="font-size:var(--text-sm);color:var(--muted);margin-top:1px">CC reasoning depth</div>' +
|
|
183
186
|
'</div>' +
|
|
184
187
|
'</div>' +
|
|
185
188
|
// W-mpmwxni2000c25c7-d — per-turn watchdog. Surfaced under CC overrides
|
|
186
189
|
// because it gates CC/doc-chat error visibility (not the agent fleet).
|
|
187
190
|
'<div style="display:grid;grid-template-columns:1fr;gap:8px;margin-top:8px">' +
|
|
188
|
-
settingsField('CC Turn Timeout', 'set-ccTurnTimeoutMs', e.ccTurnTimeoutMs || 300000, '
|
|
191
|
+
settingsField('CC Turn Timeout', 'set-ccTurnTimeoutMs', (e.ccTurnTimeoutMs || 300000) / 1000, 's', 'Per-turn no-progress watchdog for CC + doc-chat. Resets on every liveness signal (token chunk, tool call, tool update) so an actively-streaming turn — long shell command, deep search, sub-agent loop — survives indefinitely up to the outer 1h hard ceiling. Only true silence past this window fires event: error with code: cc-turn-timeout, stops the spinner, and offers Retry. Clamped to 10–3600 s.', '0.001') +
|
|
189
192
|
'</div>' +
|
|
190
193
|
'</details>' +
|
|
191
194
|
'</div>' +
|
|
@@ -198,18 +201,20 @@ async function openSettings() {
|
|
|
198
201
|
|
|
199
202
|
const paneAutoFix =
|
|
200
203
|
'<h3>Auto-fix & Review Loop</h3>' +
|
|
201
|
-
'<div class="settings-pane-sub">
|
|
204
|
+
'<div class="settings-pane-sub">Everything in this pane is <strong>automatic</strong>. Each tile below enables or disables one automatic PR-triggered dispatch trigger (build failure, merge conflict, review verdict, human comment) — the section framing carries the "auto", so the tiles just name the cause. All require the matching provider polling (Polling tab). The <em>Pause ALL</em> kill-switch below inerts every trigger at once. Non-dispatch knobs (auto-merge, auto-vote, plan/decompose defaults) moved to the new <strong>PR Lifecycle</strong> and <strong>Workflow Defaults</strong> panes.</div>' +
|
|
202
205
|
'<div class="settings-stack" style="margin-bottom:16px">' +
|
|
203
|
-
settingsToggle('🛑 Pause ALL PR auto-fix dispatches', 'set-autoFixPaused', !!e.autoFixPaused, 'Halts every PR-triggered dispatch (review, re-review, build-failure fix, review-feedback fix, human-comment fix, merge-conflict fix) on the next tick. In-flight agents keep running. Reversible without restart. Per-cause
|
|
206
|
+
settingsToggle('🛑 Pause ALL PR auto-fix dispatches', 'set-autoFixPaused', !!e.autoFixPaused, 'Halts every PR-triggered dispatch (review, re-review, build-failure fix, review-feedback fix, human-comment fix, merge-conflict fix) on the next tick. In-flight agents keep running. Reversible without restart. Per-cause tiles below are inert while this is set.') +
|
|
207
|
+
'</div>' +
|
|
208
|
+
'<div class="settings-pane-sub" style="margin-bottom:8px">Per-cause triggers — each tile automatically dispatches an agent for one PR signal (it names the exact discoverFromPrs site it gates). Enabled tiles are highlighted; disabled tiles are dimmed. When <em>Pause ALL</em> is ON every tile is inert; when it is OFF, each tile decides independently whether its site fires.</div>' +
|
|
209
|
+
'<div class="settings-tile-grid" style="margin-bottom:16px">' +
|
|
210
|
+
settingsTile('Builds', 'set-autoFixBuilds', e.autoFixBuilds !== false, 'Shared dispatch gate: auto-fix agent when a PR build fails; also requires that PR provider polling is enabled', '🔨', 'auto-fix builds') +
|
|
211
|
+
settingsTile('Conflicts', 'set-autoFixConflicts', e.autoFixConflicts !== false, 'Shared dispatch gate: auto-fix agent when a PR merge conflict is detected; also requires that PR provider polling is enabled', '🔀', 'auto-fix conflicts') +
|
|
212
|
+
settingsTile('Review PRs', 'set-autoReviewPrs', e.autoReviewPrs !== false, 'Shared dispatch gate: review agent for newly opened agent PRs; also requires that PR provider polling is enabled', '🔍', 'auto-review prs') +
|
|
213
|
+
settingsTile('Re-review PRs', 'set-autoReReviewPrs', e.autoReReviewPrs !== false, 'Shared dispatch gate: review agent after a fix push is awaiting re-review; also requires that PR provider polling is enabled', '🔁', 'auto-re-review prs') +
|
|
214
|
+
settingsTile('Review Feedback', 'set-autoFixReviewFeedback', e.autoFixReviewFeedback !== false, 'Shared dispatch gate: fix agent for minions changes-requested verdicts; also requires that PR provider polling is enabled', '✍️', 'auto-fix review feedback') +
|
|
215
|
+
settingsTile('Human Comments', 'set-autoFixHumanComments', e.autoFixHumanComments !== false, 'Shared dispatch gate: fix agent for actionable human PR comments; also requires that PR provider polling is enabled', '💬', 'auto-fix human comments') +
|
|
204
216
|
'</div>' +
|
|
205
|
-
'<div class="settings-pane-sub" style="margin-bottom:8px">Per-cause dispatch gates — each one names the exact discoverFromPrs site it gates. When <em>Pause All Auto-fix</em> is ON these are inert; when it is OFF, each gate decides independently whether its site fires.</div>' +
|
|
206
217
|
'<div class="settings-stack" style="margin-bottom:16px">' +
|
|
207
|
-
settingsToggle('Auto-fix Builds', 'set-autoFixBuilds', e.autoFixBuilds !== false, 'Shared dispatch gate: auto-fix agent when a PR build fails; also requires that PR provider polling is enabled') +
|
|
208
|
-
settingsToggle('Auto-fix Conflicts', 'set-autoFixConflicts', e.autoFixConflicts !== false, 'Shared dispatch gate: auto-fix agent when a PR merge conflict is detected; also requires that PR provider polling is enabled') +
|
|
209
|
-
settingsToggle('Auto-review PRs', 'set-autoReviewPrs', e.autoReviewPrs !== false, 'Shared dispatch gate: review agent for newly opened agent PRs; also requires that PR provider polling is enabled') +
|
|
210
|
-
settingsToggle('Auto-re-review PRs', 'set-autoReReviewPrs', e.autoReReviewPrs !== false, 'Shared dispatch gate: review agent after a fix push is awaiting re-review; also requires that PR provider polling is enabled') +
|
|
211
|
-
settingsToggle('Auto-fix Review Feedback', 'set-autoFixReviewFeedback', e.autoFixReviewFeedback !== false, 'Shared dispatch gate: fix agent for minions changes-requested verdicts; also requires that PR provider polling is enabled') +
|
|
212
|
-
settingsToggle('Auto-fix Human Comments', 'set-autoFixHumanComments', e.autoFixHumanComments !== false, 'Shared dispatch gate: fix agent for actionable human PR comments; also requires that PR provider polling is enabled') +
|
|
213
218
|
settingsToggle('Eval Loop', 'set-evalLoop', e.evalLoop !== false, 'Gates the review→fix iteration loop only (first review, re-review, review-feedback fix). Does NOT gate build-failure, merge-conflict, or human-comment fixes. Use the emergency stop above to halt everything.') +
|
|
214
219
|
settingsToggle('Pre-dispatch Eval (cheap LLM gate)', 'set-enablePreDispatchEval', e.enablePreDispatchEval !== false, 'P-d2a9f6e5: cheap LLM gate that screens work items for clear/actionable/testable criteria BEFORE queueing the agent. Catches noop dispatches authored from impossible/ambiguous WIs. Fail-open on any validator error.') +
|
|
215
220
|
settingsToggle('Pre-dispatch Eval: skip PRD-sourced items', 'set-preDispatchEvalSkipPrdSourced', e.preDispatchEvalSkipPrdSourced !== false, 'W-mq9acoo800177bcb: short-circuit the validator for items materialized from an approved/active PRD — plan-to-prd already LLM-vets them. Reduces queue-time on an N-item approved PRD from ~N×25s to nearly instant. OFF = always re-validate even PRD-sourced items.') +
|
|
@@ -231,7 +236,9 @@ async function openSettings() {
|
|
|
231
236
|
'<div class="settings-pane-sub">Post-merge / post-review lifecycle knobs. These are not dispatch gates — they control what Minions does with a PR once review or build state lands.</div>' +
|
|
232
237
|
'<div class="settings-stack">' +
|
|
233
238
|
settingsToggle('Auto-apply review vote to PR', 'set-autoApplyReviewVote', !!e.autoApplyReviewVote, 'When ON, Minions review verdicts (APPROVE / REQUEST_CHANGES) automatically flip the platform vote on ADO/GitHub. When OFF (default), verdicts are informational only and the human casts the final vote.') +
|
|
239
|
+
settingsToggle('Create PRs as draft', 'set-createPrsAsDraft', !!e.createPrsAsDraft, 'When ON, Minions-created PRs open as DRAFT (GitHub `gh pr create --draft`; ADO `az repos pr create --draft true`). When OFF (default), PRs open ready-for-review as today. Aggregate/E2E verify PRs already open as draft regardless of this flag.') +
|
|
234
240
|
settingsToggle('Auto-complete PRs', 'set-autoCompletePrs', !!e.autoCompletePrs, 'Auto-merge PRs when builds pass and review is approved (opt-in). Independent of the per-cause auto-fix gates above.') +
|
|
241
|
+
settingsToggle('Surface repo harnesses in PR body', 'set-includeHarnessSectionInPrBody', e.includeHarnessSectionInPrBody !== false, 'When ON (default), Minions-authored PRs get a fenced "Repo harnesses used" section listing the harness assets in effect for the dispatch\'s runtime + project — runtime, injected CLAUDE.md files, AGENTS.md discovery, MCP servers, and skills. Pure reporting from the same read-only source as `minions doctor --harness`; it does not change harness propagation. OFF suppresses the section.') +
|
|
235
242
|
'</div>';
|
|
236
243
|
|
|
237
244
|
// P-g7a2b4c5 — new "Workflow Defaults" pane. Owns the four workflow-level
|
|
@@ -245,7 +252,7 @@ async function openSettings() {
|
|
|
245
252
|
settingsToggle('Auto-approve Plans', 'set-autoApprovePlans', !!e.autoApprovePlans, 'PRDs are approved automatically without human review.') +
|
|
246
253
|
settingsToggle('Auto-decompose', 'set-autoDecompose', e.autoDecompose !== false, 'Large implement items are auto-split into sub-tasks.') +
|
|
247
254
|
settingsToggle('Auto-archive Plans', 'set-autoArchive', !!e.autoArchive, 'Automatically archive plans after verify completes (off = manual archive via dashboard).') +
|
|
248
|
-
settingsToggle('Auto-consolidate Memory', 'set-autoConsolidateMemory', !!e.autoConsolidateMemory, 'Periodically spawn the KB sweep (dedup + compress + normalize knowledge/) from the engine tick on a 4h cadence. Inbox→notes consolidation
|
|
255
|
+
settingsToggle('Auto-consolidate Memory', 'set-autoConsolidateMemory', !!e.autoConsolidateMemory, 'Enabled by default. Periodically spawn the KB sweep (dedup + compress + normalize knowledge/) from the engine tick on a 4h cadence. Inbox→notes consolidation runs independently every tick.') +
|
|
249
256
|
settingsToggle('Bootstrap Default Schedules', 'set-bootstrapDefaultSchedules', e.bootstrapDefaultSchedules !== false, 'Auto-create the per-project git-fetch-freshness schedule (every 12h) when a project is added, and ensure one shared daily harness-sweep schedule exists engine-wide. Idempotent and non-destructive — never overwrites a schedule you have customized. Turn off to manage these schedules entirely by hand.') +
|
|
250
257
|
'</div>';
|
|
251
258
|
|
|
@@ -291,7 +298,7 @@ async function openSettings() {
|
|
|
291
298
|
}).join('');
|
|
292
299
|
})() +
|
|
293
300
|
'</select>' +
|
|
294
|
-
'<div style="font-size:var(--text-
|
|
301
|
+
'<div style="font-size:var(--text-sm);color:var(--muted);margin-top:1px">Scales the whole dashboard. Persisted in browser + server.</div>' +
|
|
295
302
|
'</div>' +
|
|
296
303
|
slimUxControl +
|
|
297
304
|
'</div>';
|
|
@@ -340,7 +347,7 @@ async function openSettings() {
|
|
|
340
347
|
'<div>' +
|
|
341
348
|
'<label style="font-size:var(--text-sm);color:var(--muted);display:block;margin-bottom:2px">Remote default <span style="opacity:0.6">(read-only)</span></label>' +
|
|
342
349
|
'<input id="set-remoteDefaultBranch-' + p.name + '" value="' + escHtml(remoteDefault || '(unset)') + '" readonly style="width:100%;padding:4px 6px;background:var(--surface2);border:1px solid var(--border);border-radius:4px;color:var(--muted);font-size:var(--text-md);font-family:ui-monospace,SFMono-Regular,Menlo,monospace">' +
|
|
343
|
-
'<div style="font-size:var(--text-
|
|
350
|
+
'<div style="font-size:var(--text-sm);color:var(--muted);margin-top:1px">Parsed from <code>git symbolic-ref refs/remotes/origin/HEAD</code>' + (localBranch ? '. Local HEAD: <code>' + escHtml(localBranch) + '</code>' : '') + '.</div>' +
|
|
344
351
|
'</div>' +
|
|
345
352
|
'</div>';
|
|
346
353
|
// P-a3f9b207 (consolidated W-mqiaw974) — per-project checkoutMode dropdown
|
|
@@ -377,7 +384,7 @@ async function openSettings() {
|
|
|
377
384
|
}).join('');
|
|
378
385
|
var hybridPanel =
|
|
379
386
|
'<div data-checkout-hybrid-panel="' + escHtml(p.name) + '" style="' + (currentCheckoutMode === 'hybrid' ? '' : 'display:none;') + 'margin-top:6px">' +
|
|
380
|
-
'<div style="padding:6px 8px;background:rgba(234,179,8,0.12);border:1px solid var(--yellow);border-radius:4px;color:var(--yellow);font-size:var(--text-
|
|
387
|
+
'<div style="padding:6px 8px;background:rgba(234,179,8,0.12);border:1px solid var(--yellow);border-radius:4px;color:var(--yellow);font-size:var(--text-sm);line-height:1.4;margin-bottom:6px">' +
|
|
381
388
|
'⚠ Hybrid mode: only the chosen work-item type(s) run in-place on the live checkout; all others use isolated worktrees (one mutating dispatch at a time; dirty-tree recovery follows the live-checkout auto-stash/reset settings).' +
|
|
382
389
|
'</div>' +
|
|
383
390
|
'<div style="font-size:var(--text-sm);color:var(--muted);margin-bottom:2px">Work-item type(s) to run live:</div>' +
|
|
@@ -386,7 +393,7 @@ async function openSettings() {
|
|
|
386
393
|
'<input type="checkbox" id="set-liveValidationAutoDispatch-' + escHtml(p.name) + '"' + (hybridAutoPre ? ' checked' : '') + '>' +
|
|
387
394
|
'<span>Automatically run a test validation after each eligible coding work item completes</span>' +
|
|
388
395
|
'</label>' +
|
|
389
|
-
'<div data-checkout-hybrid-error="' + escHtml(p.name) + '" style="display:none;margin-top:6px;color:var(--red);font-size:var(--text-
|
|
396
|
+
'<div data-checkout-hybrid-error="' + escHtml(p.name) + '" style="display:none;margin-top:6px;color:var(--red);font-size:var(--text-sm)">Select at least one work-item type to run live.</div>' +
|
|
390
397
|
'</div>';
|
|
391
398
|
var worktreeModeBlock =
|
|
392
399
|
'<div data-search="' + escHtml(wtModeSearch) + '" style="margin-bottom:6px">' +
|
|
@@ -396,7 +403,7 @@ async function openSettings() {
|
|
|
396
403
|
'<option value="live" title="Agents run in-place in the project folder. One mutating dispatch at a time; dirty-tree handling follows the auto-stash/reset policy."' + (currentCheckoutMode === 'live' ? ' selected' : '') + '>Live checkout</option>' +
|
|
397
404
|
'<option value="hybrid" title="Only chosen work-item types run on the real checkout; all others use isolated worktrees."' + (currentCheckoutMode === 'hybrid' ? ' selected' : '') + '>Hybrid dispatch</option>' +
|
|
398
405
|
'</select>' +
|
|
399
|
-
'<div data-checkout-mode-chip="' + escHtml(p.name) + '" style="' + (currentCheckoutMode === 'live' ? '' : 'display:none;') + 'margin-top:6px;padding:6px 8px;background:rgba(234,179,8,0.12);border:1px solid var(--yellow);border-radius:4px;color:var(--yellow);font-size:var(--text-
|
|
406
|
+
'<div data-checkout-mode-chip="' + escHtml(p.name) + '" style="' + (currentCheckoutMode === 'live' ? '' : 'display:none;') + 'margin-top:6px;padding:6px 8px;background:rgba(234,179,8,0.12);border:1px solid var(--yellow);border-radius:4px;color:var(--yellow);font-size:var(--text-sm);line-height:1.4">' +
|
|
400
407
|
'⚠ Live mode: dispatches run directly in this repo\'s checkout. Only one mutating dispatch runs at a time. Dirty-tree behavior follows the auto-stash/reset settings below.' +
|
|
401
408
|
'</div>' +
|
|
402
409
|
hybridPanel +
|
|
@@ -416,7 +423,24 @@ async function openSettings() {
|
|
|
416
423
|
'<option value="on"' + (autoStashRaw === 'on' ? ' selected' : '') + '>On — auto-stash dirty tree</option>' +
|
|
417
424
|
'<option value="off"' + (autoStashRaw === 'off' ? ' selected' : '') + '>Off — fail on dirty tree</option>' +
|
|
418
425
|
'</select>' +
|
|
419
|
-
'<div style="font-size:var(--text-
|
|
426
|
+
'<div style="font-size:var(--text-sm);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>' +
|
|
427
|
+
'</div>';
|
|
428
|
+
// W-mrxv648b — per-project "Create PRs as draft" override. Tri-state:
|
|
429
|
+
// "" (Inherit → delete the key so the fleet-wide engine.createPrsAsDraft
|
|
430
|
+
// applies), "draft" (force true), "ready" (force false). Only an explicit
|
|
431
|
+
// draft/ready overrides the fleet setting; Inherit leaves p.createPrsAsDraft
|
|
432
|
+
// unset so shared.resolveCreatePrsAsDraft falls back to the engine value.
|
|
433
|
+
var createPrsAsDraftRaw = (p.createPrsAsDraft === true) ? 'draft' : (p.createPrsAsDraft === false) ? 'ready' : '';
|
|
434
|
+
var createPrsAsDraftSearch = 'create prs as draft pull request pr draft ready review lifecycle override';
|
|
435
|
+
var createPrsAsDraftBlock =
|
|
436
|
+
'<div data-search="' + escHtml(createPrsAsDraftSearch) + '" style="margin-bottom:6px">' +
|
|
437
|
+
'<label style="font-size:var(--text-sm);color:var(--muted);display:block;margin-bottom:2px">Create PRs as draft</label>' +
|
|
438
|
+
'<select id="set-createPrsAsDraft-' + 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)">' +
|
|
439
|
+
'<option value=""' + (createPrsAsDraftRaw === '' ? ' selected' : '') + '>Inherit fleet default</option>' +
|
|
440
|
+
'<option value="draft"' + (createPrsAsDraftRaw === 'draft' ? ' selected' : '') + '>Draft — open PRs as draft</option>' +
|
|
441
|
+
'<option value="ready"' + (createPrsAsDraftRaw === 'ready' ? ' selected' : '') + '>Not draft — open PRs ready</option>' +
|
|
442
|
+
'</select>' +
|
|
443
|
+
'<div style="font-size:var(--text-xs);color:var(--muted);margin-top:2px;line-height:1.4">Overrides the fleet-wide "Create PRs as draft" setting under PR Lifecycle for THIS project only. Draft = Minions-created PRs open as draft (GitHub `--draft`; ADO `--draft true`). Inherit follows the engine flag. Aggregate/E2E verify PRs and the shared-branch aggregate PR are unaffected.</div>' +
|
|
420
444
|
'</div>';
|
|
421
445
|
// W-mrchrfe100067d3a — per-project explicit allowlist of secondary repo
|
|
422
446
|
// scopes this project's checkout is also allowed to track PRs for (e.g.
|
|
@@ -434,12 +458,13 @@ async function openSettings() {
|
|
|
434
458
|
return '<div data-settings-project="' + escHtml(p.name) + '" class="settings-project-block' + (p.name === selectedProject ? '' : ' project-config-hidden') + '" data-search="project ' + escHtml(p.name.toLowerCase()) + '" style="border:1px solid var(--border);border-radius:6px;padding:10px 12px;margin-bottom:12px">' +
|
|
435
459
|
'<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:8px">' +
|
|
436
460
|
'<div style="font-size:var(--text-md);font-weight:600">' + escHtml(p.name) + '</div>' +
|
|
437
|
-
'<button onclick="MinionsSettings.removeProject(\'' + escHtml(p.name) + '\')" style="font-size:var(--text-
|
|
461
|
+
'<button onclick="MinionsSettings.removeProject(\'' + escHtml(p.name) + '\')" style="font-size:var(--text-sm);padding:2px 8px;background:transparent;color:var(--red);border:1px solid var(--red);border-radius:3px;cursor:pointer">Remove</button>' +
|
|
438
462
|
'</div>' +
|
|
439
463
|
pathRow +
|
|
440
464
|
branchGrid +
|
|
441
465
|
worktreeModeBlock +
|
|
442
466
|
autoStashBlock +
|
|
467
|
+
createPrsAsDraftBlock +
|
|
443
468
|
additionalScopesBlock +
|
|
444
469
|
driftNote +
|
|
445
470
|
'<div style="display:flex;flex-direction:column;gap:6px;margin-top:8px">' +
|
|
@@ -510,16 +535,16 @@ async function openSettings() {
|
|
|
510
535
|
'<div class="settings-pane-sub">How many agents run at once and how long they get before being killed for silence or runaway duration.</div>' +
|
|
511
536
|
'<div class="settings-grid-2">' +
|
|
512
537
|
settingsField('Max Concurrent Agents', 'set-maxConcurrent', e.maxConcurrent || 5, '', 'Max agents working simultaneously') +
|
|
513
|
-
settingsField('Min Tick Interval', 'set-tickInterval', e.tickInterval || 10000, '
|
|
514
|
-
settingsField('Agent Timeout', 'set-agentTimeout', e.agentTimeout || 18000000, '
|
|
515
|
-
settingsField('Heartbeat Timeout', 'set-heartbeatTimeout', e.heartbeatTimeout || 300000, '
|
|
538
|
+
settingsField('Min Tick Interval', 'set-tickInterval', (e.tickInterval || 10000) / 1000, 's', 'Minimum gap between tick starts. Slow ticks (PR polls, reconcilers) may delay the next slot — see `running` indicator on /engine.', '0.001') +
|
|
539
|
+
settingsField('Agent Timeout', 'set-agentTimeout', (e.agentTimeout || 18000000) / 1000, 's', 'Kill agent after this duration', '0.001') +
|
|
540
|
+
settingsField('Heartbeat Timeout', 'set-heartbeatTimeout', (e.heartbeatTimeout || 300000) / 1000, 's', 'No output = dead after this', '0.001') +
|
|
516
541
|
settingsField('Idle Alert', 'set-idleAlertMinutes', e.idleAlertMinutes || 15, 'min', 'Alert after agent idle this long') +
|
|
517
|
-
settingsField('Agent Busy Reassign', 'set-agentBusyReassignMs', e.agentBusyReassignMs || 600000, '
|
|
542
|
+
settingsField('Agent Busy Reassign', 'set-agentBusyReassignMs', (e.agentBusyReassignMs || 600000) / 1000, 's', 'Reassign work to another agent after it waits this long on a busy agent', '0.001') +
|
|
518
543
|
settingsField('Max Retries Per Agent', 'set-maxRetriesPerAgent', e.maxRetriesPerAgent ?? 2, '', 'After the same agent fails the same work item this many times, the next retry reassigns to a different eligible agent (consults routing.md + availability). Falls back to the same agent only when no alternate is available. Counted separately from total maxRetries (which still caps overall retries).') +
|
|
519
|
-
settingsField('Restart Grace Period', 'set-restartGracePeriod', e.restartGracePeriod || 1200000, '
|
|
520
|
-
settingsField('Shutdown Timeout', 'set-shutdownTimeout', e.shutdownTimeout || 300000, '
|
|
521
|
-
settingsField('Meeting Round Timeout', 'set-meetingRoundTimeout', e.meetingRoundTimeout || 900000, '
|
|
522
|
-
settingsField('Steering Deferred Max', 'set-steeringDeferredMaxMs', e.steeringDeferredMaxMs || 900000, '
|
|
544
|
+
settingsField('Restart Grace Period', 'set-restartGracePeriod', (e.restartGracePeriod || 1200000) / 1000, 's', 'Grace period before orphan detection on restart', '0.001') +
|
|
545
|
+
settingsField('Shutdown Timeout', 'set-shutdownTimeout', (e.shutdownTimeout || 300000) / 1000, 's', 'Max wait for agents during graceful shutdown', '0.001') +
|
|
546
|
+
settingsField('Meeting Round Timeout', 'set-meetingRoundTimeout', (e.meetingRoundTimeout || 900000) / 1000, 's', 'Auto-advance meeting round after this', '0.001') +
|
|
547
|
+
settingsField('Steering Deferred Max', 'set-steeringDeferredMaxMs', (e.steeringDeferredMaxMs || 900000) / 1000, 's', 'Max wait for a runtime to emit a resumable checkpoint before a deferred steering message is flagged stranded. After this, the engine warns to live-output, marks _steeringStranded on the dispatch, and (when the steering store is present) sets store status=stranded. Default 15min; range 60s–4h.', '0.001') +
|
|
523
548
|
settingsField('Steering Max Kill Retries', 'set-steeringMaxKillRetries', e.steeringMaxKillRetries ?? 3, '', 'Cap on graceful+escalation kill attempts after a steering kill is issued. Ladder waits 30s → 60s → 120s between attempts (last interval reused). Attempt 1 is graceful; attempts 2..cap are platform hard kills (taskkill /F /T on Windows; descendant-tree SIGKILL + pkill on Unix). Past cap, the engine gives up with a [steering-stuck] log + inbox notice. Default 3; range 1–5.') +
|
|
524
549
|
'</div>' +
|
|
525
550
|
'<h4 style="margin:14px 0 4px;font-size:var(--text-md)">Spawn-phase watchdog</h4>' +
|
|
@@ -528,7 +553,7 @@ async function openSettings() {
|
|
|
528
553
|
settingsToggle('Spawn-phase Watchdog', 'set-spawnPhaseWatchdogEnabled', e.spawnPhaseWatchdogEnabled !== false, 'Enable the spawn-phase MCP-init wedge detector. Default ON. Turn OFF only if you suspect false positives against a runtime whose legitimate startup exceeds the grace window.') +
|
|
529
554
|
'</div>' +
|
|
530
555
|
'<div class="settings-grid-2">' +
|
|
531
|
-
settingsField('Spawn-phase Grace', 'set-spawnPhaseGraceMs', e.spawnPhaseGraceMs || 120000, '
|
|
556
|
+
settingsField('Spawn-phase Grace', 'set-spawnPhaseGraceMs', (e.spawnPhaseGraceMs || 120000) / 1000, 's', 'Time after spawn before the watchdog can fire. Default 2min. A healthy startup ships a real event in seconds; this is generous headroom for slow MCP servers and corporate DNS.', '0.001') +
|
|
532
557
|
settingsField('Spawn-phase CPU floor', 'set-spawnPhaseMaxCpuSeconds', e.spawnPhaseMaxCpuSeconds ?? 5, 's', 'Process is "idle" if cumulative CPU seconds ≤ this. Default 5s. A genuinely busy startup burns CPU on tokenizer bootstrap, MCP IPC, or model warmup; a wedged child sits in epoll near 0s.') +
|
|
533
558
|
'</div>';
|
|
534
559
|
|
|
@@ -536,26 +561,39 @@ async function openSettings() {
|
|
|
536
561
|
'<h3>Worker Pool & Worktrees</h3>' +
|
|
537
562
|
'<div class="settings-pane-sub">Persistent CC worker pool and git worktree provisioning. Tune these only if you see worktree-create timeouts or slow CC cold-spawns.</div>' +
|
|
538
563
|
'<div class="settings-stack" style="margin-bottom:12px">' +
|
|
539
|
-
settingsToggle('CC Worker Pool', 'set-ccUseWorkerPool', (e.ccUseWorkerPool === undefined ? ((e.ccCli || e.defaultCli) === 'copilot') : !!e.ccUseWorkerPool), 'Route Command Center / doc-chat through a persistent copilot --acp worker per tab instead of spawning a fresh CLI per turn. Copilot-only (Agent Client Protocol transport); Claude does not implement ACP, so this toggle has no effect when CC runtime is Claude. Default ON for copilot (cold-spawn ~20s on Windows); forced OFF for non-copilot CC runtimes regardless of this toggle.') +
|
|
540
|
-
settingsToggle('Agent Worker Pool', 'set-agentUseWorkerPool', e.agentUseWorkerPool === true, 'Route fleet Copilot dispatches through persistent copilot --acp workers. Default OFF while the newer fleet-pool lifecycle path stabilizes; runtimes without ACP support ignore this setting.') +
|
|
564
|
+
settingsToggle('CC Worker Pool', 'set-ccUseWorkerPool', (e.ccUseWorkerPool === undefined ? ((e.ccCli || e.defaultCli) === 'copilot') : !!e.ccUseWorkerPool), 'Route Command Center / doc-chat through a persistent copilot --acp worker per tab instead of spawning a fresh CLI per turn. Copilot-only (Agent Client Protocol transport); Claude does not implement ACP, so this toggle has no effect when CC runtime is Claude. Default ON for copilot (cold-spawn ~20s on Windows); forced OFF for non-copilot CC runtimes regardless of this toggle.', { blockHint: true }) +
|
|
565
|
+
settingsToggle('Agent Worker Pool', 'set-agentUseWorkerPool', e.agentUseWorkerPool === true, 'Route fleet Copilot dispatches through persistent copilot --acp workers. Default OFF while the newer fleet-pool lifecycle path stabilizes; runtimes without ACP support ignore this setting.', { blockHint: true }) +
|
|
541
566
|
// W-mq6f2fe0000557fa — opt-in: auto-kill orphan spawn-agent processes
|
|
542
567
|
// holding a stuck worktree's cwd. Gated by safe-reap criteria (cmdline
|
|
543
568
|
// matches spawn-agent.js + basename + age > agentTimeout * 2). Default
|
|
544
569
|
// OFF because killing a foreign process is destructive.
|
|
545
570
|
settingsToggle('Auto-reap orphan worktree holders', 'set-autoReapOrphanWorktreeHolders', !!e.autoReapOrphanWorktreeHolders,
|
|
546
|
-
'When ON, the periodic orphan-worktree sweep automatically kills unambiguous orphan `spawn-agent.js` processes holding a stuck worktree\'s cwd (Windows file-lock pattern, e.g. W-mq1k8z6o003acd89 / PID 16828). Safe-reap criteria: cmdline must match spawn-agent.js, reference the worktree basename, AND process age must exceed `engine.agentTimeout * 2`. Default OFF because killing a foreign process is destructive. The holder SCAN runs either way and is appended to the escalation inbox note.') +
|
|
571
|
+
'When ON, the periodic orphan-worktree sweep automatically kills unambiguous orphan `spawn-agent.js` processes holding a stuck worktree\'s cwd (Windows file-lock pattern, e.g. W-mq1k8z6o003acd89 / PID 16828). Safe-reap criteria: cmdline must match spawn-agent.js, reference the worktree basename, AND process age must exceed `engine.agentTimeout * 2`. Default OFF because killing a foreign process is destructive. The holder SCAN runs either way and is appended to the escalation inbox note.', { blockHint: true }) +
|
|
572
|
+
settingsToggle('Live-checkout auto-stash (fleet-wide)', 'set-liveCheckoutAutoStash', e.liveCheckoutAutoStash !== false,
|
|
573
|
+
'Fleet-wide fallback for live-checkout mode (project.liveCheckoutAutoStash overrides per-project). When ON, a dirty live-checkout tree is `git stash push --include-untracked`\'d before dispatch instead of failing with LIVE_CHECKOUT_DIRTY, so dispatch proceeds without manual operator intervention. The engine NEVER pops the stash automatically — it logs the stash name and writes an inbox note so you can `git stash pop` manually. Default ON — non-destructive and recoverable via `git stash pop`; it is the first line of defense in dirty-tree recovery now that the destructive Live-checkout auto-reset defaults OFF.', { blockHint: true }) +
|
|
547
574
|
settingsToggle('Live-checkout auto-reset (fleet-wide)', 'set-liveCheckoutAutoReset', !!e.liveCheckoutAutoReset,
|
|
548
|
-
'When ON, a dirty
|
|
575
|
+
'When ON, a dirty live-checkout (in-place) tree is destructively cleaned before dispatch via `git reset --hard HEAD` + `git clean -fd` instead of failing with LIVE_CHECKOUT_DIRTY. The current branch and committed history are preserved; tracked WIP and ordinary untracked files are discarded and may be unrecoverable. This is the FLEET-WIDE fallback; a per-project `liveCheckoutAutoReset` in config.json overrides it. Default OFF. Mid-operation and detached-HEAD states are always refused before cleanup, and auto-stash is attempted first when both policies are enabled. Only affects projects running in live/in-place checkout mode.', { blockHint: true }) +
|
|
576
|
+
settingsToggle('Live-checkout auto-base-repair (fleet-wide)', 'set-liveCheckoutAutoBaseRepair', !!e.liveCheckoutAutoBaseRepair,
|
|
577
|
+
'When ON, a live-checkout (in-place) dispatch that would fail LIVE_CHECKOUT_WRONG_BASE — because HEAD sits on an unrelated topic/feature branch and no local base branch (`refs/heads/<mainBranch>`) exists to fork from — is auto-recovered by materializing a local base branch from the `origin/<mainBranch>` remote-tracking ref (a purely LOCAL ref: NO `git fetch`, so issue #226 is preserved) and forking cleanly off it. origin/<mainBranch> IS the correct base, so there is NO scope-contamination risk. This is the FLEET-WIDE fallback; a per-project `liveCheckoutAutoBaseRepair` in config.json overrides it. Bounded by the git timeout — if a partial-clone blob hydration ever hangs it degrades to exactly the pre-existing fail-closed refusal. Default OFF. Only affects projects running in live/in-place checkout mode.', { blockHint: true }) +
|
|
578
|
+
settingsToggle('Live-checkout auto-freshen (fleet-wide)', 'set-liveCheckoutAutoFreshen', !!e.liveCheckoutAutoFreshen,
|
|
579
|
+
'When ON, a live-checkout (or hybrid liveValidation) dispatch that is about to fork a NEW branch off the local base branch fast-forwards that base to `origin/<mainBranch>` FIRST — but ONLY in the strictly-safe case: the tree is clean, HEAD is on the base branch, the local base has ZERO commits ahead of `origin/<mainBranch>` (NOT the stale-base-with-unpushed-commits case — that refusal is unchanged), and the local base IS behind origin. It runs `git fetch origin <mainBranch>` then a `--ff-only` update — the ONE sanctioned live-mode fetch (issue #226 otherwise forbids fetching live checkouts). A fast-forward can never rewrite history or lose local commits, never touches a dirty or mid-operation tree, and on any fetch/network/auth failure FAILS OPEN to the pre-existing (un-freshened) behavior. A `live-checkout-autofreshen-<workItem>` inbox note records the before/after SHA only when a freshen actually happens. This is the FLEET-WIDE fallback; a per-project `liveCheckoutAutoFreshen` in config.json overrides it. Default OFF. Only affects projects running in live/in-place (or hybrid liveValidation) checkout mode.', { blockHint: true }) +
|
|
580
|
+
// W-mr1qbj90000d30bd — explicit opt-out for the ACP idle reaper. When
|
|
581
|
+
// ON, the CC Session Idle Timeout field above is ignored and the
|
|
582
|
+
// engine persists the `0` sentinel, which cc-worker-pool.js maps to an
|
|
583
|
+
// Infinity window (only closeTab ever kills the warm worker).
|
|
584
|
+
settingsToggle('Never idle-reap CC workers (uses more memory for long-idle tabs)', 'set-ccNeverIdleReap', e.ccWorkerIdleTimeoutMs === 0,
|
|
585
|
+
'When ON, a persistent `copilot --acp` CC worker is NEVER killed for inactivity alone — only closing the tab (closeTab) tears it down. Overrides CC Session Idle Timeout above. Trades idle memory/process footprint for guaranteed context durability on long-idle tabs. Default OFF.', { blockHint: true }) +
|
|
549
586
|
'</div>' +
|
|
550
587
|
'<div class="settings-grid-2">' +
|
|
551
|
-
settingsField('CC Session Idle Timeout', 'set-ccWorkerIdleTimeoutMs', Math.round((e.ccWorkerIdleTimeoutMs || 1800000) / 60000), 'minutes', 'How long a persistent `copilot --acp` CC worker stays warm with no activity before the idle reaper kills it. After a reap the next message cold-spawns a FRESH session with no memory of prior turns and CC shows a "context cleared after inactivity" notice. Shorter = less idle memory/process footprint; longer = more context durability across gaps between messages. Only affects the Copilot worker-pool path (CC Worker Pool ON). Clamped 1–480 minutes.') +
|
|
552
|
-
settingsField('Worktree Create Timeout', 'set-worktreeCreateTimeout', e.worktreeCreateTimeout || 300000, '
|
|
588
|
+
settingsField('CC Session Idle Timeout', 'set-ccWorkerIdleTimeoutMs', Math.round((e.ccWorkerIdleTimeoutMs || 1800000) / 60000), 'minutes', 'How long a persistent `copilot --acp` CC worker stays warm with no activity before the idle reaper kills it. After a reap the next message cold-spawns a FRESH session with no memory of prior turns and CC shows a "context cleared after inactivity" notice. Shorter = less idle memory/process footprint; longer = more context durability across gaps between messages. Only affects the Copilot worker-pool path (CC Worker Pool ON). Clamped 1–480 minutes. Ignored when "Never idle-reap CC workers" below is ON.') +
|
|
589
|
+
settingsField('Worktree Create Timeout', 'set-worktreeCreateTimeout', (e.worktreeCreateTimeout || 300000) / 1000, 's', 'Timeout for git worktree add (increase for large repos/Windows)', '0.001') +
|
|
553
590
|
settingsField('Worktree Create Retries', 'set-worktreeCreateRetries', e.worktreeCreateRetries || 1, '', 'Retry count for transient worktree add failures (0-3)') +
|
|
554
591
|
settingsField('Worktree Root', 'set-worktreeRoot', e.worktreeRoot || '../worktrees', '', 'Relative or absolute path for git worktrees; on Windows prefer a short path like C:\\wt') +
|
|
555
|
-
settingsField('
|
|
556
|
-
settingsField('
|
|
557
|
-
settingsField('
|
|
558
|
-
settingsField('
|
|
592
|
+
settingsField('Minimum Free Space', 'set-worktreeMinFreeSpaceGiB', Number(((e.worktreeMinFreeSpaceBytes ?? (10 * 1024 * 1024 * 1024)) / (1024 * 1024 * 1024)).toFixed(2)), 'GiB', 'Defer worktree-mode dispatch before git worktree add when the target filesystem has less free space than this reserve. The pending item is re-checked every tick and does not consume an agent retry. Set 0 to disable.') +
|
|
593
|
+
settingsField('Assert-Clean Status Probe Timeout', 'set-assertCleanStatusTimeoutMs', (e.assertCleanStatusTimeoutMs || 10000) / 1000, 's', 'Timeout for the `git status --porcelain` preflight probe in assertCleanSharedWorktree. Raise this (e.g. 60) on GVFS/Plastic-backed monorepos where sparse hydration runs longer than the 10s default. On timeout the engine quarantines the bad worktree and emits a RETRYABLE failure so the next dispatch starts fresh. Clamped 1–120 s.', '0.001') +
|
|
594
|
+
settingsField('Restart-health Timeout', 'set-restartHealthTimeoutMs', (e.restartHealthTimeoutMs || 60000) / 1000, 's', 'Cold-start budget for `minions restart` / post-update restart verification. The dashboard runs node:sqlite migrations + SPA HTML assembly + initial state reads synchronously BEFORE it binds its port, so right after `npm install` on a slow/loaded box the PID is alive but the port is unbound for tens of seconds. Below this budget that no longer prints a false "Restart verification failed" + exit(1) — the verifier keeps polling until the port listens. A genuinely crashed spawn (PID dies) still fails fast, well under the full budget. Clamped 15–300 s.', '0.001') +
|
|
595
|
+
settingsField('Orphan-holder scan timeout', 'set-orphanHolderScanTimeoutMs', (e.orphanHolderScanTimeoutMs || 5000) / 1000, 's', 'Cap on the cross-platform scan (PowerShell / /proc walk / lsof) that identifies the OS process holding a stuck worktree\'s cwd. Bumps up only matter on heavily-loaded hosts where the holder scan races the sweep tick. Clamped 1–30 s.', '0.001') +
|
|
596
|
+
settingsField('Worktree-holder reap probe timeout', 'set-statusProbeKillTimeoutMs', (e.statusProbeKillTimeoutMs || 12000) / 1000, 's', 'Windows-only. Timeout for the pre-quarantine worktree-holder reap probe (legacy git.exe-cmdline sweep + PEB-CWD scan that kills an orphaned agent process tree whose CWD pins the worktree dir, causing EBUSY on rename AND `git worktree remove --force`). The old hardcoded 2s was the proximate cause of the reaper being a no-op under concurrent-agent load (PowerShell cold-start + process enumeration exceeded 2s → ETIMEDOUT → reaped nothing). ETIMEDOUT is always swallowed (reap nothing; quarantine still proceeds), so raising this only widens the success window. Clamped 2–60 s.', '0.001') +
|
|
559
597
|
'</div>';
|
|
560
598
|
|
|
561
599
|
const paneCopilot =
|
|
@@ -661,7 +699,7 @@ async function openSettings() {
|
|
|
661
699
|
displayFeatures.map(function(f) {
|
|
662
700
|
const checked = f.enabled ? ' checked' : '';
|
|
663
701
|
const expiredBadge = f.expired
|
|
664
|
-
? ' <span style="font-size:var(--text-
|
|
702
|
+
? ' <span style="font-size:var(--text-sm);padding:1px 5px;background:rgba(220,80,80,0.15);color:var(--red);border-radius:3px;margin-left:4px">EXPIRED</span>'
|
|
665
703
|
: '';
|
|
666
704
|
const meta = [];
|
|
667
705
|
if (f.addedIn) meta.push('added in ' + escHtml(f.addedIn));
|
|
@@ -673,7 +711,7 @@ async function openSettings() {
|
|
|
673
711
|
'<div style="flex:1">' +
|
|
674
712
|
'<div style="font-size:var(--text-base);font-weight:600;color:var(--text)">' + escHtml(f.id) + expiredBadge + '</div>' +
|
|
675
713
|
(f.description ? '<div style="font-size:var(--text-sm);color:var(--muted);margin-top:2px">' + escHtml(f.description) + '</div>' : '') +
|
|
676
|
-
'<div style="font-size:var(--text-
|
|
714
|
+
'<div style="font-size:var(--text-sm);color:var(--muted);margin-top:3px">' + meta.join(' · ') + '</div>' +
|
|
677
715
|
'</div>' +
|
|
678
716
|
'</label>';
|
|
679
717
|
}).join('') +
|
|
@@ -690,7 +728,7 @@ async function openSettings() {
|
|
|
690
728
|
'<h4>Inbox</h4>' +
|
|
691
729
|
'<div class="settings-grid-2">' +
|
|
692
730
|
settingsField('Consolidation Threshold', 'set-inboxConsolidateThreshold', e.inboxConsolidateThreshold || 5, 'notes', 'Inbox notes before auto-consolidation') +
|
|
693
|
-
settingsField('Version Check Interval', 'set-versionCheckInterval', e.versionCheckInterval || 3600000, '
|
|
731
|
+
settingsField('Version Check Interval', 'set-versionCheckInterval', (e.versionCheckInterval || 3600000) / 1000, 's', 'How often to check npm for updates (default: 1 hour)', '0.001') +
|
|
694
732
|
'</div>' +
|
|
695
733
|
'<h4>Agent Memory</h4>' +
|
|
696
734
|
'<div class="settings-stack">' +
|
|
@@ -719,7 +757,7 @@ async function openSettings() {
|
|
|
719
757
|
'<h4>Diagnostics</h4>' +
|
|
720
758
|
'<div data-search="diagnostics refresh diag ring buffer status poll etag">' +
|
|
721
759
|
'<button type="button" class="btn-add" onclick="window._openRefreshDiagModal && window._openRefreshDiagModal()">Open Refresh Diagnostics</button>' +
|
|
722
|
-
'<div style="font-size:var(--text-
|
|
760
|
+
'<div style="font-size:var(--text-sm);color:var(--muted);margin-top:4px">Inspect the dashboard\'s /api/status refresh ring buffer (response status, ETag hits, render timings, per-section change flags) and optionally send a snapshot to the engine.</div>' +
|
|
723
761
|
'</div>';
|
|
724
762
|
|
|
725
763
|
// Section registry — order is intentional (Runtime + Auto-fix surface first
|
|
@@ -1293,24 +1331,65 @@ async function loadModelsForAgent(agentId, runtimeName, currentValue) {
|
|
|
1293
1331
|
cell.innerHTML = '<input ' + baseAttrs + ' list="' + escHtml(listId) + '" value="' + escHtml(currentValue || '') + '" placeholder="' + escHtml(runtimeName) + ' default" autocomplete="off" style="' + baseStyle + '"><datalist id="' + escHtml(listId) + '">' + opts + '</datalist>';
|
|
1294
1332
|
}
|
|
1295
1333
|
|
|
1296
|
-
function settingsToggle(label, id, checked, hint) {
|
|
1334
|
+
function settingsToggle(label, id, checked, hint, opts) {
|
|
1297
1335
|
// data-search powers the cross-tab search box — lowercase label + hint so
|
|
1298
1336
|
// the input filter can substring-match without dragging the visible text
|
|
1299
1337
|
// through .toLowerCase() on every keystroke.
|
|
1300
1338
|
const searchKey = (String(label || '') + ' ' + String(hint || '')).toLowerCase().replace(/"/g, '');
|
|
1301
|
-
|
|
1302
|
-
|
|
1339
|
+
// blockHint: render the hint on its own full-width line UNDER the
|
|
1340
|
+
// checkbox+label (indented to align beneath the label), mirroring the
|
|
1341
|
+
// label->control->hint block layout of settingsField. Opt-in per call — used
|
|
1342
|
+
// by panes whose toggles carry long, multi-sentence hints (e.g. Worker Pool
|
|
1343
|
+
// & Worktrees) where the default inline hint squeezes the label into a
|
|
1344
|
+
// narrow one-word-per-line column. Panes that omit opts are byte-identical
|
|
1345
|
+
// to the previous inline layout.
|
|
1346
|
+
const blockHint = !!(opts && opts.blockHint);
|
|
1347
|
+
const rowStyle = blockHint
|
|
1348
|
+
? 'display:flex;flex-wrap:wrap;align-items:flex-start;gap:2px 8px;padding:4px 0'
|
|
1349
|
+
: 'display:flex;align-items:center;gap:8px;padding:4px 0';
|
|
1350
|
+
const hintHtml = hint
|
|
1351
|
+
? (blockHint
|
|
1352
|
+
? '<div style="flex-basis:100%;margin-left:24px;font-size:var(--text-sm);color:var(--muted);line-height:1.4">' + escHtml(hint) + '</div>'
|
|
1353
|
+
: '<span style="font-size:var(--text-sm);color:var(--muted)">' + escHtml(hint) + '</span>')
|
|
1354
|
+
: '';
|
|
1355
|
+
return '<div class="settings-row" data-search="' + escHtml(searchKey) + '" style="' + rowStyle + '">' +
|
|
1356
|
+
'<input type="checkbox" id="' + id + '"' + (checked ? ' checked' : '') + ' style="accent-color:var(--blue);width:16px;height:16px;cursor:pointer;flex-shrink:0">' +
|
|
1303
1357
|
'<label for="' + id + '" style="font-size:var(--text-md);color:var(--text);cursor:pointer">' + escHtml(label) + '</label>' +
|
|
1304
|
-
|
|
1358
|
+
hintHtml +
|
|
1305
1359
|
'</div>';
|
|
1306
1360
|
}
|
|
1307
1361
|
|
|
1308
|
-
|
|
1362
|
+
// W-mryyzhug000454b7 — enable/disabled TILE for a boolean per-cause auto-fix
|
|
1363
|
+
// gate. Renders a real (visually-hidden but focusable) `<input type=checkbox
|
|
1364
|
+
// id="set-...">` as the source of truth so the existing id-based save/collect
|
|
1365
|
+
// path (getElementById('set-...').checked) is untouched, wrapped in a <label>
|
|
1366
|
+
// so the whole tile is clickable and keyboard-accessible (Tab focuses the
|
|
1367
|
+
// checkbox, Space toggles). `icon` is a decorative emoji; `extraSearch` folds
|
|
1368
|
+
// the pre-rename label into data-search so the cross-tab search box still finds
|
|
1369
|
+
// the gate by its old name (e.g. "auto-fix builds").
|
|
1370
|
+
function settingsTile(label, id, checked, hint, icon, extraSearch) {
|
|
1371
|
+
const searchKey = (String(label || '') + ' ' + String(hint || '') + ' ' + String(extraSearch || '')).toLowerCase().replace(/"/g, '');
|
|
1372
|
+
return '<label class="settings-tile" data-search="' + escHtml(searchKey) + '" title="' + escHtml(hint || '') + '">' +
|
|
1373
|
+
'<input type="checkbox" id="' + id + '"' + (checked ? ' checked' : '') + ' class="settings-tile-input">' +
|
|
1374
|
+
'<span class="settings-tile-inner">' +
|
|
1375
|
+
'<span class="settings-tile-icon" aria-hidden="true">' + escHtml(icon || '') + '</span>' +
|
|
1376
|
+
'<span class="settings-tile-label">' + escHtml(label) + '</span>' +
|
|
1377
|
+
'<span class="settings-tile-state" aria-hidden="true"></span>' +
|
|
1378
|
+
'</span>' +
|
|
1379
|
+
'</label>';
|
|
1380
|
+
}
|
|
1381
|
+
|
|
1382
|
+
function settingsField(label, id, value, unit, hint, step) {
|
|
1309
1383
|
const searchKey = (String(label || '') + ' ' + String(hint || '') + ' ' + String(unit || '')).toLowerCase().replace(/"/g, '');
|
|
1384
|
+
// `step` (optional) opts the input into type=number so fractional seconds
|
|
1385
|
+
// (e.g. a 1500ms value shown as 1.5 s) round-trip losslessly via the arrows.
|
|
1386
|
+
const stepAttr = (step !== undefined && step !== null && step !== '')
|
|
1387
|
+
? ' type="number" step="' + escHtml(String(step)) + '"'
|
|
1388
|
+
: '';
|
|
1310
1389
|
return '<div class="settings-row" data-search="' + escHtml(searchKey) + '">' +
|
|
1311
1390
|
'<label style="font-size:var(--text-sm);color:var(--muted);display:block;margin-bottom:2px">' + escHtml(label) + (unit ? ' <span style="opacity:0.6">(' + escHtml(unit) + ')</span>' : '') + '</label>' +
|
|
1312
|
-
'<input id="' + id + '" value="' + escHtml(String(value)) + '" 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)">' +
|
|
1313
|
-
(hint ? '<div style="font-size:var(--text-
|
|
1391
|
+
'<input id="' + id + '"' + stepAttr + ' value="' + escHtml(String(value)) + '" 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)">' +
|
|
1392
|
+
(hint ? '<div style="font-size:var(--text-sm);color:var(--muted);margin-top:1px">' + escHtml(hint) + '</div>' : '') +
|
|
1314
1393
|
'</div>';
|
|
1315
1394
|
}
|
|
1316
1395
|
|
|
@@ -1462,8 +1541,20 @@ async function saveSettings() {
|
|
|
1462
1541
|
if (saveBtn) { saveBtn.disabled = true; saveBtn.style.opacity = '0.6'; saveBtn.innerHTML = 'Saving...'; }
|
|
1463
1542
|
|
|
1464
1543
|
try {
|
|
1544
|
+
// Time fields are entered/displayed in SECONDS but the engine + config wire
|
|
1545
|
+
// format stays in MILLISECONDS. Convert s -> ms on save (render divides by
|
|
1546
|
+
// 1000). Missing element -> undefined so the server keeps the prior value;
|
|
1547
|
+
// blank/NaN/negative -> 0 so server-side range validation rejects the
|
|
1548
|
+
// complete save instead of silently retaining or adjusting a bad value.
|
|
1549
|
+
const secToMs = (id) => {
|
|
1550
|
+
const el = document.getElementById(id);
|
|
1551
|
+
if (!el) return undefined;
|
|
1552
|
+
const s = Number(el.value);
|
|
1553
|
+
if (!Number.isFinite(s) || s < 0) return 0;
|
|
1554
|
+
return Math.round(s * 1000);
|
|
1555
|
+
};
|
|
1465
1556
|
const enginePayload = {
|
|
1466
|
-
tickInterval:
|
|
1557
|
+
tickInterval: secToMs('set-tickInterval'),
|
|
1467
1558
|
maxConcurrent: document.getElementById('set-maxConcurrent').value,
|
|
1468
1559
|
inboxConsolidateThreshold: document.getElementById('set-inboxConsolidateThreshold').value,
|
|
1469
1560
|
memoryRetrievalShadowMode: document.getElementById('set-memoryRetrievalShadowMode').checked,
|
|
@@ -1471,22 +1562,23 @@ async function saveSettings() {
|
|
|
1471
1562
|
memoryRetrievalTopK: document.getElementById('set-memoryRetrievalTopK').value,
|
|
1472
1563
|
memoryRetrievalMaxBytes: document.getElementById('set-memoryRetrievalMaxBytes').value,
|
|
1473
1564
|
memoryRetrievalCandidateLimit: document.getElementById('set-memoryRetrievalCandidateLimit').value,
|
|
1474
|
-
agentTimeout:
|
|
1565
|
+
agentTimeout: secToMs('set-agentTimeout'),
|
|
1475
1566
|
maxTurns: document.getElementById('set-maxTurns').value,
|
|
1476
|
-
heartbeatTimeout:
|
|
1477
|
-
worktreeCreateTimeout:
|
|
1567
|
+
heartbeatTimeout: secToMs('set-heartbeatTimeout'),
|
|
1568
|
+
worktreeCreateTimeout: secToMs('set-worktreeCreateTimeout'),
|
|
1478
1569
|
worktreeCreateRetries: document.getElementById('set-worktreeCreateRetries').value,
|
|
1479
1570
|
worktreeRoot: document.getElementById('set-worktreeRoot').value,
|
|
1480
|
-
|
|
1481
|
-
|
|
1571
|
+
worktreeMinFreeSpaceBytes: Math.round(Math.max(0, Number(document.getElementById('set-worktreeMinFreeSpaceGiB').value) || 0) * 1024 * 1024 * 1024),
|
|
1572
|
+
assertCleanStatusTimeoutMs: secToMs('set-assertCleanStatusTimeoutMs'),
|
|
1573
|
+
restartHealthTimeoutMs: secToMs('set-restartHealthTimeoutMs'),
|
|
1482
1574
|
idleAlertMinutes: document.getElementById('set-idleAlertMinutes').value,
|
|
1483
|
-
shutdownTimeout:
|
|
1484
|
-
restartGracePeriod:
|
|
1485
|
-
meetingRoundTimeout:
|
|
1486
|
-
steeringDeferredMaxMs:
|
|
1575
|
+
shutdownTimeout: secToMs('set-shutdownTimeout'),
|
|
1576
|
+
restartGracePeriod: secToMs('set-restartGracePeriod'),
|
|
1577
|
+
meetingRoundTimeout: secToMs('set-meetingRoundTimeout'),
|
|
1578
|
+
steeringDeferredMaxMs: secToMs('set-steeringDeferredMaxMs'),
|
|
1487
1579
|
steeringMaxKillRetries: document.getElementById('set-steeringMaxKillRetries').value,
|
|
1488
1580
|
spawnPhaseWatchdogEnabled: document.getElementById('set-spawnPhaseWatchdogEnabled').checked,
|
|
1489
|
-
spawnPhaseGraceMs:
|
|
1581
|
+
spawnPhaseGraceMs: secToMs('set-spawnPhaseGraceMs'),
|
|
1490
1582
|
spawnPhaseMaxCpuSeconds: document.getElementById('set-spawnPhaseMaxCpuSeconds').value,
|
|
1491
1583
|
operatorLogin: (document.getElementById('set-operatorLogin')?.value ?? '').trim(),
|
|
1492
1584
|
autoApprovePlans: document.getElementById('set-autoApprovePlans').checked,
|
|
@@ -1497,6 +1589,7 @@ async function saveSettings() {
|
|
|
1497
1589
|
autoConsolidateMemory: document.getElementById('set-autoConsolidateMemory').checked,
|
|
1498
1590
|
bootstrapDefaultSchedules: document.getElementById('set-bootstrapDefaultSchedules').checked,
|
|
1499
1591
|
autoApplyReviewVote: document.getElementById('set-autoApplyReviewVote').checked,
|
|
1592
|
+
createPrsAsDraft: document.getElementById('set-createPrsAsDraft').checked,
|
|
1500
1593
|
autoFixBuilds: document.getElementById('set-autoFixBuilds').checked,
|
|
1501
1594
|
autoFixConflicts: document.getElementById('set-autoFixConflicts').checked,
|
|
1502
1595
|
autoFixPaused: document.getElementById('set-autoFixPaused').checked,
|
|
@@ -1505,6 +1598,7 @@ async function saveSettings() {
|
|
|
1505
1598
|
autoFixReviewFeedback: document.getElementById('set-autoFixReviewFeedback').checked,
|
|
1506
1599
|
autoFixHumanComments: document.getElementById('set-autoFixHumanComments').checked,
|
|
1507
1600
|
autoCompletePrs: document.getElementById('set-autoCompletePrs').checked,
|
|
1601
|
+
includeHarnessSectionInPrBody: !!document.getElementById('set-includeHarnessSectionInPrBody')?.checked,
|
|
1508
1602
|
ccUseWorkerPool: !!document.getElementById('set-ccUseWorkerPool')?.checked,
|
|
1509
1603
|
agentUseWorkerPool: !!document.getElementById('set-agentUseWorkerPool')?.checked,
|
|
1510
1604
|
autoReapOrphanWorktreeHolders: !!document.getElementById('set-autoReapOrphanWorktreeHolders')?.checked,
|
|
@@ -1512,8 +1606,8 @@ async function saveSettings() {
|
|
|
1512
1606
|
liveCheckoutAutoReset: !!document.getElementById('set-liveCheckoutAutoReset')?.checked,
|
|
1513
1607
|
liveCheckoutAutoBaseRepair: !!document.getElementById('set-liveCheckoutAutoBaseRepair')?.checked,
|
|
1514
1608
|
liveCheckoutAutoFreshen: !!document.getElementById('set-liveCheckoutAutoFreshen')?.checked,
|
|
1515
|
-
orphanHolderScanTimeoutMs:
|
|
1516
|
-
statusProbeKillTimeoutMs:
|
|
1609
|
+
orphanHolderScanTimeoutMs: secToMs('set-orphanHolderScanTimeoutMs'),
|
|
1610
|
+
statusProbeKillTimeoutMs: secToMs('set-statusProbeKillTimeoutMs'),
|
|
1517
1611
|
adoPollEnabled: document.getElementById('set-adoPollEnabled').checked,
|
|
1518
1612
|
ghPollEnabled: document.getElementById('set-ghPollEnabled').checked,
|
|
1519
1613
|
pollingPaused: document.getElementById('set-pollingPaused').checked,
|
|
@@ -1541,10 +1635,10 @@ async function saveSettings() {
|
|
|
1541
1635
|
enablePreDispatchEval: document.getElementById('set-enablePreDispatchEval').checked,
|
|
1542
1636
|
preDispatchEvalSkipPrdSourced: document.getElementById('set-preDispatchEvalSkipPrdSourced').checked,
|
|
1543
1637
|
preDispatchEvalConcurrency: document.getElementById('set-preDispatchEvalConcurrency').value,
|
|
1544
|
-
agentBusyReassignMs:
|
|
1638
|
+
agentBusyReassignMs: secToMs('set-agentBusyReassignMs'),
|
|
1545
1639
|
maxRetriesPerAgent: document.getElementById('set-maxRetriesPerAgent').value,
|
|
1546
1640
|
ignoredCommentAuthors: document.getElementById('set-ignoredCommentAuthors').value,
|
|
1547
|
-
versionCheckInterval:
|
|
1641
|
+
versionCheckInterval: secToMs('set-versionCheckInterval'),
|
|
1548
1642
|
// Runtime fleet (P-7a5c1f8e). Empty strings are intentional — they signal
|
|
1549
1643
|
// "clear this override". The server deletes the key from config.engine.
|
|
1550
1644
|
defaultCli: (document.getElementById('set-defaultCli')?.value ?? '').trim(),
|
|
@@ -1553,10 +1647,10 @@ async function saveSettings() {
|
|
|
1553
1647
|
ccModel: (document.getElementById('set-ccModel')?.value ?? '').trim(),
|
|
1554
1648
|
ccEffort: document.getElementById('set-ccEffort').value || null,
|
|
1555
1649
|
codexCcSandbox: document.getElementById('set-codexCcSandbox')?.value || 'danger-full-access',
|
|
1556
|
-
ccTurnTimeoutMs:
|
|
1650
|
+
ccTurnTimeoutMs: secToMs('set-ccTurnTimeoutMs'),
|
|
1557
1651
|
// Settings UI presents the idle timeout in minutes for readability; the
|
|
1558
1652
|
// engine stores ms (ENGINE_DEFAULTS.ccWorkerIdleTimeoutMs). Convert here;
|
|
1559
|
-
// the server
|
|
1653
|
+
// the server validates against [60000, 28800000] ms. undefined when blank so the
|
|
1560
1654
|
// server keeps the prior value rather than zeroing it. W-mr1qbj90000d30bd:
|
|
1561
1655
|
// the "Never idle-reap CC workers" toggle wins and submits the explicit
|
|
1562
1656
|
// `0` sentinel (bypasses the clamp server-side), ignoring the minutes field.
|
|
@@ -1575,9 +1669,8 @@ async function saveSettings() {
|
|
|
1575
1669
|
claudePreApproveWorkspaceMcps: !!document.getElementById('set-claudePreApproveWorkspaceMcps')?.checked,
|
|
1576
1670
|
maxBudgetUsd: (document.getElementById('set-maxBudgetUsd')?.value ?? '').trim(),
|
|
1577
1671
|
disableModelDiscovery: !!document.getElementById('set-disableModelDiscovery')?.checked,
|
|
1578
|
-
qaDualWriteJson: !!document.getElementById('set-qaDualWriteJson')?.checked,
|
|
1579
1672
|
// W-mpmwxkrw000872ec — global font-size scale. Allowlist validation
|
|
1580
|
-
//
|
|
1673
|
+
// lives server-side in the atomic settings candidate builder.
|
|
1581
1674
|
fontSize: document.getElementById('set-fontSize')?.value || 'small',
|
|
1582
1675
|
maxTurnsByType: (function() {
|
|
1583
1676
|
var mbt = {};
|
|
@@ -1662,6 +1755,13 @@ async function saveSettings() {
|
|
|
1662
1755
|
const autoStashInput = document.getElementById('set-liveCheckoutAutoStash-' + p.name);
|
|
1663
1756
|
const autoStashRaw = autoStashInput ? autoStashInput.value : '';
|
|
1664
1757
|
const autoStashValue = autoStashRaw === 'on' ? true : autoStashRaw === 'off' ? false : null;
|
|
1758
|
+
// W-mrxv648b — per-project "Create PRs as draft" override. 'draft' → true;
|
|
1759
|
+
// 'ready' → false; '' → null (Inherit: clear the override so the engine
|
|
1760
|
+
// fleet-wide `engine.createPrsAsDraft` applies). The server deletes the
|
|
1761
|
+
// field on null and validates booleans.
|
|
1762
|
+
const createPrsAsDraftInput = document.getElementById('set-createPrsAsDraft-' + p.name);
|
|
1763
|
+
const createPrsAsDraftRaw = createPrsAsDraftInput ? createPrsAsDraftInput.value : '';
|
|
1764
|
+
const createPrsAsDraftValue = createPrsAsDraftRaw === 'draft' ? true : createPrsAsDraftRaw === 'ready' ? false : null;
|
|
1665
1765
|
// W-mrchrfe100067d3a — parse the comma-separated scope list back into an
|
|
1666
1766
|
// array; empty string → null (clears the override server-side).
|
|
1667
1767
|
const additionalScopesInput = document.getElementById('set-additionalRepoScopes-' + p.name);
|
|
@@ -1673,6 +1773,7 @@ async function saveSettings() {
|
|
|
1673
1773
|
checkoutMode: checkoutMode,
|
|
1674
1774
|
liveValidation: liveValidation,
|
|
1675
1775
|
liveCheckoutAutoStash: autoStashValue,
|
|
1776
|
+
createPrsAsDraft: createPrsAsDraftValue,
|
|
1676
1777
|
additionalRepoScopes: additionalRepoScopes.length > 0 ? additionalRepoScopes : null,
|
|
1677
1778
|
workSources: {
|
|
1678
1779
|
pullRequests: { enabled: document.getElementById('set-ws-prs-' + p.name)?.checked ?? true },
|