hiiro 0.1.376 → 0.1.377
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/.DS_Store +0 -0
- data/AGENTS.md +544 -0
- data/CHANGELOG.md +9 -1
- data/CLAUDE.md +1 -553
- data/README.md +21 -1
- data/bin/h-.config +9 -0
- data/bin/h-buffer +123 -0
- data/bin/h-ch +531 -0
- data/bin/h-cmd +71 -0
- data/bin/h-config +9 -0
- data/bin/h-context +373 -0
- data/bin/h-date +37 -0
- data/bin/h-demo +14 -0
- data/bin/h-docs +388 -0
- data/bin/h-docs.bkup +388 -0
- data/bin/h-dot +35 -0
- data/bin/h-dotenv +109 -0
- data/bin/h-dotfiles +42 -0
- data/bin/h-dsstore +7 -0
- data/bin/h-dsstore-read +7 -0
- data/bin/h-git +289 -0
- data/bin/h-home +62 -0
- data/bin/h-html +380 -0
- data/bin/h-js +56 -0
- data/bin/h-jsonl +776 -0
- data/bin/h-jumplist +287 -0
- data/bin/h-loop +475 -0
- data/bin/h-ls +69 -0
- data/bin/h-mcp +385 -0
- data/bin/h-mermaid +28 -0
- data/bin/h-mic +93 -0
- data/bin/h-note +200 -0
- data/bin/h-obsidian +904 -0
- data/bin/h-osubtask +32 -0
- data/bin/h-otask +869 -0
- data/bin/h-remind +614 -0
- data/bin/h-save +154 -0
- data/bin/h-sign +118 -0
- data/bin/h-strip +39 -0
- data/bin/h-t3 +21 -0
- data/bin/h-time +37 -0
- data/bin/h-uri +9 -0
- data/bin/h-video +533 -0
- data/bin/h-vim +63 -0
- data/bin/h-xxserve +6 -0
- data/bin/h-zosubtask +22 -0
- data/docs/README.md +1 -0
- data/docs/h-save.md +52 -0
- data/docs/h-task.md +4 -4
- data/docs/t.md +9 -6
- data/lib/hiiro/queue.rb +92 -9
- data/lib/hiiro/task_cli.rb +88 -41
- data/lib/hiiro/version.rb +1 -1
- metadata +41 -2
- data/AGENTS.md +0 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 6f85065ec7cb2c8b4fe08aba7d0692ef740963b272035324d57befbf471e9e23
|
|
4
|
+
data.tar.gz: 26745904bd4837c6b3fc2a4bf3372a2715c719af23c975b1dbcf7ad1445f430c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: bcee60b2999a7acddb1918f05184ba2f84055f59440bec14b323d7a328c685cbf076a66d8c8b9753c91c92720213169c7d14b705946cf934e7382966953e9462
|
|
7
|
+
data.tar.gz: 024bb62f15a76b36e01e102f76d2a505dd78f2db8079f19fce7d3c7e19bd3d892aac31ab45db24a5b1ecc36ef631982fa40a64b6ede114693bb7b5664f5ea8f4
|
data/.DS_Store
CHANGED
|
Binary file
|
data/AGENTS.md
ADDED
|
@@ -0,0 +1,544 @@
|
|
|
1
|
+
## Project Overview
|
|
2
|
+
|
|
3
|
+
Hiiro is a lightweight CLI framework for Ruby that enables building multi-command tools similar to `git` or `docker`. It provides subcommand dispatch, abbreviation matching (e.g., `h ex hel` matches `h example hello`), and a plugin system.
|
|
4
|
+
|
|
5
|
+
## Development Commands
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
# Edit the main h script
|
|
9
|
+
h edit
|
|
10
|
+
|
|
11
|
+
# List available subcommands
|
|
12
|
+
h
|
|
13
|
+
|
|
14
|
+
# Syntax check Ruby files
|
|
15
|
+
ruby -c bin/h
|
|
16
|
+
ruby -c plugins/*.rb
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
Tests are organized under `test/`:
|
|
21
|
+
- `test/hiiro/` - Core library tests (Matcher, Options, Shell, Fuzzyfind, Todo, etc.)
|
|
22
|
+
- `test/plugins/` - Plugin tests (Pins, Tasks, Notify, Project)
|
|
23
|
+
- `test/bin/` - Bin file tests using `Hiiro::TestHarness`
|
|
24
|
+
|
|
25
|
+
The `Hiiro::TestHarness` class (in `test/test_helper.rb`) enables testing bin files by capturing the block passed to `Hiiro.run` and evaluating it in a test context with stubbed `system` calls.
|
|
26
|
+
|
|
27
|
+
## Architecture
|
|
28
|
+
|
|
29
|
+
### Core Components (bin/h)
|
|
30
|
+
|
|
31
|
+
The `Hiiro` class is the main entry point with these nested classes:
|
|
32
|
+
|
|
33
|
+
- **`Runners`** - Discovers executables matching `h-*` in PATH and manages inline subcommands. Implements exact and prefix-based matching.
|
|
34
|
+
- **`Runners::Bin`** - Represents external executables found in PATH
|
|
35
|
+
- **`Runners::Subcommand`** - Represents inline subcommands registered via blocks
|
|
36
|
+
- **`Args`** - Parses single-dash flags (`-abc` becomes flags `a`, `b`, `c`)
|
|
37
|
+
- **`Config`** - Manages `~/.config/hiiro/` directory structure
|
|
38
|
+
|
|
39
|
+
### Subcommand Resolution Flow
|
|
40
|
+
|
|
41
|
+
1. `Hiiro.init()` parses first arg as subcommand name
|
|
42
|
+
2. `Runners` searches for exact match in subcommands and PATH executables
|
|
43
|
+
3. If no exact match, tries prefix matching (abbreviations)
|
|
44
|
+
4. Ambiguous matches show help with possible options
|
|
45
|
+
|
|
46
|
+
### Plugin System
|
|
47
|
+
|
|
48
|
+
Plugins are Ruby modules with a `self.load(hiiro)` method:
|
|
49
|
+
|
|
50
|
+
```ruby
|
|
51
|
+
module MyPlugin
|
|
52
|
+
def self.load(hiiro)
|
|
53
|
+
# Add methods to hiiro instance
|
|
54
|
+
hiiro.instance_eval do
|
|
55
|
+
def my_helper; end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# Register subcommands
|
|
59
|
+
hiiro.add_subcmd(:mycmd) { |*args| ... }
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Plugins auto-load from `~/.config/hiiro/plugins/`. Load order matters when plugins depend on each other (e.g., Task and Project depend on Tmux).
|
|
65
|
+
|
|
66
|
+
### Global Values Pattern
|
|
67
|
+
|
|
68
|
+
Values passed to `Hiiro.run()` are available in subcommand handlers:
|
|
69
|
+
|
|
70
|
+
```ruby
|
|
71
|
+
Hiiro.run(*ARGV, cwd: Dir.pwd) do
|
|
72
|
+
add_subcmd(:pwd) { |*args|
|
|
73
|
+
cwd = get_value(:cwd)
|
|
74
|
+
puts cwd
|
|
75
|
+
}
|
|
76
|
+
end
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Creating Subcommands
|
|
80
|
+
|
|
81
|
+
There are two ways to add subcommands to Hiiro:
|
|
82
|
+
|
|
83
|
+
### 1. External Bin File (Preferred)
|
|
84
|
+
|
|
85
|
+
Create a new executable `bin/h-<name>` that uses `Hiiro.run`:
|
|
86
|
+
|
|
87
|
+
```ruby
|
|
88
|
+
#!/usr/bin/env ruby
|
|
89
|
+
require 'hiiro'
|
|
90
|
+
|
|
91
|
+
Hiiro.run(*ARGV, plugins: [:Tasks]) {
|
|
92
|
+
add_subcmd(:list) {
|
|
93
|
+
puts "Listing items..."
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
add_subcmd(:add) { |name, path=nil|
|
|
97
|
+
puts "Adding #{name} at #{path}"
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
add_subcmd(:remove) { |name=nil|
|
|
101
|
+
if name.nil?
|
|
102
|
+
puts "Usage: h mycommand remove <name>"
|
|
103
|
+
next
|
|
104
|
+
end
|
|
105
|
+
puts "Removed #{name}"
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
This creates commands like `h mycommand list`, `h mycommand add foo /path`.
|
|
111
|
+
|
|
112
|
+
### 2. Nested Subcommands via build_hiiro
|
|
113
|
+
|
|
114
|
+
For complex command hierarchies with shared state, create a nested Hiiro instance:
|
|
115
|
+
|
|
116
|
+
```ruby
|
|
117
|
+
def self.add_subcommands(hiiro)
|
|
118
|
+
hiiro.add_subcmd(:task) do |*args|
|
|
119
|
+
tm = TaskManager.new(hiiro, scope: :task)
|
|
120
|
+
build_hiiro(hiiro, tm).run
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def self.build_hiiro(parent_hiiro, tm)
|
|
125
|
+
bin_name = [parent_hiiro.bin, parent_hiiro.subcmd || ''].join('-')
|
|
126
|
+
|
|
127
|
+
Hiiro.run(bin_name:, args: parent_hiiro.args) do
|
|
128
|
+
add_subcmd(:list) { tm.list }
|
|
129
|
+
add_subcmd(:start) { |name| tm.start_task(name) }
|
|
130
|
+
add_subcmd(:switch) { |name=nil|
|
|
131
|
+
name ||= tm.select_task_interactive
|
|
132
|
+
tm.switch_to_task(tm.task_by_name(name))
|
|
133
|
+
}
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
This pattern:
|
|
139
|
+
- Passes remaining args from parent to child via `args: parent_hiiro.args`
|
|
140
|
+
- Allows shared state (like `tm`) across all nested subcommands
|
|
141
|
+
- Creates commands like `h task list`, `h task start foo`
|
|
142
|
+
|
|
143
|
+
## Library Components (lib/)
|
|
144
|
+
|
|
145
|
+
The `lib/hiiro.rb` file and `lib/hiiro/` directory contain the core framework classes:
|
|
146
|
+
|
|
147
|
+
### Hiiro (lib/hiiro.rb)
|
|
148
|
+
|
|
149
|
+
Main entry point with class methods:
|
|
150
|
+
- `Hiiro.run(*ARGV, plugins: [...]) { ... }` - Initialize and run immediately
|
|
151
|
+
- `Hiiro.init(*ARGV, plugins: [...]) { ... }` - Initialize without running (returns hiiro instance). **NEVER USE THIS** without a good reason, always favor `Hiiro.run`
|
|
152
|
+
|
|
153
|
+
Instance methods available in subcommand blocks:
|
|
154
|
+
- `git` - Returns `Hiiro::Git` instance for git operations
|
|
155
|
+
- `fuzzyfind(lines)` - Interactive selection via skim
|
|
156
|
+
- `fuzzyfind_from_map(hash)` - Interactive selection returning mapped value
|
|
157
|
+
- `pins` - Key-value storage per command
|
|
158
|
+
- `todo_manager` - Todo item management
|
|
159
|
+
- `attach_method(name, &block)` - Add methods to hiiro instance dynamically
|
|
160
|
+
- `make_child(subcmd, *args)` - Create nested Hiiro for sub-subcommands (returns instance, must call `.run` manually)
|
|
161
|
+
- `run_child(subcmd, *args)` - Create a nested Hiiro instance AND immediately run it (preferred over `make_child(...).run`)
|
|
162
|
+
|
|
163
|
+
### Hiiro::Matcher (lib/hiiro/matcher.rb)
|
|
164
|
+
|
|
165
|
+
Handles pattern matching for commands and items with prefix and substring matching:
|
|
166
|
+
|
|
167
|
+
```ruby
|
|
168
|
+
matcher = Hiiro::Matcher.new(items, :name)
|
|
169
|
+
|
|
170
|
+
# Prefix matching - find items where name starts with pattern
|
|
171
|
+
result = matcher.by_prefix("pre")
|
|
172
|
+
result.match? # Any matches?
|
|
173
|
+
result.one? # Exactly one match?
|
|
174
|
+
result.ambiguous? # Multiple matches?
|
|
175
|
+
result.first&.item # Get first matching item
|
|
176
|
+
result.resolved&.item # Get exact or single match
|
|
177
|
+
|
|
178
|
+
# Substring matching - find items where name contains pattern anywhere
|
|
179
|
+
result = matcher.by_substring("abc")
|
|
180
|
+
result.matches.map(&:item) # All matching items
|
|
181
|
+
|
|
182
|
+
# Path-based matching for hierarchical names (e.g., "task/subtask")
|
|
183
|
+
result = matcher.resolve_path("t/s")
|
|
184
|
+
|
|
185
|
+
# Class methods for one-off matching
|
|
186
|
+
Hiiro::Matcher.by_prefix(items, "pre", key: :name)
|
|
187
|
+
Hiiro::Matcher.by_substring(items, "abc", key: :name)
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
Note: `Hiiro::PrefixMatcher` is aliased to `Hiiro::Matcher` for backward compatibility.
|
|
191
|
+
|
|
192
|
+
### Hiiro::Git (lib/hiiro/git.rb)
|
|
193
|
+
|
|
194
|
+
Git operations wrapper with submodules for branches, worktrees, remotes, and PRs:
|
|
195
|
+
|
|
196
|
+
```ruby
|
|
197
|
+
git = hiiro.git
|
|
198
|
+
git.root # Repository root path
|
|
199
|
+
git.branch # Current branch name
|
|
200
|
+
git.branches # List all branches
|
|
201
|
+
git.worktrees # List all worktrees
|
|
202
|
+
git.add_worktree(path, branch:) # Create worktree
|
|
203
|
+
git.move_worktree(from, to) # Rename worktree
|
|
204
|
+
git.current_pr # Get current PR info
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
### Hiiro::DB (lib/hiiro/db.rb)
|
|
208
|
+
|
|
209
|
+
SQLite persistence layer backed by Sequel. All data is stored in `~/.config/hiiro/hiiro.db`.
|
|
210
|
+
|
|
211
|
+
**Setup:** `Hiiro::DB.setup!` is called at startup — creates any missing tables, then runs a one-time YAML→SQLite migration if the DB is new.
|
|
212
|
+
|
|
213
|
+
**Model registration:** Each Sequel model calls `Hiiro::DB.register(self)` so `setup!` can create its table:
|
|
214
|
+
|
|
215
|
+
```ruby
|
|
216
|
+
class Hiiro::MyModel < Sequel::Model(:my_table)
|
|
217
|
+
Hiiro::DB.register(self)
|
|
218
|
+
|
|
219
|
+
def self.create_table!(db)
|
|
220
|
+
db.create_table?(:my_table) do
|
|
221
|
+
primary_key :id
|
|
222
|
+
String :name, null: false
|
|
223
|
+
end
|
|
224
|
+
end
|
|
225
|
+
end
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
**Dual-write:** During rollout, models write to both SQLite and YAML. Once migration is stable, call `Hiiro::DB.disable_dual_write!` to stop YAML writes.
|
|
229
|
+
|
|
230
|
+
**Test isolation:** Set `ENV['HIIRO_TEST_DB'] = 'sqlite::memory:'` before requiring `hiiro` to get a clean in-memory DB per test run. Call `Hiiro::DB.setup!` after require.
|
|
231
|
+
|
|
232
|
+
**`h db` subcommand:** Inspect and manage the database:
|
|
233
|
+
- `h db status` — show connection info and migration state
|
|
234
|
+
- `h db tables` — list all tables with row counts
|
|
235
|
+
- `h db q <sql>` — run raw SQL and print results
|
|
236
|
+
- `h db migrate` — re-run YAML import (if not yet migrated)
|
|
237
|
+
- `h db restore` — restore YAML files from SQLite data
|
|
238
|
+
|
|
239
|
+
### Hiiro::Fuzzyfind (lib/hiiro/fuzzyfind.rb)
|
|
240
|
+
|
|
241
|
+
Integration with `sk` (skim) or `fzf` fuzzy finders:
|
|
242
|
+
|
|
243
|
+
```ruby
|
|
244
|
+
selected = Hiiro::Fuzzyfind.select(["option1", "option2", "option3"])
|
|
245
|
+
# Returns selected string or nil if cancelled
|
|
246
|
+
|
|
247
|
+
value = Hiiro::Fuzzyfind.map_select({ "Display 1" => "value1", "Display 2" => "value2" })
|
|
248
|
+
# Shows keys, returns corresponding value
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
### Hiiro::TodoManager (lib/hiiro/todo.rb)
|
|
252
|
+
|
|
253
|
+
Todo item management with task association:
|
|
254
|
+
|
|
255
|
+
```ruby
|
|
256
|
+
tm = Hiiro::TodoManager.new
|
|
257
|
+
tm.add("Fix bug", tags: "urgent", task_info: { task_name: "feature" })
|
|
258
|
+
tm.start(0) # Mark item as started
|
|
259
|
+
tm.done(0) # Mark item as done
|
|
260
|
+
tm.active # Items not done/skipped
|
|
261
|
+
tm.filter_by_task("feature") # Items for specific task
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
### Invocation Tracking (lib/hiiro/invocation.rb)
|
|
265
|
+
|
|
266
|
+
Every CLI invocation is automatically recorded to SQLite via `Hiiro::Invocation` and `Hiiro::InvocationResolution`. This happens in `Hiiro.init` — no extra setup needed.
|
|
267
|
+
|
|
268
|
+
**Schema:**
|
|
269
|
+
- `Hiiro::Invocation` — records `bin_name`, `argv_json`, `cwd`, `invoked_at`
|
|
270
|
+
- `Hiiro::InvocationResolution` — linked to an invocation; records `resolved_name`, `resolution_type` (exact/prefix/abbreviated), `subcmd`
|
|
271
|
+
|
|
272
|
+
**Query recent invocations:**
|
|
273
|
+
```ruby
|
|
274
|
+
Hiiro::Invocation.order(Sequel.desc(:invoked_at)).limit(20).each do |inv|
|
|
275
|
+
puts "#{inv.invoked_at} #{inv.bin_name} #{JSON.parse(inv.argv_json).join(' ')}"
|
|
276
|
+
end
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
Or via `h db q`:
|
|
280
|
+
```bash
|
|
281
|
+
h db q "SELECT bin_name, argv_json, invoked_at FROM invocations ORDER BY invoked_at DESC LIMIT 10"
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
### Hiiro::Shell (lib/hiiro/shell.rb)
|
|
285
|
+
|
|
286
|
+
Utility for piping content to external commands:
|
|
287
|
+
|
|
288
|
+
```ruby
|
|
289
|
+
Hiiro::Shell.pipe("content", "pbcopy") # Pipe string to command
|
|
290
|
+
Hiiro::Shell.pipe_lines(["a", "b"], "command") # Join array with newlines and pipe
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
### Hiiro::Options (lib/hiiro/options.rb)
|
|
294
|
+
|
|
295
|
+
Argument parsing with flag and option support:
|
|
296
|
+
|
|
297
|
+
```ruby
|
|
298
|
+
opts = Hiiro::Options.parse(args) do
|
|
299
|
+
option(:output, short: :o, desc: "Output file")
|
|
300
|
+
option(:verbose, short: :v, type: :flag, desc: "Verbose output")
|
|
301
|
+
end
|
|
302
|
+
opts.output # Value of --output or -o
|
|
303
|
+
opts.verbose # true if --verbose or -v was passed
|
|
304
|
+
opts.args # Remaining non-option arguments
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
### Hiiro::Notification (lib/hiiro/notification.rb)
|
|
308
|
+
|
|
309
|
+
macOS notification wrapper using terminal-notifier:
|
|
310
|
+
|
|
311
|
+
```ruby
|
|
312
|
+
Hiiro::Notification.show(hiiro) # Show notification based on hiiro.args
|
|
313
|
+
# Supports: -m message, -t title, -l link, -c command, -s sound (macOS system sound name via terminal-notifier -sound; none for silent)
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
### Hiiro::Queue (lib/hiiro/queue.rb)
|
|
317
|
+
|
|
318
|
+
Task queue that pipes prompts to `claude` via tmux. Tasks are markdown files with optional YAML frontmatter (`task_name`, `tree_name`, `session_name`) that flow through statuses: `wip` -> `pending` -> `running` -> `done`/`failed`.
|
|
319
|
+
|
|
320
|
+
Subcommands (`h queue <subcmd>`):
|
|
321
|
+
- `ls`/`list` - List all tasks with status, elapsed time, and preview
|
|
322
|
+
- `status` - Detailed status with working directory info
|
|
323
|
+
- `add` - Create a new prompt (opens editor or accepts stdin/args, supports `-t <task>` flag)
|
|
324
|
+
- `wip` - Create/edit a work-in-progress prompt
|
|
325
|
+
- `ready` - Move wip task to pending
|
|
326
|
+
- `run [name]` - Launch pending task(s) in tmux windows
|
|
327
|
+
- `watch` - Continuously poll and launch pending tasks
|
|
328
|
+
- `attach [name]` - Switch to running task's tmux window (fuzzy select if no name)
|
|
329
|
+
- `kill [name]` - Kill running task's tmux window, move to failed
|
|
330
|
+
- `retry [name]` - Move failed/done task back to pending
|
|
331
|
+
- `clean` - Remove all done/failed task files
|
|
332
|
+
- `dir` - Print queue directory path
|
|
333
|
+
|
|
334
|
+
Config: `~/.config/hiiro/queue/{wip,pending,running,done,failed}/`
|
|
335
|
+
|
|
336
|
+
Key internals:
|
|
337
|
+
- `Queue::Prompt` - Parses frontmatter to resolve task/tree/session for working directory
|
|
338
|
+
- Tasks launch in tmux windows within the task's session (from frontmatter) or default `hq` session
|
|
339
|
+
- Launcher script runs `cat prompt | claude`, then moves files to done/failed based on exit code
|
|
340
|
+
|
|
341
|
+
### Hiiro::ServiceManager (lib/hiiro/service_manager.rb)
|
|
342
|
+
|
|
343
|
+
Manages background development services with tmux integration, env file management, and service groups.
|
|
344
|
+
|
|
345
|
+
Subcommands (`h service <subcmd>`):
|
|
346
|
+
- `ls`/`list` - List all services with running status, port, and base_dir
|
|
347
|
+
- `start <name> [--use VAR=variation ...]` - Start a service or group; prepares env file first
|
|
348
|
+
- `stop <name>` - Stop a running service (sends C-c to tmux pane or runs stop command)
|
|
349
|
+
- `attach <name>` - Switch to service's tmux pane
|
|
350
|
+
- `open <name>` - Open service URL in browser
|
|
351
|
+
- `url <name>` / `port <name>` - Print service URL or port
|
|
352
|
+
- `status <name>` - Show detailed service info (pid, pane, task, started_at)
|
|
353
|
+
- `add` - Add new service via editor template
|
|
354
|
+
- `rm`/`remove <name>` - Remove a service
|
|
355
|
+
- `config` - Edit services.yml
|
|
356
|
+
- `groups` - List all service groups and their members
|
|
357
|
+
- `env <name>` - Show env_vars, their variation options, and base_env/env_file config
|
|
358
|
+
|
|
359
|
+
Service config (`~/.config/hiiro/services.yml`):
|
|
360
|
+
```yaml
|
|
361
|
+
my-rails:
|
|
362
|
+
base_dir: apps/myapp
|
|
363
|
+
host: localhost
|
|
364
|
+
port: 3000
|
|
365
|
+
init: ["bundle install"]
|
|
366
|
+
start: bundle exec rails s -p 3000
|
|
367
|
+
stop: ""
|
|
368
|
+
cleanup: []
|
|
369
|
+
env_file: .env.development # destination in base_dir
|
|
370
|
+
base_env: my-rails.env # template in ~/.config/hiiro/env_templates/
|
|
371
|
+
env_vars:
|
|
372
|
+
GRAPHQL_URL:
|
|
373
|
+
variations:
|
|
374
|
+
local: http://localhost:4000/graphql
|
|
375
|
+
staging: https://graphql.staging.example.com/graphql
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
Service group config (same file, distinguished by `services:` key):
|
|
379
|
+
```yaml
|
|
380
|
+
my-stack:
|
|
381
|
+
services:
|
|
382
|
+
- name: my-rails
|
|
383
|
+
use:
|
|
384
|
+
GRAPHQL_URL: staging
|
|
385
|
+
- name: my-graphql
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
Key internals:
|
|
389
|
+
- `prepare_env(svc_name, variation_overrides:)` - Copies base_env template from `~/.config/hiiro/env_templates/` to `base_dir/env_file`, then injects variation values
|
|
390
|
+
- `find_group(name)` / `start_group(name, ...)` - Detect and start service groups, applying per-member `use:` overrides
|
|
391
|
+
- Default variation is `local` when not specified
|
|
392
|
+
- State tracked in `~/.config/hiiro/services/running.yml`
|
|
393
|
+
|
|
394
|
+
### Hiiro::RunnerTool (lib/hiiro/runner_tool.rb)
|
|
395
|
+
|
|
396
|
+
Run dev tools (linters, formatters, test suites) against changed files.
|
|
397
|
+
|
|
398
|
+
Subcommands (`h run [change_set] [tool_type] [file_group]`):
|
|
399
|
+
- Default (no subcmd) - Run matching tools with positional filters
|
|
400
|
+
- `ls` - List configured tools with type, group, extensions, and variations
|
|
401
|
+
- `add` - Add new tool via editor template
|
|
402
|
+
- `rm <name>` - Remove a tool
|
|
403
|
+
- `config` - Edit tools.yml
|
|
404
|
+
|
|
405
|
+
Arguments (positional, any order):
|
|
406
|
+
- **change_set**: `dirty` (default, git status), `branch` (diff from main), `all`
|
|
407
|
+
- **tool_type**: `lint`, `test`, `format`
|
|
408
|
+
- **file_type_group**: custom group identifier (e.g., `ruby`, `frontend`)
|
|
409
|
+
- `--variation`/`-v <name>` - Use a named tool variation
|
|
410
|
+
|
|
411
|
+
Config (`~/.config/hiiro/tools.yml`):
|
|
412
|
+
```yaml
|
|
413
|
+
rubocop:
|
|
414
|
+
tool_type: lint
|
|
415
|
+
command: "rubocop [FILENAMES]"
|
|
416
|
+
file_type_group: ruby
|
|
417
|
+
file_extensions: "rb"
|
|
418
|
+
variations:
|
|
419
|
+
quick: "rubocop --only Style [FILENAMES]"
|
|
420
|
+
fix: "rubocop -A [FILENAMES]"
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
`[FILENAMES]` is replaced with the space-joined list of matching files.
|
|
424
|
+
|
|
425
|
+
### Hiiro::AppFiles (lib/hiiro/app_files.rb)
|
|
426
|
+
|
|
427
|
+
Track frequently-used files per application, open them together in your editor.
|
|
428
|
+
|
|
429
|
+
Subcommands (`h file <subcmd>`):
|
|
430
|
+
- `ls [app_name]` - List tracked files (all apps or specific app)
|
|
431
|
+
- `add <app> <file1> [file2 ...]` - Add files to an app's file list
|
|
432
|
+
- `rm <app> <file1> [file2 ...]` - Remove files
|
|
433
|
+
- `edit <app>` - Open all tracked files in editor (vim uses `-O` for vertical splits)
|
|
434
|
+
|
|
435
|
+
Config: `~/.config/hiiro/app_files.yml`
|
|
436
|
+
|
|
437
|
+
Files are resolved relative to the current task's tree root when an environment is available.
|
|
438
|
+
|
|
439
|
+
### Jumplist (bin/h-jumplist)
|
|
440
|
+
|
|
441
|
+
Vim-style navigation history for tmux. Records pane/window/session changes and lets you jump backward/forward through your navigation history.
|
|
442
|
+
|
|
443
|
+
Subcommands (`h jumplist <subcmd>`):
|
|
444
|
+
- `setup` - Install tmux hooks and keybindings (`Ctrl-B` back, `Ctrl-F` forward)
|
|
445
|
+
- `record` - Record current position (called automatically by tmux hooks)
|
|
446
|
+
- `back` - Navigate to previous position
|
|
447
|
+
- `forward` - Navigate to next position
|
|
448
|
+
- `ls`/`list` - Show history with timestamps and current position marker
|
|
449
|
+
- `clear` - Clear history
|
|
450
|
+
- `path` - Print jumplist file path
|
|
451
|
+
|
|
452
|
+
Config: `~/.config/hiiro/jumplist/` (per-client entries and position files, max 50 entries)
|
|
453
|
+
|
|
454
|
+
Dead panes are automatically pruned. Duplicate consecutive entries are deduplicated. Forward history is truncated when navigating to a new location (like vim).
|
|
455
|
+
|
|
456
|
+
### Using `run_child`
|
|
457
|
+
|
|
458
|
+
`run_child` is the instance-level equivalent of `Hiiro.run` — it creates a child Hiiro instance scoped to a subcommand and immediately dispatches it. Use it instead of `make_child(...).run`:
|
|
459
|
+
|
|
460
|
+
```ruby
|
|
461
|
+
# Inside a subcommand handler or plugin:
|
|
462
|
+
hiiro.add_subcmd(:service) do |*args|
|
|
463
|
+
sm = ServiceManager.new
|
|
464
|
+
hiiro.run_child(:service) do |h|
|
|
465
|
+
h.add_subcmd(:list) { sm.list }
|
|
466
|
+
h.add_subcmd(:start) { |name| sm.start(name) }
|
|
467
|
+
end
|
|
468
|
+
end
|
|
469
|
+
```
|
|
470
|
+
|
|
471
|
+
This is equivalent to `hiiro.make_child(:service) { ... }.run`, but cleaner and mirrors the `Hiiro.run` / `Hiiro.init` relationship.
|
|
472
|
+
|
|
473
|
+
## Coding Rules and Conventions
|
|
474
|
+
|
|
475
|
+
### `Hiiro.run` vs `h = Hiiro.init` then `h.run`
|
|
476
|
+
|
|
477
|
+
If the code sets up new classes to be used within the Hiiro set of subcommands
|
|
478
|
+
or options/flags, inside the bin that calls them, then use the `init` version.
|
|
479
|
+
|
|
480
|
+
Structure it like this:
|
|
481
|
+
|
|
482
|
+
```ruby
|
|
483
|
+
h = Hiiro.init(*ARGV) do
|
|
484
|
+
# ...
|
|
485
|
+
end
|
|
486
|
+
|
|
487
|
+
# setup classes here
|
|
488
|
+
|
|
489
|
+
h.run
|
|
490
|
+
```
|
|
491
|
+
If the bin uses classes that are already defined, then use `Hiiro.run`
|
|
492
|
+
|
|
493
|
+
### Keep docs current
|
|
494
|
+
|
|
495
|
+
ALWAYS update `README.md` and any files in `docs/` or other markdown files that describe how to use hiiro, its bins, or how it works whenever you change behavior. Never let these go stale.
|
|
496
|
+
|
|
497
|
+
## Key Files
|
|
498
|
+
|
|
499
|
+
- `exe/h` - Entry point that loads lib/hiiro.rb
|
|
500
|
+
- `exe/t`, `exe/tt` - Task CLI launchers over `Hiiro::TaskCli` (`lib/hiiro/task_cli.rb`)
|
|
501
|
+
- `bin/h-*` - External subcommands (tmux wrappers, git helpers, jumplist, etc.)
|
|
502
|
+
- `lib/hiiro.rb` - Main Hiiro class and Runners
|
|
503
|
+
- `lib/hiiro/*.rb` - Supporting classes (Git, Matcher, Fuzzyfind, Todo, Shell, Options, Notification, Tmux, Queue, ServiceManager, RunnerTool, AppFiles)
|
|
504
|
+
|
|
505
|
+
### not used anymore
|
|
506
|
+
- `plugins/*.rb` - Reusable plugin modules (Pins, Project, Tasks, Notify)
|
|
507
|
+
|
|
508
|
+
## External Dependencies
|
|
509
|
+
|
|
510
|
+
- Ruby with `pry` gem
|
|
511
|
+
- `tmux` for session/window/pane management
|
|
512
|
+
- `sk` (skim) or `fzf` for fuzzy finding
|
|
513
|
+
- `gh` CLI for GitHub operations (h-pr)
|
|
514
|
+
- `terminal-notifier` for macOS notifications (notify plugin)
|
|
515
|
+
- `claude` CLI for queue task execution
|
|
516
|
+
|
|
517
|
+
## Configuration Locations
|
|
518
|
+
|
|
519
|
+
All config lives in `~/.config/hiiro/`:
|
|
520
|
+
- `plugins/` - Auto-loaded plugin files
|
|
521
|
+
- `pins/` - Per-command YAML key-value storage
|
|
522
|
+
- `tasks/` - Task metadata for worktree management
|
|
523
|
+
- `queue/` - Prompt queue (wip, pending, running, done, failed)
|
|
524
|
+
- `services/` - Service runtime state
|
|
525
|
+
- `jumplist/` - Per-client tmux navigation history
|
|
526
|
+
- `env_templates/` - Base .env template files for services
|
|
527
|
+
- `projects.yml` - Project directory aliases
|
|
528
|
+
- `apps.yml` - App directory mappings for task plugin
|
|
529
|
+
- `services.yml` - Service and service group definitions
|
|
530
|
+
- `tools.yml` - Runner tool definitions
|
|
531
|
+
- `app_files.yml` - Per-app tracked file lists
|
|
532
|
+
|
|
533
|
+
|
|
534
|
+
# Groups of files
|
|
535
|
+
|
|
536
|
+
## tmux-related files
|
|
537
|
+
|
|
538
|
+
- bin/h-buffer
|
|
539
|
+
- bin/h-pane
|
|
540
|
+
- bin/h-window
|
|
541
|
+
- bin/h-session
|
|
542
|
+
- lib/hiiro/tmux.rb
|
|
543
|
+
- lib/hiiro/tmux/*
|
|
544
|
+
|
data/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## [
|
|
3
|
+
## [0.1.377] - 2026-09-17
|
|
4
|
+
|
|
5
|
+
### Changed
|
|
6
|
+
- `h save` redesigned with slug-based filenames (`<timestamp>-<slug>.txt` / `<timestamp>-image.png`), image handling via `pngpaste`, and environment-configurable destination via `HIIRO_SAVED_DIR`
|
|
7
|
+
|
|
8
|
+
### Added
|
|
9
|
+
- `h save` subcommands: `ls`/`list`, `dir`, `show`/`cat`, `copy`, `open`, `edit`, `rm`/`remove` for managing saved files
|
|
10
|
+
- `t path`, `t cd`, `t start`, and `t switch` accept optional `APP` argument to select a configured relative directory beneath the task root
|
|
11
|
+
- APP resolves by exact name or unique case-sensitive prefix; fails when ambiguous or missing
|
|
4
12
|
|
|
5
13
|
## [0.1.376] - 2026-09-14
|
|
6
14
|
|