diff --git a/bin/box-work.py b/bin/box-work.py index 6a696ec..d1aa728 100755 --- a/bin/box-work.py +++ b/bin/box-work.py @@ -783,8 +783,113 @@ def cmd_chats(args): print(f"[{c_cyan(ag)} : {c_dim(tname)}] {c_dim(ts)} {c_bold(author)}:\n{text}\n" + c_dim("-" * 60)) print() +WORK_COMMAND_EXAMPLES = { + "box work": [ + "box work # View fleet workspace dashboard & signals", + "box work check [agent] # Audit pre-flight health gates", + "box work heal # Automated remediation & chat nudge", + "box work start \"\" --to <agent> # Start & dispatch new build ticket", + "box work assign <issue#> --to <agent> # Assign existing ticket", + "box work merge <pr#> # Verify tests and merge PR to master", + "box work chats --agent <name> # View live multi-agent chat feed", + ], + "box work start": [ + "box work start \"Fix SSH perms\" --to 646", + "box work start \"Build integration tests\" --to pip --goal \"Run pytest on endpoints\"", + "box work start \"Emergency rebuild\" --to dev --force", + ], + "box work check": [ + "box work check # Check all agents", + "box work check 646 # Check specific agent", + ], + "box work heal": [ + "box work heal dev # Heal dev agent (token, perms, tunnel nudge)", + "box work heal 646", + ], + "box work assign": [ + "box work assign 218 --to 646", + ], + "box work merge": [ + "box work merge 217 # Test and merge PR 217 into master", + ], + "box work chats": [ + "box work chats # Last 10 chat messages across fleet", + "box work chats --agent opm --limit 5", + ], +} + +def format_work_error_shorthand(parser, message): + lines = [] + lines.append(f"\n{c_bold(c_red('❌ CLI ERROR:'))} {c_bold(message)}\n") + lines.append(c_bold(c_yellow("💡 SHORTHAND USAGE HELPER:"))) + lines.append(f" Command: {c_bold(parser.prog)}") + + sub_action = next((a for a in parser._actions if isinstance(a, argparse._SubParsersAction)), None) + if sub_action: + lines.append(f"\n{c_bold(' Available Subcommands:')}") + for name, subp in sub_action.choices.items(): + h = subp.description or getattr(subp, "help", "") or "" + if not h and getattr(sub_action, "_choices_actions", None): + for ca in sub_action._choices_actions: + if ca.dest == name: + h = ca.help or "" + break + lines.append(f" • {c_bold(f'{name:<12}')} {c_dim(h)}") + + positionals = [a for a in parser._actions if not a.option_strings and a.dest != 'help' and not isinstance(a, argparse._SubParsersAction)] + required_options = [a for a in parser._actions if a.option_strings and a.required and a.dest != 'help'] + optional_options = [a for a in parser._actions if a.option_strings and not a.required and a.dest != 'help'] + + if positionals or required_options: + lines.append(f"\n{c_bold(' Required Parameters / Arguments:')}") + for a in positionals: + lines.append(f" • {c_bold(f'{a.dest:<14}')} {a.help or '(positional)'}") + for a in required_options: + opts = "/".join(a.option_strings) + lines.append(f" • {c_bold(f'{opts:<14}')} {a.help or '(required flag)'}") + + if optional_options: + lines.append(f"\n{c_bold(' Optional Flags:')}") + for a in optional_options: + opts = "/".join(a.option_strings) + lines.append(f" • {c_cyan(f'{opts:<14}')} {c_dim(a.help or '')}") + + prog_key = parser.prog.strip() + examples = WORK_COMMAND_EXAMPLES.get(prog_key) or WORK_COMMAND_EXAMPLES.get("box work") + if examples: + lines.append(f"\n{c_bold(' Quick Examples:')}") + for ex in examples: + lines.append(f" {c_green(ex)}") + + lines.append(f"\n 📖 {c_dim('For complete manual:')} {c_bold(f'{parser.prog} --help')} {c_dim('(or')} {c_bold(f'box help {parser.prog.split()[-1]}')}{c_dim(')')}\n") + return "\n".join(lines) + +class WorkArgumentParser(argparse.ArgumentParser): + def error(self, message): + print(format_work_error_shorthand(self, message), file=sys.stderr) + sys.exit(2) + + def format_help(self): + base_help = super().format_help() + prog_key = self.prog.strip() + examples = WORK_COMMAND_EXAMPLES.get(prog_key) or WORK_COMMAND_EXAMPLES.get("box work") + extra = [] + if examples: + extra.append(c_bold("\nSHORTHAND EXAMPLES:")) + for ex in examples: + extra.append(f" {c_green(ex)}") + extra.append(c_bold("\nOPERATIONAL GUIDELINES:")) + extra.append(f" • {c_cyan('Shorthand parameter reference:')} run {c_bold('box')} alone") + extra.append(f" • {c_cyan('Comprehensive manual:')} run {c_bold('box help work')}") + extra.append(f" • {c_cyan('JSON output:')} append {c_bold('--json')} to any query command\n") + return base_help + "\n".join(extra) + def main(): - parser = argparse.ArgumentParser( + if len(sys.argv) > 1 and "help" in sys.argv[1:]: + idx = sys.argv.index("help") + sys.argv[idx] = "--help" + + parser = WorkArgumentParser( prog="box work", description="Fleet Workspace, Work Scope, and Task Orchestration Engine." ) diff --git a/bin/super-cli.py b/bin/super-cli.py index cdf3d47..bbb827b 100755 --- a/bin/super-cli.py +++ b/bin/super-cli.py @@ -6449,15 +6449,375 @@ def cmd_sysop_install(args): sys.exit(0) +# --------------------------------------------------------------------------- +# CLI Usage Helpers, Error Formatting, and Deep Manuals +# --------------------------------------------------------------------------- + +COMMAND_EXAMPLES = { + "box work": [ + "box work # View fleet workspace dashboard & signals", + "box work check [agent] # Audit pre-flight health gates", + "box work heal <agent> # Automated remediation & chat nudge", + "box work start \"<title>\" --to <agent> # Start & dispatch new build ticket", + "box work assign <issue#> --to <agent> # Assign existing ticket", + "box work merge <pr#> # Verify tests and merge PR to master", + "box work chats --agent <name> # View live multi-agent chat feed", + ], + "box work start": [ + "box work start \"Fix SSH perms\" --to 646", + "box work start \"Build integration tests\" --to pip --goal \"Run pytest on endpoints\"", + "box work start \"Emergency rebuild\" --to dev --force", + ], + "box work check": [ + "box work check # Check all agents", + "box work check 646 # Check specific agent", + ], + "box work heal": [ + "box work heal dev # Heal dev agent (token, perms, tunnel nudge)", + "box work heal 646", + ], + "box work assign": [ + "box work assign 218 --to 646", + ], + "box work merge": [ + "box work merge 217 # Test and merge PR 217 into master", + ], + "box work chats": [ + "box work chats # Last 10 chat messages across fleet", + "box work chats --agent opm --limit 5", + ], + "box tasks": [ + "box tasks list # List all tasks across queues", + "box tasks list --queue pending", + "box tasks show 218-restore-keys.md", + "box tasks create 219-my-task.md --title \"Task title\"", + ], + "box fleet": [ + "box fleet status # Node health & CDP table", + "box fleet watch # Stream status updates", + "box fleet restart muse", + "box fleet heal dev", + ], + "box approvals": [ + "box approvals check # Check pending browser approvals", + "box approvals allow 646 # Approve pending browser request", + "box approvals allow muse --always # Whitelist site permanently", + ], + "box dm": [ + "box dm log --limit 10 # View recent direct messages", + "box dm send dev \"Tunnel is down\"", + "box dm wo 646 \"Restore root authorized_keys\"", + ], + "box job": [ + "box job list # List scheduled & autonomous jobs", + "box job show <job_id>", + "box job run <job_id> # Trigger execution immediately", + ], + "box tmux": [ + "box tmux list # List tmux worker sessions", + "box tmux auto status # Status of tmux auto-approver", + ], +} + +PRIMARY_DOMAINS = [ + ("work", "Fleet workspace, task orchestration, worker scope, signals"), + ("tasks", "Agent task file queue (pending/claimed/done)"), + ("fleet", "Node health, CDP status, active tabs, watch, restart, heal"), + ("approvals", "Inspect and handle agent browser & gateway approvals"), + ("dm", "Direct messaging pipeline between operators and agents"), + ("job", "Scheduled & autonomous job management"), + ("tmux", "Tmux runtime & worker session manager"), + ("sysop", "Fleet operations installer (systemd units & timers)"), + ("help", "Comprehensive manual and documentation for any command"), +] + +def format_error_shorthand(parser, message): + lines = [] + lines.append(f"\n{c_bold(c_red('❌ CLI ERROR:'))} {c_bold(message)}\n") + lines.append(c_bold(c_yellow("💡 SHORTHAND USAGE HELPER:"))) + lines.append(f" Command: {c_bold(parser.prog)}") + + sub_action = next((a for a in parser._actions if isinstance(a, argparse._SubParsersAction)), None) + if sub_action: + if parser.prog in ("box", "super"): + lines.append(f"\n{c_bold(' Primary Domains & Commands:')}") + for d, desc in PRIMARY_DOMAINS: + lines.append(f" • {c_bold(f'{d:<12}')} {c_dim(desc)}") + else: + lines.append(f"\n{c_bold(' Available Subcommands:')}") + for name, subp in sub_action.choices.items(): + h = subp.description or getattr(subp, "help", "") or "" + if not h and getattr(sub_action, "_choices_actions", None): + for ca in sub_action._choices_actions: + if ca.dest == name: + h = ca.help or "" + break + lines.append(f" • {c_bold(f'{name:<12}')} {c_dim(h)}") + + positionals = [a for a in parser._actions if not a.option_strings and a.dest != 'help' and not isinstance(a, argparse._SubParsersAction)] + required_options = [a for a in parser._actions if a.option_strings and a.required and a.dest != 'help'] + optional_options = [a for a in parser._actions if a.option_strings and not a.required and a.dest != 'help'] + + if positionals or required_options: + lines.append(f"\n{c_bold(' Required Parameters / Arguments:')}") + for a in positionals: + lines.append(f" • {c_bold(f'{a.dest:<14}')} {a.help or '(positional)'}") + for a in required_options: + opts = "/".join(a.option_strings) + lines.append(f" • {c_bold(f'{opts:<14}')} {a.help or '(required flag)'}") + + if optional_options: + lines.append(f"\n{c_bold(' Optional Flags:')}") + for a in optional_options: + opts = "/".join(a.option_strings) + lines.append(f" • {c_cyan(f'{opts:<14}')} {c_dim(a.help or '')}") + + prog_key = parser.prog.strip() + if prog_key.startswith("super "): + prog_key = "box " + prog_key[6:] + examples = COMMAND_EXAMPLES.get(prog_key) + if not examples: + parts = prog_key.split() + if len(parts) > 2: + parent_key = " ".join(parts[:2]) + examples = COMMAND_EXAMPLES.get(parent_key) + + if examples: + lines.append(f"\n{c_bold(' Quick Examples:')}") + for ex in examples: + lines.append(f" {c_green(ex)}") + + lines.append(f"\n 📖 {c_dim('For complete manual:')} {c_bold(f'{parser.prog} --help')} {c_dim('(or')} {c_bold(f'box help {parser.prog.split()[-1]}')}{c_dim(')')}\n") + return "\n".join(lines) + +class BoxArgumentParser(argparse.ArgumentParser): + def error(self, message): + print(format_error_shorthand(self, message), file=sys.stderr) + sys.exit(2) + + def format_help(self): + base_help = super().format_help() + prog_key = self.prog.strip() + if prog_key.startswith("super "): + prog_key = "box " + prog_key[6:] + examples = COMMAND_EXAMPLES.get(prog_key) + if not examples: + parts = prog_key.split() + if len(parts) > 2: + parent_key = " ".join(parts[:2]) + examples = COMMAND_EXAMPLES.get(parent_key) + + extra = [] + if examples: + extra.append(c_bold("\nSHORTHAND EXAMPLES:")) + for ex in examples: + extra.append(f" {c_green(ex)}") + + extra.append(c_bold("\nOPERATIONAL GUIDELINES:")) + extra.append(f" • {c_cyan('Shorthand parameter reference:')} run {c_bold('box')} alone") + extra.append(f" • {c_cyan('Master comprehensive manual:')} run {c_bold('box help')} or {c_bold('box help <domain>')}") + extra.append(f" • {c_cyan('JSON output:')} append {c_bold('--json')} to any query command\n") + + return base_help + "\n".join(extra) + +def print_box_usage_reference(): + """Prints categorized primary domains and input parameters when box is run alone.""" + print(c_bold("\n=== BOX ORCHESTRATOR: INPUT PARAMETERS & USAGE REFERENCE ===\n")) + print(f"Usage: {c_bold('box <domain> [action] [arguments...] [options...]')}") + print(f" {c_bold('box help [domain]')} | {c_bold('box <domain> --help')}\n") + print(c_bold("PRIMARY DOMAINS & INPUT PARAMETERS:")) + + domains_spec = [ + ("work", "Fleet workspace, task orchestration, worker scope, and active signals", [ + ("box work [status]", "Show full operational work dashboard & worker signals"), + ("box work check [agent]", "Pre-flight health gates (Hatch, Restore, Git Config)"), + ("box work heal <agent>", "Automated remediation (tokens, collaborator, dial-in, chat)"), + ("box work start \"<title>\" --to <agent> [--goal \"<goal>\"] [--force]", "Instantly start & assign new ticket to agent"), + ("box work assign <issue#> --to <agent> [--force]", "Assign existing Gitea ticket to an agent"), + ("box work merge <pr#>", "Verify test suite and merge PR to master"), + ("box work chats [--agent <name>] [--limit <n>]", "Inspect live agent chat feeds with stream filtering"), + ]), + ("tasks", "Agent task file queue (fleet/tasks/{pending,claimed,done})", [ + ("box tasks list [--queue pending|claimed|done|all]", "List task queue files across queues"), + ("box tasks show <task-name>", "Print contents of a task file"), + ("box tasks create <name> --title \"<title>\"", "Write new pending task from template"), + ]), + ("fleet", "Node health, CDP status, active tabs, watch, restart, heal", [ + ("box fleet [status]", "Show NetVM node status table (muse, pip, 646, opm, dev, def)"), + ("box fleet watch [--interval <sec>]", "Live streaming status monitor"), + ("box fleet restart <node>", "Restart node browser & services"), + ("box fleet cdp <node>", "Print DevTools Protocol endpoint URL"), + ("box fleet heal <node>", "Run node remediation"), + ]), + ("approvals", "Inspect and handle agent browser & gateway approvals", [ + ("box approvals check [--node <name>] [-v]", "List pending modal browser approval prompts"), + ("box approvals allow <node> [--always]", "Approve pending browser prompt"), + ("box approvals inspect <node>", "Inspect active DOM modal elements"), + ]), + ("dm", "Direct messaging pipeline between operators and agents", [ + ("box dm log [--node <name>] [--limit <n>]", "Read signed message log"), + ("box dm send <target> \"<message>\"", "Send message to node/agent"), + ("box dm wo <agent> \"<instruction>\"", "Send formal work order to agent"), + ("box dm ack <msg_id>", "Acknowledge received work order"), + ]), + ("job", "Scheduled & autonomous job management", [ + ("box job list [--all]", "List configured jobs and timers"), + ("box job show <job_id>", "Display job configuration"), + ("box job run <job_id>", "Trigger immediate execution"), + ("box job status <job_id>", "Check execution status"), + ]), + ("tmux", "Tmux runtime & worker session manager", [ + ("box tmux [list]", "List active sessions on socket"), + ("box tmux auto [status|watch]", "Monitor automated approval daemon"), + ]), + ("sysop", "Fleet operations installer", [ + ("box sysop install [--dry-run]", "Install & verify systemd units and timers"), + ]), + ("help", "Comprehensive manual and documentation for any command", [ + ("box help [domain]", "Deep documentation & manual"), + ]), + ] + + for name, desc, cmds in domains_spec: + print(f" {c_bold(c_cyan(f'{name:<11}'))} {c_dim(desc)}") + for cmd_syntax, cmd_desc in cmds: + print(f" • {c_bold(cmd_syntax):<64} {c_dim(cmd_desc)}") + print() + + print(c_bold("QUICK DISPATCH SHORTCUTS:")) + print(f" Start Task: {c_green('box work start \"<title>\" --to <agent>')}") + print(f" Merge PR: {c_green('box work merge <pr#>')}") + print(f" Heal Agent: {c_green('box work heal <agent>')}") + print(f" Check Health: {c_green('box work check [agent]')}") + print(f"\n{c_dim('Run')} {c_bold('box <domain> --help')} {c_dim('or')} {c_bold('box help <domain>')} {c_dim('for full manuals and argument details.')}\n") + +def print_master_help(): + """Prints comprehensive, deep master manual for box help / box --help.""" + banner = """ +================================================================================ + BOX ORCHESTRATOR COMPREHENSIVE CLI & RUNTIME MANUAL +================================================================================ +""" + print(c_bold(banner)) + print(f"""{c_bold("SYNOPSIS:")} + box <domain> [action] [arguments...] [options...] + box help [domain] + box <domain> --help | box <domain> <action> --help + +{c_bold("OVERVIEW:")} + The 'box' CLI is the unified orchestration tool for NetVM nodes, cloud muse + agents (opm, 646, dev, pip, def, muse, muse-main), Gitea CI/CD build tasks, + approval workflows, DM message routing, scheduled jobs, and persistent tmux runtimes. + +{c_bold("CORE ARCHITECTURE & WORKER ROLES:")} + • {c_bold("opm")} (port 2228) : Fleet orchestrator & lead coordinator + • {c_bold("646")} (port 2226) : System & core runtime operator + • {c_bold("dev")} (port 2230) : Feature development & dark-node builder + • {c_bold("pip")} (port 2227) : Integration & Python builder + • {c_bold("def")} (port 2229) : Defense & telemetry monitor + • {c_bold("muse")} (port 2225) : Cloud workspace agent + • {c_bold("muse-main")} (port 2224) : GCP host node & tunnel anchor + +{c_bold("DOMAINS & ACTION SPECIFICATIONS:")} + +1. {c_bold("WORK & BUILD PIPELINE (box work ...)")} + Orchestrates autonomous cloud agents, Gitea issue-to-branch pipelines, PR merges, + and pre-flight node health verification. + • {c_bold("box work [status]")} + Parameters: None (optional --json) + Description: Full operational dashboard (worker scope, signals, tickets, PRs, chats). + • {c_bold("box work check [agent]")} + Parameters: agent (optional positional: opm, 646, dev, pip, def, muse) + Description: Pre-flight health gates (Hatch reverse tunnels, Restore persistence, Git credentials). + • {c_bold("box work heal <agent>")} + Parameters: agent (required positional) + Description: Automated self-healing engine (Gitea collaborator rights, partition tokens, + SSH container credential injection, chat recovery nudge). + • {c_bold("box work start \"<title>\" --to <agent> [--goal \"<goal>\"] [--force]")} + Parameters: + title (required positional): Short ticket title + --to (required flag): Target worker agent + --goal (optional flag): Detailed instructions / task goal + --force (optional flag): Bypass failed pre-flight health gate + Description: Runs pre-flight health gate, auto-heals if blocked, creates Gitea Issue #N, + and dispatches briefing directly into agent live chat. + • {c_bold("box work assign <issue#> --to <agent> [--force]")} + Parameters: + issue# (required positional integer): Existing Gitea issue number + --to (required flag): Target agent + Description: Reassigns issue, verifies pre-flight health, notifies agent. + • {c_bold("box work merge <pr#>")} + Parameters: pr# (required positional integer): Pull Request number + Description: Runs test suite verification, merges PR into master, and triggers + post-receive loop terminus hook. + • {c_bold("box work chats [--agent <name>] [--limit <n>]")} + Parameters: + --agent (optional flag): Filter events for specific agent + --limit (optional flag, default 10): Number of events to show + Description: Multi-agent live chat log viewer with agent-scoped stream filtering. + +2. {c_bold("TASK FILE QUEUE (box tasks ...)")} + File-backed agent task queues in fleet/tasks/{{pending,claimed,done}}. + • {c_bold("box tasks list [--queue pending|claimed|done|all] [--dir <path>]")} + • {c_bold("box tasks show <name>")} + • {c_bold("box tasks create <name> --title \"<title>\"")} + +3. {c_bold("FLEET & NODE MANAGEMENT (box fleet ...)")} + Controls Chromium NetVM nodes, D-Bus network namespaces, and CDP endpoints. + • {c_bold("box fleet [status]")} Show active nodes, latencies, threads + • {c_bold("box fleet watch [--interval <sec>]")} Real-time continuous monitoring + • {c_bold("box fleet restart <node>")} Restart node browser/profile + • {c_bold("box fleet cdp <node>")} Show DevTools protocol endpoint + • {c_bold("box fleet heal <node>")} Remediate crashed or stuck node + +4. {c_bold("BROWSER APPROVALS & GATEWAYS (box approvals ...)")} + Inspects and resolves browser modal prompts, ethical-captcha gates, and domain permissions. + • {c_bold("box approvals check [--node <name>] [-v]")} List pending approvals + • {c_bold("box approvals allow <node> [--always]")} Approve pending request + • {c_bold("box approvals inspect <node>")} Inspect active DOM modal elements + +5. {c_bold("DIRECT MESSAGING & WORK ORDERS (box dm ...)")} + Encrypted and signed inter-agent communication pipeline. + • {c_bold("box dm log [--node <name>] [--limit <n>]")} Read signed message log + • {c_bold("box dm send <target> \"<message>\"")} Send message to peer node + • {c_bold("box dm wo <agent> \"<instruction>\"")} Issue formal agent work order + • {c_bold("box dm ack <msg_id>")} Acknowledge received work order + +6. {c_bold("SCHEDULED JOBS (box job ...)")} + Background automation and recurrent job scheduling. + • {c_bold("box job list [--all]")} List all jobs and timers + • {c_bold("box job show <job_id>")} Inspect job JSON configuration + • {c_bold("box job run <job_id>")} Trigger one-shot immediate run + +7. {c_bold("TMUX PERSISTENCE RUNTIME (box tmux ...)")} + Headless terminal session management and auto-approval agents. + • {c_bold("box tmux [list]")} List active sessions on socket + • {c_bold("box tmux auto [status|watch]")} Monitor automated approval daemon + +{c_bold("ENVIRONMENT & CONFIGURATION:")} + NETVM_ROOT Path to NetVM workspace root (default: /home/super/Projects/NetVM) + CLICOLOR_FORCE Set to 1 to force ANSI color output in non-tty pipes + NO_COLOR Set to disable ANSI color formatting + GITEA_URL Base URL for Gitea API (auto-detected: loopback on bl, public domain on PC) + GITEA_TOKEN API token for Gitea automation + +{c_bold("EXIT CODES:")} + 0 Success + 1 Operational or pre-flight failure + 2 CLI syntax or missing argument error + +Run 'box <domain> --help' or 'box help <domain>' for in-depth flags on any command. +""") + def build_parser(): - common = argparse.ArgumentParser(add_help=False) + common = BoxArgumentParser(add_help=False) common.add_argument("--json", action="store_true", help="Output machine-readable JSON") - prog_name = Path(sys.argv[0]).name if sys.argv and sys.argv[0] else "super" + prog_name = Path(sys.argv[0]).name if sys.argv and sys.argv[0] else "box" if prog_name.endswith(".py"): - prog_name = "super" + prog_name = "box" - parser = argparse.ArgumentParser( + parser = BoxArgumentParser( prog=prog_name, description=f"{prog_name} — Unified Orchestrator CLI for NetVM & Box", formatter_class=argparse.RawDescriptionHelpFormatter, @@ -7389,12 +7749,30 @@ def main(): res = subprocess.run(cmd) sys.exit(res.returncode) - parser = build_parser() + # Handle empty arguments (box alone) if len(sys.argv) == 1: - # Default behavior with no arguments: show fleet status - sys.argv.append("fleet") - sys.argv.append("status") + print_box_usage_reference() + cmd_fleet_status(argparse.Namespace(json=False)) + sys.exit(0) + # Handle help variations + if len(sys.argv) > 1: + if sys.argv[1] == "help": + if len(sys.argv) == 2: + print_master_help() + sys.exit(0) + else: + target_domain = sys.argv[2] + rest = sys.argv[3:] + sys.argv = [sys.argv[0], target_domain] + rest + ["--help"] + elif sys.argv[1] in ("--help", "-h") and len(sys.argv) == 2: + print_master_help() + sys.exit(0) + elif "help" in sys.argv[2:]: + h_idx = sys.argv.index("help") + sys.argv[h_idx] = "--help" + + parser = build_parser() args = parser.parse_args() # Route commands diff --git a/tests/test_box_work.py b/tests/test_box_work.py index c39b688..2db8ad2 100644 --- a/tests/test_box_work.py +++ b/tests/test_box_work.py @@ -58,5 +58,63 @@ class TestBoxWork(unittest.TestCase): self.assertFalse(res["ready"]) self.assertEqual(res["overall"], "FAIL") + def test_cli_alone_prints_usage_reference(self): + import subprocess + proc = subprocess.run([sys.executable, str(REPO_ROOT / "bin" / "super-cli.py")], capture_output=True, text=True) + self.assertEqual(proc.returncode, 0) + self.assertIn("BOX ORCHESTRATOR: INPUT PARAMETERS & USAGE REFERENCE", proc.stdout) + self.assertIn("PRIMARY DOMAINS & INPUT PARAMETERS:", proc.stdout) + self.assertIn("box work", proc.stdout) + self.assertIn("box tasks", proc.stdout) + self.assertIn("box fleet", proc.stdout) + + def test_cli_help_prints_master_manual(self): + import subprocess + proc = subprocess.run([sys.executable, str(REPO_ROOT / "bin" / "super-cli.py"), "help"], capture_output=True, text=True) + self.assertEqual(proc.returncode, 0) + self.assertIn("BOX ORCHESTRATOR COMPREHENSIVE CLI & RUNTIME MANUAL", proc.stdout) + self.assertIn("DOMAINS & ACTION SPECIFICATIONS:", proc.stdout) + + def test_cli_domain_help_prints_subcommands_and_examples(self): + import subprocess + proc = subprocess.run([sys.executable, str(REPO_ROOT / "bin" / "super-cli.py"), "work", "help"], capture_output=True, text=True) + self.assertEqual(proc.returncode, 0) + self.assertIn("SHORTHAND EXAMPLES:", proc.stdout) + self.assertIn("OPERATIONAL GUIDELINES:", proc.stdout) + self.assertIn("box work start", proc.stdout) + + def test_cli_missing_args_prints_error_and_shorthand_helper(self): + import subprocess + proc = subprocess.run([sys.executable, str(REPO_ROOT / "bin" / "super-cli.py"), "work", "start"], capture_output=True, text=True) + self.assertEqual(proc.returncode, 2) + err = proc.stderr + self.assertIn("CLI ERROR:", err) + self.assertIn("SHORTHAND USAGE HELPER:", err) + self.assertIn("title", err) + self.assertIn("--to", err) + self.assertIn("Quick Examples:", err) + + def test_cli_invalid_subcommand_prints_shorthand_helper(self): + import subprocess + proc = subprocess.run([sys.executable, str(REPO_ROOT / "bin" / "super-cli.py"), "work", "invalid_action_xyz"], capture_output=True, text=True) + self.assertEqual(proc.returncode, 2) + err = proc.stderr + self.assertIn("CLI ERROR:", err) + self.assertIn("SHORTHAND USAGE HELPER:", err) + self.assertIn("Available Subcommands:", err) + self.assertIn("status", err) + self.assertIn("start", err) + + def test_cli_invalid_domain_prints_shorthand_helper(self): + import subprocess + proc = subprocess.run([sys.executable, str(REPO_ROOT / "bin" / "super-cli.py"), "invalid_domain_xyz"], capture_output=True, text=True) + self.assertEqual(proc.returncode, 2) + err = proc.stderr + self.assertIn("CLI ERROR:", err) + self.assertIn("SHORTHAND USAGE HELPER:", err) + self.assertIn("Primary Domains & Commands:", err) + self.assertIn("work", err) + self.assertIn("fleet", err) + if __name__ == "__main__": unittest.main()