hiiro 0.1.349 → 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: d6b10e8a634a24ac7953cb7a8639574cd7e8b7b33b4876d6930bbdc5edc2a938
4
- data.tar.gz: 2ea99568dc1b989af28b281268587f7c33c1f5174ed115935e938b0a2f21dc86
3
+ metadata.gz: 0f1727aa12c60ba32f3afd7c9594a51a9e7c3bab2fb1e24119e81555c06e0e89
4
+ data.tar.gz: ce2ea35ccd0c60690f4abe7ad964b042ece8b95059d85689e90bc6997602bafd
5
5
  SHA512:
6
- metadata.gz: 7e8c40d072f6e425770b8b817c08e35aca290ce8af7468e3ddb8bde5f2f5c137055843210abb08b241f36562bad44b779790aad009998cb2172adf649a529ead
7
- data.tar.gz: 5e83c626d13d0b0497c95a3a159eb20b6bffecb6168f8b7d2290a3cd89c312a0038aaf5dc3339a28bc448d5655b87cccffabc848c17bd857b81a9cde28a408c3
6
+ metadata.gz: 5d965fb32f1b0ca1a8311aabd72e4aefd37a19f476045ddc4f03a04488ce46d042f184895578d1cb86c854204fb8b4bab77a434179310be04c0b8e41f0d5b679
7
+ data.tar.gz: 76b0ce221f25249c2ae8f286ba1b14a3ee52094663750a2d2bb4049d2eabbcba2a210a0e89420f0f785ee2ee2b869a13c0b36032cf2da40e1e71893945e5b9a0
data/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
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
+
3
13
  ## [0.1.349] - 2026-04-17
4
14
 
5
15
  ### Removed
@@ -300,93 +310,4 @@
300
310
  - `h db cleanup` subcommand to preview and prune duplicate rows from SQLite tables
301
311
 
302
312
  ### Fixed
