llm-lean-log-cli
Advanced tools
+2
-2
| { | ||
| "name": "llm-lean-log-cli", | ||
| "version": "0.1.8", | ||
| "version": "0.2.1", | ||
| "description": "CLI tool for llm-lean-log", | ||
@@ -32,3 +32,3 @@ "scripts": { | ||
| "dependencies": { | ||
| "llm-lean-log-core": "0.1.4" | ||
| "llm-lean-log-core": "^0.2.0" | ||
| }, | ||
@@ -35,0 +35,0 @@ "devDependencies": { |
+153
-1
@@ -33,2 +33,4 @@ import { | ||
| let processExitSpy: any; | ||
| let bunFileSpy: any; | ||
| let bunWriteSpy: any; | ||
| let originalArgv: string[]; | ||
@@ -44,2 +46,12 @@ | ||
| ); | ||
| bunFileSpy = spyOn(Bun, "file").mockImplementation( | ||
| () => | ||
| ({ | ||
| exists: () => Promise.resolve(true), | ||
| text: () => Promise.resolve(""), | ||
| }) as any, | ||
| ); | ||
| bunWriteSpy = spyOn(Bun, "write").mockImplementation(() => | ||
| Promise.resolve(0), | ||
| ); | ||
| originalArgv = process.argv; | ||
@@ -52,2 +64,4 @@ }); | ||
| processExitSpy.mockRestore(); | ||
| bunFileSpy.mockRestore(); | ||
| bunWriteSpy.mockRestore(); | ||
| process.argv = originalArgv; | ||
@@ -78,2 +92,12 @@ }); | ||
| it("should show version with '-v' flag", async () => { | ||
| await runCommand(["-v"]); | ||
| expect(consoleLogSpy).toHaveBeenCalledWith(pkg.version); | ||
| }); | ||
| it("should show version with '-V' flag", async () => { | ||
| await runCommand(["-V"]); | ||
| expect(consoleLogSpy).toHaveBeenCalledWith(pkg.version); | ||
| }); | ||
| it("should call loadLogs and visualizeTable for 'list' command", async () => { | ||
@@ -92,2 +116,9 @@ const { loadLogs, visualizeTable } = core as any; | ||
| it("should work with 'ls' alias", async () => { | ||
| const { loadLogs, visualizeTable } = core as any; | ||
| await runCommand(["ls"]); | ||
| expect(loadLogs).toHaveBeenCalled(); | ||
| expect(visualizeTable).toHaveBeenCalled(); | ||
| }); | ||
| it("should call visualizeStats for 'stats' command", async () => { | ||
@@ -103,3 +134,3 @@ const { visualizeStats } = core as any; | ||
| it("should add a new log entry with 'add' command", async () => { | ||
| const { saveLogs, addLogEntry } = core as any; | ||
| const { saveLogs, addLogEntry } = core; | ||
@@ -116,2 +147,12 @@ await runCommand([ | ||
| expect(consoleLogSpy).toHaveBeenCalledWith("Log entry added successfully"); | ||
| // Verify that saveLogs was called with the expected entries | ||
| const savedEntries = (saveLogs as any).mock.calls[0][1]; | ||
| const lastEntry = savedEntries[savedEntries.length - 1]; | ||
| expect(lastEntry.name).toBe("New Log"); | ||
| expect(lastEntry.problem).toBe("Test Problem"); | ||
| expect(lastEntry.tags).toBe("test,cli"); | ||
| expect(lastEntry["created-at"]).toBeDefined(); | ||
| expect(lastEntry.id).toBeDefined(); | ||
| }); | ||
@@ -130,2 +171,13 @@ | ||
| it("should show error and exit if 'add' is missing name", async () => { | ||
| try { | ||
| await runCommand(["add"]); | ||
| } catch (e: any) { | ||
| expect(e.message).toBe("process.exit(1)"); | ||
| } | ||
| expect(consoleErrorSpy).toHaveBeenCalledWith( | ||
| expect.stringContaining("Please provide a log name"), | ||
| ); | ||
| }); | ||
| it("should search logs with 'search' command", async () => { | ||
@@ -141,2 +193,13 @@ const { searchLogs, visualizeTable } = core as any; | ||
| it("should show error and exit if 'search' is missing query", async () => { | ||
| try { | ||
| await runCommand(["search"]); | ||
| } catch (e: any) { | ||
| expect(e.message).toBe("process.exit(1)"); | ||
| } | ||
| expect(consoleErrorSpy).toHaveBeenCalledWith( | ||
| expect.stringContaining("Please provide a search query"), | ||
| ); | ||
| }); | ||
| it("should filter logs by tags with 'tags' command", async () => { | ||
@@ -152,2 +215,13 @@ const { filterByTags, visualizeTable } = core as any; | ||
| it("should show error and exit if 'tags' is missing tags", async () => { | ||
| try { | ||
| await runCommand(["tags"]); | ||
| } catch (e: any) { | ||
| expect(e.message).toBe("process.exit(1)"); | ||
| } | ||
| expect(consoleErrorSpy).toHaveBeenCalledWith( | ||
| expect.stringContaining("Please provide at least one tag"), | ||
| ); | ||
| }); | ||
| it("should view entry at index", async () => { | ||
@@ -165,2 +239,74 @@ const { loadLogs, visualizeEntry } = core as any; | ||
| it("should view last entry with --last flag", async () => { | ||
| const { loadLogs, visualizeEntry } = core as any; | ||
| loadLogs.mockResolvedValueOnce([ | ||
| { id: "1", name: "test1", problem: "p1", "created-at": "t1" }, | ||
| { id: "2", name: "test2", problem: "p2", "created-at": "t2" }, | ||
| ]); | ||
| await runCommand(["view", "--last"]); | ||
| expect(visualizeEntry).toHaveBeenCalledWith( | ||
| expect.objectContaining({ id: "2" }), | ||
| expect.any(Object), | ||
| ); | ||
| }); | ||
| it("should show error and exit if 'view' has no logs", async () => { | ||
| const { loadLogs } = core as any; | ||
| loadLogs.mockResolvedValueOnce([]); | ||
| try { | ||
| await runCommand(["view", "0"]); | ||
| } catch (e: any) { | ||
| expect(e.message).toBe("process.exit(1)"); | ||
| } | ||
| expect(consoleErrorSpy).toHaveBeenCalledWith( | ||
| expect.stringContaining("No log entries found"), | ||
| ); | ||
| }); | ||
| it("should show error and exit if 'view' index is NaN", async () => { | ||
| const { loadLogs } = core as any; | ||
| loadLogs.mockResolvedValueOnce([{ id: "1" }]); | ||
| try { | ||
| await runCommand(["view", "abc"]); | ||
| } catch (e: any) { | ||
| expect(e.message).toBe("process.exit(1)"); | ||
| } | ||
| expect(consoleErrorSpy).toHaveBeenCalledWith( | ||
| expect.stringContaining("Please provide a valid entry index"), | ||
| ); | ||
| }); | ||
| it("should show error and exit if 'view' index is out of range", async () => { | ||
| const { loadLogs } = core as any; | ||
| loadLogs.mockResolvedValueOnce([{ id: "1" }]); | ||
| try { | ||
| await runCommand(["view", "10"]); | ||
| } catch (e: any) { | ||
| expect(e.message).toBe("process.exit(1)"); | ||
| } | ||
| expect(consoleErrorSpy).toHaveBeenCalledWith( | ||
| expect.stringContaining("out of range"), | ||
| ); | ||
| }); | ||
| it("should show error and exit if entry is missing at index", async () => { | ||
| const { loadLogs } = core as any; | ||
| // Create an array with a hole or undefined | ||
| loadLogs.mockResolvedValueOnce([undefined]); | ||
| try { | ||
| await runCommand(["view", "0"]); | ||
| } catch (e: any) { | ||
| expect(e.message).toBe("process.exit(1)"); | ||
| } | ||
| expect(consoleErrorSpy).toHaveBeenCalledWith( | ||
| expect.stringContaining("Entry not found at index 0"), | ||
| ); | ||
| }); | ||
| it("should show error for unknown command", async () => { | ||
@@ -177,2 +323,8 @@ try { | ||
| it("should show help when no command is provided", async () => { | ||
| await runCommand([]); | ||
| expect(consoleLogSpy).toHaveBeenCalled(); | ||
| expect(consoleLogSpy.mock.calls[0][0]).toContain("l-log CLI"); | ||
| }); | ||
| it("should use custom log file if provided", async () => { | ||
@@ -179,0 +331,0 @@ const { loadLogs } = core as any; |
+1
-2
@@ -48,4 +48,3 @@ #!/usr/bin/env bun | ||
| --model=<name> Model name | ||
| --id=<id> Log ID (optional) | ||
| --causeIds=<ids> Comma-separated cause log IDs | ||
| --causeIds=<ids> Comma-separated cause log IDs | ||
| --effectIds=<ids> Comma-separated effect log IDs | ||
@@ -52,0 +51,0 @@ --last-commit-short-sha=<sha> Last git commit short SHA |
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
20320
27.65%470
38.64%+ Added
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
Updated