Repository navigation
Expand file tree
/
Copy pathbd-complete
More file actions
executable file
·91 lines (73 loc) · 2.82 KB
/
Copy pathbd-complete
File metadata and controls
executable file
·91 lines (73 loc) · 2.82 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
#!/usr/bin/env python3
"""Emit shell-completion candidates for beads-utils commands.
This is the single front door for every *dynamic* completion lookup: the zsh
and bash completion scripts call this and nothing else, so candidate logic is
never duplicated across shells. It is also the one place a TTL cache would
later wrap — adding caching here changes no call sites.
Each subcommand prints `value<TAB>description` lines to stdout. Lookups fail
silently (no output, exit 0) so a broken or slow command never garbles the
command line during completion.
bd-complete ids # bead ids (short form) + titles, from `bd list`
bd-complete sessions # Claude session uuids + titles
"""
from __future__ import annotations
import argparse
import json
import subprocess
import sys
from bdutils import add_version_arg
from claudeutils import list_sessions
def emit(value: str, description: str = "") -> None:
"""Print one `value<TAB>description` candidate line."""
sys.stdout.write(f"{value}\t{description}\n")
def complete_ids() -> None:
"""Full bead ids (e.g. `beads-utils-v9o.4`) + titles, from `bd list`.
Full ids rather than the short suffix: the shared project prefix makes a
wrong-project mistake visible (and lets a full id pasted on the line still
prefix-match).
"""
try:
proc = subprocess.run(
["bd", "list", "--status=all", "--limit", "0", "--json"],
capture_output=True, text=True, check=True,
)
except (OSError, subprocess.CalledProcessError):
return
try:
issues = json.loads(proc.stdout or "[]")
except json.JSONDecodeError:
return
if not isinstance(issues, list):
return
for issue in issues:
full = (isinstance(issue, dict) and issue.get("id")) or ""
if not full:
continue
emit(full, issue.get("title", "") or "")
def complete_sessions() -> None:
"""Claude session uuids + titles, newest first.
Calls into claudeutils.list_sessions() directly so the project-dir walk
lives in exactly one place rather than being duplicated here.
"""
try:
for meta in list_sessions():
emit(meta.jsonl.stem, meta.title)
except OSError:
return
def main() -> int:
parser = argparse.ArgumentParser(
description="Emit shell-completion candidates "
"(value<TAB>description) for beads-utils commands.",
)
sub = parser.add_subparsers(dest="kind", required=True)
sub.add_parser("ids", help="bead ids (short form) + titles")
sub.add_parser("sessions", help="Claude session uuids + titles")
add_version_arg(parser)
args = parser.parse_args()
if args.kind == "ids":
complete_ids()
elif args.kind == "sessions":
complete_sessions()
return 0
if __name__ == "__main__":
sys.exit(main())