hiiro 0.1.366 → 0.1.368
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 +47 -0
- data/CLAUDE.md +1 -0
- data/README.md +79 -53
- data/bin/h-alias +28 -0
- data/bin/h-bin +20 -0
- data/bin/h-env +25 -0
- data/bin/h-herdr +156 -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-herdr.md +41 -0
- data/docs/h-subtask.md +5 -44
- data/docs/h-task.md +18 -712
- data/docs/h.md +2 -2
- data/docs/t.md +89 -376
- data/docs/why-t.md +23 -25
- data/exe/h +1 -0
- data/exe/t +7 -0
- data/exe/tt +7 -0
- data/herdr-plugin/herdr-plugin.toml +47 -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 +788 -0
- 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 +22 -20
- metadata +14 -2
- data/bin/t +0 -526
- data/bin/tt +0 -20
- data/lib/hiiro/task_scope.rb +0 -92
data/docs/why-t.md
CHANGED
|
@@ -44,13 +44,13 @@ tt fix-checkout add Inspect --help output
|
|
|
44
44
|
t fix-checkout todo
|
|
45
45
|
```
|
|
46
46
|
|
|
47
|
-
Task display and todo listing show every todo with its ID, status, and text. To remove one, use its displayed ID, such as `t fix-checkout todo
|
|
47
|
+
Task display and todo listing show every todo with its ID, status, and text. To remove one, use its displayed ID, such as `t todo rm fix-checkout 42`, or print just its text with `t todo show 42`. The ID must belong to that scope. Adding or removing todos does not change the task's next action or status, and `t` does not choose the next todo for you.
|
|
48
48
|
|
|
49
|
-
Task references prefer an exact name, then a unique case-sensitive prefix. Ambiguous prefixes fail.
|
|
49
|
+
Task references prefer an exact name, then a unique case-sensitive prefix. Ambiguous prefixes fail. A first word that names no task is treated as payload for the current task, so `t todo add fix build` never creates a task named `fix`. Only `t new NAME` creates tasks, and it creates that exact name rather than resolving a prefix.
|
|
50
50
|
|
|
51
|
-
`tt
|
|
51
|
+
`tt ...` is `t todo ...`. Bare `tt` lists current-task todos, and `tt help` shows todo help. Use `t todo -` or `tt add - TEXT` for orphan todos. `-` is not a task and works only for todos.
|
|
52
52
|
|
|
53
|
-
Every word after `add` is literal text, including flags and `--`, except
|
|
53
|
+
Every word after the task in `add` is literal text, including flags and `--`, except a leading `-h` or `--help`, which shows help. Empty text fails.
|
|
54
54
|
|
|
55
55
|
Todos share the existing database table with `h todo`. `t` does not rewrite `todo.yml` or change `h task` behavior. Keep the longer investigation in a document.
|
|
56
56
|
|
|
@@ -73,7 +73,7 @@ That saves the explanation and changes the task's status to `waiting`. The next
|
|
|
73
73
|
}
|
|
74
74
|
```
|
|
75
75
|
|
|
76
|
-
Bare `t` lists every task and status, including done and archived work.
|
|
76
|
+
Bare `t` (or `t ls` / `t list`) lists every task and status, including done and archived work. Each name carries its open todo count, such as `prez (3)`, and active and waiting rows show their next-action and blocker text, so you can review what needs attention without opening every terminal.
|
|
77
77
|
|
|
78
78
|
When the answer arrives:
|
|
79
79
|
|
|
@@ -205,26 +205,24 @@ The workspace identifies running terminals, not a separate persisted-session sto
|
|
|
205
205
|
|
|
206
206
|
## Context can save typing without making scripts guess
|
|
207
207
|
|
|
208
|
-
The
|
|
209
|
-
|
|
210
|
-
Use `.` when the calling Herdr workspace, directory, or saved fallback identifies the task:
|
|
208
|
+
The command comes first, and the task is optional: `t show fix-checkout` names it, `t show` uses the current task. A first word that names a task, exactly or by unique prefix, is the task; anything else is payload for the current task, the same rule the old `h task` commands used. `-t TASK` forces a task, `-f` picks one with a fuzzy finder, and `.` stands for the current task when a payload could look like a name:
|
|
211
209
|
|
|
212
210
|
```bash
|
|
213
|
-
t
|
|
214
|
-
t
|
|
215
|
-
t
|
|
216
|
-
t .
|
|
211
|
+
t current
|
|
212
|
+
t show
|
|
213
|
+
t next
|
|
214
|
+
t next . 'Check the new test against the original failing payload'
|
|
217
215
|
```
|
|
218
216
|
|
|
219
|
-
|
|
217
|
+
The calling Herdr workspace wins over a conflicting current directory. The directory is next, followed by the saved task. Ambiguous matches and invalid, stale, or conflicting Herdr IDs are errors.
|
|
220
218
|
|
|
221
219
|
You can set that fallback without moving terminal focus:
|
|
222
220
|
|
|
223
221
|
```bash
|
|
224
|
-
t fix-checkout
|
|
222
|
+
t use fix-checkout
|
|
225
223
|
```
|
|
226
224
|
|
|
227
|
-
`t
|
|
225
|
+
`t current` only prints the selected name. Reads leave the saved fallback unchanged; `t switch NAME` saves it after a successful switch. A deleted saved task causes an error if selection reaches it. Bare `t` always lists all tasks rather than selecting one.
|
|
228
226
|
|
|
229
227
|
## An agent can leave you a useful place to resume
|
|
230
228
|
|
|
@@ -284,16 +282,16 @@ You do not need to use every command for this to pay off.
|
|
|
284
282
|
|
|
285
283
|
| Moment | Useful command | What it gives you |
|
|
286
284
|
|---|---|---|
|
|
287
|
-
| You capture a new piece of work | `t TASK
|
|
288
|
-
| You capture another step | `tt
|
|
285
|
+
| You capture a new piece of work | `t new TASK` | An exact named record and notes home |
|
|
286
|
+
| You capture another step | `tt add 'Compare the retry settings'` | A todo on the current task without replacing the next action |
|
|
289
287
|
| You decide what to work on | `t` | Every task and status, with next-action and blocker text |
|
|
290
|
-
| You resume a task | `t TASK` | The context you recorded for it |
|
|
291
|
-
| You want a fallback outside task directories and Herdr | `t TASK
|
|
292
|
-
| You need its terminals | `t TASK
|
|
293
|
-
| You want a fresh AI session | `t TASK
|
|
294
|
-
| You are about to switch away | `t
|
|
295
|
-
| Someone else is blocking progress | `t
|
|
296
|
-
| The work is complete | `t TASK
|
|
288
|
+
| You resume a task | `t show TASK` | The context you recorded for it |
|
|
289
|
+
| You want a fallback outside task directories and Herdr | `t use TASK` | Saved selection without moving terminal focus |
|
|
290
|
+
| You need its terminals | `t switch TASK` | The associated workspace and a saved fallback after success |
|
|
291
|
+
| You want a fresh AI session | `t omp TASK` | A new focused tab running the native tool |
|
|
292
|
+
| You are about to switch away | `t next 'The next concrete action'` | An instruction for your next session |
|
|
293
|
+
| Someone else is blocking progress | `t waiting 'Who or what I need'` | A waiting state and explanation |
|
|
294
|
+
| The work is complete | `t done TASK` | A done status without deleting the supporting context |
|
|
297
295
|
|
|
298
296
|
Start with task names and useful next actions. Add documents, links, and terminal organization when they make a particular task easier to resume.
|
|
299
297
|
|
|
@@ -303,4 +301,4 @@ Start with task names and useful next actions. Add documents, links, and termina
|
|
|
303
301
|
|
|
304
302
|
## Read next
|
|
305
303
|
|
|
306
|
-
[The complete t command reference](t.md) covers every subcommand, option, alias, state transition, storage location, and Herdr/worktree side effect. The
|
|
304
|
+
[The complete t command reference](t.md) covers every subcommand, option, alias, state transition, storage location, and Herdr/worktree side effect. The implementation is `Hiiro::TaskCli` in `lib/hiiro/task_cli.rb`, launched by the `t` and `tt` gem executables in `exe/`.
|
data/exe/h
CHANGED
data/exe/t
ADDED
data/exe/tt
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Hiiro task actions for Herdr. Install with `h herdr install`, which copies this
|
|
2
|
+
# directory to ~/.config/hiiro/herdr-plugin and links it. Every action opens the
|
|
3
|
+
# popup pane with HIIRO_HERDR_ACTION set; `h herdr popup` does the work there.
|
|
4
|
+
id = "hiiro"
|
|
5
|
+
name = "Hiiro tasks"
|
|
6
|
+
version = "0.1.0"
|
|
7
|
+
min_herdr_version = "0.7.4"
|
|
8
|
+
description = "Fuzzy task switcher, todo capture, and task shell/editor popups backed by the t CLI."
|
|
9
|
+
platforms = ["linux", "macos"]
|
|
10
|
+
|
|
11
|
+
[[actions]]
|
|
12
|
+
id = "switch"
|
|
13
|
+
title = "Switch to task…"
|
|
14
|
+
contexts = ["workspace"]
|
|
15
|
+
command = ["h", "herdr", "action", "switch"]
|
|
16
|
+
|
|
17
|
+
[[actions]]
|
|
18
|
+
id = "todo-add"
|
|
19
|
+
title = "Add todo to task…"
|
|
20
|
+
contexts = ["workspace"]
|
|
21
|
+
command = ["h", "herdr", "action", "todo-add"]
|
|
22
|
+
|
|
23
|
+
[[actions]]
|
|
24
|
+
id = "todos"
|
|
25
|
+
title = "Copy a todo from the current task…"
|
|
26
|
+
contexts = ["workspace"]
|
|
27
|
+
command = ["h", "herdr", "action", "todos"]
|
|
28
|
+
|
|
29
|
+
[[actions]]
|
|
30
|
+
id = "shell"
|
|
31
|
+
title = "Shell in the current task directory"
|
|
32
|
+
contexts = ["workspace"]
|
|
33
|
+
command = ["h", "herdr", "action", "shell"]
|
|
34
|
+
|
|
35
|
+
[[actions]]
|
|
36
|
+
id = "nvim"
|
|
37
|
+
title = "nvim in the current task notes"
|
|
38
|
+
contexts = ["workspace"]
|
|
39
|
+
command = ["h", "herdr", "action", "nvim"]
|
|
40
|
+
|
|
41
|
+
[[panes]]
|
|
42
|
+
id = "popup"
|
|
43
|
+
title = "hiiro"
|
|
44
|
+
placement = "popup"
|
|
45
|
+
width = "70%"
|
|
46
|
+
height = "70%"
|
|
47
|
+
command = ["h", "herdr", "popup"]
|
|
@@ -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 use NAME' unless @pin
|
|
70
|
+
|
|
71
|
+
saved = PinRecord.find_key('t', 'current_task')
|
|
72
|
+
raise Error, 'No current task; supply a task name or run t use NAME' unless saved
|
|
73
|
+
|
|
74
|
+
TaskRecord[saved.value] || raise(Error, 'Saved task no longer exists; run t use NAME')
|
|
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
|