@limina-labs/momentum 0.30.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/LICENSE +21 -0
- package/README.md +214 -0
- package/adapters/antigravity/adapter.js +196 -0
- package/adapters/antigravity/hooks.json +39 -0
- package/adapters/antigravity/instructions/AGENTS.md +638 -0
- package/adapters/antigravity/instructions/header.md +3 -0
- package/adapters/antigravity/instructions/surfaces.md +153 -0
- package/adapters/antigravity/instructions/vars.json +1 -0
- package/adapters/antigravity/scripts/antigravity-hook-adapter.sh +147 -0
- package/adapters/antigravity/skills/momentum-orient/SKILL.md +29 -0
- package/adapters/antigravity/skills/momentum-reviewer-architecture/SKILL.md +39 -0
- package/adapters/antigravity/skills/momentum-reviewer-qa/SKILL.md +38 -0
- package/adapters/antigravity/skills/momentum-reviewer-security/SKILL.md +42 -0
- package/adapters/antigravity/skills/swarm-supervisor/SKILL.md +75 -0
- package/adapters/antigravity/workflows/continue.md +39 -0
- package/adapters/antigravity/workflows/dispatch.md +49 -0
- package/adapters/antigravity/workflows/handoff.md +38 -0
- package/adapters/antigravity/workflows/review-code.md +84 -0
- package/adapters/antigravity/workflows/scout.md +42 -0
- package/adapters/antigravity/workflows/swarm.md +203 -0
- package/adapters/claude-code/adapter.js +148 -0
- package/adapters/claude-code/commands/continue.md +82 -0
- package/adapters/claude-code/commands/dispatch.md +154 -0
- package/adapters/claude-code/commands/handoff.md +85 -0
- package/adapters/claude-code/commands/review-code.md +194 -0
- package/adapters/claude-code/commands/scout.md +119 -0
- package/adapters/claude-code/commands/swarm.md +242 -0
- package/adapters/claude-code/instructions/header.md +3 -0
- package/adapters/claude-code/instructions/vars.json +1 -0
- package/adapters/claude-code/settings.json +36 -0
- package/adapters/codex/adapter.js +225 -0
- package/adapters/codex/agents/momentum-reviewer-architecture.toml +57 -0
- package/adapters/codex/agents/momentum-reviewer-qa.toml +52 -0
- package/adapters/codex/agents/momentum-reviewer-security.toml +57 -0
- package/adapters/codex/agents/swarm-supervisor.toml +76 -0
- package/adapters/codex/commands/continue.md +40 -0
- package/adapters/codex/commands/dispatch.md +111 -0
- package/adapters/codex/commands/handoff.md +57 -0
- package/adapters/codex/commands/scout.md +90 -0
- package/adapters/codex/commands/swarm.md +334 -0
- package/adapters/codex/hooks.json +36 -0
- package/adapters/codex/instructions/AGENTS.md +691 -0
- package/adapters/codex/instructions/header.md +3 -0
- package/adapters/codex/instructions/surfaces.md +206 -0
- package/adapters/codex/instructions/vars.json +1 -0
- package/adapters/codex/skills/momentum-orient/SKILL.md +29 -0
- package/adapters/opencode/adapter.js +224 -0
- package/adapters/opencode/agents/momentum-reviewer-architecture.md +54 -0
- package/adapters/opencode/agents/momentum-reviewer-qa.md +48 -0
- package/adapters/opencode/agents/momentum-reviewer-security.md +48 -0
- package/adapters/opencode/agents/swarm-supervisor.md +51 -0
- package/adapters/opencode/commands/continue.md +40 -0
- package/adapters/opencode/commands/dispatch.md +111 -0
- package/adapters/opencode/commands/handoff.md +57 -0
- package/adapters/opencode/commands/review-code.md +194 -0
- package/adapters/opencode/commands/scout.md +90 -0
- package/adapters/opencode/commands/swarm.md +334 -0
- package/adapters/opencode/instructions/AGENTS.md +604 -0
- package/adapters/opencode/instructions/header.md +3 -0
- package/adapters/opencode/instructions/surfaces.md +119 -0
- package/adapters/opencode/instructions/vars.json +1 -0
- package/adapters/opencode/plugins/momentum.js +219 -0
- package/adapters/opencode/skills/momentum-lanes/SKILL.md +30 -0
- package/adapters/opencode/skills/momentum-orient/SKILL.md +29 -0
- package/adapters/opencode/skills/momentum-track/SKILL.md +28 -0
- package/adapters/opencode/skills/momentum-validate/SKILL.md +31 -0
- package/bin/antigravity.js +112 -0
- package/bin/ecosystem.js +1302 -0
- package/bin/lanes.js +300 -0
- package/bin/momentum.js +1857 -0
- package/bin/okf.js +72 -0
- package/bin/orchestration-commands.js +305 -0
- package/bin/state-commands.js +218 -0
- package/bin/swarm.js +1104 -0
- package/bin/waves.js +147 -0
- package/core/adapter-capabilities.md +112 -0
- package/core/adapter-parity-matrix.md +170 -0
- package/core/commands/brainstorm-idea.md +98 -0
- package/core/commands/brainstorm-phase.md +129 -0
- package/core/commands/complete-phase.md +130 -0
- package/core/commands/ecosystem.md +161 -0
- package/core/commands/hotfix.md +64 -0
- package/core/commands/initiative.md +119 -0
- package/core/commands/lanes.md +94 -0
- package/core/commands/log.md +45 -0
- package/core/commands/migrate.md +70 -0
- package/core/commands/review.md +31 -0
- package/core/commands/session.md +79 -0
- package/core/commands/start-phase.md +161 -0
- package/core/commands/start-project.md +142 -0
- package/core/commands/sync-docs.md +81 -0
- package/core/commands/systematic-debug.md +46 -0
- package/core/commands/track.md +54 -0
- package/core/commands/validate.md +96 -0
- package/core/ecosystem/layout.md +128 -0
- package/core/ecosystem/lib/index.js +245 -0
- package/core/ecosystem/lib/initiative.js +258 -0
- package/core/ecosystem/lib/pointer.js +198 -0
- package/core/ecosystem/lib/state.js +295 -0
- package/core/ecosystem/schema/ecosystem.schema.json +85 -0
- package/core/ecosystem/schema/initiative.schema.json +61 -0
- package/core/ecosystem/scripts/session-append.sh +167 -0
- package/core/ecosystem/templates/ecosystem-agents.md +79 -0
- package/core/ecosystem/templates/ecosystem-claude.md +79 -0
- package/core/ecosystem/templates/ecosystem-settings-claude.json +14 -0
- package/core/ecosystem/templates/initiative-template.md +50 -0
- package/core/engines/subagent-dispatch.md +80 -0
- package/core/git-hooks/commit-msg +14 -0
- package/core/git-hooks/contract.js +176 -0
- package/core/git-hooks/pre-push +15 -0
- package/core/git-hooks/run-check.js +160 -0
- package/core/instructions/legacy-project-md-hashes.json +12 -0
- package/core/instructions/navigation.md +14 -0
- package/core/instructions/rules-body.md +454 -0
- package/core/lanes/lib/board.js +161 -0
- package/core/lanes/lib/land.js +301 -0
- package/core/lanes/lib/signals.js +207 -0
- package/core/lanes/lib/state.js +325 -0
- package/core/lib/frontmatter.js +163 -0
- package/core/lib/okf-migrate.js +374 -0
- package/core/lib/okf-types.js +61 -0
- package/core/lifecycle-contract.md +59 -0
- package/core/orchestration/capability-routing.js +120 -0
- package/core/orchestration/continue.js +102 -0
- package/core/orchestration/dispatch.js +366 -0
- package/core/orchestration/events.js +197 -0
- package/core/orchestration/handoff.js +317 -0
- package/core/orchestration/index.js +50 -0
- package/core/orchestration/run-artifact.js +93 -0
- package/core/orchestration/scout.js +327 -0
- package/core/orchestration/session-log.js +123 -0
- package/core/orchestration/tracking.js +180 -0
- package/core/orchestration/types.js +131 -0
- package/core/scripts/brainstorm-gate.sh +157 -0
- package/core/scripts/check-history-reminder.sh +110 -0
- package/core/scripts/sessionstart-handoff.sh +180 -0
- package/core/specs-templates/CLAUDE.md +484 -0
- package/core/specs-templates/README.md +32 -0
- package/core/specs-templates/specs/README.md +30 -0
- package/core/specs-templates/specs/adhoc/README.md +31 -0
- package/core/specs-templates/specs/adhoc/_TEMPLATE.md +29 -0
- package/core/specs-templates/specs/architecture/ecosystem.md +214 -0
- package/core/specs-templates/specs/backlog/backlog.md +46 -0
- package/core/specs-templates/specs/backlog/details/.gitkeep +0 -0
- package/core/specs-templates/specs/changelog/.gitkeep +0 -0
- package/core/specs-templates/specs/decisions/0000-template.md +33 -0
- package/core/specs-templates/specs/decisions/README.md +29 -0
- package/core/specs-templates/specs/decisions/impact-map.md +14 -0
- package/core/specs-templates/specs/decisions/index.md +4 -0
- package/core/specs-templates/specs/index.md +16 -0
- package/core/specs-templates/specs/phases/README.md +41 -0
- package/core/specs-templates/specs/phases/index.md +6 -0
- package/core/specs-templates/specs/planning/roadmap.md +23 -0
- package/core/specs-templates/specs/status.md +70 -0
- package/core/specs-templates/specs/vision/principles.md +16 -0
- package/core/specs-templates/specs/vision/project-charter.md +35 -0
- package/core/specs-templates/specs/vision/success-criteria.md +19 -0
- package/core/swarm/absorb.js +294 -0
- package/core/swarm/conductor.js +499 -0
- package/core/swarm/focus.js +151 -0
- package/core/swarm/inbox.js +222 -0
- package/core/swarm/join.js +138 -0
- package/core/swarm/lib/board.js +178 -0
- package/core/swarm/lib/brief.js +157 -0
- package/core/swarm/lib/git-sha-cache.js +71 -0
- package/core/swarm/lib/incremental-log.js +117 -0
- package/core/swarm/lib/manifest.js +578 -0
- package/core/swarm/lib/pre-merge.js +112 -0
- package/core/swarm/lib/saga.js +146 -0
- package/core/swarm/lib/sessions.js +83 -0
- package/core/swarm/lib/tokens.js +255 -0
- package/core/swarm/lib/wave-ordering.js +55 -0
- package/core/swarm/schema/board.schema.json +54 -0
- package/core/swarm/schema/contract.schema.json +56 -0
- package/core/swarm/schema/dispatch-run.schema.json +70 -0
- package/core/swarm/schema/manifest.schema.json +234 -0
- package/core/swarm/schema/signal.schema.json +61 -0
- package/core/swarm/signals.js +296 -0
- package/core/swarm/supervise.md +81 -0
- package/core/waves/lib/plan-graph.js +175 -0
- package/core/waves/lib/waves.js +83 -0
- package/package.json +46 -0
|
@@ -0,0 +1,454 @@
|
|
|
1
|
+
## Autonomous Behaviors (Always-On Rules)
|
|
2
|
+
|
|
3
|
+
### Rule 1: Always Orient First
|
|
4
|
+
|
|
5
|
+
Before ANY work, read `specs/status.md`. This tells you:
|
|
6
|
+
- What phase is active
|
|
7
|
+
- What's blocking progress
|
|
8
|
+
- What P0 items need attention
|
|
9
|
+
|
|
10
|
+
### Rule 2: Auto-Update Tracking After Changes
|
|
11
|
+
|
|
12
|
+
After completing ANY meaningful work, automatically update:
|
|
13
|
+
|
|
14
|
+
1. **Your phase's `tasks.md`** (the phase bound to your branch — Rule 15) — mark completed `[x]`, in-progress `[/]`
|
|
15
|
+
2. **`specs/status.md`** — if phase progress, blockers, or P0 items changed (touch only your own lane's row — Rule 15)
|
|
16
|
+
3. **`specs/changelog/YYYY-MM.md`** — log what changed (one line per change, append-only)
|
|
17
|
+
|
|
18
|
+
Use {{TASK_TOOL}} to track in-session task progress. Do NOT wait for the user to ask you to update tracking.
|
|
19
|
+
|
|
20
|
+
#### Why
|
|
21
|
+
Tracking debt compounds invisibly. A task list one day stale is recoverable; one week stale is fiction. Status drift is how phases silently lose direction.
|
|
22
|
+
|
|
23
|
+
#### Red Flags — STOP and update tracking now
|
|
24
|
+
|
|
25
|
+
| If you find yourself thinking… | …STOP and update before doing anything else |
|
|
26
|
+
|---|---|
|
|
27
|
+
| "I'll batch the tracking updates at the end" | The end never comes — context fades and details get lost |
|
|
28
|
+
| "This change is too small to log" | Small changes accumulate into invisible drift |
|
|
29
|
+
| "The diff makes it obvious what changed" | The diff shows *what*; the changelog explains *why* |
|
|
30
|
+
| "The user can read git log" | Git log doesn't index by phase or backlog ID |
|
|
31
|
+
| "I'll log this as part of the next bigger update" | Bigger updates conflate decisions and lose per-step reasoning |
|
|
32
|
+
|
|
33
|
+
#### Anti-Rationalization Counters
|
|
34
|
+
|
|
35
|
+
- "It's faster to do the work first and track at the end" — wrong: reconstruction takes 2-3× longer than real-time logging.
|
|
36
|
+
- "{{TASK_TOOL_NAME}} is enough" — {{TASK_TOOL_NAME}} is in-session only; `tasks.md` is the durable record.
|
|
37
|
+
- "Mid-task tracking interrupts flow" — a one-line update costs <30s; reconstructing a day later costs 30 minutes.
|
|
38
|
+
|
|
39
|
+
### Rule 3: Auto-Track Discoveries
|
|
40
|
+
|
|
41
|
+
When you discover a bug, tech debt, or enhancement during work:
|
|
42
|
+
- Add it to `specs/backlog/backlog.md` immediately with appropriate priority
|
|
43
|
+
- Mention it to the user: "I found [issue] and added it as [ID] to backlog"
|
|
44
|
+
|
|
45
|
+
### Rule 4: Pre-Phase Bug Check
|
|
46
|
+
|
|
47
|
+
Before starting work on a new phase:
|
|
48
|
+
- Scan `specs/backlog/backlog.md` for P0/P1 bugs
|
|
49
|
+
- If any exist, recommend addressing them first
|
|
50
|
+
- Present: "N open bugs (X critical), recommend fixing before proceeding"
|
|
51
|
+
|
|
52
|
+
Starting a phase while other lanes are active is normal (Rule 15) — the bug
|
|
53
|
+
check still runs per phase start.
|
|
54
|
+
|
|
55
|
+
### Rule 5: Phase Boundary Awareness
|
|
56
|
+
|
|
57
|
+
When completing the last task in a phase:
|
|
58
|
+
- Prompt the user: "All tasks in Phase N are complete. Run `/complete-phase` to verify and release?"
|
|
59
|
+
- Do NOT auto-complete a phase without user confirmation
|
|
60
|
+
- "Complete" means the phase bound to YOUR branch (Rule 15); landing it on
|
|
61
|
+
`main` follows the Rule 6 landing order when other lanes are in flight
|
|
62
|
+
|
|
63
|
+
### Rule 6: Git Lifecycle
|
|
64
|
+
|
|
65
|
+
> **Enforced vs advised.** momentum installs git hooks that *enforce* the
|
|
66
|
+
> high-stakes parts of this lifecycle (see `core/lifecycle-contract.md`):
|
|
67
|
+
> `commit-msg` validates Conventional Commits; `pre-push` blocks direct pushes
|
|
68
|
+
> to `main`/`staging` without the single-use `.momentum/merge-approved`
|
|
69
|
+
> sentinel, and blocks release-tag pushes lacking verification evidence
|
|
70
|
+
> (Rule 12). Hooks install to `.githooks/` via `core.hooksPath`. Emergency
|
|
71
|
+
> bypass (auditable, preferred over `--no-verify`): `MOMENTUM_SKIP_HOOKS=1`.
|
|
72
|
+
> Everything else below is agent convention, not mechanism.
|
|
73
|
+
>
|
|
74
|
+
> *Optional hardening:* enable your forge's server-side branch protection
|
|
75
|
+
> (GitHub Rulesets / GitLab protected branches / Bitbucket permissions) as an
|
|
76
|
+
> unbypassable backstop. momentum stays forge-neutral and ships no forge code.
|
|
77
|
+
|
|
78
|
+
#### Starting Work
|
|
79
|
+
- **Before ANY code change**, check current branch
|
|
80
|
+
- If on `main` or `staging`, **auto-create a feature branch**:
|
|
81
|
+
- Phase work: `phase-N-shortname`
|
|
82
|
+
- Bug fix: `fix/BUG-NNN-short-desc`
|
|
83
|
+
- Feature: `feat/short-desc`
|
|
84
|
+
- Tech debt: `refactor/TD-NNN-short-desc`
|
|
85
|
+
|
|
86
|
+
#### During Work
|
|
87
|
+
- **Auto-commit** after each logical unit with conventional commits:
|
|
88
|
+
- `feat(scope):` | `fix(scope):` | `docs:` | `refactor(scope):` | `chore:` | `infra:`
|
|
89
|
+
- Keep commits atomic — one logical change per commit
|
|
90
|
+
- Push to remote after significant milestones
|
|
91
|
+
|
|
92
|
+
#### Completing Work
|
|
93
|
+
- Commit all remaining changes, push branch
|
|
94
|
+
- **ASK the user** before merging to `staging` or `main`
|
|
95
|
+
|
|
96
|
+
| Action | Agent does automatically | Needs approval | Hook enforcement |
|
|
97
|
+
|--------|--------------------------|----------------|------------------|
|
|
98
|
+
| Create feature branch | Yes | No | — (convention) |
|
|
99
|
+
| Commit to feature branch | Yes | No | `commit-msg` validates the message |
|
|
100
|
+
| Push feature branch | Yes | No | `pre-push` allows (non-protected) |
|
|
101
|
+
| Delete merged feature branch | Yes (after confirmed merge) | No | `/complete-phase` step 13 |
|
|
102
|
+
| Merge to `staging`/`main` | No | **Yes** | `pre-push` **blocks** without `.momentum/merge-approved` |
|
|
103
|
+
| Tag a release | No | **Yes** | `pre-push` **blocks** without verification evidence |
|
|
104
|
+
|
|
105
|
+
#### Landing Order — Concurrent Lanes (Rule 15)
|
|
106
|
+
|
|
107
|
+
When more than one lane is in flight, `main` is the runway — lanes land
|
|
108
|
+
**one at a time**:
|
|
109
|
+
|
|
110
|
+
1. One lane merges (with its approval gate above).
|
|
111
|
+
2. The full suite runs green on the updated `main` **before** the next landing.
|
|
112
|
+
3. Remaining lanes **rebase onto the updated `main`** before they land.
|
|
113
|
+
4. Stacked (dependent) lanes land parent-first; a child rebases onto its
|
|
114
|
+
parent until the parent lands, then onto `main`.
|
|
115
|
+
|
|
116
|
+
Never land two lanes back-to-back without the suite passing in between — a
|
|
117
|
+
green suite on each lane's branch does not prove the *combination* is green.
|
|
118
|
+
|
|
119
|
+
#### Why
|
|
120
|
+
Direct commits to `main` bypass review, history, and rollback. A single rushed commit on `main` is harder to revert than ten commits on a branch. The branch convention is the cheapest possible insurance against catastrophic mistakes.
|
|
121
|
+
|
|
122
|
+
#### Red Flags — STOP and check the branch
|
|
123
|
+
|
|
124
|
+
| If you find yourself thinking… | …STOP and switch to a branch |
|
|
125
|
+
|---|---|
|
|
126
|
+
| "Just one tiny commit to main" | One becomes ten — branch first, decide later |
|
|
127
|
+
| "I'll create the branch after these edits" | The edits are the work; the branch is non-optional |
|
|
128
|
+
| "The hook is in the way, --no-verify just this once" | The momentum hooks are real now. Fix the cause; for a genuine emergency use the auditable `MOMENTUM_SKIP_HOOKS=1`, never blanket `--no-verify`. |
|
|
129
|
+
| "Force push is fine, nobody else is on this branch" | Future you is on this branch. `--force-with-lease` at minimum. |
|
|
130
|
+
|
|
131
|
+
#### Anti-Rationalization Counters
|
|
132
|
+
|
|
133
|
+
- "It's a one-line typo fix on main" — branches are free; revert is cheap; main is sacred.
|
|
134
|
+
- "The branch protection isn't set up yet" — that's a reason to be more careful, not less.
|
|
135
|
+
- "I'll squash-merge later, so the intermediate commits don't matter" — they matter for `git bisect` and for narrating *why*.
|
|
136
|
+
|
|
137
|
+
### Rule 7: Plan Before Implementing
|
|
138
|
+
|
|
139
|
+
For any non-trivial implementation (new feature, architectural change):
|
|
140
|
+
- Use `/brainstorm-phase` to design the approach first
|
|
141
|
+
- Present the plan for user approval before making changes
|
|
142
|
+
|
|
143
|
+
### Rule 8: Record Phase History
|
|
144
|
+
|
|
145
|
+
While working on a phase, append meaningful changes to that phase's history log — `specs/phases/<phase-bound-to-your-branch>/history.md` (Rule 15; each lane writes only its own history).
|
|
146
|
+
|
|
147
|
+
#### What counts as "meaningful"
|
|
148
|
+
|
|
149
|
+
Append a history entry when ANY of these occur:
|
|
150
|
+
|
|
151
|
+
| Trigger | Entry type |
|
|
152
|
+
|---|---|
|
|
153
|
+
| ADR was created or its status/decision changed | `[DECISION]` |
|
|
154
|
+
| Phase scope was added to or reduced | `[SCOPE_CHANGE]` |
|
|
155
|
+
| Bug, tech debt, or enhancement was added to backlog | `[DISCOVERY]` |
|
|
156
|
+
| New feature was added to the phase plan | `[FEATURE]` |
|
|
157
|
+
| Architectural pattern or integration approach changed | `[ARCH_CHANGE]` |
|
|
158
|
+
| Locked evaluator was defined or its evaluation set changed | `[EVALUATOR]` |
|
|
159
|
+
| Anything else worth a future reader's time | `[NOTE]` |
|
|
160
|
+
|
|
161
|
+
After writing a history entry, check `specs/decisions/impact-map.md` and add any new topics so `/sync-docs` can find affected files.
|
|
162
|
+
|
|
163
|
+
The hook script `scripts/check-history-reminder.sh` runs after edits as a safety net — heed its prompts.
|
|
164
|
+
|
|
165
|
+
#### Format (APPEND ONLY)
|
|
166
|
+
|
|
167
|
+
```
|
|
168
|
+
### [TYPE] YYYY-MM-DD — Short title
|
|
169
|
+
Topics: topic-1, topic-2
|
|
170
|
+
Affects-phases: phase-N-name (or "none")
|
|
171
|
+
Affects-specs: path/to/file.md#section (or "none")
|
|
172
|
+
Detail: One to three sentences describing what changed and why.
|
|
173
|
+
|
|
174
|
+
---
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
#### Why
|
|
178
|
+
The history log is the only place that preserves *why* a decision was made at the moment it was made. Specs document the current state; commits document mechanical changes; only history captures motivation. Without it, six months later nobody can reconstruct whether a constraint is load-bearing or accidental.
|
|
179
|
+
|
|
180
|
+
#### Red Flags — STOP and log
|
|
181
|
+
|
|
182
|
+
| If you find yourself thinking… | …STOP and append the entry now |
|
|
183
|
+
|---|---|
|
|
184
|
+
| "I'll write the history at the end of the phase" | You won't remember the *why*. Log when the decision is fresh. |
|
|
185
|
+
| "This decision isn't important enough to log" | If it's not worth logging, it's not worth deciding — log it or revert it. |
|
|
186
|
+
| "I already mentioned it in the commit message" | Commit messages get buried; history.md is the canonical source. |
|
|
187
|
+
| "The change is obvious from the diff" | Diffs show *what*; history shows *why*. |
|
|
188
|
+
|
|
189
|
+
#### Anti-Rationalization Counters
|
|
190
|
+
|
|
191
|
+
- "We didn't decide anything — just discovered an issue" — that's `[DISCOVERY]`, log it.
|
|
192
|
+
- "It's a minor scope tweak, not a real `[SCOPE_CHANGE]`" — every scope change is real, log it.
|
|
193
|
+
- "I'll consolidate entries later" — consolidation loses per-decision context.
|
|
194
|
+
|
|
195
|
+
### Rule 9: Doc Sync Protocol — Never Mid-Phase, Always at Completion
|
|
196
|
+
|
|
197
|
+
- **During a phase**: Record to history. Do NOT update other specs.
|
|
198
|
+
- **At phase completion**: Run `/sync-docs` BEFORE `/complete-phase`.
|
|
199
|
+
|
|
200
|
+
#### Multi-repo projects only
|
|
201
|
+
|
|
202
|
+
If this project depends on, or is depended on by, other repos in a parent workspace:
|
|
203
|
+
- NEVER modify docs that live in another repo during `/sync-docs`. You only own this repo's docs.
|
|
204
|
+
- If a history entry's `Affects-specs:` path starts with `../` (or otherwise points outside this repo), leave that file alone.
|
|
205
|
+
- Flag the cross-repo impact to the user — give the exact path — so they can sync the other repo manually.
|
|
206
|
+
- Cross-repo doc ownership is a structural choice. Never quietly change docs you don't own.
|
|
207
|
+
|
|
208
|
+
### Rule 10: Architecture Specs Stability (monorepo only)
|
|
209
|
+
|
|
210
|
+
Files under `specs/architecture/` are constitutional documents. Treat them as a stable reference *during* phase work. The key distinction is **additive bookkeeping** vs **architectural decisions**.
|
|
211
|
+
|
|
212
|
+
**During phase implementation (both types — no spec changes):**
|
|
213
|
+
- READ specs as stable reference
|
|
214
|
+
- NEVER modify them based on implementation discoveries
|
|
215
|
+
- Log all gaps and changes as `[ARCH_CHANGE]` in phase history with `Affects-specs:`
|
|
216
|
+
|
|
217
|
+
**At phase completion (via `/sync-docs`):**
|
|
218
|
+
- **Additive changes** (new fields, new ports, new modes — extending an existing design): update specs directly. No ADR required.
|
|
219
|
+
- **Decisional changes** (approach changes, trade-off choices, design direction shifts): require an ADR amendment **before** any spec update.
|
|
220
|
+
|
|
221
|
+
#### Why
|
|
222
|
+
The original "all spec changes via ADR" rule worked when the architecture was stabilizing and every change was a decision. By mid-to-late phases, the architecture is proven — most changes are additive extensions, not decisions. Requiring ADRs for bookkeeping creates spec staleness while adding no value. ADRs capture *why* a path was chosen; they're not required when you're just recording *what was added*.
|
|
223
|
+
|
|
224
|
+
#### Red Flags — STOP and route correctly
|
|
225
|
+
|
|
226
|
+
| If you find yourself thinking… | …STOP |
|
|
227
|
+
|---|---|
|
|
228
|
+
| "I just need to update one field, not a real change" | Additive — fine at completion; not now. Log `[ARCH_CHANGE]`. |
|
|
229
|
+
| "It's faster to fix the spec than to log the gap" | Faster locally, catastrophic globally — specs out of sync with rationale. |
|
|
230
|
+
| "The implementation diverged because the spec was wrong" | That's a decision — ADR first, spec update second. Don't silently rewrite. |
|
|
231
|
+
| "I'll log it as `[NOTE]` instead of `[ARCH_CHANGE]`" | If it touches `specs/architecture/`, it's `[ARCH_CHANGE]`. |
|
|
232
|
+
|
|
233
|
+
#### Anti-Rationalization Counters
|
|
234
|
+
|
|
235
|
+
- "Specs are wrong, code is right, so update specs" — only after an ADR documents *why* the design shifted.
|
|
236
|
+
- "Mid-phase spec edits are fine if I'm careful" — the rule isn't about care; it's about preventing reference instability while you're depending on the reference.
|
|
237
|
+
- "This is just renaming, not redesigning" — renames are decisions when others read the spec.
|
|
238
|
+
|
|
239
|
+
### Rule 11: Evaluator Discipline — Lock Evaluators Before Loops
|
|
240
|
+
|
|
241
|
+
Before building any learning, optimization, or self-improvement loop:
|
|
242
|
+
|
|
243
|
+
1. Define the **evaluation set** — a fixed corpus with known-good outputs
|
|
244
|
+
2. Define the **scalar** — a single number that improves or doesn't
|
|
245
|
+
3. Commit the evaluator to `tests/benchmarks/` with a version tag
|
|
246
|
+
4. Build the loop **AFTER** the evaluator is committed
|
|
247
|
+
5. **NEVER** change the evaluator while the loop is being optimized
|
|
248
|
+
|
|
249
|
+
#### Why
|
|
250
|
+
Optimization loops with mutable evaluators don't measure progress — they measure motion. Every "small fix" to the eval set silently rewrites the score history and makes A-vs-B comparisons meaningless. Locking the evaluator first costs an hour; not locking it costs the entire experiment.
|
|
251
|
+
|
|
252
|
+
#### Red Flags — STOP and freeze
|
|
253
|
+
|
|
254
|
+
| If you find yourself thinking… | …STOP |
|
|
255
|
+
|---|---|
|
|
256
|
+
| "Just one tweak to the eval so this run looks better" | That's exactly the failure mode. Freeze first; tweak in a v2 evaluator. |
|
|
257
|
+
| "We'll lock the evaluator after we know what works" | You can't know what works without a locked evaluator. |
|
|
258
|
+
| "The current eval doesn't measure what we actually care about" | Correct — but freeze it before optimizing, then version-bump to a new locked eval. |
|
|
259
|
+
| "It's just an internal experiment, locking is overkill" | Internal experiments produce internal beliefs that drive external decisions. Lock. |
|
|
260
|
+
|
|
261
|
+
#### Anti-Rationalization Counters
|
|
262
|
+
|
|
263
|
+
- "The eval set is too small, I'll just add a few more cases" — version-bump the evaluator (`v1` → `v2`); don't mutate `v1`.
|
|
264
|
+
- "I noticed a bug in the scorer mid-run" — fix it in `v2`; rerun the prior runs against `v2`; don't backfill `v1` scores.
|
|
265
|
+
- "Production data drifted, I should refresh the eval" — that's a `v2` decision, not a `v1` patch.
|
|
266
|
+
|
|
267
|
+
### Rule 12: Verify Before Claim — No Completion Without Evidence
|
|
268
|
+
|
|
269
|
+
Before claiming any task, fix, or implementation is "done":
|
|
270
|
+
|
|
271
|
+
1. Run the actual verification command (test, lint, typecheck, smoke test, build)
|
|
272
|
+
2. Read the output — both exit code and content
|
|
273
|
+
3. If the output isn't fresh from this attempt in this session, treat the task as unverified
|
|
274
|
+
4. Only mark a task `[x]` after a verification command produced passing output in this session
|
|
275
|
+
|
|
276
|
+
#### Why
|
|
277
|
+
The most common agentic-workflow failure is "should work now" — claiming completion based on intent rather than evidence. Fresh, observable output is the only signal that the change actually achieves what was claimed. Box-checking without verification compounds across phases until shipped releases contain unrun code paths.
|
|
278
|
+
|
|
279
|
+
#### Red Flags — STOP and run the verification
|
|
280
|
+
|
|
281
|
+
| If you find yourself thinking… | …STOP and run the verification before marking done |
|
|
282
|
+
|---|---|
|
|
283
|
+
| "I'm confident this works — no need to test" | Confidence is not evidence. Run the test. |
|
|
284
|
+
| "The change is small enough that I can skip verification" | "Small" is the most common predicate of a regression. Run it. |
|
|
285
|
+
| "I already tested something similar earlier" | Earlier ≠ now. Re-run against the current code. |
|
|
286
|
+
| "The unit tests pass — that's enough" | Unit tests don't catch wiring bugs. Run the integration / smoke path too. |
|
|
287
|
+
| "I'll batch verifications at the end of the phase" | At the end you can't tell which change caused which failure. Verify per-task. |
|
|
288
|
+
|
|
289
|
+
#### Anti-Rationalization Counters
|
|
290
|
+
|
|
291
|
+
- "The diff is obviously correct" — diffs lie when context is incomplete. Run the test.
|
|
292
|
+
- "The CI will catch any issue" — CI catches it after you claimed done; that's the failure mode this rule prevents.
|
|
293
|
+
- "Type checking passed, so it works" — types catch shape errors, not behavior. Run the runtime check.
|
|
294
|
+
- "I read the code carefully and it looks right" — careful reading misses race conditions, missing imports, off-by-one bugs. Verification commands don't.
|
|
295
|
+
- "The previous task was similar and that worked" — previous ≠ current. Each task gets its own verification.
|
|
296
|
+
|
|
297
|
+
If a verification command does not exist for the task, write one before marking done. If a command can't run in the current environment, say so explicitly — do not silently downgrade to "looks correct".
|
|
298
|
+
|
|
299
|
+
---
|
|
300
|
+
|
|
301
|
+
### Rule 13: Test-Driven Development (TDD) — Opt-in
|
|
302
|
+
|
|
303
|
+
If enabled in the project rules extensions (under `## Project Extensions` in this file), follow a strict test-first development loop:
|
|
304
|
+
|
|
305
|
+
1. **Red**: Write a unit or integration test that specifies the new behavior *before* writing any application code.
|
|
306
|
+
2. **Verify Failure**: Run the test runner and verify that the newly added test fails. Do not write any implementation code until you have seen the test fail.
|
|
307
|
+
3. **Green**: Write the minimal application code necessary to make the test pass.
|
|
308
|
+
4. **Refactor**: Clean up and optimize the code while keeping all tests green.
|
|
309
|
+
|
|
310
|
+
#### Red Flags — STOP and write the test first
|
|
311
|
+
|
|
312
|
+
| If you find yourself thinking… | …STOP |
|
|
313
|
+
|---|---|
|
|
314
|
+
| "I will write the tests at the end" | Post-facto tests are not TDD — they inherit confirmation bias from the implementation. |
|
|
315
|
+
| "The change is too simple to warrant a test-first approach" | Simple changes are excellent TDD candidates to establish correct wiring. |
|
|
316
|
+
|
|
317
|
+
### Rule 14: Work-Type Escalation — Pick the Lightest Type That Fits
|
|
318
|
+
|
|
319
|
+
Not every change is a phase. momentum has three work types (see
|
|
320
|
+
`specs/adhoc/README.md`):
|
|
321
|
+
|
|
322
|
+
| Type | When | How |
|
|
323
|
+
|---|---|---|
|
|
324
|
+
| `phase` | Net-new features; cross-cutting or architectural work | `/brainstorm-phase` → `/start-phase` → … → `/complete-phase` |
|
|
325
|
+
| `quick-task` | A bounded bugfix / chore / audit / dependency bump | `/hotfix` — ad-hoc record + Rule 12 gate, no phase scaffold |
|
|
326
|
+
| `spike` | Time-boxed, throwaway exploration | `/hotfix --spike` — declared, gate-exempt, record what was learned |
|
|
327
|
+
|
|
328
|
+
**Governing principle:** select the lightest work type that fits; escalate only
|
|
329
|
+
when scope/risk/cross-cutting impact justifies it. (Per Anthropic's "build the
|
|
330
|
+
simplest thing first; add structure only when it demonstrably helps.")
|
|
331
|
+
|
|
332
|
+
**A quick-task MUST escalate to a phase when it:** touches more than ~5 files of
|
|
333
|
+
production code, modifies anything under `specs/architecture/`, needs an ADR,
|
|
334
|
+
changes a public contract/interface, or displaces a planned phase.
|
|
335
|
+
|
|
336
|
+
#### Red Flags — STOP and escalate (or de-escalate)
|
|
337
|
+
|
|
338
|
+
| If you find yourself thinking… | …STOP |
|
|
339
|
+
|---|---|
|
|
340
|
+
| "This `/hotfix` is growing — I'll just keep going" | If it now touches architecture or many files, it's a phase. Escalate. |
|
|
341
|
+
| "I'll spin up a whole phase for this one-line fix" | Over-ceremony. A `/hotfix` quick-task is the right size. |
|
|
342
|
+
| "It's exploratory but I'll ship it straight to main" | A spike is gate-exempt *because* it's throwaway. Harden it as a quick-task first. |
|
|
343
|
+
|
|
344
|
+
### Rule 15: Concurrent Workstreams — Lanes
|
|
345
|
+
|
|
346
|
+
Multiple workstreams may be active in one repo at the same time (see
|
|
347
|
+
ADR-0001). A **lane** is one workstream: a branch (usually in its own
|
|
348
|
+
worktree) bound to one phase or ad-hoc record.
|
|
349
|
+
|
|
350
|
+
#### Lane binding — which phase is yours
|
|
351
|
+
|
|
352
|
+
- Your phase is **the phase bound to your branch**: branch
|
|
353
|
+
`phase-N-shortname` ↔ directory `specs/phases/phase-N-shortname/`.
|
|
354
|
+
- `specs/status.md`'s Active Phase table is the **fallback and the
|
|
355
|
+
cross-lane overview** — read it to see what else is in flight, not to
|
|
356
|
+
decide which phase is yours.
|
|
357
|
+
- Non-phase branches (`fix/*`, `chore/*`, `feat/*`) bind to the ad-hoc lane
|
|
358
|
+
(`specs/adhoc/`, Rule 14). Detached HEAD → fall back to `status.md`.
|
|
359
|
+
|
|
360
|
+
#### Lane-scoped tracking
|
|
361
|
+
|
|
362
|
+
- Write ONLY your own phase's artifacts (`tasks.md`, `history.md`,
|
|
363
|
+
`evidence/`) — these are parallel-safe by construction.
|
|
364
|
+
- Shared tracking files (`status.md`, `backlog.md`, `changelog/`) are
|
|
365
|
+
**append / own-row-touch only** from a lane: add or edit your own
|
|
366
|
+
row/line; never reformat, renumber, or rewrite other lanes' entries.
|
|
367
|
+
- The Active Phase table holds **one row per active lane**
|
|
368
|
+
(Phase | Branch | Status | Progress). Add your row at phase start; update
|
|
369
|
+
only your row; mark it at completion.
|
|
370
|
+
|
|
371
|
+
#### Landing
|
|
372
|
+
|
|
373
|
+
Lanes integrate per the Rule 6 **Landing Order** — one lane at a time, suite
|
|
374
|
+
green on updated `main` between landings, remaining lanes rebase.
|
|
375
|
+
|
|
376
|
+
**Mechanism:** `momentum lanes` — open/board/queue/signal/inbox/done/land
|
|
377
|
+
(see the `/lanes` recipe). The board shows every lane + queue pressure from
|
|
378
|
+
any session; `lanes land` enforces turn, rebase-freshness, and the
|
|
379
|
+
Rule-14-graded evidence gate before merging.
|
|
380
|
+
|
|
381
|
+
#### Off-lane work
|
|
382
|
+
|
|
383
|
+
Brainstorms and spikes are **off-lane** — zero tracking contention by
|
|
384
|
+
design. `/brainstorm-idea` writes no files; a spike writes only its own
|
|
385
|
+
`specs/adhoc/<id>/` record. Neither touches the Active Phase table.
|
|
386
|
+
|
|
387
|
+
#### Why
|
|
388
|
+
Two concurrent sessions cannot both be right about "the active phase" when
|
|
389
|
+
the spec layer models exactly one. Binding phase to branch makes each
|
|
390
|
+
session's context unambiguous, and append-only discipline on shared files
|
|
391
|
+
keeps N lanes trivially mergeable. Git isolation (worktrees) was never the
|
|
392
|
+
problem — the spec layer was.
|
|
393
|
+
|
|
394
|
+
#### Red Flags — STOP and re-scope to your lane
|
|
395
|
+
|
|
396
|
+
| If you find yourself thinking… | …STOP |
|
|
397
|
+
|---|---|
|
|
398
|
+
| "I'll just fix this line in the other phase's tasks.md while I'm here" | That's another lane's artifact. Leave it; tell the user or file a backlog item. |
|
|
399
|
+
| "status.md is stale for that other lane, I'll update their row" | Their session owns that row. Touch only your own. |
|
|
400
|
+
| "I'll reformat the Active Phase table while adding my row" | Reformatting rewrites every lane's row — append yours, change nothing else. |
|
|
401
|
+
| "Which phase am I on? I'll take status.md's first row" | Your branch decides your phase. status.md is the overview, not the binding. |
|
|
402
|
+
| "Both lanes are done, I'll merge them together to save a suite run" | One at a time; suite green between landings (Rule 6 Landing Order). |
|
|
403
|
+
|
|
404
|
+
#### Anti-Rationalization Counters
|
|
405
|
+
|
|
406
|
+
- "The other lane's edit is tiny and obviously right" — cross-lane edits are how tracking corrupts; smallness is irrelevant.
|
|
407
|
+
- "Rebasing my lane again is wasted work" — rebasing is the price of a green runway; a stale lane landing on moved `main` is how combination bugs ship.
|
|
408
|
+
- "There's only one lane active right now, Rule 15 doesn't apply" — a single lane is the N=1 case; the binding still defines which phase is yours.
|
|
409
|
+
|
|
410
|
+
---
|
|
411
|
+
|
|
412
|
+
## Naming Conventions
|
|
413
|
+
|
|
414
|
+
### Backlog IDs
|
|
415
|
+
| Type | Prefix | Example |
|
|
416
|
+
|------|--------|---------|
|
|
417
|
+
| Bug | `BUG-` | `BUG-001` |
|
|
418
|
+
| Feature | `FEAT-` | `FEAT-001` |
|
|
419
|
+
| Tech Debt | `TD-` | `TD-001` |
|
|
420
|
+
| Enhancement | `ENH-` | `ENH-001` |
|
|
421
|
+
|
|
422
|
+
### Priorities
|
|
423
|
+
| Level | Meaning | SLA |
|
|
424
|
+
|-------|---------|-----|
|
|
425
|
+
| `P0` | Critical — blocks current phase | < 1 day |
|
|
426
|
+
| `P1` | High — current/next phase | < 1 week |
|
|
427
|
+
| `P2` | Medium — within 2 phases | < 1 phase |
|
|
428
|
+
| `P3` | Low — nice to have | best-effort |
|
|
429
|
+
|
|
430
|
+
### Git Branches
|
|
431
|
+
| Type | Pattern |
|
|
432
|
+
|------|---------|
|
|
433
|
+
| Phase | `phase-N-shortname` |
|
|
434
|
+
| Feature | `feat/description` |
|
|
435
|
+
| Bug fix | `fix/description` |
|
|
436
|
+
| Refactor | `refactor/description` |
|
|
437
|
+
| Infrastructure | `infra/description` |
|
|
438
|
+
| Delete after merge | `git push origin --delete <branch>` once merged |
|
|
439
|
+
|
|
440
|
+
### Git Commits (Conventional)
|
|
441
|
+
`feat:` | `fix:` | `docs:` | `refactor:` | `chore:` | `infra:`
|
|
442
|
+
|
|
443
|
+
Also accepted by the `commit-msg` hook: `test:` `perf:` `build:` `ci:` `style:` `revert:` (standard Conventional-Commit types). Scope and breaking-change `!` are optional, e.g. `fix(install)!: …`.
|
|
444
|
+
|
|
445
|
+
Use `infra:` for CI, build, deploy, tooling, and release-pipeline changes that don't ship code.
|
|
446
|
+
|
|
447
|
+
---
|
|
448
|
+
|
|
449
|
+
## Constraints
|
|
450
|
+
|
|
451
|
+
1. **No secrets in code** — all credentials via env vars
|
|
452
|
+
2. **Never commit to main** — always use feature/phase branches
|
|
453
|
+
3. **Plan before implementing** — use `/brainstorm-phase` for non-trivial work
|
|
454
|
+
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* `momentum lanes` board + `momentum lanes queue` (Phase 21b G3, FEAT-026).
|
|
5
|
+
*
|
|
6
|
+
* Both commands are computed views over the lane manifests at
|
|
7
|
+
* <git-common-dir>/momentum/lanes (state.js, ADR-0002) — any session, any
|
|
8
|
+
* worktree, no daemon. The board ALWAYS ends with the queue-pressure
|
|
9
|
+
* footer: count of done-but-unlanded lanes + oldest wait (platform
|
|
10
|
+
* decision 4 — WIP unbounded, back-pressure visible, never a gate).
|
|
11
|
+
*
|
|
12
|
+
* `--json` output is INTERNAL (stateVersion 1) and marked `unstable: true`;
|
|
13
|
+
* publishing the shape as a contract is the 21c one-way-door decision.
|
|
14
|
+
*
|
|
15
|
+
* Contract with bin/lanes.js: print own errors, return 1 on failure,
|
|
16
|
+
* 0/undefined on success. Zero dependencies — node builtins only.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
const { spawnSync } = require('child_process');
|
|
20
|
+
|
|
21
|
+
const state = require('./state');
|
|
22
|
+
|
|
23
|
+
// ─── helpers ─────────────────────────────────────────────────────────────
|
|
24
|
+
|
|
25
|
+
function fail(msg) {
|
|
26
|
+
console.error(`✗ ${msg}`);
|
|
27
|
+
return 1;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function hasJsonFlag(argv) {
|
|
31
|
+
return Array.isArray(argv) && argv.includes('--json');
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** Humanized time since `iso`: 3m, 2h, 1d4h. '?' when unparseable. */
|
|
35
|
+
function humanAge(iso, nowMs = Date.now()) {
|
|
36
|
+
const then = Date.parse(iso);
|
|
37
|
+
if (!Number.isFinite(then)) return '?';
|
|
38
|
+
const mins = Math.max(0, Math.floor((nowMs - then) / 60000));
|
|
39
|
+
if (mins < 60) return `${mins}m`;
|
|
40
|
+
const hours = Math.floor(mins / 60);
|
|
41
|
+
if (hours < 24) return `${hours}h`;
|
|
42
|
+
const days = Math.floor(hours / 24);
|
|
43
|
+
const remHours = hours % 24;
|
|
44
|
+
return remHours ? `${days}d${remHours}h` : `${days}d`;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** `phase:phase-3-x` | `adhoc:fix-BUG-7-z` | `unbound` (ref-less). */
|
|
48
|
+
function planLabel(planNode) {
|
|
49
|
+
if (!planNode || !planNode.type) return 'unbound';
|
|
50
|
+
return planNode.ref ? `${planNode.type}:${planNode.ref}` : planNode.type;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** Queue pressure over all lanes: done count + earliest doneAt. */
|
|
54
|
+
function queuePressure(lanes) {
|
|
55
|
+
const done = lanes.filter((l) => l.status === 'done');
|
|
56
|
+
const oldestDoneAt = done.map((l) => l.doneAt).filter(Boolean).sort()[0] || null;
|
|
57
|
+
return { doneCount: done.length, oldestDoneAt };
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** True when HEAD (this worktree) is already contained in the lane branch. */
|
|
61
|
+
function isFresh(cwd, branch) {
|
|
62
|
+
const res = spawnSync('git', ['merge-base', '--is-ancestor', 'HEAD', branch], {
|
|
63
|
+
cwd, encoding: 'utf8',
|
|
64
|
+
});
|
|
65
|
+
return res.status === 0;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function currentBranch(cwd) {
|
|
69
|
+
const res = spawnSync('git', ['rev-parse', '--abbrev-ref', 'HEAD'], {
|
|
70
|
+
cwd, encoding: 'utf8',
|
|
71
|
+
});
|
|
72
|
+
return res.status === 0 ? res.stdout.trim() : 'HEAD';
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// ─── momentum lanes (board) ──────────────────────────────────────────────
|
|
76
|
+
|
|
77
|
+
function cmdBoard(cwd, argv) {
|
|
78
|
+
const json = hasJsonFlag(argv);
|
|
79
|
+
const anchor = state.resolveAnchor(cwd);
|
|
80
|
+
if (!anchor) return fail('not inside a git repository');
|
|
81
|
+
|
|
82
|
+
const lanes = state.listLanes(anchor);
|
|
83
|
+
const visible = lanes.filter((l) => l.status !== 'closed');
|
|
84
|
+
const pressure = queuePressure(lanes);
|
|
85
|
+
|
|
86
|
+
if (json) {
|
|
87
|
+
console.log(JSON.stringify({
|
|
88
|
+
stateVersion: state.STATE_VERSION,
|
|
89
|
+
unstable: true, // internal shape per ADR-0002 — may change without notice
|
|
90
|
+
lanes: visible.map((l) => ({
|
|
91
|
+
...l,
|
|
92
|
+
unread: state.unreadCount(anchor, l.id),
|
|
93
|
+
overlaps: state.overlapWarnings(anchor, l.id, l.touches),
|
|
94
|
+
})),
|
|
95
|
+
queue: pressure,
|
|
96
|
+
}, null, 2));
|
|
97
|
+
return 0;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (visible.length === 0) {
|
|
101
|
+
console.log('no lanes — open one with: momentum lanes open <branch>');
|
|
102
|
+
console.log('queue: empty — nothing awaiting landing');
|
|
103
|
+
return 0;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
for (const lane of visible) {
|
|
107
|
+
let line = `● ${lane.id} ${planLabel(lane.planNode)} ${lane.grade} ${lane.status} ${humanAge(lane.opened)}`;
|
|
108
|
+
const unread = state.unreadCount(anchor, lane.id);
|
|
109
|
+
if (unread > 0) line += ` ✉${unread}`;
|
|
110
|
+
if (state.overlapWarnings(anchor, lane.id, lane.touches).length > 0) line += ' ⚠overlap';
|
|
111
|
+
console.log(line);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if (pressure.doneCount > 0) {
|
|
115
|
+
console.log(`queue: ${pressure.doneCount} done awaiting landing — oldest waiting ${humanAge(pressure.oldestDoneAt)}`);
|
|
116
|
+
} else {
|
|
117
|
+
console.log('queue: empty — nothing awaiting landing');
|
|
118
|
+
}
|
|
119
|
+
return 0;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// ─── momentum lanes queue ────────────────────────────────────────────────
|
|
123
|
+
|
|
124
|
+
function cmdQueue(cwd, argv) {
|
|
125
|
+
const json = hasJsonFlag(argv);
|
|
126
|
+
const anchor = state.resolveAnchor(cwd);
|
|
127
|
+
if (!anchor) return fail('not inside a git repository');
|
|
128
|
+
|
|
129
|
+
const queue = state.listLanes(anchor)
|
|
130
|
+
.filter((l) => l.status === 'done')
|
|
131
|
+
.sort((a, b) => String(a.doneAt).localeCompare(String(b.doneAt)));
|
|
132
|
+
|
|
133
|
+
if (json) {
|
|
134
|
+
console.log(JSON.stringify({
|
|
135
|
+
stateVersion: state.STATE_VERSION,
|
|
136
|
+
unstable: true, // internal shape per ADR-0002 — may change without notice
|
|
137
|
+
queue: queue.map((l, i) => ({
|
|
138
|
+
...l,
|
|
139
|
+
position: i + 1,
|
|
140
|
+
fresh: isFresh(cwd, l.branch),
|
|
141
|
+
})),
|
|
142
|
+
}, null, 2));
|
|
143
|
+
return 0;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
if (queue.length === 0) {
|
|
147
|
+
console.log('landing queue empty');
|
|
148
|
+
return 0;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const integration = currentBranch(cwd);
|
|
152
|
+
queue.forEach((l, i) => {
|
|
153
|
+
const fresh = isFresh(cwd, l.branch);
|
|
154
|
+
let line = `${i + 1}. ${l.id} grade=${l.grade} done=${l.doneAt} ${fresh ? 'fresh' : 'stale'}`;
|
|
155
|
+
if (!fresh) line += ` — rebase onto ${integration} before landing`;
|
|
156
|
+
console.log(line);
|
|
157
|
+
});
|
|
158
|
+
return 0;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
module.exports = { cmdBoard, cmdQueue };
|