commitshow 0.3.18 → 0.3.19

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.
Files changed (2) hide show
  1. package/dist/lib/render.js +74 -75
  2. package/package.json +1 -1
@@ -289,77 +289,10 @@ export function renderAudit(view) {
289
289
  lines.push(' ' + boxBottom());
290
290
  lines.push('');
291
291
  }
292
- // Hero score · trophy plate. Score + caption wrapped in a double-line
293
- // ╔═╗ box so the X/Twitter screenshot has a single hero artifact you can
294
- // crop to. Box is intentionally wider than tall (≈3:2) square in cell
295
- // count is too tall once the 6-row ANSI Shadow + 1 caption + 2 padding
296
- // rows are stacked. Outer 58-col layout still centers the box.
297
- const band = total >= 75 ? 'strong' : total >= 50 ? 'mid' : 'weak';
298
- const bandTone = scoreTone(total);
299
- const bigRows = bigText(String(total));
300
- const bigWidth = bigRows[0].length;
301
- // Inner content width = the longer of (digit width, caption width) + a
302
- // small breathing margin on each side. Box outer = inner + 2 (frame).
303
- const captionVisible = isWalkOn
304
- ? `/ 100 · walk-on · ${band}`
305
- : `/ 100 · ${band}`;
306
- const SCORE_PAD = 4; // 2 cells of breathing room on each side of widest line
307
- const scoreInsideW = Math.max(bigWidth, captionVisible.length) + SCORE_PAD;
308
- const scoreOuterW = scoreInsideW + 2;
309
- // Center the trophy box inside the 58-col layout
310
- const trophyLeftPad = Math.max(0, Math.floor((58 - scoreOuterW) / 2));
311
- const trophyIndent = ' ' + ' '.repeat(trophyLeftPad);
312
- const trophyTop = c.muted('╔' + '═'.repeat(scoreInsideW) + '╗');
313
- const trophyBottom = c.muted('╚' + '═'.repeat(scoreInsideW) + '╝');
314
- const trophyBlank = c.muted('║' + ' '.repeat(scoreInsideW) + '║');
315
- // Center a colored line inside the box. visibleLen is the *visible*
316
- // (ANSI-stripped) cell count of the colored content.
317
- const trophyRow = (visibleLen, colored) => {
318
- const pad = Math.max(0, scoreInsideW - visibleLen);
319
- const lp = Math.floor(pad / 2);
320
- const rp = pad - lp;
321
- return c.muted('║') + ' '.repeat(lp) + colored + ' '.repeat(rp) + c.muted('║');
322
- };
323
- lines.push(trophyIndent + trophyTop);
324
- lines.push(trophyIndent + trophyBlank);
325
- for (const row of bigRows) {
326
- lines.push(trophyIndent + trophyRow(bigWidth, c.pixelInk(row)));
327
- }
328
- lines.push(trophyIndent + trophyBlank);
329
- // Caption row · band-tinted so the signal lives on the band word.
330
- const captionColored = isWalkOn
331
- ? c.muted('/ 100 · ') + c.gold('walk-on') + c.muted(' · ') + bandTone(band)
332
- : c.muted('/ 100 · ') + bandTone(band);
333
- lines.push(trophyIndent + trophyRow(captionVisible.length, captionColored));
334
- lines.push(trophyIndent + trophyBottom);
335
- // Walk-on sub-caption stays OUTSIDE the trophy — it's an explanation
336
- // of the cap, not part of the headline. Keeps the box clean and tight
337
- // for screenshot crops.
338
- if (isWalkOn) {
339
- const subVisible = 'audition unlocks final 5 · max walk-on score 95';
340
- const subPad = Math.floor((58 - subVisible.length) / 2);
341
- lines.push(' ' + ' '.repeat(subPad) + c.muted(subVisible));
342
- }
343
- lines.push('');
344
- // Axis bars · league shows all three; walk-on shows Audit only and
345
- // surfaces Scout + Community as locked-with-unlock-hint rows.
346
- // Walk-on Audit denominator is 45 (Brief slot excluded) so the math is
347
- // visibly consistent with the big-digit normalization above.
348
- const lockedBar = '─ audition unlocks ─'; // exactly 20 cells · matches scoreBar width
349
- const auditDen = isWalkOn ? WALK_ON_AUDIT_MAX : 50;
350
- const auditScoreClamp = Math.min(p.score_auto ?? 0, auditDen);
351
- const auditLine = ` Audit ${pad(`${auditScoreClamp}/${auditDen}`, 7)} ${scoreBar(auditScoreClamp, auditDen)}`;
352
- lines.push(' ' + auditLine);
353
- if (isWalkOn) {
354
- lines.push(' ' + ` Scout ${pad('—/30', 7)} ` + c.muted(lockedBar));
355
- lines.push(' ' + ` Comm. ${pad('—/20', 7)} ` + c.muted(lockedBar));
356
- }
357
- else {
358
- lines.push(' ' + ` Scout ${pad(`${p.score_forecast}/30`, 7)} ${scoreBar(p.score_forecast, 30)}`);
359
- lines.push(' ' + ` Comm. ${pad(`${p.score_community}/20`, 7)} ${scoreBar(p.score_community, 20)}`);
360
- }
361
- lines.push('');
362
- // (concerns/strengths block moved above the score · errors-first 2026-04-30)
292
+ // (Hero score · trophy plate + axis bars moved BELOW all info sections
293
+ // on 2026-05-04 · "info top, capture-worthy hero at the bottom" so a
294
+ // crop of the last block is a self-contained share asset. See the
295
+ // HERO BLOCK construction near the end of this function.)
363
296
  // ─── AI Coder 7 Frames · signature framework ───
