@forwardimpact/libutil 0.1.62 → 0.1.64

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,33 @@
1
+ #!/usr/bin/env node
2
+ import { countTokens } from "@forwardimpact/libutil";
3
+
4
+ /**
5
+ * Counts tokens in the provided text
6
+ * Usage: fit-tiktoken <text>
7
+ * echo "text" | fit-tiktoken
8
+ * @returns {Promise<void>}
9
+ */
10
+ async function main() {
11
+ let text = process.argv.slice(2).join(" ");
12
+
13
+ if (!text && !process.stdin.isTTY) {
14
+ const chunks = [];
15
+ for await (const chunk of process.stdin) {
16
+ chunks.push(chunk);
17
+ }
18
+ text = Buffer.concat(chunks).toString().trim();
19
+ }
20
+
21
+ if (!text) {
22
+ console.error("Usage: fit-tiktoken <text>");
23
+ console.error(' echo "text" | fit-tiktoken');
24
+ process.exit(1);
25
+ }
26
+
27
+ console.log(countTokens(text));
28
+ }
29
+
30
+ main().catch((error) => {
31
+ console.error(error.message);
32
+ process.exit(1);
33
+ });
package/finder.js CHANGED
@@ -47,6 +47,25 @@ export class Finder {
47
47
  return null;
48
48
  }
49
49
 
50
+ /**
51
+ * Resolve a data directory by upward traversal, with HOME fallback.
52
+ * @param {string} baseName - Directory name to find (e.g. "data")
53
+ * @param {string} homeDir - User home directory path
54
+ * @returns {string} Absolute path to found directory
55
+ */
56
+ findData(baseName, homeDir) {
57
+ const cwd = this.#process.cwd();
58
+ const found = this.findUpward(cwd, baseName);
59
+ if (found) return found;
60
+
61
+ const homePath = path.join(homeDir, ".fit", baseName);
62
+ if (fs.existsSync(homePath)) return homePath;
63
+
64
+ throw new Error(
65
+ `No ${baseName} directory found from ${cwd} or ${homePath}.`,
66
+ );
67
+ }
68
+
50
69
  /**
51
70
  * Find the project root directory
52
71
  * @param {string} startPath - Starting directory path
package/package.json CHANGED
@@ -1,13 +1,14 @@
1
1
  {
2
2
  "name": "@forwardimpact/libutil",
3
- "version": "0.1.62",
3
+ "version": "0.1.64",
4
4
  "description": "Utility functions and utilities for Guide",
5
5
  "license": "Apache-2.0",
6
6
  "author": "D. Olsson <hi@senzilla.io>",
7
7
  "type": "module",
8
8
  "main": "index.js",
9
9
  "bin": {
10
- "fit-download-bundle": "./bin/fit-download-bundle.js"
10
+ "fit-download-bundle": "./bin/fit-download-bundle.js",
11
+ "fit-tiktoken": "./bin/fit-tiktoken.js"
11
12
  },
12
13
  "engines": {
13
14
  "node": ">=22.0.0"
@@ -257,6 +257,79 @@ describe("Finder", () => {
257
257
  });
258
258
  });
259
259
 
260
+ describe("findData", () => {
261
+ test("finds data/ in CWD via findUpward", () => {
262
+ const dataDir = path.join(tempDir, "data");
263
+ fs.mkdirSync(dataDir);
264
+
265
+ const cwdFinder = new Finder(fsPromises, mockLogger, {
266
+ cwd: () => tempDir,
267
+ });
268
+ const result = cwdFinder.findData("data", "/nonexistent-home");
269
+
270
+ assert.strictEqual(result, dataDir);
271
+ });
272
+
273
+ test("finds data/ in a parent directory via findUpward", () => {
274
+ const dataDir = path.join(tempDir, "data");
275
+ fs.mkdirSync(dataDir);
276
+ const subDir = path.join(tempDir, "products", "pathway");
277
+ fs.mkdirSync(subDir, { recursive: true });
278
+
279
+ const cwdFinder = new Finder(fsPromises, mockLogger, {
280
+ cwd: () => subDir,
281
+ });
282
+ const result = cwdFinder.findData("data", "/nonexistent-home");
283
+
284
+ assert.strictEqual(result, dataDir);
285
+ });
286
+
287
+ test("falls back to ~/.fit/data/ when CWD traversal fails", () => {
288
+ const fakeHome = path.join(tempDir, "fakehome");
289
+ const homeFitData = path.join(fakeHome, ".fit", "data");
290
+ fs.mkdirSync(homeFitData, { recursive: true });
291
+
292
+ const isolatedDir = path.join(tempDir, "isolated");
293
+ fs.mkdirSync(isolatedDir);
294
+
295
+ const cwdFinder = new Finder(fsPromises, mockLogger, {
296
+ cwd: () => isolatedDir,
297
+ });
298
+ const result = cwdFinder.findData("data", fakeHome);
299
+
300
+ assert.strictEqual(result, homeFitData);
301
+ });
302
+
303
+ test("throws when neither CWD traversal nor HOME fallback finds directory", () => {
304
+ const isolatedDir = path.join(tempDir, "isolated");
305
+ fs.mkdirSync(isolatedDir);
306
+
307
+ const cwdFinder = new Finder(fsPromises, mockLogger, {
308
+ cwd: () => isolatedDir,
309
+ });
310
+
311
+ assert.throws(() => cwdFinder.findData("data", "/nonexistent-home"), {
312
+ message: /No data directory found/,
313
+ });
314
+ });
315
+
316
+ test("CWD takes priority over HOME when both exist", () => {
317
+ const cwdData = path.join(tempDir, "data");
318
+ fs.mkdirSync(cwdData);
319
+
320
+ const fakeHome = path.join(tempDir, "fakehome");
321
+ const homeFitData = path.join(fakeHome, ".fit", "data");
322
+ fs.mkdirSync(homeFitData, { recursive: true });
323
+
324
+ const cwdFinder = new Finder(fsPromises, mockLogger, {
325
+ cwd: () => tempDir,
326
+ });
327
+ const result = cwdFinder.findData("data", fakeHome);
328
+
329
+ assert.strictEqual(result, cwdData);
330
+ });
331
+ });
332
+
260
333
  describe("findPackagePath", () => {
261
334
  test("finds package in local monorepo structure", () => {
262
335
  // Create mock monorepo structure