hiiro 0.1.337 → 0.1.338

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: cdc7066a25c11d282e6e13914e89d1f17b93b1e6eebaadb3b78c445e9ad54730
4
- data.tar.gz: ccfe1dacaa0fadff21f621d56743d99066fec4f911de70a58741504b8a9330a3
3
+ metadata.gz: 92203914806a439748cb5f3020d0784c253e3a1ac91bebf786a2115c9aa3b0d4
4
+ data.tar.gz: 665b26d833fd387edf53814df50d6289e8dea59b56abc97ba485ed0ab169ad71
5
5
  SHA512:
6
- metadata.gz: 1c52eefc3e02bb0eadee1019f091facbfcd01509d6e57c32214032f901aebf3b0204afa1aacff3dfb3c4f9d793b298d11cf888fb02c6ddc24a0948c7737526c7
7
- data.tar.gz: f2cc1b1cfbfae9fc3c6229e140779deeee162458d2b04e1ac04a61ea515e13161f5d6a70c93316c5f1c7bfc895baa8552c809d199434e4b42dd2f90d45be91e2
6
+ metadata.gz: ceb994131ac83201c806910f87099df9e1cfbea8ffd91d5fcf15221c64ee153af859a40eb7dc36553cd5f4fd1c690f2123415b933676656fb5d70af54359f608
7
+ data.tar.gz: 5c3f66a48df5269d6d383030c8e46a88a87b451bcca5fdbf1c53fd0aebc7d437810815f616cdd70d9df0e20132c5482425555292b932694825f4972118f677ee
data/CHANGELOG.md CHANGED
@@ -1,5 +1,10 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.1.338] - 2026-04-07
4
+
5
+ ### Changed
6
+ - Renamed `registry_entries` table to `registry` (auto-migrates existing data)
7
+
3
8
  ## [0.1.337] - 2026-04-06
4
9
 
5
10
  ### Changed
@@ -312,72 +317,3 @@
312
317
  - `bin/h-pane` — load/save pane homes via `Hiiro::PaneHome` model with YAML dual-write
313
318
  - `bin/h-pr` — adds `q`/`query` subcommands for inspecting PR records via raw SQL
314
319
  - `plugins/pins.rb` — `Pin` class reads/writes via `Hiiro::PinRecord` SQLite model with YAML dual-write fallback
315
-
316
- ## [0.1.306] - 2026-03-30
317
-
318
- ### Changed
319
- - Increase delayed_update sleep duration from 5s to 15s
320
- - Add logging for delayed_update invocation in publish script
321
-
322
- ## [0.1.305] - 2026-03-30
323
-
324
- ### Changed
325
- - Refactor: use delayed_update subcommand instead of direct update call
326
- - Improve gem version matching regex in version check
327
-
328
- ## [0.1.304] - 2026-03-30
329
-
330
- ### Changed
331
- - h-notify: use universal log instead of per-session logging
332
- - Todo output simplified
333
-
334
- ## [0.1.302] - 2026-03-30
335
-
336
- ### Fixed
337
- - Truncate output lines to terminal width in tasks plugin
338
-
339
- ## [0.1.301]
340
-
341
- ### Added
342
- - Check version delayed update functionality
343
-
344
- ### Changed
345
- - h-claude: add verbose flags and refactor glob_path handling
346
-
347
- ### Fixed
348
- - Use exact session matching to prevent tmux prefix ambiguity
349
-
350
- ## [0.1.300]
351
-
352
- ### Added
353
- - h-claude: fulltext search option for agents/commands/skills
354
-
355
- ### Changed
356
- - Refactor h-claude directory traversal and file globbing
357
-
358
- ## [0.1.299]
359
-
360
- ### Added
361
- - h-pr open: support opening multiple PRs
362
-
363
- ## [0.1.298]
364
-
365
- ### Changed
366
- - Use Pathname to walk up directory tree
367
- - h-claude agents/commands/skills walk from pwd up to home
368
-
369
- ## [0.1.297]
370
-
371
- ### Added
372
- - h rnext subcommand
373
-
374
- ## [0.1.296]
375
-
376
- ### Changed
377
- - Refactor PR filter logic to pinned_pr_manager
378
- - Move PR filter logic to Pr#matches_filters?
379
-
380
- ## [0.1.295]
381
-
382
- ### Changed
383
- - Filter logic changes for PR management
data/bin/h-registry CHANGED
@@ -21,8 +21,9 @@ Hiiro.run(*ARGV, tasks: true) do
21
21
  puts '─' * 40