364
297
  // Render only the categories that produced an actionable status (fail /
365
298
  // warn / pass when meaningful). N/A categories are dropped to keep the
@@ -419,14 +352,80 @@ export function renderAudit(view) {
419
352
  const url = `https://commit.show/projects/${p.id}`;
420
353
  lines.push(' ' + c.muted('→ ') + c.cream(url));
421
354
  lines.push('');
422
- // Agent-loop hint · nudges users into the `--json | jq` workflow that
423
- // makes this CLI useful inside Claude Code · Cursor · etc. Static for
424
- // V1 could go contextual (CRIT-aware suggestions) in V1.5.
355
+ // Agent-loop hint · nudges users into the `--json` workflow that makes
356
+ // this CLI useful inside Claude Code · Cursor · etc. Kept short so it
357
+ // fits inside the 58-cell layout (longer "github.com/foo/bar --json |
358
+ // jq .concerns" forms blew past the wordmark right edge). The repo
359
+ // form drops to `.` because anyone running an agent loop is in cwd;
360
+ // the URL case is already covered by the walk-on upsell box below.
425
361
  if (concerns.length > 0) {
426
- const cmd = `commitshow audit ${p.github_url?.replace(/^https?:\/\//, '') ?? '.'} --json | jq .concerns`;
362
+ const cmd = 'commitshow audit . --json';
427
363
  lines.push(' ' + c.muted('next · feed your AI loop → ') + c.cream(cmd));
428
364
  lines.push('');
429
365
  }
366
+ // ─── HERO BLOCK · trophy + axis bars · 2026-05-04 ───
367
+ // All info sits ABOVE this block so a screenshot cropped to the bottom
368
+ // (trophy + axis bars + wordmark) is a self-contained share asset
369
+ // showing project identity, score, and brand mark in one frame.
370
+ const band = total >= 75 ? 'strong' : total >= 50 ? 'mid' : 'weak';
371
+ const bandTone = scoreTone(total);
372
+ const bigRows = bigText(String(total));
373
+ const bigWidth = bigRows[0].length;
374
+ // Trophy: name strip + big digits + caption inside one ╔═╗ frame so a
375
+ // crop of just the trophy tells the whole story (project · score · band).
376
+ const slugVisible = (p.github_url?.replace(/^https?:\/\/github\.com\//, '') ?? '').slice(0, 40);
377
+ const captionVisible = isWalkOn
378
+ ? `/ 100 · walk-on · ${band}`
379
+ : `/ 100 · ${band}`;
380
+ const SCORE_PAD = 4; // 2 cells of breathing room on each side of widest line
381
+ const scoreInsideW = Math.max(bigWidth, captionVisible.length, slugVisible.length) + SCORE_PAD;
382
+ const scoreOuterW = scoreInsideW + 2;
383
+ const trophyLeftPad = Math.max(0, Math.floor((58 - scoreOuterW) / 2));
384
+ const trophyIndent = ' ' + ' '.repeat(trophyLeftPad);
385
+ const trophyTop = c.muted('╔' + '═'.repeat(scoreInsideW) + '╗');
386
+ const trophyBottom = c.muted('╚' + '═'.repeat(scoreInsideW) + '╝');
387
+ const trophyBlank = c.muted('║' + ' '.repeat(scoreInsideW) + '║');
388
+ const trophyRow = (visibleLen, colored) => {
389
+ const pad = Math.max(0, scoreInsideW - visibleLen);
390
+ const lp = Math.floor(pad / 2);
391
+ const rp = pad - lp;
392
+ return c.muted('║') + ' '.repeat(lp) + colored + ' '.repeat(rp) + c.muted('║');
393
+ };
394
+ lines.push(trophyIndent + trophyTop);
395
+ if (slugVisible) {
396
+ lines.push(trophyIndent + trophyRow(slugVisible.length, c.muted(slugVisible)));
397
+ }
398
+ lines.push(trophyIndent + trophyBlank);
399
+ for (const row of bigRows) {
400
+ lines.push(trophyIndent + trophyRow(bigWidth, c.pixelInk(row)));
401
+ }
402
+ lines.push(trophyIndent + trophyBlank);
403
+ const captionColored = isWalkOn
404
+ ? c.muted('/ 100 · ') + c.gold('walk-on') + c.muted(' · ') + bandTone(band)
405
+ : c.muted('/ 100 · ') + bandTone(band);
406
+ lines.push(trophyIndent + trophyRow(captionVisible.length, captionColored));
407
+ lines.push(trophyIndent + trophyBottom);
408
+ if (isWalkOn) {
409
+ const subVisible = 'audition unlocks final 5 · max walk-on score 95';
410
+ const subPad = Math.floor((58 - subVisible.length) / 2);
411
+ lines.push(' ' + ' '.repeat(subPad) + c.muted(subVisible));
412
+ }
413
+ lines.push('');
414
+ // Axis bars sit directly under the trophy as the per-pillar breakdown
415
+ // — same visual frame for share screenshots.
416
+ const lockedBar = '─ audition unlocks ─';
417
+ const auditDen = isWalkOn ? WALK_ON_AUDIT_MAX : 50;
418
+ const auditScoreClamp = Math.min(p.score_auto ?? 0, auditDen);
419
+ lines.push(' ' + ` Audit ${pad(`${auditScoreClamp}/${auditDen}`, 7)} ${scoreBar(auditScoreClamp, auditDen)}`);
420
+ if (isWalkOn) {
421
+ lines.push(' ' + ` Scout ${pad('—/30', 7)} ` + c.muted(lockedBar));
422
+ lines.push(' ' + ` Comm. ${pad('—/20', 7)} ` + c.muted(lockedBar));
423
+ }
424
+ else {
425
+ lines.push(' ' + ` Scout ${pad(`${p.score_forecast}/30`, 7)} ${scoreBar(p.score_forecast, 30)}`);
426
+ lines.push(' ' + ` Comm. ${pad(`${p.score_community}/20`, 7)} ${scoreBar(p.score_community, 20)}`);
427
+ }
428
+ lines.push('');
430
429
  const wordmark = 'commit.show';
431
430
  const footerPad = Math.max(0, BOX_W - wordmark.length);
432
431
  lines.push(' '.repeat(footerPad) + c.gold(wordmark));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "commitshow",
3
- "version": "0.3.18",
3
+ "version": "0.3.19",
4
4
  "description": "commit.show CLI — audit any vibe-coded project from your terminal.",
5
5
  "type": "module",
6
6
  "bin": {