@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
package/docs/watches.md
CHANGED
|
@@ -20,41 +20,41 @@ A watch is a record persisted in `engine/state.db`. It binds:
|
|
|
20
20
|
| `requires` | Optional guard: array of predicate objects evaluated against `state` / `entity` / `prevState`; trigger is suppressed when any guard fails (false-or-error). Used to gate a watch on "PR is mergeable AND build passing" etc. |
|
|
21
21
|
| `status` | `WATCH_STATUS.ACTIVE` \| `PAUSED` \| `TRIGGERED` \| `EXPIRED` |
|
|
22
22
|
|
|
23
|
-
`createWatch()` allocates a `watch-<uid>` id, defaults the fields above, and persists through the watch store *(source: `engine/watches.js` and `engine/watches
|
|
23
|
+
`createWatch()` allocates a `watch-<uid>` id, defaults the fields above, and persists through the watch store *(source: `engine/watches/index.js` and `engine/watches/store.js`)*.
|
|
24
24
|
|
|
25
25
|
## Lifecycle (`WATCH_STATUS`)
|
|
26
26
|
|
|
27
|
-
Defined in `engine/shared.js` (`WATCH_STATUS`):
|
|
27
|
+
Defined in `engine/core/shared.js` (`WATCH_STATUS`):
|
|
28
28
|
|
|
29
29
|
| Status | Meaning |
|
|
30
30
|
|-------------|-------------------------------------------------------------------------|
|
|
31
31
|
| `active` | Eligible for evaluation each tick |
|
|
32
32
|
| `paused` | Skipped by `checkWatches`; persists indefinitely until resumed/deleted |
|
|
33
33
|
| `triggered` | Reserved status (set on demand by callers; not auto-applied) |
|
|
34
|
-
| `expired` | Auto-set when `stopAfter` is reached, or on first trigger for absolute conditions when `stopAfter === 0`. The watch is
|
|
34
|
+
| `expired` | Auto-set when `stopAfter` is reached, or on first trigger for absolute conditions when `stopAfter === 0`. The watch is retained for audit but no longer evaluated *(source: `engine/watches/index.js`)* |
|
|
35
35
|
|
|
36
|
-
Pause/resume flips the `status` field via `POST /api/watches/update` *(source: `engine/watches.js` `updateWatch`, `dashboard.js` `handleWatchesUpdate`)*.
|
|
36
|
+
Pause/resume flips the `status` field via `POST /api/watches/update` *(source: `engine/watches/index.js` `updateWatch`, `dashboard.js` `handleWatchesUpdate`)*.
|
|
37
37
|
|
|
38
38
|
## Conditions (`WATCH_CONDITION`)
|
|
39
39
|
|
|
40
|
-
Defined in `engine/shared.js` (`WATCH_CONDITION`). Conditions split into two families:
|
|
40
|
+
Defined in `engine/core/shared.js` (`WATCH_CONDITION`). Conditions split into two families:
|
|
41
41
|
|
|
42
42
|
### Absolute conditions (`WATCH_ABSOLUTE_CONDITIONS`)
|
|
43
|
-
*(source: `engine/shared.js` `WATCH_ABSOLUTE_CONDITIONS`)*
|
|
43
|
+
*(source: `engine/core/shared.js` `WATCH_ABSOLUTE_CONDITIONS`)*
|
|
44
44
|
|
|
45
45
|
`merged`, `build-fail`, `build-pass`, `completed`, `failed`, `concluded`, `approved`, `rejected`, `ready-for-merge`, `retry-limit-reached`, `all-items-done`, `item-failed-n-times`.
|
|
46
46
|
|
|
47
|
-
When `stopAfter === 0`, these are **fire-once** — the engine flips the watch to `expired` after the first trigger so a permanently-merged PR (or a permanently-true compound state assertion like `ready-for-merge`) doesn't keep notifying *(source: `engine/watches.js
|
|
47
|
+
When `stopAfter === 0`, these are **fire-once** — the engine flips the watch to `expired` after the first trigger so a permanently-merged PR (or a permanently-true compound state assertion like `ready-for-merge`) doesn't keep notifying *(source: `engine/watches/index.js`)*.
|
|
48
48
|
|
|
49
49
|
> **Per-target override (W-mp7hg58e000b5212):** the global `WATCH_ABSOLUTE_CONDITIONS` set is the legacy fallback. Each target type now declares its own `absoluteConditions: [...]` array in its spec; `registerTargetType` normalizes that into a `Set` that takes precedence at evaluation time. The plugin contract (see below) uses this to keep absolute-vs-change semantics local to each target type. Plugins that omit `absoluteConditions` get an empty set (all change-based).
|
|
50
50
|
|
|
51
51
|
### Change-based conditions
|
|
52
|
-
`status-change`, `any`, `new-comments`, `vote-change`, `stage-complete`, `ran`, `enabled`, `disabled`, `activity-change`, plus the predicate conditions added under P-w4e2f6a1 / P-w5b8d2c9 for the `pr`, `work-item`, `plan`, and `pipeline` target types (`head-commit-change`, `mergeable-flipped`, `behind-master`, `draft-flipped`, `stalled`, `dependency-met`, `stage-advanced`, `stuck-in-stage`). See `engine/shared.js` `WATCH_CONDITION` for the canonical enum.
|
|
52
|
+
`status-change`, `any`, `new-comments`, `vote-change`, `stage-complete`, `ran`, `enabled`, `disabled`, `activity-change`, plus the predicate conditions added under P-w4e2f6a1 / P-w5b8d2c9 for the `pr`, `work-item`, `plan`, and `pipeline` target types (`head-commit-change`, `mergeable-flipped`, `behind-master`, `draft-flipped`, `stalled`, `dependency-met`, `stage-advanced`, `stuck-in-stage`). See `engine/core/shared.js` `WATCH_CONDITION` for the canonical enum.
|
|
53
53
|
|
|
54
|
-
These compare the live entity against the watch's `_lastState` snapshot and run forever when `stopAfter === 0`. Baseline `_lastState` is captured on the first check so the very next change triggers the watch *(source: `engine/watches.js
|
|
54
|
+
These compare the live entity against the watch's `_lastState` snapshot and run forever when `stopAfter === 0`. Baseline `_lastState` is captured on the first check so the very next change triggers the watch *(source: `engine/watches/index.js`)*.
|
|
55
55
|
|
|
56
56
|
### Tick-counted conditions
|
|
57
|
-
`stalled`, `stuck-in-stage` — require N consecutive unchanged captures (default `WATCH_STALLED_DEFAULT_TICKS = 12`, `WATCH_STUCK_STAGE_DEFAULT_TICKS = 12`, both in `engine/shared.js`). Counters (`_unchangedTicks`, `_stuckStageTicks`) are recomputed inside `_captureState` by comparing the fresh snapshot against `prevState`.
|
|
57
|
+
`stalled`, `stuck-in-stage` — require N consecutive unchanged captures (default `WATCH_STALLED_DEFAULT_TICKS = 12`, `WATCH_STUCK_STAGE_DEFAULT_TICKS = 12`, both in `engine/core/shared.js`). Counters (`_unchangedTicks`, `_stuckStageTicks`) are recomputed inside `_captureState` by comparing the fresh snapshot against `prevState`.
|
|
58
58
|
|
|
59
59
|
### Predicate conditions
|
|
60
60
|
|
|
@@ -65,11 +65,11 @@ Several condition keys evaluate a derived predicate on the captured entity/state
|
|
|
65
65
|
- **plan** — `all-items-done` (`items_done === items_total > 0`), `item-failed-n-times` (any `missing_features[*]._retryCount >= ENGINE_DEFAULTS.maxRetries`).
|
|
66
66
|
- **pipeline** — `stage-advanced` (`current_stage_id` changed within the same `runId`), `stuck-in-stage` (current stage unchanged for `WATCH_STUCK_STAGE_DEFAULT_TICKS` checks, default 12).
|
|
67
67
|
|
|
68
|
-
Compound state-assertion predicates (`ready-for-merge`, `retry-limit-reached`, `all-items-done`, `item-failed-n-times`) live in `WATCH_ABSOLUTE_CONDITIONS` so they fire-once when `stopAfter === 0` — without that they would re-fire every tick while the assertion holds *(source: `engine/shared.js` `WATCH_ABSOLUTE_CONDITIONS`)*.
|
|
68
|
+
Compound state-assertion predicates (`ready-for-merge`, `retry-limit-reached`, `all-items-done`, `item-failed-n-times`) live in `WATCH_ABSOLUTE_CONDITIONS` so they fire-once when `stopAfter === 0` — without that they would re-fire every tick while the assertion holds *(source: `engine/core/shared.js` `WATCH_ABSOLUTE_CONDITIONS`)*.
|
|
69
69
|
|
|
70
70
|
## Target Types — `TARGET_TYPES` Registry
|
|
71
71
|
|
|
72
|
-
Target-type behavior in `engine/watches.js` is **data-driven via a registry
|
|
72
|
+
Target-type behavior in `engine/watches/index.js` is **data-driven via a registry**. Each spec uses the following fields; entries are required unless marked optional:
|
|
73
73
|
|
|
74
74
|
- `label` — human name shown in dashboard pickers
|
|
75
75
|
- `description` — **(optional)** short help text; defaults to `''` in `listTargetTypes()`
|
|
@@ -78,22 +78,22 @@ Target-type behavior in `engine/watches.js` is **data-driven via a registry** *(
|
|
|
78
78
|
- `fetchEntity(target, state)` — entity-or-null lookup; must return the fetched resource or null
|
|
79
79
|
- `captureState(entity, prevState)` — snapshot object used for change-detection diffs; `prevState` parameter lets counters and custom fields carry across checks
|
|
80
80
|
- `evaluate(condition, entity, prevState, target)` — returns `{ triggered: boolean, message: string }`; core condition-check logic
|
|
81
|
-
- `isTerminalForCondition(condition, entity, prevState)` — *(optional)* W-mqa63opd000ha836. When a watch's `condition` cannot possibly fire again because the target reached a permanent terminal state (e.g. a PR was merged/closed/abandoned and the watch is on `build-fail`, `build-pass`, `vote-change`, `new-comments`, `head-commit-change`, `mergeable-flipped`, `behind-master`, `ready-for-merge`, or `draft-flipped`), return `true` and the engine auto-expires the watch. Default returns `false` so existing target types keep polling forever. The main check loop invokes this only when `triggerCount > 0` **or** the prev-state status already matched current entity — so a watch armed on an already-terminal PR with `condition: merged` still fires once via the absolute-condition fire-once path *(source: `engine/watches.js
|
|
81
|
+
- `isTerminalForCondition(condition, entity, prevState)` — *(optional)* W-mqa63opd000ha836. When a watch's `condition` cannot possibly fire again because the target reached a permanent terminal state (e.g. a PR was merged/closed/abandoned and the watch is on `build-fail`, `build-pass`, `vote-change`, `new-comments`, `head-commit-change`, `mergeable-flipped`, `behind-master`, `ready-for-merge`, or `draft-flipped`), return `true` and the engine auto-expires the watch. Default returns `false` so existing target types keep polling forever. The main check loop invokes this only when `triggerCount > 0` **or** the prev-state status already matched current entity — so a watch armed on an already-terminal PR with `condition: merged` still fires once via the absolute-condition fire-once path *(source: `engine/watches/index.js`)*.
|
|
82
82
|
- `contextVars(entity, prevState, newState)` — *(optional)* returns object with extra action-template variables contributed by the target type (e.g., `{ httpStatus: 200, prevExtracted: 'foo' }`)
|
|
83
83
|
|
|
84
|
-
The registry IS the allowlist for `createWatch` and `/api/watches/target-types`; the old hardcoded "pr or work-item" check is gone. Add a new target type at runtime with `registerTargetType(type, spec)` and look one up with `getTargetType(type)`. `listTargetTypes()` returns the serializable form used by the dashboard
|
|
84
|
+
The registry IS the allowlist for `createWatch` and `/api/watches/target-types`; the old hardcoded "pr or work-item" check is gone. Add a new target type at runtime with `registerTargetType(type, spec)` and look one up with `getTargetType(type)`. `listTargetTypes()` returns the serializable form used by the dashboard.
|
|
85
85
|
|
|
86
|
-
### User-extensible via `
|
|
86
|
+
### User-extensible via `watch-plugins/`
|
|
87
87
|
|
|
88
|
-
At engine boot, every `*.js` file in `<MINIONS_DIR>/
|
|
88
|
+
At engine boot, every `*.js` file in `<MINIONS_DIR>/watch-plugins/` is auto-loaded **after** the built-in registrations. Plugins can add target types but cannot replace an existing type. A plugin file exports either `{ name, spec }` or an array of such objects. Failures are logged-and-skipped — one bad plugin must not break boot or block other plugins. Reloads require an engine restart.
|
|
89
89
|
|
|
90
|
-
Canonical example: `
|
|
90
|
+
Canonical example: `watch-plugins/http.js` — a generic HTTP poller covering the full plugin contract including `captureState` and `contextVars`.
|
|
91
91
|
|
|
92
|
-
This source checkout also includes `ado-author-prs`, `gh-author-prs`, and `teams-channel` plugins under `
|
|
92
|
+
This source checkout also includes `ado-author-prs`, `gh-author-prs`, and `teams-channel` plugins under `watch-plugins/`. They are dynamically loaded plugins, not members of the eight built-in target types; `GET /api/watches/target-types` is the authoritative list for the running installation.
|
|
93
93
|
|
|
94
94
|
### Built-in target types
|
|
95
95
|
|
|
96
|
-
The eight built-ins are registered at module load *(source: `engine/watches.js`
|
|
96
|
+
The eight built-ins are registered at module load *(source: `engine/watches/index.js`)*. Constants live in `WATCH_TARGET_TYPE` in `engine/core/shared.js`.
|
|
97
97
|
|
|
98
98
|
| `targetType` | Target value | Conditions | Notes |
|
|
99
99
|
|---------------|--------------------------------------|----------------------------------------------------------------------------|-------|
|
|
@@ -106,13 +106,13 @@ The eight built-ins are registered at module load *(source: `engine/watches.js`
|
|
|
106
106
|
| `dispatch` | Dispatch entry id | `completed`, `failed`, `status-change`, `any` | Looks across `pending` / `active` / `completed` lists |
|
|
107
107
|
| `agent` | Agent id | `activity-change`, `status-change`, `any` | `activity-change` fires only on transitions in/out of `'working'` |
|
|
108
108
|
|
|
109
|
-
`evaluateWatch` dispatches to `tt.evaluate(...)`; unknown target types return `"Unknown target type: ..."` and unknown conditions return `"Unknown condition: ..."` — both are non-triggering *(source: `engine/watches.js
|
|
109
|
+
`evaluateWatch` dispatches to `tt.evaluate(...)`; unknown target types return `"Unknown target type: ..."` and unknown conditions return `"Unknown condition: ..."` — both are non-triggering *(source: `engine/watches/index.js`)*.
|
|
110
110
|
|
|
111
|
-
### Plugin folder (`
|
|
111
|
+
### Plugin folder (`watch-plugins/`) — user-extensible target types
|
|
112
112
|
|
|
113
|
-
|
|
113
|
+
The plugin folder lets operators register new target types without editing engine source. At engine boot, `engine/watches/index.js` scans `<MINIONS_DIR>/watch-plugins/*.js` after the eight built-ins are registered and calls `registerTargetType()` for each unique export. Duplicate names are logged and skipped.
|
|
114
114
|
|
|
115
|
-
Each `
|
|
115
|
+
Each `watch-plugins/<name>.js` file must export `{ name, spec }` (or an array of those):
|
|
116
116
|
|
|
117
117
|
```js
|
|
118
118
|
module.exports = {
|
|
@@ -132,9 +132,9 @@ module.exports = {
|
|
|
132
132
|
};
|
|
133
133
|
```
|
|
134
134
|
|
|
135
|
-
Resolution is `path.join(shared.MINIONS_DIR, '
|
|
135
|
+
Resolution is `path.join(shared.MINIONS_DIR, 'watch-plugins')` so it works in both dev checkouts and installed `~/.minions/` layouts. Missing folder is silent; per-file failures are isolated. Legacy custom plugins under `watches.d/` remain compatibility-loaded with a warning until operators move them. Tests can re-scan via the exported `_loadPluginTargetTypes()`. Plugins are unsandboxed trusted code; see [`watch-plugins/README.md`](../watch-plugins/README.md) before adding one.
|
|
136
136
|
|
|
137
|
-
**Canonical plugin example:** [`
|
|
137
|
+
**Canonical plugin example:** [`watch-plugins/http.js`](../watch-plugins/http.js) ships a generic `http` target type — point a watch at any URL or `{ url, method, headers, body, extract, expected, regex, timeoutMs }` config and the plugin exposes `status-change`, `value-change`, `value-equals`, `value-matches`, and `http-error` conditions. Auth headers support `{{env.GH_TOKEN}}`-style substitution at fetch time. All conditions are change-based.
|
|
138
138
|
|
|
139
139
|
## Tick Integration
|
|
140
140
|
|
|
@@ -159,11 +159,11 @@ Resolution is `path.join(shared.MINIONS_DIR, 'watches.d')` so it works in both d
|
|
|
159
159
|
6. On non-trigger: writes a per-poll inbox note when `onNotMet === 'notify'`.
|
|
160
160
|
7. Refreshes `_lastState` for the next check.
|
|
161
161
|
|
|
162
|
-
I/O happens **outside the lock**. Trigger actions, including the implicit inbox notification, run through `_runActionTask`. Only `onNotMet === 'notify'` polling notes use the direct notification queue and `writeToInbox`. Each action result is persisted back onto the watch as `_lastActionResult` in a follow-up locked write. An implicit notify makes the effective action array-shaped, so its result uses the `type: 'chain'` / `steps[]` shape; an explicit action without an implicit notify preserves the legacy single-action result shape *(source: `engine/watches.js
|
|
162
|
+
I/O happens **outside the lock**. Trigger actions, including the implicit inbox notification, run through `_runActionTask`. Only `onNotMet === 'notify'` polling notes use the direct notification queue and `writeToInbox`. Each action result is persisted back onto the watch as `_lastActionResult` in a follow-up locked write. An implicit notify makes the effective action array-shaped, so its result uses the `type: 'chain'` / `steps[]` shape; an explicit action without an implicit notify preserves the legacy single-action result shape *(source: `engine/watches/index.js`)*.
|
|
163
163
|
|
|
164
164
|
## Follow-Up Actions on Trigger
|
|
165
165
|
|
|
166
|
-
`watch.action` is an optional structured action (or action chain). When the implicit inbox notification is enabled, configured actions follow it in the same effective chain. Action types live in
|
|
166
|
+
`watch.action` is an optional structured action (or action chain). When the implicit inbox notification is enabled, configured actions follow it in the same effective chain. Action types live in `engine/watches/actions.js` and are validated at create/update time. `GET /api/watches/action-types` returns the live list for dashboard pickers.
|
|
167
167
|
|
|
168
168
|
### Built-in actions
|
|
169
169
|
|
|
@@ -180,11 +180,11 @@ I/O happens **outside the lock**. Trigger actions, including the implicit inbox
|
|
|
180
180
|
| `resume-plan` | Set PRD `status=PLAN_STATUS.ACTIVE` and clear `planStale` |
|
|
181
181
|
| `cc-triage` | Invoke Command Center headlessly via the loopback `POST /api/command-center/triage` endpoint with the trigger context (and optional completion-report / live-output artifacts). Wraps the prompt in `<UNTRUSTED-INPUT>`, uses a default 10-min timeout (capped at 1 h), and is isolated from the user CC session |
|
|
182
182
|
|
|
183
|
-
Constants live in `WATCH_ACTION_TYPE` (`engine/shared.js`); handlers in `engine/
|
|
183
|
+
Constants live in `WATCH_ACTION_TYPE` (`engine/core/shared.js`); handlers live in `engine/watches/actions.js`.
|
|
184
184
|
|
|
185
185
|
### Templating
|
|
186
186
|
|
|
187
|
-
Action params support `{{var}}` substitution from the trigger context *(source: `engine/
|
|
187
|
+
Action params support `{{var}}` substitution from the trigger context *(source: `engine/watches/actions.js`)*. Built-in vars from `buildTriggerContext`:
|
|
188
188
|
|
|
189
189
|
- Always: `target`, `targetType`, `condition`, `watchId`, `triggerCount`, `message`
|
|
190
190
|
- All scalar fields from `newState` (e.g. `status`, `buildStatus`, `reviewStatus`, `lastRun`)
|
|
@@ -194,7 +194,7 @@ Unknown vars are left as `{{var}}` so callers can detect them downstream.
|
|
|
194
194
|
|
|
195
195
|
### Failure isolation
|
|
196
196
|
|
|
197
|
-
Action handlers must return `{ ok: false, summary }` rather than throw — `runWatchAction` wraps them in try/catch as a backstop
|
|
197
|
+
Action handlers must return `{ ok: false, summary }` rather than throw — `runWatchAction` wraps them in try/catch as a backstop. A bad action never blocks other watches in the same tick, and the failed result is persisted onto the watch as `_lastActionResult` for debugging. Multi-step action chains run via `runWatchActionChain` in `engine/watches/actions.js`.
|
|
198
198
|
|
|
199
199
|
## Dashboard Surface
|
|
200
200
|
|
|
@@ -227,8 +227,8 @@ CC will discover the endpoints from `GET /api/routes` and `POST /api/watches` wi
|
|
|
227
227
|
When a watch fires:
|
|
228
228
|
|
|
229
229
|
- The SQL watch record gets `triggerCount++`, `last_triggered=<ISO>`, `_lastTriggerMessage=<message>`, and a refreshed `_lastState`.
|
|
230
|
-
- When `notify === 'inbox'`, the engine prepends an implicit `{type: 'notify'}` action to the action chain (if present) or runs notify standalone, so the inbox alert participates in action-chain execution and `_lastActionResult` *(source: `engine/watches.js
|
|
231
|
-
- When `onNotMet === 'notify'` (and the condition has NOT yet fired), the engine instead queues a direct poll notification outside the action chain — independent of any `action` field *(source: `engine/watches.js
|
|
230
|
+
- When `notify === 'inbox'`, the engine prepends an implicit `{type: 'notify'}` action to the action chain (if present) or runs notify standalone, so the inbox alert participates in action-chain execution and `_lastActionResult` *(source: `engine/watches/index.js`)*. This is the **trigger-time notify**, paired with an optional explicit `action`.
|
|
231
|
+
- When `onNotMet === 'notify'` (and the condition has NOT yet fired), the engine instead queues a direct poll notification outside the action chain — independent of any `action` field *(source: `engine/watches/index.js`)*. This is a separate **onNotMet-notify**, useful for "still watching, condition not met yet" progress updates.
|
|
232
232
|
- If an action runs, `_lastActionResult` stores either the single-action shape (`{ type, ok, summary, dispatchedItemId, at }`) or the chain shape (`{ type: "chain", ok, summary, aborted, steps, at }`).
|
|
233
233
|
- The SQL engine log gets `Watch triggered: <id> — <message>` and `Watch <id> action <type-or-chain[N]>: <summary>`.
|
|
234
234
|
|
|
@@ -241,21 +241,22 @@ Absolute conditions firing under `stopAfter === 0` flip `status` to `expired`; `
|
|
|
241
241
|
| Watch never fires | Check `status === 'active'`; check `last_checked` advancing each cycle; confirm engine tick is running and `interval` isn't longer than your test window |
|
|
242
242
|
| `evaluateWatch` returns `"<label> <target> not found"` | `fetchEntity` got nothing back — wrong `target` (e.g. PR display id vs canonical id), the target type isn't loaded, or the underlying file (PR cache, plan PRD) doesn't exist |
|
|
243
243
|
| `"Unknown target type"` / `"Unknown condition"` | The registry doesn't recognise the value. Check `GET /api/watches/target-types` to see what's registered server-side; condition must be in that target type's `conditions[]` |
|
|
244
|
-
| Change condition fires immediately on first tick | Won't happen — baseline `_lastState` is captured on the first check before `evaluate` runs *(source: `engine/watches.js`)*. If you see this, inspect the persisted watch through the API |
|
|
244
|
+
| Change condition fires immediately on first tick | Won't happen — baseline `_lastState` is captured on the first check before `evaluate` runs *(source: `engine/watches/index.js`)*. If you see this, inspect the persisted watch through the API |
|
|
245
245
|
| Absolute watch fires forever instead of once | `stopAfter` is set to a non-zero value; only `stopAfter === 0` triggers fire-once expiration |
|
|
246
246
|
| Action runs but inbox notification doesn't | `notify` field isn't `'inbox'`, or `owner` is empty. `notify` and `action` are independent — both can fire, or only one |
|
|
247
247
|
| `_lastActionResult.ok === false` with `"unknown action type"` | The `action.type` isn't registered. List with `listActionTypes()` / `GET /api/watches/action-types` |
|
|
248
|
-
| Webhook action returns `"only http/https allowed"` | URLs must use `http://` or `https://` schemes; other protocols are rejected by design *(source: `engine/
|
|
248
|
+
| Webhook action returns `"only http/https allowed"` | URLs must use `http://` or `https://` schemes; other protocols are rejected by design *(source: `engine/watches/actions.js` `WEBHOOK` handler)* |
|
|
249
249
|
| Trigger fires but follow-up `dispatch-work-item` is missing | Check the engine log for `Watch <id> action <type>: <summary>`. Common reasons: missing `title`, a project-scope write failed, or the WI landed in the central scope because no project was specified |
|
|
250
|
-
| Watch `_lastActionResult` shows `"timeout"` for webhook | Webhooks have a 10s safety timeout to keep the watches tick fast *(source: `engine/
|
|
250
|
+
| Watch `_lastActionResult` shows `"timeout"` for webhook | Webhooks have a 10s safety timeout to keep the watches tick fast *(source: `engine/watches/actions.js`)* |
|
|
251
251
|
| `checkWatches` block crashes silently | Wrapped in `safe('checkWatches', ...)` so one failure doesn't abort the tick. Inspect the engine log for `Watch check error (<id>)` lines. Regression #1088: the block must use `getProjects(config)`, never the long-removed `PROJECTS` constant |
|
|
252
252
|
|
|
253
253
|
## See Also
|
|
254
254
|
|
|
255
|
-
- `engine/shared.js` — `WATCH_STATUS`, `WATCH_TARGET_TYPE`, `WATCH_CONDITION`, `WATCH_ABSOLUTE_CONDITIONS`, `WATCH_ACTION_TYPE` constants
|
|
256
|
-
- `engine/watches.js` — registry, lifecycle, tick integration, `
|
|
257
|
-
- `engine/
|
|
258
|
-
- `watches
|
|
255
|
+
- `engine/core/shared.js` — `WATCH_STATUS`, `WATCH_TARGET_TYPE`, `WATCH_CONDITION`, `WATCH_ABSOLUTE_CONDITIONS`, `WATCH_ACTION_TYPE` constants
|
|
256
|
+
- `engine/watches/index.js` — registry, lifecycle, tick integration, `watch-plugins/` loader
|
|
257
|
+
- `engine/watches/actions.js` — action registry and built-in handlers
|
|
258
|
+
- `engine/watches/store.js` — SQL-backed watch persistence
|
|
259
|
+
- `watch-plugins/http.js` — canonical user-extensible target type plugin
|
|
259
260
|
- `dashboard/pages/watches.html`, `dashboard/js/render-watches.js` — dashboard UI
|
|
260
261
|
- `test/unit/watches-module.test.js`, `test/unit/watch-actions.test.js`, `test/unit/watches-plugin-loader.test.js` — module-level tests
|
|
261
262
|
- [`auto-discovery.md`](auto-discovery.md) — overall tick cycle context
|
|
@@ -38,7 +38,7 @@ A manifest lives on each agent definition under `workspace_manifest`. All fields
|
|
|
38
38
|
The defaults are deliberately permissive so the manifest can be rolled out incrementally:
|
|
39
39
|
|
|
40
40
|
```js
|
|
41
|
-
// engine/shared.js
|
|
41
|
+
// engine/core/shared.js
|
|
42
42
|
const WORKSPACE_MANIFEST_DEFAULTS = {
|
|
43
43
|
allowed_tools: null, // no tool restriction
|
|
44
44
|
allowed_repos: null, // no repo restriction
|
|
@@ -59,13 +59,13 @@ A config that never mentions `workspace_manifest` produces the exact same dispat
|
|
|
59
59
|
| **URL fetch** | Advisory today | `allowed_external_urls` is validated at config load. No runtime helper function — a future runtime adapter hook can wire URL-fetch intercepts against the manifest. |
|
|
60
60
|
| **Memory scope** | Advisory today | `memory_scope` field is stored in the manifest (`private` = agent only sees its own `knowledge/agents/<id>.md`; `shared` = full team knowledge (current default); `read-only-shared` = reads shared memory but should not write inbox/notes). No runtime enforcement helper — full enforcement at the consolidation layer is future work. |
|
|
61
61
|
|
|
62
|
-
## Helpers (in `engine/shared.js`)
|
|
62
|
+
## Helpers (in `engine/core/shared.js`)
|
|
63
63
|
|
|
64
64
|
```js
|
|
65
65
|
const { MEMORY_SCOPES, WORKSPACE_MANIFEST_DEFAULTS,
|
|
66
66
|
validateWorkspaceManifest, resolveAgentManifest,
|
|
67
67
|
agentCanUseRepo,
|
|
68
|
-
mergeManifestAllowedTools, formatManifestRejection } = require('./engine/shared');
|
|
68
|
+
mergeManifestAllowedTools, formatManifestRejection } = require('./engine/core/shared');
|
|
69
69
|
```
|
|
70
70
|
|
|
71
71
|
- `validateWorkspaceManifest(manifest)` → `{ ok, errors }`. `null`/`undefined` is valid (uses defaults).
|
|
@@ -95,7 +95,7 @@ Because rejections route through the standard `completeDispatch(... ERROR ...)`
|
|
|
95
95
|
|
|
96
96
|
## Related
|
|
97
97
|
|
|
98
|
-
- `engine/shared.js` — manifest helpers and `FAILURE_CLASS`.
|
|
98
|
+
- `engine/core/shared.js` — manifest helpers and `FAILURE_CLASS`.
|
|
99
99
|
- `engine.js spawnAgent()` — dispatch-time enforcement.
|
|
100
100
|
- `test/unit/workspace-manifest.test.js` — full validator + gate + integration tests.
|
|
101
101
|
- [`completion-reports.md`](completion-reports.md) — how the dispatch failure surfaces in the standard completion contract.
|