codegpt-ai 2.7.0 → 2.9.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 +86 -60
- package/package.json +2 -2
package/chat.py
CHANGED
|
@@ -723,6 +723,36 @@ code_exec_count = 0
|
|
|
723
723
|
AUTO_LOCK_MINUTES = 10
|
|
724
724
|
last_activity = [time.time()]
|
|
725
725
|
|
|
726
|
+
# Rate limiting — prevent rapid-fire commands
|
|
727
|
+
RATE_LIMIT_WINDOW = 2 # seconds
|
|
728
|
+
RATE_LIMIT_MAX = 5 # max commands in window
|
|
729
|
+
_cmd_timestamps = []
|
|
730
|
+
|
|
731
|
+
|
|
732
|
+
def check_rate_limit():
|
|
733
|
+
"""Block rapid-fire command spam. Returns True if OK."""
|
|
734
|
+
now = time.time()
|
|
735
|
+
# Remove old timestamps
|
|
736
|
+
while _cmd_timestamps and now - _cmd_timestamps[0] > RATE_LIMIT_WINDOW:
|
|
737
|
+
_cmd_timestamps.pop(0)
|
|
738
|
+
_cmd_timestamps.append(now)
|
|
739
|
+
if len(_cmd_timestamps) > RATE_LIMIT_MAX:
|
|
740
|
+
return False
|
|
741
|
+
return True
|
|
742
|
+
|
|
743
|
+
|
|
744
|
+
def sanitize_input(text):
|
|
745
|
+
"""Strip control characters and null bytes from user input."""
|
|
746
|
+
# Remove null bytes, control chars (except newline/tab)
|
|
747
|
+
cleaned = ""
|
|
748
|
+
for c in text:
|
|
749
|
+
if c == '\x00':
|
|
750
|
+
continue
|
|
751
|
+
if ord(c) < 32 and c not in ('\n', '\t', '\r'):
|
|
752
|
+
continue
|
|
753
|
+
cleaned += c
|
|
754
|
+
return cleaned.strip()
|
|
755
|
+
|
|
726
756
|
|
|
727
757
|
def hash_pin(pin, salt=None):
|
|
728
758
|
"""Hash a PIN with a random salt. Returns 'salt:hash'."""
|
|
@@ -1237,72 +1267,58 @@ def print_header(model):
|
|
|
1237
1267
|
|
|
1238
1268
|
console.print()
|
|
1239
1269
|
|
|
1240
|
-
# Banner parts
|
|
1241
1270
|
R = "bold red"
|
|
1242
1271
|
B = "bold bright_blue"
|
|
1243
1272
|
D = "dim"
|
|
1244
1273
|
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
# Animate spider crawling around the banner
|
|
1284
|
-
try:
|
|
1285
|
-
with Live(
|
|
1286
|
-
Text.from_markup(build_banner(0)),
|
|
1287
|
-
console=console, refresh_per_second=6, transient=True,
|
|
1288
|
-
) as live:
|
|
1289
|
-
for frame in range(16): # 2 full laps
|
|
1290
|
-
live.update(Text.from_markup(build_banner(frame)))
|
|
1291
|
-
time.sleep(0.2)
|
|
1292
|
-
|
|
1293
|
-
# Final position — static
|
|
1294
|
-
import random
|
|
1295
|
-
final = random.randint(0, 7)
|
|
1296
|
-
console.print(Text.from_markup(build_banner(final)))
|
|
1297
|
-
except Exception:
|
|
1298
|
-
# Fallback if Live doesn't work
|
|
1299
|
-
console.print(Text.from_markup(build_banner(0)))
|
|
1274
|
+
# Banner
|
|
1275
|
+
console.print(Text.from_markup(
|
|
1276
|
+
f"[{R}] ╔══════════════════════════════════════════════════╗[/]\n"
|
|
1277
|
+
f"[{R}] ║[/] [{R}]║[/]\n"
|
|
1278
|
+
f"[{R}] ║[/] [{R}]C[/][{B}]o[/][{R}]d[/][{B}]e[/] [{R}]G[/][{B}]P[/][{R}]T[/] [{D}]v2.0[/] [{R}]║[/]\n"
|
|
1279
|
+
f"[{R}] ║[/] [{D}]local ai · powered by ollama[/] [{R}]║[/]\n"
|
|
1280
|
+
f"[{R}] ║[/] [{R}]║[/]\n"
|
|
1281
|
+
f"[{R}] ╚══════════════════════════════════════════════════╝[/]"
|
|
1282
|
+
))
|
|
1283
|
+
console.print()
|
|
1284
|
+
|
|
1285
|
+
# Info block — model, server, tokens, security
|
|
1286
|
+
total_tok = profile.get("total_tokens", 0)
|
|
1287
|
+
total_msgs = profile.get("total_messages", 0)
|
|
1288
|
+
sessions = profile.get("total_sessions", 0)
|
|
1289
|
+
pin_on = has_pin()
|
|
1290
|
+
perms = len(PERMISSION_ALWAYS_ALLOW)
|
|
1291
|
+
audit_count = 0
|
|
1292
|
+
if AUDIT_FILE.exists():
|
|
1293
|
+
try:
|
|
1294
|
+
audit_count = len(AUDIT_FILE.read_text().strip().splitlines())
|
|
1295
|
+
except Exception:
|
|
1296
|
+
pass
|
|
1297
|
+
|
|
1298
|
+
console.print(Text.from_markup(
|
|
1299
|
+
f" [{D}]model[/] [{B}]{model}[/]\n"
|
|
1300
|
+
f" [{D}]server[/] [green]{server}[/]\n"
|
|
1301
|
+
f" [{D}]user[/] {name}\n"
|
|
1302
|
+
f" [{D}]memory[/] {mem_count} items"
|
|
1303
|
+
))
|
|
1304
|
+
console.print()
|
|
1305
|
+
|
|
1306
|
+
# Token counter
|
|
1307
|
+
console.print(Text.from_markup(
|
|
1308
|
+
f" [{D}]tokens[/] [{B}]{total_tok:,}[/] [{D}]lifetime[/]\n"
|
|
1309
|
+
f" [{D}]messages[/] [{B}]{total_msgs:,}[/] [{D}]across {sessions} sessions[/]"
|
|
1310
|
+
))
|
|
1300
1311
|
console.print()
|
|
1312
|
+
|
|
1313
|
+
# Security status
|
|
1314
|
+
pin_status = f"[green]on[/]" if pin_on else f"[yellow]off[/] [{D}]— /pin-set to enable[/]"
|
|
1315
|
+
sandbox_status = f"[green]active[/]"
|
|
1301
1316
|
console.print(Text.from_markup(
|
|
1302
|
-
f" [
|
|
1303
|
-
f"
|
|
1304
|
-
f"
|
|
1305
|
-
f" [
|
|
1317
|
+
f" [{D}]security[/]\n"
|
|
1318
|
+
f" [{D}]pin lock[/] {pin_status}\n"
|
|
1319
|
+
f" [{D}]sandbox[/] {sandbox_status}\n"
|
|
1320
|
+
f" [{D}]permissions[/] [{B}]{perms}[/] [{D}]always-allowed[/]\n"
|
|
1321
|
+
f" [{D}]audit log[/] [{B}]{audit_count}[/] [{D}]events[/]"
|
|
1306
1322
|
))
|
|
1307
1323
|
console.print(Rule(style="dim", characters="─"))
|
|
1308
1324
|
console.print()
|
|
@@ -5025,6 +5041,16 @@ def main():
|
|
|
5025
5041
|
if not user_input:
|
|
5026
5042
|
continue
|
|
5027
5043
|
|
|
5044
|
+
# Sanitize input
|
|
5045
|
+
user_input = sanitize_input(user_input)
|
|
5046
|
+
if not user_input:
|
|
5047
|
+
continue
|
|
5048
|
+
|
|
5049
|
+
# Rate limit
|
|
5050
|
+
if user_input.startswith("/") and not check_rate_limit():
|
|
5051
|
+
print_err("Slow down — too many commands. Wait a moment.")
|
|
5052
|
+
continue
|
|
5053
|
+
|
|
5028
5054
|
last_activity[0] = time.time()
|
|
5029
5055
|
|
|
5030
5056
|
# Suggestion number shortcut
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codegpt-ai",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.9.0",
|
|
4
4
|
"description": "Local AI Assistant Hub — 80+ commands, 29 tools, 8 agents, training, security",
|
|
5
5
|
"author": "ArukuX",
|
|
6
6
|
"license": "MIT",
|
|
@@ -36,6 +36,6 @@
|
|
|
36
36
|
"README.md"
|
|
37
37
|
],
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"codegpt-ai": "^1.
|
|
39
|
+
"codegpt-ai": "^1.28.2"
|
|
40
40
|
}
|
|
41
41
|
}
|