hiiro 0.1.46 → 0.1.48

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: 38b5114c13aecafc04f977e28b3d1367dbdccaf6820c318cbcabff3fa6adceed
4
- data.tar.gz: 6d3f7b8b38955698b77fc7d4e6920afc6b1d5630df5e045a6bbce63784a22bb6
3
+ metadata.gz: 60d88cfd824ceff5b2fc117392fee54e69b05bd831d3cab05cd4fea07f0152ab
4
+ data.tar.gz: 2ee36dcee6939cf5e671617c53c4cc7cb052ae059df66d9cd0b1d147f38127c1
5
5
  SHA512:
6
- metadata.gz: 3d22cd8016c63f2c62c2d24c3f1f06860c57bd2348d54f33f74130efad5993cf95e6e93de2aeabe778ed063fa006f0e8c905dd4f1a70832f2226e5bf2bcb3d04
7
- data.tar.gz: c07e1243ee16e2bdcd8abf968669429b6c8fbdd1732f6f009daa4fc7dca6b85b98200882576cea7e918639b8b7ada9a13c146ae434c4fa18578efaea9492a669
6
+ metadata.gz: 2b25c56dc8a7d85db81b20609563f7929293f7437d56267f649a8a7582d0effa4228b7fcb262fc7cccf8c18c01375404b796fd27443b8a61bcd7d45bd9ece32b
7
+ data.tar.gz: e3ec792efe3604380f859b22b9c14cb8749b4c76e1b3684d3e29afe24f2c2ad865d2d978bd1cca46ef6c42d63ee62190a51a1b8fce2a018b258d5e739ff64d93
data/lib/hiiro/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  class Hiiro
2
- VERSION = "0.1.46"
2
+ VERSION = "0.1.48"
3
3
  end
data/plugins/tasks.rb CHANGED
@@ -678,7 +678,7 @@ class TaskManager
678
678
  end
679
679
  return nil if names.empty?
680
680
 
681
- sk_select(names)
681
+ sk_select(names.sort)
682
682
  end
683
683
 
684
684
  # --- Private helpers ---
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.46
4
+ version: 0.1.48
5
5
  platform: ruby
6
6
  authors:
7
7
  - Joshua Toyota
@@ -39,33 +39,24 @@ files:
39
39
  - README.md
40
40
  - Rakefile
41
41
  - TODO.md
42
- - bin/g-pr
43
42
  - bin/h
44
43
  - bin/h-app
45
44
  - bin/h-branch
46
45
  - bin/h-buffer
47
46
  - bin/h-config
48
- - bin/h-dot
49
- - bin/h-dotfiles
50
47
  - bin/h-home
51
48
  - bin/h-html
52
49
  - bin/h-link
53
50
  - bin/h-mic
54
51
  - bin/h-note
55
- - bin/h-osubtask
56
- - bin/h-otask
57
52
  - bin/h-pane
58
53
  - bin/h-plugin
59
54
  - bin/h-pr
60
- - bin/h-pr-monitor
61
- - bin/h-pr-watch
62
55
  - bin/h-project
63
- - bin/h-runtask
64
56
  - bin/h-serve
65
57
  - bin/h-session
66
58
  - bin/h-sha
67
59
  - bin/h-video
68
- - bin/h-vim
69
60
  - bin/h-window
70
61
  - bin/h-wtree
71
62
  - docs/README.md
