codegpt-ai 2.8.0 → 2.10.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 +83 -96
- 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,111 +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
|
-
"right": [
|
|
1257
|
-
f"[{D}] ╱╲[/]",
|
|
1258
|
-
f"[{D}] (o.o)╲~~~[/]",
|
|
1259
|
-
f"[{D}] ╲╱[/]",
|
|
1260
|
-
],
|
|
1261
|
-
"bottom": [
|
|
1262
|
-
f"[{D}] ||[/]",
|
|
1263
|
-
f"[{D}] ╲╲ ╱╲╲ ╱╱[/]",
|
|
1264
|
-
f"[{D}] ╲╱(o.o)╲╱[/]",
|
|
1265
|
-
f"[{D}] ╲╱[/]",
|
|
1266
|
-
],
|
|
1267
|
-
"left": [
|
|
1268
|
-
f"[{D}] ╱╲[/]",
|
|
1269
|
-
f"[{D}]~~~╱(o.o)[/]",
|
|
1270
|
-
f"[{D}] ╲╱[/]",
|
|
1271
|
-
],
|
|
1272
|
-
}
|
|
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()
|
|
1273
1284
|
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
sub = f"[{R}] ║[/]{' ' * lpad}[{D}]local ai · powered by ollama[/]{' ' * (rpad + 7)}[{R}]║[/]"
|
|
1287
|
-
stats = f"[{R}] ║[/]{' ' * lpad}[{B}]123[/] [{D}]cmds ·[/] [{B}]26[/] [{D}]tools ·[/] [{B}]8[/] [{D}]agents[/]{' ' * (rpad + 8)}[{R}]║[/]"
|
|
1288
|
-
|
|
1289
|
-
lines = []
|
|
1290
|
-
|
|
1291
|
-
if pos_name == "top":
|
|
1292
|
-
for sl in spiders["top"]:
|
|
1293
|
-
lines.append(sl)
|
|
1294
|
-
lines.extend([top_b, empty, title, sub, stats, empty, bot_b])
|
|
1295
|
-
elif pos_name == "right":
|
|
1296
|
-
lines.extend([top_b, empty, title])
|
|
1297
|
-
# Spider on right side
|
|
1298
|
-
for i, sl in enumerate(spiders["right"]):
|
|
1299
|
-
if i == 0:
|
|
1300
|
-
lines.append(f"{sub} {sl}")
|
|
1301
|
-
elif i == 1:
|
|
1302
|
-
lines.append(f"{stats} {sl}")
|
|
1303
|
-
else:
|
|
1304
|
-
lines.append(f"{empty} {sl}")
|
|
1305
|
-
lines.append(bot_b)
|
|
1306
|
-
elif pos_name == "bottom":
|
|
1307
|
-
lines.extend([top_b, empty, title, sub, stats, empty, bot_b])
|
|
1308
|
-
for sl in spiders["bottom"]:
|
|
1309
|
-
lines.append(sl)
|
|
1310
|
-
else: # left
|
|
1311
|
-
lines.append(top_b)
|
|
1312
|
-
for i, sl in enumerate(spiders["left"]):
|
|
1313
|
-
if i == 1:
|
|
1314
|
-
lines.append(f"{sl} [{R}]║[/]{' ' * lpad}[{R}]C[/][{B}]o[/][{R}]d[/][{B}]e[/] [{R}]G[/][{B}]P[/][{R}]T[/] [{D}]v2.0[/]{' ' * (rpad + 16)}[{R}]║[/]")
|
|
1315
|
-
else:
|
|
1316
|
-
lines.append(f"{' ' * 5} {empty}")
|
|
1317
|
-
lines.extend([sub, stats, empty, bot_b])
|
|
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
|
|
1318
1297
|
|
|
1319
|
-
|
|
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()
|
|
1320
1305
|
|
|
1321
|
-
#
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
console=console, refresh_per_second=4, transient=True,
|
|
1327
|
-
) as live:
|
|
1328
|
-
for lap in range(2):
|
|
1329
|
-
for pos in positions:
|
|
1330
|
-
live.update(Text.from_markup(build_banner(pos)))
|
|
1331
|
-
time.sleep(0.4)
|
|
1332
|
-
|
|
1333
|
-
# Final position
|
|
1334
|
-
import random
|
|
1335
|
-
final = random.choice(positions)
|
|
1336
|
-
console.print(Text.from_markup(build_banner(final)))
|
|
1337
|
-
except Exception:
|
|
1338
|
-
console.print(Text.from_markup(build_banner("top")))
|
|
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
|
+
))
|
|
1339
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[/]"
|
|
1340
1316
|
console.print(Text.from_markup(
|
|
1341
|
-
f" [
|
|
1342
|
-
f"
|
|
1343
|
-
f"
|
|
1344
|
-
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[/]"
|
|
1345
1322
|
))
|
|
1346
1323
|
console.print(Rule(style="dim", characters="─"))
|
|
1347
1324
|
console.print()
|
|
@@ -5064,6 +5041,16 @@ def main():
|
|
|
5064
5041
|
if not user_input:
|
|
5065
5042
|
continue
|
|
5066
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
|
+
|
|
5067
5054
|
last_activity[0] = time.time()
|
|
5068
5055
|
|
|
5069
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.10.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
|
}
|