hiiro 0.1.348 → 0.1.350

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: 20a3fd56855ee92e8afd85441d4ba206d5b3efd4c02a1300f6d7d3e08c3c942d
4
- data.tar.gz: 637f4edc0280bec7bc9a4fa9586dadd5ad91edc4fe4f5dc2af86cb0bd712f21d
3
+ metadata.gz: 0f1727aa12c60ba32f3afd7c9594a51a9e7c3bab2fb1e24119e81555c06e0e89
4
+ data.tar.gz: ce2ea35ccd0c60690f4abe7ad964b042ece8b95059d85689e90bc6997602bafd
5
5
  SHA512:
6
- metadata.gz: 39839806c55912e229c0f1fff787ae797c1a9263a1474dd7553b37a9375063513addb302050ef795c1da81662362a819e540632938352ab86daa7fc8c1e21067
7
- data.tar.gz: f1e9690bc7ead770d11d884a0b7998ed6f1a6bb93245d9a22754769c20a1c71af965c5ad722a19af7d66099825b671f306c2e128b320bde315958d0f5b85341c
6
+ metadata.gz: 5d965fb32f1b0ca1a8311aabd72e4aefd37a19f476045ddc4f03a04488ce46d042f184895578d1cb86c854204fb8b4bab77a434179310be04c0b8e41f0d5b679
7
+ data.tar.gz: 76b0ce221f25249c2ae8f286ba1b14a3ee52094663750a2d2bb4049d2eabbcba2a210a0e89420f0f785ee2ee2b869a13c0b36032cf2da40e1e71893945e5b9a0
data/.DS_Store ADDED
Binary file
data/CHANGELOG.md CHANGED
@@ -1,5 +1,20 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.1.350] - 2026-04-18
4
+
5
+ ### Added
6
+ - `h-capture` command and `Hiiro::Capture` module for clipboard/selection capture
7
+
8
+ ### Changed
9
+ - Optimize `Hiiro::Shell::Result#plain_text` and `#lines` with instance-level caching
10
+ - Refactor `Shell::Result#lines` to use `String#lines(chomp: true)` for improved line handling
11
+ - Reduce Claude API effort to `low` in publish script for faster changelog generation
12
+
13
+ ## [0.1.349] - 2026-04-17
14
+
15
+ ### Removed
16
+ - `h task branches` and `h task wtrees` convenience subcommands; use `h branch` and `h wtree` directly instead
17
+
3
18
  ## [0.1.348] - 2026-04-17
4
19
 
5
20
  ### Added
@@ -295,93 +310,4 @@
295
310
  - `h db cleanup` subcommand to preview and prune duplicate rows from SQLite tables
296
311
 
297
312
  ### Fixed
