hiiro 0.1.102 → 0.1.103
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 +4 -4
- data/bin/h-pr +267 -0
- data/bin/h-session +44 -1
- data/lib/hiiro/version.rb +1 -1
- data/plugins/tasks.rb +26 -2
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 9a10f35b3d066b06834cb59ac651c430314e158326648e7c03857d8619fe98ac
|
|
4
|
+
data.tar.gz: '0281effef29f43bc895ea11c72740c5467a66200ab9d0936ac91db5977ed111a'
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: bfd05cc89b33bddf85607dadfddafa4e5a299309484afe6d402467c220b5cb201f624a9e35ce6fa5f52ff13d3138da41991d56638a9c30f9f76d4369e4965cc6
|
|
7
|
+
data.tar.gz: d5060e6f075475f3f95e48edbadc8dd4cab5d6ea539bbe817d54efd47b417b14c9655e72a04554c86abc9f104754c1cea5379a0eaefe27d97dad3e67e9c1a8ca
|
data/bin/h-pr
CHANGED
|
@@ -5,6 +5,7 @@ require "time"
|
|
|
5
5
|
require "fileutils"
|
|
6
6
|
require "yaml"
|
|
7
7
|
require "json"
|
|
8
|
+
require "tempfile"
|
|
8
9
|
|
|
9
10
|
Hiiro.load_env
|
|
10
11
|
|
|
@@ -254,6 +255,17 @@ class PinnedPRManager
|
|
|
254
255
|
JSON.parse(output) rescue []
|
|
255
256
|
end
|
|
256
257
|
|
|
258
|
+
def fetch_my_and_assigned_prs
|
|
259
|
+
authored = `gh pr list --author @me --state open --json number,title,headRefName,url 2>/dev/null`.strip
|
|
260
|
+
assigned = `gh pr list --assignee @me --state open --json number,title,headRefName,url 2>/dev/null`.strip
|
|
261
|
+
|
|
262
|
+
authored_prs = authored.empty? ? [] : (JSON.parse(authored) rescue [])
|
|
263
|
+
assigned_prs = assigned.empty? ? [] : (JSON.parse(assigned) rescue [])
|
|
264
|
+
|
|
265
|
+
# Dedupe by PR number
|
|
266
|
+
(authored_prs + assigned_prs).uniq { |pr| pr['number'] }
|
|
267
|
+
end
|
|
268
|
+
|
|
257
269
|
def refresh_status(pr)
|
|
258
270
|
info = fetch_pr_info(pr['number'])
|
|
259
271
|
return pr unless info
|
|
@@ -668,6 +680,261 @@ Hiiro.run(*ARGV, plugins: [Tasks, Tmux, Pins]) do
|
|
|
668
680
|
puts "Status updated at #{Time.now.strftime('%H:%M:%S')}"
|
|
669
681
|
end
|
|
670
682
|
|
|
683
|
+
add_subcmd(:update) do
|
|
684
|
+
pinned = pinned_manager.load_pinned
|
|
685
|
+
|
|
686
|
+
if pinned.empty?
|
|
687
|
+
puts "No pinned PRs to update"
|
|
688
|
+
next
|
|
689
|
+
end
|
|
690
|
+
|
|
691
|
+
puts "Updating status for #{pinned.length} PR(s)..."
|
|
692
|
+
pinned.each { |pr| pinned_manager.refresh_status(pr) }
|
|
693
|
+
pinned_manager.save_pinned(pinned)
|
|
694
|
+
puts "Done."
|
|
695
|
+
end
|
|
696
|
+
|
|
697
|
+
add_subcmd(:green) do
|
|
698
|
+
pinned = pinned_manager.load_pinned
|
|
699
|
+
pinned.each { |pr| pinned_manager.refresh_status(pr) }
|
|
700
|
+
pinned_manager.save_pinned(pinned)
|
|
701
|
+
|
|
702
|
+
filtered = pinned.select { |pr|
|
|
703
|
+
c = pr['checks']
|
|
704
|
+
c && c['failed'] == 0 && c['pending'] == 0 && c['success'] > 0
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
if filtered.empty?
|
|
708
|
+
puts "No PRs with passing checks"
|
|
709
|
+
next
|
|
710
|
+
end
|
|
711
|
+
|
|
712
|
+
puts "PRs with passing checks:"
|
|
713
|
+
puts
|
|
714
|
+
filtered.each_with_index { |pr, i| puts pinned_manager.display_pinned(pr, i) }
|
|
715
|
+
end
|
|
716
|
+
|
|
717
|
+
add_subcmd(:red) do
|
|
718
|
+
pinned = pinned_manager.load_pinned
|
|
719
|
+
pinned.each { |pr| pinned_manager.refresh_status(pr) }
|
|
720
|
+
pinned_manager.save_pinned(pinned)
|
|
721
|
+
|
|
722
|
+
filtered = pinned.select { |pr|
|
|
723
|
+
c = pr['checks']
|
|
724
|
+
c && c['failed'] > 0
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
if filtered.empty?
|
|
728
|
+
puts "No PRs with failing checks"
|
|
729
|
+
next
|
|
730
|
+
end
|
|
731
|
+
|
|
732
|
+
puts "PRs with failing checks:"
|
|
733
|
+
puts
|
|
734
|
+
filtered.each_with_index { |pr, i| puts pinned_manager.display_pinned(pr, i) }
|
|
735
|
+
end
|
|
736
|
+
|
|
737
|
+
add_subcmd(:old) do
|
|
738
|
+
pinned = pinned_manager.load_pinned
|
|
739
|
+
pinned.each { |pr| pinned_manager.refresh_status(pr) }
|
|
740
|
+
pinned_manager.save_pinned(pinned)
|
|
741
|
+
|
|
742
|
+
filtered = pinned.select { |pr| pr['state'] == 'MERGED' }
|
|
743
|
+
|
|
744
|
+
if filtered.empty?
|
|
745
|
+
puts "No merged PRs"
|
|
746
|
+
next
|
|
747
|
+
end
|
|
748
|
+
|
|
749
|
+
puts "Merged PRs:"
|
|
750
|
+
puts
|
|
751
|
+
filtered.each_with_index { |pr, i| puts pinned_manager.display_pinned(pr, i) }
|
|
752
|
+
end
|
|
753
|
+
|
|
754
|
+
add_subcmd(:prune) do |*args|
|
|
755
|
+
# Alias to auto-unpin
|
|
756
|
+
pinned = pinned_manager.load_pinned
|
|
757
|
+
|
|
758
|
+
if pinned.empty?
|
|
759
|
+
puts "No pinned PRs"
|
|
760
|
+
next
|
|
761
|
+
end
|
|
762
|
+
|
|
763
|
+
pinned.each { |pr| pinned_manager.refresh_status(pr) }
|
|
764
|
+
|
|
765
|
+
merged_or_closed = pinned.select { |pr| pr['state'] == 'MERGED' || pr['state'] == 'CLOSED' }
|
|
766
|
+
|
|
767
|
+
if merged_or_closed.empty?
|
|
768
|
+
puts "No merged or closed PRs to prune"
|
|
769
|
+
pinned_manager.save_pinned(pinned)
|
|
770
|
+
next
|
|
771
|
+
end
|
|
772
|
+
|
|
773
|
+
puts "Pruning #{merged_or_closed.length} merged/closed PR(s):"
|
|
774
|
+
puts
|
|
775
|
+
|
|
776
|
+
merged_or_closed.each do |pr|
|
|
777
|
+
puts " ##{pr['number']}: #{pr['title']} [#{pr['state']}]"
|
|
778
|
+
pinned_manager.unpin(pr['number'])
|
|
779
|
+
end
|
|
780
|
+
|
|
781
|
+
puts
|
|
782
|
+
puts "Done. #{pinned_manager.load_pinned.length} PR(s) still tracked."
|
|
783
|
+
end
|
|
784
|
+
|
|
785
|
+
add_subcmd(:draft) do
|
|
786
|
+
pinned = pinned_manager.load_pinned
|
|
787
|
+
pinned.each { |pr| pinned_manager.refresh_status(pr) }
|
|
788
|
+
pinned_manager.save_pinned(pinned)
|
|
789
|
+
|
|
790
|
+
filtered = pinned.select { |pr| pr['is_draft'] == true }
|
|
791
|
+
|
|
792
|
+
if filtered.empty?
|
|
793
|
+
puts "No draft PRs"
|
|
794
|
+
next
|
|
795
|
+
end
|
|
796
|
+
|
|
797
|
+
puts "Draft PRs:"
|
|
798
|
+
puts
|
|
799
|
+
filtered.each_with_index { |pr, i| puts pinned_manager.display_pinned(pr, i) }
|
|
800
|
+
end
|
|
801
|
+
|
|
802
|
+
add_subcmd(:missing) do
|
|
803
|
+
my_prs = pinned_manager.fetch_my_and_assigned_prs
|
|
804
|
+
pinned_numbers = pinned_manager.load_pinned.map { |p| p['number'] }
|
|
805
|
+
missing = my_prs.reject { |pr| pinned_numbers.include?(pr['number']) }
|
|
806
|
+
|
|
807
|
+
if missing.empty?
|
|
808
|
+
puts "All your PRs are tracked"
|
|
809
|
+
next
|
|
810
|
+
end
|
|
811
|
+
|
|
812
|
+
puts "Untracked PRs (#{missing.count}):"
|
|
813
|
+
puts
|
|
814
|
+
missing.each { |pr| puts " ##{pr['number']} [#{pr['headRefName']}] #{pr['title']}" }
|
|
815
|
+
end
|
|
816
|
+
|
|
817
|
+
add_subcmd(:amissing) do
|
|
818
|
+
my_prs = pinned_manager.fetch_my_and_assigned_prs
|
|
819
|
+
pinned_numbers = pinned_manager.load_pinned.map { |p| p['number'] }
|
|
820
|
+
missing = my_prs.reject { |pr| pinned_numbers.include?(pr['number']) }
|
|
821
|
+
|
|
822
|
+
if missing.empty?
|
|
823
|
+
puts "All your PRs are already tracked"
|
|
824
|
+
next
|
|
825
|
+
end
|
|
826
|
+
|
|
827
|
+
missing_numbers = missing.map { |pr| pr['number'] }
|
|
828
|
+
|
|
829
|
+
tmpfile = Tempfile.new(['missing-prs-', '.yml'])
|
|
830
|
+
tmpfile.write(missing_numbers.to_yaml)
|
|
831
|
+
tmpfile.close
|
|
832
|
+
|
|
833
|
+
system(ENV['EDITOR'] || 'nvim', tmpfile.path)
|
|
834
|
+
|
|
835
|
+
to_add = YAML.safe_load_file(tmpfile.path) || []
|
|
836
|
+
tmpfile.unlink
|
|
837
|
+
|
|
838
|
+
added = 0
|
|
839
|
+
to_add.each do |num|
|
|
840
|
+
pr_info = pinned_manager.fetch_pr_info(num)
|
|
841
|
+
next unless pr_info
|
|
842
|
+
pinned_manager.pin(pr_info)
|
|
843
|
+
puts "Tracked: ##{pr_info['number']} #{pr_info['title']}"
|
|
844
|
+
added += 1
|
|
845
|
+
end
|
|
846
|
+
|
|
847
|
+
puts
|
|
848
|
+
puts "Added #{added} PR(s) to tracking."
|
|
849
|
+
end
|
|
850
|
+
|
|
851
|
+
add_subcmd(:track) do
|
|
852
|
+
pr_info = pinned_manager.fetch_current_branch_pr
|
|
853
|
+
unless pr_info
|
|
854
|
+
puts "No PR for current branch"
|
|
855
|
+
next
|
|
856
|
+
end
|
|
857
|
+
|
|
858
|
+
if pinned_manager.pinned?(pr_info['number'])
|
|
859
|
+
puts "Already tracking ##{pr_info['number']}"
|
|
860
|
+
next
|
|
861
|
+
end
|
|
862
|
+
|
|
863
|
+
full_info = pinned_manager.fetch_pr_info(pr_info['number'])
|
|
864
|
+
pinned_manager.pin(full_info)
|
|
865
|
+
puts "Now tracking ##{pr_info['number']}: #{pr_info['title']}"
|
|
866
|
+
end
|
|
867
|
+
|
|
868
|
+
add_subcmd(:ignore) do |ref = nil|
|
|
869
|
+
# Alias to unpin
|
|
870
|
+
pinned = pinned_manager.load_pinned
|
|
871
|
+
|
|
872
|
+
if pinned.empty?
|
|
873
|
+
puts "No tracked PRs"
|
|
874
|
+
next
|
|
875
|
+
end
|
|
876
|
+
|
|
877
|
+
pr_number = nil
|
|
878
|
+
|
|
879
|
+
if ref.nil?
|
|
880
|
+
lines = pinned.each_with_index.each_with_object({}) do |(pr, idx), h|
|
|
881
|
+
h[pinned_manager.display_pinned(pr, idx)] = pr['number'].to_s
|
|
882
|
+
end
|
|
883
|
+
|
|
884
|
+
pr_number = fuzzyfind_from_map(lines)
|
|
885
|
+
unless pr_number
|
|
886
|
+
puts "No PR selected"
|
|
887
|
+
next
|
|
888
|
+
end
|
|
889
|
+
elsif ref =~ /^\d+$/
|
|
890
|
+
pr_number = ref
|
|
891
|
+
else
|
|
892
|
+
puts "Usage: h pr ignore [PR_NUMBER]"
|
|
893
|
+
next
|
|
894
|
+
end
|
|
895
|
+
|
|
896
|
+
if pinned_manager.unpin(pr_number)
|
|
897
|
+
puts "Stopped tracking PR ##{pr_number}"
|
|
898
|
+
else
|
|
899
|
+
puts "PR ##{pr_number} was not tracked"
|
|
900
|
+
end
|
|
901
|
+
end
|
|
902
|
+
|
|
903
|
+
add_subcmd(:rm) do |ref = nil|
|
|
904
|
+
# Alias to ignore/unpin
|
|
905
|
+
pinned = pinned_manager.load_pinned
|
|
906
|
+
|
|
907
|
+
if pinned.empty?
|
|
908
|
+
puts "No tracked PRs"
|
|
909
|
+
next
|
|
910
|
+
end
|
|
911
|
+
|
|
912
|
+
pr_number = nil
|
|
913
|
+
|
|
914
|
+
if ref.nil?
|
|
915
|
+
lines = pinned.each_with_index.each_with_object({}) do |(pr, idx), h|
|
|
916
|
+
h[pinned_manager.display_pinned(pr, idx)] = pr['number'].to_s
|
|
917
|
+
end
|
|
918
|
+
|
|
919
|
+
pr_number = fuzzyfind_from_map(lines)
|
|
920
|
+
unless pr_number
|
|
921
|
+
puts "No PR selected"
|
|
922
|
+
next
|
|
923
|
+
end
|
|
924
|
+
elsif ref =~ /^\d+$/
|
|
925
|
+
pr_number = ref
|
|
926
|
+
else
|
|
927
|
+
puts "Usage: h pr rm [PR_NUMBER]"
|
|
928
|
+
next
|
|
929
|
+
end
|
|
930
|
+
|
|
931
|
+
if pinned_manager.unpin(pr_number)
|
|
932
|
+
puts "Removed PR ##{pr_number} from tracking"
|
|
933
|
+
else
|
|
934
|
+
puts "PR ##{pr_number} was not tracked"
|
|
935
|
+
end
|
|
936
|
+
end
|
|
937
|
+
|
|
671
938
|
add_subcmd(:'suggest-unpin') do |*args|
|
|
672
939
|
pinned = pinned_manager.load_pinned
|
|
673
940
|
|
data/bin/h-session
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env ruby
|
|
2
2
|
|
|
3
3
|
require 'hiiro'
|
|
4
|
+
require 'tempfile'
|
|
5
|
+
require 'yaml'
|
|
4
6
|
|
|
5
|
-
Hiiro.run(*ARGV, plugins: [Pins]) do
|
|
7
|
+
Hiiro.run(*ARGV, plugins: [Pins, Tasks]) do
|
|
6
8
|
tmux = tmux_client
|
|
7
9
|
|
|
8
10
|
add_subcmd(:ls, :list) { |*args|
|
|
@@ -126,4 +128,45 @@ Hiiro.run(*ARGV, plugins: [Pins]) do
|
|
|
126
128
|
puts "Copied session '#{selected}' to clipboard"
|
|
127
129
|
end
|
|
128
130
|
end
|
|
131
|
+
|
|
132
|
+
add_subcmd(:orphans) do
|
|
133
|
+
env = Environment.current
|
|
134
|
+
task_session_names = env.all_tasks.map(&:session_name)
|
|
135
|
+
orphans = env.all_sessions.reject { |s| task_session_names.include?(s.name) }
|
|
136
|
+
|
|
137
|
+
if orphans.empty?
|
|
138
|
+
puts "No orphan sessions"
|
|
139
|
+
next
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
puts "Orphan sessions (#{orphans.count}):"
|
|
143
|
+
orphans.each { |s| puts " #{s.name}" }
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
add_subcmd(:okill) do
|
|
147
|
+
env = Environment.current
|
|
148
|
+
task_session_names = env.all_tasks.map(&:session_name)
|
|
149
|
+
orphans = env.all_sessions.reject { |s| task_session_names.include?(s.name) }
|
|
150
|
+
|
|
151
|
+
if orphans.empty?
|
|
152
|
+
puts "No orphan sessions to kill"
|
|
153
|
+
next
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
orphan_names = orphans.map(&:name)
|
|
157
|
+
|
|
158
|
+
tmpfile = Tempfile.new(['orphan-sessions-', '.yml'])
|
|
159
|
+
tmpfile.write(orphan_names.to_yaml)
|
|
160
|
+
tmpfile.close
|
|
161
|
+
|
|
162
|
+
system(ENV['EDITOR'] || 'nvim', tmpfile.path)
|
|
163
|
+
|
|
164
|
+
to_kill = YAML.safe_load_file(tmpfile.path) || []
|
|
165
|
+
tmpfile.unlink
|
|
166
|
+
|
|
167
|
+
to_kill.each do |name|
|
|
168
|
+
tmux.kill_session(name)
|
|
169
|
+
puts "Killed: #{name}"
|
|
170
|
+
end
|
|
171
|
+
end
|
|
129
172
|
end
|
data/lib/hiiro/version.rb
CHANGED
data/plugins/tasks.rb
CHANGED
|
@@ -646,7 +646,7 @@ class TaskManager
|
|
|
646
646
|
h[line] = val
|
|
647
647
|
end
|
|
648
648
|
|
|
649
|
-
|
|
649
|
+
hiiro.fuzzyfind_from_map(mapping)
|
|
650
650
|
end
|
|
651
651
|
|
|
652
652
|
def select_branch_interactive(prompt = nil)
|
|
@@ -657,7 +657,7 @@ class TaskManager
|
|
|
657
657
|
end
|
|
658
658
|
return nil if name_map.empty?
|
|
659
659
|
|
|
660
|
-
|
|
660
|
+
hiiro.fuzzyfind_from_map(name_map)
|
|
661
661
|
end
|
|
662
662
|
|
|
663
663
|
# --- Private helpers ---
|
|
@@ -906,6 +906,30 @@ module Tasks
|
|
|
906
906
|
print tm.value_for_task(task_name, &:session_name)
|
|
907
907
|
end
|
|
908
908
|
|
|
909
|
+
h.add_subcmd(:current) do
|
|
910
|
+
task = tm.current_task
|
|
911
|
+
next STDERR.puts("Not in a task") unless task
|
|
912
|
+
print task.name
|
|
913
|
+
end
|
|
914
|
+
|
|
915
|
+
h.add_subcmd(:cbranch) do
|
|
916
|
+
task = tm.current_task
|
|
917
|
+
next STDERR.puts("Not in a task") unless task
|
|
918
|
+
print task.branch if task.branch
|
|
919
|
+
end
|
|
920
|
+
|
|
921
|
+
h.add_subcmd(:ctree) do
|
|
922
|
+
task = tm.current_task
|
|
923
|
+
next STDERR.puts("Not in a task") unless task
|
|
924
|
+
print task.tree_name if task.tree_name
|
|
925
|
+
end
|
|
926
|
+
|
|
927
|
+
h.add_subcmd(:csession) do
|
|
928
|
+
task = tm.current_task
|
|
929
|
+
next STDERR.puts("Not in a task") unless task
|
|
930
|
+
print task.session_name if task.session_name
|
|
931
|
+
end
|
|
932
|
+
|
|
909
933
|
h.add_subcmd(:status) { tm.status }
|
|
910
934
|
h.add_subcmd(:st) { tm.status }
|
|
911
935
|
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: hiiro
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.103
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Joshua Toyota
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-02-
|
|
11
|
+
date: 2026-02-26 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: pry
|