@chrishdx/llm-dev-server 1.0.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 (184) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +164 -0
  3. package/backend/bin/llm-dev-server.js +3 -0
  4. package/backend/dist/cli.d.ts +15 -0
  5. package/backend/dist/cli.d.ts.map +1 -0
  6. package/backend/dist/cli.js +326 -0
  7. package/backend/dist/cli.js.map +1 -0
  8. package/backend/dist/config/database.d.ts +10 -0
  9. package/backend/dist/config/database.d.ts.map +1 -0
  10. package/backend/dist/config/database.js +61 -0
  11. package/backend/dist/config/database.js.map +1 -0
  12. package/backend/dist/config/environment.d.ts +20 -0
  13. package/backend/dist/config/environment.d.ts.map +1 -0
  14. package/backend/dist/config/environment.js +77 -0
  15. package/backend/dist/config/environment.js.map +1 -0
  16. package/backend/dist/controllers/AuthController.d.ts +18 -0
  17. package/backend/dist/controllers/AuthController.d.ts.map +1 -0
  18. package/backend/dist/controllers/AuthController.js +282 -0
  19. package/backend/dist/controllers/AuthController.js.map +1 -0
  20. package/backend/dist/controllers/ConversationController.d.ts +44 -0
  21. package/backend/dist/controllers/ConversationController.d.ts.map +1 -0
  22. package/backend/dist/controllers/ConversationController.js +193 -0
  23. package/backend/dist/controllers/ConversationController.js.map +1 -0
  24. package/backend/dist/controllers/JobController.d.ts +49 -0
  25. package/backend/dist/controllers/JobController.d.ts.map +1 -0
  26. package/backend/dist/controllers/JobController.js +227 -0
  27. package/backend/dist/controllers/JobController.js.map +1 -0
  28. package/backend/dist/index.d.ts +2 -0
  29. package/backend/dist/index.d.ts.map +1 -0
  30. package/backend/dist/index.js +160 -0
  31. package/backend/dist/index.js.map +1 -0
  32. package/backend/dist/middleware/auth.middleware.d.ts +25 -0
  33. package/backend/dist/middleware/auth.middleware.d.ts.map +1 -0
  34. package/backend/dist/middleware/auth.middleware.js +116 -0
  35. package/backend/dist/middleware/auth.middleware.js.map +1 -0
  36. package/backend/dist/middleware/authelia.middleware.d.ts +26 -0
  37. package/backend/dist/middleware/authelia.middleware.d.ts.map +1 -0
  38. package/backend/dist/middleware/authelia.middleware.js +165 -0
  39. package/backend/dist/middleware/authelia.middleware.js.map +1 -0
  40. package/backend/dist/middleware/error.middleware.d.ts +23 -0
  41. package/backend/dist/middleware/error.middleware.d.ts.map +1 -0
  42. package/backend/dist/middleware/error.middleware.js +59 -0
  43. package/backend/dist/middleware/error.middleware.js.map +1 -0
  44. package/backend/dist/models/AuthToken.d.ts +42 -0
  45. package/backend/dist/models/AuthToken.d.ts.map +1 -0
  46. package/backend/dist/models/AuthToken.js +97 -0
  47. package/backend/dist/models/AuthToken.js.map +1 -0
  48. package/backend/dist/models/Conversation.d.ts +36 -0
  49. package/backend/dist/models/Conversation.d.ts.map +1 -0
  50. package/backend/dist/models/Conversation.js +100 -0
  51. package/backend/dist/models/Conversation.js.map +1 -0
  52. package/backend/dist/models/FileOperation.d.ts +36 -0
  53. package/backend/dist/models/FileOperation.d.ts.map +1 -0
  54. package/backend/dist/models/FileOperation.js +117 -0
  55. package/backend/dist/models/FileOperation.js.map +1 -0
  56. package/backend/dist/models/Job.d.ts +48 -0
  57. package/backend/dist/models/Job.d.ts.map +1 -0
  58. package/backend/dist/models/Job.js +87 -0
  59. package/backend/dist/models/Job.js.map +1 -0
  60. package/backend/dist/models/Message.d.ts +38 -0
  61. package/backend/dist/models/Message.d.ts.map +1 -0
  62. package/backend/dist/models/Message.js +87 -0
  63. package/backend/dist/models/Message.js.map +1 -0
  64. package/backend/dist/models/User.d.ts +26 -0
  65. package/backend/dist/models/User.d.ts.map +1 -0
  66. package/backend/dist/models/User.js +67 -0
  67. package/backend/dist/models/User.js.map +1 -0
  68. package/backend/dist/models/index.d.ts +13 -0
  69. package/backend/dist/models/index.d.ts.map +1 -0
  70. package/backend/dist/models/index.js +24 -0
  71. package/backend/dist/models/index.js.map +1 -0
  72. package/backend/dist/routes/auth.routes.d.ts +3 -0
  73. package/backend/dist/routes/auth.routes.d.ts.map +1 -0
  74. package/backend/dist/routes/auth.routes.js +27 -0
  75. package/backend/dist/routes/auth.routes.js.map +1 -0
  76. package/backend/dist/routes/conversation.routes.d.ts +3 -0
  77. package/backend/dist/routes/conversation.routes.d.ts.map +1 -0
  78. package/backend/dist/routes/conversation.routes.js +17 -0
  79. package/backend/dist/routes/conversation.routes.js.map +1 -0
  80. package/backend/dist/routes/filesystem.routes.d.ts +3 -0
  81. package/backend/dist/routes/filesystem.routes.d.ts.map +1 -0
  82. package/backend/dist/routes/filesystem.routes.js +64 -0
  83. package/backend/dist/routes/filesystem.routes.js.map +1 -0
  84. package/backend/dist/routes/index.d.ts +3 -0
  85. package/backend/dist/routes/index.d.ts.map +1 -0
  86. package/backend/dist/routes/index.js +27 -0
  87. package/backend/dist/routes/index.js.map +1 -0
  88. package/backend/dist/routes/job.routes.d.ts +3 -0
  89. package/backend/dist/routes/job.routes.d.ts.map +1 -0
  90. package/backend/dist/routes/job.routes.js +18 -0
  91. package/backend/dist/routes/job.routes.js.map +1 -0
  92. package/backend/dist/services/auth/BaseAuthService.d.ts +49 -0
  93. package/backend/dist/services/auth/BaseAuthService.d.ts.map +1 -0
  94. package/backend/dist/services/auth/BaseAuthService.js +97 -0
  95. package/backend/dist/services/auth/BaseAuthService.js.map +1 -0
  96. package/backend/dist/services/auth/ClaudeAuthService.d.ts +69 -0
  97. package/backend/dist/services/auth/ClaudeAuthService.d.ts.map +1 -0
  98. package/backend/dist/services/auth/ClaudeAuthService.js +401 -0
  99. package/backend/dist/services/auth/ClaudeAuthService.js.map +1 -0
  100. package/backend/dist/services/auth/CodexAuthService.d.ts +37 -0
  101. package/backend/dist/services/auth/CodexAuthService.d.ts.map +1 -0
  102. package/backend/dist/services/auth/CodexAuthService.js +186 -0
  103. package/backend/dist/services/auth/CodexAuthService.js.map +1 -0
  104. package/backend/dist/services/auth/GeminiAuthService.d.ts +50 -0
  105. package/backend/dist/services/auth/GeminiAuthService.d.ts.map +1 -0
  106. package/backend/dist/services/auth/GeminiAuthService.js +284 -0
  107. package/backend/dist/services/auth/GeminiAuthService.js.map +1 -0
  108. package/backend/dist/services/auth/JwtService.d.ts +27 -0
  109. package/backend/dist/services/auth/JwtService.d.ts.map +1 -0
  110. package/backend/dist/services/auth/JwtService.js +65 -0
  111. package/backend/dist/services/auth/JwtService.js.map +1 -0
  112. package/backend/dist/services/auth/TokenRefreshService.d.ts +36 -0
  113. package/backend/dist/services/auth/TokenRefreshService.d.ts.map +1 -0
  114. package/backend/dist/services/auth/TokenRefreshService.js +178 -0
  115. package/backend/dist/services/auth/TokenRefreshService.js.map +1 -0
  116. package/backend/dist/services/conversation/ConversationService.d.ts +89 -0
  117. package/backend/dist/services/conversation/ConversationService.d.ts.map +1 -0
  118. package/backend/dist/services/conversation/ConversationService.js +255 -0
  119. package/backend/dist/services/conversation/ConversationService.js.map +1 -0
  120. package/backend/dist/services/job/JobService.d.ts +83 -0
  121. package/backend/dist/services/job/JobService.d.ts.map +1 -0
  122. package/backend/dist/services/job/JobService.js +213 -0
  123. package/backend/dist/services/job/JobService.js.map +1 -0
  124. package/backend/dist/services/job/WorkingDirectoryService.d.ts +73 -0
  125. package/backend/dist/services/job/WorkingDirectoryService.d.ts.map +1 -0
  126. package/backend/dist/services/job/WorkingDirectoryService.js +289 -0
  127. package/backend/dist/services/job/WorkingDirectoryService.js.map +1 -0
  128. package/backend/dist/services/llm/ClaudeProvider.d.ts +16 -0
  129. package/backend/dist/services/llm/ClaudeProvider.d.ts.map +1 -0
  130. package/backend/dist/services/llm/ClaudeProvider.js +229 -0
  131. package/backend/dist/services/llm/ClaudeProvider.js.map +1 -0
  132. package/backend/dist/services/llm/CodexProvider.d.ts +15 -0
  133. package/backend/dist/services/llm/CodexProvider.d.ts.map +1 -0
  134. package/backend/dist/services/llm/CodexProvider.js +301 -0
  135. package/backend/dist/services/llm/CodexProvider.js.map +1 -0
  136. package/backend/dist/services/llm/GeminiProvider.d.ts +17 -0
  137. package/backend/dist/services/llm/GeminiProvider.d.ts.map +1 -0
  138. package/backend/dist/services/llm/GeminiProvider.js +190 -0
  139. package/backend/dist/services/llm/GeminiProvider.js.map +1 -0
  140. package/backend/dist/services/llm/LLMProviderBase.d.ts +76 -0
  141. package/backend/dist/services/llm/LLMProviderBase.d.ts.map +1 -0
  142. package/backend/dist/services/llm/LLMProviderBase.js +34 -0
  143. package/backend/dist/services/llm/LLMProviderBase.js.map +1 -0
  144. package/backend/dist/services/llm/ProviderFactory.d.ts +17 -0
  145. package/backend/dist/services/llm/ProviderFactory.d.ts.map +1 -0
  146. package/backend/dist/services/llm/ProviderFactory.js +58 -0
  147. package/backend/dist/services/llm/ProviderFactory.js.map +1 -0
  148. package/backend/dist/utils/crypto.d.ts +33 -0
  149. package/backend/dist/utils/crypto.d.ts.map +1 -0
  150. package/backend/dist/utils/crypto.js +165 -0
  151. package/backend/dist/utils/crypto.js.map +1 -0
  152. package/backend/dist/utils/logger.d.ts +4 -0
  153. package/backend/dist/utils/logger.d.ts.map +1 -0
  154. package/backend/dist/utils/logger.js +44 -0
  155. package/backend/dist/utils/logger.js.map +1 -0
  156. package/backend/dist/utils/validators.d.ts +22 -0
  157. package/backend/dist/utils/validators.d.ts.map +1 -0
  158. package/backend/dist/utils/validators.js +127 -0
  159. package/backend/dist/utils/validators.js.map +1 -0
  160. package/backend/package.json +45 -0
  161. package/backend/public/assets/index-C207-KqP.js +188 -0
  162. package/backend/public/index.html +12 -0
  163. package/package.json +96 -0
  164. package/shared/dist/index.d.ts +5 -0
  165. package/shared/dist/index.d.ts.map +1 -0
  166. package/shared/dist/index.js +25 -0
  167. package/shared/dist/index.js.map +1 -0
  168. package/shared/dist/types/api.d.ts +27 -0
  169. package/shared/dist/types/api.d.ts.map +1 -0
  170. package/shared/dist/types/api.js +3 -0
  171. package/shared/dist/types/api.js.map +1 -0
  172. package/shared/dist/types/auth.d.ts +62 -0
  173. package/shared/dist/types/auth.d.ts.map +1 -0
  174. package/shared/dist/types/auth.js +3 -0
  175. package/shared/dist/types/auth.js.map +1 -0
  176. package/shared/dist/types/conversation.d.ts +98 -0
  177. package/shared/dist/types/conversation.d.ts.map +1 -0
  178. package/shared/dist/types/conversation.js +3 -0
  179. package/shared/dist/types/conversation.js.map +1 -0
  180. package/shared/dist/types/job.d.ts +93 -0
  181. package/shared/dist/types/job.d.ts.map +1 -0
  182. package/shared/dist/types/job.js +3 -0
  183. package/shared/dist/types/job.js.map +1 -0
  184. package/shared/package.json +15 -0
