tarsk 0.2.6 → 0.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.
- package/README.md +1 -7
- package/dist/index.d.ts +3 -0
- package/dist/index.js +92 -32
- package/dist/lib/response-builder.d.ts +50 -0
- package/dist/lib/response-builder.js +56 -0
- package/dist/lib/stream-helper.d.ts +39 -0
- package/dist/lib/stream-helper.js +43 -0
- package/dist/managers/ConversationManager.d.ts +83 -0
- package/dist/managers/ConversationManager.js +129 -0
- package/dist/managers/GitManager.d.ts +133 -0
- package/dist/managers/GitManager.js +330 -0
- package/dist/managers/MetadataManager.d.ts +139 -0
- package/dist/managers/MetadataManager.js +309 -0
- package/dist/managers/ModelManager.d.ts +57 -0
- package/dist/managers/ModelManager.js +129 -0
- package/dist/managers/NeovateExecutor.d.ts +40 -0
- package/dist/managers/NeovateExecutor.js +138 -0
- package/dist/managers/ProjectManager.d.ts +162 -0
- package/dist/managers/ProjectManager.js +353 -0
- package/dist/managers/ThreadManager.d.ts +181 -0
- package/dist/managers/ThreadManager.js +325 -0
- package/dist/managers/conversation-manager.d.ts +83 -0
- package/dist/managers/conversation-manager.js +129 -0
- package/dist/managers/git-manager.d.ts +133 -0
- package/dist/managers/git-manager.js +330 -0
- package/dist/managers/metadata-manager.d.ts +139 -0
- package/dist/managers/metadata-manager.js +305 -0
- package/dist/managers/model-manager.d.ts +59 -0
- package/dist/managers/model-manager.js +144 -0
- package/dist/managers/neovate-executor.d.ts +43 -0
- package/dist/managers/neovate-executor.js +205 -0
- package/dist/managers/processing-state-manager.d.ts +40 -0
- package/dist/managers/processing-state-manager.js +27 -0
- package/dist/managers/project-manager.d.ts +199 -0
- package/dist/managers/project-manager.js +465 -0
- package/dist/managers/thread-manager.d.ts +193 -0
- package/dist/managers/thread-manager.js +368 -0
- package/dist/model-info-aihubmix.d.ts +25 -0
- package/dist/model-info-aihubmix.js +117 -0
- package/dist/model-info-openai.d.ts +17 -0
- package/dist/model-info-openai.js +59 -0
- package/dist/model-info-openrouter.d.ts +25 -0
- package/dist/model-info-openrouter.js +101 -0
- package/dist/model-info.d.ts +37 -0
- package/dist/model-info.js +39 -0
- package/dist/provider-data.d.ts +101 -0
- package/dist/provider-data.js +471 -0
- package/dist/provider.d.ts +10 -0
- package/dist/provider.js +192 -0
- package/dist/public/android-chrome-192x192.png +0 -0
- package/dist/public/android-chrome-512x512.png +0 -0
- package/dist/public/apple-touch-icon.png +0 -0
- package/dist/public/assets/index-B443aj9k.js +8506 -0
- package/dist/public/assets/index-CjXGVbI7.css +1 -0
- package/dist/public/assets/index-DJC-p914.js +8506 -0
- package/dist/public/favicon-16x16.png +0 -0
- package/dist/public/favicon-32x32.png +0 -0
- package/dist/public/favicon.ico +0 -0
- package/dist/public/index.html +28 -0
- package/dist/public/manifest.json +82 -0
- package/dist/public/placeholder-logo.svg +1 -0
- package/dist/public/placeholder.svg +1 -0
- package/dist/public/snpro.woff2 +0 -0
- package/dist/public/tarsk-color.svg +12 -0
- package/dist/public/tarsk.png +0 -0
- package/dist/public/tarsk.svg +12 -0
- package/dist/public/zalando-sans.woff2 +0 -0
- package/dist/routes/chat-old.d.ts +21 -0
- package/dist/routes/chat-old.js +251 -0
- package/dist/routes/chat.d.ts +21 -0
- package/dist/routes/chat.js +217 -0
- package/dist/routes/git.d.ts +4 -0
- package/dist/routes/git.js +668 -0
- package/dist/routes/models.d.ts +18 -0
- package/dist/routes/models.js +128 -0
- package/dist/routes/projects-old.d.ts +20 -0
- package/dist/routes/projects-old.js +297 -0
- package/dist/routes/projects.d.ts +20 -0
- package/dist/routes/projects.js +365 -0
- package/dist/routes/providers.d.ts +15 -0
- package/dist/routes/providers.js +130 -0
- package/dist/routes/threads-old.d.ts +14 -0
- package/dist/routes/threads-old.js +393 -0
- package/dist/routes/threads.d.ts +14 -0
- package/dist/routes/threads.js +352 -0
- package/dist/types/models.d.ts +315 -0
- package/dist/types/models.js +11 -0
- package/dist/utils/env-manager.d.ts +3 -0
- package/dist/utils/env-manager.js +60 -0
- package/dist/utils/open-router-models.d.ts +45 -0
- package/dist/utils/open-router-models.js +103 -0
- package/dist/utils/openai-models.d.ts +63 -0
- package/dist/utils/openai-models.js +152 -0
- package/dist/utils/openai-pricing-scraper.d.ts +17 -0
- package/dist/utils/openai-pricing-scraper.js +185 -0
- package/dist/utils/validation.d.ts +10 -0
- package/dist/utils/validation.js +20 -0
- package/dist/utils.d.ts +10 -0
- package/dist/utils.js +12 -0
- package/package.json +36 -23
- package/LICENSE.md +0 -7
- package/dist/agent/agent.js +0 -132
- package/dist/agent/interfaces.js +0 -1
- package/dist/api/encryption.js +0 -41
- package/dist/api/models.js +0 -169
- package/dist/api/prompt.js +0 -14
- package/dist/api/settings.js +0 -43
- package/dist/api/test.js +0 -29
- package/dist/api/tools.js +0 -303
- package/dist/api/utils.js +0 -18
- package/dist/interfaces/meta.js +0 -1
- package/dist/interfaces/model.js +0 -1
- package/dist/interfaces/settings.js +0 -1
- package/dist/log/log.js +0 -42
- package/dist/prompt.js +0 -49
- package/dist/tools.js +0 -85
- package/dist/utils/files.js +0 -14
- package/dist/utils/json-file.js +0 -28
- package/dist/utils/strip-markdown.js +0 -5
package/README.md
CHANGED
package/dist/index.d.ts
ADDED
package/dist/index.js
CHANGED
|
@@ -1,40 +1,100 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import
|
|
6
|
-
import {
|
|
7
|
-
import
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
2
|
+
import { Hono } from 'hono';
|
|
3
|
+
import { cors } from 'hono/cors';
|
|
4
|
+
import { serve } from '@hono/node-server';
|
|
5
|
+
import { serveStatic } from '@hono/node-server/serve-static';
|
|
6
|
+
import { exec } from 'child_process';
|
|
7
|
+
import path from 'path';
|
|
8
|
+
import { fileURLToPath } from 'url';
|
|
9
|
+
import { ProjectManagerImpl } from './managers/project-manager.js';
|
|
10
|
+
import { ThreadManagerImpl } from './managers/thread-manager.js';
|
|
11
|
+
import { GitManagerImpl } from './managers/git-manager.js';
|
|
12
|
+
import { MetadataManager } from './managers/metadata-manager.js';
|
|
13
|
+
import { NeovateExecutorImpl } from './managers/neovate-executor.js';
|
|
14
|
+
import { ConversationManagerImpl } from './managers/conversation-manager.js';
|
|
15
|
+
import { ProcessingStateManagerImpl } from './managers/processing-state-manager.js';
|
|
16
|
+
import { createProjectRoutes } from './routes/projects.js';
|
|
17
|
+
import { createThreadRoutes } from './routes/threads.js';
|
|
18
|
+
import { createChatRoutes } from './routes/chat.js';
|
|
19
|
+
import { createProviderRoutes } from './routes/providers.js';
|
|
20
|
+
import { createModelRoutes } from './routes/models.js';
|
|
21
|
+
import { createGitRoutes } from './routes/git.js';
|
|
22
|
+
import { AVAILABLE_PROGRAMS } from './types/models.js';
|
|
23
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
24
|
+
const __dirname = path.dirname(__filename);
|
|
10
25
|
const app = new Hono();
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
26
|
+
// Configure CORS middleware
|
|
27
|
+
app.use('/*', cors());
|
|
28
|
+
// Initialize managers
|
|
29
|
+
const rootFolder = process.env.ROOT_FOLDER || process.cwd();
|
|
30
|
+
const metadataManager = new MetadataManager(rootFolder);
|
|
31
|
+
const gitManager = new GitManagerImpl();
|
|
32
|
+
const projectManager = new ProjectManagerImpl(rootFolder, metadataManager, gitManager);
|
|
33
|
+
const threadManager = new ThreadManagerImpl(metadataManager, gitManager);
|
|
34
|
+
const conversationManager = new ConversationManagerImpl(rootFolder);
|
|
35
|
+
const neovateExecutor = new NeovateExecutorImpl(metadataManager);
|
|
36
|
+
const processingStateManager = new ProcessingStateManagerImpl();
|
|
37
|
+
// Initialize metadata storage
|
|
38
|
+
await metadataManager.initialize();
|
|
39
|
+
// Health check endpoint
|
|
40
|
+
app.get('/health', (c) => {
|
|
41
|
+
return c.json({
|
|
42
|
+
status: 'ok',
|
|
43
|
+
timestamp: new Date().toISOString(),
|
|
44
|
+
service: 'project-threads-manager-cli'
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
// Available programs endpoint
|
|
48
|
+
app.get('/api/programs', (c) => {
|
|
49
|
+
return c.json({
|
|
50
|
+
programs: AVAILABLE_PROGRAMS
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
// Processing threads endpoint - returns list of thread IDs currently processing
|
|
54
|
+
app.get('/api/threads/processing', (c) => {
|
|
55
|
+
return c.json({
|
|
56
|
+
processingThreadIds: processingStateManager.getProcessingThreadIds()
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
// Register API routes
|
|
60
|
+
app.route('/api/projects', createProjectRoutes(projectManager, threadManager));
|
|
61
|
+
app.route('/api/threads', createThreadRoutes(threadManager, gitManager, conversationManager));
|
|
62
|
+
app.route('/api/chat', createChatRoutes(threadManager, neovateExecutor, conversationManager, processingStateManager));
|
|
63
|
+
app.route('/api/providers', createProviderRoutes(metadataManager));
|
|
64
|
+
app.route('/api/models', createModelRoutes(metadataManager));
|
|
65
|
+
app.route('/api/git', createGitRoutes(metadataManager));
|
|
66
|
+
// Serve static files from the 'public' directory
|
|
67
|
+
// In production, this will be the built frontend app
|
|
68
|
+
const publicDir = path.join(__dirname, 'public');
|
|
69
|
+
app.use('/*', serveStatic({
|
|
70
|
+
root: path.relative(process.cwd(), publicDir)
|
|
16
71
|
}));
|
|
17
|
-
|
|
18
|
-
|
|
72
|
+
// Fallback to index.html for SPA routing
|
|
73
|
+
app.get('*', serveStatic({
|
|
74
|
+
path: path.relative(process.cwd(), path.join(publicDir, 'index.html'))
|
|
75
|
+
}));
|
|
76
|
+
// Error handling middleware for unmatched routes
|
|
77
|
+
app.all('*', (c) => {
|
|
78
|
+
const errorResponse = {
|
|
79
|
+
error: {
|
|
80
|
+
code: 'NOT_FOUND',
|
|
81
|
+
message: `Route not found: ${c.req.method} ${c.req.path}`,
|
|
82
|
+
timestamp: new Date().toISOString()
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
return c.json(errorResponse, 404);
|
|
19
86
|
});
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
app.post("/run/tool", async (c) => await api_run_tool(c));
|
|
24
|
-
app.get("/tools/:tool", async (c) => await api_get_tool(c));
|
|
25
|
-
app.delete("/tools/:tool", async (c) => await api_delete_tool(c));
|
|
26
|
-
app.get("/settings", async (c) => await api_get_settings(c));
|
|
27
|
-
app.post("/settings", async (c) => await api_save_settings(c));
|
|
28
|
-
app.get("/models", async (c) => await api_get_models(c));
|
|
87
|
+
const port = process.env.PORT ? parseInt(process.env.PORT) : 641;
|
|
88
|
+
const url = `http://localhost:${port}`;
|
|
89
|
+
console.log(`Tarsk started on ${url}`);
|
|
29
90
|
serve({
|
|
30
91
|
fetch: app.fetch,
|
|
31
|
-
port
|
|
32
|
-
}, (
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
console.log(`Tarsk is running. Visit https://tarsk.io`);
|
|
38
|
-
open("https://tarsk.io");
|
|
92
|
+
port
|
|
93
|
+
}, () => {
|
|
94
|
+
// Open browser in production/cli mode
|
|
95
|
+
if (process.env.NODE_ENV !== 'development') {
|
|
96
|
+
const start = process.platform === 'darwin' ? 'open' : process.platform === 'win32' ? 'start' : 'xdg-open';
|
|
97
|
+
exec(`${start} ${url}`);
|
|
39
98
|
}
|
|
40
99
|
});
|
|
100
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Response builder utility for centralizing API response formatting
|
|
3
|
+
*
|
|
4
|
+
* Provides factory methods for creating consistent error and success responses
|
|
5
|
+
* across all route handlers. This eliminates duplication of response formatting
|
|
6
|
+
* logic and ensures consistent error handling throughout the API.
|
|
7
|
+
*/
|
|
8
|
+
import type { ErrorResponse } from '../types/models.js';
|
|
9
|
+
/**
|
|
10
|
+
* Factory for building consistent API responses
|
|
11
|
+
*/
|
|
12
|
+
export declare class ResponseBuilder {
|
|
13
|
+
/**
|
|
14
|
+
* Creates an error response with standard error structure
|
|
15
|
+
*
|
|
16
|
+
* @param code - Machine-readable error code (e.g., 'INVALID_REQUEST', 'NOT_FOUND')
|
|
17
|
+
* @param message - Human-readable error message
|
|
18
|
+
* @param statusCode - HTTP status code to return
|
|
19
|
+
* @param details - Optional additional error context
|
|
20
|
+
* @returns Object containing both response data and HTTP status code
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```typescript
|
|
24
|
+
* const { response, statusCode } = ResponseBuilder.error('INVALID_REQUEST', 'Project ID is required', 400);
|
|
25
|
+
* return c.json(response, statusCode as any);
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
static error(code: string, message: string, statusCode: number, details?: unknown): {
|
|
29
|
+
response: ErrorResponse;
|
|
30
|
+
statusCode: number;
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* Creates a success response with optional data
|
|
34
|
+
*
|
|
35
|
+
* @param data - Response payload data
|
|
36
|
+
* @param statusCode - HTTP status code (default: 200)
|
|
37
|
+
* @returns Object containing both response data and HTTP status code
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* ```typescript
|
|
41
|
+
* const { response, statusCode } = ResponseBuilder.success(projects, 200);
|
|
42
|
+
* return c.json(response, statusCode as any);
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
static success(data: unknown, statusCode?: number): {
|
|
46
|
+
response: unknown;
|
|
47
|
+
statusCode: number;
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=response-builder.d.ts.map
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Response builder utility for centralizing API response formatting
|
|
3
|
+
*
|
|
4
|
+
* Provides factory methods for creating consistent error and success responses
|
|
5
|
+
* across all route handlers. This eliminates duplication of response formatting
|
|
6
|
+
* logic and ensures consistent error handling throughout the API.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Factory for building consistent API responses
|
|
10
|
+
*/
|
|
11
|
+
export class ResponseBuilder {
|
|
12
|
+
/**
|
|
13
|
+
* Creates an error response with standard error structure
|
|
14
|
+
*
|
|
15
|
+
* @param code - Machine-readable error code (e.g., 'INVALID_REQUEST', 'NOT_FOUND')
|
|
16
|
+
* @param message - Human-readable error message
|
|
17
|
+
* @param statusCode - HTTP status code to return
|
|
18
|
+
* @param details - Optional additional error context
|
|
19
|
+
* @returns Object containing both response data and HTTP status code
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```typescript
|
|
23
|
+
* const { response, statusCode } = ResponseBuilder.error('INVALID_REQUEST', 'Project ID is required', 400);
|
|
24
|
+
* return c.json(response, statusCode as any);
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
static error(code, message, statusCode, details) {
|
|
28
|
+
const error = {
|
|
29
|
+
code,
|
|
30
|
+
message,
|
|
31
|
+
timestamp: new Date().toISOString()
|
|
32
|
+
};
|
|
33
|
+
if (details !== undefined) {
|
|
34
|
+
error.details = details;
|
|
35
|
+
}
|
|
36
|
+
const response = { error };
|
|
37
|
+
return { response, statusCode };
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Creates a success response with optional data
|
|
41
|
+
*
|
|
42
|
+
* @param data - Response payload data
|
|
43
|
+
* @param statusCode - HTTP status code (default: 200)
|
|
44
|
+
* @returns Object containing both response data and HTTP status code
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* ```typescript
|
|
48
|
+
* const { response, statusCode } = ResponseBuilder.success(projects, 200);
|
|
49
|
+
* return c.json(response, statusCode as any);
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
static success(data, statusCode = 200) {
|
|
53
|
+
return { response: data, statusCode };
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=response-builder.js.map
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stream helper utilities for handling async generator streaming responses
|
|
3
|
+
*
|
|
4
|
+
* Centralizes streaming logic to avoid duplication across route handlers
|
|
5
|
+
*/
|
|
6
|
+
import { Context } from 'hono';
|
|
7
|
+
import { stream } from 'hono/streaming';
|
|
8
|
+
/**
|
|
9
|
+
* Options for streaming async generators
|
|
10
|
+
*/
|
|
11
|
+
export interface StreamOptions<T> {
|
|
12
|
+
/**
|
|
13
|
+
* Custom error event formatter
|
|
14
|
+
* If not provided, defaults to { type: 'error', message: ... }
|
|
15
|
+
*/
|
|
16
|
+
onError?: (error: Error) => T;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Streams an async generator as newline-delimited JSON
|
|
20
|
+
*
|
|
21
|
+
* Handles:
|
|
22
|
+
* - Iterating through async generator
|
|
23
|
+
* - Serializing each event to JSON
|
|
24
|
+
* - Writing newline-delimited format
|
|
25
|
+
* - Error handling and recovery
|
|
26
|
+
* - Proper stream cleanup
|
|
27
|
+
*
|
|
28
|
+
* @param c - Hono context
|
|
29
|
+
* @param generator - Async generator yielding events
|
|
30
|
+
* @param options - Optional configuration
|
|
31
|
+
* @returns Hono response
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```typescript
|
|
35
|
+
* return StreamHelper.streamAsyncGenerator(c, projectManager.createProject(gitUrl));
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
export declare function streamAsyncGenerator<T>(c: Context, generator: AsyncGenerator<T>, options?: StreamOptions<T>): ReturnType<typeof stream>;
|
|
39
|
+
//# sourceMappingURL=stream-helper.d.ts.map
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stream helper utilities for handling async generator streaming responses
|
|
3
|
+
*
|
|
4
|
+
* Centralizes streaming logic to avoid duplication across route handlers
|
|
5
|
+
*/
|
|
6
|
+
import { stream } from 'hono/streaming';
|
|
7
|
+
/**
|
|
8
|
+
* Streams an async generator as newline-delimited JSON
|
|
9
|
+
*
|
|
10
|
+
* Handles:
|
|
11
|
+
* - Iterating through async generator
|
|
12
|
+
* - Serializing each event to JSON
|
|
13
|
+
* - Writing newline-delimited format
|
|
14
|
+
* - Error handling and recovery
|
|
15
|
+
* - Proper stream cleanup
|
|
16
|
+
*
|
|
17
|
+
* @param c - Hono context
|
|
18
|
+
* @param generator - Async generator yielding events
|
|
19
|
+
* @param options - Optional configuration
|
|
20
|
+
* @returns Hono response
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```typescript
|
|
24
|
+
* return StreamHelper.streamAsyncGenerator(c, projectManager.createProject(gitUrl));
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
export function streamAsyncGenerator(c, generator, options) {
|
|
28
|
+
return stream(c, async (writer) => {
|
|
29
|
+
try {
|
|
30
|
+
for await (const event of generator) {
|
|
31
|
+
await writer.write(JSON.stringify(event) + '\n');
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
const errorEvent = options?.onError?.(error) || {
|
|
36
|
+
type: 'error',
|
|
37
|
+
message: error instanceof Error ? error.message : String(error)
|
|
38
|
+
};
|
|
39
|
+
await writer.write(JSON.stringify(errorEvent) + '\n');
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=stream-helper.js.map
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ConversationManager handles conversation history storage and retrieval
|
|
3
|
+
*
|
|
4
|
+
* This manager is responsible for:
|
|
5
|
+
* - Storing request/response pairs in JSON format
|
|
6
|
+
* - Retrieving conversation history for a thread
|
|
7
|
+
* - Managing conversation persistence
|
|
8
|
+
*/
|
|
9
|
+
import { ConversationHistory, ConversationMessage, NeovateEvent, FileData } from '../types/models.js';
|
|
10
|
+
/**
|
|
11
|
+
* ConversationManager interface defines the contract for conversation operations
|
|
12
|
+
*/
|
|
13
|
+
export interface ConversationManager {
|
|
14
|
+
/**
|
|
15
|
+
* Starts a new conversation message (request captured)
|
|
16
|
+
* @param threadId - The thread ID
|
|
17
|
+
* @param threadPath - The absolute path to the thread directory
|
|
18
|
+
* @param message - The user's message
|
|
19
|
+
* @param model - The model being used
|
|
20
|
+
* @param attachments - Optional file attachments
|
|
21
|
+
* @param planMode - Optional plan mode flag
|
|
22
|
+
* @returns The message ID for this conversation
|
|
23
|
+
*/
|
|
24
|
+
startMessage(threadId: string, threadPath: string, message: string, model: string, attachments?: FileData[], planMode?: boolean): Promise<string>;
|
|
25
|
+
/**
|
|
26
|
+
* Completes a conversation message (response captured)
|
|
27
|
+
* @param threadPath - The absolute path to the thread directory
|
|
28
|
+
* @param messageId - The message ID to complete
|
|
29
|
+
* @param content - The complete response content
|
|
30
|
+
* @param events - All events captured during execution
|
|
31
|
+
*/
|
|
32
|
+
completeMessage(threadPath: string, messageId: string, content: string, events: NeovateEvent[]): Promise<void>;
|
|
33
|
+
/**
|
|
34
|
+
* Gets the conversation history for a thread
|
|
35
|
+
* @param threadPath - The absolute path to the thread directory
|
|
36
|
+
* @returns The conversation history or null if not found
|
|
37
|
+
*/
|
|
38
|
+
getConversationHistory(threadPath: string): Promise<ConversationHistory | null>;
|
|
39
|
+
/**
|
|
40
|
+
* Gets the last N messages from conversation history
|
|
41
|
+
* @param threadPath - The absolute path to the thread directory
|
|
42
|
+
* @param count - Number of messages to retrieve (default: 1)
|
|
43
|
+
* @returns Array of conversation messages
|
|
44
|
+
*/
|
|
45
|
+
getLastMessages(threadPath: string, count?: number): Promise<ConversationMessage[]>;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* ConversationManagerImpl provides the implementation for conversation operations
|
|
49
|
+
*/
|
|
50
|
+
export declare class ConversationManagerImpl implements ConversationManager {
|
|
51
|
+
private metadataDir;
|
|
52
|
+
/**
|
|
53
|
+
* Create a new ConversationManagerImpl
|
|
54
|
+
* @param rootFolder - Base directory where metadata will be stored
|
|
55
|
+
*/
|
|
56
|
+
constructor(rootFolder?: string);
|
|
57
|
+
/**
|
|
58
|
+
* Starts a new conversation message
|
|
59
|
+
*/
|
|
60
|
+
startMessage(threadId: string, threadPath: string, message: string, model: string, attachments?: FileData[], planMode?: boolean): Promise<string>;
|
|
61
|
+
/**
|
|
62
|
+
* Completes a conversation message
|
|
63
|
+
*/
|
|
64
|
+
completeMessage(threadPath: string, messageId: string, content: string, events: NeovateEvent[]): Promise<void>;
|
|
65
|
+
/**
|
|
66
|
+
* Gets the conversation history for a thread
|
|
67
|
+
*/
|
|
68
|
+
getConversationHistory(threadPath: string): Promise<ConversationHistory | null>;
|
|
69
|
+
/**
|
|
70
|
+
* Gets the last N messages from conversation history
|
|
71
|
+
*/
|
|
72
|
+
getLastMessages(threadPath: string, count?: number): Promise<ConversationMessage[]>;
|
|
73
|
+
/**
|
|
74
|
+
* Saves conversation history to file
|
|
75
|
+
*/
|
|
76
|
+
private saveConversationHistory;
|
|
77
|
+
/**
|
|
78
|
+
* Gets the file path for a thread's conversation history in the metadata folder
|
|
79
|
+
* Extracts threadId from threadPath and stores in .metadata/conversations/<threadId>/history.json
|
|
80
|
+
*/
|
|
81
|
+
private getConversationFilePath;
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=ConversationManager.d.ts.map
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ConversationManager handles conversation history storage and retrieval
|
|
3
|
+
*
|
|
4
|
+
* This manager is responsible for:
|
|
5
|
+
* - Storing request/response pairs in JSON format
|
|
6
|
+
* - Retrieving conversation history for a thread
|
|
7
|
+
* - Managing conversation persistence
|
|
8
|
+
*/
|
|
9
|
+
import { promises as fs } from 'fs';
|
|
10
|
+
import { join, dirname } from 'path';
|
|
11
|
+
import { randomUUID } from 'crypto';
|
|
12
|
+
const CONVERSATION_FILE = 'conversation-history.json';
|
|
13
|
+
const METADATA_DIR = '.metadata';
|
|
14
|
+
/**
|
|
15
|
+
* ConversationManagerImpl provides the implementation for conversation operations
|
|
16
|
+
*/
|
|
17
|
+
export class ConversationManagerImpl {
|
|
18
|
+
metadataDir;
|
|
19
|
+
/**
|
|
20
|
+
* Create a new ConversationManagerImpl
|
|
21
|
+
* @param rootFolder - Base directory where metadata will be stored
|
|
22
|
+
*/
|
|
23
|
+
constructor(rootFolder = './projects') {
|
|
24
|
+
this.metadataDir = join(rootFolder, METADATA_DIR);
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Starts a new conversation message
|
|
28
|
+
*/
|
|
29
|
+
async startMessage(threadId, threadPath, message, model, attachments, planMode) {
|
|
30
|
+
const messageId = randomUUID();
|
|
31
|
+
const timestamp = new Date().toISOString();
|
|
32
|
+
// Load existing history or create new
|
|
33
|
+
let history = await this.getConversationHistory(threadPath);
|
|
34
|
+
if (!history) {
|
|
35
|
+
history = {
|
|
36
|
+
threadId,
|
|
37
|
+
messages: [],
|
|
38
|
+
lastUpdated: timestamp,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
// Create incomplete message (will be completed later)
|
|
42
|
+
const incompleteMessage = {
|
|
43
|
+
id: messageId,
|
|
44
|
+
timestamp,
|
|
45
|
+
request: {
|
|
46
|
+
message,
|
|
47
|
+
model,
|
|
48
|
+
...(attachments && { attachments }),
|
|
49
|
+
...(planMode && { planMode }),
|
|
50
|
+
},
|
|
51
|
+
response: null,
|
|
52
|
+
};
|
|
53
|
+
history.messages.push(incompleteMessage);
|
|
54
|
+
history.lastUpdated = timestamp;
|
|
55
|
+
// Save to file
|
|
56
|
+
await this.saveConversationHistory(threadPath, history);
|
|
57
|
+
return messageId;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Completes a conversation message
|
|
61
|
+
*/
|
|
62
|
+
async completeMessage(threadPath, messageId, content, events) {
|
|
63
|
+
const history = await this.getConversationHistory(threadPath);
|
|
64
|
+
if (!history) {
|
|
65
|
+
throw new Error('Conversation history not found');
|
|
66
|
+
}
|
|
67
|
+
// Find the message to complete
|
|
68
|
+
const message = history.messages.find((m) => m.id === messageId);
|
|
69
|
+
if (!message) {
|
|
70
|
+
throw new Error(`Message ${messageId} not found in conversation history`);
|
|
71
|
+
}
|
|
72
|
+
// Complete the message with response data
|
|
73
|
+
message.response = {
|
|
74
|
+
content,
|
|
75
|
+
events,
|
|
76
|
+
completedAt: new Date().toISOString(),
|
|
77
|
+
};
|
|
78
|
+
history.lastUpdated = new Date().toISOString();
|
|
79
|
+
// Save to file
|
|
80
|
+
await this.saveConversationHistory(threadPath, history);
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Gets the conversation history for a thread
|
|
84
|
+
*/
|
|
85
|
+
async getConversationHistory(threadPath) {
|
|
86
|
+
try {
|
|
87
|
+
const filePath = this.getConversationFilePath(threadPath);
|
|
88
|
+
const content = await fs.readFile(filePath, 'utf-8');
|
|
89
|
+
return JSON.parse(content);
|
|
90
|
+
}
|
|
91
|
+
catch (error) {
|
|
92
|
+
if (error instanceof Error && error.code === 'ENOENT') {
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
throw error;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Gets the last N messages from conversation history
|
|
100
|
+
*/
|
|
101
|
+
async getLastMessages(threadPath, count = 1) {
|
|
102
|
+
const history = await this.getConversationHistory(threadPath);
|
|
103
|
+
if (!history || history.messages.length === 0) {
|
|
104
|
+
return [];
|
|
105
|
+
}
|
|
106
|
+
// Return last N messages
|
|
107
|
+
return history.messages.slice(-count);
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Saves conversation history to file
|
|
111
|
+
*/
|
|
112
|
+
async saveConversationHistory(threadPath, history) {
|
|
113
|
+
const filePath = this.getConversationFilePath(threadPath);
|
|
114
|
+
// Ensure all parent directories exist
|
|
115
|
+
await fs.mkdir(dirname(filePath), { recursive: true });
|
|
116
|
+
await fs.writeFile(filePath, JSON.stringify(history, null, 2), 'utf-8');
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Gets the file path for a thread's conversation history in the metadata folder
|
|
120
|
+
* Extracts threadId from threadPath and stores in .metadata/conversations/<threadId>/history.json
|
|
121
|
+
*/
|
|
122
|
+
getConversationFilePath(threadPath) {
|
|
123
|
+
// Extract thread ID from path (last part of the path)
|
|
124
|
+
const threadId = threadPath.split(/[\\/]/).pop() || 'unknown';
|
|
125
|
+
const conversationsDir = join(this.metadataDir, 'conversations');
|
|
126
|
+
return join(conversationsDir, threadId, CONVERSATION_FILE);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
//# sourceMappingURL=ConversationManager.js.map
|