maxsimcli 4.4.0 → 4.5.0
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/dist/.tsbuildinfo +1 -1
- package/dist/assets/CHANGELOG.md +19 -0
- package/dist/assets/dashboard/server.js +248 -240
- package/dist/assets/templates/agents/AGENTS.md +1 -0
- package/dist/assets/templates/agents/maxsim-drift-checker.md +522 -0
- package/dist/assets/templates/commands/maxsim/check-drift.md +56 -0
- package/dist/assets/templates/commands/maxsim/discuss.md +70 -0
- package/dist/assets/templates/commands/maxsim/realign.md +39 -0
- package/dist/assets/templates/workflows/check-drift.md +248 -0
- package/dist/assets/templates/workflows/discuss.md +343 -0
- package/dist/assets/templates/workflows/progress.md +8 -0
- package/dist/assets/templates/workflows/realign.md +288 -0
- package/dist/assets/templates/workflows/roadmap.md +69 -20
- package/dist/backend-server.cjs +52 -29
- package/dist/backend-server.cjs.map +1 -1
- package/dist/cli.cjs +261 -5
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +20 -1
- package/dist/cli.js.map +1 -1
- package/dist/core/core.d.ts.map +1 -1
- package/dist/core/core.js +1 -0
- package/dist/core/core.js.map +1 -1
- package/dist/core/drift.d.ts +37 -0
- package/dist/core/drift.d.ts.map +1 -0
- package/dist/core/drift.js +213 -0
- package/dist/core/drift.js.map +1 -0
- package/dist/core/frontmatter.d.ts.map +1 -1
- package/dist/core/frontmatter.js +3 -0
- package/dist/core/frontmatter.js.map +1 -1
- package/dist/core/index.d.ts +3 -2
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +12 -2
- package/dist/core/index.js.map +1 -1
- package/dist/core/init.d.ts +5 -3
- package/dist/core/init.d.ts.map +1 -1
- package/dist/core/init.js +89 -0
- package/dist/core/init.js.map +1 -1
- package/dist/core/types.d.ts +50 -1
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js.map +1 -1
- package/dist/core-RRjCSt0G.cjs.map +1 -1
- package/dist/{lifecycle-0M4VqOMm.cjs → lifecycle-DxCru7rk.cjs} +2 -2
- package/dist/{lifecycle-0M4VqOMm.cjs.map → lifecycle-DxCru7rk.cjs.map} +1 -1
- package/dist/mcp/phase-tools.d.ts.map +1 -1
- package/dist/mcp/phase-tools.js +17 -4
- package/dist/mcp/phase-tools.js.map +1 -1
- package/dist/mcp-server.cjs +20 -5
- package/dist/mcp-server.cjs.map +1 -1
- package/dist/{server-G1MIg_Oe.cjs → server-By0TN-nC.cjs} +21 -6
- package/dist/server-By0TN-nC.cjs.map +1 -0
- package/dist/skills-MYlMkYNt.cjs.map +1 -1
- package/package.json +1 -1
- package/dist/server-G1MIg_Oe.cjs.map +0 -1
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
<sanity_check>
|
|
2
|
+
Before executing any step in this workflow, verify:
|
|
3
|
+
1. The current directory contains a `.planning/` folder -- if not, stop and tell the user to run `/maxsim:new-project` first.
|
|
4
|
+
2. `.planning/DRIFT-REPORT.md` exists -- if not, stop and tell the user to run `/maxsim:check-drift` first.
|
|
5
|
+
</sanity_check>
|
|
6
|
+
|
|
7
|
+
<purpose>
|
|
8
|
+
Correct spec-code divergence in either direction. Realign-to-code updates `.planning/` to match the actual codebase. Realign-to-spec generates new fix phases to make code match the spec. Reads the DRIFT-REPORT.md produced by `/maxsim:check-drift`.
|
|
9
|
+
</purpose>
|
|
10
|
+
|
|
11
|
+
<core_principle>
|
|
12
|
+
This is an interactive orchestrator workflow, not an agent spawn. Realign-to-code requires per-item user decisions (Accept/Skip/Edit). Realign-to-spec requires user approval of proposed phase groupings. The workflow drives the interaction directly.
|
|
13
|
+
</core_principle>
|
|
14
|
+
|
|
15
|
+
<required_reading>
|
|
16
|
+
Read STATE.md before any operation to load project context.
|
|
17
|
+
</required_reading>
|
|
18
|
+
|
|
19
|
+
<process>
|
|
20
|
+
|
|
21
|
+
<step name="initialize" priority="first">
|
|
22
|
+
Load context and validate prerequisites:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
INIT=$(node ~/.claude/maxsim/bin/maxsim-tools.cjs init realign "$DIRECTION")
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Parse JSON for: `has_report`, `has_planning`, `report_path`, `state_path`, `requirements_path`, `roadmap_path`, `phase_dirs`, `current_phase`, `commit_docs`.
|
|
29
|
+
|
|
30
|
+
**Validation gates:**
|
|
31
|
+
- If `has_planning` is false: "No `.planning/` directory found. Run `/maxsim:new-project` first." STOP.
|
|
32
|
+
- If `has_report` is false: "No DRIFT-REPORT.md found. Run `/maxsim:check-drift` first to generate a drift report." STOP.
|
|
33
|
+
</step>
|
|
34
|
+
|
|
35
|
+
<step name="read_report">
|
|
36
|
+
Read the drift report metadata and content:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
REPORT=$(node ~/.claude/maxsim/bin/maxsim-tools.cjs drift read-report)
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Parse the result to extract:
|
|
43
|
+
- **Frontmatter:** `status`, `critical_count`, `warning_count`, `info_count`, `undocumented_count`, `total_items`, `aligned_count`
|
|
44
|
+
- **Body sections:** "Spec Ahead of Code", "Code Ahead of Spec", "No-Go Violations", "Undocumented Features"
|
|
45
|
+
|
|
46
|
+
**If `status` is `aligned`:**
|
|
47
|
+
```
|
|
48
|
+
No drift detected -- nothing to realign. All spec items match the codebase.
|
|
49
|
+
```
|
|
50
|
+
STOP.
|
|
51
|
+
</step>
|
|
52
|
+
|
|
53
|
+
<step name="select_direction">
|
|
54
|
+
Determine the realignment direction.
|
|
55
|
+
|
|
56
|
+
**If `$DIRECTION` was provided via `$ARGUMENTS`:** Use it directly. Validate it is either `to-code` or `to-spec`.
|
|
57
|
+
|
|
58
|
+
**If no direction was provided:** Present the user with a choice:
|
|
59
|
+
|
|
60
|
+
```markdown
|
|
61
|
+
## Drift Report Summary
|
|
62
|
+
|
|
63
|
+
**Status:** {critical_count} critical | {warning_count} warning | {info_count} info | {undocumented_count} undocumented
|
|
64
|
+
|
|
65
|
+
Choose a realignment direction:
|
|
66
|
+
|
|
67
|
+
1. **to-code** -- Update `.planning/` to match current codebase (spec follows code)
|
|
68
|
+
Best when: Code is correct and spec is outdated. Accepts code reality.
|
|
69
|
+
|
|
70
|
+
2. **to-spec** -- Generate fix phases to make code match spec (code follows spec)
|
|
71
|
+
Best when: Spec is correct and code has gaps. Creates implementation phases.
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Wait for user selection.
|
|
75
|
+
</step>
|
|
76
|
+
|
|
77
|
+
<step name="realign_to_code">
|
|
78
|
+
**Execute only if direction is `to-code`.**
|
|
79
|
+
|
|
80
|
+
Parse the drift report body to extract all drifted items from:
|
|
81
|
+
- "Spec Ahead of Code" section (requirements marked complete but code missing/incomplete)
|
|
82
|
+
- "Code Ahead of Spec" section (features in code but not captured in spec)
|
|
83
|
+
- "No-Go Violations" section (code violating declared constraints)
|
|
84
|
+
- "Undocumented Features" section (features with no spec coverage)
|
|
85
|
+
|
|
86
|
+
Build a list of actionable items. For each item, extract:
|
|
87
|
+
- Requirement ID (if applicable)
|
|
88
|
+
- Section heading/description
|
|
89
|
+
- Current spec text and location
|
|
90
|
+
- What was found (or not found) in code
|
|
91
|
+
- The report's fix recommendation
|
|
92
|
+
- All spec file references from the evidence section
|
|
93
|
+
|
|
94
|
+
**Process each item interactively:**
|
|
95
|
+
|
|
96
|
+
For each drifted item, present it to the user:
|
|
97
|
+
|
|
98
|
+
```markdown
|
|
99
|
+
### Item {N}/{total}: {Requirement ID or Feature Name}
|
|
100
|
+
|
|
101
|
+
**Severity:** {CRITICAL | WARNING | INFO}
|
|
102
|
+
**Direction:** {Spec ahead of code | Code ahead of spec | No-go violation | Undocumented}
|
|
103
|
+
|
|
104
|
+
**Current spec:** {spec text from report}
|
|
105
|
+
**Code reality:** {what was found or not found}
|
|
106
|
+
**Recommendation:** {fix recommendation from report}
|
|
107
|
+
|
|
108
|
+
**Affected spec files:** {list of files that reference this item}
|
|
109
|
+
|
|
110
|
+
Choose:
|
|
111
|
+
- **Accept** -- Apply the recommended spec change
|
|
112
|
+
- **Skip** -- Leave as-is (no changes for this item)
|
|
113
|
+
- **Edit** -- Provide a custom change description
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Wait for user response.
|
|
117
|
+
|
|
118
|
+
**Apply accepted changes based on item direction:**
|
|
119
|
+
|
|
120
|
+
**For "Spec ahead of code" items** (requirement marked done but code missing):
|
|
121
|
+
- Update REQUIREMENTS.md: change `[x]` to `[ ]` for the requirement using `node ~/.claude/maxsim/bin/maxsim-tools.cjs requirements mark-incomplete {REQ_ID}`, or manually edit the checkbox if the tool does not support it.
|
|
122
|
+
- Check ROADMAP.md: if the requirement appears in success criteria for a phase, add a note that the criterion is unmet.
|
|
123
|
+
- Check STATE.md: if a decision references this requirement, add a note that the implementation is pending.
|
|
124
|
+
- Check phase SUMMARY.md files: if any summary claims this requirement was completed, add a caveat note.
|
|
125
|
+
|
|
126
|
+
**For "Code ahead of spec" items** (feature exists but spec does not mention it):
|
|
127
|
+
- If user accepts the default recommendation: add the feature as a new requirement in REQUIREMENTS.md under the appropriate version section.
|
|
128
|
+
- If user provides an edit: apply their custom text instead.
|
|
129
|
+
- Update PROJECT.md if the feature represents a significant capability not documented there.
|
|
130
|
+
|
|
131
|
+
**For "No-go violation" items** (code violating a declared constraint):
|
|
132
|
+
- Document as known tech debt in STATE.md under "Blockers/Concerns" or a "Known Tech Debt" section.
|
|
133
|
+
- Optionally mark for future fix phase.
|
|
134
|
+
|
|
135
|
+
**For "Undocumented feature" items** (code with no spec coverage):
|
|
136
|
+
- Add to REQUIREMENTS.md as a new entry documenting the existing capability.
|
|
137
|
+
- Or update PROJECT.md to document it as an existing capability, depending on user's edit.
|
|
138
|
+
|
|
139
|
+
**CRITICAL -- Multi-file consistency:** For each accepted item, identify ALL spec files that reference it (from the drift report evidence section) and update all of them. Do NOT update only REQUIREMENTS.md while leaving ROADMAP.md or STATE.md inconsistent. Use the spec file references in the drift report as the update checklist.
|
|
140
|
+
|
|
141
|
+
Track changes: maintain a running count of accepted, skipped, and edited items, and a list of all modified files.
|
|
142
|
+
|
|
143
|
+
**After processing all items:**
|
|
144
|
+
|
|
145
|
+
Check if any phase now has all success criteria met in code. For each phase referenced in the drift report:
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
# Check if phase criteria are now all satisfied
|
|
149
|
+
PHASE_STATUS=$(node ~/.claude/maxsim/bin/maxsim-tools.cjs roadmap get-phase "{phase_number}")
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
If all criteria for a phase are met after the realignment updates, auto-mark that phase complete:
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
node ~/.claude/maxsim/bin/maxsim-tools.cjs phase complete "{phase_number}"
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
**If ALL items were skipped:** "No changes applied. Drift report remains unchanged." STOP (do not commit).
|
|
159
|
+
|
|
160
|
+
**Commit changes:**
|
|
161
|
+
|
|
162
|
+
```bash
|
|
163
|
+
node ~/.claude/maxsim/bin/maxsim-tools.cjs commit "docs: realign spec to match codebase" --files {space-separated list of all modified files}
|
|
164
|
+
```
|
|
165
|
+
</step>
|
|
166
|
+
|
|
167
|
+
<step name="realign_to_spec">
|
|
168
|
+
**Execute only if direction is `to-spec`.**
|
|
169
|
+
|
|
170
|
+
Parse the drift report to extract all "Spec Ahead of Code" items -- requirements and success criteria that are specified but not yet implemented in code. Also include any "No-Go Violations" that require code changes.
|
|
171
|
+
|
|
172
|
+
Build a list of implementation gaps. For each gap, extract:
|
|
173
|
+
- Requirement ID
|
|
174
|
+
- Description of what needs to be implemented
|
|
175
|
+
- Current spec location (file and section)
|
|
176
|
+
- Evidence of what is missing from the report
|
|
177
|
+
|
|
178
|
+
**Group gaps into phases using this algorithm:**
|
|
179
|
+
|
|
180
|
+
1. **Group by requirement prefix:** Collect all gaps sharing a requirement prefix (e.g., all `DRIFT-*` gaps into one phase, all `INIT-*` into another, all `ROT-*` into another). The prefix is the text before the hyphen and number in the requirement ID.
|
|
181
|
+
|
|
182
|
+
2. **If no prefix grouping possible** (gaps have no requirement IDs or all have unique prefixes): group by affected subsystem. Cluster gaps whose evidence references common file paths or directories.
|
|
183
|
+
|
|
184
|
+
3. **Apply the 5-phase cap:**
|
|
185
|
+
- If 5 or fewer groups: use them as-is.
|
|
186
|
+
- If more than 5 groups: sort groups by gap count (ascending). Merge the smallest groups into a "Remaining Gaps" phase until only 5 groups remain.
|
|
187
|
+
|
|
188
|
+
4. **Minimum group size:** Each phase should have at minimum 2 gaps, unless it is the only group or merging is not possible.
|
|
189
|
+
|
|
190
|
+
5. **Name each phase** descriptively: "{Prefix} Implementation Gaps" or "{Subsystem} Fixes" or similar concise name.
|
|
191
|
+
|
|
192
|
+
**Present proposed phases to user:**
|
|
193
|
+
|
|
194
|
+
```markdown
|
|
195
|
+
## Proposed Realignment Phases
|
|
196
|
+
|
|
197
|
+
Based on the drift report, {gap_count} implementation gaps will be organized into {phase_count} new phases inserted after the current active phase ({current_phase}).
|
|
198
|
+
|
|
199
|
+
| # | Phase Name | Requirements | Gap Count | Description |
|
|
200
|
+
|---|-----------|-------------|-----------|-------------|
|
|
201
|
+
| 1 | {name} | {REQ-01, REQ-02} | {N} | {brief description} |
|
|
202
|
+
| 2 | {name} | {REQ-03} | {N} | {brief description} |
|
|
203
|
+
|
|
204
|
+
Approve this breakdown? (yes / suggest changes)
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
Wait for user approval. If user suggests changes, adjust the grouping accordingly.
|
|
208
|
+
|
|
209
|
+
**For each approved phase, insert after the current active phase:**
|
|
210
|
+
|
|
211
|
+
```bash
|
|
212
|
+
RESULT=$(node ~/.claude/maxsim/bin/maxsim-tools.cjs phase insert "{current_phase}" "{phase_name}")
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
The insert command creates the phase directory with decimal numbering (e.g., `04.1`, `04.2`) and updates ROADMAP.md.
|
|
216
|
+
|
|
217
|
+
**For each inserted phase, update the ROADMAP.md phase section** to include:
|
|
218
|
+
- The requirement IDs covered by this phase
|
|
219
|
+
- Success criteria extracted from the drift report (what needs to be implemented)
|
|
220
|
+
- A brief goal statement
|
|
221
|
+
|
|
222
|
+
Use the Edit tool to add requirement details and success criteria to each newly created phase entry in ROADMAP.md.
|
|
223
|
+
|
|
224
|
+
**Commit changes:**
|
|
225
|
+
|
|
226
|
+
```bash
|
|
227
|
+
node ~/.claude/maxsim/bin/maxsim-tools.cjs commit "feat: add realignment phases from drift report" --files .planning/ROADMAP.md .planning/STATE.md
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
Note: Include any new phase directories created by the insert commands in the commit files list.
|
|
231
|
+
</step>
|
|
232
|
+
|
|
233
|
+
<step name="summary">
|
|
234
|
+
Display a summary of what was changed.
|
|
235
|
+
|
|
236
|
+
**For realign-to-code:**
|
|
237
|
+
|
|
238
|
+
```markdown
|
|
239
|
+
## Realignment Complete (to-code)
|
|
240
|
+
|
|
241
|
+
**Items processed:** {total}
|
|
242
|
+
- Accepted: {accepted_count}
|
|
243
|
+
- Skipped: {skipped_count}
|
|
244
|
+
- Edited: {edited_count}
|
|
245
|
+
|
|
246
|
+
**Files modified:** {list of modified files}
|
|
247
|
+
**Phases auto-completed:** {list of phases marked complete, or "None"}
|
|
248
|
+
**Commit:** {commit hash}
|
|
249
|
+
|
|
250
|
+
The spec now reflects the current codebase state for the accepted items.
|
|
251
|
+
Skipped items remain as drift -- run `/maxsim:check-drift` again to see remaining drift.
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
**For realign-to-spec:**
|
|
255
|
+
|
|
256
|
+
```markdown
|
|
257
|
+
## Realignment Complete (to-spec)
|
|
258
|
+
|
|
259
|
+
**Implementation gaps:** {gap_count}
|
|
260
|
+
**New phases created:** {phase_count}
|
|
261
|
+
|
|
262
|
+
| Phase | Name | Requirements |
|
|
263
|
+
|-------|------|-------------|
|
|
264
|
+
| {num} | {name} | {REQ IDs} |
|
|
265
|
+
|
|
266
|
+
**Next step:** Run `/maxsim:execute-phase {first_new_phase}` to begin implementing the gaps.
|
|
267
|
+
```
|
|
268
|
+
</step>
|
|
269
|
+
|
|
270
|
+
</process>
|
|
271
|
+
|
|
272
|
+
<error_handling>
|
|
273
|
+
- **DRIFT-REPORT.md missing:** Direct user to run `/maxsim:check-drift` first. Do not attempt to generate a report.
|
|
274
|
+
- **Report status is "aligned":** Nothing to do. Inform user and stop.
|
|
275
|
+
- **All items skipped (to-code):** No changes made. Inform user that drift remains.
|
|
276
|
+
- **Zero "Spec Ahead of Code" gaps (to-spec):** Inform user "All specified items appear implemented. No fix phases needed. Consider realign-to-code instead to capture undocumented features."
|
|
277
|
+
- **Phase insert fails:** Report the error. Continue with remaining phases if possible. Document any failures in the summary.
|
|
278
|
+
- **Invalid direction argument:** Show usage: `/maxsim:realign [to-code | to-spec]`
|
|
279
|
+
</error_handling>
|
|
280
|
+
|
|
281
|
+
<critical_rules>
|
|
282
|
+
- **Item-by-item approval for to-code:** Never batch-apply changes. Present each item individually and wait for Accept/Skip/Edit.
|
|
283
|
+
- **Multi-file consistency:** When updating spec for an accepted item, update ALL referencing spec files, not just REQUIREMENTS.md. Use the evidence section from the drift report to identify all affected files.
|
|
284
|
+
- **Phase cap for to-spec:** Never create more than 5 new phases. Group and merge as described in the algorithm.
|
|
285
|
+
- **Insert after current phase:** New phases go after the current active phase, not at the end of the roadmap.
|
|
286
|
+
- **No auto-generation of reports:** This workflow reads an existing DRIFT-REPORT.md. It does not run drift detection itself.
|
|
287
|
+
- **Auto-complete phases:** After realign-to-code, check if any phase has all criteria met and auto-mark it complete.
|
|
288
|
+
</critical_rules>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<purpose>
|
|
2
|
-
Render the project roadmap in a readable format with phase status icons and plan progress counts. Read-only — does not modify any files.
|
|
2
|
+
Render the project roadmap in a readable format with phase status icons and plan progress counts. Auto-collapses completed phases to one-liners for visual clarity and paginates at 20 phases per page for large projects. Read-only — does not modify any files.
|
|
3
3
|
</purpose>
|
|
4
4
|
|
|
5
5
|
<process>
|
|
@@ -16,6 +16,8 @@ Parse JSON. If `planning_exists` is false, hard stop:
|
|
|
16
16
|
> No roadmap found. Run /maxsim:new-project to initialize.
|
|
17
17
|
|
|
18
18
|
Exit immediately. Do not continue.
|
|
19
|
+
|
|
20
|
+
**Parse `--page` argument:** If the command was invoked with `--page N`, extract the page number (default: 1). This controls which page of phases to display when total phases exceed 20.
|
|
19
21
|
</step>
|
|
20
22
|
|
|
21
23
|
<step name="analyze">
|
|
@@ -43,31 +45,74 @@ Print the roadmap to the terminal.
|
|
|
43
45
|
|
|
44
46
|
**Blank line.**
|
|
45
47
|
|
|
46
|
-
**
|
|
48
|
+
**Auto-collapse completed phases (always active, regardless of phase count):**
|
|
47
49
|
|
|
48
|
-
|
|
49
|
-
- `disk_status === 'complete'` → icon `✓`, label `DONE`
|
|
50
|
-
- `disk_status === 'partial'` → icon `►`, label `IN PROGRESS`
|
|
51
|
-
- `disk_status === 'planned' || 'empty' || 'discussed' || 'researched' || 'no_directory'` → icon `□`, label `PLANNED`
|
|
50
|
+
Render phases in two visual groups:
|
|
52
51
|
|
|
53
|
-
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
```
|
|
52
|
+
1. **Completed phases** — collapsed one-liners with no plan counts or status label:
|
|
53
|
+
```
|
|
54
|
+
✓ Phase {number}: {name}
|
|
55
|
+
```
|
|
56
|
+
Just checkmark + phase number + name. One line per completed phase. This keeps the roadmap scannable when many phases are done.
|
|
57
|
+
|
|
58
|
+
2. **Active and upcoming phases** — full detail format with icon, label, and plan counts:
|
|
59
|
+
```
|
|
60
|
+
{icon} Phase {number}: {name} {label} ({summary_count}/{plan_count} plans)
|
|
61
|
+
```
|
|
57
62
|
|
|
58
|
-
|
|
63
|
+
For active/upcoming phases:
|
|
64
|
+
- `disk_status === 'partial'` -> icon `>`, label `IN PROGRESS`
|
|
65
|
+
- `disk_status === 'planned' || 'empty' || 'discussed' || 'researched' || 'no_directory'` -> icon `[ ]`, label `PLANNED`
|
|
66
|
+
|
|
67
|
+
Pad phase names with spaces so status labels align in a column (within the active/upcoming group only).
|
|
59
68
|
|
|
60
69
|
Only show `({summary_count}/{plan_count} plans)` when `plan_count > 0`.
|
|
61
70
|
|
|
62
|
-
|
|
71
|
+
**Pagination (only when total phases exceed 20):**
|
|
72
|
+
|
|
73
|
+
After assembling all phase lines (both collapsed completed and full-detail active/upcoming), check the total phase count:
|
|
74
|
+
|
|
75
|
+
- If total phases is **20 or fewer**: show all phases. No pagination footer. This is the default experience for small/medium projects.
|
|
76
|
+
- If total phases **exceeds 20**: apply pagination.
|
|
77
|
+
- Page size: 20 phases per page.
|
|
78
|
+
- Use the `--page N` argument (default page 1) to determine which slice to show.
|
|
79
|
+
- Calculate: `first = (page - 1) * 20 + 1`, `last = min(page * 20, total)`.
|
|
80
|
+
- Show only phases from index `first` to `last`.
|
|
81
|
+
- Add a footer line after the phase list:
|
|
82
|
+
```
|
|
83
|
+
Showing phases {first}-{last} of {total}. Use --page {next_page} for next.
|
|
84
|
+
```
|
|
85
|
+
- If on the last page, omit the "Use --page" hint.
|
|
86
|
+
|
|
87
|
+
Example output (small project, no pagination):
|
|
63
88
|
```
|
|
64
|
-
|
|
89
|
+
Context-Aware SDD — 3 done / 1 active / 1 planned
|
|
90
|
+
|
|
91
|
+
✓ Phase 1: Context Rot Prevention
|
|
92
|
+
✓ Phase 2: Init Flow Overhaul
|
|
93
|
+
✓ Phase 3: Agent Coherence
|
|
94
|
+
|
|
95
|
+
> Phase 4: Spec Drift Management IN PROGRESS (2/3 plans)
|
|
96
|
+
[ ] Phase 5: Workflow Coverage PLANNED
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Example output (large project with pagination, page 1):
|
|
100
|
+
```
|
|
101
|
+
NX Monorepo Migration — 15 done / 1 active / 9 planned
|
|
102
|
+
|
|
103
|
+
✓ Phase 01: NX Workspace Scaffold
|
|
104
|
+
✓ Phase 02: packages/core TypeScript Port
|
|
105
|
+
✓ Phase 03: Shared Types
|
|
106
|
+
...
|
|
107
|
+
✓ Phase 15: CI Pipeline
|
|
108
|
+
|
|
109
|
+
> Phase 16: Dashboard Rewrite IN PROGRESS (2/5 plans)
|
|
110
|
+
[ ] Phase 17: Plugin System PLANNED
|
|
111
|
+
[ ] Phase 18: Performance Optimization PLANNED
|
|
112
|
+
[ ] Phase 19: Documentation PLANNED
|
|
113
|
+
[ ] Phase 20: Security Audit PLANNED
|
|
65
114
|
|
|
66
|
-
|
|
67
|
-
✓ Phase 02: packages/core TypeScript Port DONE (6/6 plans)
|
|
68
|
-
► Phase 09: End-to-end install and publish test loop IN PROGRESS (2/3 plans)
|
|
69
|
-
□ Phase 11: Remove Discord command PLANNED
|
|
70
|
-
□ Phase 12: UX Polish + Core Hardening PLANNED
|
|
115
|
+
Showing phases 1-20 of 25. Use --page 2 for next.
|
|
71
116
|
```
|
|
72
117
|
</step>
|
|
73
118
|
|
|
@@ -75,7 +120,11 @@ NX Monorepo Migration — 5 done / 1 active / 6 planned
|
|
|
75
120
|
|
|
76
121
|
<success_criteria>
|
|
77
122
|
- [ ] Milestone summary header rendered with done/active/planned counts
|
|
78
|
-
- [ ]
|
|
79
|
-
- [ ]
|
|
123
|
+
- [ ] Completed phases auto-collapsed to one-liners (checkmark + name only, no plan counts)
|
|
124
|
+
- [ ] Active/upcoming phases shown with full detail (icon, label, plan counts)
|
|
125
|
+
- [ ] Phases listed in numeric order within each group
|
|
126
|
+
- [ ] Pagination footer shown only when total phases exceed 20
|
|
127
|
+
- [ ] `--page N` argument controls which page to display
|
|
128
|
+
- [ ] Plan progress shown inline for active/upcoming phases that have plans
|
|
80
129
|
- [ ] Hard stop if .planning/ is missing
|
|
81
130
|
</success_criteria>
|
package/dist/backend-server.cjs
CHANGED
|
@@ -32122,17 +32122,17 @@ var require_view = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
32122
32122
|
* @private
|
|
32123
32123
|
*/
|
|
32124
32124
|
var debug = require_src$3()("express:view");
|
|
32125
|
-
var path$
|
|
32126
|
-
var fs$
|
|
32125
|
+
var path$23 = require("path");
|
|
32126
|
+
var fs$21 = require("fs");
|
|
32127
32127
|
/**
|
|
32128
32128
|
* Module variables.
|
|
32129
32129
|
* @private
|
|
32130
32130
|
*/
|
|
32131
|
-
var dirname = path$
|
|
32132
|
-
var basename = path$
|
|
32133
|
-
var extname = path$
|
|
32134
|
-
var join = path$
|
|
32135
|
-
var resolve = path$
|
|
32131
|
+
var dirname = path$23.dirname;
|
|
32132
|
+
var basename = path$23.basename;
|
|
32133
|
+
var extname = path$23.extname;
|
|
32134
|
+
var join = path$23.join;
|
|
32135
|
+
var resolve = path$23.resolve;
|
|
32136
32136
|
/**
|
|
32137
32137
|
* Module exports.
|
|
32138
32138
|
* @public
|
|
@@ -32229,7 +32229,7 @@ var require_view = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
32229
32229
|
function tryStat(path) {
|
|
32230
32230
|
debug("stat \"%s\"", path);
|
|
32231
32231
|
try {
|
|
32232
|
-
return fs$
|
|
32232
|
+
return fs$21.statSync(path);
|
|
32233
32233
|
} catch (e) {
|
|
32234
32234
|
return;
|
|
32235
32235
|
}
|
|
@@ -34450,7 +34450,7 @@ var require_types$1 = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
34450
34450
|
//#region ../../node_modules/send/node_modules/mime/mime.js
|
|
34451
34451
|
var require_mime = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
34452
34452
|
require("path");
|
|
34453
|
-
var fs$
|
|
34453
|
+
var fs$20 = require("fs");
|
|
34454
34454
|
function Mime() {
|
|
34455
34455
|
this.types = Object.create(null);
|
|
34456
34456
|
this.extensions = Object.create(null);
|
|
@@ -34485,7 +34485,7 @@ var require_mime = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
34485
34485
|
Mime.prototype.load = function(file) {
|
|
34486
34486
|
this._loading = file;
|
|
34487
34487
|
var map = {};
|
|
34488
|
-
fs$
|
|
34488
|
+
fs$20.readFileSync(file, "ascii").split(/[\r\n]+/).forEach(function(line) {
|
|
34489
34489
|
var fields = line.replace(/\s*#.*|^\s*|\s*$/g, "").split(/\s+/);
|
|
34490
34490
|
map[fields.shift()] = fields;
|
|
34491
34491
|
});
|
|
@@ -34764,12 +34764,12 @@ var require_send = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
34764
34764
|
var escapeHtml = require_escape_html();
|
|
34765
34765
|
var etag = require_etag();
|
|
34766
34766
|
var fresh = require_fresh();
|
|
34767
|
-
var fs$
|
|
34767
|
+
var fs$19 = require("fs");
|
|
34768
34768
|
var mime = require_mime();
|
|
34769
34769
|
var ms = require_ms();
|
|
34770
34770
|
var onFinished = require_on_finished();
|
|
34771
34771
|
var parseRange = require_range_parser();
|
|
34772
|
-
var path$
|
|
34772
|
+
var path$22 = require("path");
|
|
34773
34773
|
var statuses = require_statuses();
|
|
34774
34774
|
var Stream = require("stream");
|
|
34775
34775
|
var util$3 = require("util");
|
|
@@ -34777,11 +34777,11 @@ var require_send = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
34777
34777
|
* Path function references.
|
|
34778
34778
|
* @private
|
|
34779
34779
|
*/
|
|
34780
|
-
var extname = path$
|
|
34781
|
-
var join = path$
|
|
34782
|
-
var normalize = path$
|
|
34783
|
-
var resolve = path$
|
|
34784
|
-
var sep = path$
|
|
34780
|
+
var extname = path$22.extname;
|
|
34781
|
+
var join = path$22.join;
|
|
34782
|
+
var normalize = path$22.normalize;
|
|
34783
|
+
var resolve = path$22.resolve;
|
|
34784
|
+
var sep = path$22.sep;
|
|
34785
34785
|
/**
|
|
34786
34786
|
* Regular expression for identifying a bytes Range header.
|
|
34787
34787
|
* @private
|
|
@@ -35229,7 +35229,7 @@ var require_send = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
35229
35229
|
var i = 0;
|
|
35230
35230
|
var self = this;
|
|
35231
35231
|
debug("stat \"%s\"", path);
|
|
35232
|
-
fs$
|
|
35232
|
+
fs$19.stat(path, function onstat(err, stat) {
|
|
35233
35233
|
if (err && err.code === "ENOENT" && !extname(path) && path[path.length - 1] !== sep) return next(err);
|
|
35234
35234
|
if (err) return self.onStatError(err);
|
|
35235
35235
|
if (stat.isDirectory()) return self.redirect(path);
|
|
@@ -35240,7 +35240,7 @@ var require_send = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
35240
35240
|
if (self._extensions.length <= i) return err ? self.onStatError(err) : self.error(404);
|
|
35241
35241
|
var p = path + "." + self._extensions[i++];
|
|
35242
35242
|
debug("stat \"%s\"", p);
|
|
35243
|
-
fs$
|
|
35243
|
+
fs$19.stat(p, function(err, stat) {
|
|
35244
35244
|
if (err) return next(err);
|
|
35245
35245
|
if (stat.isDirectory()) return next();
|
|
35246
35246
|
self.emit("file", p, stat);
|
|
@@ -35264,7 +35264,7 @@ var require_send = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
35264
35264
|
}
|
|
35265
35265
|
var p = join(path, self._index[i]);
|
|
35266
35266
|
debug("stat \"%s\"", p);
|
|
35267
|
-
fs$
|
|
35267
|
+
fs$19.stat(p, function(err, stat) {
|
|
35268
35268
|
if (err) return next(err);
|
|
35269
35269
|
if (stat.isDirectory()) return next();
|
|
35270
35270
|
self.emit("file", p, stat);
|
|
@@ -35283,7 +35283,7 @@ var require_send = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
35283
35283
|
SendStream.prototype.stream = function stream(path, options) {
|
|
35284
35284
|
var self = this;
|
|
35285
35285
|
var res = this.res;
|
|
35286
|
-
var stream$5 = fs$
|
|
35286
|
+
var stream$5 = fs$19.createReadStream(path, options);
|
|
35287
35287
|
this.emit("stream", stream$5);
|
|
35288
35288
|
stream$5.pipe(res);
|
|
35289
35289
|
function cleanup() {
|
|
@@ -38817,7 +38817,7 @@ var require_response = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
38817
38817
|
var http$3 = require("http");
|
|
38818
38818
|
var isAbsolute = require_utils$1().isAbsolute;
|
|
38819
38819
|
var onFinished = require_on_finished();
|
|
38820
|
-
var path$
|
|
38820
|
+
var path$21 = require("path");
|
|
38821
38821
|
var statuses = require_statuses();
|
|
38822
38822
|
var merge = require_utils_merge();
|
|
38823
38823
|
var sign = require_cookie_signature().sign;
|
|
@@ -38826,9 +38826,9 @@ var require_response = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
38826
38826
|
var setCharset = require_utils$1().setCharset;
|
|
38827
38827
|
var cookie = require_cookie();
|
|
38828
38828
|
var send = require_send();
|
|
38829
|
-
var extname = path$
|
|
38829
|
+
var extname = path$21.extname;
|
|
38830
38830
|
var mime = send.mime;
|
|
38831
|
-
var resolve = path$
|
|
38831
|
+
var resolve = path$21.resolve;
|
|
38832
38832
|
var vary = require_vary();
|
|
38833
38833
|
/**
|
|
38834
38834
|
* Response prototype.
|
|
@@ -74966,6 +74966,14 @@ function parseTodoFrontmatter(content) {
|
|
|
74966
74966
|
* Ported from maxsim/bin/lib/verify.cjs
|
|
74967
74967
|
*/
|
|
74968
74968
|
|
|
74969
|
+
//#endregion
|
|
74970
|
+
//#region src/core/drift.ts
|
|
74971
|
+
/**
|
|
74972
|
+
* Drift — Drift report CRUD, requirement extraction, and spec extraction
|
|
74973
|
+
*
|
|
74974
|
+
* Provides CLI tool commands for the drift-checker agent and realign workflow.
|
|
74975
|
+
*/
|
|
74976
|
+
|
|
74969
74977
|
//#endregion
|
|
74970
74978
|
//#region src/core/phase.ts
|
|
74971
74979
|
/**
|
|
@@ -79004,14 +79012,22 @@ function registerPhaseTools(server) {
|
|
|
79004
79012
|
return mcpError(e.message, "Operation failed");
|
|
79005
79013
|
}
|
|
79006
79014
|
});
|
|
79007
|
-
server.tool("mcp_list_phases", "List
|
|
79015
|
+
server.tool("mcp_list_phases", "List phase directories with pagination. Returns sorted phases with offset/limit support.", {
|
|
79016
|
+
include_archived: booleanType().optional().default(false).describe("Include archived phases from completed milestones"),
|
|
79017
|
+
offset: numberType().optional().default(0).describe("Number of phases to skip (for pagination)"),
|
|
79018
|
+
limit: numberType().optional().default(20).describe("Maximum number of phases to return")
|
|
79019
|
+
}, async ({ include_archived, offset, limit }) => {
|
|
79008
79020
|
try {
|
|
79009
79021
|
const cwd = detectProjectRoot();
|
|
79010
79022
|
if (!cwd) return mcpError("No .planning/ directory found", "Project not detected");
|
|
79011
79023
|
const phasesDir = phasesPath(cwd);
|
|
79012
79024
|
if (!node_fs.default.existsSync(phasesDir)) return mcpSuccess({
|
|
79013
79025
|
directories: [],
|
|
79014
|
-
count: 0
|
|
79026
|
+
count: 0,
|
|
79027
|
+
total_count: 0,
|
|
79028
|
+
offset,
|
|
79029
|
+
limit,
|
|
79030
|
+
has_more: false
|
|
79015
79031
|
}, "No phases directory found");
|
|
79016
79032
|
let dirs = listSubDirs(phasesDir);
|
|
79017
79033
|
if (include_archived) {
|
|
@@ -79019,10 +79035,17 @@ function registerPhaseTools(server) {
|
|
|
79019
79035
|
for (const a of archived) dirs.push(`${a.name} [${a.milestone}]`);
|
|
79020
79036
|
}
|
|
79021
79037
|
dirs.sort((a, b) => comparePhaseNum(a, b));
|
|
79038
|
+
const total_count = dirs.length;
|
|
79039
|
+
const paginated = dirs.slice(offset, offset + limit);
|
|
79040
|
+
const has_more = offset + limit < total_count;
|
|
79022
79041
|
return mcpSuccess({
|
|
79023
|
-
directories:
|
|
79024
|
-
count:
|
|
79025
|
-
|
|
79042
|
+
directories: paginated,
|
|
79043
|
+
count: paginated.length,
|
|
79044
|
+
total_count,
|
|
79045
|
+
offset,
|
|
79046
|
+
limit,
|
|
79047
|
+
has_more
|
|
79048
|
+
}, `Showing ${paginated.length} of ${total_count} phase(s)`);
|
|
79026
79049
|
} catch (e) {
|
|
79027
79050
|
return mcpError(e.message, "Operation failed");
|
|
79028
79051
|
}
|