@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,27 +1,27 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* engine/playbook.js — Playbook rendering, system prompt building, agent context,
|
|
2
|
+
* engine/agents/playbook.js — Playbook rendering, system prompt building, agent context,
|
|
3
3
|
* task context resolution, and repo-host helpers.
|
|
4
4
|
* Extracted from engine.js.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
const fs = require('fs');
|
|
8
8
|
const path = require('path');
|
|
9
|
-
const shared = require('
|
|
10
|
-
const queries = require('
|
|
11
|
-
const { wrapUntrusted, buildSource } = require('
|
|
12
|
-
const { MINIONS_BRAND_URL } = require('
|
|
13
|
-
const features = require('
|
|
14
|
-
const memoryRetrieval = require('
|
|
15
|
-
const memoryStore = require('
|
|
9
|
+
const shared = require('../core/shared');
|
|
10
|
+
const queries = require('../core/queries');
|
|
11
|
+
const { wrapUntrusted, buildSource } = require('../core/untrusted-fence');
|
|
12
|
+
const { MINIONS_BRAND_URL } = require('../providers/comment-format');
|
|
13
|
+
const features = require('../core/features');
|
|
14
|
+
const memoryRetrieval = require('../memory/memory-retrieval');
|
|
15
|
+
const memoryStore = require('../memory/memory-store');
|
|
16
16
|
|
|
17
17
|
const { safeJsonArr, safeRead, getProjects, log, ts, dateStamp, truncateTextBytes, ENGINE_DEFAULTS, WI_STATUS, WORK_TYPE, PR_STATUS, DISPATCH_RESULT, getProjectOrg } = shared;
|
|
18
18
|
const { getConfig, getDispatch, getNotes, getPrs, getKnowledgeBaseIndex, AGENTS_DIR } = queries;
|
|
19
19
|
|
|
20
20
|
const MINIONS_DIR = shared.MINIONS_DIR;
|
|
21
|
-
const PLAYBOOKS_DIR =
|
|
21
|
+
const PLAYBOOKS_DIR = shared.resolveDefinitionDir('playbooks');
|
|
22
22
|
|
|
23
23
|
// Import tempAgents from routing module
|
|
24
|
-
const { tempAgents } = require('
|
|
24
|
+
const { tempAgents } = require('../orchestration/routing');
|
|
25
25
|
|
|
26
26
|
// ─── Repo Host Helpers ──────────────────────────────────────────────────────
|
|
27
27
|
|
|
@@ -70,7 +70,7 @@ function getPrCreateInstructions(project, config) {
|
|
|
70
70
|
`- Use --head to specify your feature branch name\n` +
|
|
71
71
|
(createPrsAsDraft ? `- Open the PR as a DRAFT: include the \`--draft\` flag exactly as shown above (the operator has "Create PRs as draft" enabled)\n` : '') +
|
|
72
72
|
`- Include a meaningful --title and body file describing the changes\n` +
|
|
73
|
-
`- If this PR contains a meaningful VISUAL/UI change (dashboard pages, slim-ux, Settings, work-item/PR/plan views, badges, layout/CSS), proactively capture + EMBED screenshots in the body — BEFORE/AFTER for fixes, AFTER-only for new UI. Publish PNGs as assets on a per-PR prerelease (\`gh release create pr-<num>-visual … --prerelease\`, or \`gh release upload … --clobber\` on re-dispatch) with a per-command \`GH_TOKEN\` for the ${org} account (NEVER \`gh auth switch\`), resolve each \`browser_download_url\`, and reference it as \`\`. Never \`git add\` a PNG; skip + record on failure. Full recipe: the "
|
|
73
|
+
`- If this PR contains a meaningful VISUAL/UI change (dashboard pages, slim-ux, Settings, work-item/PR/plan views, badges, layout/CSS), proactively capture + EMBED screenshots in the body — BEFORE/AFTER for fixes, AFTER-only for new UI. Publish PNGs as assets on a per-PR prerelease (\`gh release create pr-<num>-visual … --prerelease\`, or \`gh release upload … --clobber\` on re-dispatch) with a per-command \`GH_TOKEN\` for the ${org} account (NEVER \`gh auth switch\`), resolve each \`browser_download_url\`, and reference it as \`\`. Never \`git add\` a PNG; skip + record on failure. Full recipe: the "Visual evidence handling" section of the PR description audit.\n` +
|
|
74
74
|
PR_ATTRIBUTION_INSTRUCTION;
|
|
75
75
|
}
|
|
76
76
|
// Default: Azure DevOps — prefer `az` CLI first, ADO REST API as fallback
|
|
@@ -85,7 +85,7 @@ function getPrCreateInstructions(project, config) {
|
|
|
85
85
|
`- Use \`@<file>\` syntax for \`--description\` so Markdown, quotes, and newlines pass safely\n` +
|
|
86
86
|
`- Always set --target-branch to \`${mainBranch}\` (the main branch)\n` +
|
|
87
87
|
(createPrsAsDraft ? `- Open the PR as a DRAFT: include \`--draft true\` exactly as shown above (the operator has "Create PRs as draft" enabled). For the REST API fallback, set \`"isDraft": true\` in the request body\n` : '') +
|
|
88
|
-
`- If this PR contains a meaningful VISUAL/UI change (dashboard pages, slim-ux, Settings, work-item/PR/plan views, badges, layout/CSS), proactively capture + EMBED screenshots in the description — BEFORE/AFTER for fixes, AFTER-only for new UI. Upload via \`PUT .../pullRequests/<id>/attachments/<filename>\` with the PNG bytes and reference the returned URL. Save PNGs under \`agents/<id>/screenshots/\` only; never \`git add\` a PNG; skip + record on failure. Full recipe: the "
|
|
88
|
+
`- If this PR contains a meaningful VISUAL/UI change (dashboard pages, slim-ux, Settings, work-item/PR/plan views, badges, layout/CSS), proactively capture + EMBED screenshots in the description — BEFORE/AFTER for fixes, AFTER-only for new UI. Upload via \`PUT .../pullRequests/<id>/attachments/<filename>\` with the PNG bytes and reference the returned URL. Save PNGs under \`agents/<id>/screenshots/\` only; never \`git add\` a PNG; skip + record on failure. Full recipe: the "Visual evidence handling" section of the PR description audit\n` +
|
|
89
89
|
PR_ATTRIBUTION_INSTRUCTION + `\n` +
|
|
90
90
|
`\n` +
|
|
91
91
|
`If \`az\` is unavailable, fall back to the ADO REST API: get a token with \`az account get-access-token --resource 499b84ac-1321-427f-aa17-267ca6975798 --query accessToken -o tsv\` and \`POST .../_apis/git/repositories/${repoId}/pullrequests?api-version=7.1\` (Bearer auth). Do not use \`gh\` for Azure DevOps repositories.`;
|
|
@@ -165,7 +165,7 @@ function getPrVoteInstructions(project, config) {
|
|
|
165
165
|
"<your review body here>\n" +
|
|
166
166
|
"```\n" +
|
|
167
167
|
`Then run: \`gh pr review <number> --comment --body-file <verdict.md> --repo ${org}/${repo}\`. Do NOT use \`--approve\` or \`--request-changes\` flags — they will fail.\n\n` +
|
|
168
|
-
`**Brand link:** whenever the body names "Minions" (e.g. the \`Reviewed by Minions (…)\` sign-off), render it as \`[Minions](${MINIONS_BRAND_URL})\` per the shared rules. On the GitHub path the engine also auto-links the first bare \`… by Minions\` trailer as a backstop (\`engine/comment-format.js#linkifyBrandTrailer\`), but write the link yourself so the first occurrence is correct.`;
|
|
168
|
+
`**Brand link:** whenever the body names "Minions" (e.g. the \`Reviewed by Minions (…)\` sign-off), render it as \`[Minions](${MINIONS_BRAND_URL})\` per the shared rules. On the GitHub path the engine also auto-links the first bare \`… by Minions\` trailer as a backstop (\`engine/providers/comment-format.js#linkifyBrandTrailer\`), but write the link yourself so the first occurrence is correct.`;
|
|
169
169
|
}
|
|
170
170
|
// Azure DevOps — prefer `az` CLI first, ADO REST API as fallback.
|
|
171
171
|
// The platform reviewer vote is a POSITIVE mutation gated by autoApplyReviewVote
|
|
@@ -342,6 +342,7 @@ const PLAYBOOK_OPTIONAL_VARS = new Set([
|
|
|
342
342
|
'acceptance_criteria', // only set when item.acceptanceCriteria has entries
|
|
343
343
|
'checkpoint_context', // only set when resuming from a prior timeout
|
|
344
344
|
'retry_context', // only set when retrying after a validation-gate failure (#893)
|
|
345
|
+
'revision_feedback', // only set when a plan-to-prd run is an operator revision (W-msa0mrus00mh466f)
|
|
345
346
|
// Host-specific identifiers — always one of {ado_*, github_*} is empty
|
|
346
347
|
// (project is either ADO or GitHub, never both). Keeping them as warns
|
|
347
348
|
// produces ~96 noise lines per day on a single-host project.
|
|
@@ -417,6 +418,24 @@ const PLAYBOOK_OPTIONAL_VARS = new Set([
|
|
|
417
418
|
'role', // 'primary' | 'co-service'
|
|
418
419
|
'primary_project', // canonical primary project name; empty on single-project sessions
|
|
419
420
|
'co_services_json', // JSON-encoded co-service project names (e.g. ["api","worker"]); empty when none
|
|
421
|
+
// W-msb9kgs402813a97-a — every managed-spawn the session owns, as
|
|
422
|
+
// [{name, project, primary, health, baseUrl, ports}]. DRAFT/EXECUTE address
|
|
423
|
+
// co-service origins through this; `managed_spawn_name` stays the primary.
|
|
424
|
+
// Empty string for non-QA-session dispatches.
|
|
425
|
+
'session_services_json',
|
|
426
|
+
// W-msb9kgs402813a97-b — absolute path of the DRAFT visual-journey manifest
|
|
427
|
+
// sidecar (agents/<id>/qa-session-draft-result.json). Populated only for the
|
|
428
|
+
// DRAFT phase; SETUP/EXECUTE and non-QA dispatches render ''.
|
|
429
|
+
'qa_draft_result_sidecar',
|
|
430
|
+
// W-msb9kgs402813a97-c — the DRAFT-accepted visual-journey manifest projected
|
|
431
|
+
// into the qa-run-result coverage-entry shape
|
|
432
|
+
// ([{journeyId, name, kind, projects, services}]). EXECUTE's evidence gate
|
|
433
|
+
// grades journeyCoverage against these ids verbatim, so the EXECUTE prompt
|
|
434
|
+
// has to carry them — the DRAFT sidecar that delivered them is consumed and
|
|
435
|
+
// unlinked, and the accepted manifest lives only on the session record.
|
|
436
|
+
// Populated ONLY for the EXECUTE phase of a session that persisted a
|
|
437
|
+
// manifest; SETUP/DRAFT, logs-only, legacy, and non-QA dispatches render ''.
|
|
438
|
+
'visual_journey_manifest_json',
|
|
420
439
|
// M006 — typed handoff envelope fields. Set on a follow-up dispatch meta
|
|
421
440
|
// when lifecycle.js queues the item after a completing agent so the
|
|
422
441
|
// receiving agent has explicit context about who handed off and why.
|
|
@@ -430,6 +449,12 @@ const PLAYBOOK_OPTIONAL_VARS = new Set([
|
|
|
430
449
|
// when no prior explore WI exists; the {{#prior_explore_context}} conditional
|
|
431
450
|
// in fix.md renders the section only when non-empty.
|
|
432
451
|
'prior_explore_context',
|
|
452
|
+
// W-ms5tb6ha016fda10 — declared execution surface for this dispatch.
|
|
453
|
+
// 'control-plane' when the work item validly opted out of a repository
|
|
454
|
+
// checkout; empty/'repo' otherwise. Playbooks don't reference it directly —
|
|
455
|
+
// renderPlaybook uses it to append the control-plane hint and to relax the
|
|
456
|
+
// project_path requirement.
|
|
457
|
+
'execution_surface',
|
|
433
458
|
]);
|
|
434
459
|
|
|
435
460
|
|
|
@@ -444,7 +469,11 @@ const PLAYBOOK_REQUIRED_VARS = {
|
|
|
444
469
|
'explore': ['task_description'],
|
|
445
470
|
'ask': ['question'],
|
|
446
471
|
'plan': ['task_description', 'project_path'],
|
|
447
|
-
|
|
472
|
+
// W-ms9tcry701xz0389 — `item_id` is required because the sidecar envelope
|
|
473
|
+
// binds itself to the work item via {{item_id}}. An unrendered token there
|
|
474
|
+
// would produce a permanently unimportable result, so fail the render loudly
|
|
475
|
+
// instead of shipping a poisoned contract to the agent.
|
|
476
|
+
'plan-to-prd': ['plan_content', 'plan_file', 'prd_filename', 'project_path', 'item_id'],
|
|
448
477
|
'decompose': ['item_id', 'item_description', 'project_path'],
|
|
449
478
|
'verify': ['task_description'],
|
|
450
479
|
'test': ['item_name'],
|
|
@@ -514,7 +543,16 @@ function validatePlaybookVars(playbookName, vars) {
|
|
|
514
543
|
const required = PLAYBOOK_REQUIRED_VARS[playbookName];
|
|
515
544
|
if (!required) return { valid: true, missing: [] };
|
|
516
545
|
|
|
517
|
-
|
|
546
|
+
// W-ms5tb6ha016fda10 — a control-plane dispatch has no repository checkout,
|
|
547
|
+
// so `project_path` is legitimately empty. Requiring it would reject exactly
|
|
548
|
+
// the maintenance jobs the surface exists to make cheap. Every other
|
|
549
|
+
// required var still applies.
|
|
550
|
+
const controlPlane = vars?.execution_surface === 'control-plane';
|
|
551
|
+
const effective = controlPlane
|
|
552
|
+
? required.filter(key => key !== 'project_path' && key !== 'worktree_path')
|
|
553
|
+
: required;
|
|
554
|
+
|
|
555
|
+
const missing = effective.filter(key => {
|
|
518
556
|
const val = vars[key];
|
|
519
557
|
return val === undefined || val === null || String(val).trim() === '';
|
|
520
558
|
});
|
|
@@ -643,7 +681,7 @@ function buildQaValidateContextBlock({ runId, runbook, target, artifactsDir, res
|
|
|
643
681
|
lines.push('');
|
|
644
682
|
}
|
|
645
683
|
|
|
646
|
-
lines.push(`Use this context to execute the runbook against the live target. Write the result sidecar to \`${resultSidecar || 'the injected qa_result_sidecar path'}\` before exit — the engine consumes it in \`engine/lifecycle.js\` and calls \`qaRuns.completeRun(runId, ...)\`.`);
|
|
684
|
+
lines.push(`Use this context to execute the runbook against the live target. Write the result sidecar to \`${resultSidecar || 'the injected qa_result_sidecar path'}\` before exit — the engine consumes it in \`engine/orchestration/lifecycle.js\` and calls \`qaRuns.completeRun(runId, ...)\`.`);
|
|
647
685
|
|
|
648
686
|
return lines.join('\n');
|
|
649
687
|
}
|
|
@@ -872,7 +910,29 @@ function renderPlaybook(type, vars) {
|
|
|
872
910
|
applicable.text,
|
|
873
911
|
buildSource('review-learning', { item: vars.item_id || vars.task_id || 'unknown' })
|
|
874
912
|
);
|
|
875
|
-
|
|
913
|
+
// #3 pre-PR checklist: for dispatches that open or update a PR (every
|
|
914
|
+
// non read-only work type), frame the recalled lessons as an explicit
|
|
915
|
+
// gate the agent must clear before finalizing the PR, and tie each one
|
|
916
|
+
// back to the existing reviewLearningApplications completion contract so
|
|
917
|
+
// the confirmation is auditable. Read-only dispatches (ask/explore/plan/
|
|
918
|
+
// meeting) keep the informational framing — they open no PR to gate.
|
|
919
|
+
// The directive is trusted Minions instruction and stays OUTSIDE the
|
|
920
|
+
// untrusted fence; only the lesson bodies are fenced.
|
|
921
|
+
const recallType = String(vars.work_type || type || '').toLowerCase();
|
|
922
|
+
const prAuthoringDispatch = !shared.READ_ONLY_ROOT_TASK_TYPES.has(recallType);
|
|
923
|
+
const checklistDirective = prAuthoringDispatch
|
|
924
|
+
? 'Treat the lessons below as a **pre-PR checklist**: each is a review finding raised on a '
|
|
925
|
+
+ 'prior pull request for related code. Before you open or update this PR, confirm every one is '
|
|
926
|
+
+ 'addressed in your current changes (or does not apply), verifying each against the live code — '
|
|
927
|
+
+ 'do not assume a lesson still holds. In your completion report, record one '
|
|
928
|
+
+ '`reviewLearningApplications` entry per lesson with outcome `applied`, '
|
|
929
|
+
+ '`considered-not-applicable`, or `contradicted` and brief evidence.\n\n'
|
|
930
|
+
: '';
|
|
931
|
+
inertAppendices.push(
|
|
932
|
+
'\n\n---\n\n## Applicable Prior Review Lessons (task-selected; verify against live code)\n\n'
|
|
933
|
+
+ checklistDirective
|
|
934
|
+
+ (fenced || applicable.text)
|
|
935
|
+
);
|
|
876
936
|
}
|
|
877
937
|
} catch (e) {
|
|
878
938
|
log('warn', `Review-learning recall failed for ${vars.item_id || vars.task_id || type}: ${e.message}`);
|
|
@@ -925,7 +985,7 @@ function renderPlaybook(type, vars) {
|
|
|
925
985
|
// capability flag to avoid double-injection. Orthogonal to each runtime's
|
|
926
986
|
// native AGENTS.md discovery (CLAUDE.md is never read by Copilot/Codex, so
|
|
927
987
|
// there is nothing to conflict with). Bounded discovery (nearest-applicable
|
|
928
|
-
// walk-up, byte-capped) lives in engine/claude-md-context.js. Degrades
|
|
988
|
+
// walk-up, byte-capped) lives in engine/agents/claude-md-context.js. Degrades
|
|
929
989
|
// silently on any error.
|
|
930
990
|
//
|
|
931
991
|
// These resolved facts (runtime, bare mode, propagation flag, and the ACTUAL
|
|
@@ -1029,13 +1089,28 @@ function renderPlaybook(type, vars) {
|
|
|
1029
1089
|
} catch (e) { log('warn', `harness PR-section inject failed: ${e.message}`); }
|
|
1030
1090
|
}
|
|
1031
1091
|
|
|
1092
|
+
// W-ms5tb6ha016fda10 — control-plane execution surface. Injected only when
|
|
1093
|
+
// the dispatcher set vars.execution_surface = 'control-plane' from the work
|
|
1094
|
+
// item's validated `meta.executionSurface`. The agent has NO repository
|
|
1095
|
+
// checkout, so it must be told that explicitly — otherwise a maintenance job
|
|
1096
|
+
// wastes turns hunting for a worktree that was deliberately never allocated.
|
|
1097
|
+
if (vars.execution_surface === 'control-plane') {
|
|
1098
|
+
inertAppendices.push(buildControlPlaneHint({
|
|
1099
|
+
projectName: vars.project_name,
|
|
1100
|
+
repoName: vars.repo_name,
|
|
1101
|
+
repoHost: vars.repo_host,
|
|
1102
|
+
mainBranch: vars.main_branch,
|
|
1103
|
+
cwd: MINIONS_DIR,
|
|
1104
|
+
}));
|
|
1105
|
+
}
|
|
1106
|
+
|
|
1032
1107
|
// W-mp68q6ke0010de68 — opt-in keep_processes hint. Injected only when the
|
|
1033
1108
|
// dispatcher set vars.keep_processes (truthy) from the work item's
|
|
1034
1109
|
// `meta.keep_processes`. Built via the keep-process-sweep module so the
|
|
1035
1110
|
// copy stays in sync with the engine-side caps it actually enforces.
|
|
1036
1111
|
if (vars.keep_processes) {
|
|
1037
1112
|
try {
|
|
1038
|
-
const keepProcessSweep = require('
|
|
1113
|
+
const keepProcessSweep = require('../processes/keep-process-sweep');
|
|
1039
1114
|
const hint = keepProcessSweep.buildKeepProcessesHint({
|
|
1040
1115
|
agentId: vars.agent_id,
|
|
1041
1116
|
workItemId: vars.item_id || vars.task_id,
|
|
@@ -1052,7 +1127,7 @@ function renderPlaybook(type, vars) {
|
|
|
1052
1127
|
// managed-spawn sidecar so the engine takes over spawn + healthcheck.
|
|
1053
1128
|
if (vars.managed_spawn) {
|
|
1054
1129
|
try {
|
|
1055
|
-
const managedSpawn = require('
|
|
1130
|
+
const managedSpawn = require('../processes/managed-spawn');
|
|
1056
1131
|
const hint = managedSpawn.buildManagedSpawnHint({
|
|
1057
1132
|
agentId: vars.agent_id,
|
|
1058
1133
|
workItemId: vars.item_id || vars.task_id,
|
|
@@ -1072,7 +1147,7 @@ function renderPlaybook(type, vars) {
|
|
|
1072
1147
|
// string is returned when nothing matches, so we short-circuit on falsy.
|
|
1073
1148
|
if (vars.project_name) {
|
|
1074
1149
|
try {
|
|
1075
|
-
const managedSpawn = require('
|
|
1150
|
+
const managedSpawn = require('../processes/managed-spawn');
|
|
1076
1151
|
const liveBlock = managedSpawn.buildLiveManagedProcessesBlock({
|
|
1077
1152
|
project: vars.project_name,
|
|
1078
1153
|
});
|
|
@@ -1164,6 +1239,11 @@ function renderPlaybook(type, vars) {
|
|
|
1164
1239
|
repoHost: vars.repo_host || vars.repoHost || dispatchProject.repoHost,
|
|
1165
1240
|
};
|
|
1166
1241
|
const repoHost = getRepoHost(renderProject);
|
|
1242
|
+
const liveDashboard = shared.readDashboardPortFile(MINIONS_DIR);
|
|
1243
|
+
const dashboardPort = liveDashboard?.port || shared.resolveDashboardPort({
|
|
1244
|
+
env: process.env.MINIONS_DASHBOARD_PORT,
|
|
1245
|
+
config: config.engine?.dashboardPort,
|
|
1246
|
+
}).port;
|
|
1167
1247
|
const projectVars = {
|
|
1168
1248
|
project_name: renderProject.name || 'Unknown Project',
|
|
1169
1249
|
ado_org: repoHost === 'ado' ? (renderProject.adoOrg || 'Unknown') : '',
|
|
@@ -1179,6 +1259,7 @@ function renderPlaybook(type, vars) {
|
|
|
1179
1259
|
pr_fetch_instructions: getPrFetchInstructions(renderProject),
|
|
1180
1260
|
pr_vote_instructions: getPrVoteInstructions(renderProject, config),
|
|
1181
1261
|
repo_host_label: getRepoHostLabel(renderProject),
|
|
1262
|
+
dashboard_port: dashboardPort,
|
|
1182
1263
|
};
|
|
1183
1264
|
const allVars = { ...projectVars, ...vars };
|
|
1184
1265
|
|
|
@@ -1385,7 +1466,7 @@ function buildAgentContext(agentId, config, project) {
|
|
|
1385
1466
|
}
|
|
1386
1467
|
// Also check the central SQL pull-request scope.
|
|
1387
1468
|
try {
|
|
1388
|
-
const centralPrs = require('
|
|
1469
|
+
const centralPrs = require('../persistence/pull-requests-store').readPullRequestsForScope('central');
|
|
1389
1470
|
for (const pr of centralPrs.filter(pr => pr.status === PR_STATUS.ACTIVE)) {
|
|
1390
1471
|
if (!allPrs.some(p => p.id === pr.id)) allPrs.push({ ...pr, _project: 'central' });
|
|
1391
1472
|
}
|
|
@@ -1452,6 +1533,57 @@ function buildBaseVars(agentId, config, project) {
|
|
|
1452
1533
|
};
|
|
1453
1534
|
}
|
|
1454
1535
|
|
|
1536
|
+
/**
|
|
1537
|
+
* W-ms5tb6ha016fda10 — control-plane dispatch hint.
|
|
1538
|
+
*
|
|
1539
|
+
* Appended to the rendered prompt when the work item validly declared
|
|
1540
|
+
* `meta.executionSurface: 'control-plane'`. The agent runs at the Minions root
|
|
1541
|
+
* with NO repository checkout, so the contract has to be stated explicitly:
|
|
1542
|
+
* project identity is available as context, the repo is not on disk, and
|
|
1543
|
+
* anything that needs repository files belongs on a normal `repo` dispatch.
|
|
1544
|
+
*
|
|
1545
|
+
* Pure + platform-agnostic (no shell snippets, no hardcoded commands) so it
|
|
1546
|
+
* behaves identically on Windows, Linux, and macOS.
|
|
1547
|
+
*/
|
|
1548
|
+
function buildControlPlaneHint({ projectName, repoName, repoHost, mainBranch, cwd } = {}) {
|
|
1549
|
+
const lines = [
|
|
1550
|
+
'## Execution surface: control-plane (no repository checkout)',
|
|
1551
|
+
'',
|
|
1552
|
+
'This work item declared `meta.executionSurface: "control-plane"`, so the engine '
|
|
1553
|
+
+ 'deliberately did **not** allocate a git worktree for it. Your working directory is the '
|
|
1554
|
+
+ 'Minions root (`' + (cwd || '') + '`), not a checkout of the target repository.',
|
|
1555
|
+
'',
|
|
1556
|
+
'**What that means**',
|
|
1557
|
+
'',
|
|
1558
|
+
'- The target repository is **not** on disk for this dispatch. Do not look for a worktree, '
|
|
1559
|
+
+ 'do not `git clone`, and do not run git commands against the operator\'s checkout.',
|
|
1560
|
+
'- Do your work through the Minions dashboard API and the platform CLIs you already have '
|
|
1561
|
+
+ '(`gh` for GitHub, `az` for Azure DevOps). Those reach the remote directly and need no '
|
|
1562
|
+
+ 'local checkout.',
|
|
1563
|
+
'- Do not create a branch, commit, or open a PR from this dispatch — there is nothing to '
|
|
1564
|
+
+ 'commit from.',
|
|
1565
|
+
];
|
|
1566
|
+
const context = [];
|
|
1567
|
+
if (projectName && projectName !== 'Unknown Project') context.push(`project \`${projectName}\``);
|
|
1568
|
+
if (repoName && repoName !== 'Unknown') context.push(`repo \`${repoName}\``);
|
|
1569
|
+
if (repoHost) context.push(`host \`${repoHost}\``);
|
|
1570
|
+
if (mainBranch) context.push(`main branch \`${mainBranch}\``);
|
|
1571
|
+
if (context.length) {
|
|
1572
|
+
lines.push(
|
|
1573
|
+
'',
|
|
1574
|
+
'**Project context** (carried without a checkout): ' + context.join(', ') + '.',
|
|
1575
|
+
);
|
|
1576
|
+
}
|
|
1577
|
+
lines.push(
|
|
1578
|
+
'',
|
|
1579
|
+
'If you discover the task genuinely requires reading or changing repository files, **stop** '
|
|
1580
|
+
+ 'and report that in your completion summary instead of improvising a checkout. The work '
|
|
1581
|
+
+ 'item should be re-declared as `executionSurface: "repo"` so the engine allocates an '
|
|
1582
|
+
+ 'isolated worktree for it.',
|
|
1583
|
+
);
|
|
1584
|
+
return lines.join('\n');
|
|
1585
|
+
}
|
|
1586
|
+
|
|
1455
1587
|
function selectPlaybook(workType, item) {
|
|
1456
1588
|
// W-mpeiwz6k0005bf34-c — explicit playbook override via item.meta.playbook.
|
|
1457
1589
|
// Used by /api/qa/runbooks/run to route a `test`-type work item to the
|
|
@@ -1523,6 +1655,7 @@ module.exports = {
|
|
|
1523
1655
|
resolvePlaybookPath,
|
|
1524
1656
|
renderPlaybook,
|
|
1525
1657
|
validatePlaybookVars,
|
|
1658
|
+
buildControlPlaneHint, // W-ms5tb6ha016fda10 — exported for testing
|
|
1526
1659
|
PLAYBOOK_REQUIRED_VARS,
|
|
1527
1660
|
PLAYBOOK_OPTIONAL_VARS,
|
|
1528
1661
|
_parsePlaybookFrontmatter,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* engine/pooled-agent-process.js — child_process-shaped facade over a leased
|
|
3
|
-
* engine/agent-worker-pool.js worker (P-1d8f0b93).
|
|
2
|
+
* engine/agents/pooled-agent-process.js — child_process-shaped facade over a leased
|
|
3
|
+
* engine/agents/agent-worker-pool.js worker (P-1d8f0b93).
|
|
4
4
|
*
|
|
5
5
|
* engine.js#spawnAgent's downstream code (stdout/stderr `.on('data', ...)`
|
|
6
6
|
* handlers, the `onAgentClose` completion listener, PID-file/timeout
|
|
@@ -30,7 +30,7 @@ const { PassThrough } = require('stream');
|
|
|
30
30
|
const {
|
|
31
31
|
resolveRuntimeByCapability,
|
|
32
32
|
encodePooledOutput,
|
|
33
|
-
} = require('
|
|
33
|
+
} = require('../runtimes');
|
|
34
34
|
|
|
35
35
|
const CANCEL_GRACE_MS = 1500;
|
|
36
36
|
const DESCENDANT_INITIAL_SNAPSHOT_MS = 3000;
|
|
@@ -41,19 +41,21 @@ const _internals = {
|
|
|
41
41
|
cancelGraceMs: CANCEL_GRACE_MS,
|
|
42
42
|
killVerifyDelayMs: 50,
|
|
43
43
|
listAllProcesses() {
|
|
44
|
-
return require('
|
|
44
|
+
return require('../core/shared').listAllProcessesAsync();
|
|
45
45
|
},
|
|
46
46
|
listProcessDescendants(pid, processes) {
|
|
47
|
-
return require('
|
|
47
|
+
return require('../core/shared').listProcessDescendants(pid, processes);
|
|
48
48
|
},
|
|
49
49
|
findProcessesWithCwdInside(cwd) {
|
|
50
|
-
return require('
|
|
50
|
+
return require('../core/shared').findProcessesWithCwdInsideAsync(cwd);
|
|
51
51
|
},
|
|
52
|
-
killByPidsImmediate(pids) {
|
|
53
|
-
return require('
|
|
52
|
+
killByPidsImmediate(pids, expectedIdentities) {
|
|
53
|
+
return require('../core/shared').terminateProcess('engine.pooled-agent.descendants', pids, {
|
|
54
|
+
expectedIdentities,
|
|
55
|
+
});
|
|
54
56
|
},
|
|
55
57
|
computeReapPlan(pids, agentId, opts) {
|
|
56
|
-
return require('
|
|
58
|
+
return require('../processes/keep-process-sweep').computeReapPlan(pids, agentId, opts);
|
|
57
59
|
},
|
|
58
60
|
};
|
|
59
61
|
|
|
@@ -83,7 +85,7 @@ function dispatchOwnedDescendants(rootPid, baselinePids, processes) {
|
|
|
83
85
|
class PooledAgentProcess extends EventEmitter {
|
|
84
86
|
/**
|
|
85
87
|
* @param {object} opts
|
|
86
|
-
* @param {object} opts.pool - engine/agent-worker-pool.js module (or a test double)
|
|
88
|
+
* @param {object} opts.pool - engine/agents/agent-worker-pool.js module (or a test double)
|
|
87
89
|
* @param {object} opts.runtime - resolved runtime adapter
|
|
88
90
|
* @param {string} opts.dispatchId
|
|
89
91
|
* @param {string} opts.cwd
|
|
@@ -472,7 +474,7 @@ class PooledAgentProcess extends EventEmitter {
|
|
|
472
474
|
if (currentStartedAt === startedAt) pids.push(pid);
|
|
473
475
|
}
|
|
474
476
|
if (pids.length === 0) return true;
|
|
475
|
-
_internals.killByPidsImmediate(pids);
|
|
477
|
+
_internals.killByPidsImmediate(pids, identities);
|
|
476
478
|
const delayMs = Math.max(0, Number(_internals.killVerifyDelayMs) || 0);
|
|
477
479
|
if (delayMs > 0) await new Promise((resolve) => setTimeout(resolve, delayMs));
|
|
478
480
|
const processes = await _internals.listAllProcesses();
|
|
@@ -624,7 +626,7 @@ class PooledAgentProcess extends EventEmitter {
|
|
|
624
626
|
// child_process.kill()-shaped primitive. Cancels the in-flight ACP turn and
|
|
625
627
|
// releases its lease; the pool evicts the worker if that turn is not settled,
|
|
626
628
|
// preventing a cancelled response from leaking into the next dispatch.
|
|
627
|
-
// Full timeout/steering-kill cancel-vs-kill wiring in engine/timeout.js is
|
|
629
|
+
// Full timeout/steering-kill cancel-vs-kill wiring in engine/orchestration/timeout.js is
|
|
628
630
|
// P-6e2a4c15 — this method is the primitive that work item calls into.
|
|
629
631
|
kill() {
|
|
630
632
|
if (this.killed) return true;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* engine/preflight.js — Prerequisite and health checks for Minions.
|
|
2
|
+
* engine/agents/preflight.js — Prerequisite and health checks for Minions.
|
|
3
3
|
* Used by `minions init`, `minions start`, and `minions doctor`.
|
|
4
4
|
*
|
|
5
5
|
* Per-runtime binary + model-discovery checks (P-9e8a3f1d) — for every distinct
|
|
@@ -12,7 +12,7 @@ const fs = require('fs');
|
|
|
12
12
|
const os = require('os');
|
|
13
13
|
const path = require('path');
|
|
14
14
|
const { execSync, execFileSync } = require('child_process');
|
|
15
|
-
const shared = require('
|
|
15
|
+
const shared = require('../core/shared');
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
18
|
* Resolve the Claude Code CLI binary path. Legacy helper preserved for back-
|
|
@@ -120,7 +120,7 @@ function _distinctRuntimes(config) {
|
|
|
120
120
|
function _checkRuntimeBinary(runtimeName, { optional = false } = {}) {
|
|
121
121
|
let adapter;
|
|
122
122
|
try {
|
|
123
|
-
adapter = require('
|
|
123
|
+
adapter = require('../runtimes').resolveRuntime(runtimeName);
|
|
124
124
|
} catch (e) {
|
|
125
125
|
return {
|
|
126
126
|
name: `Runtime: ${runtimeName}`,
|
|
@@ -226,7 +226,7 @@ function runPreflight(opts = {}) {
|
|
|
226
226
|
let runtimes = configuredRuntimes;
|
|
227
227
|
if (opts.includeAllRegistered) {
|
|
228
228
|
let registered = [];
|
|
229
|
-
try { registered = require('
|
|
229
|
+
try { registered = require('../runtimes').listRuntimes(); }
|
|
230
230
|
catch { /* registry may be missing during partial installs */ }
|
|
231
231
|
runtimes = Array.from(new Set([...configuredRuntimes, ...registered])).sort();
|
|
232
232
|
}
|
|
@@ -252,7 +252,7 @@ function runPreflight(opts = {}) {
|
|
|
252
252
|
// worktreeRoot check.
|
|
253
253
|
try {
|
|
254
254
|
let runtimeNames = [];
|
|
255
|
-
try { runtimeNames = require('
|
|
255
|
+
try { runtimeNames = require('../runtimes').listRuntimes(); }
|
|
256
256
|
catch { /* registry may be missing during partial installs */ }
|
|
257
257
|
const warns = shared.runtimeConfigWarnings(opts.config, runtimeNames);
|
|
258
258
|
for (const w of warns) {
|
|
@@ -358,7 +358,7 @@ function _fleetSummaryResults(config, { dispatch } = {}) {
|
|
|
358
358
|
if (!config || typeof config !== 'object') return results;
|
|
359
359
|
const engine = config.engine || {};
|
|
360
360
|
const defaultCli = engine.defaultCli ? String(engine.defaultCli) : 'copilot';
|
|
361
|
-
const display = require('
|
|
361
|
+
const display = require('../core/queries').resolveRuntimeModelDisplay({
|
|
362
362
|
runtime: defaultCli,
|
|
363
363
|
configuredModel: engine.defaultModel,
|
|
364
364
|
dispatch,
|
|
@@ -398,7 +398,7 @@ async function _modelDiscoveryResults(config) {
|
|
|
398
398
|
let md;
|
|
399
399
|
try { md = require('./model-discovery'); } catch { return results; }
|
|
400
400
|
let registry;
|
|
401
|
-
try { registry = require('
|
|
401
|
+
try { registry = require('../runtimes'); } catch { return results; }
|
|
402
402
|
const fleetDisabled = config.engine && config.engine.disableModelDiscovery === true;
|
|
403
403
|
const runtimes = _distinctRuntimes(config);
|
|
404
404
|
for (const runtimeName of runtimes) {
|
|
@@ -521,7 +521,7 @@ function _bypassFlagResults(config) {
|
|
|
521
521
|
const results = [];
|
|
522
522
|
if (!config || typeof config !== 'object') return results;
|
|
523
523
|
let registry;
|
|
524
|
-
try { registry = require('
|
|
524
|
+
try { registry = require('../runtimes'); } catch { return results; }
|
|
525
525
|
const runtimes = _distinctRuntimes(config);
|
|
526
526
|
for (const runtimeName of runtimes) {
|
|
527
527
|
let adapter;
|
|
@@ -665,7 +665,7 @@ function doctor(minionsHome) {
|
|
|
665
665
|
// for hours. Only flagged when installed AND broken; not-installed is a
|
|
666
666
|
// neutral note since the watchdog is opt-in.
|
|
667
667
|
try {
|
|
668
|
-
const watchdog = require(path.join(minionsHome, 'engine', 'watchdog'));
|
|
668
|
+
const watchdog = require(path.join(minionsHome, 'engine', 'recovery', 'watchdog'));
|
|
669
669
|
const wh = watchdog.health({ minionsHome });
|
|
670
670
|
if (!wh.installed) {
|
|
671
671
|
runtimeResults.push({ name: 'Watchdog', ok: 'warn', message: wh.message });
|
|
@@ -698,6 +698,25 @@ function doctor(minionsHome) {
|
|
|
698
698
|
const bypassResults = _bypassFlagResults(preflightConfig);
|
|
699
699
|
runtimeResults.push(...bypassResults);
|
|
700
700
|
|
|
701
|
+
// Constellation companion presence (P-e93c85a1). Read-only and bounded:
|
|
702
|
+
// a marker read plus, at most, one loopback health request with an explicit
|
|
703
|
+
// timeout. Reporting only — Minions never downloads, executes, or installs
|
|
704
|
+
// Constellation, and an absent/incompatible companion is always a `warn`
|
|
705
|
+
// so `minions doctor` keeps its exit code on hosts without Constellation.
|
|
706
|
+
// Suppressed entirely (no row at all) by the documented opt-out.
|
|
707
|
+
try {
|
|
708
|
+
const companion = require('../api/companion');
|
|
709
|
+
const companionResult = await companion.probeCompanion({ config: preflightConfig });
|
|
710
|
+
const companionRow = companion.companionDoctorResult(companionResult);
|
|
711
|
+
if (companionRow) runtimeResults.push(companionRow);
|
|
712
|
+
} catch (err) {
|
|
713
|
+
runtimeResults.push({
|
|
714
|
+
name: 'Constellation companion',
|
|
715
|
+
ok: 'warn',
|
|
716
|
+
message: `companion-unknown — probe unavailable: ${(err && err.message) || err} (see docs/constellation-bridge.md)`,
|
|
717
|
+
});
|
|
718
|
+
}
|
|
719
|
+
|
|
701
720
|
// Print all
|
|
702
721
|
const allResults = [...results, ...runtimeResults];
|
|
703
722
|
const ok = printPreflight(allResults, { label: 'Minions Doctor' });
|
|
@@ -861,7 +880,7 @@ function runHarnessDoctor(minionsHome, opts = {}) {
|
|
|
861
880
|
const out = opts.out || (line => console.log(line));
|
|
862
881
|
|
|
863
882
|
let registry;
|
|
864
|
-
try { registry = require('
|
|
883
|
+
try { registry = require('../runtimes'); }
|
|
865
884
|
catch (e) {
|
|
866
885
|
out(`Minions Runtime Harness Inventory`);
|
|
867
886
|
out(` Could not load runtime registry: ${e.message}`);
|
|
@@ -33,16 +33,16 @@
|
|
|
33
33
|
|
|
34
34
|
const fs = require('fs');
|
|
35
35
|
const path = require('path');
|
|
36
|
-
const { runFile, cleanChildEnv,
|
|
36
|
+
const { runFile, cleanChildEnv, terminateProcess, listAllProcesses, listProcessDescendants, ts, readFileNoFollow } = require('../core/shared');
|
|
37
37
|
const {
|
|
38
38
|
resolveRuntime,
|
|
39
39
|
RUNTIME_OPTIONS_FLAG,
|
|
40
40
|
RUNTIME_IMAGES_FILE_OPTION,
|
|
41
41
|
decodeRuntimeOptions,
|
|
42
42
|
prepareWorkspace: prepareRuntimeWorkspace,
|
|
43
|
-
} = require('
|
|
44
|
-
const { acquireAdoTokenSync, isLikelyAdoToken } = require('
|
|
45
|
-
const keepProcessSweep = require('
|
|
43
|
+
} = require('../runtimes');
|
|
44
|
+
const { acquireAdoTokenSync, isLikelyAdoToken } = require('../ado/token');
|
|
45
|
+
const keepProcessSweep = require('../processes/keep-process-sweep');
|
|
46
46
|
const MAX_RUNTIME_IMAGES_FILE_BYTES = 32 * 1024 * 1024;
|
|
47
47
|
|
|
48
48
|
// ─── Pure helpers (exported for tests) ──────────────────────────────────────
|
|
@@ -246,7 +246,7 @@ async function _worktreeDirtyFiles(execFn, opts) {
|
|
|
246
246
|
const raw = typeof out === 'string'
|
|
247
247
|
? out
|
|
248
248
|
: (out?.stdout?.toString?.() ?? String(out ?? ''));
|
|
249
|
-
const shared = require('
|
|
249
|
+
const shared = require('../core/shared');
|
|
250
250
|
return String(raw)
|
|
251
251
|
.split(/\r?\n/)
|
|
252
252
|
.filter((line) => line.trim().length > 0)
|
|
@@ -329,7 +329,7 @@ async function assertStaleHeadOk({
|
|
|
329
329
|
if (!cwd) throw new Error('assertStaleHeadOk: cwd is required');
|
|
330
330
|
const execFn = typeof exec === 'function'
|
|
331
331
|
? exec
|
|
332
|
-
: require('
|
|
332
|
+
: require('../core/shared').execAsync;
|
|
333
333
|
const opts = { ...(gitOpts || {}), cwd };
|
|
334
334
|
|
|
335
335
|
// Proof of engine ownership. Absence = cannot prove current-dispatch-safe,
|
|
@@ -339,7 +339,7 @@ async function assertStaleHeadOk({
|
|
|
339
339
|
if (typeof isEngineOwned === 'function') {
|
|
340
340
|
try { return !!isEngineOwned(cwd); } catch { return false; }
|
|
341
341
|
}
|
|
342
|
-
try { return require('
|
|
342
|
+
try { return require('../core/shared').hasWorktreeOwnerMarker(cwd); } catch { return false; }
|
|
343
343
|
};
|
|
344
344
|
|
|
345
345
|
const attempts = Math.max(1, Math.trunc(Number(maxRefreshAttempts) || 0));
|
|
@@ -632,7 +632,7 @@ function main() {
|
|
|
632
632
|
deliverPromptToStdin(proc.stdin, invocation.finalPrompt, (err) => {
|
|
633
633
|
console.error(`FATAL: child startup stdin delivery failed (${err.code || 'error'}): ${err.message}`);
|
|
634
634
|
fs.appendFileSync(debugPath, `STDIN ERROR (${err.code || 'error'}): ${err.message}\n`);
|
|
635
|
-
|
|
635
|
+
terminateProcess('engine.spawn-agent.stdin-failure', proc);
|
|
636
636
|
process.exit(1);
|
|
637
637
|
});
|
|
638
638
|
} else {
|
|
@@ -649,7 +649,7 @@ function main() {
|
|
|
649
649
|
// `--add-dir` traversal, Windows process startup) the read can land well
|
|
650
650
|
// after any short timer fires, leaving Claude to bail with
|
|
651
651
|
// "System prompt file not found". The exit/SIGTERM handler below — plus the
|
|
652
|
-
// matching unlinks in engine/dispatch.js and engine/meeting.js on dispatch
|
|
652
|
+
// matching unlinks in engine/orchestration/dispatch.js and engine/orchestration/meeting.js on dispatch
|
|
653
653
|
// completion — are sufficient to keep tmp files from leaking.
|
|
654
654
|
function _cleanupSpawnTempFiles() {
|
|
655
655
|
if (wantsSystemPromptFile) {
|
|
@@ -678,7 +678,7 @@ function main() {
|
|
|
678
678
|
// that are actively working (incident: ralph-fix-mrz8ka5g0015124a pushed merge
|
|
679
679
|
// commit 8b0e6ff1 and wrote a nonce-valid success report, yet the 180s timer's
|
|
680
680
|
// killGracefully forced result:error). Startup-stall detection is owned by the
|
|
681
|
-
// engine-side spawn-phase watchdog (engine/spawn-phase-watchdog.js), which
|
|
681
|
+
// engine-side spawn-phase watchdog (engine/agents/spawn-phase-watchdog.js), which
|
|
682
682
|
// distinguishes a genuinely wedged pre-task process (idle, no live-output task
|
|
683
683
|
// activity, CPU below threshold past the grace window) from a productive-but-
|
|
684
684
|
// silent one (burning CPU) — preserving the invariant that a live tracked agent
|
|
@@ -698,13 +698,18 @@ function main() {
|
|
|
698
698
|
// taskkill /T against the dead parent PID no longer finds them. We snapshot
|
|
699
699
|
// the descendant tree periodically while the runtime is alive so the close
|
|
700
700
|
// handler can reap any survivors by PID after the parent has gone.
|
|
701
|
-
const trackedDescendants = new
|
|
701
|
+
const trackedDescendants = new Map();
|
|
702
702
|
let snapshotInFlight = false;
|
|
703
703
|
function snapshotDescendants() {
|
|
704
704
|
if (!proc.pid || snapshotInFlight) return;
|
|
705
705
|
snapshotInFlight = true;
|
|
706
706
|
try {
|
|
707
|
-
|
|
707
|
+
const processes = listAllProcesses();
|
|
708
|
+
const byPid = new Map(processes.map(entry => [Number(entry.pid), entry]));
|
|
709
|
+
for (const pid of listProcessDescendants(proc.pid, processes)) {
|
|
710
|
+
const startedAt = Number(byPid.get(pid)?.startedAt);
|
|
711
|
+
if (startedAt > 0) trackedDescendants.set(pid, startedAt);
|
|
712
|
+
}
|
|
708
713
|
} catch { /* best-effort */ }
|
|
709
714
|
finally { snapshotInFlight = false; }
|
|
710
715
|
}
|
|
@@ -782,7 +787,7 @@ function main() {
|
|
|
782
787
|
// (engine.js:1451 sets it to agents/<agentId>/live-output.log) and
|
|
783
788
|
// subtract validated, alive PIDs from the kill set. Missing or
|
|
784
789
|
// invalid file → fall through to today's behavior (reap everything).
|
|
785
|
-
let toKillPids = [...trackedDescendants];
|
|
790
|
+
let toKillPids = [...trackedDescendants.keys()];
|
|
786
791
|
let kept = [];
|
|
787
792
|
let keepRecord = null;
|
|
788
793
|
let keepReason = null;
|
|
@@ -819,7 +824,13 @@ function main() {
|
|
|
819
824
|
} else if (keepReason) {
|
|
820
825
|
try { fs.appendFileSync(debugPath, `KEEP-PIDS skipped: ${keepReason}\n`); } catch {}
|
|
821
826
|
}
|
|
822
|
-
const reaped = toKillPids.length
|
|
827
|
+
const reaped = toKillPids.length
|
|
828
|
+
? terminateProcess('engine.spawn-agent.descendants', toKillPids, {
|
|
829
|
+
expectedIdentities: new Map(
|
|
830
|
+
toKillPids.map(pid => [pid, trackedDescendants.get(pid)]),
|
|
831
|
+
),
|
|
832
|
+
})
|
|
833
|
+
: 0;
|
|
823
834
|
try { fs.appendFileSync(debugPath, `DESCENDANTS reaped=${reaped}/${toKillPids.length} kept=${kept.length}\n`); } catch {}
|
|
824
835
|
}
|
|
825
836
|
}
|