staysfixed 0.2.1 → 0.2.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/package.json +1 -1
- package/src/watch/panel.js +78 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "staysfixed",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"description": "Prove that what already worked still works after an agent changed the code. Picture checks, guards for fixed bugs, a pre-release walkthrough, and known-good markers — as a CLI and as an MCP server.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
package/src/watch/panel.js
CHANGED
|
@@ -190,6 +190,10 @@ export function panelHtml(plan = {}) {
|
|
|
190
190
|
'<div class="track" id="track"><div class="fill" id="fill"></div></div>',
|
|
191
191
|
'<span class="counts mono" id="counts"></span>',
|
|
192
192
|
'</div>',
|
|
193
|
+
// Said once, plainly. Without it the list of names and times reads as a
|
|
194
|
+
// speed report — which is exactly how it read to the first person who
|
|
195
|
+
// looked at it. The times are how long a check took; the check is this.
|
|
196
|
+
'<p class="what" id="what"></p>',
|
|
193
197
|
'</header>',
|
|
194
198
|
|
|
195
199
|
// --- the two columns. One on a narrow panel, two on a wide one. ---------
|
|
@@ -487,6 +491,19 @@ button { font: inherit; color: inherit; }
|
|
|
487
491
|
from { opacity: 0; transform: translateY(7px); filter: blur(4px); }
|
|
488
492
|
to { opacity: 1; transform: none; filter: blur(0); }
|
|
489
493
|
}
|
|
494
|
+
.what {
|
|
495
|
+
margin: 8px 0 0; font-size: var(--t-small); color: var(--faint);
|
|
496
|
+
line-height: 1.45; overflow-wrap: anywhere;
|
|
497
|
+
}
|
|
498
|
+
.rverdict {
|
|
499
|
+
flex: 0 0 auto; font-size: var(--t-small); color: var(--faint);
|
|
500
|
+
white-space: nowrap; padding-left: 10px;
|
|
501
|
+
}
|
|
502
|
+
.item.held .rverdict { color: var(--faint); }
|
|
503
|
+
.item.moved .rverdict { color: var(--moved); }
|
|
504
|
+
.item.broke .rverdict { color: var(--broke); }
|
|
505
|
+
.item.waiting .rverdict { color: var(--waiting); }
|
|
506
|
+
.item.pending .rverdict, .item.skip .rverdict { color: var(--faintest, var(--faint)); }
|
|
490
507
|
.note { margin-top: 5px; font-size: var(--t-body); color: var(--faint); overflow-wrap: anywhere; }
|
|
491
508
|
|
|
492
509
|
/* One hairline, not a row of blocks. Each finished check adds its own slice of
|
|
@@ -750,6 +767,7 @@ button { font: inherit; color: inherit; }
|
|
|
750
767
|
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
|
|
751
768
|
}
|
|
752
769
|
.item.pending .rname, .item.skip .rname { color: var(--faint); }
|
|
770
|
+
.rtime { margin-left: 12px; }
|
|
753
771
|
.rtime {
|
|
754
772
|
flex: 0 0 auto;
|
|
755
773
|
font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
|
|
@@ -1102,7 +1120,7 @@ const SCRIPT = `
|
|
|
1102
1120
|
var ui = {
|
|
1103
1121
|
clock: el('clock'), project: el('project'), app: el('app'), targetsep: el('targetsep'),
|
|
1104
1122
|
state: el('state'), note: el('note'),
|
|
1105
|
-
track: el('track'), fill: el('fill'), counts: el('counts'),
|
|
1123
|
+
track: el('track'), fill: el('fill'), counts: el('counts'), what: el('what'),
|
|
1106
1124
|
stage: el('stage'), shot: el('shot'), layerA: el('layerA'), layerB: el('layerB'), blank: el('blank'),
|
|
1107
1125
|
caption: el('caption'), shotname: el('shotname'), shotout: el('shotout'), tabs: el('tabs'),
|
|
1108
1126
|
scroll: el('scroll'), follow: el('follow'), nothing: el('nothing'),
|
|
@@ -1203,6 +1221,54 @@ const SCRIPT = `
|
|
|
1203
1221
|
}
|
|
1204
1222
|
}
|
|
1205
1223
|
|
|
1224
|
+
/**
|
|
1225
|
+
* Two or three words for the row itself.
|
|
1226
|
+
*
|
|
1227
|
+
* The long sentence stays in the detail; this is what a person reads while
|
|
1228
|
+
* scanning the column. A check that held has to say so — silence next to a
|
|
1229
|
+
* duration is what made the panel look like it was timing page loads.
|
|
1230
|
+
*/
|
|
1231
|
+
function shortOutcome(kind, ev) {
|
|
1232
|
+
var status = ev.status;
|
|
1233
|
+
if (kind === 'guard') {
|
|
1234
|
+
if (status === 'passed') return 'still holds';
|
|
1235
|
+
if (status === 'skipped') return 'left out';
|
|
1236
|
+
return 'broken again';
|
|
1237
|
+
}
|
|
1238
|
+
switch (status) {
|
|
1239
|
+
case 'passed': return 'matches';
|
|
1240
|
+
case 'changed':
|
|
1241
|
+
var n = ev.diffPixels || 0;
|
|
1242
|
+
return commas(n) + ' ' + plural(n, 'pixel', 'pixels') + ' moved';
|
|
1243
|
+
case 'new': return 'needs your eyes';
|
|
1244
|
+
case 'missing': return 'no approved picture';
|
|
1245
|
+
case 'failed': return 'no picture taken';
|
|
1246
|
+
case 'flaky': return 'would not settle';
|
|
1247
|
+
case 'skipped': return 'left out';
|
|
1248
|
+
default: return '';
|
|
1249
|
+
}
|
|
1250
|
+
}
|
|
1251
|
+
|
|
1252
|
+
/**
|
|
1253
|
+
* The one line that says what a run is, in the words a person would use.
|
|
1254
|
+
*/
|
|
1255
|
+
function describeWork(screens, guards) {
|
|
1256
|
+
var bits = [];
|
|
1257
|
+
if (screens) {
|
|
1258
|
+
bits.push(
|
|
1259
|
+
screens + ' ' + plural(screens, 'screen', 'screens') +
|
|
1260
|
+
' photographed and compared, pixel for pixel, with the picture you approved',
|
|
1261
|
+
);
|
|
1262
|
+
}
|
|
1263
|
+
if (guards) {
|
|
1264
|
+
bits.push(
|
|
1265
|
+
guards + ' ' + plural(guards, 'guard', 'guards') +
|
|
1266
|
+
' — one per bug that was already fixed once',
|
|
1267
|
+
);
|
|
1268
|
+
}
|
|
1269
|
+
return bits.join(' · ');
|
|
1270
|
+
}
|
|
1271
|
+
|
|
1206
1272
|
// -------------------------------------------------------------------------
|
|
1207
1273
|
// Numbers count rather than jump.
|
|
1208
1274
|
//
|
|
@@ -1312,10 +1378,13 @@ const SCRIPT = `
|
|
|
1312
1378
|
var rname = document.createElement('span');
|
|
1313
1379
|
rname.className = 'rname';
|
|
1314
1380
|
rname.textContent = name;
|
|
1381
|
+
var rverdict = document.createElement('span');
|
|
1382
|
+
rverdict.className = 'rverdict';
|
|
1315
1383
|
var rtime = document.createElement('span');
|
|
1316
1384
|
rtime.className = 'rtime';
|
|
1317
1385
|
row.appendChild(dot);
|
|
1318
1386
|
row.appendChild(rname);
|
|
1387
|
+
row.appendChild(rverdict);
|
|
1319
1388
|
row.appendChild(rtime);
|
|
1320
1389
|
row.insertAdjacentHTML('beforeend', CHEVRON);
|
|
1321
1390
|
|
|
@@ -1327,7 +1396,7 @@ const SCRIPT = `
|
|
|
1327
1396
|
root.appendChild(detail);
|
|
1328
1397
|
|
|
1329
1398
|
var entry = {
|
|
1330
|
-
kind: kind, name: name, root: root, row: row, time: rtime,
|
|
1399
|
+
kind: kind, name: name, root: root, row: row, time: rtime, verdict: rverdict,
|
|
1331
1400
|
detail: detail, describe: describe || '', open: false, hasDetail: false
|
|
1332
1401
|
};
|
|
1333
1402
|
|
|
@@ -1522,6 +1591,12 @@ const SCRIPT = `
|
|
|
1522
1591
|
}
|
|
1523
1592
|
ui.countScreens.textContent = countIn('picture');
|
|
1524
1593
|
ui.countGuards.textContent = countIn('guard');
|
|
1594
|
+
var nScreens = 0, nGuards = 0;
|
|
1595
|
+
for (var w = 0; w < order.length; w++) {
|
|
1596
|
+
if (order[w].kind === 'guard') nGuards++; else nScreens++;
|
|
1597
|
+
}
|
|
1598
|
+
ui.what.textContent = describeWork(nScreens, nGuards);
|
|
1599
|
+
ui.what.hidden = order.length === 0;
|
|
1525
1600
|
ui.nothing.hidden = order.length > 0;
|
|
1526
1601
|
paintMeter();
|
|
1527
1602
|
}
|
|
@@ -2344,6 +2419,7 @@ const SCRIPT = `
|
|
|
2344
2419
|
preloadAll(entry.pics);
|
|
2345
2420
|
}
|
|
2346
2421
|
entry.outText = outcomeText(kind, ev);
|
|
2422
|
+
if (entry.verdict) entry.verdict.textContent = shortOutcome(kind, ev);
|
|
2347
2423
|
entry.failedAt = (kind === 'guard' && ev.status === 'failed' && ev.failedAt) ? ev.failedAt : '';
|
|
2348
2424
|
entry.story = (kind === 'guard' && ev.status === 'failed' && ev.because) ? ev.because : '';
|
|
2349
2425
|
if (typeof ev.durationMs === 'number') tweenTo(entry.time, ev.durationMs, fmt);
|