@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
|
@@ -24,7 +24,7 @@ function renderProjects(projects) {
|
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
// Renders the per-project current-branch indicator. Driven by the gitState
|
|
27
|
-
// classifier emitted by getProjectGitStatus() in engine/queries.js.
|
|
27
|
+
// classifier emitted by getProjectGitStatus() in engine/core/queries.js.
|
|
28
28
|
// Adds a title attribute carrying the full branch name so users can still
|
|
29
29
|
// read it on hover after the CSS ellipsis-truncate (W-mpayac6d000b7d33).
|
|
30
30
|
//
|
|
@@ -78,7 +78,7 @@ function _renderProjectBranch(p) {
|
|
|
78
78
|
const detachedSuffix = p.gitDetached ? ' <span class="muted">(detached)</span>' : '';
|
|
79
79
|
// opg-microsoft/minions#664 — the counts are always vs origin/<comparator>
|
|
80
80
|
// (configured mainBranch, falling back to remoteDefaultBranch; see
|
|
81
|
-
// engine/queries.js _probeProjectGitStatus), never vs the checked-out
|
|
81
|
+
// engine/core/queries.js _probeProjectGitStatus), never vs the checked-out
|
|
82
82
|
// branch's own upstream. When branchDiffersFromMain the bare "↑N ↓M" chip
|
|
83
83
|
// reads as ambiguous (looks like it could be vs the current branch's
|
|
84
84
|
// tracking ref), so append the comparator name to the VISIBLE text too —
|
|
@@ -681,7 +681,7 @@ function renderLlmPerf(metrics) {
|
|
|
681
681
|
// Excludes:
|
|
682
682
|
// - 'agent-dispatch' (already counted in per-agent metrics[agentId] totals;
|
|
683
683
|
// summing both would double-count agent spend in the tile)
|
|
684
|
-
// - 'test-*' / '_test*' (matching engine/llm.js trackEngineUsage filter so
|
|
684
|
+
// - 'test-*' / '_test*' (matching engine/agents/llm.js trackEngineUsage filter so
|
|
685
685
|
// stale test categories don't inflate engineCalls)
|
|
686
686
|
function _aggregateEngineUsageForTokenTile(engine) {
|
|
687
687
|
let cost = 0, input = 0, output = 0, cache = 0, calls = 0;
|
|
@@ -881,3 +881,17 @@ async function _submitEditPipeline() {
|
|
|
881
881
|
}
|
|
882
882
|
|
|
883
883
|
window.MinionsPipelines = { renderPipelines, openPipelineDetail, openCreatePipelineModal, openEditPipelineModal };
|
|
884
|
+
|
|
885
|
+
// ── Slim "+ Add" deep-link (W-ms258yw0000ffd8a) ────────────────────────
|
|
886
|
+
// The Slim Automation tile's "+ Add" picker embeds this classic screen at
|
|
887
|
+
// /pipelines?embed=1#create and relies on this hook to auto-open the Create
|
|
888
|
+
// Pipeline dialog — the classic create flow is reused, not forked (CLAUDE.md
|
|
889
|
+
// slim-vs-classic). Fires only on the /pipelines path with a #create hash; the
|
|
890
|
+
// standalone classic screen and every other embed is otherwise untouched.
|
|
891
|
+
// No isReady predicate: unlike the schedule/watch forms this one has no
|
|
892
|
+
// cmdProjects/cmdAgents-backed selects, so it has nothing to wait for.
|
|
893
|
+
// Helper lives in utils.js#bootCreateDeepLink.
|
|
894
|
+
typeof bootCreateDeepLink === 'function' && bootCreateDeepLink({
|
|
895
|
+
route: '/pipelines',
|
|
896
|
+
resolve: function() { return typeof openCreatePipelineModal === 'function' ? openCreatePipelineModal : null; },
|
|
897
|
+
});
|
|
@@ -285,7 +285,11 @@ function renderPlans(plans) {
|
|
|
285
285
|
const archivedPlans = plans.filter(p => p.archived && p.format !== 'prd');
|
|
286
286
|
countEl.textContent = activePlans.length + (archivedPlans.length ? ' + ' + archivedPlans.length + ' archived' : '');
|
|
287
287
|
|
|
288
|
-
|
|
288
|
+
// Derive the plan's PRD linkage, archive flag, and canonical lifecycle
|
|
289
|
+
// status. Extracted so the Active/Completed grouping and the card renderer
|
|
290
|
+
// share one source of truth for "completed" (the derived lifecycle status),
|
|
291
|
+
// rather than matching on display text.
|
|
292
|
+
function computePlanStatusContext(p) {
|
|
289
293
|
const prdFile = planToPrdFile[p.file] || (p.file.endsWith('.json') ? p.file : '');
|
|
290
294
|
const isArchived = p.archived;
|
|
291
295
|
|
|
@@ -306,6 +310,11 @@ function renderPlans(plans) {
|
|
|
306
310
|
|
|
307
311
|
// Single source of truth: derive status from work items
|
|
308
312
|
const effectiveStatus = isArchived ? 'completed' : derivePlanStatus(prdFile, p.file, prdJsonStatus, allWi);
|
|
313
|
+
return { prdFile, isArchived, effectiveStatus };
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
function renderPlanCard(p, ctx) {
|
|
317
|
+
const { prdFile, isArchived, effectiveStatus } = ctx || computePlanStatusContext(p);
|
|
309
318
|
|
|
310
319
|
const statusLabelsMap = {
|
|
311
320
|
'completed': 'Completed', 'dispatched': 'In Progress', 'converting': 'Converting to PRD',
|
|
@@ -370,6 +379,19 @@ function renderPlans(plans) {
|
|
|
370
379
|
const deleteBtn = !isArchived ? '<button class="pr-pager-btn" style="font-size:var(--text-sm);padding:2px 8px;color:var(--red)" ' +
|
|
371
380
|
'onclick="event.stopPropagation();planDelete(\'' + escapeHtml(p.file) + '\')">Delete</button>' : '';
|
|
372
381
|
|
|
382
|
+
// Verify status badges stay inline in the meta line as informational
|
|
383
|
+
// status; the interactive action buttons move to a dedicated row below.
|
|
384
|
+
const verifyBadgesHtml = verifyWis.length >= 2
|
|
385
|
+
? verifyWis.map(v => _renderVerifyBadge(v, { projectLabel: v.project || '' })).join(' ')
|
|
386
|
+
: (hasVerifyWi ? _renderVerifyBadge(verifyWis[0]) : '');
|
|
387
|
+
const actionButtons = executeBtn + pauseBtn + resumeBtn + verifyBtn + archiveBtn + deleteBtn;
|
|
388
|
+
// Dedicated horizontal action row rendered immediately under the status
|
|
389
|
+
// (meta) line. Skipped entirely when a card has no buttons so empty rows
|
|
390
|
+
// never render.
|
|
391
|
+
const actionRow = actionButtons
|
|
392
|
+
? '<div class="plan-card-actions plan-card-action-row" onclick="event.stopPropagation()">' + actionButtons + '</div>'
|
|
393
|
+
: '';
|
|
394
|
+
|
|
373
395
|
const versionBadge = p.version ? ' <span style="font-size:var(--text-sm);font-weight:700;padding:1px 5px;border-radius:3px;background:rgba(56,139,253,0.15);color:var(--blue);vertical-align:middle">v' + p.version + '</span>' : '';
|
|
374
396
|
const statusColors = { 'completed': 'var(--green)', 'dispatched': 'var(--blue)', 'converting': 'var(--yellow)', 'paused': 'var(--muted)', 'awaiting-approval': 'var(--yellow)', 'approved': 'var(--purple,#a855f7)', 'rejected': 'var(--red)', 'has-failures': 'var(--red)', 'revision-requested': 'var(--purple,#a855f7)', 'active': 'var(--muted)', 'draft': 'var(--muted)' };
|
|
375
397
|
const cardClass = effectiveStatus === 'dispatched' || effectiveStatus === 'converting' ? 'working' : effectiveStatus === 'awaiting-approval' || effectiveStatus === 'paused' ? 'awaiting' : effectiveStatus;
|
|
@@ -414,25 +436,51 @@ function renderPlans(plans) {
|
|
|
414
436
|
(p.updatedAt ? '<span title="Last updated: ' + p.updatedAt + '">Updated ' + timeAgo(p.updatedAt) + '</span>' : '') +
|
|
415
437
|
(p.completedAt ? '<span>' + p.completedAt.slice(0, 10) + '</span>' : '') +
|
|
416
438
|
(p.generatedBy ? '<span>by ' + escapeHtml(p.generatedBy) + '</span>' : '') +
|
|
417
|
-
|
|
439
|
+
verifyBadgesHtml + archiveReadyBadge +
|
|
418
440
|
'</div>' +
|
|
441
|
+
actionRow +
|
|
419
442
|
'</div>' +
|
|
420
443
|
'</div>' +
|
|
421
444
|
actions +
|
|
422
445
|
'</div>';
|
|
423
446
|
}
|
|
424
447
|
|
|
425
|
-
|
|
448
|
+
// Group displayed plans into Active vs Completed using the canonical derived
|
|
449
|
+
// lifecycle status (computePlanStatusContext → derivePlanStatus), preserving
|
|
450
|
+
// the existing order within each group. The combined ordering is
|
|
451
|
+
// [active…, completed…]; pagination runs over that combined list so a single
|
|
452
|
+
// pager still bounds the page, and section headers are emitted where the
|
|
453
|
+
// group changes within the page.
|
|
454
|
+
const displayEntries = activePlans.map(p => {
|
|
455
|
+
const ctx = computePlanStatusContext(p);
|
|
456
|
+
return { plan: p, ctx, completed: ctx.effectiveStatus === 'completed' };
|
|
457
|
+
});
|
|
458
|
+
const orderedEntries = displayEntries.filter(e => !e.completed)
|
|
459
|
+
.concat(displayEntries.filter(e => e.completed));
|
|
460
|
+
|
|
461
|
+
const planSectionHeader = (group) =>
|
|
462
|
+
'<div class="plan-section-header">' + (group === 'completed' ? 'Completed Plans' : 'Active') + '</div>';
|
|
463
|
+
|
|
464
|
+
const totalPlanPages = Math.ceil(orderedEntries.length / PLANS_PER_PAGE);
|
|
426
465
|
if (_plansPage >= totalPlanPages) _plansPage = totalPlanPages - 1;
|
|
427
466
|
if (_plansPage < 0) _plansPage = 0;
|
|
428
467
|
const plansStart = _plansPage * PLANS_PER_PAGE;
|
|
429
|
-
const
|
|
430
|
-
|
|
431
|
-
let html =
|
|
468
|
+
const pageEntries = orderedEntries.slice(plansStart, plansStart + PLANS_PER_PAGE);
|
|
469
|
+
|
|
470
|
+
let html = '';
|
|
471
|
+
let lastGroup = null;
|
|
472
|
+
for (const entry of pageEntries) {
|
|
473
|
+
const group = entry.completed ? 'completed' : 'active';
|
|
474
|
+
if (group !== lastGroup) {
|
|
475
|
+
html += planSectionHeader(group);
|
|
476
|
+
lastGroup = group;
|
|
477
|
+
}
|
|
478
|
+
html += renderPlanCard(entry.plan, entry.ctx);
|
|
479
|
+
}
|
|
432
480
|
|
|
433
|
-
if (
|
|
481
|
+
if (orderedEntries.length > PLANS_PER_PAGE) {
|
|
434
482
|
html += '<div class="pr-pager">' +
|
|
435
|
-
'<span class="pr-page-info">' + (plansStart + 1) + '-' + Math.min(plansStart + PLANS_PER_PAGE,
|
|
483
|
+
'<span class="pr-page-info">' + (plansStart + 1) + '-' + Math.min(plansStart + PLANS_PER_PAGE, orderedEntries.length) + ' of ' + orderedEntries.length + '</span>' +
|
|
436
484
|
'<div class="pr-pager-btns">' +
|
|
437
485
|
'<button class="pr-pager-btn ' + (_plansPage === 0 ? 'disabled' : '') + '" onclick="_plansPrev()">Prev</button>' +
|
|
438
486
|
'<button class="pr-pager-btn ' + (_plansPage >= totalPlanPages - 1 ? 'disabled' : '') + '" onclick="_plansNext()">Next</button>' +
|
|
@@ -687,7 +735,7 @@ function _renderPlanModal(normalizedFile, raw, lastMod) {
|
|
|
687
735
|
modalActions += '<span style="' + bs + ';color:var(--blue)">In Progress</span> ';
|
|
688
736
|
}
|
|
689
737
|
// Verify / Verified badge — cross-repo plans fan out one verify WI per
|
|
690
|
-
// project (engine/lifecycle.js); collect them all and render one badge
|
|
738
|
+
// project (engine/orchestration/lifecycle.js); collect them all and render one badge
|
|
691
739
|
// per project so operators can see every repo's verify status.
|
|
692
740
|
const modalVerifyWis = (window._lastWorkItems || []).filter(w => w.itemType === 'verify' && w.sourcePlan === (prdFile || normalizedFile));
|
|
693
741
|
if (effectiveStatus === 'completed' && prdFile && !isArchived && modalVerifyWis.length === 0) {
|
|
@@ -63,6 +63,47 @@ async function _savePrdDesc(source, itemId) {
|
|
|
63
63
|
if (saveBtn) { saveBtn.disabled = false; saveBtn.textContent = 'Save'; }
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
+
// ── PRD item execution-state predicates — single source of truth ────────────
|
|
67
|
+
// engine/core/queries.js#getPrdInfo projects each PRD item's `status` from its
|
|
68
|
+
// materialized work item and maps `pending` -> `missing`, `dispatched` ->
|
|
69
|
+
// `in-progress`, defaulting a blank status to `missing`. So `missing` means the
|
|
70
|
+
// item has NOT STARTED — either no work item was ever materialized, or one
|
|
71
|
+
// exists and is still queued. It is materializability, never execution.
|
|
72
|
+
//
|
|
73
|
+
// Folding `missing` into "active" used to happen independently in the header,
|
|
74
|
+
// the group summary and the item detail modal, so an APPROVED PRD whose items
|
|
75
|
+
// were all `missing` (with zero pending/dispatched work items) rendered as
|
|
76
|
+
// `dispatched` / "In Progress". Every derivation below routes through these
|
|
77
|
+
// predicates so the three paths cannot drift apart again.
|
|
78
|
+
const PRD_ACTIVE_ITEM_STATUSES = ['in-progress'];
|
|
79
|
+
const PRD_NOT_STARTED_ITEM_STATUSES = ['missing'];
|
|
80
|
+
const PRD_ACTIVE_WORK_ITEM_STATUSES = ['pending', 'dispatched'];
|
|
81
|
+
|
|
82
|
+
// Canonical "this PRD item is executing right now".
|
|
83
|
+
function prdItemIsActive(item) {
|
|
84
|
+
return !!item && PRD_ACTIVE_ITEM_STATUSES.indexOf(item.status) !== -1;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Canonical "this PRD item has not started". A blank status counts: the server
|
|
88
|
+
// defaults it to `missing`, so an unset value carries the same meaning.
|
|
89
|
+
function prdItemIsNotStarted(item) {
|
|
90
|
+
if (!item) return false;
|
|
91
|
+
return !item.status || PRD_NOT_STARTED_ITEM_STATUSES.indexOf(item.status) !== -1;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Canonical "this materialized work item is live execution state".
|
|
95
|
+
function prdWorkItemIsActive(wi) {
|
|
96
|
+
return !!wi && PRD_ACTIVE_WORK_ITEM_STATUSES.indexOf(wi.status) !== -1;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// A PRD is "In Progress" only from canonical active state: a materialized work
|
|
100
|
+
// item in pending/dispatched, or an `in-progress` item projection (which also
|
|
101
|
+
// covers items whose work-item id differs from the PRD feature id and are
|
|
102
|
+
// therefore missed by the feature-id join the callers do).
|
|
103
|
+
function prdHasActiveExecution(items, workItems) {
|
|
104
|
+
return (workItems || []).some(prdWorkItemIsActive) || (items || []).some(prdItemIsActive);
|
|
105
|
+
}
|
|
106
|
+
|
|
66
107
|
function renderPrd(prd, prog) {
|
|
67
108
|
const section = document.getElementById('prd-content');
|
|
68
109
|
const badge = document.getElementById('prd-badge');
|
|
@@ -94,9 +135,9 @@ function renderPrd(prd, prog) {
|
|
|
94
135
|
// Single PRD — show status + actions in header
|
|
95
136
|
const implementItems = allWi.filter(w => prdItems.some(pi => pi.id === w.id));
|
|
96
137
|
const allDone = implementItems.length > 0 && implementItems.every(w => w.status === 'done');
|
|
97
|
-
// Unmaterialized PRD items (status === 'missing')
|
|
98
|
-
|
|
99
|
-
const hasActive =
|
|
138
|
+
// Unmaterialized PRD items (status === 'missing') are NOT started, so they
|
|
139
|
+
// never imply execution on their own — see prdHasActiveExecution above.
|
|
140
|
+
const hasActive = prdHasActiveExecution(prdItems, implementItems);
|
|
100
141
|
const prdFile = existing[0]?.file || '';
|
|
101
142
|
const prdStatus = existing[0]?.status || '';
|
|
102
143
|
const effectiveStatus = allDone && !hasActive ? 'completed' : hasActive ? 'dispatched' : prdStatus || 'active';
|
|
@@ -128,9 +169,9 @@ function renderPrd(prd, prog) {
|
|
|
128
169
|
const items = prdItems.filter(i => i.source === p.file);
|
|
129
170
|
const wiForPrd = allWi.filter(w => items.some(pi => pi.id === w.id));
|
|
130
171
|
const allDone = wiForPrd.length > 0 && wiForPrd.every(w => w.status === 'done');
|
|
131
|
-
// Unmaterialized PRD items (status === 'missing')
|
|
132
|
-
|
|
133
|
-
const hasActive =
|
|
172
|
+
// Unmaterialized PRD items (status === 'missing') are NOT started, so they
|
|
173
|
+
// never imply execution on their own — see prdHasActiveExecution above.
|
|
174
|
+
const hasActive = prdHasActiveExecution(items, wiForPrd);
|
|
134
175
|
const s = allDone && !hasActive ? 'completed' : hasActive ? 'dispatched' : p.status || 'active';
|
|
135
176
|
counts[s] = (counts[s] || 0) + 1;
|
|
136
177
|
}
|
|
@@ -195,11 +236,11 @@ function renderPrdProgress(prog) {
|
|
|
195
236
|
const total = items.length;
|
|
196
237
|
if (total === 0) return '';
|
|
197
238
|
const done = items.filter(i => i.status === 'done').length;
|
|
198
|
-
const inProgress = items.filter(
|
|
239
|
+
const inProgress = items.filter(prdItemIsActive).length;
|
|
199
240
|
const failed = items.filter(i => i.status === 'failed').length;
|
|
200
241
|
const paused = items.filter(i => i.status === 'paused').length;
|
|
201
242
|
const updated = items.filter(i => i.status === 'updated').length;
|
|
202
|
-
const missing = items.filter(
|
|
243
|
+
const missing = items.filter(prdItemIsNotStarted).length;
|
|
203
244
|
const pct = (n) => total > 0 ? ((n / total) * 100).toFixed(1) : 0;
|
|
204
245
|
|
|
205
246
|
const stats = '<div class="prd-stats" style="margin:0">' +
|
|
@@ -363,10 +404,17 @@ function renderPrdProgress(prog) {
|
|
|
363
404
|
};
|
|
364
405
|
|
|
365
406
|
const timings = prog.planTimings || {};
|
|
407
|
+
// W-msa0mrus00mh466f — server-derived PRD revision state (`none` |
|
|
408
|
+
// `in-progress` | `failed`). Derivation lives in
|
|
409
|
+
// engine/core/shared.js#derivePrdRevisionState; this renderer only paints it.
|
|
410
|
+
const revisions = prog.planRevisions || {};
|
|
366
411
|
|
|
367
412
|
const renderGroupHeader = (g) => {
|
|
368
413
|
const done = g.items.filter(i => i.status === 'done').length;
|
|
369
|
-
|
|
414
|
+
// `missing` is not-started, not work-in-progress: count it separately so the
|
|
415
|
+
// summary never advertises a not-yet-materialized item as "active".
|
|
416
|
+
const wip = g.items.filter(prdItemIsActive).length;
|
|
417
|
+
const notStarted = g.items.filter(prdItemIsNotStarted).length;
|
|
370
418
|
const summary = (g.summary || '').replace(/^Convert plan to PRD:\s*/i, '').slice(0, 80);
|
|
371
419
|
const isAwaitingApproval = g.planStatus === 'awaiting-approval';
|
|
372
420
|
const isPaused = g.planStatus === 'paused';
|
|
@@ -388,29 +436,61 @@ function renderPrdProgress(prog) {
|
|
|
388
436
|
: isPaused
|
|
389
437
|
? '<span style="color:var(--muted);font-weight:600;font-size:var(--text-sm);padding:1px 6px;border:1px solid var(--muted);border-radius:3px">PAUSED</span>'
|
|
390
438
|
: '';
|
|
391
|
-
const
|
|
439
|
+
const revision = revisions[g.file] || null;
|
|
440
|
+
const revisionActive = !!revision && revision.state === 'in-progress';
|
|
441
|
+
const revisionFailed = !!revision && revision.state === 'failed';
|
|
442
|
+
// A live revision owns this PRD: never render the generic stale recovery
|
|
443
|
+
// beside it or the user can launch a competing regenerate/resume path.
|
|
444
|
+
const showStale = (!isBlocked || isPaused) && g.planStale && !revisionActive && !revisionFailed;
|
|
392
445
|
const staleLabel = showStale
|
|
393
446
|
? '<span style="color:var(--orange);font-weight:700;font-size:var(--text-sm);padding:1px 6px;border:1px solid var(--orange);border-radius:3px;background:rgba(210,153,34,0.12)" title="Source plan changed after this PRD was generated">STALE</span>'
|
|
394
447
|
: '';
|
|
448
|
+
const revisionLabel = revisionActive
|
|
449
|
+
? '<span style="color:var(--blue);font-weight:700;font-size:var(--text-sm);padding:1px 6px;border:1px solid var(--blue);border-radius:3px;background:rgba(56,139,253,0.12)" title="A revision agent is rewriting this PRD">REVISING</span>'
|
|
450
|
+
: revisionFailed
|
|
451
|
+
? '<span style="color:var(--red);font-weight:700;font-size:var(--text-sm);padding:1px 6px;border:1px solid var(--red);border-radius:3px;background:rgba(248,81,73,0.12)" title="' + escHtml(revision.failReason || 'Revision did not complete') + '">REVISION FAILED</span>'
|
|
452
|
+
: '';
|
|
453
|
+
const revisionWiChip = (revision && revision.workItemId && typeof renderArtifactLink === 'function')
|
|
454
|
+
? renderArtifactLink({ type: 'wi', id: revision.workItemId, label: revision.workItemId, title: 'Revision work item' })
|
|
455
|
+
: (revision && revision.workItemId ? '<span class="prd-item-id">' + escHtml(revision.workItemId) + '</span>' : '');
|
|
456
|
+
const reviewPlanBtn = '<span onclick="event.stopPropagation();planView(\'' + escHtml(g.sourcePlan || g.file) + '\')" style="color:var(--blue);cursor:pointer;font-size:var(--text-sm);padding:2px 8px;background:rgba(56,139,253,0.1);border:1px solid rgba(56,139,253,0.3);border-radius:4px" title="Review latest plan changes">Review plan</span>';
|
|
457
|
+
const revisionRecovery = revisionActive
|
|
458
|
+
? '<div style="width:100%;margin-top:4px;padding:6px 8px;border:1px solid rgba(56,139,253,0.35);border-radius:4px;background:rgba(56,139,253,0.08);display:flex;align-items:center;gap:8px;flex-wrap:wrap">' +
|
|
459
|
+
'<span style="color:var(--blue);font-size:var(--text-sm);font-weight:600">🔄 Revision in progress. An agent is rewriting this PRD.</span>' +
|
|
460
|
+
revisionWiChip +
|
|
461
|
+
(revision.requestedBy ? '<span style="color:var(--muted);font-size:var(--text-sm)">requested by ' + escHtml(revision.requestedBy) + '</span>' : '') +
|
|
462
|
+
reviewPlanBtn +
|
|
463
|
+
'</div>'
|
|
464
|
+
: revisionFailed
|
|
465
|
+
? '<div style="width:100%;margin-top:4px;padding:6px 8px;border:1px solid rgba(248,81,73,0.35);border-radius:4px;background:rgba(248,81,73,0.08);display:flex;align-items:center;gap:8px;flex-wrap:wrap">' +
|
|
466
|
+
'<span style="color:var(--red);font-size:var(--text-sm);font-weight:600">⚠️ Revision failed: ' + escHtml(revision.failReason || 'the revision did not complete') + '</span>' +
|
|
467
|
+
revisionWiChip +
|
|
468
|
+
(revision.workItemId
|
|
469
|
+
? '<span onclick="event.stopPropagation();prdRetryRevision(\'' + escHtml(revision.workItemId) + '\')" style="color:var(--green);cursor:pointer;font-size:var(--text-sm);font-weight:700;padding:2px 8px;background:rgba(63,185,80,0.12);border:1px solid rgba(63,185,80,0.35);border-radius:4px" title="Requeue the revision work item">Retry revision</span>'
|
|
470
|
+
: '<span style="color:var(--muted);font-size:var(--text-sm)">Request a new revision from the Plans page.</span>') +
|
|
471
|
+
reviewPlanBtn +
|
|
472
|
+
'</div>'
|
|
473
|
+
: '';
|
|
395
474
|
const staleRecovery = showStale
|
|
396
475
|
? '<div style="width:100%;margin-top:4px;padding:6px 8px;border:1px solid rgba(210,153,34,0.35);border-radius:4px;background:rgba(210,153,34,0.08);display:flex;align-items:center;gap:8px;flex-wrap:wrap">' +
|
|
397
476
|
'<span style="color:var(--orange);font-size:var(--text-sm);font-weight:600">⚠️ Source plan was revised. This PRD may be outdated.</span>' +
|
|
398
477
|
'<span onclick="event.stopPropagation();prdRegenerate(\'' + escHtml(g.file) + '\')" style="color:var(--green);cursor:pointer;font-size:var(--text-sm);font-weight:700;padding:2px 8px;background:rgba(63,185,80,0.12);border:1px solid rgba(63,185,80,0.35);border-radius:4px" title="Compare revised plan against existing PRD and update items">Regenerate PRD</span>' +
|
|
399
478
|
'<span onclick="event.stopPropagation();prdResumeWithoutRegen(\'' + escHtml(g.file) + '\')" style="color:var(--muted);cursor:pointer;font-size:var(--text-sm);padding:2px 8px;background:var(--surface);border:1px solid var(--border);border-radius:4px" title="Resume without regenerating — use current PRD as-is">Resume as-is</span>' +
|
|
400
|
-
|
|
479
|
+
reviewPlanBtn +
|
|
401
480
|
'</div>'
|
|
402
481
|
: '';
|
|
403
482
|
const isCompleted = done > 0 && done === g.items.length;
|
|
404
|
-
// Hide regular action buttons when
|
|
405
|
-
|
|
406
|
-
const
|
|
483
|
+
// Hide regular action buttons when a recovery banner is showing — the banner
|
|
484
|
+
// owns the recovery actions for that state.
|
|
485
|
+
const suppressGroupActions = showStale || revisionActive || revisionFailed;
|
|
486
|
+
const pauseResumeBtn = suppressGroupActions ? '' : isAwaitingApproval
|
|
407
487
|
? '<span onclick="event.stopPropagation();planApprove(\'' + escHtml(g.file) + '\',this)" style="color:var(--green);cursor:pointer;font-size:var(--text-sm);padding:1px 6px;background:rgba(63,185,80,0.1);border:1px solid rgba(63,185,80,0.3);border-radius:3px">Approve</span>'
|
|
408
488
|
: isPaused
|
|
409
489
|
? '<span onclick="event.stopPropagation();planApprove(\'' + escHtml(g.file) + '\',this)" style="color:var(--green);cursor:pointer;font-size:var(--text-sm);padding:1px 6px;background:rgba(63,185,80,0.1);border:1px solid rgba(63,185,80,0.3);border-radius:3px">Resume</span>'
|
|
410
490
|
: isCompleted && !(window._lastWorkItems || []).some(w => w.itemType === 'verify' && w.sourcePlan === g.file)
|
|
411
491
|
? '<span onclick="event.stopPropagation();triggerVerify(\'' + escHtml(g.file) + '\',this)" style="color:var(--green);cursor:pointer;font-size:var(--text-sm);padding:1px 6px;background:rgba(63,185,80,0.1);border:1px solid rgba(63,185,80,0.3);border-radius:3px">Verify</span>'
|
|
412
492
|
: isCompleted ? '' : '<span onclick="event.stopPropagation();planPause(\'' + escHtml(g.file) + '\',this)" style="color:var(--yellow);cursor:pointer;font-size:var(--text-sm);padding:1px 6px;background:rgba(210,153,34,0.1);border:1px solid rgba(210,153,34,0.3);border-radius:3px">Pause</span>';
|
|
413
|
-
const archiveBtn = (!
|
|
493
|
+
const archiveBtn = (!suppressGroupActions && (isCompleted || isPaused)) ? '<span onclick="event.stopPropagation();planArchive(\'' + escHtml(g.file) + '\',this)" style="color:var(--muted);cursor:pointer;font-size:var(--text-sm);padding:1px 6px;background:rgba(139,148,158,0.1);border:1px solid rgba(139,148,158,0.3);border-radius:3px">Archive</span>' : '';
|
|
414
494
|
const deleteBtn = '<span onclick="event.stopPropagation();planDelete(\'' + escHtml(g.file) + '\')" style="color:var(--red);cursor:pointer;font-size:var(--text-sm);padding:1px 6px;background:rgba(248,81,73,0.1);border:1px solid rgba(248,81,73,0.3);border-radius:3px">Delete</span>';
|
|
415
495
|
const sourcePlanLink = g.sourcePlan
|
|
416
496
|
? '<span onclick="event.stopPropagation();planView(\'' + escHtml(g.sourcePlan) + '\')" style="color:var(--blue);cursor:pointer;font-size:var(--text-sm);padding:1px 6px;background:rgba(56,139,253,0.1);border:1px solid rgba(56,139,253,0.3);border-radius:3px" title="View source plan">📄 Plan</span>'
|
|
@@ -424,9 +504,10 @@ function renderPrdProgress(prog) {
|
|
|
424
504
|
: '<span style="font-size:var(--text-sm);padding:1px 5px;border-radius:3px;background:rgba(56,139,253,0.12);color:var(--blue);font-weight:400" title="Each item gets its own branch (work/P-xxx) and PR">🔀 parallel branches</span>') +
|
|
425
505
|
pausedLabel +
|
|
426
506
|
staleLabel +
|
|
507
|
+
revisionLabel +
|
|
427
508
|
'<span style="font-weight:700;font-size:var(--text-base);color:' + (done === g.items.length && g.items.length > 0 ? 'var(--green)' : 'var(--text)') + '">' + (g.items.length > 0 ? Math.round((done / g.items.length) * 100) : 0) + '%</span>' +
|
|
428
509
|
'<span style="color:var(--muted);font-weight:400;font-size:var(--text-sm)">' + g.items.length + ' items' +
|
|
429
|
-
(done ? ' · ' + done + ' done' : '') + (wip ? ' · ' + wip + ' active' : '') +
|
|
510
|
+
(done ? ' · ' + done + ' done' : '') + (wip ? ' · ' + wip + ' active' : '') + (notStarted ? ' · ' + notStarted + ' to do' : '') +
|
|
430
511
|
'</span>' +
|
|
431
512
|
(g.prdUpdatedAt ? '<span style="color:var(--muted);font-weight:400;font-size:var(--text-sm)" title="PRD last updated: ' + g.prdUpdatedAt + '">PRD updated ' + timeAgo(g.prdUpdatedAt) + '</span>' : '') +
|
|
432
513
|
runtimeLabel +
|
|
@@ -443,6 +524,7 @@ function renderPrdProgress(prog) {
|
|
|
443
524
|
deleteBtn +
|
|
444
525
|
'</span>') +
|
|
445
526
|
staleRecovery +
|
|
527
|
+
revisionRecovery +
|
|
446
528
|
'</div>';
|
|
447
529
|
};
|
|
448
530
|
|
|
@@ -844,9 +926,14 @@ async function prdItemEdit(source, itemId) {
|
|
|
844
926
|
let completionHtml = '';
|
|
845
927
|
const isDone = item.status === 'done';
|
|
846
928
|
const isFailed = item.status === 'failed';
|
|
847
|
-
const isActive = item
|
|
848
|
-
|
|
849
|
-
|
|
929
|
+
const isActive = prdItemIsActive(item);
|
|
930
|
+
// `missing` is the server's projection for "not materialized, or materialized
|
|
931
|
+
// but still queued" — it must render as its truthful not-started state, never
|
|
932
|
+
// as an In Progress completion panel.
|
|
933
|
+
const isNotStarted = prdItemIsNotStarted(item);
|
|
934
|
+
const isQueued = isNotStarted && prdWorkItemIsActive(wi);
|
|
935
|
+
|
|
936
|
+
if (isDone || isFailed || isActive || isNotStarted) {
|
|
850
937
|
const agent = wi?.dispatched_to || completedEntry?.agent || '';
|
|
851
938
|
const completedAt = wi?.completedAt || completedEntry?.completed_at || '';
|
|
852
939
|
const summary = completedEntry?.resultSummary || '';
|
|
@@ -857,8 +944,8 @@ async function prdItemEdit(source, itemId) {
|
|
|
857
944
|
: '<code>' + escHtml(pr.id) + '</code>';
|
|
858
945
|
}).join(', ');
|
|
859
946
|
|
|
860
|
-
const statusColor = isDone ? 'var(--green)' : isFailed ? 'var(--red)' : 'var(--blue)';
|
|
861
|
-
const statusLabel = isDone ? 'Completed' : isFailed ? 'Failed' : 'In Progress';
|
|
947
|
+
const statusColor = isDone ? 'var(--green)' : isFailed ? 'var(--red)' : isActive ? 'var(--blue)' : 'var(--muted)';
|
|
948
|
+
const statusLabel = isDone ? 'Completed' : isFailed ? 'Failed' : isActive ? 'In Progress' : isQueued ? 'Queued' : 'Not started';
|
|
862
949
|
|
|
863
950
|
completionHtml = '<div style="background:var(--surface);border:1px solid var(--border);border-left:3px solid ' + statusColor + ';border-radius:4px;padding:10px 12px;margin-bottom:12px">' +
|
|
864
951
|
'<div style="display:flex;align-items:center;gap:8px;margin-bottom:6px">' +
|
|
@@ -1034,6 +1121,28 @@ function prdResumeWithoutRegen(prdFile) {
|
|
|
1034
1121
|
'Plan resumed (PRD unchanged)');
|
|
1035
1122
|
}
|
|
1036
1123
|
|
|
1124
|
+
// W-msa0mrus00mh466f — recovery for a failed revision: requeue the SAME
|
|
1125
|
+
// revision work item rather than enqueuing a competing operation.
|
|
1126
|
+
async function prdRetryRevision(workItemId) {
|
|
1127
|
+
if (!workItemId) return;
|
|
1128
|
+
try {
|
|
1129
|
+
const res = await fetch('/api/work-items/retry', {
|
|
1130
|
+
method: 'POST', headers: { 'Content-Type': 'application/json' },
|
|
1131
|
+
body: JSON.stringify({ id: workItemId })
|
|
1132
|
+
});
|
|
1133
|
+
if (res.ok) {
|
|
1134
|
+
showToast('cmd-toast', 'Revision ' + workItemId + ' requeued', true);
|
|
1135
|
+
if (typeof wakeEngine === 'function') wakeEngine();
|
|
1136
|
+
if (typeof refresh === 'function') refresh();
|
|
1137
|
+
} else {
|
|
1138
|
+
const d = await res.json().catch(() => ({}));
|
|
1139
|
+
showToast('cmd-toast', 'Retry failed: ' + (d.error || 'unknown'), false);
|
|
1140
|
+
}
|
|
1141
|
+
} catch (e) {
|
|
1142
|
+
showToast('cmd-toast', 'Error: ' + e.message, false);
|
|
1143
|
+
}
|
|
1144
|
+
}
|
|
1145
|
+
|
|
1037
1146
|
function openArchive(i) {
|
|
1038
1147
|
const a = archivedPrds[i];
|
|
1039
1148
|
if (!a) return;
|
|
@@ -1109,7 +1218,7 @@ function openArchive(i) {
|
|
|
1109
1218
|
|
|
1110
1219
|
// "QA this PRD" — one-shot bridge from a completed/approved PRD card to a QA
|
|
1111
1220
|
// Session. POSTs the PRD file to /api/qa/from-prd (P-b3e9d4a1), which builds the
|
|
1112
|
-
// spec via engine/qa
|
|
1221
|
+
// spec via engine/qa/from-prd.js then reuses createSession + queueSetup. On
|
|
1113
1222
|
// success we navigate to the QA Sessions page so the operator can watch it run;
|
|
1114
1223
|
// the endpoint returns a clean 400 (never 500) for any unusable PRD, surfaced
|
|
1115
1224
|
// here as a toast. Mirrors triggerVerify's button-state + error handling.
|
|
@@ -1136,4 +1245,4 @@ async function qaThisPrd(file, btn) {
|
|
|
1136
1245
|
}
|
|
1137
1246
|
}
|
|
1138
1247
|
|
|
1139
|
-
window.MinionsPrd = { renderPrd, renderPrdProgress, openArchivedPrdModal, showArchivedPrdDetail, prdItemEdit, prdItemSave, prdItemRemove, prdItemRequeue, prdItemReopen, prdRegenerate, openArchive, qaThisPrd, _togglePrdDescEdit, _cancelPrdDescEdit, _savePrdDesc };
|
|
1248
|
+
window.MinionsPrd = { renderPrd, renderPrdProgress, openArchivedPrdModal, showArchivedPrdDetail, prdItemEdit, prdItemSave, prdItemRemove, prdItemRequeue, prdItemReopen, prdRegenerate, prdRetryRevision, openArchive, qaThisPrd, _togglePrdDescEdit, _cancelPrdDescEdit, _savePrdDesc };
|