diff --git a/bin/dev-dm.py b/bin/dev-dm.py new file mode 100755 index 0000000..caacce9 --- /dev/null +++ b/bin/dev-dm.py @@ -0,0 +1,71 @@ +#!/usr/bin/env python3 +""" +dev-dm.py: Developer Direct Messages + +For operator-to-developer communication (muse, pip task agents). +Developers are browser-only, no SSH. Uses headless via dm.py backend. + +Distinct from opp-dm.py (for operators: 646, operator-main). + +Usage: + dev-dm.py send --agent muse --target main "message" + dev-dm.py read --agent muse --target main +""" +import argparse +import subprocess +import sys + +DM_PY = "/home/super/Projects/NetVM/bin/dm.py" + +def run(cmd, timeout=90): + result = subprocess.run(cmd, shell=True, capture_output=True, text=True, timeout=timeout) + return result.stdout.strip() + +def dev_send(agent, target, message): + """Send a dev DM via headless (dm.py backend).""" + if agent not in ["muse", "pip"]: + print(f"ERROR: dev-dm only for muse, pip (not {agent})", file=sys.stderr) + sys.exit(1) + # Delegate to dm.py + safe = message.replace('"', '\\"')[:1000] + cmd = f"{DM_PY} send --agent {agent} --target {target} \"{safe}\"" + # Run on bl + bl_cmd = f"ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o BatchMode=yes super@100.123.153.75 '{cmd}'" + vm_cmd = f"ssh -i ~/.ssh/vm_to_gcp -o ProxyCommand=\"$HOME/workspace/bin/ssh-via-proxy %h %p\" -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o BatchMode=yes super@34.139.37.135 \"{bl_cmd}\"" + result = run(vm_cmd) + print(f"DEV-DM sent to {agent}/{target}") + return result + +def dev_read(agent, target, n=5): + """Read dev DMs via headless.""" + if agent not in ["muse", "pip"]: + print(f"ERROR: dev-dm only for muse, pip", file=sys.stderr) + sys.exit(1) + cmd = f"{DM_PY} read --agent {agent} --target {target} --n {n}" + bl_cmd = f"ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o BatchMode=yes super@100.123.153.75 '{cmd}'" + vm_cmd = f"ssh -i ~/.ssh/vm_to_gcp -o ProxyCommand=\"$HOME/workspace/bin/ssh-via-proxy %h %p\" -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o BatchMode=yes super@34.139.37.135 \"{bl_cmd}\"" + result = run(vm_cmd) + print(result) + return result + +def main(): + p = argparse.ArgumentParser(description="DEV-DM: Developer Direct Messages") + sub = p.add_subparsers(dest='cmd', required=True) + + ps = sub.add_parser('send', help='Send dev DM') + ps.add_argument('--agent', required=True, choices=['muse', 'pip']) + ps.add_argument('--target', required=True, help='main or chat_id') + ps.add_argument('message', help='Message') + ps.set_defaults(func=lambda a: dev_send(a.agent, a.target, a.message)) + + pr = sub.add_parser('read', help='Read dev DMs') + pr.add_argument('--agent', required=True, choices=['muse', 'pip']) + pr.add_argument('--target', required=True) + pr.add_argument('--n', type=int, default=5) + pr.set_defaults(func=lambda a: dev_read(a.agent, a.target, a.n)) + + args = p.parse_args() + args.func(args) + +if __name__ == '__main__': + main() diff --git a/bin/opp-dm.py b/bin/opp-dm.py new file mode 100755 index 0000000..9dc7859 --- /dev/null +++ b/bin/opp-dm.py @@ -0,0 +1,70 @@ +#!/usr/bin/env python3 +""" +opp-dm.py: Operator Direct Messages + +For operator-to-operator communication (646, operator-main). +Operators have SSH access and infrastructure tools. +This is bidirectional and reliable. + +Distinct from dev-dm.py (for task agents: muse, pip). + +Usage: + opp-dm.py send --to 646 "message" # operator-main -> 646 + opp-dm.py send --to operator-main "msg" # 646 -> operator-main (via SSH) + opp-dm.py read [--from 646] # Read operator messages +""" +import argparse +import subprocess +import sys +import time + +# Operators have SSH access to bl +# Messages stored in a shared location on bl +BL_MSG_DIR = "/home/super/Projects/NetVM/opp-dms" + +def bl_run(cmd): + """Run command on bl via SSH.""" + full = f"ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o BatchMode=yes super@100.123.153.75 '{cmd}'" + # Via VM + vm_cmd = f"ssh -i ~/.ssh/vm_to_gcp -o ProxyCommand=\"$HOME/workspace/bin/ssh-via-proxy %h %p\" -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o BatchMode=yes super@34.139.37.135 \"{full}\"" + result = subprocess.run(vm_cmd, shell=True, capture_output=True, text=True, timeout=30) + return result.stdout.strip() + +def opp_send(to, message, from_who="operator-main"): + """Send an operator DM (stored on bl, both can access via SSH).""" + import datetime + ts = datetime.datetime.now().isoformat() + # Escape for shell + safe = message.replace("'", "'\"'\"'")[:1000] + cmd = f"mkdir -p {BL_MSG_DIR} && echo '{ts} [{from_who}]: {safe}' >> {BL_MSG_DIR}/{to}.log && echo 'sent'" + result = bl_run(cmd) + print(f"OPP-DM sent to {to}") + return result + +def opp_read(who="operator-main", n=5): + """Read operator DMs.""" + cmd = f"tail -n {n*2} {BL_MSG_DIR}/{who}.log 2>/dev/null || echo 'no messages'" + result = bl_run(cmd) + print(result) + return result + +def main(): + p = argparse.ArgumentParser(description="OPP-DM: Operator Direct Messages") + sub = p.add_subparsers(dest='cmd', required=True) + + ps = sub.add_parser('send', help='Send operator DM') + ps.add_argument('--to', required=True, choices=['646', 'operator-main']) + ps.add_argument('--from', dest='from_who', default='operator-main') + ps.add_argument('message', help='Message') + ps.set_defaults(func=lambda a: opp_send(a.to, a.message, a.from_who)) + + pr = sub.add_parser('read', help='Read operator DMs') + pr.add_argument('--who', default='operator-main', choices=['646', 'operator-main']) + pr.add_argument('--n', type=int, default=5) + pr.set_defaults(func=lambda a: opp_read(a.who, a.n)) + + args = p.parse_args() + args.func(args) + +if __name__ == '__main__': + main()