@tiens.nguyen/gu-cli 1.0.686

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 (43) hide show
  1. package/README.md +52 -0
  2. package/agent-model-command.mjs +259 -0
  3. package/agent-model-label.mjs +159 -0
  4. package/clear-state.mjs +149 -0
  5. package/client-expert-api.mjs +736 -0
  6. package/client-expert-run.mjs +892 -0
  7. package/client-expert-setup.mjs +616 -0
  8. package/coding-choice-tags.mjs +69 -0
  9. package/coding-key-prompt.mjs +229 -0
  10. package/coding-provider-setup.mjs +808 -0
  11. package/completed-flush.mjs +105 -0
  12. package/daemon-control.mjs +462 -0
  13. package/device-login.mjs +212 -0
  14. package/doctor-check.mjs +239 -0
  15. package/embed-model-command.mjs +157 -0
  16. package/first-run-steps.mjs +171 -0
  17. package/gonext_agent_chat.py +12299 -0
  18. package/gonext_mlx_embed.py +155 -0
  19. package/gonext_probe_agent.py +93 -0
  20. package/gonext_transcribe.py +130 -0
  21. package/gu-cli.mjs +4930 -0
  22. package/gu-repl.mjs +10326 -0
  23. package/job-pools.mjs +89 -0
  24. package/model-doctor.mjs +1494 -0
  25. package/node-version.mjs +40 -0
  26. package/ollama-setup.mjs +832 -0
  27. package/package.json +100 -0
  28. package/platform-tools.mjs +520 -0
  29. package/poll-errors.mjs +141 -0
  30. package/proxy-command.mjs +165 -0
  31. package/proxy-config.mjs +255 -0
  32. package/proxy-dispatcher.mjs +132 -0
  33. package/proxy-selftest.mjs +234 -0
  34. package/proxy-store.mjs +69 -0
  35. package/rag-job-config.mjs +59 -0
  36. package/rag-selftest.mjs +215 -0
  37. package/s3-setup.mjs +85 -0
  38. package/terminal-copy.mjs +248 -0
  39. package/terminal-hover.mjs +153 -0
  40. package/terminal-layout.mjs +2507 -0
  41. package/terminal-viewport.mjs +602 -0
  42. package/thinking_words.txt +1003 -0
  43. package/version-check.mjs +72 -0
