@resolveio/server-lib 20.13.11 → 20.14.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/collections/ai-terminal-conversation.collection.d.ts +2 -0
- package/collections/ai-terminal-conversation.collection.js +133 -0
- package/collections/ai-terminal-conversation.collection.js.map +1 -0
- package/collections/ai-terminal-message.collection.d.ts +2 -0
- package/collections/ai-terminal-message.collection.js +113 -0
- package/collections/ai-terminal-message.collection.js.map +1 -0
- package/collections/communication-metric.collection.d.ts +2 -0
- package/collections/communication-metric.collection.js +133 -0
- package/collections/communication-metric.collection.js.map +1 -0
- package/collections/openai-usage-ledger.collection.d.ts +2 -0
- package/collections/openai-usage-ledger.collection.js +120 -0
- package/collections/openai-usage-ledger.collection.js.map +1 -0
- package/managers/communication-metric.manager.d.ts +16 -0
- package/managers/communication-metric.manager.js +134 -0
- package/managers/communication-metric.manager.js.map +1 -0
- package/managers/method.manager.d.ts +2 -0
- package/managers/method.manager.js +162 -45
- package/managers/method.manager.js.map +1 -1
- package/managers/openai-usage-ledger.manager.d.ts +14 -0
- package/managers/openai-usage-ledger.manager.js +137 -0
- package/managers/openai-usage-ledger.manager.js.map +1 -0
- package/managers/subscription.manager.js +2 -0
- package/managers/subscription.manager.js.map +1 -1
- package/methods/ai-terminal.d.ts +1 -0
- package/methods/ai-terminal.js +1200 -0
- package/methods/ai-terminal.js.map +1 -0
- package/methods/report-builder.js +741 -0
- package/methods/report-builder.js.map +1 -1
- package/methods.ts +27 -0
- package/models/ai-terminal-conversation.model.d.ts +16 -0
- package/models/ai-terminal-conversation.model.js +4 -0
- package/models/ai-terminal-conversation.model.js.map +1 -0
- package/models/ai-terminal-message.model.d.ts +22 -0
- package/models/ai-terminal-message.model.js +4 -0
- package/models/ai-terminal-message.model.js.map +1 -0
- package/models/communication-metric.model.d.ts +20 -0
- package/models/communication-metric.model.js +4 -0
- package/models/communication-metric.model.js.map +1 -0
- package/models/openai-usage-ledger.model.d.ts +14 -0
- package/models/openai-usage-ledger.model.js +4 -0
- package/models/openai-usage-ledger.model.js.map +1 -0
- package/package.json +5 -1
- package/public_api.d.ts +13 -0
- package/public_api.js +13 -0
- package/public_api.js.map +1 -1
- package/publications/ai-terminal.d.ts +1 -0
- package/publications/ai-terminal.js +58 -0
- package/publications/ai-terminal.js.map +1 -0
- package/publications.ts +6 -0
- package/services/codex-client.d.ts +81 -0
- package/services/codex-client.js +991 -0
- package/services/codex-client.js.map +1 -0
- package/services/openai-client.d.ts +46 -0
- package/services/openai-client.js +315 -0
- package/services/openai-client.js.map +1 -0
- package/util/common.js +20 -53
- package/util/common.js.map +1 -1
- package/util/tokenizer.d.ts +5 -0
- package/util/tokenizer.js +35 -0
- package/util/tokenizer.js.map +1 -0
|
@@ -0,0 +1,1200 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
12
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
|
|
13
|
+
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
14
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
15
|
+
function step(op) {
|
|
16
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
17
|
+
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
18
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
19
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
20
|
+
switch (op[0]) {
|
|
21
|
+
case 0: case 1: t = op; break;
|
|
22
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
23
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
24
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
25
|
+
default:
|
|
26
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
27
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
28
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
29
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
30
|
+
if (t[2]) _.ops.pop();
|
|
31
|
+
_.trys.pop(); continue;
|
|
32
|
+
}
|
|
33
|
+
op = body.call(thisArg, _);
|
|
34
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
35
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
var __values = (this && this.__values) || function(o) {
|
|
39
|
+
var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
|
|
40
|
+
if (m) return m.call(o);
|
|
41
|
+
if (o && typeof o.length === "number") return {
|
|
42
|
+
next: function () {
|
|
43
|
+
if (o && i >= o.length) o = void 0;
|
|
44
|
+
return { value: o && o[i++], done: !o };
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
|
|
48
|
+
};
|
|
49
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
50
|
+
exports.loadAiTerminalMethods = loadAiTerminalMethods;
|
|
51
|
+
var fs_1 = require("fs");
|
|
52
|
+
var os = require("os");
|
|
53
|
+
var path = require("path");
|
|
54
|
+
var simpl_schema_1 = require("simpl-schema");
|
|
55
|
+
var resolveio_server_app_1 = require("../resolveio-server-app");
|
|
56
|
+
var user_collection_1 = require("../collections/user.collection");
|
|
57
|
+
var ai_terminal_conversation_collection_1 = require("../collections/ai-terminal-conversation.collection");
|
|
58
|
+
var ai_terminal_message_collection_1 = require("../collections/ai-terminal-message.collection");
|
|
59
|
+
var common_1 = require("../util/common");
|
|
60
|
+
var tokenizer_1 = require("../util/tokenizer");
|
|
61
|
+
var openai_client_1 = require("../services/openai-client");
|
|
62
|
+
var codex_client_1 = require("../services/codex-client");
|
|
63
|
+
var openai_usage_ledger_manager_1 = require("../managers/openai-usage-ledger.manager");
|
|
64
|
+
var DEFAULT_MAX_FILE_MB = 50;
|
|
65
|
+
var DEFAULT_MAX_TOTAL_MB = 100;
|
|
66
|
+
var DEFAULT_MAX_ATTACHMENT_CHARS = 12000;
|
|
67
|
+
var DEFAULT_MAX_TOTAL_ATTACHMENT_CHARS = 40000;
|
|
68
|
+
var DEFAULT_CODEX_MODEL = 'gpt-5.2-codex';
|
|
69
|
+
var DEFAULT_CODEX_TIMEOUT_MS = 180000;
|
|
70
|
+
var AI_ASSISTANT_SYSTEM_PROMPT = [
|
|
71
|
+
'You are the ResolveIO in-app AI assistant running with read-only access to the codebase.',
|
|
72
|
+
'- Do not provide code snippets, full code, or file contents.',
|
|
73
|
+
'- Do not modify files, run destructive commands, or access databases.',
|
|
74
|
+
'- Do not access secrets, credentials, or user data.',
|
|
75
|
+
'- Do not assist with hacking, bypassing security, or abuse.',
|
|
76
|
+
'- Prefer high-level explanations and point to file paths or routes.',
|
|
77
|
+
'- If a request is out of scope, offer to create a support ticket with a short summary.',
|
|
78
|
+
'- Keep responses concise and use low reasoning effort.'
|
|
79
|
+
].join('\n');
|
|
80
|
+
var assistantCodexClient = null;
|
|
81
|
+
function loadAiTerminalMethods(methodManager) {
|
|
82
|
+
methodManager.methods({
|
|
83
|
+
aiTerminalConversationCreate: {
|
|
84
|
+
check: new simpl_schema_1.default({
|
|
85
|
+
payload: {
|
|
86
|
+
type: Object,
|
|
87
|
+
blackbox: true
|
|
88
|
+
}
|
|
89
|
+
}),
|
|
90
|
+
function: function (payload) {
|
|
91
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
92
|
+
var now, doc, result;
|
|
93
|
+
return __generator(this, function (_a) {
|
|
94
|
+
switch (_a.label) {
|
|
95
|
+
case 0:
|
|
96
|
+
now = new Date();
|
|
97
|
+
doc = {
|
|
98
|
+
id_client: normalizeOptionalString(payload.id_client),
|
|
99
|
+
id_app: normalizeOptionalString(payload.id_app),
|
|
100
|
+
title: normalizeOptionalString(payload.title) || 'New Conversation',
|
|
101
|
+
mode: normalizeConversationMode(payload.mode),
|
|
102
|
+
branch_enabled: payload.branch_enabled === true,
|
|
103
|
+
branch_name: normalizeOptionalString(payload.branch_name),
|
|
104
|
+
status: normalizeConversationStatus(payload.status),
|
|
105
|
+
profile_id: normalizeOptionalString(payload.profile_id),
|
|
106
|
+
metadata: payload.metadata || {},
|
|
107
|
+
last_message_at: undefined,
|
|
108
|
+
last_message_id: undefined,
|
|
109
|
+
createdAt: now,
|
|
110
|
+
updatedAt: now
|
|
111
|
+
};
|
|
112
|
+
return [4 /*yield*/, ai_terminal_conversation_collection_1.AiTerminalConversations.insertOne(doc)];
|
|
113
|
+
case 1:
|
|
114
|
+
result = _a.sent();
|
|
115
|
+
return [2 /*return*/, { id_conversation: result._id }];
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
},
|
|
121
|
+
aiTerminalConversationUpdate: {
|
|
122
|
+
check: new simpl_schema_1.default({
|
|
123
|
+
id_conversation: {
|
|
124
|
+
type: String
|
|
125
|
+
},
|
|
126
|
+
patch: {
|
|
127
|
+
type: Object,
|
|
128
|
+
blackbox: true
|
|
129
|
+
}
|
|
130
|
+
}),
|
|
131
|
+
function: function (id_conversation, patch) {
|
|
132
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
133
|
+
var update;
|
|
134
|
+
return __generator(this, function (_a) {
|
|
135
|
+
switch (_a.label) {
|
|
136
|
+
case 0:
|
|
137
|
+
update = {
|
|
138
|
+
updatedAt: new Date()
|
|
139
|
+
};
|
|
140
|
+
if (patch.title !== undefined) {
|
|
141
|
+
update.title = normalizeOptionalString(patch.title);
|
|
142
|
+
}
|
|
143
|
+
if (patch.status !== undefined) {
|
|
144
|
+
update.status = normalizeConversationStatus(patch.status);
|
|
145
|
+
}
|
|
146
|
+
if (patch.branch_enabled !== undefined) {
|
|
147
|
+
update.branch_enabled = !!patch.branch_enabled;
|
|
148
|
+
}
|
|
149
|
+
if (patch.branch_name !== undefined) {
|
|
150
|
+
update.branch_name = normalizeOptionalString(patch.branch_name);
|
|
151
|
+
}
|
|
152
|
+
if (patch.profile_id !== undefined) {
|
|
153
|
+
update.profile_id = normalizeOptionalString(patch.profile_id);
|
|
154
|
+
}
|
|
155
|
+
if (patch.metadata !== undefined) {
|
|
156
|
+
update.metadata = patch.metadata || {};
|
|
157
|
+
}
|
|
158
|
+
return [4 /*yield*/, ai_terminal_conversation_collection_1.AiTerminalConversations.updateOne({ _id: id_conversation }, { $set: update })];
|
|
159
|
+
case 1:
|
|
160
|
+
_a.sent();
|
|
161
|
+
return [2 /*return*/, { id_conversation: id_conversation }];
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
},
|
|
167
|
+
aiTerminalConversationDelete: {
|
|
168
|
+
check: new simpl_schema_1.default({
|
|
169
|
+
id_conversation: {
|
|
170
|
+
type: String
|
|
171
|
+
}
|
|
172
|
+
}),
|
|
173
|
+
function: function (id_conversation) {
|
|
174
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
175
|
+
return __generator(this, function (_a) {
|
|
176
|
+
switch (_a.label) {
|
|
177
|
+
case 0: return [4 /*yield*/, ai_terminal_message_collection_1.AiTerminalMessages.deleteMany({ id_conversation: id_conversation })];
|
|
178
|
+
case 1:
|
|
179
|
+
_a.sent();
|
|
180
|
+
return [4 /*yield*/, ai_terminal_conversation_collection_1.AiTerminalConversations.deleteOne({ _id: id_conversation })];
|
|
181
|
+
case 2:
|
|
182
|
+
_a.sent();
|
|
183
|
+
return [2 /*return*/, { id_conversation: id_conversation }];
|
|
184
|
+
}
|
|
185
|
+
});
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
},
|
|
189
|
+
aiTerminalUploadFile: {
|
|
190
|
+
check: new simpl_schema_1.default({
|
|
191
|
+
id_conversation: {
|
|
192
|
+
type: String
|
|
193
|
+
},
|
|
194
|
+
file_name: {
|
|
195
|
+
type: String
|
|
196
|
+
},
|
|
197
|
+
content_base64: {
|
|
198
|
+
type: String
|
|
199
|
+
},
|
|
200
|
+
content_type: {
|
|
201
|
+
type: String,
|
|
202
|
+
optional: true
|
|
203
|
+
},
|
|
204
|
+
size: {
|
|
205
|
+
type: Number
|
|
206
|
+
}
|
|
207
|
+
}),
|
|
208
|
+
function: function (id_conversation, file_name, content_base64, size, content_type) {
|
|
209
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
210
|
+
var limits, safeName, uploadRoot, targetDir, targetPath, dataBuffer, data;
|
|
211
|
+
return __generator(this, function (_a) {
|
|
212
|
+
switch (_a.label) {
|
|
213
|
+
case 0:
|
|
214
|
+
limits = resolveUploadLimits();
|
|
215
|
+
if (size > limits.maxFileBytes) {
|
|
216
|
+
throw new Error("File exceeds ".concat(limits.maxFileMb, "MB limit."));
|
|
217
|
+
}
|
|
218
|
+
safeName = sanitizeFilename(file_name);
|
|
219
|
+
uploadRoot = resolveUploadRoot();
|
|
220
|
+
targetDir = path.join(uploadRoot, id_conversation);
|
|
221
|
+
return [4 /*yield*/, fs_1.promises.mkdir(targetDir, { recursive: true })];
|
|
222
|
+
case 1:
|
|
223
|
+
_a.sent();
|
|
224
|
+
targetPath = path.join(targetDir, safeName);
|
|
225
|
+
dataBuffer = Buffer.from(content_base64, 'base64');
|
|
226
|
+
data = new Uint8Array(dataBuffer);
|
|
227
|
+
if (data.byteLength !== size) {
|
|
228
|
+
if (data.byteLength > limits.maxFileBytes) {
|
|
229
|
+
throw new Error("File exceeds ".concat(limits.maxFileMb, "MB limit."));
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
return [4 /*yield*/, fs_1.promises.writeFile(targetPath, data)];
|
|
233
|
+
case 2:
|
|
234
|
+
_a.sent();
|
|
235
|
+
return [2 /*return*/, {
|
|
236
|
+
id_file: (0, common_1.objectIdHexString)(),
|
|
237
|
+
name: safeName,
|
|
238
|
+
size: data.byteLength,
|
|
239
|
+
type: normalizeOptionalString(content_type),
|
|
240
|
+
local_path: targetPath
|
|
241
|
+
}];
|
|
242
|
+
}
|
|
243
|
+
});
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
},
|
|
247
|
+
aiTerminalRun: {
|
|
248
|
+
check: new simpl_schema_1.default({
|
|
249
|
+
payload: {
|
|
250
|
+
type: Object,
|
|
251
|
+
blackbox: true
|
|
252
|
+
}
|
|
253
|
+
}),
|
|
254
|
+
function: function (payload) {
|
|
255
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
256
|
+
return __generator(this, function (_a) {
|
|
257
|
+
switch (_a.label) {
|
|
258
|
+
case 0: return [4 /*yield*/, executeAiTerminalRun(payload, this)];
|
|
259
|
+
case 1: return [2 /*return*/, _a.sent()];
|
|
260
|
+
}
|
|
261
|
+
});
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
},
|
|
265
|
+
aiCoderTerminalUploadFile: {
|
|
266
|
+
check: new simpl_schema_1.default({
|
|
267
|
+
id_conversation: {
|
|
268
|
+
type: String
|
|
269
|
+
},
|
|
270
|
+
file_name: {
|
|
271
|
+
type: String
|
|
272
|
+
},
|
|
273
|
+
content_base64: {
|
|
274
|
+
type: String
|
|
275
|
+
},
|
|
276
|
+
size: {
|
|
277
|
+
type: Number
|
|
278
|
+
},
|
|
279
|
+
content_type: {
|
|
280
|
+
type: String,
|
|
281
|
+
optional: true
|
|
282
|
+
}
|
|
283
|
+
}),
|
|
284
|
+
function: function (id_conversation, file_name, content_base64, size, content_type) {
|
|
285
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
286
|
+
return __generator(this, function (_a) {
|
|
287
|
+
switch (_a.label) {
|
|
288
|
+
case 0: return [4 /*yield*/, handleCodexUpload(id_conversation, file_name, content_base64, size, content_type)];
|
|
289
|
+
case 1: return [2 /*return*/, _a.sent()];
|
|
290
|
+
}
|
|
291
|
+
});
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
},
|
|
295
|
+
aiCoderTerminalRunCodex: {
|
|
296
|
+
check: new simpl_schema_1.default({
|
|
297
|
+
payload: {
|
|
298
|
+
type: Object,
|
|
299
|
+
blackbox: true
|
|
300
|
+
}
|
|
301
|
+
}),
|
|
302
|
+
function: function (payload) {
|
|
303
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
304
|
+
return __generator(this, function (_a) {
|
|
305
|
+
switch (_a.label) {
|
|
306
|
+
case 0: return [4 /*yield*/, executeAiAssistantCodexRun(payload, this)];
|
|
307
|
+
case 1: return [2 /*return*/, _a.sent()];
|
|
308
|
+
}
|
|
309
|
+
});
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
},
|
|
313
|
+
aiCoderTerminalDeployTest: {
|
|
314
|
+
check: new simpl_schema_1.default({
|
|
315
|
+
id_conversation: {
|
|
316
|
+
type: String
|
|
317
|
+
}
|
|
318
|
+
}),
|
|
319
|
+
function: function () {
|
|
320
|
+
throw new Error('Test deploys are not supported for AI assistant sessions.');
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
function executeAiTerminalRun(payload, context) {
|
|
326
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
327
|
+
var input, message, isSuperAdmin, guardrailsEnabled, guardrail, conversation_1, now_1, userMsg, assistantMsg, conversation, now, attachments, attachmentData, config, systemPrompt, userPromptTemplate, userPrompt, historyLimit, history, _a, messages, openaiSettings, client, response, usage, idClient, userDoc, assistantDoc, insertResult;
|
|
328
|
+
return __generator(this, function (_b) {
|
|
329
|
+
switch (_b.label) {
|
|
330
|
+
case 0:
|
|
331
|
+
input = payload || {};
|
|
332
|
+
message = normalizeOptionalString(input.message);
|
|
333
|
+
if (!message) {
|
|
334
|
+
throw new Error('Message is required.');
|
|
335
|
+
}
|
|
336
|
+
return [4 /*yield*/, resolveIsSuperAdmin(context === null || context === void 0 ? void 0 : context.id_user)];
|
|
337
|
+
case 1:
|
|
338
|
+
isSuperAdmin = _b.sent();
|
|
339
|
+
guardrailsEnabled = input.guardrails !== false && !isSuperAdmin;
|
|
340
|
+
if (!guardrailsEnabled) return [3 /*break*/, 6];
|
|
341
|
+
guardrail = evaluateGuardrails(message);
|
|
342
|
+
if (!(guardrail === null || guardrail === void 0 ? void 0 : guardrail.blocked)) return [3 /*break*/, 6];
|
|
343
|
+
return [4 /*yield*/, ensureConversation(input, 'openai')];
|
|
344
|
+
case 2:
|
|
345
|
+
conversation_1 = _b.sent();
|
|
346
|
+
now_1 = new Date();
|
|
347
|
+
userMsg = {
|
|
348
|
+
id_conversation: conversation_1._id,
|
|
349
|
+
role: 'user',
|
|
350
|
+
content: message,
|
|
351
|
+
createdAt: now_1,
|
|
352
|
+
updatedAt: now_1
|
|
353
|
+
};
|
|
354
|
+
assistantMsg = {
|
|
355
|
+
id_conversation: conversation_1._id,
|
|
356
|
+
role: 'assistant',
|
|
357
|
+
content: guardrail.response,
|
|
358
|
+
metadata: {
|
|
359
|
+
blocked: true,
|
|
360
|
+
reason: guardrail.reason
|
|
361
|
+
},
|
|
362
|
+
createdAt: now_1,
|
|
363
|
+
updatedAt: now_1
|
|
364
|
+
};
|
|
365
|
+
return [4 /*yield*/, ai_terminal_message_collection_1.AiTerminalMessages.insertOne(userMsg)];
|
|
366
|
+
case 3:
|
|
367
|
+
_b.sent();
|
|
368
|
+
return [4 /*yield*/, ai_terminal_message_collection_1.AiTerminalMessages.insertOne(assistantMsg)];
|
|
369
|
+
case 4:
|
|
370
|
+
_b.sent();
|
|
371
|
+
return [4 /*yield*/, touchConversation(conversation_1._id, now_1)];
|
|
372
|
+
case 5:
|
|
373
|
+
_b.sent();
|
|
374
|
+
return [2 /*return*/, {
|
|
375
|
+
conversation: conversation_1,
|
|
376
|
+
message: assistantMsg,
|
|
377
|
+
guardrails: { blocked: true, reason: guardrail.reason }
|
|
378
|
+
}];
|
|
379
|
+
case 6: return [4 /*yield*/, ensureConversation(input, 'openai')];
|
|
380
|
+
case 7:
|
|
381
|
+
conversation = _b.sent();
|
|
382
|
+
now = new Date();
|
|
383
|
+
attachments = Array.isArray(input.attachments) ? input.attachments : [];
|
|
384
|
+
return [4 /*yield*/, readAttachmentContents(attachments)];
|
|
385
|
+
case 8:
|
|
386
|
+
attachmentData = _b.sent();
|
|
387
|
+
config = sanitizeConfig(input.config || {});
|
|
388
|
+
systemPrompt = normalizeOptionalString(config.system_prompt) || '';
|
|
389
|
+
userPromptTemplate = normalizeOptionalString(config.user_prompt_template);
|
|
390
|
+
userPrompt = buildUserPrompt(userPromptTemplate, message, attachmentData.promptText);
|
|
391
|
+
historyLimit = normalizeHistoryLimit(input.max_history);
|
|
392
|
+
if (!(historyLimit > 0)) return [3 /*break*/, 10];
|
|
393
|
+
return [4 /*yield*/, ai_terminal_message_collection_1.AiTerminalMessages.find({ id_conversation: conversation._id, role: { $in: ['user', 'assistant'] } }, { sort: { createdAt: 1 }, limit: historyLimit * 2 })];
|
|
394
|
+
case 9:
|
|
395
|
+
_a = _b.sent();
|
|
396
|
+
return [3 /*break*/, 11];
|
|
397
|
+
case 10:
|
|
398
|
+
_a = [];
|
|
399
|
+
_b.label = 11;
|
|
400
|
+
case 11:
|
|
401
|
+
history = _a;
|
|
402
|
+
messages = [];
|
|
403
|
+
if (systemPrompt) {
|
|
404
|
+
messages.push({ role: 'system', content: systemPrompt });
|
|
405
|
+
}
|
|
406
|
+
history.forEach(function (entry) {
|
|
407
|
+
var role = entry.role === 'assistant' ? 'assistant' : 'user';
|
|
408
|
+
var content = normalizeOptionalString(entry.content);
|
|
409
|
+
if (content) {
|
|
410
|
+
messages.push({ role: role, content: content });
|
|
411
|
+
}
|
|
412
|
+
});
|
|
413
|
+
if (userPrompt) {
|
|
414
|
+
messages.push({ role: 'user', content: userPrompt });
|
|
415
|
+
}
|
|
416
|
+
openaiSettings = resolveOpenAISettings(config);
|
|
417
|
+
client = new openai_client_1.OpenAIClient(openaiSettings);
|
|
418
|
+
return [4 /*yield*/, client.chat(messages, { timeoutMs: 60000, responseFormat: config.response_format })];
|
|
419
|
+
case 12:
|
|
420
|
+
response = _b.sent();
|
|
421
|
+
usage = response.usage || estimateUsage(messages, response.content, openaiSettings.model);
|
|
422
|
+
idClient = resolveClientId(conversation, input.id_client);
|
|
423
|
+
if (!idClient) return [3 /*break*/, 14];
|
|
424
|
+
return [4 /*yield*/, (0, openai_usage_ledger_manager_1.recordOpenAIUsage)({
|
|
425
|
+
id_client: idClient,
|
|
426
|
+
model: response.model || openaiSettings.model || 'unknown',
|
|
427
|
+
input_tokens: usage.inputTokens,
|
|
428
|
+
output_tokens: usage.outputTokens,
|
|
429
|
+
total_tokens: usage.totalTokens,
|
|
430
|
+
category: 'ai-terminal',
|
|
431
|
+
id_conversation: conversation._id
|
|
432
|
+
})];
|
|
433
|
+
case 13:
|
|
434
|
+
_b.sent();
|
|
435
|
+
_b.label = 14;
|
|
436
|
+
case 14:
|
|
437
|
+
userDoc = {
|
|
438
|
+
id_conversation: conversation._id,
|
|
439
|
+
role: 'user',
|
|
440
|
+
content: message,
|
|
441
|
+
attachments: attachmentData.attachments,
|
|
442
|
+
createdAt: now,
|
|
443
|
+
updatedAt: now
|
|
444
|
+
};
|
|
445
|
+
assistantDoc = {
|
|
446
|
+
id_conversation: conversation._id,
|
|
447
|
+
role: 'assistant',
|
|
448
|
+
content: response.content,
|
|
449
|
+
usage: {
|
|
450
|
+
model: response.model || openaiSettings.model,
|
|
451
|
+
input_tokens: usage.inputTokens,
|
|
452
|
+
output_tokens: usage.outputTokens,
|
|
453
|
+
total_tokens: usage.totalTokens
|
|
454
|
+
},
|
|
455
|
+
createdAt: now,
|
|
456
|
+
updatedAt: now
|
|
457
|
+
};
|
|
458
|
+
return [4 /*yield*/, ai_terminal_message_collection_1.AiTerminalMessages.insertOne(userDoc)];
|
|
459
|
+
case 15:
|
|
460
|
+
_b.sent();
|
|
461
|
+
return [4 /*yield*/, ai_terminal_message_collection_1.AiTerminalMessages.insertOne(assistantDoc)];
|
|
462
|
+
case 16:
|
|
463
|
+
insertResult = _b.sent();
|
|
464
|
+
return [4 /*yield*/, touchConversation(conversation._id, now, insertResult._id)];
|
|
465
|
+
case 17:
|
|
466
|
+
_b.sent();
|
|
467
|
+
if (!(input.delete_files_after_run !== false)) return [3 /*break*/, 19];
|
|
468
|
+
return [4 /*yield*/, cleanupAttachments(attachmentData.attachments)];
|
|
469
|
+
case 18:
|
|
470
|
+
_b.sent();
|
|
471
|
+
_b.label = 19;
|
|
472
|
+
case 19: return [2 /*return*/, {
|
|
473
|
+
conversation: conversation,
|
|
474
|
+
message: assistantDoc,
|
|
475
|
+
usage: assistantDoc.usage
|
|
476
|
+
}];
|
|
477
|
+
}
|
|
478
|
+
});
|
|
479
|
+
});
|
|
480
|
+
}
|
|
481
|
+
function executeAiAssistantCodexRun(payload, context) {
|
|
482
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
483
|
+
var input, message, guardrail, conversation_2, now_2, userMsg, assistantMsg, conversation, now, attachments, attachmentData, historyLimit, history, _a, historyLines, prompt, workspaceRoot, codexClient, runOptions, responseText, assistantContent, userDoc, assistantDoc, insertResult;
|
|
484
|
+
return __generator(this, function (_b) {
|
|
485
|
+
switch (_b.label) {
|
|
486
|
+
case 0:
|
|
487
|
+
input = payload || {};
|
|
488
|
+
message = normalizeOptionalString(input.message);
|
|
489
|
+
if (!message) {
|
|
490
|
+
throw new Error('Message is required.');
|
|
491
|
+
}
|
|
492
|
+
if (!(context === null || context === void 0 ? void 0 : context.id_user)) {
|
|
493
|
+
throw new Error('Unauthorized.');
|
|
494
|
+
}
|
|
495
|
+
guardrail = evaluateAssistantGuardrails(message);
|
|
496
|
+
if (!(guardrail === null || guardrail === void 0 ? void 0 : guardrail.blocked)) return [3 /*break*/, 5];
|
|
497
|
+
return [4 /*yield*/, ensureConversation(input, 'codex')];
|
|
498
|
+
case 1:
|
|
499
|
+
conversation_2 = _b.sent();
|
|
500
|
+
now_2 = new Date();
|
|
501
|
+
userMsg = {
|
|
502
|
+
id_conversation: conversation_2._id,
|
|
503
|
+
role: 'user',
|
|
504
|
+
content: message,
|
|
505
|
+
createdAt: now_2,
|
|
506
|
+
updatedAt: now_2
|
|
507
|
+
};
|
|
508
|
+
assistantMsg = {
|
|
509
|
+
id_conversation: conversation_2._id,
|
|
510
|
+
role: 'assistant',
|
|
511
|
+
content: guardrail.response,
|
|
512
|
+
metadata: {
|
|
513
|
+
blocked: true,
|
|
514
|
+
reason: guardrail.reason
|
|
515
|
+
},
|
|
516
|
+
createdAt: now_2,
|
|
517
|
+
updatedAt: now_2
|
|
518
|
+
};
|
|
519
|
+
return [4 /*yield*/, ai_terminal_message_collection_1.AiTerminalMessages.insertOne(userMsg)];
|
|
520
|
+
case 2:
|
|
521
|
+
_b.sent();
|
|
522
|
+
return [4 /*yield*/, ai_terminal_message_collection_1.AiTerminalMessages.insertOne(assistantMsg)];
|
|
523
|
+
case 3:
|
|
524
|
+
_b.sent();
|
|
525
|
+
return [4 /*yield*/, touchConversation(conversation_2._id, now_2)];
|
|
526
|
+
case 4:
|
|
527
|
+
_b.sent();
|
|
528
|
+
return [2 /*return*/, {
|
|
529
|
+
conversation: conversation_2,
|
|
530
|
+
message: assistantMsg,
|
|
531
|
+
guardrails: { blocked: true, reason: guardrail.reason }
|
|
532
|
+
}];
|
|
533
|
+
case 5: return [4 /*yield*/, ensureConversation(input, 'codex')];
|
|
534
|
+
case 6:
|
|
535
|
+
conversation = _b.sent();
|
|
536
|
+
now = new Date();
|
|
537
|
+
attachments = Array.isArray(input.attachments) ? input.attachments : [];
|
|
538
|
+
return [4 /*yield*/, readAttachmentContents(attachments)];
|
|
539
|
+
case 7:
|
|
540
|
+
attachmentData = _b.sent();
|
|
541
|
+
historyLimit = normalizeHistoryLimit(input.max_history);
|
|
542
|
+
if (!(historyLimit > 0)) return [3 /*break*/, 9];
|
|
543
|
+
return [4 /*yield*/, ai_terminal_message_collection_1.AiTerminalMessages.find({ id_conversation: conversation._id, role: { $in: ['user', 'assistant'] } }, { sort: { createdAt: 1 }, limit: historyLimit * 2 })];
|
|
544
|
+
case 8:
|
|
545
|
+
_a = _b.sent();
|
|
546
|
+
return [3 /*break*/, 10];
|
|
547
|
+
case 9:
|
|
548
|
+
_a = [];
|
|
549
|
+
_b.label = 10;
|
|
550
|
+
case 10:
|
|
551
|
+
history = _a;
|
|
552
|
+
historyLines = [];
|
|
553
|
+
history.forEach(function (entry) {
|
|
554
|
+
var role = entry.role === 'assistant' ? 'Assistant' : 'User';
|
|
555
|
+
var content = normalizeOptionalString(entry.content);
|
|
556
|
+
if (content) {
|
|
557
|
+
historyLines.push("".concat(role, ": ").concat(content));
|
|
558
|
+
}
|
|
559
|
+
});
|
|
560
|
+
prompt = buildAssistantCodexPrompt(message, attachmentData.promptText, historyLines.join('\n'));
|
|
561
|
+
return [4 /*yield*/, resolveAssistantWorkspaceRoot()];
|
|
562
|
+
case 11:
|
|
563
|
+
workspaceRoot = _b.sent();
|
|
564
|
+
codexClient = getAssistantCodexClient();
|
|
565
|
+
runOptions = {
|
|
566
|
+
timeoutMs: resolveCodexTimeoutMs(),
|
|
567
|
+
threadOptions: {
|
|
568
|
+
workingDirectory: workspaceRoot,
|
|
569
|
+
sandboxMode: 'read-only',
|
|
570
|
+
skipGitRepoCheck: true,
|
|
571
|
+
modelReasoningEffort: 'low',
|
|
572
|
+
networkAccessEnabled: false,
|
|
573
|
+
webSearchMode: 'disabled',
|
|
574
|
+
webSearchEnabled: false,
|
|
575
|
+
approvalPolicy: 'never'
|
|
576
|
+
}
|
|
577
|
+
};
|
|
578
|
+
return [4 /*yield*/, codexClient.run(prompt, runOptions)];
|
|
579
|
+
case 12:
|
|
580
|
+
responseText = _b.sent();
|
|
581
|
+
assistantContent = sanitizeAssistantResponse(responseText);
|
|
582
|
+
userDoc = {
|
|
583
|
+
id_conversation: conversation._id,
|
|
584
|
+
role: 'user',
|
|
585
|
+
content: message,
|
|
586
|
+
attachments: attachmentData.attachments,
|
|
587
|
+
createdAt: now,
|
|
588
|
+
updatedAt: now
|
|
589
|
+
};
|
|
590
|
+
assistantDoc = {
|
|
591
|
+
id_conversation: conversation._id,
|
|
592
|
+
role: 'assistant',
|
|
593
|
+
content: assistantContent,
|
|
594
|
+
metadata: {
|
|
595
|
+
model: resolveCodexModel()
|
|
596
|
+
},
|
|
597
|
+
createdAt: now,
|
|
598
|
+
updatedAt: now
|
|
599
|
+
};
|
|
600
|
+
return [4 /*yield*/, ai_terminal_message_collection_1.AiTerminalMessages.insertOne(userDoc)];
|
|
601
|
+
case 13:
|
|
602
|
+
_b.sent();
|
|
603
|
+
return [4 /*yield*/, ai_terminal_message_collection_1.AiTerminalMessages.insertOne(assistantDoc)];
|
|
604
|
+
case 14:
|
|
605
|
+
insertResult = _b.sent();
|
|
606
|
+
return [4 /*yield*/, touchConversation(conversation._id, now, insertResult._id)];
|
|
607
|
+
case 15:
|
|
608
|
+
_b.sent();
|
|
609
|
+
if (!(input.delete_files_after_run !== false)) return [3 /*break*/, 17];
|
|
610
|
+
return [4 /*yield*/, cleanupAttachments(attachmentData.attachments)];
|
|
611
|
+
case 16:
|
|
612
|
+
_b.sent();
|
|
613
|
+
_b.label = 17;
|
|
614
|
+
case 17: return [2 /*return*/, {
|
|
615
|
+
conversation: conversation,
|
|
616
|
+
message: assistantDoc
|
|
617
|
+
}];
|
|
618
|
+
}
|
|
619
|
+
});
|
|
620
|
+
});
|
|
621
|
+
}
|
|
622
|
+
function resolveCodexTimeoutMs() {
|
|
623
|
+
var config = resolveio_server_app_1.ResolveIOServer.getServerConfig() || {};
|
|
624
|
+
var raw = normalizeOptionalNumber(config['AI_ASSISTANT_CODEX_TIMEOUT_MS'] || process.env.AI_ASSISTANT_CODEX_TIMEOUT_MS);
|
|
625
|
+
if (raw && raw > 0) {
|
|
626
|
+
return (0, common_1.round)(raw);
|
|
627
|
+
}
|
|
628
|
+
return DEFAULT_CODEX_TIMEOUT_MS;
|
|
629
|
+
}
|
|
630
|
+
function resolveCodexModel() {
|
|
631
|
+
var config = resolveio_server_app_1.ResolveIOServer.getServerConfig() || {};
|
|
632
|
+
var raw = normalizeOptionalString(config['AI_ASSISTANT_CODEX_MODEL']
|
|
633
|
+
|| process.env.AI_ASSISTANT_CODEX_MODEL
|
|
634
|
+
|| config['AI_TERMINAL_CODEX_MODEL']
|
|
635
|
+
|| process.env.AI_TERMINAL_CODEX_MODEL
|
|
636
|
+
|| config['AI_DASHBOARD_CODEX_MODEL']
|
|
637
|
+
|| process.env.AI_DASHBOARD_CODEX_MODEL);
|
|
638
|
+
return raw || DEFAULT_CODEX_MODEL;
|
|
639
|
+
}
|
|
640
|
+
function resolveCodexSettings() {
|
|
641
|
+
var serverConfig = resolveio_server_app_1.ResolveIOServer.getServerConfig() || {};
|
|
642
|
+
var apiKey = (serverConfig['OPENAI_API_KEY'] || process.env.OPENAI_API_KEY || '').trim();
|
|
643
|
+
if (!apiKey) {
|
|
644
|
+
throw new Error('OpenAI API key missing. Add OPENAI_API_KEY to server config.');
|
|
645
|
+
}
|
|
646
|
+
return {
|
|
647
|
+
apiKey: apiKey,
|
|
648
|
+
baseUrl: (serverConfig['OPENAI_BASE_URL'] || process.env.OPENAI_BASE_URL || '').trim() || undefined,
|
|
649
|
+
model: resolveCodexModel(),
|
|
650
|
+
maxRetries: normalizeOptionalNumber(serverConfig['OPENAI_MAX_RETRIES'] || process.env.OPENAI_MAX_RETRIES),
|
|
651
|
+
retryDelayMs: normalizeOptionalNumber(serverConfig['OPENAI_RETRY_DELAY_MS'] || process.env.OPENAI_RETRY_DELAY_MS)
|
|
652
|
+
};
|
|
653
|
+
}
|
|
654
|
+
function getAssistantCodexClient() {
|
|
655
|
+
if (!assistantCodexClient) {
|
|
656
|
+
assistantCodexClient = new codex_client_1.CodexClient(resolveCodexSettings());
|
|
657
|
+
}
|
|
658
|
+
return assistantCodexClient;
|
|
659
|
+
}
|
|
660
|
+
function resolveAssistantWorkspaceRoot() {
|
|
661
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
662
|
+
var config, configured, candidate, stat, _a;
|
|
663
|
+
return __generator(this, function (_b) {
|
|
664
|
+
switch (_b.label) {
|
|
665
|
+
case 0:
|
|
666
|
+
config = resolveio_server_app_1.ResolveIOServer.getServerConfig() || {};
|
|
667
|
+
configured = normalizeOptionalString(config['AI_ASSISTANT_WORKSPACE_ROOT']
|
|
668
|
+
|| process.env.AI_ASSISTANT_WORKSPACE_ROOT
|
|
669
|
+
|| config['CODEX_WORKSPACE_ROOT']
|
|
670
|
+
|| process.env.CODEX_WORKSPACE_ROOT);
|
|
671
|
+
candidate = configured || resolveio_server_app_1.ResolveIOServer.getClientDir() || process.cwd();
|
|
672
|
+
stat = null;
|
|
673
|
+
_b.label = 1;
|
|
674
|
+
case 1:
|
|
675
|
+
_b.trys.push([1, 3, , 4]);
|
|
676
|
+
return [4 /*yield*/, fs_1.promises.stat(candidate)];
|
|
677
|
+
case 2:
|
|
678
|
+
stat = _b.sent();
|
|
679
|
+
return [3 /*break*/, 4];
|
|
680
|
+
case 3:
|
|
681
|
+
_a = _b.sent();
|
|
682
|
+
stat = null;
|
|
683
|
+
return [3 /*break*/, 4];
|
|
684
|
+
case 4:
|
|
685
|
+
if (!stat || !stat.isDirectory()) {
|
|
686
|
+
throw new Error('AI assistant workspace root not found.');
|
|
687
|
+
}
|
|
688
|
+
return [2 /*return*/, candidate];
|
|
689
|
+
}
|
|
690
|
+
});
|
|
691
|
+
});
|
|
692
|
+
}
|
|
693
|
+
function buildAssistantCodexPrompt(message, attachmentText, historyText) {
|
|
694
|
+
var trimmedHistory = normalizeOptionalString(historyText);
|
|
695
|
+
var historyBlock = trimmedHistory ? "\n\nConversation so far:\n".concat(trimmedHistory) : '';
|
|
696
|
+
return "System:\n".concat(AI_ASSISTANT_SYSTEM_PROMPT).concat(historyBlock, "\n\nUser:\n").concat(message).concat(attachmentText || '').trim();
|
|
697
|
+
}
|
|
698
|
+
function sanitizeAssistantResponse(value) {
|
|
699
|
+
var raw = normalizeOptionalString(value);
|
|
700
|
+
if (!raw) {
|
|
701
|
+
return 'I could not generate a response. Please try again.';
|
|
702
|
+
}
|
|
703
|
+
var withoutBlocks = raw.replace(/```[\\s\\S]*?```/g, '').replace(/`([^`]+)`/g, '$1').trim();
|
|
704
|
+
if (!withoutBlocks) {
|
|
705
|
+
return 'I can’t share code, but I can point you to files or explain behavior at a high level.';
|
|
706
|
+
}
|
|
707
|
+
return withoutBlocks;
|
|
708
|
+
}
|
|
709
|
+
function evaluateAssistantGuardrails(message) {
|
|
710
|
+
var e_1, _a;
|
|
711
|
+
var normalized = String(message || '').toLowerCase();
|
|
712
|
+
var patterns = [
|
|
713
|
+
{
|
|
714
|
+
pattern: /\b(show|share|paste|provide|dump|output)\b.*\b(code|snippet|file|function|class|script|sql)\b/i,
|
|
715
|
+
reason: 'Code sharing is restricted.',
|
|
716
|
+
response: 'I can’t share code. I can explain behavior and point you to file paths or routes.'
|
|
717
|
+
},
|
|
718
|
+
{
|
|
719
|
+
pattern: /\b(write|generate|create|implement|fix)\b.*\b(code|script|function|class|endpoint|sql)\b/i,
|
|
720
|
+
reason: 'Code generation is restricted.',
|
|
721
|
+
response: 'I can’t generate code. I can explain how the feature works and where to look in the project.'
|
|
722
|
+
},
|
|
723
|
+
{
|
|
724
|
+
pattern: /\b(credentials?|passwords?|secrets?|tokens?)\b/i,
|
|
725
|
+
reason: 'Credentials and secrets are restricted.',
|
|
726
|
+
response: 'I can’t help with credentials or secrets. If you need access, please contact support.'
|
|
727
|
+
},
|
|
728
|
+
{
|
|
729
|
+
pattern: /\b(delete|drop|truncate)\s+(database|db|schema)\b/i,
|
|
730
|
+
reason: 'Database operations are restricted.',
|
|
731
|
+
response: 'I can’t help with database operations. I can explain system behavior or file locations.'
|
|
732
|
+
},
|
|
733
|
+
{
|
|
734
|
+
pattern: /\b(shell|terminal|ssh|sudo|rm\\s+-rf|chmod|chown)\b/i,
|
|
735
|
+
reason: 'System operations are restricted.',
|
|
736
|
+
response: 'I can’t help with system operations. I can explain workflows and where to find related code.'
|
|
737
|
+
},
|
|
738
|
+
{
|
|
739
|
+
pattern: /\b(exploit|bypass|malware|phishing|ransomware|ddos|hack)\b/i,
|
|
740
|
+
reason: 'Security abuse is restricted.',
|
|
741
|
+
response: 'I can’t assist with that request.'
|
|
742
|
+
}
|
|
743
|
+
];
|
|
744
|
+
try {
|
|
745
|
+
for (var patterns_1 = __values(patterns), patterns_1_1 = patterns_1.next(); !patterns_1_1.done; patterns_1_1 = patterns_1.next()) {
|
|
746
|
+
var entry = patterns_1_1.value;
|
|
747
|
+
if (entry.pattern.test(normalized)) {
|
|
748
|
+
return {
|
|
749
|
+
blocked: true,
|
|
750
|
+
reason: entry.reason,
|
|
751
|
+
response: entry.response
|
|
752
|
+
};
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
757
|
+
finally {
|
|
758
|
+
try {
|
|
759
|
+
if (patterns_1_1 && !patterns_1_1.done && (_a = patterns_1.return)) _a.call(patterns_1);
|
|
760
|
+
}
|
|
761
|
+
finally { if (e_1) throw e_1.error; }
|
|
762
|
+
}
|
|
763
|
+
return null;
|
|
764
|
+
}
|
|
765
|
+
function resolveOpenAISettings(config) {
|
|
766
|
+
var serverConfig = resolveio_server_app_1.ResolveIOServer.getServerConfig() || {};
|
|
767
|
+
var apiKey = (serverConfig['OPENAI_API_KEY'] || process.env.OPENAI_API_KEY || '').trim();
|
|
768
|
+
if (!apiKey) {
|
|
769
|
+
throw new Error('OpenAI API key missing. Add OPENAI_API_KEY to server config.');
|
|
770
|
+
}
|
|
771
|
+
return {
|
|
772
|
+
apiKey: apiKey,
|
|
773
|
+
baseUrl: (serverConfig['OPENAI_BASE_URL'] || process.env.OPENAI_BASE_URL || '').trim() || undefined,
|
|
774
|
+
model: normalizeOptionalString(config === null || config === void 0 ? void 0 : config.model) || (serverConfig['OPENAI_MODEL'] || process.env.OPENAI_MODEL || 'gpt-5.1').trim(),
|
|
775
|
+
temperature: normalizeOptionalNumber(config === null || config === void 0 ? void 0 : config.temperature),
|
|
776
|
+
maxTokens: normalizeOptionalNumber(config === null || config === void 0 ? void 0 : config.max_tokens),
|
|
777
|
+
maxRetries: normalizeOptionalNumber(serverConfig['OPENAI_MAX_RETRIES'] || process.env.OPENAI_MAX_RETRIES),
|
|
778
|
+
retryDelayMs: normalizeOptionalNumber(serverConfig['OPENAI_RETRY_DELAY_MS'] || process.env.OPENAI_RETRY_DELAY_MS)
|
|
779
|
+
};
|
|
780
|
+
}
|
|
781
|
+
function resolveUploadLimits() {
|
|
782
|
+
var config = resolveio_server_app_1.ResolveIOServer.getServerConfig() || {};
|
|
783
|
+
var maxFileMb = normalizeOptionalNumber(config['AI_TERMINAL_MAX_FILE_MB'] || process.env.AI_TERMINAL_MAX_FILE_MB) || DEFAULT_MAX_FILE_MB;
|
|
784
|
+
var maxTotalMb = normalizeOptionalNumber(config['AI_TERMINAL_MAX_TOTAL_MB'] || process.env.AI_TERMINAL_MAX_TOTAL_MB) || DEFAULT_MAX_TOTAL_MB;
|
|
785
|
+
return {
|
|
786
|
+
maxFileBytes: (0, common_1.round)(maxFileMb * 1024 * 1024),
|
|
787
|
+
maxFileMb: maxFileMb,
|
|
788
|
+
maxTotalBytes: (0, common_1.round)(maxTotalMb * 1024 * 1024),
|
|
789
|
+
maxTotalMb: maxTotalMb
|
|
790
|
+
};
|
|
791
|
+
}
|
|
792
|
+
function resolveUploadRoot() {
|
|
793
|
+
var config = resolveio_server_app_1.ResolveIOServer.getServerConfig() || {};
|
|
794
|
+
var configured = normalizeOptionalString(config['AI_TERMINAL_UPLOAD_ROOT'] || process.env.AI_TERMINAL_UPLOAD_ROOT);
|
|
795
|
+
if (configured) {
|
|
796
|
+
return configured;
|
|
797
|
+
}
|
|
798
|
+
return path.join(os.tmpdir(), 'resolveio-ai-terminal-uploads');
|
|
799
|
+
}
|
|
800
|
+
function handleCodexUpload(id_conversation, file_name, content_base64, size, content_type) {
|
|
801
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
802
|
+
var limits, safeName, uploadRoot, targetDir, targetPath, dataBuffer, data;
|
|
803
|
+
return __generator(this, function (_a) {
|
|
804
|
+
switch (_a.label) {
|
|
805
|
+
case 0:
|
|
806
|
+
limits = resolveUploadLimits();
|
|
807
|
+
if (size > limits.maxFileBytes) {
|
|
808
|
+
throw new Error("File exceeds ".concat(limits.maxFileMb, "MB limit."));
|
|
809
|
+
}
|
|
810
|
+
safeName = sanitizeFilename(file_name);
|
|
811
|
+
uploadRoot = resolveUploadRoot();
|
|
812
|
+
targetDir = path.join(uploadRoot, id_conversation);
|
|
813
|
+
return [4 /*yield*/, fs_1.promises.mkdir(targetDir, { recursive: true })];
|
|
814
|
+
case 1:
|
|
815
|
+
_a.sent();
|
|
816
|
+
targetPath = path.join(targetDir, safeName);
|
|
817
|
+
dataBuffer = Buffer.from(content_base64, 'base64');
|
|
818
|
+
data = new Uint8Array(dataBuffer);
|
|
819
|
+
if (data.byteLength > limits.maxFileBytes) {
|
|
820
|
+
throw new Error("File exceeds ".concat(limits.maxFileMb, "MB limit."));
|
|
821
|
+
}
|
|
822
|
+
return [4 /*yield*/, fs_1.promises.writeFile(targetPath, data)];
|
|
823
|
+
case 2:
|
|
824
|
+
_a.sent();
|
|
825
|
+
return [2 /*return*/, {
|
|
826
|
+
id_file: (0, common_1.objectIdHexString)(),
|
|
827
|
+
name: safeName,
|
|
828
|
+
size: data.byteLength,
|
|
829
|
+
type: normalizeOptionalString(content_type),
|
|
830
|
+
local_path: targetPath
|
|
831
|
+
}];
|
|
832
|
+
}
|
|
833
|
+
});
|
|
834
|
+
});
|
|
835
|
+
}
|
|
836
|
+
function readAttachmentContents(attachments) {
|
|
837
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
838
|
+
var limits, totalBytes, totalChars, chunks, cleaned, attachments_1, attachments_1_1, attachment, localPath, safe, stat, ext, name_1, type, readable, content, _a, e_2_1;
|
|
839
|
+
var e_2, _b;
|
|
840
|
+
return __generator(this, function (_c) {
|
|
841
|
+
switch (_c.label) {
|
|
842
|
+
case 0:
|
|
843
|
+
if (!attachments || !attachments.length) {
|
|
844
|
+
return [2 /*return*/, { promptText: '', attachments: [] }];
|
|
845
|
+
}
|
|
846
|
+
limits = resolveAttachmentLimits();
|
|
847
|
+
totalBytes = 0;
|
|
848
|
+
totalChars = 0;
|
|
849
|
+
chunks = [];
|
|
850
|
+
cleaned = [];
|
|
851
|
+
_c.label = 1;
|
|
852
|
+
case 1:
|
|
853
|
+
_c.trys.push([1, 11, 12, 13]);
|
|
854
|
+
attachments_1 = __values(attachments), attachments_1_1 = attachments_1.next();
|
|
855
|
+
_c.label = 2;
|
|
856
|
+
case 2:
|
|
857
|
+
if (!!attachments_1_1.done) return [3 /*break*/, 10];
|
|
858
|
+
attachment = attachments_1_1.value;
|
|
859
|
+
localPath = normalizeOptionalString(attachment.local_path);
|
|
860
|
+
if (!localPath) {
|
|
861
|
+
return [3 /*break*/, 9];
|
|
862
|
+
}
|
|
863
|
+
safe = ensurePathUnderRoot(localPath, resolveUploadRoot());
|
|
864
|
+
if (!safe) {
|
|
865
|
+
return [3 /*break*/, 9];
|
|
866
|
+
}
|
|
867
|
+
_c.label = 3;
|
|
868
|
+
case 3:
|
|
869
|
+
_c.trys.push([3, 8, , 9]);
|
|
870
|
+
return [4 /*yield*/, fs_1.promises.stat(localPath)];
|
|
871
|
+
case 4:
|
|
872
|
+
stat = _c.sent();
|
|
873
|
+
if (!stat.isFile()) {
|
|
874
|
+
return [3 /*break*/, 9];
|
|
875
|
+
}
|
|
876
|
+
totalBytes += stat.size;
|
|
877
|
+
if (totalBytes > limits.maxTotalBytes) {
|
|
878
|
+
return [3 /*break*/, 10];
|
|
879
|
+
}
|
|
880
|
+
ext = path.extname(localPath).toLowerCase();
|
|
881
|
+
name_1 = normalizeOptionalString(attachment.name) || path.basename(localPath);
|
|
882
|
+
type = normalizeOptionalString(attachment.type);
|
|
883
|
+
readable = isReadableAttachment(type, ext);
|
|
884
|
+
content = '';
|
|
885
|
+
if (!readable) return [3 /*break*/, 6];
|
|
886
|
+
return [4 /*yield*/, fs_1.promises.readFile(localPath, 'utf8')];
|
|
887
|
+
case 5:
|
|
888
|
+
content = _c.sent();
|
|
889
|
+
if (content.length > limits.maxAttachmentChars) {
|
|
890
|
+
content = content.slice(0, limits.maxAttachmentChars) + '\n[...truncated]';
|
|
891
|
+
}
|
|
892
|
+
return [3 /*break*/, 7];
|
|
893
|
+
case 6:
|
|
894
|
+
content = "[".concat(name_1, " attached; binary content omitted]");
|
|
895
|
+
_c.label = 7;
|
|
896
|
+
case 7:
|
|
897
|
+
totalChars += content.length;
|
|
898
|
+
if (totalChars > limits.maxTotalAttachmentChars) {
|
|
899
|
+
return [3 /*break*/, 10];
|
|
900
|
+
}
|
|
901
|
+
chunks.push("File: ".concat(name_1, "\n").concat(content));
|
|
902
|
+
cleaned.push({
|
|
903
|
+
id: attachment.id,
|
|
904
|
+
name: name_1,
|
|
905
|
+
type: type,
|
|
906
|
+
size: stat.size,
|
|
907
|
+
local_path: localPath
|
|
908
|
+
});
|
|
909
|
+
return [3 /*break*/, 9];
|
|
910
|
+
case 8:
|
|
911
|
+
_a = _c.sent();
|
|
912
|
+
return [3 /*break*/, 9];
|
|
913
|
+
case 9:
|
|
914
|
+
attachments_1_1 = attachments_1.next();
|
|
915
|
+
return [3 /*break*/, 2];
|
|
916
|
+
case 10: return [3 /*break*/, 13];
|
|
917
|
+
case 11:
|
|
918
|
+
e_2_1 = _c.sent();
|
|
919
|
+
e_2 = { error: e_2_1 };
|
|
920
|
+
return [3 /*break*/, 13];
|
|
921
|
+
case 12:
|
|
922
|
+
try {
|
|
923
|
+
if (attachments_1_1 && !attachments_1_1.done && (_b = attachments_1.return)) _b.call(attachments_1);
|
|
924
|
+
}
|
|
925
|
+
finally { if (e_2) throw e_2.error; }
|
|
926
|
+
return [7 /*endfinally*/];
|
|
927
|
+
case 13: return [2 /*return*/, {
|
|
928
|
+
promptText: chunks.length ? "\n\nAttachments:\n".concat(chunks.join('\n\n')) : '',
|
|
929
|
+
attachments: cleaned
|
|
930
|
+
}];
|
|
931
|
+
}
|
|
932
|
+
});
|
|
933
|
+
});
|
|
934
|
+
}
|
|
935
|
+
function resolveAttachmentLimits() {
|
|
936
|
+
var config = resolveio_server_app_1.ResolveIOServer.getServerConfig() || {};
|
|
937
|
+
var maxAttachmentChars = normalizeOptionalNumber(config['AI_TERMINAL_MAX_ATTACHMENT_CHARS'] || process.env.AI_TERMINAL_MAX_ATTACHMENT_CHARS)
|
|
938
|
+
|| DEFAULT_MAX_ATTACHMENT_CHARS;
|
|
939
|
+
var maxTotalAttachmentChars = normalizeOptionalNumber(config['AI_TERMINAL_MAX_TOTAL_ATTACHMENT_CHARS'] || process.env.AI_TERMINAL_MAX_TOTAL_ATTACHMENT_CHARS)
|
|
940
|
+
|| DEFAULT_MAX_TOTAL_ATTACHMENT_CHARS;
|
|
941
|
+
var limits = resolveUploadLimits();
|
|
942
|
+
return {
|
|
943
|
+
maxAttachmentChars: maxAttachmentChars,
|
|
944
|
+
maxTotalAttachmentChars: maxTotalAttachmentChars,
|
|
945
|
+
maxTotalBytes: limits.maxTotalBytes
|
|
946
|
+
};
|
|
947
|
+
}
|
|
948
|
+
function buildUserPrompt(template, inputText, attachmentText) {
|
|
949
|
+
var data = {
|
|
950
|
+
input: inputText || '',
|
|
951
|
+
today: new Date().toISOString().slice(0, 10)
|
|
952
|
+
};
|
|
953
|
+
if (template) {
|
|
954
|
+
return applyTemplate(template, data).trim() + attachmentText;
|
|
955
|
+
}
|
|
956
|
+
return "".concat(inputText || '').concat(attachmentText).trim();
|
|
957
|
+
}
|
|
958
|
+
function applyTemplate(template, data) {
|
|
959
|
+
var output = template;
|
|
960
|
+
Object.keys(data).forEach(function (key) {
|
|
961
|
+
var value = data[key] || '';
|
|
962
|
+
var pattern = new RegExp("{{\\s*".concat(key, "\\s*}}"), 'gi');
|
|
963
|
+
output = output.replace(pattern, value);
|
|
964
|
+
});
|
|
965
|
+
return output;
|
|
966
|
+
}
|
|
967
|
+
function sanitizeConfig(source) {
|
|
968
|
+
return {
|
|
969
|
+
mode: normalizeOptionalString(source === null || source === void 0 ? void 0 : source.mode),
|
|
970
|
+
model: normalizeOptionalString(source === null || source === void 0 ? void 0 : source.model),
|
|
971
|
+
system_prompt: normalizeOptionalString(source === null || source === void 0 ? void 0 : source.system_prompt),
|
|
972
|
+
user_prompt_template: normalizeOptionalString(source === null || source === void 0 ? void 0 : source.user_prompt_template),
|
|
973
|
+
response_format: normalizeOptionalString(source === null || source === void 0 ? void 0 : source.response_format),
|
|
974
|
+
temperature: normalizeOptionalNumber(source === null || source === void 0 ? void 0 : source.temperature),
|
|
975
|
+
max_tokens: normalizeOptionalNumber(source === null || source === void 0 ? void 0 : source.max_tokens)
|
|
976
|
+
};
|
|
977
|
+
}
|
|
978
|
+
function ensureConversation(input, mode) {
|
|
979
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
980
|
+
var idConversation, existing, now, doc, result;
|
|
981
|
+
return __generator(this, function (_a) {
|
|
982
|
+
switch (_a.label) {
|
|
983
|
+
case 0:
|
|
984
|
+
idConversation = normalizeOptionalString(input.id_conversation);
|
|
985
|
+
if (!idConversation) return [3 /*break*/, 2];
|
|
986
|
+
return [4 /*yield*/, ai_terminal_conversation_collection_1.AiTerminalConversations.findById(idConversation)];
|
|
987
|
+
case 1:
|
|
988
|
+
existing = _a.sent();
|
|
989
|
+
if (existing) {
|
|
990
|
+
return [2 /*return*/, existing];
|
|
991
|
+
}
|
|
992
|
+
_a.label = 2;
|
|
993
|
+
case 2:
|
|
994
|
+
now = new Date();
|
|
995
|
+
doc = {
|
|
996
|
+
id_client: normalizeOptionalString(input.id_client),
|
|
997
|
+
id_app: normalizeOptionalString(input.id_app),
|
|
998
|
+
title: 'New Conversation',
|
|
999
|
+
mode: mode,
|
|
1000
|
+
branch_enabled: mode === 'codex',
|
|
1001
|
+
status: normalizeConversationStatus('active'),
|
|
1002
|
+
profile_id: normalizeOptionalString(input.profile_id),
|
|
1003
|
+
metadata: {},
|
|
1004
|
+
createdAt: now,
|
|
1005
|
+
updatedAt: now
|
|
1006
|
+
};
|
|
1007
|
+
return [4 /*yield*/, ai_terminal_conversation_collection_1.AiTerminalConversations.insertOne(doc)];
|
|
1008
|
+
case 3:
|
|
1009
|
+
result = _a.sent();
|
|
1010
|
+
return [2 /*return*/, result];
|
|
1011
|
+
}
|
|
1012
|
+
});
|
|
1013
|
+
});
|
|
1014
|
+
}
|
|
1015
|
+
function touchConversation(idConversation, timestamp, lastMessageId) {
|
|
1016
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
1017
|
+
var update;
|
|
1018
|
+
return __generator(this, function (_a) {
|
|
1019
|
+
switch (_a.label) {
|
|
1020
|
+
case 0:
|
|
1021
|
+
update = {
|
|
1022
|
+
updatedAt: timestamp,
|
|
1023
|
+
last_message_at: timestamp
|
|
1024
|
+
};
|
|
1025
|
+
if (lastMessageId) {
|
|
1026
|
+
update.last_message_id = lastMessageId;
|
|
1027
|
+
}
|
|
1028
|
+
return [4 /*yield*/, ai_terminal_conversation_collection_1.AiTerminalConversations.updateOne({ _id: idConversation }, { $set: update })];
|
|
1029
|
+
case 1:
|
|
1030
|
+
_a.sent();
|
|
1031
|
+
return [2 /*return*/];
|
|
1032
|
+
}
|
|
1033
|
+
});
|
|
1034
|
+
});
|
|
1035
|
+
}
|
|
1036
|
+
function normalizeOptionalString(value) {
|
|
1037
|
+
var raw = typeof value === 'string' ? value.trim() : '';
|
|
1038
|
+
return raw || '';
|
|
1039
|
+
}
|
|
1040
|
+
function normalizeConversationMode(value) {
|
|
1041
|
+
var normalized = normalizeOptionalString(value).toLowerCase();
|
|
1042
|
+
if (normalized === 'codex') {
|
|
1043
|
+
return 'codex';
|
|
1044
|
+
}
|
|
1045
|
+
return 'openai';
|
|
1046
|
+
}
|
|
1047
|
+
function normalizeConversationStatus(value) {
|
|
1048
|
+
var normalized = normalizeOptionalString(value).toLowerCase();
|
|
1049
|
+
if (normalized === 'archived') {
|
|
1050
|
+
return 'archived';
|
|
1051
|
+
}
|
|
1052
|
+
return 'active';
|
|
1053
|
+
}
|
|
1054
|
+
function normalizeOptionalNumber(value) {
|
|
1055
|
+
var parsed = Number(value);
|
|
1056
|
+
return Number.isFinite(parsed) ? parsed : undefined;
|
|
1057
|
+
}
|
|
1058
|
+
function normalizeHistoryLimit(value) {
|
|
1059
|
+
var parsed = Number(value);
|
|
1060
|
+
if (!Number.isFinite(parsed)) {
|
|
1061
|
+
return 12;
|
|
1062
|
+
}
|
|
1063
|
+
return Math.min(Math.max((0, common_1.round)(parsed), 0), 30);
|
|
1064
|
+
}
|
|
1065
|
+
function resolveClientId(conversation, inputClientId) {
|
|
1066
|
+
return normalizeOptionalString(inputClientId) || normalizeOptionalString(conversation === null || conversation === void 0 ? void 0 : conversation.id_client);
|
|
1067
|
+
}
|
|
1068
|
+
function estimateUsage(messages, responseText, model) {
|
|
1069
|
+
var inputTokens = (0, tokenizer_1.countChatTokens)(messages, model);
|
|
1070
|
+
var outputTokens = (0, tokenizer_1.countTokens)(responseText || '', model);
|
|
1071
|
+
return {
|
|
1072
|
+
inputTokens: inputTokens,
|
|
1073
|
+
outputTokens: outputTokens,
|
|
1074
|
+
totalTokens: inputTokens + outputTokens
|
|
1075
|
+
};
|
|
1076
|
+
}
|
|
1077
|
+
function evaluateGuardrails(message) {
|
|
1078
|
+
var e_3, _a;
|
|
1079
|
+
var normalized = String(message || '').toLowerCase();
|
|
1080
|
+
var patterns = [
|
|
1081
|
+
{ pattern: /\b(source\s*code|full\s*code|entire\s*code|repo\s*dump|repository|git\s*clone)\b/i, reason: 'Code access is restricted.' },
|
|
1082
|
+
{ pattern: /\b(credentials?|passwords?|secrets?|tokens?)\b/i, reason: 'Credentials and secrets are restricted.' },
|
|
1083
|
+
{ pattern: /\b(delete|drop)\s+(database|db|schema)\b/i, reason: 'Database operations are restricted.' },
|
|
1084
|
+
{ pattern: /\b(shell|terminal|ssh|sudo|rm\s+-rf|chmod|chown)\b/i, reason: 'Server operations are restricted.' },
|
|
1085
|
+
{ pattern: /\b(exploit|bypass|malware|phishing|ransomware|ddos)\b/i, reason: 'Security abuse is restricted.' }
|
|
1086
|
+
];
|
|
1087
|
+
try {
|
|
1088
|
+
for (var patterns_2 = __values(patterns), patterns_2_1 = patterns_2.next(); !patterns_2_1.done; patterns_2_1 = patterns_2.next()) {
|
|
1089
|
+
var entry = patterns_2_1.value;
|
|
1090
|
+
if (entry.pattern.test(normalized)) {
|
|
1091
|
+
return {
|
|
1092
|
+
blocked: true,
|
|
1093
|
+
reason: entry.reason,
|
|
1094
|
+
response: 'I can’t help with that request because it could impact system security or expose protected information. If you need a change, describe the outcome and I can help within approved workflows.'
|
|
1095
|
+
};
|
|
1096
|
+
}
|
|
1097
|
+
}
|
|
1098
|
+
}
|
|
1099
|
+
catch (e_3_1) { e_3 = { error: e_3_1 }; }
|
|
1100
|
+
finally {
|
|
1101
|
+
try {
|
|
1102
|
+
if (patterns_2_1 && !patterns_2_1.done && (_a = patterns_2.return)) _a.call(patterns_2);
|
|
1103
|
+
}
|
|
1104
|
+
finally { if (e_3) throw e_3.error; }
|
|
1105
|
+
}
|
|
1106
|
+
return null;
|
|
1107
|
+
}
|
|
1108
|
+
function resolveIsSuperAdmin(id_user) {
|
|
1109
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
1110
|
+
var user, _a;
|
|
1111
|
+
var _b;
|
|
1112
|
+
return __generator(this, function (_c) {
|
|
1113
|
+
switch (_c.label) {
|
|
1114
|
+
case 0:
|
|
1115
|
+
if (!id_user) {
|
|
1116
|
+
return [2 /*return*/, false];
|
|
1117
|
+
}
|
|
1118
|
+
_c.label = 1;
|
|
1119
|
+
case 1:
|
|
1120
|
+
_c.trys.push([1, 3, , 4]);
|
|
1121
|
+
return [4 /*yield*/, user_collection_1.Users.findById(id_user)];
|
|
1122
|
+
case 2:
|
|
1123
|
+
user = _c.sent();
|
|
1124
|
+
return [2 /*return*/, !!((_b = user === null || user === void 0 ? void 0 : user.roles) === null || _b === void 0 ? void 0 : _b.super_admin)];
|
|
1125
|
+
case 3:
|
|
1126
|
+
_a = _c.sent();
|
|
1127
|
+
return [2 /*return*/, false];
|
|
1128
|
+
case 4: return [2 /*return*/];
|
|
1129
|
+
}
|
|
1130
|
+
});
|
|
1131
|
+
});
|
|
1132
|
+
}
|
|
1133
|
+
function sanitizeFilename(value) {
|
|
1134
|
+
var trimmed = (value || '').trim();
|
|
1135
|
+
var base = path.basename(trimmed);
|
|
1136
|
+
return base.replace(/[^\w.\-]/g, '_') || "upload_".concat(Date.now());
|
|
1137
|
+
}
|
|
1138
|
+
function isReadableAttachment(type, ext) {
|
|
1139
|
+
var normalizedType = (type || '').toLowerCase();
|
|
1140
|
+
if (normalizedType.startsWith('text/')) {
|
|
1141
|
+
return true;
|
|
1142
|
+
}
|
|
1143
|
+
if (['application/json', 'application/xml', 'application/csv'].includes(normalizedType)) {
|
|
1144
|
+
return true;
|
|
1145
|
+
}
|
|
1146
|
+
return ['.txt', '.md', '.json', '.csv', '.xml', '.log', '.yml', '.yaml', '.ts', '.tsx', '.js', '.jsx', '.css', '.scss', '.html', '.htm', '.sql'].includes(ext);
|
|
1147
|
+
}
|
|
1148
|
+
function ensurePathUnderRoot(targetPath, root) {
|
|
1149
|
+
var resolvedRoot = path.resolve(root);
|
|
1150
|
+
var resolvedTarget = path.resolve(targetPath);
|
|
1151
|
+
return resolvedTarget.startsWith(resolvedRoot);
|
|
1152
|
+
}
|
|
1153
|
+
function cleanupAttachments(attachments) {
|
|
1154
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
1155
|
+
var uploadRoot, removals;
|
|
1156
|
+
var _this = this;
|
|
1157
|
+
return __generator(this, function (_a) {
|
|
1158
|
+
switch (_a.label) {
|
|
1159
|
+
case 0:
|
|
1160
|
+
if (!attachments || !attachments.length) {
|
|
1161
|
+
return [2 /*return*/];
|
|
1162
|
+
}
|
|
1163
|
+
uploadRoot = resolveUploadRoot();
|
|
1164
|
+
removals = attachments.map(function (attachment) { return __awaiter(_this, void 0, void 0, function () {
|
|
1165
|
+
var localPath, safe, _a;
|
|
1166
|
+
return __generator(this, function (_b) {
|
|
1167
|
+
switch (_b.label) {
|
|
1168
|
+
case 0:
|
|
1169
|
+
localPath = normalizeOptionalString(attachment.local_path);
|
|
1170
|
+
if (!localPath) {
|
|
1171
|
+
return [2 /*return*/];
|
|
1172
|
+
}
|
|
1173
|
+
safe = ensurePathUnderRoot(localPath, uploadRoot);
|
|
1174
|
+
if (!safe) {
|
|
1175
|
+
return [2 /*return*/];
|
|
1176
|
+
}
|
|
1177
|
+
_b.label = 1;
|
|
1178
|
+
case 1:
|
|
1179
|
+
_b.trys.push([1, 3, , 4]);
|
|
1180
|
+
return [4 /*yield*/, fs_1.promises.rm(localPath, { force: true })];
|
|
1181
|
+
case 2:
|
|
1182
|
+
_b.sent();
|
|
1183
|
+
return [3 /*break*/, 4];
|
|
1184
|
+
case 3:
|
|
1185
|
+
_a = _b.sent();
|
|
1186
|
+
return [3 /*break*/, 4];
|
|
1187
|
+
case 4: return [2 /*return*/];
|
|
1188
|
+
}
|
|
1189
|
+
});
|
|
1190
|
+
}); });
|
|
1191
|
+
return [4 /*yield*/, Promise.all(removals)];
|
|
1192
|
+
case 1:
|
|
1193
|
+
_a.sent();
|
|
1194
|
+
return [2 /*return*/];
|
|
1195
|
+
}
|
|
1196
|
+
});
|
|
1197
|
+
});
|
|
1198
|
+
}
|
|
1199
|
+
|
|
1200
|
+
//# sourceMappingURL=ai-terminal.js.map
|