298
- - Prevent duplicate pinned_prs during import with `insert_conflict` and per-row rescue
299
-
300
- ## [0.1.308.pre.6] - 2026-03-31
301
-
302
- ### Fixed
303
- - Prevent duplicate pinned_prs during import with `insert_conflict` and per-row rescue
304
-
305
- ## [0.1.308.pre.5] - 2026-03-31
306
-
307
- ### Added
308
- - `h-claude vim` subcommand to open all matched files in `$EDITOR`
309
-
310
- ### Fixed
311
- - `h branch ls` now sorts oldest-first so most recent branches appear at bottom
312
-
313
- ## [0.1.308.pre.4] - 2026-03-31
314
-
315
- ### Fixed
316
- - Don't pass empty string arg to gem when `--pre` is false
317
-
318
- ## [0.1.308.pre.3] - 2026-03-31
319
-
320
- ### Changed
321
- - Poll RubyGems in `delayed_update` instead of blind sleep for more reliable version detection
322
-
323
- ### Fixed
324
- - Per-row rescue in `import_todos` so one bad row doesn't abort the entire batch
325
-
326
- ## [0.1.308.pre.2] - 2026-03-31
327
-
328
- ### Added
329
- - `--pre`/`-p` flag to `h install` and `h update` for installing/updating pre-release versions
330
-
331
- ### Changed
332
- - Merge `prs` and `pinned_prs` tables into single `prs` table in SQLite schema
333
- - Refactor PR storage to use unified table structure
334
-
335
- ### Fixed
336
- - YAML migration for todos, prs, pinned_prs, and tags to correctly handle merged schema
337
-
338
- ## [0.1.308.pre.1] - 2026-03-31
339
-
340
- ### Added
341
- - `Hiiro::Effects` injectable interface for testable file system and command execution
342
- - `null_fs` to `TestHarness` for testing without side effects
343
- - Effects helpers and accessors to `TestHarness` for controlled effect simulation
344
- - `Hiiro::Invocation` and `Hiiro::InvocationResolution` tracking in PaneHome SQLite migration
345
-
346
- ### Changed
347
- - Refactor effects layer: expose `executor` and `fs` as accessors on `Hiiro::Effects`
348
- - `h-db` command now includes h-pane in SQLite migration
349
- - Gem version handling: treat non-main branches as pre-release in publish script
350
-
351
- ### Fixed
352
- - `h-branch co` and `h-branch rm` restore extra argument pass-through
353
- - Test suite: add missing `TestHarness` stubs and fix pre-existing test failures
354
- - Test fixtures: anchor `load_bin` path to project root instead of `Dir.pwd`
355
-
356
- ### Deprecated
357
- - `SystemCallCapture` — use `Hiiro::Effects` helpers in `TestHarness` instead
358
-
359
- ## [0.1.307]
360
-
361
- ### Added
362
- - `Hiiro::DB` — SQLite foundation via Sequel; `DB.setup!` creates all tables, `DB.connection` establishes connection eagerly at load time; supports `HIIRO_TEST_DB=sqlite::memory:` for tests
363
- - `lib/hiiro/db.rb` — one-time YAML→SQLite migration (`migrate_yaml!`) guarded by `schema_migrations` table; dual-write mode (`dual_write?` / `disable_dual_write!`) for gradual cutover
364
- - `lib/hiiro/branch.rb` — `Hiiro::Branch` Sequel model for worktree branch records
365
- - `lib/hiiro/tracked_pr.rb` — `Hiiro::TrackedPr` Sequel model for tracked PR records (`:prs` table)
366
- - `lib/hiiro/link.rb` — `Hiiro::Link` Sequel model with `matches?`, `display_string`, `to_h` helpers
367
- - `lib/hiiro/project.rb` — `Hiiro::Project` Sequel model
368
- - `lib/hiiro/pane_home.rb` — `Hiiro::PaneHome` Sequel model with `data_json` JSON blob
369
- - `lib/hiiro/pin_record.rb` — `Hiiro::PinRecord` Sequel model for per-command key-value pin storage
370
- - `lib/hiiro/task_record.rb` — `Hiiro::TaskRecord` Sequel model for task metadata
371
- - `lib/hiiro/app_record.rb` — `Hiiro::AppRecord` Sequel model for app directory mappings
372
- - `lib/hiiro/assignment.rb` — `Hiiro::Assignment` Sequel model for worktree→branch assignments
373
- - `lib/hiiro/reminder.rb` — `Hiiro::Reminder` Sequel model
374
- - `lib/hiiro/invocation.rb` — `Hiiro::Invocation` and `Hiiro::InvocationResolution` Sequel models; every CLI invocation is recorded to SQLite for history/analytics
375
- - `bin/h-db` — new subcommand: `h db status`, `h db tables`, `h db q <sql>`, `h db migrate`, `h db restore`
376
-
377
- ### Changed
378
- - `lib/hiiro/todo.rb` — `TodoItem` is now a `Sequel::Model`; `TodoManager` reads/writes via SQLite with YAML dual-write fallback
379
- - `lib/hiiro/tags.rb` — `Tag` is now a `Sequel::Model`; tag operations persist to SQLite with YAML dual-write fallback
380
- - `lib/hiiro/pinned_pr_manager.rb` — `PinnedPR` is now a `Sequel::Model` (`lib/hiiro/pinned_pr.rb`); `PinnedPRManager` reads/writes via SQLite with YAML dual-write
381
- - `lib/hiiro/projects.rb` — `Projects#from_config` reads from `Hiiro::Project` SQLite model with YAML fallback
382
- - `lib/hiiro/tasks.rb` — `TaskManager::Config` reads/writes tasks and apps via `Hiiro::TaskRecord` and `Hiiro::AppRecord` SQLite models
383
- - `bin/h-branch` — `BranchManager` reads/writes via `Hiiro::Branch` and `Hiiro::TrackedPr` SQLite models with YAML dual-write fallback; adds `q`/`query` subcommands for raw SQL inspection
384
- - `bin/h-link` — reads/writes links via `Hiiro::Link` SQLite model with YAML dual-write fallback; adds `q`/`query` subcommands
385
- - `bin/h-pane` — load/save pane homes via `Hiiro::PaneHome` model with YAML dual-write
386
- - `bin/h-pr` — adds `q`/`query` subcommands for inspecting PR records via raw SQL
387
- - `plugins/pins.rb` — `Pin` class reads/writes via `Hiiro::PinRecord` SQLite model with YAML dual-write fallback
313
+ - Prevent duplicate pinned_prs during import with `insert_conflict` and per-row rescue
data/bin/h-capture ADDED
@@ -0,0 +1,175 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'fileutils'
4
+ require 'open3'
5
+ require 'time'
6
+ require 'hiiro'
7
+
8
+ CAPTURES_DIR = File.expand_path('~/.local/share/hiiro/captures')
9
+
10
+ # TODO(USER): implement resolve_path.
11
+ #
12
+ # Given a name-or-path string from `h capture file <fpath_or_name> ...`,
13
+ # return the absolute filesystem path where the capture should be written.
14
+ #
15
+ # Spec from the user:
16
+ # - If the input has NO path separators (just a bare filename like "build.log"),
17
+ # the file goes in CAPTURES_DIR.
18
+ # - Otherwise it's a path expression — write it relative to the current
19
+ # working directory (or honor it as-is if already absolute).
20
+ #
21
+ # Open design questions for you to decide:
22
+ # - Should "~/foo.log" be expanded? (File.expand_path handles this for free)
23
+ # - Should we ensure parent dirs exist via FileUtils.mkdir_p?
24
+ # - Should paths starting with "./" be normalized?
25
+ #
26
+ # Whichever rules you pick, this 5–8 line method is the contract for where
27
+ # `h capture file` writes — so it's worth getting right for your workflow.
28
+ def resolve_path(name_or_path)
29
+ raise NotImplementedError, "resolve_path not yet implemented — see TODO in bin/h-capture"
30
+ end
31
+
32
+ def ensure_dir(path)
33
+ FileUtils.mkdir_p(File.dirname(path))
34
+ end
35
+
36
+ # Run cmd, tee combined stdout+stderr to terminal AND to output_path.
37
+ # If our own stdin is piped (not a tty), forward it into the subprocess.
38
+ def run_and_capture(cmd_args, output_path)
39
+ ensure_dir(output_path)
40
+ exit_status = nil
41
+
42
+ File.open(output_path, 'w') do |f|
43
+ Open3.popen2e(*cmd_args) do |stdin, stdout_err, wait_thr|
44
+ pipe_thread = if !STDIN.tty?
45
+ Thread.new do
46
+ IO.copy_stream(STDIN, stdin)
47
+ rescue Errno::EPIPE, IOError
48
+ # subprocess closed stdin early — fine
49
+ ensure
50
+ stdin.close rescue nil
51
+ end
52
+ else
53
+ stdin.close
54
+ nil
55
+ end
56
+
57
+ loop do
58
+ chunk = stdout_err.readpartial(4096)
59
+ $stdout.write(chunk)
60
+ $stdout.flush
61
+ f.write(chunk)
62
+ rescue EOFError
63
+ break
64
+ end
65
+
66
+ pipe_thread&.join
67
+ exit_status = wait_thr.value.exitstatus
68
+ end
69
+ end
70
+
71
+ exit_status
72
+ end
73
+
74
+ def fetch_capture(num)
75
+ Hiiro::Capture.at_offset(num.to_i)
76
+ end
77
+
78
+ def record_capture(name:, path:, command:, exit_status:)
79
+ Hiiro::Capture.create(
80
+ name: name,
81
+ path: path,
82
+ command: command,
83
+ exit_status: exit_status
84
+ )
85
+ end
86
+
87
+ Hiiro.run(*ARGV) do
88
+ add_subcmd(:new) do |*args|
89
+ if args.empty?
90
+ puts "Usage: h capture new <command> [args...]"
91
+ exit 1
92
+ end
93
+
94
+ name = "#{Time.now.strftime('%Y%m%d%H%M%S')}.output"
95
+ path = File.join(CAPTURES_DIR, name)
96
+ ensure_dir(path)
97
+
98
+ code = run_and_capture(args, path)
99
+ record_capture(name: name, path: path, command: args.join(' '), exit_status: code)
100
+ warn "\n[capture saved: #{path} (exit #{code})]"
101
+ end
102
+
103
+ add_subcmd(:file) do |fpath = nil, *args|
104
+ if fpath.nil? || args.empty?
105
+ puts "Usage: h capture file <fpath_or_name> <command> [args...]"
106
+ exit 1
107
+ end
108
+
109
+ path = resolve_path(fpath)
110
+ name = File.basename(fpath)
111
+
112
+ code = run_and_capture(args, path)
113
+ record_capture(name: name, path: path, command: args.join(' '), exit_status: code)
114
+ warn "\n[capture saved: #{path} (exit #{code})]"
115
+ end
116
+
117
+ add_subcmd(:ls) do |num = nil|
118
+ captures = if num.nil?
119
+ Hiiro::Capture.recent
120
+ elsif num.to_i >= 0
121
+ cap = Hiiro::Capture.at_offset(num.to_i)
122
+ cap ? [cap] : []
123
+ else
124
+ Hiiro::Capture.recent(num.to_i.abs)
125
+ end
126
+
127
+ if captures.empty?
128
+ puts "No captures."
129
+ next
130
+ end
131
+
132
+ captures.each_with_index { |cap, i| puts cap.display_string(i) }
133
+ end
134
+
135
+ add_subcmd(:cat) do |num = 0|
136
+ cap = fetch_capture(num)
137
+ if cap.nil?
138
+ warn "No capture at offset #{num}."
139
+ exit 1
140
+ end
141
+ unless File.exist?(cap.path)
142
+ warn "File missing: #{cap.path}"
143
+ exit 1
144
+ end
145
+ $stdout.write(File.read(cap.path))
146
+ end
147
+
148
+ add_subcmd(:cppath) do |num = 0|
149
+ cap = fetch_capture(num)
150
+ if cap.nil?
151
+ warn "No capture at offset #{num}."
152
+ exit 1
153
+ end
154
+ Hiiro::Shell.pipe(cap.path, 'pbcopy')
155
+ puts "Copied path: #{cap.path}"
156
+ end
157
+
158
+ add_subcmd(:cp) do |num = 0|
159
+ cap = fetch_capture(num)
160
+ if cap.nil?
161
+ warn "No capture at offset #{num}."
162
+ exit 1
163
+ end
164
+ unless File.exist?(cap.path)
165
+ warn "File missing: #{cap.path}"
166
+ exit 1
167
+ end
168
+ Hiiro::Shell.pipe(File.read(cap.path), 'pbcopy')
169
+ puts "Copied contents of: #{cap.path}"
170
+ end
171
+
172
+ add_subcmd(:path) do
173
+ print CAPTURES_DIR
174
+ end
175
+ end
@@ -0,0 +1,42 @@
1
+ require 'sequel'
2
+
3
+ class Hiiro
4
+ class Capture < Sequel::Model(:captures)
5
+ Hiiro::DB.register(self)
6
+
7
+ def self.create_table!(db)
8
+ db.create_table?(:captures) do
9
+ primary_key :id
10
+ String :name, null: false
11
+ String :path, null: false
12
+ String :command
13
+ Integer :exit_status
14
+ end
15
+ end
16
+
17
+ # Most-recent-first scope. id is autoincrement, so desc(:id) == chronological reverse.
18
+ def self.recent(limit = nil)
19
+ ds = order(Sequel.desc(:id))
20
+ limit ? ds.limit(limit).all : ds.all
21
+ end
22
+
23
+ # Fetch the capture at offset n from the most recent (0 = newest).
24
+ def self.at_offset(n)
25
+ order(Sequel.desc(:id)).offset(n.to_i).first
26
+ end
27
+
28
+ def status_glyph
29
+ case exit_status
30
+ when 0 then "\e[32m✓\e[0m"
31
+ when nil then "\e[33m?\e[0m"
32
+ else "\e[31m✗\e[0m"
33
+ end
34
+ end
35
+
36
+ def display_string(idx)
37
+ cmd = command.to_s
38
+ cmd = cmd[0, 57] + '…' if cmd.length > 60
39
+ format("%4d. %s %-22s %s", idx, status_glyph, name, cmd)
40
+ end
41
+ end
42
+ end
data/lib/hiiro/shell.rb CHANGED
@@ -77,6 +77,21 @@ class Hiiro
77
77
  end
