@straiffi/archon 1.2.8 → 1.2.10
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/dist/client/assets/{TestsDialog-XEE4TEv4.js → TestsDialog-BPHhOIWL.js} +1 -1
- package/dist/client/assets/{badge-RYXMXLW8.js → badge-DtLPY3ow.js} +12 -12
- package/dist/client/assets/index-FvaV49M1.js +149 -0
- package/dist/client/assets/index-Qf62KDwt.css +2 -0
- package/dist/client/index.html +3 -3
- package/dist/server/db.js +33 -0
- package/dist/server/db.js.map +1 -1
- package/dist/server/index.js +120 -3
- package/dist/server/index.js.map +1 -1
- package/dist/server/lib/agent.js +2 -2
- package/dist/server/lib/agent.js.map +1 -1
- package/dist/server/lib/attachments.js +202 -0
- package/dist/server/lib/attachments.js.map +1 -0
- package/dist/server/lib/buildFlow.js +1 -1
- package/dist/server/lib/buildFlow.js.map +1 -1
- package/dist/server/lib/chatMessages.js +4 -1
- package/dist/server/lib/chatMessages.js.map +1 -1
- package/dist/server/lib/chatOperations.js +33 -11
- package/dist/server/lib/chatOperations.js.map +1 -1
- package/dist/server/lib/chatTargets.js +11 -0
- package/dist/server/lib/chatTargets.js.map +1 -1
- package/dist/server/lib/chats.js +21 -4
- package/dist/server/lib/chats.js.map +1 -1
- package/dist/server/lib/runtimePaths.js +7 -0
- package/dist/server/lib/runtimePaths.js.map +1 -1
- package/dist/server/lib/thinkingState.js +67 -0
- package/dist/server/lib/thinkingState.js.map +1 -0
- package/dist/server/lib/ticketUndo.js +2 -2
- package/dist/server/lib/ticketUndo.js.map +1 -1
- package/dist/server/lib/ticketWorkflowOperations.js +1 -1
- package/dist/server/lib/ticketWorkflowOperations.js.map +1 -1
- package/dist/server/lib/tickets.js +6 -0
- package/dist/server/lib/tickets.js.map +1 -1
- package/dist/server/workers/build.js +6 -1
- package/dist/server/workers/build.js.map +1 -1
- package/dist/server/workers/chat.js +55 -9
- package/dist/server/workers/chat.js.map +1 -1
- package/dist/server/workers/followUp.js +6 -1
- package/dist/server/workers/followUp.js.map +1 -1
- package/dist/server/workers/plan.js +7 -2
- package/dist/server/workers/plan.js.map +1 -1
- package/dist/server/workers/planFollowUp.js +7 -2
- package/dist/server/workers/planFollowUp.js.map +1 -1
- package/dist/server/workers/review.js +5 -0
- package/dist/server/workers/review.js.map +1 -1
- package/package.json +5 -2
- package/dist/client/assets/index-BAYGY5L6.js +0 -149
- package/dist/client/assets/index-DWMCGEsT.css +0 -2
package/dist/server/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import express from 'express';
|
|
2
|
+
import multer from 'multer';
|
|
2
3
|
import { existsSync } from 'fs';
|
|
3
4
|
import { createServer } from 'http';
|
|
4
5
|
import { fileURLToPath } from 'url';
|
|
@@ -8,6 +9,7 @@ import cors from 'cors';
|
|
|
8
9
|
import { adjectives, animals, uniqueNamesGenerator } from 'unique-names-generator';
|
|
9
10
|
import db from './db.js';
|
|
10
11
|
import { deleteChatSession, getChatSession, listChatSessions, updateChatSessionMode } from './lib/chats.js';
|
|
12
|
+
import { createChatAttachment, deleteChatAttachment, getChatAttachmentById, getChatAttachmentForSession, getChatAttachmentLinkedMessageId, MAX_CHAT_ATTACHMENTS_PER_TURN, MAX_CHAT_ATTACHMENT_SIZE_BYTES, readChatAttachmentContent, validateImageAttachment, } from './lib/attachments.js';
|
|
11
13
|
import { createProjectChatSession, resolveChatMode, resolveChatTool, stopProjectChatSessionResponse, submitProjectChatSessionMessage, } from './lib/chatOperations.js';
|
|
12
14
|
import { resolveChatSessionTarget } from './lib/chatTargets.js';
|
|
13
15
|
import { createChatMessage, getChatMessage, updateChatMessageContent } from './lib/chatMessages.js';
|
|
@@ -275,6 +277,24 @@ const asTrimmedString = (value) => {
|
|
|
275
277
|
return typeof value === 'string' ? value.trim() : '';
|
|
276
278
|
};
|
|
277
279
|
const COMMIT_MESSAGE_DIFF_CHAR_LIMIT = 12_000;
|
|
280
|
+
const chatAttachmentUpload = multer({
|
|
281
|
+
storage: multer.memoryStorage(),
|
|
282
|
+
limits: {
|
|
283
|
+
files: MAX_CHAT_ATTACHMENTS_PER_TURN,
|
|
284
|
+
fileSize: MAX_CHAT_ATTACHMENT_SIZE_BYTES,
|
|
285
|
+
},
|
|
286
|
+
});
|
|
287
|
+
const getChatAttachmentUploadErrorMessage = (error) => {
|
|
288
|
+
if (error instanceof multer.MulterError) {
|
|
289
|
+
if (error.code === 'LIMIT_FILE_COUNT') {
|
|
290
|
+
return 'You can attach up to 4 images per turn.';
|
|
291
|
+
}
|
|
292
|
+
if (error.code === 'LIMIT_FILE_SIZE') {
|
|
293
|
+
return 'Images must be 10 MB or smaller.';
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
return 'Unable to upload the selected images right now.';
|
|
297
|
+
};
|
|
278
298
|
const normalizeGeneratedCommitMessage = (value) => {
|
|
279
299
|
const firstLine = value
|
|
280
300
|
.replace(/\r/g, '\n')
|
|
@@ -871,12 +891,12 @@ const listBundleConversationTickets = (projectId, bundleId) => {
|
|
|
871
891
|
};
|
|
872
892
|
const moveBundleTicketToReview = (ticket) => {
|
|
873
893
|
const laneOrder = assignTicketLaneOrder({ ...ticket, state: 'review' });
|
|
874
|
-
db.prepare('UPDATE tickets SET state = ?, tool = ?, agent_status = NULL,
|
|
894
|
+
db.prepare('UPDATE tickets SET state = ?, tool = ?, agent_status = NULL, streaming_response = NULL, lane_order = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?').run('review', resolveTicketTool(ticket, config.tool ?? 'opencode'), laneOrder ?? null, ticket.id);
|
|
875
895
|
return getTicket(ticket.id);
|
|
876
896
|
};
|
|
877
897
|
const restoreBundleReviewTicketToBuild = (ticket) => {
|
|
878
898
|
const laneOrder = assignTicketLaneOrder({ ...ticket, state: 'build' });
|
|
879
|
-
db.prepare('UPDATE tickets SET state = ?, agent_status = ?,
|
|
899
|
+
db.prepare('UPDATE tickets SET state = ?, agent_status = ?, streaming_response = NULL, lane_order = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?').run('build', 'done', laneOrder ?? null, ticket.id);
|
|
880
900
|
return getTicket(ticket.id);
|
|
881
901
|
};
|
|
882
902
|
const resolveBundleLatestSessionTicket = (tickets) => {
|
|
@@ -2164,6 +2184,103 @@ app.post('/projects/:id/chat-sessions/:sessionId/messages', (req, res) => {
|
|
|
2164
2184
|
}
|
|
2165
2185
|
return res.status(result.status).json(result.value);
|
|
2166
2186
|
});
|
|
2187
|
+
app.post('/projects/:id/chat-sessions/:sessionId/attachments', (req, res) => {
|
|
2188
|
+
const project = getProjectById(req.params.id);
|
|
2189
|
+
if (!project) {
|
|
2190
|
+
return res.status(404).json({ error: 'Not found' });
|
|
2191
|
+
}
|
|
2192
|
+
const chatSession = getProjectChatSession(project.id, req.params.sessionId);
|
|
2193
|
+
if (!chatSession) {
|
|
2194
|
+
return res.status(404).json({ error: 'Not found' });
|
|
2195
|
+
}
|
|
2196
|
+
if (chatSession.agent_status === 'running') {
|
|
2197
|
+
return res.status(409).json({ error: 'Wait for the current chat response to finish before uploading images.' });
|
|
2198
|
+
}
|
|
2199
|
+
return chatAttachmentUpload.array('files', MAX_CHAT_ATTACHMENTS_PER_TURN)(req, res, error => {
|
|
2200
|
+
if (error) {
|
|
2201
|
+
return res.status(400).json({ error: getChatAttachmentUploadErrorMessage(error) });
|
|
2202
|
+
}
|
|
2203
|
+
const files = (req.files ?? []);
|
|
2204
|
+
if (files.length === 0) {
|
|
2205
|
+
return res.status(400).json({ error: 'At least one image is required.' });
|
|
2206
|
+
}
|
|
2207
|
+
for (const file of files) {
|
|
2208
|
+
const validationError = validateImageAttachment({
|
|
2209
|
+
mimeType: file.mimetype,
|
|
2210
|
+
originalName: file.originalname,
|
|
2211
|
+
});
|
|
2212
|
+
if (validationError) {
|
|
2213
|
+
return res.status(400).json({ error: validationError });
|
|
2214
|
+
}
|
|
2215
|
+
}
|
|
2216
|
+
const createdAttachmentIds = [];
|
|
2217
|
+
try {
|
|
2218
|
+
const attachments = files.map(file => {
|
|
2219
|
+
const attachment = createChatAttachment({
|
|
2220
|
+
chatSessionId: chatSession.id,
|
|
2221
|
+
originalName: file.originalname,
|
|
2222
|
+
mimeType: file.mimetype,
|
|
2223
|
+
buffer: file.buffer,
|
|
2224
|
+
projectId: project.id,
|
|
2225
|
+
});
|
|
2226
|
+
createdAttachmentIds.push(attachment.id);
|
|
2227
|
+
return attachment;
|
|
2228
|
+
});
|
|
2229
|
+
return res.status(201).json({ attachments });
|
|
2230
|
+
}
|
|
2231
|
+
catch (uploadError) {
|
|
2232
|
+
for (const attachmentId of createdAttachmentIds) {
|
|
2233
|
+
const attachment = getChatAttachmentById(attachmentId);
|
|
2234
|
+
if (!attachment) {
|
|
2235
|
+
continue;
|
|
2236
|
+
}
|
|
2237
|
+
deleteChatAttachment(attachment);
|
|
2238
|
+
}
|
|
2239
|
+
return res.status(500).json({ error: uploadError instanceof Error ? uploadError.message : 'Unable to upload the selected images right now.' });
|
|
2240
|
+
}
|
|
2241
|
+
});
|
|
2242
|
+
});
|
|
2243
|
+
app.delete('/projects/:id/chat-sessions/:sessionId/attachments/:attachmentId', (req, res) => {
|
|
2244
|
+
const project = getProjectById(req.params.id);
|
|
2245
|
+
if (!project) {
|
|
2246
|
+
return res.status(404).json({ error: 'Not found' });
|
|
2247
|
+
}
|
|
2248
|
+
const chatSession = getProjectChatSession(project.id, req.params.sessionId);
|
|
2249
|
+
if (!chatSession) {
|
|
2250
|
+
return res.status(404).json({ error: 'Not found' });
|
|
2251
|
+
}
|
|
2252
|
+
const attachment = getChatAttachmentForSession(req.params.attachmentId, chatSession.id);
|
|
2253
|
+
if (!attachment) {
|
|
2254
|
+
return res.status(404).json({ error: 'Attachment not found' });
|
|
2255
|
+
}
|
|
2256
|
+
if (getChatAttachmentLinkedMessageId(attachment.id)) {
|
|
2257
|
+
return res.status(409).json({ error: 'Sent message attachments cannot be removed.' });
|
|
2258
|
+
}
|
|
2259
|
+
deleteChatAttachment(attachment);
|
|
2260
|
+
return res.json({ ok: true });
|
|
2261
|
+
});
|
|
2262
|
+
app.get('/projects/:id/chat-sessions/:sessionId/attachments/:attachmentId/content', (req, res) => {
|
|
2263
|
+
const project = getProjectById(req.params.id);
|
|
2264
|
+
if (!project) {
|
|
2265
|
+
return res.status(404).json({ error: 'Not found' });
|
|
2266
|
+
}
|
|
2267
|
+
const chatSession = getProjectChatSession(project.id, req.params.sessionId);
|
|
2268
|
+
if (!chatSession) {
|
|
2269
|
+
return res.status(404).json({ error: 'Not found' });
|
|
2270
|
+
}
|
|
2271
|
+
const attachment = getChatAttachmentForSession(req.params.attachmentId, chatSession.id);
|
|
2272
|
+
if (!attachment) {
|
|
2273
|
+
return res.status(404).json({ error: 'Attachment not found' });
|
|
2274
|
+
}
|
|
2275
|
+
try {
|
|
2276
|
+
const content = readChatAttachmentContent(attachment);
|
|
2277
|
+
res.type(attachment.mime_type);
|
|
2278
|
+
return res.send(content);
|
|
2279
|
+
}
|
|
2280
|
+
catch {
|
|
2281
|
+
return res.status(404).json({ error: 'Attachment content not found' });
|
|
2282
|
+
}
|
|
2283
|
+
});
|
|
2167
2284
|
app.post('/projects/:id/chat-sessions/:sessionId/stop', async (req, res) => {
|
|
2168
2285
|
const result = await stopProjectChatSessionResponse({
|
|
2169
2286
|
projectId: req.params.id,
|
|
@@ -4640,7 +4757,7 @@ app.post('/tickets/:id/retry', (req, res) => {
|
|
|
4640
4757
|
if (ticket.agent_status !== 'error') {
|
|
4641
4758
|
return res.status(400).json({ error: 'Ticket is not in error state' });
|
|
4642
4759
|
}
|
|
4643
|
-
db.prepare('UPDATE tickets SET agent_status = NULL, agent_log = NULL, streaming_response = NULL, build_completed_at = NULL, auto_park_dismissed_at = NULL, updated_at = CURRENT_TIMESTAMP WHERE id = ?').run(req.params.id);
|
|
4760
|
+
db.prepare('UPDATE tickets SET agent_status = NULL, agent_log = NULL, agent_message_id = NULL, previous_agent_log = NULL, previous_agent_message_id = NULL, streaming_response = NULL, build_completed_at = NULL, auto_park_dismissed_at = NULL, updated_at = CURRENT_TIMESTAMP WHERE id = ?').run(req.params.id);
|
|
4644
4761
|
const updated = getTicket(req.params.id);
|
|
4645
4762
|
io.emit('ticket:updated', updated);
|
|
4646
4763
|
res.json(updated);
|