lacy 1.8.11 → 1.8.13

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 (109) hide show
  1. package/.claude/settings.local.json +26 -0
  2. package/.github/FUNDING.yml +3 -0
  3. package/.github/ISSUE_TEMPLATE/bug_report.yml +49 -0
  4. package/.github/ISSUE_TEMPLATE/config.yml +5 -0
  5. package/.github/ISSUE_TEMPLATE/feature_request.yml +28 -0
  6. package/.github/PULL_REQUEST_TEMPLATE.md +17 -0
  7. package/.github/SECURITY.md +32 -0
  8. package/.github/assets/logo-horizontal-dark.png +0 -0
  9. package/.github/assets/logo-horizontal-dark.svg +17 -0
  10. package/.github/assets/logo-horizontal.png +0 -0
  11. package/.github/assets/logo-horizontal.svg +17 -0
  12. package/.github/assets/logo.png +0 -0
  13. package/.github/assets/logo.svg +12 -0
  14. package/.github/assets/social-preview.png +0 -0
  15. package/.github/assets/social-preview.svg +50 -0
  16. package/.github/dependabot.yml +21 -0
  17. package/.github/workflows/ci.yml +80 -0
  18. package/.github/workflows/dependabot-auto-merge.yml +32 -0
  19. package/CHANGELOG.md +366 -0
  20. package/CLAUDE.md +340 -0
  21. package/CONTRIBUTING.md +141 -0
  22. package/LICENSE +110 -0
  23. package/README.md +201 -31
  24. package/RELEASING.md +148 -0
  25. package/STYLE.md +202 -0
  26. package/assets/hero.jpeg +0 -0
  27. package/assets/mode-indicators.jpeg +0 -0
  28. package/assets/real-time-indicator.jpeg +0 -0
  29. package/assets/supported-tools.jpeg +0 -0
  30. package/bin/lacy +1028 -0
  31. package/docs/ADDING-BACKENDS.md +124 -0
  32. package/docs/DEVTO-ARTICLE.md +94 -0
  33. package/docs/DOCS.md +68 -0
  34. package/docs/GROWTH-STRATEGY.md +119 -0
  35. package/docs/HN-RESPONSES.md +122 -0
  36. package/docs/LAUNCH-COPY-FINAL.md +105 -0
  37. package/docs/MARKETING.md +411 -0
  38. package/docs/NATURAL_LANGUAGE_DETECTION.md +204 -0
  39. package/docs/UGC_VIDEO_SCRIPT.md +114 -0
  40. package/docs/articles/devto-how-i-made-my-terminal-understand-english.md +117 -0
  41. package/docs/demo-color-transition.gif +0 -0
  42. package/docs/demo-full.gif +0 -0
  43. package/docs/demo-indicator.gif +0 -0
  44. package/docs/launch-thread-may6.sh +158 -0
  45. package/docs/videos/README.md +189 -0
  46. package/docs/videos/generate_frames.py +510 -0
  47. package/docs/videos/generate_frames_v2.py +729 -0
  48. package/docs/videos/generate_short.py +328 -0
  49. package/docs/videos/generate_short_v2.py +526 -0
  50. package/docs/videos/lacy-shell-demo-v2.mp4 +0 -0
  51. package/docs/videos/lacy-shell-demo.mp4 +0 -0
  52. package/docs/videos/lacy-shell-short-v2.mp4 +0 -0
  53. package/docs/videos/lacy-shell-short.mp4 +0 -0
  54. package/install.sh +1009 -0
  55. package/lacy.plugin.bash +75 -0
  56. package/lacy.plugin.fish +43 -0
  57. package/lacy.plugin.zsh +65 -0
  58. package/lib/animations.zsh +3 -0
  59. package/lib/bash/completions.bash +40 -0
  60. package/lib/bash/execute.bash +233 -0
  61. package/lib/bash/init.bash +40 -0
  62. package/lib/bash/keybindings.bash +134 -0
  63. package/lib/bash/prompt.bash +85 -0
  64. package/lib/commands/info.sh +25 -0
  65. package/lib/config.zsh +3 -0
  66. package/lib/constants.zsh +3 -0
  67. package/lib/core/animations.sh +271 -0
  68. package/lib/core/commands.sh +297 -0
  69. package/lib/core/config.sh +340 -0
  70. package/lib/core/constants.sh +366 -0
  71. package/lib/core/context.sh +260 -0
  72. package/lib/core/detection.sh +417 -0
  73. package/lib/core/mcp.sh +741 -0
  74. package/lib/core/modes.sh +123 -0
  75. package/lib/core/preheat.sh +496 -0
  76. package/lib/core/spinner.sh +174 -0
  77. package/lib/core/telemetry.sh +99 -0
  78. package/lib/detection.zsh +3 -0
  79. package/lib/execute.zsh +3 -0
  80. package/lib/fish/config.fish +66 -0
  81. package/lib/fish/detection.fish +90 -0
  82. package/lib/fish/execute.fish +105 -0
  83. package/lib/fish/keybindings.fish +42 -0
  84. package/lib/fish/prompt.fish +30 -0
  85. package/lib/keybindings.zsh +3 -0
  86. package/lib/mcp.zsh +3 -0
  87. package/lib/modes.zsh +3 -0
  88. package/lib/preheat.zsh +3 -0
  89. package/lib/prompt.zsh +3 -0
  90. package/lib/spinner.zsh +3 -0
  91. package/lib/zsh/completions.zsh +60 -0
  92. package/lib/zsh/execute.zsh +294 -0
  93. package/lib/zsh/init.zsh +26 -0
  94. package/lib/zsh/keybindings.zsh +551 -0
  95. package/lib/zsh/prompt.zsh +90 -0
  96. package/package.json +42 -27
  97. package/packages/lacy/README.md +61 -0
  98. package/packages/lacy/commands/info.sh +25 -0
  99. package/{index.mjs → packages/lacy/index.mjs} +247 -20
  100. package/packages/lacy/package-lock.json +71 -0
  101. package/packages/lacy/package.json +42 -0
  102. package/script/release.ts +487 -0
  103. package/squirrel.toml +36 -0
  104. package/tests/test_bash.bash +163 -0
  105. package/tests/test_core.sh +607 -0
  106. package/tests/test_gemini.sh +119 -0
  107. package/tests/test_gemini_mcp.sh +126 -0
  108. package/tests/test_preheat_server.zsh +446 -0
  109. package/uninstall.sh +52 -0
