@hasna/terminal 2.0.5 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (263) hide show
  1. package/dist/cli.js +52 -21
  2. package/package.json +1 -1
  3. package/src/ai.ts +77 -130
  4. package/src/cli.tsx +51 -21
  5. package/src/command-validator.ts +11 -0
  6. package/src/context-hints.ts +291 -0
  7. package/src/discover.ts +238 -0
  8. package/src/economy.ts +53 -0
  9. package/src/output-processor.ts +7 -18
  10. package/src/output-store.ts +65 -0
  11. package/src/providers/base.ts +3 -1
  12. package/src/providers/groq.ts +108 -0
  13. package/src/providers/index.ts +26 -2
  14. package/src/providers/providers.test.ts +4 -2
  15. package/src/providers/xai.ts +108 -0
  16. package/src/sessions-db.ts +81 -0
  17. package/temp/rtk/.claude/agents/code-reviewer.md +221 -0
  18. package/temp/rtk/.claude/agents/debugger.md +519 -0
  19. package/temp/rtk/.claude/agents/rtk-testing-specialist.md +461 -0
  20. package/temp/rtk/.claude/agents/rust-rtk.md +511 -0
  21. package/temp/rtk/.claude/agents/technical-writer.md +355 -0
  22. package/temp/rtk/.claude/commands/diagnose.md +352 -0
  23. package/temp/rtk/.claude/commands/test-routing.md +362 -0
  24. package/temp/rtk/.claude/hooks/bash/pre-commit-format.sh +16 -0
  25. package/temp/rtk/.claude/hooks/rtk-rewrite.sh +70 -0
  26. package/temp/rtk/.claude/hooks/rtk-suggest.sh +152 -0
  27. package/temp/rtk/.claude/rules/cli-testing.md +526 -0
  28. package/temp/rtk/.claude/skills/issue-triage/SKILL.md +348 -0
  29. package/temp/rtk/.claude/skills/issue-triage/templates/issue-comment.md +134 -0
  30. package/temp/rtk/.claude/skills/performance.md +435 -0
  31. package/temp/rtk/.claude/skills/pr-triage/SKILL.md +315 -0
  32. package/temp/rtk/.claude/skills/pr-triage/templates/review-comment.md +71 -0
  33. package/temp/rtk/.claude/skills/repo-recap.md +206 -0
  34. package/temp/rtk/.claude/skills/rtk-tdd/SKILL.md +78 -0
  35. package/temp/rtk/.claude/skills/rtk-tdd/references/testing-patterns.md +124 -0
  36. package/temp/rtk/.claude/skills/security-guardian.md +503 -0
  37. package/temp/rtk/.claude/skills/ship.md +404 -0
  38. package/temp/rtk/.github/workflows/benchmark.yml +34 -0
  39. package/temp/rtk/.github/workflows/dco-check.yaml +12 -0
  40. package/temp/rtk/.github/workflows/release-please.yml +51 -0
  41. package/temp/rtk/.github/workflows/release.yml +343 -0
  42. package/temp/rtk/.github/workflows/security-check.yml +135 -0
  43. package/temp/rtk/.github/workflows/validate-docs.yml +78 -0
  44. package/temp/rtk/.release-please-manifest.json +3 -0
  45. package/temp/rtk/ARCHITECTURE.md +1491 -0
  46. package/temp/rtk/CHANGELOG.md +640 -0
  47. package/temp/rtk/CLAUDE.md +605 -0
  48. package/temp/rtk/CONTRIBUTING.md +199 -0
  49. package/temp/rtk/Cargo.lock +1668 -0
  50. package/temp/rtk/Cargo.toml +64 -0
  51. package/temp/rtk/Formula/rtk.rb +43 -0
  52. package/temp/rtk/INSTALL.md +390 -0
  53. package/temp/rtk/LICENSE +21 -0
  54. package/temp/rtk/README.md +386 -0
  55. package/temp/rtk/README_es.md +159 -0
  56. package/temp/rtk/README_fr.md +197 -0
  57. package/temp/rtk/README_ja.md +159 -0
  58. package/temp/rtk/README_ko.md +159 -0
  59. package/temp/rtk/README_zh.md +167 -0
  60. package/temp/rtk/ROADMAP.md +15 -0
  61. package/temp/rtk/SECURITY.md +217 -0
  62. package/temp/rtk/TEST_EXEC_TIME.md +102 -0
  63. package/temp/rtk/build.rs +57 -0
  64. package/temp/rtk/docs/AUDIT_GUIDE.md +432 -0
  65. package/temp/rtk/docs/FEATURES.md +1410 -0
  66. package/temp/rtk/docs/TROUBLESHOOTING.md +309 -0
  67. package/temp/rtk/docs/filter-workflow.md +102 -0
  68. package/temp/rtk/docs/images/gain-dashboard.jpg +0 -0
  69. package/temp/rtk/docs/tracking.md +583 -0
  70. package/temp/rtk/hooks/opencode-rtk.ts +39 -0
  71. package/temp/rtk/hooks/rtk-awareness.md +29 -0
  72. package/temp/rtk/hooks/rtk-rewrite.sh +61 -0
  73. package/temp/rtk/hooks/test-rtk-rewrite.sh +442 -0
  74. package/temp/rtk/install.sh +124 -0
  75. package/temp/rtk/release-please-config.json +10 -0
  76. package/temp/rtk/scripts/benchmark.sh +592 -0
  77. package/temp/rtk/scripts/check-installation.sh +162 -0
  78. package/temp/rtk/scripts/install-local.sh +37 -0
  79. package/temp/rtk/scripts/rtk-economics.sh +137 -0
  80. package/temp/rtk/scripts/test-all.sh +561 -0
  81. package/temp/rtk/scripts/test-aristote.sh +227 -0
  82. package/temp/rtk/scripts/test-tracking.sh +79 -0
  83. package/temp/rtk/scripts/update-readme-metrics.sh +32 -0
  84. package/temp/rtk/scripts/validate-docs.sh +73 -0
  85. package/temp/rtk/src/aws_cmd.rs +880 -0
  86. package/temp/rtk/src/binlog.rs +1645 -0
  87. package/temp/rtk/src/cargo_cmd.rs +1727 -0
  88. package/temp/rtk/src/cc_economics.rs +1157 -0
  89. package/temp/rtk/src/ccusage.rs +340 -0
  90. package/temp/rtk/src/config.rs +187 -0
  91. package/temp/rtk/src/container.rs +855 -0
  92. package/temp/rtk/src/curl_cmd.rs +134 -0
  93. package/temp/rtk/src/deps.rs +268 -0
  94. package/temp/rtk/src/diff_cmd.rs +367 -0
  95. package/temp/rtk/src/discover/mod.rs +274 -0
  96. package/temp/rtk/src/discover/provider.rs +388 -0
  97. package/temp/rtk/src/discover/registry.rs +2022 -0
  98. package/temp/rtk/src/discover/report.rs +202 -0
  99. package/temp/rtk/src/discover/rules.rs +667 -0
  100. package/temp/rtk/src/display_helpers.rs +402 -0
  101. package/temp/rtk/src/dotnet_cmd.rs +1771 -0
  102. package/temp/rtk/src/dotnet_format_report.rs +133 -0
  103. package/temp/rtk/src/dotnet_trx.rs +593 -0
  104. package/temp/rtk/src/env_cmd.rs +204 -0
  105. package/temp/rtk/src/filter.rs +462 -0
  106. package/temp/rtk/src/filters/README.md +52 -0
  107. package/temp/rtk/src/filters/ansible-playbook.toml +34 -0
  108. package/temp/rtk/src/filters/basedpyright.toml +47 -0
  109. package/temp/rtk/src/filters/biome.toml +45 -0
  110. package/temp/rtk/src/filters/brew-install.toml +37 -0
  111. package/temp/rtk/src/filters/composer-install.toml +40 -0
  112. package/temp/rtk/src/filters/df.toml +16 -0
  113. package/temp/rtk/src/filters/dotnet-build.toml +64 -0
  114. package/temp/rtk/src/filters/du.toml +16 -0
  115. package/temp/rtk/src/filters/fail2ban-client.toml +15 -0
  116. package/temp/rtk/src/filters/gcc.toml +49 -0
  117. package/temp/rtk/src/filters/gcloud.toml +22 -0
  118. package/temp/rtk/src/filters/hadolint.toml +24 -0
  119. package/temp/rtk/src/filters/helm.toml +29 -0
  120. package/temp/rtk/src/filters/iptables.toml +27 -0
  121. package/temp/rtk/src/filters/jj.toml +28 -0
  122. package/temp/rtk/src/filters/jq.toml +24 -0
  123. package/temp/rtk/src/filters/make.toml +41 -0
  124. package/temp/rtk/src/filters/markdownlint.toml +24 -0
  125. package/temp/rtk/src/filters/mix-compile.toml +27 -0
  126. package/temp/rtk/src/filters/mix-format.toml +15 -0
  127. package/temp/rtk/src/filters/mvn-build.toml +44 -0
  128. package/temp/rtk/src/filters/oxlint.toml +43 -0
  129. package/temp/rtk/src/filters/ping.toml +63 -0
  130. package/temp/rtk/src/filters/pio-run.toml +40 -0
  131. package/temp/rtk/src/filters/poetry-install.toml +50 -0
  132. package/temp/rtk/src/filters/pre-commit.toml +35 -0
  133. package/temp/rtk/src/filters/ps.toml +16 -0
  134. package/temp/rtk/src/filters/quarto-render.toml +41 -0
  135. package/temp/rtk/src/filters/rsync.toml +48 -0
  136. package/temp/rtk/src/filters/shellcheck.toml +27 -0
  137. package/temp/rtk/src/filters/shopify-theme.toml +29 -0
  138. package/temp/rtk/src/filters/skopeo.toml +45 -0
  139. package/temp/rtk/src/filters/sops.toml +16 -0
  140. package/temp/rtk/src/filters/ssh.toml +44 -0
  141. package/temp/rtk/src/filters/stat.toml +34 -0
  142. package/temp/rtk/src/filters/swift-build.toml +41 -0
  143. package/temp/rtk/src/filters/systemctl-status.toml +33 -0
  144. package/temp/rtk/src/filters/terraform-plan.toml +35 -0
  145. package/temp/rtk/src/filters/tofu-fmt.toml +16 -0
  146. package/temp/rtk/src/filters/tofu-init.toml +38 -0
  147. package/temp/rtk/src/filters/tofu-plan.toml +35 -0
  148. package/temp/rtk/src/filters/tofu-validate.toml +17 -0
  149. package/temp/rtk/src/filters/trunk-build.toml +39 -0
  150. package/temp/rtk/src/filters/ty.toml +50 -0
  151. package/temp/rtk/src/filters/uv-sync.toml +37 -0
  152. package/temp/rtk/src/filters/xcodebuild.toml +99 -0
  153. package/temp/rtk/src/filters/yamllint.toml +25 -0
  154. package/temp/rtk/src/find_cmd.rs +598 -0
  155. package/temp/rtk/src/format_cmd.rs +386 -0
  156. package/temp/rtk/src/gain.rs +723 -0
  157. package/temp/rtk/src/gh_cmd.rs +1651 -0
  158. package/temp/rtk/src/git.rs +2012 -0
  159. package/temp/rtk/src/go_cmd.rs +592 -0
  160. package/temp/rtk/src/golangci_cmd.rs +254 -0
  161. package/temp/rtk/src/grep_cmd.rs +288 -0
  162. package/temp/rtk/src/gt_cmd.rs +810 -0
  163. package/temp/rtk/src/hook_audit_cmd.rs +283 -0
  164. package/temp/rtk/src/hook_check.rs +171 -0
  165. package/temp/rtk/src/init.rs +1859 -0
  166. package/temp/rtk/src/integrity.rs +537 -0
  167. package/temp/rtk/src/json_cmd.rs +231 -0
  168. package/temp/rtk/src/learn/detector.rs +628 -0
  169. package/temp/rtk/src/learn/mod.rs +119 -0
  170. package/temp/rtk/src/learn/report.rs +184 -0
  171. package/temp/rtk/src/lint_cmd.rs +694 -0
  172. package/temp/rtk/src/local_llm.rs +316 -0
  173. package/temp/rtk/src/log_cmd.rs +248 -0
  174. package/temp/rtk/src/ls.rs +324 -0
  175. package/temp/rtk/src/main.rs +2482 -0
  176. package/temp/rtk/src/mypy_cmd.rs +389 -0
  177. package/temp/rtk/src/next_cmd.rs +241 -0
  178. package/temp/rtk/src/npm_cmd.rs +236 -0
  179. package/temp/rtk/src/parser/README.md +267 -0
  180. package/temp/rtk/src/parser/error.rs +46 -0
  181. package/temp/rtk/src/parser/formatter.rs +336 -0
  182. package/temp/rtk/src/parser/mod.rs +311 -0
  183. package/temp/rtk/src/parser/types.rs +119 -0
  184. package/temp/rtk/src/pip_cmd.rs +302 -0
  185. package/temp/rtk/src/playwright_cmd.rs +479 -0
  186. package/temp/rtk/src/pnpm_cmd.rs +573 -0
  187. package/temp/rtk/src/prettier_cmd.rs +221 -0
  188. package/temp/rtk/src/prisma_cmd.rs +482 -0
  189. package/temp/rtk/src/psql_cmd.rs +382 -0
  190. package/temp/rtk/src/pytest_cmd.rs +384 -0
  191. package/temp/rtk/src/read.rs +217 -0
  192. package/temp/rtk/src/rewrite_cmd.rs +50 -0
  193. package/temp/rtk/src/ruff_cmd.rs +402 -0
  194. package/temp/rtk/src/runner.rs +271 -0
  195. package/temp/rtk/src/summary.rs +297 -0
  196. package/temp/rtk/src/tee.rs +405 -0
  197. package/temp/rtk/src/telemetry.rs +248 -0
  198. package/temp/rtk/src/toml_filter.rs +1655 -0
  199. package/temp/rtk/src/tracking.rs +1416 -0
  200. package/temp/rtk/src/tree.rs +209 -0
  201. package/temp/rtk/src/tsc_cmd.rs +259 -0
  202. package/temp/rtk/src/utils.rs +432 -0
  203. package/temp/rtk/src/verify_cmd.rs +47 -0
  204. package/temp/rtk/src/vitest_cmd.rs +385 -0
  205. package/temp/rtk/src/wc_cmd.rs +401 -0
  206. package/temp/rtk/src/wget_cmd.rs +260 -0
  207. package/temp/rtk/tests/fixtures/dotnet/build_failed.txt +11 -0
  208. package/temp/rtk/tests/fixtures/dotnet/format_changes.json +31 -0
  209. package/temp/rtk/tests/fixtures/dotnet/format_empty.json +1 -0
  210. package/temp/rtk/tests/fixtures/dotnet/format_success.json +12 -0
  211. package/temp/rtk/tests/fixtures/dotnet/test_failed.txt +18 -0
  212. package/dist/App.js +0 -404
  213. package/dist/Browse.js +0 -79
  214. package/dist/FuzzyPicker.js +0 -47
  215. package/dist/Onboarding.js +0 -51
  216. package/dist/Spinner.js +0 -12
  217. package/dist/StatusBar.js +0 -49
  218. package/dist/ai.js +0 -368
  219. package/dist/cache.js +0 -41
  220. package/dist/command-rewriter.js +0 -64
  221. package/dist/command-validator.js +0 -77
  222. package/dist/compression.js +0 -107
  223. package/dist/diff-cache.js +0 -107
  224. package/dist/economy.js +0 -79
  225. package/dist/expand-store.js +0 -38
  226. package/dist/file-cache.js +0 -72
  227. package/dist/file-index.js +0 -62
  228. package/dist/history.js +0 -62
  229. package/dist/lazy-executor.js +0 -54
  230. package/dist/line-dedup.js +0 -59
  231. package/dist/loop-detector.js +0 -75
  232. package/dist/mcp/install.js +0 -98
  233. package/dist/mcp/server.js +0 -569
  234. package/dist/noise-filter.js +0 -86
  235. package/dist/output-processor.js +0 -136
  236. package/dist/output-router.js +0 -41
  237. package/dist/parsers/base.js +0 -2
  238. package/dist/parsers/build.js +0 -64
  239. package/dist/parsers/errors.js +0 -101
  240. package/dist/parsers/files.js +0 -78
  241. package/dist/parsers/git.js +0 -99
  242. package/dist/parsers/index.js +0 -48
  243. package/dist/parsers/tests.js +0 -89
  244. package/dist/providers/anthropic.js +0 -39
  245. package/dist/providers/base.js +0 -4
  246. package/dist/providers/cerebras.js +0 -95
  247. package/dist/providers/index.js +0 -49
  248. package/dist/recipes/model.js +0 -20
  249. package/dist/recipes/storage.js +0 -136
  250. package/dist/search/content-search.js +0 -68
  251. package/dist/search/file-search.js +0 -61
  252. package/dist/search/filters.js +0 -34
  253. package/dist/search/index.js +0 -5
  254. package/dist/search/semantic.js +0 -320
  255. package/dist/session-boot.js +0 -59
  256. package/dist/session-context.js +0 -55
  257. package/dist/sessions-db.js +0 -120
  258. package/dist/smart-display.js +0 -286
  259. package/dist/snapshots.js +0 -51
  260. package/dist/supervisor.js +0 -112
  261. package/dist/test-watchlist.js +0 -131
  262. package/dist/tree.js +0 -94
  263. package/dist/usage-cache.js +0 -65
