terminal-ai-helper 2.3.0 → 2.3.2

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/VERSION CHANGED
@@ -1 +1 @@
1
- 2.3.0
1
+ 2.3.2
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "terminal-ai-helper",
3
- "version": "2.3.0",
3
+ "version": "2.3.2",
4
4
  "description": "The terminal that knows your next command Bash/Zsh suggestions that learn from your own history Offline and private with no account required",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -15,6 +15,12 @@ _tai_prompt() {
15
15
  raw="${raw#"${raw%%[![:space:]]*}"}" # drop the leading indent
16
16
  while [[ "$raw" == [0-9]* ]]; do raw="${raw#?}"; done # drop the history number
17
17
  last_cmd="${raw#"${raw%%[![:space:]]*}"}" # drop the space after it
18
+ # A completion's own space rides the line into the history (`nano ` after a
19
+ # menu choice), and the store strips it — but this shell's next prediction
20
+ # looks the last command up in the sequence table by its exact text, and the
21
+ # table's keys are the stored, stripped rows. Trim here, once per command,
22
+ # so `nano ` predicts what followed `nano` and records the same row either way.
23
+ while [[ "$last_cmd" == *[[:space:]] ]]; do last_cmd="${last_cmd%?}"; done
18
24
  if [[ -n "$last_cmd" && "$last_cmd" != "$_TAI_LAST" ]]; then
19
25
  _TAI_LAST="$last_cmd"
20
26
  # The unit cache pre-loads itself in the background after a command that
@@ -247,12 +253,25 @@ _tai_complete() {
247
253
  # by both loops above — once as the file that is here, once as the line the
248
254
  # history holds — and COMPREPLY holding it twice makes readline print it twice.
249
255
  _tai_reply() {
250
- local c
256
+ local c x
251
257
  # A learned line carrying raw control bytes is not a completion it is this
252
258
  # plugin's promise to never paint: what it would write is escape bytes.
253
259
  [[ "$1" =~ [[:cntrl:]] ]] && return 0
254
- for c in "${COMPREPLY[@]}"; do [[ "$c" == "$1" ]] && return 0; done
255
- COMPREPLY+=("$1")
260
+ c="$1"
261
+ # A completion that leaves the line one bare word is a command waiting for
262
+ # its arguments, and readline's own completion would have written the space
263
+ # between them (`cat tzz_solo `). `-o nospace` took that append away from
264
+ # every entry so a directory's slash could stand alone, so the entries that
265
+ # want the space carry it — measured on a real shell, a match holding a
266
+ # trailing space is inserted verbatim, and the common prefix of matches that
267
+ # disagree past the space is the prefix alone. Three shapes carry none: a
268
+ # directory's slash, which is the path still being typed; a whole learned
269
+ # line, which is the line the user ran, and whose space would ride the next
270
+ # Enter into the history as a row of its own; and a name that already holds
271
+ # a space, which is more than one shell word already.
272
+ if [[ -n "$c" && "$c" != */ && "$c" != *[[:space:]]* ]]; then c="$c "; fi
273
+ for x in "${COMPREPLY[@]}"; do [[ "$x" == "$c" ]] && return 0; done
274
+ COMPREPLY+=("$c")
256
275
  }
257
276
  complete -o nospace -F _tai_complete tai 2>/dev/null
258
277
  # -o default is what makes Tab fall back to readline's own filename completion
@@ -769,6 +769,24 @@ _tai_menu_commit() {
769
769
  # slash from truncating what gets written.
770
770
  (( ${_TAI_MENU_Q[_TAI_MENU_IDX]} )) && { _tai_quote "$entry"; entry="$_TAI_QUOTED" }
771
771
  BUFFER="${BUFFER[1,$(( _TAI_MENU_FROM - 1 ))]}$entry${BUFFER[_TAI_MENU_TO + 1,-1]}"
772
+ # A completion that leaves the line one bare word is a command waiting for its
773
+ # arguments, and the space between them is written for the user — every
774
+ # shell's own completion does this, and readline's half of this plugin always
775
+ # did (`cat tzz_solo `). The report: choosing `nano` out of the menu put
776
+ # `nano` in the line, and the user typed the space by hand, once per line,
777
+ # every time. Three shapes write nothing after them: a directory's slash,
778
+ # which is the path still being typed; a whole learned line, which is the
779
+ # line the user ran, and whose space would ride the next Enter into the
780
+ # history as a row of its own; and a name that already holds a space, whose
781
+ # quoting is the shell word it is.
782
+ [[ "$entry" != */ && "$entry" != *[[:space:]]* ]] && BUFFER+=" "
783
+ # What the commit wrote is the line the user took. Without this, the space a
784
+ # bare-word commit writes is one deletion from the learned line itself, and
785
+ # the loose glimpse answered the very next redraw with the line just taken —
786
+ # `cd tzz_dir ` re-offering `cd tzz_dir` from under the cursor. The same
787
+ # dismiss an Up from a glimpse sets: while the text stands, the list does not
788
+ # spring back, and the next keystroke re-arms it.
789
+ _TAI_MENU_DISMISS="$BUFFER"
772
790
  CURSOR=${#BUFFER}
773
791
  _tai_menu_close
774
792
  }
@@ -114,6 +114,26 @@ _tai_update() {
114
114
  fi
115
115
  return
116
116
  fi
117
+ # The accept echo is the one redraw that paints nothing. When the line is
118
+ # accepted, zsh re-renders it as it will run, and that render fires this
119
+ # hook — which answered it like any keystroke: it ran the query for the
120
+ # line one last time and painted the hint back onto the row the shell was
121
+ # leaving. The report: Enters on an empty prompt stacked gray `cd …` lines
122
+ # that read as commands the user ran, and a scrollback reader believed
123
+ # them. So the accept path raises _TAI_ACCEPT, and this hook takes tai's
124
+ # own paint down and stands aside: the echo shows what was typed, and what
125
+ # tai drew goes down with the line it rode in on. line-init lowers the
126
+ # flag with everything else it resets — the next line paints as usual.
127
+ if (( _TAI_ACCEPT )); then
128
+ _TAI_SUGGESTION=""
129
+ (( _TAI_MENU_IDX )) && _tai_menu_close
130
+ if (( _TAI_DREW )); then
131
+ POSTDISPLAY=""
132
+ region_highlight=()
133
+ _TAI_DREW=0
134
+ fi
135
+ return
136
+ fi
117
137
  local -i ours_was=$_TAI_DREW
118
138
  # What the last widget was decides whether this buffer is typed. The hook
119
139
  # runs after every widget, and the names here are the ones that mean an
@@ -348,10 +368,32 @@ tai-enter() {
348
368
  # A glimpsed menu still swallows the selection; Enter at a disarmed menu is
349
369
  # the line's Enter.
350
370
  if (( _TAI_MENU_IDX )); then _tai_menu_close; POSTDISPLAY=""; region_highlight=(); fi
371
+ # What runs is what was typed, and the echo of it must say so. zsh's final
372
+ # render of the accepted line fires the redraw hook, which would answer it
373
+ # with a fresh query and paint the hint back onto the row being left; the
374
+ # flag stands the hook down for that one render. See _tai_update.
375
+ _TAI_ACCEPT=1
351
376
  zle accept-line
352
377
  }
353
378
  zle -N tai-enter
354
379
 
380
+ # Enter is not the only door to a running line: TAI_NO_MENU=1 leaves ^M on
381
+ # stock accept-line, and so can a user binding of their own. The wrapper
382
+ # raises the same flag tai-enter raises, so the accept echo paints nothing
383
+ # in those shells either. It is registered only while the name is still the
384
+ # builtin — an accept-line another plugin wrapped is theirs, their clear
385
+ # already answers their own hint, and tai-enter raises the flag itself
386
+ # before it calls accept-line by name, so the hook stands down either way.
387
+ typeset -gi _TAI_ACCEPT=0
388
+ tai-accept-line() {
389
+ _TAI_ACCEPT=1
390
+ zle .accept-line
391
+ }
392
+ zle -N tai-accept-line
393
+ case "${widgets[accept-line]:-}" in
394
+ builtin*) zle -N accept-line tai-accept-line ;;
395
+ esac
396
+
355
397
  # Right arrow accepts the suggestion at the end of the line, and moves the
356
398
  # cursor one character anywhere else. Bound straight to tai-accept it took
357
399
  # forward-char away entirely: with a ghost on screen there was then no key left
@@ -560,6 +602,10 @@ _tai_line_init() {
560
602
  # exit hook, and a flag carried into the next line would stand tai down for
561
603
  # every keystroke of it. The hook pair is the truth; this is the belt.
562
604
  _TAI_ISEARCH=0
605
+ # Nor is a line still being accepted: the accept flag stands the redraw
606
+ # hook down for the echo of the line that is leaving, and a new line is
607
+ # painted on again from its first redraw.
608
+ _TAI_ACCEPT=0
563
609
  region_highlight=()
564
610
  _tai_menu_close
565
611
  # The prophecy. _TAI_SEQ answers "what did I run after this", and the fresh
@@ -716,6 +762,12 @@ _tai_preexec() {
716
762
  # resolved in the background write instead, which also means the repo, branch
717
763
  # and cwd all describe the same moment. bash has always done it this way.
718
764
  _TAI_CMD="$1"
765
+ # A completion's own space rides the line into preexec (`nano ` after a menu
766
+ # choice), and the store strips it on the way in — but this shell's next
767
+ # prediction looks the last command up in the sequence table by its exact
768
+ # text, and the table's keys are the stored, stripped rows. Trim here, once
769
+ # per command, so `nano ` predicts what followed `nano`.
770
+ while [[ "$_TAI_CMD" == *[[:space:]] ]]; do _TAI_CMD="${_TAI_CMD%?}"; done
719
771
  # The directory the command was *run from*. A prompt-time $PWD comes after the
720
772
  # command, so for `cd src` the recorded origin was the destination — and the
721
773
  # path-liveness check judged the cd's argument against the place it had just
package/readme.md CHANGED
@@ -38,7 +38,7 @@ exec zsh
38
38
  ✓ bash installed
39
39
 
40
40
  1. Type a few letters — tai finishes the command in grey. → takes it.
41
- 2. Tab opens a menu of what fits. Enter picks; a second Enter runs.
41
+ 2. Tab opens a menu of what fits. Enter picks, space after the command included; a second Enter runs.
42
42
  3. It learns from your history — offline, private, no account.
43
43
 
44
44
  Try it now: type "cd " and watch the grey.