add slash command shortcuts

This commit is contained in:
GangGreenTemperTatum
2026-03-29 08:48:56 -04:00
parent cfd2e7d5f3
commit 0f6e68af87
3 changed files with 224 additions and 2 deletions
+3
View File
@@ -325,6 +325,9 @@ uv run p4rs3lt0ngv3-cli encode --transform base64 --text "Hello World"
uv run p4rs3lt0ngv3-cli decode --transform base64 --text "SGVsbG8gV29ybGQ="
uv run p4rs3lt0ngv3-cli auto-decode --text "SGVsbG8="
uv run p4rs3lt0ngv3-cli agent "encode 'Attack at dawn' as caesar shift 5"
uv run p4rs3lt0ngv3-cli /base64 Hello
uv run p4rs3lt0ngv3-cli /base64 --decode SGVsbG8=
uv run p4rs3lt0ngv3-cli /caesar --shift 5 "Attack at dawn"
```
Notes:
+197 -2
View File
@@ -48,6 +48,109 @@ def emit(data: Any, as_json: bool) -> None:
print(json.dumps(data, indent=2, ensure_ascii=False))
def coerce_option_value(raw: str) -> Any:
lowered = raw.lower()
if lowered in {"true", "false"}:
return lowered == "true"
try:
return int(raw)
except ValueError:
try:
return float(raw)
except ValueError:
return raw
def parse_slash_command(argv: list[str]) -> tuple[str, dict[str, Any]] | None:
if not argv:
return None
first = argv[0]
if not first.startswith("/") or first == "/":
return None
name = first[1:]
if not name:
return None
if name == "inspect":
if len(argv) < 2:
raise ValueError("Usage: /inspect <transform> [--json]")
return ("inspect", {"transform": argv[1], "json": "--json" in argv[2:]})
if name == "list":
category = None
json_mode = False
tokens = argv[1:]
index = 0
while index < len(tokens):
token = tokens[index]
if token == "--json":
json_mode = True
elif token == "--category":
if index + 1 >= len(tokens):
raise ValueError("Missing value for --category")
category = tokens[index + 1]
index += 1
else:
raise ValueError(f"Unsupported option for /list: {token}")
index += 1
return ("list", {"category": category, "json": json_mode})
if name == "decode":
tokens = argv[1:]
json_mode = False
if "--json" in tokens:
json_mode = True
tokens = [token for token in tokens if token != "--json"]
return ("auto-decode", {"text": " ".join(tokens), "json": json_mode})
action = "encode"
json_mode = False
options: dict[str, Any] = {}
text_tokens: list[str] = []
tokens = argv[1:]
index = 0
while index < len(tokens):
token = tokens[index]
if token == "--decode":
action = "decode"
elif token == "--preview":
action = "preview"
elif token == "--json":
json_mode = True
elif token == "--option":
if index + 1 >= len(tokens):
raise ValueError("Missing value for --option")
options.update(parse_option_pairs([tokens[index + 1]]))
index += 1
elif token.startswith("--"):
flag = token[2:]
if "=" in flag:
key, value = flag.split("=", 1)
options[key] = coerce_option_value(value)
elif index + 1 < len(tokens) and not tokens[index + 1].startswith("--"):
options[flag] = coerce_option_value(tokens[index + 1])
index += 1
else:
options[flag] = True
else:
text_tokens.append(token)
index += 1
return (
"transform-shortcut",
{
"transform": name,
"action": action,
"text": " ".join(text_tokens),
"json": json_mode,
"options": options,
},
)
def build_parser() -> argparse.ArgumentParser:
parser = argparse.ArgumentParser(prog="p4rs3lt0ngv3-cli", description="Agent-based CLI for P4RS3LT0NGV3")
subparsers = parser.add_subparsers(dest="command", required=True)
@@ -80,8 +183,101 @@ def build_parser() -> argparse.ArgumentParser:
def main(argv: list[str] | None = None) -> int:
raw_argv = list(sys.argv[1:] if argv is None else argv)
try:
slash_command = parse_slash_command(raw_argv)
except ValueError as exc:
print(str(exc), file=sys.stderr)
return 1
if slash_command is not None:
command, payload = slash_command
try:
ensure_node_available()
if command == "list":
transforms = list_transforms()
if payload["category"]:
transforms = [transform for transform in transforms if transform.category == payload["category"]]
if payload["json"]:
emit(
[
{
"key": transform.key,
"name": transform.name,
"category": transform.category,
"can_decode": transform.can_decode,
}
for transform in transforms
],
True,
)
else:
for transform in transforms:
decode_flag = "decode" if transform.can_decode else "encode-only"
print(f"{transform.key:24} {transform.category:12} {decode_flag:11} {transform.name}")
return 0
if command == "inspect":
transform = find_transform(payload["transform"])
if not transform:
raise BridgeError(f"Unknown transform: {payload['transform']}")
meta = inspect_transform(transform.key)
data = {
"key": meta.key,
"name": meta.name,
"category": meta.category,
"priority": meta.priority,
"can_decode": meta.can_decode,
"input_kind": meta.input_kind,
"options": [
{
"id": option.id,
"label": option.label,
"type": option.type,
"default": option.default,
"min": option.min,
"max": option.max,
"step": option.step,
"options": option.options,
}
for option in meta.configurable_options
],
}
emit(data, payload["json"])
return 0
if command == "auto-decode":
result = auto_decode(payload["text"])
emit(result or {}, payload["json"])
return 0 if result else 1
if command == "transform-shortcut":
transform = find_transform(payload["transform"])
if not transform:
raise BridgeError(f"Unknown transform: {payload['transform']}")
text = payload["text"] or read_text_argument(None)
result = run_transform(payload["action"], transform.key, text, payload["options"])
if payload["json"]:
emit(
{
"action": result.action,
"transform": result.transform_key,
"transform_name": result.transform_name,
"options": result.options,
"output": result.output,
},
True,
)
else:
emit(result.output, False)
return 0
except (BridgeError, ValueError) as exc:
print(str(exc), file=sys.stderr)
return 1
parser = build_parser()
args = parser.parse_args(argv)
args = parser.parse_args(raw_argv)
try:
ensure_node_available()
@@ -180,4 +376,3 @@ def main(argv: list[str] | None = None) -> int:
if __name__ == "__main__":
raise SystemExit(main())
+24
View File
@@ -88,3 +88,27 @@ def test_agent_can_chain_steps() -> None:
payload = parse_json_output(process)
assert payload["final_output"] == "Hi"
assert len(payload["outputs"]) == 2
def test_slash_command_encodes_text() -> None:
process = run_cli("/base64", "Hello")
assert process.returncode == 0, process.stderr
assert process.stdout.strip() == "SGVsbG8="
def test_slash_command_decodes_text() -> None:
process = run_cli("/base64", "--decode", "SGVsbG8=")
assert process.returncode == 0, process.stderr
assert process.stdout.strip() == "Hello"
def test_slash_command_supports_transform_flags() -> None:
process = run_cli("/caesar", "--shift", "5", "Attack", "at", "dawn")
assert process.returncode == 0, process.stderr
assert process.stdout.strip() == "Fyyfhp fy ifbs"
def test_slash_command_supports_inspect() -> None:
process = run_cli("/inspect", "caesar", "--json")
payload = parse_json_output(process)
assert payload["key"] == "caesar"