aboutsummaryrefslogtreecommitdiff
path: root/modules/core/terminal.js
diff options
context:
space:
mode:
Diffstat (limited to 'modules/core/terminal.js')
-rw-r--r--modules/core/terminal.js9
1 files changed, 7 insertions, 2 deletions
diff --git a/modules/core/terminal.js b/modules/core/terminal.js
index b058346..5c7a8fb 100644
--- a/modules/core/terminal.js
+++ b/modules/core/terminal.js
@@ -15,6 +15,9 @@
this.systemCmds = new Set(this._baseSystem);
this.suspiciousFlags = new Set(this._baseSuspiciousFlags);
this.whitelist = new Set(this._baseWhitelist);
+ // AI loop-guard: depth counter (reentrant, race-safe vs parallel tool calls)
+ this._aiToolDepth = 0;
+ this._lastUnknownCmd = null;
// Load persisted user deltas (add/remove) so hardcoded defaults can be demoted.
this._loadSecurityDeltas();
this._registerBuiltIn();
@@ -168,6 +171,7 @@
return { cmd, args, known, destructive, system, unknown, hasSuspicious };
}
async checkAndRun(rawInput) {
+ this._lastUnknownCmd = null;
const { cmd, args, known, destructive, system, unknown, hasSuspicious } = this._classify(rawInput);
// Level 3 Audit: just log and allow
if (this.level === 3) {
@@ -191,13 +195,14 @@
return;
}
// Level 1: typo of a safe whitelisted command → one-tap clickable fix, no AI call burned
- if (sug && sug.dist <= 1 && this.whitelist.has(sug.cmd) && this.terminal.showSuggestionBar && !this._aiToolCall) {
+ if (sug && sug.dist <= 1 && this.whitelist.has(sug.cmd) && this.terminal.showSuggestionBar && !(this._aiToolDepth > 0)) {
this.terminal.print(`Unknown command "${cmd}" — did you mean:`, 'warning');
this.terminal.showSuggestionBar(sug.cmd, args);
return;
}
// AI-invoked commands must not route back to AI (infinite loop) — return structured error
- if (this._aiToolCall) {
+ if (this._aiToolDepth > 0) {
+ this._lastUnknownCmd = cmd;
this.terminal.print(`Command not found: ${cmd}${sug ? `. Did you mean: ${sug.cmd}?` : ''}`, 'error');
return;
}