@@ -1,286 +0,0 @@
1
- // Smart output display — compress repetitive output into grouped patterns
2
- import { dirname, basename } from "path";
3
- /** Detect if lines look like file paths */
4
- function looksLikePaths(lines) {
5
- if (lines.length < 3)
6
- return false;
7
- const pathLike = lines.filter(l => l.trim().match(/^\.?\//) || l.trim().includes("/"));
8
- return pathLike.length > lines.length * 0.6;
9
- }
10
- /** Find the varying part between similar strings and create a glob pattern */
11
- function findPattern(items) {
12
- if (items.length < 2)
13
- return null;
14
- const first = items[0];
15
- const last = items[items.length - 1];
16
- // Find common prefix
17
- let prefixLen = 0;
18
- while (prefixLen < first.length && prefixLen < last.length && first[prefixLen] === last[prefixLen]) {
19
- prefixLen++;
20
- }
21
- // Find common suffix
22
- let suffixLen = 0;
23
- while (suffixLen < first.length - prefixLen &&
24
- suffixLen < last.length - prefixLen &&
25
- first[first.length - 1 - suffixLen] === last[last.length - 1 - suffixLen]) {
26
- suffixLen++;
27
- }
28
- const prefix = first.slice(0, prefixLen);
29
- const suffix = suffixLen > 0 ? first.slice(-suffixLen) : "";
30
- if (prefix.length + suffix.length < first.length * 0.3)
31
- return null; // too different
32
- return `${prefix}*${suffix}`;
33
- }
34
- /** Group file paths by directory */
35
- function groupByDir(paths) {
36
- const groups = new Map();
37
- for (const p of paths) {
38
- const dir = dirname(p.trim());
39
- const file = basename(p.trim());
40
- if (!groups.has(dir))
41
- groups.set(dir, []);
42
- groups.get(dir).push(file);
43
- }
44
- return groups;
45
- }
46
- /** Detect duplicate filenames across directories */
47
- function findDuplicates(paths) {
48
- const byName = new Map();
49
- for (const p of paths) {
50
- const file = basename(p.trim());
51
- if (!byName.has(file))
52
- byName.set(file, []);
53
- byName.get(file).push(dirname(p.trim()));
54
- }
55
- // Only return files that appear in 2+ dirs
56
- const dupes = new Map();
57
- for (const [file, dirs] of byName) {
58
- if (dirs.length >= 2)
59
- dupes.set(file, dirs);
60
- }
61
- return dupes;
62
- }
63
- /** Collapse node_modules paths */
64
- function collapseNodeModules(paths) {
65
- const nodeModulesPaths = [];
66
- const otherPaths = [];
67
- for (const p of paths) {
68
- if (p.includes("node_modules")) {
69
- nodeModulesPaths.push(p);
70
- }
71
- else {
72
- otherPaths.push(p);
73
- }
74
- }
75
- return { nodeModulesPaths, otherPaths };
76
- }
77
- /** Smart display: compress file path output into grouped patterns */
78
- export function smartDisplay(lines) {
79
- if (lines.length <= 5)
80
- return lines;
81
- // Try ls -la table compression first
82
- const lsCompressed = compressLsTable(lines);
83
- if (lsCompressed)
84
- return lsCompressed;
85
- if (!looksLikePaths(lines))
86
- return compressGeneric(lines);
87
- const paths = lines.map(l => l.trim()).filter(l => l);
88
- const result = [];
89
- // Step 1: Separate node_modules
90
- const { nodeModulesPaths, otherPaths } = collapseNodeModules(paths);
91
- // Step 2: Find duplicates in non-node_modules paths
92
- const dupes = findDuplicates(otherPaths);
93
- const handledPaths = new Set();
94
- // Show duplicates first
95
- for (const [file, dirs] of dupes) {
96
- if (dirs.length >= 3) {
97
- result.push(` **/${file} ×${dirs.length}`);
98
- result.push(` ${dirs.slice(0, 5).join(", ")}${dirs.length > 5 ? ` +${dirs.length - 5} more` : ""}`);
99
- for (const d of dirs) {
100
- handledPaths.add(`${d}/${file}`);
101
- }
102
- }
103
- }
104
- // Step 3: Group remaining by directory
105
- const remaining = otherPaths.filter(p => !handledPaths.has(p.trim()));
106
- const dirGroups = groupByDir(remaining);
107
- for (const [dir, files] of dirGroups) {
108
- if (files.length === 1) {
109
- result.push(` ${dir}/${files[0]}`);
110
- }
111
- else if (files.length <= 3) {
112
- result.push(` ${dir}/`);
113
- for (const f of files)
114
- result.push(` ${f}`);
115
- }
116
- else {
117
- // Try to find a pattern
118
- const sorted = files.sort();
119
- const pattern = findPattern(sorted);
120
- if (pattern) {
121
- const dateRange = collapseDateRange(sorted);
122
- const rangeStr = dateRange ? ` (${dateRange})` : "";
123
- result.push(` ${dir}/${pattern} ×${files.length}${rangeStr}`);
124
- }
125
- else {
126
- result.push(` ${dir}/ (${files.length} files)`);
127
- // Show first 2 + count
128
- result.push(` ${sorted[0]}, ${sorted[1]}${files.length > 2 ? `, +${files.length - 2} more` : ""}`);
129
- }
130
- }
131
- }
132
- // Step 4: Collapsed node_modules summary
133
- if (nodeModulesPaths.length > 0) {
134
- if (nodeModulesPaths.length <= 2) {
135
- for (const p of nodeModulesPaths)
136
- result.push(` ${p}`);
137
- }
138
- else {
139
- // Group node_modules by package name
140
- const nmGroups = new Map();
141
- for (const p of nodeModulesPaths) {
142
- // Extract package name from path: ./X/node_modules/PKG/...
143
- const match = p.match(/node_modules\/(@[^/]+\/[^/]+|[^/]+)/);
144
- const pkg = match ? match[1] : "other";
145
- nmGroups.set(pkg, (nmGroups.get(pkg) ?? 0) + 1);
146
- }
147
- result.push(` node_modules/ (${nodeModulesPaths.length} matches)`);
148
- const topPkgs = [...nmGroups.entries()].sort((a, b) => b[1] - a[1]).slice(0, 3);
149
- for (const [pkg, count] of topPkgs) {
150
- result.push(` ${pkg} ×${count}`);
151
- }
152
- if (nmGroups.size > 3) {
153
- result.push(` +${nmGroups.size - 3} more packages`);
154
- }
155
- }
156
- }
157
- return result;
158
- }
159
- /** Detect date range in timestamps and collapse */
160
- function collapseDateRange(files) {
161
- const timestamps = [];
162
- for (const f of files) {
163
- const match = f.match(/(\d{4})-(\d{2})-(\d{2})T?(\d{2})?/);
164
- if (match) {
165
- const [, y, m, d, h] = match;
166
- timestamps.push(new Date(`${y}-${m}-${d}T${h ?? "00"}:00:00`));
167
- }
168
- }
169
- if (timestamps.length < 2)
170
- return null;
171
- timestamps.sort((a, b) => a.getTime() - b.getTime());
172
- const first = timestamps[0];
173
- const last = timestamps[timestamps.length - 1];
174
- const fmt = (d) => `${d.getMonth() + 1}/${d.getDate()}`;
175
- if (first.toDateString() === last.toDateString()) {
176
- return `${fmt(first)}`;
177
- }
178
- return `${fmt(first)}–${fmt(last)}`;
179
- }
180
- /** Detect and compress ls -la style table output */
181
- function compressLsTable(lines) {
182
- // Detect ls -la format: permissions size date name
183
- const lsPattern = /^[dlcbps-][rwxsStT-]{9}\s+\d+\s+\S+\s+\S+\s+\S+\s+\w+\s+\d+\s+[\d:]+\s+.+$/;
184
- const isLsOutput = lines.filter(l => lsPattern.test(l.trim())).length > lines.length * 0.5;
185
- if (!isLsOutput)
186
- return null;
187
- const result = [];
188
- const dirs = [];
189
- const files = [];
190
- let totalSize = 0;
191
- for (const line of lines) {
192
- const match = line.trim().match(/^([dlcbps-])[rwxsStT-]{9}\s+\d+\s+\S+\s+\S+\s+(\S+)\s+\w+\s+\d+\s+[\d:]+\s+(.+)$/);
193
- if (!match) {
194
- if (line.trim().startsWith("total "))
195
- continue;
196
- result.push(line);
197
- continue;
198
- }
199
- const [, type, sizeStr, name] = match;
200
- const size = parseInt(sizeStr) || 0;
201
- totalSize += size;
202
- if (type === "d") {
203
- dirs.push(name);
204
- }
205
- else {
206
- files.push({ name, size: formatSize(size) });
207
- }
208
- }
209
- // Compact display
210
- if (dirs.length > 0) {
211
- result.push(` 📁 ${dirs.join(" ")}${dirs.length > 5 ? ` (+${dirs.length - 5} more)` : ""}`);
212
- }
213
- if (files.length <= 8) {
214
- for (const f of files) {
215
- result.push(` ${f.size.padStart(6)} ${f.name}`);
216
- }
217
- }
218
- else {
219
- // Show top 5 by size + count
220
- const sorted = files.sort((a, b) => parseSize(b.size) - parseSize(a.size));
221
- for (const f of sorted.slice(0, 5)) {
222
- result.push(` ${f.size.padStart(6)} ${f.name}`);
223
- }
224
- result.push(` ... +${files.length - 5} more files (${formatSize(totalSize)} total)`);
225
- }
226
- return result;
227
- }
228
- function formatSize(bytes) {
229
- if (bytes >= 1_000_000)
230
- return `${(bytes / 1_000_000).toFixed(1)}M`;
231
- if (bytes >= 1_000)
232
- return `${(bytes / 1_000).toFixed(1)}K`;
233
- return `${bytes}B`;
234
- }
235
- function parseSize(s) {
236
- const match = s.match(/([\d.]+)([BKMG])?/);
237
- if (!match)
238
- return 0;
239
- const n = parseFloat(match[1]);
240
- const unit = match[2];
241
- if (unit === "K")
242
- return n * 1000;
243
- if (unit === "M")
244
- return n * 1000000;
245
- if (unit === "G")
246
- return n * 1000000000;
247
- return n;
248
- }
249
- /** Compress non-path generic output by deduplicating similar lines */
250
- function compressGeneric(lines) {
251
- if (lines.length <= 10)
252
- return lines;
253
- const result = [];
254
- let repeatCount = 0;
255
- let lastPattern = "";
256
- for (let i = 0; i < lines.length; i++) {
257
- const line = lines[i];
258
- // Normalize: remove numbers, timestamps, hashes for pattern matching
259
- const pattern = line
260
- .replace(/\d{4}-\d{2}-\d{2}T[\d:.-]+Z?/g, "TIMESTAMP")
261
- .replace(/\b[0-9a-f]{7,40}\b/g, "HASH")
262
- .replace(/\b\d+\b/g, "N")
263
- .trim();
264
- if (pattern === lastPattern && i > 0) {
265
- repeatCount++;
266
- }
267
- else {
268
- if (repeatCount > 1) {
269
- result.push(` ... ×${repeatCount} similar`);
270
- }
271
- else if (repeatCount === 1) {
272
- result.push(lines[i - 1]);
273
- }
274
- result.push(line);
275
- lastPattern = pattern;
276
- repeatCount = 0;
277
- }
278
- }
279
- if (repeatCount > 1) {
280
- result.push(` ... ×${repeatCount} similar`);
281
- }
282
- else if (repeatCount === 1) {
283
- result.push(lines[lines.length - 1]);
284
- }
285
- return result;
286
- }
package/dist/snapshots.js DELETED
@@ -1,51 +0,0 @@
1
- // Session snapshots — capture terminal state for agent context handoff
2
- import { loadHistory } from "./history.js";
3
- import { bgStatus } from "./supervisor.js";
4
- import { getEconomyStats, formatTokens } from "./economy.js";
5
- import { listRecipes } from "./recipes/storage.js";
6
- /** Capture a compact snapshot of the current terminal state */
7
- export function captureSnapshot() {
8
- // Filtered env — only relevant vars, no secrets
9
- const safeEnvKeys = [
10
- "PATH", "HOME", "USER", "SHELL", "NODE_ENV", "PWD", "LANG",
11
- "TERM", "EDITOR", "VISUAL",
12
- ];
13
- const env = {};
14
- for (const key of safeEnvKeys) {
15
- if (process.env[key])
16
- env[key] = process.env[key];
17
- }
18
- // Running processes
19
- const processes = bgStatus().map(p => ({
20
- pid: p.pid,
21
- command: p.command,
22
- port: p.port,
23
- uptime: Date.now() - p.startedAt,
24
- }));
25
- // Recent commands (last 10, compressed)
26
- const history = loadHistory().slice(-10);
27
- const recentCommands = history.map(h => ({
28
- cmd: h.cmd,
29
- exitCode: h.error,
30
- summary: h.nl !== h.cmd ? h.nl : undefined,
31
- }));
32
- // Project recipes
33
- const recipes = listRecipes(process.cwd()).slice(0, 10).map(r => ({
34
- name: r.name,
35
- command: r.command,
36
- }));
37
- // Economy
38
- const econ = getEconomyStats();
39
- return {
40
- cwd: process.cwd(),
41
- env,
42
- runningProcesses: processes,
43
- recentCommands,
44
- recipes,
45
- economy: {
46
- tokensSaved: formatTokens(econ.totalTokensSaved),
47
- tokensUsed: formatTokens(econ.totalTokensUsed),
48
- },
49
- timestamp: Date.now(),
50
- };
51
- }
@@ -1,112 +0,0 @@
1
- // Process supervisor — manages background processes for agents and humans
2
- import { spawn } from "child_process";
3
- import { createConnection } from "net";
4
- const processes = new Map();
5
- /** Auto-detect port from common commands */
6
- function detectPort(command) {
7
- // "next dev -p 3001", "vite --port 4000", etc.
8
- const portMatch = command.match(/-p\s+(\d+)|--port\s+(\d+)|PORT=(\d+)/);
9
- if (portMatch)
10
- return parseInt(portMatch[1] ?? portMatch[2] ?? portMatch[3]);
11
- // Common defaults
12
- if (/\bnext\s+dev\b/.test(command))
13
- return 3000;
14
- if (/\bvite\b/.test(command))
15
- return 5173;
16
- if (/\bnuxt\s+dev\b/.test(command))
17
- return 3000;
18
- if (/\bremix\s+dev\b/.test(command))
19
- return 5173;
20
- return undefined;
21
- }
22
- /** Start a background process */
23
- export function bgStart(command, cwd) {
24
- const workDir = cwd ?? process.cwd();
25
- const proc = spawn("/bin/zsh", ["-c", command], {
26
- cwd: workDir,
27
- stdio: ["ignore", "pipe", "pipe"],
28
- detached: false,
29
- });
30
- const meta = {
31
- pid: proc.pid,
32
- command,
33
- cwd: workDir,
34
- port: detectPort(command),
35
- startedAt: Date.now(),
36
- lastOutput: [],
37
- };
38
- const pushOutput = (d) => {
39
- const lines = d.toString().split("\n").filter(l => l.trim());
40
- meta.lastOutput.push(...lines);
41
- // Keep last 50 lines
42
- if (meta.lastOutput.length > 50) {
43
- meta.lastOutput = meta.lastOutput.slice(-50);
44
- }
45
- };
46
- proc.stdout?.on("data", pushOutput);
47
- proc.stderr?.on("data", pushOutput);
48
- proc.on("close", (code) => {
49
- meta.exitCode = code ?? 0;
50
- });
51
- processes.set(proc.pid, { proc, meta });
52
- return meta;
53
- }
54
- /** List all managed processes */
55
- export function bgStatus() {
56
- const result = [];
57
- for (const [pid, { proc, meta }] of processes) {
58
- // Check if still alive
59
- try {
60
- process.kill(pid, 0);
61
- result.push({ ...meta, lastOutput: meta.lastOutput.slice(-5) });
62
- }
63
- catch {
64
- // Process is dead
65
- result.push({ ...meta, exitCode: meta.exitCode ?? -1, lastOutput: meta.lastOutput.slice(-5) });
66
- }
67
- }
68
- return result;
69
- }
70
- /** Stop a background process */
71
- export function bgStop(pid) {
72
- const entry = processes.get(pid);
73
- if (!entry)
74
- return false;
75
- try {
76
- entry.proc.kill("SIGTERM");
77
- processes.delete(pid);
78
- return true;
79
- }
80
- catch {
81
- return false;
82
- }
83
- }
84
- /** Get logs for a background process */
85
- export function bgLogs(pid, tail = 20) {
86
- const entry = processes.get(pid);
87
- if (!entry)
88
- return [];
89
- return entry.meta.lastOutput.slice(-tail);
90
- }
91
- /** Wait for a port to be ready */
92
- export function bgWaitPort(port, timeoutMs = 30000) {
93
- return new Promise((resolve) => {
94
- const start = Date.now();
95
- const check = () => {
96
- if (Date.now() - start > timeoutMs) {
97
- resolve(false);
98
- return;
99
- }
100
- const sock = createConnection({ port, host: "127.0.0.1" });
101
- sock.on("connect", () => {
102
- sock.destroy();
103
- resolve(true);
104
- });
105
- sock.on("error", () => {
106
- sock.destroy();
107
- setTimeout(check, 500);
108
- });
109
- };
110
- check();
111
- });
112
- }
@@ -1,131 +0,0 @@
1
- // Test focus tracker — tracks test status across runs, only reports changes
2
- // Instead of showing "248 passed, 2 failed" every time, shows:
3
- // "auth.login: FIXED, auth.logout: STILL FAILING, 246 unchanged"
4
- // Per-cwd watchlist
5
- const watchlists = new Map();
6
- /** Extract test names and status from test runner output (any runner) */
7
- function extractTests(output) {
8
- const tests = [];
9
- const lines = output.split("\n");
10
- for (let i = 0; i < lines.length; i++) {
11
- const line = lines[i];
12
- // PASS/FAIL with test name: "PASS src/auth.test.ts" or "✓ login works" or "✗ logout fails"
13
- const passMatch = line.match(/(?:PASS|✓|✔|✅)\s+(.+)/);
14
- if (passMatch) {
15
- tests.push({ name: passMatch[1].trim(), status: "pass" });
16
- continue;
17
- }
18
- const failMatch = line.match(/(?:FAIL|✗|✕|❌|×)\s+(.+)/);
19
- if (failMatch) {
20
- // Capture error from next few lines
21
- const errorLines = [];
22
- for (let j = i + 1; j < Math.min(i + 5, lines.length); j++) {
23
- if (lines[j].match(/(?:PASS|FAIL|✓|✗|✔|✕|Tests:|^\s*$)/))
24
- break;
25
- errorLines.push(lines[j].trim());
26
- }
27
- tests.push({ name: failMatch[1].trim(), status: "fail", error: errorLines.join(" ").slice(0, 200) });
28
- continue;
29
- }
30
- // Jest/vitest style: " ● test name" for failures
31
- const jestFail = line.match(/^\s*●\s+(.+)/);
32
- if (jestFail) {
33
- tests.push({ name: jestFail[1].trim(), status: "fail" });
34
- continue;
35
- }
36
- }
37
- return tests;
38
- }
39
- /** Detect if output looks like test runner output */
40
- export function isTestOutput(output, command) {
41
- // If the command is explicitly a test command, trust it
42
- if (command && /\b(bun\s+test|npm\s+test|jest|vitest|pytest|cargo\s+test|go\s+test)\b/.test(command))
43
- return true;
44
- // Otherwise require BOTH a summary line AND a test runner marker in the output
45
- const summaryLine = /(?:\d+\s+pass|\d+\s+fail|Tests?:\s+\d+|Ran\s+\d+\s+tests?)\s*$/im;
46
- const testMarkers = /(?:✓|✗|✔|✕|PASS\s+\S+\.test|FAIL\s+\S+\.test|bun test v|jest|vitest|pytest)/;
47
- return summaryLine.test(output) && testMarkers.test(output);
48
- }
49
- /** Track test results and return only changes */
50
- export function trackTests(cwd, output) {
51
- const current = extractTests(output);
52
- const prev = watchlists.get(cwd);
53
- // Count totals from raw output (more reliable than extracted tests)
54
- let totalPassed = 0, totalFailed = 0;
55
- const summaryMatch = output.match(/(\d+)\s+pass/i);
56
- const failMatch = output.match(/(\d+)\s+fail/i);
57
- if (summaryMatch)
58
- totalPassed = parseInt(summaryMatch[1]);
59
- if (failMatch)
60
- totalFailed = parseInt(failMatch[1]);
61
- // Fallback to extracted counts
62
- if (totalPassed === 0)
63
- totalPassed = current.filter(t => t.status === "pass").length;
64
- if (totalFailed === 0)
65
- totalFailed = current.filter(t => t.status === "fail").length;
66
- // Store current for next comparison
67
- const currentMap = new Map();
68
- for (const t of current)
69
- currentMap.set(t.name, t);
70
- watchlists.set(cwd, currentMap);
71
- // First run — no comparison possible
72
- if (!prev) {
73
- return {
74
- changed: [],
75
- newTests: current.filter(t => t.status === "fail"), // only show failures on first run
76
- totalPassed,
77
- totalFailed,
78
- unchangedCount: 0,
79
- firstRun: true,
80
- };
81
- }
82
- // Compare with previous
83
- const changed = [];
84
- const newTests = [];
85
- let unchangedCount = 0;
86
- for (const [name, test] of currentMap) {
87
- const prevTest = prev.get(name);
88
- if (!prevTest) {
89
- newTests.push(test);
90
- }
91
- else if (prevTest.status !== test.status) {
92
- changed.push({ name, from: prevTest.status, to: test.status, error: test.error });
93
- }
94
- else {
95
- unchangedCount++;
96
- }
97
- }
98
- return { changed, newTests, totalPassed, totalFailed, unchangedCount, firstRun: false };
99
- }
100
- /** Format watchlist result for display */
101
- export function formatWatchResult(result) {
102
- const lines = [];
103
- if (result.firstRun) {
104
- lines.push(`${result.totalPassed} passed, ${result.totalFailed} failed`);
105
- if (result.newTests.length > 0) {
106
- for (const t of result.newTests) {
107
- lines.push(` ✗ ${t.name}${t.error ? `: ${t.error}` : ""}`);
108
- }
109
- }
110
- return lines.join("\n");
111
- }
112
- // Status changes
113
- for (const c of result.changed) {
114
- if (c.to === "pass")
115
- lines.push(` ✓ FIXED: ${c.name}`);
116
- else
117
- lines.push(` ✗ BROKE: ${c.name}${c.error ? ` — ${c.error}` : ""}`);
118
- }
119
- // New failures
120
- for (const t of result.newTests.filter(t => t.status === "fail")) {
121
- lines.push(` ✗ NEW FAIL: ${t.name}${t.error ? ` — ${t.error}` : ""}`);
122
- }
123
- // Summary
124
- if (result.changed.length === 0 && result.newTests.filter(t => t.status === "fail").length === 0) {
125
- lines.push(`✓ ${result.totalPassed} passed, ${result.totalFailed} failed (no changes)`);
126
- }
127
- else {
128
- lines.push(`${result.totalPassed} passed, ${result.totalFailed} failed, ${result.unchangedCount} unchanged`);
129
- }
130
- return lines.join("\n");
131
- }
package/dist/tree.js DELETED
@@ -1,94 +0,0 @@
1
- // Tree compression — convert flat file paths to compact tree representation
2
- import { readdirSync, statSync } from "fs";
3
- import { join, basename } from "path";
4
- import { DEFAULT_EXCLUDE_DIRS } from "./search/filters.js";
5
- /** Build a tree from a directory */
6
- export function buildTree(dirPath, options = {}) {
7
- const { maxDepth = 2, includeHidden = false, depth = 0 } = options;
8
- const name = basename(dirPath) || dirPath;
9
- const node = { name, type: "dir", children: [], fileCount: 0 };
10
- if (depth >= maxDepth) {
11
- // Count files without listing them
12
- try {
13
- const entries = readdirSync(dirPath);
14
- node.fileCount = entries.length;
15
- node.children = undefined; // don't expand
16
- }
17
- catch {
18
- node.fileCount = 0;
19
- }
20
- return node;
21
- }
22
- try {
23
- const entries = readdirSync(dirPath);
24
- for (const entry of entries) {
25
- if (!includeHidden && entry.startsWith("."))
26
- continue;
27
- if (DEFAULT_EXCLUDE_DIRS.includes(entry)) {
28
- // Show as collapsed with count
29
- try {
30
- const subPath = join(dirPath, entry);
31
- const subStat = statSync(subPath);
32
- if (subStat.isDirectory()) {
33
- node.children.push({ name: entry, type: "dir", fileCount: -1 }); // -1 = hidden
34
- continue;
35
- }
36
- }
37
- catch {
38
- continue;
39
- }
40
- }
41
- const fullPath = join(dirPath, entry);
42
- try {
43
- const stat = statSync(fullPath);
44
- if (stat.isDirectory()) {
45
- node.children.push(buildTree(fullPath, { maxDepth, includeHidden, depth: depth + 1 }));
46
- }
47
- else {
48
- node.children.push({ name: entry, type: "file", size: stat.size });
49
- node.fileCount++;
50
- }
51
- }
52
- catch {
53
- continue;
54
- }
55
- }
56
- }
57
- catch { }
58
- return node;
59
- }
60
- /** Render tree as compact string (for agents — minimum tokens) */
61
- export function compactTree(node, indent = 0) {
62
- const pad = " ".repeat(indent);
63
- if (node.type === "file")
64
- return `${pad}${node.name}`;
65
- if (node.fileCount === -1)
66
- return `${pad}${node.name}/ (hidden)`;
67
- if (!node.children || node.children.length === 0)
68
- return `${pad}${node.name}/ (empty)`;
69
- if (!node.children.some(c => c.children)) {
70
- // Leaf directory — compact single line
71
- const files = node.children.filter(c => c.type === "file").map(c => c.name);
72
- const dirs = node.children.filter(c => c.type === "dir");
73
- const parts = [];
74
- if (files.length <= 5) {
75
- parts.push(...files);
76
- }
77
- else {
78
- parts.push(`${files.length} files`);
79
- }
80
- for (const d of dirs) {
81
- parts.push(`${d.name}/${d.fileCount != null ? ` (${d.fileCount === -1 ? "hidden" : d.fileCount + " files"})` : ""}`);
82
- }
83
- return `${pad}${node.name}/ [${parts.join(", ")}]`;
84
- }
85
- const lines = [`${pad}${node.name}/`];
86
- for (const child of node.children) {
87
- lines.push(compactTree(child, indent + 1));
88
- }
89
- return lines.join("\n");
90
- }
91
- /** Render tree as JSON (for MCP) */
92
- export function treeToJson(node) {
93
- return node;
94
- }