22
22
  end
23
23
  alias_col = e.short_name ? "[#{e.short_name}]".ljust(18) : ' ' * 18
24
+ value_col = e.value ? " = #{e.value}" : ''
24
25
  desc_col = e.description ? " # #{e.description}" : ''
25
- puts " #{alias_col} #{e.name}#{desc_col}"
26
+ puts " #{alias_col} #{e.name}#{value_col}#{desc_col}"
26
27
  end
27
28
  puts
28
29
  end
@@ -33,10 +34,10 @@ Hiiro.run(*ARGV, tasks: true) do
33
34
  puts types.empty? ? "No types registered yet." : types.join("\n")
34
35
  end
35
36
 
36
- # h registry add <type> <name> [--alias <short>] [--desc <description>]
37
+ # h registry add <type> <name> [value] [--alias <short>] [--desc <description>]
37
38
  add_subcmd(:add) do |type, name, *rest|
38
39
  unless type && name
39
- puts "Usage: h registry add <type> <name> [--alias <short>] [--desc <text>]"
40
+ puts "Usage: h registry add <type> <name> [value] [--alias <short>] [--desc <text>]"
40
41
  next
41
42
  end
42
43
  opts = Hiiro::Options.setup {
@@ -44,6 +45,9 @@ Hiiro.run(*ARGV, tasks: true) do
44
45
  option(:desc, short: :d, desc: 'Description')
45
46
  }.parse(rest)
46
47
 
48
+ # First positional arg after name is the value
49
+ value = opts.args.first
50
+
47
51
  existing = Hiiro::RegistryEntry.find_by_ref(name, type: type)
48
52
  if existing
49
53
  puts "Already registered: #{existing.display}"
