@hasna/terminal 2.3.0 → 2.3.2

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.
Files changed (267) hide show
  1. package/dist/App.js +404 -0
  2. package/dist/Browse.js +79 -0
  3. package/dist/FuzzyPicker.js +47 -0
  4. package/dist/Onboarding.js +51 -0
  5. package/dist/Spinner.js +12 -0
  6. package/dist/StatusBar.js +49 -0
  7. package/dist/ai.js +322 -0
  8. package/dist/cache.js +41 -0
  9. package/dist/cli.js +64 -16
  10. package/dist/command-rewriter.js +64 -0
  11. package/dist/command-validator.js +86 -0
  12. package/dist/compression.js +107 -0
  13. package/dist/context-hints.js +275 -0
  14. package/dist/diff-cache.js +107 -0
  15. package/dist/discover.js +212 -0
  16. package/dist/economy.js +123 -0
  17. package/dist/expand-store.js +38 -0
  18. package/dist/file-cache.js +72 -0
  19. package/dist/file-index.js +62 -0
  20. package/dist/history.js +62 -0
  21. package/dist/lazy-executor.js +54 -0
  22. package/dist/line-dedup.js +59 -0
  23. package/dist/loop-detector.js +75 -0
  24. package/dist/mcp/install.js +98 -0
  25. package/dist/mcp/server.js +569 -0
  26. package/dist/noise-filter.js +86 -0
  27. package/dist/output-processor.js +129 -0
  28. package/dist/output-router.js +41 -0
  29. package/dist/output-store.js +111 -0
  30. package/dist/parsers/base.js +2 -0
  31. package/dist/parsers/build.js +64 -0
  32. package/dist/parsers/errors.js +101 -0
  33. package/dist/parsers/files.js +78 -0
  34. package/dist/parsers/git.js +99 -0
  35. package/dist/parsers/index.js +48 -0
  36. package/dist/parsers/tests.js +89 -0
  37. package/dist/providers/anthropic.js +39 -0
  38. package/dist/providers/base.js +4 -0
  39. package/dist/providers/cerebras.js +95 -0
  40. package/dist/providers/groq.js +95 -0
  41. package/dist/providers/index.js +73 -0
  42. package/dist/providers/xai.js +95 -0
  43. package/dist/recipes/model.js +20 -0
  44. package/dist/recipes/storage.js +136 -0
  45. package/dist/search/content-search.js +68 -0
  46. package/dist/search/file-search.js +61 -0
  47. package/dist/search/filters.js +34 -0
  48. package/dist/search/index.js +5 -0
  49. package/dist/search/semantic.js +320 -0
  50. package/dist/session-boot.js +59 -0
  51. package/dist/session-context.js +55 -0
  52. package/dist/sessions-db.js +173 -0
  53. package/dist/smart-display.js +286 -0
  54. package/dist/snapshots.js +51 -0
  55. package/dist/supervisor.js +112 -0
  56. package/dist/test-watchlist.js +131 -0
  57. package/dist/tool-profiles.js +122 -0
  58. package/dist/tree.js +94 -0
  59. package/dist/usage-cache.js +65 -0
  60. package/package.json +8 -1
  61. package/src/ai.ts +8 -0
  62. package/src/cli.tsx +57 -18
  63. package/src/output-processor.ts +6 -1
  64. package/src/output-store.ts +58 -12
  65. package/src/tool-profiles.ts +139 -0
  66. package/.claude/scheduled_tasks.lock +0 -1
  67. package/.github/ISSUE_TEMPLATE/bug_report.md +0 -20
  68. package/.github/ISSUE_TEMPLATE/feature_request.md +0 -14
  69. package/CONTRIBUTING.md +0 -80
  70. package/benchmarks/benchmark.mjs +0 -115
  71. package/imported_modules.txt +0 -0
  72. package/temp/rtk/.claude/agents/code-reviewer.md +0 -221
  73. package/temp/rtk/.claude/agents/debugger.md +0 -519
  74. package/temp/rtk/.claude/agents/rtk-testing-specialist.md +0 -461
  75. package/temp/rtk/.claude/agents/rust-rtk.md +0 -511
  76. package/temp/rtk/.claude/agents/technical-writer.md +0 -355
  77. package/temp/rtk/.claude/commands/diagnose.md +0 -352
  78. package/temp/rtk/.claude/commands/test-routing.md +0 -362
  79. package/temp/rtk/.claude/hooks/bash/pre-commit-format.sh +0 -16
  80. package/temp/rtk/.claude/hooks/rtk-rewrite.sh +0 -70
  81. package/temp/rtk/.claude/hooks/rtk-suggest.sh +0 -152
  82. package/temp/rtk/.claude/rules/cli-testing.md +0 -526
  83. package/temp/rtk/.claude/skills/issue-triage/SKILL.md +0 -348
  84. package/temp/rtk/.claude/skills/issue-triage/templates/issue-comment.md +0 -134
  85. package/temp/rtk/.claude/skills/performance.md +0 -435
  86. package/temp/rtk/.claude/skills/pr-triage/SKILL.md +0 -315
  87. package/temp/rtk/.claude/skills/pr-triage/templates/review-comment.md +0 -71
  88. package/temp/rtk/.claude/skills/repo-recap.md +0 -206
  89. package/temp/rtk/.claude/skills/rtk-tdd/SKILL.md +0 -78
  90. package/temp/rtk/.claude/skills/rtk-tdd/references/testing-patterns.md +0 -124
  91. package/temp/rtk/.claude/skills/security-guardian.md +0 -503
  92. package/temp/rtk/.claude/skills/ship.md +0 -404
  93. package/temp/rtk/.github/workflows/benchmark.yml +0 -34
  94. package/temp/rtk/.github/workflows/dco-check.yaml +0 -12
  95. package/temp/rtk/.github/workflows/release-please.yml +0 -51
  96. package/temp/rtk/.github/workflows/release.yml +0 -343
  97. package/temp/rtk/.github/workflows/security-check.yml +0 -135
  98. package/temp/rtk/.github/workflows/validate-docs.yml +0 -78
  99. package/temp/rtk/.release-please-manifest.json +0 -3
  100. package/temp/rtk/ARCHITECTURE.md +0 -1491
  101. package/temp/rtk/CHANGELOG.md +0 -640
  102. package/temp/rtk/CLAUDE.md +0 -605
  103. package/temp/rtk/CONTRIBUTING.md +0 -199
  104. package/temp/rtk/Cargo.lock +0 -1668
  105. package/temp/rtk/Cargo.toml +0 -64
  106. package/temp/rtk/Formula/rtk.rb +0 -43
  107. package/temp/rtk/INSTALL.md +0 -390
  108. package/temp/rtk/LICENSE +0 -21
  109. package/temp/rtk/README.md +0 -386
  110. package/temp/rtk/README_es.md +0 -159
  111. package/temp/rtk/README_fr.md +0 -197
  112. package/temp/rtk/README_ja.md +0 -159
  113. package/temp/rtk/README_ko.md +0 -159
  114. package/temp/rtk/README_zh.md +0 -167
  115. package/temp/rtk/ROADMAP.md +0 -15
  116. package/temp/rtk/SECURITY.md +0 -217
  117. package/temp/rtk/TEST_EXEC_TIME.md +0 -102
  118. package/temp/rtk/build.rs +0 -57
  119. package/temp/rtk/docs/AUDIT_GUIDE.md +0 -432
  120. package/temp/rtk/docs/FEATURES.md +0 -1410
  121. package/temp/rtk/docs/TROUBLESHOOTING.md +0 -309
  122. package/temp/rtk/docs/filter-workflow.md +0 -102
  123. package/temp/rtk/docs/images/gain-dashboard.jpg +0 -0
  124. package/temp/rtk/docs/tracking.md +0 -583
  125. package/temp/rtk/hooks/opencode-rtk.ts +0 -39
  126. package/temp/rtk/hooks/rtk-awareness.md +0 -29
  127. package/temp/rtk/hooks/rtk-rewrite.sh +0 -61
  128. package/temp/rtk/hooks/test-rtk-rewrite.sh +0 -442
  129. package/temp/rtk/install.sh +0 -124
  130. package/temp/rtk/release-please-config.json +0 -10
  131. package/temp/rtk/scripts/benchmark.sh +0 -592
  132. package/temp/rtk/scripts/check-installation.sh +0 -162
  133. package/temp/rtk/scripts/install-local.sh +0 -37
  134. package/temp/rtk/scripts/rtk-economics.sh +0 -137
  135. package/temp/rtk/scripts/test-all.sh +0 -561
  136. package/temp/rtk/scripts/test-aristote.sh +0 -227
  137. package/temp/rtk/scripts/test-tracking.sh +0 -79
  138. package/temp/rtk/scripts/update-readme-metrics.sh +0 -32
  139. package/temp/rtk/scripts/validate-docs.sh +0 -73
  140. package/temp/rtk/src/aws_cmd.rs +0 -880
  141. package/temp/rtk/src/binlog.rs +0 -1645
  142. package/temp/rtk/src/cargo_cmd.rs +0 -1727
  143. package/temp/rtk/src/cc_economics.rs +0 -1157
  144. package/temp/rtk/src/ccusage.rs +0 -340
  145. package/temp/rtk/src/config.rs +0 -187
  146. package/temp/rtk/src/container.rs +0 -855
  147. package/temp/rtk/src/curl_cmd.rs +0 -134
  148. package/temp/rtk/src/deps.rs +0 -268
  149. package/temp/rtk/src/diff_cmd.rs +0 -367
  150. package/temp/rtk/src/discover/mod.rs +0 -274
  151. package/temp/rtk/src/discover/provider.rs +0 -388
  152. package/temp/rtk/src/discover/registry.rs +0 -2022
  153. package/temp/rtk/src/discover/report.rs +0 -202
  154. package/temp/rtk/src/discover/rules.rs +0 -667
  155. package/temp/rtk/src/display_helpers.rs +0 -402
  156. package/temp/rtk/src/dotnet_cmd.rs +0 -1771
  157. package/temp/rtk/src/dotnet_format_report.rs +0 -133
  158. package/temp/rtk/src/dotnet_trx.rs +0 -593
  159. package/temp/rtk/src/env_cmd.rs +0 -204
  160. package/temp/rtk/src/filter.rs +0 -462
  161. package/temp/rtk/src/filters/README.md +0 -52
  162. package/temp/rtk/src/filters/ansible-playbook.toml +0 -34
  163. package/temp/rtk/src/filters/basedpyright.toml +0 -47
  164. package/temp/rtk/src/filters/biome.toml +0 -45
  165. package/temp/rtk/src/filters/brew-install.toml +0 -37
  166. package/temp/rtk/src/filters/composer-install.toml +0 -40
  167. package/temp/rtk/src/filters/df.toml +0 -16
  168. package/temp/rtk/src/filters/dotnet-build.toml +0 -64
  169. package/temp/rtk/src/filters/du.toml +0 -16
  170. package/temp/rtk/src/filters/fail2ban-client.toml +0 -15
  171. package/temp/rtk/src/filters/gcc.toml +0 -49
  172. package/temp/rtk/src/filters/gcloud.toml +0 -22
  173. package/temp/rtk/src/filters/hadolint.toml +0 -24
  174. package/temp/rtk/src/filters/helm.toml +0 -29
  175. package/temp/rtk/src/filters/iptables.toml +0 -27
  176. package/temp/rtk/src/filters/jj.toml +0 -28
  177. package/temp/rtk/src/filters/jq.toml +0 -24
  178. package/temp/rtk/src/filters/make.toml +0 -41
  179. package/temp/rtk/src/filters/markdownlint.toml +0 -24
  180. package/temp/rtk/src/filters/mix-compile.toml +0 -27
  181. package/temp/rtk/src/filters/mix-format.toml +0 -15
  182. package/temp/rtk/src/filters/mvn-build.toml +0 -44
  183. package/temp/rtk/src/filters/oxlint.toml +0 -43
  184. package/temp/rtk/src/filters/ping.toml +0 -63
  185. package/temp/rtk/src/filters/pio-run.toml +0 -40
  186. package/temp/rtk/src/filters/poetry-install.toml +0 -50
  187. package/temp/rtk/src/filters/pre-commit.toml +0 -35
  188. package/temp/rtk/src/filters/ps.toml +0 -16
  189. package/temp/rtk/src/filters/quarto-render.toml +0 -41
  190. package/temp/rtk/src/filters/rsync.toml +0 -48
  191. package/temp/rtk/src/filters/shellcheck.toml +0 -27
  192. package/temp/rtk/src/filters/shopify-theme.toml +0 -29
  193. package/temp/rtk/src/filters/skopeo.toml +0 -45
  194. package/temp/rtk/src/filters/sops.toml +0 -16
  195. package/temp/rtk/src/filters/ssh.toml +0 -44
  196. package/temp/rtk/src/filters/stat.toml +0 -34
  197. package/temp/rtk/src/filters/swift-build.toml +0 -41
  198. package/temp/rtk/src/filters/systemctl-status.toml +0 -33
  199. package/temp/rtk/src/filters/terraform-plan.toml +0 -35
  200. package/temp/rtk/src/filters/tofu-fmt.toml +0 -16
  201. package/temp/rtk/src/filters/tofu-init.toml +0 -38
  202. package/temp/rtk/src/filters/tofu-plan.toml +0 -35
  203. package/temp/rtk/src/filters/tofu-validate.toml +0 -17
  204. package/temp/rtk/src/filters/trunk-build.toml +0 -39
  205. package/temp/rtk/src/filters/ty.toml +0 -50
  206. package/temp/rtk/src/filters/uv-sync.toml +0 -37
  207. package/temp/rtk/src/filters/xcodebuild.toml +0 -99
  208. package/temp/rtk/src/filters/yamllint.toml +0 -25
  209. package/temp/rtk/src/find_cmd.rs +0 -598
  210. package/temp/rtk/src/format_cmd.rs +0 -386
  211. package/temp/rtk/src/gain.rs +0 -723
  212. package/temp/rtk/src/gh_cmd.rs +0 -1651
  213. package/temp/rtk/src/git.rs +0 -2012
  214. package/temp/rtk/src/go_cmd.rs +0 -592
  215. package/temp/rtk/src/golangci_cmd.rs +0 -254
  216. package/temp/rtk/src/grep_cmd.rs +0 -288
  217. package/temp/rtk/src/gt_cmd.rs +0 -810
  218. package/temp/rtk/src/hook_audit_cmd.rs +0 -283
  219. package/temp/rtk/src/hook_check.rs +0 -171
  220. package/temp/rtk/src/init.rs +0 -1859
  221. package/temp/rtk/src/integrity.rs +0 -537
  222. package/temp/rtk/src/json_cmd.rs +0 -231
  223. package/temp/rtk/src/learn/detector.rs +0 -628
  224. package/temp/rtk/src/learn/mod.rs +0 -119
  225. package/temp/rtk/src/learn/report.rs +0 -184
  226. package/temp/rtk/src/lint_cmd.rs +0 -694
  227. package/temp/rtk/src/local_llm.rs +0 -316
  228. package/temp/rtk/src/log_cmd.rs +0 -248
  229. package/temp/rtk/src/ls.rs +0 -324
  230. package/temp/rtk/src/main.rs +0 -2482
  231. package/temp/rtk/src/mypy_cmd.rs +0 -389
  232. package/temp/rtk/src/next_cmd.rs +0 -241
  233. package/temp/rtk/src/npm_cmd.rs +0 -236
  234. package/temp/rtk/src/parser/README.md +0 -267
  235. package/temp/rtk/src/parser/error.rs +0 -46
  236. package/temp/rtk/src/parser/formatter.rs +0 -336
  237. package/temp/rtk/src/parser/mod.rs +0 -311
  238. package/temp/rtk/src/parser/types.rs +0 -119
  239. package/temp/rtk/src/pip_cmd.rs +0 -302
  240. package/temp/rtk/src/playwright_cmd.rs +0 -479
  241. package/temp/rtk/src/pnpm_cmd.rs +0 -573
  242. package/temp/rtk/src/prettier_cmd.rs +0 -221
  243. package/temp/rtk/src/prisma_cmd.rs +0 -482
  244. package/temp/rtk/src/psql_cmd.rs +0 -382
  245. package/temp/rtk/src/pytest_cmd.rs +0 -384
  246. package/temp/rtk/src/read.rs +0 -217
  247. package/temp/rtk/src/rewrite_cmd.rs +0 -50
  248. package/temp/rtk/src/ruff_cmd.rs +0 -402
  249. package/temp/rtk/src/runner.rs +0 -271
  250. package/temp/rtk/src/summary.rs +0 -297
  251. package/temp/rtk/src/tee.rs +0 -405
  252. package/temp/rtk/src/telemetry.rs +0 -248
  253. package/temp/rtk/src/toml_filter.rs +0 -1655
  254. package/temp/rtk/src/tracking.rs +0 -1416
  255. package/temp/rtk/src/tree.rs +0 -209
  256. package/temp/rtk/src/tsc_cmd.rs +0 -259
  257. package/temp/rtk/src/utils.rs +0 -432
  258. package/temp/rtk/src/verify_cmd.rs +0 -47
  259. package/temp/rtk/src/vitest_cmd.rs +0 -385
  260. package/temp/rtk/src/wc_cmd.rs +0 -401
  261. package/temp/rtk/src/wget_cmd.rs +0 -260
  262. package/temp/rtk/tests/fixtures/dotnet/build_failed.txt +0 -11
  263. package/temp/rtk/tests/fixtures/dotnet/format_changes.json +0 -31
  264. package/temp/rtk/tests/fixtures/dotnet/format_empty.json +0 -1
  265. package/temp/rtk/tests/fixtures/dotnet/format_success.json +0 -12
  266. package/temp/rtk/tests/fixtures/dotnet/test_failed.txt +0 -18
  267. package/tsconfig.json +0 -15
