lazyclaw 3.99.22 → 3.99.24

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 (3) hide show
  1. package/cli.mjs +42 -32
  2. package/package.json +1 -1
  3. package/web/dashboard.html +46 -33
package/cli.mjs CHANGED
@@ -1469,42 +1469,52 @@ function _attachGhostAutocomplete(rl) {
1469
1469
  // two of the inner lines were 33 cols vs the others' 32, so the
1470
1470
  // ╮ rendered into the next line).
1471
1471
  function _renderBanner(version) {
1472
- const W = 30;
1473
- const accent = (s) => `\x1b[38;5;208m${s}\x1b[0m`;
1474
- // 24-bit color so the mascot reads in the same warm orange as the
1475
- // dist/index.html SVG (#d97757). Falls back gracefully on terminals
1476
- // that ignore truecolor — the glyphs are visible regardless.
1477
- const orange = (s) => `\x1b[38;2;217;119;87m${s}\x1b[0m`;
1478
- // Inner content of each banner row — DO NOT pad here, the wrapper
1479
- // does it. Backslashes are JS-escaped so each `\\` renders as one
1480
- // literal `\` in the output.
1481
- const inner = [
1482
- ' _',
1483
- ' | |__ _ _____ _ _',
1484
- " | / _` |_ / || | '_|",
1485
- ' |_\\__,_/__\\_, |_|',
1486
- ' LazyClaw |__/ ' + String(version || '?.?.?').padEnd(10).slice(0, 10),
1472
+ // Rebuilt from the Claude Design handoff bundle (v0.1 mascot sheet):
1473
+ // Claude's asterisk star wearing a crab/crustacean helmet with two
1474
+ // antenna-claws. 10-line "big ASCII" form fits a terminal banner
1475
+ // without zoom and reads at any monospace font that has the
1476
+ // box-drawing + geometric-shape glyphs.
1477
+ //
1478
+ // Palette (CLAUDE ORIGINAL): helmet body #c33d2a, helmet shadow
1479
+ // #7a1f15, star body #d97757, star shadow #a04f32, eyes ink
1480
+ // #c7bca6 / muted slits. Truecolor ANSI; degrades gracefully on
1481
+ // terminals that ignore it.
1482
+ const helmet = (s) => `\x1b[38;2;195;61;42m${s}\x1b[0m`; // #c33d2a
1483
+ const star = (s) => `\x1b[38;2;217;119;87m${s}\x1b[0m`; // #d97757 — Claude orange
1484
+ const ink = (s) => `\x1b[38;2;241;234;217m${s}\x1b[0m`; // #f1ead9 paper-ink
1485
+ const dim = (s) => `\x1b[2m${s}\x1b[0m`;
1486
+ const muted = (s) => `\x1b[38;2;122;110;95m${s}\x1b[0m`; // #7a6e5f
1487
+
1488
+ const v = String(version || '?.?.?');
1489
+ // Left column — sprite. Right column — wordmark + tagline, aligned
1490
+ // to the helmet's eye-row / brim. The trailing spaces preserve the
1491
+ // grid so any caller padding the lines (or copying them) doesn't
1492
+ // get ragged edges.
1493
+ const left = [
1494
+ ` ${helmet('▲')} ${helmet('▲')} `,
1495
+ ` ${helmet('│')} ${helmet('│')} `,
1496
+ ` ${helmet('╔══════════╗')} `,
1497
+ ` ${helmet('║')} ${helmet('║')} `,
1498
+ ` ${helmet('║')} ${muted('──')} ${muted('──')} ${helmet('║')} `,
1499
+ ` ${helmet('║')} ${helmet('║')} `,
1500
+ ` ${helmet('╚══════════╝')} `,
1501
+ ` ${star('✦')} `,
1502
+ ` ${star('╱|╲')} `,
1503
+ ` ${star('╱ | ╲')} `,
1487
1504
  ];
1488
- // Pixel-art mascot mirrored from the lazyclaude SPA's #claudeMascot
1489
- // SVG (orange rectangles → block characters). Squashed to 5 rows so
1490
- // it lines up with `inner` in the banner. Eye sockets are left blank
1491
- // (the SVG fills them with #000); a hollow gap reads as eyes against
1492
- // the orange body in any monospace font.
1493
- const mascot = [
1505
+ const right = [
1506
+ '',
1507
+ '',
1508
+ '',
1509
+ ` ${ink('lazyclaw')} ${dim('v' + v)}`,
1510
+ ` ${dim('a sleepy 8-bit')}`,
1511
+ ` ${dim('terminal assistant')}`,
1512
+ '',
1513
+ '',
1494
1514
  '',
1495
- orange(' ██ ██'),
1496
- orange(' ██████████████'),
1497
- orange(' ██ ') + '██' + orange(' ') + '██' + orange(' ██'),
1498
- orange(' ██████████████'),
1499
- orange(' ██ ██'),
1500
1515
  '',
1501
1516
  ];
1502
- const banner = [
1503
- '╭' + '─'.repeat(W) + '╮',
1504
- ...inner.map((s) => '│' + s.padEnd(W).slice(0, W) + '│'),
1505
- '╰' + '─'.repeat(W) + '╯',
1506
- ];
1507
- return banner.map((l, i) => ' ' + accent(l) + (mascot[i] ? ' ' + mascot[i] : ''));
1517
+ return left.map((l, i) => ' ' + l + (right[i] || ''));
1508
1518
  }
1509
1519
 
1510
1520
  function _printChatBanner(activeProvName, activeModel, version) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lazyclaw",
3
- "version": "3.99.22",
3
+ "version": "3.99.24",
4
4
  "description": "Lazy, elegant terminal CLI for chatting with Claude / OpenAI / Gemini / Ollama and orchestrating multi-step LLM workflows. Banner-on-launch, slash-command ghost autocomplete, persistent sessions, local HTTP gateway.",
5
5
  "keywords": [
6
6
  "claude",
@@ -42,24 +42,14 @@
42
42
  gap: 14px;
43
43
  }
44
44
  .logo { font-weight: 700; font-size: 16px; color: var(--accent); display: flex; align-items: center; gap: 10px; }
45
- .logo .mascot { width: 36px; height: 32px; flex: none; }
45
+ .logo .mascot { width: 44px; height: 44px; flex: none; image-rendering: pixelated; image-rendering: crisp-edges; }
46
46
  .ver { color: var(--dim); font-size: 11px; }
47
- /* lazyclaude pixel-mascot — copied verbatim from dist/index.html so the
48
- lazyclaw web dashboard wears the same character as the larger SPA. */
49
- .mascot .mj-body { animation: mj-jump 1s ease-in-out infinite; transform-origin: center bottom; }
50
- .mascot .mj-shadow { animation: mj-sh 1s ease-in-out infinite; }
51
- .mascot .mj-la { animation: mj-wl 1s ease-in-out infinite; transform-origin: right center; }
52
- .mascot .mj-ra { animation: mj-wr 1s ease-in-out infinite; transform-origin: left center; }
53
- .mascot .mj-le { animation: mj-ear 1s ease-in-out infinite; transform-origin: center bottom; }
54
- .mascot .mj-re { animation: mj-ear 1s ease-in-out infinite .1s; transform-origin: center bottom; }
55
- @keyframes mj-jump { 0%, 100% { transform: translateY(0) scaleY(1) scaleX(1); } 30% { transform: translateY(-10px) scaleY(1.1) scaleX(.95); } 50% { transform: translateY(-12px) scaleY(1.05) scaleX(.98); } 80% { transform: translateY(-3px) scaleY(.95) scaleX(1.05); } }
56
- @keyframes mj-sh { 0%, 100% { transform: scaleX(1); opacity: .25; } 50% { transform: scaleX(.4); opacity: .08; } }
57
- @keyframes mj-wl { 0%, 100% { transform: rotate(0); } 50% { transform: rotate(-25deg); } }
58
- @keyframes mj-wr { 0%, 100% { transform: rotate(0); } 50% { transform: rotate(25deg); } }
59
- @keyframes mj-ear { 0%, 100% { transform: scaleY(1); } 40% { transform: scaleY(1.2); } 60% { transform: scaleY(.85); } }
60
- @media (prefers-reduced-motion: reduce) {
61
- .mascot .mj-body, .mascot .mj-shadow, .mascot .mj-la, .mascot .mj-ra, .mascot .mj-le, .mascot .mj-re { animation: none; }
62
- }
47
+ /* lazyclaw 16x16 pixel mascot — Claude Design handoff (mascot sheet
48
+ v0.1, "claude original" palette). Claude's asterisk star (#d97757)
49
+ worn under a crustacean helmet (#c33d2a) with two antenna-claws.
50
+ Idle pose (sleepy slits). Hover gently brightens the helmet. */
51
+ .mascot { transition: filter 0.2s ease; }
52
+ .logo:hover .mascot { filter: drop-shadow(0 0 6px rgba(217, 119, 87, 0.45)); }
63
53
  nav.tabs {
64
54
  display: flex;
65
55
  gap: 2px;
@@ -286,22 +276,39 @@
286
276
  <body>
287
277
  <header>
288
278
  <div class="logo">
289
- <svg class="mascot" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 90" aria-hidden="true">
290
- <ellipse class="mj-shadow" cx="50" cy="82" rx="22" ry="5" fill="#000"/>
291
- <g class="mj-body">
292
- <rect class="mj-le" x="22" y="10" width="8" height="14" fill="#d97757"/>
293
- <rect class="mj-re" x="70" y="10" width="8" height="14" fill="#d97757"/>
294
- <rect x="18" y="24" width="64" height="4" fill="#d97757"/>
295
- <rect x="14" y="28" width="72" height="32" fill="#d97757"/>
296
- <rect x="30" y="34" width="8" height="10" fill="#000"/>
297
- <rect x="62" y="34" width="8" height="10" fill="#000"/>
298
- <rect class="mj-la" x="2" y="36" width="12" height="8" fill="#d97757"/>
299
- <rect class="mj-ra" x="86" y="36" width="12" height="8" fill="#d97757"/>
300
- <rect x="24" y="60" width="12" height="14" fill="#d97757"/>
301
- <rect x="64" y="60" width="12" height="14" fill="#d97757"/>
302
- </g>
279
+ <svg class="mascot" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" shape-rendering="crispEdges" aria-label="lazyclaw mascot" role="img">
280
+ <!-- antennae / claws -->
281
+ <rect x="3" y="1" width="1" height="1" fill="#a02b1c"/>
282
+ <rect x="12" y="1" width="1" height="1" fill="#a02b1c"/>
283
+ <rect x="3" y="2" width="1" height="1" fill="#a02b1c"/>
284
+ <rect x="12" y="2" width="1" height="1" fill="#a02b1c"/>
285
+ <!-- helmet -->
286
+ <rect x="3" y="3" width="10" height="1" fill="#c33d2a"/>
287
+ <rect x="2" y="4" width="12" height="1" fill="#c33d2a"/>
288
+ <rect x="1" y="5" width="2" height="1" fill="#c33d2a"/>
289
+ <rect x="3" y="5" width="1" height="1" fill="#ff8a6a"/>
290
+ <rect x="4" y="5" width="8" height="1" fill="#c33d2a"/>
291
+ <rect x="12" y="5" width="1" height="1" fill="#ff8a6a"/>
292
+ <rect x="13" y="5" width="2" height="1" fill="#c33d2a"/>
293
+ <rect x="1" y="6" width="14" height="1" fill="#c33d2a"/>
294
+ <rect x="2" y="7" width="12" height="1" fill="#c33d2a"/>
295
+ <!-- star body (Claude asterisk) — top edge below helmet brim -->
296
+ <rect x="3" y="8" width="10" height="1" fill="#d97757"/>
297
+ <!-- face row (idle: sleepy slit eyes) -->
298
+ <rect x="2" y="9" width="3" height="1" fill="#d97757"/>
299
+ <rect x="5" y="9" width="2" height="1" fill="#1a1410"/>
300
+ <rect x="7" y="9" width="2" height="1" fill="#d97757"/>
301
+ <rect x="9" y="9" width="2" height="1" fill="#1a1410"/>
302
+ <rect x="11" y="9" width="3" height="1" fill="#d97757"/>
303
+ <!-- star arms + tip -->
304
+ <rect x="1" y="10" width="14" height="1" fill="#d97757"/>
305
+ <rect x="0" y="11" width="16" height="1" fill="#d97757"/>
306
+ <rect x="1" y="12" width="14" height="1" fill="#d97757"/>
307
+ <rect x="3" y="13" width="10" height="1" fill="#d97757"/>
308
+ <rect x="5" y="14" width="6" height="1" fill="#d97757"/>
309
+ <rect x="7" y="15" width="2" height="1" fill="#d97757"/>
303
310
  </svg>
304
- <span>LazyClaw</span>
311
+ <span>lazyclaw</span>
305
312
  </div>
306
313
  <div class="ver" id="version">…</div>
307
314
  </header>
@@ -1398,7 +1405,13 @@
1398
1405
  headers: { 'content-type': 'application/json' },
1399
1406
  body: JSON.stringify(body),
1400
1407
  });
1401
- const reply = r.text || r.output || '(empty)';
1408
+ // Daemon's POST /agent returns { reply, usage?, cost? }. Older
1409
+ // drafts used { text } / { output }; accept any of them so a
1410
+ // dashboard hitting an older or newer daemon both work.
1411
+ const reply = (typeof r.reply === 'string' ? r.reply : '')
1412
+ || (typeof r.text === 'string' ? r.text : '')
1413
+ || (typeof r.output === 'string' ? r.output : '')
1414
+ || '(empty)';
1402
1415
  appendMsg('assistant', reply);
1403
1416
  chatHistory.push({ role: 'assistant', text: reply });
1404
1417
  const dur = ((Date.now() - t0) / 1000).toFixed(1);