78
78
 
79
79
  class Result
80
+ # Factory: reads chunks from an IO (popen handle), optionally tee-ing
81
+ # each chunk to `tee` as it arrives. Used by Shell.stream / stream_combined.
82
+ # Pass tee: nil to capture without printing.
83
+ def self.collect_chunks(io, wait_thr, tee: $stdout)
84
+ output = +""
85
+ loop do
86
+ chunk = io.readpartial(4096)
87
+ tee&.write(chunk)
88
+ output << chunk
89
+ rescue EOFError
90
+ break
91
+ end
92
+ new(output, wait_thr.value)
93
+ end
94
+
80
95
  # Matches the full ANSI/VT100 escape sequence spec:
81
96
  # cursor movement, erase, colors, SGR — everything a terminal interprets.
82
97
  # [^[] catches all single-char Fe sequences (e.g. \eM, \eD); \[...] catches CSI.
@@ -115,27 +130,12 @@ class Hiiro
115
130
  # Strip ANSI escape codes for text processing or filtering.
116
131
  # Also strips bare \r (carriage-return-only, used by progress bars).
117
132
  def plain_text
118
- stdout.gsub(ANSI_PATTERN, '').gsub(/\r(?!\n)/, '')
133
+ @plain_text ||= stdout.gsub(ANSI_PATTERN, '').gsub(/\r(?!\n)/, '')
119
134
  end
