@trawlme/cli 3.2.0 → 3.4.0

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.
@@ -3,47 +3,57 @@
3
3
  * art. Distinct from Clawd's 8-bit lane: Pinch is drawn with full 24-bit
4
4
  * (`\x1b[38;2;r;g;bm` / `\x1b[48;2;r;g;bm`) color blocks, not a fixed palette.
5
5
  *
6
- * The 14×9 cube-grid is packed two grid rows into one terminal row: the
6
+ * The 9×6 cube-grid (#133 mini) is packed two grid rows into one terminal
7
+ * row: the
7
8
  * upper row's color becomes the half-block's foreground, the lower row's
8
9
  * becomes its background, using the upper-half-block glyph '▀' (or '▄' when
9
- * only the lower half is filled). A 9-row grid therefore renders in 5
10
- * terminal rows, 14 columns wide. '.' cells are transparent — no color
10
+ * only the lower half is filled). A 6-row grid therefore renders in 3
11
+ * terminal rows, 9 columns wide. '.' cells are transparent — no color
11
12
  * escape is emitted for that half, so the terminal's own background shows
12
13
  * through.
13
14
  *
14
15
  * Grids + palette are mirrored from trawl_vue
15
16
  * `src/modules/trawl/assets/mascot/_src/pinch.model.mjs` (AVCOLORS +
16
17
  * AVATAR_GRIDS, rev r6f) — no cross-repo import (cli is a standalone npm
17
- * package). Claws are 2×2 'O' blocks at cols 0-1 / 12-13, fully outside the
18
- * body silhouette (on the sides), per r6f.
18
+ * package). Claws are 1-wide 2-tall 'O' blocks at cols 0 / 8, on the SIDES
19
+ * (raised for wave/thumbsup/celebrating/shocked), per the r6f shape.
19
20
  *
