appydave-tools 0.70.0 → 0.71.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.
- checksums.yaml +4 -4
- data/.claude/commands/brainstorming-agent.md +227 -0
- data/.claude/commands/cli-test.md +251 -0
- data/.claude/commands/dev.md +234 -0
- data/.claude/commands/po.md +227 -0
- data/.claude/commands/progress.md +51 -0
- data/.claude/commands/uat.md +321 -0
- data/.rubocop.yml +9 -0
- data/AGENTS.md +43 -0
- data/CHANGELOG.md +12 -0
- data/CLAUDE.md +26 -3
- data/README.md +15 -0
- data/bin/dam +21 -1
- data/bin/jump.rb +29 -0
- data/bin/subtitle_processor.rb +54 -1
- data/bin/zsh_history.rb +846 -0
- data/docs/README.md +162 -69
- data/docs/architecture/cli/exe-bin-convention.md +434 -0
- data/docs/architecture/cli-patterns.md +631 -0
- data/docs/architecture/gpt-context/gpt-context-architecture.md +325 -0
- data/docs/architecture/gpt-context/gpt-context-implementation-guide.md +419 -0
- data/docs/architecture/gpt-context/gpt-context-vision.md +179 -0
- data/docs/architecture/testing/testing-patterns.md +762 -0
- data/docs/backlog.md +120 -0
- data/docs/cli-tests/FR-3-jump-location-tool.md +515 -0
- data/docs/specs/fr-002-gpt-context-help-system.md +265 -0
- data/docs/specs/fr-003-jump-location-tool.md +779 -0
- data/docs/specs/zsh-history-tool.md +820 -0
- data/docs/uat/FR-3-jump-location-tool.md +741 -0
- data/exe/jump +11 -0
- data/exe/{subtitle_manager → subtitle_processor} +1 -1
- data/exe/zsh_history +11 -0
- data/lib/appydave/tools/configuration/openai.rb +1 -1
- data/lib/appydave/tools/dam/file_helper.rb +28 -0
- data/lib/appydave/tools/dam/project_listing.rb +4 -30
- data/lib/appydave/tools/dam/s3_operations.rb +2 -1
- data/lib/appydave/tools/dam/ssd_status.rb +226 -0
- data/lib/appydave/tools/dam/status.rb +3 -51
- data/lib/appydave/tools/jump/cli.rb +561 -0
- data/lib/appydave/tools/jump/commands/add.rb +52 -0
- data/lib/appydave/tools/jump/commands/base.rb +43 -0
- data/lib/appydave/tools/jump/commands/generate.rb +153 -0
- data/lib/appydave/tools/jump/commands/remove.rb +58 -0
- data/lib/appydave/tools/jump/commands/report.rb +214 -0
- data/lib/appydave/tools/jump/commands/update.rb +42 -0
- data/lib/appydave/tools/jump/commands/validate.rb +54 -0
- data/lib/appydave/tools/jump/config.rb +233 -0
- data/lib/appydave/tools/jump/formatters/base.rb +48 -0
- data/lib/appydave/tools/jump/formatters/json_formatter.rb +19 -0
- data/lib/appydave/tools/jump/formatters/paths_formatter.rb +21 -0
- data/lib/appydave/tools/jump/formatters/table_formatter.rb +183 -0
- data/lib/appydave/tools/jump/location.rb +134 -0
- data/lib/appydave/tools/jump/path_validator.rb +47 -0
- data/lib/appydave/tools/jump/search.rb +230 -0
- data/lib/appydave/tools/subtitle_processor/transcript.rb +51 -0
- data/lib/appydave/tools/version.rb +1 -1
- data/lib/appydave/tools/zsh_history/command.rb +37 -0
- data/lib/appydave/tools/zsh_history/config.rb +235 -0
- data/lib/appydave/tools/zsh_history/filter.rb +184 -0
- data/lib/appydave/tools/zsh_history/formatter.rb +75 -0
- data/lib/appydave/tools/zsh_history/parser.rb +101 -0
- data/lib/appydave/tools.rb +25 -0
- data/package.json +1 -1
- metadata +51 -4
data/bin/zsh_history.rb
ADDED
|
@@ -0,0 +1,846 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
# ZSH History Tool - Parse, filter, and clean ZSH history
|
|
5
|
+
|
|
6
|
+
$LOAD_PATH.unshift(File.expand_path('../lib', __dir__))
|
|
7
|
+
|
|
8
|
+
require 'appydave/tools'
|
|
9
|
+
|
|
10
|
+
# ZSH History CLI - Parse, filter, and clean ZSH history
|
|
11
|
+
class ZshHistoryCLI
|
|
12
|
+
def initialize
|
|
13
|
+
@commands = {
|
|
14
|
+
'help' => method(:help_command),
|
|
15
|
+
'show' => method(:show_command),
|
|
16
|
+
'stats' => method(:stats_command),
|
|
17
|
+
'search' => method(:search_command),
|
|
18
|
+
'purge' => method(:purge_command),
|
|
19
|
+
'config' => method(:config_command)
|
|
20
|
+
}
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
|
24
|
+
def run
|
|
25
|
+
command = ARGV[0]
|
|
26
|
+
|
|
27
|
+
# Handle --version and -v flags
|
|
28
|
+
if ['--version', '-v'].include?(command)
|
|
29
|
+
puts "zsh_history v#{Appydave::Tools::VERSION}"
|
|
30
|
+
puts 'Part of appydave-tools gem'
|
|
31
|
+
exit
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Handle --help and -h flags
|
|
35
|
+
if ['--help', '-h'].include?(command)
|
|
36
|
+
show_main_help
|
|
37
|
+
exit
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
if command.nil?
|
|
41
|
+
puts 'ZSH History - Parse, filter, and manage shell history'
|
|
42
|
+
puts "Version: #{Appydave::Tools::VERSION}"
|
|
43
|
+
puts ''
|
|
44
|
+
puts 'Usage: zsh_history [command] [options]'
|
|
45
|
+
puts ''
|
|
46
|
+
puts 'Commands:'
|
|
47
|
+
puts ' zsh_history show # Display wanted commands'
|
|
48
|
+
puts ' zsh_history stats # Show statistics'
|
|
49
|
+
puts ' zsh_history search <pattern> # Search history'
|
|
50
|
+
puts ' zsh_history purge # Rewrite history file (careful!)'
|
|
51
|
+
puts ' zsh_history config # Manage configuration/profiles'
|
|
52
|
+
puts ''
|
|
53
|
+
puts "Run 'zsh_history help' for more information."
|
|
54
|
+
exit
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
if @commands.key?(command)
|
|
58
|
+
@commands[command].call(ARGV[1..])
|
|
59
|
+
else
|
|
60
|
+
puts "Unknown command: #{command}"
|
|
61
|
+
puts ''
|
|
62
|
+
puts 'Available commands: show, stats, search, purge, config, help'
|
|
63
|
+
puts ''
|
|
64
|
+
puts "Run 'zsh_history help' for detailed information."
|
|
65
|
+
exit 1
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
# rubocop:enable Metrics/MethodLength, Metrics/AbcSize
|
|
69
|
+
|
|
70
|
+
private
|
|
71
|
+
|
|
72
|
+
# ============================================================
|
|
73
|
+
# HELP COMMAND
|
|
74
|
+
# ============================================================
|
|
75
|
+
|
|
76
|
+
# rubocop:disable Metrics/MethodLength, Metrics/CyclomaticComplexity
|
|
77
|
+
def help_command(args)
|
|
78
|
+
topic = args[0]
|
|
79
|
+
|
|
80
|
+
case topic
|
|
81
|
+
when 'show'
|
|
82
|
+
show_show_help
|
|
83
|
+
when 'stats'
|
|
84
|
+
show_stats_help
|
|
85
|
+
when 'search'
|
|
86
|
+
show_search_help
|
|
87
|
+
when 'purge'
|
|
88
|
+
show_purge_help
|
|
89
|
+
when 'config'
|
|
90
|
+
show_config_help
|
|
91
|
+
when 'profiles'
|
|
92
|
+
show_profiles_help
|
|
93
|
+
when 'patterns'
|
|
94
|
+
show_patterns_help
|
|
95
|
+
when 'workflow'
|
|
96
|
+
show_workflow_help
|
|
97
|
+
when nil
|
|
98
|
+
show_main_help
|
|
99
|
+
else
|
|
100
|
+
puts "Unknown help topic: #{topic}"
|
|
101
|
+
puts ''
|
|
102
|
+
puts 'Available help topics:'
|
|
103
|
+
puts ' zsh_history help show # Display filtered commands'
|
|
104
|
+
puts ' zsh_history help stats # Show statistics'
|
|
105
|
+
puts ' zsh_history help search # Search history'
|
|
106
|
+
puts ' zsh_history help purge # Rewrite history file'
|
|
107
|
+
puts ' zsh_history help config # Configuration management'
|
|
108
|
+
puts ' zsh_history help profiles # Profile system'
|
|
109
|
+
puts ' zsh_history help patterns # Include/exclude pattern system'
|
|
110
|
+
puts ' zsh_history help workflow # Typical usage workflow'
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
# rubocop:enable Metrics/MethodLength, Metrics/CyclomaticComplexity
|
|
114
|
+
|
|
115
|
+
# rubocop:disable Metrics/MethodLength
|
|
116
|
+
def show_main_help
|
|
117
|
+
puts <<~HELP
|
|
118
|
+
ZSH History - Parse, filter, and manage shell history
|
|
119
|
+
|
|
120
|
+
Usage: zsh_history [command] [options]
|
|
121
|
+
|
|
122
|
+
Commands:
|
|
123
|
+
show Display wanted commands (read-only)
|
|
124
|
+
stats Show statistics about your history
|
|
125
|
+
search <pattern> Search history with regex pattern
|
|
126
|
+
purge Rewrite history file (removes unwanted)
|
|
127
|
+
config Manage configuration and profiles
|
|
128
|
+
help [topic] Show help information
|
|
129
|
+
|
|
130
|
+
Quick Examples:
|
|
131
|
+
zsh_history show # Display wanted commands
|
|
132
|
+
zsh_history show --days 7 # Last 7 days only
|
|
133
|
+
zsh_history show --profile crash-recovery # Use specific profile
|
|
134
|
+
zsh_history stats # Show statistics
|
|
135
|
+
zsh_history search docker # Find docker commands
|
|
136
|
+
zsh_history config init # Create config files
|
|
137
|
+
|
|
138
|
+
Global Options:
|
|
139
|
+
-p, --profile NAME Use named profile for patterns
|
|
140
|
+
-d, --days N Only show last N days
|
|
141
|
+
|
|
142
|
+
Help Topics:
|
|
143
|
+
zsh_history help show # Display options
|
|
144
|
+
zsh_history help stats # Statistics options
|
|
145
|
+
zsh_history help search # Search options
|
|
146
|
+
zsh_history help purge # Rewrite history file
|
|
147
|
+
zsh_history help config # Configuration management
|
|
148
|
+
zsh_history help profiles # Profile system
|
|
149
|
+
zsh_history help patterns # How patterns work
|
|
150
|
+
zsh_history help workflow # Typical usage workflow
|
|
151
|
+
|
|
152
|
+
How It Works:
|
|
153
|
+
Commands are categorized into three groups:
|
|
154
|
+
- WANTED: Useful commands to keep (git commit, docker, rake, etc.)
|
|
155
|
+
- UNWANTED: Noise to remove (ls, cd, typos, output lines)
|
|
156
|
+
- UNSURE: Commands that don't match any pattern
|
|
157
|
+
|
|
158
|
+
Patterns can be customized via profiles. See 'zsh_history help profiles'.
|
|
159
|
+
|
|
160
|
+
For more information: https://github.com/appydave/appydave-tools
|
|
161
|
+
HELP
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
def show_show_help
|
|
165
|
+
puts <<~HELP
|
|
166
|
+
Show Command - Display filtered commands (read-only)
|
|
167
|
+
|
|
168
|
+
Usage: zsh_history show [options]
|
|
169
|
+
|
|
170
|
+
Options:
|
|
171
|
+
-d, --days N Only show last N days
|
|
172
|
+
-u, --unsure Show only unsure commands (for debugging patterns)
|
|
173
|
+
-a, --all Show ALL commands (no filtering)
|
|
174
|
+
-v, --verbose Show which pattern matched each command
|
|
175
|
+
-p, --profile NAME Use named profile for patterns
|
|
176
|
+
-o, --output PATH Write output to file instead of stdout
|
|
177
|
+
-f, --file PATH Use different history file (default: ~/.zsh_history)
|
|
178
|
+
|
|
179
|
+
Examples:
|
|
180
|
+
zsh_history show # Show wanted commands
|
|
181
|
+
zsh_history show --days 7 # Last 7 days
|
|
182
|
+
zsh_history show --unsure # Show only unsure commands
|
|
183
|
+
zsh_history show --verbose # Show matching patterns
|
|
184
|
+
zsh_history show --all # Show everything unfiltered
|
|
185
|
+
zsh_history show -o history.txt # Write to file
|
|
186
|
+
zsh_history show --profile file-exploration # Use different profile
|
|
187
|
+
|
|
188
|
+
Output Format:
|
|
189
|
+
2025-12-13 10:30:45 git commit -m "Add feature"
|
|
190
|
+
2025-12-13 10:31:02 docker build .
|
|
191
|
+
|
|
192
|
+
Verbose Output:
|
|
193
|
+
2025-12-13 10:30:45 [WANTED: ^git commit] git commit -m "Add feature"
|
|
194
|
+
2025-12-13 10:31:02 [WANTED: ^docker ] docker build .
|
|
195
|
+
|
|
196
|
+
See Also:
|
|
197
|
+
zsh_history help patterns # Understand the filtering system
|
|
198
|
+
zsh_history help purge # Actually rewrite history file
|
|
199
|
+
HELP
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
def show_stats_help
|
|
203
|
+
puts <<~HELP
|
|
204
|
+
Stats Command - Show history statistics
|
|
205
|
+
|
|
206
|
+
Usage: zsh_history stats [options]
|
|
207
|
+
|
|
208
|
+
Options:
|
|
209
|
+
-d, --days N Only analyze last N days
|
|
210
|
+
-f, --file PATH Use different history file
|
|
211
|
+
|
|
212
|
+
Examples:
|
|
213
|
+
zsh_history stats # Full history stats
|
|
214
|
+
zsh_history stats --days 7 # Last 7 days only
|
|
215
|
+
zsh_history stats --days 30 # Last 30 days
|
|
216
|
+
|
|
217
|
+
Output:
|
|
218
|
+
ZSH History Statistics
|
|
219
|
+
==================================================
|
|
220
|
+
Total commands: 8265
|
|
221
|
+
Wanted: 2693 (32.6%)
|
|
222
|
+
Unwanted: 2610 (31.6%)
|
|
223
|
+
Unsure: 2962 (35.8%)
|
|
224
|
+
|
|
225
|
+
Date range: 2025-08-24 to 2025-12-13 (111 days)
|
|
226
|
+
|
|
227
|
+
Use Cases:
|
|
228
|
+
- See how much noise is in your history
|
|
229
|
+
- Track history size over time
|
|
230
|
+
- Decide if you need to clean up
|
|
231
|
+
HELP
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
def show_search_help
|
|
235
|
+
puts <<~HELP
|
|
236
|
+
Search Command - Search history with regex
|
|
237
|
+
|
|
238
|
+
Usage: zsh_history search <pattern> [options]
|
|
239
|
+
|
|
240
|
+
Options:
|
|
241
|
+
-d, --days N Only search last N days
|
|
242
|
+
-a, --all Search ALL commands (not just wanted)
|
|
243
|
+
-f, --file PATH Use different history file
|
|
244
|
+
|
|
245
|
+
Pattern:
|
|
246
|
+
Uses Ruby regex (case-insensitive by default)
|
|
247
|
+
|
|
248
|
+
Examples:
|
|
249
|
+
zsh_history search docker # Find docker commands
|
|
250
|
+
zsh_history search "git.*main" # Git commands with 'main'
|
|
251
|
+
zsh_history search dam # Find DAM tool usage
|
|
252
|
+
zsh_history search claude # Find Claude CLI usage
|
|
253
|
+
zsh_history search "npm|yarn|bun" # Any JS package manager
|
|
254
|
+
|
|
255
|
+
With Date Filter:
|
|
256
|
+
zsh_history search docker --days 7 # Docker commands this week
|
|
257
|
+
|
|
258
|
+
Search All (including unwanted):
|
|
259
|
+
zsh_history search ls --all # Even though 'ls' is unwanted
|
|
260
|
+
HELP
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
def show_patterns_help
|
|
264
|
+
puts <<~HELP
|
|
265
|
+
Pattern System - How commands are categorized
|
|
266
|
+
|
|
267
|
+
Commands are matched against regex patterns in this order:
|
|
268
|
+
1. EXCLUDE patterns checked first (marks as UNWANTED)
|
|
269
|
+
2. INCLUDE patterns checked second (marks as WANTED)
|
|
270
|
+
3. No match = UNSURE
|
|
271
|
+
|
|
272
|
+
EXCLUDE Patterns (noise removal):
|
|
273
|
+
^[a-z]$ Single letter typos
|
|
274
|
+
^[a-z]{2}$ Two letter typos
|
|
275
|
+
^ls$, ^ls - Directory listings
|
|
276
|
+
^pwd$, ^clear$ Basic navigation
|
|
277
|
+
^cd$, ^cd ..$ Directory changes
|
|
278
|
+
^git status$ Quick git checks (not commits)
|
|
279
|
+
^git diff$, ^git log$
|
|
280
|
+
^gs$, ^gd$, ^gl$ Git aliases
|
|
281
|
+
^history History commands
|
|
282
|
+
^which, ^type Command lookups
|
|
283
|
+
^cat, ^head, ^tail File viewing
|
|
284
|
+
^zsh: command not found Error messages
|
|
285
|
+
|
|
286
|
+
INCLUDE Patterns (valuable commands):
|
|
287
|
+
^git commit Commits (not status/diff)
|
|
288
|
+
^git push, ^git add
|
|
289
|
+
^docker Docker commands
|
|
290
|
+
^claude Claude CLI
|
|
291
|
+
^dam DAM tool
|
|
292
|
+
^rake, ^bundle Ruby development
|
|
293
|
+
^bun, ^npm run JS development
|
|
294
|
+
^brew install Package installation
|
|
295
|
+
^j[a-z] Jump aliases (jad, jfli, etc.)
|
|
296
|
+
|
|
297
|
+
UNSURE:
|
|
298
|
+
Commands matching neither list need manual review.
|
|
299
|
+
Use --unsure flag to include them in output.
|
|
300
|
+
|
|
301
|
+
Examples:
|
|
302
|
+
'vim file.txt' -> UNSURE (not in either list)
|
|
303
|
+
'git status' -> UNWANTED (in exclude list)
|
|
304
|
+
'git commit -m "x"' -> WANTED (in include list)
|
|
305
|
+
'ls -la' -> UNWANTED (matches ^ls -)
|
|
306
|
+
'docker build .' -> WANTED (matches ^docker )
|
|
307
|
+
HELP
|
|
308
|
+
end
|
|
309
|
+
|
|
310
|
+
def show_workflow_help
|
|
311
|
+
puts <<~HELP
|
|
312
|
+
Typical Workflow - How to use this tool
|
|
313
|
+
|
|
314
|
+
1. CHECK STATS FIRST
|
|
315
|
+
See how much noise is in your history:
|
|
316
|
+
|
|
317
|
+
$ zsh_history stats
|
|
318
|
+
Total: 8265, Wanted: 32.6%, Unwanted: 31.6%, Unsure: 35.8%
|
|
319
|
+
|
|
320
|
+
2. REVIEW WHAT WOULD BE KEPT
|
|
321
|
+
Preview the filtered output:
|
|
322
|
+
|
|
323
|
+
$ zsh_history show --days 30
|
|
324
|
+
|
|
325
|
+
3. CHECK UNSURE COMMANDS
|
|
326
|
+
See what's not being categorized:
|
|
327
|
+
|
|
328
|
+
$ zsh_history show --unsure --days 7
|
|
329
|
+
|
|
330
|
+
4. SEARCH FOR SPECIFIC COMMANDS
|
|
331
|
+
Find commands you need:
|
|
332
|
+
|
|
333
|
+
$ zsh_history search docker
|
|
334
|
+
$ zsh_history search "git.*feature"
|
|
335
|
+
|
|
336
|
+
5. DRY RUN FIRST
|
|
337
|
+
Preview what purge would do:
|
|
338
|
+
|
|
339
|
+
$ zsh_history purge --days 90 --dry-run
|
|
340
|
+
|
|
341
|
+
6. PURGE HISTORY (CAREFUL!)
|
|
342
|
+
Only when you're confident:
|
|
343
|
+
|
|
344
|
+
$ zsh_history purge --days 90
|
|
345
|
+
|
|
346
|
+
This creates a backup first:
|
|
347
|
+
~/.zsh_history.backup.20251213-103045
|
|
348
|
+
|
|
349
|
+
Use Cases:
|
|
350
|
+
- After a terminal crash, find what you were doing
|
|
351
|
+
- Clean up history before sharing screen
|
|
352
|
+
- Remove noise accumulated over months
|
|
353
|
+
- Find that docker command from last week
|
|
354
|
+
HELP
|
|
355
|
+
end
|
|
356
|
+
|
|
357
|
+
def show_purge_help
|
|
358
|
+
puts <<~HELP
|
|
359
|
+
Purge Command - Rewrite history file (DANGEROUS!)
|
|
360
|
+
|
|
361
|
+
Removes unwanted commands from your history file permanently.
|
|
362
|
+
|
|
363
|
+
Usage: zsh_history purge [options]
|
|
364
|
+
|
|
365
|
+
Options:
|
|
366
|
+
-d, --days N Only keep last N days
|
|
367
|
+
-u, --unsure Include unsure commands (keep more)
|
|
368
|
+
--dry-run Preview what would be removed
|
|
369
|
+
-f, --file PATH Use different history file
|
|
370
|
+
|
|
371
|
+
Safety Features:
|
|
372
|
+
1. Creates timestamped backup before writing:
|
|
373
|
+
~/.zsh_history.backup.20251213-103045
|
|
374
|
+
|
|
375
|
+
2. Refuses if keeping < 10% of commands:
|
|
376
|
+
"This seems too aggressive"
|
|
377
|
+
|
|
378
|
+
3. Shows count before/after
|
|
379
|
+
|
|
380
|
+
Examples:
|
|
381
|
+
# Preview first with show
|
|
382
|
+
zsh_history show --days 90
|
|
383
|
+
|
|
384
|
+
# Then purge
|
|
385
|
+
zsh_history purge --days 90
|
|
386
|
+
|
|
387
|
+
# Keep unsure commands too
|
|
388
|
+
zsh_history purge --days 90 --unsure
|
|
389
|
+
|
|
390
|
+
# Dry run (preview only)
|
|
391
|
+
zsh_history purge --days 90 --dry-run
|
|
392
|
+
|
|
393
|
+
Recovery:
|
|
394
|
+
If something goes wrong, restore from backup:
|
|
395
|
+
|
|
396
|
+
$ cp ~/.zsh_history.backup.20251213-103045 ~/.zsh_history
|
|
397
|
+
$ exec zsh # Reload shell
|
|
398
|
+
|
|
399
|
+
WARNING:
|
|
400
|
+
- This permanently modifies your history file
|
|
401
|
+
- The backup is your only recovery option
|
|
402
|
+
- Test with 'show' first to preview
|
|
403
|
+
- Consider keeping unsure commands (--unsure)
|
|
404
|
+
HELP
|
|
405
|
+
end
|
|
406
|
+
|
|
407
|
+
def show_config_help
|
|
408
|
+
puts <<~HELP
|
|
409
|
+
Config Command - Manage configuration and profiles
|
|
410
|
+
|
|
411
|
+
Usage: zsh_history config [subcommand]
|
|
412
|
+
|
|
413
|
+
Subcommands:
|
|
414
|
+
(none) Show configuration status
|
|
415
|
+
init Create default config files
|
|
416
|
+
list List available profiles
|
|
417
|
+
path Show config directory path
|
|
418
|
+
|
|
419
|
+
Examples:
|
|
420
|
+
zsh_history config # Show status
|
|
421
|
+
zsh_history config init # Create default config
|
|
422
|
+
zsh_history config list # List profiles
|
|
423
|
+
|
|
424
|
+
Config Location:
|
|
425
|
+
~/.config/appydave/zsh_history/
|
|
426
|
+
|
|
427
|
+
Config Structure:
|
|
428
|
+
config.txt - Settings (default_profile=crash-recovery)
|
|
429
|
+
base_exclude.txt - Patterns always excluded (typos, output)
|
|
430
|
+
profiles/
|
|
431
|
+
crash-recovery/
|
|
432
|
+
exclude.txt - Profile-specific excludes
|
|
433
|
+
include.txt - Profile-specific includes
|
|
434
|
+
|
|
435
|
+
See Also:
|
|
436
|
+
zsh_history help profiles # How profiles work
|
|
437
|
+
zsh_history help patterns # Pattern format
|
|
438
|
+
HELP
|
|
439
|
+
end
|
|
440
|
+
|
|
441
|
+
def show_profiles_help
|
|
442
|
+
puts <<~HELP
|
|
443
|
+
Profile System - Scenario-specific pattern sets
|
|
444
|
+
|
|
445
|
+
Profiles allow different include/exclude patterns for different use cases.
|
|
446
|
+
The same command might be "wanted" in one scenario but "noise" in another.
|
|
447
|
+
|
|
448
|
+
How It Works:
|
|
449
|
+
1. base_exclude.txt is ALWAYS applied (typos, output lines, errors)
|
|
450
|
+
2. Profile adds additional exclude/include patterns
|
|
451
|
+
3. Patterns are simple regex, one per line
|
|
452
|
+
|
|
453
|
+
Built-in Profile: crash-recovery
|
|
454
|
+
Use case: Find what you were working on when terminal crashed
|
|
455
|
+
Excludes: ls, cd, git status (navigation noise)
|
|
456
|
+
Includes: git commit, docker, rake (actual work)
|
|
457
|
+
|
|
458
|
+
Using Profiles:
|
|
459
|
+
zsh_history show --profile crash-recovery
|
|
460
|
+
zsh_history stats --profile crash-recovery
|
|
461
|
+
zsh_history purge --profile crash-recovery
|
|
462
|
+
|
|
463
|
+
Default Profile:
|
|
464
|
+
Set in ~/.config/appydave/zsh_history/config.txt:
|
|
465
|
+
default_profile=crash-recovery
|
|
466
|
+
|
|
467
|
+
When set, profile is used automatically without --profile flag.
|
|
468
|
+
|
|
469
|
+
Creating Custom Profiles:
|
|
470
|
+
1. Create directory: ~/.config/appydave/zsh_history/profiles/my-profile/
|
|
471
|
+
2. Add exclude.txt with patterns to exclude
|
|
472
|
+
3. Add include.txt with patterns to include
|
|
473
|
+
4. Use: zsh_history show --profile my-profile
|
|
474
|
+
|
|
475
|
+
Example Profile: file-exploration
|
|
476
|
+
exclude.txt:
|
|
477
|
+
^git
|
|
478
|
+
^docker
|
|
479
|
+
^rake
|
|
480
|
+
include.txt:
|
|
481
|
+
^cat
|
|
482
|
+
^head
|
|
483
|
+
^tail
|
|
484
|
+
^less
|
|
485
|
+
^vim
|
|
486
|
+
^nano
|
|
487
|
+
|
|
488
|
+
Pattern Format:
|
|
489
|
+
- One regex per line
|
|
490
|
+
- Lines starting with # are comments
|
|
491
|
+
- Blank lines ignored
|
|
492
|
+
- Case-insensitive matching
|
|
493
|
+
- ^ anchors to start of command
|
|
494
|
+
HELP
|
|
495
|
+
end
|
|
496
|
+
# rubocop:enable Metrics/MethodLength
|
|
497
|
+
|
|
498
|
+
# ============================================================
|
|
499
|
+
# SHOW COMMAND
|
|
500
|
+
# ============================================================
|
|
501
|
+
|
|
502
|
+
# rubocop:disable Metrics/AbcSize
|
|
503
|
+
def show_command(args)
|
|
504
|
+
options = parse_common_options(args)
|
|
505
|
+
|
|
506
|
+
parser_instance = Appydave::Tools::ZshHistory::Parser.new(options[:history_path])
|
|
507
|
+
commands = parser_instance.parse
|
|
508
|
+
|
|
509
|
+
if commands.empty?
|
|
510
|
+
puts "No commands found in #{options[:history_path]}"
|
|
511
|
+
exit
|
|
512
|
+
end
|
|
513
|
+
|
|
514
|
+
filter = Appydave::Tools::ZshHistory::Filter.new(profile: options[:profile])
|
|
515
|
+
result = filter.apply(commands, days: options[:days])
|
|
516
|
+
|
|
517
|
+
formatter = Appydave::Tools::ZshHistory::Formatter.new
|
|
518
|
+
|
|
519
|
+
output = if options[:all]
|
|
520
|
+
formatter.format_commands(commands, verbose: options[:verbose])
|
|
521
|
+
elsif options[:unsure]
|
|
522
|
+
formatter.format_commands(result.unsure.sort_by(&:timestamp), verbose: options[:verbose])
|
|
523
|
+
else
|
|
524
|
+
formatter.format_commands(result.wanted.sort_by(&:timestamp), verbose: options[:verbose])
|
|
525
|
+
end
|
|
526
|
+
|
|
527
|
+
write_output(output, options[:output])
|
|
528
|
+
end
|
|
529
|
+
# rubocop:enable Metrics/AbcSize
|
|
530
|
+
|
|
531
|
+
# ============================================================
|
|
532
|
+
# PURGE COMMAND
|
|
533
|
+
# ============================================================
|
|
534
|
+
|
|
535
|
+
# rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
|
536
|
+
def purge_command(args)
|
|
537
|
+
options = parse_common_options(args)
|
|
538
|
+
|
|
539
|
+
parser_instance = Appydave::Tools::ZshHistory::Parser.new(options[:history_path])
|
|
540
|
+
commands = parser_instance.parse
|
|
541
|
+
|
|
542
|
+
if commands.empty?
|
|
543
|
+
puts "No commands found in #{options[:history_path]}"
|
|
544
|
+
exit
|
|
545
|
+
end
|
|
546
|
+
|
|
547
|
+
filter = Appydave::Tools::ZshHistory::Filter.new(profile: options[:profile])
|
|
548
|
+
result = filter.apply(commands, days: options[:days])
|
|
549
|
+
|
|
550
|
+
commands_to_write = result.wanted
|
|
551
|
+
commands_to_write += result.unsure if options[:unsure]
|
|
552
|
+
|
|
553
|
+
if commands_to_write.size < commands.size * 0.1
|
|
554
|
+
puts "Warning: Would only keep #{commands_to_write.size} of #{commands.size} commands (< 10%)"
|
|
555
|
+
puts 'This seems too aggressive. Use --days to be more selective or check your patterns.'
|
|
556
|
+
exit 1
|
|
557
|
+
end
|
|
558
|
+
|
|
559
|
+
if options[:dry_run]
|
|
560
|
+
puts "DRY RUN - Would keep #{commands_to_write.size} of #{commands.size} commands"
|
|
561
|
+
puts " Wanted: #{result.wanted.size}"
|
|
562
|
+
puts " Unsure: #{result.unsure.size}#{options[:unsure] ? ' (included)' : ' (excluded)'}"
|
|
563
|
+
puts " Unwanted: #{result.unwanted.size} (removed)"
|
|
564
|
+
puts ''
|
|
565
|
+
puts "Run without --dry-run to actually rewrite #{options[:history_path]}"
|
|
566
|
+
else
|
|
567
|
+
formatter = Appydave::Tools::ZshHistory::Formatter.new
|
|
568
|
+
formatter.write_history(commands_to_write, options[:history_path])
|
|
569
|
+
end
|
|
570
|
+
end
|
|
571
|
+
# rubocop:enable Metrics/MethodLength, Metrics/AbcSize
|
|
572
|
+
|
|
573
|
+
# ============================================================
|
|
574
|
+
# STATS COMMAND
|
|
575
|
+
# ============================================================
|
|
576
|
+
|
|
577
|
+
# rubocop:disable Metrics/AbcSize
|
|
578
|
+
def stats_command(args)
|
|
579
|
+
options = parse_common_options(args)
|
|
580
|
+
|
|
581
|
+
parser_instance = Appydave::Tools::ZshHistory::Parser.new(options[:history_path])
|
|
582
|
+
commands = parser_instance.parse
|
|
583
|
+
|
|
584
|
+
if commands.empty?
|
|
585
|
+
puts "No commands found in #{options[:history_path]}"
|
|
586
|
+
exit
|
|
587
|
+
end
|
|
588
|
+
|
|
589
|
+
filter = Appydave::Tools::ZshHistory::Filter.new(profile: options[:profile])
|
|
590
|
+
result = filter.apply(commands, days: options[:days])
|
|
591
|
+
|
|
592
|
+
date_range = nil
|
|
593
|
+
unless commands.empty?
|
|
594
|
+
sorted = commands.sort_by(&:timestamp)
|
|
595
|
+
date_range = {
|
|
596
|
+
from: sorted.first.formatted_datetime('%Y-%m-%d'),
|
|
597
|
+
to: sorted.last.formatted_datetime('%Y-%m-%d'),
|
|
598
|
+
days: ((sorted.last.timestamp - sorted.first.timestamp) / (24 * 60 * 60)).round
|
|
599
|
+
}
|
|
600
|
+
end
|
|
601
|
+
|
|
602
|
+
formatter = Appydave::Tools::ZshHistory::Formatter.new
|
|
603
|
+
puts formatter.format_stats(result.stats, date_range: date_range)
|
|
604
|
+
end
|
|
605
|
+
# rubocop:enable Metrics/AbcSize
|
|
606
|
+
|
|
607
|
+
# ============================================================
|
|
608
|
+
# SEARCH COMMAND
|
|
609
|
+
# ============================================================
|
|
610
|
+
|
|
611
|
+
def search_command(args)
|
|
612
|
+
pattern = args.shift
|
|
613
|
+
show_search_usage_and_exit if pattern.nil? || pattern.start_with?('-')
|
|
614
|
+
|
|
615
|
+
options = parse_common_options(args)
|
|
616
|
+
commands = load_and_filter_commands(options)
|
|
617
|
+
matches = find_matches(commands, pattern, options)
|
|
618
|
+
|
|
619
|
+
exit_with_no_matches(pattern) if matches.empty?
|
|
620
|
+
|
|
621
|
+
formatter = Appydave::Tools::ZshHistory::Formatter.new
|
|
622
|
+
puts formatter.format_commands(matches.sort_by(&:timestamp), verbose: options[:verbose])
|
|
623
|
+
end
|
|
624
|
+
|
|
625
|
+
def show_search_usage_and_exit
|
|
626
|
+
puts 'Usage: zsh_history search <pattern> [options]'
|
|
627
|
+
puts ''
|
|
628
|
+
puts 'Examples:'
|
|
629
|
+
puts ' zsh_history search docker'
|
|
630
|
+
puts ' zsh_history search "git.*main"'
|
|
631
|
+
puts ' zsh_history search claude --days 7'
|
|
632
|
+
exit 1
|
|
633
|
+
end
|
|
634
|
+
|
|
635
|
+
def load_and_filter_commands(options)
|
|
636
|
+
parser_instance = Appydave::Tools::ZshHistory::Parser.new(options[:history_path])
|
|
637
|
+
commands = parser_instance.parse
|
|
638
|
+
if commands.empty?
|
|
639
|
+
puts "No commands found in #{options[:history_path]}"
|
|
640
|
+
exit
|
|
641
|
+
end
|
|
642
|
+
{ commands: commands, result: Appydave::Tools::ZshHistory::Filter.new(profile: options[:profile]).apply(commands, days: options[:days]) }
|
|
643
|
+
end
|
|
644
|
+
|
|
645
|
+
def find_matches(data, pattern, options)
|
|
646
|
+
grep_pattern = Regexp.new(pattern, Regexp::IGNORECASE)
|
|
647
|
+
if options[:all]
|
|
648
|
+
data[:commands].select { |cmd| cmd.text.match?(grep_pattern) }
|
|
649
|
+
else
|
|
650
|
+
data[:result].wanted.select { |cmd| cmd.text.match?(grep_pattern) } +
|
|
651
|
+
data[:result].unsure.select { |cmd| cmd.text.match?(grep_pattern) }
|
|
652
|
+
end
|
|
653
|
+
end
|
|
654
|
+
|
|
655
|
+
def exit_with_no_matches(pattern)
|
|
656
|
+
puts "No matches found for: #{pattern}"
|
|
657
|
+
exit
|
|
658
|
+
end
|
|
659
|
+
|
|
660
|
+
# ============================================================
|
|
661
|
+
# CONFIG COMMAND
|
|
662
|
+
# ============================================================
|
|
663
|
+
|
|
664
|
+
def config_command(args)
|
|
665
|
+
subcommand = args[0]
|
|
666
|
+
|
|
667
|
+
case subcommand
|
|
668
|
+
when 'init'
|
|
669
|
+
config_init
|
|
670
|
+
when 'list'
|
|
671
|
+
config_list
|
|
672
|
+
when 'path'
|
|
673
|
+
config_path
|
|
674
|
+
when nil, 'status'
|
|
675
|
+
config_status
|
|
676
|
+
else
|
|
677
|
+
puts "Unknown config subcommand: #{subcommand}"
|
|
678
|
+
puts ''
|
|
679
|
+
puts 'Usage: zsh_history config [subcommand]'
|
|
680
|
+
puts ''
|
|
681
|
+
puts 'Subcommands:'
|
|
682
|
+
puts ' zsh_history config # Show config status'
|
|
683
|
+
puts ' zsh_history config init # Create default config files'
|
|
684
|
+
puts ' zsh_history config list # List available profiles'
|
|
685
|
+
puts ' zsh_history config path # Show config directory path'
|
|
686
|
+
end
|
|
687
|
+
end
|
|
688
|
+
|
|
689
|
+
def config_status
|
|
690
|
+
config = Appydave::Tools::ZshHistory::Config.new
|
|
691
|
+
|
|
692
|
+
puts 'ZSH History Configuration'
|
|
693
|
+
puts '=' * 50
|
|
694
|
+
puts ''
|
|
695
|
+
puts "Config path: #{config.config_path}"
|
|
696
|
+
puts "Configured: #{config.configured? ? 'Yes' : 'No'}"
|
|
697
|
+
puts ''
|
|
698
|
+
|
|
699
|
+
if config.configured?
|
|
700
|
+
display_profiles(config)
|
|
701
|
+
else
|
|
702
|
+
puts "Run 'zsh_history config init' to create default configuration."
|
|
703
|
+
end
|
|
704
|
+
end
|
|
705
|
+
|
|
706
|
+
def display_profiles(config)
|
|
707
|
+
puts 'Profiles:'
|
|
708
|
+
profiles = config.available_profiles
|
|
709
|
+
if profiles.empty?
|
|
710
|
+
puts ' (none)'
|
|
711
|
+
else
|
|
712
|
+
profiles.each do |profile|
|
|
713
|
+
default_marker = profile == config.default_profile ? ' (default)' : ''
|
|
714
|
+
puts " - #{profile}#{default_marker}"
|
|
715
|
+
end
|
|
716
|
+
end
|
|
717
|
+
|
|
718
|
+
puts ''
|
|
719
|
+
puts "Default profile: #{config.default_profile || '(none)'}"
|
|
720
|
+
end
|
|
721
|
+
|
|
722
|
+
def config_init
|
|
723
|
+
config_path = Appydave::Tools::ZshHistory::Config.create_default_config
|
|
724
|
+
puts "Created default configuration at: #{config_path}"
|
|
725
|
+
puts ''
|
|
726
|
+
puts 'Files created:'
|
|
727
|
+
puts ' config.txt - Default profile setting'
|
|
728
|
+
puts ' base_exclude.txt - Patterns always excluded'
|
|
729
|
+
puts ' profiles/'
|
|
730
|
+
puts ' crash-recovery/'
|
|
731
|
+
puts ' exclude.txt - Profile-specific excludes'
|
|
732
|
+
puts ' include.txt - Profile-specific includes'
|
|
733
|
+
puts ''
|
|
734
|
+
puts 'Edit these files to customize your patterns.'
|
|
735
|
+
end
|
|
736
|
+
|
|
737
|
+
def config_list
|
|
738
|
+
config = Appydave::Tools::ZshHistory::Config.new
|
|
739
|
+
|
|
740
|
+
unless config.configured?
|
|
741
|
+
puts 'No configuration found.'
|
|
742
|
+
puts "Run 'zsh_history config init' to create default configuration."
|
|
743
|
+
return
|
|
744
|
+
end
|
|
745
|
+
|
|
746
|
+
profiles = config.available_profiles
|
|
747
|
+
if profiles.empty?
|
|
748
|
+
puts 'No profiles found.'
|
|
749
|
+
else
|
|
750
|
+
puts 'Available profiles:'
|
|
751
|
+
puts ''
|
|
752
|
+
profiles.each do |profile|
|
|
753
|
+
default_marker = profile == config.default_profile ? ' (default)' : ''
|
|
754
|
+
puts " #{profile}#{default_marker}"
|
|
755
|
+
description = load_profile_description(config.config_path, profile)
|
|
756
|
+
puts " #{description}" if description
|
|
757
|
+
puts ''
|
|
758
|
+
end
|
|
759
|
+
end
|
|
760
|
+
end
|
|
761
|
+
|
|
762
|
+
def load_profile_description(config_path, profile)
|
|
763
|
+
desc_file = File.join(config_path, 'profiles', profile, 'description.txt')
|
|
764
|
+
return nil unless File.exist?(desc_file)
|
|
765
|
+
|
|
766
|
+
lines = File.readlines(desc_file).map(&:strip).reject(&:empty?)
|
|
767
|
+
# Return first line after the title (the "Use when:" line)
|
|
768
|
+
lines[1] if lines.size > 1
|
|
769
|
+
end
|
|
770
|
+
|
|
771
|
+
def config_path
|
|
772
|
+
puts Appydave::Tools::ZshHistory::Config::DEFAULT_CONFIG_PATH
|
|
773
|
+
end
|
|
774
|
+
|
|
775
|
+
# ============================================================
|
|
776
|
+
# OUTPUT HELPERS
|
|
777
|
+
# ============================================================
|
|
778
|
+
|
|
779
|
+
def write_output(content, output_path)
|
|
780
|
+
if output_path
|
|
781
|
+
File.write(output_path, content)
|
|
782
|
+
puts "Written to: #{output_path}"
|
|
783
|
+
else
|
|
784
|
+
puts content
|
|
785
|
+
end
|
|
786
|
+
end
|
|
787
|
+
|
|
788
|
+
# ============================================================
|
|
789
|
+
# OPTION PARSING
|
|
790
|
+
# ============================================================
|
|
791
|
+
|
|
792
|
+
# rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
|
793
|
+
def parse_common_options(args)
|
|
794
|
+
options = {
|
|
795
|
+
days: nil,
|
|
796
|
+
unsure: false,
|
|
797
|
+
verbose: false,
|
|
798
|
+
all: false,
|
|
799
|
+
dry_run: false,
|
|
800
|
+
profile: nil,
|
|
801
|
+
output: nil,
|
|
802
|
+
history_path: File.expand_path('~/.zsh_history')
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
parser = OptionParser.new do |opts|
|
|
806
|
+
opts.on('-d', '--days N', Integer, 'Only show last N days') do |days|
|
|
807
|
+
options[:days] = days
|
|
808
|
+
end
|
|
809
|
+
|
|
810
|
+
opts.on('-u', '--unsure', 'Include unsure commands') do
|
|
811
|
+
options[:unsure] = true
|
|
812
|
+
end
|
|
813
|
+
|
|
814
|
+
opts.on('-a', '--all', 'Show all commands (no filtering)') do
|
|
815
|
+
options[:all] = true
|
|
816
|
+
end
|
|
817
|
+
|
|
818
|
+
opts.on('-v', '--verbose', 'Show which pattern matched') do
|
|
819
|
+
options[:verbose] = true
|
|
820
|
+
end
|
|
821
|
+
|
|
822
|
+
opts.on('--dry-run', 'Preview changes without writing') do
|
|
823
|
+
options[:dry_run] = true
|
|
824
|
+
end
|
|
825
|
+
|
|
826
|
+
opts.on('-p', '--profile NAME', 'Use named profile for patterns') do |name|
|
|
827
|
+
options[:profile] = name
|
|
828
|
+
end
|
|
829
|
+
|
|
830
|
+
opts.on('-o', '--output PATH', 'Write output to file') do |path|
|
|
831
|
+
options[:output] = File.expand_path(path)
|
|
832
|
+
end
|
|
833
|
+
|
|
834
|
+
opts.on('-f', '--file PATH', 'Path to history file') do |path|
|
|
835
|
+
options[:history_path] = File.expand_path(path)
|
|
836
|
+
end
|
|
837
|
+
end
|
|
838
|
+
|
|
839
|
+
parser.parse!(args)
|
|
840
|
+
options
|
|
841
|
+
end
|
|
842
|
+
# rubocop:enable Metrics/MethodLength, Metrics/AbcSize
|
|
843
|
+
end
|
|
844
|
+
|
|
845
|
+
# Run CLI
|
|
846
|
+
ZshHistoryCLI.new.run if $PROGRAM_NAME == __FILE__
|