@@ -53,6 +57,7 @@ Hiiro.run(*ARGV, tasks: true) do
53
57
  entry = Hiiro::RegistryEntry.create(
54
58
  resource_type: type,
55
59
  name: name,
60
+ value: value,
56
61
  short_name: opts.alias,
57
62
  description: opts.desc,
58
63
  created_at: Time.now.iso8601
@@ -60,15 +65,26 @@ Hiiro.run(*ARGV, tasks: true) do
60
65
  puts "Added:\n#{entry.display}"
61
66
  end
62
67
 
63
- # h registry rm <name_or_alias> [type]
64
- add_subcmd(:rm, :remove) do |ref, type = nil|
68
+ # h registry rm <name_or_alias> [type] [-s]
69
+ add_subcmd(:rm, :remove) do |*args|
70
+ opts = Hiiro::Options.setup {
71
+ option(:substring, short: :s, type: :flag, desc: 'Match substring anywhere in name')
72
+ }.parse(args)
73
+
74
+ ref, type = opts.args
65
75
  unless ref
66
- puts "Usage: h registry rm <name_or_alias> [type]"
76
+ puts "Usage: h registry rm <name_or_alias> [type] [-s]"
67
77
  next
68
78
  end
69
- entry = Hiiro::RegistryEntry.find_by_ref(ref, type: type ? type.to_s : nil)
79
+ entry = Hiiro::RegistryEntry.find_by_ref(ref, type: type&.to_s, substring: opts.substring)
70
80
  unless entry
71
- puts "Not found: #{ref}#{type ? " (type: #{type})" : ''}"
81
+ matches = Hiiro::RegistryEntry.find_all_by_ref(ref, type: type&.to_s, substring: opts.substring)
82
+ if matches.any?
83
+ puts "Ambiguous match '#{ref}' - #{matches.size} entries:"
84
+ matches.each { |e| puts " #{e.resource_type}/#{e.name}" }
85
+ else
86
+ puts "Not found: #{ref}#{type ? " (type: #{type})" : ''}"
87
+ end
72
88
  next
73
89
  end
74
90
  puts "Removing: #{entry.display}"
@@ -76,24 +92,52 @@ Hiiro.run(*ARGV, tasks: true) do
76
92
  puts "Done."
77
93
  end
78
94
 
79
- # h registry get <name_or_alias> [type] — prints canonical name (scriptable)
80
- add_subcmd(:get) do |ref, type = nil|
95
+ # h registry get <name_or_alias> [type] [-s] — prints value (or name if no value)
96
+ # Supports prefix matching; use -s/--substring for substring match
97
+ # Prints all matching values (one per line) if multiple matches
98
+ add_subcmd(:get) do |*args|
99
+ opts = Hiiro::Options.setup {
100
+ option(:substring, short: :s, type: :flag, desc: 'Match substring anywhere in name')
101
+ }.parse(args)
102
+
103
+ ref, type = opts.args
81
104
  unless ref
82
- puts "Usage: h registry get <name_or_alias> [type]"
105
+ puts "Usage: h registry get <name_or_alias> [type] [-s]"
83
106
  next
84
107
  end
85
- entry = Hiiro::RegistryEntry.find_by_ref(ref, type: type ? type.to_s : nil)
86
- entry ? puts(entry.name) : exit(1)
108
+
109
+ matches = Hiiro::RegistryEntry.find_all_by_ref(ref, type: type&.to_s, substring: opts.substring)
110
+ if matches.empty?
111
+ exit(1)
112
+ else
113
+ matches.each { |e| puts(e.value || e.name) }
114
+ end
87
115
  end
88
116
 
89
- # h registry show <name_or_alias> [type] — human-readable detail
90
- add_subcmd(:show) do |ref, type = nil|
117
+ # h registry show <name_or_alias> [type] [-s] — human-readable detail
118
+ add_subcmd(:show) do |*args|
119
+ opts = Hiiro::Options.setup {
120
+ option(:substring, short: :s, type: :flag, desc: 'Match substring anywhere in name')
121
+ }.parse(args)
122
+
123
+ ref, type = opts.args
91
124
  unless ref
92
- puts "Usage: h registry show <name_or_alias> [type]"
125
+ puts "Usage: h registry show <name_or_alias> [type] [-s]"
93
126
  next
94
127
  end
95
- entry = Hiiro::RegistryEntry.find_by_ref(ref, type: type ? type.to_s : nil)
96
- entry ? puts(entry.display) : (puts "Not found: #{ref}"; exit 1)
128
+ entry = Hiiro::RegistryEntry.find_by_ref(ref, type: type&.to_s, substring: opts.substring)
129
+ if entry
130
+ puts entry.display
131
+ else
132
+ matches = Hiiro::RegistryEntry.find_all_by_ref(ref, type: type&.to_s, substring: opts.substring)
133
+ if matches.any?
134
+ puts "Ambiguous match '#{ref}' - #{matches.size} entries:"
135
+ matches.each { |e| puts " #{e.resource_type}/#{e.name}" }
136
+ else
137
+ puts "Not found: #{ref}"
138
+ end
139
+ exit 1
140
+ end
97
141
  end
98
142
 
99
143
  # h registry select [type] — fuzzyfinder, prints canonical name
@@ -110,19 +154,50 @@ Hiiro.run(*ARGV, tasks: true) do
110
154
  puts name
111
155
  end
112
156
 
113
- # h registry set-alias <name_or_alias> <new_alias> [type]
114
- add_subcmd(:'set-alias') do |ref, new_alias, type = nil|
157
+ # h registry set-alias <name_or_alias> <new_alias> [type] [-s]
158
+ add_subcmd(:'set-alias') do |*args|
159
+ opts = Hiiro::Options.setup {
160
+ option(:substring, short: :s, type: :flag, desc: 'Match substring anywhere in name')
161
+ }.parse(args)
162
+
163
+ ref, new_alias, type = opts.args
115
164
  unless ref && new_alias
116
- puts "Usage: h registry set-alias <name_or_alias> <new_alias> [type]"
165
+ puts "Usage: h registry set-alias <name_or_alias> <new_alias> [type] [-s]"
117
166
  next
118
167
  end
119
- entry = Hiiro::RegistryEntry.find_by_ref(ref, type: type ? type.to_s : nil)
168
+ entry = Hiiro::RegistryEntry.find_by_ref(ref, type: type&.to_s, substring: opts.substring)
120
169
  unless entry
121
- puts "Not found: #{ref}"
170
+ matches = Hiiro::RegistryEntry.find_all_by_ref(ref, type: type&.to_s, substring: opts.substring)
171
+ if matches.any?
172
+ puts "Ambiguous match '#{ref}' - #{matches.size} entries:"
173
+ matches.each { |e| puts " #{e.resource_type}/#{e.name}" }
174
+ else
175
+ puts "Not found: #{ref}"
176
+ end
122
177
  next
123
178
  end
124
179
  entry.update(short_name: new_alias)
125
180
  puts entry.display
126
181
  end
127
182
 
183
+ # h registry set <type> <name> <value> — update value of existing entry (or create)
184
+ add_subcmd(:set, :update) do |type, name, value = nil|
185
+ unless type && name
186
+ puts "Usage: h registry set <type> <name> <value>"
187
+ next
188
+ end
189
+ entry = Hiiro::RegistryEntry.find_by_ref(name, type: type)
190
+ if entry
191
+ entry.update(value: value)
192
+ else
193
+ entry = Hiiro::RegistryEntry.create(
194
+ resource_type: type,
195
+ name: name,
196
+ value: value,
197
+ created_at: Time.now.iso8601
198
+ )
199
+ end
200
+ puts entry.display
201
+ end
202
+
128
203
  end
data/lib/hiiro/db.rb CHANGED
@@ -37,6 +37,8 @@ class Hiiro
37
37
 
38
38
  MODELS.each do |cls|
39
39
  cls.create_table!(conn)
40
+ # Run model-specific migrations (e.g., adding columns to existing tables)
41
+ cls.migrate!(conn) if cls.respond_to?(:migrate!)
40
42
  # Clear all schema-related caches on the model and its anonymous Sequel
41
43
  # parent class. When require_valid_table=false and the table didn't exist
42
44
  # at class-definition time, Sequel caches empty results for @db_schema,
@@ -1,14 +1,20 @@
1
1
  require 'sequel'
2
2
 
3
3
  class Hiiro
4
- class RegistryEntry < Sequel::Model(:registry_entries)
4
+ class RegistryEntry < Sequel::Model(:registry)
5
5
  Hiiro::DB.register(self)
6
6
 
7
7
  def self.create_table!(db)
8
- db.create_table?(:registry_entries) do
8
+ # Rename old table if it exists
9
+ if db.table_exists?(:registry_entries) && !db.table_exists?(:registry)
10
+ db.rename_table(:registry_entries, :registry)
11
+ end
12
+
13
+ db.create_table?(:registry) do
9
14
  primary_key :id
10
15
  String :resource_type, null: false # e.g. "service", "queue", "worker"
11
16
  String :name, null: false # canonical identifier
17
+ String :value # stored value (optional)
12
18
  String :short_name # alias / shorthand
13
19
  String :description
14
20
  String :meta_json # arbitrary JSON for extra fields
@@ -18,16 +24,65 @@ class Hiiro
18
24
  end
19
25
  end
20
26
 
27
+ def self.migrate!(db)
28
+ # Add value column if missing (migration for existing DBs)
29
+ unless db.schema(:registry).any? { |col, _| col == :value }
30
+ db.alter_table(:registry) { add_column :value, String }
31
+ end
32
+ end
33
+
21
34
  # ── Finders ──────────────────────────────────────────────────────────────
22
35
 
23
36
  def self.of_type(type) = where(resource_type: type.to_s).order(:name).all
24
37
  def self.all_ordered = order(:resource_type, :name).all
25
38
  def self.known_types = distinct.select_map(:resource_type).sort
26
39
 
27
- # Resolve by exact name or short_name within a type (or globally).
28
- def self.find_by_ref(ref, type: nil)
40
+ # Resolve by exact name, short_name, or prefix within a type (or globally).
41
+ # Returns single entry or nil. Ambiguous prefix matches return nil.
42
+ def self.find_by_ref(ref, type: nil, substring: false)
43
+ scope = type ? where(resource_type: type.to_s) : self
44
+
45
+ # Try exact match first (name or short_name)
46
+ exact = scope.where(name: ref).first || scope.where(short_name: ref).first
47
+ return exact if exact
48
+
49
+ # Fall back to prefix/substring matching
50
+ entries = scope.all
51
+ matcher = Hiiro::Matcher.new(entries, :name)
52
+ result = substring ? matcher.by_substring(ref) : matcher.by_prefix(ref)
53
+
54
+ # Only return if unambiguous (exactly one match)
55
+ return result.first.item if result.one?
56
+
57
+ # Also try matching against short_name
58
+ matcher_short = Hiiro::Matcher.new(entries.select(&:short_name), :short_name)
59
+ result_short = substring ? matcher_short.by_substring(ref) : matcher_short.by_prefix(ref)
60
+ return result_short.first.item if result_short.one?
61
+
62
+ nil
63
+ end
64
+
65
+ # Find all entries matching ref (for showing ambiguous matches)
66
+ # Checks both name and short_name, returns unique entries
67
+ def self.find_all_by_ref(ref, type: nil, substring: false)
29
68
  scope = type ? where(resource_type: type.to_s) : self
30
- scope.where(name: ref).first || scope.where(short_name: ref).first
69
+
70
+ # Check for exact matches first
71
+ exact = scope.where(name: ref).all + scope.where(short_name: ref).all
72
+ return exact.uniq(&:id) if exact.any?
73
+
74
+ # Fall back to prefix/substring matching on name
75
+ entries = scope.all
76
+ matcher = Hiiro::Matcher.new(entries, :name)
77
+ result = substring ? matcher.by_substring(ref) : matcher.by_prefix(ref)
78
+ name_matches = result.matches.map(&:item)
79
+
80
+ # Also match on short_name
81
+ matcher_short = Hiiro::Matcher.new(entries.select(&:short_name), :short_name)
82
+ result_short = substring ? matcher_short.by_substring(ref) : matcher_short.by_prefix(ref)
83
+ short_matches = result_short.matches.map(&:item)
84
+
85
+ (name_matches + short_matches).uniq(&:id)
31
86
  end
32
87
 
33
88
  # Fuzzy-finder display lines: "type short name description"
@@ -51,12 +106,14 @@ class Hiiro
51
106
 
52
107
  def fuzzy_line
53
108
  parts = [resource_type.ljust(14), short_name&.ljust(16) || ' ' * 16, name]
109
+ parts << " = #{value}" if value && !value.empty?
54
110
  parts << " # #{description}" if description && !description.empty?
55
111
  parts.join(' ').strip
56
112
  end
57
113
 
58
114
  def display
59
115
  lines = ["#{resource_type} / #{name}"]
116
+ lines << " value: #{value}" if value
60
117
  lines << " alias: #{short_name}" if short_name
61
118
  lines << " desc: #{description}" if description
62
119
  meta.each { |k, v| lines << " #{k}: #{v}" } unless meta.empty?
data/lib/hiiro/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  class Hiiro
2
- VERSION = "0.1.337"
2
+ VERSION = "0.1.338"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hiiro
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.337
4
+ version: 0.1.338
5
5
  platform: ruby
6
6
  authors:
7
7
  - Joshua Toyota