@ikunin/sprintpilot 2.3.5 → 2.3.7
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.
|
@@ -640,6 +640,50 @@ function hasGraphvizBinary() {
|
|
|
640
640
|
}
|
|
641
641
|
}
|
|
642
642
|
|
|
643
|
+
// Find the Mermaid CLI binary on PATH. Cross-platform: npm installs
|
|
644
|
+
// CLI tools as `.cmd` shims on Windows, and Node's spawn family does
|
|
645
|
+
// not auto-resolve PATHEXT extensions without `shell: true`. We probe
|
|
646
|
+
// platform-appropriate candidates explicitly. Returns the resolved
|
|
647
|
+
// binary name (suitable for spawnSync) or null if none found.
|
|
648
|
+
function findMermaidCliBinary() {
|
|
649
|
+
const candidates =
|
|
650
|
+
process.platform === 'win32'
|
|
651
|
+
? ['mmdc.cmd', 'mmdc.ps1', 'mmdc.bat', 'mmdc.exe', 'mmdc']
|
|
652
|
+
: ['mmdc'];
|
|
653
|
+
for (const name of candidates) {
|
|
654
|
+
try {
|
|
655
|
+
const r = spawnSync(name, ['--version'], { stdio: 'ignore' });
|
|
656
|
+
if (r.status === 0) return name;
|
|
657
|
+
} catch {
|
|
658
|
+
// ENOENT etc — try next candidate
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
return null;
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
// Try to render `<mmd>` to a sibling `<mmd>.png` via mmdc. Returns
|
|
665
|
+
// { written: true, file: <png-path> } — success
|
|
666
|
+
// { written: false, reason: 'mmdc-missing' } — toolchain absent
|
|
667
|
+
// { written: false, reason: 'render-failed', message: <stderr> } — toolchain errored
|
|
668
|
+
// Never throws; the caller threads the result into the envelope.
|
|
669
|
+
function tryRenderMermaidPng(mmdPath) {
|
|
670
|
+
const bin = findMermaidCliBinary();
|
|
671
|
+
if (!bin) {
|
|
672
|
+
return { written: false, reason: 'mmdc-missing' };
|
|
673
|
+
}
|
|
674
|
+
const pngPath = mmdPath.endsWith('.mmd') ? mmdPath.slice(0, -4) + '.png' : mmdPath + '.png';
|
|
675
|
+
const r = spawnSync(bin, ['-i', mmdPath, '-o', pngPath, '-b', 'transparent', '--quiet'], {
|
|
676
|
+
encoding: 'utf8',
|
|
677
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
678
|
+
windowsHide: true,
|
|
679
|
+
});
|
|
680
|
+
if (r.status !== 0) {
|
|
681
|
+
const message = (r.stderr || r.stdout || 'mmdc exited non-zero').trim();
|
|
682
|
+
return { written: false, reason: 'render-failed', message };
|
|
683
|
+
}
|
|
684
|
+
return { written: true, file: pngPath };
|
|
685
|
+
}
|
|
686
|
+
|
|
643
687
|
function defaultRenderOutputPath(projectRoot, format) {
|
|
644
688
|
const ext = format === 'graphviz' ? 'dot' : 'mmd';
|
|
645
689
|
return path.join(projectRoot, '_bmad-output', 'implementation-artifacts', `sprint-plan-dag.${ext}`);
|
|
@@ -694,12 +738,29 @@ function runRender({ projectRoot, epic, format, output }) {
|
|
|
694
738
|
};
|
|
695
739
|
}
|
|
696
740
|
|
|
741
|
+
// Sibling-PNG render (mermaid only). Non-fatal: caller surfaces the
|
|
742
|
+
// reason if mmdc is missing or errored. graphviz users render via
|
|
743
|
+
// `dot -Tpng …` themselves; no auto-PNG for that format.
|
|
744
|
+
let pngEnvelope = null;
|
|
745
|
+
if (effectiveFormat === 'mermaid') {
|
|
746
|
+
const pngResult = tryRenderMermaidPng(outputPath);
|
|
747
|
+
if (pngResult.written) {
|
|
748
|
+
pngEnvelope = { png_file: pngResult.file };
|
|
749
|
+
} else {
|
|
750
|
+
pngEnvelope = {
|
|
751
|
+
png_reason: pngResult.reason,
|
|
752
|
+
...(pngResult.message ? { png_message: pngResult.message } : {}),
|
|
753
|
+
};
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
|
|
697
757
|
return {
|
|
698
758
|
wrote: true,
|
|
699
759
|
file: outputPath,
|
|
700
760
|
format: effectiveFormat,
|
|
701
761
|
requested_format: requestedFormat,
|
|
702
762
|
...(fallbackReason ? { fallback: fallbackReason } : {}),
|
|
763
|
+
...(pngEnvelope || {}),
|
|
703
764
|
nodes: dag.nodes.length,
|
|
704
765
|
edges: dag.edges.length,
|
|
705
766
|
};
|
|
@@ -113,8 +113,8 @@ node _Sprintpilot/scripts/resolve-dag.js render --format mermaid \
|
|
|
113
113
|
[--epic <id>] [--output <path>] --project-root <root>
|
|
114
114
|
```
|
|
115
115
|
|
|
116
|
-
Returns JSON `{wrote, file, format, nodes, edges, fallback?}`.
|
|
117
|
-
read the rendered file and inline its contents in a ```mermaid fenced
|
|
116
|
+
Returns JSON `{wrote, file, format, nodes, edges, fallback?, png_file?, png_reason?, png_message?}`.
|
|
117
|
+
Then read the rendered file and inline its contents in a ```mermaid fenced
|
|
118
118
|
code block so the chat client (Claude Code, etc.) renders the diagram
|
|
119
119
|
inline. Also report the file path so the user can preview elsewhere:
|
|
120
120
|
|
|
@@ -134,6 +134,35 @@ cross-references back to the user's tracker (Jira / Linear / GitHub /
|
|
|
134
134
|
GitLab). Stories/epics without an issue_id render with the bare key —
|
|
135
135
|
silence communicates "not tracked" rather than spamming `[no issue]`.
|
|
136
136
|
|
|
137
|
+
**PNG sibling render.** As a side-effect of the mermaid render, the
|
|
138
|
+
script tries to produce a `<file>.png` next to the `.mmd` via the
|
|
139
|
+
official Mermaid CLI (`mmdc`). You **MUST** examine the envelope's
|
|
140
|
+
`png_*` fields and surface one of the three outcomes to the user —
|
|
141
|
+
silence is a bug, especially when mmdc is missing.
|
|
142
|
+
|
|
143
|
+
- **`png_file` set** → PNG produced. Report:
|
|
144
|
+
> Also wrote PNG: `<png_file>` (rendered via Mermaid CLI).
|
|
145
|
+
|
|
146
|
+
- **`png_reason: "mmdc-missing"`** → Mermaid CLI is not installed.
|
|
147
|
+
You **MUST** tell the user how to install it, verbatim:
|
|
148
|
+
> PNG render skipped — Mermaid CLI (`mmdc`) is not installed.
|
|
149
|
+
> To get a `.png` alongside the `.mmd` next time, install it:
|
|
150
|
+
>
|
|
151
|
+
> ```
|
|
152
|
+
> npm install -g @mermaid-js/mermaid-cli
|
|
153
|
+
> ```
|
|
154
|
+
>
|
|
155
|
+
> Works on Windows, Linux, and macOS. Requires Node 18+.
|
|
156
|
+
> After installing, re-run `/sprintpilot-dependency-graph mermaid`.
|
|
157
|
+
|
|
158
|
+
Do not silently drop this. The `.mmd` file is still useful but the
|
|
159
|
+
install hint is the primary value of this code path.
|
|
160
|
+
|
|
161
|
+
- **`png_reason: "render-failed"`** → mmdc was found but errored.
|
|
162
|
+
Report the `png_message` verbatim and suggest re-running with
|
|
163
|
+
`mmdc -i <mmd-path> -o <png-path>` outside the skill to see the
|
|
164
|
+
full toolchain error.
|
|
165
|
+
|
|
137
166
|
### Graphviz
|
|
138
167
|
|
|
139
168
|
```
|
|
@@ -224,4 +253,6 @@ have different leading hyphen segments — leverage the JSON output).</action>
|
|
|
224
253
|
| Plan file corrupt | Surface the parse error from `sprint-plan.js read`; suggest re-running the planning skill. |
|
|
225
254
|
| Cycle detected (`resolve-dag.js` exits 1 with "cycle detected") | Report the cycling node list verbatim. Suggest reviewing `plan.dependencies.stories` for the named keys, or re-running `/sprintpilot-plan-sprint` to re-infer. |
|
|
226
255
|
| Graphviz binary missing | Note the fallback; tell the user how to install `dot`; do NOT silently retry with a different format. |
|
|
256
|
+
| Mermaid CLI (`mmdc`) missing (mermaid format, `png_reason: "mmdc-missing"`) | You **MUST** report the install command: `npm install -g @mermaid-js/mermaid-cli` (cross-platform, requires Node 18+). The `.mmd` file is still written, but never skip the install hint — that's the user-actionable signal. |
|
|
257
|
+
| Mermaid CLI present but errored (`png_reason: "render-failed"`) | Surface `png_message` verbatim; suggest re-running `mmdc -i <mmd> -o <png>` outside the skill to see the full toolchain error. |
|
|
227
258
|
| Output file write fails (permission, disk full) | Surface the error from the resolve-dag stderr; chat-render the JSON output as a fallback so the user still gets something usable. |
|
package/package.json
CHANGED