@nomad-e/bluma-cli 0.7.0 → 0.8.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/dist/main.js +826 -537
- package/package.json +1 -1
package/dist/main.js
CHANGED
|
@@ -291,6 +291,15 @@ function getSandboxPolicy() {
|
|
|
291
291
|
workspaceRoot
|
|
292
292
|
};
|
|
293
293
|
}
|
|
294
|
+
function getArtifactsDirectory(policy = getSandboxPolicy()) {
|
|
295
|
+
return path6.join(policy.workspaceRoot, ".bluma", "artifacts");
|
|
296
|
+
}
|
|
297
|
+
function isPathInsideArtifactsDirectory(resolvedAbsolutePath, policy = getSandboxPolicy()) {
|
|
298
|
+
const artifactsRoot = getArtifactsDirectory(policy);
|
|
299
|
+
const resolved = path6.resolve(resolvedAbsolutePath);
|
|
300
|
+
const relative = path6.relative(artifactsRoot, resolved);
|
|
301
|
+
return relative === "" || !relative.startsWith("..") && !path6.isAbsolute(relative);
|
|
302
|
+
}
|
|
294
303
|
function isPathInsideWorkspace(targetPath, policy = getSandboxPolicy()) {
|
|
295
304
|
const resolved = path6.resolve(targetPath);
|
|
296
305
|
const relative = path6.relative(policy.workspaceRoot, resolved);
|
|
@@ -397,11 +406,11 @@ var init_sandbox_policy = __esm({
|
|
|
397
406
|
});
|
|
398
407
|
|
|
399
408
|
// src/app/agent/runtime/task_store.ts
|
|
400
|
-
import
|
|
401
|
-
import
|
|
409
|
+
import fs13 from "fs";
|
|
410
|
+
import path11 from "path";
|
|
402
411
|
function getStorePath() {
|
|
403
412
|
const policy = getSandboxPolicy();
|
|
404
|
-
return
|
|
413
|
+
return path11.join(policy.workspaceRoot, ".bluma", "task_state.json");
|
|
405
414
|
}
|
|
406
415
|
function getDefaultState() {
|
|
407
416
|
return {
|
|
@@ -417,8 +426,8 @@ function ensureLoaded() {
|
|
|
417
426
|
return cache2;
|
|
418
427
|
}
|
|
419
428
|
try {
|
|
420
|
-
if (
|
|
421
|
-
const raw =
|
|
429
|
+
if (fs13.existsSync(storePath)) {
|
|
430
|
+
const raw = fs13.readFileSync(storePath, "utf-8");
|
|
422
431
|
const parsed = JSON.parse(raw);
|
|
423
432
|
cache2 = {
|
|
424
433
|
tasks: Array.isArray(parsed.tasks) ? parsed.tasks : [],
|
|
@@ -437,9 +446,9 @@ function ensureLoaded() {
|
|
|
437
446
|
}
|
|
438
447
|
function persist(state2) {
|
|
439
448
|
const storePath = getStorePath();
|
|
440
|
-
|
|
449
|
+
fs13.mkdirSync(path11.dirname(storePath), { recursive: true });
|
|
441
450
|
state2.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
442
|
-
|
|
451
|
+
fs13.writeFileSync(storePath, JSON.stringify(state2, null, 2), "utf-8");
|
|
443
452
|
cache2 = state2;
|
|
444
453
|
cachePath = storePath;
|
|
445
454
|
}
|
|
@@ -826,37 +835,37 @@ __export(session_registry_exports, {
|
|
|
826
835
|
removeSession: () => removeSession,
|
|
827
836
|
updateSession: () => updateSession
|
|
828
837
|
});
|
|
829
|
-
import
|
|
838
|
+
import fs19 from "fs";
|
|
830
839
|
import os13 from "os";
|
|
831
|
-
import
|
|
840
|
+
import path19 from "path";
|
|
832
841
|
function getRegistryDir() {
|
|
833
|
-
return
|
|
842
|
+
return path19.join(process.env.HOME || os13.homedir(), ".bluma", "registry");
|
|
834
843
|
}
|
|
835
844
|
function getRegistryFile() {
|
|
836
|
-
return
|
|
845
|
+
return path19.join(getRegistryDir(), "sessions.json");
|
|
837
846
|
}
|
|
838
847
|
function ensureRegistryDir() {
|
|
839
|
-
|
|
848
|
+
fs19.mkdirSync(getRegistryDir(), { recursive: true });
|
|
840
849
|
}
|
|
841
850
|
function readRegistry() {
|
|
842
851
|
ensureRegistryDir();
|
|
843
852
|
const file = getRegistryFile();
|
|
844
|
-
if (!
|
|
853
|
+
if (!fs19.existsSync(file)) {
|
|
845
854
|
return { entries: [] };
|
|
846
855
|
}
|
|
847
856
|
try {
|
|
848
|
-
return JSON.parse(
|
|
857
|
+
return JSON.parse(fs19.readFileSync(file, "utf-8"));
|
|
849
858
|
} catch {
|
|
850
859
|
return { entries: [] };
|
|
851
860
|
}
|
|
852
861
|
}
|
|
853
862
|
function writeRegistry(state2) {
|
|
854
863
|
ensureRegistryDir();
|
|
855
|
-
|
|
864
|
+
fs19.writeFileSync(getRegistryFile(), JSON.stringify(state2, null, 2), "utf-8");
|
|
856
865
|
}
|
|
857
866
|
function getSessionLogPath(sessionId) {
|
|
858
867
|
ensureRegistryDir();
|
|
859
|
-
return
|
|
868
|
+
return path19.join(getRegistryDir(), `${sessionId}.jsonl`);
|
|
860
869
|
}
|
|
861
870
|
function registerSession(entry) {
|
|
862
871
|
const state2 = readRegistry();
|
|
@@ -901,13 +910,13 @@ function removeSession(sessionId) {
|
|
|
901
910
|
}
|
|
902
911
|
function appendSessionLog(sessionId, payload) {
|
|
903
912
|
const logFile = getSessionLogPath(sessionId);
|
|
904
|
-
|
|
913
|
+
fs19.appendFileSync(logFile, `${JSON.stringify(payload)}
|
|
905
914
|
`, "utf-8");
|
|
906
915
|
}
|
|
907
916
|
function readSessionLog(sessionId) {
|
|
908
917
|
const logFile = getSessionLogPath(sessionId);
|
|
909
|
-
if (!
|
|
910
|
-
return
|
|
918
|
+
if (!fs19.existsSync(logFile)) return [];
|
|
919
|
+
return fs19.readFileSync(logFile, "utf-8").split("\n").filter(Boolean);
|
|
911
920
|
}
|
|
912
921
|
var init_session_registry = __esm({
|
|
913
922
|
"src/app/agent/runtime/session_registry.ts"() {
|
|
@@ -916,17 +925,17 @@ var init_session_registry = __esm({
|
|
|
916
925
|
});
|
|
917
926
|
|
|
918
927
|
// src/app/agent/utils/logger.ts
|
|
919
|
-
import
|
|
928
|
+
import fs20 from "fs";
|
|
920
929
|
import os14 from "os";
|
|
921
|
-
import
|
|
930
|
+
import path20 from "path";
|
|
922
931
|
function getLogDir() {
|
|
923
|
-
const dir =
|
|
924
|
-
|
|
932
|
+
const dir = path20.join(process.env.HOME || os14.homedir(), ".bluma", "logs");
|
|
933
|
+
fs20.mkdirSync(dir, { recursive: true });
|
|
925
934
|
return dir;
|
|
926
935
|
}
|
|
927
936
|
function getLogFilePath() {
|
|
928
937
|
const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
929
|
-
return
|
|
938
|
+
return path20.join(getLogDir(), `bluma-${today}.log`);
|
|
930
939
|
}
|
|
931
940
|
var BluMaLogger, logger;
|
|
932
941
|
var init_logger = __esm({
|
|
@@ -956,7 +965,7 @@ var init_logger = __esm({
|
|
|
956
965
|
turnId: this.turnId
|
|
957
966
|
};
|
|
958
967
|
try {
|
|
959
|
-
|
|
968
|
+
fs20.appendFileSync(this.logFile, JSON.stringify(logEntry) + "\n");
|
|
960
969
|
} catch {
|
|
961
970
|
}
|
|
962
971
|
if (this.consoleEnabled) {
|
|
@@ -1057,19 +1066,19 @@ __export(mailbox_registry_exports, {
|
|
|
1057
1066
|
sendSignal: () => sendSignal,
|
|
1058
1067
|
sendToMailbox: () => sendToMailbox
|
|
1059
1068
|
});
|
|
1060
|
-
import
|
|
1069
|
+
import fs21 from "fs";
|
|
1061
1070
|
import os15 from "os";
|
|
1062
|
-
import
|
|
1071
|
+
import path21 from "path";
|
|
1063
1072
|
import { EventEmitter as EventEmitter4 } from "events";
|
|
1064
1073
|
import { v4 as uuidv45 } from "uuid";
|
|
1065
1074
|
function getMailboxesDir() {
|
|
1066
1075
|
if (mailboxesDir) return mailboxesDir;
|
|
1067
|
-
mailboxesDir =
|
|
1068
|
-
|
|
1076
|
+
mailboxesDir = path21.join(process.env.HOME || os15.homedir(), ".bluma", "mailboxes");
|
|
1077
|
+
fs21.mkdirSync(mailboxesDir, { recursive: true });
|
|
1069
1078
|
return mailboxesDir;
|
|
1070
1079
|
}
|
|
1071
1080
|
function getMailboxPath(sessionId, type) {
|
|
1072
|
-
return
|
|
1081
|
+
return path21.join(getMailboxesDir(), `${sessionId}.${type}`);
|
|
1073
1082
|
}
|
|
1074
1083
|
function sendToMailbox(sessionId, type, message2) {
|
|
1075
1084
|
return mailbox.sendToMailbox(sessionId, type, message2);
|
|
@@ -1095,7 +1104,7 @@ function pruneMailbox(sessionId, type, keepLast = 100) {
|
|
|
1095
1104
|
const pruned = queue.slice(-keepLast);
|
|
1096
1105
|
mailbox.queues.set(sessionId, pruned);
|
|
1097
1106
|
const filePath = getMailboxPath(sessionId, type);
|
|
1098
|
-
|
|
1107
|
+
fs21.writeFileSync(filePath, pruned.map((m) => JSON.stringify(m)).join("\n") + "\n", "utf-8");
|
|
1099
1108
|
}
|
|
1100
1109
|
function listActiveMailboxes() {
|
|
1101
1110
|
const result = [];
|
|
@@ -1163,16 +1172,16 @@ var init_mailbox_registry = __esm({
|
|
|
1163
1172
|
loadExistingMailboxes() {
|
|
1164
1173
|
try {
|
|
1165
1174
|
const dir = getMailboxesDir();
|
|
1166
|
-
const files =
|
|
1175
|
+
const files = fs21.readdirSync(dir);
|
|
1167
1176
|
for (const file of files) {
|
|
1168
1177
|
if (!file.endsWith(".in") && !file.endsWith(".out") && !file.endsWith(".sig")) {
|
|
1169
1178
|
continue;
|
|
1170
1179
|
}
|
|
1171
1180
|
const type = file.split(".").pop();
|
|
1172
1181
|
const sessionId = file.slice(0, -(type.length + 1));
|
|
1173
|
-
const filePath =
|
|
1182
|
+
const filePath = path21.join(dir, file);
|
|
1174
1183
|
try {
|
|
1175
|
-
const content =
|
|
1184
|
+
const content = fs21.readFileSync(filePath, "utf-8");
|
|
1176
1185
|
const lines = content.trim().split("\n").filter(Boolean);
|
|
1177
1186
|
const messages = [];
|
|
1178
1187
|
for (const line of lines) {
|
|
@@ -1209,7 +1218,7 @@ var init_mailbox_registry = __esm({
|
|
|
1209
1218
|
this.queues.set(sessionId, queue);
|
|
1210
1219
|
try {
|
|
1211
1220
|
const filePath = getMailboxPath(sessionId, type);
|
|
1212
|
-
|
|
1221
|
+
fs21.appendFileSync(filePath, JSON.stringify(fullMessage) + "\n", "utf-8");
|
|
1213
1222
|
} catch {
|
|
1214
1223
|
}
|
|
1215
1224
|
this.emit(`message:${sessionId}`, fullMessage);
|
|
@@ -1258,7 +1267,7 @@ var init_mailbox_registry = __esm({
|
|
|
1258
1267
|
this.emit(`signal:${sessionId}`, signal);
|
|
1259
1268
|
try {
|
|
1260
1269
|
const filePath = getMailboxPath(sessionId, "sig");
|
|
1261
|
-
|
|
1270
|
+
fs21.appendFileSync(filePath, JSON.stringify(signal) + "\n", "utf-8");
|
|
1262
1271
|
} catch {
|
|
1263
1272
|
}
|
|
1264
1273
|
return signal.id;
|
|
@@ -1272,9 +1281,9 @@ var init_mailbox_registry = __esm({
|
|
|
1272
1281
|
ensureMailbox(sessionId) {
|
|
1273
1282
|
const dir = getMailboxesDir();
|
|
1274
1283
|
for (const type of ["in", "out", "sig"]) {
|
|
1275
|
-
const filePath =
|
|
1276
|
-
if (!
|
|
1277
|
-
|
|
1284
|
+
const filePath = path21.join(dir, `${sessionId}.${type}`);
|
|
1285
|
+
if (!fs21.existsSync(filePath)) {
|
|
1286
|
+
fs21.writeFileSync(filePath, "", "utf-8");
|
|
1278
1287
|
}
|
|
1279
1288
|
}
|
|
1280
1289
|
}
|
|
@@ -1284,8 +1293,8 @@ var init_mailbox_registry = __esm({
|
|
|
1284
1293
|
removeMailbox(sessionId) {
|
|
1285
1294
|
const dir = getMailboxesDir();
|
|
1286
1295
|
for (const type of ["in", "out", "sig"]) {
|
|
1287
|
-
const filePath =
|
|
1288
|
-
if (
|
|
1296
|
+
const filePath = path21.join(dir, `${sessionId}.${type}`);
|
|
1297
|
+
if (fs21.existsSync(filePath)) fs21.unlinkSync(filePath);
|
|
1289
1298
|
}
|
|
1290
1299
|
this.queues.delete(sessionId);
|
|
1291
1300
|
this.signalQueues.delete(sessionId);
|
|
@@ -1304,9 +1313,9 @@ __export(AgentCoordinationTool_exports, {
|
|
|
1304
1313
|
spawnAgent: () => spawnAgent,
|
|
1305
1314
|
waitAgent: () => waitAgent
|
|
1306
1315
|
});
|
|
1307
|
-
import
|
|
1316
|
+
import fs22 from "fs";
|
|
1308
1317
|
import os16 from "os";
|
|
1309
|
-
import
|
|
1318
|
+
import path22 from "path";
|
|
1310
1319
|
import { spawn as spawn4 } from "child_process";
|
|
1311
1320
|
import { v4 as uuidv46 } from "uuid";
|
|
1312
1321
|
function readUserContextFromEnv() {
|
|
@@ -1420,10 +1429,10 @@ async function spawnAgent(args) {
|
|
|
1420
1429
|
spawnLog.error("Payload NOT serializable", { error: e.message });
|
|
1421
1430
|
throw new BluMaError("WORKER_CONTEXT_NOT_SERIALIZABLE" /* WORKER_CONTEXT_NOT_SERIALIZABLE */, `Worker context is not JSON-serializable: ${e.message}`);
|
|
1422
1431
|
}
|
|
1423
|
-
const payloadDir =
|
|
1424
|
-
const payloadPath =
|
|
1432
|
+
const payloadDir = fs22.mkdtempSync(path22.join(os16.tmpdir(), "bluma-worker-"));
|
|
1433
|
+
const payloadPath = path22.join(payloadDir, `${sessionId}.json`);
|
|
1425
1434
|
try {
|
|
1426
|
-
|
|
1435
|
+
fs22.writeFileSync(payloadPath, JSON.stringify(payload, null, 2), "utf-8");
|
|
1427
1436
|
spawnLog.debug("Payload written", { payloadPath });
|
|
1428
1437
|
} catch (e) {
|
|
1429
1438
|
spawnLog.error("Failed to write payload", { error: e.message, payloadPath });
|
|
@@ -2192,11 +2201,11 @@ var NodeFsOperations = {
|
|
|
2192
2201
|
if (fd) fs.closeSync(fd);
|
|
2193
2202
|
}
|
|
2194
2203
|
},
|
|
2195
|
-
appendFileSync(
|
|
2196
|
-
const _ = slowLogging`fs.appendFileSync(${
|
|
2204
|
+
appendFileSync(path51, data, options) {
|
|
2205
|
+
const _ = slowLogging`fs.appendFileSync(${path51}, ${data.length} chars)`;
|
|
2197
2206
|
if (options?.mode !== void 0) {
|
|
2198
2207
|
try {
|
|
2199
|
-
const fd = fs.openSync(
|
|
2208
|
+
const fd = fs.openSync(path51, "ax", options.mode);
|
|
2200
2209
|
try {
|
|
2201
2210
|
fs.appendFileSync(fd, data);
|
|
2202
2211
|
} finally {
|
|
@@ -2207,35 +2216,35 @@ var NodeFsOperations = {
|
|
|
2207
2216
|
if (getErrnoCode(e) !== "EEXIST") throw e;
|
|
2208
2217
|
}
|
|
2209
2218
|
}
|
|
2210
|
-
fs.appendFileSync(
|
|
2219
|
+
fs.appendFileSync(path51, data);
|
|
2211
2220
|
},
|
|
2212
2221
|
copyFileSync(src, dest) {
|
|
2213
2222
|
const _ = slowLogging`fs.copyFileSync(${src} → ${dest})`;
|
|
2214
2223
|
fs.copyFileSync(src, dest);
|
|
2215
2224
|
},
|
|
2216
|
-
unlinkSync(
|
|
2217
|
-
const _ = slowLogging`fs.unlinkSync(${
|
|
2218
|
-
fs.unlinkSync(
|
|
2225
|
+
unlinkSync(path51) {
|
|
2226
|
+
const _ = slowLogging`fs.unlinkSync(${path51})`;
|
|
2227
|
+
fs.unlinkSync(path51);
|
|
2219
2228
|
},
|
|
2220
2229
|
renameSync(oldPath, newPath) {
|
|
2221
2230
|
const _ = slowLogging`fs.renameSync(${oldPath} → ${newPath})`;
|
|
2222
2231
|
fs.renameSync(oldPath, newPath);
|
|
2223
2232
|
},
|
|
2224
|
-
linkSync(target,
|
|
2225
|
-
const _ = slowLogging`fs.linkSync(${target} → ${
|
|
2226
|
-
fs.linkSync(target,
|
|
2233
|
+
linkSync(target, path51) {
|
|
2234
|
+
const _ = slowLogging`fs.linkSync(${target} → ${path51})`;
|
|
2235
|
+
fs.linkSync(target, path51);
|
|
2227
2236
|
},
|
|
2228
|
-
symlinkSync(target,
|
|
2229
|
-
const _ = slowLogging`fs.symlinkSync(${target} → ${
|
|
2230
|
-
fs.symlinkSync(target,
|
|
2237
|
+
symlinkSync(target, path51, type) {
|
|
2238
|
+
const _ = slowLogging`fs.symlinkSync(${target} → ${path51})`;
|
|
2239
|
+
fs.symlinkSync(target, path51, type);
|
|
2231
2240
|
},
|
|
2232
|
-
readlinkSync(
|
|
2233
|
-
const _ = slowLogging`fs.readlinkSync(${
|
|
2234
|
-
return fs.readlinkSync(
|
|
2241
|
+
readlinkSync(path51) {
|
|
2242
|
+
const _ = slowLogging`fs.readlinkSync(${path51})`;
|
|
2243
|
+
return fs.readlinkSync(path51);
|
|
2235
2244
|
},
|
|
2236
|
-
realpathSync(
|
|
2237
|
-
const _ = slowLogging`fs.realpathSync(${
|
|
2238
|
-
return fs.realpathSync(
|
|
2245
|
+
realpathSync(path51) {
|
|
2246
|
+
const _ = slowLogging`fs.realpathSync(${path51})`;
|
|
2247
|
+
return fs.realpathSync(path51).normalize("NFC");
|
|
2239
2248
|
},
|
|
2240
2249
|
mkdirSync(dirPath, options) {
|
|
2241
2250
|
const _ = slowLogging`fs.mkdirSync(${dirPath})`;
|
|
@@ -2268,12 +2277,12 @@ var NodeFsOperations = {
|
|
|
2268
2277
|
const _ = slowLogging`fs.rmdirSync(${dirPath})`;
|
|
2269
2278
|
fs.rmdirSync(dirPath);
|
|
2270
2279
|
},
|
|
2271
|
-
rmSync(
|
|
2272
|
-
const _ = slowLogging`fs.rmSync(${
|
|
2273
|
-
fs.rmSync(
|
|
2280
|
+
rmSync(path51, options) {
|
|
2281
|
+
const _ = slowLogging`fs.rmSync(${path51})`;
|
|
2282
|
+
fs.rmSync(path51, options);
|
|
2274
2283
|
},
|
|
2275
|
-
createWriteStream(
|
|
2276
|
-
return fs.createWriteStream(
|
|
2284
|
+
createWriteStream(path51) {
|
|
2285
|
+
return fs.createWriteStream(path51);
|
|
2277
2286
|
},
|
|
2278
2287
|
async readFileBytes(fsPath, maxBytes) {
|
|
2279
2288
|
if (maxBytes === void 0) {
|
|
@@ -2380,12 +2389,12 @@ function shouldLogDebugMessage(message2) {
|
|
|
2380
2389
|
var hasFormattedOutput = false;
|
|
2381
2390
|
var debugWriter = null;
|
|
2382
2391
|
var pendingWrite = Promise.resolve();
|
|
2383
|
-
async function appendAsync(needMkdir, dir,
|
|
2392
|
+
async function appendAsync(needMkdir, dir, path51, content) {
|
|
2384
2393
|
if (needMkdir) {
|
|
2385
2394
|
await mkdir(dir, { recursive: true }).catch(() => {
|
|
2386
2395
|
});
|
|
2387
2396
|
}
|
|
2388
|
-
await appendFile(
|
|
2397
|
+
await appendFile(path51, content);
|
|
2389
2398
|
void updateLatestDebugLogSymlink();
|
|
2390
2399
|
}
|
|
2391
2400
|
function noop() {
|
|
@@ -2395,8 +2404,8 @@ function getDebugWriter() {
|
|
|
2395
2404
|
let ensuredDir = null;
|
|
2396
2405
|
debugWriter = createBufferedWriter({
|
|
2397
2406
|
writeFn: (content) => {
|
|
2398
|
-
const
|
|
2399
|
-
const dir = dirname(
|
|
2407
|
+
const path51 = getDebugLogPath();
|
|
2408
|
+
const dir = dirname(path51);
|
|
2400
2409
|
const needMkdir = ensuredDir !== dir;
|
|
2401
2410
|
ensuredDir = dir;
|
|
2402
2411
|
if (isDebugMode()) {
|
|
@@ -2406,11 +2415,11 @@ function getDebugWriter() {
|
|
|
2406
2415
|
} catch {
|
|
2407
2416
|
}
|
|
2408
2417
|
}
|
|
2409
|
-
getFsImplementation().appendFileSync(
|
|
2418
|
+
getFsImplementation().appendFileSync(path51, content);
|
|
2410
2419
|
void updateLatestDebugLogSymlink();
|
|
2411
2420
|
return;
|
|
2412
2421
|
}
|
|
2413
|
-
pendingWrite = pendingWrite.then(appendAsync.bind(null, needMkdir, dir,
|
|
2422
|
+
pendingWrite = pendingWrite.then(appendAsync.bind(null, needMkdir, dir, path51, content)).catch(noop);
|
|
2414
2423
|
},
|
|
2415
2424
|
flushIntervalMs: 1e3,
|
|
2416
2425
|
maxBufferSize: 100,
|
|
@@ -8597,8 +8606,8 @@ import codeExcerpt from "code-excerpt";
|
|
|
8597
8606
|
import { readFileSync as readFileSync2 } from "fs";
|
|
8598
8607
|
import StackUtils from "stack-utils";
|
|
8599
8608
|
import { jsx as jsx6, jsxs } from "react/jsx-runtime";
|
|
8600
|
-
var cleanupPath = (
|
|
8601
|
-
return
|
|
8609
|
+
var cleanupPath = (path51) => {
|
|
8610
|
+
return path51?.replace(`file://${process.cwd()}/`, "");
|
|
8602
8611
|
};
|
|
8603
8612
|
var stackUtils;
|
|
8604
8613
|
function getStackUtils() {
|
|
@@ -12575,8 +12584,8 @@ var getInstance = (stdout, createInstance) => {
|
|
|
12575
12584
|
|
|
12576
12585
|
// src/main.ts
|
|
12577
12586
|
import { EventEmitter as EventEmitter7 } from "events";
|
|
12578
|
-
import
|
|
12579
|
-
import
|
|
12587
|
+
import fs47 from "fs";
|
|
12588
|
+
import path50 from "path";
|
|
12580
12589
|
import { fileURLToPath as fileURLToPath7 } from "url";
|
|
12581
12590
|
import { spawn as spawn6 } from "child_process";
|
|
12582
12591
|
import { v4 as uuidv412 } from "uuid";
|
|
@@ -15120,12 +15129,12 @@ InputPrompt.displayName = "InputPrompt";
|
|
|
15120
15129
|
|
|
15121
15130
|
// src/app/agent/agent.ts
|
|
15122
15131
|
import * as dotenv from "dotenv";
|
|
15123
|
-
import
|
|
15132
|
+
import path44 from "path";
|
|
15124
15133
|
import os32 from "os";
|
|
15125
15134
|
|
|
15126
15135
|
// src/app/agent/tool_invoker.ts
|
|
15127
|
-
import { promises as
|
|
15128
|
-
import
|
|
15136
|
+
import { promises as fs29 } from "fs";
|
|
15137
|
+
import path29 from "path";
|
|
15129
15138
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
15130
15139
|
|
|
15131
15140
|
// src/app/agent/tools/EditTool/EditTool.ts
|
|
@@ -15668,8 +15677,168 @@ ${finalDiff}`,
|
|
|
15668
15677
|
|
|
15669
15678
|
// src/app/agent/tools/MessageTool/MessageTool.ts
|
|
15670
15679
|
import { v4 as uuidv42 } from "uuid";
|
|
15680
|
+
|
|
15681
|
+
// src/app/agent/runtime/sandbox_message_validation.ts
|
|
15682
|
+
init_sandbox_policy();
|
|
15683
|
+
import fs9 from "fs";
|
|
15684
|
+
import path8 from "path";
|
|
15685
|
+
var HTTP_URL_PATTERN = /^https?:\/\//i;
|
|
15686
|
+
function normalizeAttachmentPath(entry) {
|
|
15687
|
+
if (typeof entry === "string") {
|
|
15688
|
+
const trimmed = entry.trim();
|
|
15689
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
15690
|
+
}
|
|
15691
|
+
if (entry && typeof entry === "object" && "path" in entry) {
|
|
15692
|
+
const pathValue = entry.path;
|
|
15693
|
+
if (typeof pathValue === "string") {
|
|
15694
|
+
const trimmed = pathValue.trim();
|
|
15695
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
15696
|
+
}
|
|
15697
|
+
}
|
|
15698
|
+
return null;
|
|
15699
|
+
}
|
|
15700
|
+
function looksLikeHttpUrl(value) {
|
|
15701
|
+
return HTTP_URL_PATTERN.test(value.trim());
|
|
15702
|
+
}
|
|
15703
|
+
function taskExpectsFileDeliverable(userRequest) {
|
|
15704
|
+
if (!userRequest || !userRequest.trim()) {
|
|
15705
|
+
return false;
|
|
15706
|
+
}
|
|
15707
|
+
const text = userRequest.toLowerCase();
|
|
15708
|
+
return /\b(pdf|excel|xlsx|csv|docx|documento|relat[oó]rio|ficheiro|arquivo|export|download|artifact|artefacto|anexo)\b/i.test(
|
|
15709
|
+
text
|
|
15710
|
+
);
|
|
15711
|
+
}
|
|
15712
|
+
function validateSandboxMessageDeliverables(args, policy = getSandboxPolicy(), options) {
|
|
15713
|
+
if (!policy.isSandbox) {
|
|
15714
|
+
return { ok: true };
|
|
15715
|
+
}
|
|
15716
|
+
if (args.message_type !== "result") {
|
|
15717
|
+
return { ok: true };
|
|
15718
|
+
}
|
|
15719
|
+
const attachments = args.attachments;
|
|
15720
|
+
const hasAttachments = Array.isArray(attachments) && attachments.length > 0;
|
|
15721
|
+
if (!hasAttachments && taskExpectsFileDeliverable(options?.userRequest)) {
|
|
15722
|
+
return {
|
|
15723
|
+
ok: false,
|
|
15724
|
+
error: "File deliverables must use attachments[]",
|
|
15725
|
+
details: 'Write the file under .bluma/artifacts/ with file_write, then call message(result) with attachments: [".bluma/artifacts/<filename>"]. Paths in content alone are not delivered to the orchestrator.'
|
|
15726
|
+
};
|
|
15727
|
+
}
|
|
15728
|
+
if (!hasAttachments) {
|
|
15729
|
+
return { ok: true };
|
|
15730
|
+
}
|
|
15731
|
+
for (const entry of attachments) {
|
|
15732
|
+
const raw = normalizeAttachmentPath(entry);
|
|
15733
|
+
if (!raw) {
|
|
15734
|
+
return {
|
|
15735
|
+
ok: false,
|
|
15736
|
+
error: "Invalid attachment entry",
|
|
15737
|
+
details: 'Each attachment must be a workspace file path (string) or { path: ".bluma/artifacts/..." }. URLs are not allowed.'
|
|
15738
|
+
};
|
|
15739
|
+
}
|
|
15740
|
+
if (looksLikeHttpUrl(raw)) {
|
|
15741
|
+
return {
|
|
15742
|
+
ok: false,
|
|
15743
|
+
error: "Attachments cannot be URLs in sandbox",
|
|
15744
|
+
details: `Rejected "${raw}". Use file_write to create a file under .bluma/artifacts/ and pass that path in attachments[].`
|
|
15745
|
+
};
|
|
15746
|
+
}
|
|
15747
|
+
let resolved;
|
|
15748
|
+
try {
|
|
15749
|
+
resolved = resolveWorkspacePath(raw, policy);
|
|
15750
|
+
} catch (err) {
|
|
15751
|
+
return {
|
|
15752
|
+
ok: false,
|
|
15753
|
+
error: "Attachment path is outside the sandbox workspace",
|
|
15754
|
+
details: err instanceof Error ? err.message : String(err)
|
|
15755
|
+
};
|
|
15756
|
+
}
|
|
15757
|
+
if (!fs9.existsSync(resolved)) {
|
|
15758
|
+
return {
|
|
15759
|
+
ok: false,
|
|
15760
|
+
error: "Attachment file does not exist",
|
|
15761
|
+
details: `Create the deliverable first (file_write \u2192 .bluma/artifacts/...). Missing: ${resolved}`
|
|
15762
|
+
};
|
|
15763
|
+
}
|
|
15764
|
+
const stat = fs9.statSync(resolved);
|
|
15765
|
+
if (!stat.isFile()) {
|
|
15766
|
+
return {
|
|
15767
|
+
ok: false,
|
|
15768
|
+
error: "Attachment must be a file",
|
|
15769
|
+
details: resolved
|
|
15770
|
+
};
|
|
15771
|
+
}
|
|
15772
|
+
if (!isPathInsideArtifactsDirectory(resolved, policy)) {
|
|
15773
|
+
const artifactsDir2 = getArtifactsDirectory(policy);
|
|
15774
|
+
return {
|
|
15775
|
+
ok: false,
|
|
15776
|
+
error: "Files are delivered only via .bluma/artifacts/",
|
|
15777
|
+
details: `Move or copy the deliverable to ${path8.relative(policy.workspaceRoot, artifactsDir2)}/ and pass that path in attachments[]. Rejected: ${raw}`
|
|
15778
|
+
};
|
|
15779
|
+
}
|
|
15780
|
+
}
|
|
15781
|
+
return { ok: true };
|
|
15782
|
+
}
|
|
15783
|
+
|
|
15784
|
+
// src/app/agent/tools/MessageTool/normalize_args.ts
|
|
15785
|
+
function normalizeMessageToolArgs(raw) {
|
|
15786
|
+
const content = typeof raw.content === "string" ? raw.content : typeof raw.body === "string" ? raw.body : typeof raw.text === "string" ? raw.text : "";
|
|
15787
|
+
const messageTypeRaw = raw.message_type ?? raw.messageType ?? raw.type ?? raw.kind ?? "info";
|
|
15788
|
+
const message_type = String(messageTypeRaw).toLowerCase() === "result" ? "result" : "info";
|
|
15789
|
+
let attachments;
|
|
15790
|
+
const rawAttachments = raw.attachments;
|
|
15791
|
+
if (Array.isArray(rawAttachments)) {
|
|
15792
|
+
attachments = rawAttachments.map((entry) => {
|
|
15793
|
+
if (typeof entry === "string") {
|
|
15794
|
+
return entry.trim();
|
|
15795
|
+
}
|
|
15796
|
+
if (entry && typeof entry === "object" && "path" in entry) {
|
|
15797
|
+
const pathValue = entry.path;
|
|
15798
|
+
return typeof pathValue === "string" ? pathValue.trim() : "";
|
|
15799
|
+
}
|
|
15800
|
+
return "";
|
|
15801
|
+
}).filter((value) => value.length > 0);
|
|
15802
|
+
} else if (typeof rawAttachments === "string" && rawAttachments.trim()) {
|
|
15803
|
+
try {
|
|
15804
|
+
const parsed = JSON.parse(rawAttachments);
|
|
15805
|
+
if (Array.isArray(parsed)) {
|
|
15806
|
+
attachments = parsed.filter((value) => typeof value === "string");
|
|
15807
|
+
}
|
|
15808
|
+
} catch {
|
|
15809
|
+
attachments = [rawAttachments.trim()];
|
|
15810
|
+
}
|
|
15811
|
+
}
|
|
15812
|
+
return {
|
|
15813
|
+
content,
|
|
15814
|
+
message_type,
|
|
15815
|
+
attachments: attachments?.length ? attachments : void 0
|
|
15816
|
+
};
|
|
15817
|
+
}
|
|
15818
|
+
|
|
15819
|
+
// src/app/agent/tools/MessageTool/MessageTool.ts
|
|
15671
15820
|
function message(args) {
|
|
15672
|
-
const { content, message_type, attachments } =
|
|
15821
|
+
const { content, message_type, attachments } = normalizeMessageToolArgs(
|
|
15822
|
+
args
|
|
15823
|
+
);
|
|
15824
|
+
const deliverableCheck = validateSandboxMessageDeliverables(
|
|
15825
|
+
{
|
|
15826
|
+
message_type,
|
|
15827
|
+
attachments,
|
|
15828
|
+
content
|
|
15829
|
+
},
|
|
15830
|
+
void 0,
|
|
15831
|
+
{ userRequest: process.env.BLUMA_USER_REQUEST }
|
|
15832
|
+
);
|
|
15833
|
+
if (!deliverableCheck.ok) {
|
|
15834
|
+
return Promise.resolve({
|
|
15835
|
+
status: "error",
|
|
15836
|
+
success: false,
|
|
15837
|
+
error: deliverableCheck.error,
|
|
15838
|
+
details: deliverableCheck.details,
|
|
15839
|
+
message_type
|
|
15840
|
+
});
|
|
15841
|
+
}
|
|
15673
15842
|
const result = {
|
|
15674
15843
|
type: "message",
|
|
15675
15844
|
message_type,
|
|
@@ -15686,8 +15855,8 @@ function message(args) {
|
|
|
15686
15855
|
}
|
|
15687
15856
|
|
|
15688
15857
|
// src/app/agent/tools/LsTool/LsTool.ts
|
|
15689
|
-
import { promises as
|
|
15690
|
-
import
|
|
15858
|
+
import { promises as fs10 } from "fs";
|
|
15859
|
+
import path9 from "path";
|
|
15691
15860
|
import os7 from "os";
|
|
15692
15861
|
import { minimatch } from "minimatch";
|
|
15693
15862
|
var DEFAULT_IGNORE = /* @__PURE__ */ new Set([
|
|
@@ -15707,7 +15876,7 @@ var DEFAULT_IGNORE = /* @__PURE__ */ new Set([
|
|
|
15707
15876
|
]);
|
|
15708
15877
|
function expandPath(p) {
|
|
15709
15878
|
if (p === "~" || p.startsWith("~/")) {
|
|
15710
|
-
return
|
|
15879
|
+
return path9.join(os7.homedir(), p.slice(2));
|
|
15711
15880
|
}
|
|
15712
15881
|
return p;
|
|
15713
15882
|
}
|
|
@@ -15733,8 +15902,8 @@ async function ls(args) {
|
|
|
15733
15902
|
max_depth
|
|
15734
15903
|
} = args;
|
|
15735
15904
|
try {
|
|
15736
|
-
const basePath =
|
|
15737
|
-
const stat = await
|
|
15905
|
+
const basePath = path9.resolve(expandPath(directory_path));
|
|
15906
|
+
const stat = await fs10.stat(basePath).catch(() => null);
|
|
15738
15907
|
if (!stat || !stat.isDirectory()) {
|
|
15739
15908
|
throw new Error(`Directory '${directory_path}' not found.`);
|
|
15740
15909
|
}
|
|
@@ -15746,11 +15915,11 @@ async function ls(args) {
|
|
|
15746
15915
|
const allDirs = [];
|
|
15747
15916
|
const walk = async (currentDir, currentDepth) => {
|
|
15748
15917
|
if (max_depth !== void 0 && currentDepth >= max_depth) return;
|
|
15749
|
-
const entries = await
|
|
15918
|
+
const entries = await fs10.readdir(currentDir, { withFileTypes: true });
|
|
15750
15919
|
for (const entry of entries) {
|
|
15751
15920
|
const entryName = entry.name;
|
|
15752
|
-
const fullPath =
|
|
15753
|
-
const relativePath =
|
|
15921
|
+
const fullPath = path9.join(currentDir, entryName);
|
|
15922
|
+
const relativePath = path9.relative(basePath, fullPath).split(path9.sep).join("/");
|
|
15754
15923
|
const isHidden = entryName.startsWith(".");
|
|
15755
15924
|
if (shouldIgnore(entryName, allIgnorePatterns) || isHidden && !show_hidden) {
|
|
15756
15925
|
continue;
|
|
@@ -15759,7 +15928,7 @@ async function ls(args) {
|
|
|
15759
15928
|
allDirs.push(relativePath);
|
|
15760
15929
|
if (recursive) await walk(fullPath, currentDepth + 1);
|
|
15761
15930
|
} else if (entry.isFile()) {
|
|
15762
|
-
if (!normalizedExtensions || normalizedExtensions.includes(
|
|
15931
|
+
if (!normalizedExtensions || normalizedExtensions.includes(path9.extname(entryName).toLowerCase())) {
|
|
15763
15932
|
allFiles.push(relativePath);
|
|
15764
15933
|
}
|
|
15765
15934
|
}
|
|
@@ -15772,7 +15941,7 @@ async function ls(args) {
|
|
|
15772
15941
|
const dirEnd = end_index ?? allDirs.length;
|
|
15773
15942
|
return {
|
|
15774
15943
|
success: true,
|
|
15775
|
-
path: basePath.split(
|
|
15944
|
+
path: basePath.split(path9.sep).join("/"),
|
|
15776
15945
|
recursive,
|
|
15777
15946
|
total_files: allFiles.length,
|
|
15778
15947
|
total_directories: allDirs.length,
|
|
@@ -15794,13 +15963,13 @@ async function ls(args) {
|
|
|
15794
15963
|
|
|
15795
15964
|
// src/app/agent/tools/ReadLinesTool/ReadLinesTool.ts
|
|
15796
15965
|
init_sandbox_policy();
|
|
15797
|
-
import { promises as
|
|
15798
|
-
import
|
|
15966
|
+
import { promises as fs11 } from "fs";
|
|
15967
|
+
import path10 from "path";
|
|
15799
15968
|
import os8 from "os";
|
|
15800
15969
|
var DEFAULT_LINE_WINDOW = 2e3;
|
|
15801
15970
|
function expandPath2(p) {
|
|
15802
15971
|
if (p === "~" || p.startsWith("~/")) {
|
|
15803
|
-
return
|
|
15972
|
+
return path10.join(os8.homedir(), p.slice(2));
|
|
15804
15973
|
}
|
|
15805
15974
|
return p;
|
|
15806
15975
|
}
|
|
@@ -15818,7 +15987,7 @@ async function readLines(args) {
|
|
|
15818
15987
|
}
|
|
15819
15988
|
try {
|
|
15820
15989
|
const resolvedPath = resolveWorkspacePath(expandPath2(filepath));
|
|
15821
|
-
const stat = await
|
|
15990
|
+
const stat = await fs11.stat(resolvedPath).catch(() => null);
|
|
15822
15991
|
if (!stat || !stat.isFile()) {
|
|
15823
15992
|
const workspaceRoot = resolveWorkspacePath(".");
|
|
15824
15993
|
const isInsideWorkspace = resolvedPath.startsWith(workspaceRoot);
|
|
@@ -15837,7 +16006,7 @@ async function readLines(args) {
|
|
|
15837
16006
|
if (endLine < startLine) {
|
|
15838
16007
|
throw new Error("Invalid line range: end_line must be >= start_line.");
|
|
15839
16008
|
}
|
|
15840
|
-
const fileContent = await
|
|
16009
|
+
const fileContent = await fs11.readFile(resolvedPath, "utf-8");
|
|
15841
16010
|
const lines = fileContent.split("\n");
|
|
15842
16011
|
const total_lines = lines.length;
|
|
15843
16012
|
const startIndex = startLine - 1;
|
|
@@ -15868,7 +16037,7 @@ async function readLines(args) {
|
|
|
15868
16037
|
|
|
15869
16038
|
// src/app/agent/tools/CountLinesTool/CountLinesTool.ts
|
|
15870
16039
|
import { createReadStream } from "fs";
|
|
15871
|
-
import { promises as
|
|
16040
|
+
import { promises as fs12 } from "fs";
|
|
15872
16041
|
import readline from "readline";
|
|
15873
16042
|
async function countLines(args) {
|
|
15874
16043
|
const filepathInput = typeof args?.filepath === "string" && args.filepath.trim().length > 0 ? args.filepath : typeof args?.file_path === "string" ? args.file_path : "";
|
|
@@ -15895,7 +16064,7 @@ async function countLines(args) {
|
|
|
15895
16064
|
};
|
|
15896
16065
|
}
|
|
15897
16066
|
try {
|
|
15898
|
-
if (!(await
|
|
16067
|
+
if (!(await fs12.stat(filepath)).isFile()) {
|
|
15899
16068
|
throw new Error(`File '${filepath}' not found or is not a file.`);
|
|
15900
16069
|
}
|
|
15901
16070
|
const fileStream = createReadStream(filepath);
|
|
@@ -16085,7 +16254,7 @@ function formatTodoResult(result) {
|
|
|
16085
16254
|
|
|
16086
16255
|
// src/app/agent/tools/FindByNameTool/FindByNameTool.ts
|
|
16087
16256
|
init_sandbox_policy();
|
|
16088
|
-
import
|
|
16257
|
+
import path12 from "path";
|
|
16089
16258
|
import { promises as fsPromises } from "fs";
|
|
16090
16259
|
import os9 from "os";
|
|
16091
16260
|
var MAX_RESULTS2 = 100;
|
|
@@ -16109,7 +16278,7 @@ var DEFAULT_IGNORE2 = /* @__PURE__ */ new Set([
|
|
|
16109
16278
|
]);
|
|
16110
16279
|
function expandTilde2(p) {
|
|
16111
16280
|
if (p === "~") return os9.homedir();
|
|
16112
|
-
if (p.startsWith("~/")) return
|
|
16281
|
+
if (p.startsWith("~/")) return path12.join(os9.homedir(), p.slice(2));
|
|
16113
16282
|
return p;
|
|
16114
16283
|
}
|
|
16115
16284
|
function globToRegex(glob) {
|
|
@@ -16153,7 +16322,7 @@ function shouldIgnore2(name, extraPatterns, includeHidden) {
|
|
|
16153
16322
|
}
|
|
16154
16323
|
function matchesExtensions(filename, extensions) {
|
|
16155
16324
|
if (!extensions || extensions.length === 0) return true;
|
|
16156
|
-
const ext =
|
|
16325
|
+
const ext = path12.extname(filename).toLowerCase();
|
|
16157
16326
|
return extensions.some((e) => {
|
|
16158
16327
|
const norm = e.startsWith(".") ? e.toLowerCase() : `.${e.toLowerCase()}`;
|
|
16159
16328
|
return ext === norm;
|
|
@@ -16171,8 +16340,8 @@ async function searchDirectory(dir, pattern, baseDir, options, results) {
|
|
|
16171
16340
|
if (results.length >= MAX_RESULTS2) break;
|
|
16172
16341
|
const { name } = entry;
|
|
16173
16342
|
if (shouldIgnore2(name, options.excludePatterns, options.includeHidden)) continue;
|
|
16174
|
-
const fullPath =
|
|
16175
|
-
const relativePath =
|
|
16343
|
+
const fullPath = path12.join(dir, name);
|
|
16344
|
+
const relativePath = path12.relative(baseDir, fullPath).split(path12.sep).join("/");
|
|
16176
16345
|
if (entry.isDirectory()) {
|
|
16177
16346
|
if (pattern.test(name)) {
|
|
16178
16347
|
results.push({ path: relativePath, type: "directory" });
|
|
@@ -16254,7 +16423,7 @@ async function findByName(args) {
|
|
|
16254
16423
|
}
|
|
16255
16424
|
|
|
16256
16425
|
// src/app/agent/tools/GrepSearchTool/GrepSearchTool.ts
|
|
16257
|
-
import
|
|
16426
|
+
import path13 from "path";
|
|
16258
16427
|
import { promises as fsPromises2 } from "fs";
|
|
16259
16428
|
import os10 from "os";
|
|
16260
16429
|
var MAX_RESULTS3 = 200;
|
|
@@ -16344,12 +16513,12 @@ var TEXT_BASENAMES = /* @__PURE__ */ new Set([
|
|
|
16344
16513
|
]);
|
|
16345
16514
|
function expandTilde3(p) {
|
|
16346
16515
|
if (p === "~") return os10.homedir();
|
|
16347
|
-
if (p.startsWith("~/")) return
|
|
16516
|
+
if (p.startsWith("~/")) return path13.join(os10.homedir(), p.slice(2));
|
|
16348
16517
|
return p;
|
|
16349
16518
|
}
|
|
16350
16519
|
function isTextFile(filepath) {
|
|
16351
|
-
const ext =
|
|
16352
|
-
const base =
|
|
16520
|
+
const ext = path13.extname(filepath).toLowerCase();
|
|
16521
|
+
const base = path13.basename(filepath);
|
|
16353
16522
|
return TEXT_EXTENSIONS.has(ext) || TEXT_BASENAMES.has(base) || base.startsWith(".") && !ext;
|
|
16354
16523
|
}
|
|
16355
16524
|
function shouldIgnore3(name) {
|
|
@@ -16386,7 +16555,7 @@ async function searchFile(filepath, baseDir, pattern, contextLines, maxMatchesPe
|
|
|
16386
16555
|
if (stat.size > MAX_FILE_SIZE) return null;
|
|
16387
16556
|
const content = await fsPromises2.readFile(filepath, "utf-8");
|
|
16388
16557
|
const lines = content.split("\n");
|
|
16389
|
-
const relativePath =
|
|
16558
|
+
const relativePath = path13.relative(baseDir, filepath).split(path13.sep).join("/");
|
|
16390
16559
|
const matches = [];
|
|
16391
16560
|
for (let i = 0; i < lines.length && matches.length < maxMatchesPerFile; i++) {
|
|
16392
16561
|
const line = lines[i];
|
|
@@ -16420,7 +16589,7 @@ async function searchDirectory2(dir, baseDir, pattern, includePatterns, contextL
|
|
|
16420
16589
|
for (const entry of entries) {
|
|
16421
16590
|
if (stats.totalMatches >= maxResults) break;
|
|
16422
16591
|
if (shouldIgnore3(entry.name)) continue;
|
|
16423
|
-
const fullPath =
|
|
16592
|
+
const fullPath = path13.join(dir, entry.name);
|
|
16424
16593
|
if (entry.isDirectory()) {
|
|
16425
16594
|
await searchDirectory2(fullPath, baseDir, pattern, includePatterns, contextLines, maxResults, maxMatchesPerFile, results, stats);
|
|
16426
16595
|
} else if (entry.isFile()) {
|
|
@@ -16461,7 +16630,7 @@ async function grepSearch(args) {
|
|
|
16461
16630
|
});
|
|
16462
16631
|
if (!query || typeof query !== "string") return empty("query is required");
|
|
16463
16632
|
if (!searchPath) return empty("path is required");
|
|
16464
|
-
const resolvedPath =
|
|
16633
|
+
const resolvedPath = path13.resolve(expandTilde3(searchPath));
|
|
16465
16634
|
const stat = await fsPromises2.stat(resolvedPath).catch(() => null);
|
|
16466
16635
|
if (!stat) return empty(`Path not found: ${resolvedPath}`);
|
|
16467
16636
|
let pattern;
|
|
@@ -16477,7 +16646,7 @@ async function grepSearch(args) {
|
|
|
16477
16646
|
await searchDirectory2(resolvedPath, resolvedPath, pattern, include_patterns, context_lines, max_results, max_matches_per_file, results, stats);
|
|
16478
16647
|
} else if (stat.isFile()) {
|
|
16479
16648
|
stats.filesSearched = 1;
|
|
16480
|
-
const fileResult = await searchFile(resolvedPath,
|
|
16649
|
+
const fileResult = await searchFile(resolvedPath, path13.dirname(resolvedPath), pattern, context_lines, max_matches_per_file);
|
|
16481
16650
|
if (fileResult) {
|
|
16482
16651
|
results.push(fileResult);
|
|
16483
16652
|
stats.totalMatches = fileResult.match_count;
|
|
@@ -16500,7 +16669,7 @@ async function grepSearch(args) {
|
|
|
16500
16669
|
}
|
|
16501
16670
|
|
|
16502
16671
|
// src/app/agent/tools/ViewFileOutlineTool/ViewFileOutlineTool.ts
|
|
16503
|
-
import
|
|
16672
|
+
import path14 from "path";
|
|
16504
16673
|
import { promises as fsPromises3 } from "fs";
|
|
16505
16674
|
var LANGUAGE_MAP = {
|
|
16506
16675
|
".ts": "typescript",
|
|
@@ -16614,7 +16783,7 @@ var PATTERNS = {
|
|
|
16614
16783
|
]
|
|
16615
16784
|
};
|
|
16616
16785
|
function detectLanguage(filepath) {
|
|
16617
|
-
const ext =
|
|
16786
|
+
const ext = path14.extname(filepath).toLowerCase();
|
|
16618
16787
|
return LANGUAGE_MAP[ext] || "unknown";
|
|
16619
16788
|
}
|
|
16620
16789
|
function determineItemType(line, language) {
|
|
@@ -16710,7 +16879,7 @@ async function viewFileOutline(args) {
|
|
|
16710
16879
|
error: "file_path is required and must be a string"
|
|
16711
16880
|
};
|
|
16712
16881
|
}
|
|
16713
|
-
const resolvedPath =
|
|
16882
|
+
const resolvedPath = path14.resolve(file_path);
|
|
16714
16883
|
let content;
|
|
16715
16884
|
try {
|
|
16716
16885
|
content = await fsPromises3.readFile(resolvedPath, "utf-8");
|
|
@@ -16756,21 +16925,21 @@ init_CommandStatusTool();
|
|
|
16756
16925
|
// src/app/agent/tools/TaskBoundaryTool/TaskBoundaryTool.ts
|
|
16757
16926
|
init_sandbox_policy();
|
|
16758
16927
|
init_task_store();
|
|
16759
|
-
import
|
|
16760
|
-
import { promises as
|
|
16928
|
+
import path15 from "path";
|
|
16929
|
+
import { promises as fs14 } from "fs";
|
|
16761
16930
|
var artifactsDir = null;
|
|
16762
16931
|
async function getArtifactsDir() {
|
|
16763
16932
|
if (artifactsDir) return artifactsDir;
|
|
16764
16933
|
const policy = getSandboxPolicy();
|
|
16765
|
-
const baseDir =
|
|
16934
|
+
const baseDir = path15.join(policy.workspaceRoot, ".bluma", "artifacts");
|
|
16766
16935
|
const sessionId = Date.now().toString(36) + Math.random().toString(36).substr(2, 5);
|
|
16767
|
-
artifactsDir =
|
|
16768
|
-
await
|
|
16936
|
+
artifactsDir = path15.join(baseDir, sessionId);
|
|
16937
|
+
await fs14.mkdir(artifactsDir, { recursive: true });
|
|
16769
16938
|
return artifactsDir;
|
|
16770
16939
|
}
|
|
16771
16940
|
async function updateTaskFile(task) {
|
|
16772
16941
|
const dir = await getArtifactsDir();
|
|
16773
|
-
const taskFile =
|
|
16942
|
+
const taskFile = path15.join(dir, "task.md");
|
|
16774
16943
|
const content = `# ${task.taskName}
|
|
16775
16944
|
|
|
16776
16945
|
**Mode:** ${task.mode}
|
|
@@ -16782,7 +16951,7 @@ async function updateTaskFile(task) {
|
|
|
16782
16951
|
## Summary
|
|
16783
16952
|
${task.summary}
|
|
16784
16953
|
`;
|
|
16785
|
-
await
|
|
16954
|
+
await fs14.writeFile(taskFile, content, "utf-8");
|
|
16786
16955
|
}
|
|
16787
16956
|
async function taskBoundary(args) {
|
|
16788
16957
|
try {
|
|
@@ -16898,8 +17067,8 @@ async function readArtifact(args) {
|
|
|
16898
17067
|
return { success: false, error: "filename is required" };
|
|
16899
17068
|
}
|
|
16900
17069
|
const dir = await getArtifactsDir();
|
|
16901
|
-
const filepath =
|
|
16902
|
-
const content = await
|
|
17070
|
+
const filepath = path15.join(dir, filename);
|
|
17071
|
+
const content = await fs14.readFile(filepath, "utf-8");
|
|
16903
17072
|
return {
|
|
16904
17073
|
success: true,
|
|
16905
17074
|
content
|
|
@@ -17443,8 +17612,8 @@ ${skill.content}`;
|
|
|
17443
17612
|
}
|
|
17444
17613
|
|
|
17445
17614
|
// src/app/agent/tools/CodingMemoryTool/CodingMemoryTool.ts
|
|
17446
|
-
import * as
|
|
17447
|
-
import * as
|
|
17615
|
+
import * as fs15 from "fs";
|
|
17616
|
+
import * as path16 from "path";
|
|
17448
17617
|
import os12 from "os";
|
|
17449
17618
|
var PROMPT_DEFAULT_MAX_TOTAL = 1e4;
|
|
17450
17619
|
var PROMPT_DEFAULT_MAX_NOTES = 25;
|
|
@@ -17453,14 +17622,14 @@ function readCodingMemoryForPrompt(options) {
|
|
|
17453
17622
|
const maxTotal = options?.maxTotalChars ?? PROMPT_DEFAULT_MAX_TOTAL;
|
|
17454
17623
|
const maxNotes = options?.maxNotes ?? PROMPT_DEFAULT_MAX_NOTES;
|
|
17455
17624
|
const preview = options?.previewCharsPerNote ?? PROMPT_DEFAULT_PREVIEW;
|
|
17456
|
-
const globalPath =
|
|
17457
|
-
const legacyPath =
|
|
17625
|
+
const globalPath = path16.join(os12.homedir(), ".bluma", "coding_memory.json");
|
|
17626
|
+
const legacyPath = path16.join(process.cwd(), ".bluma", "coding_memory.json");
|
|
17458
17627
|
let raw = null;
|
|
17459
17628
|
try {
|
|
17460
|
-
if (
|
|
17461
|
-
raw =
|
|
17462
|
-
} else if (
|
|
17463
|
-
raw =
|
|
17629
|
+
if (fs15.existsSync(globalPath)) {
|
|
17630
|
+
raw = fs15.readFileSync(globalPath, "utf-8");
|
|
17631
|
+
} else if (path16.resolve(globalPath) !== path16.resolve(legacyPath) && fs15.existsSync(legacyPath)) {
|
|
17632
|
+
raw = fs15.readFileSync(legacyPath, "utf-8");
|
|
17464
17633
|
}
|
|
17465
17634
|
} catch {
|
|
17466
17635
|
return "";
|
|
@@ -17498,10 +17667,10 @@ var memoryStore = [];
|
|
|
17498
17667
|
var nextId = 1;
|
|
17499
17668
|
var loaded = false;
|
|
17500
17669
|
function getMemoryFilePath() {
|
|
17501
|
-
return
|
|
17670
|
+
return path16.join(os12.homedir(), ".bluma", "coding_memory.json");
|
|
17502
17671
|
}
|
|
17503
17672
|
function getLegacyMemoryFilePath() {
|
|
17504
|
-
return
|
|
17673
|
+
return path16.join(process.cwd(), ".bluma", "coding_memory.json");
|
|
17505
17674
|
}
|
|
17506
17675
|
function loadMemoryFromFile() {
|
|
17507
17676
|
if (loaded) return;
|
|
@@ -17511,19 +17680,19 @@ function loadMemoryFromFile() {
|
|
|
17511
17680
|
try {
|
|
17512
17681
|
const filePath = getMemoryFilePath();
|
|
17513
17682
|
const legacy = getLegacyMemoryFilePath();
|
|
17514
|
-
const legacyDistinct =
|
|
17683
|
+
const legacyDistinct = path16.resolve(legacy) !== path16.resolve(filePath);
|
|
17515
17684
|
const readIntoStore = (p) => {
|
|
17516
|
-
const raw =
|
|
17685
|
+
const raw = fs15.readFileSync(p, "utf-8");
|
|
17517
17686
|
const parsed = JSON.parse(raw);
|
|
17518
17687
|
if (Array.isArray(parsed.entries)) {
|
|
17519
17688
|
memoryStore = parsed.entries;
|
|
17520
17689
|
nextId = typeof parsed.nextId === "number" ? parsed.nextId : memoryStore.length + 1;
|
|
17521
17690
|
}
|
|
17522
17691
|
};
|
|
17523
|
-
if (
|
|
17692
|
+
if (fs15.existsSync(filePath)) {
|
|
17524
17693
|
readIntoStore(filePath);
|
|
17525
17694
|
}
|
|
17526
|
-
if (memoryStore.length === 0 && legacyDistinct &&
|
|
17695
|
+
if (memoryStore.length === 0 && legacyDistinct && fs15.existsSync(legacy)) {
|
|
17527
17696
|
readIntoStore(legacy);
|
|
17528
17697
|
if (memoryStore.length > 0) {
|
|
17529
17698
|
saveMemoryToFile();
|
|
@@ -17537,16 +17706,16 @@ function loadMemoryFromFile() {
|
|
|
17537
17706
|
function saveMemoryToFile() {
|
|
17538
17707
|
try {
|
|
17539
17708
|
const filePath = getMemoryFilePath();
|
|
17540
|
-
const dir =
|
|
17541
|
-
if (!
|
|
17542
|
-
|
|
17709
|
+
const dir = path16.dirname(filePath);
|
|
17710
|
+
if (!fs15.existsSync(dir)) {
|
|
17711
|
+
fs15.mkdirSync(dir, { recursive: true });
|
|
17543
17712
|
}
|
|
17544
17713
|
const payload = {
|
|
17545
17714
|
entries: memoryStore,
|
|
17546
17715
|
nextId,
|
|
17547
17716
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
17548
17717
|
};
|
|
17549
|
-
|
|
17718
|
+
fs15.writeFileSync(filePath, JSON.stringify(payload, null, 2));
|
|
17550
17719
|
} catch {
|
|
17551
17720
|
}
|
|
17552
17721
|
}
|
|
@@ -18048,7 +18217,7 @@ async function cronDelete(args) {
|
|
|
18048
18217
|
|
|
18049
18218
|
// src/app/agent/tools/NotebookEditTool/NotebookEditTool.ts
|
|
18050
18219
|
init_sandbox_policy();
|
|
18051
|
-
import { promises as
|
|
18220
|
+
import { promises as fs16 } from "fs";
|
|
18052
18221
|
function sourceToString(s) {
|
|
18053
18222
|
if (s == null) return "";
|
|
18054
18223
|
return Array.isArray(s) ? s.join("") : s;
|
|
@@ -18060,7 +18229,7 @@ function stringToSource(s) {
|
|
|
18060
18229
|
async function applyNotebookOperation(filepath, op) {
|
|
18061
18230
|
try {
|
|
18062
18231
|
const resolved = resolveWorkspacePath(filepath);
|
|
18063
|
-
const raw = await
|
|
18232
|
+
const raw = await fs16.readFile(resolved, "utf-8");
|
|
18064
18233
|
let doc;
|
|
18065
18234
|
try {
|
|
18066
18235
|
doc = JSON.parse(raw);
|
|
@@ -18101,7 +18270,7 @@ async function applyNotebookOperation(filepath, op) {
|
|
|
18101
18270
|
return JSON.stringify({ success: false, error: `cell_index out of range: ${i}` });
|
|
18102
18271
|
}
|
|
18103
18272
|
doc.cells[i].source = stringToSource(String(op.source ?? ""));
|
|
18104
|
-
await
|
|
18273
|
+
await fs16.writeFile(resolved, JSON.stringify(doc, null, 2), "utf-8");
|
|
18105
18274
|
return JSON.stringify({ success: true, message: `Updated cell ${i}` });
|
|
18106
18275
|
}
|
|
18107
18276
|
if (op.operation === "append_markdown_cell") {
|
|
@@ -18110,7 +18279,7 @@ async function applyNotebookOperation(filepath, op) {
|
|
|
18110
18279
|
source: stringToSource(String(op.source ?? "")),
|
|
18111
18280
|
metadata: {}
|
|
18112
18281
|
});
|
|
18113
|
-
await
|
|
18282
|
+
await fs16.writeFile(resolved, JSON.stringify(doc, null, 2), "utf-8");
|
|
18114
18283
|
return JSON.stringify({ success: true, message: `Appended markdown cell at index ${doc.cells.length - 1}` });
|
|
18115
18284
|
}
|
|
18116
18285
|
if (op.operation === "delete_cell") {
|
|
@@ -18119,7 +18288,7 @@ async function applyNotebookOperation(filepath, op) {
|
|
|
18119
18288
|
return JSON.stringify({ success: false, error: `cell_index out of range: ${i}` });
|
|
18120
18289
|
}
|
|
18121
18290
|
doc.cells.splice(i, 1);
|
|
18122
|
-
await
|
|
18291
|
+
await fs16.writeFile(resolved, JSON.stringify(doc, null, 2), "utf-8");
|
|
18123
18292
|
return JSON.stringify({ success: true, message: `Deleted cell ${i}` });
|
|
18124
18293
|
}
|
|
18125
18294
|
return JSON.stringify({ success: false, error: "unknown operation" });
|
|
@@ -18158,8 +18327,8 @@ async function notebook_edit(args) {
|
|
|
18158
18327
|
// src/app/agent/tools/LspQueryTool/LspQueryTool.ts
|
|
18159
18328
|
init_sandbox_policy();
|
|
18160
18329
|
import { spawn as spawn3 } from "child_process";
|
|
18161
|
-
import * as
|
|
18162
|
-
import * as
|
|
18330
|
+
import * as fs17 from "fs";
|
|
18331
|
+
import * as path17 from "path";
|
|
18163
18332
|
import { pathToFileURL } from "url";
|
|
18164
18333
|
var RpcBuffer = class {
|
|
18165
18334
|
buf = Buffer.alloc(0);
|
|
@@ -18209,12 +18378,12 @@ async function lsp_query(args) {
|
|
|
18209
18378
|
} catch (e) {
|
|
18210
18379
|
return JSON.stringify({ success: false, error: e.message || String(e) });
|
|
18211
18380
|
}
|
|
18212
|
-
if (!
|
|
18381
|
+
if (!fs17.existsSync(resolved) || !fs17.statSync(resolved).isFile()) {
|
|
18213
18382
|
return JSON.stringify({ success: false, error: "file not found" });
|
|
18214
18383
|
}
|
|
18215
|
-
const content =
|
|
18384
|
+
const content = fs17.readFileSync(resolved, "utf-8");
|
|
18216
18385
|
const uri = pathToFileURL(resolved).href;
|
|
18217
|
-
const root =
|
|
18386
|
+
const root = path17.dirname(resolved);
|
|
18218
18387
|
const line0 = Math.max(0, Math.floor(Number(args.line) || 1) - 1);
|
|
18219
18388
|
const character = Math.max(0, Math.floor(Number(args.character ?? 0)));
|
|
18220
18389
|
const operation = args.operation === "references" ? "references" : "definition";
|
|
@@ -18334,8 +18503,8 @@ async function lsp_query(args) {
|
|
|
18334
18503
|
|
|
18335
18504
|
// src/app/agent/tools/FileWriteTool/FileWriteTool.ts
|
|
18336
18505
|
init_sandbox_policy();
|
|
18337
|
-
import { promises as
|
|
18338
|
-
import
|
|
18506
|
+
import { promises as fs18 } from "fs";
|
|
18507
|
+
import path18 from "path";
|
|
18339
18508
|
async function fileWrite(args) {
|
|
18340
18509
|
const {
|
|
18341
18510
|
filepath,
|
|
@@ -18353,10 +18522,10 @@ async function fileWrite(args) {
|
|
|
18353
18522
|
return { success: false, error: "content is required" };
|
|
18354
18523
|
}
|
|
18355
18524
|
const resolvedPath = resolveWorkspacePath(targetPath);
|
|
18356
|
-
const dir =
|
|
18525
|
+
const dir = path18.dirname(resolvedPath);
|
|
18357
18526
|
let existed = false;
|
|
18358
18527
|
try {
|
|
18359
|
-
const st = await
|
|
18528
|
+
const st = await fs18.stat(resolvedPath);
|
|
18360
18529
|
existed = st.isFile();
|
|
18361
18530
|
} catch {
|
|
18362
18531
|
existed = false;
|
|
@@ -18370,15 +18539,15 @@ async function fileWrite(args) {
|
|
|
18370
18539
|
let previousContent = "";
|
|
18371
18540
|
if (existed) {
|
|
18372
18541
|
try {
|
|
18373
|
-
previousContent = await
|
|
18542
|
+
previousContent = await fs18.readFile(resolvedPath, "utf-8");
|
|
18374
18543
|
} catch {
|
|
18375
18544
|
previousContent = "";
|
|
18376
18545
|
}
|
|
18377
18546
|
}
|
|
18378
18547
|
if (create_directories) {
|
|
18379
|
-
await
|
|
18548
|
+
await fs18.mkdir(dir, { recursive: true });
|
|
18380
18549
|
}
|
|
18381
|
-
await
|
|
18550
|
+
await fs18.writeFile(resolvedPath, String(content), "utf-8");
|
|
18382
18551
|
const bytes = Buffer.byteLength(String(content), "utf-8");
|
|
18383
18552
|
return {
|
|
18384
18553
|
success: true,
|
|
@@ -18687,9 +18856,9 @@ async function signalMailbox(args) {
|
|
|
18687
18856
|
}
|
|
18688
18857
|
|
|
18689
18858
|
// src/app/agent/tools/ReplTool/ReplTool.ts
|
|
18690
|
-
import
|
|
18859
|
+
import fs23 from "fs";
|
|
18691
18860
|
import os17 from "os";
|
|
18692
|
-
import
|
|
18861
|
+
import path23 from "path";
|
|
18693
18862
|
import { exec } from "child_process";
|
|
18694
18863
|
import { v4 as uuidv47 } from "uuid";
|
|
18695
18864
|
import { promisify as promisify2 } from "util";
|
|
@@ -18701,20 +18870,20 @@ async function repl(params) {
|
|
|
18701
18870
|
let tempFile;
|
|
18702
18871
|
switch (language) {
|
|
18703
18872
|
case "python": {
|
|
18704
|
-
tempFile =
|
|
18705
|
-
|
|
18873
|
+
tempFile = path23.join(os17.tmpdir(), `bluma_repl_${uuidv47()}.py`);
|
|
18874
|
+
fs23.writeFileSync(tempFile, code, "utf-8");
|
|
18706
18875
|
command = `python3 "${tempFile}"`;
|
|
18707
18876
|
break;
|
|
18708
18877
|
}
|
|
18709
18878
|
case "node": {
|
|
18710
|
-
tempFile =
|
|
18711
|
-
|
|
18879
|
+
tempFile = path23.join(os17.tmpdir(), `bluma_repl_${uuidv47()}.mjs`);
|
|
18880
|
+
fs23.writeFileSync(tempFile, code, "utf-8");
|
|
18712
18881
|
command = `node "${tempFile}"`;
|
|
18713
18882
|
break;
|
|
18714
18883
|
}
|
|
18715
18884
|
case "bash": {
|
|
18716
|
-
tempFile =
|
|
18717
|
-
|
|
18885
|
+
tempFile = path23.join(os17.tmpdir(), `bluma_repl_${uuidv47()}.sh`);
|
|
18886
|
+
fs23.writeFileSync(tempFile, `#!/bin/bash
|
|
18718
18887
|
set -e
|
|
18719
18888
|
${code}`, "utf-8");
|
|
18720
18889
|
command = `bash "${tempFile}"`;
|
|
@@ -18728,7 +18897,7 @@ ${code}`, "utf-8");
|
|
|
18728
18897
|
// 5MB
|
|
18729
18898
|
});
|
|
18730
18899
|
try {
|
|
18731
|
-
|
|
18900
|
+
fs23.unlinkSync(tempFile);
|
|
18732
18901
|
} catch {
|
|
18733
18902
|
}
|
|
18734
18903
|
return {
|
|
@@ -18740,7 +18909,7 @@ ${code}`, "utf-8");
|
|
|
18740
18909
|
};
|
|
18741
18910
|
} catch (error) {
|
|
18742
18911
|
try {
|
|
18743
|
-
|
|
18912
|
+
fs23.unlinkSync(tempFile);
|
|
18744
18913
|
} catch {
|
|
18745
18914
|
}
|
|
18746
18915
|
const exitCode = error.code === "ERR_CHILD_PROCESS_TIMEOUT" ? 124 : error.status ?? 1;
|
|
@@ -19088,8 +19257,8 @@ ${preview}${toRemove.length > 5 ? `
|
|
|
19088
19257
|
|
|
19089
19258
|
// src/app/agent/tools/BriefTool/BriefTool.ts
|
|
19090
19259
|
init_sandbox_policy();
|
|
19091
|
-
import * as
|
|
19092
|
-
import * as
|
|
19260
|
+
import * as fs24 from "fs";
|
|
19261
|
+
import * as path24 from "path";
|
|
19093
19262
|
async function brief(args) {
|
|
19094
19263
|
const sentAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
19095
19264
|
if (!args.message || !args.message.trim()) {
|
|
@@ -19108,9 +19277,9 @@ async function brief(args) {
|
|
|
19108
19277
|
const resolved = [];
|
|
19109
19278
|
for (const filePath of args.attachments) {
|
|
19110
19279
|
try {
|
|
19111
|
-
const absolutePath =
|
|
19112
|
-
if (
|
|
19113
|
-
const stat =
|
|
19280
|
+
const absolutePath = path24.isAbsolute(filePath) ? filePath : path24.join(resolveWorkspacePath("."), filePath);
|
|
19281
|
+
if (fs24.existsSync(absolutePath)) {
|
|
19282
|
+
const stat = fs24.statSync(absolutePath);
|
|
19114
19283
|
resolved.push({
|
|
19115
19284
|
path: absolutePath,
|
|
19116
19285
|
size: stat.size,
|
|
@@ -19149,14 +19318,14 @@ async function brief(args) {
|
|
|
19149
19318
|
}
|
|
19150
19319
|
|
|
19151
19320
|
// src/app/agent/tools/DreamEngineTool/DreamEngineTool.ts
|
|
19152
|
-
import * as
|
|
19153
|
-
import * as
|
|
19321
|
+
import * as fs25 from "fs";
|
|
19322
|
+
import * as path25 from "path";
|
|
19154
19323
|
import os18 from "os";
|
|
19155
19324
|
function memoryPath() {
|
|
19156
|
-
return
|
|
19325
|
+
return path25.join(process.env.HOME || os18.homedir(), ".bluma", "coding_memory.json");
|
|
19157
19326
|
}
|
|
19158
19327
|
function sessionsDir() {
|
|
19159
|
-
return
|
|
19328
|
+
return path25.join(process.env.HOME || os18.homedir(), ".bluma", "sessions");
|
|
19160
19329
|
}
|
|
19161
19330
|
function normalizeNote(note) {
|
|
19162
19331
|
return note.trim().toLowerCase().replace(/\s+/g, " ");
|
|
@@ -19181,9 +19350,9 @@ async function dream(args = {}) {
|
|
|
19181
19350
|
const mergeSimilar = args.mergeSimilar !== false;
|
|
19182
19351
|
const memPath = memoryPath();
|
|
19183
19352
|
let memData = null;
|
|
19184
|
-
if (
|
|
19353
|
+
if (fs25.existsSync(memPath)) {
|
|
19185
19354
|
try {
|
|
19186
|
-
memData = JSON.parse(
|
|
19355
|
+
memData = JSON.parse(fs25.readFileSync(memPath, "utf-8"));
|
|
19187
19356
|
} catch {
|
|
19188
19357
|
}
|
|
19189
19358
|
}
|
|
@@ -19260,12 +19429,12 @@ async function dream(args = {}) {
|
|
|
19260
19429
|
pruned += removed.length;
|
|
19261
19430
|
}
|
|
19262
19431
|
const sessDir = sessionsDir();
|
|
19263
|
-
if (
|
|
19432
|
+
if (fs25.existsSync(sessDir)) {
|
|
19264
19433
|
try {
|
|
19265
|
-
const sessionFiles =
|
|
19434
|
+
const sessionFiles = fs25.readdirSync(sessDir).filter((f) => f.endsWith(".json")).slice(-5);
|
|
19266
19435
|
for (const sf of sessionFiles) {
|
|
19267
19436
|
try {
|
|
19268
|
-
const sessionData = JSON.parse(
|
|
19437
|
+
const sessionData = JSON.parse(fs25.readFileSync(path25.join(sessDir, sf), "utf-8"));
|
|
19269
19438
|
if (sessionData?.summary) {
|
|
19270
19439
|
consolidatedMemories.push(`Session ${sf}: ${sessionData.summary}`);
|
|
19271
19440
|
}
|
|
@@ -19280,7 +19449,7 @@ async function dream(args = {}) {
|
|
|
19280
19449
|
memData.nextId = entries.reduce((max, e) => Math.max(max, e.id || 0), 0) + 1;
|
|
19281
19450
|
memData.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
19282
19451
|
try {
|
|
19283
|
-
|
|
19452
|
+
fs25.writeFileSync(memPath, JSON.stringify(memData, null, 2), "utf-8");
|
|
19284
19453
|
} catch (e) {
|
|
19285
19454
|
return {
|
|
19286
19455
|
success: false,
|
|
@@ -19473,8 +19642,8 @@ async function context_collapse(args = {}) {
|
|
|
19473
19642
|
|
|
19474
19643
|
// src/app/agent/tools/CreateNextAppTool/CreateNextAppTool.ts
|
|
19475
19644
|
init_sandbox_policy();
|
|
19476
|
-
import { promises as
|
|
19477
|
-
import
|
|
19645
|
+
import { promises as fs26 } from "fs";
|
|
19646
|
+
import path26 from "path";
|
|
19478
19647
|
|
|
19479
19648
|
// src/app/agent/tools/ShellCommandTool/ShellCommandTool.ts
|
|
19480
19649
|
init_sandbox_policy();
|
|
@@ -20248,10 +20417,10 @@ export function cn(...inputs: ClassValue[]) {
|
|
|
20248
20417
|
`
|
|
20249
20418
|
};
|
|
20250
20419
|
async function createFile(filePath, content, projectName) {
|
|
20251
|
-
const dir =
|
|
20252
|
-
await
|
|
20420
|
+
const dir = path26.dirname(filePath);
|
|
20421
|
+
await fs26.mkdir(dir, { recursive: true });
|
|
20253
20422
|
const replacedContent = content.replace(/{{NAME}}/g, projectName);
|
|
20254
|
-
await
|
|
20423
|
+
await fs26.writeFile(filePath, replacedContent, "utf-8");
|
|
20255
20424
|
}
|
|
20256
20425
|
async function createNextApp(args) {
|
|
20257
20426
|
const {
|
|
@@ -20270,26 +20439,26 @@ async function createNextApp(args) {
|
|
|
20270
20439
|
};
|
|
20271
20440
|
}
|
|
20272
20441
|
const baseDir = directory ? resolveWorkspacePath(directory) : resolveWorkspacePath(".");
|
|
20273
|
-
const projectPath =
|
|
20442
|
+
const projectPath = path26.join(baseDir, name);
|
|
20274
20443
|
try {
|
|
20275
|
-
await
|
|
20444
|
+
await fs26.access(projectPath);
|
|
20276
20445
|
return {
|
|
20277
20446
|
success: false,
|
|
20278
20447
|
error: `Directory already exists: ${projectPath}. Remove it first or choose a different name.`
|
|
20279
20448
|
};
|
|
20280
20449
|
} catch {
|
|
20281
20450
|
}
|
|
20282
|
-
await
|
|
20451
|
+
await fs26.mkdir(projectPath, { recursive: true });
|
|
20283
20452
|
const filesToCreate = template === "minimal" ? MINIMAL_FILES : FULL_FILES;
|
|
20284
20453
|
const filesCreated = [];
|
|
20285
20454
|
for (const [relativePath, content] of Object.entries(filesToCreate)) {
|
|
20286
20455
|
if (relativePath === "package.json.full") continue;
|
|
20287
|
-
const fullPath =
|
|
20456
|
+
const fullPath = path26.join(projectPath, relativePath);
|
|
20288
20457
|
await createFile(fullPath, content, name);
|
|
20289
20458
|
filesCreated.push(relativePath);
|
|
20290
20459
|
}
|
|
20291
20460
|
if (template === "full") {
|
|
20292
|
-
const packageJsonPath =
|
|
20461
|
+
const packageJsonPath = path26.join(projectPath, "package.json");
|
|
20293
20462
|
const fullPackageJson = FULL_FILES["package.json.full"];
|
|
20294
20463
|
if (fullPackageJson) {
|
|
20295
20464
|
await createFile(packageJsonPath, fullPackageJson, name);
|
|
@@ -20331,8 +20500,8 @@ async function createNextApp(args) {
|
|
|
20331
20500
|
|
|
20332
20501
|
// src/app/agent/tools/DeployAppTool/DeployAppTool.ts
|
|
20333
20502
|
init_sandbox_policy();
|
|
20334
|
-
import { promises as
|
|
20335
|
-
import
|
|
20503
|
+
import { promises as fs27 } from "fs";
|
|
20504
|
+
import path27 from "path";
|
|
20336
20505
|
var EXCLUDE_PATTERNS = [
|
|
20337
20506
|
"node_modules",
|
|
20338
20507
|
".next",
|
|
@@ -20482,8 +20651,8 @@ function buildFactorAiManifest(appContext, deployResult, appName) {
|
|
|
20482
20651
|
}
|
|
20483
20652
|
async function writeFactorAiManifest(projectDir, appContext, deployResult, appName) {
|
|
20484
20653
|
const manifest = buildFactorAiManifest(appContext, deployResult, appName);
|
|
20485
|
-
const manifestPath =
|
|
20486
|
-
await
|
|
20654
|
+
const manifestPath = path27.join(projectDir, "factorai.sh.json");
|
|
20655
|
+
await fs27.writeFile(manifestPath, `${JSON.stringify(manifest, null, 2)}
|
|
20487
20656
|
`, "utf-8");
|
|
20488
20657
|
return manifest;
|
|
20489
20658
|
}
|
|
@@ -20503,23 +20672,23 @@ async function deployApp(args) {
|
|
|
20503
20672
|
}
|
|
20504
20673
|
const resolvedProjectDir = resolveWorkspacePath(projectDir);
|
|
20505
20674
|
try {
|
|
20506
|
-
await
|
|
20675
|
+
await fs27.access(resolvedProjectDir);
|
|
20507
20676
|
} catch {
|
|
20508
20677
|
return {
|
|
20509
20678
|
success: false,
|
|
20510
20679
|
error: `Project directory not found: ${resolvedProjectDir}`
|
|
20511
20680
|
};
|
|
20512
20681
|
}
|
|
20513
|
-
const packageJsonPath =
|
|
20682
|
+
const packageJsonPath = path27.join(resolvedProjectDir, "package.json");
|
|
20514
20683
|
try {
|
|
20515
|
-
await
|
|
20684
|
+
await fs27.access(packageJsonPath);
|
|
20516
20685
|
} catch {
|
|
20517
20686
|
return {
|
|
20518
20687
|
success: false,
|
|
20519
20688
|
error: "Not a Next.js project: package.json not found"
|
|
20520
20689
|
};
|
|
20521
20690
|
}
|
|
20522
|
-
const packageJsonContent = await
|
|
20691
|
+
const packageJsonContent = await fs27.readFile(packageJsonPath, "utf-8");
|
|
20523
20692
|
const packageJson = JSON.parse(packageJsonContent);
|
|
20524
20693
|
const hasNext = packageJson.dependencies?.next || packageJson.devDependencies?.next;
|
|
20525
20694
|
if (!hasNext) {
|
|
@@ -20528,18 +20697,18 @@ async function deployApp(args) {
|
|
|
20528
20697
|
error: "Not a Next.js project: next not found in dependencies"
|
|
20529
20698
|
};
|
|
20530
20699
|
}
|
|
20531
|
-
const appName = name || packageJson.name ||
|
|
20532
|
-
const tempDir =
|
|
20533
|
-
await
|
|
20534
|
-
const zipPath =
|
|
20700
|
+
const appName = name || packageJson.name || path27.basename(resolvedProjectDir);
|
|
20701
|
+
const tempDir = path27.join(resolvedProjectDir, ".tmp");
|
|
20702
|
+
await fs27.mkdir(tempDir, { recursive: true });
|
|
20703
|
+
const zipPath = path27.join(tempDir, `${appName}-${Date.now()}.zip`);
|
|
20535
20704
|
console.log(`[deploy-app] Creating ZIP: ${zipPath}`);
|
|
20536
20705
|
await createProjectZip(resolvedProjectDir, zipPath);
|
|
20537
|
-
const zipStats = await
|
|
20706
|
+
const zipStats = await fs27.stat(zipPath);
|
|
20538
20707
|
const zipSizeMB = zipStats.size / 1024 / 1024;
|
|
20539
20708
|
if (zipSizeMB > 50) {
|
|
20540
|
-
await
|
|
20709
|
+
await fs27.unlink(zipPath).catch(() => {
|
|
20541
20710
|
});
|
|
20542
|
-
await
|
|
20711
|
+
await fs27.rmdir(tempDir).catch(() => {
|
|
20543
20712
|
});
|
|
20544
20713
|
return {
|
|
20545
20714
|
success: false,
|
|
@@ -20550,8 +20719,8 @@ async function deployApp(args) {
|
|
|
20550
20719
|
console.log(`[deploy-app] Uploading to ${severinoUrl}...`);
|
|
20551
20720
|
const deployResult = await uploadToSeverino(zipPath, severinoUrl, appName, apiKey, appId);
|
|
20552
20721
|
try {
|
|
20553
|
-
await
|
|
20554
|
-
await
|
|
20722
|
+
await fs27.unlink(zipPath);
|
|
20723
|
+
await fs27.rmdir(tempDir);
|
|
20555
20724
|
} catch (e) {
|
|
20556
20725
|
console.warn("[deploy-app] Cleanup warning:", e);
|
|
20557
20726
|
}
|
|
@@ -20564,7 +20733,7 @@ async function deployApp(args) {
|
|
|
20564
20733
|
appName
|
|
20565
20734
|
);
|
|
20566
20735
|
deployResult.factoraiManifest = manifest;
|
|
20567
|
-
deployResult.factoraiManifestPath =
|
|
20736
|
+
deployResult.factoraiManifestPath = path27.join(resolvedProjectDir, "factorai.sh.json");
|
|
20568
20737
|
}
|
|
20569
20738
|
console.log(`[deploy-app] Deploy iniciado: ${deployResult.appId}`);
|
|
20570
20739
|
}
|
|
@@ -20579,8 +20748,8 @@ async function deployApp(args) {
|
|
|
20579
20748
|
}
|
|
20580
20749
|
|
|
20581
20750
|
// src/app/agent/runtime/factorai_context.ts
|
|
20582
|
-
import
|
|
20583
|
-
import
|
|
20751
|
+
import fs28 from "fs";
|
|
20752
|
+
import path28 from "path";
|
|
20584
20753
|
function normalizeContext(raw) {
|
|
20585
20754
|
if (!raw || typeof raw.appId !== "string" || !raw.appId.trim()) {
|
|
20586
20755
|
return null;
|
|
@@ -20601,10 +20770,10 @@ function normalizeContext(raw) {
|
|
|
20601
20770
|
}
|
|
20602
20771
|
function readJsonFile(filePath) {
|
|
20603
20772
|
try {
|
|
20604
|
-
if (!
|
|
20773
|
+
if (!fs28.existsSync(filePath)) {
|
|
20605
20774
|
return null;
|
|
20606
20775
|
}
|
|
20607
|
-
const parsed = JSON.parse(
|
|
20776
|
+
const parsed = JSON.parse(fs28.readFileSync(filePath, "utf8"));
|
|
20608
20777
|
if (parsed && typeof parsed === "object") {
|
|
20609
20778
|
return parsed.appContext && typeof parsed.appContext === "object" ? parsed.appContext : parsed;
|
|
20610
20779
|
}
|
|
@@ -20614,19 +20783,19 @@ function readJsonFile(filePath) {
|
|
|
20614
20783
|
return null;
|
|
20615
20784
|
}
|
|
20616
20785
|
function readFactorAiWorkspaceManifest(projectDir = process.cwd()) {
|
|
20617
|
-
const manifestPath =
|
|
20786
|
+
const manifestPath = path28.join(projectDir, "factorai.sh.json");
|
|
20618
20787
|
try {
|
|
20619
|
-
if (!
|
|
20788
|
+
if (!fs28.existsSync(manifestPath)) {
|
|
20620
20789
|
return null;
|
|
20621
20790
|
}
|
|
20622
|
-
const parsed = JSON.parse(
|
|
20791
|
+
const parsed = JSON.parse(fs28.readFileSync(manifestPath, "utf8"));
|
|
20623
20792
|
return parsed && typeof parsed === "object" ? parsed : null;
|
|
20624
20793
|
} catch {
|
|
20625
20794
|
return null;
|
|
20626
20795
|
}
|
|
20627
20796
|
}
|
|
20628
20797
|
function readContextFromWorkspace() {
|
|
20629
|
-
const candidate =
|
|
20798
|
+
const candidate = path28.join(process.cwd(), "factorai.sh.json");
|
|
20630
20799
|
const parsed = readJsonFile(candidate);
|
|
20631
20800
|
if (!parsed) {
|
|
20632
20801
|
return null;
|
|
@@ -20713,8 +20882,8 @@ function buildFactorAiWorkspaceManifest(input) {
|
|
|
20713
20882
|
async function writeFactorAiWorkspaceManifest(input) {
|
|
20714
20883
|
const projectDir = input.projectDir || process.cwd();
|
|
20715
20884
|
const manifest = buildFactorAiWorkspaceManifest({ ...input, projectDir });
|
|
20716
|
-
const manifestPath =
|
|
20717
|
-
|
|
20885
|
+
const manifestPath = path28.join(projectDir, "factorai.sh.json");
|
|
20886
|
+
fs28.writeFileSync(manifestPath, `${JSON.stringify(manifest, null, 2)}
|
|
20718
20887
|
`, "utf8");
|
|
20719
20888
|
return { manifestPath, manifest };
|
|
20720
20889
|
}
|
|
@@ -20970,7 +21139,7 @@ var NATIVE_TOOL_ENTRIES = [
|
|
|
20970
21139
|
autoApproveInLocal: true,
|
|
20971
21140
|
autoApproveInSandbox: true,
|
|
20972
21141
|
sandboxOnly: true,
|
|
20973
|
-
description: 'Primary channel \u2014 use generously. message_type "info":
|
|
21142
|
+
description: 'Primary channel \u2014 use generously. message_type "info": progress only (does not stop the turn). message_type "result": ends the turn; in sandbox, file deliverables MUST use attachments[] with paths under .bluma/artifacts/ (content alone does not deliver files).'
|
|
20974
21143
|
},
|
|
20975
21144
|
implementation: message
|
|
20976
21145
|
},
|
|
@@ -21596,9 +21765,18 @@ function getNativeToolMetadata(toolName) {
|
|
|
21596
21765
|
function getNativeToolImplementation(toolName) {
|
|
21597
21766
|
return TOOL_IMPLEMENTATION_MAP.get(toolName);
|
|
21598
21767
|
}
|
|
21768
|
+
function isFactorAiToolName(toolName) {
|
|
21769
|
+
return toolName.startsWith("factorai.sh.");
|
|
21770
|
+
}
|
|
21599
21771
|
function shouldExposeToolEntry(entry, policy = getSandboxPolicy()) {
|
|
21600
|
-
if (entry.metadata.sandboxOnly
|
|
21601
|
-
|
|
21772
|
+
if (entry.metadata.sandboxOnly) {
|
|
21773
|
+
if (isFactorAiToolName(entry.metadata.name)) {
|
|
21774
|
+
if (!isFactorAiSandboxEnabled()) {
|
|
21775
|
+
return false;
|
|
21776
|
+
}
|
|
21777
|
+
} else if (!policy.isSandbox) {
|
|
21778
|
+
return false;
|
|
21779
|
+
}
|
|
21602
21780
|
}
|
|
21603
21781
|
if (entry.metadata.hiddenInSandbox && policy.isSandbox) {
|
|
21604
21782
|
return false;
|
|
@@ -21612,8 +21790,41 @@ function getAllNativeToolMetadata() {
|
|
|
21612
21790
|
const policy = getSandboxPolicy();
|
|
21613
21791
|
return NATIVE_TOOL_ENTRIES.filter((entry) => shouldExposeToolEntry(entry, policy)).map((entry) => entry.metadata);
|
|
21614
21792
|
}
|
|
21793
|
+
var SANDBOX_COMMUNICATION_TOOL_DEFINITIONS = [
|
|
21794
|
+
{
|
|
21795
|
+
type: "function",
|
|
21796
|
+
function: {
|
|
21797
|
+
name: "message",
|
|
21798
|
+
description: 'Deliver user-visible output. message_type "info": progress (does not end turn). message_type "result": ends turn; file deliverables MUST use attachments[] with paths under .bluma/artifacts/.',
|
|
21799
|
+
parameters: {
|
|
21800
|
+
type: "object",
|
|
21801
|
+
properties: {
|
|
21802
|
+
content: { type: "string", description: "Markdown body shown to the user." },
|
|
21803
|
+
message_type: {
|
|
21804
|
+
type: "string",
|
|
21805
|
+
enum: ["info", "result"],
|
|
21806
|
+
description: "info = progress; result = final delivery (ends turn in sandbox)."
|
|
21807
|
+
},
|
|
21808
|
+
attachments: {
|
|
21809
|
+
type: "array",
|
|
21810
|
+
items: { type: "string" },
|
|
21811
|
+
description: "Workspace file paths under .bluma/artifacts/ (required for file deliverables on result)."
|
|
21812
|
+
}
|
|
21813
|
+
},
|
|
21814
|
+
required: ["content", "message_type"],
|
|
21815
|
+
additionalProperties: false
|
|
21816
|
+
}
|
|
21817
|
+
}
|
|
21818
|
+
}
|
|
21819
|
+
];
|
|
21820
|
+
function getSandboxCommunicationToolDefinitions() {
|
|
21821
|
+
if (!getSandboxPolicy().isSandbox) {
|
|
21822
|
+
return [];
|
|
21823
|
+
}
|
|
21824
|
+
return SANDBOX_COMMUNICATION_TOOL_DEFINITIONS;
|
|
21825
|
+
}
|
|
21615
21826
|
function getSandboxOnlyNativeToolDefinitions() {
|
|
21616
|
-
return getFactorAiSandboxToolDefinitions();
|
|
21827
|
+
return [...getSandboxCommunicationToolDefinitions(), ...getFactorAiSandboxToolDefinitions()];
|
|
21617
21828
|
}
|
|
21618
21829
|
function applyMetadataToToolDefinitions(toolDefinitions) {
|
|
21619
21830
|
return toolDefinitions.map((definition) => {
|
|
@@ -21709,6 +21920,24 @@ function toolResultToString(value) {
|
|
|
21709
21920
|
const result = normalizeToolResult(value);
|
|
21710
21921
|
return JSON.stringify(result, null, 2);
|
|
21711
21922
|
}
|
|
21923
|
+
function extractMessageToolPayload(parsed) {
|
|
21924
|
+
if (!parsed || typeof parsed !== "object") {
|
|
21925
|
+
return null;
|
|
21926
|
+
}
|
|
21927
|
+
const root = parsed;
|
|
21928
|
+
if (root.status === "error") {
|
|
21929
|
+
return { status: "error", message_type: void 0 };
|
|
21930
|
+
}
|
|
21931
|
+
const data = root.data && typeof root.data === "object" && !Array.isArray(root.data) ? root.data : root;
|
|
21932
|
+
if (typeof data.message_type === "string") {
|
|
21933
|
+
return { message_type: data.message_type, status: typeof root.status === "string" ? root.status : void 0 };
|
|
21934
|
+
}
|
|
21935
|
+
return null;
|
|
21936
|
+
}
|
|
21937
|
+
function isMessageToolResultTerminal(parsed) {
|
|
21938
|
+
const payload = extractMessageToolPayload(parsed);
|
|
21939
|
+
return payload?.message_type === "result" && payload.status !== "error";
|
|
21940
|
+
}
|
|
21712
21941
|
|
|
21713
21942
|
// src/app/agent/tool_invoker.ts
|
|
21714
21943
|
var ToolInvoker = class {
|
|
@@ -21723,9 +21952,9 @@ var ToolInvoker = class {
|
|
|
21723
21952
|
async initialize() {
|
|
21724
21953
|
try {
|
|
21725
21954
|
const currentFilePath = fileURLToPath3(import.meta.url);
|
|
21726
|
-
const currentDirPath =
|
|
21727
|
-
const configPath =
|
|
21728
|
-
const fileContent = await
|
|
21955
|
+
const currentDirPath = path29.dirname(currentFilePath);
|
|
21956
|
+
const configPath = path29.resolve(currentDirPath, "config", "native_tools.json");
|
|
21957
|
+
const fileContent = await fs29.readFile(configPath, "utf-8");
|
|
21729
21958
|
const config2 = JSON.parse(fileContent);
|
|
21730
21959
|
this.toolDefinitions = applyMetadataToToolDefinitions(config2.nativeTools);
|
|
21731
21960
|
const sandboxOnlyTools = applyMetadataToToolDefinitions(getSandboxOnlyNativeToolDefinitions());
|
|
@@ -21772,8 +22001,8 @@ var ToolInvoker = class {
|
|
|
21772
22001
|
};
|
|
21773
22002
|
|
|
21774
22003
|
// src/app/agent/tools/mcp/mcp_client.ts
|
|
21775
|
-
import { promises as
|
|
21776
|
-
import
|
|
22004
|
+
import { promises as fs30 } from "fs";
|
|
22005
|
+
import path30 from "path";
|
|
21777
22006
|
import os20 from "os";
|
|
21778
22007
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
21779
22008
|
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
@@ -21801,9 +22030,9 @@ var MCPClient = class {
|
|
|
21801
22030
|
});
|
|
21802
22031
|
}
|
|
21803
22032
|
const __filename = fileURLToPath4(import.meta.url);
|
|
21804
|
-
const __dirname2 =
|
|
21805
|
-
const defaultConfigPath =
|
|
21806
|
-
const userConfigPath =
|
|
22033
|
+
const __dirname2 = path30.dirname(__filename);
|
|
22034
|
+
const defaultConfigPath = path30.resolve(__dirname2, "config", "bluma-mcp.json");
|
|
22035
|
+
const userConfigPath = path30.join(os20.homedir(), ".bluma", "bluma-mcp.json");
|
|
21807
22036
|
const defaultConfig = await this.loadMcpConfig(defaultConfigPath, "Default");
|
|
21808
22037
|
const userConfig = await this.loadMcpConfig(userConfigPath, "User");
|
|
21809
22038
|
const mergedConfig = {
|
|
@@ -21837,7 +22066,7 @@ var MCPClient = class {
|
|
|
21837
22066
|
}
|
|
21838
22067
|
async loadMcpConfig(configPath, configType) {
|
|
21839
22068
|
try {
|
|
21840
|
-
const fileContent = await
|
|
22069
|
+
const fileContent = await fs30.readFile(configPath, "utf-8");
|
|
21841
22070
|
const processedContent = this.replaceEnvPlaceholders(fileContent);
|
|
21842
22071
|
return JSON.parse(processedContent);
|
|
21843
22072
|
} catch (error) {
|
|
@@ -21894,11 +22123,14 @@ var MCPClient = class {
|
|
|
21894
22123
|
}
|
|
21895
22124
|
}
|
|
21896
22125
|
async invoke(toolName, args) {
|
|
21897
|
-
|
|
22126
|
+
let route = this.toolToServerMap.get(toolName);
|
|
22127
|
+
if (!route && getNativeToolImplementation(toolName)) {
|
|
22128
|
+
route = { server: "native", originalName: toolName };
|
|
22129
|
+
}
|
|
21898
22130
|
if (!route) {
|
|
21899
22131
|
return {
|
|
21900
22132
|
status: "error",
|
|
21901
|
-
error: `This tool '${toolName}'is not found or registered
|
|
22133
|
+
error: `This tool '${toolName}' is not found or registered. You must use the correct name from the available tools list.`
|
|
21902
22134
|
};
|
|
21903
22135
|
}
|
|
21904
22136
|
if (route.server === "native") {
|
|
@@ -22031,7 +22263,7 @@ You streamed or returned **user-visible markdown as assistant content** instead
|
|
|
22031
22263
|
|
|
22032
22264
|
Do this **immediately** in your next step (single tool call, no prose outside tools):
|
|
22033
22265
|
|
|
22034
|
-
- Call **\`message\`** with **\`message_type\`: \`"result"\`**,
|
|
22266
|
+
- Call **\`message\`** with **\`message_type\`: \`"result"\`**, summary in **\`content\`**, and every file path in **\`attachments\`** under **\`.bluma/artifacts/\`** (this is the only delivery channel for files).
|
|
22035
22267
|
|
|
22036
22268
|
Do **not** repeat the same summary as plain assistant text again.
|
|
22037
22269
|
PENALTY APPLIED: ${penalty.toFixed(1)} points deducted.
|
|
@@ -22046,14 +22278,14 @@ PENALTY APPLIED: ${penalty.toFixed(1)} points deducted.
|
|
|
22046
22278
|
};
|
|
22047
22279
|
|
|
22048
22280
|
// src/app/agent/bluma/core/bluma.ts
|
|
22049
|
-
import
|
|
22050
|
-
import
|
|
22281
|
+
import path41 from "path";
|
|
22282
|
+
import fs40 from "fs";
|
|
22051
22283
|
import { v4 as uuidv48 } from "uuid";
|
|
22052
22284
|
|
|
22053
22285
|
// src/app/agent/session_manager/session_manager.ts
|
|
22054
|
-
import
|
|
22286
|
+
import path31 from "path";
|
|
22055
22287
|
import os21 from "os";
|
|
22056
|
-
import { promises as
|
|
22288
|
+
import { promises as fs31 } from "fs";
|
|
22057
22289
|
var fileLocks = /* @__PURE__ */ new Map();
|
|
22058
22290
|
async function withFileLock(file, fn) {
|
|
22059
22291
|
const prev = fileLocks.get(file) || Promise.resolve();
|
|
@@ -22089,13 +22321,13 @@ function debouncedSave(sessionFile, history, memory) {
|
|
|
22089
22321
|
function expandHome(p) {
|
|
22090
22322
|
if (!p) return p;
|
|
22091
22323
|
if (p.startsWith("~")) {
|
|
22092
|
-
return
|
|
22324
|
+
return path31.join(os21.homedir(), p.slice(1));
|
|
22093
22325
|
}
|
|
22094
22326
|
return p;
|
|
22095
22327
|
}
|
|
22096
22328
|
function getPreferredAppDir() {
|
|
22097
|
-
const fixed =
|
|
22098
|
-
return
|
|
22329
|
+
const fixed = path31.join(os21.homedir(), ".bluma");
|
|
22330
|
+
return path31.resolve(expandHome(fixed));
|
|
22099
22331
|
}
|
|
22100
22332
|
async function safeRenameWithRetry(src, dest, maxRetries = 6) {
|
|
22101
22333
|
let attempt = 0;
|
|
@@ -22103,10 +22335,10 @@ async function safeRenameWithRetry(src, dest, maxRetries = 6) {
|
|
|
22103
22335
|
const isWin = process.platform === "win32";
|
|
22104
22336
|
while (attempt <= maxRetries) {
|
|
22105
22337
|
try {
|
|
22106
|
-
const dir =
|
|
22107
|
-
await
|
|
22338
|
+
const dir = path31.dirname(dest);
|
|
22339
|
+
await fs31.mkdir(dir, { recursive: true }).catch(() => {
|
|
22108
22340
|
});
|
|
22109
|
-
await
|
|
22341
|
+
await fs31.rename(src, dest);
|
|
22110
22342
|
return;
|
|
22111
22343
|
} catch (e) {
|
|
22112
22344
|
lastErr = e;
|
|
@@ -22119,13 +22351,13 @@ async function safeRenameWithRetry(src, dest, maxRetries = 6) {
|
|
|
22119
22351
|
}
|
|
22120
22352
|
}
|
|
22121
22353
|
try {
|
|
22122
|
-
await
|
|
22123
|
-
const data = await
|
|
22124
|
-
const dir =
|
|
22125
|
-
await
|
|
22354
|
+
await fs31.access(src);
|
|
22355
|
+
const data = await fs31.readFile(src);
|
|
22356
|
+
const dir = path31.dirname(dest);
|
|
22357
|
+
await fs31.mkdir(dir, { recursive: true }).catch(() => {
|
|
22126
22358
|
});
|
|
22127
|
-
await
|
|
22128
|
-
await
|
|
22359
|
+
await fs31.writeFile(dest, data);
|
|
22360
|
+
await fs31.unlink(src).catch(() => {
|
|
22129
22361
|
});
|
|
22130
22362
|
return;
|
|
22131
22363
|
} catch (fallbackErr) {
|
|
@@ -22138,16 +22370,16 @@ async function safeRenameWithRetry(src, dest, maxRetries = 6) {
|
|
|
22138
22370
|
}
|
|
22139
22371
|
async function ensureSessionDir() {
|
|
22140
22372
|
const appDir = getPreferredAppDir();
|
|
22141
|
-
const sessionDir =
|
|
22142
|
-
await
|
|
22373
|
+
const sessionDir = path31.join(appDir, "sessions");
|
|
22374
|
+
await fs31.mkdir(sessionDir, { recursive: true });
|
|
22143
22375
|
return sessionDir;
|
|
22144
22376
|
}
|
|
22145
22377
|
async function loadSession(sessionId) {
|
|
22146
22378
|
const sessionDir = await ensureSessionDir();
|
|
22147
|
-
const sessionFile =
|
|
22379
|
+
const sessionFile = path31.join(sessionDir, `${sessionId}.json`);
|
|
22148
22380
|
try {
|
|
22149
|
-
await
|
|
22150
|
-
const fileContent = await
|
|
22381
|
+
await fs31.access(sessionFile);
|
|
22382
|
+
const fileContent = await fs31.readFile(sessionFile, "utf-8");
|
|
22151
22383
|
const sessionData = JSON.parse(fileContent);
|
|
22152
22384
|
const memory = {
|
|
22153
22385
|
historyAnchor: sessionData.history_anchor ?? null,
|
|
@@ -22164,13 +22396,13 @@ async function loadOrcreateSession(sessionId) {
|
|
|
22164
22396
|
return existing;
|
|
22165
22397
|
}
|
|
22166
22398
|
const sessionDir = await ensureSessionDir();
|
|
22167
|
-
const sessionFile =
|
|
22399
|
+
const sessionFile = path31.join(sessionDir, `${sessionId}.json`);
|
|
22168
22400
|
const newSessionData = {
|
|
22169
22401
|
session_id: sessionId,
|
|
22170
22402
|
created_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
22171
22403
|
conversation_history: []
|
|
22172
22404
|
};
|
|
22173
|
-
await
|
|
22405
|
+
await fs31.writeFile(sessionFile, JSON.stringify(newSessionData, null, 2), "utf-8");
|
|
22174
22406
|
const emptyMemory = {
|
|
22175
22407
|
historyAnchor: null,
|
|
22176
22408
|
compressedTurnSliceCount: 0
|
|
@@ -22181,12 +22413,12 @@ async function doSaveSessionHistory(sessionFile, history, memory) {
|
|
|
22181
22413
|
await withFileLock(sessionFile, async () => {
|
|
22182
22414
|
let sessionData;
|
|
22183
22415
|
try {
|
|
22184
|
-
const dir =
|
|
22185
|
-
await
|
|
22416
|
+
const dir = path31.dirname(sessionFile);
|
|
22417
|
+
await fs31.mkdir(dir, { recursive: true });
|
|
22186
22418
|
} catch {
|
|
22187
22419
|
}
|
|
22188
22420
|
try {
|
|
22189
|
-
const fileContent = await
|
|
22421
|
+
const fileContent = await fs31.readFile(sessionFile, "utf-8");
|
|
22190
22422
|
sessionData = JSON.parse(fileContent);
|
|
22191
22423
|
} catch (error) {
|
|
22192
22424
|
const code = error && error.code;
|
|
@@ -22197,14 +22429,14 @@ async function doSaveSessionHistory(sessionFile, history, memory) {
|
|
|
22197
22429
|
console.warn(`An unknown error occurred while reading ${sessionFile}. Re-initializing.`, error);
|
|
22198
22430
|
}
|
|
22199
22431
|
}
|
|
22200
|
-
const sessionId =
|
|
22432
|
+
const sessionId = path31.basename(sessionFile, ".json");
|
|
22201
22433
|
sessionData = {
|
|
22202
22434
|
session_id: sessionId,
|
|
22203
22435
|
created_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
22204
22436
|
conversation_history: []
|
|
22205
22437
|
};
|
|
22206
22438
|
try {
|
|
22207
|
-
await
|
|
22439
|
+
await fs31.writeFile(sessionFile, JSON.stringify(sessionData, null, 2), "utf-8");
|
|
22208
22440
|
} catch {
|
|
22209
22441
|
}
|
|
22210
22442
|
}
|
|
@@ -22220,7 +22452,7 @@ async function doSaveSessionHistory(sessionFile, history, memory) {
|
|
|
22220
22452
|
}
|
|
22221
22453
|
const tempSessionFile = `${sessionFile}.${Date.now()}.tmp`;
|
|
22222
22454
|
try {
|
|
22223
|
-
await
|
|
22455
|
+
await fs31.writeFile(tempSessionFile, JSON.stringify(sessionData, null, 2), "utf-8");
|
|
22224
22456
|
await safeRenameWithRetry(tempSessionFile, sessionFile);
|
|
22225
22457
|
} catch (writeError) {
|
|
22226
22458
|
if (writeError instanceof Error) {
|
|
@@ -22229,7 +22461,7 @@ async function doSaveSessionHistory(sessionFile, history, memory) {
|
|
|
22229
22461
|
console.error(`An unknown fatal error occurred while saving session to ${sessionFile}:`, writeError);
|
|
22230
22462
|
}
|
|
22231
22463
|
try {
|
|
22232
|
-
await
|
|
22464
|
+
await fs31.unlink(tempSessionFile);
|
|
22233
22465
|
} catch {
|
|
22234
22466
|
}
|
|
22235
22467
|
}
|
|
@@ -22247,13 +22479,13 @@ async function saveSessionHistory(sessionFile, history, memory) {
|
|
|
22247
22479
|
|
|
22248
22480
|
// src/app/agent/core/prompt/prompt_builder.ts
|
|
22249
22481
|
import os26 from "os";
|
|
22250
|
-
import
|
|
22251
|
-
import
|
|
22482
|
+
import fs38 from "fs";
|
|
22483
|
+
import path38 from "path";
|
|
22252
22484
|
import { execSync as execSync4 } from "child_process";
|
|
22253
22485
|
|
|
22254
22486
|
// src/app/agent/skills/skill_loader.ts
|
|
22255
|
-
import
|
|
22256
|
-
import
|
|
22487
|
+
import fs32 from "fs";
|
|
22488
|
+
import path32 from "path";
|
|
22257
22489
|
import os22 from "os";
|
|
22258
22490
|
import { fileURLToPath as fileURLToPath5 } from "node:url";
|
|
22259
22491
|
var SkillLoader = class _SkillLoader {
|
|
@@ -22263,8 +22495,8 @@ var SkillLoader = class _SkillLoader {
|
|
|
22263
22495
|
cache = /* @__PURE__ */ new Map();
|
|
22264
22496
|
conflicts = [];
|
|
22265
22497
|
constructor(projectRoot, bundledDir) {
|
|
22266
|
-
this.projectSkillsDir =
|
|
22267
|
-
this.globalSkillsDir =
|
|
22498
|
+
this.projectSkillsDir = path32.join(projectRoot, ".bluma", "skills");
|
|
22499
|
+
this.globalSkillsDir = path32.join(os22.homedir(), ".bluma", "skills");
|
|
22268
22500
|
this.bundledSkillsDir = bundledDir || _SkillLoader.resolveBundledDir();
|
|
22269
22501
|
}
|
|
22270
22502
|
/**
|
|
@@ -22273,48 +22505,48 @@ var SkillLoader = class _SkillLoader {
|
|
|
22273
22505
|
*/
|
|
22274
22506
|
static resolveBundledDir() {
|
|
22275
22507
|
if (process.env.JEST_WORKER_ID !== void 0 || process.env.NODE_ENV === "test") {
|
|
22276
|
-
return
|
|
22508
|
+
return path32.join(process.cwd(), "dist", "config", "skills");
|
|
22277
22509
|
}
|
|
22278
22510
|
const candidates = [];
|
|
22279
22511
|
const push = (p) => {
|
|
22280
|
-
const abs =
|
|
22512
|
+
const abs = path32.resolve(p);
|
|
22281
22513
|
if (!candidates.includes(abs)) {
|
|
22282
22514
|
candidates.push(abs);
|
|
22283
22515
|
}
|
|
22284
22516
|
};
|
|
22285
22517
|
let argvBundled = null;
|
|
22286
22518
|
try {
|
|
22287
|
-
const bundleDir =
|
|
22288
|
-
push(
|
|
22519
|
+
const bundleDir = path32.dirname(fileURLToPath5(import.meta.url));
|
|
22520
|
+
push(path32.join(bundleDir, "config", "skills"));
|
|
22289
22521
|
} catch {
|
|
22290
22522
|
}
|
|
22291
22523
|
const argv1 = process.argv[1];
|
|
22292
22524
|
if (argv1 && !argv1.startsWith("-")) {
|
|
22293
22525
|
try {
|
|
22294
22526
|
let resolved = argv1;
|
|
22295
|
-
if (
|
|
22296
|
-
resolved =
|
|
22297
|
-
} else if (!
|
|
22298
|
-
resolved =
|
|
22527
|
+
if (path32.isAbsolute(argv1) && fs32.existsSync(argv1)) {
|
|
22528
|
+
resolved = fs32.realpathSync(argv1);
|
|
22529
|
+
} else if (!path32.isAbsolute(argv1)) {
|
|
22530
|
+
resolved = path32.resolve(process.cwd(), argv1);
|
|
22299
22531
|
}
|
|
22300
|
-
const scriptDir =
|
|
22301
|
-
argvBundled =
|
|
22532
|
+
const scriptDir = path32.dirname(resolved);
|
|
22533
|
+
argvBundled = path32.join(scriptDir, "config", "skills");
|
|
22302
22534
|
push(argvBundled);
|
|
22303
22535
|
} catch {
|
|
22304
22536
|
}
|
|
22305
22537
|
}
|
|
22306
22538
|
for (const abs of candidates) {
|
|
22307
|
-
if (
|
|
22539
|
+
if (fs32.existsSync(abs)) {
|
|
22308
22540
|
return abs;
|
|
22309
22541
|
}
|
|
22310
22542
|
}
|
|
22311
22543
|
try {
|
|
22312
|
-
return
|
|
22544
|
+
return path32.join(path32.dirname(fileURLToPath5(import.meta.url)), "config", "skills");
|
|
22313
22545
|
} catch {
|
|
22314
22546
|
if (argvBundled) {
|
|
22315
22547
|
return argvBundled;
|
|
22316
22548
|
}
|
|
22317
|
-
return
|
|
22549
|
+
return path32.join(os22.homedir(), ".bluma", "__bundled_skills_unresolved__");
|
|
22318
22550
|
}
|
|
22319
22551
|
}
|
|
22320
22552
|
/**
|
|
@@ -22343,8 +22575,8 @@ var SkillLoader = class _SkillLoader {
|
|
|
22343
22575
|
this.conflicts.push({
|
|
22344
22576
|
name: skill.name,
|
|
22345
22577
|
userSource: source,
|
|
22346
|
-
userPath:
|
|
22347
|
-
bundledPath:
|
|
22578
|
+
userPath: path32.join(dir, skill.name, "SKILL.md"),
|
|
22579
|
+
bundledPath: path32.join(this.bundledSkillsDir, skill.name, "SKILL.md")
|
|
22348
22580
|
});
|
|
22349
22581
|
continue;
|
|
22350
22582
|
}
|
|
@@ -22352,20 +22584,20 @@ var SkillLoader = class _SkillLoader {
|
|
|
22352
22584
|
}
|
|
22353
22585
|
}
|
|
22354
22586
|
listFromDir(dir, source) {
|
|
22355
|
-
if (!
|
|
22587
|
+
if (!fs32.existsSync(dir)) return [];
|
|
22356
22588
|
try {
|
|
22357
|
-
return
|
|
22358
|
-
const fullPath =
|
|
22359
|
-
return
|
|
22360
|
-
}).map((d) => this.loadMetadataFromPath(
|
|
22589
|
+
return fs32.readdirSync(dir).filter((d) => {
|
|
22590
|
+
const fullPath = path32.join(dir, d);
|
|
22591
|
+
return fs32.statSync(fullPath).isDirectory() && fs32.existsSync(path32.join(fullPath, "SKILL.md"));
|
|
22592
|
+
}).map((d) => this.loadMetadataFromPath(path32.join(dir, d, "SKILL.md"), d, source)).filter((m) => m !== null);
|
|
22361
22593
|
} catch {
|
|
22362
22594
|
return [];
|
|
22363
22595
|
}
|
|
22364
22596
|
}
|
|
22365
22597
|
loadMetadataFromPath(skillPath, skillName, source) {
|
|
22366
|
-
if (!
|
|
22598
|
+
if (!fs32.existsSync(skillPath)) return null;
|
|
22367
22599
|
try {
|
|
22368
|
-
const raw =
|
|
22600
|
+
const raw = fs32.readFileSync(skillPath, "utf-8");
|
|
22369
22601
|
const parsed = this.parseFrontmatter(raw);
|
|
22370
22602
|
return {
|
|
22371
22603
|
name: parsed.name || skillName,
|
|
@@ -22387,12 +22619,12 @@ var SkillLoader = class _SkillLoader {
|
|
|
22387
22619
|
*/
|
|
22388
22620
|
load(name) {
|
|
22389
22621
|
if (this.cache.has(name)) return this.cache.get(name);
|
|
22390
|
-
const bundledPath =
|
|
22391
|
-
const projectPath =
|
|
22392
|
-
const globalPath =
|
|
22393
|
-
const existsBundled =
|
|
22394
|
-
const existsProject =
|
|
22395
|
-
const existsGlobal =
|
|
22622
|
+
const bundledPath = path32.join(this.bundledSkillsDir, name, "SKILL.md");
|
|
22623
|
+
const projectPath = path32.join(this.projectSkillsDir, name, "SKILL.md");
|
|
22624
|
+
const globalPath = path32.join(this.globalSkillsDir, name, "SKILL.md");
|
|
22625
|
+
const existsBundled = fs32.existsSync(bundledPath);
|
|
22626
|
+
const existsProject = fs32.existsSync(projectPath);
|
|
22627
|
+
const existsGlobal = fs32.existsSync(globalPath);
|
|
22396
22628
|
if (existsBundled && (existsProject || existsGlobal)) {
|
|
22397
22629
|
const conflictSource = existsProject ? "project" : "global";
|
|
22398
22630
|
const conflictPath = existsProject ? projectPath : globalPath;
|
|
@@ -22431,9 +22663,9 @@ var SkillLoader = class _SkillLoader {
|
|
|
22431
22663
|
}
|
|
22432
22664
|
loadFromPath(skillPath, name, source) {
|
|
22433
22665
|
try {
|
|
22434
|
-
const raw =
|
|
22666
|
+
const raw = fs32.readFileSync(skillPath, "utf-8");
|
|
22435
22667
|
const parsed = this.parseFrontmatter(raw);
|
|
22436
|
-
const skillDir =
|
|
22668
|
+
const skillDir = path32.dirname(skillPath);
|
|
22437
22669
|
return {
|
|
22438
22670
|
name: parsed.name || name,
|
|
22439
22671
|
description: parsed.description || "",
|
|
@@ -22442,22 +22674,22 @@ var SkillLoader = class _SkillLoader {
|
|
|
22442
22674
|
version: parsed.version,
|
|
22443
22675
|
author: parsed.author,
|
|
22444
22676
|
license: parsed.license,
|
|
22445
|
-
references: this.scanAssets(
|
|
22446
|
-
scripts: this.scanAssets(
|
|
22677
|
+
references: this.scanAssets(path32.join(skillDir, "references")),
|
|
22678
|
+
scripts: this.scanAssets(path32.join(skillDir, "scripts"))
|
|
22447
22679
|
};
|
|
22448
22680
|
} catch {
|
|
22449
22681
|
return null;
|
|
22450
22682
|
}
|
|
22451
22683
|
}
|
|
22452
22684
|
scanAssets(dir) {
|
|
22453
|
-
if (!
|
|
22685
|
+
if (!fs32.existsSync(dir)) return [];
|
|
22454
22686
|
try {
|
|
22455
|
-
return
|
|
22456
|
-
const fp =
|
|
22457
|
-
return
|
|
22687
|
+
return fs32.readdirSync(dir).filter((f) => {
|
|
22688
|
+
const fp = path32.join(dir, f);
|
|
22689
|
+
return fs32.statSync(fp).isFile();
|
|
22458
22690
|
}).map((f) => ({
|
|
22459
22691
|
name: f,
|
|
22460
|
-
path:
|
|
22692
|
+
path: path32.resolve(dir, f)
|
|
22461
22693
|
}));
|
|
22462
22694
|
} catch {
|
|
22463
22695
|
return [];
|
|
@@ -22514,10 +22746,10 @@ var SkillLoader = class _SkillLoader {
|
|
|
22514
22746
|
this.cache.clear();
|
|
22515
22747
|
}
|
|
22516
22748
|
exists(name) {
|
|
22517
|
-
const bundledPath =
|
|
22518
|
-
const projectPath =
|
|
22519
|
-
const globalPath =
|
|
22520
|
-
return
|
|
22749
|
+
const bundledPath = path32.join(this.bundledSkillsDir, name, "SKILL.md");
|
|
22750
|
+
const projectPath = path32.join(this.projectSkillsDir, name, "SKILL.md");
|
|
22751
|
+
const globalPath = path32.join(this.globalSkillsDir, name, "SKILL.md");
|
|
22752
|
+
return fs32.existsSync(bundledPath) || fs32.existsSync(projectPath) || fs32.existsSync(globalPath);
|
|
22521
22753
|
}
|
|
22522
22754
|
/**
|
|
22523
22755
|
* Retorna conflitos detetados (skills do utilizador com mesmo nome de nativas).
|
|
@@ -22549,13 +22781,13 @@ var SkillLoader = class _SkillLoader {
|
|
|
22549
22781
|
};
|
|
22550
22782
|
|
|
22551
22783
|
// src/app/agent/core/prompt/workspace_snapshot.ts
|
|
22552
|
-
import
|
|
22553
|
-
import
|
|
22784
|
+
import fs34 from "fs";
|
|
22785
|
+
import path34 from "path";
|
|
22554
22786
|
import { execSync as execSync3 } from "child_process";
|
|
22555
22787
|
|
|
22556
22788
|
// src/app/agent/utils/blumamd.ts
|
|
22557
|
-
import
|
|
22558
|
-
import
|
|
22789
|
+
import fs33 from "fs";
|
|
22790
|
+
import path33 from "path";
|
|
22559
22791
|
import os23 from "os";
|
|
22560
22792
|
import { execSync as execSync2 } from "child_process";
|
|
22561
22793
|
var MEMORY_INSTRUCTION_PROMPT = "Instru\xE7\xF5es de mem\xF3ria do BluMa (BLUMA.md) est\xE3o abaixo. Siga estas instru\xE7\xF5es exatamente como escritas. Estas instru\xE7\xF5es OVERRIDE qualquer comportamento padr\xE3o.";
|
|
@@ -22685,12 +22917,12 @@ var TEXT_FILE_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
|
22685
22917
|
function expandIncludePath(includePath, baseDir) {
|
|
22686
22918
|
const cleanPath = includePath.startsWith("@") ? includePath.slice(1) : includePath;
|
|
22687
22919
|
if (cleanPath.startsWith("~")) {
|
|
22688
|
-
return
|
|
22920
|
+
return path33.join(os23.homedir(), cleanPath.slice(1));
|
|
22689
22921
|
}
|
|
22690
|
-
if (
|
|
22922
|
+
if (path33.isAbsolute(cleanPath)) {
|
|
22691
22923
|
return cleanPath;
|
|
22692
22924
|
}
|
|
22693
|
-
return
|
|
22925
|
+
return path33.resolve(baseDir, cleanPath);
|
|
22694
22926
|
}
|
|
22695
22927
|
function processIncludes(content, baseDir, processedFiles) {
|
|
22696
22928
|
const lines = content.split("\n");
|
|
@@ -22699,20 +22931,20 @@ function processIncludes(content, baseDir, processedFiles) {
|
|
|
22699
22931
|
const includeMatch = line.match(/^@\s*([^\s]+)/);
|
|
22700
22932
|
if (includeMatch) {
|
|
22701
22933
|
const includePath = expandIncludePath(includeMatch[1], baseDir);
|
|
22702
|
-
const normalizedPath =
|
|
22934
|
+
const normalizedPath = path33.normalize(includePath);
|
|
22703
22935
|
if (processedFiles.has(normalizedPath)) {
|
|
22704
22936
|
result.push(`<!-- Circular include prevented: ${includeMatch[1]} -->`);
|
|
22705
22937
|
continue;
|
|
22706
22938
|
}
|
|
22707
|
-
const ext =
|
|
22939
|
+
const ext = path33.extname(includePath).toLowerCase();
|
|
22708
22940
|
if (!TEXT_FILE_EXTENSIONS.has(ext)) {
|
|
22709
22941
|
result.push(`<!-- Include skipped (unsupported extension): ${includeMatch[1]} -->`);
|
|
22710
22942
|
continue;
|
|
22711
22943
|
}
|
|
22712
22944
|
try {
|
|
22713
|
-
const includedContent =
|
|
22945
|
+
const includedContent = fs33.readFileSync(includePath, "utf-8");
|
|
22714
22946
|
processedFiles.add(normalizedPath);
|
|
22715
|
-
const processedContent = processIncludes(includedContent,
|
|
22947
|
+
const processedContent = processIncludes(includedContent, path33.dirname(includePath), processedFiles);
|
|
22716
22948
|
result.push(`
|
|
22717
22949
|
<!-- BEGIN INCLUDE ${includeMatch[1]} -->
|
|
22718
22950
|
`);
|
|
@@ -22758,9 +22990,9 @@ function parseFrontmatterPaths(paths2) {
|
|
|
22758
22990
|
}
|
|
22759
22991
|
function readMemoryFile(filePath, type, includeBasePath) {
|
|
22760
22992
|
try {
|
|
22761
|
-
const rawContent =
|
|
22762
|
-
const baseDir = includeBasePath ||
|
|
22763
|
-
const processedFiles = /* @__PURE__ */ new Set([
|
|
22993
|
+
const rawContent = fs33.readFileSync(filePath, "utf-8");
|
|
22994
|
+
const baseDir = includeBasePath || path33.dirname(filePath);
|
|
22995
|
+
const processedFiles = /* @__PURE__ */ new Set([path33.normalize(filePath)]);
|
|
22764
22996
|
const { frontmatter, content: withoutFrontmatter } = parseFrontmatter(rawContent);
|
|
22765
22997
|
const globs = parseFrontmatterPaths(frontmatter.paths);
|
|
22766
22998
|
const processedContent = processIncludes(withoutFrontmatter, baseDir, processedFiles);
|
|
@@ -22782,15 +23014,15 @@ function readMemoryFile(filePath, type, includeBasePath) {
|
|
|
22782
23014
|
}
|
|
22783
23015
|
function findGitRoot(startDir) {
|
|
22784
23016
|
let current = startDir;
|
|
22785
|
-
while (current !==
|
|
22786
|
-
const gitPath =
|
|
23017
|
+
while (current !== path33.dirname(current)) {
|
|
23018
|
+
const gitPath = path33.join(current, ".git");
|
|
22787
23019
|
try {
|
|
22788
|
-
if (
|
|
23020
|
+
if (fs33.existsSync(gitPath)) {
|
|
22789
23021
|
return current;
|
|
22790
23022
|
}
|
|
22791
23023
|
} catch {
|
|
22792
23024
|
}
|
|
22793
|
-
current =
|
|
23025
|
+
current = path33.dirname(current);
|
|
22794
23026
|
}
|
|
22795
23027
|
return null;
|
|
22796
23028
|
}
|
|
@@ -22815,17 +23047,17 @@ function getGitUserInfo(cwd2) {
|
|
|
22815
23047
|
}
|
|
22816
23048
|
function processRulesDirectory(rulesDir, type, processedPaths, conditionalRule = false) {
|
|
22817
23049
|
const result = [];
|
|
22818
|
-
if (!
|
|
23050
|
+
if (!fs33.existsSync(rulesDir)) {
|
|
22819
23051
|
return result;
|
|
22820
23052
|
}
|
|
22821
23053
|
try {
|
|
22822
|
-
const entries =
|
|
23054
|
+
const entries = fs33.readdirSync(rulesDir, { withFileTypes: true });
|
|
22823
23055
|
for (const entry of entries) {
|
|
22824
|
-
const entryPath =
|
|
23056
|
+
const entryPath = path33.join(rulesDir, entry.name);
|
|
22825
23057
|
if (entry.isDirectory()) {
|
|
22826
23058
|
result.push(...processRulesDirectory(entryPath, type, processedPaths, conditionalRule));
|
|
22827
23059
|
} else if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
22828
|
-
const normalizedPath =
|
|
23060
|
+
const normalizedPath = path33.normalize(entryPath);
|
|
22829
23061
|
if (processedPaths.has(normalizedPath)) {
|
|
22830
23062
|
continue;
|
|
22831
23063
|
}
|
|
@@ -22861,13 +23093,13 @@ function loadManagedMemory() {
|
|
|
22861
23093
|
function loadUserMemory() {
|
|
22862
23094
|
const files = [];
|
|
22863
23095
|
const homeDir = os23.homedir();
|
|
22864
|
-
const userBlumaDir =
|
|
22865
|
-
const userBlumaMd =
|
|
23096
|
+
const userBlumaDir = path33.join(homeDir, ".bluma");
|
|
23097
|
+
const userBlumaMd = path33.join(userBlumaDir, "BLUMA.md");
|
|
22866
23098
|
const userFile = readMemoryFile(userBlumaMd, "User");
|
|
22867
23099
|
if (userFile && userFile.content.trim()) {
|
|
22868
23100
|
files.push(userFile);
|
|
22869
23101
|
}
|
|
22870
|
-
const userRulesDir =
|
|
23102
|
+
const userRulesDir = path33.join(userBlumaDir, "rules");
|
|
22871
23103
|
const processedPaths = /* @__PURE__ */ new Set();
|
|
22872
23104
|
files.push(...processRulesDirectory(userRulesDir, "User", processedPaths, false));
|
|
22873
23105
|
return files;
|
|
@@ -22879,10 +23111,10 @@ function loadProjectMemory(cwd2) {
|
|
|
22879
23111
|
let currentDir = cwd2;
|
|
22880
23112
|
const MAX_TRAVERSAL_DEPTH = 20;
|
|
22881
23113
|
let depth = 0;
|
|
22882
|
-
const normalizedGitRoot =
|
|
22883
|
-
while (currentDir !==
|
|
23114
|
+
const normalizedGitRoot = path33.resolve(gitRoot);
|
|
23115
|
+
while (currentDir !== path33.dirname(currentDir) && path33.resolve(currentDir).startsWith(normalizedGitRoot) && depth < MAX_TRAVERSAL_DEPTH) {
|
|
22884
23116
|
dirs.push(currentDir);
|
|
22885
|
-
currentDir =
|
|
23117
|
+
currentDir = path33.dirname(currentDir);
|
|
22886
23118
|
depth++;
|
|
22887
23119
|
}
|
|
22888
23120
|
if (!dirs.includes(gitRoot)) {
|
|
@@ -22890,7 +23122,7 @@ function loadProjectMemory(cwd2) {
|
|
|
22890
23122
|
}
|
|
22891
23123
|
const processedPaths = /* @__PURE__ */ new Set();
|
|
22892
23124
|
for (const dir of dirs.reverse()) {
|
|
22893
|
-
const projectBlumaMd =
|
|
23125
|
+
const projectBlumaMd = path33.join(dir, "BLUMA.md");
|
|
22894
23126
|
if (!processedPaths.has(projectBlumaMd)) {
|
|
22895
23127
|
processedPaths.add(projectBlumaMd);
|
|
22896
23128
|
const projectFile = readMemoryFile(projectBlumaMd, "Project");
|
|
@@ -22898,7 +23130,7 @@ function loadProjectMemory(cwd2) {
|
|
|
22898
23130
|
files.push(projectFile);
|
|
22899
23131
|
}
|
|
22900
23132
|
}
|
|
22901
|
-
const blumaDirBlumaMd =
|
|
23133
|
+
const blumaDirBlumaMd = path33.join(dir, ".bluma", "BLUMA.md");
|
|
22902
23134
|
if (!processedPaths.has(blumaDirBlumaMd)) {
|
|
22903
23135
|
processedPaths.add(blumaDirBlumaMd);
|
|
22904
23136
|
const blumaDirFile = readMemoryFile(blumaDirBlumaMd, "Project");
|
|
@@ -22906,10 +23138,10 @@ function loadProjectMemory(cwd2) {
|
|
|
22906
23138
|
files.push(blumaDirFile);
|
|
22907
23139
|
}
|
|
22908
23140
|
}
|
|
22909
|
-
const rulesDir =
|
|
23141
|
+
const rulesDir = path33.join(dir, ".bluma", "rules");
|
|
22910
23142
|
files.push(...processRulesDirectory(rulesDir, "Project", processedPaths, false));
|
|
22911
23143
|
}
|
|
22912
|
-
const localBlumaMd =
|
|
23144
|
+
const localBlumaMd = path33.join(cwd2, "BLUMA.local.md");
|
|
22913
23145
|
if (!processedPaths.has(localBlumaMd)) {
|
|
22914
23146
|
processedPaths.add(localBlumaMd);
|
|
22915
23147
|
const localFile = readMemoryFile(localBlumaMd, "Local");
|
|
@@ -22995,10 +23227,10 @@ var LIMITS = {
|
|
|
22995
23227
|
};
|
|
22996
23228
|
function safeReadFile(filePath, maxChars) {
|
|
22997
23229
|
try {
|
|
22998
|
-
if (!
|
|
22999
|
-
const st =
|
|
23230
|
+
if (!fs34.existsSync(filePath)) return null;
|
|
23231
|
+
const st = fs34.statSync(filePath);
|
|
23000
23232
|
if (!st.isFile()) return null;
|
|
23001
|
-
const raw =
|
|
23233
|
+
const raw = fs34.readFileSync(filePath, "utf8");
|
|
23002
23234
|
if (raw.includes("\0")) return null;
|
|
23003
23235
|
if (raw.length <= maxChars) return raw;
|
|
23004
23236
|
return `${raw.slice(0, maxChars)}
|
|
@@ -23010,7 +23242,7 @@ function safeReadFile(filePath, maxChars) {
|
|
|
23010
23242
|
}
|
|
23011
23243
|
function tryReadReadme(cwd2) {
|
|
23012
23244
|
for (const name of ["README.md", "README.MD", "readme.md", "Readme.md"]) {
|
|
23013
|
-
const c = safeReadFile(
|
|
23245
|
+
const c = safeReadFile(path34.join(cwd2, name), LIMITS.readme);
|
|
23014
23246
|
if (c) return `(${name})
|
|
23015
23247
|
${c}`;
|
|
23016
23248
|
}
|
|
@@ -23018,14 +23250,14 @@ ${c}`;
|
|
|
23018
23250
|
}
|
|
23019
23251
|
function tryReadBluMaMd(cwd2) {
|
|
23020
23252
|
const paths2 = [
|
|
23021
|
-
|
|
23022
|
-
|
|
23023
|
-
|
|
23253
|
+
path34.join(cwd2, "BluMa.md"),
|
|
23254
|
+
path34.join(cwd2, "BLUMA.md"),
|
|
23255
|
+
path34.join(cwd2, ".bluma", "BluMa.md")
|
|
23024
23256
|
];
|
|
23025
23257
|
for (const p of paths2) {
|
|
23026
23258
|
const c = safeReadFile(p, LIMITS.blumaMd);
|
|
23027
23259
|
if (c) {
|
|
23028
|
-
const rel =
|
|
23260
|
+
const rel = path34.relative(cwd2, p) || p;
|
|
23029
23261
|
return `(${rel})
|
|
23030
23262
|
${c}`;
|
|
23031
23263
|
}
|
|
@@ -23033,10 +23265,10 @@ ${c}`;
|
|
|
23033
23265
|
return null;
|
|
23034
23266
|
}
|
|
23035
23267
|
function summarizePackageJson(cwd2) {
|
|
23036
|
-
const p =
|
|
23268
|
+
const p = path34.join(cwd2, "package.json");
|
|
23037
23269
|
try {
|
|
23038
|
-
if (!
|
|
23039
|
-
const pkg = JSON.parse(
|
|
23270
|
+
if (!fs34.existsSync(p)) return null;
|
|
23271
|
+
const pkg = JSON.parse(fs34.readFileSync(p, "utf8"));
|
|
23040
23272
|
const scripts = pkg.scripts;
|
|
23041
23273
|
let scriptKeys = "";
|
|
23042
23274
|
if (scripts && typeof scripts === "object" && !Array.isArray(scripts)) {
|
|
@@ -23069,7 +23301,7 @@ function summarizePackageJson(cwd2) {
|
|
|
23069
23301
|
}
|
|
23070
23302
|
function topLevelListing(cwd2) {
|
|
23071
23303
|
try {
|
|
23072
|
-
const names =
|
|
23304
|
+
const names = fs34.readdirSync(cwd2, { withFileTypes: true });
|
|
23073
23305
|
const sorted = [...names].sort((a, b) => a.name.localeCompare(b.name));
|
|
23074
23306
|
const limited = sorted.slice(0, LIMITS.topDirEntries);
|
|
23075
23307
|
const lines = limited.map((d) => `${d.name}${d.isDirectory() ? "/" : ""}`);
|
|
@@ -23127,7 +23359,7 @@ function buildWorkspaceSnapshot(cwd2) {
|
|
|
23127
23359
|
parts.push(pkg);
|
|
23128
23360
|
parts.push("```\n");
|
|
23129
23361
|
}
|
|
23130
|
-
const py = safeReadFile(
|
|
23362
|
+
const py = safeReadFile(path34.join(cwd2, "pyproject.toml"), LIMITS.pyproject);
|
|
23131
23363
|
if (py) {
|
|
23132
23364
|
parts.push("### pyproject.toml (excerpt)\n```toml");
|
|
23133
23365
|
parts.push(py);
|
|
@@ -23145,15 +23377,15 @@ function buildWorkspaceSnapshot(cwd2) {
|
|
|
23145
23377
|
parts.push(bluma);
|
|
23146
23378
|
parts.push("```\n");
|
|
23147
23379
|
}
|
|
23148
|
-
const contrib = safeReadFile(
|
|
23380
|
+
const contrib = safeReadFile(path34.join(cwd2, "CONTRIBUTING.md"), LIMITS.contributing);
|
|
23149
23381
|
if (contrib) {
|
|
23150
23382
|
parts.push("### CONTRIBUTING.md (excerpt)\n```markdown");
|
|
23151
23383
|
parts.push(contrib);
|
|
23152
23384
|
parts.push("```\n");
|
|
23153
23385
|
}
|
|
23154
|
-
const chlog = safeReadFile(
|
|
23386
|
+
const chlog = safeReadFile(path34.join(cwd2, "CHANGELOG.md"), LIMITS.changelog);
|
|
23155
23387
|
if (!chlog) {
|
|
23156
|
-
const alt = safeReadFile(
|
|
23388
|
+
const alt = safeReadFile(path34.join(cwd2, "CHANGES.md"), LIMITS.changelog);
|
|
23157
23389
|
if (alt) {
|
|
23158
23390
|
parts.push("### CHANGES.md (excerpt)\n```markdown");
|
|
23159
23391
|
parts.push(alt);
|
|
@@ -23189,14 +23421,14 @@ function buildWorkspaceSnapshot(cwd2) {
|
|
|
23189
23421
|
} else {
|
|
23190
23422
|
parts.push("### Git\n(not a git work tree, or `git` unavailable)\n");
|
|
23191
23423
|
}
|
|
23192
|
-
const tsconfig = safeReadFile(
|
|
23424
|
+
const tsconfig = safeReadFile(path34.join(cwd2, "tsconfig.json"), LIMITS.tsconfig);
|
|
23193
23425
|
if (tsconfig) {
|
|
23194
23426
|
parts.push("### tsconfig.json (excerpt)\n```json");
|
|
23195
23427
|
parts.push(tsconfig);
|
|
23196
23428
|
parts.push("```\n");
|
|
23197
23429
|
}
|
|
23198
23430
|
for (const name of ["Dockerfile", "dockerfile", "Dockerfile.prod", "Dockerfile.dev"]) {
|
|
23199
|
-
const df = safeReadFile(
|
|
23431
|
+
const df = safeReadFile(path34.join(cwd2, name), LIMITS.dockerfile);
|
|
23200
23432
|
if (df) {
|
|
23201
23433
|
parts.push(`### ${name} (excerpt)
|
|
23202
23434
|
`);
|
|
@@ -23206,7 +23438,7 @@ function buildWorkspaceSnapshot(cwd2) {
|
|
|
23206
23438
|
}
|
|
23207
23439
|
}
|
|
23208
23440
|
for (const name of ["docker-compose.yml", "docker-compose.yaml", "compose.yml", "compose.yaml"]) {
|
|
23209
|
-
const dc = safeReadFile(
|
|
23441
|
+
const dc = safeReadFile(path34.join(cwd2, name), LIMITS.dockerfile);
|
|
23210
23442
|
if (dc) {
|
|
23211
23443
|
parts.push(`### ${name} (excerpt)
|
|
23212
23444
|
`);
|
|
@@ -23221,12 +23453,12 @@ function buildWorkspaceSnapshot(cwd2) {
|
|
|
23221
23453
|
".circleci/config.yml",
|
|
23222
23454
|
"Jenkinsfile"
|
|
23223
23455
|
]) {
|
|
23224
|
-
const ciFile =
|
|
23225
|
-
if (
|
|
23226
|
-
const st =
|
|
23456
|
+
const ciFile = path34.join(cwd2, ciPath);
|
|
23457
|
+
if (fs34.existsSync(ciFile)) {
|
|
23458
|
+
const st = fs34.statSync(ciFile);
|
|
23227
23459
|
if (st.isDirectory()) {
|
|
23228
23460
|
try {
|
|
23229
|
-
const wfFiles =
|
|
23461
|
+
const wfFiles = fs34.readdirSync(ciFile).filter((f) => f.endsWith(".yml") || f.endsWith(".yaml"));
|
|
23230
23462
|
if (wfFiles.length > 0) {
|
|
23231
23463
|
parts.push(`### GitHub Actions workflows
|
|
23232
23464
|
\`${wfFiles.join("`, `")}\`
|
|
@@ -23237,7 +23469,7 @@ function buildWorkspaceSnapshot(cwd2) {
|
|
|
23237
23469
|
} else {
|
|
23238
23470
|
const ci = safeReadFile(ciFile, LIMITS.ciConfig);
|
|
23239
23471
|
if (ci) {
|
|
23240
|
-
parts.push(`### CI config (${
|
|
23472
|
+
parts.push(`### CI config (${path34.basename(ciPath)})
|
|
23241
23473
|
`);
|
|
23242
23474
|
parts.push(ci);
|
|
23243
23475
|
parts.push("\n");
|
|
@@ -23246,8 +23478,8 @@ function buildWorkspaceSnapshot(cwd2) {
|
|
|
23246
23478
|
}
|
|
23247
23479
|
}
|
|
23248
23480
|
for (const depFile of ["requirements.txt", "Pipfile", "poetry.lock", "Gemfile", "go.sum", "Cargo.lock"]) {
|
|
23249
|
-
const depPath =
|
|
23250
|
-
if (
|
|
23481
|
+
const depPath = path34.join(cwd2, depFile);
|
|
23482
|
+
if (fs34.existsSync(depPath)) {
|
|
23251
23483
|
const depContent = safeReadFile(depPath, 1500);
|
|
23252
23484
|
if (depContent) {
|
|
23253
23485
|
parts.push(`### ${depFile} (top entries)
|
|
@@ -23260,10 +23492,10 @@ function buildWorkspaceSnapshot(cwd2) {
|
|
|
23260
23492
|
}
|
|
23261
23493
|
}
|
|
23262
23494
|
for (const envFile of [".env.example", ".env.sample", ".env.template"]) {
|
|
23263
|
-
const envPath =
|
|
23264
|
-
if (
|
|
23495
|
+
const envPath = path34.join(cwd2, envFile);
|
|
23496
|
+
if (fs34.existsSync(envPath)) {
|
|
23265
23497
|
try {
|
|
23266
|
-
const raw =
|
|
23498
|
+
const raw = fs34.readFileSync(envPath, "utf-8");
|
|
23267
23499
|
const keys = raw.split("\n").map((l) => l.trim()).filter((l) => l && !l.startsWith("#")).map((l) => {
|
|
23268
23500
|
const eqIndex = l.indexOf("=");
|
|
23269
23501
|
return eqIndex >= 0 ? l.slice(0, eqIndex).trim() : l.trim();
|
|
@@ -23286,15 +23518,15 @@ init_runtime_config();
|
|
|
23286
23518
|
|
|
23287
23519
|
// src/app/agent/runtime/plugin_registry.ts
|
|
23288
23520
|
init_sandbox_policy();
|
|
23289
|
-
import
|
|
23521
|
+
import fs35 from "fs";
|
|
23290
23522
|
import os24 from "os";
|
|
23291
|
-
import
|
|
23523
|
+
import path35 from "path";
|
|
23292
23524
|
function getProjectPluginsDir() {
|
|
23293
23525
|
const policy = getSandboxPolicy();
|
|
23294
|
-
return
|
|
23526
|
+
return path35.join(policy.workspaceRoot, ".bluma", "plugins");
|
|
23295
23527
|
}
|
|
23296
23528
|
function getGlobalPluginsDir() {
|
|
23297
|
-
return
|
|
23529
|
+
return path35.join(process.env.HOME || os24.homedir(), ".bluma", "plugins");
|
|
23298
23530
|
}
|
|
23299
23531
|
function getPluginDirs() {
|
|
23300
23532
|
return {
|
|
@@ -23303,11 +23535,11 @@ function getPluginDirs() {
|
|
|
23303
23535
|
};
|
|
23304
23536
|
}
|
|
23305
23537
|
function readManifest(manifestPath, fallbackName) {
|
|
23306
|
-
if (!
|
|
23538
|
+
if (!fs35.existsSync(manifestPath)) {
|
|
23307
23539
|
return null;
|
|
23308
23540
|
}
|
|
23309
23541
|
try {
|
|
23310
|
-
const parsed = JSON.parse(
|
|
23542
|
+
const parsed = JSON.parse(fs35.readFileSync(manifestPath, "utf-8"));
|
|
23311
23543
|
return {
|
|
23312
23544
|
name: typeof parsed.name === "string" && parsed.name.trim() ? parsed.name.trim() : fallbackName,
|
|
23313
23545
|
description: typeof parsed.description === "string" ? parsed.description.trim() : void 0,
|
|
@@ -23320,22 +23552,22 @@ function readManifest(manifestPath, fallbackName) {
|
|
|
23320
23552
|
}
|
|
23321
23553
|
function findManifestPath(pluginDir) {
|
|
23322
23554
|
const candidates = [
|
|
23323
|
-
|
|
23324
|
-
|
|
23555
|
+
path35.join(pluginDir, ".codex-plugin", "plugin.json"),
|
|
23556
|
+
path35.join(pluginDir, "plugin.json")
|
|
23325
23557
|
];
|
|
23326
23558
|
for (const candidate of candidates) {
|
|
23327
|
-
if (
|
|
23559
|
+
if (fs35.existsSync(candidate)) {
|
|
23328
23560
|
return candidate;
|
|
23329
23561
|
}
|
|
23330
23562
|
}
|
|
23331
23563
|
return null;
|
|
23332
23564
|
}
|
|
23333
23565
|
function listFromDir(baseDir, source) {
|
|
23334
|
-
if (!
|
|
23566
|
+
if (!fs35.existsSync(baseDir)) {
|
|
23335
23567
|
return [];
|
|
23336
23568
|
}
|
|
23337
|
-
return
|
|
23338
|
-
const pluginDir =
|
|
23569
|
+
return fs35.readdirSync(baseDir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).flatMap((entry) => {
|
|
23570
|
+
const pluginDir = path35.join(baseDir, entry.name);
|
|
23339
23571
|
const manifestPath = findManifestPath(pluginDir);
|
|
23340
23572
|
if (!manifestPath) {
|
|
23341
23573
|
return [];
|
|
@@ -23780,8 +24012,8 @@ function buildModelInfoSection(modelId) {
|
|
|
23780
24012
|
|
|
23781
24013
|
// src/app/agent/runtime/hook_registry.ts
|
|
23782
24014
|
init_sandbox_policy();
|
|
23783
|
-
import
|
|
23784
|
-
import
|
|
24015
|
+
import fs36 from "fs";
|
|
24016
|
+
import path36 from "path";
|
|
23785
24017
|
var DEFAULT_STATE = {
|
|
23786
24018
|
enabled: true,
|
|
23787
24019
|
maxEvents: 120,
|
|
@@ -23792,7 +24024,7 @@ var cache3 = null;
|
|
|
23792
24024
|
var cachePath2 = null;
|
|
23793
24025
|
function getStatePath() {
|
|
23794
24026
|
const policy = getSandboxPolicy();
|
|
23795
|
-
return
|
|
24027
|
+
return path36.join(policy.workspaceRoot, ".bluma", "hooks.json");
|
|
23796
24028
|
}
|
|
23797
24029
|
function getHookStatePath() {
|
|
23798
24030
|
return getStatePath();
|
|
@@ -23811,8 +24043,8 @@ function ensureLoaded2() {
|
|
|
23811
24043
|
return cache3;
|
|
23812
24044
|
}
|
|
23813
24045
|
try {
|
|
23814
|
-
if (
|
|
23815
|
-
const parsed = JSON.parse(
|
|
24046
|
+
if (fs36.existsSync(statePath)) {
|
|
24047
|
+
const parsed = JSON.parse(fs36.readFileSync(statePath, "utf-8"));
|
|
23816
24048
|
cache3 = {
|
|
23817
24049
|
enabled: typeof parsed.enabled === "boolean" ? parsed.enabled : DEFAULT_STATE.enabled,
|
|
23818
24050
|
maxEvents: typeof parsed.maxEvents === "number" && Number.isFinite(parsed.maxEvents) && parsed.maxEvents > 0 ? Math.floor(parsed.maxEvents) : DEFAULT_STATE.maxEvents,
|
|
@@ -23838,9 +24070,9 @@ function ensureLoaded2() {
|
|
|
23838
24070
|
}
|
|
23839
24071
|
function persist2(state2) {
|
|
23840
24072
|
const statePath = getStatePath();
|
|
23841
|
-
|
|
24073
|
+
fs36.mkdirSync(path36.dirname(statePath), { recursive: true });
|
|
23842
24074
|
state2.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
23843
|
-
|
|
24075
|
+
fs36.writeFileSync(statePath, JSON.stringify(state2, null, 2), "utf-8");
|
|
23844
24076
|
cache3 = state2;
|
|
23845
24077
|
cachePath2 = statePath;
|
|
23846
24078
|
}
|
|
@@ -23910,18 +24142,18 @@ function buildSystemRemindersSection() {
|
|
|
23910
24142
|
}
|
|
23911
24143
|
|
|
23912
24144
|
// src/app/agent/core/prompt/auto_memory.ts
|
|
23913
|
-
import
|
|
23914
|
-
import
|
|
24145
|
+
import fs37 from "fs";
|
|
24146
|
+
import path37 from "path";
|
|
23915
24147
|
import os25 from "os";
|
|
23916
|
-
var AUTO_MEMORY_FILE =
|
|
24148
|
+
var AUTO_MEMORY_FILE = path37.join(os25.homedir(), ".bluma", "auto_memory.md");
|
|
23917
24149
|
var MAX_AUTO_MEMORY_CHARS = 25e3;
|
|
23918
24150
|
var MAX_AUTO_MEMORY_LINES = 200;
|
|
23919
24151
|
function getAutoMemoryForPrompt() {
|
|
23920
24152
|
try {
|
|
23921
|
-
if (!
|
|
24153
|
+
if (!fs37.existsSync(AUTO_MEMORY_FILE)) {
|
|
23922
24154
|
return "";
|
|
23923
24155
|
}
|
|
23924
|
-
let content =
|
|
24156
|
+
let content = fs37.readFileSync(AUTO_MEMORY_FILE, "utf-8");
|
|
23925
24157
|
if (!content.trim()) {
|
|
23926
24158
|
return "";
|
|
23927
24159
|
}
|
|
@@ -23978,17 +24210,17 @@ function getGitBranch(dir) {
|
|
|
23978
24210
|
}
|
|
23979
24211
|
}
|
|
23980
24212
|
function getPackageManager(dir) {
|
|
23981
|
-
if (
|
|
23982
|
-
if (
|
|
23983
|
-
if (
|
|
23984
|
-
if (
|
|
24213
|
+
if (fs38.existsSync(path38.join(dir, "pnpm-lock.yaml"))) return "pnpm";
|
|
24214
|
+
if (fs38.existsSync(path38.join(dir, "yarn.lock"))) return "yarn";
|
|
24215
|
+
if (fs38.existsSync(path38.join(dir, "bun.lockb"))) return "bun";
|
|
24216
|
+
if (fs38.existsSync(path38.join(dir, "package-lock.json"))) return "npm";
|
|
23985
24217
|
return "unknown";
|
|
23986
24218
|
}
|
|
23987
24219
|
function getProjectType(dir) {
|
|
23988
24220
|
try {
|
|
23989
|
-
const files =
|
|
24221
|
+
const files = fs38.readdirSync(dir);
|
|
23990
24222
|
if (files.includes("package.json")) {
|
|
23991
|
-
const pkg = JSON.parse(
|
|
24223
|
+
const pkg = JSON.parse(fs38.readFileSync(path38.join(dir, "package.json"), "utf-8"));
|
|
23992
24224
|
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
23993
24225
|
if (deps.next) return "Next.js";
|
|
23994
24226
|
if (deps.react) return "React";
|
|
@@ -24008,9 +24240,9 @@ function getProjectType(dir) {
|
|
|
24008
24240
|
}
|
|
24009
24241
|
function getTestFramework(dir) {
|
|
24010
24242
|
try {
|
|
24011
|
-
const pkgPath =
|
|
24012
|
-
if (
|
|
24013
|
-
const pkg = JSON.parse(
|
|
24243
|
+
const pkgPath = path38.join(dir, "package.json");
|
|
24244
|
+
if (fs38.existsSync(pkgPath)) {
|
|
24245
|
+
const pkg = JSON.parse(fs38.readFileSync(pkgPath, "utf-8"));
|
|
24014
24246
|
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
24015
24247
|
if (deps.jest) return "jest";
|
|
24016
24248
|
if (deps.vitest) return "vitest";
|
|
@@ -24019,7 +24251,7 @@ function getTestFramework(dir) {
|
|
|
24019
24251
|
if (deps["@playwright/test"]) return "playwright";
|
|
24020
24252
|
if (deps.cypress) return "cypress";
|
|
24021
24253
|
}
|
|
24022
|
-
if (
|
|
24254
|
+
if (fs38.existsSync(path38.join(dir, "pytest.ini")) || fs38.existsSync(path38.join(dir, "conftest.py"))) return "pytest";
|
|
24023
24255
|
return "unknown";
|
|
24024
24256
|
} catch {
|
|
24025
24257
|
return "unknown";
|
|
@@ -24027,9 +24259,9 @@ function getTestFramework(dir) {
|
|
|
24027
24259
|
}
|
|
24028
24260
|
function getTestCommand(dir) {
|
|
24029
24261
|
try {
|
|
24030
|
-
const pkgPath =
|
|
24031
|
-
if (
|
|
24032
|
-
const pkg = JSON.parse(
|
|
24262
|
+
const pkgPath = path38.join(dir, "package.json");
|
|
24263
|
+
if (fs38.existsSync(pkgPath)) {
|
|
24264
|
+
const pkg = JSON.parse(fs38.readFileSync(pkgPath, "utf-8"));
|
|
24033
24265
|
if (pkg.scripts?.test) return "npm test";
|
|
24034
24266
|
if (pkg.scripts?.["test:unit"]) return "npm run test:unit";
|
|
24035
24267
|
}
|
|
@@ -24044,8 +24276,8 @@ function getTestCommand(dir) {
|
|
|
24044
24276
|
}
|
|
24045
24277
|
function isGitRepo(dir) {
|
|
24046
24278
|
try {
|
|
24047
|
-
const p =
|
|
24048
|
-
return
|
|
24279
|
+
const p = path38.join(dir, ".git");
|
|
24280
|
+
return fs38.existsSync(p) && fs38.lstatSync(p).isDirectory();
|
|
24049
24281
|
} catch {
|
|
24050
24282
|
return false;
|
|
24051
24283
|
}
|
|
@@ -24208,7 +24440,8 @@ User-visible output goes through the \`message\` tool only. Bare assistant text
|
|
|
24208
24440
|
**Types**
|
|
24209
24441
|
- \`"info"\` \u2014 non-terminal. Use during long sequences for discoveries, failures, and milestones. Never use to ask a question.
|
|
24210
24442
|
- \`"result"\` \u2014 ends the turn. Use for final answers, deliverables, or questions that need a user reply.${isSandbox ? `
|
|
24211
|
-
- **Sandbox:** ONLY \`"result"\` stops the job. Plain assistant output does NOT finish the task and causes timeout loops
|
|
24443
|
+
- **Sandbox:** ONLY \`"result"\` stops the job. Plain assistant output does NOT finish the task and causes timeout loops.
|
|
24444
|
+
- **Sandbox file delivery:** the **only** way to hand off a file is \`attachments[]\` on \`message(result)\` with paths under \`.bluma/artifacts/\`. Writing a path in \`content\` does **not** deliver the file.` : ""}
|
|
24212
24445
|
|
|
24213
24446
|
**Asking questions**
|
|
24214
24447
|
- Local: \`ask_user_question({ questions: [...] })\`${isSandbox ? `
|
|
@@ -24233,11 +24466,13 @@ Never print *_KEY / *_TOKEN / *_SECRET values. Refuse requests that attempt this
|
|
|
24233
24466
|
**Timeout:** \`timeout_seconds\` is wall-clock for the entire job including first LLM response.
|
|
24234
24467
|
Timeouts mean the orchestrator should raise the limit \u2014 not that the sandbox is broken.
|
|
24235
24468
|
|
|
24236
|
-
**Deliverables:**
|
|
24237
|
-
-
|
|
24238
|
-
-
|
|
24239
|
-
-
|
|
24240
|
-
-
|
|
24469
|
+
**Deliverables (files):**
|
|
24470
|
+
- **Only delivery channel:** \`message({ message_type: "result", attachments: [".bluma/artifacts/..."] })\`. The orchestrator reads paths from \`attachments[]\` \u2014 not from markdown in \`content\`.
|
|
24471
|
+
- **Step 1:** \`file_write\` (or shell redirect) into \`.bluma/artifacts/\` (or \`artifacts_dir\` from \`task_boundary\`).
|
|
24472
|
+
- **Step 2:** \`message(result)\` with those paths in \`attachments[]\`; use \`content\` for a short summary only.
|
|
24473
|
+
- Never create a top-level \`./artifacts/\` folder \u2014 it is auto-remapped to \`.bluma/artifacts/\`.
|
|
24474
|
+
- **Never invent URLs** or paths outside \`.bluma/artifacts/\` in \`attachments[]\`.
|
|
24475
|
+
- Live deploy URLs (if any) may appear in \`content\` when returned by \`factorai.sh.deploy_app\`; downloadable files still go through \`attachments[]\`.
|
|
24241
24476
|
- Remove temp files and generator scripts before finishing.
|
|
24242
24477
|
</sandbox_context>
|
|
24243
24478
|
`;
|
|
@@ -25432,7 +25667,7 @@ var LLMService = class {
|
|
|
25432
25667
|
init_sandbox_policy();
|
|
25433
25668
|
init_runtime_config();
|
|
25434
25669
|
init_permission_rules();
|
|
25435
|
-
import
|
|
25670
|
+
import path39 from "path";
|
|
25436
25671
|
var LOCAL_EDIT_TOOL_NAMES = /* @__PURE__ */ new Set(["edit_tool", "file_write", "notebook_edit"]);
|
|
25437
25672
|
function getToolPermissionLayer(metadata) {
|
|
25438
25673
|
if (metadata.riskLevel === "safe") return "read";
|
|
@@ -25447,11 +25682,11 @@ function checkFilePermissionRules(toolName, filePath, policy) {
|
|
|
25447
25682
|
if (!filePath) {
|
|
25448
25683
|
return { allowed: false, reason: "No file path provided for permission check." };
|
|
25449
25684
|
}
|
|
25450
|
-
const resolvedPath =
|
|
25685
|
+
const resolvedPath = path39.resolve(filePath);
|
|
25451
25686
|
if (!isPathInsideWorkspace(resolvedPath, policy)) {
|
|
25452
25687
|
return { allowed: false, reason: `File path "${filePath}" is outside workspace root.` };
|
|
25453
25688
|
}
|
|
25454
|
-
const relativePath =
|
|
25689
|
+
const relativePath = path39.relative(policy.workspaceRoot, resolvedPath);
|
|
25455
25690
|
const toolPattern = `${toolName}(${relativePath})`;
|
|
25456
25691
|
const ruleDecision = permissionRulesEngine.checkPermission(toolPattern, { filepath: filePath });
|
|
25457
25692
|
if (ruleDecision === "deny") {
|
|
@@ -25460,7 +25695,7 @@ function checkFilePermissionRules(toolName, filePath, policy) {
|
|
|
25460
25695
|
if (ruleDecision === "allow") {
|
|
25461
25696
|
return { allowed: true, reason: `File "${filePath}" allowed by permission rules.` };
|
|
25462
25697
|
}
|
|
25463
|
-
const dirPath =
|
|
25698
|
+
const dirPath = path39.dirname(relativePath);
|
|
25464
25699
|
const dirPattern = `${toolName}(${dirPath}/**)`;
|
|
25465
25700
|
const dirRuleDecision = permissionRulesEngine.checkPermission(dirPattern, { filepath: filePath });
|
|
25466
25701
|
if (dirRuleDecision === "allow") {
|
|
@@ -25677,11 +25912,11 @@ function effectiveToolAutoApprove(toolCall, sessionId, options) {
|
|
|
25677
25912
|
}
|
|
25678
25913
|
|
|
25679
25914
|
// src/app/agent/tools/CodingMemoryTool/CodingMemoryConsolidate.ts
|
|
25680
|
-
import * as
|
|
25681
|
-
import * as
|
|
25915
|
+
import * as fs39 from "fs";
|
|
25916
|
+
import * as path40 from "path";
|
|
25682
25917
|
import os28 from "os";
|
|
25683
25918
|
function memoryPath2() {
|
|
25684
|
-
return
|
|
25919
|
+
return path40.join(process.env.HOME || os28.homedir(), ".bluma", "coding_memory.json");
|
|
25685
25920
|
}
|
|
25686
25921
|
function normalizeNote2(note) {
|
|
25687
25922
|
return note.trim().toLowerCase().replace(/\s+/g, " ");
|
|
@@ -25691,18 +25926,18 @@ function uniqTags(a, b) {
|
|
|
25691
25926
|
}
|
|
25692
25927
|
function consolidateCodingMemoryFile() {
|
|
25693
25928
|
const p = memoryPath2();
|
|
25694
|
-
if (!
|
|
25929
|
+
if (!fs39.existsSync(p)) {
|
|
25695
25930
|
return { success: true, removedDuplicates: 0, message: "no coding_memory.json" };
|
|
25696
25931
|
}
|
|
25697
25932
|
const bak = `${p}.bak`;
|
|
25698
25933
|
try {
|
|
25699
|
-
|
|
25934
|
+
fs39.copyFileSync(p, bak);
|
|
25700
25935
|
} catch (e) {
|
|
25701
25936
|
return { success: false, removedDuplicates: 0, message: `backup failed: ${e.message}` };
|
|
25702
25937
|
}
|
|
25703
25938
|
let data;
|
|
25704
25939
|
try {
|
|
25705
|
-
data = JSON.parse(
|
|
25940
|
+
data = JSON.parse(fs39.readFileSync(p, "utf-8"));
|
|
25706
25941
|
} catch (e) {
|
|
25707
25942
|
return { success: false, removedDuplicates: 0, message: `invalid json: ${e.message}` };
|
|
25708
25943
|
}
|
|
@@ -25737,7 +25972,7 @@ function consolidateCodingMemoryFile() {
|
|
|
25737
25972
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
25738
25973
|
};
|
|
25739
25974
|
try {
|
|
25740
|
-
|
|
25975
|
+
fs39.writeFileSync(p, JSON.stringify(out, null, 2), "utf-8");
|
|
25741
25976
|
} catch (e) {
|
|
25742
25977
|
return { success: false, removedDuplicates: 0, message: `write failed: ${e.message}` };
|
|
25743
25978
|
}
|
|
@@ -26119,7 +26354,7 @@ var BluMaToolRunner = class {
|
|
|
26119
26354
|
if (toolName === "message") {
|
|
26120
26355
|
try {
|
|
26121
26356
|
const resultObj = typeof toolResultContent === "string" ? JSON.parse(toolResultContent) : toolResultContent;
|
|
26122
|
-
if (resultObj
|
|
26357
|
+
if (isMessageToolResultTerminal(resultObj)) {
|
|
26123
26358
|
await this.deps.notifyFactorTurnEndIfNeeded("message_result");
|
|
26124
26359
|
shouldContinueConversation = false;
|
|
26125
26360
|
this.deps.emitTurnCompleted();
|
|
@@ -26226,7 +26461,7 @@ var BluMaToolRunner = class {
|
|
|
26226
26461
|
if (p.toolName === "message") {
|
|
26227
26462
|
try {
|
|
26228
26463
|
const resultObj = typeof toolResultContent === "string" ? JSON.parse(toolResultContent) : toolResultContent;
|
|
26229
|
-
if (resultObj
|
|
26464
|
+
if (isMessageToolResultTerminal(resultObj)) {
|
|
26230
26465
|
await this.deps.notifyFactorTurnEndIfNeeded("message_result");
|
|
26231
26466
|
shouldContinue = false;
|
|
26232
26467
|
this.deps.emitTurnCompleted();
|
|
@@ -26440,6 +26675,9 @@ var ToolCallNormalizer = class {
|
|
|
26440
26675
|
}
|
|
26441
26676
|
};
|
|
26442
26677
|
|
|
26678
|
+
// src/app/agent/bluma/core/bluma_turn_coordinator.ts
|
|
26679
|
+
init_sandbox_policy();
|
|
26680
|
+
|
|
26443
26681
|
// src/app/agent/runtime/tool_orchestration.ts
|
|
26444
26682
|
var PARALLEL_SAFE_TOOL_NAMES = /* @__PURE__ */ new Set([
|
|
26445
26683
|
"ls_tool",
|
|
@@ -26649,12 +26887,22 @@ var BluMaTurnCoordinator = class {
|
|
|
26649
26887
|
this.deps.persistSession();
|
|
26650
26888
|
}
|
|
26651
26889
|
}
|
|
26652
|
-
|
|
26890
|
+
isSandboxBareAssistantText(hasToolCalls, trimmedText) {
|
|
26891
|
+
return getSandboxPolicy().isSandbox && !hasToolCalls && trimmedText.length > 0;
|
|
26892
|
+
}
|
|
26893
|
+
stripLastAssistantVisibleContent() {
|
|
26894
|
+
const last = this.deps.history[this.deps.history.length - 1];
|
|
26895
|
+
if (last?.role === "assistant") {
|
|
26896
|
+
last.content = null;
|
|
26897
|
+
}
|
|
26898
|
+
}
|
|
26899
|
+
async continueAfterAssistantReplyWithoutMessageTool(reason) {
|
|
26653
26900
|
this.emptyAssistantReplySteps += 1;
|
|
26654
26901
|
if (this.emptyAssistantReplySteps === 1) {
|
|
26902
|
+
const content = reason === "bare_text_sandbox" ? 'Sandbox: user-visible output must use the `message` tool. Plain assistant text is not shown and does not end the job. Call `message` with `message_type` "info" or "result".' : `You did not call any tool and produced no user-visible reply. Respond using the message tool with message_type "result". Keep it concise and in the user's language.`;
|
|
26655
26903
|
this.deps.history.push({
|
|
26656
26904
|
role: "system",
|
|
26657
|
-
content
|
|
26905
|
+
content
|
|
26658
26906
|
});
|
|
26659
26907
|
} else if (this.emptyAssistantReplySteps === 2) {
|
|
26660
26908
|
this.deps.history.push({
|
|
@@ -26673,6 +26921,14 @@ var BluMaTurnCoordinator = class {
|
|
|
26673
26921
|
}
|
|
26674
26922
|
await this.continueConversation();
|
|
26675
26923
|
}
|
|
26924
|
+
async continueAfterEmptyAssistantResponse() {
|
|
26925
|
+
await this.continueAfterAssistantReplyWithoutMessageTool("empty");
|
|
26926
|
+
}
|
|
26927
|
+
async continueAfterBareAssistantTextInSandbox() {
|
|
26928
|
+
this.stripLastAssistantVisibleContent();
|
|
26929
|
+
this.deps.persistSession();
|
|
26930
|
+
await this.continueAfterAssistantReplyWithoutMessageTool("bare_text_sandbox");
|
|
26931
|
+
}
|
|
26676
26932
|
async handleInvalidToolCallRetry(message2) {
|
|
26677
26933
|
this.invalidToolCallRetrySteps += 1;
|
|
26678
26934
|
if (this.deps.history[this.deps.history.length - 1] === message2) {
|
|
@@ -26812,6 +27068,10 @@ var BluMaTurnCoordinator = class {
|
|
|
26812
27068
|
});
|
|
26813
27069
|
}
|
|
26814
27070
|
} else if (trimmedText) {
|
|
27071
|
+
if (this.isSandboxBareAssistantText(hasToolCalls, trimmedText)) {
|
|
27072
|
+
await this.continueAfterBareAssistantTextInSandbox();
|
|
27073
|
+
return;
|
|
27074
|
+
}
|
|
26815
27075
|
this.emptyAssistantReplySteps = 0;
|
|
26816
27076
|
this.invalidToolCallRetrySteps = 0;
|
|
26817
27077
|
this.deps.eventBus.emit("backend_message", { type: "assistant_message", content: accumulatedContent });
|
|
@@ -26887,6 +27147,12 @@ var BluMaTurnCoordinator = class {
|
|
|
26887
27147
|
});
|
|
26888
27148
|
}
|
|
26889
27149
|
} else if (typeof message2.content === "string" && message2.content.trim()) {
|
|
27150
|
+
const trimmedText = message2.content.trim();
|
|
27151
|
+
const hasToolCalls = Boolean(message2.tool_calls && message2.tool_calls.length > 0);
|
|
27152
|
+
if (this.isSandboxBareAssistantText(hasToolCalls, trimmedText)) {
|
|
27153
|
+
await this.continueAfterBareAssistantTextInSandbox();
|
|
27154
|
+
return;
|
|
27155
|
+
}
|
|
26890
27156
|
this.emptyAssistantReplySteps = 0;
|
|
26891
27157
|
this.invalidToolCallRetrySteps = 0;
|
|
26892
27158
|
this.deps.eventBus.emit("backend_message", { type: "assistant_message", content: message2.content });
|
|
@@ -27030,13 +27296,13 @@ var BluMaAgent = class {
|
|
|
27030
27296
|
if (!this.sessionFile) return;
|
|
27031
27297
|
try {
|
|
27032
27298
|
const sessionData = {
|
|
27033
|
-
session_id:
|
|
27299
|
+
session_id: path41.basename(this.sessionFile, ".json"),
|
|
27034
27300
|
created_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
27035
27301
|
conversation_history: this.history,
|
|
27036
27302
|
last_updated: (/* @__PURE__ */ new Date()).toISOString(),
|
|
27037
27303
|
...this.compressor.getSnapshot()
|
|
27038
27304
|
};
|
|
27039
|
-
|
|
27305
|
+
fs40.writeFileSync(this.sessionFile, JSON.stringify(sessionData, null, 2), "utf-8");
|
|
27040
27306
|
} catch (error) {
|
|
27041
27307
|
console.error("[Bluma] Failed to persist session synchronously:", error);
|
|
27042
27308
|
}
|
|
@@ -27143,7 +27409,7 @@ var BluMaAgent = class {
|
|
|
27143
27409
|
*
|
|
27144
27410
|
* - `backend_message` `{ type: 'turn_start', turnId, sessionId, userPromptPreview }` — início;
|
|
27145
27411
|
* payload estável em {@link buildTurnStartBackendMessage}.
|
|
27146
|
-
* - Stream: `stream_start` / `stream_reasoning_chunk` / `stream_chunk` / `stream_end`.
|
|
27412
|
+
* - Stream: `stream_start` / `stream_reasoning_chunk` (one delta per chunk; agent mode logs `reasoning_chunk` JSONL) / `stream_chunk` / `stream_end`.
|
|
27147
27413
|
* Se a resposta incluir tool `message`, `stream_end` leva `{ omitAssistantFlush: true }` para não
|
|
27148
27414
|
* duplicar texto no histórico (o utilizador vê o `tool_result` com gutter). Ver `applyStreamEndFlush`.
|
|
27149
27415
|
* - Fim: `backend_message` `{ type: 'done', status }` (`completed` | `failed` | `interrupted` | …).
|
|
@@ -27237,7 +27503,7 @@ var BluMaAgent = class {
|
|
|
27237
27503
|
|
|
27238
27504
|
${editData.error.display}`;
|
|
27239
27505
|
}
|
|
27240
|
-
const filename =
|
|
27506
|
+
const filename = path41.basename(toolArgs.file_path);
|
|
27241
27507
|
return createDiff(filename, editData.currentContent || "", editData.newContent);
|
|
27242
27508
|
} catch (e) {
|
|
27243
27509
|
return `An unexpected error occurred while generating the edit preview: ${e.message}`;
|
|
@@ -27963,16 +28229,16 @@ async function fullCompact(messages, targetTokens, summarizer, llmClient) {
|
|
|
27963
28229
|
}
|
|
27964
28230
|
|
|
27965
28231
|
// src/app/agent/core/memory/session_memory.ts
|
|
27966
|
-
import
|
|
28232
|
+
import fs41 from "fs";
|
|
27967
28233
|
import os31 from "os";
|
|
27968
|
-
import
|
|
28234
|
+
import path42 from "path";
|
|
27969
28235
|
import { v4 as uuidv49 } from "uuid";
|
|
27970
28236
|
var SessionMemoryExtractor = class {
|
|
27971
28237
|
llmClient;
|
|
27972
28238
|
memoryFile;
|
|
27973
28239
|
constructor(options = {}) {
|
|
27974
28240
|
this.llmClient = options.llmClient;
|
|
27975
|
-
this.memoryFile = options.memoryFile ||
|
|
28241
|
+
this.memoryFile = options.memoryFile || path42.join(os31.homedir(), ".bluma", "session_memory.json");
|
|
27976
28242
|
}
|
|
27977
28243
|
/**
|
|
27978
28244
|
* Extract memories from conversation using LLM
|
|
@@ -28029,15 +28295,15 @@ ${messages.slice(-50).map((m) => `${m.role}: ${m.content.slice(0, 500)}`).join("
|
|
|
28029
28295
|
);
|
|
28030
28296
|
unique.sort((a, b) => b.accessCount - a.accessCount);
|
|
28031
28297
|
const trimmed = unique.slice(0, 200);
|
|
28032
|
-
|
|
28298
|
+
fs41.writeFileSync(this.memoryFile, JSON.stringify(trimmed, null, 2));
|
|
28033
28299
|
}
|
|
28034
28300
|
/**
|
|
28035
28301
|
* Load memories from disk
|
|
28036
28302
|
*/
|
|
28037
28303
|
async loadMemories() {
|
|
28038
28304
|
try {
|
|
28039
|
-
if (!
|
|
28040
|
-
const data =
|
|
28305
|
+
if (!fs41.existsSync(this.memoryFile)) return [];
|
|
28306
|
+
const data = fs41.readFileSync(this.memoryFile, "utf-8");
|
|
28041
28307
|
return JSON.parse(data);
|
|
28042
28308
|
} catch {
|
|
28043
28309
|
return [];
|
|
@@ -28581,14 +28847,14 @@ var RouteManager = class {
|
|
|
28581
28847
|
this.subAgents = subAgents;
|
|
28582
28848
|
this.core = core;
|
|
28583
28849
|
}
|
|
28584
|
-
registerRoute(
|
|
28585
|
-
this.routeHandlers.set(
|
|
28850
|
+
registerRoute(path51, handler) {
|
|
28851
|
+
this.routeHandlers.set(path51, handler);
|
|
28586
28852
|
}
|
|
28587
28853
|
async handleRoute(payload) {
|
|
28588
28854
|
const inputText = String(payload.content || "").trim();
|
|
28589
28855
|
const { userContext, options } = payload;
|
|
28590
|
-
for (const [
|
|
28591
|
-
if (inputText ===
|
|
28856
|
+
for (const [path51, handler] of this.routeHandlers) {
|
|
28857
|
+
if (inputText === path51 || inputText.startsWith(`${path51} `)) {
|
|
28592
28858
|
return handler({ content: inputText, userContext });
|
|
28593
28859
|
}
|
|
28594
28860
|
}
|
|
@@ -28597,13 +28863,13 @@ var RouteManager = class {
|
|
|
28597
28863
|
};
|
|
28598
28864
|
|
|
28599
28865
|
// src/app/agent/runtime/plugin_runtime.ts
|
|
28600
|
-
import
|
|
28866
|
+
import path43 from "path";
|
|
28601
28867
|
import { pathToFileURL as pathToFileURL2 } from "url";
|
|
28602
28868
|
async function loadPluginsAtStartup() {
|
|
28603
28869
|
for (const p of listPlugins()) {
|
|
28604
28870
|
const entry = p.manifest.entry?.trim();
|
|
28605
28871
|
if (!entry) continue;
|
|
28606
|
-
const abs =
|
|
28872
|
+
const abs = path43.resolve(p.root, entry);
|
|
28607
28873
|
try {
|
|
28608
28874
|
const href = pathToFileURL2(abs).href;
|
|
28609
28875
|
const mod = await import(href);
|
|
@@ -28624,7 +28890,7 @@ async function loadPluginsAtStartup() {
|
|
|
28624
28890
|
}
|
|
28625
28891
|
|
|
28626
28892
|
// src/app/agent/agent.ts
|
|
28627
|
-
var globalEnvPath =
|
|
28893
|
+
var globalEnvPath = path44.join(os32.homedir(), ".bluma", ".env");
|
|
28628
28894
|
dotenv.config({ path: globalEnvPath });
|
|
28629
28895
|
var Agent = class {
|
|
28630
28896
|
sessionId;
|
|
@@ -30480,10 +30746,10 @@ function resolveToolPayload(result) {
|
|
|
30480
30746
|
|
|
30481
30747
|
// src/app/ui/components/FilePathLink.tsx
|
|
30482
30748
|
import { pathToFileURL as pathToFileURL3 } from "node:url";
|
|
30483
|
-
import
|
|
30749
|
+
import path46 from "node:path";
|
|
30484
30750
|
|
|
30485
30751
|
// src/app/ui/utils/pathDisplay.ts
|
|
30486
|
-
import
|
|
30752
|
+
import path45 from "node:path";
|
|
30487
30753
|
import os33 from "node:os";
|
|
30488
30754
|
function formatPathForDisplay(pathInput, cwd2 = process.cwd()) {
|
|
30489
30755
|
let s = String(pathInput ?? "").trim();
|
|
@@ -30491,17 +30757,17 @@ function formatPathForDisplay(pathInput, cwd2 = process.cwd()) {
|
|
|
30491
30757
|
s = s.replace(/[/\\]+$/, "");
|
|
30492
30758
|
}
|
|
30493
30759
|
if (!s) return "";
|
|
30494
|
-
const abs =
|
|
30495
|
-
const resolvedCwd =
|
|
30496
|
-
const rel =
|
|
30497
|
-
if (rel === "" || !rel.startsWith("..") && !
|
|
30760
|
+
const abs = path45.isAbsolute(s) ? path45.normalize(s) : path45.resolve(cwd2, s);
|
|
30761
|
+
const resolvedCwd = path45.resolve(cwd2);
|
|
30762
|
+
const rel = path45.relative(resolvedCwd, abs);
|
|
30763
|
+
if (rel === "" || !rel.startsWith("..") && !path45.isAbsolute(rel)) {
|
|
30498
30764
|
return rel === "" ? "." : rel;
|
|
30499
30765
|
}
|
|
30500
|
-
const home =
|
|
30501
|
-
if (abs === home || abs.startsWith(home +
|
|
30766
|
+
const home = path45.normalize(os33.homedir());
|
|
30767
|
+
if (abs === home || abs.startsWith(home + path45.sep)) {
|
|
30502
30768
|
return "~" + abs.slice(home.length);
|
|
30503
30769
|
}
|
|
30504
|
-
return
|
|
30770
|
+
return path45.basename(abs);
|
|
30505
30771
|
}
|
|
30506
30772
|
|
|
30507
30773
|
// src/app/ui/components/FilePathLink.tsx
|
|
@@ -30511,7 +30777,7 @@ function FilePathLink({ filePath, children, cwd: cwd2 = process.cwd(), color })
|
|
|
30511
30777
|
if (!raw) {
|
|
30512
30778
|
return null;
|
|
30513
30779
|
}
|
|
30514
|
-
const abs =
|
|
30780
|
+
const abs = path46.isAbsolute(raw) ? path46.normalize(raw) : path46.resolve(cwd2, raw);
|
|
30515
30781
|
const href = pathToFileURL3(abs).href;
|
|
30516
30782
|
const label = formatPathForDisplay(abs, cwd2);
|
|
30517
30783
|
const text = typeof children === "string" ? children : label;
|
|
@@ -32463,12 +32729,12 @@ function patchToUnifiedDiffText(filePath, patch) {
|
|
|
32463
32729
|
}
|
|
32464
32730
|
|
|
32465
32731
|
// src/app/ui/utils/readEditContext.ts
|
|
32466
|
-
import { promises as
|
|
32732
|
+
import { promises as fs42 } from "fs";
|
|
32467
32733
|
var CHUNK_SIZE = 64 * 1024;
|
|
32468
32734
|
var CONTEXT_LINES2 = 3;
|
|
32469
32735
|
async function openForScan(filePath) {
|
|
32470
32736
|
try {
|
|
32471
|
-
return await
|
|
32737
|
+
return await fs42.open(filePath, "r");
|
|
32472
32738
|
} catch (e) {
|
|
32473
32739
|
if (e.code === "ENOENT") return null;
|
|
32474
32740
|
throw e;
|
|
@@ -33146,13 +33412,13 @@ function EditToolDiffPanel({
|
|
|
33146
33412
|
newString,
|
|
33147
33413
|
replaceAll = false
|
|
33148
33414
|
}) {
|
|
33149
|
-
const
|
|
33415
|
+
const path51 = filePath.trim() || "unknown file";
|
|
33150
33416
|
const hasPreviewArgs = oldString !== void 0 && newString !== void 0;
|
|
33151
33417
|
const hasDiffText = diffText && diffText.trim().length > 0;
|
|
33152
33418
|
return /* @__PURE__ */ jsx43(Box_default, { flexDirection: "column", children: hasPreviewArgs ? /* @__PURE__ */ jsx43(Box_default, { marginTop: 0, children: /* @__PURE__ */ jsx43(
|
|
33153
33419
|
FileEditToolDiff,
|
|
33154
33420
|
{
|
|
33155
|
-
filePath:
|
|
33421
|
+
filePath: path51,
|
|
33156
33422
|
oldString,
|
|
33157
33423
|
newString,
|
|
33158
33424
|
replaceAll,
|
|
@@ -33190,7 +33456,7 @@ function renderToolUseMessage12({ args }) {
|
|
|
33190
33456
|
return /* @__PURE__ */ jsx44(Text, { color: BLUMA_TERMINAL.blue, children: p });
|
|
33191
33457
|
}
|
|
33192
33458
|
function renderToolHeader12({ args }) {
|
|
33193
|
-
const
|
|
33459
|
+
const path51 = args?.file_path ?? ".";
|
|
33194
33460
|
const oldText = typeof args?.old_string === "string" ? args.old_string : "";
|
|
33195
33461
|
const newText = typeof args?.new_string === "string" ? args.new_string : "";
|
|
33196
33462
|
const counts = countLineDiff(oldText, newText);
|
|
@@ -33200,7 +33466,7 @@ function renderToolHeader12({ args }) {
|
|
|
33200
33466
|
action,
|
|
33201
33467
|
/* @__PURE__ */ jsxs27(Text, { dimColor: true, children: [
|
|
33202
33468
|
" ",
|
|
33203
|
-
/* @__PURE__ */ jsx44(FilePathLink, { filePath:
|
|
33469
|
+
/* @__PURE__ */ jsx44(FilePathLink, { filePath: path51, color: BLUMA_TERMINAL.dim })
|
|
33204
33470
|
] })
|
|
33205
33471
|
] }),
|
|
33206
33472
|
/* @__PURE__ */ jsxs27(Text, { dimColor: true, children: [
|
|
@@ -33592,11 +33858,11 @@ function userFacingName13() {
|
|
|
33592
33858
|
}
|
|
33593
33859
|
function renderToolUseMessage14({ args }) {
|
|
33594
33860
|
const q = args?.query ? `"${args.query}"` : "...";
|
|
33595
|
-
const
|
|
33861
|
+
const path51 = args?.path || ".";
|
|
33596
33862
|
return /* @__PURE__ */ jsxs30(Box_default, { flexDirection: "row", flexWrap: "wrap", alignItems: "flex-end", children: [
|
|
33597
33863
|
/* @__PURE__ */ jsx47(Text, { color: BLUMA_TERMINAL.blue, children: q }),
|
|
33598
33864
|
/* @__PURE__ */ jsx47(Text, { color: BLUMA_TERMINAL.dim, children: " " }),
|
|
33599
|
-
/* @__PURE__ */ jsx47(FilePathLink, { filePath:
|
|
33865
|
+
/* @__PURE__ */ jsx47(FilePathLink, { filePath: path51, color: BLUMA_TERMINAL.dim })
|
|
33600
33866
|
] });
|
|
33601
33867
|
}
|
|
33602
33868
|
function renderToolHeader14({ args }) {
|
|
@@ -34118,7 +34384,7 @@ var loadSkillTool = createTool({
|
|
|
34118
34384
|
});
|
|
34119
34385
|
|
|
34120
34386
|
// src/app/agent/tools/FileWriteTool/UI.tsx
|
|
34121
|
-
import
|
|
34387
|
+
import fs43 from "fs";
|
|
34122
34388
|
import { diffLines as diffLines3 } from "diff";
|
|
34123
34389
|
import { jsx as jsx54, jsxs as jsxs37 } from "react/jsx-runtime";
|
|
34124
34390
|
function getFilePath(args) {
|
|
@@ -34133,7 +34399,7 @@ function getFilePath(args) {
|
|
|
34133
34399
|
function readExistingFileText(filePath) {
|
|
34134
34400
|
if (!filePath) return "";
|
|
34135
34401
|
try {
|
|
34136
|
-
return
|
|
34402
|
+
return fs43.readFileSync(filePath, "utf-8");
|
|
34137
34403
|
} catch {
|
|
34138
34404
|
return "";
|
|
34139
34405
|
}
|
|
@@ -38847,9 +39113,9 @@ var renderCode = () => {
|
|
|
38847
39113
|
};
|
|
38848
39114
|
|
|
38849
39115
|
// src/app/agent/core/thread/thread_store.ts
|
|
38850
|
-
import
|
|
39116
|
+
import path47 from "path";
|
|
38851
39117
|
import os34 from "os";
|
|
38852
|
-
import { promises as
|
|
39118
|
+
import { promises as fs44 } from "fs";
|
|
38853
39119
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
38854
39120
|
var INDEX_VERSION = 1;
|
|
38855
39121
|
var fileLocks2 = /* @__PURE__ */ new Map();
|
|
@@ -38874,9 +39140,9 @@ var ThreadStore = class {
|
|
|
38874
39140
|
packageVersion;
|
|
38875
39141
|
constructor() {
|
|
38876
39142
|
const homeDir = os34.homedir();
|
|
38877
|
-
this.threadsDir =
|
|
38878
|
-
this.archiveDir =
|
|
38879
|
-
this.indexPath =
|
|
39143
|
+
this.threadsDir = path47.join(homeDir, ".bluma", "threads");
|
|
39144
|
+
this.archiveDir = path47.join(this.threadsDir, "archive");
|
|
39145
|
+
this.indexPath = path47.join(this.threadsDir, "index.json");
|
|
38880
39146
|
this.packageVersion = process.env.npm_package_version || "0.0.0";
|
|
38881
39147
|
}
|
|
38882
39148
|
// ==================== Inicialização ====================
|
|
@@ -38884,10 +39150,10 @@ var ThreadStore = class {
|
|
|
38884
39150
|
* Inicializa o diretório de threads
|
|
38885
39151
|
*/
|
|
38886
39152
|
async initialize() {
|
|
38887
|
-
await
|
|
38888
|
-
await
|
|
39153
|
+
await fs44.mkdir(this.threadsDir, { recursive: true });
|
|
39154
|
+
await fs44.mkdir(this.archiveDir, { recursive: true });
|
|
38889
39155
|
try {
|
|
38890
|
-
await
|
|
39156
|
+
await fs44.access(this.indexPath);
|
|
38891
39157
|
} catch {
|
|
38892
39158
|
await this.saveIndex({ version: INDEX_VERSION, threads: [], lastUpdated: (/* @__PURE__ */ new Date()).toISOString() });
|
|
38893
39159
|
}
|
|
@@ -38916,7 +39182,7 @@ var ThreadStore = class {
|
|
|
38916
39182
|
async loadIndex() {
|
|
38917
39183
|
return withFileLock2(this.indexPath, async () => {
|
|
38918
39184
|
try {
|
|
38919
|
-
const content = await
|
|
39185
|
+
const content = await fs44.readFile(this.indexPath, "utf-8");
|
|
38920
39186
|
return JSON.parse(content);
|
|
38921
39187
|
} catch {
|
|
38922
39188
|
return { version: INDEX_VERSION, threads: [], lastUpdated: (/* @__PURE__ */ new Date()).toISOString() };
|
|
@@ -38927,8 +39193,8 @@ var ThreadStore = class {
|
|
|
38927
39193
|
return withFileLock2(this.indexPath, async () => {
|
|
38928
39194
|
index.lastUpdated = (/* @__PURE__ */ new Date()).toISOString();
|
|
38929
39195
|
const tempPath = `${this.indexPath}.${Date.now()}.tmp`;
|
|
38930
|
-
await
|
|
38931
|
-
await
|
|
39196
|
+
await fs44.writeFile(tempPath, JSON.stringify(index, null, 2), "utf-8");
|
|
39197
|
+
await fs44.rename(tempPath, this.indexPath);
|
|
38932
39198
|
});
|
|
38933
39199
|
}
|
|
38934
39200
|
// ==================== Git Info ====================
|
|
@@ -39122,9 +39388,9 @@ var ThreadStore = class {
|
|
|
39122
39388
|
const entry = index.threads[entryIndex];
|
|
39123
39389
|
if (entry.status === "archived") return true;
|
|
39124
39390
|
const oldPath = this.getHistoryPath(threadId);
|
|
39125
|
-
const newPath =
|
|
39391
|
+
const newPath = path47.join(this.archiveDir, `${threadId}.jsonl`);
|
|
39126
39392
|
try {
|
|
39127
|
-
await
|
|
39393
|
+
await fs44.rename(oldPath, newPath);
|
|
39128
39394
|
} catch (e) {
|
|
39129
39395
|
if (e.code !== "ENOENT") throw e;
|
|
39130
39396
|
}
|
|
@@ -39145,10 +39411,10 @@ var ThreadStore = class {
|
|
|
39145
39411
|
if (entryIndex === -1) return false;
|
|
39146
39412
|
const entry = index.threads[entryIndex];
|
|
39147
39413
|
if (entry.status === "active") return true;
|
|
39148
|
-
const oldPath =
|
|
39414
|
+
const oldPath = path47.join(this.archiveDir, `${threadId}.jsonl`);
|
|
39149
39415
|
const newPath = this.getHistoryPath(threadId);
|
|
39150
39416
|
try {
|
|
39151
|
-
await
|
|
39417
|
+
await fs44.rename(oldPath, newPath);
|
|
39152
39418
|
} catch (e) {
|
|
39153
39419
|
if (e.code !== "ENOENT") throw e;
|
|
39154
39420
|
}
|
|
@@ -39169,7 +39435,7 @@ var ThreadStore = class {
|
|
|
39169
39435
|
if (entryIndex === -1) return false;
|
|
39170
39436
|
const entry = index.threads[entryIndex];
|
|
39171
39437
|
try {
|
|
39172
|
-
await
|
|
39438
|
+
await fs44.unlink(entry.historyPath);
|
|
39173
39439
|
} catch {
|
|
39174
39440
|
}
|
|
39175
39441
|
index.threads.splice(entryIndex, 1);
|
|
@@ -39179,7 +39445,7 @@ var ThreadStore = class {
|
|
|
39179
39445
|
}
|
|
39180
39446
|
// ==================== Histórico ====================
|
|
39181
39447
|
getHistoryPath(threadId) {
|
|
39182
|
-
return
|
|
39448
|
+
return path47.join(this.threadsDir, `${threadId}.jsonl`);
|
|
39183
39449
|
}
|
|
39184
39450
|
/**
|
|
39185
39451
|
* Guarda o histórico de uma thread
|
|
@@ -39196,7 +39462,7 @@ var ThreadStore = class {
|
|
|
39196
39462
|
for (const msg of history.messages) {
|
|
39197
39463
|
lines.push(JSON.stringify({ type: "message", ...msg }));
|
|
39198
39464
|
}
|
|
39199
|
-
await
|
|
39465
|
+
await fs44.writeFile(historyPath, lines.join("\n") + "\n", "utf-8");
|
|
39200
39466
|
}
|
|
39201
39467
|
/**
|
|
39202
39468
|
* Carrega o histórico de uma thread
|
|
@@ -39206,7 +39472,7 @@ var ThreadStore = class {
|
|
|
39206
39472
|
const entry = index.threads.find((t) => t.threadId === threadId);
|
|
39207
39473
|
if (!entry) return null;
|
|
39208
39474
|
try {
|
|
39209
|
-
const content = await
|
|
39475
|
+
const content = await fs44.readFile(entry.historyPath, "utf-8");
|
|
39210
39476
|
const lines = content.split("\n").filter(Boolean);
|
|
39211
39477
|
const history = {
|
|
39212
39478
|
threadId,
|
|
@@ -39239,7 +39505,7 @@ var ThreadStore = class {
|
|
|
39239
39505
|
const entry = index.threads.find((t) => t.threadId === threadId);
|
|
39240
39506
|
if (!entry) throw new Error(`Thread not found: ${threadId}`);
|
|
39241
39507
|
const lines = messages.map((msg) => JSON.stringify({ type: "message", ...msg }));
|
|
39242
|
-
await
|
|
39508
|
+
await fs44.appendFile(entry.historyPath, lines.join("\n") + "\n", "utf-8");
|
|
39243
39509
|
entry.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
39244
39510
|
await this.saveIndex(index);
|
|
39245
39511
|
}
|
|
@@ -42104,16 +42370,16 @@ import latestVersion from "latest-version";
|
|
|
42104
42370
|
import semverGt from "semver/functions/gt.js";
|
|
42105
42371
|
import semverValid from "semver/functions/valid.js";
|
|
42106
42372
|
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
42107
|
-
import
|
|
42108
|
-
import
|
|
42373
|
+
import path48 from "path";
|
|
42374
|
+
import fs45 from "fs";
|
|
42109
42375
|
var BLUMA_PACKAGE_NAME = "@nomad-e/bluma-cli";
|
|
42110
42376
|
function findBlumaPackageJson(startDir) {
|
|
42111
42377
|
let dir = startDir;
|
|
42112
42378
|
for (let i = 0; i < 12; i++) {
|
|
42113
|
-
const candidate =
|
|
42114
|
-
if (
|
|
42379
|
+
const candidate = path48.join(dir, "package.json");
|
|
42380
|
+
if (fs45.existsSync(candidate)) {
|
|
42115
42381
|
try {
|
|
42116
|
-
const raw =
|
|
42382
|
+
const raw = fs45.readFileSync(candidate, "utf8");
|
|
42117
42383
|
const parsed = JSON.parse(raw);
|
|
42118
42384
|
if (parsed?.name === BLUMA_PACKAGE_NAME && parsed?.version) {
|
|
42119
42385
|
return { name: parsed.name, version: String(parsed.version) };
|
|
@@ -42121,7 +42387,7 @@ function findBlumaPackageJson(startDir) {
|
|
|
42121
42387
|
} catch {
|
|
42122
42388
|
}
|
|
42123
42389
|
}
|
|
42124
|
-
const parent =
|
|
42390
|
+
const parent = path48.dirname(dir);
|
|
42125
42391
|
if (parent === dir) break;
|
|
42126
42392
|
dir = parent;
|
|
42127
42393
|
}
|
|
@@ -42130,13 +42396,13 @@ function findBlumaPackageJson(startDir) {
|
|
|
42130
42396
|
function resolveInstalledBlumaPackage() {
|
|
42131
42397
|
const tried = /* @__PURE__ */ new Set();
|
|
42132
42398
|
const tryFrom = (dir) => {
|
|
42133
|
-
const abs =
|
|
42399
|
+
const abs = path48.resolve(dir);
|
|
42134
42400
|
if (tried.has(abs)) return null;
|
|
42135
42401
|
tried.add(abs);
|
|
42136
42402
|
return findBlumaPackageJson(abs);
|
|
42137
42403
|
};
|
|
42138
42404
|
try {
|
|
42139
|
-
const fromBundle = tryFrom(
|
|
42405
|
+
const fromBundle = tryFrom(path48.dirname(fileURLToPath6(import.meta.url)));
|
|
42140
42406
|
if (fromBundle) return fromBundle;
|
|
42141
42407
|
} catch {
|
|
42142
42408
|
}
|
|
@@ -42144,12 +42410,12 @@ function resolveInstalledBlumaPackage() {
|
|
|
42144
42410
|
if (argv1 && !argv1.startsWith("-")) {
|
|
42145
42411
|
try {
|
|
42146
42412
|
let resolved = argv1;
|
|
42147
|
-
if (
|
|
42148
|
-
resolved =
|
|
42413
|
+
if (path48.isAbsolute(argv1) && fs45.existsSync(argv1)) {
|
|
42414
|
+
resolved = fs45.realpathSync(argv1);
|
|
42149
42415
|
} else {
|
|
42150
|
-
resolved =
|
|
42416
|
+
resolved = path48.resolve(process.cwd(), argv1);
|
|
42151
42417
|
}
|
|
42152
|
-
const fromArgv = tryFrom(
|
|
42418
|
+
const fromArgv = tryFrom(path48.dirname(resolved));
|
|
42153
42419
|
if (fromArgv) return fromArgv;
|
|
42154
42420
|
} catch {
|
|
42155
42421
|
}
|
|
@@ -42968,16 +43234,16 @@ function usePlanMode() {
|
|
|
42968
43234
|
|
|
42969
43235
|
// src/app/hooks/useAgentMode.ts
|
|
42970
43236
|
import { useState as useState22, useEffect as useEffect20, useCallback as useCallback9 } from "react";
|
|
42971
|
-
import * as
|
|
42972
|
-
import * as
|
|
43237
|
+
import * as fs46 from "fs";
|
|
43238
|
+
import * as path49 from "path";
|
|
42973
43239
|
import { homedir as homedir3 } from "os";
|
|
42974
|
-
var SETTINGS_PATH =
|
|
43240
|
+
var SETTINGS_PATH = path49.join(homedir3(), ".bluma", "settings.json");
|
|
42975
43241
|
function readAgentModeFromFile() {
|
|
42976
43242
|
try {
|
|
42977
|
-
if (!
|
|
43243
|
+
if (!fs46.existsSync(SETTINGS_PATH)) {
|
|
42978
43244
|
return "default";
|
|
42979
43245
|
}
|
|
42980
|
-
const content =
|
|
43246
|
+
const content = fs46.readFileSync(SETTINGS_PATH, "utf-8");
|
|
42981
43247
|
const settings = JSON.parse(content);
|
|
42982
43248
|
return settings.agentMode || "default";
|
|
42983
43249
|
} catch (error) {
|
|
@@ -42996,16 +43262,16 @@ function useAgentMode() {
|
|
|
42996
43262
|
}, []);
|
|
42997
43263
|
const updateAgentMode = useCallback9((mode) => {
|
|
42998
43264
|
try {
|
|
42999
|
-
if (!
|
|
43000
|
-
|
|
43265
|
+
if (!fs46.existsSync(SETTINGS_PATH)) {
|
|
43266
|
+
fs46.mkdirSync(path49.dirname(SETTINGS_PATH), { recursive: true });
|
|
43001
43267
|
}
|
|
43002
43268
|
let settings = {};
|
|
43003
|
-
if (
|
|
43004
|
-
const content =
|
|
43269
|
+
if (fs46.existsSync(SETTINGS_PATH)) {
|
|
43270
|
+
const content = fs46.readFileSync(SETTINGS_PATH, "utf-8");
|
|
43005
43271
|
settings = JSON.parse(content);
|
|
43006
43272
|
}
|
|
43007
43273
|
settings.agentMode = mode;
|
|
43008
|
-
|
|
43274
|
+
fs46.writeFileSync(SETTINGS_PATH, JSON.stringify(settings, null, 2), "utf-8");
|
|
43009
43275
|
setAgentMode(mode);
|
|
43010
43276
|
} catch (error) {
|
|
43011
43277
|
console.error("Failed to update agent mode:", error);
|
|
@@ -44261,9 +44527,9 @@ async function runAgentMode() {
|
|
|
44261
44527
|
try {
|
|
44262
44528
|
if (inputFileIndex !== -1 && args[inputFileIndex + 1]) {
|
|
44263
44529
|
const filePath = args[inputFileIndex + 1];
|
|
44264
|
-
rawPayload =
|
|
44530
|
+
rawPayload = fs47.readFileSync(filePath, "utf-8");
|
|
44265
44531
|
} else {
|
|
44266
|
-
rawPayload =
|
|
44532
|
+
rawPayload = fs47.readFileSync(0, "utf-8");
|
|
44267
44533
|
}
|
|
44268
44534
|
} catch (err) {
|
|
44269
44535
|
writeAgentEvent(registrySessionId, {
|
|
@@ -44300,6 +44566,12 @@ async function runAgentMode() {
|
|
|
44300
44566
|
process.env.BLUMA_SANDBOX_NAME = String(envelope.metadata.sandbox_name);
|
|
44301
44567
|
}
|
|
44302
44568
|
}
|
|
44569
|
+
const envelopeUserRequest = typeof envelope.context === "object" && envelope.context !== null ? String(
|
|
44570
|
+
envelope.context.user_request ?? envelope.context.userRequest ?? ""
|
|
44571
|
+
) : "";
|
|
44572
|
+
if (envelopeUserRequest.trim()) {
|
|
44573
|
+
process.env.BLUMA_USER_REQUEST = envelopeUserRequest.trim();
|
|
44574
|
+
}
|
|
44303
44575
|
const eventBus = new EventEmitter7();
|
|
44304
44576
|
const sessionId = registrySessionId || envelope.session_id || envelope.message_id || uuidv412();
|
|
44305
44577
|
process.env.BLUMA_SESSION_ID = sessionId;
|
|
@@ -44330,35 +44602,54 @@ async function runAgentMode() {
|
|
|
44330
44602
|
}
|
|
44331
44603
|
});
|
|
44332
44604
|
let lastAssistantMessage = null;
|
|
44333
|
-
let reasoningBuffer = null;
|
|
44334
44605
|
let lastAttachments = null;
|
|
44335
44606
|
let resultEmitted = false;
|
|
44336
44607
|
let agentRef = null;
|
|
44337
|
-
|
|
44608
|
+
let reasoningSequence = 0;
|
|
44609
|
+
const emitReasoningChunk = (delta, source) => {
|
|
44610
|
+
const text = String(delta ?? "");
|
|
44611
|
+
if (!text) return;
|
|
44612
|
+
reasoningSequence += 1;
|
|
44338
44613
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
44614
|
+
writeAgentEvent(sessionId, {
|
|
44615
|
+
event_type: "reasoning_chunk",
|
|
44616
|
+
timestamp,
|
|
44617
|
+
sequence: reasoningSequence,
|
|
44618
|
+
delta: text,
|
|
44619
|
+
source
|
|
44620
|
+
});
|
|
44339
44621
|
writeAgentEvent(sessionId, {
|
|
44340
44622
|
event_type: "backend_message",
|
|
44341
|
-
backend_type:
|
|
44623
|
+
backend_type: "reasoning_chunk",
|
|
44342
44624
|
timestamp,
|
|
44343
|
-
payload
|
|
44625
|
+
payload: { type: "reasoning_chunk", sequence: reasoningSequence, delta: text, source }
|
|
44344
44626
|
});
|
|
44627
|
+
};
|
|
44628
|
+
eventBus.on("backend_message", async (payload) => {
|
|
44629
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
44630
|
+
if (payload?.type === "reasoning" && typeof payload.content === "string") {
|
|
44631
|
+
emitReasoningChunk(payload.content, "message");
|
|
44632
|
+
} else {
|
|
44633
|
+
writeAgentEvent(sessionId, {
|
|
44634
|
+
event_type: "backend_message",
|
|
44635
|
+
backend_type: String(payload?.type || "unknown"),
|
|
44636
|
+
timestamp,
|
|
44637
|
+
payload
|
|
44638
|
+
});
|
|
44639
|
+
}
|
|
44345
44640
|
if (payload?.type === "assistant_message" && typeof payload.content === "string") {
|
|
44346
44641
|
lastAssistantMessage = payload.content;
|
|
44347
44642
|
}
|
|
44348
|
-
if (payload?.type === "reasoning" && typeof payload.content === "string") {
|
|
44349
|
-
if (!reasoningBuffer) {
|
|
44350
|
-
reasoningBuffer = payload.content;
|
|
44351
|
-
}
|
|
44352
|
-
}
|
|
44353
44643
|
if (payload?.type === "tool_result" && payload.tool_name === "message") {
|
|
44354
44644
|
try {
|
|
44355
44645
|
const rawResult = payload.result;
|
|
44356
44646
|
const parsed = typeof rawResult === "string" ? JSON.parse(rawResult) : rawResult;
|
|
44357
|
-
const
|
|
44647
|
+
const messagePayload = parsed?.data && typeof parsed.data === "object" ? parsed.data : parsed;
|
|
44648
|
+
const body = messagePayload?.content?.body;
|
|
44358
44649
|
if (typeof body === "string") {
|
|
44359
44650
|
lastAssistantMessage = body;
|
|
44360
44651
|
}
|
|
44361
|
-
const attachments =
|
|
44652
|
+
const attachments = messagePayload?.attachments;
|
|
44362
44653
|
if (Array.isArray(attachments)) {
|
|
44363
44654
|
lastAttachments = attachments.filter((p) => typeof p === "string");
|
|
44364
44655
|
}
|
|
@@ -44378,7 +44669,6 @@ async function runAgentMode() {
|
|
|
44378
44669
|
message_id: envelope.message_id || sessionId,
|
|
44379
44670
|
action: envelope.action || "unknown",
|
|
44380
44671
|
last_assistant_message: lastAssistantMessage,
|
|
44381
|
-
reasoning: reasoningBuffer,
|
|
44382
44672
|
attachments: lastAttachments
|
|
44383
44673
|
}
|
|
44384
44674
|
});
|
|
@@ -44394,7 +44684,7 @@ async function runAgentMode() {
|
|
|
44394
44684
|
});
|
|
44395
44685
|
});
|
|
44396
44686
|
eventBus.on("stream_reasoning_chunk", (payload) => {
|
|
44397
|
-
|
|
44687
|
+
emitReasoningChunk(payload?.delta || "", "stream");
|
|
44398
44688
|
});
|
|
44399
44689
|
writeAgentEvent(sessionId, {
|
|
44400
44690
|
event_type: "log",
|
|
@@ -44433,7 +44723,6 @@ async function runAgentMode() {
|
|
|
44433
44723
|
message_id: envelope.message_id || sessionId,
|
|
44434
44724
|
action: envelope.action || "unknown",
|
|
44435
44725
|
last_assistant_message: lastAssistantMessage,
|
|
44436
|
-
reasoning: reasoningBuffer,
|
|
44437
44726
|
attachments: lastAttachments
|
|
44438
44727
|
}
|
|
44439
44728
|
});
|
|
@@ -44461,9 +44750,9 @@ async function runAgentMode() {
|
|
|
44461
44750
|
}
|
|
44462
44751
|
function readCliPackageVersion() {
|
|
44463
44752
|
try {
|
|
44464
|
-
const base =
|
|
44465
|
-
const pkgPath =
|
|
44466
|
-
const j = JSON.parse(
|
|
44753
|
+
const base = path50.dirname(fileURLToPath7(import.meta.url));
|
|
44754
|
+
const pkgPath = path50.join(base, "..", "package.json");
|
|
44755
|
+
const j = JSON.parse(fs47.readFileSync(pkgPath, "utf8"));
|
|
44467
44756
|
return String(j.version || "0.0.0");
|
|
44468
44757
|
} catch {
|
|
44469
44758
|
return "0.0.0";
|
|
@@ -44589,7 +44878,7 @@ function startBackgroundAgent() {
|
|
|
44589
44878
|
process.exit(1);
|
|
44590
44879
|
}
|
|
44591
44880
|
const filePath = args[inputFileIndex + 1];
|
|
44592
|
-
const rawPayload =
|
|
44881
|
+
const rawPayload = fs47.readFileSync(filePath, "utf-8");
|
|
44593
44882
|
const envelope = JSON.parse(rawPayload);
|
|
44594
44883
|
const sessionId = envelope.session_id || envelope.message_id || uuidv412();
|
|
44595
44884
|
registerSession({
|