hiiro 0.1.368 → 0.1.369
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 +7 -1
- data/README.md +2 -1
- data/docs/t.md +3 -3
- data/lib/hiiro/task_cli.rb +88 -15
- data/lib/hiiro/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3565b794ff2dd7e61d45810479a5bed58621c54ac4e3afa51f12adeb9626c639
|
|
4
|
+
data.tar.gz: 75073d800fee5ab0185eea6062b39961b7f68c4200a1f428f8ac72f090edabd5
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9435184f96a4b71ea43ecb873180411326aaf5ebb866153748be8f9e5fdbe7605d92c71df4506498029772f510374e91034ce74748663a9d1b4de8ff264d5c17
|
|
7
|
+
data.tar.gz: 8a8a5539086877c051ce05639fdb2c72a626c88d92284981c551fff2a3b6a8d6e048250d969b6fedb4e811c720da0a4c58a1e6aa97dddebeba1a478f1c26194e
|
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [0.1.369] - 2026-09-14
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
- `t switch NAME` matches live Herdr workspaces that belong to no task, and the fuzzy finder for `switch` lists tasks plus those workspaces, numbering duplicate workspace names
|
|
9
|
+
- `t` opens the fuzzy finder instead of failing when a task prefix is ambiguous or no current task can be resolved, when stdin is a terminal
|
|
10
|
+
|
|
5
11
|
## [0.1.368] - 2026-09-14
|
|
6
12
|
|
|
7
13
|
### Added
|
|
@@ -97,4 +103,4 @@
|
|
|
97
103
|
- Focus the exact Herdr pane through the socket API and read the CLI's plain-text pane output without JSON parsing.
|
|
98
104
|
- Restore the missing `Hiiro::Bins` helper so `require "hiiro"` boots and commands like `h jumplist record` dispatch correctly.
|
|
99
105
|
- Make Hiiro's Ruby requirement explicit as Ruby 3.2+ and have rbenv-wide gem installs skip incompatible Ruby versions.
|
|
100
|
-
- Update the publish script to preserve the Ruby support constant, run only on supported Ruby, and install releases only into compatible rbenv versions.
|
|
106
|
+
- Update the publish script to preserve the Ruby support constant, run only on supported Ruby, and install releases only into compatible rbenv versions.
|
data/README.md
CHANGED
|
@@ -73,7 +73,8 @@ Commands that act on a task take it from the first positional argument when
|
|
|
73
73
|
that word names a task (exact or unique case-sensitive prefix); otherwise the
|
|
74
74
|
current task is used and the word stays in the payload, exactly like the old
|
|
75
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.
|
|
76
|
+
`.` is the current task, and `-` selects orphan todos. On a terminal, an ambiguous
|
|
77
|
+
prefix or a missing current task opens the fuzzy finder; non-interactive runs fail.
|
|
77
78
|
|
|
78
79
|
The current task is the calling Herdr workspace, then the current directory
|
|
79
80
|
inside a task home, code directory, worktree, or registered directory, then the
|
data/docs/t.md
CHANGED
|
@@ -17,11 +17,11 @@ The command comes first. Commands that act on a task take it from the first posi
|
|
|
17
17
|
|
|
18
18
|
1. If the first positional word names a task, exactly or by a unique case-sensitive prefix, it is the task and is removed from the arguments.
|
|
19
19
|
2. Otherwise the current task is used and the word stays in the payload. So `t todo add fix build` adds to the current task and `t todo add prez fix build` adds to `prez`.
|
|
20
|
-
3. An ambiguous prefix
|
|
20
|
+
3. An ambiguous prefix opens the fuzzy finder over the matching tasks when stdin is a terminal, and is an error otherwise.
|
|
21
21
|
|
|
22
22
|
`-t TASK` / `--task TASK` forces a task and fails if it does not exist. `-f` / `--find` picks one with `sk` or `fzf`. `.` is the current task, useful when a payload could be mistaken for a name: `t next . Finish slides`. `-` selects orphan todos in todo commands only. Words starting with `-` are never treated as task names. Passthrough commands (`todo add`, `sh`, `pane run`, and the AI launchers) accept `-t`, `--task=NAME`, and `-f` only as their leading arguments.
|
|
23
23
|
|
|
24
|
-
The current task is resolved by `Hiiro::CurrentTask`: the calling Herdr workspace when `HERDR_*` variables identify one, then the working directory inside a task home, primary directory, worktree, or registered directory, then the task saved by `t use`. Ambiguous matches and stale or conflicting Herdr IDs are errors. Commands that only list, create, or show help never resolve the current task.
|
|
24
|
+
The current task is resolved by `Hiiro::CurrentTask`: the calling Herdr workspace when `HERDR_*` variables identify one, then the working directory inside a task home, primary directory, worktree, or registered directory, then the task saved by `t use`. With no context at all, a terminal gets the fuzzy finder over every task; non-interactive runs fail. Ambiguous directory or workspace matches and stale or conflicting Herdr IDs are always errors. Commands that only list, create, or show help never resolve the current task.
|
|
25
25
|
|
|
26
26
|
Task names may be `parent/child` for subtasks. `t new NAME` creates exactly `NAME`; nothing else creates tasks. Only `help`, `ls`, and `list` are reserved words; a task literally named `show` or `new` is reachable with `-t show`.
|
|
27
27
|
|
|
@@ -112,7 +112,7 @@ t pane run [TASK] ID|LABEL [--] COMMAND...
|
|
|
112
112
|
t pane split [TASK] ID|LABEL [--direction right|down] [--directory PATH] [--command COMMAND]
|
|
113
113
|
```
|
|
114
114
|
|
|
115
|
-
These require a running Herdr server. The workspace label is the task session or name with `.` replaced by `_`. `switch` focuses the existing workspace or creates it in the start directory (`--directory`, else primary directory, worktree, or home), and saves the task as the fallback when it was named explicitly. `--show` only prints the workspace, tabs, and panes. Tab and pane references match a live ID or label, then a unique prefix; with no reference and several candidates a fuzzy finder opens.
|
|
115
|
+
These require a running Herdr server. The workspace label is the task session or name with `.` replaced by `_`. `switch` also accepts the name of a live Herdr workspace that belongs to no task, exactly or by unique prefix, and focuses it; a task with the same name wins. When the name is ambiguous, or no task or context is given, a terminal gets a fuzzy finder over tasks and loose workspaces, with duplicate workspace names numbered in the label only. `switch` focuses the existing task workspace or creates it in the start directory (`--directory`, else primary directory, worktree, or home), and saves the task as the fallback when it was named explicitly. `--show` only prints the workspace, tabs, and panes. Tab and pane references match a live ID or label, then a unique prefix; with no reference and several candidates a fuzzy finder opens.
|
|
116
116
|
|
|
117
117
|
## Native AI sessions
|
|
118
118
|
|
data/lib/hiiro/task_cli.rb
CHANGED
|
@@ -40,24 +40,37 @@ class Hiiro
|
|
|
40
40
|
add_flag :find, short: :f, desc: 'Choose the task with a fuzzy finder'
|
|
41
41
|
end
|
|
42
42
|
|
|
43
|
-
def task_names
|
|
44
|
-
Hiiro::TaskRecord.all_as_list.map(&:name)
|
|
45
|
-
end
|
|
46
|
-
|
|
47
43
|
# Exact name, else unique prefix; ambiguous prefixes fail; nil when nothing matches.
|
|
44
|
+
# Exact name, else unique prefix. An ambiguous prefix opens the fuzzy finder
|
|
45
|
+
# over the candidates on a TTY and fails otherwise. nil when nothing matches.
|
|
48
46
|
def lookup_task(reference)
|
|
49
47
|
result = Hiiro::Matcher.new(Hiiro::TaskRecord.all_as_list, :name).by_prefix(reference.to_s)
|
|
50
48
|
match = result.resolved
|
|
51
|
-
|
|
52
|
-
|
|
49
|
+
return match.item if match
|
|
50
|
+
return nil unless result.ambiguous?
|
|
51
|
+
candidates = result.matches.map(&:item)
|
|
52
|
+
raise Error, "Ambiguous task #{reference}: #{candidates.map(&:name).join(', ')}" unless $stdin.tty?
|
|
53
|
+
pick_task(candidates)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def pick_task(candidates)
|
|
57
|
+
raise Error, 'No tasks; create one with t new NAME' if candidates.empty?
|
|
58
|
+
name = fuzzyfind(candidates.map(&:name))
|
|
59
|
+
raise Error, 'No task selected' if name.nil? || name.strip.empty?
|
|
60
|
+
candidates.find { |task| task.name == name.strip } || raise(Error, "No task named #{name.strip}")
|
|
53
61
|
end
|
|
54
62
|
|
|
55
63
|
def lookup_task!(reference)
|
|
56
64
|
lookup_task(reference) || raise(Error, "Task not found: #{reference}; run t new #{reference}")
|
|
57
65
|
end
|
|
58
66
|
|
|
67
|
+
# Current task from Herdr, directory, or the saved pin. With no context at all,
|
|
68
|
+
# a TTY gets the fuzzy finder over every task; ambiguous or stale context still fails.
|
|
59
69
|
def current_task
|
|
60
70
|
Hiiro::CurrentTask.new(herdr: -> { herdr_client }, pin: true).resolve!
|
|
71
|
+
rescue Hiiro::Error => e
|
|
72
|
+
raise unless $stdin.tty? && e.message.start_with?('No current task')
|
|
73
|
+
pick_task(Hiiro::TaskRecord.all_as_list)
|
|
61
74
|
end
|
|
62
75
|
|
|
63
76
|
# Old h task rule: [task, remaining_args]. The first positional is the task
|
|
@@ -80,11 +93,7 @@ class Hiiro
|
|
|
80
93
|
end
|
|
81
94
|
end
|
|
82
95
|
return [lookup_task!(forced), args] if forced
|
|
83
|
-
if find
|
|
84
|
-
name = fuzzyfind(task_names)
|
|
85
|
-
raise Error, 'No task selected' if name.nil? || name.strip.empty?
|
|
86
|
-
return [lookup_task!(name.strip), args]
|
|
87
|
-
end
|
|
96
|
+
return [pick_task(Hiiro::TaskRecord.all_as_list), args] if find
|
|
88
97
|
first = args.first
|
|
89
98
|
if first == '.'
|
|
90
99
|
args.shift
|
|
@@ -450,6 +459,65 @@ class Hiiro
|
|
|
450
459
|
puts workspace
|
|
451
460
|
end
|
|
452
461
|
|
|
462
|
+
# --- switch targets: tasks plus live Herdr workspaces that are not task workspaces ---
|
|
463
|
+
|
|
464
|
+
def loose_workspaces
|
|
465
|
+
return [] unless herdr_client.server_running?
|
|
466
|
+
labels = Hiiro::TaskRecord.all_as_list.map { |task| workspace_label(task) }
|
|
467
|
+
client.workspaces.reject { |workspace| labels.include?(workspace.name) }
|
|
468
|
+
end
|
|
469
|
+
|
|
470
|
+
# Fuzzy map over tasks and loose workspaces; duplicate workspace names are numbered
|
|
471
|
+
# in the label only, so the choice still maps to the exact workspace.
|
|
472
|
+
def pick_switch_target(tasks, workspaces)
|
|
473
|
+
raise Error, 'No tasks or workspaces to choose from' if tasks.empty? && workspaces.empty?
|
|
474
|
+
counts = workspaces.group_by(&:name).transform_values(&:length)
|
|
475
|
+
seen = Hash.new(0)
|
|
476
|
+
map = tasks.to_h { |task| [task.name, task] }
|
|
477
|
+
workspaces.each do |workspace|
|
|
478
|
+
seen[workspace.name] += 1
|
|
479
|
+
label = counts[workspace.name] > 1 ? "#{workspace.name} ##{seen[workspace.name]}" : workspace.name
|
|
480
|
+
map["#{label} (workspace)"] = workspace
|
|
481
|
+
end
|
|
482
|
+
fuzzyfind_from_map(map) || raise(Error, 'Nothing selected')
|
|
483
|
+
end
|
|
484
|
+
|
|
485
|
+
# [target, explicit]. A task wins over a workspace with the same name.
|
|
486
|
+
def switch_target(args)
|
|
487
|
+
args = args.dup
|
|
488
|
+
return [lookup_task!(opts.task), true] if opts.task
|
|
489
|
+
return [pick_switch_target(Hiiro::TaskRecord.all_as_list, loose_workspaces), true] if opts.find
|
|
490
|
+
first = args.first
|
|
491
|
+
if first && first != '.' && !first.start_with?('-')
|
|
492
|
+
args.shift
|
|
493
|
+
no_args!(args)
|
|
494
|
+
tasks = Hiiro::TaskRecord.all_as_list
|
|
495
|
+
workspaces = loose_workspaces
|
|
496
|
+
exact = tasks.find { |task| task.name == first }
|
|
497
|
+
return [exact, true] if exact
|
|
498
|
+
exact_ws = workspaces.select { |workspace| workspace.name == first }
|
|
499
|
+
return [exact_ws.first, false] if exact_ws.one?
|
|
500
|
+
task_matches = tasks.select { |task| task.name.start_with?(first) }
|
|
501
|
+
ws_matches = exact_ws.any? ? exact_ws : workspaces.select { |workspace| workspace.name.start_with?(first) }
|
|
502
|
+
return [task_matches.first, true] if task_matches.one? && ws_matches.empty?
|
|
503
|
+
return [ws_matches.first, false] if ws_matches.one? && task_matches.empty?
|
|
504
|
+
raise Error, "No task or workspace matches #{first}" if task_matches.empty? && ws_matches.empty?
|
|
505
|
+
names = (task_matches.map(&:name) + ws_matches.map { |w| "#{w.name} (workspace)" }).join(', ')
|
|
506
|
+
raise Error, "Ambiguous #{first}: #{names}" unless $stdin.tty?
|
|
507
|
+
target = pick_switch_target(task_matches, ws_matches)
|
|
508
|
+
return [target, target.is_a?(Hiiro::TaskRecord)]
|
|
509
|
+
end
|
|
510
|
+
args.shift if first == '.'
|
|
511
|
+
no_args!(args)
|
|
512
|
+
begin
|
|
513
|
+
[Hiiro::CurrentTask.new(herdr: -> { herdr_client }, pin: true).resolve!, false]
|
|
514
|
+
rescue Hiiro::Error => e
|
|
515
|
+
raise unless $stdin.tty? && e.message.start_with?('No current task')
|
|
516
|
+
target = pick_switch_target(Hiiro::TaskRecord.all_as_list, loose_workspaces)
|
|
517
|
+
[target, target.is_a?(Hiiro::TaskRecord)]
|
|
518
|
+
end
|
|
519
|
+
end
|
|
520
|
+
|
|
453
521
|
# --- Worktrees (shared with h task via Hiiro::TaskManager) ---
|
|
454
522
|
|
|
455
523
|
def tree_manager
|
|
@@ -668,10 +736,15 @@ class Hiiro
|
|
|
668
736
|
end
|
|
669
737
|
|
|
670
738
|
add_option :directory, desc: 'Existing start directory'
|
|
671
|
-
add_cmd(:switch, :workspace, args: ['task?'], opts: [*TASK_OPTIONS, :directory, :show]) do
|
|
672
|
-
explicit =
|
|
673
|
-
|
|
674
|
-
|
|
739
|
+
add_cmd(:switch, :workspace, args: ['task-or-workspace?'], opts: [*TASK_OPTIONS, :directory, :show]) do
|
|
740
|
+
target, explicit = switch_target(opts.args)
|
|
741
|
+
if target.is_a?(Hiiro::Herdr::Workspace)
|
|
742
|
+
raise Error, '--show applies to task workspaces' if opts.show
|
|
743
|
+
check_result(client.focus_workspace(target.id))
|
|
744
|
+
puts target
|
|
745
|
+
else
|
|
746
|
+
opts.show ? show_workspace(target) : open_workspace(target, save: explicit)
|
|
747
|
+
end
|
|
675
748
|
end
|
|
676
749
|
|
|
677
750
|
[%w[omp], %w[codex cdx], %w[claude cld]].each do |names|
|
data/lib/hiiro/version.rb
CHANGED