@@ -0,0 +1,153 @@
1
+ /**
2
+ * Interacting with a printed thought block: what the pointer is over, and what a click does.
3
+ *
4
+ * WHY THIS IS ITS OWN MODULE
5
+ * --------------------------
6
+ * This logic lived inside gu-repl.mjs, reading half a dozen module-level things directly —
7
+ * `transcript`, `hoveredThought`, `barPinned()`, `transcriptRows()`. That file has no main
8
+ * guard, so importing it starts a REPL, which meant the hover rules could not be executed by a
9
+ * test at all: the only coverage possible was to REIMPLEMENT them beside the real ones and
10
+ * assert on the copy, plus source-reading to check the two had not drifted.
11
+ *
12
+ * That is backwards for the part of the terminal a pointer touches hundreds of times a minute,
13
+ * and it is the same seam the rest of this codebase already uses where a rule matters:
14
+ * `pickUsableVersion` takes `usable` injected "so the rule is testable without a filesystem",
15
+ * and `refreshJobsForClientView` takes its store calls the same way. This is that, for hover.
16
+ *
17
+ * BEHAVIOUR IS UNCHANGED. Every rule below was moved, not rewritten, and the byte-level tests
18
+ * in tests/hover-repaint.test.mjs still stand behind it as the backstop that says the SEQUENCES
19
+ * are right; these say the DECISIONS are.
20
+ *
21
+ * Hover and click are the same feature from two angles — the pointer marks a block, the click
22
+ * opens it — and they share state: a toggle MOVES rows under a motionless pointer, so it has to
23
+ * invalidate what hover cached. Keeping them apart would mean keeping that dependency implicit.
24
+ */
25
+
26
+ /**
27
+ * A block was toggled and its rows replaced: fix up every position. → the delta, in lines.
28
+ *
29
+ * THE PART WORTH TESTING IS THE ARITHMETIC. Expanding a thought makes it taller, and every
30
+ * block BELOW it in the transcript moves down by exactly that much. Get the shift wrong and the
31
+ * blocks below stay clickable at the rows they used to occupy — so a click lands on the wrong
32
+ * thought, or on nothing, with no error and nothing on screen to explain it.
33
+ *
34
+ * `newEnd` comes from the transcript's replaceRange, which is the only thing that knows how many
35
+ * lines actually landed. Blocks ABOVE are untouched by construction: nothing moved above the
36
+ * block that changed.
37
+ *
38
+ * Mutates in place, because the caller's `thoughtBlocks` array and these objects are the same
39
+ * ones the hit-test reads — returning copies would leave the live state stale.
40
+ */
41
+ export function applyToggleShift(blocks, block, newEnd) {
42
+ const delta = newEnd - block.to;
43
+ block.collapsed = !block.collapsed;
44
+ block.to = newEnd;
45
+ for (const b of blocks ?? []) {
46
+ if (b !== block && b.from > block.from) {
47
+ b.from += delta;
48
+ b.to += delta;
49
+ }
50
+ }
51
+ return delta;
52
+ }
53
+
54
+ /**
55
+ * Make a hover controller. All effects are injected — nothing here knows about a terminal.
56
+ *
57
+ * pinned() → is the bar pinned? Hover is meaningless without a rendered view.
58
+ * transcriptRows() → rows the transcript owns (the scrolling area LESS the live block).
59
+ * blockAtRow(row) → the recorded block under that screen row, or null.
60
+ * paintRows(b, on) → that block's rows, in the hovered or resting colour.
61
+ * replaceRange(f,t,r) → swap those recorded lines; null when the range is gone.
62
+ * repaintSeq(block) → bytes that redraw the block where it already sits ("" if off screen).
63
+ * write(seq) → put bytes on screen.
64
+ * afterPaint() → put the caret back where the user is typing.
65
+ */
66
+ export function createHoverController({
67
+ pinned = () => true,
68
+ transcriptRows = () => 1,
69
+ blockAtRow = () => null,
70
+ paintRows = () => [],
71
+ replaceRange = () => null,
72
+ repaintSeq = () => "",
73
+ write = () => {},
74
+ afterPaint = () => {},
75
+ } = {}) {
76
+ // The block the pointer is currently over, or null. Only ever ONE — highlighting two would
77
+ // say two things are about to happen.
78
+ let hovered = null;
79
+ let lastKey = "";
80
+
81
+ /**
82
+ * The pointer moved to `row`. → true when something was repainted.
83
+ *
84
+ * HIGHLIGHT ONLY. Hovering does not expand: expanding reflows everything below it, and a
85
+ * transcript that rearranges itself as the mouse crosses the screen is unusable. It is also
86
+ * the one thing an in-place repaint cannot express — the block's rows are rewritten where
87
+ * they are, so a block that changed HEIGHT would corrupt every row beneath it.
88
+ */
89
+ function hover(row) {
90
+ if (!pinned()) return false;
91
+
92
+ // A pointer crossing the window sends a report per CELL, and resolving a row to a block
93
+ // wraps the entire transcript — so doing that per report would burn real CPU on a mouse
94
+ // only passing through. The row is the cheap key: nothing can change until it does.
95
+ //
96
+ // …EXCEPT THE LIVE BLOCK'S HEIGHT, which is why that is in the key too. It grows and
97
+ // shrinks as a step's detail lines come and go, and every transcript row above it moves
98
+ // when it does — so a STILL pointer is over a different line than it was, and a row-only
99
+ // key would hold the highlight on the block it used to be over.
100
+ const key = `${row}:${transcriptRows()}`;
101
+ if (key === lastKey) return false;
102
+ lastKey = key;
103
+
104
+ const block = blockAtRow(row);
105
+ if (block === hovered) return false;
106
+ const previous = hovered;
107
+ hovered = block;
108
+
109
+ // Recolour both: the one being left and the one being entered. Same row count either way
110
+ // (only the colour changed), so neither range can move — which is what makes repainting
111
+ // them in place safe.
112
+ let touched = false;
113
+ for (const [b, on] of [[previous, false], [block, true]]) {
114
+ if (!b) continue;
115
+ if (replaceRange(b.from, b.to, paintRows(b, on)) !== null) touched = true;
116
+ }
117
+ if (!touched) return false;
118
+
119
+ // COLOUR ONLY, IN PLACE. The two blocks whose colour just changed are redrawn where they
120
+ // already are; every other row is left untouched. Repainting the whole view here is the
121
+ // #211 bug: it bottom-aligns the transcript and re-saves the output position, so the next
122
+ // printed line lands on rows that already have content.
123
+ let seq = "";
124
+ for (const b of [previous, block]) if (b) seq += repaintSeq(b);
125
+ if (!seq) return false;
126
+ write(seq);
127
+ afterPaint();
128
+ return true;
129
+ }
130
+
131
+ return {
132
+ hover,
133
+ /** The block under the pointer, or null. */
134
+ get hovered() {
135
+ return hovered;
136
+ },
137
+ /**
138
+ * Forget the cached row.
139
+ *
140
+ * Called by anything that MOVES rows under a motionless pointer — a block growing as its
141
+ * prose is appended, or one expanding on a click. Without it the next report at the same
142
+ * row is treated as "nothing changed" and the highlight is stranded on the old block.
143
+ */
144
+ reset() {
145
+ lastKey = "";
146
+ },
147
+ /** Drop the highlight entirely (the view was rebuilt; nothing is under the pointer). */
148
+ clear() {
149
+ hovered = null;
150
+ lastKey = "";
151
+ },
152
+ };
153
+ }