@ff-labs/bun 0.1.0 → 0.1.1

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.
@@ -0,0 +1,226 @@
1
+ #!/usr/bin/env bun
2
+ /**
3
+ * Interactive file finder demo
4
+ *
5
+ * Usage:
6
+ * bunx fff-demo [directory]
7
+ * bun examples/search.ts [directory]
8
+ *
9
+ * Indexes the specified directory (or cwd) and provides an interactive
10
+ * search prompt with detailed metadata about results.
11
+ */
12
+
13
+ import { FileFinder } from "../src/index";
14
+ import * as readline from "readline";
15
+
16
+ const RESET = "\x1b[0m";
17
+ const BOLD = "\x1b[1m";
18
+ const DIM = "\x1b[2m";
19
+ const GREEN = "\x1b[32m";
20
+ const YELLOW = "\x1b[33m";
21
+ const BLUE = "\x1b[34m";
22
+ const MAGENTA = "\x1b[35m";
23
+ const CYAN = "\x1b[36m";
24
+ const RED = "\x1b[31m";
25
+
26
+ function formatGitStatus(status: string): string {
27
+ switch (status) {
28
+ case "modified":
29
+ return `${YELLOW}M${RESET}`;
30
+ case "untracked":
31
+ return `${GREEN}?${RESET}`;
32
+ case "added":
33
+ return `${GREEN}A${RESET}`;
34
+ case "deleted":
35
+ return `${RED}D${RESET}`;
36
+ case "renamed":
37
+ return `${BLUE}R${RESET}`;
38
+ case "clear":
39
+ case "current":
40
+ return `${DIM} ${RESET}`;
41
+ default:
42
+ return `${DIM}${status.charAt(0)}${RESET}`;
43
+ }
44
+ }
45
+
46
+ function formatScore(score: number): string {
47
+ if (score >= 100) return `${GREEN}${score}${RESET}`;
48
+ if (score >= 50) return `${YELLOW}${score}${RESET}`;
49
+ if (score > 0) return `${DIM}${score}${RESET}`;
50
+ return `${DIM}0${RESET}`;
51
+ }
52
+
53
+ function formatSize(bytes: number): string {
54
+ if (bytes < 1024) return `${bytes}B`;
55
+ if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)}K`;
56
+ return `${(bytes / 1024 / 1024).toFixed(1)}M`;
57
+ }
58
+
59
+ function formatTime(unixSeconds: number): string {
60
+ if (unixSeconds === 0) return "unknown";
61
+ const date = new Date(unixSeconds * 1000);
62
+ const now = new Date();
63
+ const diffMs = now.getTime() - date.getTime();
64
+ const diffMins = Math.floor(diffMs / 60000);
65
+ const diffHours = Math.floor(diffMs / 3600000);
66
+ const diffDays = Math.floor(diffMs / 86400000);
67
+
68
+ if (diffMins < 1) return "just now";
69
+ if (diffMins < 60) return `${diffMins}m ago`;
70
+ if (diffHours < 24) return `${diffHours}h ago`;
71
+ if (diffDays < 7) return `${diffDays}d ago`;
72
+ return date.toLocaleDateString();
73
+ }
74
+
75
+ async function main() {
76
+ const targetDir = process.argv[2] || process.cwd();
77
+
78
+ console.log(`${BOLD}${CYAN}fff - Fast File Finder Demo${RESET}\n`);
79
+
80
+ // Check library availability
81
+ if (!FileFinder.isAvailable()) {
82
+ console.error(`${RED}Error: Native library not found.${RESET}`);
83
+ console.error("Build with: cargo build --release -p fff-c");
84
+ process.exit(1);
85
+ }
86
+
87
+ // Initialize
88
+ console.log(`${DIM}Initializing index for: ${targetDir}${RESET}`);
89
+ const initResult = FileFinder.init({
90
+ basePath: targetDir,
91
+ skipDatabases: true, // Skip frecency DB for demo simplicity
92
+ });
93
+
94
+ if (!initResult.ok) {
95
+ console.error(`${RED}Init failed: ${initResult.error}${RESET}`);
96
+ process.exit(1);
97
+ }
98
+
99
+ // Wait for scan with progress
100
+ process.stdout.write(`${DIM}Scanning files...${RESET}`);
101
+ const startTime = Date.now();
102
+ let lastCount = 0;
103
+
104
+ while (FileFinder.isScanning()) {
105
+ const progress = FileFinder.getScanProgress();
106
+ if (progress.ok && progress.value.scannedFilesCount !== lastCount) {
107
+ lastCount = progress.value.scannedFilesCount;
108
+ process.stdout.write(`\r${DIM}Scanning files... ${lastCount}${RESET} `);
109
+ }
110
+ await new Promise((r) => setTimeout(r, 50));
111
+ }
112
+
113
+ const scanTime = Date.now() - startTime;
114
+ const finalProgress = FileFinder.getScanProgress();
115
+ const totalFiles = finalProgress.ok ? finalProgress.value.scannedFilesCount : 0;
116
+
117
+ console.log(`\r${GREEN}✓${RESET} Indexed ${BOLD}${totalFiles}${RESET} files in ${scanTime}ms\n`);
118
+
119
+ // Show index info
120
+ const health = FileFinder.healthCheck();
121
+ if (health.ok) {
122
+ console.log(`${DIM}─────────────────────────────────────────${RESET}`);
123
+ console.log(`${DIM}Version:${RESET} ${health.value.version}`);
124
+ console.log(`${DIM}Base path:${RESET} ${health.value.filePicker.basePath}`);
125
+ if (health.value.git.repositoryFound) {
126
+ console.log(`${DIM}Git root:${RESET} ${health.value.git.workdir}`);
127
+ }
128
+ console.log(`${DIM}─────────────────────────────────────────${RESET}\n`);
129
+ }
130
+
131
+ // Interactive search loop
132
+ const rl = readline.createInterface({
133
+ input: process.stdin,
134
+ output: process.stdout,
135
+ });
136
+
137
+ console.log(`${BOLD}Enter a search query${RESET} (or 'q' to quit, empty for all files):\n`);
138
+
139
+ const prompt = () => {
140
+ rl.question(`${CYAN}search>${RESET} `, (query) => {
141
+ if (query.toLowerCase() === "q" || query.toLowerCase() === "quit") {
142
+ console.log(`\n${DIM}Goodbye!${RESET}`);
143
+ FileFinder.destroy();
144
+ rl.close();
145
+ process.exit(0);
146
+ }
147
+
148
+ const searchStart = Date.now();
149
+ const result = FileFinder.search(query, { pageSize: 15 });
150
+ const searchTime = Date.now() - searchStart;
151
+
152
+ if (!result.ok) {
153
+ console.log(`${RED}Search error: ${result.error}${RESET}\n`);
154
+ prompt();
155
+ return;
156
+ }
157
+
158
+ const { items, scores, totalMatched, totalFiles } = result.value;
159
+
160
+ console.log();
161
+ console.log(
162
+ `${DIM}Found ${BOLD}${totalMatched}${RESET}${DIM} matches in ${totalFiles} files (${searchTime}ms)${RESET}`
163
+ );
164
+ console.log();
165
+
166
+ if (items.length === 0) {
167
+ console.log(`${DIM}No matches found.${RESET}\n`);
168
+ prompt();
169
+ return;
170
+ }
171
+
172
+ // Header
173
+ console.log(
174
+ `${DIM} Git │ Score │ Size │ Modified │ Path${RESET}`
175
+ );
176
+ console.log(`${DIM}──────┼───────┼────────┼────────────┼${"─".repeat(40)}${RESET}`);
177
+
178
+ // Results
179
+ for (let i = 0; i < items.length; i++) {
180
+ const item = items[i];
181
+ const score = scores[i];
182
+
183
+ const gitStatus = formatGitStatus(item.gitStatus);
184
+ const totalScore = formatScore(score.total);
185
+ const size = formatSize(item.size).padStart(6);
186
+ const modified = formatTime(item.modified).padEnd(10);
187
+ const path = item.relativePath;
188
+
189
+ console.log(
190
+ ` ${gitStatus} │ ${totalScore.padStart(5)} │ ${size} │ ${modified} │ ${path}`
191
+ );
192
+
193
+ // Show score breakdown for top results
194
+ if (i < 3 && score.total > 0) {
195
+ const breakdown: string[] = [];
196
+ if (score.baseScore > 0) breakdown.push(`base:${score.baseScore}`);
197
+ if (score.filenameBonus > 0) breakdown.push(`filename:+${score.filenameBonus}`);
198
+ if (score.frecencyBoost > 0) breakdown.push(`frecency:+${score.frecencyBoost}`);
199
+ if (score.comboMatchBoost > 0) breakdown.push(`combo:+${score.comboMatchBoost}`);
200
+ if (score.distancePenalty < 0) breakdown.push(`distance:${score.distancePenalty}`);
201
+ if (score.exactMatch) breakdown.push(`${GREEN}exact${RESET}`);
202
+
203
+ if (breakdown.length > 0) {
204
+ console.log(`${DIM} │ │ │ │ └─ ${breakdown.join(", ")}${RESET}`);
205
+ }
206
+ }
207
+ }
208
+
209
+ if (totalMatched > items.length) {
210
+ console.log(
211
+ `${DIM} │ │ │ │ ... and ${totalMatched - items.length} more${RESET}`
212
+ );
213
+ }
214
+
215
+ console.log();
216
+ prompt();
217
+ });
218
+ };
219
+
220
+ prompt();
221
+ }
222
+
223
+ main().catch((err) => {
224
+ console.error(`${RED}Fatal error: ${err.message}${RESET}`);
225
+ process.exit(1);
226
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ff-labs/bun",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "private": false,
5
5
  "nativeBinaryHash": "6c641aa",
6
6
  "description": "High-performance fuzzy file finder for Bun - perfect for LLM agent tools",
@@ -14,12 +14,14 @@
14
14
  }
15
15
  },
16
16
  "bin": {
17
- "fff": "./scripts/cli.cjs"
17
+ "fff": "./scripts/cli.ts",
18
+ "fff-demo": "./examples/search.ts"
18
19
  },
19
20
  "files": [
20
21
  "src",
21
22
  "bin",
22
- "scripts"
23
+ "scripts",
24
+ "examples"
23
25
  ],
24
26
  "scripts": {
25
27
  "postinstall": "bun ./scripts/postinstall.ts",
package/scripts/cli.ts CHANGED
File without changes
package/scripts/cli.cjs DELETED
@@ -1,16 +0,0 @@
1
- #!/usr/bin/env node
2
- // Wrapper script for npm - delegates to Bun
3
- const { execSync } = require("child_process");
4
- const { join } = require("path");
5
-
6
- const script = join(__dirname, "cli.ts");
7
- const args = process.argv.slice(2).join(" ");
8
-
9
- try {
10
- execSync(`bun ${script} ${args}`, {
11
- stdio: "inherit",
12
- cwd: process.cwd()
13
- });
14
- } catch (error) {
15
- process.exit(error.status || 1);
16
- }