@yemi33/minions 0.1.2447 → 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 +66 -7
- package/dashboard/js/detail-panel.js +36 -0
- package/dashboard/js/memory-panel.js +59 -12
- package/dashboard/js/qa.js +186 -45
- 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 +52 -6
- 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
|
@@ -1,26 +1,26 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* engine/lifecycle.js — Post-completion hooks, PR sync, agent history/metrics, plan chaining.
|
|
2
|
+
* engine/orchestration/lifecycle.js — Post-completion hooks, PR sync, agent history/metrics, plan chaining.
|
|
3
3
|
* Extracted from engine.js.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
const fs = require('fs');
|
|
7
7
|
const path = require('path');
|
|
8
8
|
const os = require('os');
|
|
9
|
-
const shared = require('
|
|
9
|
+
const shared = require('../core/shared');
|
|
10
10
|
const { safeRead, safeJson, safeJsonArr, safeJsonNoRestore, safeWrite, mutateJsonFileLocked, mutateWorkItems, execAsync, getPrLinks,
|
|
11
11
|
log, ts, dateStamp, WI_STATUS, DONE_STATUSES, PLAN_TERMINAL_STATUSES, WORK_TYPE, PLAN_STATUS, PRD_ITEM_STATUS, PRD_MATERIALIZABLE, PR_STATUS, REVIEW_STATUS, RETRY_DELAY_MS, DISPATCH_RESULT,
|
|
12
12
|
ENGINE_DEFAULTS, DEFAULT_AGENT_METRICS, FAILURE_CLASS } = shared;
|
|
13
|
-
const { resolveRuntime, hasUnfinishedToolCall } = require('
|
|
14
|
-
const adoGitAuth = require('
|
|
15
|
-
const queries = require('
|
|
16
|
-
const harness = require('
|
|
17
|
-
const reviewLearning = require('
|
|
18
|
-
const smallStateStore = require('
|
|
19
|
-
const prdStore = require('
|
|
20
|
-
const memoryStore = require('
|
|
21
|
-
const promotion = require('
|
|
13
|
+
const { resolveRuntime, hasUnfinishedToolCall } = require('../runtimes');
|
|
14
|
+
const adoGitAuth = require('../ado/git-auth');
|
|
15
|
+
const queries = require('../core/queries');
|
|
16
|
+
const harness = require('../agents/harness');
|
|
17
|
+
const reviewLearning = require('../memory/review-learning');
|
|
18
|
+
const smallStateStore = require('../persistence/small-state-store');
|
|
19
|
+
const prdStore = require('../planning/prd-store');
|
|
20
|
+
const memoryStore = require('../memory/memory-store');
|
|
21
|
+
const promotion = require('../memory/promotion');
|
|
22
22
|
const { isBranchActive } = require('./cooldown');
|
|
23
|
-
const { resolveExecutionModel } = require('
|
|
23
|
+
const { resolveExecutionModel } = require('../core/execution-model');
|
|
24
24
|
const { worktreeMatchesBranch, getWorktreeBranch, cleanupMergedPrLocalBranch } = require('./cleanup');
|
|
25
25
|
const { getConfig, getInboxFiles, getNotes, getPrs, getDispatch,
|
|
26
26
|
MINIONS_DIR, ENGINE_DIR, PLANS_DIR, INBOX_DIR, AGENTS_DIR } = queries;
|
|
@@ -356,7 +356,7 @@ function checkPlanCompletion(meta, config) {
|
|
|
356
356
|
// a crafted `plan.feature_branch` (e.g. `main; rm -rf ~`) or PR
|
|
357
357
|
// `branch` field reaches the Bash tool via template literal
|
|
358
358
|
// interpolation. github.js validates pr.branch on API persistence
|
|
359
|
-
// (engine/github.js:612-622), but feature_branch has no upstream
|
|
359
|
+
// (engine/providers/github.js:612-622), but feature_branch has no upstream
|
|
360
360
|
// validator and mainBranch can fall through unvalidated from project
|
|
361
361
|
// config when `git rev-parse` can't verify it (shared.js:1328). Defense
|
|
362
362
|
// in depth lives here, at the actual interpolation site.
|
|
@@ -728,6 +728,8 @@ function updateWorkItemStatus(meta, status, reason) {
|
|
|
728
728
|
delete target.failReason;
|
|
729
729
|
delete target.failedAt;
|
|
730
730
|
delete target._retryCount;
|
|
731
|
+
delete target._infrastructureRetryCount;
|
|
732
|
+
delete target._lastInfrastructureFailureClass;
|
|
731
733
|
delete target._retriesByAgent;
|
|
732
734
|
target.completedAgents = Object.entries(target.agentResults)
|
|
733
735
|
.filter(([, r]) => r.status === WI_STATUS.DONE)
|
|
@@ -745,6 +747,8 @@ function updateWorkItemStatus(meta, status, reason) {
|
|
|
745
747
|
delete target.failReason;
|
|
746
748
|
delete target.failedAt;
|
|
747
749
|
delete target._retryCount;
|
|
750
|
+
delete target._infrastructureRetryCount;
|
|
751
|
+
delete target._lastInfrastructureFailureClass;
|
|
748
752
|
delete target._retriesByAgent;
|
|
749
753
|
// P-e0b4f7a5 — successful completion (including a phantom-retry
|
|
750
754
|
// succeeding) clears the phantom markers so cleanup can reap the
|
|
@@ -1195,12 +1199,12 @@ function syncPrsFromOutput(output, agentId, meta, config, opts = {}) {
|
|
|
1195
1199
|
log('warn', `Duplicate PR detected: ${fullId} on branch ${entry.branch || entryBranch} — already tracked as ${duplicateOnBranch.id}. Skipping.`);
|
|
1196
1200
|
// Best-effort close the duplicate on GitHub (non-blocking, fire-and-forget).
|
|
1197
1201
|
// The closing comment is wrapped with the minions marker so the PR-comment
|
|
1198
|
-
// classifier (engine/github.js _isMinionsAuthoredComment, sub-task -b)
|
|
1202
|
+
// classifier (engine/providers/github.js _isMinionsAuthoredComment, sub-task -b)
|
|
1199
1203
|
// recognizes it as engine-authored and never queues a fix-dispatch on it.
|
|
1200
1204
|
try {
|
|
1201
1205
|
const ghSlug = outputText.match(/github\.com\/([^/]+\/[^/]+)/)?.[1];
|
|
1202
1206
|
if (ghSlug) {
|
|
1203
|
-
const { buildMinionsCommentBody } = require('
|
|
1207
|
+
const { buildMinionsCommentBody } = require('../providers/gh-comment');
|
|
1204
1208
|
const dupComment = buildMinionsCommentBody({
|
|
1205
1209
|
agentId: 'engine',
|
|
1206
1210
|
kind: 'positive-signal',
|
|
@@ -1261,7 +1265,7 @@ async function _fetchGitHubPrStateForEnrollment(slug, prNumber) {
|
|
|
1261
1265
|
}
|
|
1262
1266
|
let token = null;
|
|
1263
1267
|
try {
|
|
1264
|
-
const ghToken = require('
|
|
1268
|
+
const ghToken = require('../providers/gh-token');
|
|
1265
1269
|
if (typeof ghToken.resolveTokenForSlug === 'function') {
|
|
1266
1270
|
token = ghToken.resolveTokenForSlug(slug);
|
|
1267
1271
|
}
|
|
@@ -1291,7 +1295,7 @@ function _liveGitHubStateToPrStatus(liveState) {
|
|
|
1291
1295
|
|
|
1292
1296
|
function _existingPrRecordForCanonicalId(canonicalPrId) {
|
|
1293
1297
|
try {
|
|
1294
|
-
const store = require('
|
|
1298
|
+
const store = require('../persistence/pull-requests-store');
|
|
1295
1299
|
if (typeof store.readAllPullRequests !== 'function') return null;
|
|
1296
1300
|
const all = store.readAllPullRequests() || [];
|
|
1297
1301
|
return all.find(pr => pr && pr.id === canonicalPrId) || null;
|
|
@@ -1398,7 +1402,7 @@ async function enrollPrFromCanonicalId(canonicalPrId, project, opts = {}) {
|
|
|
1398
1402
|
try {
|
|
1399
1403
|
const adoParts = scope.slice('ado:'.length).split('/');
|
|
1400
1404
|
if (adoParts.length === 3) {
|
|
1401
|
-
const ado = require('
|
|
1405
|
+
const ado = require('../ado');
|
|
1402
1406
|
if (typeof ado.fetchAdoPrMetadata === 'function') {
|
|
1403
1407
|
const meta = await ado.fetchAdoPrMetadata(prNumber, adoParts[0], adoParts[1], adoParts[2], project);
|
|
1404
1408
|
if (meta) {
|
|
@@ -1501,7 +1505,7 @@ function stampWiPrRef(meta, config) {
|
|
|
1501
1505
|
const projects = (config && Array.isArray(config.projects))
|
|
1502
1506
|
? config.projects : shared.getProjects(config || {});
|
|
1503
1507
|
|
|
1504
|
-
const prStore = require('
|
|
1508
|
+
const prStore = require('../persistence/pull-requests-store');
|
|
1505
1509
|
const allPrs = prStore.readAllPullRequests();
|
|
1506
1510
|
let found = allPrs.find(r => Array.isArray(r.prdItems) && r.prdItems.includes(itemId)) || null;
|
|
1507
1511
|
|
|
@@ -1646,10 +1650,12 @@ function runFileCapture(file, args, opts = {}) {
|
|
|
1646
1650
|
const timer = timeout ? setTimeout(() => {
|
|
1647
1651
|
timedOut = true;
|
|
1648
1652
|
if (!child) return;
|
|
1649
|
-
shared.
|
|
1653
|
+
shared.terminateProcess('engine.lifecycle.hook-timeout-graceful', child, {
|
|
1654
|
+
graceMs: 1000,
|
|
1655
|
+
});
|
|
1650
1656
|
// Hard-kill fallback if the child ignores SIGTERM. Cleared on close.
|
|
1651
1657
|
hardKillTimer = setTimeout(() => {
|
|
1652
|
-
try { shared.
|
|
1658
|
+
try { shared.terminateProcess('engine.lifecycle.hook-timeout-force', child); } catch {}
|
|
1653
1659
|
}, 2500);
|
|
1654
1660
|
}, timeout) : null;
|
|
1655
1661
|
try {
|
|
@@ -1662,14 +1668,20 @@ function runFileCapture(file, args, opts = {}) {
|
|
|
1662
1668
|
child.stderr?.setEncoding('utf8');
|
|
1663
1669
|
child.stdout?.on('data', chunk => {
|
|
1664
1670
|
if (stdout.length + chunk.length > MAX_BUFFER) {
|
|
1665
|
-
if (!killedForBuffer) {
|
|
1671
|
+
if (!killedForBuffer) {
|
|
1672
|
+
killedForBuffer = true;
|
|
1673
|
+
try { shared.terminateProcess('engine.lifecycle.hook-buffer-limit', child); } catch {}
|
|
1674
|
+
}
|
|
1666
1675
|
return;
|
|
1667
1676
|
}
|
|
1668
1677
|
stdout += chunk;
|
|
1669
1678
|
});
|
|
1670
1679
|
child.stderr?.on('data', chunk => {
|
|
1671
1680
|
if (stderr.length + chunk.length > MAX_BUFFER) {
|
|
1672
|
-
if (!killedForBuffer) {
|
|
1681
|
+
if (!killedForBuffer) {
|
|
1682
|
+
killedForBuffer = true;
|
|
1683
|
+
try { shared.terminateProcess('engine.lifecycle.hook-buffer-limit', child); } catch {}
|
|
1684
|
+
}
|
|
1673
1685
|
return;
|
|
1674
1686
|
}
|
|
1675
1687
|
stderr += chunk;
|
|
@@ -1747,7 +1759,7 @@ async function findOpenPrForBranch(meta, config) {
|
|
|
1747
1759
|
return null;
|
|
1748
1760
|
}
|
|
1749
1761
|
if (host === 'ado') {
|
|
1750
|
-
const found = await require('
|
|
1762
|
+
const found = await require('../ado').findOpenPrOnBranch(projectObj, meta.branch);
|
|
1751
1763
|
return found ? { project: projectObj, prNumber: found.prNumber, url: found.url } : null;
|
|
1752
1764
|
}
|
|
1753
1765
|
log('debug', `Skipping branch PR lookup for unsupported repo host "${host}" on ${projectObj.name}`);
|
|
@@ -2368,8 +2380,8 @@ async function updatePrAfterReview(agentId, pr, project, config, resultSummary,
|
|
|
2368
2380
|
: null;
|
|
2369
2381
|
const hostForChecks = hostFromCanonical || projectObjForChecks?.repoHost || null;
|
|
2370
2382
|
let checkFn = null;
|
|
2371
|
-
if (hostForChecks === 'github') checkFn = require('
|
|
2372
|
-
else if (hostForChecks === 'ado') checkFn = require('
|
|
2383
|
+
if (hostForChecks === 'github') checkFn = require('../providers/github').checkLiveReviewStatus;
|
|
2384
|
+
else if (hostForChecks === 'ado') checkFn = require('../ado').checkLiveReviewStatus;
|
|
2373
2385
|
else log('warn', `Cannot resolve repoHost for review of ${reviewPr.id} (unparseable canonical id and no project config); skipping live review check.`);
|
|
2374
2386
|
try {
|
|
2375
2387
|
if (projectObjForChecks && checkFn) {
|
|
@@ -2410,9 +2422,9 @@ async function updatePrAfterReview(agentId, pr, project, config, resultSummary,
|
|
|
2410
2422
|
if (canDismissOwnPriorNegative) {
|
|
2411
2423
|
try {
|
|
2412
2424
|
const reconcileFn = hostForChecks === 'github'
|
|
2413
|
-
? require('
|
|
2425
|
+
? require('../providers/github').dismissPriorViewerChangesRequestedReviews
|
|
2414
2426
|
: hostForChecks === 'ado'
|
|
2415
|
-
? require('
|
|
2427
|
+
? require('../ado').resetReviewerNegativeVote
|
|
2416
2428
|
: null;
|
|
2417
2429
|
if (typeof reconcileFn === 'function') {
|
|
2418
2430
|
const result = await reconcileFn(reviewPr, projectObjForChecks);
|
|
@@ -2584,15 +2596,19 @@ async function updatePrAfterReview(agentId, pr, project, config, resultSummary,
|
|
|
2584
2596
|
|
|
2585
2597
|
log('info', `Updated ${reviewPr.id} → minions review: ${postReviewStatus || REVIEW_STATUS.WAITING} by ${reviewerName}`);
|
|
2586
2598
|
if (updatedTarget) {
|
|
2587
|
-
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2599
|
+
try {
|
|
2600
|
+
createReviewFeedbackForAuthor(agentId, updatedTarget, config, {
|
|
2601
|
+
reviewContent: reviewNote,
|
|
2602
|
+
project: reviewProject,
|
|
2603
|
+
dispatchId: dispatchItem?.id || structuredCompletion?.dispatchId || null,
|
|
2604
|
+
sourceItem: dispatchItem?.meta?.item?.id || null,
|
|
2605
|
+
postReviewStatus,
|
|
2606
|
+
reviewVerdict: verdictRaw,
|
|
2607
|
+
findingIdentity: shared.prReviewFindingIdentity(updatedTarget),
|
|
2608
|
+
});
|
|
2609
|
+
} catch (err) {
|
|
2610
|
+
log('warn', `Review-learning candidate capture failed for ${reviewPr.id}: ${err.message}`);
|
|
2611
|
+
}
|
|
2596
2612
|
}
|
|
2597
2613
|
}
|
|
2598
2614
|
|
|
@@ -2715,13 +2731,13 @@ async function detectPrFixBranchChange(meta, config) {
|
|
|
2715
2731
|
}
|
|
2716
2732
|
|
|
2717
2733
|
// #639 — lazy requires for the host-specific live build/conflict checkers.
|
|
2718
|
-
// engine/github.js and engine/ado.js both lazy-require lifecycle.js (see
|
|
2734
|
+
// engine/providers/github.js and engine/ado/index.js both lazy-require lifecycle.js (see
|
|
2719
2735
|
// their `lifecycleModule()` helpers), so a top-level require here would form
|
|
2720
2736
|
// an import cycle. Deferring to first call avoids that.
|
|
2721
2737
|
let _githubPrModule = null;
|
|
2722
|
-
function githubPrModule() { if (!_githubPrModule) _githubPrModule = require('
|
|
2738
|
+
function githubPrModule() { if (!_githubPrModule) _githubPrModule = require('../providers/github'); return _githubPrModule; }
|
|
2723
2739
|
let _adoPrModule = null;
|
|
2724
|
-
function adoPrModule() { if (!_adoPrModule) _adoPrModule = require('
|
|
2740
|
+
function adoPrModule() { if (!_adoPrModule) _adoPrModule = require('../ado'); return _adoPrModule; }
|
|
2725
2741
|
|
|
2726
2742
|
// #639 — No-op fix detection previously only proved whether the agent pushed
|
|
2727
2743
|
// a NEW commit; it never checked whether the build the fix was dispatched
|
|
@@ -3113,7 +3129,7 @@ function clearPrNoOpFixAttempt(target, cause) {
|
|
|
3113
3129
|
}
|
|
3114
3130
|
|
|
3115
3131
|
// W-mpx44p05000ze8d8 — Proactive GC for stale `_noOpFixes` records. Called
|
|
3116
|
-
// from `engine/ado.js` + `engine/github.js` `pollPrStatus` after the live PR
|
|
3132
|
+
// from `engine/ado/index.js` + `engine/providers/github.js` `pollPrStatus` after the live PR
|
|
3117
3133
|
// fields (headSha, buildStatus, humanFeedback, mergeStatus, reviewStatus,
|
|
3118
3134
|
// lastPushedAt, etc.) have been refreshed for the current tick. Any
|
|
3119
3135
|
// `_noOpFixes[cause]` whose stored `evidenceFingerprint` no longer matches
|
|
@@ -3604,7 +3620,7 @@ async function handlePostMerge(pr, project, config, newStatus) {
|
|
|
3604
3620
|
|
|
3605
3621
|
// `project.localPath` guard: central/observed PRs (e.g. ADO PRs tracked in
|
|
3606
3622
|
// central PRs with no configured project are polled via a
|
|
3607
|
-
// *synthesized* project that has no localPath (engine/ado.js + engine/github.js
|
|
3623
|
+
// *synthesized* project that has no localPath (engine/ado/index.js + engine/providers/github.js
|
|
3608
3624
|
// central-poll loops). There is no checkout to clean for those, and an
|
|
3609
3625
|
// unguarded path.resolve(undefined) here threw "paths[0] argument must be of
|
|
3610
3626
|
// type string" — caught upstream and logged as "failed to poll central PR".
|
|
@@ -3876,7 +3892,7 @@ function extractSkillsFromOutput(output, agentId, dispatchItem, config, runtimeN
|
|
|
3876
3892
|
const ccContent = `---\nname: ${name}\ndescription: ${description}\n---\n\n${marker}\n\n${body.trim()}\n`;
|
|
3877
3893
|
if (!fs.existsSync(skillDir)) fs.mkdirSync(skillDir, { recursive: true });
|
|
3878
3894
|
shared.safeWrite(skillPath, ccContent);
|
|
3879
|
-
try { require('
|
|
3895
|
+
try { require('../core/queries').invalidateSkillsCache(); } catch {}
|
|
3880
3896
|
log('info', `Extracted skill "${name}" from ${agentName} → ${skillPath}`);
|
|
3881
3897
|
|
|
3882
3898
|
}
|
|
@@ -5194,7 +5210,7 @@ function detectNonTerminalResultSummary(_resultSummary, structuredCompletion, co
|
|
|
5194
5210
|
// the PR-attachment contract hard-fails them with no retry.
|
|
5195
5211
|
//
|
|
5196
5212
|
// Only enabled at call sites where there is no other success signal (e.g.
|
|
5197
|
-
// engine/timeout.js completeFromOutput). runPostCompletionHooks has richer
|
|
5213
|
+
// engine/orchestration/timeout.js completeFromOutput). runPostCompletionHooks has richer
|
|
5198
5214
|
// signals (PRs created, plan-to-prd PRD file existence, autoRecover) and
|
|
5199
5215
|
// must not be demoted by this heuristic.
|
|
5200
5216
|
if (opts && opts.detectPhantom) {
|
|
@@ -5950,7 +5966,7 @@ function dispatchReReviewForFix(fixDispatchItem, meta, config, opts = {}) {
|
|
|
5950
5966
|
}
|
|
5951
5967
|
|
|
5952
5968
|
const routing = require('./routing');
|
|
5953
|
-
const playbook = require('
|
|
5969
|
+
const playbook = require('../agents/playbook');
|
|
5954
5970
|
const dispatchModule = require('./dispatch');
|
|
5955
5971
|
|
|
5956
5972
|
const reviewAuthor = livePr.agent || pr.agent || null;
|
|
@@ -6153,7 +6169,7 @@ function captureTaskMemoryEpisode(dispatchItem, agentId, outcome, structuredComp
|
|
|
6153
6169
|
].join('\n');
|
|
6154
6170
|
|
|
6155
6171
|
try {
|
|
6156
|
-
return require('
|
|
6172
|
+
return require('../memory/memory-store').upsertMemoryRecord({
|
|
6157
6173
|
memoryType: 'episodic',
|
|
6158
6174
|
scopeType: project ? 'project' : (agentId ? 'agent' : 'global'),
|
|
6159
6175
|
scopeKey: project || agentId || '',
|
|
@@ -6520,24 +6536,28 @@ async function runPostCompletionHooks(dispatchItem, agentId, code, stdout, confi
|
|
|
6520
6536
|
let prdFound = false;
|
|
6521
6537
|
let resolvedPrdFilename = null;
|
|
6522
6538
|
const expectedFile = meta.item._prdFilename;
|
|
6523
|
-
const prdStore = require('
|
|
6539
|
+
const prdStore = require('../planning/prd-store');
|
|
6540
|
+
const prdResultSidecar = require('../planning/prd-result-sidecar');
|
|
6524
6541
|
const agentId = meta._agentId || meta.item.dispatched_to;
|
|
6525
|
-
|
|
6526
|
-
|
|
6527
|
-
|
|
6528
|
-
|
|
6529
|
-
|
|
6530
|
-
|
|
6531
|
-
|
|
6532
|
-
|
|
6533
|
-
|
|
6534
|
-
|
|
6535
|
-
|
|
6536
|
-
|
|
6537
|
-
|
|
6538
|
-
|
|
6539
|
-
|
|
6540
|
-
|
|
6542
|
+
if (expectedFile && agentId) {
|
|
6543
|
+
// W-msa0mrus00mh466f — a revision import must land the PRD back in a
|
|
6544
|
+
// coherent state in the SAME write that imports it: status returns to
|
|
6545
|
+
// awaiting-approval, staleness clears, the source-plan sync fields are
|
|
6546
|
+
// re-baselined and the revision pointers are dropped. The relation is
|
|
6547
|
+
// handed to the sidecar module (which owns the single writePrd) rather
|
|
6548
|
+
// than re-written here, so no reader can observe a completed revision
|
|
6549
|
+
// still paired with the stale recovery controls.
|
|
6550
|
+
const outcome = prdResultSidecar.consumePrdResultSidecar({
|
|
6551
|
+
agentsDir: AGENTS_DIR,
|
|
6552
|
+
agentId,
|
|
6553
|
+
expectedFilename: expectedFile,
|
|
6554
|
+
planFile: meta.item.planFile,
|
|
6555
|
+
workItemId: meta.item.id,
|
|
6556
|
+
revisionForPrd: meta.item._revisionForPrd,
|
|
6557
|
+
plansDir: PLANS_DIR,
|
|
6558
|
+
});
|
|
6559
|
+
if (!outcome.imported && outcome.code !== prdResultSidecar.PRD_RESULT_OUTCOME.ABSENT) {
|
|
6560
|
+
log('warn', `plan-to-prd ${meta.item.id}: could not import result sidecar: ${outcome.reason}`);
|
|
6541
6561
|
}
|
|
6542
6562
|
}
|
|
6543
6563
|
for (const { filename, archived, plan } of prdStore.listPrdRows()) {
|
|
@@ -6549,8 +6569,27 @@ async function runPostCompletionHooks(dispatchItem, agentId, code, stdout, confi
|
|
|
6549
6569
|
}
|
|
6550
6570
|
}
|
|
6551
6571
|
if (!prdFound && meta.item.planFile) {
|
|
6572
|
+
// Fallback scan. The canonical hit is a live PRD that declares this plan
|
|
6573
|
+
// markdown as its `source_plan`.
|
|
6574
|
+
//
|
|
6575
|
+
// The second clause is a legacy carve-out: a work item whose `planFile`
|
|
6576
|
+
// names a PRD file rather than the source plan markdown (the shape
|
|
6577
|
+
// /api/plans/revise produced before W-msa1y79a01271b91) can NEVER match by
|
|
6578
|
+
// source_plan — prdMatchesSourcePlan compares basenames and a `.json` key
|
|
6579
|
+
// never equals a `.md` one — so the gate would fail every attempt until
|
|
6580
|
+
// maxRetries. Treating a planFile that directly names a live PRD as a hit
|
|
6581
|
+
// lets such an item converge onto the PRD it actually pointed at, and the
|
|
6582
|
+
// migration block below repoints `_prdFilename` at it.
|
|
6583
|
+
//
|
|
6584
|
+
// This deliberately does NOT relax the sidecar-import `source_plan` guard
|
|
6585
|
+
// above: that guard is what stopped a mis-addressed sidecar from being
|
|
6586
|
+
// written under a freshly-minted filename and duplicating the PRD.
|
|
6587
|
+
const planFileKey = shared.sourcePlanKey(meta.item.planFile);
|
|
6588
|
+
const planFileNamesPrd = planFileKey.toLowerCase().endsWith('.json');
|
|
6552
6589
|
for (const { filename, archived, plan } of prdStore.listPrdRows()) {
|
|
6553
|
-
if (
|
|
6590
|
+
if (archived) continue;
|
|
6591
|
+
if (shared.prdMatchesSourcePlan(plan.source_plan, meta.item.planFile)
|
|
6592
|
+
|| (planFileNamesPrd && filename === planFileKey)) {
|
|
6554
6593
|
prdFound = true;
|
|
6555
6594
|
resolvedPrdFilename = filename;
|
|
6556
6595
|
break;
|
|
@@ -6594,7 +6633,12 @@ async function runPostCompletionHooks(dispatchItem, agentId, code, stdout, confi
|
|
|
6594
6633
|
// buildWorkItemDispatchVars()'s retry_context var (W-mrbq53ra000lf2e5) so the
|
|
6595
6634
|
// retried agent knows the PRD file was never found instead of silently
|
|
6596
6635
|
// repeating the same mistake.
|
|
6597
|
-
|
|
6636
|
+
// W-ms9tcry701xz0389 — the reason deliberately carries NO filename.
|
|
6637
|
+
// It is replayed verbatim into the retry prompt, and a filename
|
|
6638
|
+
// captured here is a snapshot of the FAILED attempt; quoting it can
|
|
6639
|
+
// only compete with the authoritative `{{prd_filename}}` the next
|
|
6640
|
+
// dispatch renders. Name the plan and the contract, not the value.
|
|
6641
|
+
const gateReason = `Validation gate (#893): no PRD result sidecar was imported for planFile "${meta.item.planFile || w.planFile || '(unknown)'}" after the previous attempt completed. Write agents/<agent-id>/prd-result.json exactly as the playbook's Output section specifies — including the "filename" the engine pins for this dispatch — before finishing.`;
|
|
6598
6642
|
if (retries < ENGINE_DEFAULTS.maxRetries) {
|
|
6599
6643
|
w.status = WI_STATUS.PENDING;
|
|
6600
6644
|
w._retryCount = retries + 1;
|
|
@@ -6846,7 +6890,7 @@ async function runPostCompletionHooks(dispatchItem, agentId, code, stdout, confi
|
|
|
6846
6890
|
// id lives at `dispatchItem.meta.item.meta.qaRunId` in production, NOT
|
|
6847
6891
|
// at `dispatchItem.meta.qaRunId`. Accept both locations to mirror the
|
|
6848
6892
|
// keep_processes / managed_spawn skip-worktree-removal pattern below
|
|
6849
|
-
// (engine/lifecycle.js, "_wiMetaForSkip" block) — that way fast-path
|
|
6893
|
+
// (engine/orchestration/lifecycle.js, "_wiMetaForSkip" block) — that way fast-path
|
|
6850
6894
|
// dispatchers that synthesize meta.qaRunId at the top level keep
|
|
6851
6895
|
// working too. The agent writes agents/<id>/qa-run-result.json before
|
|
6852
6896
|
// exit. qa-runs consumes the file exactly once and verifies its runId
|
|
@@ -6858,12 +6902,12 @@ async function runPostCompletionHooks(dispatchItem, agentId, code, stdout, confi
|
|
|
6858
6902
|
&& completionContractFailure?.nonTerminal !== true
|
|
6859
6903
|
&& Number(meta?.item?._retryCount || 0) < ENGINE_DEFAULTS.maxRetries;
|
|
6860
6904
|
if (qaRunId && lifecycleGateCanRetry) {
|
|
6861
|
-
try { require('
|
|
6905
|
+
try { require('../qa/runs').prepareResultSidecar(agentId || '_unknown', qaRunId); }
|
|
6862
6906
|
catch (e) { log('warn', `qa-validate deferred sidecar cleanup for ${qaRunId}: ${e.message}`); }
|
|
6863
6907
|
log('warn', `qa-validate run ${qaRunId} remains pending while completion validation retries`);
|
|
6864
6908
|
} else if (qaRunId) {
|
|
6865
6909
|
try {
|
|
6866
|
-
const qaRuns = require('
|
|
6910
|
+
const qaRuns = require('../qa/runs');
|
|
6867
6911
|
const consumed = qaRuns.consumeResultSidecar(agentId || '_unknown', qaRunId);
|
|
6868
6912
|
if (consumed.cleanupError) {
|
|
6869
6913
|
log('warn', `qa-validate sidecar cleanup for ${qaRunId}: ${consumed.cleanupError}`);
|
|
@@ -6879,6 +6923,10 @@ async function runPostCompletionHooks(dispatchItem, agentId, code, stdout, confi
|
|
|
6879
6923
|
status: parsed.status,
|
|
6880
6924
|
summary: typeof parsed.summary === 'string' ? parsed.summary : '',
|
|
6881
6925
|
artifacts: Array.isArray(parsed.artifacts) ? parsed.artifacts : [],
|
|
6926
|
+
// W-msb9kgs402813a97-c — per-journey outcomes drive the EXECUTE
|
|
6927
|
+
// evidence gate. Forwarded only when the agent declared them, so
|
|
6928
|
+
// legacy qa-validate sidecars keep their historical record shape.
|
|
6929
|
+
journeyCoverage: parsed.journeyCoverage,
|
|
6882
6930
|
});
|
|
6883
6931
|
log('info', `qa-validate run ${qaRunId} → ${parsed.status} (${(parsed.artifacts || []).length} artifacts)`);
|
|
6884
6932
|
} else {
|
|
@@ -6910,7 +6958,7 @@ async function runPostCompletionHooks(dispatchItem, agentId, code, stdout, confi
|
|
|
6910
6958
|
|
|
6911
6959
|
// P-a3f7c1b2 — QA Session lifecycle hook. The SETUP / DRAFT / EXECUTE work
|
|
6912
6960
|
// items carry `meta.sessionId` and `meta.sessionPhase` (set by the
|
|
6913
|
-
// qa-sessions chain helpers — see engine/qa
|
|
6961
|
+
// qa-sessions chain helpers — see engine/qa/sessions.js). On each agent
|
|
6914
6962
|
// exit we delegate to the matching handler, which validates the state
|
|
6915
6963
|
// transition and queues the next phase WI when applicable. The qa-validate
|
|
6916
6964
|
// qaRunId hook above (line 4340) already handles the qa-runs sidecar for
|
|
@@ -6925,7 +6973,7 @@ async function runPostCompletionHooks(dispatchItem, agentId, code, stdout, confi
|
|
|
6925
6973
|
const qaSessionPhase = meta?.sessionPhase || meta?.item?.meta?.sessionPhase;
|
|
6926
6974
|
if (qaSessionId && qaSessionPhase && !lifecycleGateCanRetry) {
|
|
6927
6975
|
try {
|
|
6928
|
-
const qaSessions = require('
|
|
6976
|
+
const qaSessions = require('../qa/sessions');
|
|
6929
6977
|
const scope = resolveWorkItemScope(meta);
|
|
6930
6978
|
const project = meta?.project?.name || meta?.item?.project || null;
|
|
6931
6979
|
const failureReason = typeof resultSummary === 'string' && resultSummary
|
|
@@ -6944,14 +6992,31 @@ async function runPostCompletionHooks(dispatchItem, agentId, code, stdout, confi
|
|
|
6944
6992
|
}
|
|
6945
6993
|
} else if (qaSessionPhase === 'draft') {
|
|
6946
6994
|
// The DRAFT agent reports the relative test file path in its
|
|
6947
|
-
// structured completion as `testFile
|
|
6948
|
-
//
|
|
6949
|
-
//
|
|
6950
|
-
// record still works without it (EXECUTE prompt falls back to the
|
|
6951
|
-
// generic test.<ext> hint).
|
|
6995
|
+
// structured completion as `testFile`; the session record still works
|
|
6996
|
+
// without it (EXECUTE prompt falls back to the generic test.<ext>
|
|
6997
|
+
// hint).
|
|
6952
6998
|
const testFile = structuredCompletion && typeof structuredCompletion.testFile === 'string'
|
|
6953
6999
|
? structuredCompletion.testFile
|
|
6954
7000
|
: null;
|
|
7001
|
+
// W-msb9kgs402813a97-b — the DRAFT visual-journey manifest rides its
|
|
7002
|
+
// own single-use sidecar (agents/<id>/qa-session-draft-result.json),
|
|
7003
|
+
// consumed here exactly once. Consumed on EVERY draft completion, not
|
|
7004
|
+
// just successful ones, so a failed attempt cannot leave a manifest
|
|
7005
|
+
// behind for the next dispatch of the same session to inherit.
|
|
7006
|
+
const visualJourney = require('../qa/visual-journey');
|
|
7007
|
+
let draftManifest = null;
|
|
7008
|
+
try {
|
|
7009
|
+
const consumed = visualJourney.consumeDraftResultSidecar(agentId || '_unknown', qaSessionId);
|
|
7010
|
+
if (consumed.cleanupError) {
|
|
7011
|
+
log('warn', `qa-session draft sidecar cleanup for ${qaSessionId}: ${consumed.cleanupError}`);
|
|
7012
|
+
}
|
|
7013
|
+
if (consumed.ok) draftManifest = consumed.manifest;
|
|
7014
|
+
else if (consumed.reason !== 'missing') {
|
|
7015
|
+
log('warn', `qa-session ${qaSessionId} draft sidecar ${consumed.reason} at ${consumed.filePath}`);
|
|
7016
|
+
}
|
|
7017
|
+
} catch (sidecarErr) {
|
|
7018
|
+
log('warn', `qa-session draft sidecar read for ${qaSessionId}: ${sidecarErr.message}`);
|
|
7019
|
+
}
|
|
6955
7020
|
const session = qaSessions.getSession(qaSessionId);
|
|
6956
7021
|
if (session && session.spec && session.spec.mode === 'auto' && effectiveSuccess) {
|
|
6957
7022
|
// Auto-mode chains EXECUTE; we need a qa-runs record up-front. The
|
|
@@ -6960,9 +7025,9 @@ async function runPostCompletionHooks(dispatchItem, agentId, code, stdout, confi
|
|
|
6960
7025
|
// the qa-runs record is created here on the auto path.
|
|
6961
7026
|
let qaRunId = null;
|
|
6962
7027
|
try {
|
|
6963
|
-
const qaRuns = require('
|
|
7028
|
+
const qaRuns = require('../qa/runs');
|
|
6964
7029
|
const run = qaRuns.createRun({
|
|
6965
|
-
runbookId:
|
|
7030
|
+
runbookId: qaSessions.sessionOwnedRunbookId(qaSessionId),
|
|
6966
7031
|
targetName: session.managedSpawnName,
|
|
6967
7032
|
project: project || session.spec.project || null,
|
|
6968
7033
|
});
|
|
@@ -6970,31 +7035,55 @@ async function runPostCompletionHooks(dispatchItem, agentId, code, stdout, confi
|
|
|
6970
7035
|
} catch (createErr) {
|
|
6971
7036
|
log('warn', `qa-session auto-mode createRun failed for ${qaSessionId}: ${createErr.message}`);
|
|
6972
7037
|
}
|
|
6973
|
-
qaSessions.handleDraftComplete(qaSessionId, {
|
|
7038
|
+
const draftOutcome = qaSessions.handleDraftComplete(qaSessionId, {
|
|
6974
7039
|
success: true,
|
|
6975
7040
|
testFile,
|
|
7041
|
+
manifest: draftManifest,
|
|
6976
7042
|
scope,
|
|
6977
7043
|
project,
|
|
6978
7044
|
qaRunId,
|
|
6979
7045
|
reason: failureReason,
|
|
6980
7046
|
});
|
|
7047
|
+
// The visual-journey gate can refuse a draft AFTER the qa-run above
|
|
7048
|
+
// was created. EXECUTE never runs, so terminalize the record here
|
|
7049
|
+
// instead of leaving it pending forever.
|
|
7050
|
+
if (qaRunId && draftOutcome && draftOutcome.nextState === qaSessions.QA_SESSION_STATE.FAILED) {
|
|
7051
|
+
try {
|
|
7052
|
+
require('../qa/runs').completeRun(qaRunId, {
|
|
7053
|
+
status: 'errored',
|
|
7054
|
+
summary: (qaSessions.getSession(qaSessionId) || {}).error
|
|
7055
|
+
|| 'QA Session DRAFT rejected before EXECUTE',
|
|
7056
|
+
artifacts: [],
|
|
7057
|
+
});
|
|
7058
|
+
} catch (runErr) {
|
|
7059
|
+
log('warn', `qa-session ${qaSessionId} could not terminalize orphaned run ${qaRunId}: ${runErr.message}`);
|
|
7060
|
+
}
|
|
7061
|
+
}
|
|
6981
7062
|
} else {
|
|
6982
7063
|
qaSessions.handleDraftComplete(qaSessionId, {
|
|
6983
7064
|
success: !!effectiveSuccess,
|
|
6984
7065
|
testFile,
|
|
7066
|
+
manifest: draftManifest,
|
|
6985
7067
|
reason: failureReason,
|
|
6986
7068
|
});
|
|
6987
7069
|
}
|
|
6988
7070
|
} else if (qaSessionPhase === 'execute') {
|
|
6989
7071
|
// The qaRunId block above (line 4340) already wrote the terminal
|
|
6990
|
-
// qa-runs record. Re-read it to drive the session state
|
|
7072
|
+
// qa-runs record. Re-read it to drive the session state — and hand
|
|
7073
|
+
// the record itself to the session layer so the W-msb9kgs402813a97-c
|
|
7074
|
+
// evidence gate reads the same artifacts/journeyCoverage rather than
|
|
7075
|
+
// re-querying.
|
|
6991
7076
|
let qaRunStatus = null;
|
|
7077
|
+
let qaRunRecord = null;
|
|
6992
7078
|
const linkedQaRunId = meta?.qaRunId || meta?.item?.meta?.qaRunId;
|
|
6993
7079
|
if (linkedQaRunId) {
|
|
6994
7080
|
try {
|
|
6995
|
-
const qaRuns = require('
|
|
7081
|
+
const qaRuns = require('../qa/runs');
|
|
6996
7082
|
const run = qaRuns.getRun(linkedQaRunId);
|
|
6997
|
-
if (run
|
|
7083
|
+
if (run) {
|
|
7084
|
+
qaRunRecord = run;
|
|
7085
|
+
if (run.status) qaRunStatus = run.status;
|
|
7086
|
+
}
|
|
6998
7087
|
} catch (readErr) {
|
|
6999
7088
|
log('warn', `qa-session execute qa-run lookup failed for ${qaSessionId}: ${readErr.message}`);
|
|
7000
7089
|
}
|
|
@@ -7002,6 +7091,7 @@ async function runPostCompletionHooks(dispatchItem, agentId, code, stdout, confi
|
|
|
7002
7091
|
qaSessions.handleExecuteComplete(qaSessionId, {
|
|
7003
7092
|
success: !!effectiveSuccess,
|
|
7004
7093
|
qaRunStatus,
|
|
7094
|
+
qaRun: qaRunRecord,
|
|
7005
7095
|
summary: resultSummary || null,
|
|
7006
7096
|
reason: failureReason,
|
|
7007
7097
|
});
|
|
@@ -7014,6 +7104,24 @@ async function runPostCompletionHooks(dispatchItem, agentId, code, stdout, confi
|
|
|
7014
7104
|
// Plan chaining removed — user must explicitly execute plan-to-prd after reviewing the plan
|
|
7015
7105
|
if (effectiveSuccess && meta?.item?.sourcePlan) checkPlanCompletion(meta, config);
|
|
7016
7106
|
|
|
7107
|
+
// W-msal3ser01q4ccb3 — auto-QA for successfully verified PRDs (opt-in via
|
|
7108
|
+
// engine.autoQaCompletedPrds, default off). Deliberately hooked on a
|
|
7109
|
+
// SUCCESSFUL verify work item rather than on the PRD's `status: completed`
|
|
7110
|
+
// flip: checkPlanCompletion above sets that status BEFORE verification runs,
|
|
7111
|
+
// so triggering there would race the verify agent and miss the canonical
|
|
7112
|
+
// prd/guides/verify-<plan>.md the QA spec builder prefers. `skipDoneStatus`
|
|
7113
|
+
// is honoured because the verify-missing-PR guard flips the WI to `failed`
|
|
7114
|
+
// without clearing effectiveSuccess. Everything else — guide presence,
|
|
7115
|
+
// cross-repo fan-in, durable dedupe — is re-derived from persisted state
|
|
7116
|
+
// inside the hook so a restart or duplicate callback cannot double-launch.
|
|
7117
|
+
if (effectiveSuccess && !skipDoneStatus && type === WORK_TYPE.VERIFY && meta?.item?.sourcePlan) {
|
|
7118
|
+
try {
|
|
7119
|
+
require('../qa/auto-prd-qa').maybeAutoQaAfterVerify(meta.item, config);
|
|
7120
|
+
} catch (err) {
|
|
7121
|
+
log('warn', `auto-qa after verify: ${err.message}`);
|
|
7122
|
+
}
|
|
7123
|
+
}
|
|
7124
|
+
|
|
7017
7125
|
// Archive is manual — user archives plans from the dashboard when ready
|
|
7018
7126
|
|
|
7019
7127
|
// Scheduled task back-reference: update SQL state and write a linked inbox note.
|
|
@@ -7023,7 +7131,7 @@ async function runPostCompletionHooks(dispatchItem, agentId, code, stdout, confi
|
|
|
7023
7131
|
const itemId = meta.item.id;
|
|
7024
7132
|
shared.mutateScheduleRuns((runs) => {
|
|
7025
7133
|
// P-c549d07e — preserve existing fields (esp. recentWorkItemIds ring
|
|
7026
|
-
// populated at dispatch time by engine/scheduler.writeScheduleRunEntry).
|
|
7134
|
+
// populated at dispatch time by engine/orchestration/scheduler.writeScheduleRunEntry).
|
|
7027
7135
|
// The literal-object replacement that lived here previously silently
|
|
7028
7136
|
// clobbered the ring on every successful completion.
|
|
7029
7137
|
const existing = typeof runs[scheduleId] === 'object' && runs[scheduleId] ? runs[scheduleId] : {};
|
|
@@ -7065,7 +7173,7 @@ async function runPostCompletionHooks(dispatchItem, agentId, code, stdout, confi
|
|
|
7065
7173
|
// returns, and their workdir validator checks `<cwd>` on disk. If the
|
|
7066
7174
|
// worktree is deleted here first, every sidecar pointing at the worktree
|
|
7067
7175
|
// fails with a bogus `invalid-workdir: directory does not exist`
|
|
7068
|
-
// rejection. The cleanup sweep (engine/cleanup.js) reaps the worktree
|
|
7176
|
+
// rejection. The cleanup sweep (engine/orchestration/cleanup.js) reaps the worktree
|
|
7069
7177
|
// afterwards: when acceptance fails, the >2h age sweep picks it up; when
|
|
7070
7178
|
// acceptance succeeds, the managed-spawn cwd anchor in cleanup.js keeps
|
|
7071
7179
|
// the worktree alive while the engine-owned services run inside it.
|
|
@@ -7152,7 +7260,7 @@ async function runPostCompletionHooks(dispatchItem, agentId, code, stdout, confi
|
|
|
7152
7260
|
// reviewer slot can't sit at -5 indefinitely. Idempotent via the PR-target
|
|
7153
7261
|
// dedup in addToDispatch; agent assignment is a soft preference (review-
|
|
7154
7262
|
// skilled agents first, then any idle agent) — NEVER block on a specific
|
|
7155
|
-
// reviewer. See engine/ado.js:resetReviewerNegativeVote for the verdict-
|
|
7263
|
+
// reviewer. See engine/ado/index.js:resetReviewerNegativeVote for the verdict-
|
|
7156
7264
|
// flip reset that fires on the resulting APPROVE.
|
|
7157
7265
|
try {
|
|
7158
7266
|
dispatchReReviewForFix(dispatchItem, meta, config, { agentId, resultSummary });
|
|
@@ -7236,7 +7344,7 @@ async function runPostCompletionHooks(dispatchItem, agentId, code, stdout, confi
|
|
|
7236
7344
|
function handleQaSessionSetupCompletion(meta, opts = {}) {
|
|
7237
7345
|
const qaSessionId = meta?.sessionId || meta?.item?.meta?.sessionId;
|
|
7238
7346
|
if (!qaSessionId) return null;
|
|
7239
|
-
const qaSessions = require('
|
|
7347
|
+
const qaSessions = require('../qa/sessions');
|
|
7240
7348
|
const scope = opts.scope || resolveWorkItemScope(meta);
|
|
7241
7349
|
const project = opts.project !== undefined
|
|
7242
7350
|
? opts.project
|
|
@@ -7259,7 +7367,7 @@ function handleQaSessionSetupCompletion(meta, opts = {}) {
|
|
|
7259
7367
|
// (e.g., manually raised PRs, cross-plan PRs, or PRs created while engine was paused).
|
|
7260
7368
|
function syncPrdFromPrs(config) {
|
|
7261
7369
|
try {
|
|
7262
|
-
const { reconcileItemsWithPrs } = require('
|
|
7370
|
+
const { reconcileItemsWithPrs } = require('../../engine');
|
|
7263
7371
|
config = config || queries.getConfig();
|
|
7264
7372
|
const allProjects = shared.getProjects(config);
|
|
7265
7373
|
|
|
@@ -7325,7 +7433,7 @@ function syncPrdFromPrs(config) {
|
|
|
7325
7433
|
// Paused, rejected, awaiting-approval, completed, and archived PRDs are
|
|
7326
7434
|
// skipped via _PRD_FROZEN_STATUSES. The locked write is idempotent.
|
|
7327
7435
|
function advancePrdStatusOnAllItemsDone(config) {
|
|
7328
|
-
const prdFiles = require('
|
|
7436
|
+
const prdFiles = require('../planning/prd-store').listPrdRows().filter(row => !row.archived).map(row => row.filename);
|
|
7329
7437
|
if (!prdFiles.length) return;
|
|
7330
7438
|
|
|
7331
7439
|
const allWorkItems = queries.getWorkItems(config);
|
|
@@ -7393,7 +7501,7 @@ function advancePrdStatusOnAllItemsDone(config) {
|
|
|
7393
7501
|
//
|
|
7394
7502
|
// This runs per-tick (right after syncPrdFromPrs). It reads the NORMALIZED
|
|
7395
7503
|
// shared PR schema, so a single sweep covers both GitHub and ADO
|
|
7396
|
-
// pollers at once (engine/github.js + engine/ado.js are intentional mirrors
|
|
7504
|
+
// pollers at once (engine/providers/github.js + engine/ado/index.js are intentional mirrors
|
|
7397
7505
|
// writing the same schema) — the durable single-source approach the task
|
|
7398
7506
|
// allows in lieu of hooking each poller's merged transition separately. Because
|
|
7399
7507
|
// it re-stamps every tick, the persisted copy is KEPT CURRENT through the
|
|
@@ -7673,7 +7781,7 @@ function pruneScopeMismatchDuplicatePrs(config) {
|
|
|
7673
7781
|
}
|
|
7674
7782
|
|
|
7675
7783
|
// Index all PRs by repository-scoped identity across all projects.
|
|
7676
|
-
const store = require('
|
|
7784
|
+
const store = require('../persistence/pull-requests-store');
|
|
7677
7785
|
const allPrs = store.readAllPullRequests() || [];
|
|
7678
7786
|
const byId = new Map();
|
|
7679
7787
|
for (const pr of allPrs) {
|
|
@@ -8097,7 +8205,7 @@ module.exports = {
|
|
|
8097
8205
|
// exercise both paths directly.
|
|
8098
8206
|
recordWorktreeHeldPause,
|
|
8099
8207
|
clearWorktreeHeldPause,
|
|
8100
|
-
// W-mpx44p05000ze8d8 — exported so engine/ado.js + engine/github.js can
|
|
8208
|
+
// W-mpx44p05000ze8d8 — exported so engine/ado/index.js + engine/providers/github.js can
|
|
8101
8209
|
// drop stale `_noOpFixes` records during their PR status poll, and so
|
|
8102
8210
|
// unit tests can exercise the sweep helper directly.
|
|
8103
8211
|
sweepStalePrNoOpFixes,
|