@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.
- package/dist/App.js +404 -0
- package/dist/Browse.js +79 -0
- package/dist/FuzzyPicker.js +47 -0
- package/dist/Onboarding.js +51 -0
- package/dist/Spinner.js +12 -0
- package/dist/StatusBar.js +49 -0
- package/dist/ai.js +322 -0
- package/dist/cache.js +41 -0
- package/dist/cli.js +64 -16
- package/dist/command-rewriter.js +64 -0
- package/dist/command-validator.js +86 -0
- package/dist/compression.js +107 -0
- package/dist/context-hints.js +275 -0
- package/dist/diff-cache.js +107 -0
- package/dist/discover.js +212 -0
- package/dist/economy.js +123 -0
- package/dist/expand-store.js +38 -0
- package/dist/file-cache.js +72 -0
- package/dist/file-index.js +62 -0
- package/dist/history.js +62 -0
- package/dist/lazy-executor.js +54 -0
- package/dist/line-dedup.js +59 -0
- package/dist/loop-detector.js +75 -0
- package/dist/mcp/install.js +98 -0
- package/dist/mcp/server.js +569 -0
- package/dist/noise-filter.js +86 -0
- package/dist/output-processor.js +129 -0
- package/dist/output-router.js +41 -0
- package/dist/output-store.js +111 -0
- package/dist/parsers/base.js +2 -0
- package/dist/parsers/build.js +64 -0
- package/dist/parsers/errors.js +101 -0
- package/dist/parsers/files.js +78 -0
- package/dist/parsers/git.js +99 -0
- package/dist/parsers/index.js +48 -0
- package/dist/parsers/tests.js +89 -0
- package/dist/providers/anthropic.js +39 -0
- package/dist/providers/base.js +4 -0
- package/dist/providers/cerebras.js +95 -0
- package/dist/providers/groq.js +95 -0
- package/dist/providers/index.js +73 -0
- package/dist/providers/xai.js +95 -0
- package/dist/recipes/model.js +20 -0
- package/dist/recipes/storage.js +136 -0
- package/dist/search/content-search.js +68 -0
- package/dist/search/file-search.js +61 -0
- package/dist/search/filters.js +34 -0
- package/dist/search/index.js +5 -0
- package/dist/search/semantic.js +320 -0
- package/dist/session-boot.js +59 -0
- package/dist/session-context.js +55 -0
- package/dist/sessions-db.js +173 -0
- package/dist/smart-display.js +286 -0
- package/dist/snapshots.js +51 -0
- package/dist/supervisor.js +112 -0
- package/dist/test-watchlist.js +131 -0
- package/dist/tool-profiles.js +122 -0
- package/dist/tree.js +94 -0
- package/dist/usage-cache.js +65 -0
- package/package.json +8 -1
- package/src/ai.ts +8 -0
- package/src/cli.tsx +57 -18
- package/src/output-processor.ts +6 -1
- package/src/output-store.ts +58 -12
- package/src/tool-profiles.ts +139 -0
- package/.claude/scheduled_tasks.lock +0 -1
- package/.github/ISSUE_TEMPLATE/bug_report.md +0 -20
- package/.github/ISSUE_TEMPLATE/feature_request.md +0 -14
- package/CONTRIBUTING.md +0 -80
- package/benchmarks/benchmark.mjs +0 -115
- package/imported_modules.txt +0 -0
- package/temp/rtk/.claude/agents/code-reviewer.md +0 -221
- package/temp/rtk/.claude/agents/debugger.md +0 -519
- package/temp/rtk/.claude/agents/rtk-testing-specialist.md +0 -461
- package/temp/rtk/.claude/agents/rust-rtk.md +0 -511
- package/temp/rtk/.claude/agents/technical-writer.md +0 -355
- package/temp/rtk/.claude/commands/diagnose.md +0 -352
- package/temp/rtk/.claude/commands/test-routing.md +0 -362
- package/temp/rtk/.claude/hooks/bash/pre-commit-format.sh +0 -16
- package/temp/rtk/.claude/hooks/rtk-rewrite.sh +0 -70
- package/temp/rtk/.claude/hooks/rtk-suggest.sh +0 -152
- package/temp/rtk/.claude/rules/cli-testing.md +0 -526
- package/temp/rtk/.claude/skills/issue-triage/SKILL.md +0 -348
- package/temp/rtk/.claude/skills/issue-triage/templates/issue-comment.md +0 -134
- package/temp/rtk/.claude/skills/performance.md +0 -435
- package/temp/rtk/.claude/skills/pr-triage/SKILL.md +0 -315
- package/temp/rtk/.claude/skills/pr-triage/templates/review-comment.md +0 -71
- package/temp/rtk/.claude/skills/repo-recap.md +0 -206
- package/temp/rtk/.claude/skills/rtk-tdd/SKILL.md +0 -78
- package/temp/rtk/.claude/skills/rtk-tdd/references/testing-patterns.md +0 -124
- package/temp/rtk/.claude/skills/security-guardian.md +0 -503
- package/temp/rtk/.claude/skills/ship.md +0 -404
- package/temp/rtk/.github/workflows/benchmark.yml +0 -34
- package/temp/rtk/.github/workflows/dco-check.yaml +0 -12
- package/temp/rtk/.github/workflows/release-please.yml +0 -51
- package/temp/rtk/.github/workflows/release.yml +0 -343
- package/temp/rtk/.github/workflows/security-check.yml +0 -135
- package/temp/rtk/.github/workflows/validate-docs.yml +0 -78
- package/temp/rtk/.release-please-manifest.json +0 -3
- package/temp/rtk/ARCHITECTURE.md +0 -1491
- package/temp/rtk/CHANGELOG.md +0 -640
- package/temp/rtk/CLAUDE.md +0 -605
- package/temp/rtk/CONTRIBUTING.md +0 -199
- package/temp/rtk/Cargo.lock +0 -1668
- package/temp/rtk/Cargo.toml +0 -64
- package/temp/rtk/Formula/rtk.rb +0 -43
- package/temp/rtk/INSTALL.md +0 -390
- package/temp/rtk/LICENSE +0 -21
- package/temp/rtk/README.md +0 -386
- package/temp/rtk/README_es.md +0 -159
- package/temp/rtk/README_fr.md +0 -197
- package/temp/rtk/README_ja.md +0 -159
- package/temp/rtk/README_ko.md +0 -159
- package/temp/rtk/README_zh.md +0 -167
- package/temp/rtk/ROADMAP.md +0 -15
- package/temp/rtk/SECURITY.md +0 -217
- package/temp/rtk/TEST_EXEC_TIME.md +0 -102
- package/temp/rtk/build.rs +0 -57
- package/temp/rtk/docs/AUDIT_GUIDE.md +0 -432
- package/temp/rtk/docs/FEATURES.md +0 -1410
- package/temp/rtk/docs/TROUBLESHOOTING.md +0 -309
- package/temp/rtk/docs/filter-workflow.md +0 -102
- package/temp/rtk/docs/images/gain-dashboard.jpg +0 -0
- package/temp/rtk/docs/tracking.md +0 -583
- package/temp/rtk/hooks/opencode-rtk.ts +0 -39
- package/temp/rtk/hooks/rtk-awareness.md +0 -29
- package/temp/rtk/hooks/rtk-rewrite.sh +0 -61
- package/temp/rtk/hooks/test-rtk-rewrite.sh +0 -442
- package/temp/rtk/install.sh +0 -124
- package/temp/rtk/release-please-config.json +0 -10
- package/temp/rtk/scripts/benchmark.sh +0 -592
- package/temp/rtk/scripts/check-installation.sh +0 -162
- package/temp/rtk/scripts/install-local.sh +0 -37
- package/temp/rtk/scripts/rtk-economics.sh +0 -137
- package/temp/rtk/scripts/test-all.sh +0 -561
- package/temp/rtk/scripts/test-aristote.sh +0 -227
- package/temp/rtk/scripts/test-tracking.sh +0 -79
- package/temp/rtk/scripts/update-readme-metrics.sh +0 -32
- package/temp/rtk/scripts/validate-docs.sh +0 -73
- package/temp/rtk/src/aws_cmd.rs +0 -880
- package/temp/rtk/src/binlog.rs +0 -1645
- package/temp/rtk/src/cargo_cmd.rs +0 -1727
- package/temp/rtk/src/cc_economics.rs +0 -1157
- package/temp/rtk/src/ccusage.rs +0 -340
- package/temp/rtk/src/config.rs +0 -187
- package/temp/rtk/src/container.rs +0 -855
- package/temp/rtk/src/curl_cmd.rs +0 -134
- package/temp/rtk/src/deps.rs +0 -268
- package/temp/rtk/src/diff_cmd.rs +0 -367
- package/temp/rtk/src/discover/mod.rs +0 -274
- package/temp/rtk/src/discover/provider.rs +0 -388
- package/temp/rtk/src/discover/registry.rs +0 -2022
- package/temp/rtk/src/discover/report.rs +0 -202
- package/temp/rtk/src/discover/rules.rs +0 -667
- package/temp/rtk/src/display_helpers.rs +0 -402
- package/temp/rtk/src/dotnet_cmd.rs +0 -1771
- package/temp/rtk/src/dotnet_format_report.rs +0 -133
- package/temp/rtk/src/dotnet_trx.rs +0 -593
- package/temp/rtk/src/env_cmd.rs +0 -204
- package/temp/rtk/src/filter.rs +0 -462
- package/temp/rtk/src/filters/README.md +0 -52
- package/temp/rtk/src/filters/ansible-playbook.toml +0 -34
- package/temp/rtk/src/filters/basedpyright.toml +0 -47
- package/temp/rtk/src/filters/biome.toml +0 -45
- package/temp/rtk/src/filters/brew-install.toml +0 -37
- package/temp/rtk/src/filters/composer-install.toml +0 -40
- package/temp/rtk/src/filters/df.toml +0 -16
- package/temp/rtk/src/filters/dotnet-build.toml +0 -64
- package/temp/rtk/src/filters/du.toml +0 -16
- package/temp/rtk/src/filters/fail2ban-client.toml +0 -15
- package/temp/rtk/src/filters/gcc.toml +0 -49
- package/temp/rtk/src/filters/gcloud.toml +0 -22
- package/temp/rtk/src/filters/hadolint.toml +0 -24
- package/temp/rtk/src/filters/helm.toml +0 -29
- package/temp/rtk/src/filters/iptables.toml +0 -27
- package/temp/rtk/src/filters/jj.toml +0 -28
- package/temp/rtk/src/filters/jq.toml +0 -24
- package/temp/rtk/src/filters/make.toml +0 -41
- package/temp/rtk/src/filters/markdownlint.toml +0 -24
- package/temp/rtk/src/filters/mix-compile.toml +0 -27
- package/temp/rtk/src/filters/mix-format.toml +0 -15
- package/temp/rtk/src/filters/mvn-build.toml +0 -44
- package/temp/rtk/src/filters/oxlint.toml +0 -43
- package/temp/rtk/src/filters/ping.toml +0 -63
- package/temp/rtk/src/filters/pio-run.toml +0 -40
- package/temp/rtk/src/filters/poetry-install.toml +0 -50
- package/temp/rtk/src/filters/pre-commit.toml +0 -35
- package/temp/rtk/src/filters/ps.toml +0 -16
- package/temp/rtk/src/filters/quarto-render.toml +0 -41
- package/temp/rtk/src/filters/rsync.toml +0 -48
- package/temp/rtk/src/filters/shellcheck.toml +0 -27
- package/temp/rtk/src/filters/shopify-theme.toml +0 -29
- package/temp/rtk/src/filters/skopeo.toml +0 -45
- package/temp/rtk/src/filters/sops.toml +0 -16
- package/temp/rtk/src/filters/ssh.toml +0 -44
- package/temp/rtk/src/filters/stat.toml +0 -34
- package/temp/rtk/src/filters/swift-build.toml +0 -41
- package/temp/rtk/src/filters/systemctl-status.toml +0 -33
- package/temp/rtk/src/filters/terraform-plan.toml +0 -35
- package/temp/rtk/src/filters/tofu-fmt.toml +0 -16
- package/temp/rtk/src/filters/tofu-init.toml +0 -38
- package/temp/rtk/src/filters/tofu-plan.toml +0 -35
- package/temp/rtk/src/filters/tofu-validate.toml +0 -17
- package/temp/rtk/src/filters/trunk-build.toml +0 -39
- package/temp/rtk/src/filters/ty.toml +0 -50
- package/temp/rtk/src/filters/uv-sync.toml +0 -37
- package/temp/rtk/src/filters/xcodebuild.toml +0 -99
- package/temp/rtk/src/filters/yamllint.toml +0 -25
- package/temp/rtk/src/find_cmd.rs +0 -598
- package/temp/rtk/src/format_cmd.rs +0 -386
- package/temp/rtk/src/gain.rs +0 -723
- package/temp/rtk/src/gh_cmd.rs +0 -1651
- package/temp/rtk/src/git.rs +0 -2012
- package/temp/rtk/src/go_cmd.rs +0 -592
- package/temp/rtk/src/golangci_cmd.rs +0 -254
- package/temp/rtk/src/grep_cmd.rs +0 -288
- package/temp/rtk/src/gt_cmd.rs +0 -810
- package/temp/rtk/src/hook_audit_cmd.rs +0 -283
- package/temp/rtk/src/hook_check.rs +0 -171
- package/temp/rtk/src/init.rs +0 -1859
- package/temp/rtk/src/integrity.rs +0 -537
- package/temp/rtk/src/json_cmd.rs +0 -231
- package/temp/rtk/src/learn/detector.rs +0 -628
- package/temp/rtk/src/learn/mod.rs +0 -119
- package/temp/rtk/src/learn/report.rs +0 -184
- package/temp/rtk/src/lint_cmd.rs +0 -694
- package/temp/rtk/src/local_llm.rs +0 -316
- package/temp/rtk/src/log_cmd.rs +0 -248
- package/temp/rtk/src/ls.rs +0 -324
- package/temp/rtk/src/main.rs +0 -2482
- package/temp/rtk/src/mypy_cmd.rs +0 -389
- package/temp/rtk/src/next_cmd.rs +0 -241
- package/temp/rtk/src/npm_cmd.rs +0 -236
- package/temp/rtk/src/parser/README.md +0 -267
- package/temp/rtk/src/parser/error.rs +0 -46
- package/temp/rtk/src/parser/formatter.rs +0 -336
- package/temp/rtk/src/parser/mod.rs +0 -311
- package/temp/rtk/src/parser/types.rs +0 -119
- package/temp/rtk/src/pip_cmd.rs +0 -302
- package/temp/rtk/src/playwright_cmd.rs +0 -479
- package/temp/rtk/src/pnpm_cmd.rs +0 -573
- package/temp/rtk/src/prettier_cmd.rs +0 -221
- package/temp/rtk/src/prisma_cmd.rs +0 -482
- package/temp/rtk/src/psql_cmd.rs +0 -382
- package/temp/rtk/src/pytest_cmd.rs +0 -384
- package/temp/rtk/src/read.rs +0 -217
- package/temp/rtk/src/rewrite_cmd.rs +0 -50
- package/temp/rtk/src/ruff_cmd.rs +0 -402
- package/temp/rtk/src/runner.rs +0 -271
- package/temp/rtk/src/summary.rs +0 -297
- package/temp/rtk/src/tee.rs +0 -405
- package/temp/rtk/src/telemetry.rs +0 -248
- package/temp/rtk/src/toml_filter.rs +0 -1655
- package/temp/rtk/src/tracking.rs +0 -1416
- package/temp/rtk/src/tree.rs +0 -209
- package/temp/rtk/src/tsc_cmd.rs +0 -259
- package/temp/rtk/src/utils.rs +0 -432
- package/temp/rtk/src/verify_cmd.rs +0 -47
- package/temp/rtk/src/vitest_cmd.rs +0 -385
- package/temp/rtk/src/wc_cmd.rs +0 -401
- package/temp/rtk/src/wget_cmd.rs +0 -260
- package/temp/rtk/tests/fixtures/dotnet/build_failed.txt +0 -11
- package/temp/rtk/tests/fixtures/dotnet/format_changes.json +0 -31
- package/temp/rtk/tests/fixtures/dotnet/format_empty.json +0 -1
- package/temp/rtk/tests/fixtures/dotnet/format_success.json +0 -12
- package/temp/rtk/tests/fixtures/dotnet/test_failed.txt +0 -18
- package/tsconfig.json +0 -15
package/src/output-store.ts
CHANGED
|
@@ -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.
|
|
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
|
-
/**
|
|
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
|
-
.
|
|
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
|
-
|
|
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 <
|
|
32
|
-
totalSize +=
|
|
33
|
-
if (i >=
|
|
34
|
-
try { unlinkSync(
|
|
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.
|
package/benchmarks/benchmark.mjs
DELETED
|
@@ -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`);
|
package/imported_modules.txt
DELETED
|
File without changes
|