@@ -1,13 +1,11 @@
1
1
  // Output store — saves full raw output to disk when AI compresses it
2
- // Agents can read the file for full detail. Rotates to cap disk usage.
2
+ // Agents can read the file for full detail. Tiered retention strategy.
3
3
 
4
4
  import { existsSync, mkdirSync, writeFileSync, readdirSync, statSync, unlinkSync } from "fs";
5
5
  import { join } from "path";
6
6
  import { createHash } from "crypto";
7
7
 
8
8
  const OUTPUTS_DIR = join(process.env.HOME ?? "~", ".terminal", "outputs");
9
- const MAX_FILES = 50;
10
- const MAX_TOTAL_SIZE = 5 * 1024 * 1024; // 5MB
11
9
 
12
10
  /** Ensure outputs directory exists */
13
11
  function ensureDir() {
@@ -19,19 +17,59 @@ function hashOutput(command: string, output: string): string {
19
17
  return createHash("md5").update(command + output.slice(0, 1000)).digest("hex").slice(0, 12);
20
18
  }
21
19
 
22
- /** Rotate old files to stay within limits */
20
+ /** Tiered retention: recent = keep all, older = keep only high-value */
23
21
  function rotate() {
24
22
  try {
23
+ const now = Date.now();
24
+ const ONE_HOUR = 60 * 60 * 1000;
25
+ const ONE_DAY = 24 * ONE_HOUR;
26
+
25
27
  const files = readdirSync(OUTPUTS_DIR)
26
- .map(f => ({ name: f, path: join(OUTPUTS_DIR, f), mtime: statSync(join(OUTPUTS_DIR, f)).mtimeMs, size: statSync(join(OUTPUTS_DIR, f)).size }))
28
+ .filter(f => f.endsWith(".txt"))
29
+ .map(f => {
30
+ const path = join(OUTPUTS_DIR, f);
31
+ const stat = statSync(path);
32
+ return { name: f, path, mtime: stat.mtimeMs, size: stat.size };
33
+ })
27
34
  .sort((a, b) => b.mtime - a.mtime); // newest first
28
35
 
29
- // Remove excess files
36
+ for (const file of files) {
37
+ const age = now - file.mtime;
38
+
39
+ // Last 1 hour: keep everything
40
+ if (age < ONE_HOUR) continue;
41
+
42
+ // Last 24 hours: keep outputs >2KB (meaningful compression)
43
+ if (age < ONE_DAY) {
44
+ if (file.size < 2000) {
45
+ try { unlinkSync(file.path); } catch {}
46
+ }
47
+ continue;
48
+ }
49
+
50
+ // Older than 24h: keep only >10KB (high-value saves)
51
+ if (file.size < 10000) {
52
+ try { unlinkSync(file.path); } catch {}
53
+ continue;
54
+ }
55
+
56
+ // Older than 7 days: remove everything
57
+ if (age > 7 * ONE_DAY) {
58
+ try { unlinkSync(file.path); } catch {}
59
+ }
60
+ }
61
+
62
+ // Hard cap: never exceed 100 files or 10MB total
63
+ const remaining = readdirSync(OUTPUTS_DIR)
64
+ .filter(f => f.endsWith(".txt"))
65
+ .map(f => ({ path: join(OUTPUTS_DIR, f), mtime: statSync(join(OUTPUTS_DIR, f)).mtimeMs, size: statSync(join(OUTPUTS_DIR, f)).size }))
66
+ .sort((a, b) => b.mtime - a.mtime);
67
+
30
68
  let totalSize = 0;
31
- for (let i = 0; i < files.length; i++) {
32
- totalSize += files[i].size;
33
- if (i >= MAX_FILES || totalSize > MAX_TOTAL_SIZE) {
34
- try { unlinkSync(files[i].path); } catch {}
69
+ for (let i = 0; i < remaining.length; i++) {
70
+ totalSize += remaining[i].size;
71
+ if (i >= 100 || totalSize > 10 * 1024 * 1024) {
72
+ try { unlinkSync(remaining[i].path); } catch {}
35
73
  }
36
74
  }
37
75
  } catch {}
@@ -45,12 +83,10 @@ export function saveOutput(command: string, rawOutput: string): string {
45
83
  const filename = `${hash}.txt`;
46
84
  const filepath = join(OUTPUTS_DIR, filename);
47
85
 
48
- // Write with command header
49
86
  const content = `$ ${command}\n${"─".repeat(60)}\n${rawOutput}`;
50
87
  writeFileSync(filepath, content, "utf8");
51
88
 
52
89
  rotate();
53
-
54
90
  return filepath;
55
91
  }
56
92
 
@@ -63,3 +99,13 @@ export function formatOutputHint(filepath: string): string {
63
99
  export function getOutputsDir(): string {
64
100
  return OUTPUTS_DIR;
65
101
  }
102
+
103
+ /** Manually purge all outputs */
104
+ export function purgeOutputs(): number {
105
+ if (!existsSync(OUTPUTS_DIR)) return 0;
106
+ let count = 0;
107
+ for (const f of readdirSync(OUTPUTS_DIR)) {
108
+ try { unlinkSync(join(OUTPUTS_DIR, f)); count++; } catch {}
109
+ }
110
+ return count;
111
+ }
@@ -0,0 +1,139 @@
1
+ // Tool profiles — config-driven AI enhancement for specific command categories
2
+ // Profiles are loaded from ~/.terminal/profiles/ (user-customizable)
3
+ // Each profile tells the AI how to handle a specific tool's output
4
+
5
+ import { existsSync, readFileSync, readdirSync } from "fs";
6
+ import { join } from "path";
7
+
8
+ export interface ToolProfile {
9
+ name: string;
10
+ /** Regex pattern to detect this tool in a command */
11
+ detect: string;
12
+ /** Hints injected into the AI output processor prompt */
13
+ hints: {
14
+ compress?: string; // How to compress this tool's output
15
+ errors?: string; // How to extract errors from this tool
16
+ success?: string; // What success looks like
17
+ };
18
+ /** Output handling */
19
+ output?: {
20
+ maxLines?: number; // Cap output before AI processing
21
+ preservePatterns?: string[]; // Regex patterns to always keep
22
+ stripPatterns?: string[]; // Regex patterns to always remove
23
+ };
24
+ }
25
+
26
+ const PROFILES_DIR = join(process.env.HOME ?? "~", ".terminal", "profiles");
27
+
28
+ /** Built-in profiles — sensible defaults, user can override */
29
+ const BUILTIN_PROFILES: ToolProfile[] = [
30
+ {
31
+ name: "git",
32
+ detect: "^git\\b",
33
+ hints: {
34
+ compress: "For git output: show branch, file counts, insertions/deletions summary. Collapse individual diffs to file-level stats.",
35
+ errors: "Git errors often include a suggested fix (e.g., 'did you mean X?'). Extract the suggestion.",
36
+ success: "Clean working tree, successful push/pull, merge complete.",
37
+ },
38
+ output: { preservePatterns: ["conflict", "CONFLICT", "fatal", "error", "diverged"] },
39
+ },
40
+ {
41
+ name: "test",
42
+ detect: "\\b(bun|npm|yarn|pnpm)\\s+(test|run\\s+test)|\\bpytest\\b|\\bcargo\\s+test\\b|\\bgo\\s+test\\b",
43
+ hints: {
44
+ compress: "For test output: show pass/fail counts FIRST, then list ONLY failing test names with error snippets. Skip passing tests entirely.",
45
+ errors: "Test failures have: test name, expected vs actual, stack trace. Extract all three.",
46
+ success: "All tests passing = one line: '✓ N tests pass, 0 fail'",
47
+ },
48
+ output: { preservePatterns: ["FAIL", "fail", "Error", "✗", "expected", "received"] },
49
+ },
50
+ {
51
+ name: "build",
52
+ detect: "\\b(tsc|bun\\s+run\\s+build|npm\\s+run\\s+build|cargo\\s+build|go\\s+build|make)\\b",
53
+ hints: {
54
+ compress: "For build output: if success with no errors, say '✓ Build succeeded'. If errors, list each error with file:line and message.",
55
+ errors: "Build errors have file:line:column format. Group by file.",
56
+ success: "Empty output or exit 0 = build succeeded.",
57
+ },
58
+ },
59
+ {
60
+ name: "lint",
61
+ detect: "\\b(eslint|biome|ruff|clippy|golangci-lint|prettier|tsc\\s+--noEmit)\\b",
62
+ hints: {
63
+ compress: "For lint output: group violations by rule name, show count per rule, one example per rule. Skip clean files.",
64
+ errors: "Lint violations: file:line rule-name message. Group by rule.",
65
+ },
66
+ output: { maxLines: 100 },
67
+ },
68
+ {
69
+ name: "install",
70
+ detect: "\\b(npm\\s+install|bun\\s+install|yarn|pip\\s+install|cargo\\s+build|go\\s+mod)\\b",
71
+ hints: {
72
+ compress: "For install output: show only errors and final summary (packages added/removed/updated). Strip progress bars, funding notices, deprecation warnings.",
73
+ },
74
+ output: { stripPatterns: ["npm warn", "packages are looking for funding", "run `npm fund`"] },
75
+ },
76
+ {
77
+ name: "find",
78
+ detect: "^find\\b",
79
+ hints: {
80
+ compress: "For find output: if >50 results, group by top-level directory with counts. Show first 10 results as examples.",
81
+ },
82
+ },
83
+ {
84
+ name: "docker",
85
+ detect: "\\b(docker|kubectl|helm)\\b",
86
+ hints: {
87
+ compress: "For container output: show container status, image, ports. Strip pull progress and layer hashes.",
88
+ errors: "Docker errors: extract the error message after 'Error response from daemon:'",
89
+ },
90
+ },
91
+ ];
92
+
93
+ /** Load user profiles from ~/.terminal/profiles/ */
94
+ function loadUserProfiles(): ToolProfile[] {
95
+ if (!existsSync(PROFILES_DIR)) return [];
96
+
97
+ const profiles: ToolProfile[] = [];
98
+ try {
99
+ for (const file of readdirSync(PROFILES_DIR)) {
100
+ if (!file.endsWith(".json")) continue;
101
+ try {
102
+ const content = JSON.parse(readFileSync(join(PROFILES_DIR, file), "utf8"));
103
+ if (content.name && content.detect) profiles.push(content as ToolProfile);
104
+ } catch {}
105
+ }
106
+ } catch {}
107
+ return profiles;
108
+ }
109
+
110
+ /** Get all profiles — user profiles override builtins by name */
111
+ export function getProfiles(): ToolProfile[] {
112
+ const user = loadUserProfiles();
113
+ const userNames = new Set(user.map(p => p.name));
114
+ const builtins = BUILTIN_PROFILES.filter(p => !userNames.has(p.name));
115
+ return [...user, ...builtins];
116
+ }
117
+
118
+ /** Find the matching profile for a command */
119
+ export function matchProfile(command: string): ToolProfile | null {
120
+ for (const profile of getProfiles()) {
121
+ try {
122
+ if (new RegExp(profile.detect).test(command)) return profile;
123
+ } catch {}
124
+ }
125
+ return null;
126
+ }
127
+
128
+ /** Format profile hints for injection into AI prompt */
129
+ export function formatProfileHints(command: string): string {
130
+ const profile = matchProfile(command);
131
+ if (!profile) return "";
132
+
133
+ const lines: string[] = [`TOOL PROFILE (${profile.name}):`];
134
+ if (profile.hints.compress) lines.push(` Compression: ${profile.hints.compress}`);
135
+ if (profile.hints.errors) lines.push(` Errors: ${profile.hints.errors}`);
136
+ if (profile.hints.success) lines.push(` Success: ${profile.hints.success}`);
137
+
138
+ return lines.join("\n");
139
+ }
@@ -1 +0,0 @@
1
- {"sessionId":"c1e414c7-f1a5-4b9e-bcc4-64c451584cb8","pid":1236,"acquiredAt":1773584959902}
@@ -1,20 +0,0 @@
1
- ---
2
- name: Bug Report
3
- about: Report a bug in open-terminal
4
- labels: bug
5
- ---
6
-
7
- **Command:**
8
- `terminal exec "..."`
9
-
10
- **Expected:**
11
- What you expected to happen
12
-
13
- **Actual:**
14
- What actually happened
15
-
16
- **Environment:**
17
- - OS:
18
- - Node/Bun version:
19
- - open-terminal version: (`terminal --version`)
20
- - Provider: Cerebras / Anthropic
@@ -1,14 +0,0 @@
1
- ---
2
- name: Feature Request
3
- about: Suggest a feature for open-terminal
4
- labels: enhancement
5
- ---
6
-
7
- **Use case:**
8
- What problem does this solve?
9
-
10
- **Proposed solution:**
11
- How should it work?
12
-
13
- **Alternatives considered:**
14
- Other approaches you thought about
package/CONTRIBUTING.md DELETED
@@ -1,80 +0,0 @@
1
- # Contributing to open-terminal
2
-
3
- Thanks for your interest in contributing! open-terminal is an open-source smart terminal wrapper that saves AI agents 73-90% of tokens on terminal output.
4
-
5
- ## Development Setup
6
-
7
- ```bash
8
- git clone https://github.com/hasna/terminal.git
9
- cd terminal
10
- npm install
11
- npm run build # TypeScript compilation
12
- bun test # Run tests
13
- ```
14
-
15
- ## Architecture
16
-
17
- ```
18
- src/
19
- cli.tsx # CLI entry point (TUI + subcommands)
20
- ai.ts # NL translation (Cerebras/Anthropic providers)
21
- compression.ts # Token compression engine
22
- noise-filter.ts # Strip noise (npm fund, progress bars, etc.)
23
- command-rewriter.ts # Auto-optimize commands before execution
24
- output-processor.ts # AI-powered output summarization
25
- diff-cache.ts # Diff-aware output caching
26
- smart-display.ts # Visual output compression for TUI
27
- file-cache.ts # Session file read cache
28
- lazy-executor.ts # Lazy execution for large results
29
- expand-store.ts # Progressive disclosure store
30
- economy.ts # Token savings tracker
31
- sessions-db.ts # SQLite session tracking
32
- supervisor.ts # Background process manager
33
- snapshots.ts # Session state snapshots
34
- tree.ts # Tree compression for file listings
35
- mcp/
36
- server.ts # MCP server (20+ tools)
37
- install.ts # MCP installer for Claude/Codex/Gemini
38
- providers/
39
- base.ts # LLM provider interface
40
- anthropic.ts # Anthropic provider
41
- cerebras.ts # Cerebras provider (default)
42
- parsers/ # Structured output parsers
43
- search/ # Smart search (file, content, semantic)
44
- recipes/ # Reusable command templates
45
- ```
46
-
47
- ## How to Contribute
48
-
49
- ### Adding a new parser
50
- Parsers detect and structure specific command output types. See `src/parsers/` for examples. Each parser needs:
51
- - `detect(command, output)` — returns true if this parser can handle the output
52
- - `parse(command, output)` — returns structured data
53
-
54
- ### Adding a command rewrite rule
55
- See `src/command-rewriter.ts`. Add a pattern + rewrite function to the `rules` array.
56
-
57
- ### Adding an MCP tool
58
- See `src/mcp/server.ts`. Register with `server.tool(name, description, schema, handler)`.
59
-
60
- ## Running Tests
61
-
62
- ```bash
63
- bun test # All tests
64
- bun test src/parsers/ # Parser tests only
65
- bun test --coverage # With coverage
66
- ```
67
-
68
- ## Commit Convention
69
-
70
- We use conventional commits:
71
- - `feat:` — new feature
72
- - `fix:` — bug fix
73
- - `refactor:` — code restructuring
74
- - `test:` — adding tests
75
- - `docs:` — documentation
76
- - `chore:` — maintenance
77
-
78
- ## License
79
-
80
- Apache 2.0 — Copyright 2026 Hasna, Inc.
@@ -1,115 +0,0 @@
1
- #!/usr/bin/env bun
2
- // Reproducible benchmark: measures token savings across real commands
3
- // Run: bun benchmarks/benchmark.mjs
4
-
5
- import { compress, stripAnsi } from "../dist/compression.js";
6
- import { parseOutput, estimateTokens, tokenSavings } from "../dist/parsers/index.js";
7
- import { searchContent } from "../dist/search/index.js";
8
- import { diffOutput, clearDiffCache } from "../dist/diff-cache.js";
9
- import { smartDisplay } from "../dist/smart-display.js";
10
- import { stripNoise } from "../dist/noise-filter.js";
11
- import { rewriteCommand } from "../dist/command-rewriter.js";
12
- import { execSync } from "child_process";
13
-
14
- const cwd = process.cwd();
15
- const run = (cmd) => { try { return execSync(cmd, { encoding: "utf8", cwd, maxBuffer: 10*1024*1024 }).trim(); } catch(e) { return e.stdout?.trim() ?? ""; } };
16
-
17
- let totalRaw = 0, totalSaved = 0;
18
- const rows = [];
19
-
20
- function track(name, rawText, compressedText) {
21
- const raw = estimateTokens(rawText);
22
- const comp = estimateTokens(compressedText);
23
- const saved = Math.max(0, raw - comp);
24
- totalRaw += raw;
25
- totalSaved += saved;
26
- rows.push({ name, raw, comp, saved, pct: raw > 0 ? Math.round(saved/raw*100) : 0 });
27
- }
28
-
29
- console.log("open-terminal benchmark — measuring real token savings\n");
30
-
31
- // 1. Noise filter on npm install-like output
32
- const npmSim = "added 847 packages in 12s\n\n143 packages are looking for funding\n run `npm fund` for details\n\nfound 0 vulnerabilities\n";
33
- const npmClean = stripNoise(npmSim).cleaned;
34
- track("npm install (noise filter)", npmSim, npmClean);
35
-
36
- // 2. Command rewriting
37
- const rwTests = [
38
- ["find . -name '*.ts' | grep -v node_modules", "find pipe→filter"],
39
- ["cat package.json | grep name", "cat pipe→grep"],
40
- ["git log", "git log→oneline"],
41
- ["npm ls", "npm ls→depth0"],
42
- ];
43
- for (const [cmd, label] of rwTests) {
44
- const rw = rewriteCommand(cmd);
45
- if (rw.changed) {
46
- const rawOut = run(cmd) || cmd;
47
- const rwOut = run(rw.rewritten) || rw.rewritten;
48
- track(`rewrite: ${label}`, rawOut, rwOut);
49
- }
50
- }
51
-
52
- // 3. Structured parsing
53
- const gitStatus = run("git status");
54
- const gsParsed = parseOutput("git status", gitStatus);
55
- if (gsParsed) track("git status (structured)", gitStatus, JSON.stringify(gsParsed.data));
56
-
57
- const gitLog = run("git log -15");
58
- const glParsed = parseOutput("git log -15", gitLog);
59
- if (glParsed) track("git log -15 (structured)", gitLog, JSON.stringify(glParsed.data));
60
-
61
- // 4. Token budget compression
62
- const bigLs = run("ls -laR src/");
63
- const c1 = compress("ls -laR src/", bigLs, { maxTokens: 150 });
64
- track("ls -laR src/ (budget 150)", bigLs, c1.content);
65
-
66
- // 5. Search overflow guard
67
- const rawGrep = run("grep -rn export src/ | head -200");
68
- const search = await searchContent("export", cwd, { maxResults: 10 });
69
- track("grep export (overflow guard)", rawGrep, JSON.stringify(search));
70
-
71
- // 6. Smart display on paths
72
- const findPng = run("find . -name '*.png' -not -path '*/node_modules/*' 2>/dev/null | head -50");
73
- if (findPng) {
74
- const display = smartDisplay(findPng.split("\n"));
75
- track("find *.png (smart display)", findPng, display.join("\n"));
76
- }
77
-
78
- // 7. Diff caching (identical re-run)
79
- clearDiffCache();
80
- const testOut = run("bun test 2>&1");
81
- diffOutput("bun test", cwd, testOut);
82
- const d2 = diffOutput("bun test", cwd, testOut);
83
- track("bun test (identical re-run)", testOut, d2.diffSummary);
84
-
85
- // 8. Diff caching (fuzzy — simulated 95% similar)
86
- clearDiffCache();
87
- const testA = "PASS test1\nPASS test2\nPASS test3\nPASS test4\nPASS test5\nPASS test6\nPASS test7\nPASS test8\nPASS test9\nFAIL test10\nTests: 9 passed, 1 failed";
88
- const testB = "PASS test1\nPASS test2\nPASS test3\nPASS test4\nPASS test5\nPASS test6\nPASS test7\nPASS test8\nPASS test9\nPASS test10\nTests: 10 passed, 0 failed";
89
- diffOutput("test", "/tmp", testA);
90
- const fuzzyDiff = diffOutput("test", "/tmp", testB);
91
- track("test (fuzzy diff, 1 change)", testA, fuzzyDiff.added.join("\n") + "\n" + fuzzyDiff.removed.join("\n"));
92
-
93
- // 9. Budget compression on large ls
94
- const bigLs2 = run("ls -laR . 2>/dev/null | head -300");
95
- const c2 = compress("ls -laR .", bigLs2, { maxTokens: 100 });
96
- track("ls -laR . (budget 100, 300 lines)", bigLs2, c2.content);
97
-
98
- // Print results
99
- console.log("┌─────────────────────────────────────────────┬──────┬──────┬───────┬──────┐");
100
- console.log("│ Scenario │ Raw │ Comp │ Saved │ % │");
101
- console.log("├─────────────────────────────────────────────┼──────┼──────┼───────┼──────┤");
102
- for (const r of rows) {
103
- console.log("│ " + r.name.padEnd(43) + " │ " + String(r.raw).padStart(4) + " │ " + String(r.comp).padStart(4) + " │ " + String(r.saved).padStart(5) + " │ " + (r.pct + "%").padStart(4) + " │");
104
- }
105
- console.log("├─────────────────────────────────────────────┼──────┼──────┼───────┼──────┤");
106
- const pct = Math.round(totalSaved/totalRaw*100);
107
- console.log("│ " + "TOTAL".padEnd(43) + " │ " + String(totalRaw).padStart(4) + " │ " + String(totalRaw-totalSaved).padStart(4) + " │ " + String(totalSaved).padStart(5) + " │ " + (pct + "%").padStart(4) + " │");
108
- console.log("└─────────────────────────────────────────────┴──────┴──────┴───────┴──────┘");
109
-
110
- // Cost analysis
111
- const sonnetRate = 3.0;
112
- const cerebrasInputRate = 0.60;
113
- const savingsUsd = totalSaved * sonnetRate / 1_000_000;
114
- console.log(`\nAt Claude Sonnet $3/M: ${totalSaved} tokens saved = $${savingsUsd.toFixed(6)}`);
115
- console.log(`At 500 commands/day: ~$${(savingsUsd * 50).toFixed(2)}/day, $${(savingsUsd * 50 * 30).toFixed(0)}/month saved`);
File without changes