@hasna/terminal 0.6.1 → 0.7.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/cli.js +107 -0
- package/dist/command-rewriter.js +2 -2
- package/package.json +1 -1
- package/src/cli.tsx +113 -0
- package/src/command-rewriter.ts +2 -2
package/dist/cli.js
CHANGED
|
@@ -2,6 +2,113 @@
|
|
|
2
2
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
3
|
import { render } from "ink";
|
|
4
4
|
const args = process.argv.slice(2);
|
|
5
|
+
// ── Help / Version ───────────────────────────────────────────────────────────
|
|
6
|
+
if (args[0] === "--help" || args[0] === "-h" || args[0] === "help") {
|
|
7
|
+
console.log(`open-terminal v0.6.1 — Smart terminal for AI agents and humans
|
|
8
|
+
|
|
9
|
+
USAGE:
|
|
10
|
+
terminal Launch interactive NL terminal (TUI)
|
|
11
|
+
terminal <subcommand> Run a specific command
|
|
12
|
+
|
|
13
|
+
SUBCOMMANDS:
|
|
14
|
+
mcp serve Start MCP server (stdio transport)
|
|
15
|
+
mcp install --claude|--codex|--gemini|--all
|
|
16
|
+
Install as MCP server for AI agents
|
|
17
|
+
hook install --claude Install Claude Code PostToolUse hook
|
|
18
|
+
hook uninstall Remove hooks
|
|
19
|
+
recipe add <name> <cmd> Save a reusable command recipe
|
|
20
|
+
recipe list List saved recipes
|
|
21
|
+
recipe run <name> [--var=X] Run a recipe with variable substitution
|
|
22
|
+
recipe delete <name> Delete a recipe
|
|
23
|
+
collection create <name> Create a recipe collection
|
|
24
|
+
collection list List collections
|
|
25
|
+
project init Initialize project-scoped recipes
|
|
26
|
+
repo Show git repo state (branch + status + log)
|
|
27
|
+
symbols <file> Show file outline (functions, classes, exports)
|
|
28
|
+
stats Show token economy dashboard
|
|
29
|
+
sessions List recent terminal sessions
|
|
30
|
+
sessions stats Show session analytics
|
|
31
|
+
sessions <id> Show session details
|
|
32
|
+
snapshot Capture terminal state as JSON
|
|
33
|
+
--help Show this help
|
|
34
|
+
--version Show version
|
|
35
|
+
|
|
36
|
+
MCP TOOLS (20+):
|
|
37
|
+
execute, execute_smart, execute_diff, expand, browse,
|
|
38
|
+
search_files, search_content, search_semantic, read_file,
|
|
39
|
+
read_symbol, symbols, repo_state, explain_error, status,
|
|
40
|
+
bg_start, bg_stop, bg_status, bg_logs, bg_wait_port,
|
|
41
|
+
list_recipes, run_recipe, save_recipe, list_collections,
|
|
42
|
+
snapshot, token_stats, session_history
|
|
43
|
+
|
|
44
|
+
ENVIRONMENT:
|
|
45
|
+
CEREBRAS_API_KEY Cerebras API key (free, open-source default)
|
|
46
|
+
ANTHROPIC_API_KEY Anthropic API key (Claude models)
|
|
47
|
+
`);
|
|
48
|
+
process.exit(0);
|
|
49
|
+
}
|
|
50
|
+
if (args[0] === "--version" || args[0] === "-v") {
|
|
51
|
+
console.log("0.6.1");
|
|
52
|
+
process.exit(0);
|
|
53
|
+
}
|
|
54
|
+
// ── Exec command — smart execution for agents ────────────────────────────────
|
|
55
|
+
if (args[0] === "exec") {
|
|
56
|
+
const command = args.slice(1).join(" ");
|
|
57
|
+
if (!command) {
|
|
58
|
+
console.error("Usage: terminal exec <command>");
|
|
59
|
+
process.exit(1);
|
|
60
|
+
}
|
|
61
|
+
const { execSync } = await import("child_process");
|
|
62
|
+
const { stripAnsi } = await import("./compression.js");
|
|
63
|
+
const { stripNoise } = await import("./noise-filter.js");
|
|
64
|
+
const { processOutput, shouldProcess } = await import("./output-processor.js");
|
|
65
|
+
const { rewriteCommand } = await import("./command-rewriter.js");
|
|
66
|
+
const { shouldBeLazy, toLazy } = await import("./lazy-executor.js");
|
|
67
|
+
const { estimateTokens } = await import("./parsers/index.js");
|
|
68
|
+
// Rewrite command if possible
|
|
69
|
+
const rw = rewriteCommand(command);
|
|
70
|
+
const actualCmd = rw.changed ? rw.rewritten : command;
|
|
71
|
+
if (rw.changed)
|
|
72
|
+
console.error(`[open-terminal] rewritten: ${actualCmd} (${rw.reason})`);
|
|
73
|
+
try {
|
|
74
|
+
const start = Date.now();
|
|
75
|
+
const raw = execSync(actualCmd, { encoding: "utf8", maxBuffer: 10 * 1024 * 1024, cwd: process.cwd() });
|
|
76
|
+
const duration = Date.now() - start;
|
|
77
|
+
const clean = stripNoise(stripAnsi(raw)).cleaned;
|
|
78
|
+
const rawTokens = estimateTokens(raw);
|
|
79
|
+
// Lazy mode for huge output
|
|
80
|
+
if (shouldBeLazy(clean)) {
|
|
81
|
+
const lazy = toLazy(clean, actualCmd);
|
|
82
|
+
const savedTokens = rawTokens - estimateTokens(JSON.stringify(lazy));
|
|
83
|
+
console.log(JSON.stringify({ ...lazy, duration, tokensSaved: savedTokens }));
|
|
84
|
+
process.exit(0);
|
|
85
|
+
}
|
|
86
|
+
// AI summary for medium-large output
|
|
87
|
+
if (shouldProcess(clean)) {
|
|
88
|
+
const processed = await processOutput(actualCmd, clean);
|
|
89
|
+
if (processed.aiProcessed && processed.tokensSaved > 30) {
|
|
90
|
+
console.log(processed.summary);
|
|
91
|
+
const savedTokens = rawTokens - estimateTokens(processed.summary);
|
|
92
|
+
console.error(`[open-terminal] ${rawTokens} → ${rawTokens - savedTokens} tokens (saved ${savedTokens}, ${Math.round(savedTokens / rawTokens * 100)}%)`);
|
|
93
|
+
process.exit(0);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
// Small/medium output — just noise-strip and return
|
|
97
|
+
console.log(clean);
|
|
98
|
+
const savedTokens = rawTokens - estimateTokens(clean);
|
|
99
|
+
if (savedTokens > 10) {
|
|
100
|
+
console.error(`[open-terminal] saved ${savedTokens} tokens (noise filter)`);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
catch (e) {
|
|
104
|
+
// Command failed — show error output
|
|
105
|
+
const stderr = e.stderr?.toString() ?? "";
|
|
106
|
+
const stdout = e.stdout?.toString() ?? "";
|
|
107
|
+
console.log(stripNoise(stripAnsi(stdout + stderr)).cleaned);
|
|
108
|
+
process.exit(e.status ?? 1);
|
|
109
|
+
}
|
|
110
|
+
process.exit(0);
|
|
111
|
+
}
|
|
5
112
|
// ── MCP commands ─────────────────────────────────────────────────────────────
|
|
6
113
|
if (args[0] === "mcp") {
|
|
7
114
|
if (args[1] === "serve" || args.length === 1) {
|
package/dist/command-rewriter.js
CHANGED
|
@@ -41,10 +41,10 @@ const rules = [
|
|
|
41
41
|
rewrite: () => "npm ls --depth=0",
|
|
42
42
|
reason: "full tree is massive, top-level usually enough",
|
|
43
43
|
},
|
|
44
|
-
// ps aux without filter →
|
|
44
|
+
// ps aux without filter → sort by memory and head (macOS compatible)
|
|
45
45
|
{
|
|
46
46
|
pattern: /^ps\s+aux\s*$/,
|
|
47
|
-
rewrite: () => "ps aux
|
|
47
|
+
rewrite: () => "ps aux | sort -k4 -rn | head -20",
|
|
48
48
|
reason: "full process list is noise, show top consumers",
|
|
49
49
|
},
|
|
50
50
|
];
|
package/package.json
CHANGED
package/src/cli.tsx
CHANGED
|
@@ -4,6 +4,119 @@ import { render } from "ink";
|
|
|
4
4
|
|
|
5
5
|
const args = process.argv.slice(2);
|
|
6
6
|
|
|
7
|
+
// ── Help / Version ───────────────────────────────────────────────────────────
|
|
8
|
+
|
|
9
|
+
if (args[0] === "--help" || args[0] === "-h" || args[0] === "help") {
|
|
10
|
+
console.log(`open-terminal v0.6.1 — Smart terminal for AI agents and humans
|
|
11
|
+
|
|
12
|
+
USAGE:
|
|
13
|
+
terminal Launch interactive NL terminal (TUI)
|
|
14
|
+
terminal <subcommand> Run a specific command
|
|
15
|
+
|
|
16
|
+
SUBCOMMANDS:
|
|
17
|
+
mcp serve Start MCP server (stdio transport)
|
|
18
|
+
mcp install --claude|--codex|--gemini|--all
|
|
19
|
+
Install as MCP server for AI agents
|
|
20
|
+
hook install --claude Install Claude Code PostToolUse hook
|
|
21
|
+
hook uninstall Remove hooks
|
|
22
|
+
recipe add <name> <cmd> Save a reusable command recipe
|
|
23
|
+
recipe list List saved recipes
|
|
24
|
+
recipe run <name> [--var=X] Run a recipe with variable substitution
|
|
25
|
+
recipe delete <name> Delete a recipe
|
|
26
|
+
collection create <name> Create a recipe collection
|
|
27
|
+
collection list List collections
|
|
28
|
+
project init Initialize project-scoped recipes
|
|
29
|
+
repo Show git repo state (branch + status + log)
|
|
30
|
+
symbols <file> Show file outline (functions, classes, exports)
|
|
31
|
+
stats Show token economy dashboard
|
|
32
|
+
sessions List recent terminal sessions
|
|
33
|
+
sessions stats Show session analytics
|
|
34
|
+
sessions <id> Show session details
|
|
35
|
+
snapshot Capture terminal state as JSON
|
|
36
|
+
--help Show this help
|
|
37
|
+
--version Show version
|
|
38
|
+
|
|
39
|
+
MCP TOOLS (20+):
|
|
40
|
+
execute, execute_smart, execute_diff, expand, browse,
|
|
41
|
+
search_files, search_content, search_semantic, read_file,
|
|
42
|
+
read_symbol, symbols, repo_state, explain_error, status,
|
|
43
|
+
bg_start, bg_stop, bg_status, bg_logs, bg_wait_port,
|
|
44
|
+
list_recipes, run_recipe, save_recipe, list_collections,
|
|
45
|
+
snapshot, token_stats, session_history
|
|
46
|
+
|
|
47
|
+
ENVIRONMENT:
|
|
48
|
+
CEREBRAS_API_KEY Cerebras API key (free, open-source default)
|
|
49
|
+
ANTHROPIC_API_KEY Anthropic API key (Claude models)
|
|
50
|
+
`);
|
|
51
|
+
process.exit(0);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (args[0] === "--version" || args[0] === "-v") {
|
|
55
|
+
console.log("0.6.1");
|
|
56
|
+
process.exit(0);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// ── Exec command — smart execution for agents ────────────────────────────────
|
|
60
|
+
|
|
61
|
+
if (args[0] === "exec") {
|
|
62
|
+
const command = args.slice(1).join(" ");
|
|
63
|
+
if (!command) { console.error("Usage: terminal exec <command>"); process.exit(1); }
|
|
64
|
+
|
|
65
|
+
const { execSync } = await import("child_process");
|
|
66
|
+
const { stripAnsi } = await import("./compression.js");
|
|
67
|
+
const { stripNoise } = await import("./noise-filter.js");
|
|
68
|
+
const { processOutput, shouldProcess } = await import("./output-processor.js");
|
|
69
|
+
const { rewriteCommand } = await import("./command-rewriter.js");
|
|
70
|
+
const { shouldBeLazy, toLazy } = await import("./lazy-executor.js");
|
|
71
|
+
const { estimateTokens } = await import("./parsers/index.js");
|
|
72
|
+
|
|
73
|
+
// Rewrite command if possible
|
|
74
|
+
const rw = rewriteCommand(command);
|
|
75
|
+
const actualCmd = rw.changed ? rw.rewritten : command;
|
|
76
|
+
if (rw.changed) console.error(`[open-terminal] rewritten: ${actualCmd} (${rw.reason})`);
|
|
77
|
+
|
|
78
|
+
try {
|
|
79
|
+
const start = Date.now();
|
|
80
|
+
const raw = execSync(actualCmd, { encoding: "utf8", maxBuffer: 10 * 1024 * 1024, cwd: process.cwd() });
|
|
81
|
+
const duration = Date.now() - start;
|
|
82
|
+
const clean = stripNoise(stripAnsi(raw)).cleaned;
|
|
83
|
+
const rawTokens = estimateTokens(raw);
|
|
84
|
+
|
|
85
|
+
// Lazy mode for huge output
|
|
86
|
+
if (shouldBeLazy(clean)) {
|
|
87
|
+
const lazy = toLazy(clean, actualCmd);
|
|
88
|
+
const savedTokens = rawTokens - estimateTokens(JSON.stringify(lazy));
|
|
89
|
+
console.log(JSON.stringify({ ...lazy, duration, tokensSaved: savedTokens }));
|
|
90
|
+
process.exit(0);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// AI summary for medium-large output
|
|
94
|
+
if (shouldProcess(clean)) {
|
|
95
|
+
const processed = await processOutput(actualCmd, clean);
|
|
96
|
+
if (processed.aiProcessed && processed.tokensSaved > 30) {
|
|
97
|
+
console.log(processed.summary);
|
|
98
|
+
const savedTokens = rawTokens - estimateTokens(processed.summary);
|
|
99
|
+
console.error(`[open-terminal] ${rawTokens} → ${rawTokens - savedTokens} tokens (saved ${savedTokens}, ${Math.round(savedTokens/rawTokens*100)}%)`);
|
|
100
|
+
process.exit(0);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Small/medium output — just noise-strip and return
|
|
105
|
+
console.log(clean);
|
|
106
|
+
const savedTokens = rawTokens - estimateTokens(clean);
|
|
107
|
+
if (savedTokens > 10) {
|
|
108
|
+
console.error(`[open-terminal] saved ${savedTokens} tokens (noise filter)`);
|
|
109
|
+
}
|
|
110
|
+
} catch (e: any) {
|
|
111
|
+
// Command failed — show error output
|
|
112
|
+
const stderr = e.stderr?.toString() ?? "";
|
|
113
|
+
const stdout = e.stdout?.toString() ?? "";
|
|
114
|
+
console.log(stripNoise(stripAnsi(stdout + stderr)).cleaned);
|
|
115
|
+
process.exit(e.status ?? 1);
|
|
116
|
+
}
|
|
117
|
+
process.exit(0);
|
|
118
|
+
}
|
|
119
|
+
|
|
7
120
|
// ── MCP commands ─────────────────────────────────────────────────────────────
|
|
8
121
|
|
|
9
122
|
if (args[0] === "mcp") {
|
package/src/command-rewriter.ts
CHANGED
|
@@ -47,10 +47,10 @@ const rules: RewriteRule[] = [
|
|
|
47
47
|
rewrite: () => "npm ls --depth=0",
|
|
48
48
|
reason: "full tree is massive, top-level usually enough",
|
|
49
49
|
},
|
|
50
|
-
// ps aux without filter →
|
|
50
|
+
// ps aux without filter → sort by memory and head (macOS compatible)
|
|
51
51
|
{
|
|
52
52
|
pattern: /^ps\s+aux\s*$/,
|
|
53
|
-
rewrite: () => "ps aux
|
|
53
|
+
rewrite: () => "ps aux | sort -k4 -rn | head -20",
|
|
54
54
|
reason: "full process list is noise, show top consumers",
|
|
55
55
|
},
|
|
56
56
|
];
|