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.
Files changed (119) hide show
  1. package/README.md +1 -7
  2. package/dist/index.d.ts +3 -0
  3. package/dist/index.js +92 -32
  4. package/dist/lib/response-builder.d.ts +50 -0
  5. package/dist/lib/response-builder.js +56 -0
  6. package/dist/lib/stream-helper.d.ts +39 -0
  7. package/dist/lib/stream-helper.js +43 -0
  8. package/dist/managers/ConversationManager.d.ts +83 -0
  9. package/dist/managers/ConversationManager.js +129 -0
  10. package/dist/managers/GitManager.d.ts +133 -0
  11. package/dist/managers/GitManager.js +330 -0
  12. package/dist/managers/MetadataManager.d.ts +139 -0
  13. package/dist/managers/MetadataManager.js +309 -0
  14. package/dist/managers/ModelManager.d.ts +57 -0
  15. package/dist/managers/ModelManager.js +129 -0
  16. package/dist/managers/NeovateExecutor.d.ts +40 -0
  17. package/dist/managers/NeovateExecutor.js +138 -0
  18. package/dist/managers/ProjectManager.d.ts +162 -0
  19. package/dist/managers/ProjectManager.js +353 -0
  20. package/dist/managers/ThreadManager.d.ts +181 -0
  21. package/dist/managers/ThreadManager.js +325 -0
  22. package/dist/managers/conversation-manager.d.ts +83 -0
  23. package/dist/managers/conversation-manager.js +129 -0
  24. package/dist/managers/git-manager.d.ts +133 -0
  25. package/dist/managers/git-manager.js +330 -0
  26. package/dist/managers/metadata-manager.d.ts +139 -0
  27. package/dist/managers/metadata-manager.js +305 -0
  28. package/dist/managers/model-manager.d.ts +59 -0
  29. package/dist/managers/model-manager.js +144 -0
  30. package/dist/managers/neovate-executor.d.ts +43 -0
  31. package/dist/managers/neovate-executor.js +205 -0
  32. package/dist/managers/processing-state-manager.d.ts +40 -0
  33. package/dist/managers/processing-state-manager.js +27 -0
  34. package/dist/managers/project-manager.d.ts +199 -0
  35. package/dist/managers/project-manager.js +465 -0
  36. package/dist/managers/thread-manager.d.ts +193 -0
  37. package/dist/managers/thread-manager.js +368 -0
  38. package/dist/model-info-aihubmix.d.ts +25 -0
  39. package/dist/model-info-aihubmix.js +117 -0
  40. package/dist/model-info-openai.d.ts +17 -0
  41. package/dist/model-info-openai.js +59 -0
  42. package/dist/model-info-openrouter.d.ts +25 -0
  43. package/dist/model-info-openrouter.js +101 -0
  44. package/dist/model-info.d.ts +37 -0
  45. package/dist/model-info.js +39 -0
  46. package/dist/provider-data.d.ts +101 -0
  47. package/dist/provider-data.js +471 -0
  48. package/dist/provider.d.ts +10 -0
  49. package/dist/provider.js +192 -0
  50. package/dist/public/android-chrome-192x192.png +0 -0
  51. package/dist/public/android-chrome-512x512.png +0 -0
  52. package/dist/public/apple-touch-icon.png +0 -0
  53. package/dist/public/assets/index-B443aj9k.js +8506 -0
  54. package/dist/public/assets/index-CjXGVbI7.css +1 -0
  55. package/dist/public/assets/index-DJC-p914.js +8506 -0
  56. package/dist/public/favicon-16x16.png +0 -0
  57. package/dist/public/favicon-32x32.png +0 -0
  58. package/dist/public/favicon.ico +0 -0
  59. package/dist/public/index.html +28 -0
  60. package/dist/public/manifest.json +82 -0
  61. package/dist/public/placeholder-logo.svg +1 -0
  62. package/dist/public/placeholder.svg +1 -0
  63. package/dist/public/snpro.woff2 +0 -0
  64. package/dist/public/tarsk-color.svg +12 -0
  65. package/dist/public/tarsk.png +0 -0
  66. package/dist/public/tarsk.svg +12 -0
  67. package/dist/public/zalando-sans.woff2 +0 -0
  68. package/dist/routes/chat-old.d.ts +21 -0
  69. package/dist/routes/chat-old.js +251 -0
  70. package/dist/routes/chat.d.ts +21 -0
  71. package/dist/routes/chat.js +217 -0
  72. package/dist/routes/git.d.ts +4 -0
  73. package/dist/routes/git.js +668 -0
  74. package/dist/routes/models.d.ts +18 -0
  75. package/dist/routes/models.js +128 -0
  76. package/dist/routes/projects-old.d.ts +20 -0
  77. package/dist/routes/projects-old.js +297 -0
  78. package/dist/routes/projects.d.ts +20 -0
  79. package/dist/routes/projects.js +365 -0
  80. package/dist/routes/providers.d.ts +15 -0
  81. package/dist/routes/providers.js +130 -0
  82. package/dist/routes/threads-old.d.ts +14 -0
  83. package/dist/routes/threads-old.js +393 -0
  84. package/dist/routes/threads.d.ts +14 -0
  85. package/dist/routes/threads.js +352 -0
  86. package/dist/types/models.d.ts +315 -0
  87. package/dist/types/models.js +11 -0
  88. package/dist/utils/env-manager.d.ts +3 -0
  89. package/dist/utils/env-manager.js +60 -0
  90. package/dist/utils/open-router-models.d.ts +45 -0
  91. package/dist/utils/open-router-models.js +103 -0
  92. package/dist/utils/openai-models.d.ts +63 -0
  93. package/dist/utils/openai-models.js +152 -0
  94. package/dist/utils/openai-pricing-scraper.d.ts +17 -0
  95. package/dist/utils/openai-pricing-scraper.js +185 -0
  96. package/dist/utils/validation.d.ts +10 -0
  97. package/dist/utils/validation.js +20 -0
  98. package/dist/utils.d.ts +10 -0
  99. package/dist/utils.js +12 -0
  100. package/package.json +36 -23
  101. package/LICENSE.md +0 -7
  102. package/dist/agent/agent.js +0 -132
  103. package/dist/agent/interfaces.js +0 -1
  104. package/dist/api/encryption.js +0 -41
  105. package/dist/api/models.js +0 -169
  106. package/dist/api/prompt.js +0 -14
  107. package/dist/api/settings.js +0 -43
  108. package/dist/api/test.js +0 -29
  109. package/dist/api/tools.js +0 -303
  110. package/dist/api/utils.js +0 -18
  111. package/dist/interfaces/meta.js +0 -1
  112. package/dist/interfaces/model.js +0 -1
  113. package/dist/interfaces/settings.js +0 -1
  114. package/dist/log/log.js +0 -42
  115. package/dist/prompt.js +0 -49
  116. package/dist/tools.js +0 -85
  117. package/dist/utils/files.js +0 -14
  118. package/dist/utils/json-file.js +0 -28
  119. package/dist/utils/strip-markdown.js +0 -5