120
135
 
121
136
  # Plain text split into non-empty lines.
122
137
  def lines
123
- plain_text.split("\n").reject(&:empty?)
124
- end
125
-
126
- # Factory: reads chunks from an IO (popen handle), optionally tee-ing
127
- # each chunk to `tee` as it arrives. Used by Shell.stream / stream_combined.
128
- # Pass tee: nil to capture without printing.
129
- def self.collect_chunks(io, wait_thr, tee: $stdout)
130
- output = +""
131
- loop do
132
- chunk = io.readpartial(4096)
133
- tee&.write(chunk)
134
- output << chunk
135
- rescue EOFError
136
- break
137
- end
138
- new(output, wait_thr.value)
138
+ @lines ||= plain_text.lines(chomp: true)
139
139
  end
140
140
  end
141
141
  end
data/lib/hiiro/tasks.rb CHANGED
@@ -1410,14 +1410,6 @@ class Hiiro
1410
1410
  h.add_subcmd(:prs) do |*args|
1411
1411
  exec('h', 'pr', *args)
1412
1412
  end
1413
-
1414
- h.add_subcmd(:branches) do |*args|
1415
- exec('h', 'branch', *args)
1416
- end
1417
-
1418
- h.add_subcmd(:wtrees) do |*args|
1419
- exec('h', 'wtree', *args)
1420
- end
1421
1413
  end
