@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 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) {
@@ -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 → add sort and head
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 --sort=-%mem | head -20",
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hasna/terminal",
3
- "version": "0.6.1",
3
+ "version": "0.7.0",
4
4
  "description": "Smart terminal wrapper for AI agents and humans — structured output, token compression, MCP server, natural language",
5
5
  "type": "module",
6
6
  "bin": {
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") {
@@ -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 → add sort and head
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 --sort=-%mem | head -20",
53
+ rewrite: () => "ps aux | sort -k4 -rn | head -20",
54
54
  reason: "full process list is noise, show top consumers",
55
55
  },
56
56
  ];