writethevision 7.0.3 → 7.0.4

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/package.json +1 -1
  2. package/src/cli.js +72 -20
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "writethevision",
3
- "version": "7.0.3",
3
+ "version": "7.0.4",
4
4
  "description": "Write The Vision (WTV): vision-driven development with the Habakkuk workflow. 10 agents + 21 skills for Claude Code, Codex CLI, and OpenCode.",
5
5
  "author": "Christopher Hogg",
6
6
  "license": "MIT",
package/src/cli.js CHANGED
@@ -402,13 +402,71 @@ function getAgentLocations() {
402
402
  return locations;
403
403
  }
404
404
 
405
- function brickifyAsciiArt(asciiArt) {
406
- if (!asciiArt) return asciiArt;
405
+ const BLOCK_FONT_3X5 = {
406
+ A: ['███', '█ █', '███', '█ █', '█ █'],
407
+ B: ['██ ', '█ █', '██ ', '█ █', '██ '],
408
+ C: ['███', '█ ', '█ ', '█ ', '███'],
409
+ D: ['██ ', '█ █', '█ █', '█ █', '██ '],
410
+ E: ['███', '█ ', '██ ', '█ ', '███'],
411
+ F: ['███', '█ ', '██ ', '█ ', '█ '],
412
+ G: ['███', '█ ', '█ █', '█ █', '███'],
413
+ H: ['█ █', '█ █', '███', '█ █', '█ █'],
414
+ I: ['███', ' █ ', ' █ ', ' █ ', '███'],
415
+ J: [' ██', ' █', ' █', '█ █', '██ '],
416
+ K: ['█ █', '█ █', '██ ', '█ █', '█ █'],
417
+ L: ['█ ', '█ ', '█ ', '█ ', '███'],
418
+ M: ['█ █', '███', '███', '█ █', '█ █'],
419
+ N: ['█ █', '███', '███', '███', '█ █'],
420
+ O: ['███', '█ █', '█ █', '█ █', '███'],
421
+ P: ['███', '█ █', '███', '█ ', '█ '],
422
+ Q: ['███', '█ █', '█ █', '███', ' █'],
423
+ R: ['███', '█ █', '███', '█ █', '█ █'],
424
+ S: ['███', '█ ', '███', ' █', '███'],
425
+ T: ['███', ' █ ', ' █ ', ' █ ', ' █ '],
426
+ U: ['█ █', '█ █', '█ █', '█ █', '███'],
427
+ V: ['█ █', '█ █', '█ █', '█ █', ' █ '],
428
+ W: ['█ █', '█ █', '███', '███', '█ █'],
429
+ X: ['█ █', '█ █', ' █ ', '█ █', '█ █'],
430
+ Y: ['█ █', '█ █', ' █ ', ' █ ', ' █ '],
431
+ Z: ['███', ' █', ' █ ', '█ ', '███'],
432
+ ' ': [' ', ' ', ' ', ' ', ' '],
433
+ '-': [' ', ' ', '███', ' ', ' '],
434
+ '?': ['███', ' █', ' ██', ' ', ' █ '],
435
+ };
436
+
437
+ function renderBlockText(text, { maxWidth = null, color = null, bold = false } = {}) {
438
+ const normalized = String(text || '').toUpperCase();
439
+ const glyphWidth = 3;
440
+ const letterGap = 1;
441
+ const maxCharsPerLine = maxWidth
442
+ ? Math.max(1, Math.floor((maxWidth + letterGap) / (glyphWidth + letterGap)))
443
+ : normalized.length;
444
+
445
+ const chunks = [];
446
+ for (let i = 0; i < normalized.length; i += maxCharsPerLine) {
447
+ chunks.push(normalized.slice(i, i + maxCharsPerLine));
448
+ }
449
+
450
+ const renderedLines = [];
451
+ for (let chunkIndex = 0; chunkIndex < chunks.length; chunkIndex++) {
452
+ const chunk = chunks[chunkIndex];
453
+ for (let row = 0; row < 5; row++) {
454
+ const rowText = chunk
455
+ .split('')
456
+ .map(ch => (BLOCK_FONT_3X5[ch] ? BLOCK_FONT_3X5[ch][row] : BLOCK_FONT_3X5['?']?.[row] || '???'))
457
+ .join(' '.repeat(letterGap));
458
+
459
+ const prefix = color ? (bold ? color + c.bold : color) : '';
460
+ const suffix = color ? c.reset : '';
461
+ renderedLines.push(prefix + rowText + suffix);
462
+ }
463
+
464
+ if (chunkIndex !== chunks.length - 1) {
465
+ renderedLines.push('');
466
+ }
467
+ }
407
468
 
408
- return asciiArt
409
- .split('\n')
410
- .map(line => line.replace(/[^\s]/g, '█'))
411
- .join('\n');
469
+ return renderedLines.join('\n');
412
470
  }
413
471
 
414
472
  function parseAgentFile(filePath) {
@@ -453,7 +511,7 @@ function parseAgentFile(filePath) {
453
511
  let asciiArt = '';
454
512
  const asciiMatch = content.match(/```text\n([\s\S]+?)\n```/);
455
513
  if (asciiMatch) {
456
- asciiArt = brickifyAsciiArt(asciiMatch[1]);
514
+ asciiArt = asciiMatch[1];
457
515
  }
458
516
 
459
517
  return {
@@ -1685,11 +1743,7 @@ async function meetTheTeam() {
1685
1743
  console.log(` ${c.bold}${c.yellow}PAUL — THE MASTERBUILDER${c.reset}`);
1686
1744
  console.log(` ${c.dim}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${c.reset}`);
1687
1745
  const paulAgent = parseAgentFile(join(TEMPLATES_DIR, 'agents', 'paul.md'));
1688
- if (paulAgent && paulAgent.asciiArt) {
1689
- console.log(paulAgent.asciiArt);
1690
- } else {
1691
- console.log(AVATARS.paul);
1692
- }
1746
+ console.log(AVATARS.paul || (paulAgent && paulAgent.asciiArt ? paulAgent.asciiArt : ''));
1693
1747
  await sleep(shortPause);
1694
1748
  console.log(`
1695
1749
  ${c.cyan}"According to the grace of God which is given unto me,${c.reset}
@@ -1719,11 +1773,7 @@ async function meetTheTeam() {
1719
1773
  console.log(` ${artisan.color}${c.bold}${artisan.name}${c.reset}`);
1720
1774
  const templatePath = join(TEMPLATES_DIR, 'agents', artisan.file);
1721
1775
  const agent = parseAgentFile(templatePath);
1722
- if (agent && agent.asciiArt) {
1723
- console.log(agent.asciiArt);
1724
- } else {
1725
- console.log(AVATARS[artisan.id]);
1726
- }
1776
+ console.log(AVATARS[artisan.id] || (agent && agent.asciiArt ? agent.asciiArt : ''));
1727
1777
  console.log(` ${c.dim}${artisan.domain}${c.reset}`);
1728
1778
  if (artisan.verse) {
1729
1779
  console.log(` ${c.dim}${artisan.verse.ref}${c.reset} ${c.dim}"${artisan.verse.text}"${c.reset}`);
@@ -3522,13 +3572,15 @@ async function agentsInteractive() {
3522
3572
  if (agent.wantsGlobal) statusText += c.blue + 'Global ' + c.reset;
3523
3573
  if (!agent.wantsLocal && !agent.wantsGlobal) statusText = c.dim + 'None' + c.reset;
3524
3574
 
3575
+ const terminalWidth = process.stdout.columns || 80;
3576
+ const detailWidth = Math.max(20, terminalWidth - detailStartX - 1);
3577
+ const nameBanner = renderBlockText(agent.name, { maxWidth: detailWidth, color: c.magenta, bold: true });
3578
+
3525
3579
  const details = [
3526
- `${c.magenta}${c.bold}${agent.name.toUpperCase()}${c.reset}`,
3580
+ nameBanner,
3527
3581
  `Status: ${statusText}`,
3528
3582
  '',
3529
3583
  `${c.dim}${agent.description}${c.reset}`,
3530
- '',
3531
- agent.asciiArt ? agent.asciiArt : `${c.dim}[ No Portrait ]${c.reset}`
3532
3584
  ];
3533
3585
 
3534
3586
  // Draw details