1422
1414
 
1423
1415
  task_hiiro
data/lib/hiiro/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  class Hiiro
2
- VERSION = "0.1.348"
2
+ VERSION = "0.1.350"
3
3
  end
data/lib/hiiro.rb CHANGED
@@ -21,6 +21,7 @@ require_relative "hiiro/options"
21
21
  require_relative "hiiro/input_file"
22
22
  require_relative "hiiro/paths"
23
23
  require_relative "hiiro/link"
24
+ require_relative "hiiro/capture"
24
25
  require_relative "hiiro/branch"
25
26
  require_relative "hiiro/check_run"
26
27
  require_relative "hiiro/tags"
data/script/publish CHANGED
@@ -166,7 +166,7 @@ class Claude
166
166
  }
167
167
  PROMPT
168
168
 
169
- raw = IO.popen(["claude", "-p", "--model", MODEL], "r+") { |io|
169
+ raw = IO.popen(["claude", "-p", "--model", MODEL, '--effort', 'low'], "r+") { |io|
170
170
  io.write(prompt)
171
171
  io.close_write
172
172
  io.read
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.348
4
+ version: 0.1.350
5
5
  platform: ruby
6
6
  authors:
7
7
  - Joshua Toyota
@@ -117,6 +117,7 @@ executables:
117
117
  extensions: []
118
118
  extra_rdoc_files: []
119
119
  files:
120
+ - ".DS_Store"
120
121
  - ".config/.keep"
121
122
  - CHANGELOG.md
122
123
  - CLAUDE.md
@@ -130,6 +131,7 @@ files:
130
131
  - bin/h-bin
131
132
  - bin/h-branch
132
133
  - bin/h-buffer
134
+ - bin/h-capture
133
135
  - bin/h-claude
134
136
  - bin/h-commit
135
137
  - bin/h-config
@@ -325,6 +327,7 @@ files:
325
327
  - lib/hiiro/background.rb
326
328
  - lib/hiiro/bins.rb
327
329
  - lib/hiiro/branch.rb
330
+ - lib/hiiro/capture.rb
328
331
  - lib/hiiro/check_run.rb
329
332
  - lib/hiiro/config.rb
330
333
  - lib/hiiro/db.rb