package/README.md CHANGED
@@ -1,9 +1,3 @@
1
1
  # Tarsk
2
2
 
3
- Tarsk is an AI tool available at https://tarsk.io.
4
-
5
- Run `npx tarsk` to launch it.
6
-
7
- ## Details
8
-
9
- This will serve at `http://localhost:4021`
3
+ Run `npx tarsk` to start the Tarsk App.
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -1,40 +1,100 @@
1
1
  #!/usr/bin/env node
2
- import { serve } from "@hono/node-server";
3
- import { Hono } from "hono";
4
- import { cors } from "hono/cors";
5
- import open from 'open';
6
- import { api_prompt } from "./api/prompt.js";
7
- import { api_delete_tool, api_get_tool, api_get_tools, api_run_tool, api_save_tool, } from "./api/tools.js";
8
- import { api_get_settings, api_save_settings } from "./api/settings.js";
9
- import { api_get_models } from "./api/models.js";
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
- app.use("/*", cors({
12
- origin: (origin, c) => {
13
- return (origin.startsWith("http://localhost") ||
14
- origin.startsWith('https://tarsk.io')) ? origin : "x";
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
- app.get("/", (c) => {
18
- return c.text("Tarsk Started.");
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
- app.post("/prompt", async (c) => await api_prompt(c));
21
- app.post("/tools", async (c) => await api_save_tool(c));
22
- app.get("/tools", async (c) => await api_get_tools(c));
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: 4021,
32
- }, (info) => {
33
- if (process.env._ && process.env._.endsWith('tsx')) {
34
- console.log(`Tarsk is running in dev mode on http://localhost:${info.port}`);
35
- }
36
- else {
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