lazyclaw 5.0.8 → 5.0.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.
- package/cli.mjs +11 -1
- package/package.json +1 -1
- package/tui/splash.mjs +76 -28
- package/tui/wordmark.mjs +21 -3
package/cli.mjs
CHANGED
|
@@ -1658,7 +1658,17 @@ async function _renderV5Banner(version) {
|
|
|
1658
1658
|
if (!a) return _renderBanner(version); // missing tarball asset → v4 figlet
|
|
1659
1659
|
const v = String(version || '?.?.?');
|
|
1660
1660
|
const rows = [];
|
|
1661
|
-
|
|
1661
|
+
const palette = a.wordmark.palette || [];
|
|
1662
|
+
const gradient = a.wordmark.gradient || [];
|
|
1663
|
+
function tint(idx, s) {
|
|
1664
|
+
const hex = palette[idx] || '#FFB347';
|
|
1665
|
+
const m = /^#?([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/i.exec(hex);
|
|
1666
|
+
if (!m) return _orange(s);
|
|
1667
|
+
const [, r, g, b] = m;
|
|
1668
|
+
const R = parseInt(r, 16), G = parseInt(g, 16), B = parseInt(b, 16);
|
|
1669
|
+
return `\x1b[38;2;${R};${G};${B}m${s}\x1b[0m`;
|
|
1670
|
+
}
|
|
1671
|
+
a.wordmark.rows.forEach((r, i) => rows.push(tint(gradient[i] ?? 1, ' ' + r)));
|
|
1662
1672
|
rows.push('');
|
|
1663
1673
|
for (const r of a.banner.rows) rows.push(_orange(' ' + r));
|
|
1664
1674
|
rows.push(_orange(' ' + `lazyclaw v${v}`));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lazyclaw",
|
|
3
|
-
"version": "5.0.
|
|
3
|
+
"version": "5.0.9",
|
|
4
4
|
"description": "Lazy, elegant terminal CLI for chatting with Claude / OpenAI / Gemini / Ollama, orchestrating multi-step LLM workflows, and running multi-agent Slack teams with cross-task memory. Banner-on-launch, slash-command ghost autocomplete, persistent sessions, local HTTP gateway.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"claude",
|
package/tui/splash.mjs
CHANGED
|
@@ -1,23 +1,29 @@
|
|
|
1
|
-
// tui/splash.mjs — Hermes-style hero splash
|
|
1
|
+
// tui/splash.mjs — Hermes-style hero splash with gradient wordmark,
|
|
2
|
+
// subcommand catalog, tool registry, skill index, and a bottom status bar.
|
|
2
3
|
//
|
|
3
4
|
// Layout (terminal-width responsive):
|
|
4
5
|
//
|
|
5
|
-
//
|
|
6
|
-
// ...
|
|
6
|
+
// LAZYCLAW wordmark (top, per-row gradient orange)
|
|
7
7
|
//
|
|
8
|
-
//
|
|
9
|
-
// │ [sloth braille]
|
|
10
|
-
// │
|
|
11
|
-
// │
|
|
12
|
-
// │
|
|
13
|
-
//
|
|
8
|
+
// ╭─ lazyclaw vX.Y.Z · trainer-split · FTS5 recall · 6-backend sandbox ─╮
|
|
9
|
+
// │ [sloth braille] Subcommands │
|
|
10
|
+
// │ core / workflow / config / state / ... │
|
|
11
|
+
// │ Available Tools │
|
|
12
|
+
// │ fs / exec / git / ... │
|
|
13
|
+
// │ Available Skills │
|
|
14
|
+
// │ N subcommands · M tool groups · K skills · /help │
|
|
15
|
+
// ╰──────────────────────────────────────────────────────────────────────╯
|
|
14
16
|
//
|
|
15
|
-
// provider · X · Y
|
|
16
|
-
// /
|
|
17
|
-
// Session:
|
|
17
|
+
// provider · X · Y · trainer · A · B
|
|
18
|
+
// /cwd
|
|
19
|
+
// Session: ...
|
|
18
20
|
//
|
|
19
21
|
// Welcome to lazyclaw. Type your message or /help for commands.
|
|
20
22
|
// + Tip: ...
|
|
23
|
+
//
|
|
24
|
+
// ───────────────────────────────────────────────────────────────────────
|
|
25
|
+
// provider · model | ctx -- | [progress] | 0s
|
|
26
|
+
// ───────────────────────────────────────────────────────────────────────
|
|
21
27
|
import React from 'react';
|
|
22
28
|
import { Box, Text } from 'ink';
|
|
23
29
|
import stringWidth from 'string-width';
|
|
@@ -28,6 +34,19 @@ import { wordmark } from './wordmark.mjs';
|
|
|
28
34
|
const LMARGIN = ' ';
|
|
29
35
|
const TITLE = ' trainer-split · FTS5 recall · 6-backend sandbox ';
|
|
30
36
|
|
|
37
|
+
// Subcommand catalog — grouped for the splash so a new user sees the
|
|
38
|
+
// surface area at a glance. Mirrors SUBCOMMANDS in cli.mjs.
|
|
39
|
+
export const SUBCOMMAND_GROUPS = [
|
|
40
|
+
['core', ['chat', 'agent', 'orchestrator', 'dashboard', 'menu']],
|
|
41
|
+
['workflow', ['run', 'resume', 'inspect', 'clear', 'validate', 'graph']],
|
|
42
|
+
['config', ['config', 'auth', 'rates', 'providers', 'setup', 'onboard']],
|
|
43
|
+
['state', ['sessions', 'skills', 'workspace', 'memory', 'status', 'doctor']],
|
|
44
|
+
['runtime', ['daemon', 'cron', 'loop', 'loops', 'goal']],
|
|
45
|
+
['channels', ['slack', 'telegram', 'matrix', 'channels', 'message', 'pairing']],
|
|
46
|
+
['v5', ['sandbox', 'personality', 'migrate', 'hermes', 'openclaw', 'trajectories']],
|
|
47
|
+
['utility', ['browse', 'version', 'completion', 'help', 'export', 'import', 'nodes']],
|
|
48
|
+
];
|
|
49
|
+
|
|
31
50
|
function fit(text, max) {
|
|
32
51
|
if (stringWidth(text) <= max) return text.padEnd(max);
|
|
33
52
|
let lo = 0, hi = text.length;
|
|
@@ -56,38 +75,49 @@ function skillRow({ group, names }) {
|
|
|
56
75
|
return `${group.padEnd(12)} ${tail}`;
|
|
57
76
|
}
|
|
58
77
|
|
|
78
|
+
function subcommandRow([label, verbs]) {
|
|
79
|
+
return `${label.padEnd(12)} ${verbs.join(' · ')}`;
|
|
80
|
+
}
|
|
81
|
+
|
|
59
82
|
export function renderSplashToString(props, opts = {}) {
|
|
60
83
|
const cols = opts.columns || process.stdout.columns || 100;
|
|
61
84
|
const TERM = Math.max(80, cols);
|
|
62
85
|
const PANEL_W = TERM - LMARGIN.length * 2;
|
|
63
|
-
const INNER = PANEL_W - 4;
|
|
86
|
+
const INNER = PANEL_W - 4;
|
|
64
87
|
const SLOTH_W = banner.width;
|
|
65
88
|
const RIGHT_W = Math.max(40, INNER - SLOTH_W - 2);
|
|
66
89
|
|
|
67
90
|
const lines = [];
|
|
68
91
|
|
|
69
|
-
//
|
|
92
|
+
// 1) wordmark
|
|
70
93
|
for (const r of wordmark.rows) lines.push(LMARGIN + r);
|
|
71
94
|
lines.push('');
|
|
72
95
|
|
|
73
|
-
//
|
|
96
|
+
// 2) panel top with inset title
|
|
74
97
|
const versionLabel = ` lazyclaw ${props.version || ''} ·${TITLE} `;
|
|
75
98
|
const dashLeft = '─'.repeat(8);
|
|
76
99
|
const dashRight = '─'.repeat(Math.max(2, PANEL_W - 2 - dashLeft.length - stringWidth(versionLabel)));
|
|
77
100
|
lines.push(`${LMARGIN}╭${dashLeft}${versionLabel}${dashRight}╮`);
|
|
78
101
|
|
|
79
|
-
//
|
|
102
|
+
// 3) right column content (subcommands + tools + skills)
|
|
80
103
|
const { tools = [], skills = [] } = props;
|
|
81
104
|
const right = [];
|
|
105
|
+
right.push('Subcommands');
|
|
106
|
+
for (const g of SUBCOMMAND_GROUPS) right.push(subcommandRow(g));
|
|
107
|
+
right.push('');
|
|
82
108
|
right.push('Available Tools');
|
|
83
|
-
for (const t of tools.slice(0,
|
|
84
|
-
if (tools.length >
|
|
109
|
+
for (const t of tools.slice(0, 14)) right.push(toolRow(t));
|
|
110
|
+
if (tools.length > 14) right.push(`(and ${tools.length - 14} more...)`);
|
|
85
111
|
right.push('');
|
|
86
112
|
right.push('Available Skills');
|
|
87
|
-
|
|
88
|
-
|
|
113
|
+
if (skills.length === 0) right.push('(none installed)');
|
|
114
|
+
else {
|
|
115
|
+
for (const s of skills.slice(0, 8)) right.push(skillRow(s));
|
|
116
|
+
if (skills.length > 8) right.push(`(and ${skills.length - 8} more skill groups...)`);
|
|
117
|
+
}
|
|
89
118
|
right.push('');
|
|
90
|
-
|
|
119
|
+
const subcmdCount = SUBCOMMAND_GROUPS.reduce((n, [, v]) => n + v.length, 0);
|
|
120
|
+
right.push(`${subcmdCount} subcommands · ${tools.length} tool groups · ${skills.length} skills · /help for commands`);
|
|
91
121
|
|
|
92
122
|
const sloth = banner.rows.slice();
|
|
93
123
|
while (sloth.length < right.length) sloth.push(' '.repeat(SLOTH_W));
|
|
@@ -101,7 +131,7 @@ export function renderSplashToString(props, opts = {}) {
|
|
|
101
131
|
lines.push(`${LMARGIN}╰${'─'.repeat(PANEL_W - 2)}╯`);
|
|
102
132
|
lines.push('');
|
|
103
133
|
|
|
104
|
-
//
|
|
134
|
+
// 4) provider / session info
|
|
105
135
|
const { provider, model, trainer = {}, sessionId, cwd } = props;
|
|
106
136
|
const tProv = trainer.provider || provider;
|
|
107
137
|
const tModel = trainer.model || model;
|
|
@@ -111,19 +141,37 @@ export function renderSplashToString(props, opts = {}) {
|
|
|
111
141
|
lines.push('');
|
|
112
142
|
lines.push(`${LMARGIN}Welcome to lazyclaw. Type your message or /help for commands.`);
|
|
113
143
|
lines.push(`${LMARGIN}+ Tip: trainer learns from your Claude Pro subscription at $0.`);
|
|
144
|
+
lines.push('');
|
|
145
|
+
|
|
146
|
+
// 5) bottom border + status bar + border (Hermes-style separator)
|
|
147
|
+
const sep = '─'.repeat(PANEL_W);
|
|
148
|
+
lines.push(LMARGIN + sep);
|
|
149
|
+
const ctx = props.ctxUsed != null && props.ctxTotal != null
|
|
150
|
+
? `[${'░'.repeat(20)}] ${props.ctxUsed}/${props.ctxTotal}`
|
|
151
|
+
: `[${'░'.repeat(20)}] --`;
|
|
152
|
+
lines.push(`${LMARGIN} ${provider} · ${model} | ctx -- | ${ctx} | 0s`);
|
|
153
|
+
lines.push(LMARGIN + sep);
|
|
114
154
|
|
|
115
155
|
return lines.join('\n');
|
|
116
156
|
}
|
|
117
157
|
|
|
118
158
|
export function Splash(props) {
|
|
119
|
-
const
|
|
120
|
-
|
|
121
|
-
const
|
|
159
|
+
const cols = process.stdout.columns || 100;
|
|
160
|
+
const TERM = Math.max(80, cols);
|
|
161
|
+
const PANEL_W = TERM - LMARGIN.length * 2;
|
|
162
|
+
const out = renderSplashToString(props, { columns: cols });
|
|
163
|
+
const lines = out.split('\n');
|
|
164
|
+
const palette = wordmark.palette;
|
|
165
|
+
const gradient = wordmark.gradient;
|
|
166
|
+
|
|
122
167
|
return React.createElement(
|
|
123
168
|
Box,
|
|
124
169
|
{ flexDirection: 'column' },
|
|
125
|
-
lines.map((line, i) =>
|
|
126
|
-
|
|
127
|
-
|
|
170
|
+
lines.map((line, i) => {
|
|
171
|
+
let color;
|
|
172
|
+
if (i < wordmark.height) color = palette[gradient[i] ?? 1];
|
|
173
|
+
else if (i < wordmark.height + 1 + 1 + banner.height) color = theme.fg; // panel + sloth tinted
|
|
174
|
+
return React.createElement(Text, { key: i, color }, line);
|
|
175
|
+
})
|
|
128
176
|
);
|
|
129
177
|
}
|
package/tui/wordmark.mjs
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
|
-
//
|
|
2
|
-
//
|
|
1
|
+
// "Larry 3D"-style LAZYCLAW wordmark — 13 rows × 120 cols, shared between
|
|
2
|
+
// chat splash and launcher. Gradient palette maps each row to one of four
|
|
3
|
+
// warm-orange shades; top rows = brightest, bottom rows = shadow-dark.
|
|
4
|
+
//
|
|
5
|
+
// The string-output renderer (renderSplashToString) emits the raw rows;
|
|
6
|
+
// the ink/launcher color path picks PALETTE[GRADIENT[row]] when ANSI is
|
|
7
|
+
// available.
|
|
8
|
+
|
|
9
|
+
export const PALETTE = [
|
|
10
|
+
'#FFD580', // 0 top — warm white-gold
|
|
11
|
+
'#FFB347', // 1 highlight (current single-tone reference)
|
|
12
|
+
'#E08020', // 2 midtone — amber
|
|
13
|
+
'#A05010', // 3 bottom — burnt shadow
|
|
14
|
+
];
|
|
15
|
+
|
|
16
|
+
// 13 rows; bias toward bottom for shadow depth.
|
|
17
|
+
export const GRADIENT = [0, 0, 0, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3];
|
|
18
|
+
|
|
3
19
|
export const wordmark = {
|
|
4
20
|
rows: [
|
|
5
21
|
" ____ ____ _____ _____ _____ _____ ____ ____ _____ ",
|
|
@@ -18,5 +34,7 @@ export const wordmark = {
|
|
|
18
34
|
],
|
|
19
35
|
width: 120,
|
|
20
36
|
height: 13,
|
|
21
|
-
fg: "#FFB347"
|
|
37
|
+
fg: "#FFB347",
|
|
38
|
+
gradient: GRADIENT,
|
|
39
|
+
palette: PALETTE,
|
|
22
40
|
};
|