20
- * See comes-io/trawl_cli#94, comes-io/trawl_cli#122.
21
+ * State parity (#135): the CLI now carries all 9 canonical AVATAR_STATES
22
+ * from the source model — idle · working · celebrating · thumbsup · confused
23
+ * · wave · heart · sleepy · shocked — with the SAME names (before #135 the
24
+ * CLI shipped 4 states and called `working` "thinking", a name not in the
25
+ * source). Each is a 9×6 mini redraw preserving that state's distinguishing
26
+ * feature.
27
+ *
28
+ * See comes-io/trawl_cli#94, comes-io/trawl_cli#122, comes-io/trawl_cli#135.
21
29
  */
22
- export type PinchState = 'wave' | 'thinking' | 'celebrating' | 'confused';
30
+ export type PinchState = 'idle' | 'working' | 'celebrating' | 'thumbsup' | 'confused' | 'wave' | 'heart' | 'sleepy' | 'shocked';
31
+ /** All 9 canonical states, in the source model's AVATAR_STATES order. */
32
+ export declare const PINCH_STATES: readonly PinchState[];
23
33
  /**
24
34
  * Render Pinch as 24-bit ANSI half-block art for the given state, plus a
25
35
  * one-line caption. Pure — never touches process.env/stdout; callers must
26
36
  * gate on `pinchEnabled()` before printing the result.
27
37
  *
28
- * `frame` is accepted for signature stability but currently unused every
29
- * state's grid is static (see `gridForState`).
38
+ * `frame` only affects `working` (the cyan antenna-tip blip alternates every
39
+ * frame); every other state's grid is static.
30
40
  */
31
41
  export declare function renderPinch(state: PinchState, frame?: number): string;
32
42
  /**
33
43
  * #131 — the ART lines only (no caption), optionally COMPACT: trailing and
34
44
  * leading fully-transparent grid rows are dropped so Pinch takes fewer
35
- * terminal lines (the r6f grids carry an all-'.' bottom row + blank-ish
36
- * antenna padding). Used by the animation loop, where a caption + full
37
- * height would be too heavy for a frame redrawn every ~380ms.
45
+ * terminal lines (some grids carry an all-'.' padding row). Used by the
46
+ * animation loop, where a caption + full height would be too heavy for a
47
+ * frame redrawn every ~380ms. `working` is rendered at frame 0 (blip on).
38
48
  */
39
49
  export declare function renderPinchArt(state: PinchState, opts?: {
40
50
  compact?: boolean;
41
51
  }): string;
42
52
  /**
43
53
  * #131 — frame sequence for the "working" animation shown during long waits
44
- * (the `create` wizard, `--watch`). Reuses the existing r6f state grids: the
45
- * claws pump up (wave → celebrating) and back down, reading as Pinch busily
46
- * waving while it works. No new art — just an order over the grids we have.
54
+ * (the `create` wizard, `--watch`). The claws pump up (working wave →
55
+ * celebrating) and back down, reading as Pinch busily working. No new art —
56
+ * an order over the canonical state grids.
47
57
  */
48
58
  export declare const WORKING_FRAMES: readonly PinchState[];
49
59
  /**
package/dist/lib/pinch.js CHANGED
@@ -3,97 +3,186 @@
3
3
  * art. Distinct from Clawd's 8-bit lane: Pinch is drawn with full 24-bit
4
4
  * (`\x1b[38;2;r;g;bm` / `\x1b[48;2;r;g;bm`) color blocks, not a fixed palette.
5
5
  *
6
- * The 14×9 cube-grid is packed two grid rows into one terminal row: the
6
+ * The 9×6 cube-grid (#133 mini) is packed two grid rows into one terminal
7
+ * row: the
7
8
  * upper row's color becomes the half-block's foreground, the lower row's
8
9
  * becomes its background, using the upper-half-block glyph '▀' (or '▄' when
9
- * only the lower half is filled). A 9-row grid therefore renders in 5
10
- * terminal rows, 14 columns wide. '.' cells are transparent — no color
10
+ * only the lower half is filled). A 6-row grid therefore renders in 3
11
+ * terminal rows, 9 columns wide. '.' cells are transparent — no color
11
12
  * escape is emitted for that half, so the terminal's own background shows
12
13
  * through.
13
14
  *
14
15
  * Grids + palette are mirrored from trawl_vue
15
16
  * `src/modules/trawl/assets/mascot/_src/pinch.model.mjs` (AVCOLORS +
16
17
  * AVATAR_GRIDS, rev r6f) — no cross-repo import (cli is a standalone npm
17
- * package). Claws are 2×2 'O' blocks at cols 0-1 / 12-13, fully outside the
18
- * body silhouette (on the sides), per r6f.
18
+ * package). Claws are 1-wide 2-tall 'O' blocks at cols 0 / 8, on the SIDES
19
+ * (raised for wave/thumbsup/celebrating/shocked), per the r6f shape.
19
20
  *
20
- * See comes-io/trawl_cli#94, comes-io/trawl_cli#122.
21
+ * State parity (#135): the CLI now carries all 9 canonical AVATAR_STATES
22
+ * from the source model — idle · working · celebrating · thumbsup · confused
23
+ * · wave · heart · sleepy · shocked — with the SAME names (before #135 the
24
+ * CLI shipped 4 states and called `working` "thinking", a name not in the
25
+ * source). Each is a 9×6 mini redraw preserving that state's distinguishing
26
+ * feature.
27
+ *
28
+ * See comes-io/trawl_cli#94, comes-io/trawl_cli#122, comes-io/trawl_cli#135.
21
29
  */
22
- /** Grid-char → RGB, ported from AVCOLORS (pinch.model.mjs, rev r6f). */
30
+ /** Grid-char → RGB, ported from AVCOLORS (pinch.model.mjs, rev r6f). 'C'
31
+ * (cyan) is the `working` thinking-blip — not present in any static grid,
32
+ * injected per-frame on the antenna tips. */
23
33
  const PALETTE = {
24
34
  B: [0x29, 0x79, 0xff], // blue — shell
25
35
  O: [0xfb, 0x92, 0x3c], // orange — antennae / claws
26
36
  W: [0xff, 0xff, 0xff], // white — eye whites
27
37
  K: [0x12, 0x30, 0x33], // navy — pupils / mouth / blush-adjacent mouth corner
28
- P: [0xf4, 0x72, 0xb6], // pink — blush
38
+ P: [0xf4, 0x72, 0xb6], // pink — blush / heart-eyes
39
+ C: [0x06, 0xb6, 0xd4], // cyan — `working` thinking-blip on the antenna tips
29
40
  };
30
41
  const TRANSPARENT = '.';
42
+ /** All 9 canonical states, in the source model's AVATAR_STATES order. */
43
+ export const PINCH_STATES = [
44
+ 'idle',
45
+ 'working',
46
+ 'celebrating',
47
+ 'thumbsup',
48
+ 'confused',
49
+ 'wave',
50
+ 'heart',
51
+ 'sleepy',
52
+ 'shocked',
53
+ ];
31
54
  /**
32
- * Explicit per-state 14×9 grids, ported verbatim from trawl_vue's
33
- * AVATAR_GRIDS (pinch.model.mjs, rev r6f) — no derivation/mutation from a
34
- * shared base, so each state stays a straight, auditable copy of its source
35
- * grid. CLI state source grid: wave→wave, thinking→working (a.k.a.
36
- * AVGRID/idle), celebrating→celebrating, confused→confused.
55
+ * Explicit per-state 9×6 grids (#133 mini shape, #135 full state parity).
56
+ * The 14×9 grids were ported from trawl_vue's AVATAR_GRIDS (pinch.model.mjs,
57
+ * rev r6f); these mini redraws preserve each state's feature at a smaller
58
+ * pixel count. Grid layout (cols 0-8, body/shell cols 1-7):
59
+ * row 0 antennae (O at cols 2,6 — spread to 1,7 when drooped)
60
+ * row 1 head top (+ claw at col 0/8 when RAISED)
61
+ * row 2 eyes (+ claw at col 0/8 when RAISED)
62
+ * row 3 head mid
63
+ * row 4 mouth + blush (+ claw at col 0/8 when RESTING)
64
+ * row 5 head bottom (+ claw at col 0/8 when RESTING)
65
+ * Claws are the 1-wide 2-tall O blocks at cols 0/8. Eyes: left = W+K at
66
+ * cols 2-3, right = K+W at cols 5-6 (pupils inward).
37
67
  */
38
68
  const GRIDS = {
39
- wave: [
40
- '....O....O....',
41
- '....O....O....',
42
- '..BBBBBBBBBB..',
43
- '..BWWBBBBWWBOO',
44
- '..BWKBBBBKWBOO',
45
- '..BBBBBBBBBB..',
46
- 'OOBBPKBBKPBB..',
47
- 'OOBBBBKKBBBB..',
48
- '..............',
69
+ // calm resting face, both claws down, normal smile.
70
+ idle: [
71
+ '..O...O..',
72
+ '.BBBBBBB.',
73
+ '.BWKBKWB.',
74
+ '.BBBBBBB.',
75
+ 'OBPKKKPBO',
76
+ 'OBBBBBBBO',
49
77
  ],
50
- // 'thinking' maps to the source's 'working' grid (identical to 'idle').
51
- // The frame param is accepted for signature compatibility but ignored — a
52
- // static working frame rather than an animated blip (#122, simplified;
53
- // the source has no per-frame "thinking" animation to port).
54
- thinking: [
55
- '....O....O....',
56
- '....O....O....',
57
- '..BBBBBBBBBB..',
58
- '..BWWBBBBWWB..',
59
- '..BWKBBBBKWB..',
60
- '..BBBBBBBBBB..',
61
- 'OOBBPKBBKPBBOO',
62
- 'OOBBBBKKBBBBOO',
63
- '..............',
78
+ // idle pose + the cyan thinking-blip on the antenna tips (frame-toggled in
79
+ // `gridForState`) the only animated static state.
80
+ working: [
81
+ '..O...O..',
82
+ '.BBBBBBB.',
83
+ '.BWKBKWB.',
84
+ '.BBBBBBB.',
85
+ 'OBPKKKPBO',
86
+ 'OBBBBBBBO',
64
87
  ],
88
+ // both claws raised (rows 1-2) + a big open mouth.
65
89
  celebrating: [
66
- '....O....O....',
67
- '....O....O....',
68
- '..BBBBBBBBBB..',
69
- 'OOBWWBBBBWWBOO',
70
- 'OOBWKBBBBKWBOO',
71
- '..BBBBBBBBBB..',
72
- '..BBPKKKKPBB..',
73
- '..BBBKKKKBBB..',
74
- '..............',
90
+ '..O...O..',
91
+ 'OBBBBBBBO',
92
+ 'OBWKBKWBO',
93
+ '.BBBBBBB.',
94
+ '.BKKKKKB.',
95
+ '.BBBBBBB.',
96
+ ],
97
+ // right claw raised (rows 1-2) + a thumb pixel poking up above it (row 0,
98
+ // col 8); left claw resting.
99
+ thumbsup: [
100
+ '..O...O.O',
101
+ '.BBBBBBBO',
102
+ '.BWKBKWBO',
103
+ '.BBBBBBB.',
104
+ 'OBPKKKPB.',
105
+ 'OBBBBBBB.',
75
106
  ],
107
+ // antennae drooped + spread, flat mouth (no K), claws resting. A '?' is
108
+ // appended beside the eye line by `renderPinch`.
76
109
  confused: [
77
- '..............',
78
- '...O......O...',
79
- '..BBBBBBBBBB..',
80
- '..BWWBBBBWWB..',
81
- '..BWKBBBBKWB..',
82
- '..BBBBBBBBBB..',
83
- 'OOBBPBBBBPBBOO',
84
- 'OOBBBBKKBBBBOO',
85
- '..............',
110
+ '.O.....O.',
111
+ '.BBBBBBB.',
112
+ '.BWKBKWB.',
113
+ '.BBBBBBB.',
114
+ 'OBPBBBPBO',
115
+ 'OBBBBBBBO',
116
+ ],
117
+ // right claw raised (rows 1-2), left claw resting; base face.
118
+ wave: [
119
+ '..O...O..',
120
+ '.BBBBBBBO',
121
+ '.BWKBKWBO',
122
+ '.BBBBBBB.',
123
+ 'OBPKKKPB.',
124
+ 'OBBBBBBB.',
125
+ ],
126
+ // pink heart-eyes (P replaces the W+K pupils), claws resting, normal smile.
127
+ heart: [
128
+ '..O...O..',
129
+ '.BBBBBBB.',
130
+ '.BPPBPPB.',
131
+ '.BBBBBBB.',
132
+ 'OBPKKKPBO',
133
+ 'OBBBBBBBO',
134
+ ],
135
+ // closed eyes (flat K line, no white), antennae drooped + spread, flat
136
+ // mouth, claws resting — like confused but eyes shut and no '?'.
137
+ sleepy: [
138
+ '.O.....O.',
139
+ '.BBBBBBB.',
140
+ '.BKKBKKB.',
141
+ '.BBBBBBB.',
142
+ 'OBPBBBPBO',
143
+ 'OBBBBBBBO',
144
+ ],
145
+ // both claws raised (rows 1-2) + a small round mouth (single K, row 4) —
146
+ // like celebrating's raise but a startled dot mouth, not the wide smile.
147
+ shocked: [
148
+ '..O...O..',
149
+ 'OBBBBBBBO',
150
+ 'OBWKBKWBO',
151
+ '.BBBBBBB.',
152
+ '.BBBKBBB.',
153
+ '.BBBBBBB.',
86
154
  ],
87
155
  };
88
156
  const CAPTIONS = {
89
- wave: 'Pinch says hi.',
90
- thinking: 'Pinch is thinking…',
157
+ idle: 'Pinch is here.',
158
+ working: 'Pinch is working…',
91
159
  celebrating: 'Pinch is celebrating!',
160
+ thumbsup: 'Pinch approves!',
92
161
  confused: 'Pinch looks confused.',
162
+ wave: 'Pinch says hi.',
163
+ heart: 'Pinch loves it.',
164
+ sleepy: 'Pinch is sleepy…',
165
+ shocked: 'Pinch is shocked!',
93
166
  };
94
- /** Look up the grid for `state`. `frame` is accepted (signature stability
95
- * for `renderPinch`) but unused — every current state's grid is static. */
96
- function gridForState(state, _frame) {
167
+ /** Antenna-tip cells (row 0) for the `working` cyan blip: cols 2 & 6. */
168
+ const ANTENNA_TIP_COLS = [2, 6];
169
+ /** Replace the chars at `indices` in `row` with `ch` — never mutates `row`. */
170
+ function setCells(row, indices, ch) {
171
+ const chars = row.split('');
172
+ for (const i of indices)
173
+ chars[i] = ch;
174
+ return chars.join('');
175
+ }
176
+ /** Look up the grid for `state`. `frame` only affects `working`: on even
177
+ * frames its antenna tips blip cyan (the thinking indicator), on odd frames
178
+ * they stay orange — a 2-frame pulse with no layout shift. Every other
179
+ * state's grid is static and ignores `frame`. */
180
+ function gridForState(state, frame) {
181
+ if (state === 'working' && frame % 2 === 0) {
182
+ const rows = [...GRIDS.working];
183
+ rows[0] = setCells(rows[0], ANTENNA_TIP_COLS, 'C');
184
+ return rows;
185
+ }
97
186
  return GRIDS[state];
98
187
  }
99
188
  const RESET = '\x1b[0m';
@@ -120,7 +209,8 @@ function renderCell(upper, lower) {
120
209
  return `${fgCode(lowerColor)}▄${RESET}`;
121
210
  return `${fgCode(upperColor)}${bgCode(lowerColor)}▀${RESET}`;
122
211
  }
123
- /** Pack a 9-row grid into 5 terminal lines (rows 0-1, 2-3, 4-5, 6-7, 8-blank). */
212
+ /** Pack a grid into terminal lines, 2 grid rows per line (upper=fg, lower=bg).
213
+ * The #133 mini grid is 6 rows → 3 lines. */
124
214
  function renderGrid(rows) {
125
215
  const lines = [];
126
216
  for (let i = 0; i < rows.length; i += 2) {
@@ -139,27 +229,25 @@ function renderGrid(rows) {
139
229
  * one-line caption. Pure — never touches process.env/stdout; callers must
140
230
  * gate on `pinchEnabled()` before printing the result.
141
231
  *
142
- * `frame` is accepted for signature stability but currently unused every
143
- * state's grid is static (see `gridForState`).
232
+ * `frame` only affects `working` (the cyan antenna-tip blip alternates every
233
+ * frame); every other state's grid is static.
144
234
  */
145
235
  export function renderPinch(state, frame = 0) {
146
236
  const grid = gridForState(state, frame);
147
237
  const lines = renderGrid(grid);
148
238
  if (state === 'confused') {
149
- // "beside the art" — a bold '?' to the right of the eye row (grid rows
150
- // 4-5 pack into terminal line index 2, unchanged by the r6f grid — the
151
- // antenna/shell/eye/claw row layout stayed the same, only width + claw
152
- // placement changed).
153
- lines[2] = `${lines[2]} \x1b[1m?${RESET}`;
239
+ // "beside the art" — a bold '?' to the right of the eye row. In the #133
240
+ // mini grid the eyes are grid rows 2-3, which pack into terminal line 1.
241
+ lines[1] = `${lines[1]} \x1b[1m?${RESET}`;
154
242
  }
155
243
  return [...lines, CAPTIONS[state]].join('\n');
156
244
  }
157
245
  /**
158
246
  * #131 — the ART lines only (no caption), optionally COMPACT: trailing and
159
247
  * leading fully-transparent grid rows are dropped so Pinch takes fewer
160
- * terminal lines (the r6f grids carry an all-'.' bottom row + blank-ish
161
- * antenna padding). Used by the animation loop, where a caption + full
162
- * height would be too heavy for a frame redrawn every ~380ms.
248
+ * terminal lines (some grids carry an all-'.' padding row). Used by the
249
+ * animation loop, where a caption + full height would be too heavy for a
250
+ * frame redrawn every ~380ms. `working` is rendered at frame 0 (blip on).
163
251
  */
164
252
  export function renderPinchArt(state, opts = {}) {
165
253
  let grid = gridForState(state, 0);
@@ -175,16 +263,16 @@ export function renderPinchArt(state, opts = {}) {
175
263
  }
176
264
  const lines = renderGrid(grid);
177
265
  if (state === 'confused')
178
- lines[2] = `${lines[2]} \x1b[1m?${RESET}`;
266
+ lines[1] = `${lines[1]} \x1b[1m?${RESET}`;
179
267
  return lines.join('\n');
180
268
  }
181
269
  /**
182
270
  * #131 — frame sequence for the "working" animation shown during long waits
183
- * (the `create` wizard, `--watch`). Reuses the existing r6f state grids: the
184
- * claws pump up (wave → celebrating) and back down, reading as Pinch busily
185
- * waving while it works. No new art — just an order over the grids we have.
271
+ * (the `create` wizard, `--watch`). The claws pump up (working wave →
272
+ * celebrating) and back down, reading as Pinch busily working. No new art —
273
+ * an order over the canonical state grids.
186
274
  */
187
- export const WORKING_FRAMES = ['thinking', 'wave', 'celebrating', 'wave'];
275
+ export const WORKING_FRAMES = ['working', 'wave', 'celebrating', 'wave'];
188
276
  /**
189
277
  * True when it's safe to print Pinch art: a real color-capable interactive
190
278
  * terminal. False under NO_COLOR (https://no-color.org — presence, not
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@trawlme/cli",
3
- "version": "3.2.0",
3
+ "version": "3.4.0",
4
4
  "description": "Trawl CLI — manage scraps from the terminal",
5
5
  "type": "module",
6
6
  "bin": {