data/bin/g-pr DELETED
@@ -1,327 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- require "hiiro"
4
- require "time"
5
- require "fileutils"
6
- require "yaml"
7
- require "json"
8
-
9
- Hiiro.load_env
10
- hiiro = Hiiro.init(*ARGV, plugins: [OldTask, Tmux, Pins])
11
-
12
- class PRManager
13
- attr_reader :hiiro
14
-
15
- def initialize(hiiro)
16
- @hiiro = hiiro
17
- end
18
-
19
- def help
20
- puts "Usage: h pr <subcommand> [args]"
21
- puts
22
- puts "Subcommands:"
23
- puts " save [PR_NUMBER] Record PR for this task (auto-detects if omitted)"
24
- puts " history List PR history (oldest to newest)"
25
- puts " history --worktree=X Filter by worktree"
26
- puts " history --task=X Filter by task"
27
- puts " history --session=X Filter by tmux session"
28
- puts " current Show current branch's PR info"
29
- puts " open [PR_NUMBER] Open PR in browser"
30
- puts " view [PR_NUMBER] View PR details in terminal"
31
- end
32
-
33
- def save(pr_number = nil)
34
- pr_info = fetch_pr_info(pr_number)
35
- unless pr_info
36
- puts "ERROR: Could not find PR"
37
- puts "Make sure you have the gh CLI installed and authenticated."
38
- return false
39
- end
40
-
41
- entry = build_entry(pr_info)
42
- unless entry[:task]
43
- puts "WARNING: Not in a task session, saving without task info"
44
- end
45
-
46
- data = load_data
47
- data['prs'] ||= []
48
-
49
- # Check if this PR is already recorded for this task
50
- existing = data['prs'].find do |p|
51
- p['number'] == pr_info['number'] && p['task'] == entry[:task]
52
- end
53
-
54
- if existing
55
- # Update existing entry
56
- existing.merge!(entry.transform_keys(&:to_s))
57
- existing['updated_at'] = Time.now.iso8601
58
- puts "Updated PR ##{pr_info['number']} for task '#{entry[:task]}'"
59
- else
60
- # Add new entry
61
- data['prs'] << entry.transform_keys(&:to_s).merge('created_at' => Time.now.iso8601)
62
- puts "Saved PR ##{pr_info['number']} for task '#{entry[:task]}'"
63
- end
64
-
65
- save_data(data)
66
- show_entry(entry)
67
- true
68
- end
69
-
70
- def history(args = [])
71
- filters = parse_filters(args)
72
- data = load_data
73
- prs = data['prs'] || []
74
-
75
- if prs.empty?
76
- puts "No PRs recorded."
77
- puts "Use 'h pr save' to record the current PR."
78
- return
79
- end
80
-
81
- # Apply filters
82
- prs = filter_entries(prs, filters)
83
-
84
- if prs.empty?
85
- puts "No PRs match the given filters."
86
- return
87
- end
88
-
89
- # Sort by created_at (oldest first)
90
- prs = prs.sort_by { |p| p['created_at'] || '' }
91
-
92
- puts "PR history (oldest to newest):"
93
- puts
94
- prs.each_with_index do |pr, idx|
95
- puts format_entry(pr, idx + 1)
96
- end
97
- end
98
-
99
- def current
100
- pr_info = fetch_pr_info
101
- unless pr_info
102
- puts "No PR found for current branch."
103
- puts "Create one with 'gh pr create' or specify a PR number."
104
- return false
105
- end
106
-
107
- entry = build_entry(pr_info)
108
- puts "Current PR info:"
109
- puts
110
- show_entry(entry)
111
- end
112
-
113
- def open(pr_number = nil)
114
- if pr_number
115
- system('gh', 'pr', 'view', pr_number.to_s, '--web')
116
- else
117
- system('gh', 'pr', 'view', '--web')
118
- end
119
- end
120
-
121
- def view(pr_number = nil)
122
- if pr_number
123
- system('gh', 'pr', 'view', pr_number.to_s)
124
- else
125
- system('gh', 'pr', 'view')
126
- end
127
- end
128
-
129
- private
130
-
131
- def fetch_pr_info(pr_number = nil)
132
- cmd = if pr_number
133
- ['gh', 'pr', 'view', pr_number.to_s, '--json', 'number,title,url,headRefName,state']
134
- else
135
- ['gh', 'pr', 'view', '--json', 'number,title,url,headRefName,state']
136
- end
137
-
138
- output = `#{cmd.join(' ')} 2>/dev/null`
139
- return nil if output.empty?
140
-
141
- JSON.parse(output)
142
- rescue JSON::ParserError
143
- nil
144
- end
145
-
146
- def build_entry(pr_info)
147
- task_info = hiiro.task_manager.send(:current_task)
148
- tmux_info = capture_tmux_info
149
-
150
- {
151
- number: pr_info['number'],
152
- title: pr_info['title'],
153
- url: pr_info['url'],
154
- branch: pr_info['headRefName'],
155
- state: pr_info['state'],
156
- worktree: task_info&.[](:tree),
157
- task: task_info&.[](:task),
158
- tmux: tmux_info
159
- }
160
- end
161
-
162
- def capture_tmux_info
163
- return nil unless ENV['TMUX']
164
-
165
- {
166
- 'session' => `tmux display-message -p '#S'`.strip,
167
- 'window' => `tmux display-message -p '#W'`.strip,
168
- 'pane' => ENV['TMUX_PANE']
169
- }
170
- end
171
-
172
- def parse_filters(args)
173
- filters = {}
174
- args.each do |arg|
175
- case arg
176
- when /^--worktree=(.+)$/
177
- filters[:worktree] = $1
178
- when /^--task=(.+)$/
179
- filters[:task] = $1
180
- when /^--session=(.+)$/
181
- filters[:session] = $1
182
- when /^-w(.+)$/
183
- filters[:worktree] = $1
184
- when /^-t(.+)$/
185
- filters[:task] = $1
186
- when /^-s(.+)$/
187
- filters[:session] = $1
188
- end
189
- end
190
- filters
191
- end
192
-
193
- def filter_entries(entries, filters)
194
- entries.select do |entry|
195
- next false if filters[:worktree] && !entry['worktree']&.include?(filters[:worktree])
196
- next false if filters[:task] && !entry['task']&.include?(filters[:task])
197
- next false if filters[:session] && entry.dig('tmux', 'session') != filters[:session]
198
- true
199
- end
200
- end
201
-
202
- def format_entry(entry, num)
203
- lines = []
204
- lines << "#{num}. PR ##{entry['number']}: #{entry['title']}"
205
- lines << " Branch: #{entry['branch']}"
206
- lines << " State: #{entry['state']}"
207
- lines << " Task: #{entry['task'] || '(none)'}"
208
- lines << " Worktree: #{entry['worktree'] || '(none)'}"
209
- if entry['tmux']
210
- lines << " Tmux: #{entry['tmux']['session']}/#{entry['tmux']['window']}"
211
- end
212
- lines << " Created: #{entry['created_at']}"
213
- lines << " URL: #{entry['url']}"
214
- lines.join("\n")
215
- end
216
-
217
- def show_entry(entry)
218
- puts " PR: ##{entry[:number]}"
219
- puts " Title: #{entry[:title]}"
220
- puts " Branch: #{entry[:branch]}"
221
- puts " State: #{entry[:state]}"
222
- puts " URL: #{entry[:url]}"
223
- puts " Task: #{entry[:task] || '(none)'}"
224
- puts " Worktree: #{entry[:worktree] || '(none)'}"
225
- if entry[:tmux]
226
- puts " Tmux session: #{entry[:tmux]['session']}"
227
- puts " Tmux window: #{entry[:tmux]['window']}"
228
- puts " Tmux pane: #{entry[:tmux]['pane']}"
229
- end
230
- end
231
-
232
- def data_file
233
- File.join(Dir.home, '.config', 'hiiro', 'prs.yml')
234
- end
235
-
236
- def load_data
237
- return {} unless File.exist?(data_file)
238
- YAML.safe_load_file(data_file) || {}
239
- end
240
-
241
- def save_data(data)
242
- FileUtils.mkdir_p(File.dirname(data_file))
243
- File.write(data_file, YAML.dump(data))
244
- end
245
- end
246
-
247
- WATCH_BLOCK = lambda { |original_pr_number=nil, *args|
248
- watch = o.get_value(:watch)
249
- fail_fast = o.get_value(:fail_fast)
250
-
251
- pr_valid = false
252
- pr_number = nil
253
- if !original_pr_number.nil? && pin_value = o.pins.get(original_pr_number)
254
- pr_valid = true
255
- pr_number = pin_value
256
- end
257
-
258
- pr_args = [pr_valid ? pr_number : original_pr_number].compact
259
- args = [*pr_args, *args]
260
-
261
- base_cmd = %w[gh pr checks]
262
- base_cmd << '--watch' if watch
263
- base_cmd << '--fail-fast' if fail_fast
264
-
265
- command = [
266
- *base_cmd,
267
- *args,
268
- ]
269
-
270
- puts command: command, base_cmd: base_cmd, args: args;
271
-
272
- result = system(*command)
273
-
274
- pr_info = JSON.parse(`gh pr view #{pr_args.first} --json url,number,title`)
275
- pr_url = pr_info['url']
276
- pr_number = pr_info['number']
277
- pr_title = pr_info['title']
278
-
279
- if result
280
- system('say', 'pr good')
281
- system('terminal-notifier', '-title', 'PR Good', '-message', "##{pr_number}: #{pr_title}", '-open', pr_url)
282
- else
283
- system('say', 'pr bad')
284
- system('terminal-notifier', '-title', 'PR Bad', '-message', "##{pr_number}: #{pr_title}", '-open', pr_url)
285
- end
286
- }
287
-
288
- manager = PRManager.new(hiiro)
289
-
290
- hiiro.add_subcmd(:check, &WATCH_BLOCK)
291
- hiiro.add_subcmd(:watch, watch: true, &WATCH_BLOCK)
292
- hiiro.add_subcmd(:fwatch, watch: true, fail_fast: true, &WATCH_BLOCK)
293
-
294
- hiiro.add_subcmd(:number) { |*args|
295
- stdout = `gh pr view`
296
-
297
- number = stdout[/number:\s*(\d+)/, 1]
298
-
299
- if number
300
- print number
301
- else
302
- puts stdout
303
- end
304
- }
305
-
306
- hiiro.add_subcmd(:link) { |*args|
307
- stdout = `gh pr view`
308
-
309
- number = stdout[/number:\s*(\d+)/, 1]
310
-
311
- if number
312
- print ['https://github.com/instacart/carrot/pull/', number].join
313
- else
314
- puts stdout
315
- end
316
- }
317
-
318
- hiiro.add_subcmd(:edit) { system(ENV['EDITOR'] || 'nvim', __FILE__) }
319
- hiiro.add_subcmd(:save) { |pr_number=nil| manager.save(pr_number) }
320
- hiiro.add_subcmd(:history) { |*args| manager.history(args) }
321
- hiiro.add_subcmd(:current) { manager.current }
322
- hiiro.add_subcmd(:open) { |pr_number=nil| manager.open(pr_number) }
323
- hiiro.add_subcmd(:view) { |pr_number=nil| manager.view(pr_number) }
324
-
325
- hiiro.add_default { manager.help }
326
-
327
- hiiro.run
data/bin/h-dot DELETED
@@ -1,35 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- require 'hiiro'
4
-
5
- hiiro = Hiiro.init(*ARGV)
6
-
7
- hiiro.add_subcmd(:compare) do |*args|
8
- left = File.join(Dir.home, 'proj/home/bin')
9
- right = File.join(Dir.home, 'bin')
10
- diff = `diff -qrs #{left} #{right}`.lines(chomp: true)
11
-
12
- diff.each do |line|
13
- next if line.match?(/[.]DS_Store/)
14
-
15
- case line
16
- when /^Only in #{left}:/
17
- match = line.match(/^Only in ([^:]+):\s*(\S.*)/)
18
- _, fname = match.captures
19
- puts "ln -v #{File.join(left, fname).inspect} #{File.join(right, fname).inspect}"
20
- when /^Only in #{right}:/
21
- match = line.match(/^Only in ([^:]+):\s*(\S.*)/)
22
- _, fname = match.captures
23
- puts "ln -v #{File.join(right, fname).inspect} #{File.join(left, fname).inspect}"
24
- when / differ/
25
- match = line.match(/^Files (.*) and (.*) differ/)
26
- lname, rname = match.captures
27
- puts "vim -d #{lname.inspect} #{rname.inspect}"
28
- end
29
- puts
30
- end
31
- end
32
-
33
-
34
- hiiro.run
35
-
data/bin/h-dotfiles DELETED
@@ -1,42 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- require 'hiiro'
4
-
5
- EDITOR = ENV.fetch('EDITOR', 'nvim')
6
- BASE_DIR = File.join(Dir.home, 'proj', 'home')
7
-
8
- o = Hiiro.init(*ARGV)
9
-
10
- o.add_subcmd(:edit) { |*args|
11
- system(EDITOR, __FILE__)
12
- }
13
-
14
- o.add_subcmd(:path) { |*args|
15
- print BASE_DIR
16
- }
17
-
18
- o.add_subcmd(:skf) { |*args|
19
- Dir.chdir(BASE_DIR)
20
- system('skf', *args)
21
- }
22
-
23
- o.add_subcmd(:rg) { |*args|
24
- Dir.chdir(BASE_DIR)
25
- system('rg', '-S', *args)
26
- }
27
-
28
- o.add_subcmd(:rgall) { |*args|
29
- Dir.chdir(BASE_DIR)
30
- system('rg', '-S', '--no-ignore-vcs', *args)
31
- }
32
-
33
- o.add_subcmd(:ebin) { |*args|
34
- system(EDITOR, *args)
35
- }
36
-
37
- if o.runnable?
38
- o.run
39
- else
40
- puts :no_runnable_found
41
- end
42
-
data/bin/h-osubtask DELETED
@@ -1,32 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- # Shorthand for `h task subtask`
4
-
5
- require "hiiro"
6
- require "fileutils"
7
- require "yaml"
8
- require "time"
9
-
10
- Hiiro.load_env
11
- hiiro = Hiiro.init(*ARGV, plugins: [Tmux, OldTask])
12
-
13
- tasks = hiiro.task_manager
14
-
15
- hiiro.add_subcmd(:edit) { system(ENV['EDITOR'] || 'nvim', __FILE__) }
16
- hiiro.add_subcmd(:list) { tasks.list_subtasks }
17
- hiiro.add_subcmd(:ls) { tasks.list_subtasks }
18
- hiiro.add_subcmd(:new) { |subtask_name| tasks.new_subtask(subtask_name) }
19
- hiiro.add_subcmd(:switch) { |subtask_name=nil| tasks.switch_subtask(subtask_name) }
20
- hiiro.add_subcmd(:app) { |app_name| tasks.subtask_open_app(app_name) }
21
- hiiro.add_subcmd(:path) { |app_name=nil| tasks.subtask_app_path(app_name) }
22
- hiiro.add_subcmd(:cd) { |*args| tasks.subtask_cd_app(*args) }
23
- hiiro.add_subcmd(:apps) { tasks.list_configured_apps }
24
- hiiro.add_subcmd(:status) { tasks.subtask_status }
25
- hiiro.add_subcmd(:st) { tasks.subtask_status }
26
- hiiro.add_subcmd(:save) { tasks.save_subtask }
27
- hiiro.add_subcmd(:stop) { |subtask_name=nil| subtask_name ? tasks.stop_subtask(subtask_name) : tasks.stop_subtask }
28
- hiiro.add_subcmd(:current) { print tasks.current_subtask_name }
29
-
30
- hiiro.add_default { tasks.subtask_help }
31
-
32
- hiiro.run