@@ -0,0 +1,60 @@
1
+ #!/usr/bin/env zsh
2
+
3
+ # ZSH tab completion for the `lacy` CLI
4
+ # Sourced by lib/zsh/init.zsh after all core modules are loaded
5
+
6
+ _lacy_complete() {
7
+ local -a commands
8
+ commands=(
9
+ 'setup:Interactive settings'
10
+ 'install:Install Lacy Shell'
11
+ 'uninstall:Remove Lacy Shell'
12
+ 'update:Pull latest changes'
13
+ 'reinstall:Fresh installation'
14
+ 'status:Show installation status'
15
+ 'info:Show basic information'
16
+ 'doctor:Diagnose common issues'
17
+ 'config:Show or edit configuration'
18
+ 'new:Clear saved session'
19
+ 'resume:Show saved session info'
20
+ 'logs:Show recent agent query log'
21
+ 'changelog:Show latest release notes'
22
+ 'completions:Print shell completion script'
23
+ 'version:Show version'
24
+ 'help:Show help'
25
+ )
26
+
27
+ local -a tool_names
28
+ tool_names=(lash claude opencode gemini codex custom auto)
29
+
30
+ case "${words[2]}" in
31
+ config)
32
+ local -a sub
33
+ sub=('show:Print config' 'edit:Open in $EDITOR' 'path:Print config path')
34
+ _describe 'config subcommand' sub
35
+ ;;
36
+ logs)
37
+ local -a sub
38
+ sub=('--clear:Clear the log' '--count:Print entry count')
39
+ _describe 'logs option' sub
40
+ ;;
41
+ tool)
42
+ case "${words[3]}" in
43
+ set) _describe 'tool name' tool_names ;;
44
+ *)
45
+ local -a sub
46
+ sub=('set:Set active tool' 'list:List available tools')
47
+ _describe 'tool subcommand' sub
48
+ ;;
49
+ esac
50
+ ;;
51
+ completions)
52
+ _describe 'shell' '(zsh bash)'
53
+ ;;
54
+ *)
55
+ _describe 'lacy command' commands
56
+ ;;
57
+ esac
58
+ }
59
+
60
+ compdef _lacy_complete lacy 2>/dev/null || true
@@ -0,0 +1,294 @@
1
+ #!/usr/bin/env zsh
2
+
3
+ # Command execution logic for Lacy Shell
4
+
5
+ # Pending internal command (set by slash-command handler, dispatched by precmd)
6
+ LACY_SHELL_PENDING_CMD=""
7
+
8
+ # Smart accept-line widget that handles agent queries
9
+ lacy_shell_smart_accept_line() {
10
+ # If Lacy Shell is disabled, use normal accept-line
11
+ if [[ "$LACY_SHELL_ENABLED" != true ]]; then
12
+ zle .accept-line
13
+ return
14
+ fi
15
+
16
+ local input="$BUFFER"
17
+
18
+ # Skip empty commands — also dismiss any ghost text suggestion
19
+ if [[ -z "$input" ]]; then
20
+ LACY_SHELL_SUGGESTION=""
21
+ zle .accept-line
22
+ return
23
+ fi
24
+
25
+ # Intercept slash-prefixed session commands (/new, /reset, /clear, /resume)
26
+ local _slashcmd="$input"
27
+ _slashcmd="${_slashcmd#"${_slashcmd%%[^[:space:]]*}"}"
28
+ case "$_slashcmd" in
29
+ /new|/reset|/clear|/resume)
30
+ local _slash_hist="${input//\\/\\\\}"
31
+ print -s -- "$_slash_hist"
32
+ fc -AI 2>/dev/null
33
+ if [[ "$_slashcmd" == "/resume" ]]; then
34
+ LACY_SHELL_PENDING_CMD="session_resume"
35
+ else
36
+ LACY_SHELL_PENDING_CMD="session_new"
37
+ fi
38
+ BUFFER=""
39
+ zle .accept-line
40
+ return
41
+ ;;
42
+ esac
43
+
44
+ # Classify using centralized detection (handles whitespace trimming internally)
45
+ local classification
46
+ classification=$(lacy_shell_classify_input "$input")
47
+
48
+ case "$classification" in
49
+ "neutral")
50
+ zle .accept-line
51
+ return
52
+ ;;
53
+ "shell")
54
+ # Trim input to check for ! bypass
55
+ local trimmed="$input"
56
+ trimmed="${trimmed#"${trimmed%%[^[:space:]]*}"}"
57
+
58
+ if [[ "$trimmed" == !* ]]; then
59
+ # Strip the ! prefix, keep everything after it
60
+ trimmed="${trimmed#!}"
61
+ BUFFER="$trimmed"
62
+ fi
63
+
64
+ # Handle "exit" explicitly: in shell mode pass through to builtin,
65
+ # in auto/agent mode quit lacy shell
66
+ local first_word="${trimmed%% *}"
67
+ if [[ "$first_word" == "exit" && "$LACY_SHELL_CURRENT_MODE" != "shell" ]]; then
68
+ lacy_shell_quit
69
+ return
70
+ fi
71
+
72
+ # In auto mode, flag commands with NL markers as reroute candidates.
73
+ # Explicit "mode shell" should never re-route.
74
+ if [[ "$LACY_SHELL_CURRENT_MODE" == "auto" ]] && lacy_shell_has_nl_markers "$trimmed"; then
75
+ LACY_SHELL_REROUTE_CANDIDATE="$trimmed"
76
+ else
77
+ LACY_SHELL_REROUTE_CANDIDATE=""
78
+ fi
79
+
80
+ # Record command for terminal context (agent will see it on next query)
81
+ _lacy_ctx_mark_command "$BUFFER"
82
+
83
+ zle .accept-line
84
+ return
85
+ ;;
86
+ "agent")
87
+ # Strip @ agent bypass prefix if present
88
+ local agent_input="$input"
89
+ local _at_trimmed="${agent_input#"${agent_input%%[^[:space:]]*}"}"
90
+ if [[ "$_at_trimmed" == @* ]]; then
91
+ agent_input="${_at_trimmed#@}"
92
+ agent_input="${agent_input#"${agent_input%%[^[:space:]]*}"}"
93
+ fi
94
+
95
+ # Add to history before clearing buffer.
96
+ # Double backslashes before print -s: ZSH's print processes \X escape
97
+ # sequences even with -s, so "Google\ Chrome" becomes "Google Chrome".
98
+ # Doubling (\ → \\) makes print convert \\ → \, preserving the original.
99
+ local _hist_input="${input//\\/\\\\}"
100
+ print -s -- "$_hist_input"
101
+ # Flush to HISTFILE immediately — needed for INC_APPEND_HISTORY / SHARE_HISTORY users,
102
+ # since the subsequent empty-buffer accept-line doesn't trigger a file write.
103
+ fc -AI 2>/dev/null
104
+
105
+ # Defer agent execution to precmd — output produced inside a ZLE
106
+ # widget (after zle .accept-line) confuses ZLE's cursor tracking,
107
+ # causing the prompt to overwrite short (one-line) results.
108
+ LACY_SHELL_PENDING_QUERY="$agent_input"
109
+ BUFFER=""
110
+ zle .accept-line
111
+ ;;
112
+ esac
113
+ }
114
+
115
+ # Disable input interception (emergency mode)
116
+ lacy_shell_disable_interception() {
117
+ echo "🚨 Disabling Lacy Shell input interception"
118
+ zle -A .accept-line accept-line
119
+ echo "✅ Normal shell behavior restored"
120
+ echo " Run 'lacy_shell_enable_interception' to re-enable"
121
+ }
122
+
123
+ # Re-enable input interception
124
+ lacy_shell_enable_interception() {
125
+ echo "🔄 Re-enabling Lacy Shell input interception"
126
+ zle -N accept-line lacy_shell_smart_accept_line
127
+ echo "✅ Lacy Shell features restored"
128
+ }
129
+
130
+ # lacy_shell_execute_agent is in lib/core/commands.sh
131
+
132
+ # Precmd hook - called before each prompt
133
+ lacy_shell_precmd() {
134
+ # Capture exit code immediately — must be the first line
135
+ local last_exit=$?
136
+
137
+ # Track exit code for terminal context (only for real shell commands)
138
+ _lacy_ctx_on_precmd $last_exit
139
+
140
+ # Ensure terminal state is clean (safety net for interrupted spinners / agent tools)
141
+ printf '\e[?25h' # Cursor visible
142
+ printf '\e[?7h' # Line wrapping enabled
143
+
144
+ # Don't run if disabled or quitting
145
+ if [[ "$LACY_SHELL_ENABLED" != true || "$LACY_SHELL_QUITTING" == true ]]; then
146
+ LACY_SHELL_REROUTE_CANDIDATE=""
147
+ return
148
+ fi
149
+
150
+ # Clear any previous ghost text suggestion
151
+ LACY_SHELL_SUGGESTION=""
152
+
153
+ # Check reroute candidate: if the command failed with a non-signal exit
154
+ # code (< 128), set ghost text suggestion to re-try via agent with @ prefix.
155
+ if [[ -n "$LACY_SHELL_REROUTE_CANDIDATE" ]]; then
156
+ local candidate="$LACY_SHELL_REROUTE_CANDIDATE"
157
+ LACY_SHELL_REROUTE_CANDIDATE=""
158
+ if (( last_exit != 0 && last_exit < LACY_SIGNAL_EXIT_THRESHOLD )); then
159
+ LACY_SHELL_SUGGESTION="@ ${candidate}"
160
+ fi
161
+ fi
162
+ # Handle deferred quit triggered by Ctrl-D without letting EOF propagate
163
+ if [[ "$LACY_SHELL_DEFER_QUIT" == true ]]; then
164
+ LACY_SHELL_DEFER_QUIT=false
165
+ LACY_SHELL_REROUTE_CANDIDATE=""
166
+ lacy_shell_quit
167
+ return
168
+ fi
169
+ # Handle pending internal commands (from slash-prefixed session commands)
170
+ if [[ -n "$LACY_SHELL_PENDING_CMD" ]]; then
171
+ local _cmd="$LACY_SHELL_PENDING_CMD"
172
+ LACY_SHELL_PENDING_CMD=""
173
+ case "$_cmd" in
174
+ session_new) lacy_session_new ;;
175
+ session_resume) lacy_session_resume ;;
176
+ esac
177
+ fi
178
+
179
+ # Handle pending agent query (deferred from ZLE widget for clean cursor tracking)
180
+ if [[ -n "$LACY_SHELL_PENDING_QUERY" ]]; then
181
+ local pending="$LACY_SHELL_PENDING_QUERY"
182
+ LACY_SHELL_PENDING_QUERY=""
183
+ # Restore query text on the prompt block above.
184
+ # accept-line cleared the buffer (to prevent shell execution), so the
185
+ # prompt was displayed with no input text. Move up over the entire prompt
186
+ # (which may span multiple lines), clear it, and reprint with the query.
187
+ local _expanded_ps1
188
+ _expanded_ps1=$(print -Pn "$LACY_SHELL_BASE_PS1")
189
+ local _prompt_lines=1
190
+ local _tmp="$_expanded_ps1"
191
+ while [[ "$_tmp" == *$'\n'* ]]; do
192
+ _tmp="${_tmp#*$'\n'}"
193
+ (( _prompt_lines++ ))
194
+ done
195
+ # Move up to start of prompt block, clear to end of screen
196
+ printf "\e[${_prompt_lines}A\e[J"
197
+ # Reprint full prompt with agent-colored indicator + query text
198
+ print -Pn "${LACY_SHELL_BASE_PS1}%F{${LACY_COLOR_AGENT}}${LACY_INDICATOR_CHAR}%f "
199
+ printf '%s\n' "$pending"
200
+ lacy_shell_execute_agent "$pending"
201
+ fi
202
+
203
+ # If a Ctrl-C message is currently displayed, skip redraw to preserve it
204
+ if [[ -n "$LACY_SHELL_MESSAGE_JOB_PID" ]] && kill -0 "$LACY_SHELL_MESSAGE_JOB_PID" 2>/dev/null; then
205
+ return
206
+ fi
207
+ # Update prompt with current mode
208
+ lacy_shell_update_prompt
209
+ }
210
+
211
+ # Quit lacy shell function
212
+ lacy_shell_quit() {
213
+ # Disable Lacy Shell immediately
214
+ LACY_SHELL_ENABLED=false
215
+ LACY_SHELL_QUITTING=true
216
+ unset LACY_SHELL_ACTIVE
217
+
218
+ echo ""
219
+ lacy_print_color "$LACY_COLOR_NEUTRAL" "$LACY_MSG_QUIT"
220
+ echo ""
221
+
222
+ # CRITICAL: Remove precmd hooks FIRST to prevent redrawing
223
+ precmd_functions=(${precmd_functions:#lacy_shell_precmd})
224
+ precmd_functions=(${precmd_functions:#lacy_shell_update_prompt})
225
+
226
+ # Disable input interception (only if ZLE is active)
227
+ if [[ -n "$ZLE_VERSION" ]]; then
228
+ zle -A .accept-line accept-line 2>/dev/null
229
+ fi
230
+
231
+ # Comprehensive terminal reset sequence
232
+ # Reset all terminal attributes and clear any scroll regions
233
+ # Avoid full terminal reset (\033c) because it can cause prompt systems to redraw unpredictably
234
+ echo -ne "\033[0m" # Reset all attributes
235
+ echo -ne "\033[r" # Reset scroll region to full screen
236
+ echo -ne "\033[?7h" # Enable line wrapping
237
+ echo -ne "\033[?25h" # Ensure cursor is visible
238
+ echo -ne "\033[?1049l" # Exit alternate screen if active
239
+ echo -ne "\033[1;1H" # Move to top-left
240
+ echo -ne "\033[J" # Clear from cursor to end of screen
241
+
242
+ # Stop any preheated servers
243
+ lacy_preheat_cleanup
244
+
245
+ # Run cleanup
246
+ lacy_shell_cleanup
247
+
248
+ # Prepare for prompt display if not in ZLE
249
+ if [[ -z "$ZLE_VERSION" ]]; then
250
+ print -r -- ""
251
+ fi
252
+
253
+ # Unset aliases and function overrides
254
+ unalias ask mode tool spinner quit_lacy quit stop disable_lacy enable_lacy 2>/dev/null
255
+ unfunction lacy 2>/dev/null
256
+
257
+ # Define a `lacy` function so user can re-enter by typing `lacy`
258
+ local _ldir="$LACY_SHELL_DIR"
259
+ eval "lacy() {
260
+ if [[ \$# -eq 0 ]]; then
261
+ unfunction lacy 2>/dev/null
262
+ LACY_SHELL_LOADED=false
263
+ source \"${_ldir}/lacy.plugin.zsh\"
264
+ else
265
+ command lacy \"\$@\"
266
+ fi
267
+ }"
268
+
269
+ # Restore original prompt
270
+ lacy_shell_restore_prompt
271
+
272
+ # Print newline and trigger prompt display
273
+ echo ""
274
+ if [[ -n "$ZLE_VERSION" ]]; then
275
+ zle -I 2>/dev/null
276
+ zle -R 2>/dev/null
277
+ zle reset-prompt 2>/dev/null || true
278
+ fi
279
+ }
280
+
281
+ # lacy_shell_mode, lacy_shell_tool, lacy_shell_spinner, lacy_shell_clear_conversation,
282
+ # lacy_shell_show_conversation, and lacy() are in lib/core/commands.sh
283
+
284
+ # Aliases
285
+ alias ask="lacy_shell_query_agent"
286
+ alias mode="lacy_shell_mode"
287
+ alias tool="lacy_shell_tool"
288
+ alias spinner="lacy_shell_spinner"
289
+ alias quit_lacy="lacy_shell_quit"
290
+ alias quit="lacy_shell_quit"
291
+ alias stop="lacy_shell_quit"
292
+
293
+ alias disable_lacy="lacy_shell_disable_interception"
294
+ alias enable_lacy="lacy_shell_enable_interception"
@@ -0,0 +1,26 @@
1
+ #!/usr/bin/env zsh
2
+
3
+ # ZSH adapter init — sources shared core + ZSH-specific modules
4
+
5
+ # Shell type is already set by lacy.plugin.zsh before sourcing this file.
6
+ # LACY_SHELL_TYPE="zsh"
7
+ # _LACY_ARR_OFFSET=1
8
+
9
+ # Source shared core modules
10
+ source "$LACY_SHELL_DIR/lib/core/constants.sh"
11
+ source "$LACY_SHELL_DIR/lib/core/config.sh"
12
+ source "$LACY_SHELL_DIR/lib/core/modes.sh"
13
+ source "$LACY_SHELL_DIR/lib/core/animations.sh"
14
+ source "$LACY_SHELL_DIR/lib/core/spinner.sh"
15
+ source "$LACY_SHELL_DIR/lib/core/mcp.sh"
16
+ source "$LACY_SHELL_DIR/lib/core/preheat.sh"
17
+ source "$LACY_SHELL_DIR/lib/core/context.sh"
18
+ source "$LACY_SHELL_DIR/lib/core/detection.sh"
19
+ source "$LACY_SHELL_DIR/lib/core/commands.sh"
20
+ source "$LACY_SHELL_DIR/lib/core/telemetry.sh"
21
+
22
+ # Source ZSH-specific adapter modules
23
+ source "$LACY_SHELL_DIR/lib/zsh/keybindings.zsh"
24
+ source "$LACY_SHELL_DIR/lib/zsh/prompt.zsh"
25
+ source "$LACY_SHELL_DIR/lib/zsh/execute.zsh"
26
+ source "$LACY_SHELL_DIR/lib/zsh/completions.zsh"