@ikunin/sprintpilot 2.3.7 → 2.3.9
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.
|
@@ -1608,9 +1608,14 @@ function cmdStart(opts) {
|
|
|
1608
1608
|
// cover (multiple stories completed, branch heads moved, etc.). The
|
|
1609
1609
|
// flag is logged into the ledger so the audit trail records that
|
|
1610
1610
|
// the user opted in to bypass.
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1611
|
+
// Most-recent ledger entry that carries a fingerprint — either the last
|
|
1612
|
+
// clean `halt` or a previously-accepted `resume` (which we re-baseline
|
|
1613
|
+
// on accept, below). Without the re-baseline, every subsequent
|
|
1614
|
+
// `autopilot start` re-detected the same divergence and re-accepted
|
|
1615
|
+
// in a loop.
|
|
1616
|
+
const lastBaseline = ledger.lastWithFingerprint({ projectRoot });
|
|
1617
|
+
if (lastBaseline && lastBaseline.fingerprint) {
|
|
1618
|
+
const d = divergence.detect({ projectRoot }, lastBaseline.fingerprint);
|
|
1614
1619
|
if (!d.identical) {
|
|
1615
1620
|
let autoAck = null;
|
|
1616
1621
|
const persistedStory = persisted.current_story || null;
|
|
@@ -1643,6 +1648,11 @@ function cmdStart(opts) {
|
|
|
1643
1648
|
persisted.story_file_path = null;
|
|
1644
1649
|
persisted.current_epic = null;
|
|
1645
1650
|
persisted.current_bmad_step = null;
|
|
1651
|
+
// v2.3.9 — re-baseline the fingerprint on the resume entry. The
|
|
1652
|
+
// next `autopilot start` reads lastWithFingerprint and sees THIS
|
|
1653
|
+
// fresh fingerprint instead of the stale halt one, so the same
|
|
1654
|
+
// divergence won't re-fire on every boot.
|
|
1655
|
+
const rebaseline = divergence.fingerprint({ projectRoot });
|
|
1646
1656
|
ledger.append(
|
|
1647
1657
|
{
|
|
1648
1658
|
kind: 'resume',
|
|
@@ -1650,8 +1660,9 @@ function cmdStart(opts) {
|
|
|
1650
1660
|
kind: 'divergence_accepted',
|
|
1651
1661
|
...accepted,
|
|
1652
1662
|
differences: d.differences,
|
|
1653
|
-
last_phase:
|
|
1663
|
+
last_phase: lastBaseline.phase || null,
|
|
1654
1664
|
},
|
|
1665
|
+
fingerprint: rebaseline,
|
|
1655
1666
|
},
|
|
1656
1667
|
{ projectRoot },
|
|
1657
1668
|
);
|
|
@@ -159,6 +159,20 @@ function last(context, kind) {
|
|
|
159
159
|
return null;
|
|
160
160
|
}
|
|
161
161
|
|
|
162
|
+
// lastWithFingerprint(context) — return the most recent entry that carries
|
|
163
|
+
// a `.fingerprint` field, regardless of kind. Used by resume-divergence
|
|
164
|
+
// detection so the baseline can come from either a `halt` (clean stop) or
|
|
165
|
+
// a `resume` with `divergence_accepted` (rebaselined after auto-accept).
|
|
166
|
+
// Without this, accepting a divergence didn't refresh the baseline and
|
|
167
|
+
// every subsequent `autopilot start` re-detected the same divergence.
|
|
168
|
+
function lastWithFingerprint(context) {
|
|
169
|
+
const entries = read(context);
|
|
170
|
+
for (let i = entries.length - 1; i >= 0; i -= 1) {
|
|
171
|
+
if (entries[i] && entries[i].fingerprint) return entries[i];
|
|
172
|
+
}
|
|
173
|
+
return null;
|
|
174
|
+
}
|
|
175
|
+
|
|
162
176
|
// nextSeq — compute the next sequence number by inspecting the last line.
|
|
163
177
|
// Reading just the tail is cheap because we use append-only JSONL.
|
|
164
178
|
function nextSeq(fs, filePath) {
|
|
@@ -360,6 +374,7 @@ module.exports = {
|
|
|
360
374
|
read,
|
|
361
375
|
readSince,
|
|
362
376
|
last,
|
|
377
|
+
lastWithFingerprint,
|
|
363
378
|
tail,
|
|
364
379
|
resolveLedgerPath,
|
|
365
380
|
};
|
|
@@ -661,6 +661,19 @@ function findMermaidCliBinary() {
|
|
|
661
661
|
return null;
|
|
662
662
|
}
|
|
663
663
|
|
|
664
|
+
// PNG render dimensions. mmdc defaults are 800×600 which produces an
|
|
665
|
+
// unusably-small image once a DAG has more than a handful of nodes
|
|
666
|
+
// — story labels and edges get squashed and unreadable. We override
|
|
667
|
+
// with a wide-format high-DPI render that stays legible up to ~80
|
|
668
|
+
// nodes and prints / pastes cleanly into PRs and docs:
|
|
669
|
+
// width 2400 (wide; flowchart LR is wider than tall)
|
|
670
|
+
// height 1800
|
|
671
|
+
// scale 2 (final PNG = width*scale × height*scale = 4800×3600)
|
|
672
|
+
// Roughly 1–3 MB per render — well within reason for sprint artifacts.
|
|
673
|
+
const PNG_WIDTH = 2400;
|
|
674
|
+
const PNG_HEIGHT = 1800;
|
|
675
|
+
const PNG_SCALE = 2;
|
|
676
|
+
|
|
664
677
|
// Try to render `<mmd>` to a sibling `<mmd>.png` via mmdc. Returns
|
|
665
678
|
// { written: true, file: <png-path> } — success
|
|
666
679
|
// { written: false, reason: 'mmdc-missing' } — toolchain absent
|
|
@@ -672,11 +685,32 @@ function tryRenderMermaidPng(mmdPath) {
|
|
|
672
685
|
return { written: false, reason: 'mmdc-missing' };
|
|
673
686
|
}
|
|
674
687
|
const pngPath = mmdPath.endsWith('.mmd') ? mmdPath.slice(0, -4) + '.png' : mmdPath + '.png';
|
|
675
|
-
const r = spawnSync(
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
688
|
+
const r = spawnSync(
|
|
689
|
+
bin,
|
|
690
|
+
[
|
|
691
|
+
'-i',
|
|
692
|
+
mmdPath,
|
|
693
|
+
'-o',
|
|
694
|
+
pngPath,
|
|
695
|
+
// White background, not transparent — DAG node fills (greens,
|
|
696
|
+
// yellows, greys) need a known light surface for contrast. On a
|
|
697
|
+
// transparent PNG these wash out against dark IDE/browser themes.
|
|
698
|
+
'-b',
|
|
699
|
+
'white',
|
|
700
|
+
'--width',
|
|
701
|
+
String(PNG_WIDTH),
|
|
702
|
+
'--height',
|
|
703
|
+
String(PNG_HEIGHT),
|
|
704
|
+
'--scale',
|
|
705
|
+
String(PNG_SCALE),
|
|
706
|
+
'--quiet',
|
|
707
|
+
],
|
|
708
|
+
{
|
|
709
|
+
encoding: 'utf8',
|
|
710
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
711
|
+
windowsHide: true,
|
|
712
|
+
},
|
|
713
|
+
);
|
|
680
714
|
if (r.status !== 0) {
|
|
681
715
|
const message = (r.stderr || r.stdout || 'mmdc exited non-zero').trim();
|
|
682
716
|
return { written: false, reason: 'render-failed', message };
|
package/package.json
CHANGED