@hasna/terminal 1.2.2 → 1.3.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/dist/ai.js +2 -0
- package/dist/cli.js +17 -9
- package/dist/output-processor.js +2 -2
- package/package.json +1 -1
- package/src/ai.ts +2 -0
- package/src/cli.tsx +15 -9
- package/src/output-processor.ts +2 -2
package/dist/ai.js
CHANGED
|
@@ -43,6 +43,8 @@ const IRREVERSIBLE_PATTERNS = [
|
|
|
43
43
|
// Code modification / package installation (security risk)
|
|
44
44
|
/\bnpx\s+\S+/, /\bnpm\s+install\b/, /\bbun\s+add\b/, /\bpip\s+install\b/,
|
|
45
45
|
/\bcodemod\b/, /\bsed\s+-i\b/, /\bawk\s.*>/, /\bperl\s+-[pi]\b/,
|
|
46
|
+
// File creation/modification (READ-ONLY terminal)
|
|
47
|
+
/\btouch\b/, /\bmkdir\b/, /\becho\s.*>/, /\btee\b/, /\bcp\b/, /\bmv\b/,
|
|
46
48
|
];
|
|
47
49
|
export function isIrreversible(command) {
|
|
48
50
|
return IRREVERSIBLE_PATTERNS.some((r) => r.test(command));
|
package/dist/cli.js
CHANGED
|
@@ -471,17 +471,20 @@ else if (args.length > 0) {
|
|
|
471
471
|
console.log(JSON.stringify(lazy, null, 2));
|
|
472
472
|
process.exit(0);
|
|
473
473
|
}
|
|
474
|
-
// AI
|
|
475
|
-
|
|
474
|
+
// AI answer framing — ALWAYS use in NL mode (even for small output)
|
|
475
|
+
// The AI needs to ANSWER the question, not just pass through data
|
|
476
|
+
if (clean.length > 10) {
|
|
476
477
|
const processed = await processOutput(actualCmd, clean, prompt);
|
|
477
|
-
if (processed.aiProcessed
|
|
478
|
-
|
|
478
|
+
if (processed.aiProcessed) {
|
|
479
|
+
if (processed.tokensSaved > 0)
|
|
480
|
+
recordSaving("compressed", processed.tokensSaved);
|
|
479
481
|
console.log(processed.summary);
|
|
480
|
-
|
|
482
|
+
if (processed.tokensSaved > 10)
|
|
483
|
+
console.error(`[open-terminal] ${rawTokens} → ${rawTokens - processed.tokensSaved} tokens (saved ${processed.tokensSaved})`);
|
|
481
484
|
process.exit(0);
|
|
482
485
|
}
|
|
483
486
|
}
|
|
484
|
-
//
|
|
487
|
+
// Fallback: AI unavailable — pass through clean
|
|
485
488
|
console.log(clean);
|
|
486
489
|
const saved = rawTokens - estimateTokens(clean);
|
|
487
490
|
if (saved > 10) {
|
|
@@ -490,9 +493,14 @@ else if (args.length > 0) {
|
|
|
490
493
|
}
|
|
491
494
|
}
|
|
492
495
|
catch (e) {
|
|
493
|
-
|
|
494
|
-
const
|
|
495
|
-
const
|
|
496
|
+
// Empty result (grep exit 1 = no matches) — not a real error
|
|
497
|
+
const errStdout = e.stdout?.toString() ?? "";
|
|
498
|
+
const errStderr = e.stderr?.toString() ?? "";
|
|
499
|
+
if (e.status === 1 && !errStdout.trim() && !errStderr.trim()) {
|
|
500
|
+
console.log(`No results found for: ${prompt}`);
|
|
501
|
+
process.exit(0);
|
|
502
|
+
}
|
|
503
|
+
const combined = errStderr && errStdout.includes(errStderr.trim()) ? errStdout : errStdout + errStderr;
|
|
496
504
|
console.log(stripNoise(stripAnsi(combined)).cleaned);
|
|
497
505
|
process.exit(e.status ?? 1);
|
|
498
506
|
}
|
package/dist/output-processor.js
CHANGED
|
@@ -22,8 +22,8 @@ RULES:
|
|
|
22
22
|
*/
|
|
23
23
|
export async function processOutput(command, output, originalPrompt) {
|
|
24
24
|
const lines = output.split("\n");
|
|
25
|
-
// Short output —
|
|
26
|
-
if (lines.length <= MIN_LINES_TO_PROCESS) {
|
|
25
|
+
// Short output — skip AI UNLESS we have an original prompt (NL mode needs answer framing)
|
|
26
|
+
if (lines.length <= MIN_LINES_TO_PROCESS && !originalPrompt) {
|
|
27
27
|
return {
|
|
28
28
|
summary: output,
|
|
29
29
|
full: output,
|
package/package.json
CHANGED
package/src/ai.ts
CHANGED
|
@@ -51,6 +51,8 @@ const IRREVERSIBLE_PATTERNS = [
|
|
|
51
51
|
// Code modification / package installation (security risk)
|
|
52
52
|
/\bnpx\s+\S+/, /\bnpm\s+install\b/, /\bbun\s+add\b/, /\bpip\s+install\b/,
|
|
53
53
|
/\bcodemod\b/, /\bsed\s+-i\b/, /\bawk\s.*>/, /\bperl\s+-[pi]\b/,
|
|
54
|
+
// File creation/modification (READ-ONLY terminal)
|
|
55
|
+
/\btouch\b/, /\bmkdir\b/, /\becho\s.*>/, /\btee\b/, /\bcp\b/, /\bmv\b/,
|
|
54
56
|
];
|
|
55
57
|
|
|
56
58
|
export function isIrreversible(command: string): boolean {
|
package/src/cli.tsx
CHANGED
|
@@ -455,25 +455,31 @@ else if (args.length > 0) {
|
|
|
455
455
|
process.exit(0);
|
|
456
456
|
}
|
|
457
457
|
|
|
458
|
-
// AI
|
|
459
|
-
|
|
458
|
+
// AI answer framing — ALWAYS use in NL mode (even for small output)
|
|
459
|
+
// The AI needs to ANSWER the question, not just pass through data
|
|
460
|
+
if (clean.length > 10) {
|
|
460
461
|
const processed = await processOutput(actualCmd, clean, prompt);
|
|
461
|
-
if (processed.aiProcessed
|
|
462
|
-
recordSaving("compressed", processed.tokensSaved);
|
|
462
|
+
if (processed.aiProcessed) {
|
|
463
|
+
if (processed.tokensSaved > 0) recordSaving("compressed", processed.tokensSaved);
|
|
463
464
|
console.log(processed.summary);
|
|
464
|
-
console.error(`[open-terminal] ${rawTokens} → ${rawTokens - processed.tokensSaved} tokens (saved ${processed.tokensSaved})`);
|
|
465
|
+
if (processed.tokensSaved > 10) console.error(`[open-terminal] ${rawTokens} → ${rawTokens - processed.tokensSaved} tokens (saved ${processed.tokensSaved})`);
|
|
465
466
|
process.exit(0);
|
|
466
467
|
}
|
|
467
468
|
}
|
|
468
469
|
|
|
469
|
-
//
|
|
470
|
+
// Fallback: AI unavailable — pass through clean
|
|
470
471
|
console.log(clean);
|
|
471
472
|
const saved = rawTokens - estimateTokens(clean);
|
|
472
473
|
if (saved > 10) { recordSaving("compressed", saved); console.error(`[open-terminal] saved ${saved} tokens`); }
|
|
473
474
|
} catch (e: any) {
|
|
474
|
-
|
|
475
|
-
const
|
|
476
|
-
const
|
|
475
|
+
// Empty result (grep exit 1 = no matches) — not a real error
|
|
476
|
+
const errStdout = e.stdout?.toString() ?? "";
|
|
477
|
+
const errStderr = e.stderr?.toString() ?? "";
|
|
478
|
+
if (e.status === 1 && !errStdout.trim() && !errStderr.trim()) {
|
|
479
|
+
console.log(`No results found for: ${prompt}`);
|
|
480
|
+
process.exit(0);
|
|
481
|
+
}
|
|
482
|
+
const combined = errStderr && errStdout.includes(errStderr.trim()) ? errStdout : errStdout + errStderr;
|
|
477
483
|
console.log(stripNoise(stripAnsi(combined)).cleaned);
|
|
478
484
|
process.exit(e.status ?? 1);
|
|
479
485
|
}
|
package/src/output-processor.ts
CHANGED
|
@@ -52,8 +52,8 @@ export async function processOutput(
|
|
|
52
52
|
): Promise<ProcessedOutput> {
|
|
53
53
|
const lines = output.split("\n");
|
|
54
54
|
|
|
55
|
-
// Short output —
|
|
56
|
-
if (lines.length <= MIN_LINES_TO_PROCESS) {
|
|
55
|
+
// Short output — skip AI UNLESS we have an original prompt (NL mode needs answer framing)
|
|
56
|
+
if (lines.length <= MIN_LINES_TO_PROCESS && !originalPrompt) {
|
|
57
57
|
return {
|
|
58
58
|
summary: output,
|
|
59
59
|
full: output,
|