hiiro 0.1.366 → 0.1.367
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/CHANGELOG.md +29 -0
- data/CLAUDE.md +1 -0
- data/README.md +47 -9
- data/bin/h-bin +20 -0
- data/bin/h-task +1 -0
- data/bin/t +1 -0
- data/bin/tt +1 -0
- data/docs/h-bin.md +49 -2
- data/docs/h-subtask.md +5 -44
- data/docs/h-task.md +20 -557
- data/docs/h.md +1 -2
- data/docs/t.md +17 -7
- data/docs/why-t.md +2 -2
- data/exe/h +1 -0
- data/exe/t +7 -0
- data/exe/tt +7 -0
- data/lib/hiiro/current_task.rb +92 -0
- data/lib/hiiro/error.rb +5 -0
- data/lib/hiiro/git/worktrees.rb +1 -1
- data/lib/hiiro/git.rb +8 -2
- data/lib/hiiro/task_cli.rb +671 -0
- data/lib/hiiro/task_scope.rb +2 -43
- data/lib/hiiro/task_sessions.rb +1 -1
- data/lib/hiiro/tasks.rb +40 -27
- data/lib/hiiro/version.rb +1 -1
- data/lib/hiiro.rb +23 -20
- metadata +9 -1
- data/bin/t +0 -526
- data/bin/tt +0 -20
data/exe/t
ADDED
data/exe/tt
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
class Hiiro
|
|
2
|
+
# Resolves the current task record shared by `t` (via TaskScope) and
|
|
3
|
+
# Environment#task (via `h` commands):
|
|
4
|
+
#
|
|
5
|
+
# 1. Herdr workspace, when HERDR_* env vars identify one
|
|
6
|
+
# 2. Working directory inside a task home, code directory, or registered directory
|
|
7
|
+
# 3. Saved `t TASK current` pin (only when pin: true)
|
|
8
|
+
#
|
|
9
|
+
# resolve! raises Hiiro::Error with a user-facing message; resolve returns nil instead.
|
|
10
|
+
class CurrentTask
|
|
11
|
+
def initialize(herdr: nil, cwd: Dir.pwd, pin: true, tasks: nil)
|
|
12
|
+
@herdr = herdr
|
|
13
|
+
@cwd = cwd
|
|
14
|
+
@pin = pin
|
|
15
|
+
@tasks = tasks
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def resolve
|
|
19
|
+
resolve!
|
|
20
|
+
rescue Hiiro::Error
|
|
21
|
+
nil
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def resolve!
|
|
25
|
+
herdr_task || directory_task || pinned_task
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
private
|
|
29
|
+
|
|
30
|
+
def tasks
|
|
31
|
+
@tasks ||= TaskRecord.all_as_list
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def herdr_task
|
|
35
|
+
return nil unless @herdr && (ENV['HERDR_WORKSPACE_ID'] || ENV['HERDR_PANE_ID'] || ENV['HERDR_ENV'] == '1')
|
|
36
|
+
|
|
37
|
+
herdr = @herdr.call
|
|
38
|
+
unless herdr.server_running?
|
|
39
|
+
raise Error, 'Herdr is not running; start Herdr for workspace/tab/pane commands, or supply a task name for task data'
|
|
40
|
+
end
|
|
41
|
+
pane = herdr.get_pane(ENV['HERDR_PANE_ID']) if ENV['HERDR_PANE_ID']
|
|
42
|
+
raise Error, 'Cannot resolve the current Herdr pane; supply a task name' if ENV['HERDR_PANE_ID'] && !pane
|
|
43
|
+
|
|
44
|
+
workspace_id = ENV['HERDR_WORKSPACE_ID'] || pane&.workspace_id
|
|
45
|
+
raise Error, 'Conflicting Herdr pane/workspace context; supply a task name' if pane && workspace_id != pane.workspace_id
|
|
46
|
+
|
|
47
|
+
workspace = workspace_id ? herdr.get_workspace(workspace_id) : herdr.current_workspace
|
|
48
|
+
raise Error, 'Cannot resolve the current Herdr workspace; supply a task name' unless workspace
|
|
49
|
+
|
|
50
|
+
matches = tasks.select { |task| workspace_label(task) == workspace.name }
|
|
51
|
+
raise Error, "Ambiguous workspace task: #{matches.map(&:name).join(', ')}" if matches.length > 1
|
|
52
|
+
|
|
53
|
+
matches.first
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def directory_task
|
|
57
|
+
cwd = File.realpath(@cwd)
|
|
58
|
+
registered = TaskResource.where(kind: 'directory').select_map([:task_id, :target]).group_by(&:first)
|
|
59
|
+
matches = tasks.select do |task|
|
|
60
|
+
paths = [task.home, code_directory(task), *registered.fetch(task.id, []).map(&:last)].compact
|
|
61
|
+
paths.any? { |path| inside?(cwd, path) }
|
|
62
|
+
end
|
|
63
|
+
raise Error, "Ambiguous directory task: #{matches.map(&:name).join(', ')}" if matches.length > 1
|
|
64
|
+
|
|
65
|
+
matches.first
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def pinned_task
|
|
69
|
+
raise Error, 'No current task; supply a task name or run t TASK current' unless @pin
|
|
70
|
+
|
|
71
|
+
saved = PinRecord.find_key('t', 'current_task')
|
|
72
|
+
raise Error, 'No current task; supply a task name or run t TASK current' unless saved
|
|
73
|
+
|
|
74
|
+
TaskRecord[saved.value] || raise(Error, 'Saved task no longer exists; run t TASK current')
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def workspace_label(task)
|
|
78
|
+
(task.session || task.name).tr('.', '_')
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def code_directory(task)
|
|
82
|
+
task.primary_directory || (task.tree && (task.tree.start_with?('/') ? task.tree : File.join(Hiiro::WORK_DIR, task.tree)))
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def inside?(path, directory)
|
|
86
|
+
return false unless Dir.exist?(directory)
|
|
87
|
+
|
|
88
|
+
root = File.realpath(directory)
|
|
89
|
+
path == root || path.start_with?(root == File::SEPARATOR ? root : root + File::SEPARATOR)
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
data/lib/hiiro/error.rb
ADDED
data/lib/hiiro/git/worktrees.rb
CHANGED
|
@@ -26,7 +26,7 @@ class Hiiro
|
|
|
26
26
|
|
|
27
27
|
def self.fetch(repo_path: nil)
|
|
28
28
|
output = if repo_path
|
|
29
|
-
`git -C #{repo_path.shellescape} worktree list --porcelain 2>/dev/null`
|
|
29
|
+
`git -C #{Hiiro::Git.repo_dir(repo_path).shellescape} worktree list --porcelain 2>/dev/null`
|
|
30
30
|
else
|
|
31
31
|
`git worktree list --porcelain 2>/dev/null`
|
|
32
32
|
end
|
data/lib/hiiro/git.rb
CHANGED
|
@@ -7,6 +7,12 @@ require_relative 'git/pr'
|
|
|
7
7
|
|
|
8
8
|
class Hiiro
|
|
9
9
|
class Git
|
|
10
|
+
# Directory to pass to `git -C` for a repo path. REPO_PATH points at
|
|
11
|
+
# ~/work/.git, which is a gitfile in the bare layout, so use its parent.
|
|
12
|
+
def self.repo_dir(repo_path)
|
|
13
|
+
File.file?(repo_path.to_s) ? File.dirname(repo_path) : repo_path
|
|
14
|
+
end
|
|
15
|
+
|
|
10
16
|
def self.root
|
|
11
17
|
`git rev-parse --show-toplevel 2>/dev/null`.strip
|
|
12
18
|
end
|
|
@@ -128,7 +134,7 @@ class Hiiro
|
|
|
128
134
|
|
|
129
135
|
def add_worktree_detached(path, repo_path: nil)
|
|
130
136
|
if repo_path
|
|
131
|
-
run_system('-C', repo_path, 'worktree', 'add', '--detach', path)
|
|
137
|
+
run_system('-C', self.class.repo_dir(repo_path), 'worktree', 'add', '--detach', path)
|
|
132
138
|
else
|
|
133
139
|
run_system('worktree', 'add', '--detach', path)
|
|
134
140
|
end
|
|
@@ -136,7 +142,7 @@ class Hiiro
|
|
|
136
142
|
|
|
137
143
|
def move_worktree(from, to, repo_path: nil)
|
|
138
144
|
if repo_path
|
|
139
|
-
run_system('-C', repo_path, 'worktree', 'move', from, to)
|
|
145
|
+
run_system('-C', self.class.repo_dir(repo_path), 'worktree', 'move', from, to)
|
|
140
146
|
else
|
|
141
147
|
run_system('worktree', 'move', from, to)
|
|
142
148
|
end
|