@loghead/core 0.1.19 → 0.1.20

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.
@@ -1,39 +0,0 @@
1
- import { Ollama } from "ollama";
2
-
3
- export class OllamaService {
4
- private client: Ollama;
5
- private model: string;
6
-
7
- constructor(host = "http://localhost:11434", model = "qwen3-embedding:0.6b") {
8
- this.client = new Ollama({ host });
9
- this.model = model;
10
- }
11
-
12
- async generateEmbedding(prompt: string): Promise<number[]> {
13
- try {
14
- const response = await this.client.embeddings({
15
- model: this.model,
16
- prompt: prompt,
17
- });
18
- return response.embedding;
19
- } catch (error) {
20
- console.error("Failed to generate embedding:", error);
21
- throw error;
22
- }
23
- }
24
-
25
- async ensureModel() {
26
- try {
27
- const list = await this.client.list();
28
- const exists = list.models.some((m) => m.name.includes(this.model));
29
-
30
- if (!exists) {
31
- console.log(`Model ${this.model} not found. Pulling...`);
32
- await this.client.pull({ model: this.model });
33
- console.log("Model pulled.");
34
- }
35
- } catch (e) {
36
- console.warn("Could not check/pull ollama model:", e);
37
- }
38
- }
39
- }
@@ -1,63 +0,0 @@
1
- import { assertEquals, assertExists } from "@std/assert";
2
- import { migrate } from "../db/migrate.ts";
3
-
4
- // Set up environment to use in-memory DB before importing client
5
- Deno.env.set("LOGHEAD_DB_PATH", ":memory:");
6
-
7
- // Dynamic import to ensure env var is set before module loads
8
- // We trigger the side-effect of client.ts (creating DB connection)
9
- await import("../db/client.ts");
10
- const { DbService } = await import("../services/db.ts");
11
-
12
- Deno.test("DbService - Project Management", async (t) => {
13
- // @ts-ignore: Dynamic import returns any
14
- const service = new DbService();
15
-
16
- // Initialize DB schema
17
- migrate(false);
18
-
19
- await t.step("createProject creates a project", () => {
20
- const project = service.createProject("Test Project");
21
- assertExists(project.id);
22
- assertEquals(project.name, "Test Project");
23
- });
24
-
25
- await t.step("listProjects returns projects", () => {
26
- const projects = service.listProjects();
27
- assertExists(projects.find(p => p.name === "Test Project"));
28
- });
29
-
30
- await t.step("deleteProject deletes a project", () => {
31
- const projects = service.listProjects();
32
- const project = projects.find(p => p.name === "Test Project");
33
- if (project) {
34
- service.deleteProject(project.id);
35
-
36
- const remaining = service.listProjects();
37
- assertEquals(remaining.find(p => p.name === "Test Project"), undefined);
38
- }
39
- });
40
- });
41
-
42
- Deno.test("DbService - Stream Management", async (t) => {
43
- // @ts-ignore: Dynamic import returns any
44
- const service = new DbService();
45
-
46
- // Create a fresh project for this test suite
47
- const project = service.createProject("Stream Project");
48
-
49
- await t.step("createStream creates a stream", () => {
50
- const stream = service.createStream(project.id, "terminal", "My Stream", { foo: "bar" });
51
- assertExists(stream.id);
52
- assertEquals(stream.name, "My Stream");
53
- assertEquals(stream.type, "terminal");
54
- // @ts-ignore: Property access
55
- assertEquals(stream.config, { foo: "bar" });
56
- });
57
-
58
- await t.step("listStreams returns streams", () => {
59
- const streams = service.listStreams(project.id);
60
- assertEquals(streams.length, 1);
61
- assertEquals(streams[0].name, "My Stream");
62
- });
63
- });
package/src/types.ts DELETED
@@ -1,31 +0,0 @@
1
-
2
- export interface Project {
3
- id: string;
4
- name: string;
5
- created_at?: string;
6
- streams?: Stream[];
7
- }
8
-
9
- export interface Stream {
10
- id: string;
11
- project_id: string;
12
- type: string;
13
- name: string;
14
- config: Record<string, unknown> | string;
15
- created_at?: string;
16
- }
17
-
18
- export interface Log {
19
- id: string;
20
- stream_id: string;
21
- content: string;
22
- timestamp: string;
23
- metadata: Record<string, unknown> | string;
24
- }
25
-
26
- export interface SearchResult {
27
- content: string;
28
- timestamp: string;
29
- similarity?: number;
30
- metadata?: Record<string, unknown>;
31
- }
package/src/ui/main.ts DELETED
@@ -1,197 +0,0 @@
1
- import { DbService } from "../services/db";
2
- import { AuthService } from "../services/auth";
3
- import inquirer from "inquirer";
4
- import chalk from "chalk";
5
-
6
- let title = `
7
- █████ █████ █████
8
- ▒▒███ ▒▒███ ▒▒███
9
- ▒███ ██████ ███████ ▒███████ ██████ ██████ ███████
10
- ▒███ ███▒▒███ ███▒▒███ ▒███▒▒███ ███▒▒███ ▒▒▒▒▒███ ███▒▒███
11
- ▒███ ▒███ ▒███▒███ ▒███ ▒███ ▒███ ▒███████ ███████ ▒███ ▒███
12
- ▒███ █▒███ ▒███▒███ ▒███ ▒███ ▒███ ▒███▒▒▒ ███▒▒███ ▒███ ▒███
13
- ███████████▒▒██████ ▒▒███████ ████ █████▒▒██████ ▒▒████████▒▒████████
14
- ▒▒▒▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒ ▒▒▒▒▒███▒▒▒▒ ▒▒▒▒▒ ▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒
15
- ███ ▒███
16
- ▒▒██████
17
- ▒▒▒▒▒▒ `;
18
-
19
- export async function startTui(db: DbService, token: string) {
20
- const port = process.env.PORT || 4567;
21
- const showHeader = () => {
22
- console.clear();
23
- console.log(chalk.bold(title));
24
- console.log(chalk.bold(`\nServer URL :`) + " " + chalk.dim(`http://localhost:${port}`));
25
- console.log(chalk.bold(`MCP Token :`) + " " + chalk.dim(token) + "\n");
26
- };
27
-
28
- while (true) {
29
- showHeader();
30
- const projects = db.listProjects();
31
-
32
- const projectChoices: (inquirer.Separator | { name: string; value: string })[] = projects.map(p => ({ name: p.name, value: p.id }));
33
- projectChoices.push(new inquirer.Separator());
34
- projectChoices.push({ name: chalk.green("+ Create Project"), value: "create_project" });
35
- projectChoices.push({ name: chalk.red("Exit"), value: "exit" });
36
-
37
- const { projectId } = await inquirer.prompt([{
38
- type: "list",
39
- name: "projectId",
40
- message: "Select a project",
41
- choices: projectChoices,
42
- pageSize: 10,
43
- prefix: "💡"
44
- }]);
45
-
46
- if (projectId === "exit") break;
47
-
48
- if (projectId === "create_project") {
49
- const { name } = await inquirer.prompt([{
50
- type: "input",
51
- name: "name",
52
- message: "Project Name:",
53
- prefix: "💡"
54
- }]);
55
- if (name) {
56
- db.createProject(name);
57
- }
58
- continue;
59
- }
60
-
61
- // List streams for project
62
- while (true) {
63
- showHeader();
64
- const project = projects.find(p => p.id === projectId);
65
- console.log(chalk.bold.blue(`Project: ${project?.name}\n`));
66
-
67
- const streams = db.listStreams(projectId);
68
-
69
- const streamChoices: (inquirer.Separator | { name: string; value: string })[] = streams.map(s => ({
70
- name: `${s.name} (${s.type})`,
71
- value: s.id
72
- }));
73
- streamChoices.push(new inquirer.Separator());
74
- streamChoices.push({ name: chalk.green("+ Create Stream"), value: "create_stream" });
75
- streamChoices.push({ name: chalk.yellow("Back"), value: "back" });
76
-
77
- const { streamId } = await inquirer.prompt([{
78
- type: "list",
79
- name: "streamId",
80
- message: "Select a stream",
81
- choices: streamChoices,
82
- pageSize: 10,
83
- prefix: "💡"
84
- }]);
85
-
86
- if (streamId === "back") break;
87
-
88
- if (streamId === "create_stream") {
89
- showHeader();
90
- console.log(chalk.bold.blue(`Project: ${project?.name}`));
91
- console.log(chalk.bold.blue(` └─ Create Stream\n`));
92
-
93
- const { name, type } = await inquirer.prompt([
94
- {
95
- type: "input",
96
- name: "name",
97
- message: "Stream name:",
98
- prefix: "💡"
99
- },
100
- {
101
- type: "list",
102
- name: "type",
103
- message: "Stream type:",
104
- choices: ["browser", "terminal", "docker", "opentelemetry"],
105
- prefix: "💡"
106
- }
107
- ]);
108
-
109
- if (name && type) {
110
- // For now, empty config
111
- const s = await db.createStream(projectId, type, name, {});
112
- console.log(chalk.green(`\nStream created!`));
113
- console.log(chalk.bold.yellow(`Token: ${s.token}\n`));
114
-
115
- await inquirer.prompt([{
116
- type: "input",
117
- name: "continue",
118
- message: "Press enter to continue...",
119
- prefix: "💡"
120
- }]);
121
- }
122
- continue;
123
- }
124
-
125
- // Stream Actions
126
- while (true) {
127
- showHeader();
128
- const stream = streams.find(s => s.id === streamId);
129
- console.log(chalk.bold.blue(`Project: ${project?.name}`));
130
- console.log(chalk.bold.blue(` └─ Stream: ${stream?.name} (${stream?.type})\n`));
131
-
132
- const { action } = await inquirer.prompt([{
133
- type: "list",
134
- name: "action",
135
- message: "Action",
136
- choices: [
137
- { name: "View logs", value: "view_logs" },
138
- { name: "Get token", value: "get_token" },
139
- { name: "Delete stream", value: "delete_stream" },
140
- { name: chalk.yellow("Back"), value: "back" }
141
- ],
142
- prefix: "💡"
143
- }]);
144
-
145
- if (action === "back") break;
146
-
147
- if (action === "get_token") {
148
- const auth = new AuthService();
149
- const token = await auth.createStreamToken(streamId);
150
- console.log(chalk.green(`\nToken for ${stream?.name}:`));
151
- console.log(chalk.bold.yellow(`${token}\n`));
152
-
153
- await inquirer.prompt([{
154
- type: "input",
155
- name: "continue",
156
- message: "Press enter to continue...",
157
- prefix: "💡"
158
- }]);
159
- }
160
-
161
- if (action === "delete_stream") {
162
- const { confirm } = await inquirer.prompt([{
163
- type: "confirm",
164
- name: "confirm",
165
- message: `Are you sure you want to delete stream ${stream?.name}?`
166
- }]);
167
- if (confirm) {
168
- db.deleteStream(streamId);
169
- break; // Go back to stream list
170
- }
171
- }
172
-
173
- if (action === "view_logs") {
174
- console.clear();
175
- console.log(chalk.bold.green(`Logs for ${stream?.name}:\n`));
176
-
177
- const logs = db.getRecentLogs(streamId, 20);
178
- if (logs.length === 0) {
179
- console.log("No logs recorded yet.");
180
- } else {
181
- [...logs].reverse().forEach(log => {
182
- console.log(`${chalk.dim(log.timestamp)} ${log.content}`);
183
- });
184
- }
185
-
186
- console.log("\n");
187
- await inquirer.prompt([{
188
- type: "input",
189
- name: "return",
190
- message: "Press enter to return...",
191
- prefix: "💡"
192
- }]);
193
- }
194
- }
195
- }
196
- }
197
- }
@@ -1,52 +0,0 @@
1
- import chalk from "chalk";
2
- import { OllamaService } from "../services/ollama";
3
- import { migrate } from "../db/migrate";
4
-
5
- export async function ensureInfrastructure() {
6
- console.log(chalk.bold.blue("\n🚀Performing system preflight checks..."));
7
-
8
- // 1. Check Local Ollama
9
- await checkStep("Checking local Ollama...", async () => {
10
- try {
11
- // Node.js fetch needs global fetch or polyfill in Node 18+.
12
- // Assuming Node 18+ which has fetch.
13
- const response = await fetch("http://localhost:11434/api/tags");
14
- if (!response.ok) throw new Error("Ollama is not running");
15
- } catch {
16
- throw new Error("Ollama is not accessible at http://localhost:11434. Please install and run Ollama.");
17
- }
18
- });
19
-
20
- // 2. Check Database & Migrations (SQLite)
21
- await checkStep("Initializing database...", async () => {
22
- try {
23
- migrate(false);
24
- } catch (e) {
25
- console.log(chalk.yellow("\n ➤ Migration failed..."));
26
- throw e;
27
- }
28
- });
29
-
30
- // 3. Check Ollama Model
31
- await checkStep("Checking embedding model (qwen3-embedding)...", async () => {
32
- const ollama = new OllamaService();
33
- await ollama.ensureModel();
34
- });
35
-
36
- console.log(`${chalk.green("✔")} System preflight checks complete`);
37
- }
38
-
39
- async function checkStep(name: string, action: () => Promise<void>) {
40
- // Print pending state
41
- process.stdout.write(`${chalk.cyan("○")} ${name}`);
42
-
43
- try {
44
- await action();
45
- // Clear line and print success
46
- process.stdout.write(`\r${chalk.green("✔")} ${name} \n`);
47
- } catch (e) {
48
- process.stdout.write(`\r${chalk.red("✖")} ${name}\n`);
49
- console.error(chalk.red(` Error: ${e instanceof Error ? e.message : e}`));
50
- process.exit(1);
51
- }
52
- }
@@ -1,62 +0,0 @@
1
- import { OllamaService } from "../src/services/ollama";
2
- import { performance } from "perf_hooks";
3
-
4
- async function runTest() {
5
- console.log("Starting Embedding Performance Test...");
6
-
7
- const service = new OllamaService();
8
-
9
- // Ensure model exists first so pull time doesn't affect metrics
10
- console.log("Checking model availability...");
11
- await service.ensureModel();
12
-
13
- const testString = "This is a test log message that simulates a typical log entry in a production system. It contains some details about an error or an event that occurred.";
14
- const iterations = 10;
15
- const latencies: number[] = [];
16
-
17
- console.log(`Running ${iterations} iterations...`);
18
-
19
- for (let i = 0; i < iterations; i++) {
20
- const start = performance.now();
21
- try {
22
- await service.generateEmbedding(testString);
23
- const end = performance.now();
24
- const duration = end - start;
25
- latencies.push(duration);
26
- console.log(`Iteration ${i + 1}: ${duration.toFixed(2)}ms`);
27
- } catch (e) {
28
- console.error(`Iteration ${i + 1} failed:`, e);
29
- }
30
- }
31
-
32
- if (latencies.length > 0) {
33
- const warmUp = latencies[0];
34
- const results = latencies.slice(1); // Remove warm-up
35
-
36
- console.log("\n--- Results ---");
37
- console.log(`Total Iterations: ${latencies.length}`);
38
- console.log(`Warm-up Time: ${warmUp.toFixed(2)}ms`);
39
-
40
- if (results.length > 0) {
41
- const min = Math.min(...results);
42
- const max = Math.max(...results);
43
-
44
- // Calculate Median
45
- results.sort((a, b) => a - b);
46
- const mid = Math.floor(results.length / 2);
47
- const median = results.length % 2 !== 0
48
- ? results[mid]
49
- : (results[mid - 1] + results[mid]) / 2;
50
-
51
- console.log(`Min Latency (excl. warmup): ${min.toFixed(2)}ms`);
52
- console.log(`Avg Latency (excl. warmup): ${median.toFixed(2)}ms`);
53
- console.log(`Max Latency (excl. warmup): ${max.toFixed(2)}ms`);
54
- } else {
55
- console.log("Not enough iterations to calculate stats (need > 1).");
56
- }
57
- } else {
58
- console.log("\nNo successful iterations.");
59
- }
60
- }
61
-
62
- runTest().catch(console.error);
package/tsconfig.json DELETED
@@ -1,15 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "target": "ES2022",
4
- "module": "CommonJS",
5
- "moduleResolution": "node",
6
- "outDir": "./dist",
7
- "rootDir": "./src",
8
- "strict": true,
9
- "esModuleInterop": true,
10
- "skipLibCheck": true,
11
- "forceConsistentCasingInFileNames": true
12
- },
13
- "include": ["src/**/*"],
14
- "exclude": ["node_modules", "**/*.test.ts"]
15
- }