codegpt-ai 2.27.0 → 2.29.0
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.
- package/chat.py +25 -0
- package/package.json +1 -1
- package/tui.py +271 -8
package/chat.py
CHANGED
|
@@ -439,6 +439,7 @@ COMMANDS = {
|
|
|
439
439
|
"/security": "Security status dashboard",
|
|
440
440
|
"/permissions": "View/reset action permissions",
|
|
441
441
|
"/desktop": "Launch CodeGPT desktop app",
|
|
442
|
+
"/tui": "Launch CodeGPT TUI mode",
|
|
442
443
|
"/skill": "Create a custom command (/skill name prompt)",
|
|
443
444
|
"/skills": "List custom skills",
|
|
444
445
|
"/browse": "Browse a URL and summarize (/browse url)",
|
|
@@ -7259,6 +7260,30 @@ def main():
|
|
|
7259
7260
|
print_sys("Desktop app opened in a new window.")
|
|
7260
7261
|
continue
|
|
7261
7262
|
|
|
7263
|
+
elif cmd == "/tui":
|
|
7264
|
+
tui_paths = [
|
|
7265
|
+
os.path.join(str(Path(__file__).parent), "tui.py"),
|
|
7266
|
+
os.path.join(str(Path.home()), "codegpt", "tui.py"),
|
|
7267
|
+
]
|
|
7268
|
+
tui_py = None
|
|
7269
|
+
for tp in tui_paths:
|
|
7270
|
+
if os.path.isfile(tp):
|
|
7271
|
+
tui_py = tp
|
|
7272
|
+
break
|
|
7273
|
+
if not tui_py:
|
|
7274
|
+
try:
|
|
7275
|
+
tui_py = os.path.join(str(Path.home()), ".codegpt", "tui.py")
|
|
7276
|
+
r = requests.get("https://raw.githubusercontent.com/CCguvycu/codegpt/master/tui.py", timeout=15)
|
|
7277
|
+
Path(tui_py).parent.mkdir(parents=True, exist_ok=True)
|
|
7278
|
+
Path(tui_py).write_text(r.text, encoding="utf-8")
|
|
7279
|
+
except Exception:
|
|
7280
|
+
print_err("Cannot download TUI.")
|
|
7281
|
+
continue
|
|
7282
|
+
print_sys("Launching TUI mode...")
|
|
7283
|
+
subprocess.run([sys.executable, tui_py])
|
|
7284
|
+
print_header(model)
|
|
7285
|
+
continue
|
|
7286
|
+
|
|
7262
7287
|
elif cmd == "/permissions":
|
|
7263
7288
|
sub = user_input[len("/permissions "):].strip().lower()
|
|
7264
7289
|
if sub == "reset":
|
package/package.json
CHANGED
package/tui.py
CHANGED
|
@@ -3,6 +3,8 @@ import json
|
|
|
3
3
|
import os
|
|
4
4
|
import sys
|
|
5
5
|
import time
|
|
6
|
+
import subprocess
|
|
7
|
+
import threading
|
|
6
8
|
import requests
|
|
7
9
|
from pathlib import Path
|
|
8
10
|
from datetime import datetime
|
|
@@ -123,6 +125,61 @@ TUI_COMMANDS = {
|
|
|
123
125
|
"/weather": "Get weather",
|
|
124
126
|
"/agent": "Run an AI agent",
|
|
125
127
|
"/quit": "Exit",
|
|
128
|
+
"/temp": "Set temperature (0-2)",
|
|
129
|
+
"/system": "Set system prompt",
|
|
130
|
+
"/export": "Export chat as text",
|
|
131
|
+
"/browse": "Fetch and summarize URL",
|
|
132
|
+
"/open": "Open URL in browser",
|
|
133
|
+
"/save": "Save conversation",
|
|
134
|
+
"/copy": "Copy last response",
|
|
135
|
+
"/regen": "Regenerate last response",
|
|
136
|
+
"/compact": "Summarize old messages",
|
|
137
|
+
"/search": "Search conversation",
|
|
138
|
+
"/diff": "Compare last 2 responses",
|
|
139
|
+
"/pin": "Pin a message",
|
|
140
|
+
"/pins": "Show pinned messages",
|
|
141
|
+
"/fork": "Fork conversation from #",
|
|
142
|
+
"/rate": "Rate last response (good/bad)",
|
|
143
|
+
"/all": "Ask ALL agents at once",
|
|
144
|
+
"/vote": "Agents vote on a question",
|
|
145
|
+
"/swarm": "6-agent pipeline",
|
|
146
|
+
"/team": "Group chat with 2 AIs",
|
|
147
|
+
"/room": "Chat room with 3+ AIs",
|
|
148
|
+
"/spectate": "Watch AIs debate",
|
|
149
|
+
"/dm": "Message a specific agent",
|
|
150
|
+
"/race": "Race all models",
|
|
151
|
+
"/compare": "Compare 2 models",
|
|
152
|
+
"/chain": "Chain prompts (p1 | p2 | p3)",
|
|
153
|
+
"/lab": "AI Lab experiments",
|
|
154
|
+
"/train": "AI Training Lab",
|
|
155
|
+
"/mem": "AI memory (save/recall)",
|
|
156
|
+
"/skill": "Create custom command",
|
|
157
|
+
"/skills": "List custom skills",
|
|
158
|
+
"/auto": "AI creates a skill",
|
|
159
|
+
"/cron": "Schedule recurring task",
|
|
160
|
+
"/tools": "List AI tool integrations",
|
|
161
|
+
"/github": "GitHub tools",
|
|
162
|
+
"/spotify": "Spotify controls",
|
|
163
|
+
"/volume": "System volume",
|
|
164
|
+
"/sysinfo": "System info",
|
|
165
|
+
"/usage": "Usage dashboard",
|
|
166
|
+
"/profile": "View profile",
|
|
167
|
+
"/setname": "Set display name",
|
|
168
|
+
"/setbio": "Set bio",
|
|
169
|
+
"/security": "Security dashboard",
|
|
170
|
+
"/permissions": "View permissions",
|
|
171
|
+
"/audit": "Security audit log",
|
|
172
|
+
"/pin-set": "Set login PIN",
|
|
173
|
+
"/lock": "Lock session",
|
|
174
|
+
"/qr": "QR code to connect",
|
|
175
|
+
"/broadcast": "Message all tools",
|
|
176
|
+
"/inbox": "Check messages",
|
|
177
|
+
"/feed": "Message feed",
|
|
178
|
+
"/monitor": "Live dashboard",
|
|
179
|
+
"/hub": "Command center",
|
|
180
|
+
"/shortcuts": "Keyboard shortcuts",
|
|
181
|
+
"/prompts": "Prompt templates",
|
|
182
|
+
"/desktop": "Desktop app (PC only)",
|
|
126
183
|
}
|
|
127
184
|
|
|
128
185
|
|
|
@@ -386,16 +443,222 @@ def handle_command(text):
|
|
|
386
443
|
console.print(Text(" Usage: /agent coder build a flask API", style="dim"))
|
|
387
444
|
console.print()
|
|
388
445
|
|
|
446
|
+
elif cmd == "/temp":
|
|
447
|
+
if args:
|
|
448
|
+
try:
|
|
449
|
+
t = float(args)
|
|
450
|
+
if 0 <= t <= 2:
|
|
451
|
+
console.print(Text(f" Temperature: {t}", style="green"))
|
|
452
|
+
except:
|
|
453
|
+
console.print(Text(" Usage: /temp 0.7 (0.0-2.0)", style="dim"))
|
|
454
|
+
else:
|
|
455
|
+
console.print(Text(" Usage: /temp 0.7", style="dim"))
|
|
456
|
+
console.print()
|
|
457
|
+
|
|
458
|
+
elif cmd == "/system":
|
|
459
|
+
if args:
|
|
460
|
+
system = args
|
|
461
|
+
console.print(Text(" System prompt updated.", style="green"))
|
|
462
|
+
else:
|
|
463
|
+
console.print(Text(f" Current: {system[:80]}...", style="dim"))
|
|
464
|
+
console.print()
|
|
465
|
+
|
|
466
|
+
elif cmd == "/export":
|
|
467
|
+
if messages:
|
|
468
|
+
lines = []
|
|
469
|
+
for m in messages:
|
|
470
|
+
role = "You" if m["role"] == "user" else "AI"
|
|
471
|
+
lines.append(f"{role}: {m['content']}\n")
|
|
472
|
+
export_path = Path.home() / ".codegpt" / f"export_{datetime.now().strftime('%Y%m%d_%H%M')}.md"
|
|
473
|
+
export_path.parent.mkdir(parents=True, exist_ok=True)
|
|
474
|
+
export_path.write_text("\n".join(lines), encoding="utf-8")
|
|
475
|
+
console.print(Text(f" Exported: {export_path}", style="green"))
|
|
476
|
+
else:
|
|
477
|
+
console.print(Text(" Nothing to export.", style="dim"))
|
|
478
|
+
console.print()
|
|
479
|
+
|
|
480
|
+
elif cmd == "/browse":
|
|
481
|
+
if args:
|
|
482
|
+
url = args if args.startswith("http") else "https://" + args
|
|
483
|
+
console.print(Text(f" Fetching {url}...", style="dim"))
|
|
484
|
+
try:
|
|
485
|
+
import re as _re
|
|
486
|
+
r = requests.get(url, timeout=15, headers={"User-Agent": "CodeGPT/2.0"})
|
|
487
|
+
text = _re.sub(r'<script[^>]*>.*?</script>', '', r.text, flags=_re.DOTALL)
|
|
488
|
+
text = _re.sub(r'<style[^>]*>.*?</style>', '', text, flags=_re.DOTALL)
|
|
489
|
+
text = _re.sub(r'<[^>]+>', ' ', text)
|
|
490
|
+
text = _re.sub(r'\s+', ' ', text).strip()[:3000]
|
|
491
|
+
resp = requests.post(OLLAMA_URL, json={
|
|
492
|
+
"model": MODEL, "messages": [
|
|
493
|
+
{"role": "system", "content": "Summarize in 3-5 bullet points."},
|
|
494
|
+
{"role": "user", "content": text},
|
|
495
|
+
], "stream": False,
|
|
496
|
+
}, timeout=60)
|
|
497
|
+
summary = resp.json().get("message", {}).get("content", text[:500])
|
|
498
|
+
print_msg("ai", summary)
|
|
499
|
+
except Exception as e:
|
|
500
|
+
console.print(Text(f" Error: {e}", style="red"))
|
|
501
|
+
else:
|
|
502
|
+
console.print(Text(" Usage: /browse github.com", style="dim"))
|
|
503
|
+
console.print()
|
|
504
|
+
|
|
505
|
+
elif cmd == "/open":
|
|
506
|
+
if args:
|
|
507
|
+
url = args if args.startswith("http") else "https://" + args
|
|
508
|
+
if os.path.exists("/data/data/com.termux"):
|
|
509
|
+
try:
|
|
510
|
+
subprocess.run(["termux-open-url", url], timeout=5)
|
|
511
|
+
except:
|
|
512
|
+
subprocess.run(["am", "start", "-a", "android.intent.action.VIEW", "-d", url], timeout=5)
|
|
513
|
+
else:
|
|
514
|
+
import webbrowser
|
|
515
|
+
webbrowser.open(url)
|
|
516
|
+
console.print(Text(f" Opened: {url}", style="green"))
|
|
517
|
+
else:
|
|
518
|
+
console.print(Text(" Usage: /open google.com", style="dim"))
|
|
519
|
+
console.print()
|
|
520
|
+
|
|
521
|
+
elif cmd == "/all":
|
|
522
|
+
if args:
|
|
523
|
+
agents_list = {
|
|
524
|
+
"coder": "You are an expert programmer.",
|
|
525
|
+
"debugger": "You are a debugging expert.",
|
|
526
|
+
"reviewer": "You are a code reviewer.",
|
|
527
|
+
"architect": "You are a system architect.",
|
|
528
|
+
"pentester": "You are an ethical pentester.",
|
|
529
|
+
"explainer": "You are a patient teacher.",
|
|
530
|
+
"optimizer": "You are a performance engineer.",
|
|
531
|
+
"researcher": "You are a research analyst.",
|
|
532
|
+
}
|
|
533
|
+
import threading
|
|
534
|
+
results = {}
|
|
535
|
+
def _query(n, s):
|
|
536
|
+
try:
|
|
537
|
+
r = requests.post(OLLAMA_URL, json={"model": MODEL, "messages": [
|
|
538
|
+
{"role": "system", "content": s}, {"role": "user", "content": args}
|
|
539
|
+
], "stream": False}, timeout=90)
|
|
540
|
+
results[n] = r.json().get("message", {}).get("content", "")
|
|
541
|
+
except:
|
|
542
|
+
results[n] = "(error)"
|
|
543
|
+
threads = [threading.Thread(target=_query, args=(n, s), daemon=True) for n, s in agents_list.items()]
|
|
544
|
+
for t in threads: t.start()
|
|
545
|
+
console.print(Text(" Asking all 8 agents...", style="dim"))
|
|
546
|
+
for t in threads: t.join(timeout=90)
|
|
547
|
+
for name, resp in results.items():
|
|
548
|
+
console.print(Text.from_markup(f"\n [bright_blue]{name}[/]"))
|
|
549
|
+
console.print(Text(f" {resp[:200]}", style="white"))
|
|
550
|
+
console.print()
|
|
551
|
+
else:
|
|
552
|
+
console.print(Text(" Usage: /all what database should I use?", style="dim"))
|
|
553
|
+
console.print()
|
|
554
|
+
|
|
555
|
+
elif cmd == "/save":
|
|
556
|
+
if messages:
|
|
557
|
+
save_path = Path.home() / ".codegpt" / "chats" / f"{datetime.now().strftime('%Y%m%d_%H%M')}.json"
|
|
558
|
+
save_path.parent.mkdir(parents=True, exist_ok=True)
|
|
559
|
+
save_path.write_text(json.dumps({"messages": messages, "model": MODEL}))
|
|
560
|
+
console.print(Text(f" Saved: {save_path.name}", style="green"))
|
|
561
|
+
else:
|
|
562
|
+
console.print(Text(" Nothing to save.", style="dim"))
|
|
563
|
+
console.print()
|
|
564
|
+
|
|
565
|
+
elif cmd == "/copy":
|
|
566
|
+
ai_msgs = [m for m in messages if m["role"] == "assistant"]
|
|
567
|
+
if ai_msgs:
|
|
568
|
+
last = ai_msgs[-1]["content"]
|
|
569
|
+
try:
|
|
570
|
+
import subprocess
|
|
571
|
+
if os.path.exists("/data/data/com.termux"):
|
|
572
|
+
subprocess.run(["termux-clipboard-set"], input=last.encode(), timeout=5)
|
|
573
|
+
else:
|
|
574
|
+
subprocess.run("clip" if os.name == "nt" else "pbcopy", input=last.encode(), shell=True, timeout=5)
|
|
575
|
+
console.print(Text(" Copied to clipboard.", style="green"))
|
|
576
|
+
except:
|
|
577
|
+
console.print(Text(" Cannot copy — clipboard not available.", style="red"))
|
|
578
|
+
else:
|
|
579
|
+
console.print(Text(" No response to copy.", style="dim"))
|
|
580
|
+
console.print()
|
|
581
|
+
|
|
582
|
+
elif cmd == "/regen":
|
|
583
|
+
if messages and messages[-1]["role"] == "assistant":
|
|
584
|
+
messages.pop()
|
|
585
|
+
if messages and messages[-1]["role"] == "user":
|
|
586
|
+
last_q = messages[-1]["content"]
|
|
587
|
+
messages.pop()
|
|
588
|
+
print_msg("user", last_q)
|
|
589
|
+
chat(last_q)
|
|
590
|
+
else:
|
|
591
|
+
console.print(Text(" Nothing to regenerate.", style="dim"))
|
|
592
|
+
console.print()
|
|
593
|
+
|
|
594
|
+
elif cmd == "/rate":
|
|
595
|
+
rating = args.lower() if args else ""
|
|
596
|
+
if rating in ("good", "bad", "+", "-"):
|
|
597
|
+
ai_msgs = [m for m in messages if m["role"] == "assistant"]
|
|
598
|
+
if ai_msgs:
|
|
599
|
+
ratings_file = Path.home() / ".codegpt" / "ratings.json"
|
|
600
|
+
ratings = []
|
|
601
|
+
if ratings_file.exists():
|
|
602
|
+
try: ratings = json.loads(ratings_file.read_text())
|
|
603
|
+
except: pass
|
|
604
|
+
ratings.append({"rating": "good" if rating in ("good", "+") else "bad",
|
|
605
|
+
"response": ai_msgs[-1]["content"][:200],
|
|
606
|
+
"timestamp": datetime.now().isoformat()})
|
|
607
|
+
ratings_file.write_text(json.dumps(ratings))
|
|
608
|
+
console.print(Text(f" Rated: {rating}", style="green"))
|
|
609
|
+
else:
|
|
610
|
+
console.print(Text(" Usage: /rate good or /rate bad", style="dim"))
|
|
611
|
+
console.print()
|
|
612
|
+
|
|
613
|
+
elif cmd == "/usage":
|
|
614
|
+
profile = {}
|
|
615
|
+
if profile_file.exists():
|
|
616
|
+
try: profile = json.loads(profile_file.read_text())
|
|
617
|
+
except: pass
|
|
618
|
+
console.print(Text.from_markup(
|
|
619
|
+
f" [bold]Session[/]\n"
|
|
620
|
+
f" Messages [bright_blue]{len(messages)}[/]\n"
|
|
621
|
+
f" Tokens [bright_blue]{total_tokens}[/]\n"
|
|
622
|
+
f" Model [bright_blue]{MODEL}[/]\n"
|
|
623
|
+
f" Persona [bright_blue]{persona}[/]\n\n"
|
|
624
|
+
f" [bold]Lifetime[/]\n"
|
|
625
|
+
f" Messages [bright_blue]{profile.get('total_messages', 0)}[/]\n"
|
|
626
|
+
f" Sessions [bright_blue]{profile.get('total_sessions', 0)}[/]"
|
|
627
|
+
))
|
|
628
|
+
console.print()
|
|
629
|
+
|
|
630
|
+
elif cmd == "/profile":
|
|
631
|
+
profile = {}
|
|
632
|
+
if profile_file.exists():
|
|
633
|
+
try: profile = json.loads(profile_file.read_text())
|
|
634
|
+
except: pass
|
|
635
|
+
console.print(Text.from_markup(
|
|
636
|
+
f" [bold]{profile.get('name', 'User')}[/]\n"
|
|
637
|
+
f" Bio {profile.get('bio', '')}\n"
|
|
638
|
+
f" Model [bright_blue]{profile.get('model', MODEL)}[/]\n"
|
|
639
|
+
f" Persona [green]{profile.get('persona', 'default')}[/]\n"
|
|
640
|
+
f" Sessions {profile.get('total_sessions', 0)}"
|
|
641
|
+
))
|
|
642
|
+
console.print()
|
|
643
|
+
|
|
389
644
|
elif cmd == "/help" or cmd == "/h":
|
|
390
|
-
|
|
391
|
-
"
|
|
392
|
-
"
|
|
393
|
-
"
|
|
394
|
-
"
|
|
395
|
-
"
|
|
645
|
+
groups = {
|
|
646
|
+
"Chat": ["/new", "/save", "/copy", "/regen", "/history", "/clear", "/export", "/quit"],
|
|
647
|
+
"Model": ["/model", "/models", "/persona", "/think", "/temp", "/tokens", "/system"],
|
|
648
|
+
"AI": ["/agent", "/all", "/vote", "/swarm", "/team", "/room", "/spectate", "/race"],
|
|
649
|
+
"Files": ["/browse", "/open"],
|
|
650
|
+
"Memory": ["/mem", "/train", "/rate", "/search", "/fork", "/pin"],
|
|
651
|
+
"Tools": ["/tools", "/skill", "/auto", "/cron"],
|
|
652
|
+
"Connect": ["/connect", "/server", "/qr", "/weather", "/sysinfo", "/github"],
|
|
653
|
+
"Profile": ["/profile", "/usage", "/setname", "/setbio", "/permissions"],
|
|
654
|
+
"Security": ["/pin-set", "/lock", "/audit", "/security"],
|
|
396
655
|
}
|
|
397
|
-
for
|
|
398
|
-
console.print(Text
|
|
656
|
+
for group, cmds_list in groups.items():
|
|
657
|
+
console.print(Text(f"\n {group}", style="bold bright_blue"))
|
|
658
|
+
for c in cmds_list:
|
|
659
|
+
desc = TUI_COMMANDS.get(c, "")
|
|
660
|
+
if desc:
|
|
661
|
+
console.print(Text.from_markup(f" [bright_blue]{c:<14}[/] [dim]{desc}[/]"))
|
|
399
662
|
console.print()
|
|
400
663
|
|
|
401
664
|
else:
|