hiiro 0.1.308.pre.6 → 0.1.309

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: c2e93dab3f776838c51b113721effb0ac86a0cbc20dd9a61742004d5a5335a6e
4
- data.tar.gz: a1ae67e29ac11aec8f3e476dbd708cf7ec3d5b85967d78a1565c3df193af4a1d
3
+ metadata.gz: 64fee11a94745ab455e4a3681d71b101db2319eb1def5ab5fc884191e5289bb2
4
+ data.tar.gz: 4508a89bfc1a9a0ce5570820346db8fa09434b62e8b21c8b83ee9fa6bd384a10
5
5
  SHA512:
6
- metadata.gz: bea26329f94d13d1806fb90603b9c23c7f41dd42eb1e954ba8d6c6a4bd2f8e9ed88e80770314e4b3a6ec0223115f9a82ae633e547e4252ba2b84626ff3dee6dd
7
- data.tar.gz: 36c1711d34c509e4070aed248c030601a87801a02e8a15aa2ad806ed475d1e2f8792b30903c35ea3a513ed479db5ec903ca95a1bf099285840ae5453bc64fa15
6
+ metadata.gz: d0a2039f5a8c1717c94bfcf010d8b59629666eb15a03316f7d9a07be5aacdff4d6a1becca8f0f03079a4a46e6a7ac850a9a3283008ccf3cc905ba98a89fa98f4
7
+ data.tar.gz: 76cd5e53ff951e720b2544c01653766573e61b132eab4499c3b0e95a5d10707a61ac7fffde7d4a266b1896627cab6d57198eb99aa7896f2ef7103bececa2f357
data/CHANGELOG.md CHANGED
@@ -1,6 +1,22 @@
1
1
  ```markdown
2
2
  # Changelog
3
3
 
4
+ ## [0.1.309] - 2026-03-31
5
+
6
+ ### Added
7
+ - `h link tag` support for tagging links in the link manager
8
+
9
+ ### Fixed
10
+ - Correct argument passing in `run_child` to prevent arg dropping in nested Hiiro instances
11
+
12
+ ## [0.1.308] - 2026-03-31
13
+
14
+ ### Added
15
+ - `h db cleanup` subcommand to preview and prune duplicate rows from SQLite tables
16
+
17
+ ### Fixed
18
+ - Prevent duplicate pinned_prs during import with `insert_conflict` and per-row rescue
19
+
4
20
  ## [0.1.308.pre.6] - 2026-03-31
5
21
 
6
22
  ### Fixed
data/bin/h-db CHANGED
@@ -171,6 +171,104 @@ Hiiro.run(*ARGV) do
171
171
  Hiiro::DB.remigrate!(only: tables)
172
172
  end
173
173
 
174
+ add_subcmd(:cleanup) do
175
+ require 'fileutils'
176
+ db = Hiiro::DB.connection
177
+ timestamp = Time.now.strftime('%Y%m%d%H%M%S')
178
+ sql_path = File.expand_path("~/notes/files/hiiro-cleanup-#{timestamp}.sql")
179
+ FileUtils.mkdir_p(File.dirname(sql_path))
180
+
181
+ # Natural unique keys per table — used to detect duplicate groups
182
+ dedup_keys = {
183
+ prs: %w[number],
184
+ branches: %w[name],
185
+ tags: %w[name taggable_type taggable_id],
186
+ links: %w[url],
187
+ tasks: %w[name],
188
+ apps: %w[name],
189
+ projects: %w[name],
190
+ assignments: %w[worktree],
191
+ pins: %w[command key],
192
+ pane_homes: %w[name],
193
+ check_runs: %w[pr_number name],
194
+ reminders: %w[text],
195
+ }
196
+
197
+ lines = []
198
+ lines << "-- Hiiro DB duplicate cleanup — #{Time.now.iso8601}"
199
+ lines << "-- Review each statement. Remove lines you do NOT want to run, then:"
200
+ lines << "--"
201
+ lines << "-- sqlite3 #{Hiiro::DB::DB_FILE} < #{sql_path}"
202
+ lines << "--"
203
+ lines << "-- Or run individual statements with:"
204
+ lines << "--"
205
+ lines << "-- h db q \"DELETE FROM ...\""
206
+ lines << "--"
207
+ lines << ""
208
+
209
+ found_any = false
210
+
211
+ dedup_keys.each do |table, keys|
212
+ next unless db.table_exists?(table)
213
+ schema_cols = db.schema(table).map { |col, _| col.to_s }
214
+ next unless (keys - schema_cols).empty?
215
+ next unless schema_cols.include?('id')
216
+
217
+ key_cols_sql = keys.map { |k| "\"#{k}\"" }.join(', ')
218
+ dupes = db.fetch(<<~SQL).all
219
+ SELECT #{key_cols_sql}, COUNT(*) AS cnt
220
+ FROM #{table}
221
+ GROUP BY #{key_cols_sql}
222
+ HAVING cnt > 1
223
+ SQL
224
+ next if dupes.empty?
225
+
226
+ found_any = true
227
+ lines << "-- ===== #{table}: #{dupes.length} duplicate group#{'s' unless dupes.length == 1} ====="
228
+ lines << ""
229
+
230
+ dupes.each do |row|
231
+ # Build a Sequel dataset filtered to this duplicate group
232
+ ds = db[table]
233
+ keys.each do |k|
234
+ val = row[k.to_sym]
235
+ ds = val.nil? ? ds.where(Sequel.lit("\"#{k}\" IS NULL")) : ds.where(k.to_sym => val)
236
+ end
237
+
238
+ all_ids = ds.select(:id).map(:id).sort
239
+ keep_id = all_ids.max
240
+ drop_ids = all_ids - [keep_id]
241
+
242
+ key_desc = keys.map { |k| "#{k}=#{row[k.to_sym].inspect}" }.join(', ')
243
+ lines << "-- #{table}: #{key_desc}"
244
+ lines << "-- keeping id=#{keep_id}, dropping id=#{drop_ids.join(', ')}"
245
+ lines << "DELETE FROM #{table} WHERE id IN (#{drop_ids.join(', ')});"
246
+ lines << ""
247
+ end
248
+ end
249
+
250
+ if found_any
251
+ File.write(sql_path, lines.join("\n"))
252
+
253
+ # Update ~/notes/files/INDEX
254
+ index_path = File.expand_path('~/notes/files/INDEX')
255
+ File.open(index_path, 'a') { |f| f.puts sql_path }
256
+
257
+ edit_files(sql_path)
258
+
259
+ puts
260
+ puts "SQL file: #{sql_path}"
261
+ puts
262
+ puts "To apply after editing:"
263
+ puts " sqlite3 #{Hiiro::DB::DB_FILE} < #{sql_path}"
264
+ puts
265
+ puts "Or run individual statements with:"
266
+ puts " h db q \"DELETE FROM ...\""
267
+ else
268
+ puts "No duplicates found across tracked tables."
269
+ end
270
+ end
271
+
174
272
  add_subcmd(:restore) do
175
273
  config_dir = File.expand_path('~/.config/hiiro')
176
274
  archives = Dir.glob(File.join(config_dir, 'sqlite-migration.*.tar.gz')).sort
data/bin/h-link CHANGED
@@ -8,7 +8,9 @@ require 'tempfile'
8
8
  require "hiiro"
9
9
 
10
10
  opts = Hiiro::Options.setup {
11
- option(:shorthand, short: :s)
11
+ option(:shorthand, short: :s, desc: 'Shorthand alias for the link')
12
+ option(:tag, short: :t, multi: true, desc: 'Tag for the link (repeatable)')
13
+ option(:tags, multi: true, desc: 'Tag for the link (alias for --tag, repeatable)')
12
14
  }
13
15
 
14
16
  class LinkManager
@@ -262,7 +264,8 @@ Hiiro.run(*ARGV, plugins: [Pins], links_file: lm.links_file) do
262
264
 
263
265
  url = add_args.shift
264
266
  vals = opts.parse!(add_args)
265
- description = add_args.join(' ')
267
+ description = vals.args.join(' ')
268
+ tags = (Array(vals.tag) + Array(vals.tags)).uniq.reject(&:empty?)
266
269
 
267
270
  new_link = Hiiro::Link.create(
268
271
  url: url,
@@ -270,6 +273,7 @@ Hiiro.run(*ARGV, plugins: [Pins], links_file: lm.links_file) do
270
273
  shorthand: vals.shorthand,
271
274
  created_at: Time.now.iso8601
272
275
  )
276
+ Hiiro::Tag.tag!(new_link, *tags) if tags.any?
273
277
  lm.save_yaml_backup
274
278
 
275
279
  puts "Saved link ##{Hiiro::Link.count}: #{url}"
@@ -472,6 +476,30 @@ Hiiro.run(*ARGV, plugins: [Pins], links_file: lm.links_file) do
472
476
  system('open', url)
473
477
  end
474
478
 
479
+ add_subcmd(:paste) do |*paste_args|
480
+ url = `pbpaste`.strip
481
+
482
+ if url.empty?
483
+ puts "Clipboard is empty."
484
+ exit 1
485
+ end
486
+
487
+ vals = opts.parse!(paste_args)
488
+ description = vals.args.join(' ')
489
+ tags = (Array(vals.tag) + Array(vals.tags)).uniq.reject(&:empty?)
490
+
491
+ new_link = Hiiro::Link.create(
492
+ url: url,
493
+ description: description,
494
+ shorthand: vals.shorthand,
495
+ created_at: Time.now.iso8601
496
+ )
497
+ Hiiro::Tag.tag!(new_link, *tags) if tags.any?
498
+ lm.save_yaml_backup
499
+
500
+ puts "Saved link ##{Hiiro::Link.count}: #{url}"
501
+ end
502
+
475
503
  add_subcmd(:path) do |*path_args|
476
504
  print lm.links_file
477
505
  end
data/lib/hiiro/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  class Hiiro
2
- VERSION = "0.1.308.pre.6"
2
+ VERSION = "0.1.309"
3
3
  end
data/lib/hiiro.rb CHANGED
@@ -229,7 +229,7 @@ class Hiiro
229
229
  block.arity == 1 ? block.call(h) : h.instance_eval(&block) if block
230
230
  end
231
231
 
232
- Hiiro.init(bin_name: child_bin_name, args: child_args, **kwargs, &wrapper)
232
+ Hiiro.init(child_bin_name, *child_args, **kwargs, &wrapper)
233
233
  end
234
234
 
235
235
  def run_child(custom_subcmd=nil, custom_args=nil, **kwargs, &block)
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.308.pre.6
4
+ version: 0.1.309
5
5
  platform: ruby
6
6
  authors:
7
7
  - Joshua Toyota