lux-hammer 0.3.8 → 0.3.9
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/.version +1 -1
- data/lib/hammer/parser.rb +5 -1
- data/lib/hammer/shell.rb +4 -4
- data/lib/lux-hammer.rb +53 -13
- data/recipes/git-helper.rb +2 -0
- data/recipes/llm.rb +3 -0
- data/recipes/srt.rb +2 -0
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 60fa663d47e0d1d68790c40125c1594ae0152d99695cd57fe1d86294b1a5c348
|
|
4
|
+
data.tar.gz: 779a8291e200bff69a8c3b237662a88647a50071eb038f47fe695d547c805094
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 6b2114d72e01ee7aef8166a4881915d4c124e0cce67c6c9e5d680fb945750aa8b338fc7041332dcaf6d54fe15fac04cf3e85271e8cd75b5bc3126edacb30f827
|
|
7
|
+
data.tar.gz: 7f85fb830fae721e969e2d23e28a9c282c6655b8b9f29aa5c8dd15a9fa3e5f55eddcfa9a978d7605c37c1ca20c177b43c1475114f64f870e41e5993c56287854
|
data/.version
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.3.
|
|
1
|
+
0.3.9
|
data/lib/hammer/parser.rb
CHANGED
|
@@ -63,7 +63,11 @@ class Hammer
|
|
|
63
63
|
@options.each do |opt|
|
|
64
64
|
break if positional.empty?
|
|
65
65
|
next if opt.boolean? || values.key?(opt.name)
|
|
66
|
-
|
|
66
|
+
if opt.type == :array
|
|
67
|
+
values[opt.name] = opt.cast(positional.shift(positional.size))
|
|
68
|
+
else
|
|
69
|
+
values[opt.name] = opt.cast(positional.shift)
|
|
70
|
+
end
|
|
67
71
|
end
|
|
68
72
|
|
|
69
73
|
@options.each do |opt|
|
data/lib/hammer/shell.rb
CHANGED
|
@@ -31,8 +31,8 @@ class Hammer
|
|
|
31
31
|
|
|
32
32
|
# `say` with no args returns a proxy so you can write `say.cyan 'hi'`.
|
|
33
33
|
# `say('')` still prints a blank line; `say('x', :cyan)` is unchanged.
|
|
34
|
-
def say(text =
|
|
35
|
-
return SayProxy.new if text
|
|
34
|
+
def say(text = :_say_no_arg, color = nil)
|
|
35
|
+
return SayProxy.new if text == :_say_no_arg
|
|
36
36
|
puts paint(text, color)
|
|
37
37
|
end
|
|
38
38
|
|
|
@@ -116,9 +116,9 @@ class Hammer
|
|
|
116
116
|
$stdout.print "\e[#{items.size}A\r\e[J"
|
|
117
117
|
$stdout.print "#{paint("> #{items[selected]}", :green)}\r\n"
|
|
118
118
|
return selected
|
|
119
|
-
when "\x03"
|
|
119
|
+
when "\x03" # Ctrl-C
|
|
120
120
|
$stdout.print "\e[#{items.size}A\r\e[J"
|
|
121
|
-
|
|
121
|
+
raise Interrupt
|
|
122
122
|
when "\e"
|
|
123
123
|
# ESC may stand alone or start an arrow sequence \e[A / \e[B.
|
|
124
124
|
if IO.select([io], nil, nil, 0.01) && io.getch == '['
|
data/lib/lux-hammer.rb
CHANGED
|
@@ -414,6 +414,13 @@ class Hammer
|
|
|
414
414
|
run_command(cmd, argv, full: name, quiet: true)
|
|
415
415
|
end
|
|
416
416
|
|
|
417
|
+
# True when -h or --help appears in argv before a `--` stop-marker.
|
|
418
|
+
def help_requested?(argv)
|
|
419
|
+
stop = argv.index('--')
|
|
420
|
+
scan = stop ? argv[0...stop] : argv
|
|
421
|
+
scan.include?('-h') || scan.include?('--help')
|
|
422
|
+
end
|
|
423
|
+
|
|
417
424
|
public
|
|
418
425
|
|
|
419
426
|
# Find a command by canonical name or alt within this class. Falls
|
|
@@ -605,30 +612,26 @@ class Hammer
|
|
|
605
612
|
end
|
|
606
613
|
end
|
|
607
614
|
|
|
608
|
-
|
|
609
|
-
stop = argv.index('--')
|
|
610
|
-
scan = stop ? argv[0...stop] : argv
|
|
611
|
-
scan.include?('-h') || scan.include?('--help')
|
|
612
|
-
end
|
|
615
|
+
public
|
|
613
616
|
|
|
614
617
|
# `extended: true` is the verbose `help` / `-h` / `--help` form -
|
|
615
618
|
# appends global flags, the GitHub footer, and (for the hammer binary)
|
|
616
619
|
# a Hammerfile example. Bare invocation passes `extended: false` so
|
|
617
620
|
# the no-args output stays a clean command listing.
|
|
618
|
-
def print_help(target = nil,
|
|
621
|
+
def print_help(target = nil, expanded: false, extended: false)
|
|
619
622
|
if target
|
|
620
623
|
# `help ns:` is equivalent to `ns:` - namespace listing.
|
|
621
624
|
if target.end_with?(':') && target != ':'
|
|
622
625
|
bare = target.chomp(':')
|
|
623
626
|
ns, canonical = resolve_namespace(bare)
|
|
624
|
-
return print_namespace_help(canonical, ns
|
|
627
|
+
return print_namespace_help(canonical, ns) if ns
|
|
625
628
|
Shell.print_error("unknown: #{target}")
|
|
626
629
|
return
|
|
627
630
|
end
|
|
628
631
|
cmd, _, canonical = resolve(target)
|
|
629
632
|
return print_command_help(cmd, canonical) if cmd
|
|
630
633
|
ns, canonical = resolve_namespace(target)
|
|
631
|
-
return print_namespace_help(canonical, ns,
|
|
634
|
+
return print_namespace_help(canonical, ns, expanded: expanded) if ns
|
|
632
635
|
Shell.print_error("unknown: #{target}")
|
|
633
636
|
return
|
|
634
637
|
end
|
|
@@ -639,7 +642,7 @@ class Hammer
|
|
|
639
642
|
Shell.say ''
|
|
640
643
|
@app_desc.each_line { |l| Shell.say " #{l.chomp}" }
|
|
641
644
|
end
|
|
642
|
-
if
|
|
645
|
+
if expanded
|
|
643
646
|
each_command { |path, c| print_full_block(path, c) unless c.desc.empty? }
|
|
644
647
|
else
|
|
645
648
|
Shell.say ''
|
|
@@ -670,10 +673,9 @@ class Hammer
|
|
|
670
673
|
|
|
671
674
|
# `extended:` is accepted for parity with `print_help` but intentionally
|
|
672
675
|
# not used here - the global-flags / Hammerfile-example / footer block
|
|
673
|
-
# is root-help-only.
|
|
674
|
-
#
|
|
675
|
-
|
|
676
|
-
def print_namespace_help(prefix, ns, full: false, extended: false)
|
|
676
|
+
# is root-help-only. `expanded:` is also accepted for parity; a namespace
|
|
677
|
+
# listing is always the compact command list.
|
|
678
|
+
def print_namespace_help(prefix, ns, expanded: false, extended: false)
|
|
677
679
|
Shell.say "Usage: #{program_name} #{prefix}:COMMAND [ARGS]", :cyan
|
|
678
680
|
rows = []
|
|
679
681
|
sibling = find_namespace_sibling(prefix)
|
|
@@ -989,6 +991,17 @@ class Hammer
|
|
|
989
991
|
argv = argv.dup
|
|
990
992
|
force_system = !!argv.delete('--system')
|
|
991
993
|
|
|
994
|
+
# Shebang invocation: `hammer /path/to/script ...args` (kernel passes
|
|
995
|
+
# the script path as argv[0] for `#!/usr/bin/env hammer` files).
|
|
996
|
+
# Treat the script as a self-contained CLI: no Hammerfile lookup, no
|
|
997
|
+
# chdir (commands run in the caller's cwd), no `hammer`-binary
|
|
998
|
+
# built-ins/banners. Detection requires a `#!`+`hammer` first line so
|
|
999
|
+
# task names that happen to be paths don't get hijacked.
|
|
1000
|
+
if (script = shebang_script(argv.first))
|
|
1001
|
+
argv.shift
|
|
1002
|
+
return run_shebang(script, argv)
|
|
1003
|
+
end
|
|
1004
|
+
|
|
992
1005
|
path = force_system ? nil : find_hammerfile(Dir.pwd)
|
|
993
1006
|
unless path
|
|
994
1007
|
# No Hammerfile (or --system) - all built-ins are reachable. Bare
|
|
@@ -1058,6 +1071,33 @@ class Hammer
|
|
|
1058
1071
|
klass.start(argv)
|
|
1059
1072
|
end
|
|
1060
1073
|
|
|
1074
|
+
# Returns the script path if `arg` looks like a shebang script that
|
|
1075
|
+
# delegates to hammer (first line starts with `#!` and mentions
|
|
1076
|
+
# `hammer`). Returns nil otherwise. Used by `cli` to detect
|
|
1077
|
+
# `#!/usr/bin/env hammer` invocations where the kernel passes the
|
|
1078
|
+
# script path as argv[0].
|
|
1079
|
+
def self.shebang_script(arg)
|
|
1080
|
+
return nil unless arg
|
|
1081
|
+
return nil if arg.start_with?('-')
|
|
1082
|
+
return nil unless File.file?(arg) && File.readable?(arg)
|
|
1083
|
+
head = File.open(arg, &:gets).to_s
|
|
1084
|
+
return nil unless head.start_with?('#!') && head.include?('hammer')
|
|
1085
|
+
arg
|
|
1086
|
+
end
|
|
1087
|
+
|
|
1088
|
+
# Evaluate a shebang script as a self-contained CLI. Mirrors `recipe`
|
|
1089
|
+
# semantics: no chdir, no `@hammer_binary` flag, no `register_core`
|
|
1090
|
+
# built-ins (so the script's `--help` shows only what it defines).
|
|
1091
|
+
# `program_name` is the script's basename so help reads "myscript foo"
|
|
1092
|
+
# rather than "hammer foo" - works even when invoked via a symlink in
|
|
1093
|
+
# PATH, since argv[0] is the path the user typed.
|
|
1094
|
+
def self.run_shebang(path, argv)
|
|
1095
|
+
klass = Class.new(Hammer)
|
|
1096
|
+
klass.instance_variable_set(:@program_name, File.basename(path))
|
|
1097
|
+
Builder.new(klass).evaluate(File.read(path), path)
|
|
1098
|
+
klass.start(argv)
|
|
1099
|
+
end
|
|
1100
|
+
|
|
1061
1101
|
# True if argv goes through a built-in dispatch path (`:default` or
|
|
1062
1102
|
# `:help`) - meaning bare `hammer`, leading-flag invocations like
|
|
1063
1103
|
# `hammer -h`, or explicit help requests. These don't need a project
|
data/recipes/git-helper.rb
CHANGED
data/recipes/llm.rb
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
#!/usr/bin/env hammer
|
|
1
2
|
# desc: personal LLM utility CLI (memory store, prompt-token expander, ...)
|
|
3
|
+
# executable: chmod +x this file and run directly, or symlink into PATH
|
|
2
4
|
|
|
3
5
|
desc <<~TXT
|
|
4
6
|
llm - personal LLM utility CLI
|
|
@@ -54,6 +56,7 @@ namespace :memory do
|
|
|
54
56
|
end
|
|
55
57
|
[meta, body.to_s.sub(/\A\n+/, '')]
|
|
56
58
|
end
|
|
59
|
+
|
|
57
60
|
task :list do
|
|
58
61
|
desc 'List stored memories with type and one-line description'
|
|
59
62
|
example 'llm memory list'
|
data/recipes/srt.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: lux-hammer
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.3.
|
|
4
|
+
version: 0.3.9
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Dino Reic
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-05-
|
|
11
|
+
date: 2026-05-26 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: minitest
|