@@ -0,0 +1,213 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.JobService = void 0;
7
+ const models_1 = require("../../models");
8
+ const WorkingDirectoryService_1 = require("./WorkingDirectoryService");
9
+ const logger_1 = __importDefault(require("../../utils/logger"));
10
+ class JobService {
11
+ /**
12
+ * Create a new job
13
+ */
14
+ static async createJob(params) {
15
+ // Validate and create working directory
16
+ const workingDir = await WorkingDirectoryService_1.WorkingDirectoryService.validateAndCreate(params.workingDirectory);
17
+ // Create job
18
+ const job = await models_1.Job.create({
19
+ name: params.name,
20
+ description: params.description,
21
+ workingDirectory: workingDir,
22
+ systemPrompt: params.systemPrompt,
23
+ maxBudgetUsd: params.maxBudgetUsd,
24
+ status: "pending",
25
+ conversationCount: 0,
26
+ messageCount: 0,
27
+ });
28
+ logger_1.default.info(`Created job: ${job.id} (${job.name})`);
29
+ return job;
30
+ }
31
+ /**
32
+ * Get job by ID
33
+ */
34
+ static async getJob(jobId) {
35
+ return await models_1.Job.findByPk(jobId);
36
+ }
37
+ /**
38
+ * Get job with conversations
39
+ */
40
+ static async getJobWithConversations(jobId) {
41
+ const job = await models_1.Job.findByPk(jobId);
42
+ if (!job)
43
+ return null;
44
+ const conversations = await models_1.Conversation.findAll({
45
+ where: { jobId },
46
+ order: [["updatedAt", "DESC"]],
47
+ });
48
+ return { job, conversations };
49
+ }
50
+ /**
51
+ * List jobs
52
+ */
53
+ static async listJobs(params) {
54
+ const { status, provider, limit = 20, offset = 0, search } = params;
55
+ const where = {};
56
+ if (status)
57
+ where.status = status;
58
+ if (search) {
59
+ where.name = { $like: `%${search}%` };
60
+ }
61
+ // Build query to filter by provider if specified
62
+ const include = provider
63
+ ? [
64
+ {
65
+ model: models_1.Conversation,
66
+ where: { provider },
67
+ attributes: [],
68
+ required: true,
69
+ },
70
+ ]
71
+ : [];
72
+ const { rows, count } = await models_1.Job.findAndCountAll({
73
+ where,
74
+ include,
75
+ limit,
76
+ offset,
77
+ order: [["createdAt", "DESC"]],
78
+ distinct: true, // Important when using include with hasMany
79
+ });
80
+ return { jobs: rows, total: count };
81
+ }
82
+ /**
83
+ * Update job
84
+ */
85
+ static async updateJob(jobId, params) {
86
+ const job = await models_1.Job.findByPk(jobId);
87
+ if (!job) {
88
+ throw new Error("Job not found");
89
+ }
90
+ const updates = {};
91
+ if (params.name !== undefined)
92
+ updates.name = params.name;
93
+ if (params.description !== undefined)
94
+ updates.description = params.description;
95
+ if (params.status !== undefined) {
96
+ updates.status = params.status;
97
+ // Update timestamps based on status
98
+ if (params.status === "running" && !job.startedAt) {
99
+ updates.startedAt = new Date();
100
+ }
101
+ if (["completed", "failed", "cancelled"].includes(params.status)) {
102
+ updates.completedAt = new Date();
103
+ }
104
+ }
105
+ if (params.systemPrompt !== undefined)
106
+ updates.systemPrompt = params.systemPrompt;
107
+ if (params.maxBudgetUsd !== undefined)
108
+ updates.maxBudgetUsd = params.maxBudgetUsd;
109
+ await job.update(updates);
110
+ logger_1.default.info(`Updated job: ${jobId}`);
111
+ return job;
112
+ }
113
+ /**
114
+ * Update job statistics (conversation and message counts)
115
+ */
116
+ static async updateJobStatistics(jobId) {
117
+ const job = await models_1.Job.findByPk(jobId);
118
+ if (!job)
119
+ return;
120
+ const conversationCount = await models_1.Conversation.count({ where: { jobId } });
121
+ const messageCount = await models_1.Message.count({
122
+ include: [
123
+ {
124
+ model: models_1.Conversation,
125
+ where: { jobId },
126
+ attributes: [],
127
+ as: "conversation",
128
+ },
129
+ ],
130
+ });
131
+ await job.update({ conversationCount, messageCount });
132
+ }
133
+ /**
134
+ * Delete job
135
+ */
136
+ static async deleteJob(jobId) {
137
+ const job = await models_1.Job.findByPk(jobId);
138
+ if (!job) {
139
+ throw new Error("Job not found");
140
+ }
141
+ await job.destroy();
142
+ logger_1.default.info(`Deleted job: ${jobId}`);
143
+ }
144
+ /**
145
+ * Get job statistics
146
+ */
147
+ static async getJobStatistics(jobId) {
148
+ const [messageCount, conversationCount, fileOpCount] = await Promise.all([
149
+ models_1.Message.count({
150
+ include: [
151
+ {
152
+ model: models_1.Conversation,
153
+ where: { jobId },
154
+ attributes: [],
155
+ as: "conversation",
156
+ },
157
+ ],
158
+ }),
159
+ models_1.Conversation.count({ where: { jobId } }),
160
+ models_1.FileOperation.count({ where: { jobId } }),
161
+ ]);
162
+ // Calculate total token usage from all conversations
163
+ const conversations = await models_1.Conversation.findAll({
164
+ where: { jobId },
165
+ attributes: ["totalTokens", "provider"],
166
+ });
167
+ const totalTokens = conversations.reduce((sum, conv) => sum + (conv.totalTokens || 0), 0);
168
+ // Calculate provider breakdown
169
+ const providerMap = new Map();
170
+ for (const conv of conversations) {
171
+ const existing = providerMap.get(conv.provider) || {
172
+ conversationCount: 0,
173
+ messageCount: 0,
174
+ };
175
+ existing.conversationCount++;
176
+ providerMap.set(conv.provider, existing);
177
+ }
178
+ // Get message counts per provider
179
+ for (const [provider, stats] of providerMap) {
180
+ const providerConversations = conversations.filter((c) => c.provider === provider);
181
+ const providerMessageCount = await models_1.Message.count({
182
+ where: {
183
+ conversationId: providerConversations.map((c) => c.id),
184
+ },
185
+ });
186
+ stats.messageCount = providerMessageCount;
187
+ }
188
+ const providerBreakdown = Array.from(providerMap.entries()).map(([provider, stats]) => ({
189
+ provider,
190
+ ...stats,
191
+ }));
192
+ return {
193
+ messageCount,
194
+ conversationCount,
195
+ fileOperations: fileOpCount,
196
+ tokenUsage: {
197
+ input: 0, // Would need to aggregate from messages
198
+ output: 0,
199
+ total: totalTokens,
200
+ },
201
+ providerBreakdown,
202
+ };
203
+ }
204
+ /**
205
+ * Cancel job
206
+ */
207
+ static async cancelJob(jobId) {
208
+ return await this.updateJob(jobId, { status: "cancelled" });
209
+ }
210
+ }
211
+ exports.JobService = JobService;
212
+ exports.default = JobService;
213
+ //# sourceMappingURL=JobService.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"JobService.js","sourceRoot":"","sources":["../../../src/services/job/JobService.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,73 @@
1
+ export interface FileInfo {
2
+ name: string;
3
+ path: string;
4
+ size: number;
5
+ modified: Date;
6
+ }
7
+ export interface DirectoryEntry {
8
+ name: string;
9
+ path: string;
10
+ isDirectory: boolean;
11
+ size?: number;
12
+ modified?: string;
13
+ isReadable: boolean;
14
+ isWritable: boolean;
15
+ }
16
+ export interface BrowseResult {
17
+ currentPath: string;
18
+ parentPath: string | null;
19
+ entries: DirectoryEntry[];
20
+ roots: {
21
+ name: string;
22
+ path: string;
23
+ }[];
24
+ }
25
+ export declare class WorkingDirectoryService {
26
+ /**
27
+ * Get available root directories for browsing
28
+ */
29
+ static getRoots(): {
30
+ name: string;
31
+ path: string;
32
+ }[];
33
+ /**
34
+ * Check if a path is allowed for browsing
35
+ */
36
+ static isPathAllowed(targetPath: string): boolean;
37
+ /**
38
+ * Browse directory on the server
39
+ */
40
+ static browse(targetPath?: string): Promise<BrowseResult>;
41
+ /**
42
+ * Create a new directory
43
+ */
44
+ static createDirectory(parentPath: string, name: string): Promise<string>;
45
+ /**
46
+ * Validate and create working directory
47
+ */
48
+ static validateAndCreate(workingDir: string): Promise<string>;
49
+ /**
50
+ * List files in directory
51
+ */
52
+ static listFiles(workingDir: string, subPath?: string, recursive?: boolean): Promise<{
53
+ files: FileInfo[];
54
+ directories: string[];
55
+ }>;
56
+ /**
57
+ * Read file content
58
+ */
59
+ static readFile(workingDir: string, filePath: string): Promise<{
60
+ content: string;
61
+ mimeType: string;
62
+ }>;
63
+ /**
64
+ * Write file
65
+ */
66
+ static writeFile(workingDir: string, filePath: string, content: string | Buffer): Promise<string>;
67
+ /**
68
+ * Get MIME type from file path
69
+ */
70
+ private static getMimeType;
71
+ }
72
+ export default WorkingDirectoryService;
73
+ //# sourceMappingURL=WorkingDirectoryService.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WorkingDirectoryService.d.ts","sourceRoot":"","sources":["../../../src/services/job/WorkingDirectoryService.ts"],"names":[],"mappings":"AAoBA,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,IAAI,CAAC;CAChB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,OAAO,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,OAAO,CAAC;IACpB,UAAU,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,YAAY;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,OAAO,EAAE,cAAc,EAAE,CAAC;IAC1B,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CACzC;AAED,qBAAa,uBAAuB;IAClC;;OAEG;IACH,MAAM,CAAC,QAAQ,IAAI;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE;IAQnD;;OAEG;IACH,MAAM,CAAC,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO;IAajD;;OAEG;WACU,MAAM,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IA4F/D;;OAEG;WACU,eAAe,CAC1B,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,MAAM,CAAC;IA6BlB;;OAEG;WACU,iBAAiB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAgCnE;;OAEG;WACU,SAAS,CACpB,UAAU,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE,MAAM,EAChB,SAAS,UAAQ,GAChB,OAAO,CAAC;QAAE,KAAK,EAAE,QAAQ,EAAE,CAAC;QAAC,WAAW,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IA4CxD;;OAEG;WACU,QAAQ,CACnB,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;IAoBjD;;OAEG;WACU,SAAS,CACpB,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,GAAG,MAAM,GACvB,OAAO,CAAC,MAAM,CAAC;IAoBlB;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,WAAW;CAqB3B;AAED,eAAe,uBAAuB,CAAC"}
@@ -0,0 +1,289 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.WorkingDirectoryService = void 0;
7
+ const path_1 = __importDefault(require("path"));
8
+ const promises_1 = __importDefault(require("fs/promises"));
9
+ const os_1 = __importDefault(require("os"));
10
+ const logger_1 = __importDefault(require("../../utils/logger"));
11
+ const environment_1 = __importDefault(require("../../config/environment"));
12
+ // Directories that are completely forbidden
13
+ const FORBIDDEN_DIRECTORIES = [
14
+ "/etc",
15
+ "/usr",
16
+ "/System",
17
+ "/bin",
18
+ "/sbin",
19
+ "/var",
20
+ "/private",
21
+ ];
22
+ // Base directories that users can browse from
23
+ const ALLOWED_BROWSE_ROOTS = [environment_1.default.WORKING_DIR_BASE, os_1.default.homedir(), "/tmp"];
24
+ class WorkingDirectoryService {
25
+ /**
26
+ * Get available root directories for browsing
27
+ */
28
+ static getRoots() {
29
+ return [
30
+ { name: "Workspaces", path: path_1.default.resolve(environment_1.default.WORKING_DIR_BASE) },
31
+ { name: "Home", path: os_1.default.homedir() },
32
+ { name: "Temp", path: "/tmp" },
33
+ ];
34
+ }
35
+ /**
36
+ * Check if a path is allowed for browsing
37
+ */
38
+ static isPathAllowed(targetPath) {
39
+ const absolutePath = path_1.default.resolve(targetPath);
40
+ // Check against forbidden directories
41
+ for (const forbidden of FORBIDDEN_DIRECTORIES) {
42
+ if (absolutePath.startsWith(forbidden) && absolutePath !== os_1.default.homedir()) {
43
+ return false;
44
+ }
45
+ }
46
+ return true;
47
+ }
48
+ /**
49
+ * Browse directory on the server
50
+ */
51
+ static async browse(targetPath) {
52
+ const roots = this.getRoots();
53
+ // Default to workspaces directory
54
+ let currentPath = targetPath
55
+ ? path_1.default.resolve(targetPath)
56
+ : path_1.default.resolve(environment_1.default.WORKING_DIR_BASE);
57
+ // Security check
58
+ if (!this.isPathAllowed(currentPath)) {
59
+ throw new Error(`Access to ${currentPath} is not allowed`);
60
+ }
61
+ // Check if directory exists, if not fall back to workspaces
62
+ try {
63
+ const stats = await promises_1.default.stat(currentPath);
64
+ if (!stats.isDirectory()) {
65
+ currentPath = path_1.default.dirname(currentPath);
66
+ }
67
+ }
68
+ catch {
69
+ currentPath = path_1.default.resolve(environment_1.default.WORKING_DIR_BASE);
70
+ // Create if doesn't exist
71
+ await promises_1.default.mkdir(currentPath, { recursive: true, mode: 0o755 });
72
+ }
73
+ // Get parent path
74
+ const parentPath = path_1.default.dirname(currentPath);
75
+ const hasParent = parentPath !== currentPath && this.isPathAllowed(parentPath);
76
+ // Read directory entries
77
+ const entries = [];
78
+ try {
79
+ const dirEntries = await promises_1.default.readdir(currentPath, { withFileTypes: true });
80
+ for (const entry of dirEntries) {
81
+ // Skip hidden files/directories (starting with .)
82
+ if (entry.name.startsWith("."))
83
+ continue;
84
+ const entryPath = path_1.default.join(currentPath, entry.name);
85
+ let isReadable = false;
86
+ let isWritable = false;
87
+ let size;
88
+ let modified;
89
+ try {
90
+ await promises_1.default.access(entryPath, promises_1.default.constants.R_OK);
91
+ isReadable = true;
92
+ }
93
+ catch { }
94
+ try {
95
+ await promises_1.default.access(entryPath, promises_1.default.constants.W_OK);
96
+ isWritable = true;
97
+ }
98
+ catch { }
99
+ try {
100
+ const stats = await promises_1.default.stat(entryPath);
101
+ size = stats.size;
102
+ modified = stats.mtime.toISOString();
103
+ }
104
+ catch { }
105
+ entries.push({
106
+ name: entry.name,
107
+ path: entryPath,
108
+ isDirectory: entry.isDirectory(),
109
+ size,
110
+ modified,
111
+ isReadable,
112
+ isWritable,
113
+ });
114
+ }
115
+ // Sort: directories first, then alphabetically
116
+ entries.sort((a, b) => {
117
+ if (a.isDirectory && !b.isDirectory)
118
+ return -1;
119
+ if (!a.isDirectory && b.isDirectory)
120
+ return 1;
121
+ return a.name.localeCompare(b.name);
122
+ });
123
+ }
124
+ catch (error) {
125
+ logger_1.default.error(`Failed to browse directory ${currentPath}:`, error);
126
+ throw new Error(`Cannot read directory: ${currentPath}`);
127
+ }
128
+ return {
129
+ currentPath,
130
+ parentPath: hasParent ? parentPath : null,
131
+ entries,
132
+ roots,
133
+ };
134
+ }
135
+ /**
136
+ * Create a new directory
137
+ */
138
+ static async createDirectory(parentPath, name) {
139
+ const absoluteParent = path_1.default.resolve(parentPath);
140
+ if (!this.isPathAllowed(absoluteParent)) {
141
+ throw new Error(`Access to ${absoluteParent} is not allowed`);
142
+ }
143
+ // Validate name
144
+ if (!name ||
145
+ name.includes("/") ||
146
+ name.includes("\\") ||
147
+ name.startsWith(".")) {
148
+ throw new Error("Invalid directory name");
149
+ }
150
+ const newDirPath = path_1.default.join(absoluteParent, name);
151
+ try {
152
+ await promises_1.default.mkdir(newDirPath, { recursive: true, mode: 0o755 });
153
+ logger_1.default.info(`Created directory: ${newDirPath}`);
154
+ return newDirPath;
155
+ }
156
+ catch (error) {
157
+ const message = error instanceof Error ? error.message : String(error);
158
+ throw new Error(`Failed to create directory: ${message}`);
159
+ }
160
+ }
161
+ /**
162
+ * Validate and create working directory
163
+ */
164
+ static async validateAndCreate(workingDir) {
165
+ // Resolve to absolute path
166
+ const absolutePath = path_1.default.resolve(workingDir);
167
+ // Security check: prevent access to sensitive directories
168
+ for (const forbidden of FORBIDDEN_DIRECTORIES) {
169
+ if (absolutePath.startsWith(forbidden)) {
170
+ throw new Error(`Access to ${forbidden} is forbidden`);
171
+ }
172
+ }
173
+ // Create directory if it doesn't exist
174
+ try {
175
+ await promises_1.default.mkdir(absolutePath, { recursive: true, mode: 0o755 });
176
+ }
177
+ catch (error) {
178
+ const message = error instanceof Error ? error.message : String(error);
179
+ throw new Error(`Failed to create directory: ${message}`);
180
+ }
181
+ // Verify write permissions
182
+ const testFile = path_1.default.join(absolutePath, `.write-test-${Date.now()}`);
183
+ try {
184
+ await promises_1.default.writeFile(testFile, "test", "utf8");
185
+ await promises_1.default.unlink(testFile);
186
+ }
187
+ catch (error) {
188
+ throw new Error(`Working directory ${absolutePath} is not writable`);
189
+ }
190
+ logger_1.default.info(`Validated working directory: ${absolutePath}`);
191
+ return absolutePath;
192
+ }
193
+ /**
194
+ * List files in directory
195
+ */
196
+ static async listFiles(workingDir, subPath, recursive = false) {
197
+ const targetDir = subPath ? path_1.default.join(workingDir, subPath) : workingDir;
198
+ // Security check
199
+ if (!targetDir.startsWith(workingDir)) {
200
+ throw new Error("Path traversal detected");
201
+ }
202
+ const entries = await promises_1.default.readdir(targetDir, { withFileTypes: true });
203
+ const files = [];
204
+ const directories = [];
205
+ for (const entry of entries) {
206
+ if (entry.isDirectory()) {
207
+ directories.push(entry.name);
208
+ if (recursive) {
209
+ const subFiles = await this.listFiles(workingDir, path_1.default.join(subPath || "", entry.name), true);
210
+ files.push(...subFiles.files);
211
+ directories.push(...subFiles.directories.map((d) => path_1.default.join(entry.name, d)));
212
+ }
213
+ }
214
+ else if (entry.isFile()) {
215
+ const fullPath = path_1.default.join(targetDir, entry.name);
216
+ const stats = await promises_1.default.stat(fullPath);
217
+ files.push({
218
+ name: entry.name,
219
+ path: path_1.default.relative(workingDir, fullPath),
220
+ size: stats.size,
221
+ modified: stats.mtime,
222
+ });
223
+ }
224
+ }
225
+ return { files, directories };
226
+ }
227
+ /**
228
+ * Read file content
229
+ */
230
+ static async readFile(workingDir, filePath) {
231
+ const absolutePath = path_1.default.join(workingDir, filePath);
232
+ // Security check
233
+ if (!absolutePath.startsWith(workingDir)) {
234
+ throw new Error("Path traversal detected");
235
+ }
236
+ try {
237
+ await promises_1.default.access(absolutePath, promises_1.default.constants.R_OK);
238
+ }
239
+ catch {
240
+ throw new Error("File not found");
241
+ }
242
+ const content = await promises_1.default.readFile(absolutePath, "utf8");
243
+ const mimeType = this.getMimeType(absolutePath);
244
+ return { content, mimeType };
245
+ }
246
+ /**
247
+ * Write file
248
+ */
249
+ static async writeFile(workingDir, filePath, content) {
250
+ const absolutePath = path_1.default.join(workingDir, filePath);
251
+ // Security check
252
+ if (!absolutePath.startsWith(workingDir)) {
253
+ throw new Error("Path traversal detected");
254
+ }
255
+ // Create parent directory
256
+ await promises_1.default.mkdir(path_1.default.dirname(absolutePath), {
257
+ recursive: true,
258
+ mode: 0o755,
259
+ });
260
+ // Write file
261
+ await promises_1.default.writeFile(absolutePath, content, { mode: 0o644 });
262
+ return path_1.default.relative(workingDir, absolutePath);
263
+ }
264
+ /**
265
+ * Get MIME type from file path
266
+ */
267
+ static getMimeType(filePath) {
268
+ const ext = path_1.default.extname(filePath).toLowerCase();
269
+ const mimeTypes = {
270
+ ".txt": "text/plain",
271
+ ".md": "text/markdown",
272
+ ".json": "application/json",
273
+ ".js": "text/javascript",
274
+ ".ts": "text/typescript",
275
+ ".tsx": "text/typescript",
276
+ ".jsx": "text/javascript",
277
+ ".py": "text/x-python",
278
+ ".html": "text/html",
279
+ ".css": "text/css",
280
+ ".yaml": "text/yaml",
281
+ ".yml": "text/yaml",
282
+ ".xml": "text/xml",
283
+ };
284
+ return mimeTypes[ext] || "application/octet-stream";
285
+ }
286
+ }
287
+ exports.WorkingDirectoryService = WorkingDirectoryService;
288
+ exports.default = WorkingDirectoryService;
289
+ //# sourceMappingURL=WorkingDirectoryService.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WorkingDirectoryService.js","sourceRoot":"","sources":["../../../src/services/job/WorkingDirectoryService.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ import { LLMProviderBase, LLMProviderConfig, SendMessageParams, SendMessageResult, ProviderStatus } from "./LLMProviderBase";
2
+ export declare class ClaudeProvider extends LLMProviderBase {
3
+ private currentSessionId?;
4
+ constructor(providerConfig: LLMProviderConfig);
5
+ initialize(): Promise<void>;
6
+ sendMessage(params: SendMessageParams): Promise<SendMessageResult>;
7
+ private handleJsonResponse;
8
+ private handleStreamingResponse;
9
+ resumeSession(sessionId: string): Promise<boolean>;
10
+ endSession(): Promise<void>;
11
+ getStatus(): Promise<ProviderStatus>;
12
+ cleanup(): Promise<void>;
13
+ private resolveClaudeCli;
14
+ }
15
+ export default ClaudeProvider;
16
+ //# sourceMappingURL=ClaudeProvider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ClaudeProvider.d.ts","sourceRoot":"","sources":["../../../src/services/llm/ClaudeProvider.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,eAAe,EACf,iBAAiB,EACjB,iBAAiB,EACjB,iBAAiB,EACjB,cAAc,EACf,MAAM,mBAAmB,CAAC;AAqB3B,qBAAa,cAAe,SAAQ,eAAe;IACjD,OAAO,CAAC,gBAAgB,CAAC,CAAS;gBAEtB,cAAc,EAAE,iBAAiB;IAIvC,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAgC3B,WAAW,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,iBAAiB,CAAC;YAyD1D,kBAAkB;YAuFlB,uBAAuB;IAkD/B,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAMlD,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAK3B,SAAS,IAAI,OAAO,CAAC,cAAc,CAAC;IAQpC,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAK9B,OAAO,CAAC,gBAAgB;CAuBzB;AAED,eAAe,cAAc,CAAC"}