303
- - Prevent duplicate pinned_prs during import with `insert_conflict` and per-row rescue
304
-
305
- ## [0.1.308.pre.6] - 2026-03-31
306
-
307
- ### Fixed
308
- - Prevent duplicate pinned_prs during import with `insert_conflict` and per-row rescue
309
-
310
- ## [0.1.308.pre.5] - 2026-03-31
311
-
312
- ### Added
313
- - `h-claude vim` subcommand to open all matched files in `$EDITOR`
314
-
315
- ### Fixed
316
- - `h branch ls` now sorts oldest-first so most recent branches appear at bottom
317
-
318
- ## [0.1.308.pre.4] - 2026-03-31
319
-
320
- ### Fixed
321
- - Don't pass empty string arg to gem when `--pre` is false
322
-
323
- ## [0.1.308.pre.3] - 2026-03-31
324
-
325
- ### Changed
326
- - Poll RubyGems in `delayed_update` instead of blind sleep for more reliable version detection
327
-
328
- ### Fixed
329
- - Per-row rescue in `import_todos` so one bad row doesn't abort the entire batch
330
-
331
- ## [0.1.308.pre.2] - 2026-03-31
332
-
333
- ### Added
334
- - `--pre`/`-p` flag to `h install` and `h update` for installing/updating pre-release versions
335
-
336
- ### Changed
337
- - Merge `prs` and `pinned_prs` tables into single `prs` table in SQLite schema
338
- - Refactor PR storage to use unified table structure
339
-
340
- ### Fixed
341
- - YAML migration for todos, prs, pinned_prs, and tags to correctly handle merged schema
342
-
343
- ## [0.1.308.pre.1] - 2026-03-31
344
-
345
- ### Added
346
- - `Hiiro::Effects` injectable interface for testable file system and command execution
347
- - `null_fs` to `TestHarness` for testing without side effects
348
- - Effects helpers and accessors to `TestHarness` for controlled effect simulation
349
- - `Hiiro::Invocation` and `Hiiro::InvocationResolution` tracking in PaneHome SQLite migration
350
-
351
- ### Changed
352
- - Refactor effects layer: expose `executor` and `fs` as accessors on `Hiiro::Effects`
353
- - `h-db` command now includes h-pane in SQLite migration
354
- - Gem version handling: treat non-main branches as pre-release in publish script
355
-
356
- ### Fixed
357
- - `h-branch co` and `h-branch rm` restore extra argument pass-through
358
- - Test suite: add missing `TestHarness` stubs and fix pre-existing test failures
359
- - Test fixtures: anchor `load_bin` path to project root instead of `Dir.pwd`
360
-
361
- ### Deprecated
362
- - `SystemCallCapture` — use `Hiiro::Effects` helpers in `TestHarness` instead
363
-
364
- ## [0.1.307]
365
-
366
- ### Added
367
- - `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
368
- - `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
369
- - `lib/hiiro/branch.rb` — `Hiiro::Branch` Sequel model for worktree branch records
370
- - `lib/hiiro/tracked_pr.rb` — `Hiiro::TrackedPr` Sequel model for tracked PR records (`:prs` table)
371
- - `lib/hiiro/link.rb` — `Hiiro::Link` Sequel model with `matches?`, `display_string`, `to_h` helpers
372
- - `lib/hiiro/project.rb` — `Hiiro::Project` Sequel model
373
- - `lib/hiiro/pane_home.rb` — `Hiiro::PaneHome` Sequel model with `data_json` JSON blob
374
- - `lib/hiiro/pin_record.rb` — `Hiiro::PinRecord` Sequel model for per-command key-value pin storage
375
- - `lib/hiiro/task_record.rb` — `Hiiro::TaskRecord` Sequel model for task metadata
376
- - `lib/hiiro/app_record.rb` — `Hiiro::AppRecord` Sequel model for app directory mappings
377
- - `lib/hiiro/assignment.rb` — `Hiiro::Assignment` Sequel model for worktree→branch assignments
378
- - `lib/hiiro/reminder.rb` — `Hiiro::Reminder` Sequel model
379
- - `lib/hiiro/invocation.rb` — `Hiiro::Invocation` and `Hiiro::InvocationResolution` Sequel models; every CLI invocation is recorded to SQLite for history/analytics
380
- - `bin/h-db` — new subcommand: `h db status`, `h db tables`, `h db q <sql>`, `h db migrate`, `h db restore`
381
-
382
- ### Changed
383
- - `lib/hiiro/todo.rb` — `TodoItem` is now a `Sequel::Model`; `TodoManager` reads/writes via SQLite with YAML dual-write fallback
384
- - `lib/hiiro/tags.rb` — `Tag` is now a `Sequel::Model`; tag operations persist to SQLite with YAML dual-write fallback
385
- - `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
386
- - `lib/hiiro/projects.rb` — `Projects#from_config` reads from `Hiiro::Project` SQLite model with YAML fallback
387
- - `lib/hiiro/tasks.rb` — `TaskManager::Config` reads/writes tasks and apps via `Hiiro::TaskRecord` and `Hiiro::AppRecord` SQLite models
388
- - `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
389
- - `bin/h-link` — reads/writes links via `Hiiro::Link` SQLite model with YAML dual-write fallback; adds `q`/`query` subcommands
390
- - `bin/h-pane` — load/save pane homes via `Hiiro::PaneHome` model with YAML dual-write
391
- - `bin/h-pr` — adds `q`/`query` subcommands for inspecting PR records via raw SQL
392
- - `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/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  class Hiiro
2
- VERSION = "0.1.349"
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.349
4
+ version: 0.1.350
5
5
  platform: ruby
6
6
  authors:
7
7
  - Joshua Toyota
@@ -131,6 +131,7 @@ files:
131
131
  - bin/h-bin
132
132
  - bin/h-branch
133
133
  - bin/h-buffer
134
+ - bin/h-capture
134
135
  - bin/h-claude
135
136
  - bin/h-commit
136
137
  - bin/h-config
@@ -326,6 +327,7 @@ files:
326
327
  - lib/hiiro/background.rb
327
328
  - lib/hiiro/bins.rb
328
329
  - lib/hiiro/branch.rb
330
+ - lib/hiiro/capture.rb
329
331
  - lib/hiiro/check_run.rb
330
332
  - lib/hiiro/config.rb
331
333
  - lib/hiiro/db.rb