@yemi33/minions 0.1.2448 → 0.1.2449
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/cli-api-client.js +1 -1
- package/bin/install-internal-minions.js +1382 -44
- package/bin/install-layout.js +150 -0
- package/bin/minions.js +460 -167
- package/dashboard/docs/typography.md +65 -12
- package/dashboard/js/command-center.js +58 -4
- package/dashboard/js/detail-panel.js +36 -0
- package/dashboard/js/memory-panel.js +59 -12
- package/dashboard/js/qa.js +179 -20
- package/dashboard/js/refresh.js +148 -12
- package/dashboard/js/render-dispatch.js +3 -4
- package/dashboard/js/render-inbox.js +2 -2
- package/dashboard/js/render-other.js +3 -3
- package/dashboard/js/render-pipelines.js +14 -0
- package/dashboard/js/render-plans.js +57 -9
- package/dashboard/js/render-prd.js +132 -23
- package/dashboard/js/render-prs.js +195 -166
- package/dashboard/js/render-schedules.js +63 -3
- package/dashboard/js/render-utils.js +3 -3
- package/dashboard/js/render-watches.js +19 -3
- package/dashboard/js/render-work-items.js +238 -30
- package/dashboard/js/settings.js +205 -54
- package/dashboard/js/utils.js +51 -1
- package/dashboard/pages/home.html +1 -1
- package/dashboard/pages/qa.html +1 -16
- package/dashboard/pages/work.html +40 -0
- package/dashboard/shared/cc-limits.js +79 -0
- package/dashboard/shared/pr-filters.js +21 -38
- package/dashboard/shared/project-git-summary.js +1 -1
- package/dashboard/shared/record-filters.js +169 -0
- package/dashboard/shared/watches-source.js +1 -1
- package/dashboard/shared/welcome-popup.js +1 -1
- package/dashboard/shared/wi-filters.js +302 -0
- package/dashboard/slim/body.html +1 -0
- package/dashboard/slim/js/command-send.js +26 -0
- package/dashboard/slim/js/modals-tiles.js +380 -39
- package/dashboard/slim/js/status.js +13 -21
- package/dashboard/slim/layout.html +1 -0
- package/dashboard/slim/panel-bootstrap.js +6 -2
- package/dashboard/slim/styles.css +38 -0
- package/dashboard/styles.css +159 -55
- package/dashboard-build.js +13 -2
- package/dashboard.js +956 -423
- package/docs/README.md +11 -6
- package/docs/api-errors.md +2 -2
- package/docs/architecture-review-2026-07-09.md +1 -1
- package/docs/architecture.excalidraw +2 -2
- package/docs/auto-discovery.md +18 -9
- package/docs/branch-derivation.md +4 -4
- package/docs/capture-demos.js +39 -2
- package/docs/ci-runner-canary.md +123 -0
- package/docs/claude-md-propagation.md +2 -2
- package/docs/cloud-agent-dispatch.md +204 -0
- package/docs/command-center.md +7 -7
- package/docs/completion-reports.md +43 -20
- package/docs/constants.md +10 -3
- package/docs/constellation-bridge.md +134 -6
- package/docs/constellation-style-telemetry.md +4 -4
- package/docs/contracts/capability-protocol.v1.json +165 -0
- package/docs/cooldown-merge-semantics.md +12 -12
- package/docs/copilot-cli-schema.md +7 -7
- package/docs/cross-repo-plans.md +10 -10
- package/docs/dead-code-audit-retractions.md +5 -5
- package/docs/default-branch-ci.md +173 -0
- package/docs/deprecated.json +31 -31
- package/docs/design-inbox-entries-schema.md +3 -3
- package/docs/design-language.md +1051 -0
- package/docs/design-state-storage.md +11 -11
- package/docs/diagnostics-crash-reports.md +9 -9
- package/docs/diagnostics-memory.md +5 -5
- package/docs/documentation-audit-2026-07-09.md +7 -7
- package/docs/engine-restart.md +90 -5
- package/docs/harness-mode.md +1 -1
- package/docs/internal-install.md +338 -39
- package/docs/kb-dedup-duplicate-pair-investigation.md +5 -5
- package/docs/kb-pr3223-cascade-archiving.md +1 -1
- package/docs/kb-pr696-merge-conflict-docs.md +6 -6
- package/docs/kb-sweep.md +35 -35
- package/docs/keep-processes.md +1 -1
- package/docs/live-checkout-mode.md +30 -30
- package/docs/managed-spawn.md +18 -14
- package/docs/named-agents.md +7 -7
- package/docs/plan-lifecycle.md +69 -2
- package/docs/pr-author-identity.md +114 -0
- package/docs/pr-auto-fix-dispatch.md +19 -4
- package/docs/pr-comment-followup.md +6 -6
- package/docs/pr-review-fix-loop.md +59 -10
- package/docs/process-termination.md +40 -0
- package/docs/proposals/repo-pool-for-live-checkout.md +13 -13
- package/docs/qa-runbook-lifecycle.md +367 -17
- package/docs/qa-runbooks.md +3 -3
- package/docs/rfc-completion-json.md +18 -18
- package/docs/runtime-adapters.md +26 -21
- package/docs/security.md +6 -6
- package/docs/self-improvement.md +4 -4
- package/docs/shared-lifecycle-module-map.md +473 -472
- package/docs/skills.md +52 -3
- package/docs/slim-ux/concepts.md +121 -116
- package/docs/specs/agent-configurability.md +18 -18
- package/docs/specs/agent-rename.md +18 -18
- package/docs/team-memory.md +38 -21
- package/docs/timeouts-and-liveness.md +118 -10
- package/docs/tutorials/01-install-and-connect.md +1 -1
- package/docs/watches.md +40 -39
- package/docs/workspace-manifests.md +4 -4
- package/docs/worktree-lifecycle.md +293 -14
- package/engine/README.md +46 -0
- package/engine/{ado-comment.js → ado/comment.js} +8 -8
- package/engine/{ado-git-auth.js → ado/git-auth.js} +4 -4
- package/engine/{ado.js → ado/index.js} +417 -63
- package/engine/{ado-status.js → ado/status.js} +6 -8
- package/engine/{ado-token.js → ado/token.js} +1 -1
- package/engine/{acp-transport.js → agents/acp-transport.js} +62 -22
- package/engine/{agent-worker-pool.js → agents/agent-worker-pool.js} +17 -8
- package/engine/{cc-worker-pool.js → agents/cc-worker-pool.js} +16 -6
- package/engine/{claude-md-context.js → agents/claude-md-context.js} +5 -5
- package/engine/{harness-context.js → agents/harness-context.js} +5 -5
- package/engine/{harness.js → agents/harness.js} +3 -3
- package/engine/{llm.js → agents/llm.js} +18 -14
- package/engine/{model-discovery.js → agents/model-discovery.js} +2 -2
- package/engine/{playbook.js → agents/playbook.js} +155 -22
- package/engine/{pooled-agent-process.js → agents/pooled-agent-process.js} +14 -12
- package/engine/{preflight.js → agents/preflight.js} +29 -10
- package/engine/{spawn-agent.js → agents/spawn-agent.js} +25 -14
- package/engine/{spawn-phase-watchdog.js → agents/spawn-phase-watchdog.js} +16 -7
- package/engine/{steering.js → agents/steering.js} +5 -5
- package/engine/{tools-inventory.js → agents/tools-inventory.js} +2 -2
- package/engine/{agent-api-validation.js → api/agent-api-validation.js} +2 -2
- package/engine/{api-validation.js → api/api-validation.js} +1 -1
- package/engine/api/bridge.js +787 -0
- package/engine/{cc-api-validation.js → api/cc-api-validation.js} +1 -1
- package/engine/api/companion.js +560 -0
- package/engine/{content-api-validation.js → api/content-api-validation.js} +2 -2
- package/engine/{pr-issue-validation.js → api/pr-issue-validation.js} +33 -6
- package/engine/{settings-validation.js → api/settings-validation.js} +32 -4
- package/engine/api-contracts/agent-content.js +4 -4
- package/engine/api-contracts/capability-manifest.js +236 -0
- package/engine/api-contracts/capability-protocol.js +333 -0
- package/engine/api-contracts/cc-ops.js +1 -1
- package/engine/api-contracts/config-runtime.js +5 -0
- package/engine/api-contracts/core.js +28 -1
- package/engine/api-contracts/index.js +100 -0
- package/engine/api-contracts/orchestration.js +18 -5
- package/engine/api-contracts/pull-requests.js +37 -6
- package/engine/api-contracts/qa-process.js +29 -6
- package/engine/api-contracts/work-plan-prd.js +21 -1
- package/engine/cloud/contract.js +212 -0
- package/engine/cloud/index.js +159 -0
- package/engine/{execution-model.js → core/execution-model.js} +1 -1
- package/engine/{features.js → core/features.js} +4 -4
- package/engine/{operator-identity.js → core/operator-identity.js} +1 -1
- package/engine/{queries.js → core/queries.js} +201 -36
- package/engine/{safe-expr.js → core/safe-expr.js} +1 -1
- package/engine/{shared.js → core/shared.js} +1637 -175
- package/engine/{stdio-timestamps.js → core/stdio-timestamps.js} +1 -1
- package/engine/{untrusted-fence.js → core/untrusted-fence.js} +3 -3
- package/engine/db/index.js +11 -2
- package/engine/db/migrations/002-dispatches.js +3 -3
- package/engine/db/migrations/003-work-items.js +1 -1
- package/engine/db/migrations/004-pull-requests.js +1 -1
- package/engine/db/migrations/006-metrics.js +1 -1
- package/engine/db/migrations/007-watches.js +2 -2
- package/engine/db/migrations/008-small-state.js +1 -1
- package/engine/db/migrations/009-qa.js +1 -1
- package/engine/db/migrations/010-pr-links.js +1 -1
- package/engine/db/migrations/011-remaining-state.js +1 -1
- package/engine/db/migrations/012-steering-deliveries.js +2 -2
- package/engine/db/migrations/013-backfill-broken-note-links.js +1 -1
- package/engine/db/migrations/014-pr-fix-target-prefs.js +2 -2
- package/engine/db/migrations/015-plans-prds.js +0 -0
- package/engine/db/migrations/018-sql-only-cutover.js +2 -2
- package/engine/db/migrations/021-archived-work-items.js +1 -1
- package/engine/db/migrations/022-global-cc-session.js +1 -1
- package/engine/db/migrations/023-engine-state.js +1 -1
- package/engine/db/migrations/025-malformed-work-item-phantoms.js +1 -1
- package/engine/db/migrations/027-review-learning-lifecycle.js +1 -1
- package/engine/db/migrations/029-repair-reused-versions.js +20 -0
- package/engine/db/migrations/031-pr-author-identity.js +137 -0
- package/engine/{consolidation.js → memory/consolidation.js} +6 -6
- package/engine/{kb-sweep-runner.js → memory/kb-sweep-runner.js} +2 -2
- package/engine/{kb-sweep.js → memory/kb-sweep.js} +9 -7
- package/engine/{memory-retrieval.js → memory/memory-retrieval.js} +46 -4
- package/engine/{memory-store.js → memory/memory-store.js} +3 -3
- package/engine/{promotion.js → memory/promotion.js} +3 -3
- package/engine/{review-learning-backfill.js → memory/review-learning-backfill.js} +6 -6
- package/engine/{review-learning.js → memory/review-learning.js} +10 -5
- package/engine/{diagnostics-memory.js → observability/diagnostics-memory.js} +1 -1
- package/engine/{logs-store.js → observability/logs-store.js} +5 -5
- package/engine/{metrics-store.js → observability/metrics-store.js} +4 -4
- package/engine/{check-status.js → operations/check-status.js} +3 -3
- package/engine/{cli.js → operations/cli.js} +271 -113
- package/engine/{distribution.js → operations/distribution.js} +5 -6
- package/engine/{cleanup.js → orchestration/cleanup.js} +72 -45
- package/engine/{cooldown.js → orchestration/cooldown.js} +5 -5
- package/engine/{dispatch-events.js → orchestration/dispatch-events.js} +2 -2
- package/engine/{dispatch.js → orchestration/dispatch.js} +129 -36
- package/engine/orchestration/failed-scheduled-cleanup.js +274 -0
- package/engine/{lifecycle.js → orchestration/lifecycle.js} +198 -90
- package/engine/{meeting.js → orchestration/meeting.js} +6 -16
- package/engine/{pipeline.js → orchestration/pipeline.js} +12 -12
- package/engine/{pre-dispatch-eval.js → orchestration/pre-dispatch-eval.js} +10 -9
- package/engine/{routing.js → orchestration/routing.js} +3 -3
- package/engine/{schedule-bootstrap.js → orchestration/schedule-bootstrap.js} +4 -4
- package/engine/{scheduler.js → orchestration/scheduler.js} +38 -8
- package/engine/{timeout.js → orchestration/timeout.js} +158 -109
- package/engine/{db-events.js → persistence/db-events.js} +2 -2
- package/engine/{dispatch-store.js → persistence/dispatch-store.js} +7 -7
- package/engine/{inbox-store.js → persistence/inbox-store.js} +2 -2
- package/engine/{note-link-backfill.js → persistence/note-link-backfill.js} +4 -4
- package/engine/{pr-fix-target-store.js → persistence/pr-fix-target-store.js} +8 -8
- package/engine/{pull-requests-store.js → persistence/pull-requests-store.js} +21 -7
- package/engine/{small-state-store.js → persistence/small-state-store.js} +31 -31
- package/engine/persistence/state-operations.js +350 -0
- package/engine/{steering-store.js → persistence/steering-store.js} +6 -6
- package/engine/{issues.js → planning/issues.js} +2 -2
- package/engine/{plan-prd-validation.js → planning/plan-prd-validation.js} +8 -2
- package/engine/planning/prd-result-sidecar.js +190 -0
- package/engine/{prd-store.js → planning/prd-store.js} +17 -17
- package/engine/{project-discovery.js → planning/project-discovery.js} +5 -5
- package/engine/{projects.js → planning/projects.js} +10 -10
- package/engine/{resolve-area.js → planning/resolve-area.js} +1 -1
- package/engine/{work-item-validation.js → planning/work-item-validation.js} +39 -3
- package/engine/{work-items-store.js → planning/work-items-store.js} +29 -21
- package/engine/{keep-process-sweep.js → processes/keep-process-sweep.js} +57 -17
- package/engine/{managed-spawn-launcher.js → processes/managed-spawn-launcher.js} +3 -3
- package/engine/{managed-spawn.js → processes/managed-spawn.js} +97 -46
- package/engine/{process-utils.js → processes/process-utils.js} +599 -55
- package/engine/{abandoned-pr-reconciliation.js → providers/abandoned-pr-reconciliation.js} +17 -7
- package/engine/{comment-classifier.js → providers/comment-classifier.js} +85 -17
- package/engine/{comment-format.js → providers/comment-format.js} +5 -5
- package/engine/{gh-comment.js → providers/gh-comment.js} +15 -15
- package/engine/{gh-token.js → providers/gh-token.js} +4 -4
- package/engine/{github.js → providers/github.js} +131 -54
- package/engine/{pr-action.js → providers/pr-action.js} +13 -12
- package/engine/{pr-clone-keep.js → providers/pr-clone-keep.js} +7 -7
- package/engine/{pr-devbox.js → providers/pr-devbox.js} +6 -6
- package/engine/{pr-fix-target.js → providers/pr-fix-target.js} +13 -13
- package/engine/{pr-remote-patch.js → providers/pr-remote-patch.js} +4 -4
- package/engine/{pr-resolve.js → providers/pr-resolve.js} +7 -7
- package/engine/{pr-temp-clone.js → providers/pr-temp-clone.js} +5 -5
- package/engine/{pr-track.js → providers/pr-track.js} +11 -13
- package/engine/{shared-branch-pr-reconcile.js → providers/shared-branch-pr-reconcile.js} +4 -4
- package/engine/qa/auto-prd-qa.js +313 -0
- package/engine/{qa-from-prd.js → qa/from-prd.js} +42 -12
- package/engine/qa/prd-session.js +240 -0
- package/engine/{qa-process-validation.js → qa/process-validation.js} +14 -9
- package/engine/{qa-runbooks.js → qa/runbooks.js} +1 -1
- package/engine/{qa-runs.js → qa/runs.js} +286 -15
- package/engine/{qa-sessions.js → qa/sessions.js} +595 -49
- package/engine/qa/visual-journey.js +654 -0
- package/engine/{qa-runners.js → qa-runners/index.js} +7 -7
- package/engine/qa-runners/maestro.js +3 -3
- package/engine/qa-runners/playwright.js +2 -2
- package/engine/{restart-health.js → recovery/restart-health.js} +48 -4
- package/engine/recovery/stop-stack.js +607 -0
- package/engine/{supervisor.js → recovery/supervisor.js} +105 -175
- package/engine/{watchdog.js → recovery/watchdog.js} +136 -13
- package/engine/runtimes/claude.js +14 -12
- package/engine/runtimes/codex.js +8 -6
- package/engine/runtimes/copilot.js +17 -16
- package/engine/{watch-actions.js → watches/actions.js} +13 -13
- package/engine/{watches.js → watches/index.js} +43 -32
- package/engine/{watches-store.js → watches/store.js} +4 -4
- package/engine/{create-pr-worktree.js → worktrees/create-pr.js} +1 -1
- package/engine/{worktree-gc.js → worktrees/gc.js} +70 -22
- package/engine/worktrees/inventory.js +671 -0
- package/engine/{live-checkout.js → worktrees/live-checkout.js} +4 -4
- package/engine/{worktree-pool.js → worktrees/pool.js} +2 -2
- package/engine/{worktree-preflight.js → worktrees/preflight.js} +1 -0
- package/engine/worktrees/quarantine-refs.js +173 -0
- package/engine.js +1137 -208
- package/minions.js +147 -77
- package/package.json +10 -6
- package/playbooks/_pr-description-audit.md +110 -78
- package/playbooks/build-fix-complex.md +2 -0
- package/playbooks/fix.md +16 -12
- package/playbooks/implement-shared.md +2 -0
- package/playbooks/implement.md +19 -20
- package/playbooks/plan-to-prd.md +18 -3
- package/playbooks/qa-session-draft.md +136 -1
- package/playbooks/qa-session-execute.md +80 -2
- package/playbooks/qa-session-setup.md +17 -1
- package/playbooks/qa-validate.md +1 -1
- package/playbooks/setup.md +2 -0
- package/playbooks/shared-rules.md +25 -32
- package/playbooks/templates/followup-dispatch.md +4 -3
- package/playbooks/verify.md +1 -1
- package/prompts/cc-system.md +19 -27
- package/watch-plugins/README.md +92 -0
- package/watch-plugins/ado-author-prs.js +336 -0
- package/watch-plugins/gh-author-prs.js +375 -0
- package/watch-plugins/http.js +474 -0
- package/watch-plugins/teams-channel.js +869 -0
- package/docs/dev-composite-workflow.md +0 -101
- package/docs/pr-screenshots/pr-886/after-single-header.png +0 -0
- package/docs/pr-screenshots/pr-886/before-duplicate-header.png +0 -0
- package/docs/pr-screenshots/pr-895/01-cancellation-reason-detail.png +0 -0
- 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-901/projects-tab-default.png +0 -0
- package/docs/pr-screenshots/pr-901/projects-tab-fmf-selected.png +0 -0
- package/docs/pr-screenshots/pr-916/model-picker-AFTER-crop.png +0 -0
- package/docs/pr-screenshots/pr-916/model-picker-AFTER.png +0 -0
- package/docs/pr-screenshots/pr-916/model-picker-BEFORE-crop.png +0 -0
- package/docs/pr-screenshots/pr-916/model-picker-BEFORE.png +0 -0
- package/docs/pr-screenshots/pr-916/model-picker-dropdown-AFTER.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/visual-evidence-ci.md +0 -103
- package/engine/bridge.js +0 -379
- package/engine/quarantine-refs.js +0 -103
- package/engine/state-operations.js +0 -178
- /package/engine/{steering-constraints.js → agents/steering-constraints.js} +0 -0
|
@@ -430,7 +430,11 @@ function openScheduleDetail(id) {
|
|
|
430
430
|
// ─── Form ───────────────────────────────────────────────────────────────────
|
|
431
431
|
|
|
432
432
|
function _scheduleFormHtml(sched, isEdit) {
|
|
433
|
-
const types = ['implement', 'test', 'explore', 'ask', 'review', 'fix'];
|
|
433
|
+
const types = ['implement', 'test', 'explore', 'ask', 'review', 'fix', 'setup'];
|
|
434
|
+
// W-ms5tb6ha016fda10 — only these types may run without a repository
|
|
435
|
+
// checkout. Mirrors shared.CONTROL_PLANE_ELIGIBLE_TYPES; the server
|
|
436
|
+
// re-validates fail-closed, so this is a UX affordance, not the gate.
|
|
437
|
+
const controlPlaneTypes = ['setup', 'ask', 'explore', 'meeting'];
|
|
434
438
|
const priorities = Array.isArray(window.MINIONS_WORK_ITEM_PRIORITIES)
|
|
435
439
|
? window.MINIONS_WORK_ITEM_PRIORITIES
|
|
436
440
|
: [];
|
|
@@ -510,12 +514,21 @@ function _scheduleFormHtml(sched, isEdit) {
|
|
|
510
514
|
'</div>' +
|
|
511
515
|
'<div style="display:flex;gap:12px">' +
|
|
512
516
|
'<label style="color:var(--text);font-size:var(--text-md);flex:1">Type' +
|
|
513
|
-
'<select id="sched-edit-type" style="' + inputStyle + '">' + typeOpts + '</select>' +
|
|
517
|
+
'<select id="sched-edit-type" style="' + inputStyle + '" onchange="_syncScheduleSurfaceAvailability()">' + typeOpts + '</select>' +
|
|
514
518
|
'</label>' +
|
|
515
519
|
'<label style="color:var(--text);font-size:var(--text-md);flex:1">Priority' +
|
|
516
520
|
'<select id="sched-edit-priority" style="' + inputStyle + '">' + priOpts + '</select>' +
|
|
517
521
|
'</label>' +
|
|
518
522
|
'</div>' +
|
|
523
|
+
'<label id="sched-surface-row" style="color:var(--text);font-size:var(--text-md)"' +
|
|
524
|
+
' title="Control-plane tasks call the Minions API and gh/az only. The engine skips git worktree creation entirely, so they cost no checkout and never race shared remote refs. Only setup / ask / explore / meeting may use it.">' +
|
|
525
|
+
'Execution surface' +
|
|
526
|
+
'<select id="sched-edit-surface" style="' + inputStyle + '">' +
|
|
527
|
+
'<option value="repo"' + (sched.executionSurface === 'control-plane' ? '' : ' selected') + '>repo — allocate a git worktree (default)</option>' +
|
|
528
|
+
'<option value="control-plane"' + (sched.executionSurface === 'control-plane' ? ' selected' : '') + '>control-plane — API/CLI only, no checkout</option>' +
|
|
529
|
+
'</select>' +
|
|
530
|
+
'<span id="sched-surface-hint" style="display:block;margin-top:4px;font-size:var(--text-base);color:var(--muted)"></span>' +
|
|
531
|
+
'</label>' +
|
|
519
532
|
'<div style="display:flex;gap:12px">' +
|
|
520
533
|
'<label style="color:var(--text);font-size:var(--text-md);flex:1">Project' +
|
|
521
534
|
'<select id="sched-edit-project" style="' + inputStyle + '">' + projOpts + '</select>' +
|
|
@@ -534,6 +547,33 @@ function _scheduleFormHtml(sched, isEdit) {
|
|
|
534
547
|
'</div>';
|
|
535
548
|
}
|
|
536
549
|
|
|
550
|
+
function _scheduleControlPlaneTypes() {
|
|
551
|
+
return ['setup', 'ask', 'explore', 'meeting'];
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
/**
|
|
555
|
+
* W-ms5tb6ha016fda10 — keep the Execution-surface selector honest as the Type
|
|
556
|
+
* changes. Repo-reading/mutating types cannot run without a checkout, so the
|
|
557
|
+
* control-plane option is disabled (and any stale selection reset) rather than
|
|
558
|
+
* letting the operator submit something the server will reject.
|
|
559
|
+
*/
|
|
560
|
+
function _syncScheduleSurfaceAvailability() {
|
|
561
|
+
const typeEl = document.getElementById('sched-edit-type');
|
|
562
|
+
const surfaceEl = document.getElementById('sched-edit-surface');
|
|
563
|
+
const hintEl = document.getElementById('sched-surface-hint');
|
|
564
|
+
if (!typeEl || !surfaceEl) return;
|
|
565
|
+
const eligible = _scheduleControlPlaneTypes().includes(typeEl.value);
|
|
566
|
+
const cpOption = surfaceEl.querySelector('option[value="control-plane"]');
|
|
567
|
+
if (cpOption) cpOption.disabled = !eligible;
|
|
568
|
+
if (!eligible && surfaceEl.value === 'control-plane') surfaceEl.value = 'repo';
|
|
569
|
+
surfaceEl.disabled = !eligible;
|
|
570
|
+
if (hintEl) {
|
|
571
|
+
hintEl.textContent = eligible
|
|
572
|
+
? 'Control-plane skips git worktree creation — use it for API/CLI-only maintenance jobs.'
|
|
573
|
+
: 'Type "' + typeEl.value + '" reads or changes repository files, so it always gets a worktree.';
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
|
|
537
577
|
function openCreateScheduleModal() {
|
|
538
578
|
window._schedComputedCron = '';
|
|
539
579
|
document.getElementById('modal-title').textContent = 'New Scheduled Task';
|
|
@@ -542,6 +582,7 @@ function openCreateScheduleModal() {
|
|
|
542
582
|
// eslint-disable-next-line no-unsanitized/property -- reason: structural HTML is a string literal; all user data wrapped in escHtml() by _scheduleFormHtml() (fields: project names, agent ids/names)
|
|
543
583
|
document.getElementById('modal-body').innerHTML = _scheduleFormHtml({}, false);
|
|
544
584
|
document.getElementById('modal').classList.add('open');
|
|
585
|
+
_syncScheduleSurfaceAvailability();
|
|
545
586
|
_updateCronPreview();
|
|
546
587
|
}
|
|
547
588
|
|
|
@@ -556,6 +597,7 @@ function openEditScheduleModal(id) {
|
|
|
556
597
|
document.getElementById('modal-body').innerHTML = _scheduleFormHtml(sched, true);
|
|
557
598
|
window._editScheduleId = id;
|
|
558
599
|
document.getElementById('modal').classList.add('open');
|
|
600
|
+
_syncScheduleSurfaceAvailability();
|
|
559
601
|
_updateCronPreview();
|
|
560
602
|
}
|
|
561
603
|
|
|
@@ -569,6 +611,8 @@ async function submitSchedule(isEdit, e) {
|
|
|
569
611
|
const project = document.getElementById('sched-edit-project').value;
|
|
570
612
|
const agent = document.getElementById('sched-edit-agent').value;
|
|
571
613
|
const description = document.getElementById('sched-edit-desc').value;
|
|
614
|
+
const surfaceEl = document.getElementById('sched-edit-surface');
|
|
615
|
+
const executionSurface = surfaceEl && !surfaceEl.disabled ? surfaceEl.value : 'repo';
|
|
572
616
|
|
|
573
617
|
let id;
|
|
574
618
|
if (isEdit) {
|
|
@@ -581,7 +625,7 @@ async function submitSchedule(isEdit, e) {
|
|
|
581
625
|
if (!title) { _resetSchedBtn(); _showScheduleError('Title is required'); return; }
|
|
582
626
|
if (!cron) { _resetSchedBtn(); _showScheduleError('Schedule is required \u2014 select days and time, or use natural language'); return; }
|
|
583
627
|
|
|
584
|
-
const payload = { id, title, cron, type, priority, project: project || undefined, agent: agent || undefined, description: description || undefined, enabled: true };
|
|
628
|
+
const payload = { id, title, cron, type, priority, project: project || undefined, agent: agent || undefined, description: description || undefined, enabled: true, executionSurface };
|
|
585
629
|
const url = isEdit ? '/api/schedules/update' : '/api/schedules';
|
|
586
630
|
try {
|
|
587
631
|
const res = await fetch(url, {
|
|
@@ -689,3 +733,19 @@ async function deleteSchedule(id) {
|
|
|
689
733
|
window._generateScheduleId = _generateScheduleId;
|
|
690
734
|
|
|
691
735
|
window.MinionsSchedules = { renderSchedules, openCreateScheduleModal, openEditScheduleModal, openScheduleDetail, submitSchedule, toggleScheduleEnabled, runScheduleNow, deleteSchedule, _cronToHuman, _parseNaturalCron, _toggleCronMode, _quickSelectDays, _toggleDayPill, _updateCronPreview, _schedPrev, _schedNext, _schedSetView };
|
|
736
|
+
|
|
737
|
+
// ── Slim "+ Add" deep-link (W-ms258yw0000ffd8a) ────────────────────────
|
|
738
|
+
// The Slim Automation tile's "+ Add" picker embeds this classic screen at
|
|
739
|
+
// /schedule?embed=1#create and relies on this hook to auto-open the Create
|
|
740
|
+
// Scheduled Task dialog — the classic create flow is reused, not forked (CLAUDE
|
|
741
|
+
// .md slim-vs-classic). Fires only on the /schedule path with a #create hash;
|
|
742
|
+
// the standalone classic screen and every other embed is otherwise untouched.
|
|
743
|
+
// isReady is load-bearing: _scheduleFormHtml builds its Project/Agent selects
|
|
744
|
+
// from cmdProjects/cmdAgents (see above), which refresh.js only fills after the
|
|
745
|
+
// first data tick — opening earlier yields a form with empty dropdowns that
|
|
746
|
+
// never self-heals. Helper lives in utils.js#bootCreateDeepLink.
|
|
747
|
+
typeof bootCreateDeepLink === 'function' && bootCreateDeepLink({
|
|
748
|
+
route: '/schedule',
|
|
749
|
+
resolve: function() { return typeof openCreateScheduleModal === 'function' ? openCreateScheduleModal : null; },
|
|
750
|
+
isReady: classicCreateFormDataReady,
|
|
751
|
+
});
|
|
@@ -82,7 +82,7 @@ function formatToolSummary(name, input) {
|
|
|
82
82
|
// record, rendered in sequence so prose and tool activity stay interleaved.
|
|
83
83
|
//
|
|
84
84
|
// Text-segment boundaries come from the server `segmentId` on chunk events
|
|
85
|
-
// (engine/llm.js increments it on a tool boundary or a non-extending text
|
|
85
|
+
// (engine/agents/llm.js increments it on a tool boundary or a non-extending text
|
|
86
86
|
// push). When segmentId is absent (Copilot pool path, live-stream replay,
|
|
87
87
|
// older engine) ccSegmentsApplyChunk falls back to a heuristic: a chunk that
|
|
88
88
|
// arrives after a tool starts a new text segment; a chunk that extends the
|
|
@@ -343,7 +343,7 @@ function _renderJsonObj(obj, state) {
|
|
|
343
343
|
// W-mpob4nyk0006580e — the terminal banner is no longer derived here.
|
|
344
344
|
// The engine's dispatch.result is the single source of truth and is
|
|
345
345
|
// pushed to the live view via the SSE `dispatch.terminal` channel
|
|
346
|
-
// (engine/dispatch-events.js → dashboard.js handleAgentLiveStream).
|
|
346
|
+
// (engine/orchestration/dispatch-events.js → dashboard.js handleAgentLiveStream).
|
|
347
347
|
// `result` JSONL lines and the `[process-exit]` sentinel are still
|
|
348
348
|
// parsed for other purposes (e.g. tool deltas above), but they must
|
|
349
349
|
// NOT trigger any banner here — log heuristics can disagree with the
|
|
@@ -466,7 +466,7 @@ function renderAgentOutput(text) {
|
|
|
466
466
|
/**
|
|
467
467
|
* W-mpob4nyk0006580e — render the terminal banner from an authoritative
|
|
468
468
|
* `dispatch.terminal` SSE event. The shape mirrors
|
|
469
|
-
* engine/dispatch-events.js buildTerminalEvent():
|
|
469
|
+
* engine/orchestration/dispatch-events.js buildTerminalEvent():
|
|
470
470
|
* { type, ts, dispatchId, agentId, result, reason, failureClass, prUrl, summary }
|
|
471
471
|
*
|
|
472
472
|
* The banner state mirrors `dispatch.result` exactly — green for SUCCESS,
|
|
@@ -93,8 +93,8 @@ function _targetTypeLabel(type) {
|
|
|
93
93
|
// renderArtifactLink / openArtifact (defined in render-utils.js). Returns null
|
|
94
94
|
// for targetTypes that don't correspond to a navigable artifact (teams-channel,
|
|
95
95
|
// future plugin types) so callers fall back to plain text rendering. The
|
|
96
|
-
// mapping covers the 8 first-class TARGET_TYPES
|
|
97
|
-
// (engine/shared.js#WATCH_TARGET_TYPE) — dispatch ids are WI ids in practice
|
|
96
|
+
// mapping covers the 8 first-class TARGET_TYPES in engine/watches.js
|
|
97
|
+
// (engine/core/shared.js#WATCH_TARGET_TYPE) — dispatch ids are WI ids in practice
|
|
98
98
|
// so they share the wi chip target.
|
|
99
99
|
var _WATCH_TARGET_TO_ART_TYPE = {
|
|
100
100
|
'pr': 'pr',
|
|
@@ -754,7 +754,7 @@ function submitWatch() {
|
|
|
754
754
|
// P-w14e7a8c — Phase 7.1: harvest action steps from the chain editor.
|
|
755
755
|
// 0 steps -> action: null (notify-only legacy behavior).
|
|
756
756
|
// 1 step -> action: { type, params, guard? } (single-object form).
|
|
757
|
-
// 2+ steps -> action: [ {...}, ... ] (array-form chain — engine/
|
|
757
|
+
// 2+ steps -> action: [ {...}, ... ] (array-form chain — engine/watches/actions.js
|
|
758
758
|
// runWatchActionChain handles it).
|
|
759
759
|
var stepRows = document.querySelectorAll('.watch-step-row');
|
|
760
760
|
var steps = [];
|
|
@@ -867,3 +867,19 @@ window.MinionsWatches = {
|
|
|
867
867
|
_watchTargetToArtType: _watchTargetToArtType,
|
|
868
868
|
_renderWatchTargetChip: _renderWatchTargetChip,
|
|
869
869
|
};
|
|
870
|
+
|
|
871
|
+
// ── Slim "+ Add" deep-link (W-ms258yw0000ffd8a) ────────────────────────
|
|
872
|
+
// The Slim Automation tile's "+ Add" picker embeds this classic screen at
|
|
873
|
+
// /watches?embed=1#create and relies on this hook to auto-open the Create Watch
|
|
874
|
+
// dialog — the classic create flow is reused, not forked (CLAUDE.md slim-vs-
|
|
875
|
+
// classic). Fires only on the /watches path with a #create hash; the standalone
|
|
876
|
+
// classic screen and every other embed is otherwise untouched.
|
|
877
|
+
// isReady is load-bearing: _renderCreateWatchModal builds its Owner/Project
|
|
878
|
+
// selects from cmdAgents/cmdProjects (see above), which refresh.js only fills
|
|
879
|
+
// after the first data tick — opening earlier yields a form with empty dropdowns
|
|
880
|
+
// that never self-heals. Helper lives in utils.js#bootCreateDeepLink.
|
|
881
|
+
typeof bootCreateDeepLink === 'function' && bootCreateDeepLink({
|
|
882
|
+
route: '/watches',
|
|
883
|
+
resolve: function() { return typeof openCreateWatchModal === 'function' ? openCreateWatchModal : null; },
|
|
884
|
+
isReady: classicCreateFormDataReady,
|
|
885
|
+
});
|
|
@@ -1,9 +1,41 @@
|
|
|
1
1
|
// dashboard/js/render-work-items.js — Work item rendering and management extracted from dashboard.html
|
|
2
2
|
|
|
3
3
|
let allWorkItems = [];
|
|
4
|
+
let filteredWorkItems = [];
|
|
4
5
|
let wiPage = 0;
|
|
6
|
+
let wiFilterOptionsSignature = '';
|
|
5
7
|
const WI_PER_PAGE = 20;
|
|
6
8
|
|
|
9
|
+
// Filter + sort controls modeled on the PR table (dashboard/js/render-prs.js).
|
|
10
|
+
// Each dimension maps to a <select> in dashboard/pages/work.html; options are
|
|
11
|
+
// populated dynamically from the current data set with a signature guard so the
|
|
12
|
+
// user's selection survives the 4s refresh poll. (W-ms7kutzv003q17ad)
|
|
13
|
+
const WI_FILTER_CONTROL_IDS = {
|
|
14
|
+
status: 'wi-filter-status',
|
|
15
|
+
type: 'wi-filter-type',
|
|
16
|
+
project: 'wi-filter-project',
|
|
17
|
+
agent: 'wi-filter-agent',
|
|
18
|
+
priority: 'wi-filter-priority',
|
|
19
|
+
};
|
|
20
|
+
const WI_FILTER_ALL_LABELS = {
|
|
21
|
+
status: 'All statuses',
|
|
22
|
+
type: 'All types',
|
|
23
|
+
project: 'All projects',
|
|
24
|
+
agent: 'All agents',
|
|
25
|
+
priority: 'All priorities',
|
|
26
|
+
};
|
|
27
|
+
const WI_SORT_LABELS = [
|
|
28
|
+
{ value: 'lifecycle', label: 'Lifecycle (active first)' },
|
|
29
|
+
{ value: 'updated', label: 'Last updated' },
|
|
30
|
+
{ value: 'created', label: 'Created' },
|
|
31
|
+
{ value: 'priority', label: 'Priority' },
|
|
32
|
+
{ value: 'status', label: 'Status' },
|
|
33
|
+
{ value: 'type', label: 'Type' },
|
|
34
|
+
];
|
|
35
|
+
const WI_SORT_CONTROL_ID = 'wi-sort-by';
|
|
36
|
+
const WI_SORT_DIR_CONTROL_ID = 'wi-sort-dir';
|
|
37
|
+
|
|
38
|
+
|
|
7
39
|
// W-mq08kuog001110a6 — Needs-Attention badge for stuck pending work items.
|
|
8
40
|
//
|
|
9
41
|
// A pending WI is "needs attention" when the engine is intentionally refusing
|
|
@@ -26,6 +58,7 @@ const WI_PER_PAGE = 20;
|
|
|
26
58
|
// * branch_locked — wait for the holding dispatch
|
|
27
59
|
// * worktree_branch_held — configured checkout is re-checked each tick
|
|
28
60
|
// * dependency_unmet — auto-clears when upstream dep finishes (engine discovery loop + DEPENDENCY_MET watch)
|
|
61
|
+
// * dependency_conflict — dep-branch merge conflict repair in progress; auto-clears when the conflict-repair WI completes (W-mrzqfozm00035365)
|
|
29
62
|
// * live_checkout_busy — one live-mode dispatch at a time; clears when running dispatch finishes
|
|
30
63
|
//
|
|
31
64
|
// no_agent (kept as a trigger) now means the engine found NO eligible agent
|
|
@@ -73,6 +106,22 @@ function needsAttentionInfo(item) {
|
|
|
73
106
|
var budgetMsg = 'Assigned agent ' + agent + ' is over its maxBudgetUsd cap.';
|
|
74
107
|
return { kind: 'budget_exceeded', short: budgetMsg, full: budgetMsg };
|
|
75
108
|
}
|
|
109
|
+
// W-mrzqfozm00035365 — a downstream item whose dependency-branch merge
|
|
110
|
+
// conflict could NOT be repaired (repair WI failed/cancelled, or completed
|
|
111
|
+
// but the branches still conflict) is an actionable block: it will not
|
|
112
|
+
// dispatch until a human resolves the conflict on the dep branch. The
|
|
113
|
+
// in-progress `dependency_conflict` state is deliberately NOT surfaced here —
|
|
114
|
+
// it auto-clears when the repair completes.
|
|
115
|
+
if (reason === 'dependency_conflict_unresolved') {
|
|
116
|
+
var dc = item._dependencyConflict || {};
|
|
117
|
+
var cb = dc.conflictBranch || '(dependency branch)';
|
|
118
|
+
var cw = dc.conflictsWith || 'the base branch';
|
|
119
|
+
var rw = dc.repairWiId || '(conflict-fix work item)';
|
|
120
|
+
var dcMsg = 'Dependency branch ' + cb + ' conflicts with ' + cw +
|
|
121
|
+
' and the conflict-repair work item ' + rw + ' did not resolve it. ' +
|
|
122
|
+
'Resolve the conflict on ' + cb + ' (or re-run ' + rw + '); this item re-runs dependency integration automatically once the repair succeeds.';
|
|
123
|
+
return { kind: 'dependency_conflict_unresolved', short: dcMsg, full: dcMsg };
|
|
124
|
+
}
|
|
76
125
|
return null;
|
|
77
126
|
}
|
|
78
127
|
|
|
@@ -80,6 +129,20 @@ function formatPendingReason(item, detailed) {
|
|
|
80
129
|
var reason = item && item._pendingReason ? String(item._pendingReason) : '';
|
|
81
130
|
if (!reason) return '';
|
|
82
131
|
if (reason === 'already_dispatched') return 'Queued — waiting for available agent slot';
|
|
132
|
+
if (reason === 'dependency_conflict') {
|
|
133
|
+
if (!detailed) return 'dependency conflict — repair in progress';
|
|
134
|
+
var dcp = item._dependencyConflict || {};
|
|
135
|
+
return 'Dependency branch ' + (dcp.conflictBranch || '(unknown)') + ' conflicts with ' +
|
|
136
|
+
(dcp.conflictsWith || 'the base branch') + '. Held pending behind conflict-repair ' +
|
|
137
|
+
(dcp.repairWiId || '(repair WI)') + '; auto-resumes when the repair completes.';
|
|
138
|
+
}
|
|
139
|
+
if (reason === 'dependency_conflict_unresolved') {
|
|
140
|
+
if (!detailed) return 'dependency conflict — needs attention';
|
|
141
|
+
var dcu = item._dependencyConflict || {};
|
|
142
|
+
return 'Dependency branch ' + (dcu.conflictBranch || '(unknown)') + ' still conflicts with ' +
|
|
143
|
+
(dcu.conflictsWith || 'the base branch') + ' after conflict-repair ' +
|
|
144
|
+
(dcu.repairWiId || '(repair WI)') + '. Needs manual resolution.';
|
|
145
|
+
}
|
|
83
146
|
if (reason === 'agents_busy') return 'Waiting for an available agent — all eligible agents are busy';
|
|
84
147
|
if (reason !== 'worktree_branch_held') return reason.replace(/_/g, ' ');
|
|
85
148
|
if (!detailed) return 'operator checkout holds branch';
|
|
@@ -187,6 +250,7 @@ function wiRow(item) {
|
|
|
187
250
|
'</td>' +
|
|
188
251
|
'<td>' + prLink + (failSnippet ? failSnippet : '') + '</td>' +
|
|
189
252
|
'<td><span class="pr-date">' + escapeHtml((item.created || '').slice(0, 16).replace('T', ' ')) + '</span></td>' +
|
|
253
|
+
'<td><span class="pr-date" title="' + escapeHtml(_wiUpdatedTitle(item)) + '">' + escapeHtml(_wiUpdatedLabel(item)) + '</span></td>' +
|
|
190
254
|
'<td style="white-space:nowrap;font-size:var(--text-sm);color:var(--muted)">' +
|
|
191
255
|
(function() {
|
|
192
256
|
// /api/status slims the full arrays into integer counts
|
|
@@ -217,44 +281,188 @@ function wiRow(item) {
|
|
|
217
281
|
'</tr>';
|
|
218
282
|
}
|
|
219
283
|
|
|
284
|
+
function _wiUpdatedLabel(item) {
|
|
285
|
+
var ms = window.MinionsWorkItemFilters && window.MinionsWorkItemFilters.lastUpdatedMs
|
|
286
|
+
? window.MinionsWorkItemFilters.lastUpdatedMs(item)
|
|
287
|
+
: null;
|
|
288
|
+
if (ms == null) return '—';
|
|
289
|
+
return typeof timeAgo === 'function' ? timeAgo(new Date(ms).toISOString()) : new Date(ms).toISOString().slice(0, 16).replace('T', ' ');
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
function _wiUpdatedTitle(item) {
|
|
293
|
+
var ms = window.MinionsWorkItemFilters && window.MinionsWorkItemFilters.lastUpdatedMs
|
|
294
|
+
? window.MinionsWorkItemFilters.lastUpdatedMs(item)
|
|
295
|
+
: null;
|
|
296
|
+
if (ms == null) return 'No update timestamp';
|
|
297
|
+
return new Date(ms).toISOString().slice(0, 16).replace('T', ' ') + ' UTC';
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// Populate the filter <select>s from the current data set. Guarded by a
|
|
301
|
+
// signature so options only re-render when the derivable option set changes —
|
|
302
|
+
// this preserves the user's current selection across the periodic poll. Mirrors
|
|
303
|
+
// _syncPrFilterOptions in render-prs.js. (W-ms7kutzv003q17ad)
|
|
304
|
+
function _syncWiFilterOptions(items) {
|
|
305
|
+
if (!window.MinionsWorkItemFilters) return;
|
|
306
|
+
const options = window.MinionsWorkItemFilters.options(items);
|
|
307
|
+
const controls = Object.keys(WI_FILTER_CONTROL_IDS).map(function(dimension) {
|
|
308
|
+
return {
|
|
309
|
+
dimension: dimension,
|
|
310
|
+
select: document.getElementById(WI_FILTER_CONTROL_IDS[dimension]),
|
|
311
|
+
};
|
|
312
|
+
}).filter(function(entry) { return entry.select; });
|
|
313
|
+
if (!controls.length) return;
|
|
314
|
+
const signature = JSON.stringify(options);
|
|
315
|
+
if (signature === wiFilterOptionsSignature) return;
|
|
316
|
+
wiFilterOptionsSignature = signature;
|
|
317
|
+
controls.forEach(function(entry) {
|
|
318
|
+
const dimension = entry.dimension;
|
|
319
|
+
const select = entry.select;
|
|
320
|
+
const selected = select.value;
|
|
321
|
+
const all = document.createElement('option');
|
|
322
|
+
all.value = '';
|
|
323
|
+
all.textContent = WI_FILTER_ALL_LABELS[dimension];
|
|
324
|
+
const nodes = [all].concat((options[dimension] || []).map(function(option) {
|
|
325
|
+
const node = document.createElement('option');
|
|
326
|
+
node.value = option.value;
|
|
327
|
+
node.textContent = option.label;
|
|
328
|
+
return node;
|
|
329
|
+
}));
|
|
330
|
+
select.replaceChildren(...nodes);
|
|
331
|
+
if (nodes.some(function(node) { return node.value === selected; })) select.value = selected;
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
function _readWiFilters() {
|
|
336
|
+
const filters = {};
|
|
337
|
+
Object.keys(WI_FILTER_CONTROL_IDS).forEach(function(dimension) {
|
|
338
|
+
const select = document.getElementById(WI_FILTER_CONTROL_IDS[dimension]);
|
|
339
|
+
filters[dimension] = select ? select.value : '';
|
|
340
|
+
});
|
|
341
|
+
return filters;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
function _hasActiveWiFilters(filters) {
|
|
345
|
+
return Object.keys(WI_FILTER_CONTROL_IDS).some(function(dimension) {
|
|
346
|
+
return Boolean(filters[dimension]);
|
|
347
|
+
});
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
// Single source for the sort default in this module: the shared helper's
|
|
351
|
+
// WI_SORT_DEFAULT (dashboard/shared/wi-filters.js), with one literal fallback
|
|
352
|
+
// for the no-module case. Kept in sync with the shared default by
|
|
353
|
+
// test/unit/wi-filters.test.js.
|
|
354
|
+
function _wiSortDefault() {
|
|
355
|
+
return (window.MinionsWorkItemFilters && window.MinionsWorkItemFilters.sortDefault)
|
|
356
|
+
|| { sortBy: 'lifecycle', dir: 'desc' };
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
function _readWiSort() {
|
|
360
|
+
const byEl = document.getElementById(WI_SORT_CONTROL_ID);
|
|
361
|
+
const dirEl = document.getElementById(WI_SORT_DIR_CONTROL_ID);
|
|
362
|
+
const def = _wiSortDefault();
|
|
363
|
+
return {
|
|
364
|
+
sortBy: byEl && byEl.value ? byEl.value : def.sortBy,
|
|
365
|
+
dir: dirEl && dirEl.value ? dirEl.value : def.dir,
|
|
366
|
+
};
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
function applyWiFilters() {
|
|
370
|
+
wiPage = 0;
|
|
371
|
+
renderWorkItems(allWorkItems, { preserveScroll: false });
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
function resetWiFilters() {
|
|
375
|
+
Object.keys(WI_FILTER_CONTROL_IDS).forEach(function(dimension) {
|
|
376
|
+
const select = document.getElementById(WI_FILTER_CONTROL_IDS[dimension]);
|
|
377
|
+
if (select) select.value = '';
|
|
378
|
+
});
|
|
379
|
+
const byEl = document.getElementById(WI_SORT_CONTROL_ID);
|
|
380
|
+
const dirEl = document.getElementById(WI_SORT_DIR_CONTROL_ID);
|
|
381
|
+
const def = _wiSortDefault();
|
|
382
|
+
if (byEl) byEl.value = def.sortBy;
|
|
383
|
+
if (dirEl) {
|
|
384
|
+
dirEl.value = def.dir;
|
|
385
|
+
_syncWiSortDirLabel(dirEl);
|
|
386
|
+
}
|
|
387
|
+
applyWiFilters();
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
// Toggle the asc/desc direction button (value + arrow glyph) and re-render.
|
|
391
|
+
function toggleWiSortDir() {
|
|
392
|
+
const dirEl = document.getElementById(WI_SORT_DIR_CONTROL_ID);
|
|
393
|
+
if (dirEl) {
|
|
394
|
+
dirEl.value = dirEl.value === 'asc' ? 'desc' : 'asc';
|
|
395
|
+
_syncWiSortDirLabel(dirEl);
|
|
396
|
+
}
|
|
397
|
+
applyWiFilters();
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
function _syncWiSortDirLabel(dirEl) {
|
|
401
|
+
if (!dirEl) return;
|
|
402
|
+
const asc = dirEl.value === 'asc';
|
|
403
|
+
dirEl.setAttribute('aria-label', asc ? 'Sort ascending (oldest first)' : 'Sort descending (newest first)');
|
|
404
|
+
dirEl.title = asc ? 'Ascending — click for descending' : 'Descending — click for ascending';
|
|
405
|
+
dirEl.textContent = asc ? '\u2191 Asc' : '\u2193 Desc';
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
// Apply the active filters + sort to the raw items. dashboard-build.js always
|
|
409
|
+
// assembles dashboard/shared/wi-filters.js before this module (enforced by
|
|
410
|
+
// test/unit/wi-filters.test.js), so the shared helper is the ONE definition of
|
|
411
|
+
// filter and lifecycle-sort semantics. A stripped harness without it renders
|
|
412
|
+
// the raw list rather than carrying a second, drift-prone status order.
|
|
413
|
+
function _computeWiView(items) {
|
|
414
|
+
const filters = _readWiFilters();
|
|
415
|
+
const sort = _readWiSort();
|
|
416
|
+
const wf = window.MinionsWorkItemFilters;
|
|
417
|
+
if (!wf) return { view: items.slice(), filters: filters };
|
|
418
|
+
return { view: wf.sort(wf.filter(items, filters), sort), filters: filters };
|
|
419
|
+
}
|
|
420
|
+
|
|
220
421
|
function renderWorkItems(items, opts) {
|
|
221
422
|
opts = opts || {};
|
|
222
423
|
items = items.filter(function(w) { return !isDeleted('wi:' + w.id); });
|
|
223
|
-
// Sort: active/dispatched first, then by most recent activity
|
|
224
|
-
const statusOrder = { dispatched: 0, pending: 1, queued: 1, failed: 2, done: 3 };
|
|
225
|
-
items.sort((a, b) => {
|
|
226
|
-
const sa = statusOrder[a.status] ?? 2, sb = statusOrder[b.status] ?? 2;
|
|
227
|
-
if (sa !== sb) return sa - sb;
|
|
228
|
-
const ta = a.completedAt || a.dispatched_at || a.created || '';
|
|
229
|
-
const tb = b.completedAt || b.dispatched_at || b.created || '';
|
|
230
|
-
return tb.localeCompare(ta); // most recent first
|
|
231
|
-
});
|
|
232
424
|
allWorkItems = items;
|
|
425
|
+
_syncWiFilterOptions(allWorkItems);
|
|
426
|
+
const computed = _computeWiView(allWorkItems);
|
|
427
|
+
const view = computed.view;
|
|
428
|
+
filteredWorkItems = view;
|
|
233
429
|
const el = document.getElementById('work-items-content');
|
|
234
430
|
const countEl = document.getElementById('wi-count');
|
|
235
|
-
|
|
236
|
-
if (
|
|
431
|
+
const summaryEl = document.getElementById('wi-filter-summary');
|
|
432
|
+
if (countEl) countEl.textContent = view.length;
|
|
433
|
+
if (summaryEl) {
|
|
434
|
+
summaryEl.textContent = _hasActiveWiFilters(computed.filters)
|
|
435
|
+
? 'Showing ' + view.length + ' of ' + allWorkItems.length
|
|
436
|
+
: '';
|
|
437
|
+
}
|
|
438
|
+
if (!allWorkItems.length) {
|
|
439
|
+
wiPage = 0;
|
|
237
440
|
el.innerHTML = '<p class="empty">No work items. Add tasks via Command Center above.</p>';
|
|
238
441
|
return;
|
|
239
442
|
}
|
|
443
|
+
if (!view.length) {
|
|
444
|
+
wiPage = 0;
|
|
445
|
+
el.innerHTML = '<p class="empty">No work items match the selected filters.</p>';
|
|
446
|
+
return;
|
|
447
|
+
}
|
|
240
448
|
|
|
241
|
-
const totalPages = Math.ceil(
|
|
449
|
+
const totalPages = Math.ceil(view.length / WI_PER_PAGE);
|
|
242
450
|
const previousPage = wiPage;
|
|
243
451
|
if (wiPage >= totalPages) wiPage = totalPages - 1;
|
|
244
452
|
const start = wiPage * WI_PER_PAGE;
|
|
245
|
-
const pageItems =
|
|
453
|
+
const pageItems = view.slice(start, start + WI_PER_PAGE);
|
|
246
454
|
|
|
247
|
-
let html = '<div class="pr-table-wrap"><table class="pr-table"><thead><tr><th>Title</th><th>Project</th><th>Type</th><th>Priority</th><th>Status</th><th>Agent</th><th>PR</th><th>Created</th><th></th><th></th></tr></thead><tbody>';
|
|
455
|
+
let html = '<div class="pr-table-wrap"><table class="pr-table"><thead><tr><th>Title</th><th>Project</th><th>Type</th><th>Priority</th><th>Status</th><th>Agent</th><th>PR</th><th>Created</th><th>Updated</th><th></th><th></th></tr></thead><tbody>';
|
|
248
456
|
html += pageItems.map(wiRow).join('');
|
|
249
457
|
html += '</tbody></table></div>';
|
|
250
458
|
|
|
251
|
-
if (
|
|
459
|
+
if (view.length > WI_PER_PAGE) {
|
|
252
460
|
html += '<div class="pr-pager">' +
|
|
253
|
-
'<span class="pr-page-info">Showing ' + (start+1) + ' to ' + Math.min(start+WI_PER_PAGE,
|
|
461
|
+
'<span class="pr-page-info">Showing ' + (start+1) + ' to ' + Math.min(start+WI_PER_PAGE, view.length) + ' of ' + view.length + '</span>' +
|
|
254
462
|
'<div class="pr-pager-btns">' +
|
|
255
463
|
'<button class="pr-pager-btn ' + (wiPage === 0 ? 'disabled' : '') + '" onclick="wiPrev()">Prev</button>' +
|
|
256
464
|
'<button class="pr-pager-btn ' + (wiPage >= totalPages-1 ? 'disabled' : '') + '" onclick="wiNext()">Next</button>' +
|
|
257
|
-
'<button class="pr-pager-btn see-all" onclick="openAllWorkItems()">See all ' +
|
|
465
|
+
'<button class="pr-pager-btn see-all" onclick="openAllWorkItems()">See all ' + view.length + '</button>' +
|
|
258
466
|
'</div>' +
|
|
259
467
|
'</div>';
|
|
260
468
|
}
|
|
@@ -517,7 +725,7 @@ async function retryWorkItem(id, source) {
|
|
|
517
725
|
}
|
|
518
726
|
|
|
519
727
|
function wiPrev() { if (wiPage > 0) { wiPage--; renderWorkItems(allWorkItems, { preserveScroll: false }); } }
|
|
520
|
-
function wiNext() { const tp = Math.ceil(
|
|
728
|
+
function wiNext() { const tp = Math.ceil(filteredWorkItems.length / WI_PER_PAGE); if (wiPage < tp-1) { wiPage++; renderWorkItems(allWorkItems, { preserveScroll: false }); } }
|
|
521
729
|
|
|
522
730
|
let _feedbackRating = null;
|
|
523
731
|
function feedbackWorkItem(id, source) {
|
|
@@ -676,7 +884,7 @@ async function _submitCreateWorkItem(e) {
|
|
|
676
884
|
}
|
|
677
885
|
|
|
678
886
|
// P-79b47b0c — Derive a canonical PR id (`<host>:<slug>#<number>`) from a
|
|
679
|
-
// GitHub or ADO PR URL. Matches the format produced by engine/queries.js
|
|
887
|
+
// GitHub or ADO PR URL. Matches the format produced by engine/core/queries.js
|
|
680
888
|
// when stamping pr.id. Returns null when the URL doesn't match a known
|
|
681
889
|
// host pattern.
|
|
682
890
|
function _wiDeriveCanonicalPrIdFromUrl(url) {
|
|
@@ -691,7 +899,7 @@ function _wiDeriveCanonicalPrIdFromUrl(url) {
|
|
|
691
899
|
// W-ms0ytfdd000d5a26 — provenance hint for the WI detail modal's Model field.
|
|
692
900
|
// Explains WHERE the shown model came from so an operator can tell a recorded
|
|
693
901
|
// fact from a projection. Mirrors the `source` values produced by
|
|
694
|
-
// engine/execution-model.js#resolveWorkItemModel.
|
|
902
|
+
// engine/core/execution-model.js#resolveWorkItemModel.
|
|
695
903
|
function _wiModelSourceHint(m) {
|
|
696
904
|
var runtime = m.runtime || 'runtime';
|
|
697
905
|
var hint;
|
|
@@ -766,7 +974,7 @@ function _wiRenderDetail(item) {
|
|
|
766
974
|
html += field('Description', '<div id="wi-detail-desc" style="font-size:var(--text-md);max-height:320px;overflow-y:auto;padding:8px 10px;background:var(--surface2);border:1px solid var(--border);border-radius:var(--radius-sm)">' + _descHtml + '</div>');
|
|
767
975
|
html += field('Agent', escapeHtml(item.dispatched_to || item.agent || 'Auto'));
|
|
768
976
|
// W-ms0ytfdd000d5a26 — the model this work item actually ran on. Resolved
|
|
769
|
-
// server-side (engine/queries.js#resolveWorkItemModelInfo) so persisted
|
|
977
|
+
// server-side (engine/core/queries.js#resolveWorkItemModelInfo) so persisted
|
|
770
978
|
// dispatch evidence — what the runtime reported, else what Minions requested
|
|
771
979
|
// — always beats current config. Items with no dispatch record show the
|
|
772
980
|
// projection from current config, marked as such. When nothing concrete is
|
|
@@ -795,8 +1003,8 @@ function _wiRenderDetail(item) {
|
|
|
795
1003
|
if (item.failReason) html += field('Failure Reason', '<span style="color:var(--red)">' + escapeHtml(item.failReason) + '</span>');
|
|
796
1004
|
// W-mrtdet41000h935a — surface the cancellation reason for CANCELLED items.
|
|
797
1005
|
// Cancellers stamp the reason on the record: POST /api/work-items/cancel and
|
|
798
|
-
// engine/dispatch.js/
|
|
799
|
-
// path (engine/lifecycle.js) writes `cancellationReason`. Prefer _cancelledBy,
|
|
1006
|
+
// engine/orchestration/dispatch.js and engine/watches/actions.js write `_cancelledBy`; the goal-invalidation
|
|
1007
|
+
// path (engine/orchestration/lifecycle.js) writes `cancellationReason`. Prefer _cancelledBy,
|
|
800
1008
|
// fall back to cancellationReason, then a no-reason marker. cancelledAt (ISO) is
|
|
801
1009
|
// rendered like the other timestamps when present. Reason text can carry
|
|
802
1010
|
// untrusted PR/branch content, so it is escaped.
|
|
@@ -885,7 +1093,7 @@ function _wiRenderDetail(item) {
|
|
|
885
1093
|
// P-c549d07e — "Spawned by" back-link chip. The schedule/pipeline that
|
|
886
1094
|
// dispatched this WI is the natural Back target from the WI modal. The
|
|
887
1095
|
// primary source is meta.spawnedBy ('schedule:<id>' | 'pipeline:<id>'),
|
|
888
|
-
// stamped by engine/scheduler.js + engine/pipeline.js on new dispatches.
|
|
1096
|
+
// stamped by engine/orchestration/scheduler.js + engine/orchestration/pipeline.js on new dispatches.
|
|
889
1097
|
// For older WIs already in state we fall back to (a) item._scheduleId
|
|
890
1098
|
// and (b) item.createdBy when it starts with 'pipeline:' so historical
|
|
891
1099
|
// items still light up the chip — purely additive, no behavior change.
|
|
@@ -925,7 +1133,7 @@ function _wiRenderDetail(item) {
|
|
|
925
1133
|
// named e.g. "src"). The genuine source-plan/PRD case is already fully
|
|
926
1134
|
// covered by arts.plan / arts.prd / arts.sourcePlan below, which are
|
|
927
1135
|
// populated server-side from the WI's real sourcePlan/_planFileName/
|
|
928
|
-
// planFile fields (engine/queries.js) — no separate item._source-based
|
|
1136
|
+
// planFile fields (engine/core/queries.js) — no separate item._source-based
|
|
929
1137
|
// chip is needed.
|
|
930
1138
|
var arts = item._artifacts || {};
|
|
931
1139
|
var artPills = '';
|
|
@@ -963,7 +1171,7 @@ function _wiRenderDetail(item) {
|
|
|
963
1171
|
|
|
964
1172
|
// P-34fa5d79 — Mentions: notes whose YAML frontmatter cites this WI
|
|
965
1173
|
// (work_item: / wi: / sourceItem:). Slim string[] field set by
|
|
966
|
-
// engine/queries.js#getWorkItems from _buildNotesByWiMap. Each entry is
|
|
1174
|
+
// engine/core/queries.js#getWorkItems from _buildNotesByWiMap. Each entry is
|
|
967
1175
|
// either a bare inbox filename or `archive:<filename>` for archive notes.
|
|
968
1176
|
//
|
|
969
1177
|
// #308 — repeated attempts for one WI used to render a flat pile of
|
|
@@ -1077,9 +1285,9 @@ function openWorkItemDetail(id, source) {
|
|
|
1077
1285
|
}
|
|
1078
1286
|
|
|
1079
1287
|
function openAllWorkItems() {
|
|
1080
|
-
document.getElementById('modal-title').textContent = 'All Work Items (' +
|
|
1081
|
-
const html = '<div class="pr-table-wrap"><table class="pr-table"><thead><tr><th>Title</th><th>Project</th><th>Type</th><th>Priority</th><th>Status</th><th>Agent</th><th>PR</th><th>Created</th><th></th><th></th></tr></thead><tbody>' +
|
|
1082
|
-
|
|
1288
|
+
document.getElementById('modal-title').textContent = 'All Work Items (' + filteredWorkItems.length + ')';
|
|
1289
|
+
const html = '<div class="pr-table-wrap"><table class="pr-table"><thead><tr><th>Title</th><th>Project</th><th>Type</th><th>Priority</th><th>Status</th><th>Agent</th><th>PR</th><th>Created</th><th>Updated</th><th></th><th></th></tr></thead><tbody>' +
|
|
1290
|
+
filteredWorkItems.map(wiRow).join('') + '</tbody></table></div>';
|
|
1083
1291
|
// eslint-disable-next-line no-unsanitized/property -- reason: structural HTML is a string literal; all user data wrapped in escapeHtml() by wiRow() (fields: work item id/title/source/status/agent/PR links/dates/follow-up metadata)
|
|
1084
1292
|
document.getElementById('modal-body').innerHTML = html;
|
|
1085
1293
|
document.getElementById('modal-body').style.fontFamily = "'Segoe UI', system-ui, sans-serif";
|
|
@@ -1206,7 +1414,7 @@ function _wiInjectSourceChipFromFrontmatter(content, containerId) {
|
|
|
1206
1414
|
}
|
|
1207
1415
|
|
|
1208
1416
|
if (typeof window !== 'undefined') {
|
|
1209
|
-
window.MinionsWork = { wiRow, renderWorkItems, editWorkItem, submitWorkItemEdit, deleteWorkItem, archiveWorkItem, toggleWorkItemArchive, retryWorkItem, wiPrev, wiNext, feedbackWorkItem, openCreateWorkItemModal, openWorkItemDetail, openAllWorkItems, viewAgentOutput, openInboxNote, needsAttentionInfo };
|
|
1417
|
+
window.MinionsWork = { wiRow, renderWorkItems, editWorkItem, submitWorkItemEdit, deleteWorkItem, archiveWorkItem, toggleWorkItemArchive, retryWorkItem, wiPrev, wiNext, feedbackWorkItem, openCreateWorkItemModal, openWorkItemDetail, openAllWorkItems, viewAgentOutput, openInboxNote, needsAttentionInfo, applyWiFilters, resetWiFilters, toggleWiSortDir };
|
|
1210
1418
|
}
|
|
1211
1419
|
// exported for testing — pure helpers safe to require under Node (no DOM deps).
|
|
1212
1420
|
if (typeof module !== 'undefined' && module.exports) {
|