dev-loops 0.6.0 → 0.7.2
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/.claude/.claude-plugin/plugin.json +1 -1
- package/.claude/agents/dev-loop.md +8 -7
- package/.claude/agents/fixer.md +1 -0
- package/.claude/agents/refiner.md +2 -2
- package/.claude/agents/review.md +4 -3
- package/.claude/commands/{auto.md → loop-auto.md} +1 -1
- package/.claude/commands/loop-continue.md +15 -0
- package/.claude/commands/loop-enqueue.md +22 -0
- package/.claude/commands/loop-grill.md +17 -0
- package/.claude/commands/{info.md → loop-info.md} +2 -2
- package/.claude/commands/loop-queue-status.md +24 -0
- package/.claude/commands/{start-spike.md → loop-start-spike.md} +2 -2
- package/.claude/commands/{start.md → loop-start.md} +1 -1
- package/.claude/commands/{status.md → loop-status.md} +1 -1
- package/.claude/hooks/_bash-command-classify.mjs +333 -29
- package/.claude/hooks/_hook-decisions.mjs +138 -15
- package/.claude/hooks/pre-tool-use-bash-gate.mjs +36 -15
- package/.claude/skills/copilot-pr-followup/SKILL.md +60 -34
- package/.claude/skills/dev-loop/SKILL.md +16 -12
- package/.claude/skills/docs/acceptance-criteria-verification.md +8 -3
- package/.claude/skills/docs/anti-patterns.md +5 -3
- package/.claude/skills/docs/artifact-authority-contract.md +30 -11
- package/.claude/skills/docs/confirmation-rules.md +1 -0
- package/.claude/skills/docs/contract-style-guide.md +37 -0
- package/.claude/skills/docs/copilot-loop-operations.md +19 -15
- package/.claude/skills/docs/cross-harness-regression-contract.md +60 -0
- package/.claude/skills/docs/debt-remediation-contract.md +1 -1
- package/.claude/skills/docs/epic-tree-refinement-procedure.md +25 -22
- package/.claude/skills/docs/issue-intake-procedure.md +26 -19
- package/.claude/skills/docs/local-planning-flow.md +1 -1
- package/.claude/skills/docs/local-planning-worked-example.md +1 -1
- package/.claude/skills/docs/merge-preconditions.md +30 -12
- package/.claude/skills/docs/plan-file-contract.md +1 -1
- package/.claude/skills/docs/pr-lifecycle-contract.md +44 -35
- package/.claude/skills/docs/public-dev-loop-contract.md +60 -44
- package/.claude/skills/docs/retrospective-checkpoint-contract.md +106 -79
- package/.claude/skills/docs/spike-mode-contract.md +14 -7
- package/.claude/skills/docs/stop-conditions.md +30 -15
- package/.claude/skills/docs/tracker-first-loop-state.md +13 -8
- package/.claude/skills/docs/ui-e2e-scoping-step.md +32 -0
- package/.claude/skills/docs/validation-policy.md +4 -5
- package/.claude/skills/docs/workflow-handoff-contract.md +39 -0
- package/.claude/skills/local-implementation/SKILL.md +62 -145
- package/.claude/skills/loop-grill/SKILL.md +163 -0
- package/AGENTS.md +1 -0
- package/CHANGELOG.md +101 -0
- package/README.md +9 -9
- package/agents/dev-loop.agent.md +11 -10
- package/agents/developer.agent.md +1 -1
- package/agents/docs.agent.md +1 -1
- package/agents/fixer.agent.md +2 -1
- package/agents/quality.agent.md +1 -1
- package/agents/refiner.agent.md +3 -3
- package/agents/review.agent.md +5 -4
- package/cli/index.mjs +35 -42
- package/extension/README.md +4 -4
- package/extension/checks.ts +1 -5
- package/extension/harness-types.ts +1 -0
- package/extension/index.ts +6 -0
- package/extension/pi-extension-adapter.ts +2 -0
- package/extension/presentation.ts +7 -19
- package/package.json +12 -12
- package/scripts/_core-helpers.mjs +2 -0
- package/scripts/claude/headless-dev-loop.mjs +1 -1
- package/scripts/docs/validate-rule-ownership.mjs +442 -0
- package/scripts/docs/validate-state-machine-conformance.mjs +1092 -0
- package/scripts/github/_review-thread-mutations.mjs +5 -2
- package/scripts/github/capture-review-threads.mjs +2 -9
- package/scripts/github/comment-issue.mjs +2 -9
- package/scripts/github/create-label.mjs +133 -0
- package/scripts/github/create-pr.mjs +119 -10
- package/scripts/github/detect-checkpoint-evidence.mjs +259 -18
- package/scripts/github/detect-linked-issue-pr.mjs +22 -6
- package/scripts/github/edit-pr.mjs +259 -0
- package/scripts/github/fetch-ci-logs.mjs +2 -9
- package/scripts/github/list-issues.mjs +2 -9
- package/scripts/github/list-review-threads.mjs +277 -0
- package/scripts/github/manage-sub-issues.mjs +46 -10
- package/scripts/github/offer-human-handoff.mjs +8 -5
- package/scripts/github/post-gate-findings.mjs +20 -5
- package/scripts/github/probe-ci-status.mjs +8 -2
- package/scripts/github/probe-copilot-review.mjs +21 -14
- package/scripts/github/ready-for-review.mjs +26 -8
- package/scripts/github/reconcile-draft-gate.mjs +7 -3
- package/scripts/github/reply-resolve-review-thread.mjs +16 -5
- package/scripts/github/reply-resolve-review-threads.mjs +69 -7
- package/scripts/github/request-copilot-review.mjs +98 -26
- package/scripts/github/resolve-handoff-candidates.mjs +7 -3
- package/scripts/github/resolve-tracker-local-spec.mjs +9 -3
- package/scripts/github/stage-reviewer-draft.mjs +10 -2
- package/scripts/github/tick-verified-checkboxes.mjs +202 -0
- package/scripts/github/upsert-checkpoint-verdict.mjs +105 -15
- package/scripts/github/verify-briefing-prefixes.mjs +191 -0
- package/scripts/github/verify-fresh-review-context.mjs +226 -32
- package/scripts/github/view-pr.mjs +150 -0
- package/scripts/github/wait-pr-checks.mjs +171 -0
- package/scripts/github/write-gate-context.mjs +458 -65
- package/scripts/github/write-gate-findings-log.mjs +128 -2
- package/scripts/lib/jq-output.mjs +18 -0
- package/scripts/loop/_post-convergence-change.mjs +211 -0
- package/scripts/loop/_pr-runner-coordination.mjs +70 -0
- package/scripts/loop/_repo-root-resolver.mjs +47 -0
- package/scripts/loop/build-handoff-envelope.mjs +14 -4
- package/scripts/loop/check-retro-tooling.mjs +14 -3
- package/scripts/loop/checkpoint-contract.mjs +7 -4
- package/scripts/loop/cleanup-worktree.mjs +12 -3
- package/scripts/loop/conductor-monitor.mjs +12 -18
- package/scripts/loop/copilot-pr-handoff.mjs +162 -14
- package/scripts/loop/debt-remediate.mjs +24 -12
- package/scripts/loop/detect-change-scope.mjs +38 -9
- package/scripts/loop/detect-copilot-loop-state.mjs +34 -8
- package/scripts/loop/detect-copilot-session-activity.mjs +7 -3
- package/scripts/loop/detect-initial-copilot-pr-state.mjs +7 -3
- package/scripts/loop/detect-internal-only-pr.mjs +8 -2
- package/scripts/loop/detect-issue-refinement-artifact.mjs +6 -3
- package/scripts/loop/detect-pr-gate-coordination-state.mjs +184 -69
- package/scripts/loop/detect-reviewer-loop-state.mjs +12 -2
- package/scripts/loop/detect-tracker-first-loop-state.mjs +9 -1
- package/scripts/loop/detect-tracker-pr-state.mjs +10 -3
- package/scripts/loop/ensure-worktree.mjs +8 -3
- package/scripts/loop/info.mjs +12 -4
- package/scripts/loop/inspect-run-viewer/constants.mjs +4 -18
- package/scripts/loop/inspect-run-viewer/vendor/mermaid.min.js +3405 -0
- package/scripts/loop/inspect-run-viewer-ci-changes.mjs +18 -6
- package/scripts/loop/inspect-run-viewer.mjs +67 -4
- package/scripts/loop/inspect-run.mjs +8 -2
- package/scripts/loop/outer-loop.mjs +8 -4
- package/scripts/loop/pr-runner-coordination.mjs +2 -9
- package/scripts/loop/pre-commit-branch-guard.mjs +16 -10
- package/scripts/loop/pre-flight-gate.mjs +9 -9
- package/scripts/loop/pre-pr-ready-gate.mjs +8 -4
- package/scripts/loop/pre-write-remote-freshness-guard.mjs +13 -4
- package/scripts/loop/provision-worktree.mjs +74 -3
- package/scripts/loop/resolve-dev-loop-startup.mjs +216 -10
- package/scripts/loop/resolve-gate-dispatch.mjs +134 -0
- package/scripts/loop/resolve-pr-conflicts.mjs +14 -7
- package/scripts/loop/run-conductor-cycle.mjs +8 -2
- package/scripts/loop/run-queue.mjs +18 -9
- package/scripts/loop/run-refinement-audit.mjs +8 -9
- package/scripts/loop/run-watch-cycle.mjs +2 -9
- package/scripts/loop/sanctioned-commands.mjs +106 -0
- package/scripts/loop/steer-loop.mjs +29 -16
- package/scripts/loop/validate-pr-body-spec.mjs +223 -0
- package/scripts/loop/watch-initial-copilot-pr.mjs +8 -3
- package/scripts/pages/build-site.mjs +59 -8
- package/scripts/pages/build-state-atlas.mjs +443 -0
- package/scripts/projects/_resolve-project.mjs +1 -0
- package/scripts/projects/add-queue-item.mjs +60 -54
- package/scripts/projects/archive-done-items.mjs +49 -84
- package/scripts/projects/ensure-queue-board.mjs +10 -36
- package/scripts/projects/list-queue-items.mjs +59 -382
- package/scripts/projects/move-queue-item.mjs +21 -449
- package/scripts/projects/reconcile-queue.mjs +253 -0
- package/scripts/projects/reorder-queue-item.mjs +43 -68
- package/scripts/projects/resolve-active-board-item.mjs +108 -46
- package/scripts/projects/sync-item-status.mjs +15 -10
- package/scripts/refine/_refine-helpers.mjs +21 -5
- package/scripts/refine/exit-spike.mjs +18 -8
- package/scripts/refine/promote-plan.mjs +22 -16
- package/scripts/refine/prose-linkage-detector.mjs +1 -1
- package/scripts/refine/refine-plan-file.mjs +13 -4
- package/scripts/refine/refinement-completeness-checker.mjs +1 -1
- package/scripts/refine/scaffold-spike-file.mjs +4 -8
- package/scripts/refine/scope-boundary-cross-checker.mjs +1 -1
- package/scripts/refine/tree-integrity-validator.mjs +1 -1
- package/scripts/refine/validate-plan-file.mjs +1 -1
- package/scripts/refine/validate-spike-file.mjs +1 -1
- package/scripts/refine/verify.mjs +11 -6
- package/scripts/release/assert-core-dependency-version.mjs +123 -0
- package/scripts/release/extract-changelog-section.mjs +16 -2
- package/skills/copilot-pr-followup/SKILL.md +60 -34
- package/skills/dev-loop/SKILL.md +11 -7
- package/skills/docs/acceptance-criteria-verification.md +8 -3
- package/skills/docs/anti-patterns.md +5 -3
- package/skills/docs/artifact-authority-contract.md +30 -11
- package/skills/docs/confirmation-rules.md +1 -0
- package/skills/docs/contract-style-guide.md +37 -0
- package/skills/docs/copilot-loop-operations.md +19 -15
- package/skills/docs/cross-harness-regression-contract.md +60 -0
- package/skills/docs/debt-remediation-contract.md +1 -1
- package/skills/docs/epic-tree-refinement-procedure.md +25 -22
- package/skills/docs/issue-intake-procedure.md +26 -19
- package/skills/docs/local-planning-flow.md +1 -1
- package/skills/docs/local-planning-worked-example.md +1 -1
- package/skills/docs/merge-preconditions.md +30 -12
- package/skills/docs/plan-file-contract.md +1 -1
- package/skills/docs/pr-lifecycle-contract.md +44 -35
- package/skills/docs/public-dev-loop-contract.md +60 -44
- package/skills/docs/required-rules.json +149 -0
- package/skills/docs/retrospective-checkpoint-contract.md +106 -79
- package/skills/docs/spike-mode-contract.md +14 -7
- package/skills/docs/stop-conditions.md +30 -15
- package/skills/docs/tracker-first-loop-state.md +13 -8
- package/skills/docs/ui-e2e-scoping-step.md +32 -0
- package/skills/docs/validation-policy.md +4 -5
- package/skills/docs/workflow-handoff-contract.md +39 -0
- package/skills/local-implementation/SKILL.md +62 -145
- package/skills/loop-grill/SKILL.md +165 -0
- package/.claude/commands/continue.md +0 -15
- package/scripts/docs/validate-no-duplicate-rules.mjs +0 -250
- package/scripts/loop/conductor.mjs +0 -233
- package/scripts/loop/detect-stale-runner.mjs +0 -265
- package/scripts/loop/pre-push-main-guard.mjs +0 -117
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,107 @@ All notable changes to this project will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
## Unreleased
|
|
6
6
|
|
|
7
|
+
## 0.7.2 - 2026-07-06
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- **Package-escaping imports in `@dev-loops/core` broke every consumer install (#1241).** `queue-board-sync.mjs` and `queue-board-ordering.mjs` imported `move-queue-item`/`list-queue-items` via `../../../../scripts/projects/*`, paths outside the package root that the published tarball (src/**+bin/** only) cannot resolve — so `resolve-active-board-item` (loop startup) and `ready-for-review` threw `ERR_MODULE_NOT_FOUND` on install for every release from 0.3.0 to 0.7.1. The `main` implementations now live in `@dev-loops/core` (`src/projects/`, exported via the package map); the two `scripts/projects/*` files are thin CLI wrappers importing core by package name. A packaged-install smoke test (`test:pack`) npm-packs both packages, installs them in a temp dir, imports every `@dev-loops/core` export-map entry, and runs the affected CLIs with `--help` — closing the artifact-layout gap that let five releases ship broken.
|
|
12
|
+
|
|
13
|
+
## 0.7.1 - 2026-07-05
|
|
14
|
+
|
|
15
|
+
### Changed
|
|
16
|
+
|
|
17
|
+
- **`captureDiffFromBase` pins `diff.renames`/`diff.algorithm`/`diff.context` and `core.abbrev`/`core.autocrlf` for cross-environment reproducibility (#1168).** The isolation `-c` overrides for the persisted `--base` neutral diff seed already made the diff byte-identical within a single run, but a machine with a contrary local gitconfig could still produce different bytes for the same base/HEAD pair — and, via `diff.renames`, a different `scope.changedFiles`/`adjacentCode` membership (rename vs delete+add). The five settings are now pinned alongside the existing overrides.
|
|
18
|
+
|
|
19
|
+
### Removed
|
|
20
|
+
|
|
21
|
+
- **Dead `isFenceLine` field dropped from `stepFence` (#1166).** `stepFence` (`packages/core/src/loop/issue-refinement-artifact.mjs`) computed and returned `isFenceLine` on every branch, but none of its three call sites (`parseMarkdownSections`, `extractChecklistItems`, `sectionHasBody`) read it. Removed from the return shape and its JSDoc; `fence`/`insideFence` and all fence-detection logic are unchanged.
|
|
22
|
+
|
|
23
|
+
### Fixed
|
|
24
|
+
|
|
25
|
+
- **Worktree provisioning creates the `@dev-loops/core` workspace link so `scripts/**` CLIs validate the branch's core (#1144).** Worktrees provisioned by `ensure-worktree.mjs`/`provision-worktree.mjs` have no `node_modules`, so any `scripts/**` CLI importing `@dev-loops/core` resolved the bare specifier by walking up to the MAIN checkout's `node_modules/@dev-loops/core` instead of the worktree's own `packages/core` — `npm run verify` in a worktree silently tested main's core, not the branch's. Provisioning now creates the relative symlink `node_modules/@dev-loops/core → ../../packages/core` unconditionally: idempotent on a correct existing link, replaces a stale/broken link, never clobbers a real file/dir already at the destination, and is reported in the provisioning summary.
|
|
26
|
+
- **Sibling logical columns resolved via `loadStateColumnMap` in pickup and archive (#1143).** `resolve-active-board-item.mjs` hardcoded the literal `"In Progress"` column for the live `/loop-continue` pickup query instead of resolving it through `loadStateColumnMap`/`LOGICAL_COLUMN.IN_PROGRESS` the way #1142 already did for Next Up, so a repo overriding `queue.statusColumns.in_progress` would have pickup silently miss the active item. An audit found the same gap in `archive-done-items.mjs` (`selectArchivable()` hardcoded `"Done"`). Both now resolve through the shared mapping, fail closed on a malformed `.devloops`, and honor configured overrides; `--help`/display literals in other scripts were left as-is (illustrative examples, not routing logic).
|
|
27
|
+
- **The post-convergence significance detector is content-aware, so comment/JSDoc-only changes don't reopen Copilot past the round cap (#1137).** Significance in `_post-convergence-change.mjs` (shared by `copilot-pr-handoff` and `detect-pr-gate-coordination-state`) was classified by path/size only, so a trivial comment fix could re-trip a re-request past the cap. A new `isCommentOnlyFileChange` classifier inspects the compare diff's patch hunks with a per-hunk block-comment state machine (reset at every `@@` header, conservative toward "significant") and filters comment-only JS/TS files out before the existing `>=20 lines`/`>=2 files` thresholds. A file with no `patch` (binary/oversized) is never treated as comment-only; the stale `+++`/`---` header-skip (never present in `gh compare` patches) was removed.
|
|
28
|
+
- **`copilot-pr-handoff` fails closed on a pending Copilot review at the round cap (#1165).** At the cap with a `--force-rerequest-review` in flight, handoff routed to `ROUND_CAP_CLEAN_FALLBACK` ("continue to pre_approval_gate") whenever the fail-silent secondary reopen-facts fetch (`gh pr view` + `gh compare`) failed — silently reading significance as false — while `detect-pr-gate-coordination-state`, reusing its already-validated PR data, correctly gated; the loop follows handoff as the pre-flight authority, so a significant change could skip Copilot's review (hit live on PR #1164). While a requested review is pending on the current head at the cap, handoff now surfaces `waiting_for_copilot_review` (action `watch`) before the fragile escape-hatch fetch can downgrade to "proceed"; a `--watch-status` refresh skips the guard so a request that never resolves re-settles to the clean fallback and the loop cannot dead-end.
|
|
29
|
+
- **Merge-block hook message explains that evidence writes and `gh pr merge` must be separate tool calls (#1172).** The "vanishing" gate-evidence ledgers on PRs #1167/#1169/#1171 were never swept: the PreToolUse bash gate evaluates `gh pr merge` before the tool call executes, so a compound command that both writes gate evidence (`write-gate-findings-log`/`upsert-checkpoint-verdict`) and merges in the same call is blocked at hook time — the write never runs. `decideBashGate` now appends a hint to the deny message in exactly that compound case (a bare `gh pr merge` keeps the standard message; no allow/deny boundary changes), and the write → verify → merge-alone contract is documented in `skills/docs/merge-preconditions.md`.
|
|
30
|
+
- **Light-mode-aware pre-merge gate accepts scoped inline verdicts (#1174).** `buildPreMergeGateCheck` rejected any `inline_single_agent` verdict whenever `gates.requireFanoutEvidence` was on (the repo default), so a genuinely under-threshold micro-PR's #1043 light-path verdict was unmergeable without a full fan-out (hit live on PR #1173, 1 file / 11 lines). An inline verdict is now accepted only when lightMode is enabled, the merge-base scope re-derived at merge time is under threshold (underivable scope → rejected, fail-closed), no `gate:full` label is present, and a non-empty inline reason is recorded; the findings-log ledger is still required, and the fan-out path (`fanout_fanin` verdicts, ledger, provenance enforcement) is unchanged.
|
|
31
|
+
- **`validate-pr-body-spec` enforces a `Closes #N` closing-keyword reference (#1181).** Five lightweight PRs merged without auto-closing their issues because the PR-body-as-spec validator never required the linkage. It now fails closed with `missing_closing_issue_reference` when the body carries no GitHub closing-keyword issue reference, supports `--expected-issue <n>` (`closes_wrong_issue` on a mismatch), and reports the extracted `closesIssues` — all keyword variants and the cross-repo `owner/repo#N` form accepted, while references inside fenced code blocks or inline code spans don't count.
|
|
32
|
+
|
|
33
|
+
## 0.7.0 - 2026-07-05
|
|
34
|
+
|
|
35
|
+
### Added
|
|
36
|
+
|
|
37
|
+
- **Lightweight local-first path — PR body as spec-of-record, no phase doc (#1025).** Local-first now supports a lightweight path for chores, bugfixes, and small mechanical changes where the PR description itself is the spec-of-record — no phase/plan doc is minted or committed. When active, `loop startup` no longer requires `--plan-file` and the pre-approval review agent reads the PR body (objective, in-scope/non-goals, testable acceptance criteria, definition of done, risks) instead of resolving a plan-file path; a new `validate-pr-body-spec` CLI enforces the required sections fail-closed. The gate sequence is unchanged (draft → pre-approval fanout → detect-evidence → human merge); only the backing artifact differs. Closes the phase-history pollution from minting a numbered phase doc for a six-file rename chore.
|
|
38
|
+
- **`lightMode` wired to gate dispatch — micro-PRs skip full fanout (#1043).** A PR under the `localImplementation.lightMode` threshold (`maxFiles`/`maxLines`, and no `gate:full` label) collapses the `draft_gate` + `pre_approval_gate` fanout to a single inline correctness + no-op check and skips Copilot polling; the draft→ready boundary is still recorded (`requireDraftFirst`). Two escalation paths: the inline check auto-escalates to full fanout on any finding at or above `worth-fixing-now`, and the maintainer-controlled `gate:full` label forces full fanout regardless of size. Scope detection fails closed — a diff whose size can't be determined runs the full fanout, not the light path.
|
|
39
|
+
- **Context-builder additive angle authority (#1048).** Gate angle resolution was subtractive-only (it could drop configured angles but never add one). With `gates.<gate>.additiveAngles` enabled (default off), the resolver may now pull in a review lens the diff's change categories imply even when it isn't in the gate's configured pool — drawn from `gates.anglePool` (or the union of known personas). Bounded and auditable: `excludeAngles` stays a hard ceiling, `mandatoryAngles` the floor, and each addition is recorded with an `"added"` rationale naming the triggering category alongside the existing kept/dropped entries.
|
|
40
|
+
- **Grouped board-summary mode for `queue list` (#1061).** `dev-loops queue list --summary` (alias `--group-by status`) returns a whole-board digest grouped by Status column in board order (`{ ok, groups: { <status>: { count, items } } }`), with `--done-limit` to cap the Done group, composing with `--jq`/`--silent`. One sanctioned call for the by-status overview that previously tempted an inline `| python3` grouping (retro rule 5); `--summary` is mutually exclusive with `--column`/`--limit`.
|
|
41
|
+
- **Cross-harness regression contract (#1086).** dev-loops is harness-agnostic (Pi + Claude Code); the rule "any harness-specific change MUST NOT regress other harnesses" is now a repo-wide working rule in `AGENTS.md`, with the detailed procedure in `skills/docs/cross-harness-regression-contract.md` (what counts as a harness-specific change, the required Claude-Code-path suites, and the additive-on-Pi / no-op-or-validated-on-Claude bar). Promotes the constraint from an ad-hoc section of #1084 to a universal, pre-0.7 enforced contract.
|
|
42
|
+
|
|
43
|
+
### Changed
|
|
44
|
+
|
|
45
|
+
- **`LOGIC_CHANGE` maps to a core review subset instead of fallback-to-all (#1049).** `dynamicAngles` was effectively decorative for code PRs: any non-trivial code change classified as `ambiguous`, which fell back to the full 15-angle draft pool. `LOGIC_CHANGE` now maps to a core-for-code angle subset in `CATEGORY_ANGLE_MAP` and no longer forces `ambiguous`/fallback-to-all (reserved for genuinely unclassifiable diffs); other categories still union in their mapped angles. A typical code PR now resolves to a handful of angles, with peripheral lenses (link-check, config-drift, etc.) appearing only when the diff implicates their category. Mandatory floor and exclude ceiling unchanged; each dropped angle keeps its recorded rationale.
|
|
46
|
+
- **`--jq`/`--silent` are now a base-CLI guarantee for every JSON-emitting command (#1071).** The output contract was per-script opt-in, so JSON-emitting commands like `sync-item-status.mjs` rejected `--jq` and forced grep/inline-parse workarounds. Every JSON-emitting command now routes through the shared emit path (`scripts/lib/jq-output.mjs`), so `--jq` filtering, invalid-filter fail-closed (exit 2), and `--silent` exit-code-only come for free; a contract test enforces it so new commands inherit the guarantee and can't regress.
|
|
47
|
+
- **Sanctioned operation→wrapper command map baked into the default handoff (#1081).** Which dev-loops wrapper to use for which operation (reads: `view-pr`/`probe-ci-status`/`fetch-ci-logs`/`list-issues`/`probe-copilot-review`; edits: `edit-pr`/`comment-issue`; lifecycle: `ready-for-review`/`create-pr`/`request-copilot-review`/`reply-resolve`/gate-verdict) is now a structural part of every dev-loop handoff, sourced once (`scripts/loop/sanctioned-commands.mjs`, carried via the handoff envelope + `agents/dev-loop.agent.md`) instead of an ad-hoc per-handoff decision — so a spawned subagent no longer re-derives the map or rediscovers a wrapper mid-run.
|
|
48
|
+
- **Playwright configs consolidated into one projects-based, registry-driven config (#1056).** The five byte-identical `playwright.*.config.mjs` files (one per UI slice) collapse to a single `playwright.config.mjs` with one Playwright project per registered slice; `test:playwright:<slice>` scripts run `--project=<slice>`. Adding a UI artifact now needs only a registry entry (already required by the ui-e2e-scoping gate) and no new config file; per-slice output dirs / report paths are preserved.
|
|
49
|
+
- **Deduplicated the three Playwright smoke jobs via a composite action (#1058).** `viewer-smoke` / `deck-smoke` / `article-smoke` shared copy-pasted setup (checkout, Node, `npm ci`, WebKit cache-restore, `playwright install`). The shared setup moves into `.github/actions/playwright-webkit/action.yml`, keeping the three separate jobs and their zero-cost `changes`-gated skips (a matrix would have paid setup on skipped legs). `UI_E2E_CHECK_NAMES` and the scoping contract are unaffected.
|
|
50
|
+
- **Faster `test:scripts` real-git tests (#1129).** Real-git fixtures paid `git` fsync on every object write; `test:scripts` now runs with `core.fsync=none` / `core.fsyncObjectFiles=false` (via `GIT_CONFIG_*`), cutting the process-spawn-heavy suite's wall time with no behavior change. The originally-proposed concurrent single-pool `verify` runner was reverted (oversubscription risk); the fsync disable is the kept win.
|
|
51
|
+
|
|
52
|
+
### Removed
|
|
53
|
+
|
|
54
|
+
- **`mermaid` is no longer a runtime dependency (#1089).** The inspect-run viewer serves the same pinned `mermaid.min.js` (11.15.0) from a vendored copy at `scripts/loop/inspect-run-viewer/vendor/mermaid.min.js` instead of resolving it out of `node_modules`; the `/assets/mermaid.min.js` route, `loadMermaidBrowserScript` seam, and offline behavior are unchanged. The vendored bundle is sha256-pinned by test (`test/loop/inspect-run-viewer-client.test.mjs`) and `test/extension-package-contract.test.mjs` guards that mermaid stays out of `dependencies`. Net install footprint shrinks (the mermaid transitive tree no longer installs); the npm tarball grows ~3.3MB unpacked from the vendored asset.
|
|
55
|
+
- **Breaking: dead-code deletion — ponytail audit batch 1 (#1088).** Removed unused public surface with no in-repo callers: the `@dev-loops/core` export subpaths `./debt/signals`, `./debt/score`, `./debt/finding`, and `./refinement/ac-dod-matrix` along with the now-dead `refinementContract` handoff-envelope plumbing (builder pass-through and validation in `handoff-envelope.mjs`) that only that module fed (the underlying `debt/score.mjs` module remains and is still tested internally); the `dev-loops-capture-deep-persona-signals` bin and the whole deep-persona-signals feature (`packages/core/src/debt/deep-persona-signals.mjs`); `createClaudeExtensionAdapter` (removed from the `@dev-loops/core/harness` exports along with its `claude-extension-adapter.mjs` module); the dead OUTER-graph tables `OUTER_STATE_TO_ROUTING_OUTCOME`, `OUTER_STATE_TO_OUTER_ACTION`, and `OUTER_NONTERMINAL_STATES` from `@dev-loops/core/loop/conductor-routing`; the config surface `localPlanning.plansDir` with its resolver `resolvePlansDir`, plus the unrelated dead config resolvers `resolveInternalPathPatterns` and `resolveMaxFanoutReviewers`; and the script CLIs `scripts/loop/conductor.mjs`, `scripts/loop/detect-stale-runner.mjs`, and `scripts/loop/pre-push-main-guard.mjs` (with their tests). Deprecation shim: a `localPlanning` block in a consumer `.devloops` file is still **accepted and ignored** (tolerated deprecated key in both zod schemas and `schemas/dev-loop-config.schema.json`) so existing configs keep parsing; remove the block at your convenience.
|
|
56
|
+
|
|
57
|
+
### Fixed
|
|
58
|
+
|
|
59
|
+
- **Guard `draft_gate` self-heal against unbounded recursion on a lagged draft-state read (#1020).** `upsert-checkpoint-verdict`'s `postDraftGateViaDraftTransition` converts a `ready` PR to draft, re-posts the verdict, then restores ready — but when GitHub's draft-state read lagged the conversion mutation, the re-entry saw the PR still non-draft and recursed, hanging with a swallowed Node exit 13. A `_draftTransitionInProgress` reentrancy guard now breaks the loop and fails closed with the complete manual recovery commands instead of hanging.
|
|
60
|
+
- **Resolve repo root and ledgers worktree-relative, not from `process.cwd()` (#1052; folds #1050 and #1019).** Under the normal per-PR-worktree flow the session cwd and the PR worktree are different checkouts, so cwd-bound reads/writes silently diverged: the pre-merge fan-out ledger check bound to the session cwd and false-blocked clean gates (#1050, hit PR #1044 twice), and `detect-copilot-loop-state` read `maxCopilotRounds` from cwd instead of the worktree `.devloops` (#1019). A shared worktree resolver now derives the repo root from the PR worktree, so the ledger writer and the pre-merge check bind to the same checkout regardless of session cwd. Pure resolution-location correctness — no gate semantics or ledger-format change.
|
|
61
|
+
- **Block subagent-initiated external writes (#1051).** Gate/dev-loop subagents had twice minted unauthorized, user-attributed GitHub issues. The bash gate now blocks raw `gh issue create` / `gh issue comment` / `gh pr comment` on the target repo when initiated by a subagent and directs to the sanctioned path; contract-driven writes (gate-verdict comments, reply-resolve review threads, board sync) and the main-agent/operator path are unaffected. Unit + e2e coverage mirrors the `gh pr create` guard.
|
|
62
|
+
- **Wrapped `gh pr view` / `gh pr edit` so the retro internal-tooling gate is satisfiable (#1057).** The remaining PR-facing reads/edits a real gate run needs had no dev-loops wrapper, so an honest run could never record a clean retrospective (`internalToolingOnly: true`, `rawCallViolations: []`) and the gate blocked code-clean PRs by waiver. New `scripts/github/view-pr.mjs` and `edit-pr.mjs` (jq-output-backed, `--jq`/`--silent`) complete the coverage; `workflow.requireRetrospectiveInternalTooling` is re-armed to `true`.
|
|
63
|
+
- **Tick verified PR-body acceptance-criteria checkboxes after a clean `pre_approval_gate` (#1066).** The gate verified acceptance criteria but only updated the linked issue, so merged PRs displayed all `- [ ]` unchecked, reading as never-confirmed. A single `gh pr edit --body-file` now flips `- [ ]` → `- [x]` for the items the gate positively confirmed (CRLF preserved, duplicate flipped labels de-duped, only verified items ticked, unconfirmable items left unchecked — fail closed).
|
|
64
|
+
- **Key fresh-context review sentinels per head SHA / round (#1095).** On a `draft_gate` retry after a fix commit, the round-1 per-(cwd, scope) sentinel from `verify-fresh-review-context.mjs` was still present, so every retry reviewer failed closed and burned a launch to refuse. The sentinel key now includes the head-SHA round component, so a new head never collides with a prior round while same-round re-entry still fails closed; the orchestrator-owned sentinel lifecycle is documented in the gate-review sub-loop contract.
|
|
65
|
+
- **Honor `queue.statusColumns.next_up` across ordering, pickup, and the projects layer (#1098).** Board-sync resolved logical columns through the `statusColumns` display-name overrides, but the ordering (`resolveNextUpOrder`) and `add-queue-item --next-up` hardcoded the literal `"Next Up"`, so a repo that renamed its Next Up column got a driver querying a non-existent column (fail-closed board-query-error or empty). The logical→display resolution now flows through the same shared mapping everywhere; board-sync stays the single source of the mapping.
|
|
66
|
+
- **Auto-release the runner-coordination lock on run completion + document stale-lock takeover (#1109, Seam 1 of #1084).** A completed/stopped run left its `.pi/runner-coordination/<repo>/pr-<n>.json` claim in place, so a merge-authorized re-dispatch (fresh run id) was refused `ownership_lost` — hit live on a 9.5h-old stale lock. A run now releases its coordination claims on completion/stop, and the stale-lock takeover path is documented; a genuinely active (non-stale) claim still fails closed.
|
|
67
|
+
- **Record fan-out provenance + opt-in enforcement, route-to-conductor (#1110, Seam 2 dev-loops of #1084).** `requireFanoutEvidence` was artifact-only, so a single agent could self-produce every per-angle review plus a ledger and label the verdict `fanout_fanin`. The findings-log ledger now records fan-out provenance (distinct reviewer count and dispatch provenance), and an opt-in `requireFanoutProvenance` check in `buildPreMergeGateCheck` re-validates it (internally consistent across checkouts, `distinctReviewers >=` the floor) to distinguish real parallel review from single-agent artifacts; a child that cannot fan out fails closed with a route-to-conductor message.
|
|
68
|
+
- **Fix `tools:` frontmatter so pi provisions the subagent tool at child depth (#1111, Seam 2 core of #1084).** pi-subagents parses the `tools:` frontmatter line with a naive comma split (no real YAML), so the flow-sequence form `tools: [read, …, subagent]` read `subagent]` (bracket attached) and never matched — child fan-out was impossible on pi. The `tools:` lines in `agents/*.agent.md` and `.pi/agents/*.agent.md` drop the brackets for the comma-scalar form; the generated `.claude/` mirror regenerates byte-identical (`normalizeToolList` already splits on commas), so the fix is additive on pi and a no-op on Claude Code (governed by the #1086 cross-harness contract).
|
|
69
|
+
- **Make `copilot-pr-handoff` and gate-coordination agree past the Copilot round cap (#1126).** Round-cap enforcement lived only in `copilot-pr-handoff.mjs`, so after `maxCopilotRounds` was reached `detect-pr-gate-coordination-state.mjs` still surfaced `rerequest_copilot_review` — advertising a re-request the handoff would refuse. Both now defer to a shared round-cap + significant-change detector, so they agree at the cap boundary.
|
|
70
|
+
- **Treat body-mention cross-references as non-owning board links (#1130, #1124).** `detect-linked-issue-pr` accepted a bare `CrossReferencedEvent` as an issue's linked open ready PR, but that event fires on any body mention (`Seam 1 of #1084`, `part of #X`), so a sub-issue-tree PR dragged every mentioned sibling into In Progress and jammed `resolve-active-board-item` with "multiple in-progress". An owning link now requires `willCloseTarget: true` (or a `ConnectedEvent`); a direct `gatherLiveFacts` open-issue→linked-ready-PR unit test (#1124) covers the reconcile bridge.
|
|
71
|
+
- **Run gate fan-out reviewers in the PR's actual worktree/head (#1135).** Reviewers dispatched with worktree isolation got a fresh checkout of stale `main` and no access to the gitignored `tmp/gate-context` bundle, so a reviewer could silently review the wrong tree without the seeded context. The read-only per-angle review dispatch now runs in the PR worktree/head with the seeded gate-context bundle (a worktree-locality guard rejects an out-of-tree `--context-path`), honoring the build-once/seed-many contract.
|
|
72
|
+
- **`write-gate-context --base` builds the diff + adjacentCode bundle on the CLI path (#1140).** The library built the "build once, seed many" bundle only when handed a diff; the CLI exposed no diff flag, so every CLI-driven gate wrote a thin briefing (`scope.diffPath: null`, empty `changedFiles`, no `adjacentCode`) and each of N reviewers re-ran the same `git diff`. A new `--base <ref>` flag captures the full diff plus the per-file 1-hop adjacent-code bundle once (`scope.diffSource="base"`), so every reviewer is seeded with the identical neutral bundle; without it the CLI still emits an explicit thin briefing.
|
|
73
|
+
- **Fix `manage-sub-issues reorder` always failing (#1160).** Reorder seeded its cursor with `after_id=0`, but GitHub's priority endpoint rejects `0` with an empty-body HTTP 500, which `gh` surfaced as `unexpected end of JSON input` — the loop aborted on the first call so no reorder ever succeeded. The first item now uses `before_id=<current head>` (or skips when it is already first) and chains `after_id` after; `ghApi` also surfaces the HTTP status on empty-body non-2xx responses.
|
|
74
|
+
- **Eliminated the version-skew class: pinned consumer-facing CLI invocations + release-time core-version assertion (#1036, root cause of #1033).** Every consumer-facing CLI example now pins `npx dev-loops@<version>` (single source: the package version) instead of a bare `npx dev-loops` that resolves a possibly-stale global/cached copy: `README.md`, `docs/migrating-to-dev-loops.md`, and the `cli/index.mjs` help/setup strings. Global `npm install -g dev-loops` is reframed as an optional, drift-prone shell convenience — explicitly not the supported invocation path. A new fail-closed contract test (`test/contracts/cli-invocation-contract.test.mjs`) bans bare `npx dev-loops` across the README/docs/CLI surface. The Pi extension already resolves the CLI and `@dev-loops/core` from the installed pinned package (module imports, updated via `pi update git:...`), never a global install; `extension/README.md` now states that lockstep contract. Root-cause fix for the mis-published-bundle failure mode: `scripts/release/assert-core-dependency-version.mjs` (node-builtins-only) fails the release when root `dev-loops`'s `@dev-loops/core` dependency major.minor differs from the version being released, wired as a step in `.github/workflows/release.yml` before the GitHub Release is created; a unit test (`test/docs/assert-core-dependency-version.test.mjs`) rejects the #1033-shaped bad manifest (`0.6.2` / `^0.2.6`) and guards the real manifest. Non-goals (YAGNI): no per-startup runtime skew watcher, no auto `npm i -g` on update.
|
|
75
|
+
|
|
76
|
+
- **Bash gate now blocks raw `gh pr create`, closing the draft-first hole.** The PreToolUse bash gate already blocked `gh pr ready`/`gh pr merge` without evidence, but nothing guarded PR *creation* — so raw `gh pr create` (which defaults to ready-for-review) silently bypassed the `workflow.requireDraftFirst` contract. It now denies raw `gh pr create` on the target repo and directs callers to the canonical wrapper `scripts/github/create-pr.mjs` (`dev-loops pr create`), which always drafts and self-assigns. The wrapper runs `gh pr create` inside a node child process, so its command is unaffected; an explicit non-target `--repo` and non-target-repo cwd pass through. The create gate now denies an explicit `--repo` targeting the repo regardless of cwd (#1047) — raw `gh pr create --repo <target>` run from outside the repo previously slipped through. New `commandContainsGhPrCreate`/`extractRepoFlagFromGhPrCreateAnywhere` in `packages/core/src/loop/bash-command-classify.mjs`, a create branch in `decideBashGate` (`packages/core/src/claude/hook-decisions.mjs`), and detection wiring in `.claude/hooks/pre-tool-use-bash-gate.mjs`; unit + e2e coverage added. The `gh pr <verb>` matcher now also treats newlines/`\r` as segment separators and normalizes a leading env-assignment (`GH_TOKEN=x`), `command`/`env`/`exec` wrapper, or absolute/relative gh path before the `^gh` test — closing the same bypass gap identically for `gh pr ready`/`gh pr merge` (subshell/group forms remain out of scope). The create gate no longer short-circuits ready/merge gating in compound commands: an out-of-scope create (e.g. `gh pr create --repo other/repo && gh pr merge 5`) now falls through so the gated ready/merge segment is still evaluated instead of being allowed early. The create gate now evaluates each create segment's scope so a leading out-of-scope create can't shield a later in-scope raw create.
|
|
77
|
+
|
|
78
|
+
- **`strategy.default: local-first` now respected end to end as the built-in code default (#1033).** `BUILT_IN_DEFAULT_TARGET_PREFERENCE` and `BUILT_IN_DEFAULTS.strategy.default` changed from `github-first` to `local-first` in `packages/core/src/loop/public-dev-loop-routing.mjs` and `packages/core/src/config/config.mjs`. The `resolveTargetPreference` fallback in `scripts/loop/resolve-dev-loop-startup.mjs` (line 267) and the config-load-error fallback (line 675) were also changed from `prefer_github_first` to `prefer_local`, so configless repos now resolve to local-first through the CLI path too. The 32 tests that previously relied on the implicit github-first default were updated to pin `PREFER_GITHUB_FIRST` explicitly; one config test assertion and one routing-config test updated to match the new built-in default. Docs updated: `targetPreference` table in `skills/docs/public-dev-loop-contract.md` now shows `prefer_local (default)`; `BUILT_IN_DEFAULTS` description in `skills/docs/artifact-authority-contract.md` updated to `local-first`.
|
|
79
|
+
|
|
80
|
+
## 0.6.2 - 2026-06-30
|
|
81
|
+
|
|
82
|
+
### Changed
|
|
83
|
+
|
|
84
|
+
- **Terminology pass: 'named human/person' → 'contributor' across all doc surfaces (#1026).** Articles (`docs/articles/dev-loops-deep-dive.{md,html}`, `introducing-dev-loops.html`), decks (`docs/presentations/dev-loops-deep-dive.html`, `introducing-dev-loops.html`, `applied-dev-loops-presentation.md`), `skills/docs/merge-preconditions.md`, `schemas/dev-loop-config.schema.json`, and `packages/core/src/config/config.mjs` docstring. Deep-dive article subtitle tightened; attention-bottleneck section rewritten for clarity. `.md`/`.html` pair synced (`fast enough to be routine`).
|
|
85
|
+
|
|
86
|
+
### Fixed
|
|
87
|
+
|
|
88
|
+
- **`deriveUiE2ePassed` blocked the gate on SKIPPED UI e2e checks (#1026).** `viewer-smoke` is `SKIPPED` (not `FAILURE`) on PRs that don't touch viewer files — it means "not applicable to this run." The function now treats `SKIPPED` the same as `SUCCESS` so a skipped check no longer incorrectly blocks `run_pre_approval_gate`. Test coverage added.
|
|
89
|
+
|
|
90
|
+
- **`plugin.json` was missing from the v0.6.1 version bump (#1026).** `.claude/.claude-plugin/plugin.json` was still at `0.6.0`; bumped to `0.6.1` (now `0.6.2` in this release). Stale generated `.claude/` assets regenerated.
|
|
91
|
+
|
|
92
|
+
## 0.6.1 - 2026-06-30
|
|
93
|
+
|
|
94
|
+
### Changed
|
|
95
|
+
|
|
96
|
+
- **Docs: refresh intro article + deck to the 0.6.0 command surface + current velocity snapshot (#1015, #1018).** `/dev-loops:continue` now shows both forms — `/dev-loops:continue 112` (issue or PR) and bare `/dev-loops:continue` (resumes the single in-progress board item, fail-closed on 0/multiple). Adds `/dev-loops:start-spike "…"` to the command list in both the intro article (`docs/articles/introducing-dev-loops.{md,html}`) and the intro deck (`docs/presentations/introducing-dev-loops.html`). The Pi command set in the catch-all router note now lists `start-spike`. The velocity snapshot paragraph is updated from the previous "two-week, ~100 PR" estimate to a verified four-day snapshot (87 PRs, ~22/day, v0.4.0 + v0.5.0).
|
|
97
|
+
|
|
98
|
+
- **Deep-dive deck: desktop responsiveness, mandatory snap, keyboard nav (#1021, #1022).** Desktop layout adjusts for wider viewports. Section scroll-snap is enforced. Keyboard navigation is enabled.
|
|
99
|
+
|
|
100
|
+
- **Namespace Claude Code slash commands with `loop-` prefix to avoid collisions (#1023).** The 6 dev-loop commands (`.claude/commands/`) are now `/loop-start`, `/loop-auto`, `/loop-continue`, `/loop-start-spike`, `/loop-info`, `/loop-status` — renamed from bare `/start` etc. which collided with Claude Code built-ins (notably `/status`). Source files renamed from `commands/*.command.md` to `commands/loop-*.command.md`; generated assets updated; no-drift test updated.
|
|
101
|
+
|
|
102
|
+
### Fixed
|
|
103
|
+
|
|
104
|
+
- **`release.yml` auto-Release never ran — the CHANGELOG extractor pulled in `@dev-loops/core` (#1016, regression in #996's first run).** `scripts/release/extract-changelog-section.mjs` imported `isDirectCliRun` from `scripts/_core-helpers.mjs`, which re-exports from the `@dev-loops/core` workspace package. `release.yml` runs the extractor with **no `npm ci`** (a text parser needs no install), so on a `v*` tag push the import `ERR_MODULE_NOT_FOUND`ed before any notes were extracted and the GitHub Release was never created (the same hands-off-publish gap #996 set out to close). The extractor now imports **only `node:` builtins** — `isDirectCliRun` is inlined (`node:fs` `realpathSync` + `node:url` `fileURLToPath`), all behavior unchanged (`--version`/`--changelog`, leading-`v` strip, heading lookahead so `0.5.1` ≠ `0.5.10`, stop-at-next-`## `, no Unreleased bleed, exit 1 absent/empty, exit 2 arg/file error, the `extractChangelogSection()` export). A new guard test parses the script's `import` statements and asserts every specifier is `node:`-prefixed, so a future workspace import can't silently reintroduce the deps-free break. `release.yml` is unchanged — the standalone script is the fix.
|
|
105
|
+
|
|
106
|
+
- **Close `gh pr merge` bypass hole in the PreToolUse gate (#1024).** A hand-run `gh pr merge` could skip the pre-approval gate entirely because the PreToolUse Bash hook only blocked `gh pr ready`. The hook now also blocks `gh pr merge` unless `detect-checkpoint-evidence.mjs` confirms clean current-head `draft_gate` + `pre_approval_gate` evidence (fanout_fanin, no inline verdicts). Two compound-command bypass paths are also closed: (1) the all-segments scanner (`commandContainsGhPrReady`/`commandContainsGhPrMerge`) catches gated verbs in any shell segment, not just the first; (2) `gh pr ready N && gh pr merge N` no longer short-circuits to ready-only — both verbs are detected independently and the stricter merge gate is applied. Pi extension public API (`isGhPrReadyCommand`, extractors) retains first-segment-only semantics (correct: `false && gh pr ready 42` short-circuits so ready never ran).
|
|
107
|
+
|
|
7
108
|
## 0.6.0 - 2026-06-29
|
|
8
109
|
|
|
9
110
|
### Added
|
package/README.md
CHANGED
|
@@ -49,17 +49,17 @@ The same entrypoints are also available as direct named commands — thin wrappe
|
|
|
49
49
|
|
|
50
50
|
### CLI only
|
|
51
51
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
dev-loops --help # verify
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
Or run directly without installing:
|
|
52
|
+
Run the CLI **version-pinned** to the plugin/extension you have installed. The pin is the
|
|
53
|
+
single source of truth (`<version>` = your installed `dev-loops` version) and cannot drift:
|
|
58
54
|
|
|
59
55
|
```bash
|
|
60
|
-
npx dev-loops --help
|
|
56
|
+
npx dev-loops@<version> --help
|
|
61
57
|
```
|
|
62
58
|
|
|
59
|
+
A global `npm install -g dev-loops` is **not** the supported invocation path: the global
|
|
60
|
+
binary updates independently of the plugin/extension and silently drifts out of version
|
|
61
|
+
(#833/#1036). Install it only as an optional bare shell convenience.
|
|
62
|
+
|
|
63
63
|
### Claude Code plugin
|
|
64
64
|
|
|
65
65
|
The repo ships a Claude Code plugin rooted at `.claude/` (manifest at
|
|
@@ -202,7 +202,7 @@ Phase 8 is the active durable phase; Phase 7 second-repo pilot is deferred. See
|
|
|
202
202
|
Gate review angles, refinement settings, persona mappings, and workflow defaults are config-driven via `.pi/dev-loop/defaults.yaml`. Consumer repos override values in `.devloops` at repo root (legacy `.pi/dev-loop/settings.yaml` still loads with a deprecation warning). The loader also accepts `.yml` and `.json` extensions and legacy `overrides.*` files as fallback formats. See [Extension Documentation](./extension/README.md) for details.
|
|
203
203
|
|
|
204
204
|
```bash
|
|
205
|
-
npx dev-loops gates # see what reviewers will check
|
|
205
|
+
npx dev-loops@<version> gates # see what reviewers will check
|
|
206
206
|
```
|
|
207
207
|
|
|
208
208
|
Key surfaces:
|
|
@@ -264,7 +264,7 @@ The `/dev-loops` command surface covers the direct dev-loop entrypoints plus rea
|
|
|
264
264
|
npx dev-loops@<version> gates
|
|
265
265
|
```
|
|
266
266
|
|
|
267
|
-
Use `npm install -g dev-loops` only
|
|
267
|
+
Use `npm install -g dev-loops` only as a bare shell convenience outside Pi; it is not version-pinned, can drift against the plugin/extension, and is not the supported invocation path (prefer `npx dev-loops@<version>`).
|
|
268
268
|
|
|
269
269
|
The package exposes the `/dev-loops` extension command surface, the `dev-loops` shell CLI, and packaged skills from `package.json` `pi.skills`.
|
|
270
270
|
|
package/agents/dev-loop.agent.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: "dev-loop"
|
|
3
3
|
description: "Use as the single public workflow entrypoint. Route from canonical current state to the deterministic internal strategy, preferring GitHub-first paths and only using local phase implementation when explicitly requested. Keywords: dev-loop, public entrypoint, route workflow, continue dev loop."
|
|
4
|
-
tools:
|
|
4
|
+
tools: read, search, execute, bash, agent, todo, subagent
|
|
5
5
|
argument-hint: "A dev-loop intent such as issue number/URL, PR number/URL, or a request to continue/inspect current state."
|
|
6
6
|
systemPromptMode: append
|
|
7
7
|
inheritProjectContext: true
|
|
@@ -16,13 +16,14 @@ Your job is to provide the callable `dev-loop` public façade and route to the c
|
|
|
16
16
|
|
|
17
17
|
## Handoff envelope mandate (first action)
|
|
18
18
|
|
|
19
|
-
The agent's first action after resolving authoritative state
|
|
19
|
+
The agent's first action after resolving authoritative state MUST be to build the handoff envelope via `buildDevLoopHandoffEnvelope()` from `@dev-loops/core`.
|
|
20
20
|
|
|
21
21
|
The envelope is the primary handoff artifact — it is derived from resolver output, settings, and gate state, and it determines:
|
|
22
22
|
- `requiredReads` — the canonical ordered list of files to load
|
|
23
23
|
- `nextAction` — the bounded task to execute
|
|
24
|
-
- `stopRules` — stop boundaries that
|
|
24
|
+
- `stopRules` — stop boundaries that MUST NOT be crossed without authorization
|
|
25
25
|
- `acceptance` — self-validation criteria for declaring completion
|
|
26
|
+
- `sanctionedCommands` — the operation → wrapper command map (reads/edits/lifecycle), plus the forbidden and orchestrator-owned lists. Carried by DEFAULT on every build so you never re-derive which wrapper performs a GitHub/loop operation. Do NOT restate the map here — the single source of truth is `scripts/loop/sanctioned-commands.mjs`, surfaced verbatim in the envelope.
|
|
26
27
|
|
|
27
28
|
**Construction sequence:**
|
|
28
29
|
<!-- pi-only -->
|
|
@@ -43,7 +44,7 @@ NEVER fall back to `find /` or any unbounded filesystem walk to locate the CLI
|
|
|
43
44
|
5. Load every path listed in `requiredReads` (in order).
|
|
44
45
|
6. Execute `nextAction` constrained by `stopRules` and `acceptance`.
|
|
45
46
|
|
|
46
|
-
**The agent
|
|
47
|
+
**The agent MUST NOT load skills, route packs, or delegate work before the envelope is built and read.** The derivation contract is [Workflow Handoff Contract](../skills/docs/workflow-handoff-contract.md).
|
|
47
48
|
|
|
48
49
|
Prose task composition is a fallback only when `buildDevLoopHandoffEnvelope()` is unavailable (missing `@dev-loops/core` package) — the handoff contract in `skills/docs/workflow-handoff-contract.md` applies in that fallback case.
|
|
49
50
|
|
|
@@ -53,7 +54,7 @@ After the handoff envelope is built and read, load the `dev-loop` skill ([Dev Lo
|
|
|
53
54
|
|
|
54
55
|
When that skill is not available at the expected path, resolve it from the skill installation layout (see the skill's "Skill asset path resolution" section).
|
|
55
56
|
|
|
56
|
-
This entrypoint
|
|
57
|
+
This entrypoint MUST stay thin: do not restate the skill's phase sequencing or workflow policy here. The envelope owns handoff sequencing; the skill owns routed strategy execution procedures.
|
|
57
58
|
|
|
58
59
|
Treat the deterministic public routing contract in [Public Dev Loop Contract](../skills/docs/public-dev-loop-contract.md) and the `dev-loop` skill as the authority for choosing the current execution path. Do not force users to choose internal strategy names up front.
|
|
59
60
|
|
|
@@ -71,12 +72,12 @@ If local facts, GitHub facts, and helper/state-machine output do not agree well
|
|
|
71
72
|
## Subagent delegation
|
|
72
73
|
|
|
73
74
|
<!-- pi-only -->
|
|
74
|
-
This agent
|
|
75
|
+
This agent's frontmatter `tools:` comma-token scalar includes `subagent` (single-line comma form, no brackets — see #1111) and it sets `maxSubagentDepth: 3` to allow orchestrating parallel review, chains, and staged fix passes.
|
|
75
76
|
<!-- /pi-only -->
|
|
76
77
|
|
|
77
|
-
All delegation
|
|
78
|
+
All delegation MUST originate from the handoff envelope: the envelope's `nextAction`, `requiredReads`, `stopRules`, and `acceptance` define the bounded task. The envelope is passed to child subagents as their primary handoff artifact.
|
|
78
79
|
|
|
79
|
-
The pi-subagents skill is parent-only, so delegated subagents do not receive orchestration patterns. This section exists as the minimal locally-enforced subset needed for correct delegation — it is not a restatement of the full policy. The `dev-loop` skill owns all procedural rules; this section only declares the invariants the agent
|
|
80
|
+
The pi-subagents skill is parent-only, so delegated subagents do not receive orchestration patterns. This section exists as the minimal locally-enforced subset needed for correct delegation — it is not a restatement of the full policy. The `dev-loop` skill owns all procedural rules; this section only declares the invariants the agent MUST follow when it cannot defer to the skill:
|
|
80
81
|
- One writer thread; `async: true` default; `context: "fresh"` for reviewers.
|
|
81
82
|
- No child subagent spawning beyond assigned fanout work.
|
|
82
83
|
- Bounded tasks with concrete scope, exit conditions, and validation expectations.
|
|
@@ -86,8 +87,8 @@ The pi-subagents skill is parent-only, so delegated subagents do not receive orc
|
|
|
86
87
|
|
|
87
88
|
- **Prefer `intercom` when available.** If the `pi-intercom` extension is active, use `intercom({ action: "ask", ... })` instead of `contact_supervisor`. The `intercom` tool uses message-based delivery (no blocking tool-call state) — see the pi documentation for `intercom({ action: "ask", ... })` parameters and reply conventions.
|
|
88
89
|
- **When `intercom` is unavailable,** do not call `contact_supervisor`. Instead, brief the supervisor to include the decision in the resume message when re-dispatching. The subagent states what it needs in the task description; the supervisor provides the answer on resume. This avoids the broken response path entirely.
|
|
89
|
-
- **If `contact_supervisor` was already called** (legacy code or unavoidable): expect a ~60s idle timeout followed by a pause. On resume, the supervisor
|
|
90
|
-
- **Timeout detection (supervisor-side):** if a `contact_supervisor` call has been pending for >30s, the supervisor
|
|
90
|
+
- **If `contact_supervisor` was already called** (legacy code or unavoidable): expect a ~60s idle timeout followed by a pause. On resume, the supervisor MUST inject the decision in the resume message — do not rely on `intercom` on resume when it was unavailable at call time.
|
|
91
|
+
- **Timeout detection (supervisor-side):** if a `contact_supervisor` call has been pending for >30s, the supervisor SHOULD treat it as a probable timeout and prepare to inject the decision in the resume message on re-dispatch. The subagent cannot execute this detection while blocked inside `contact_supervisor`; the supervisor MUST observe the pending duration externally.
|
|
91
92
|
<!-- /pi-only -->
|
|
92
93
|
|
|
93
94
|
## Output
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: "developer"
|
|
3
3
|
description: "Use for direct product implementation in this repository: focused code changes, refactors, tests, bug fixes, and feature work within an already-scoped task. Keywords: implement feature, write code, refactor module, add tests, fix bug, update source."
|
|
4
|
-
tools:
|
|
4
|
+
tools: read, search, execute, bash, edit, write
|
|
5
5
|
argument-hint: "Focused implementation task, relevant files, success criteria, and required verification."
|
|
6
6
|
systemPromptMode: append
|
|
7
7
|
inheritProjectContext: true
|
package/agents/docs.agent.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: "docs"
|
|
3
3
|
description: "Use for README updates, plan docs, architecture notes, agent docs, migration notes, narrow documentation changes that must stay aligned with implementation work, and documentation-correctness review for the current change. Keywords: docs, README, plans, documentation, agent docs, rollout notes, changelog-style summary, docs review."
|
|
4
|
-
tools:
|
|
4
|
+
tools: read, search, execute, bash, edit, write
|
|
5
5
|
argument-hint: "Documentation task or documentation-correctness review, affected files, source changes to reflect, and required level of detail."
|
|
6
6
|
systemPromptMode: append
|
|
7
7
|
inheritProjectContext: true
|
package/agents/fixer.agent.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: "fixer"
|
|
3
3
|
description: "Use for addressing active pull request review comments and threads: inspect unresolved feedback, make the narrow fix, verify it, push the fixing commit, reply with the resolving commit, and resolve the thread. Keywords: fixer, PR comments, address review feedback, resolve review threads, push fix commit."
|
|
4
|
-
tools:
|
|
4
|
+
tools: read, search, execute, bash, edit, write
|
|
5
5
|
argument-hint: "Review-fix task, PR number or branch, target reviewer/thread/file, and required verification."
|
|
6
6
|
systemPromptMode: append
|
|
7
7
|
inheritProjectContext: true
|
|
@@ -28,6 +28,7 @@ You are a focused review-fix agent. You take an existing pull request with revie
|
|
|
28
28
|
|
|
29
29
|
## Review Workflow
|
|
30
30
|
1. Read unresolved review threads and any general review comments.
|
|
31
|
+
- Prefer the deterministic helper `scripts/github/list-review-threads.mjs --unresolved-only` to enumerate threads with their reply/resolve ids, rather than hand-writing a GraphQL query.
|
|
31
32
|
2. Group related comments by file and identify the underlying concern behind each comment.
|
|
32
33
|
3. Decide the best resolution for each concern: exact requested change, better alternative fix, explanation-only resolution, or escalation for expert judgment.
|
|
33
34
|
4. If expert input is needed, stop before editing or resolving the thread and report the question, evidence, and options.
|
package/agents/quality.agent.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: "quality"
|
|
3
3
|
description: "Use for build systems, test runners, type-checking, linting, package scripts, GitHub Actions workflows, caches, release verification, and quality gates. Keywords: CI, workflow, GitHub Actions, build, test, cache, typecheck, package scripts, branch protection."
|
|
4
|
-
tools:
|
|
4
|
+
tools: read, search, execute, bash, edit, write
|
|
5
5
|
argument-hint: "Quality or CI task, relevant workflows/config files, required checks, and verification expectations."
|
|
6
6
|
systemPromptMode: append
|
|
7
7
|
inheritProjectContext: true
|
package/agents/refiner.agent.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: "refiner"
|
|
3
3
|
description: "Use for refining one approved implementation phase at a time into a complete, testable plan with acceptance criteria, definition of done, risks, non-goals, unresolved questions, and RFC escalation notes. Keywords: refiner, phase refinement, acceptance criteria, definition of done, RFC escalation, merged plan."
|
|
4
|
-
tools:
|
|
4
|
+
tools: read, search, execute, bash, edit, write
|
|
5
5
|
argument-hint: "Active phase doc or rough plan, phase boundary, known constraints, and any prior planning artifacts to refine."
|
|
6
6
|
systemPromptMode: append
|
|
7
7
|
inheritProjectContext: true
|
|
@@ -40,7 +40,7 @@ For the active phase, require and produce:
|
|
|
40
40
|
- if no explicit definition of done exists, add a `Proposed DoD` subsection before the matrix
|
|
41
41
|
- explicit risks, watchpoints, and unresolved questions
|
|
42
42
|
- validation steps and tests to write first
|
|
43
|
-
- durable decisions that
|
|
43
|
+
- durable decisions that SHOULD be preserved in the phase doc
|
|
44
44
|
- when the phase includes a bounded audit or scan: prioritized findings, the highest-value follow-up candidates, and an explicit statement of what the current phase will not rewrite or broaden
|
|
45
45
|
- When an audit artifact is provided, treat it as a first-class planning input: summarize the audited scope, list prioritized findings, include the highest-value follow-up candidates, and classify each meaningful finding as exactly one of current-phase scope/AC, DoD expectation, explicit non-goal / defer, or risk/watchpoint
|
|
46
46
|
- Do not invent audit findings when no audit artifact was provided
|
|
@@ -85,4 +85,4 @@ Return:
|
|
|
85
85
|
|
|
86
86
|
## Completion quality bar
|
|
87
87
|
- A refinement is complete only when no item in the AC/DoD/Non-goal coverage matrix has status `Partial`, `Unmet`, or `Unverified`.
|
|
88
|
-
- Any `Partial`, `Unmet`, or `Unverified` item means the refinement is still incomplete and
|
|
88
|
+
- Any `Partial`, `Unmet`, or `Unverified` item means the refinement is still incomplete and MUST NOT be presented as ready.
|
package/agents/review.agent.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: "review"
|
|
3
3
|
description: "Use for pull request review from a product and engineering perspective: check the implementation against the PR description, relevant plan, acceptance criteria, definition of done, non-goals, coding best practices, security expectations, and merge readiness. Keywords: review, PR review, acceptance criteria review, DoD review, security review, plan compliance."
|
|
4
|
-
tools:
|
|
4
|
+
tools: read, search, execute, bash, edit, write
|
|
5
5
|
argument-hint: "PR number or branch, relevant plan files, and any specific review focus areas or constraints."
|
|
6
6
|
systemPromptMode: append
|
|
7
7
|
inheritProjectContext: true
|
|
@@ -33,10 +33,11 @@ This agent has two modes. The default mode is the full-PR review described in th
|
|
|
33
33
|
|
|
34
34
|
You are in scoped angle-review mode when the invocation supplies a single review `<angle>` plus a gate-context artifact path (`tmp/gate-context/<repo-slug>/pr-<N>/<gate>-<headSha>.json`, written by `scripts/github/write-gate-context.mjs`). Review like an external code reviewer hunting real bugs, not a process auditor: your job is to find concrete defects in the changed code and its call paths, not to remark that "there is no test" or that a doc section is thin. In that mode:
|
|
35
35
|
|
|
36
|
-
- **
|
|
36
|
+
- **No worktree isolation (mandatory):** you review in the PR's actual worktree/head — the same checkout the gate-context preamble ran in — never a fresh isolated worktree. You are read-only and never mutate files, so isolation buys nothing; a fresh worktree would also be checked out from `main` (not the PR head) and would lack the gitignored, worktree-local gate-context bundle below, so you'd silently review the wrong stale tree (#1135).
|
|
37
|
+
- **Fresh-context guard (mandatory):** run `node scripts/github/verify-fresh-review-context.mjs --scope <angle> --context-path <gate-context-artifact-path>` at startup. If it reports `fresh: false` (exit 1) or any error — including a missing gate-context artifact (`gateContextPresent: false`), which is the fail-closed signal that you're not in the right worktree/head — refuse to proceed and report the failure; do not review on inherited context or without seeded context. "Fresh" here means your context is the **neutral builder artifact + your angle**, and explicitly NOT the main agent's conversation/state or a prior reviewer session's state. The injected neutral bundle is the INTENDED seed (allowed); main-agent or cross-session state bleed still fails closed.
|
|
37
38
|
- **Use the PROVIDED neutral bundle as your base; do NOT re-derive it from scratch:** the gate-context artifact carries the diff (`scope.diffPath`) and a deterministic, neutral adjacent-code bundle in `adjacentCode` (each changed file plus its 1-hop import in/out-edges, with a `stripped`/`truncated`/`missing` manifest). Start from this bundle — it is the build-once, work-deduped seed shared verbatim across all reviewers. Only widen (load more files) per-angle when the bundle genuinely lacks something your angle needs; do not re-build the whole diff/adjacent-code graph yourself.
|
|
38
39
|
- **Single-angle scope:** review ONLY the supplied angle's concern. Read the gate-context artifact for the resolved angle set, change scope (branch, head SHA, touched files), acceptance-criteria pointer, and validation posture. Do not review other angles; the fan-in pass consolidates across angles.
|
|
39
|
-
- **Read the FULL diff, not just hunks:** the gate-context artifact records `scope.diffPath` (a repo-relative path to the complete captured diff) and `scope.changedFiles` (full repo-relative paths). Read the entire diff from `scope.diffPath`; if it is `null` or missing, reconstruct it yourself with `git diff` against the change's base (e.g. `git diff origin/main...HEAD` or the branch/head SHA in `scope`). Do not review off a partial or summarized hunk list — you
|
|
40
|
+
- **Read the FULL diff, not just hunks:** the gate-context artifact records `scope.diffPath` (a repo-relative path to the complete captured diff) and `scope.changedFiles` (full repo-relative paths). Read the entire diff from `scope.diffPath`; if it is `null` or missing, reconstruct it yourself with `git diff` against the change's base (e.g. `git diff origin/main...HEAD` or the branch/head SHA in `scope`). Do not review off a partial or summarized hunk list — you MUST see every changed line for your angle.
|
|
40
41
|
- **Reason about ADJACENT related code from the bundle first:** the `adjacentCode` bundle already includes the changed files' callers, callees, and imports (1-hop). Read those entries before opening anything else. For each changed function, trace the real call paths a defect would flow through, and confirm that caller and callee contracts still match (argument shapes, return shapes, error/null conventions, units). If the bundle truncated or stripped a file you need (see its `truncated`/`stripped` manifest), open that file directly to widen.
|
|
41
42
|
- **Review ADVERSARIALLY — hunt concrete defects:** actively try to break the changed code. Hunt for edge cases, missing or wrong input validation, numeric coercion bugs (NaN, Infinity, floats where integers are assumed, negative values, string-to-number coercion), null/undefined handling, off-by-one and boundary conditions, mismatched caller/callee contracts, and dedup/identity bugs (wrong key, reference vs. value equality, unstable ordering). For every finding, give the concrete `file:line` plus the specific failing scenario or input that triggers the defect — not high-altitude "is there a test?" commentary.
|
|
42
43
|
- **Strictly read-only, but WIDEN SCOPE when needed:** never edit files, stage, commit, push, request reviews, resolve threads, or post PR comments. Findings are returned via the output artifact only; fixes are applied later by the fix cycle, not by this agent. Because you are read-only, you MAY open any additional repository files required to judge your angle (callers, callees, contracts, sibling modules, configs, tests) — widening to read adjacent code is expected and safe. Record every file/module you consulted beyond the briefing's `changedFiles`/`diffPath` in the optional `contextWidened` field on your output artifact.
|
|
@@ -75,7 +76,7 @@ When NOT given an angle scope, behave exactly as the full-PR review agent descri
|
|
|
75
76
|
- Prefer concrete findings with file references and impact over generic style commentary.
|
|
76
77
|
- Distinguish clearly between must-fix findings, lower-severity risks, and informational gaps.
|
|
77
78
|
- If the PR description omits required sections, is too thin to ground review without reconstructing intent from commits, or includes verdict status, evidence, or changelog content, treat that as a first-class review issue.
|
|
78
|
-
- The review verdict
|
|
79
|
+
- The review verdict MUST carry the acceptance-criteria and definition-of-done assessment in explicit markdown verification tables, including status plus concise evidence for each row.
|
|
79
80
|
- For follow-up reviews on the same PR, do not repost full AC/DoD tables: include only delta rows where status or supporting evidence changed, and explicitly note when there are no AC/DoD deltas.
|
|
80
81
|
- When changelog coverage is needed, include a dedicated `## Changelog` section in the review verdict comment so post-merge automation can consume it without reading the PR description.
|
|
81
82
|
|
package/cli/index.mjs
CHANGED
|
@@ -17,6 +17,34 @@ import { createPiAdapter } from "@dev-loops/core/harness";
|
|
|
17
17
|
|
|
18
18
|
const REPO_ROOT = fileURLToPath(new URL("..", import.meta.url));
|
|
19
19
|
|
|
20
|
+
// `project` is an alias for `queue` minus the run driver — derived, not duplicated.
|
|
21
|
+
const QUEUE_ROUTES = {
|
|
22
|
+
run: "scripts/loop/run-queue.mjs",
|
|
23
|
+
list: "scripts/projects/list-queue-items.mjs",
|
|
24
|
+
add: "scripts/projects/add-queue-item.mjs",
|
|
25
|
+
move: "scripts/projects/move-queue-item.mjs",
|
|
26
|
+
reorder: "scripts/projects/reorder-queue-item.mjs",
|
|
27
|
+
"archive-done": "scripts/projects/archive-done-items.mjs",
|
|
28
|
+
"sync-status": "scripts/projects/sync-item-status.mjs",
|
|
29
|
+
ensure: "scripts/projects/ensure-queue-board.mjs",
|
|
30
|
+
"resolve-active": "scripts/projects/resolve-active-board-item.mjs",
|
|
31
|
+
reconcile: "scripts/projects/reconcile-queue.mjs",
|
|
32
|
+
};
|
|
33
|
+
const { run: _queueRunRoute, ...PROJECT_ROUTES } = QUEUE_ROUTES;
|
|
34
|
+
|
|
35
|
+
const QUEUE_DESCRIPTIONS = {
|
|
36
|
+
run: "Run queue driver",
|
|
37
|
+
list: "List queue board items",
|
|
38
|
+
add: "Add issue/PR to queue board",
|
|
39
|
+
move: "Move queue item between Status columns",
|
|
40
|
+
reorder: "Reorder items (move-to-top/move-after/order, --dry-run)",
|
|
41
|
+
"archive-done": "Archive closed Done items older than a duration",
|
|
42
|
+
"sync-status": "Sync a queued issue/PR's board Status column (best-effort)",
|
|
43
|
+
ensure: "Create/repair queue board bootstrap surface",
|
|
44
|
+
reconcile: "Reconcile board Status columns from live GitHub state (idempotent)",
|
|
45
|
+
};
|
|
46
|
+
const { run: _queueRunDescription, ...PROJECT_DESCRIPTIONS } = QUEUE_DESCRIPTIONS;
|
|
47
|
+
|
|
20
48
|
const SUBCOMMAND_ROUTES = {
|
|
21
49
|
gate: {
|
|
22
50
|
"upsert-verdict": "scripts/github/upsert-checkpoint-verdict.mjs",
|
|
@@ -50,27 +78,8 @@ const SUBCOMMAND_ROUTES = {
|
|
|
50
78
|
"ready-for-review": "scripts/github/ready-for-review.mjs",
|
|
51
79
|
"reconcile-draft": "scripts/github/reconcile-draft-gate.mjs",
|
|
52
80
|
},
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
add: "scripts/projects/add-queue-item.mjs",
|
|
56
|
-
move: "scripts/projects/move-queue-item.mjs",
|
|
57
|
-
reorder: "scripts/projects/reorder-queue-item.mjs",
|
|
58
|
-
"archive-done": "scripts/projects/archive-done-items.mjs",
|
|
59
|
-
"sync-status": "scripts/projects/sync-item-status.mjs",
|
|
60
|
-
ensure: "scripts/projects/ensure-queue-board.mjs",
|
|
61
|
-
"resolve-active": "scripts/projects/resolve-active-board-item.mjs",
|
|
62
|
-
},
|
|
63
|
-
queue: {
|
|
64
|
-
run: "scripts/loop/run-queue.mjs",
|
|
65
|
-
list: "scripts/projects/list-queue-items.mjs",
|
|
66
|
-
add: "scripts/projects/add-queue-item.mjs",
|
|
67
|
-
move: "scripts/projects/move-queue-item.mjs",
|
|
68
|
-
reorder: "scripts/projects/reorder-queue-item.mjs",
|
|
69
|
-
"archive-done": "scripts/projects/archive-done-items.mjs",
|
|
70
|
-
"sync-status": "scripts/projects/sync-item-status.mjs",
|
|
71
|
-
ensure: "scripts/projects/ensure-queue-board.mjs",
|
|
72
|
-
"resolve-active": "scripts/projects/resolve-active-board-item.mjs",
|
|
73
|
-
},
|
|
81
|
+
queue: QUEUE_ROUTES,
|
|
82
|
+
project: PROJECT_ROUTES,
|
|
74
83
|
inspect: {
|
|
75
84
|
run: "scripts/loop/inspect-run.mjs",
|
|
76
85
|
viewer: "scripts/loop/inspect-run-viewer.mjs",
|
|
@@ -143,25 +152,8 @@ const SUBCOMMAND_DESCRIPTIONS = {
|
|
|
143
152
|
"ready-for-review": "Mark PR ready for review",
|
|
144
153
|
"reconcile-draft": "Reconcile non-draft PR",
|
|
145
154
|
},
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
add: "Add issue/PR to queue board",
|
|
149
|
-
move: "Move queue item between Status columns",
|
|
150
|
-
reorder: "Reorder items (move-to-top/move-after/order, --dry-run)",
|
|
151
|
-
"archive-done": "Archive closed Done items older than a duration",
|
|
152
|
-
"sync-status": "Sync a queued issue/PR's board Status column (best-effort)",
|
|
153
|
-
ensure: "Create/repair queue board bootstrap surface",
|
|
154
|
-
},
|
|
155
|
-
queue: {
|
|
156
|
-
run: "Run queue driver",
|
|
157
|
-
list: "List queue board items",
|
|
158
|
-
add: "Add issue/PR to queue board",
|
|
159
|
-
move: "Move queue item between Status columns",
|
|
160
|
-
reorder: "Reorder items (move-to-top/move-after/order, --dry-run)",
|
|
161
|
-
"archive-done": "Archive closed Done items older than a duration",
|
|
162
|
-
"sync-status": "Sync a queued issue/PR's board Status column (best-effort)",
|
|
163
|
-
ensure: "Create/repair queue board bootstrap surface",
|
|
164
|
-
},
|
|
155
|
+
queue: QUEUE_DESCRIPTIONS,
|
|
156
|
+
project: PROJECT_DESCRIPTIONS,
|
|
165
157
|
inspect: {
|
|
166
158
|
run: "Inspect run state",
|
|
167
159
|
viewer: "Start inspection viewer",
|
|
@@ -252,7 +244,8 @@ function buildCliHelpLines() {
|
|
|
252
244
|
"Use `dev-loops <category> <subcommand> --help` for per-subcommand usage.",
|
|
253
245
|
"",
|
|
254
246
|
"`/dev-loops hide` remains an extension-only Pi command.",
|
|
255
|
-
"Run via `npx dev-loops
|
|
247
|
+
"Run via `npx dev-loops@<version>` pinned to your plugin/extension version (a global",
|
|
248
|
+
"`npm install -g dev-loops` can drift and is not the supported invocation path); see the",
|
|
256
249
|
"README for Pi-extension and Claude Code plugin setup.",
|
|
257
250
|
];
|
|
258
251
|
}
|
|
@@ -275,7 +268,7 @@ function orderedCliSetupSteps(checks) {
|
|
|
275
268
|
return [
|
|
276
269
|
"1. Use `/dev-loop` (Claude Code) or `/skill:dev-loop` (Pi) to start or continue a dev loop — the single public entry.",
|
|
277
270
|
"2. Run `dev-loops status` whenever you want a concise readiness snapshot.",
|
|
278
|
-
"3. Run via `npx dev-loops
|
|
271
|
+
"3. Run via `npx dev-loops@<version>` pinned to your plugin/extension version (a global `npm install -g dev-loops` can drift and is not the supported invocation path); see the README for Pi-extension and Claude Code plugin setup.",
|
|
279
272
|
];
|
|
280
273
|
}
|
|
281
274
|
|
package/extension/README.md
CHANGED
|
@@ -9,6 +9,8 @@ Installing the package exposes two thin wrappers over one shared deterministic c
|
|
|
9
9
|
|
|
10
10
|
Installing the package with `pi install git:github.com/mfittko/dev-loops` exposes the packaged skills through `package.json` `pi.skills`, and the extension syncs packaged agent files (`agents/*.agent.md`) into `~/.agents/` on `session_start`.
|
|
11
11
|
|
|
12
|
+
**Version pinning (no global-install skew).** The extension resolves both the CLI and `@dev-loops/core` from the installed, pinned package (module imports, not a global `dev-loops` binary), and updates itself via the pinned `pi update git:github.com/mfittko/dev-loops` seam above. It never depends on a separately-updated global install, so it stays in lockstep with the installed version by construction (#1036).
|
|
13
|
+
|
|
12
14
|
## Command surface
|
|
13
15
|
|
|
14
16
|
- `/dev-loops`
|
|
@@ -144,7 +146,6 @@ autonomy:
|
|
|
144
146
|
|
|
145
147
|
workflow:
|
|
146
148
|
requireRetrospective: true
|
|
147
|
-
requireRetrospectiveGate: true
|
|
148
149
|
requireDraftFirst: true
|
|
149
150
|
devModeDefault: true
|
|
150
151
|
```
|
|
@@ -178,13 +179,12 @@ The optional `workflow` family carries repo-level workflow posture without hardc
|
|
|
178
179
|
```yaml
|
|
179
180
|
workflow:
|
|
180
181
|
requireRetrospective: false
|
|
181
|
-
requireRetrospectiveGate: false
|
|
182
182
|
requireDraftFirst: false
|
|
183
183
|
devModeDefault: false
|
|
184
184
|
```
|
|
185
185
|
|
|
186
186
|
- `requireRetrospective` — when enabled by repo settings, the next qualifying GitHub-first async start/resume must honor the retrospective checkpoint gate
|
|
187
|
-
- `requireRetrospectiveGate` —
|
|
187
|
+
- `requireRetrospectiveGate` — **removed (issue #1077)**. The retrospective is now advisory: it always runs and returns findings to the conductor via the envelope's `retrospectiveFindings` field and an advisory PR comment, never blocking merge or any transition. There is no longer a merge-gate config key for the retrospective.
|
|
188
188
|
- `requireDraftFirst` — marks draft-first PR creation as required workflow policy for repos that opt in
|
|
189
189
|
- `devModeDefault` — declares that local implementation should default to formal dev mode; this is config-only for now and establishes source-of-truth config plus docs for future runtime consumers
|
|
190
190
|
|
|
@@ -222,7 +222,7 @@ Current Phase 3+ contract:
|
|
|
222
222
|
|
|
223
223
|
Root verification and test commands are intentionally explicit:
|
|
224
224
|
- `npm run verify` is the canonical root verification path (`npm test` + `npm run test:dev-loop`)
|
|
225
|
-
- `npm test` runs the current root test suite (`test:assets`, `test:extension`, `test:scripts`, and `test:
|
|
225
|
+
- `npm test` runs the current root test suite (`test:assets`, `test:extension`, `test:scripts`, `test:core`, and `test:docs`)
|
|
226
226
|
- `npm run test:extension`
|
|
227
227
|
- `npm run test:extension` currently expands to one `node --import tsx --test ...` invocation in `package.json`; prefer the script entrypoint over copying the file list into downstream docs or runbooks
|
|
228
228
|
- `npm run test:scripts`
|
package/extension/checks.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { DEV_LOOP_CHECK_IDS } from '../lib/dev-loops-core.mjs';
|
|
2
2
|
import { createInspectRunViewerLifecycleManager } from '../scripts/loop/inspect-run-viewer/managed-instance.mjs';
|
|
3
3
|
import type { ExtensionHarnessAdapter } from './harness-types.ts';
|
|
4
4
|
|
|
@@ -77,7 +77,3 @@ export function createExtensionCoreRuntime(
|
|
|
77
77
|
},
|
|
78
78
|
};
|
|
79
79
|
}
|
|
80
|
-
|
|
81
|
-
export async function collectDevLoopChecks(adapter: ExtensionHarnessAdapter): Promise<DevLoopCheck[]> {
|
|
82
|
-
return collectSharedDevLoopChecks(createExtensionCoreRuntime(adapter));
|
|
83
|
-
}
|
|
@@ -29,6 +29,7 @@ export type HarnessContext = {
|
|
|
29
29
|
cwd: string;
|
|
30
30
|
hasUI: boolean;
|
|
31
31
|
ui: HarnessUi;
|
|
32
|
+
sendUserMessage?: (message: string, options?: Record<string, unknown>) => unknown;
|
|
32
33
|
};
|
|
33
34
|
|
|
34
35
|
export type HarnessLifecycleEvent = 'session_start' | 'tool_result' | 'user_bash' | 'agent_end';
|
package/extension/index.ts
CHANGED
|
@@ -26,6 +26,10 @@ const STATUS_KEY = 'dev-loops';
|
|
|
26
26
|
const WIDGET_KEY = 'dev-loops.setup';
|
|
27
27
|
const PACKAGED_AGENTS_ROOT = new URL('../agents/', import.meta.url);
|
|
28
28
|
|
|
29
|
+
async function dispatchDevLoopIntent(ctx: { sendUserMessage?: (message: string) => unknown }, intent: string) {
|
|
30
|
+
await ctx.sendUserMessage?.(`/skill:dev-loop ${intent}`);
|
|
31
|
+
}
|
|
32
|
+
|
|
29
33
|
export function syncPackagedAgents({
|
|
30
34
|
sourceRoot = fileURLToPath(PACKAGED_AGENTS_ROOT),
|
|
31
35
|
targetRoot = path.join(os.homedir(), '.agents'),
|
|
@@ -92,10 +96,12 @@ export default function (pi: ExtensionAPI, runtimeOverrides: ExtensionRuntimeOve
|
|
|
92
96
|
return;
|
|
93
97
|
case 'entrypoint':
|
|
94
98
|
ctx.ui.setWidget(WIDGET_KEY, buildEntrypointLines(result.action, result.intent), { placement: 'belowEditor' });
|
|
99
|
+
await dispatchDevLoopIntent(ctx, result.intent);
|
|
95
100
|
ctx.ui.notify(`dev-loops ${result.action}: ${result.intent}`, 'info');
|
|
96
101
|
return;
|
|
97
102
|
case 'start_spike':
|
|
98
103
|
ctx.ui.setWidget(WIDGET_KEY, buildEntrypointLines('start-spike', result.intent), { placement: 'belowEditor' });
|
|
104
|
+
await dispatchDevLoopIntent(ctx, result.intent);
|
|
99
105
|
ctx.ui.notify(`dev-loops start-spike: ${result.intent}`, 'info');
|
|
100
106
|
return;
|
|
101
107
|
case 'checks':
|