localvault 1.12.1 → 1.12.3

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5c37fd43d64105bf78e7501e458c98159958c4a6eca101d6716a3781b6bbb61f
4
- data.tar.gz: 9f869cee27f7c118f91acf009d85cb0cef9204d9a99ada99b59939c63f7c2b22
3
+ metadata.gz: 6798f21f6875910fa68c5300a929b4c18e757a9c03251cd71d46bb46e6cd85b7
4
+ data.tar.gz: a40a445f7d92baad0645bc9ab2f2a900bda43d09a657e07735c565bb5f705f01
5
5
  SHA512:
6
- metadata.gz: e503618d966e392d38a84969dae01d5355fcbccef921bad3f738a33b17139c71782e880f375756d865f1457b2c3fe23faf1175d65700caab1e5a3c1a5220e52d
7
- data.tar.gz: 12bbf4acd6091c45afda3489035977e88169cce34e0313f51c8f75d8d35df71379fa6799af4e1d8e6ad252dc69971f3c41d09ee65c8aaf72ec83b9b748b54cc1
6
+ metadata.gz: 45cf703a841eedc73c9b77ac19a92059075dd914c4c1075ff79beca784b61fce4396ffbf51b206315f55c6179c44270d3238a6174c479bc1a2e9e1e9bf4e34d7
7
+ data.tar.gz: 661933cfaa2a6f1a69a5459f0e87580912178e1faeeff0becf7823e4fbb007fa63fad8cfa2f7a05d363146309e20ef1ad4b316143d94a541ba1efb78ae3aa340
@@ -0,0 +1,84 @@
1
+ require "thor"
2
+
3
+ module LocalVault
4
+ class CLI
5
+ # Colors every help surface — the main screen, `help COMMAND`, and
6
+ # subcommand namespaces — by hooking the shell Thor already routes all
7
+ # help output through, rather than colorizing at each call site.
8
+ #
9
+ # Thor disables color itself when stdout is not a TTY, so piped output
10
+ # stays plain.
11
+ class HelpShell < Thor::Shell::Color
12
+ # "Usage:", "Options:", "Description:", "Runtime options:"
13
+ LABEL = /\A([A-Z][A-Za-z ]*:)\s*\z/
14
+ # A leading run of caps: "GETTING STARTED", "NESTED KEY (dot-notation)"
15
+ HEADING = /\A(\s*)([A-Z][A-Z0-9'\/\-]*(?: [A-Z0-9'\/\-]+)*)(?=\z|[\s(:])/
16
+
17
+ def say(message = "", color = nil, force_new_line = (message.to_s !~ /( |\t)\Z/))
18
+ if color.nil? && message.is_a?(String)
19
+ message = message.lines.map { |line| decorate(line.chomp) }.join("\n")
20
+ end
21
+ super
22
+ end
23
+
24
+ # Thor word-wraps long descriptions, which collapses the alignment of
25
+ # example blocks (`localvault set K V # comment` loses its spacing).
26
+ # Lines flagged with \x05 — Thor's no-wrap marker, which every example in
27
+ # our long_desc blocks already carries — are printed verbatim instead, so
28
+ # examples stay aligned while prose still wraps to the terminal.
29
+ def print_wrapped(message, options = {})
30
+ indent = options[:indent] || 0
31
+ prose = []
32
+
33
+ message.to_s.lines.each do |line|
34
+ line = line.chomp
35
+ if line.lstrip.start_with?("\x05")
36
+ wrap_prose(prose, options)
37
+ stdout.puts("#{" " * indent}#{decorate(line.sub("\x05", ''))}")
38
+ elsif line.strip.empty?
39
+ wrap_prose(prose, options)
40
+ stdout.puts
41
+ else
42
+ prose << line
43
+ end
44
+ end
45
+
46
+ wrap_prose(prose, options)
47
+ end
48
+
49
+ # Option tables: green the flag column ("-v, [--vault=VAULT]").
50
+ def print_table(array, options = {})
51
+ array = array.map do |row|
52
+ first, *rest = row
53
+ first.is_a?(String) && first.strip.start_with?("-") ? [set_color(first, :green), *rest] : row
54
+ end
55
+ super
56
+ end
57
+
58
+ private
59
+
60
+ # Hand a run of prose lines back to Thor's wrapper, then reset the buffer.
61
+ def wrap_prose(lines, options)
62
+ return if lines.empty?
63
+ text = lines.join("\n")
64
+ lines.clear
65
+ return if text.strip.empty?
66
+ Thor::Shell::Basic.instance_method(:print_wrapped)
67
+ .bind_call(self, text.lines.map { |l| decorate(l.chomp) }.join("\n"), options)
68
+ end
69
+
70
+ def decorate(line)
71
+ return line unless can_display_colors?
72
+
73
+ if (match = LABEL.match(line))
74
+ return line.sub(match[1], set_color(match[1], :cyan, true))
75
+ end
76
+
77
+ match = HEADING.match(line)
78
+ return line unless match && match[2].length >= 4
79
+
80
+ "#{match[1]}#{set_color(match[2], :cyan, true)}#{line[(match[1].length + match[2].length)..]}"
81
+ end
82
+ end
83
+ end
84
+ end
@@ -66,7 +66,9 @@ module LocalVault
66
66
 
67
67
  def self.start(given_args = ARGV, config = {})
68
68
  require_relative "cli/error_presenter"
69
- config[:shell] ||= Thor::Base.shell.new
69
+ require_relative "cli/help_shell"
70
+ Thor::Base.shell = HelpShell # subcommand namespaces build their own shells
71
+ config[:shell] ||= HelpShell.new
70
72
  result = dispatch(nil, normalize_legacy_group_option(given_args.dup), nil, config)
71
73
  result.is_a?(CommandStatus) ? result.code : 0
72
74
  rescue Thor::Error => error
@@ -114,7 +116,7 @@ module LocalVault
114
116
  # disappearing from help.
115
117
  HELP_SECTIONS = [
116
118
  ["GETTING STARTED", %w[login config init demo]],
117
- ["SECRETS", %w[set get show groups list delete import env exec]],
119
+ ["SECRETS", %w[set get show reveal groups list delete import env exec]],
118
120
  ["VAULT MANAGEMENT", %w[vaults switch rekey unlock lock reset rename copy]],
119
121
  ["SYNC (requires localvault login)", %w[sync]],
120
122
  ["TEAM SHARING (requires localvault login)", %w[dashboard verify add remove team]],
@@ -150,8 +152,6 @@ module LocalVault
150
152
  rendered = sections.map { |title, names| [title, names.flat_map { |n| help_rows_for(n) }] }
151
153
  width = rendered.flat_map { |_, rows| rows.map { |usage, _| usage.length } }.max + 4
152
154
 
153
- say_header = ->(text) { shell.say shell.set_color(text, :cyan, true) }
154
-
155
155
  shell.say ""
156
156
  shell.say shell.set_color("LocalVault", :cyan, true) + " — encrypted local secrets vault with MCP support for AI agents"
157
157
  shell.say " https://inventlist.com/tools/localvault"
@@ -159,22 +159,22 @@ module LocalVault
159
159
  rendered.each do |title, rows|
160
160
  next if rows.empty?
161
161
  shell.say ""
162
- say_header.call(title)
162
+ shell.say title
163
163
  rows.each do |usage, desc|
164
164
  shell.say " localvault #{shell.set_color(usage.ljust(width), :green)}#{desc}"
165
165
  end
166
166
  end
167
167
 
168
168
  shell.say ""
169
- say_header.call("SAFE SECRET INPUT (preferred over passing values as arguments)")
169
+ shell.say("SAFE SECRET INPUT (preferred over passing values as arguments)")
170
170
  shell.say " printf '%s' \"$SECRET\" | localvault set KEY --stdin"
171
171
  shell.say ""
172
- say_header.call("PROJECTS (dot-notation groups inside one vault)")
172
+ shell.say("PROJECTS (dot-notation groups inside one vault)")
173
173
  shell.say " localvault set platepose.API_KEY v Store a key in the 'platepose' group"
174
174
  shell.say " Filter any command with -p: show -p platepose, exec -p platepose -- CMD"
175
175
  shell.say " Delete a whole group: localvault delete 'platepose.*'"
176
176
  shell.say ""
177
- say_header.call("USING SECRETS WITH ANY CLI")
177
+ shell.say("USING SECRETS WITH ANY CLI")
178
178
  shell.say " localvault exec -- inventlist ships list"
179
179
  shell.say " localvault exec -- curl -H \"Authorization: Bearer $API_KEY\" ..."
180
180
  shell.say ""
@@ -526,6 +526,29 @@ module LocalVault
526
526
  abort_with "Wrong passphrase for vault '#{vault_name}'"
527
527
  end
528
528
 
529
+ desc "reveal [GROUP]", "Show secrets with values unmasked (same as `show --reveal`)"
530
+ long_desc <<~DESC
531
+ Show secrets with their values unmasked. Identical to `show --reveal`, and
532
+ it takes the same options — `reveal` is simply the verb most people reach
533
+ for. A bare argument is treated as the group to show.
534
+
535
+ \x05 localvault reveal # every secret, unmasked
536
+ \x05 localvault reveal CLOUDFLARE # one group
537
+ \x05 localvault reveal --group CLOUDFLARE # the same thing
538
+ \x05 localvault reveal -p kuickr -v intellectaco
539
+
540
+ Plaintext output is still gated: it refuses to print values when stdout is
541
+ not a terminal, so a redirect or a pipe can't quietly capture secrets.
542
+ DESC
543
+ method_option :group, aliases: "-g", type: :string, lazy_default: GROUP_ALL_SENTINEL, desc: "Show all groups or one group by name"
544
+ method_option :project, aliases: "-p", type: :string, desc: "Show only this project group"
545
+ def reveal(group = nil)
546
+ merged = options.merge("reveal" => true)
547
+ merged["group"] = group if group && merged["project"].nil?
548
+ self.options = merged
549
+ show
550
+ end
551
+
529
552
  desc "show", "Display secrets in a formatted table (masked by default)"
530
553
  long_desc <<~DESC
531
554
  Show secrets in the current vault. Values are masked by default.
@@ -785,6 +808,14 @@ module LocalVault
785
808
  require_relative "cli/guard"
786
809
  require_relative "cli/identity_cmd"
787
810
 
811
+ # Thor 1.5 injects a `tree` command into every class. Inside a namespace it
812
+ # lists under a name that isn't even callable (`identity_command tree`), and
813
+ # at top level it prints a raw class path as the root. Our grouped help
814
+ # covers the same ground properly, so drop it everywhere.
815
+ [self, Guard, Keys, Team, Sync, IdentityCommand].each do |namespace|
816
+ namespace.remove_command(:tree) if namespace.all_commands.key?("tree")
817
+ end
818
+
788
819
  register(Guard, "guard", "guard SUBCOMMAND", "Block plaintext secrets in agent tool traffic (Claude Code hooks)")
789
820
  register(IdentityCommand, "identity", "identity SUBCOMMAND", "Show or set your local identity (alias, handle, public key)")
790
821
  register(Keys, "keys", "keys SUBCOMMAND", "Manage your X25519 keypair for vault sharing")
@@ -1,3 +1,3 @@
1
1
  module LocalVault
2
- VERSION = "1.12.1"
2
+ VERSION = "1.12.3"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: localvault
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.12.1
4
+ version: 1.12.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nauman Tariq
@@ -112,6 +112,7 @@ files:
112
112
  - lib/localvault/cli.rb
113
113
  - lib/localvault/cli/error_presenter.rb
114
114
  - lib/localvault/cli/guard.rb
115
+ - lib/localvault/cli/help_shell.rb
115
116
  - lib/localvault/cli/identity_cmd.rb
116
117
  - lib/localvault/cli/keys.rb
117
118
  - lib/localvault/cli/sync.rb