hiiro 0.1.367 → 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 +18 -0
- data/README.md +36 -48
- data/bin/h-alias +28 -0
- data/bin/h-env +25 -0
- data/bin/h-herdr +156 -0
- data/docs/h-herdr.md +41 -0
- data/docs/h-task.md +13 -170
- data/docs/h.md +1 -0
- data/docs/t.md +91 -388
- data/docs/why-t.md +21 -23
- data/herdr-plugin/herdr-plugin.toml +47 -0
- data/lib/hiiro/current_task.rb +3 -3
- data/lib/hiiro/task_cli.rb +279 -162
- data/lib/hiiro/version.rb +1 -1
- data/lib/hiiro.rb +0 -1
- metadata +6 -2
- data/lib/hiiro/task_scope.rb +0 -51
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 975c627734daa28e7efa5c45802cd3f296ec3f338c7e2ad73835e22d219223e6
|
|
4
|
+
data.tar.gz: bcd42f9f3b2ca7bbaf33b67e1535aa4729d3701f353d313bfe3a7f64c27b3e19
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 22b19c645b77356da44007ab866f00f769ef875444b9ad5b4d00ae080ff5797b3b4cc3c500b65118ba3801f025c061f8ef01bb885aff7a63692c83c3b1ee09cc
|
|
7
|
+
data.tar.gz: aad14264c543596424e10c301401e618e13adbef8dd7e6088b9d1b6c3e9374a357040d2886843057c290f0dda65a6f6100992bfbf3bdd3d1049eb914984ea8c5
|
data/CHANGELOG.md
CHANGED
|
@@ -2,9 +2,25 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [0.1.368] - 2026-09-14
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
- `h herdr`: Herdr plugin exposing `t` through keybound popups for fuzzy task switching, todo capture, todo copying, task shell, and nvim access; `h herdr install` copies and links the plugin, `h herdr keys` prints keybindings
|
|
9
|
+
|
|
10
|
+
### Changed
|
|
11
|
+
- Task CLI grammar converted to command-first: `t COMMAND [TASK] [ARGS...]` matching the legacy `h task` rule where the first positional word is the task when it names one (exact or unique prefix), otherwise the current task is used and the word stays in the payload
|
|
12
|
+
|
|
13
|
+
### Removed
|
|
14
|
+
- `Hiiro::TaskScope` class; task resolution logic integrated into `Hiiro::TaskCli`
|
|
15
|
+
|
|
5
16
|
## [0.1.367] - 2026-09-14
|
|
6
17
|
|
|
7
18
|
### Added
|
|
19
|
+
- `t use TASK` (alias `pin`) saves the fallback task; `t current` now only prints
|
|
20
|
+
- `-t TASK` / `-f` task options on every `t` command that acts on a task
|
|
21
|
+
- `h herdr`: a Herdr plugin (`herdr-plugin/herdr-plugin.toml`) with actions `hiiro.switch`, `hiiro.todo-add`, `hiiro.todos`, `hiiro.shell`, and `hiiro.nvim` that open a popup running `t`; `h herdr install` copies and links it, `h herdr keys` prints keybindings
|
|
22
|
+
- `Hiiro::TestHarness` understands `add_cmd`, `add_option`, `add_flag`, and `opts`
|
|
23
|
+
- `t TASK todo show ID` and `tt TASK show ID` print one todo's text; `todo ls --plain` prints text only
|
|
8
24
|
- Add `h env add NAME VALUE` and `h alias add NAME COMMAND...` to append safely quoted shell definitions, preferring existing zsh module files and falling back to the root dotfiles. Use native Hiiro options, including `opts.global` and `--`.
|
|
9
25
|
- Add `h bin add NAME [COMMAND ...]` to generate executable `Hiiro.run` templates with optional empty `add_cmd` blocks. Serialize command names as Ruby symbols and refuse existing files or symlinks.
|
|
10
26
|
- `t ls` and `t list` root commands list tasks like bare `t`
|
|
@@ -20,6 +36,8 @@
|
|
|
20
36
|
- `h task start` and worktree listing failed with "Not a directory" when `~/work/.git` is a gitfile; git now runs in the parent directory
|
|
21
37
|
|
|
22
38
|
### Changed
|
|
39
|
+
- `t` grammar is now command-first, `t COMMAND [TASK] [ARGS...]`, matching the old `h task` rule: the first positional word is the task when it names one (exact or unique prefix), otherwise the current task is used and the word stays in the payload. `.` is the current task, `-` selects orphan todos. `tt ...` is `t todo ...`. `Hiiro::TaskScope` is removed
|
|
40
|
+
- `t todo add` no longer creates tasks; only `t new NAME` does
|
|
23
41
|
- Move the task CLI into `lib/hiiro/task_cli.rb` (`Hiiro::TaskCli`); `exe/t` and `exe/tt` are thin `Hiiro.run` launchers and `bin/t`, `bin/tt` are symlinks
|
|
24
42
|
- `t` requires `hiiro` like other bins instead of editing the load path; `task_scope` and `task_sessions` load with `hiiro`
|
|
25
43
|
- `t` errors print without a backtrace; task, scope, and session errors subclass `Hiiro::Error`
|
data/README.md
CHANGED
|
@@ -64,66 +64,53 @@ h ping
|
|
|
64
64
|
`t` and `tt` are gem executables in `exe/`, installed alongside `h`. They are thin
|
|
65
65
|
`Hiiro.run` launchers over `Hiiro::TaskCli` in `lib/hiiro/task_cli.rb`, which uses
|
|
66
66
|
the `add_cmd` DSL and existing task records. `bin/t` and `bin/tt` are symlinks to
|
|
67
|
-
the `exe/` files for running from a checkout with `ruby -Ilib bin/t`. `t NAME
|
|
68
|
-
creates a task and its notes directory
|
|
69
|
-
|
|
70
|
-
Use `t TASK
|
|
71
|
-
done and archived tasks, with the count of open todos after each name.
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
then the current directory, then the saved task. Stale or ambiguous context is
|
|
83
|
-
an error. `t TASK current` saves a named selection without focusing a terminal;
|
|
84
|
-
`t . current` only prints it. `t TASK switch` and `t TASK workspace` focus or
|
|
85
|
-
create the task workspace and save a named selection only after success.
|
|
86
|
-
`--show` inspects without changing focus or the saved task.
|
|
67
|
+
the `exe/` files for running from a checkout with `ruby -Ilib bin/t`. `t new NAME`
|
|
68
|
+
creates a task and its notes directory; `t tree new NAME` adds a Git worktree.
|
|
69
|
+
|
|
70
|
+
Use `t COMMAND [TASK] [ARGS...]`. Bare `t`, `t ls`, or `t list` lists every task,
|
|
71
|
+
including done and archived tasks, with the count of open todos after each name.
|
|
72
|
+
Commands that act on a task take it from the first positional argument when
|
|
73
|
+
that word names a task (exact or unique case-sensitive prefix); otherwise the
|
|
74
|
+
current task is used and the word stays in the payload, exactly like the old
|
|
75
|
+
`h task` commands. `-t TASK` forces a task, `-f` picks one with a fuzzy finder,
|
|
76
|
+
`.` is the current task, and `-` selects orphan todos. Ambiguous prefixes fail.
|
|
77
|
+
|
|
78
|
+
The current task is the calling Herdr workspace, then the current directory
|
|
79
|
+
inside a task home, code directory, worktree, or registered directory, then the
|
|
80
|
+
task saved with `t use TASK`. `t switch TASK` focuses or creates the task
|
|
81
|
+
workspace and also saves it. `t current` only prints.
|
|
87
82
|
|
|
88
83
|
```sh
|
|
89
|
-
t investigation
|
|
90
|
-
t investigation
|
|
91
|
-
t
|
|
92
|
-
tt
|
|
93
|
-
t
|
|
94
|
-
t investigation
|
|
95
|
-
t
|
|
96
|
-
t investigation
|
|
97
|
-
t investigation
|
|
98
|
-
t
|
|
99
|
-
t
|
|
100
|
-
t
|
|
84
|
+
t new investigation
|
|
85
|
+
t next investigation "Inspect the failing request"
|
|
86
|
+
t todo add investigation Compare the retry settings
|
|
87
|
+
tt add Inspect --help output # current task
|
|
88
|
+
t doc new investigation findings
|
|
89
|
+
t show investigation
|
|
90
|
+
t todo rm 42 # an ID printed by show or todo list
|
|
91
|
+
t use investigation
|
|
92
|
+
t switch investigation
|
|
93
|
+
t switch --show
|
|
94
|
+
t next . "Write the handoff"
|
|
95
|
+
t tree new investigation
|
|
101
96
|
```
|
|
102
97
|
|
|
103
|
-
A task has one `next_action` and can have multiple independent todos. `t
|
|
104
|
-
and `t
|
|
105
|
-
`t
|
|
106
|
-
`tt
|
|
107
|
-
`tt help` displays todo help. Use `t - todo` or `tt -` for orphan todos, including
|
|
108
|
-
`add` and `rm`. `-` is not a task and is invalid outside todo commands.
|
|
98
|
+
A task has one `next_action` and can have multiple independent todos. `t show`
|
|
99
|
+
and `t todo` print todos with their IDs, statuses, and text in ID order.
|
|
100
|
+
`t todo show ID` prints one todo's text and `t todo rm ID` deletes it.
|
|
101
|
+
`tt ...` is `t todo ...`. Use `t todo -` and `tt add - TEXT` for orphan todos.
|
|
109
102
|
|
|
110
|
-
Every argument after `todo add` is literal text, including flags and
|
|
111
|
-
except
|
|
112
|
-
|
|
103
|
+
Every argument after the task in `todo add` is literal text, including flags and
|
|
104
|
+
`--`, except a leading `-h` or `--help`. Empty text fails. Only `t new NAME`
|
|
105
|
+
creates tasks.
|
|
113
106
|
|
|
114
107
|
Todos share the existing `todos` table with `h todo`. `t` writes only to the
|
|
115
108
|
database and does not rewrite `todo.yml`. Adding or removing a todo does not
|
|
116
109
|
change the task's next action, status, or saved selection. Task completion and
|
|
117
110
|
archival preserve todos. `h task` is a symlink to `t`, so both share one grammar.
|
|
118
111
|
|
|
119
|
-
`t TASK
|
|
112
|
+
`t omp [TASK]`, `t codex` or `cdx`, and `t claude` or `cld` start fresh
|
|
120
113
|
native CLI sessions in new focused Herdr tabs. Claude always runs `claude`.
|
|
121
|
-
Only a nonempty prefix of `resume` as the first tool argument changes mode.
|
|
122
|
-
Bare `resume` focuses the unique running instance of that tool in the task
|
|
123
|
-
workspace, or launches the native resume picker if none is running. Multiple
|
|
124
|
-
running matches are an error. With an ID or any other arguments after `resume`,
|
|
125
|
-
the command always opens a new tab and passes those arguments to the native CLI.
|
|
126
|
-
All other arguments, including `--help`, are tool flags, not `t` flags.
|
|
127
114
|
|
|
128
115
|
Tasks can share an existing directory, including a worktree. `t` does not change
|
|
129
116
|
Git state or promise task-isolated persisted AI sessions in shared directories.
|
|
@@ -141,6 +128,7 @@ See the [task command reference](docs/t.md) for all commands and the [workflow i
|
|
|
141
128
|
| `h setup` | Install plugins and subcommands to system paths |
|
|
142
129
|
| `h edit` | Open the h script in your editor |
|
|
143
130
|
| `h alert` | macOS desktop notifications via terminal-notifier |
|
|
131
|
+
| `h herdr` | Herdr plugin for `t`: fuzzy task switcher, todo capture, todo copy, task shell and nvim popups (`h herdr install`) |
|
|
144
132
|
| `h task` | Same program as `t`: task records, todos, worktrees (`t NAME tree new`), and Herdr workspaces |
|
|
145
133
|
|
|
146
134
|
### External Subcommands
|
data/bin/h-alias
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
require 'hiiro'
|
|
4
|
+
|
|
5
|
+
Hiiro.run do
|
|
6
|
+
add_flag :global, short: :g, desc: 'Create a global zsh alias'
|
|
7
|
+
|
|
8
|
+
add_cmd :add, args: ['NAME', 'COMMAND...'], opts: [:global] do
|
|
9
|
+
abort 'Usage: h alias add [--global|-g] NAME COMMAND...' unless opts.args.length >= 2
|
|
10
|
+
name, *command_args = opts.args
|
|
11
|
+
abort 'Invalid alias name' unless /\A[A-Za-z0-9_.][A-Za-z0-9_.-]*\z/.match?(name)
|
|
12
|
+
command = command_args.length == 1 ? command_args.first : Shellwords.join(command_args)
|
|
13
|
+
quoted = "'" + command.gsub("'") { "'\\''" } + "'"
|
|
14
|
+
|
|
15
|
+
home = ENV.fetch('HOME')
|
|
16
|
+
path = File.join(home, '.zshrc.d', 'aliases.zsh')
|
|
17
|
+
path = File.join(home, '.zshrc') unless File.file?(path)
|
|
18
|
+
|
|
19
|
+
File.open(path, 'a+', 0o600) do |file|
|
|
20
|
+
unless file.size.zero?
|
|
21
|
+
file.seek(-1, IO::SEEK_END)
|
|
22
|
+
file.write("\n") unless file.read(1) == "\n"
|
|
23
|
+
end
|
|
24
|
+
file.write("alias #{opts.global ? '-g ' : ''}#{name}=#{quoted}\n")
|
|
25
|
+
end
|
|
26
|
+
puts "Added alias to #{path}"
|
|
27
|
+
end
|
|
28
|
+
end
|
data/bin/h-env
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
require 'hiiro'
|
|
4
|
+
|
|
5
|
+
Hiiro.run do
|
|
6
|
+
add_cmd :add, args: %i[NAME VALUE] do
|
|
7
|
+
abort 'Usage: h env add NAME VALUE' unless opts.args.length == 2
|
|
8
|
+
name, value = opts.args
|
|
9
|
+
abort 'Invalid environment variable name' unless /\A[A-Za-z_][A-Za-z0-9_]*\z/.match?(name)
|
|
10
|
+
|
|
11
|
+
home = ENV.fetch('HOME')
|
|
12
|
+
path = File.join(home, '.zshenv.d', 'vars.zsh')
|
|
13
|
+
path = File.join(home, '.zshenv') unless File.file?(path)
|
|
14
|
+
escaped = value.gsub(/["\\$`]/) { |char| "\\#{char}" }
|
|
15
|
+
|
|
16
|
+
File.open(path, 'a+', 0o600) do |file|
|
|
17
|
+
unless file.size.zero?
|
|
18
|
+
file.seek(-1, IO::SEEK_END)
|
|
19
|
+
file.write("\n") unless file.read(1) == "\n"
|
|
20
|
+
end
|
|
21
|
+
file.write("export #{name}=\"#{escaped}\"\n")
|
|
22
|
+
end
|
|
23
|
+
puts "Added environment variable to #{path}"
|
|
24
|
+
end
|
|
25
|
+
end
|
data/bin/h-herdr
ADDED
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
require 'hiiro'
|
|
4
|
+
require 'fileutils'
|
|
5
|
+
|
|
6
|
+
# Herdr plugin glue for the t task CLI. The plugin manifest lives in the gem's
|
|
7
|
+
# herdr-plugin/ directory; `h herdr install` copies it to ~/.config/hiiro/herdr-plugin
|
|
8
|
+
# and links it with `herdr plugin link`. Actions run headless behind keybindings and
|
|
9
|
+
# open the plugin popup; `h herdr popup` runs inside that popup with a real TTY.
|
|
10
|
+
|
|
11
|
+
PLUGIN_ID = 'hiiro'
|
|
12
|
+
ACTIONS = %w[switch todo-add todos shell nvim].freeze
|
|
13
|
+
INSTALL_DIR = Hiiro::Config.config_dir('herdr-plugin')
|
|
14
|
+
SOURCE_DIR = File.expand_path('../herdr-plugin', File.dirname(File.realpath(__FILE__)))
|
|
15
|
+
KEYS_SNIPPET = <<~TOML
|
|
16
|
+
# Hiiro task actions (h herdr keys)
|
|
17
|
+
[[keys.command]]
|
|
18
|
+
key = "prefix+t"
|
|
19
|
+
type = "plugin_action"
|
|
20
|
+
command = "hiiro.switch"
|
|
21
|
+
description = "switch to task"
|
|
22
|
+
|
|
23
|
+
[[keys.command]]
|
|
24
|
+
key = "prefix+shift+a"
|
|
25
|
+
type = "plugin_action"
|
|
26
|
+
command = "hiiro.todo-add"
|
|
27
|
+
description = "add todo"
|
|
28
|
+
|
|
29
|
+
[[keys.command]]
|
|
30
|
+
key = "prefix+shift+y"
|
|
31
|
+
type = "plugin_action"
|
|
32
|
+
command = "hiiro.todos"
|
|
33
|
+
description = "copy a todo"
|
|
34
|
+
|
|
35
|
+
[[keys.command]]
|
|
36
|
+
key = "prefix+shift+s"
|
|
37
|
+
type = "plugin_action"
|
|
38
|
+
command = "hiiro.shell"
|
|
39
|
+
description = "task shell popup"
|
|
40
|
+
|
|
41
|
+
[[keys.command]]
|
|
42
|
+
key = "prefix+shift+e"
|
|
43
|
+
type = "plugin_action"
|
|
44
|
+
command = "hiiro.nvim"
|
|
45
|
+
description = "task notes in nvim"
|
|
46
|
+
TOML
|
|
47
|
+
|
|
48
|
+
def herdr_bin
|
|
49
|
+
ENV['HERDR_BIN_PATH'] || 'herdr'
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def source_dir
|
|
53
|
+
return SOURCE_DIR if File.exist?(File.join(SOURCE_DIR, 'herdr-plugin.toml'))
|
|
54
|
+
gem_root = Gem.loaded_specs['hiiro']&.full_gem_path
|
|
55
|
+
gem_root && File.join(gem_root, 'herdr-plugin')
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
Hiiro.run(*ARGV, external_commands: false) do
|
|
59
|
+
add_cmd(:install) do
|
|
60
|
+
no_args = opts.args.empty?
|
|
61
|
+
raise Hiiro::Error, 'h herdr install takes no arguments' unless no_args
|
|
62
|
+
src = source_dir
|
|
63
|
+
raise Hiiro::Error, 'Plugin manifest not found; reinstall the hiiro gem' unless src
|
|
64
|
+
FileUtils.mkdir_p(File.dirname(INSTALL_DIR))
|
|
65
|
+
FileUtils.rm_rf(INSTALL_DIR)
|
|
66
|
+
FileUtils.cp_r(src, INSTALL_DIR)
|
|
67
|
+
puts "Copied plugin to #{INSTALL_DIR}"
|
|
68
|
+
linked = system(herdr_bin, 'plugin', 'link', INSTALL_DIR)
|
|
69
|
+
puts(linked ? 'Linked plugin "hiiro" in Herdr' : 'Plugin already linked or link failed; run: herdr plugin list')
|
|
70
|
+
puts "\nAdd keybindings to ~/.config/herdr/config.toml (h herdr keys prints them), then run:"
|
|
71
|
+
puts ' herdr server reload-config'
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
add_cmd(:uninstall) do
|
|
75
|
+
system(herdr_bin, 'plugin', 'unlink', PLUGIN_ID)
|
|
76
|
+
FileUtils.rm_rf(INSTALL_DIR)
|
|
77
|
+
puts "Removed #{INSTALL_DIR}"
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
add_cmd(:keys) { puts KEYS_SNIPPET }
|
|
81
|
+
|
|
82
|
+
add_cmd(:actions) { ACTIONS.each { |name| puts "hiiro.#{name}" } }
|
|
83
|
+
|
|
84
|
+
# Headless: bound to a key, opens the popup with the chosen action.
|
|
85
|
+
add_cmd(:action, args: %i[name]) do
|
|
86
|
+
name = opts.args.first
|
|
87
|
+
raise Hiiro::Error, "Unknown action #{name}; one of #{ACTIONS.join(', ')}" unless ACTIONS.include?(name)
|
|
88
|
+
size = %w[shell nvim].include?(name) ? %w[--width 90% --height 90%] : []
|
|
89
|
+
system(herdr_bin, 'plugin', 'pane', 'open', '--plugin', PLUGIN_ID, '--entrypoint', 'popup',
|
|
90
|
+
'--env', "HIIRO_HERDR_ACTION=#{name}", *size, '--focus')
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# Runs inside the popup pane (real TTY, HERDR_WORKSPACE_ID set by Herdr).
|
|
94
|
+
add_cmd(:popup) do
|
|
95
|
+
name = ENV['HIIRO_HERDR_ACTION'] || opts.args.first
|
|
96
|
+
raise Hiiro::Error, "Set HIIRO_HERDR_ACTION to one of #{ACTIONS.join(', ')}" unless ACTIONS.include?(name)
|
|
97
|
+
run_popup(name)
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def tasks
|
|
101
|
+
Hiiro::TaskRecord.all_as_list.reject { |task| %w[done archived].include?(task.task_status) }
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def current_task_name
|
|
105
|
+
Hiiro::CurrentTask.new(herdr: -> { herdr_client }, pin: true).resolve&.name
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def pick_task(prompt_current: true)
|
|
109
|
+
current = prompt_current && current_task_name
|
|
110
|
+
names = tasks.map(&:name)
|
|
111
|
+
names = [current, *names.reject { |n| n == current }] if current
|
|
112
|
+
raise Hiiro::Error, 'No tasks; create one with t NAME new' if names.empty?
|
|
113
|
+
choice = fuzzyfind(names)
|
|
114
|
+
raise Hiiro::Error, 'No task selected' if choice.nil? || choice.strip.empty?
|
|
115
|
+
choice.strip
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def pause(message)
|
|
119
|
+
$stderr.puts message
|
|
120
|
+
sleep 2
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def run_popup(name)
|
|
124
|
+
case name
|
|
125
|
+
when 'switch'
|
|
126
|
+
task = pick_task(prompt_current: false)
|
|
127
|
+
system('t', 'switch', task) || pause("t switch #{task} failed")
|
|
128
|
+
when 'todo-add'
|
|
129
|
+
task = pick_task
|
|
130
|
+
print "Todo for #{task}: "
|
|
131
|
+
text = $stdin.gets.to_s.strip
|
|
132
|
+
raise Hiiro::Error, 'No todo text' if text.empty?
|
|
133
|
+
system('t', 'todo', 'add', '-t', task, text) || pause('todo add failed')
|
|
134
|
+
sleep 1
|
|
135
|
+
when 'todos'
|
|
136
|
+
task = current_task_name || pick_task
|
|
137
|
+
items = Hiiro::TodoItem.where(task_name: task, subtask_name: nil).exclude(status: %w[done skip]).order(:id).all
|
|
138
|
+
raise Hiiro::Error, "No open todos for #{task}" if items.empty?
|
|
139
|
+
text = fuzzyfind_from_map(items.to_h { |item| ["#{item.id} #{item.text}", item.text] })
|
|
140
|
+
raise Hiiro::Error, 'No todo selected' unless text
|
|
141
|
+
Hiiro::Shell.pipe(text, 'pbcopy')
|
|
142
|
+
puts "Copied: #{text}"
|
|
143
|
+
sleep 1
|
|
144
|
+
when 'shell'
|
|
145
|
+
exec('t', 'sh')
|
|
146
|
+
when 'nvim'
|
|
147
|
+
task = Hiiro::CurrentTask.new(herdr: -> { herdr_client }, pin: true).resolve!
|
|
148
|
+
FileUtils.mkdir_p(task.home)
|
|
149
|
+
Dir.chdir(task.home)
|
|
150
|
+
exec(ENV['EDITOR'] || 'nvim', '.')
|
|
151
|
+
end
|
|
152
|
+
rescue Hiiro::Error => e
|
|
153
|
+
pause("ERROR: #{e.message}")
|
|
154
|
+
exit 1
|
|
155
|
+
end
|
|
156
|
+
end
|
data/docs/h-herdr.md
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# h herdr
|
|
2
|
+
|
|
3
|
+
Expose the `t` task CLI inside Herdr as keybound actions. Each action opens a session-modal popup that runs `h herdr popup`, so fuzzy pickers and editors get a real TTY without disturbing the tiled layout.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
h herdr install # copies herdr-plugin/ to ~/.config/hiiro/herdr-plugin and runs herdr plugin link
|
|
9
|
+
h herdr keys # prints [[keys.command]] entries to paste into ~/.config/herdr/config.toml
|
|
10
|
+
herdr server reload-config
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
`h herdr uninstall` unlinks the plugin and removes the copied directory. Requires Herdr 0.7.4 or newer, and `sk` or `fzf` on `PATH`.
|
|
14
|
+
|
|
15
|
+
## Actions
|
|
16
|
+
|
|
17
|
+
| Action | Default key | Popup behavior |
|
|
18
|
+
|---|---|---|
|
|
19
|
+
| `hiiro.switch` | `prefix+t` | Fuzzy-pick an active or waiting task, then `t NAME switch` |
|
|
20
|
+
| `hiiro.todo-add` | `prefix+shift+a` | Fuzzy-pick a task (current task first), type the todo text, then `t NAME todo add TEXT` |
|
|
21
|
+
| `hiiro.todos` | `prefix+shift+y` | Fuzzy-pick an open todo of the current task and copy its text to the clipboard |
|
|
22
|
+
| `hiiro.shell` | `prefix+shift+s` | 90% popup running `t sh` in the current task's start directory |
|
|
23
|
+
| `hiiro.nvim` | `prefix+shift+e` | 90% popup running `$EDITOR` (default `nvim`) in the current task's notes home |
|
|
24
|
+
|
|
25
|
+
The current task resolves through `Hiiro::CurrentTask`: the popup's Herdr workspace, then the working directory, then the task saved with `t use TASK`. Errors print in the popup for two seconds before it closes.
|
|
26
|
+
|
|
27
|
+
## Subcommands
|
|
28
|
+
|
|
29
|
+
| Command | Behavior |
|
|
30
|
+
|---|---|
|
|
31
|
+
| `h herdr install` | Copy the manifest from the gem, link it in Herdr, print next steps |
|
|
32
|
+
| `h herdr uninstall` | Unlink and remove the copy |
|
|
33
|
+
| `h herdr keys` | Print the keybinding snippet |
|
|
34
|
+
| `h herdr actions` | List action ids |
|
|
35
|
+
| `h herdr action NAME` | Headless: open the popup for NAME (what the manifest binds) |
|
|
36
|
+
| `h herdr popup` | Runs inside the popup; reads `HIIRO_HERDR_ACTION` |
|
|
37
|
+
|
|
38
|
+
## Files
|
|
39
|
+
|
|
40
|
+
- `herdr-plugin/herdr-plugin.toml` in the gem: manifest with five `[[actions]]` and one `[[panes]]` popup entrypoint
|
|
41
|
+
- `bin/h-herdr`: actions, popup logic, install and keys helpers
|
data/docs/h-task.md
CHANGED
|
@@ -8,185 +8,28 @@ Task todos use the existing `todos` table shared with `h todo`. `t` writes to th
|
|
|
8
8
|
|
|
9
9
|
## t
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
The grammar is `t TASK COMMAND...`. Bare `t`, `t ls`, or `t list` lists all tasks, including done and archived tasks, with open todo counts. `t TASK` shows the task. Only exact root `t help` displays generic usage and native scoped help without looking up a task. First words such as `new`, `show`, `edit`, `pry`, and `he` are task references, not root commands or help abbreviations.
|
|
14
|
-
|
|
15
|
-
Named references match an exact name first, then a unique case-sensitive prefix. Ambiguous prefixes are errors. Unknown names fail except with `t NAME new` or `t NAME todo add TEXT...`. Explicit `new` creates exactly `NAME` without prefix resolution. `t TASK help` shows task commands, and `t TASK todo help` shows todo commands. Native command abbreviations apply inside these scopes.
|
|
16
|
-
|
|
17
|
-
Use `.` to select the current task, including when supplying a payload: `t . next 'Compare the export'`. Selection checks the calling Herdr workspace, then the current directory inside a task home, code directory, or registered directory, then the saved task. Workspace context wins over a conflicting directory. Ambiguous matches and invalid, stale, or conflicting Herdr IDs are errors. Outside Herdr, an unrelated focused workspace does not affect selection. An explicit name bypasses context lookup.
|
|
18
|
-
|
|
19
|
-
`t TASK current` prints the resolved name and saves a named selection without changing terminal focus. `t . current` only prints it. The fallback is a `PinRecord` with `command='t'`, `key='current_task'`, and the task ID as a JSON integer in `value_json`. A missing saved task is an error when selection reaches that fallback. Reads and workspace opens through `.` do not replace it.
|
|
20
|
-
|
|
21
|
-
### Task records
|
|
22
|
-
|
|
23
|
-
```text
|
|
24
|
-
t
|
|
25
|
-
t TASK
|
|
26
|
-
t TASK show
|
|
27
|
-
t TASK current
|
|
28
|
-
t NAME new
|
|
29
|
-
t TASK next [TEXT...] [--clear]
|
|
30
|
-
t TASK status [active|waiting|done|archived]
|
|
31
|
-
t TASK waiting [TEXT...] [--clear]
|
|
32
|
-
t TASK done
|
|
33
|
-
t TASK archive
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
Bare `t`, `t ls`, and `t list` list tasks regardless of context or the saved task, showing each name with its open todo count, e.g. `prez (3)`. There is no root `new` or `show` action. `next`, `waiting`, and `status` without a payload display the selected task's current value.
|
|
37
|
-
|
|
38
|
-
`t NAME new` creates a record and `~/notes/work/NAME`. It never creates a Git worktree, moves code, or launches Herdr. Repeating `new` keeps the exact existing record and ensures its home exists. Names contain 1-120 ASCII letters, digits, dots, underscores, or hyphens and start with a letter or digit. Existing names that contain other characters remain usable, with those characters percent-encoded in the computed home directory name.
|
|
39
|
-
|
|
40
|
-
Setting waiting text changes status to `waiting`. Clearing that text changes a waiting task back to `active`. `done` and `archive` change status and record timestamps. They never remove todos, a task home, a file, a directory, a link, or a workspace. `t TASK status active` reopens a task.
|
|
41
|
-
|
|
42
|
-
```bash
|
|
43
|
-
t audit-invoices new
|
|
44
|
-
t audit-invoices next 'Compare the September export'
|
|
45
|
-
t audit-invoices waiting 'Finance approval'
|
|
46
|
-
t audit-invoices waiting --clear
|
|
47
|
-
t audit-invoices done
|
|
48
|
-
t audit-invoices
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
### Task todos
|
|
52
|
-
|
|
53
|
-
```text
|
|
54
|
-
t TASK todo
|
|
55
|
-
t TASK todo list
|
|
56
|
-
t TASK todo ls
|
|
57
|
-
t TASK todo add TEXT...
|
|
58
|
-
t TASK todo rm ID
|
|
59
|
-
tt TASK [COMMAND...]
|
|
60
|
-
tt
|
|
61
|
-
tt help
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
`tt TASK ...` delegates to `t TASK todo ...`. Bare `tt` means `t . todo`, and `tt help` shows todo help without task lookup. The default todo action is listing. `t - todo` and `tt -` select orphan todos, with `add` and `rm` available in that scope. `-` is invalid outside todo commands and never creates a task.
|
|
65
|
-
|
|
66
|
-
If a named `todo add` finds no match, it creates the task using `new` validation and home rules, then adds one todo with status `not_started`. Task and todo database writes use one immediate SQLite transaction. Other todo actions never create tasks.
|
|
67
|
-
|
|
68
|
-
Every token after `add` is literal text, including flags and `--`, except that leading `add -h` or `add --help` displays native option help. The tokens are joined with spaces. Missing, empty, or whitespace-only text fails before task creation.
|
|
69
|
-
|
|
70
|
-
```bash
|
|
71
|
-
t audit-invoices todo add Compare the September export
|
|
72
|
-
tt audit-invoices add Inspect --help output
|
|
73
|
-
t audit-invoices todo
|
|
74
|
-
t audit-invoices todo rm 42
|
|
75
|
-
tt - add Buy printer paper
|
|
76
|
-
```
|
|
77
|
-
|
|
78
|
-
Use an ID printed by `show` or todo listing in place of `42`. `rm` accepts exactly one decimal database ID belonging to the selected scope, not a list position or suffix. Missing, invalid, or extra arguments fail.
|
|
79
|
-
|
|
80
|
-
Task display and todo listing print each matching item's ID, status, and text in ID order. Matching uses the full task name exactly, including legacy rows with both `task_name` and `subtask_name`. A parent task does not include its subtasks' todos. New task todos store the full task name in `task_name` and leave `subtask_name` unset. Orphan rows leave both unset.
|
|
81
|
-
|
|
82
|
-
Each task still has one independent `next_action`. Adding or removing todos does not change that field, task status, or saved selection. `t` has no todo-completion command or automatic next-action promotion. The separate `h task` and `h todo` commands keep their existing behavior.
|
|
83
|
-
|
|
84
|
-
### Directory, link, PR, and file references
|
|
85
|
-
|
|
86
|
-
```text
|
|
87
|
-
t TASK directory add PATH [--primary] [--label LABEL]
|
|
88
|
-
t TASK directory list
|
|
89
|
-
t TASK directory open [ID|PATH|LABEL]
|
|
90
|
-
t TASK link add URL [--kind general|issue|thread] [--label LABEL]
|
|
91
|
-
t TASK link list [--kind general|issue|thread]
|
|
92
|
-
t TASK link open [ID|URL|LABEL]
|
|
93
|
-
t TASK pr add URL [--label LABEL]
|
|
94
|
-
t TASK pr list
|
|
95
|
-
t TASK pr open [ID|URL|LABEL]
|
|
96
|
-
t TASK file add PATH [--label LABEL]
|
|
97
|
-
t TASK file list
|
|
98
|
-
t TASK file open [ID|PATH|LABEL]
|
|
99
|
-
```
|
|
100
|
-
|
|
101
|
-
Directory and file attachments must already exist. `add` stores their canonical paths without moving or copying anything. Repeating an identical attachment does not create another reference. `--primary` marks an attached directory as the default code directory for new workspace tabs and panes. An existing directory can be a Git worktree. Registering it does not create a worktree or alter sparse checkout.
|
|
102
|
-
|
|
103
|
-
Links must be absolute HTTP or HTTPS URLs. `link list` includes PR references unless a kind filter is present. PRs use the same resource storage as other links and do not require a Git repository or provider API.
|
|
104
|
-
|
|
105
|
-
`file list` also discovers files in the task home, including documents, without registration. Home files can be opened by a relative path or an unambiguous basename. An omitted open selector works only when exactly one resource matches. Otherwise, the command requires an ID, path, URL, or unique label.
|
|
106
|
-
|
|
107
|
-
`open` uses the operating system's default application. Attachments remain references even after task completion. List commands also accept `ls`. Leaf help, such as `t audit-invoices directory add --help`, lists options without running the action.
|
|
108
|
-
|
|
109
|
-
### Documents
|
|
110
|
-
|
|
111
|
-
```text
|
|
112
|
-
t TASK doc new NAME [TITLE...]
|
|
113
|
-
t TASK doc list
|
|
114
|
-
t TASK doc open [NAME]
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
`doc new` creates a Markdown file in the task home with an initial heading. It never overwrites an existing file. Documents have a stable task-ID prefix, such as `task-42-investigation.md`, to avoid collisions in `mdoc`'s shared HTML output directory. `t TASK doc open investigation` accepts the short name and invokes `mdoc`. Existing Markdown files in the task home also appear without registration.
|
|
118
|
-
|
|
119
|
-
Task creation, metadata, references, and document creation/listing work without Git or Herdr when a named task is supplied. Document reading requires `mdoc` on `PATH` and its existing configuration.
|
|
120
|
-
|
|
121
|
-
### Herdr workspaces, tabs, and panes
|
|
122
|
-
|
|
123
|
-
```text
|
|
124
|
-
t TASK workspace [--directory PATH]
|
|
125
|
-
t TASK switch [--directory PATH]
|
|
126
|
-
t TASK workspace --show
|
|
127
|
-
t TASK switch --show
|
|
128
|
-
t TASK tab list
|
|
129
|
-
t TASK tab new [LABEL] [--directory PATH] [--command COMMAND]
|
|
130
|
-
t TASK tab open ID|LABEL
|
|
131
|
-
t TASK pane list
|
|
132
|
-
t TASK pane open ID|LABEL
|
|
133
|
-
t TASK pane read ID|LABEL
|
|
134
|
-
t TASK pane run ID|LABEL -- COMMAND...
|
|
135
|
-
t TASK pane split ID|LABEL [--direction right|down] [--directory PATH] [--command COMMAND]
|
|
136
|
-
```
|
|
137
|
-
|
|
138
|
-
These commands require a running Herdr server. `t TASK workspace` and its `switch` alias focus the workspace with the task's label or create one. They save a named task only after a successful switch. `t . workspace` leaves the saved fallback unchanged. A new workspace starts in the explicit directory, the primary code directory, the legacy worktree, or the task home, in that order. `--directory` changes that operation's start directory without changing stored attachments.
|
|
139
|
-
|
|
140
|
-
`--show` queries the current tabs and panes without saving, focusing, or creating a workspace. `workspace` and `switch` are direct commands, not groups. Native Hiiro abbreviation matching accepts `t TASK wor`.
|
|
141
|
-
|
|
142
|
-
Tab and pane selectors must belong to the selected task's workspace. Duplicate labels require a live ID. No pane or tab ID is stored as durable task identity. Task workspace labels follow Herdr's dot-to-underscore normalization. Colliding task or workspace labels are errors rather than fuzzy matches.
|
|
143
|
-
|
|
144
|
-
Use `--` before literal command arguments that begin with a dash:
|
|
145
|
-
|
|
146
|
-
```bash
|
|
147
|
-
t audit-invoices pane run PANE_ID -- printf '%s\n' --example
|
|
148
|
-
```
|
|
149
|
-
|
|
150
|
-
### Native AI sessions
|
|
151
|
-
|
|
152
|
-
`t TASK omp`, `t TASK codex` or `cdx`, and `t TASK claude` or `cld` create new focused tabs in the task workspace. They launch the native `omp`, `codex`, and `claude` executables, respectively. The workspace is created if needed. Fresh sessions are the default.
|
|
153
|
-
|
|
154
|
-
Only the first tool argument can select resume mode. A nonempty prefix of `resume`, such as `r`, `res`, or `resume`, consumes that token. OMP and Claude receive `--resume`; Codex receives its `resume` subcommand.
|
|
155
|
-
|
|
156
|
-
With no remaining arguments, resume focuses the unique genuinely running tool in that workspace, using Herdr's agent metadata rather than the tab label. Multiple running matches are an error that reports their IDs. If none is running, a new tab launches the native resume picker.
|
|
157
|
-
|
|
158
|
-
With any remaining arguments, resume always opens a new tab and forwards those arguments unchanged. Session IDs and options belong to the native CLI. Other arguments, including `--help` and `--`, also pass through unchanged. `t` does not inject model, permission, continue, or fresh-session flags.
|
|
159
|
-
|
|
160
|
-
```bash
|
|
161
|
-
t audit-invoices omp
|
|
162
|
-
t audit-invoices cdx r
|
|
163
|
-
t audit-invoices cld resume SESSION_ID
|
|
164
|
-
t audit-invoices codex resume --help
|
|
165
|
-
t audit-invoices claude --help
|
|
166
|
-
```
|
|
167
|
-
|
|
168
|
-
The launcher scopes live-pane lookup to the task workspace. Persisted session discovery remains native CLI behavior and is not necessarily task-isolated when tasks share a directory. `t` performs no auth or API requests and makes no automatic Git changes.
|
|
11
|
+
`h task` is a symlink to `t`, so `h task ARGS...` is `t ARGS...`. The grammar is `t COMMAND [TASK] [ARGS...]`: the command comes first, and commands that act on a task take it from the first positional argument when that word names a task (exact or unique prefix); otherwise the current task is used and the word stays in the payload. `-t TASK` forces a task, `-f` picks one with a fuzzy finder, `.` is the current task, and `-` selects orphan todos. See [t](t.md) for every command.
|
|
169
12
|
|
|
170
13
|
## h task
|
|
171
14
|
|
|
172
|
-
`h task` is the same program as `t`: `bin/h-task` is a symlink to `exe/t`, so `h task ARGS...` behaves exactly like `t ARGS...` with the task-first grammar above. `h subtask` is gone; a subtask is a task named `parent/child`, and `t parent/child
|
|
15
|
+
`h task` is the same program as `t`: `bin/h-task` is a symlink to `exe/t`, so `h task ARGS...` behaves exactly like `t ARGS...` with the task-first grammar above. `h subtask` is gone; a subtask is a task named `parent/child`, and `t tree new parent/child` creates its worktree under `~/work/parent/child`.
|
|
173
16
|
|
|
174
17
|
Worktree operations that used to live only under `h task` are now task commands:
|
|
175
18
|
|
|
176
19
|
| Old | Now |
|
|
177
20
|
|---|---|
|
|
178
|
-
| `h task start NAME [APP] [-s GROUP]` | `t
|
|
179
|
-
| `h task switch NAME [APP]` | `t NAME
|
|
180
|
-
| `h task stop NAME` | `t
|
|
181
|
-
| `h task resume [TREE]` | `t
|
|
182
|
-
| `h task path`, `h task branch`, `h task tree` | `t TASK
|
|
183
|
-
| `h task sh [CMD...]` | `t
|
|
184
|
-
| `h task cd` | `t TASK
|
|
185
|
-
| `h task todo ...` | `t
|
|
21
|
+
| `h task start NAME [APP] [-s GROUP]` | `t tree new NAME [--app APP] [--sparse GROUP]` (creates the task record if needed, then the worktree, then the Herdr workspace) |
|
|
22
|
+
| `h task switch NAME [APP]` | `t switch NAME [--directory DIR]` |
|
|
23
|
+
| `h task stop NAME` | `t tree rm NAME` (detaches the worktree, keeps the directory, registers it as a directory resource) |
|
|
24
|
+
| `h task resume [TREE]` | `t tree resume NAME [TREE]` |
|
|
25
|
+
| `h task path`, `h task branch`, `h task tree` | `t path [TASK]`, `t branch [TASK]`, `t tree [TASK]` |
|
|
26
|
+
| `h task sh [CMD...]` | `t sh [TASK] [CMD...]` |
|
|
27
|
+
| `h task cd` | `t cd [TASK]` |
|
|
28
|
+
| `h task todo ...` | `t todo ... [TASK]` or `tt ...` |
|
|
186
29
|
| `h task ls` | `t ls` |
|
|
187
|
-
| `h task current` | `t
|
|
30
|
+
| `h task current` | `t current` |
|
|
188
31
|
| `h task queue`, `service`, `run`, `file` | `h queue`, `h service`, `h run`, `h file` |
|
|
189
32
|
|
|
190
|
-
`h task tag`, `untag`, `tags`, `sparse`, `from`, `prune`, `apps`, `save`, `status`, and `prs` were not carried over. Tag branches with `h branch tag`, inspect worktrees with `h wtree`, and register an existing directory with `t
|
|
33
|
+
`h task tag`, `untag`, `tags`, `sparse`, `from`, `prune`, `apps`, `save`, `status`, and `prs` were not carried over. Tag branches with `h branch tag`, inspect worktrees with `h wtree`, and register an existing directory with `t directory add [TASK] PATH --primary`.
|
|
191
34
|
|
|
192
|
-
`Hiiro::TaskManager` still holds the worktree creation code that `t
|
|
35
|
+
`Hiiro::TaskManager` still holds the worktree creation code that `t tree new` and the shared `Hiiro::CurrentTask` resolver use; `h service`, `h run`, and `h file` keep using it for the current task through `Environment#task`, which now also recognizes a task by its home, primary directory, or registered directories.
|
data/docs/h.md
CHANGED
|
@@ -30,6 +30,7 @@ These subcommands are defined directly in `exe/h` or loaded from `lib/`:
|
|
|
30
30
|
| [`h service`](h-service.md) | Dev service management with Herdr, env files, and service groups | `lib/hiiro/service_manager.rb` |
|
|
31
31
|
| `h setup` | Install plugins and bin scripts to `~/bin` | `exe/h` |
|
|
32
32
|
| [`h task`](h-task.md) | Symlink to `t`: task records, todos, worktrees, and Herdr workspaces | `lib/hiiro/task_cli.rb` |
|
|
33
|
+
| [`h herdr`](h-herdr.md) | Herdr plugin exposing `t` as keybound popups: switch task, add/copy todos, task shell, nvim | `bin/h-herdr`, `herdr-plugin/` |
|
|
33
34
|
| `h version` | Print installed hiiro version (`-a` for all rbenv versions) | `exe/h` |
|
|
34
35
|
|
|
35
36
|
## External subcommands
|