@nomad-e/bluma-cli 0.1.63 → 0.1.64
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 +1439 -252
- package/package.json +6 -1
package/dist/main.js
CHANGED
|
@@ -1720,10 +1720,10 @@ var init_themes = __esm({
|
|
|
1720
1720
|
import React19 from "react";
|
|
1721
1721
|
import { render } from "ink";
|
|
1722
1722
|
import { EventEmitter as EventEmitter4 } from "events";
|
|
1723
|
-
import
|
|
1724
|
-
import
|
|
1723
|
+
import fs37 from "fs";
|
|
1724
|
+
import path42 from "path";
|
|
1725
1725
|
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
1726
|
-
import { spawn as
|
|
1726
|
+
import { spawn as spawn6 } from "child_process";
|
|
1727
1727
|
import { v4 as uuidv412 } from "uuid";
|
|
1728
1728
|
|
|
1729
1729
|
// src/app/ui/App.tsx
|
|
@@ -2532,7 +2532,7 @@ var filterSlashCommands = (query) => {
|
|
|
2532
2532
|
let tier = 3;
|
|
2533
2533
|
let scorePrimary = 0;
|
|
2534
2534
|
let scoreSecondary = Number.MAX_SAFE_INTEGER;
|
|
2535
|
-
|
|
2535
|
+
const scoreTertiary = name.length;
|
|
2536
2536
|
if (isPrefix) {
|
|
2537
2537
|
tier = 0;
|
|
2538
2538
|
scorePrimary = q.length * -1;
|
|
@@ -4270,12 +4270,12 @@ function EditToolDiffPanel({
|
|
|
4270
4270
|
maxHeight = EDIT_DIFF_PREVIEW_MAX_LINES,
|
|
4271
4271
|
fallbackSnippet
|
|
4272
4272
|
}) {
|
|
4273
|
-
const
|
|
4273
|
+
const path43 = filePath.trim() || "unknown file";
|
|
4274
4274
|
const diff = diffText?.trim() ?? "";
|
|
4275
4275
|
return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", children: [
|
|
4276
4276
|
/* @__PURE__ */ jsx5(Box5, { flexDirection: "row", flexWrap: "wrap", children: /* @__PURE__ */ jsxs5(Text5, { color: isNewFile ? BLUMA_TERMINAL.success : void 0, children: [
|
|
4277
4277
|
isNewFile ? "Created " : "Wrote to ",
|
|
4278
|
-
/* @__PURE__ */ jsx5(Text5, { bold: true, children:
|
|
4278
|
+
/* @__PURE__ */ jsx5(Text5, { bold: true, children: path43 })
|
|
4279
4279
|
] }) }),
|
|
4280
4280
|
description ? /* @__PURE__ */ jsx5(Text5, { dimColor: true, wrap: "wrap", children: description }) : null,
|
|
4281
4281
|
diff.length > 0 ? /* @__PURE__ */ jsx5(Box5, { marginTop: 0, children: /* @__PURE__ */ jsx5(SimpleDiff, { text: diff, maxHeight, frame: true }) }) : fallbackSnippet ? /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", marginTop: 0, children: [
|
|
@@ -4604,7 +4604,7 @@ var renderFindByName = ({ args }) => {
|
|
|
4604
4604
|
var renderGrepSearch = ({ args }) => {
|
|
4605
4605
|
const parsed = parseArgs(args);
|
|
4606
4606
|
const query = parsed.query || "";
|
|
4607
|
-
const
|
|
4607
|
+
const path43 = parsed.path || ".";
|
|
4608
4608
|
return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "row", flexWrap: "wrap", children: [
|
|
4609
4609
|
/* @__PURE__ */ jsxs8(Text8, { color: BLUMA_TERMINAL.muted, children: [
|
|
4610
4610
|
'"',
|
|
@@ -4613,7 +4613,7 @@ var renderGrepSearch = ({ args }) => {
|
|
|
4613
4613
|
] }),
|
|
4614
4614
|
/* @__PURE__ */ jsxs8(Text8, { color: BLUMA_TERMINAL.m3OnSurface, bold: true, children: [
|
|
4615
4615
|
" ",
|
|
4616
|
-
|
|
4616
|
+
path43
|
|
4617
4617
|
] })
|
|
4618
4618
|
] });
|
|
4619
4619
|
};
|
|
@@ -5039,12 +5039,12 @@ var ConfirmationPrompt = memo4(ConfirmationPromptComponent);
|
|
|
5039
5039
|
|
|
5040
5040
|
// src/app/agent/agent.ts
|
|
5041
5041
|
import * as dotenv from "dotenv";
|
|
5042
|
-
import
|
|
5043
|
-
import
|
|
5042
|
+
import path40 from "path";
|
|
5043
|
+
import os27 from "os";
|
|
5044
5044
|
|
|
5045
5045
|
// src/app/agent/tool_invoker.ts
|
|
5046
|
-
import { promises as
|
|
5047
|
-
import
|
|
5046
|
+
import { promises as fs25 } from "fs";
|
|
5047
|
+
import path27 from "path";
|
|
5048
5048
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
5049
5049
|
|
|
5050
5050
|
// src/app/agent/tools/natives/edit.ts
|
|
@@ -5099,9 +5099,9 @@ function countOccurrences(text, search) {
|
|
|
5099
5099
|
return text.split(search).length - 1;
|
|
5100
5100
|
}
|
|
5101
5101
|
function ensureCorrectEdit(currentContent, originalOldString, originalNewString, expectedReplacements) {
|
|
5102
|
-
|
|
5103
|
-
|
|
5104
|
-
|
|
5102
|
+
const finalOldString = originalOldString;
|
|
5103
|
+
const finalNewString = originalNewString;
|
|
5104
|
+
const occurrences = countOccurrences(currentContent, finalOldString);
|
|
5105
5105
|
if (occurrences > 0) {
|
|
5106
5106
|
return [finalOldString, finalNewString, occurrences];
|
|
5107
5107
|
}
|
|
@@ -5258,7 +5258,7 @@ async function calculateEdit(filePath, oldString, newString, expectedReplacement
|
|
|
5258
5258
|
};
|
|
5259
5259
|
}
|
|
5260
5260
|
let currentContent = null;
|
|
5261
|
-
|
|
5261
|
+
const isNewFile = false;
|
|
5262
5262
|
try {
|
|
5263
5263
|
const stats = await fs6.stat(normalizedFilePath);
|
|
5264
5264
|
if (stats.size > MAX_FILE_SIZE) {
|
|
@@ -5706,7 +5706,7 @@ async function readLines(args) {
|
|
|
5706
5706
|
if (startIndex >= total_lines) {
|
|
5707
5707
|
throw new Error(`start_line (${startLine}) exceeds file length (${total_lines} lines).`);
|
|
5708
5708
|
}
|
|
5709
|
-
|
|
5709
|
+
const endIndex = Math.min(endLine, total_lines);
|
|
5710
5710
|
const contentLines = lines.slice(startIndex, endIndex);
|
|
5711
5711
|
let content = contentLines.join("\n");
|
|
5712
5712
|
if (args.line_number_prefix === true) {
|
|
@@ -6028,7 +6028,7 @@ var DEFAULT_IGNORE_PATTERNS = [
|
|
|
6028
6028
|
var MAX_RESULTS2 = 100;
|
|
6029
6029
|
var MAX_DEPTH_DEFAULT = 10;
|
|
6030
6030
|
function globToRegex(glob) {
|
|
6031
|
-
|
|
6031
|
+
const regex = glob.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*\*/g, "{{DOUBLESTAR}}").replace(/\*/g, "[^/]*").replace(/\?/g, ".").replace(/{{DOUBLESTAR}}/g, ".*");
|
|
6032
6032
|
return new RegExp(`^${regex}$`, "i");
|
|
6033
6033
|
}
|
|
6034
6034
|
function shouldIgnore(name, ignorePatterns, includeHidden) {
|
|
@@ -8913,7 +8913,7 @@ async function dream(args = {}) {
|
|
|
8913
8913
|
const used = /* @__PURE__ */ new Set();
|
|
8914
8914
|
for (let i = 0; i < entries.length; i++) {
|
|
8915
8915
|
if (used.has(entries[i].id)) continue;
|
|
8916
|
-
|
|
8916
|
+
const current = { ...entries[i] };
|
|
8917
8917
|
used.add(entries[i].id);
|
|
8918
8918
|
for (let j = i + 1; j < entries.length; j++) {
|
|
8919
8919
|
if (used.has(entries[j].id)) continue;
|
|
@@ -9188,6 +9188,1021 @@ async function context_collapse(args = {}) {
|
|
|
9188
9188
|
|
|
9189
9189
|
// src/app/agent/runtime/native_tool_catalog.ts
|
|
9190
9190
|
init_agent_coordination();
|
|
9191
|
+
|
|
9192
|
+
// src/app/agent/tools/natives/create-next-app.ts
|
|
9193
|
+
init_sandbox_policy();
|
|
9194
|
+
import { promises as fs23 } from "fs";
|
|
9195
|
+
import path25 from "path";
|
|
9196
|
+
|
|
9197
|
+
// src/app/agent/tools/natives/shell_command.ts
|
|
9198
|
+
init_sandbox_policy();
|
|
9199
|
+
import os15 from "os";
|
|
9200
|
+
import { spawn as spawn5 } from "child_process";
|
|
9201
|
+
var MAX_OUTPUT_SIZE2 = 3e4;
|
|
9202
|
+
var MAX_OUTPUT_LINES = 200;
|
|
9203
|
+
var OUTPUT_TRUNCATION_MESSAGE = "\n\n[OUTPUT TRUNCATED - use `| head -n X` or redirect to file for full output]";
|
|
9204
|
+
var DANGEROUS_PATTERNS = [
|
|
9205
|
+
// === ELEVAÇÃO DE PRIVILÉGIOS ===
|
|
9206
|
+
/^sudo\s+/i,
|
|
9207
|
+
// sudo commands
|
|
9208
|
+
/^doas\s+/i,
|
|
9209
|
+
// doas (BSD sudo alternative)
|
|
9210
|
+
/^su\s+/i,
|
|
9211
|
+
// switch user
|
|
9212
|
+
/^pkexec\s+/i,
|
|
9213
|
+
// PolicyKit execution
|
|
9214
|
+
/\|\s*sudo\s+/i,
|
|
9215
|
+
// piped to sudo
|
|
9216
|
+
/;\s*sudo\s+/i,
|
|
9217
|
+
// chained with sudo
|
|
9218
|
+
/&&\s*sudo\s+/i,
|
|
9219
|
+
// AND chained with sudo
|
|
9220
|
+
// === COMANDOS DESTRUTIVOS ===
|
|
9221
|
+
/\brm\s+(-[rf]+\s+)*[\/~]/i,
|
|
9222
|
+
// rm com paths perigosos (/, ~)
|
|
9223
|
+
/\brm\s+-[rf]*\s+\*/i,
|
|
9224
|
+
// rm -rf *
|
|
9225
|
+
/\bchmod\s+(777|666)\s+\//i,
|
|
9226
|
+
// chmod 777/666 em paths root
|
|
9227
|
+
/\bchown\s+.*\s+\//i,
|
|
9228
|
+
// chown em paths root
|
|
9229
|
+
/\bdd\s+.*of=\/dev\/(sd|hd|nvme)/i,
|
|
9230
|
+
// dd para discos
|
|
9231
|
+
/\bmkfs\./i,
|
|
9232
|
+
// format filesystem
|
|
9233
|
+
/>\s*\/dev\/(sd|hd|nvme)/i,
|
|
9234
|
+
// redirect para disco
|
|
9235
|
+
/\bshred\s+/i,
|
|
9236
|
+
// secure delete
|
|
9237
|
+
// === FORK BOMB / RESOURCE EXHAUSTION ===
|
|
9238
|
+
/:\(\)\s*\{\s*:\|:&\s*\}\s*;:/,
|
|
9239
|
+
// fork bomb clássico
|
|
9240
|
+
/\bwhile\s+true\s*;\s*do/i,
|
|
9241
|
+
// infinite loop
|
|
9242
|
+
/\byes\s+\|/i,
|
|
9243
|
+
// yes piped (resource exhaustion)
|
|
9244
|
+
// === NETWORK PERIGOSO ===
|
|
9245
|
+
/\bcurl\s+.*\|\s*(ba)?sh/i,
|
|
9246
|
+
// curl | bash (remote code exec)
|
|
9247
|
+
/\bwget\s+.*\|\s*(ba)?sh/i,
|
|
9248
|
+
// wget | bash
|
|
9249
|
+
/\bnc\s+-[el]/i
|
|
9250
|
+
// netcat listener (backdoor)
|
|
9251
|
+
];
|
|
9252
|
+
var INTERACTIVE_PATTERNS2 = [
|
|
9253
|
+
/^(vim|vi|nano|emacs|pico)\s*/i,
|
|
9254
|
+
// editors
|
|
9255
|
+
/^(less|more|most)\s*/i,
|
|
9256
|
+
// pagers
|
|
9257
|
+
/^(top|htop|btop|atop|nmon)\s*/i,
|
|
9258
|
+
// monitoring tools
|
|
9259
|
+
/^(ssh|telnet|ftp|sftp)\s+/i,
|
|
9260
|
+
// remote connections
|
|
9261
|
+
/^(mysql|psql|redis-cli|mongo|mongosh)\s*$/i,
|
|
9262
|
+
// database CLIs (sem script)
|
|
9263
|
+
/^(python|python3|node|ruby|irb|lua)\s*$/i,
|
|
9264
|
+
// REPLs sem script
|
|
9265
|
+
/^(gdb|lldb)\s*/i,
|
|
9266
|
+
// debuggers
|
|
9267
|
+
/^(bc|dc)\s*$/i
|
|
9268
|
+
// calculators
|
|
9269
|
+
];
|
|
9270
|
+
function shellCommand(args) {
|
|
9271
|
+
const {
|
|
9272
|
+
command,
|
|
9273
|
+
timeout = 300,
|
|
9274
|
+
// 5 minutos por padrão
|
|
9275
|
+
cwd = process.cwd(),
|
|
9276
|
+
verbose = false
|
|
9277
|
+
} = args;
|
|
9278
|
+
return new Promise((resolve2) => {
|
|
9279
|
+
const startTime = Date.now();
|
|
9280
|
+
const platform = os15.platform();
|
|
9281
|
+
const commandTrimmed = command.trim();
|
|
9282
|
+
let resolvedCwd;
|
|
9283
|
+
try {
|
|
9284
|
+
resolvedCwd = resolveCommandCwd(cwd);
|
|
9285
|
+
} catch (err) {
|
|
9286
|
+
const result = {
|
|
9287
|
+
status: "blocked",
|
|
9288
|
+
exitCode: null,
|
|
9289
|
+
stdout: "",
|
|
9290
|
+
stderr: `Command blocked: ${err.message}`,
|
|
9291
|
+
command,
|
|
9292
|
+
cwd,
|
|
9293
|
+
platform,
|
|
9294
|
+
duration: Date.now() - startTime,
|
|
9295
|
+
blockedReason: "sandbox_path_violation"
|
|
9296
|
+
};
|
|
9297
|
+
return resolve2(formatResult(result, verbose));
|
|
9298
|
+
}
|
|
9299
|
+
for (const pattern of DANGEROUS_PATTERNS) {
|
|
9300
|
+
if (pattern.test(commandTrimmed)) {
|
|
9301
|
+
const result = {
|
|
9302
|
+
status: "blocked",
|
|
9303
|
+
exitCode: null,
|
|
9304
|
+
stdout: "",
|
|
9305
|
+
stderr: `Command blocked: "${commandTrimmed}" requires elevated privileges (sudo/doas). These commands require interactive password input which cannot be handled. Alternatives:
|
|
9306
|
+
1. Run the command manually in terminal
|
|
9307
|
+
2. Configure passwordless sudo for this specific command
|
|
9308
|
+
3. Run BluMa as root (not recommended)`,
|
|
9309
|
+
command,
|
|
9310
|
+
cwd,
|
|
9311
|
+
platform,
|
|
9312
|
+
duration: Date.now() - startTime,
|
|
9313
|
+
blockedReason: "requires_sudo"
|
|
9314
|
+
};
|
|
9315
|
+
return resolve2(formatResult(result, verbose));
|
|
9316
|
+
}
|
|
9317
|
+
}
|
|
9318
|
+
for (const pattern of INTERACTIVE_PATTERNS2) {
|
|
9319
|
+
if (pattern.test(commandTrimmed)) {
|
|
9320
|
+
const result = {
|
|
9321
|
+
status: "blocked",
|
|
9322
|
+
exitCode: null,
|
|
9323
|
+
stdout: "",
|
|
9324
|
+
stderr: `Command blocked: "${commandTrimmed}" is an interactive command. Interactive commands require user input and cannot be handled by the agent. Alternatives:
|
|
9325
|
+
1. Use non-interactive alternatives (e.g., 'cat' instead of 'less')
|
|
9326
|
+
2. Run the command manually in terminal
|
|
9327
|
+
3. For editors, use edit_tool instead`,
|
|
9328
|
+
command,
|
|
9329
|
+
cwd,
|
|
9330
|
+
platform,
|
|
9331
|
+
duration: Date.now() - startTime,
|
|
9332
|
+
blockedReason: "interactive_command"
|
|
9333
|
+
};
|
|
9334
|
+
return resolve2(formatResult(result, verbose));
|
|
9335
|
+
}
|
|
9336
|
+
}
|
|
9337
|
+
let shellCmd;
|
|
9338
|
+
let shellArgs;
|
|
9339
|
+
if (platform === "win32") {
|
|
9340
|
+
shellCmd = process.env.COMSPEC || "cmd.exe";
|
|
9341
|
+
shellArgs = ["/c", command];
|
|
9342
|
+
} else {
|
|
9343
|
+
shellCmd = process.env.SHELL || "/bin/bash";
|
|
9344
|
+
shellArgs = ["-c", command];
|
|
9345
|
+
}
|
|
9346
|
+
let stdout = "";
|
|
9347
|
+
let stderr = "";
|
|
9348
|
+
let stdoutTruncated = false;
|
|
9349
|
+
let stderrTruncated = false;
|
|
9350
|
+
let timedOut = false;
|
|
9351
|
+
let finished = false;
|
|
9352
|
+
const childProcess = spawn5(shellCmd, shellArgs, {
|
|
9353
|
+
cwd: resolvedCwd,
|
|
9354
|
+
env: process.env,
|
|
9355
|
+
// Importante: no Windows, precisamos do shell, mas spawn já lida com isso
|
|
9356
|
+
windowsHide: true
|
|
9357
|
+
});
|
|
9358
|
+
const timeoutId = setTimeout(() => {
|
|
9359
|
+
if (!finished) {
|
|
9360
|
+
timedOut = true;
|
|
9361
|
+
childProcess.kill("SIGTERM");
|
|
9362
|
+
setTimeout(() => {
|
|
9363
|
+
if (!finished) {
|
|
9364
|
+
childProcess.kill("SIGKILL");
|
|
9365
|
+
}
|
|
9366
|
+
}, 2e3);
|
|
9367
|
+
}
|
|
9368
|
+
}, timeout * 1e3);
|
|
9369
|
+
if (childProcess.stdout) {
|
|
9370
|
+
childProcess.stdout.on("data", (data) => {
|
|
9371
|
+
if (!stdoutTruncated) {
|
|
9372
|
+
stdout += data.toString();
|
|
9373
|
+
if (stdout.length > MAX_OUTPUT_SIZE2) {
|
|
9374
|
+
stdout = stdout.substring(0, MAX_OUTPUT_SIZE2) + OUTPUT_TRUNCATION_MESSAGE;
|
|
9375
|
+
stdoutTruncated = true;
|
|
9376
|
+
}
|
|
9377
|
+
}
|
|
9378
|
+
});
|
|
9379
|
+
}
|
|
9380
|
+
if (childProcess.stderr) {
|
|
9381
|
+
childProcess.stderr.on("data", (data) => {
|
|
9382
|
+
if (!stderrTruncated) {
|
|
9383
|
+
stderr += data.toString();
|
|
9384
|
+
if (stderr.length > MAX_OUTPUT_SIZE2) {
|
|
9385
|
+
stderr = stderr.substring(0, MAX_OUTPUT_SIZE2) + OUTPUT_TRUNCATION_MESSAGE;
|
|
9386
|
+
stderrTruncated = true;
|
|
9387
|
+
}
|
|
9388
|
+
}
|
|
9389
|
+
});
|
|
9390
|
+
}
|
|
9391
|
+
childProcess.on("error", (error) => {
|
|
9392
|
+
if (!finished) {
|
|
9393
|
+
finished = true;
|
|
9394
|
+
clearTimeout(timeoutId);
|
|
9395
|
+
const result = {
|
|
9396
|
+
status: "error",
|
|
9397
|
+
exitCode: null,
|
|
9398
|
+
stdout: stdout.trim(),
|
|
9399
|
+
stderr: `Failed to execute command: ${error.message}`,
|
|
9400
|
+
command,
|
|
9401
|
+
cwd,
|
|
9402
|
+
platform,
|
|
9403
|
+
duration: Date.now() - startTime
|
|
9404
|
+
};
|
|
9405
|
+
resolve2(formatResult(result, verbose));
|
|
9406
|
+
}
|
|
9407
|
+
});
|
|
9408
|
+
childProcess.on("close", (code, signal) => {
|
|
9409
|
+
if (!finished) {
|
|
9410
|
+
finished = true;
|
|
9411
|
+
clearTimeout(timeoutId);
|
|
9412
|
+
const result = {
|
|
9413
|
+
status: timedOut ? "timeout" : code === 0 ? "success" : "error",
|
|
9414
|
+
exitCode: code,
|
|
9415
|
+
stdout: stdout.trim(),
|
|
9416
|
+
stderr: timedOut ? `Command timed out after ${timeout} seconds
|
|
9417
|
+
${stderr.trim()}` : stderr.trim(),
|
|
9418
|
+
command,
|
|
9419
|
+
cwd,
|
|
9420
|
+
platform,
|
|
9421
|
+
duration: Date.now() - startTime,
|
|
9422
|
+
truncated: stdoutTruncated || stderrTruncated
|
|
9423
|
+
};
|
|
9424
|
+
resolve2(formatResult(result, verbose));
|
|
9425
|
+
}
|
|
9426
|
+
});
|
|
9427
|
+
});
|
|
9428
|
+
}
|
|
9429
|
+
function smartTruncate(text) {
|
|
9430
|
+
if (!text) return { result: "", wasTruncated: false };
|
|
9431
|
+
let result = text;
|
|
9432
|
+
let wasTruncated = false;
|
|
9433
|
+
if (result.length > MAX_OUTPUT_SIZE2) {
|
|
9434
|
+
result = result.substring(0, MAX_OUTPUT_SIZE2);
|
|
9435
|
+
wasTruncated = true;
|
|
9436
|
+
}
|
|
9437
|
+
const lines = result.split("\n");
|
|
9438
|
+
if (lines.length > MAX_OUTPUT_LINES) {
|
|
9439
|
+
const head = lines.slice(0, 50);
|
|
9440
|
+
const tail = lines.slice(-50);
|
|
9441
|
+
result = head.join("\n") + `
|
|
9442
|
+
|
|
9443
|
+
... [${lines.length - 100} lines omitted] ...
|
|
9444
|
+
|
|
9445
|
+
` + tail.join("\n");
|
|
9446
|
+
wasTruncated = true;
|
|
9447
|
+
}
|
|
9448
|
+
return { result, wasTruncated };
|
|
9449
|
+
}
|
|
9450
|
+
function formatResult(result, verbose) {
|
|
9451
|
+
const stdout = smartTruncate(result.stdout);
|
|
9452
|
+
const stderr = smartTruncate(result.stderr);
|
|
9453
|
+
const wasTruncated = result.truncated || stdout.wasTruncated || stderr.wasTruncated;
|
|
9454
|
+
if (verbose) {
|
|
9455
|
+
return JSON.stringify({
|
|
9456
|
+
...result,
|
|
9457
|
+
stdout: stdout.result,
|
|
9458
|
+
stderr: stderr.result,
|
|
9459
|
+
truncated: wasTruncated
|
|
9460
|
+
}, null, 2);
|
|
9461
|
+
}
|
|
9462
|
+
const output = {
|
|
9463
|
+
status: result.status,
|
|
9464
|
+
exitCode: result.exitCode
|
|
9465
|
+
};
|
|
9466
|
+
if (stdout.result) {
|
|
9467
|
+
output.stdout = stdout.result;
|
|
9468
|
+
}
|
|
9469
|
+
if (stderr.result) {
|
|
9470
|
+
output.stderr = stderr.result;
|
|
9471
|
+
}
|
|
9472
|
+
if (result.status === "timeout") {
|
|
9473
|
+
output.message = `Command exceeded timeout of ${result.duration / 1e3}s`;
|
|
9474
|
+
}
|
|
9475
|
+
if (result.status === "blocked" && result.blockedReason) {
|
|
9476
|
+
output.blockedReason = result.blockedReason;
|
|
9477
|
+
}
|
|
9478
|
+
if (wasTruncated) {
|
|
9479
|
+
output.warning = "Output truncated (30KB / 200 lines max). Use `| head -n X` or redirect to file.";
|
|
9480
|
+
}
|
|
9481
|
+
return JSON.stringify(output, null, 2);
|
|
9482
|
+
}
|
|
9483
|
+
|
|
9484
|
+
// src/app/agent/tools/natives/create-next-app.ts
|
|
9485
|
+
var MINIMAL_FILES = {
|
|
9486
|
+
"package.json": `{
|
|
9487
|
+
"name": "{{NAME}}",
|
|
9488
|
+
"version": "0.1.0",
|
|
9489
|
+
"private": true,
|
|
9490
|
+
"scripts": {
|
|
9491
|
+
"dev": "next dev",
|
|
9492
|
+
"build": "next build",
|
|
9493
|
+
"start": "next start",
|
|
9494
|
+
"lint": "next lint"
|
|
9495
|
+
},
|
|
9496
|
+
"dependencies": {
|
|
9497
|
+
"next": "^14.1.0",
|
|
9498
|
+
"react": "^18.2.0",
|
|
9499
|
+
"react-dom": "^18.2.0"
|
|
9500
|
+
},
|
|
9501
|
+
"devDependencies": {
|
|
9502
|
+
"@types/node": "^20.11.0",
|
|
9503
|
+
"@types/react": "^18.2.0",
|
|
9504
|
+
"@types/react-dom": "^18.2.0",
|
|
9505
|
+
"typescript": "^5.3.0",
|
|
9506
|
+
"tailwindcss": "^3.4.0",
|
|
9507
|
+
"postcss": "^8.4.0",
|
|
9508
|
+
"autoprefixer": "^10.4.0",
|
|
9509
|
+
"eslint": "^8.56.0",
|
|
9510
|
+
"eslint-config-next": "^14.1.0"
|
|
9511
|
+
}
|
|
9512
|
+
}
|
|
9513
|
+
`,
|
|
9514
|
+
"tsconfig.json": `{
|
|
9515
|
+
"compilerOptions": {
|
|
9516
|
+
"lib": ["dom", "dom.iterable", "esnext"],
|
|
9517
|
+
"allowJs": true,
|
|
9518
|
+
"skipLibCheck": true,
|
|
9519
|
+
"strict": true,
|
|
9520
|
+
"noEmit": true,
|
|
9521
|
+
"esModuleInterop": true,
|
|
9522
|
+
"module": "esnext",
|
|
9523
|
+
"moduleResolution": "bundler",
|
|
9524
|
+
"resolveJsonModule": true,
|
|
9525
|
+
"isolatedModules": true,
|
|
9526
|
+
"jsx": "preserve",
|
|
9527
|
+
"incremental": true,
|
|
9528
|
+
"plugins": [
|
|
9529
|
+
{
|
|
9530
|
+
"name": "next"
|
|
9531
|
+
}
|
|
9532
|
+
],
|
|
9533
|
+
"paths": {
|
|
9534
|
+
"@/*": ["./*"]
|
|
9535
|
+
}
|
|
9536
|
+
},
|
|
9537
|
+
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
|
|
9538
|
+
"exclude": ["node_modules"]
|
|
9539
|
+
}
|
|
9540
|
+
`,
|
|
9541
|
+
"next.config.js": `/** @type {import('next').NextConfig} */
|
|
9542
|
+
const nextConfig = {
|
|
9543
|
+
output: 'standalone',
|
|
9544
|
+
reactStrictMode: true,
|
|
9545
|
+
}
|
|
9546
|
+
|
|
9547
|
+
module.exports = nextConfig
|
|
9548
|
+
`,
|
|
9549
|
+
"tailwind.config.ts": `import type { Config } from 'tailwindcss'
|
|
9550
|
+
|
|
9551
|
+
const config: Config = {
|
|
9552
|
+
content: [
|
|
9553
|
+
'./pages/**/*.{js,ts,jsx,tsx,mdx}',
|
|
9554
|
+
'./components/**/*.{js,ts,jsx,tsx,mdx}',
|
|
9555
|
+
'./app/**/*.{js,ts,jsx,tsx,mdx}',
|
|
9556
|
+
],
|
|
9557
|
+
theme: {
|
|
9558
|
+
extend: {
|
|
9559
|
+
backgroundImage: {
|
|
9560
|
+
'gradient-radial': 'radial-gradient(var(--tw-gradient-stops))',
|
|
9561
|
+
'gradient-conic':
|
|
9562
|
+
'conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))',
|
|
9563
|
+
},
|
|
9564
|
+
},
|
|
9565
|
+
},
|
|
9566
|
+
plugins: [],
|
|
9567
|
+
}
|
|
9568
|
+
export default config
|
|
9569
|
+
`,
|
|
9570
|
+
"postcss.config.js": `module.exports = {
|
|
9571
|
+
plugins: {
|
|
9572
|
+
tailwindcss: {},
|
|
9573
|
+
autoprefixer: {},
|
|
9574
|
+
},
|
|
9575
|
+
}
|
|
9576
|
+
`,
|
|
9577
|
+
".eslintrc.json": `{
|
|
9578
|
+
"extends": "next/core-web-vitals"
|
|
9579
|
+
}
|
|
9580
|
+
`,
|
|
9581
|
+
".gitignore": `# dependencies
|
|
9582
|
+
/node_modules
|
|
9583
|
+
/.pnp
|
|
9584
|
+
.pnp.js
|
|
9585
|
+
|
|
9586
|
+
# testing
|
|
9587
|
+
/coverage
|
|
9588
|
+
|
|
9589
|
+
# next.js
|
|
9590
|
+
/.next/
|
|
9591
|
+
/out/
|
|
9592
|
+
|
|
9593
|
+
# production
|
|
9594
|
+
/build
|
|
9595
|
+
|
|
9596
|
+
# misc
|
|
9597
|
+
.DS_Store
|
|
9598
|
+
*.pem
|
|
9599
|
+
|
|
9600
|
+
# debug
|
|
9601
|
+
npm-debug.log*
|
|
9602
|
+
yarn-debug.log*
|
|
9603
|
+
yarn-error.log*
|
|
9604
|
+
|
|
9605
|
+
# local env files
|
|
9606
|
+
.env*.local
|
|
9607
|
+
.env
|
|
9608
|
+
|
|
9609
|
+
# typescript
|
|
9610
|
+
*.tsbuildinfo
|
|
9611
|
+
next-env.d.ts
|
|
9612
|
+
`
|
|
9613
|
+
};
|
|
9614
|
+
var FULL_FILES = {
|
|
9615
|
+
...MINIMAL_FILES,
|
|
9616
|
+
// App Router structure
|
|
9617
|
+
"app/layout.tsx": `import type { Metadata } from "next";
|
|
9618
|
+
import { Inter } from "next/font/google";
|
|
9619
|
+
import "./globals.css";
|
|
9620
|
+
|
|
9621
|
+
const inter = Inter({ subsets: ["latin"] });
|
|
9622
|
+
|
|
9623
|
+
export const metadata: Metadata = {
|
|
9624
|
+
title: "{{NAME}}",
|
|
9625
|
+
description: "Generated by create-next-app",
|
|
9626
|
+
};
|
|
9627
|
+
|
|
9628
|
+
export default function RootLayout({
|
|
9629
|
+
children,
|
|
9630
|
+
}: Readonly<{
|
|
9631
|
+
children: React.ReactNode;
|
|
9632
|
+
}>) {
|
|
9633
|
+
return (
|
|
9634
|
+
<html lang="en">
|
|
9635
|
+
<body className={inter.className}>{children}</body>
|
|
9636
|
+
</html>
|
|
9637
|
+
);
|
|
9638
|
+
}
|
|
9639
|
+
`,
|
|
9640
|
+
"app/page.tsx": `export default function Home() {
|
|
9641
|
+
return (
|
|
9642
|
+
<main className="flex min-h-screen flex-col items-center justify-between p-24">
|
|
9643
|
+
<div className="z-10 w-full max-w-5xl items-center justify-between font-mono text-sm lg:flex">
|
|
9644
|
+
<p className="fixed left-0 top-0 flex w-full justify-center border-b border-gray-300 bg-gradient-to-b from-zinc-200 pb-6 pt-8 backdrop-blur-2xl dark:border-neutral-800 dark:bg-zinc-800/30 dark:from-inherit lg:static lg:w-auto lg:rounded-xl lg:border lg:bg-gray-200 lg:p-4 lg:dark:bg-zinc-800/30">
|
|
9645
|
+
Welcome to <code className="font-mono font-bold">{{NAME}}</code>
|
|
9646
|
+
</p>
|
|
9647
|
+
</div>
|
|
9648
|
+
|
|
9649
|
+
<div className="mb-32 grid text-center lg:max-w-5xl lg:w-full lg:mb-0 lg:grid-cols-4 lg:text-left">
|
|
9650
|
+
<a
|
|
9651
|
+
href="https://nextjs.org/docs"
|
|
9652
|
+
className="group rounded-lg border border-transparent px-5 py-4 transition-colors hover:border-gray-300 hover:bg-gray-100 hover:dark:border-neutral-700 hover:dark:bg-neutral-800/30"
|
|
9653
|
+
target="_blank"
|
|
9654
|
+
rel="noopener noreferrer"
|
|
9655
|
+
>
|
|
9656
|
+
<h2 className={\`mb-3 text-2xl font-semibold\`}>
|
|
9657
|
+
Docs{" "}
|
|
9658
|
+
<span className="inline-block transition-transform group-hover:translate-x-1 motion-reduce:transform-none">
|
|
9659
|
+
->
|
|
9660
|
+
</span>
|
|
9661
|
+
</h2>
|
|
9662
|
+
<p className={\`m-0 max-w-[30ch] text-sm opacity-50\`}>
|
|
9663
|
+
Find in-depth information about Next.js features and API.
|
|
9664
|
+
</p>
|
|
9665
|
+
</a>
|
|
9666
|
+
|
|
9667
|
+
<a
|
|
9668
|
+
href="https://nextjs.org/learn"
|
|
9669
|
+
className="group rounded-lg border border-transparent px-5 py-4 transition-colors hover:border-gray-300 hover:bg-gray-100 hover:dark:border-neutral-700 hover:dark:bg-neutral-800/30"
|
|
9670
|
+
target="_blank"
|
|
9671
|
+
rel="noopener noreferrer"
|
|
9672
|
+
>
|
|
9673
|
+
<h2 className={\`mb-3 text-2xl font-semibold\`}>
|
|
9674
|
+
Learn{" "}
|
|
9675
|
+
<span className="inline-block transition-transform group-hover:translate-x-1 motion-reduce:transform-none">
|
|
9676
|
+
->
|
|
9677
|
+
</span>
|
|
9678
|
+
</h2>
|
|
9679
|
+
<p className={\`m-0 max-w-[30ch] text-sm opacity-50\`}>
|
|
9680
|
+
Learn about Next.js in an interactive course with quizzes!
|
|
9681
|
+
</p>
|
|
9682
|
+
</a>
|
|
9683
|
+
|
|
9684
|
+
<a
|
|
9685
|
+
href="https://vercel.com/templates"
|
|
9686
|
+
className="group rounded-lg border border-transparent px-5 py-4 transition-colors hover:border-gray-300 hover:bg-gray-100 hover:dark:border-neutral-700 hover:dark:bg-neutral-800/30"
|
|
9687
|
+
target="_blank"
|
|
9688
|
+
rel="noopener noreferrer"
|
|
9689
|
+
>
|
|
9690
|
+
<h2 className={\`mb-3 text-2xl font-semibold\`}>
|
|
9691
|
+
Templates{" "}
|
|
9692
|
+
<span className="inline-block transition-transform group-hover:translate-x-1 motion-reduce:transform-none">
|
|
9693
|
+
->
|
|
9694
|
+
</span>
|
|
9695
|
+
</h2>
|
|
9696
|
+
<p className={\`m-0 max-w-[30ch] text-sm opacity-50\`}>
|
|
9697
|
+
Explore starter templates for Next.js.
|
|
9698
|
+
</p>
|
|
9699
|
+
</a>
|
|
9700
|
+
|
|
9701
|
+
<a
|
|
9702
|
+
href="https://vercel.com/new"
|
|
9703
|
+
className="group rounded-lg border border-transparent px-5 py-4 transition-colors hover:border-gray-300 hover:bg-gray-100 hover:dark:border-neutral-700 hover:dark:bg-neutral-800/30"
|
|
9704
|
+
target="_blank"
|
|
9705
|
+
rel="noopener noreferrer"
|
|
9706
|
+
>
|
|
9707
|
+
<h2 className={\`mb-3 text-2xl font-semibold\`}>
|
|
9708
|
+
Deploy{" "}
|
|
9709
|
+
<span className="inline-block transition-transform group-hover:translate-x-1 motion-reduce:transform-none">
|
|
9710
|
+
->
|
|
9711
|
+
</span>
|
|
9712
|
+
</h2>
|
|
9713
|
+
<p className={\`m-0 max-w-[30ch] text-sm opacity-50 text-balance\`}>
|
|
9714
|
+
Instantly deploy your Next.js site to a shareable URL with Vercel.
|
|
9715
|
+
</p>
|
|
9716
|
+
</a>
|
|
9717
|
+
</div>
|
|
9718
|
+
</main>
|
|
9719
|
+
);
|
|
9720
|
+
}
|
|
9721
|
+
`,
|
|
9722
|
+
"app/globals.css": `@tailwind base;
|
|
9723
|
+
@tailwind components;
|
|
9724
|
+
@tailwind utilities;
|
|
9725
|
+
|
|
9726
|
+
:root {
|
|
9727
|
+
--foreground-rgb: 0, 0, 0;
|
|
9728
|
+
--background-start-rgb: 214, 219, 220;
|
|
9729
|
+
--background-end-rgb: 255, 255, 255;
|
|
9730
|
+
}
|
|
9731
|
+
|
|
9732
|
+
@media (prefers-color-scheme: dark) {
|
|
9733
|
+
:root {
|
|
9734
|
+
--foreground-rgb: 255, 255, 255;
|
|
9735
|
+
--background-start-rgb: 0, 0, 0;
|
|
9736
|
+
--background-end-rgb: 0, 0, 0;
|
|
9737
|
+
}
|
|
9738
|
+
}
|
|
9739
|
+
|
|
9740
|
+
body {
|
|
9741
|
+
color: rgb(var(--foreground-rgb));
|
|
9742
|
+
background: linear-gradient(
|
|
9743
|
+
to bottom,
|
|
9744
|
+
transparent,
|
|
9745
|
+
rgb(var(--background-end-rgb))
|
|
9746
|
+
)
|
|
9747
|
+
rgb(var(--background-start-rgb));
|
|
9748
|
+
}
|
|
9749
|
+
|
|
9750
|
+
@layer utilities {
|
|
9751
|
+
.text-balance {
|
|
9752
|
+
text-wrap: balance;
|
|
9753
|
+
}
|
|
9754
|
+
}
|
|
9755
|
+
`,
|
|
9756
|
+
// shadcn/ui base components
|
|
9757
|
+
"components/ui/button.tsx": `import * as React from "react"
|
|
9758
|
+
import { cva, type VariantProps } from "class-variance-authority"
|
|
9759
|
+
import { cn } from "@/lib/utils"
|
|
9760
|
+
|
|
9761
|
+
const buttonVariants = cva(
|
|
9762
|
+
"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
|
|
9763
|
+
{
|
|
9764
|
+
variants: {
|
|
9765
|
+
variant: {
|
|
9766
|
+
default: "bg-primary text-primary-foreground hover:bg-primary/90",
|
|
9767
|
+
destructive:
|
|
9768
|
+
"bg-destructive text-destructive-foreground hover:bg-destructive/90",
|
|
9769
|
+
outline:
|
|
9770
|
+
"border border-input bg-background hover:bg-accent hover:text-accent-foreground",
|
|
9771
|
+
secondary:
|
|
9772
|
+
"bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
|
9773
|
+
ghost: "hover:bg-accent hover:text-accent-foreground",
|
|
9774
|
+
link: "text-primary underline-offset-4 hover:underline",
|
|
9775
|
+
},
|
|
9776
|
+
size: {
|
|
9777
|
+
default: "h-10 px-4 py-2",
|
|
9778
|
+
sm: "h-9 rounded-md px-3",
|
|
9779
|
+
lg: "h-11 rounded-md px-8",
|
|
9780
|
+
icon: "h-10 w-10",
|
|
9781
|
+
},
|
|
9782
|
+
},
|
|
9783
|
+
defaultVariants: {
|
|
9784
|
+
variant: "default",
|
|
9785
|
+
size: "default",
|
|
9786
|
+
},
|
|
9787
|
+
}
|
|
9788
|
+
)
|
|
9789
|
+
|
|
9790
|
+
export interface ButtonProps
|
|
9791
|
+
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
|
|
9792
|
+
VariantProps<typeof buttonVariants> {
|
|
9793
|
+
asChild?: boolean
|
|
9794
|
+
}
|
|
9795
|
+
|
|
9796
|
+
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
|
9797
|
+
({ className, variant, size, asChild = false, ...props }, ref) => {
|
|
9798
|
+
const Comp = asChild ? Slot : "button"
|
|
9799
|
+
return (
|
|
9800
|
+
<Comp
|
|
9801
|
+
className={cn(buttonVariants({ variant, size, className }))}
|
|
9802
|
+
ref={ref}
|
|
9803
|
+
{...props}
|
|
9804
|
+
/>
|
|
9805
|
+
)
|
|
9806
|
+
}
|
|
9807
|
+
)
|
|
9808
|
+
Button.displayName = "Button"
|
|
9809
|
+
|
|
9810
|
+
export { Button, buttonVariants }
|
|
9811
|
+
`,
|
|
9812
|
+
"components/ui/card.tsx": `import * as React from "react"
|
|
9813
|
+
import { cn } from "@/lib/utils"
|
|
9814
|
+
|
|
9815
|
+
const Card = React.forwardRef<
|
|
9816
|
+
HTMLDivElement,
|
|
9817
|
+
React.HTMLAttributes<HTMLDivElement>
|
|
9818
|
+
>(({ className, ...props }, ref) => (
|
|
9819
|
+
<div
|
|
9820
|
+
ref={ref}
|
|
9821
|
+
className={cn(
|
|
9822
|
+
"rounded-lg border bg-card text-card-foreground shadow-sm",
|
|
9823
|
+
className
|
|
9824
|
+
)}
|
|
9825
|
+
{...props}
|
|
9826
|
+
/>
|
|
9827
|
+
))
|
|
9828
|
+
Card.displayName = "Card"
|
|
9829
|
+
|
|
9830
|
+
const CardHeader = React.forwardRef<
|
|
9831
|
+
HTMLDivElement,
|
|
9832
|
+
React.HTMLAttributes<HTMLDivElement>
|
|
9833
|
+
>(({ className, ...props }, ref) => (
|
|
9834
|
+
<div
|
|
9835
|
+
ref={ref}
|
|
9836
|
+
className={cn("flex flex-col space-y-1.5 p-6", className)}
|
|
9837
|
+
{...props}
|
|
9838
|
+
/>
|
|
9839
|
+
))
|
|
9840
|
+
CardHeader.displayName = "CardHeader"
|
|
9841
|
+
|
|
9842
|
+
const CardTitle = React.forwardRef<
|
|
9843
|
+
HTMLParagraphElement,
|
|
9844
|
+
React.HTMLAttributes<HTMLHeadingElement>
|
|
9845
|
+
>(({ className, ...props }, ref) => (
|
|
9846
|
+
<h3
|
|
9847
|
+
ref={ref}
|
|
9848
|
+
className={cn(
|
|
9849
|
+
"text-2xl font-semibold leading-none tracking-tight",
|
|
9850
|
+
className
|
|
9851
|
+
)}
|
|
9852
|
+
{...props}
|
|
9853
|
+
/>
|
|
9854
|
+
))
|
|
9855
|
+
CardTitle.displayName = "CardTitle"
|
|
9856
|
+
|
|
9857
|
+
const CardDescription = React.forwardRef<
|
|
9858
|
+
HTMLParagraphElement,
|
|
9859
|
+
React.HTMLAttributes<HTMLParagraphElement>
|
|
9860
|
+
>(({ className, ...props }, ref) => (
|
|
9861
|
+
<p
|
|
9862
|
+
ref={ref}
|
|
9863
|
+
className={cn("text-sm text-muted-foreground", className)}
|
|
9864
|
+
{...props}
|
|
9865
|
+
/>
|
|
9866
|
+
))
|
|
9867
|
+
CardDescription.displayName = "CardDescription"
|
|
9868
|
+
|
|
9869
|
+
const CardContent = React.forwardRef<
|
|
9870
|
+
HTMLDivElement,
|
|
9871
|
+
React.HTMLAttributes<HTMLDivElement>
|
|
9872
|
+
>(({ className, ...props }, ref) => (
|
|
9873
|
+
<div ref={ref} className={cn("p-6 pt-0", className)} {...props} />
|
|
9874
|
+
))
|
|
9875
|
+
CardContent.displayName = "CardContent"
|
|
9876
|
+
|
|
9877
|
+
const CardFooter = React.forwardRef<
|
|
9878
|
+
HTMLDivElement,
|
|
9879
|
+
React.HTMLAttributes<HTMLDivElement>
|
|
9880
|
+
>(({ className, ...props }, ref) => (
|
|
9881
|
+
<div
|
|
9882
|
+
ref={ref}
|
|
9883
|
+
className={cn("flex items-center p-6 pt-0", className)}
|
|
9884
|
+
{...props}
|
|
9885
|
+
/>
|
|
9886
|
+
))
|
|
9887
|
+
CardFooter.displayName = "CardFooter"
|
|
9888
|
+
|
|
9889
|
+
export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent }
|
|
9890
|
+
`,
|
|
9891
|
+
"components/ui/input.tsx": `import * as React from "react"
|
|
9892
|
+
import { cn } from "@/lib/utils"
|
|
9893
|
+
|
|
9894
|
+
export interface InputProps
|
|
9895
|
+
extends React.InputHTMLAttributes<HTMLInputElement> {}
|
|
9896
|
+
|
|
9897
|
+
const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
|
9898
|
+
({ className, type, ...props }, ref) => {
|
|
9899
|
+
return (
|
|
9900
|
+
<input
|
|
9901
|
+
type={type}
|
|
9902
|
+
className={cn(
|
|
9903
|
+
"flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
|
|
9904
|
+
className
|
|
9905
|
+
)}
|
|
9906
|
+
ref={ref}
|
|
9907
|
+
{...props}
|
|
9908
|
+
/>
|
|
9909
|
+
)
|
|
9910
|
+
}
|
|
9911
|
+
)
|
|
9912
|
+
Input.displayName = "Input"
|
|
9913
|
+
|
|
9914
|
+
export { Input }
|
|
9915
|
+
`,
|
|
9916
|
+
"lib/utils.ts": `import { type ClassValue, clsx } from "clsx"
|
|
9917
|
+
import { twMerge } from "tailwind-merge"
|
|
9918
|
+
|
|
9919
|
+
export function cn(...inputs: ClassValue[]) {
|
|
9920
|
+
return twMerge(clsx(inputs))
|
|
9921
|
+
}
|
|
9922
|
+
`,
|
|
9923
|
+
// Add clsx and tailwind-merge to package.json dependencies
|
|
9924
|
+
"package.json.full": `{
|
|
9925
|
+
"name": "{{NAME}}",
|
|
9926
|
+
"version": "0.1.0",
|
|
9927
|
+
"private": true,
|
|
9928
|
+
"scripts": {
|
|
9929
|
+
"dev": "next dev",
|
|
9930
|
+
"build": "next build",
|
|
9931
|
+
"start": "next start",
|
|
9932
|
+
"lint": "next lint"
|
|
9933
|
+
},
|
|
9934
|
+
"dependencies": {
|
|
9935
|
+
"next": "^14.1.0",
|
|
9936
|
+
"react": "^18.2.0",
|
|
9937
|
+
"react-dom": "^18.2.0",
|
|
9938
|
+
"class-variance-authority": "^0.7.0",
|
|
9939
|
+
"clsx": "^2.1.0",
|
|
9940
|
+
"tailwind-merge": "^2.2.0"
|
|
9941
|
+
},
|
|
9942
|
+
"devDependencies": {
|
|
9943
|
+
"@types/node": "^20.11.0",
|
|
9944
|
+
"@types/react": "^18.2.0",
|
|
9945
|
+
"@types/react-dom": "^18.2.0",
|
|
9946
|
+
"typescript": "^5.3.0",
|
|
9947
|
+
"tailwindcss": "^3.4.0",
|
|
9948
|
+
"postcss": "^8.4.0",
|
|
9949
|
+
"autoprefixer": "^10.4.0",
|
|
9950
|
+
"eslint": "^8.56.0",
|
|
9951
|
+
"eslint-config-next": "^14.1.0"
|
|
9952
|
+
}
|
|
9953
|
+
}
|
|
9954
|
+
`
|
|
9955
|
+
};
|
|
9956
|
+
async function createFile(filePath, content, projectName) {
|
|
9957
|
+
const dir = path25.dirname(filePath);
|
|
9958
|
+
await fs23.mkdir(dir, { recursive: true });
|
|
9959
|
+
const replacedContent = content.replace(/{{NAME}}/g, projectName);
|
|
9960
|
+
await fs23.writeFile(filePath, replacedContent, "utf-8");
|
|
9961
|
+
}
|
|
9962
|
+
async function createNextApp(args) {
|
|
9963
|
+
const {
|
|
9964
|
+
name,
|
|
9965
|
+
directory,
|
|
9966
|
+
template = "full"
|
|
9967
|
+
} = args;
|
|
9968
|
+
try {
|
|
9969
|
+
if (!name || typeof name !== "string") {
|
|
9970
|
+
return { success: false, error: "name is required and must be a string" };
|
|
9971
|
+
}
|
|
9972
|
+
if (!/^[a-z0-9-_]+$/.test(name)) {
|
|
9973
|
+
return {
|
|
9974
|
+
success: false,
|
|
9975
|
+
error: "name must contain only lowercase letters, numbers, hyphens, and underscores"
|
|
9976
|
+
};
|
|
9977
|
+
}
|
|
9978
|
+
const baseDir = directory ? resolveWorkspacePath(directory) : resolveWorkspacePath(".");
|
|
9979
|
+
const projectPath = path25.join(baseDir, name);
|
|
9980
|
+
try {
|
|
9981
|
+
await fs23.access(projectPath);
|
|
9982
|
+
return {
|
|
9983
|
+
success: false,
|
|
9984
|
+
error: `Directory already exists: ${projectPath}. Remove it first or choose a different name.`
|
|
9985
|
+
};
|
|
9986
|
+
} catch {
|
|
9987
|
+
}
|
|
9988
|
+
await fs23.mkdir(projectPath, { recursive: true });
|
|
9989
|
+
const filesToCreate = template === "minimal" ? MINIMAL_FILES : FULL_FILES;
|
|
9990
|
+
const filesCreated = [];
|
|
9991
|
+
for (const [relativePath, content] of Object.entries(filesToCreate)) {
|
|
9992
|
+
if (relativePath === "package.json.full") continue;
|
|
9993
|
+
const fullPath = path25.join(projectPath, relativePath);
|
|
9994
|
+
await createFile(fullPath, content, name);
|
|
9995
|
+
filesCreated.push(relativePath);
|
|
9996
|
+
}
|
|
9997
|
+
if (template === "full") {
|
|
9998
|
+
const packageJsonPath = path25.join(projectPath, "package.json");
|
|
9999
|
+
const fullPackageJson = FULL_FILES["package.json.full"];
|
|
10000
|
+
if (fullPackageJson) {
|
|
10001
|
+
await createFile(packageJsonPath, fullPackageJson, name);
|
|
10002
|
+
}
|
|
10003
|
+
}
|
|
10004
|
+
console.log(`[create-next-app] Installing dependencies in ${projectPath}...`);
|
|
10005
|
+
const installResult = await shellCommand({
|
|
10006
|
+
command: "npm install",
|
|
10007
|
+
cwd: projectPath,
|
|
10008
|
+
timeout: 300
|
|
10009
|
+
// 5 minutos
|
|
10010
|
+
});
|
|
10011
|
+
const installJson = JSON.parse(installResult);
|
|
10012
|
+
if (installJson.status !== "success") {
|
|
10013
|
+
console.warn("[create-next-app] npm install warnings:", installJson.stderr);
|
|
10014
|
+
}
|
|
10015
|
+
const nextSteps = [
|
|
10016
|
+
`cd ${name}`,
|
|
10017
|
+
"npm run dev",
|
|
10018
|
+
"Open http://localhost:3000",
|
|
10019
|
+
template === "full" ? "Components shadcn/ui dispon\xEDveis em components/ui/" : "Adicione componentes conforme necess\xE1rio"
|
|
10020
|
+
];
|
|
10021
|
+
console.log(`[create-next-app] Projeto criado: ${projectPath}`);
|
|
10022
|
+
return {
|
|
10023
|
+
success: true,
|
|
10024
|
+
projectPath,
|
|
10025
|
+
directory: name,
|
|
10026
|
+
filesCreated,
|
|
10027
|
+
nextSteps
|
|
10028
|
+
};
|
|
10029
|
+
} catch (error) {
|
|
10030
|
+
console.error("[create-next-app] Error:", error.message);
|
|
10031
|
+
return {
|
|
10032
|
+
success: false,
|
|
10033
|
+
error: error.message || String(error)
|
|
10034
|
+
};
|
|
10035
|
+
}
|
|
10036
|
+
}
|
|
10037
|
+
|
|
10038
|
+
// src/app/agent/tools/natives/deploy-app.ts
|
|
10039
|
+
init_sandbox_policy();
|
|
10040
|
+
import { promises as fs24 } from "fs";
|
|
10041
|
+
import path26 from "path";
|
|
10042
|
+
var EXCLUDE_PATTERNS = [
|
|
10043
|
+
"node_modules",
|
|
10044
|
+
".next",
|
|
10045
|
+
".git",
|
|
10046
|
+
".gitignore",
|
|
10047
|
+
"dist",
|
|
10048
|
+
"build",
|
|
10049
|
+
"*.log",
|
|
10050
|
+
".DS_Store",
|
|
10051
|
+
".env.local",
|
|
10052
|
+
".env*.local",
|
|
10053
|
+
"coverage",
|
|
10054
|
+
".vercel",
|
|
10055
|
+
".turbo"
|
|
10056
|
+
];
|
|
10057
|
+
async function createProjectZip(projectDir, zipPath) {
|
|
10058
|
+
const excludes = [];
|
|
10059
|
+
for (const pattern of EXCLUDE_PATTERNS) {
|
|
10060
|
+
excludes.push("--exclude", pattern);
|
|
10061
|
+
}
|
|
10062
|
+
const zipCommand = `zip -r "${zipPath}" . ${excludes.join(" ")}`;
|
|
10063
|
+
const result = await shellCommand({
|
|
10064
|
+
command: zipCommand,
|
|
10065
|
+
cwd: projectDir,
|
|
10066
|
+
timeout: 120
|
|
10067
|
+
// 2 minutos para zippar
|
|
10068
|
+
});
|
|
10069
|
+
const resultJson = JSON.parse(result);
|
|
10070
|
+
if (resultJson.status !== "success") {
|
|
10071
|
+
throw new Error(`Failed to create ZIP: ${resultJson.stderr}`);
|
|
10072
|
+
}
|
|
10073
|
+
return zipPath;
|
|
10074
|
+
}
|
|
10075
|
+
async function uploadToSeverino(zipPath, severinoUrl, name, apiKey) {
|
|
10076
|
+
const deployUrl = `${severinoUrl.replace(/\/$/, "")}/api/v1/deploy`;
|
|
10077
|
+
const curlArgs = [
|
|
10078
|
+
"-X",
|
|
10079
|
+
"POST",
|
|
10080
|
+
deployUrl,
|
|
10081
|
+
"-F",
|
|
10082
|
+
`file=@${zipPath}`
|
|
10083
|
+
];
|
|
10084
|
+
if (name) {
|
|
10085
|
+
curlArgs.push("-F", `name=${name}`);
|
|
10086
|
+
}
|
|
10087
|
+
if (apiKey) {
|
|
10088
|
+
curlArgs.push("-H", `Authorization: Bearer ${apiKey}`);
|
|
10089
|
+
curlArgs.push("-H", `X-API-Key: ${apiKey}`);
|
|
10090
|
+
}
|
|
10091
|
+
curlArgs.push("-H", "Accept: application/json");
|
|
10092
|
+
const curlCommand = `curl ${curlArgs.join(" ")}`;
|
|
10093
|
+
const result = await shellCommand({
|
|
10094
|
+
command: curlCommand,
|
|
10095
|
+
timeout: 60
|
|
10096
|
+
// 1 minuto para upload
|
|
10097
|
+
});
|
|
10098
|
+
const resultJson = JSON.parse(result);
|
|
10099
|
+
if (resultJson.status !== "success") {
|
|
10100
|
+
throw new Error(`Upload failed: ${resultJson.stderr}`);
|
|
10101
|
+
}
|
|
10102
|
+
try {
|
|
10103
|
+
const response = JSON.parse(resultJson.stdout);
|
|
10104
|
+
if (response.success === false || response.error) {
|
|
10105
|
+
const errorMsg = typeof response.error === "string" ? response.error : response.error?.message || "Deploy failed";
|
|
10106
|
+
return {
|
|
10107
|
+
success: false,
|
|
10108
|
+
error: errorMsg
|
|
10109
|
+
};
|
|
10110
|
+
}
|
|
10111
|
+
const data = response.data || {};
|
|
10112
|
+
return {
|
|
10113
|
+
success: true,
|
|
10114
|
+
appId: data.appId,
|
|
10115
|
+
name: data.name,
|
|
10116
|
+
status: data.status || "building",
|
|
10117
|
+
url: severinoUrl.replace(/\/$/, "") + `/app/${data.appId}`,
|
|
10118
|
+
message: data.message || "Deploy iniciado"
|
|
10119
|
+
};
|
|
10120
|
+
} catch (parseError) {
|
|
10121
|
+
throw new Error(`Failed to parse response: ${parseError.message}`);
|
|
10122
|
+
}
|
|
10123
|
+
}
|
|
10124
|
+
async function deployApp(args) {
|
|
10125
|
+
const envSeverinoUrl = process.env.SEVERINO_URL || "http://localhost:3000";
|
|
10126
|
+
const envApiKey = process.env.SEVERINO_API_KEY || void 0;
|
|
10127
|
+
const {
|
|
10128
|
+
projectDir,
|
|
10129
|
+
name,
|
|
10130
|
+
severinoUrl = envSeverinoUrl,
|
|
10131
|
+
apiKey = envApiKey
|
|
10132
|
+
} = args;
|
|
10133
|
+
try {
|
|
10134
|
+
if (!projectDir || typeof projectDir !== "string") {
|
|
10135
|
+
return { success: false, error: "projectDir is required" };
|
|
10136
|
+
}
|
|
10137
|
+
const resolvedProjectDir = resolveWorkspacePath(projectDir);
|
|
10138
|
+
try {
|
|
10139
|
+
await fs24.access(resolvedProjectDir);
|
|
10140
|
+
} catch {
|
|
10141
|
+
return {
|
|
10142
|
+
success: false,
|
|
10143
|
+
error: `Project directory not found: ${resolvedProjectDir}`
|
|
10144
|
+
};
|
|
10145
|
+
}
|
|
10146
|
+
const packageJsonPath = path26.join(resolvedProjectDir, "package.json");
|
|
10147
|
+
try {
|
|
10148
|
+
await fs24.access(packageJsonPath);
|
|
10149
|
+
} catch {
|
|
10150
|
+
return {
|
|
10151
|
+
success: false,
|
|
10152
|
+
error: "Not a Next.js project: package.json not found"
|
|
10153
|
+
};
|
|
10154
|
+
}
|
|
10155
|
+
const packageJsonContent = await fs24.readFile(packageJsonPath, "utf-8");
|
|
10156
|
+
const packageJson = JSON.parse(packageJsonContent);
|
|
10157
|
+
const hasNext = packageJson.dependencies?.next || packageJson.devDependencies?.next;
|
|
10158
|
+
if (!hasNext) {
|
|
10159
|
+
return {
|
|
10160
|
+
success: false,
|
|
10161
|
+
error: "Not a Next.js project: next not found in dependencies"
|
|
10162
|
+
};
|
|
10163
|
+
}
|
|
10164
|
+
const appName = name || packageJson.name || path26.basename(resolvedProjectDir);
|
|
10165
|
+
const tempDir = path26.join(resolvedProjectDir, ".tmp");
|
|
10166
|
+
await fs24.mkdir(tempDir, { recursive: true });
|
|
10167
|
+
const zipPath = path26.join(tempDir, `${appName}-${Date.now()}.zip`);
|
|
10168
|
+
console.log(`[deploy-app] Creating ZIP: ${zipPath}`);
|
|
10169
|
+
await createProjectZip(resolvedProjectDir, zipPath);
|
|
10170
|
+
const zipStats = await fs24.stat(zipPath);
|
|
10171
|
+
const zipSizeMB = zipStats.size / 1024 / 1024;
|
|
10172
|
+
if (zipSizeMB > 50) {
|
|
10173
|
+
await fs24.unlink(zipPath).catch(() => {
|
|
10174
|
+
});
|
|
10175
|
+
await fs24.rmdir(tempDir).catch(() => {
|
|
10176
|
+
});
|
|
10177
|
+
return {
|
|
10178
|
+
success: false,
|
|
10179
|
+
error: `ZIP too large: ${zipSizeMB.toFixed(2)}MB (max: 50MB)`
|
|
10180
|
+
};
|
|
10181
|
+
}
|
|
10182
|
+
console.log(`[deploy-app] ZIP size: ${zipSizeMB.toFixed(2)}MB`);
|
|
10183
|
+
console.log(`[deploy-app] Uploading to ${severinoUrl}...`);
|
|
10184
|
+
const deployResult = await uploadToSeverino(zipPath, severinoUrl, appName, apiKey);
|
|
10185
|
+
try {
|
|
10186
|
+
await fs24.unlink(zipPath);
|
|
10187
|
+
await fs24.rmdir(tempDir);
|
|
10188
|
+
} catch (e) {
|
|
10189
|
+
console.warn("[deploy-app] Cleanup warning:", e);
|
|
10190
|
+
}
|
|
10191
|
+
if (deployResult.success) {
|
|
10192
|
+
console.log(`[deploy-app] Deploy iniciado: ${deployResult.appId}`);
|
|
10193
|
+
}
|
|
10194
|
+
return deployResult;
|
|
10195
|
+
} catch (error) {
|
|
10196
|
+
console.error("[deploy-app] Error:", error.message);
|
|
10197
|
+
return {
|
|
10198
|
+
success: false,
|
|
10199
|
+
error: error.message || String(error)
|
|
10200
|
+
};
|
|
10201
|
+
}
|
|
10202
|
+
}
|
|
10203
|
+
|
|
10204
|
+
// src/app/agent/runtime/native_tool_catalog.ts
|
|
10205
|
+
init_sandbox_policy();
|
|
9191
10206
|
var NATIVE_TOOL_ENTRIES = [
|
|
9192
10207
|
{
|
|
9193
10208
|
metadata: {
|
|
@@ -9751,6 +10766,28 @@ var NATIVE_TOOL_ENTRIES = [
|
|
|
9751
10766
|
description: "Kill a running worker by session_id. Use when a worker is stuck or needs to be cancelled immediately. Sends SIGTERM and cleans up mailbox."
|
|
9752
10767
|
},
|
|
9753
10768
|
implementation: killAgent
|
|
10769
|
+
},
|
|
10770
|
+
{
|
|
10771
|
+
metadata: {
|
|
10772
|
+
name: "create_next_app",
|
|
10773
|
+
category: "filesystem",
|
|
10774
|
+
riskLevel: "write",
|
|
10775
|
+
autoApproveInLocal: false,
|
|
10776
|
+
autoApproveInSandbox: true,
|
|
10777
|
+
description: "Create a new Next.js project instantly with App Router, shadcn/ui components, Tailwind CSS, and TypeScript. Templates: minimal (basic structure) or full (with pre-built UI components)."
|
|
10778
|
+
},
|
|
10779
|
+
implementation: createNextApp
|
|
10780
|
+
},
|
|
10781
|
+
{
|
|
10782
|
+
metadata: {
|
|
10783
|
+
name: "deploy_app",
|
|
10784
|
+
category: "execution",
|
|
10785
|
+
riskLevel: "network",
|
|
10786
|
+
autoApproveInLocal: false,
|
|
10787
|
+
autoApproveInSandbox: true,
|
|
10788
|
+
description: "Deploy a Next.js project to Severino. Zips the project (excluding node_modules, .next) and uploads to /api/v1/deploy. Returns appId and live URL."
|
|
10789
|
+
},
|
|
10790
|
+
implementation: deployApp
|
|
9754
10791
|
}
|
|
9755
10792
|
];
|
|
9756
10793
|
var TOOL_METADATA_MAP = new Map(
|
|
@@ -9766,6 +10803,10 @@ function getNativeToolImplementation(toolName) {
|
|
|
9766
10803
|
return TOOL_IMPLEMENTATION_MAP.get(toolName);
|
|
9767
10804
|
}
|
|
9768
10805
|
function getAllNativeToolMetadata() {
|
|
10806
|
+
const policy = getSandboxPolicy();
|
|
10807
|
+
if (!policy.isSandbox) {
|
|
10808
|
+
return NATIVE_TOOL_ENTRIES.filter((entry) => entry.metadata.autoApproveInLocal !== false || !["create_next_app", "deploy_app"].includes(entry.metadata.name)).map((entry) => entry.metadata);
|
|
10809
|
+
}
|
|
9769
10810
|
return NATIVE_TOOL_ENTRIES.map((entry) => entry.metadata);
|
|
9770
10811
|
}
|
|
9771
10812
|
function applyMetadataToToolDefinitions(toolDefinitions) {
|
|
@@ -9791,9 +10832,9 @@ var ToolInvoker = class {
|
|
|
9791
10832
|
async initialize() {
|
|
9792
10833
|
try {
|
|
9793
10834
|
const __filename = fileURLToPath2(import.meta.url);
|
|
9794
|
-
const __dirname =
|
|
9795
|
-
const configPath =
|
|
9796
|
-
const fileContent = await
|
|
10835
|
+
const __dirname = path27.dirname(__filename);
|
|
10836
|
+
const configPath = path27.resolve(__dirname, "config", "native_tools.json");
|
|
10837
|
+
const fileContent = await fs25.readFile(configPath, "utf-8");
|
|
9797
10838
|
const config2 = JSON.parse(fileContent);
|
|
9798
10839
|
this.toolDefinitions = applyMetadataToToolDefinitions(config2.nativeTools);
|
|
9799
10840
|
} catch (error) {
|
|
@@ -9835,9 +10876,9 @@ var ToolInvoker = class {
|
|
|
9835
10876
|
};
|
|
9836
10877
|
|
|
9837
10878
|
// src/app/agent/tools/mcp/mcp_client.ts
|
|
9838
|
-
import { promises as
|
|
9839
|
-
import
|
|
9840
|
-
import
|
|
10879
|
+
import { promises as fs26 } from "fs";
|
|
10880
|
+
import path28 from "path";
|
|
10881
|
+
import os16 from "os";
|
|
9841
10882
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
9842
10883
|
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
9843
10884
|
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
|
|
@@ -9864,9 +10905,9 @@ var MCPClient = class {
|
|
|
9864
10905
|
});
|
|
9865
10906
|
}
|
|
9866
10907
|
const __filename = fileURLToPath3(import.meta.url);
|
|
9867
|
-
const __dirname =
|
|
9868
|
-
const defaultConfigPath =
|
|
9869
|
-
const userConfigPath =
|
|
10908
|
+
const __dirname = path28.dirname(__filename);
|
|
10909
|
+
const defaultConfigPath = path28.resolve(__dirname, "config", "bluma-mcp.json");
|
|
10910
|
+
const userConfigPath = path28.join(os16.homedir(), ".bluma", "bluma-mcp.json");
|
|
9870
10911
|
const defaultConfig = await this.loadMcpConfig(defaultConfigPath, "Default");
|
|
9871
10912
|
const userConfig = await this.loadMcpConfig(userConfigPath, "User");
|
|
9872
10913
|
const mergedConfig = {
|
|
@@ -9900,7 +10941,7 @@ var MCPClient = class {
|
|
|
9900
10941
|
}
|
|
9901
10942
|
async loadMcpConfig(configPath, configType) {
|
|
9902
10943
|
try {
|
|
9903
|
-
const fileContent = await
|
|
10944
|
+
const fileContent = await fs26.readFile(configPath, "utf-8");
|
|
9904
10945
|
const processedContent = this.replaceEnvPlaceholders(fileContent);
|
|
9905
10946
|
return JSON.parse(processedContent);
|
|
9906
10947
|
} catch (error) {
|
|
@@ -9919,7 +10960,7 @@ var MCPClient = class {
|
|
|
9919
10960
|
async connectToStdioServer(serverName, config2) {
|
|
9920
10961
|
let commandToExecute = config2.command;
|
|
9921
10962
|
let argsToExecute = config2.args || [];
|
|
9922
|
-
const isWindows =
|
|
10963
|
+
const isWindows = os16.platform() === "win32";
|
|
9923
10964
|
if (!isWindows && commandToExecute.toLowerCase() === "cmd") {
|
|
9924
10965
|
if (argsToExecute.length >= 2 && argsToExecute[0].toLowerCase() === "/c") {
|
|
9925
10966
|
commandToExecute = argsToExecute[1];
|
|
@@ -10077,13 +11118,13 @@ PENALTY APPLIED: ${penalty.toFixed(1)} points deducted.
|
|
|
10077
11118
|
};
|
|
10078
11119
|
|
|
10079
11120
|
// src/app/agent/bluma/core/bluma.ts
|
|
10080
|
-
import
|
|
11121
|
+
import path37 from "path";
|
|
10081
11122
|
import { v4 as uuidv48 } from "uuid";
|
|
10082
11123
|
|
|
10083
11124
|
// src/app/agent/session_manager/session_manager.ts
|
|
10084
|
-
import
|
|
10085
|
-
import
|
|
10086
|
-
import { promises as
|
|
11125
|
+
import path29 from "path";
|
|
11126
|
+
import os17 from "os";
|
|
11127
|
+
import { promises as fs27 } from "fs";
|
|
10087
11128
|
var fileLocks = /* @__PURE__ */ new Map();
|
|
10088
11129
|
async function withFileLock(file, fn) {
|
|
10089
11130
|
const prev = fileLocks.get(file) || Promise.resolve();
|
|
@@ -10119,13 +11160,13 @@ function debouncedSave(sessionFile, history, memory) {
|
|
|
10119
11160
|
function expandHome(p) {
|
|
10120
11161
|
if (!p) return p;
|
|
10121
11162
|
if (p.startsWith("~")) {
|
|
10122
|
-
return
|
|
11163
|
+
return path29.join(os17.homedir(), p.slice(1));
|
|
10123
11164
|
}
|
|
10124
11165
|
return p;
|
|
10125
11166
|
}
|
|
10126
11167
|
function getPreferredAppDir() {
|
|
10127
|
-
const fixed =
|
|
10128
|
-
return
|
|
11168
|
+
const fixed = path29.join(os17.homedir(), ".bluma");
|
|
11169
|
+
return path29.resolve(expandHome(fixed));
|
|
10129
11170
|
}
|
|
10130
11171
|
async function safeRenameWithRetry(src, dest, maxRetries = 6) {
|
|
10131
11172
|
let attempt = 0;
|
|
@@ -10133,10 +11174,10 @@ async function safeRenameWithRetry(src, dest, maxRetries = 6) {
|
|
|
10133
11174
|
const isWin = process.platform === "win32";
|
|
10134
11175
|
while (attempt <= maxRetries) {
|
|
10135
11176
|
try {
|
|
10136
|
-
const dir =
|
|
10137
|
-
await
|
|
11177
|
+
const dir = path29.dirname(dest);
|
|
11178
|
+
await fs27.mkdir(dir, { recursive: true }).catch(() => {
|
|
10138
11179
|
});
|
|
10139
|
-
await
|
|
11180
|
+
await fs27.rename(src, dest);
|
|
10140
11181
|
return;
|
|
10141
11182
|
} catch (e) {
|
|
10142
11183
|
lastErr = e;
|
|
@@ -10149,13 +11190,13 @@ async function safeRenameWithRetry(src, dest, maxRetries = 6) {
|
|
|
10149
11190
|
}
|
|
10150
11191
|
}
|
|
10151
11192
|
try {
|
|
10152
|
-
await
|
|
10153
|
-
const data = await
|
|
10154
|
-
const dir =
|
|
10155
|
-
await
|
|
11193
|
+
await fs27.access(src);
|
|
11194
|
+
const data = await fs27.readFile(src);
|
|
11195
|
+
const dir = path29.dirname(dest);
|
|
11196
|
+
await fs27.mkdir(dir, { recursive: true }).catch(() => {
|
|
10156
11197
|
});
|
|
10157
|
-
await
|
|
10158
|
-
await
|
|
11198
|
+
await fs27.writeFile(dest, data);
|
|
11199
|
+
await fs27.unlink(src).catch(() => {
|
|
10159
11200
|
});
|
|
10160
11201
|
return;
|
|
10161
11202
|
} catch (fallbackErr) {
|
|
@@ -10168,16 +11209,16 @@ async function safeRenameWithRetry(src, dest, maxRetries = 6) {
|
|
|
10168
11209
|
}
|
|
10169
11210
|
async function ensureSessionDir() {
|
|
10170
11211
|
const appDir = getPreferredAppDir();
|
|
10171
|
-
const sessionDir =
|
|
10172
|
-
await
|
|
11212
|
+
const sessionDir = path29.join(appDir, "sessions");
|
|
11213
|
+
await fs27.mkdir(sessionDir, { recursive: true });
|
|
10173
11214
|
return sessionDir;
|
|
10174
11215
|
}
|
|
10175
11216
|
async function loadOrcreateSession(sessionId) {
|
|
10176
11217
|
const sessionDir = await ensureSessionDir();
|
|
10177
|
-
const sessionFile =
|
|
11218
|
+
const sessionFile = path29.join(sessionDir, `${sessionId}.json`);
|
|
10178
11219
|
try {
|
|
10179
|
-
await
|
|
10180
|
-
const fileContent = await
|
|
11220
|
+
await fs27.access(sessionFile);
|
|
11221
|
+
const fileContent = await fs27.readFile(sessionFile, "utf-8");
|
|
10181
11222
|
const sessionData = JSON.parse(fileContent);
|
|
10182
11223
|
const memory = {
|
|
10183
11224
|
historyAnchor: sessionData.history_anchor ?? null,
|
|
@@ -10190,7 +11231,7 @@ async function loadOrcreateSession(sessionId) {
|
|
|
10190
11231
|
created_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
10191
11232
|
conversation_history: []
|
|
10192
11233
|
};
|
|
10193
|
-
await
|
|
11234
|
+
await fs27.writeFile(sessionFile, JSON.stringify(newSessionData, null, 2), "utf-8");
|
|
10194
11235
|
const emptyMemory = {
|
|
10195
11236
|
historyAnchor: null,
|
|
10196
11237
|
compressedTurnSliceCount: 0
|
|
@@ -10202,12 +11243,12 @@ async function doSaveSessionHistory(sessionFile, history, memory) {
|
|
|
10202
11243
|
await withFileLock(sessionFile, async () => {
|
|
10203
11244
|
let sessionData;
|
|
10204
11245
|
try {
|
|
10205
|
-
const dir =
|
|
10206
|
-
await
|
|
11246
|
+
const dir = path29.dirname(sessionFile);
|
|
11247
|
+
await fs27.mkdir(dir, { recursive: true });
|
|
10207
11248
|
} catch {
|
|
10208
11249
|
}
|
|
10209
11250
|
try {
|
|
10210
|
-
const fileContent = await
|
|
11251
|
+
const fileContent = await fs27.readFile(sessionFile, "utf-8");
|
|
10211
11252
|
sessionData = JSON.parse(fileContent);
|
|
10212
11253
|
} catch (error) {
|
|
10213
11254
|
const code = error && error.code;
|
|
@@ -10218,14 +11259,14 @@ async function doSaveSessionHistory(sessionFile, history, memory) {
|
|
|
10218
11259
|
console.warn(`An unknown error occurred while reading ${sessionFile}. Re-initializing.`, error);
|
|
10219
11260
|
}
|
|
10220
11261
|
}
|
|
10221
|
-
const sessionId =
|
|
11262
|
+
const sessionId = path29.basename(sessionFile, ".json");
|
|
10222
11263
|
sessionData = {
|
|
10223
11264
|
session_id: sessionId,
|
|
10224
11265
|
created_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
10225
11266
|
conversation_history: []
|
|
10226
11267
|
};
|
|
10227
11268
|
try {
|
|
10228
|
-
await
|
|
11269
|
+
await fs27.writeFile(sessionFile, JSON.stringify(sessionData, null, 2), "utf-8");
|
|
10229
11270
|
} catch {
|
|
10230
11271
|
}
|
|
10231
11272
|
}
|
|
@@ -10241,7 +11282,7 @@ async function doSaveSessionHistory(sessionFile, history, memory) {
|
|
|
10241
11282
|
}
|
|
10242
11283
|
const tempSessionFile = `${sessionFile}.${Date.now()}.tmp`;
|
|
10243
11284
|
try {
|
|
10244
|
-
await
|
|
11285
|
+
await fs27.writeFile(tempSessionFile, JSON.stringify(sessionData, null, 2), "utf-8");
|
|
10245
11286
|
await safeRenameWithRetry(tempSessionFile, sessionFile);
|
|
10246
11287
|
} catch (writeError) {
|
|
10247
11288
|
if (writeError instanceof Error) {
|
|
@@ -10250,7 +11291,7 @@ async function doSaveSessionHistory(sessionFile, history, memory) {
|
|
|
10250
11291
|
console.error(`An unknown fatal error occurred while saving session to ${sessionFile}:`, writeError);
|
|
10251
11292
|
}
|
|
10252
11293
|
try {
|
|
10253
|
-
await
|
|
11294
|
+
await fs27.unlink(tempSessionFile);
|
|
10254
11295
|
} catch {
|
|
10255
11296
|
}
|
|
10256
11297
|
}
|
|
@@ -10267,15 +11308,15 @@ async function saveSessionHistory(sessionFile, history, memory) {
|
|
|
10267
11308
|
}
|
|
10268
11309
|
|
|
10269
11310
|
// src/app/agent/core/prompt/prompt_builder.ts
|
|
10270
|
-
import
|
|
10271
|
-
import
|
|
10272
|
-
import
|
|
11311
|
+
import os21 from "os";
|
|
11312
|
+
import fs32 from "fs";
|
|
11313
|
+
import path34 from "path";
|
|
10273
11314
|
import { execSync as execSync3 } from "child_process";
|
|
10274
11315
|
|
|
10275
11316
|
// src/app/agent/skills/skill_loader.ts
|
|
10276
|
-
import
|
|
10277
|
-
import
|
|
10278
|
-
import
|
|
11317
|
+
import fs28 from "fs";
|
|
11318
|
+
import path30 from "path";
|
|
11319
|
+
import os18 from "os";
|
|
10279
11320
|
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
10280
11321
|
var SkillLoader = class _SkillLoader {
|
|
10281
11322
|
bundledSkillsDir;
|
|
@@ -10284,8 +11325,8 @@ var SkillLoader = class _SkillLoader {
|
|
|
10284
11325
|
cache = /* @__PURE__ */ new Map();
|
|
10285
11326
|
conflicts = [];
|
|
10286
11327
|
constructor(projectRoot, bundledDir) {
|
|
10287
|
-
this.projectSkillsDir =
|
|
10288
|
-
this.globalSkillsDir =
|
|
11328
|
+
this.projectSkillsDir = path30.join(projectRoot, ".bluma", "skills");
|
|
11329
|
+
this.globalSkillsDir = path30.join(os18.homedir(), ".bluma", "skills");
|
|
10289
11330
|
this.bundledSkillsDir = bundledDir || _SkillLoader.resolveBundledDir();
|
|
10290
11331
|
}
|
|
10291
11332
|
/**
|
|
@@ -10294,48 +11335,48 @@ var SkillLoader = class _SkillLoader {
|
|
|
10294
11335
|
*/
|
|
10295
11336
|
static resolveBundledDir() {
|
|
10296
11337
|
if (process.env.JEST_WORKER_ID !== void 0 || process.env.NODE_ENV === "test") {
|
|
10297
|
-
return
|
|
11338
|
+
return path30.join(process.cwd(), "dist", "config", "skills");
|
|
10298
11339
|
}
|
|
10299
11340
|
const candidates = [];
|
|
10300
11341
|
const push = (p) => {
|
|
10301
|
-
const abs =
|
|
11342
|
+
const abs = path30.resolve(p);
|
|
10302
11343
|
if (!candidates.includes(abs)) {
|
|
10303
11344
|
candidates.push(abs);
|
|
10304
11345
|
}
|
|
10305
11346
|
};
|
|
10306
11347
|
let argvBundled = null;
|
|
10307
11348
|
try {
|
|
10308
|
-
const bundleDir =
|
|
10309
|
-
push(
|
|
11349
|
+
const bundleDir = path30.dirname(fileURLToPath4(import.meta.url));
|
|
11350
|
+
push(path30.join(bundleDir, "config", "skills"));
|
|
10310
11351
|
} catch {
|
|
10311
11352
|
}
|
|
10312
11353
|
const argv1 = process.argv[1];
|
|
10313
11354
|
if (argv1 && !argv1.startsWith("-")) {
|
|
10314
11355
|
try {
|
|
10315
11356
|
let resolved = argv1;
|
|
10316
|
-
if (
|
|
10317
|
-
resolved =
|
|
10318
|
-
} else if (!
|
|
10319
|
-
resolved =
|
|
11357
|
+
if (path30.isAbsolute(argv1) && fs28.existsSync(argv1)) {
|
|
11358
|
+
resolved = fs28.realpathSync(argv1);
|
|
11359
|
+
} else if (!path30.isAbsolute(argv1)) {
|
|
11360
|
+
resolved = path30.resolve(process.cwd(), argv1);
|
|
10320
11361
|
}
|
|
10321
|
-
const scriptDir =
|
|
10322
|
-
argvBundled =
|
|
11362
|
+
const scriptDir = path30.dirname(resolved);
|
|
11363
|
+
argvBundled = path30.join(scriptDir, "config", "skills");
|
|
10323
11364
|
push(argvBundled);
|
|
10324
11365
|
} catch {
|
|
10325
11366
|
}
|
|
10326
11367
|
}
|
|
10327
11368
|
for (const abs of candidates) {
|
|
10328
|
-
if (
|
|
11369
|
+
if (fs28.existsSync(abs)) {
|
|
10329
11370
|
return abs;
|
|
10330
11371
|
}
|
|
10331
11372
|
}
|
|
10332
11373
|
try {
|
|
10333
|
-
return
|
|
11374
|
+
return path30.join(path30.dirname(fileURLToPath4(import.meta.url)), "config", "skills");
|
|
10334
11375
|
} catch {
|
|
10335
11376
|
if (argvBundled) {
|
|
10336
11377
|
return argvBundled;
|
|
10337
11378
|
}
|
|
10338
|
-
return
|
|
11379
|
+
return path30.join(os18.homedir(), ".bluma", "__bundled_skills_unresolved__");
|
|
10339
11380
|
}
|
|
10340
11381
|
}
|
|
10341
11382
|
/**
|
|
@@ -10364,8 +11405,8 @@ var SkillLoader = class _SkillLoader {
|
|
|
10364
11405
|
this.conflicts.push({
|
|
10365
11406
|
name: skill.name,
|
|
10366
11407
|
userSource: source,
|
|
10367
|
-
userPath:
|
|
10368
|
-
bundledPath:
|
|
11408
|
+
userPath: path30.join(dir, skill.name, "SKILL.md"),
|
|
11409
|
+
bundledPath: path30.join(this.bundledSkillsDir, skill.name, "SKILL.md")
|
|
10369
11410
|
});
|
|
10370
11411
|
continue;
|
|
10371
11412
|
}
|
|
@@ -10373,20 +11414,20 @@ var SkillLoader = class _SkillLoader {
|
|
|
10373
11414
|
}
|
|
10374
11415
|
}
|
|
10375
11416
|
listFromDir(dir, source) {
|
|
10376
|
-
if (!
|
|
11417
|
+
if (!fs28.existsSync(dir)) return [];
|
|
10377
11418
|
try {
|
|
10378
|
-
return
|
|
10379
|
-
const fullPath =
|
|
10380
|
-
return
|
|
10381
|
-
}).map((d) => this.loadMetadataFromPath(
|
|
11419
|
+
return fs28.readdirSync(dir).filter((d) => {
|
|
11420
|
+
const fullPath = path30.join(dir, d);
|
|
11421
|
+
return fs28.statSync(fullPath).isDirectory() && fs28.existsSync(path30.join(fullPath, "SKILL.md"));
|
|
11422
|
+
}).map((d) => this.loadMetadataFromPath(path30.join(dir, d, "SKILL.md"), d, source)).filter((m) => m !== null);
|
|
10382
11423
|
} catch {
|
|
10383
11424
|
return [];
|
|
10384
11425
|
}
|
|
10385
11426
|
}
|
|
10386
11427
|
loadMetadataFromPath(skillPath, skillName, source) {
|
|
10387
|
-
if (!
|
|
11428
|
+
if (!fs28.existsSync(skillPath)) return null;
|
|
10388
11429
|
try {
|
|
10389
|
-
const raw =
|
|
11430
|
+
const raw = fs28.readFileSync(skillPath, "utf-8");
|
|
10390
11431
|
const parsed = this.parseFrontmatter(raw);
|
|
10391
11432
|
return {
|
|
10392
11433
|
name: parsed.name || skillName,
|
|
@@ -10408,12 +11449,12 @@ var SkillLoader = class _SkillLoader {
|
|
|
10408
11449
|
*/
|
|
10409
11450
|
load(name) {
|
|
10410
11451
|
if (this.cache.has(name)) return this.cache.get(name);
|
|
10411
|
-
const bundledPath =
|
|
10412
|
-
const projectPath =
|
|
10413
|
-
const globalPath =
|
|
10414
|
-
const existsBundled =
|
|
10415
|
-
const existsProject =
|
|
10416
|
-
const existsGlobal =
|
|
11452
|
+
const bundledPath = path30.join(this.bundledSkillsDir, name, "SKILL.md");
|
|
11453
|
+
const projectPath = path30.join(this.projectSkillsDir, name, "SKILL.md");
|
|
11454
|
+
const globalPath = path30.join(this.globalSkillsDir, name, "SKILL.md");
|
|
11455
|
+
const existsBundled = fs28.existsSync(bundledPath);
|
|
11456
|
+
const existsProject = fs28.existsSync(projectPath);
|
|
11457
|
+
const existsGlobal = fs28.existsSync(globalPath);
|
|
10417
11458
|
if (existsBundled && (existsProject || existsGlobal)) {
|
|
10418
11459
|
const conflictSource = existsProject ? "project" : "global";
|
|
10419
11460
|
const conflictPath = existsProject ? projectPath : globalPath;
|
|
@@ -10452,9 +11493,9 @@ var SkillLoader = class _SkillLoader {
|
|
|
10452
11493
|
}
|
|
10453
11494
|
loadFromPath(skillPath, name, source) {
|
|
10454
11495
|
try {
|
|
10455
|
-
const raw =
|
|
11496
|
+
const raw = fs28.readFileSync(skillPath, "utf-8");
|
|
10456
11497
|
const parsed = this.parseFrontmatter(raw);
|
|
10457
|
-
const skillDir =
|
|
11498
|
+
const skillDir = path30.dirname(skillPath);
|
|
10458
11499
|
return {
|
|
10459
11500
|
name: parsed.name || name,
|
|
10460
11501
|
description: parsed.description || "",
|
|
@@ -10463,22 +11504,22 @@ var SkillLoader = class _SkillLoader {
|
|
|
10463
11504
|
version: parsed.version,
|
|
10464
11505
|
author: parsed.author,
|
|
10465
11506
|
license: parsed.license,
|
|
10466
|
-
references: this.scanAssets(
|
|
10467
|
-
scripts: this.scanAssets(
|
|
11507
|
+
references: this.scanAssets(path30.join(skillDir, "references")),
|
|
11508
|
+
scripts: this.scanAssets(path30.join(skillDir, "scripts"))
|
|
10468
11509
|
};
|
|
10469
11510
|
} catch {
|
|
10470
11511
|
return null;
|
|
10471
11512
|
}
|
|
10472
11513
|
}
|
|
10473
11514
|
scanAssets(dir) {
|
|
10474
|
-
if (!
|
|
11515
|
+
if (!fs28.existsSync(dir)) return [];
|
|
10475
11516
|
try {
|
|
10476
|
-
return
|
|
10477
|
-
const fp =
|
|
10478
|
-
return
|
|
11517
|
+
return fs28.readdirSync(dir).filter((f) => {
|
|
11518
|
+
const fp = path30.join(dir, f);
|
|
11519
|
+
return fs28.statSync(fp).isFile();
|
|
10479
11520
|
}).map((f) => ({
|
|
10480
11521
|
name: f,
|
|
10481
|
-
path:
|
|
11522
|
+
path: path30.resolve(dir, f)
|
|
10482
11523
|
}));
|
|
10483
11524
|
} catch {
|
|
10484
11525
|
return [];
|
|
@@ -10535,10 +11576,10 @@ var SkillLoader = class _SkillLoader {
|
|
|
10535
11576
|
this.cache.clear();
|
|
10536
11577
|
}
|
|
10537
11578
|
exists(name) {
|
|
10538
|
-
const bundledPath =
|
|
10539
|
-
const projectPath =
|
|
10540
|
-
const globalPath =
|
|
10541
|
-
return
|
|
11579
|
+
const bundledPath = path30.join(this.bundledSkillsDir, name, "SKILL.md");
|
|
11580
|
+
const projectPath = path30.join(this.projectSkillsDir, name, "SKILL.md");
|
|
11581
|
+
const globalPath = path30.join(this.globalSkillsDir, name, "SKILL.md");
|
|
11582
|
+
return fs28.existsSync(bundledPath) || fs28.existsSync(projectPath) || fs28.existsSync(globalPath);
|
|
10542
11583
|
}
|
|
10543
11584
|
/**
|
|
10544
11585
|
* Retorna conflitos detetados (skills do utilizador com mesmo nome de nativas).
|
|
@@ -10570,8 +11611,8 @@ var SkillLoader = class _SkillLoader {
|
|
|
10570
11611
|
};
|
|
10571
11612
|
|
|
10572
11613
|
// src/app/agent/core/prompt/workspace_snapshot.ts
|
|
10573
|
-
import
|
|
10574
|
-
import
|
|
11614
|
+
import fs29 from "fs";
|
|
11615
|
+
import path31 from "path";
|
|
10575
11616
|
import { execSync as execSync2 } from "child_process";
|
|
10576
11617
|
var LIMITS = {
|
|
10577
11618
|
readme: 1e4,
|
|
@@ -10586,10 +11627,10 @@ var LIMITS = {
|
|
|
10586
11627
|
};
|
|
10587
11628
|
function safeReadFile(filePath, maxChars) {
|
|
10588
11629
|
try {
|
|
10589
|
-
if (!
|
|
10590
|
-
const st =
|
|
11630
|
+
if (!fs29.existsSync(filePath)) return null;
|
|
11631
|
+
const st = fs29.statSync(filePath);
|
|
10591
11632
|
if (!st.isFile()) return null;
|
|
10592
|
-
const raw =
|
|
11633
|
+
const raw = fs29.readFileSync(filePath, "utf8");
|
|
10593
11634
|
if (raw.length <= maxChars) return raw;
|
|
10594
11635
|
return `${raw.slice(0, maxChars)}
|
|
10595
11636
|
|
|
@@ -10600,7 +11641,7 @@ function safeReadFile(filePath, maxChars) {
|
|
|
10600
11641
|
}
|
|
10601
11642
|
function tryReadReadme(cwd) {
|
|
10602
11643
|
for (const name of ["README.md", "README.MD", "readme.md", "Readme.md"]) {
|
|
10603
|
-
const c = safeReadFile(
|
|
11644
|
+
const c = safeReadFile(path31.join(cwd, name), LIMITS.readme);
|
|
10604
11645
|
if (c) return `(${name})
|
|
10605
11646
|
${c}`;
|
|
10606
11647
|
}
|
|
@@ -10608,14 +11649,14 @@ ${c}`;
|
|
|
10608
11649
|
}
|
|
10609
11650
|
function tryReadBluMaMd(cwd) {
|
|
10610
11651
|
const paths = [
|
|
10611
|
-
|
|
10612
|
-
|
|
10613
|
-
|
|
11652
|
+
path31.join(cwd, "BluMa.md"),
|
|
11653
|
+
path31.join(cwd, "BLUMA.md"),
|
|
11654
|
+
path31.join(cwd, ".bluma", "BluMa.md")
|
|
10614
11655
|
];
|
|
10615
11656
|
for (const p of paths) {
|
|
10616
11657
|
const c = safeReadFile(p, LIMITS.blumaMd);
|
|
10617
11658
|
if (c) {
|
|
10618
|
-
const rel =
|
|
11659
|
+
const rel = path31.relative(cwd, p) || p;
|
|
10619
11660
|
return `(${rel})
|
|
10620
11661
|
${c}`;
|
|
10621
11662
|
}
|
|
@@ -10623,10 +11664,10 @@ ${c}`;
|
|
|
10623
11664
|
return null;
|
|
10624
11665
|
}
|
|
10625
11666
|
function summarizePackageJson(cwd) {
|
|
10626
|
-
const p =
|
|
11667
|
+
const p = path31.join(cwd, "package.json");
|
|
10627
11668
|
try {
|
|
10628
|
-
if (!
|
|
10629
|
-
const pkg = JSON.parse(
|
|
11669
|
+
if (!fs29.existsSync(p)) return null;
|
|
11670
|
+
const pkg = JSON.parse(fs29.readFileSync(p, "utf8"));
|
|
10630
11671
|
const scripts = pkg.scripts;
|
|
10631
11672
|
let scriptKeys = "";
|
|
10632
11673
|
if (scripts && typeof scripts === "object" && !Array.isArray(scripts)) {
|
|
@@ -10659,7 +11700,7 @@ function summarizePackageJson(cwd) {
|
|
|
10659
11700
|
}
|
|
10660
11701
|
function topLevelListing(cwd) {
|
|
10661
11702
|
try {
|
|
10662
|
-
const names =
|
|
11703
|
+
const names = fs29.readdirSync(cwd, { withFileTypes: true });
|
|
10663
11704
|
const sorted = [...names].sort((a, b) => a.name.localeCompare(b.name));
|
|
10664
11705
|
const limited = sorted.slice(0, LIMITS.topDirEntries);
|
|
10665
11706
|
const lines = limited.map((d) => `${d.name}${d.isDirectory() ? "/" : ""}`);
|
|
@@ -10717,7 +11758,7 @@ function buildWorkspaceSnapshot(cwd) {
|
|
|
10717
11758
|
parts.push(pkg);
|
|
10718
11759
|
parts.push("```\n");
|
|
10719
11760
|
}
|
|
10720
|
-
const py = safeReadFile(
|
|
11761
|
+
const py = safeReadFile(path31.join(cwd, "pyproject.toml"), LIMITS.pyproject);
|
|
10721
11762
|
if (py) {
|
|
10722
11763
|
parts.push("### pyproject.toml (excerpt)\n```toml");
|
|
10723
11764
|
parts.push(py);
|
|
@@ -10735,15 +11776,15 @@ function buildWorkspaceSnapshot(cwd) {
|
|
|
10735
11776
|
parts.push(bluma);
|
|
10736
11777
|
parts.push("```\n");
|
|
10737
11778
|
}
|
|
10738
|
-
const contrib = safeReadFile(
|
|
11779
|
+
const contrib = safeReadFile(path31.join(cwd, "CONTRIBUTING.md"), LIMITS.contributing);
|
|
10739
11780
|
if (contrib) {
|
|
10740
11781
|
parts.push("### CONTRIBUTING.md (excerpt)\n```markdown");
|
|
10741
11782
|
parts.push(contrib);
|
|
10742
11783
|
parts.push("```\n");
|
|
10743
11784
|
}
|
|
10744
|
-
const chlog = safeReadFile(
|
|
11785
|
+
const chlog = safeReadFile(path31.join(cwd, "CHANGELOG.md"), LIMITS.changelog);
|
|
10745
11786
|
if (!chlog) {
|
|
10746
|
-
const alt = safeReadFile(
|
|
11787
|
+
const alt = safeReadFile(path31.join(cwd, "CHANGES.md"), LIMITS.changelog);
|
|
10747
11788
|
if (alt) {
|
|
10748
11789
|
parts.push("### CHANGES.md (excerpt)\n```markdown");
|
|
10749
11790
|
parts.push(alt);
|
|
@@ -10783,15 +11824,15 @@ init_runtime_config();
|
|
|
10783
11824
|
|
|
10784
11825
|
// src/app/agent/runtime/plugin_registry.ts
|
|
10785
11826
|
init_sandbox_policy();
|
|
10786
|
-
import
|
|
10787
|
-
import
|
|
10788
|
-
import
|
|
11827
|
+
import fs30 from "fs";
|
|
11828
|
+
import os19 from "os";
|
|
11829
|
+
import path32 from "path";
|
|
10789
11830
|
function getProjectPluginsDir() {
|
|
10790
11831
|
const policy = getSandboxPolicy();
|
|
10791
|
-
return
|
|
11832
|
+
return path32.join(policy.workspaceRoot, ".bluma", "plugins");
|
|
10792
11833
|
}
|
|
10793
11834
|
function getGlobalPluginsDir() {
|
|
10794
|
-
return
|
|
11835
|
+
return path32.join(process.env.HOME || os19.homedir(), ".bluma", "plugins");
|
|
10795
11836
|
}
|
|
10796
11837
|
function getPluginDirs() {
|
|
10797
11838
|
return {
|
|
@@ -10800,11 +11841,11 @@ function getPluginDirs() {
|
|
|
10800
11841
|
};
|
|
10801
11842
|
}
|
|
10802
11843
|
function readManifest(manifestPath, fallbackName) {
|
|
10803
|
-
if (!
|
|
11844
|
+
if (!fs30.existsSync(manifestPath)) {
|
|
10804
11845
|
return null;
|
|
10805
11846
|
}
|
|
10806
11847
|
try {
|
|
10807
|
-
const parsed = JSON.parse(
|
|
11848
|
+
const parsed = JSON.parse(fs30.readFileSync(manifestPath, "utf-8"));
|
|
10808
11849
|
return {
|
|
10809
11850
|
name: typeof parsed.name === "string" && parsed.name.trim() ? parsed.name.trim() : fallbackName,
|
|
10810
11851
|
description: typeof parsed.description === "string" ? parsed.description.trim() : void 0,
|
|
@@ -10817,22 +11858,22 @@ function readManifest(manifestPath, fallbackName) {
|
|
|
10817
11858
|
}
|
|
10818
11859
|
function findManifestPath(pluginDir) {
|
|
10819
11860
|
const candidates = [
|
|
10820
|
-
|
|
10821
|
-
|
|
11861
|
+
path32.join(pluginDir, ".codex-plugin", "plugin.json"),
|
|
11862
|
+
path32.join(pluginDir, "plugin.json")
|
|
10822
11863
|
];
|
|
10823
11864
|
for (const candidate of candidates) {
|
|
10824
|
-
if (
|
|
11865
|
+
if (fs30.existsSync(candidate)) {
|
|
10825
11866
|
return candidate;
|
|
10826
11867
|
}
|
|
10827
11868
|
}
|
|
10828
11869
|
return null;
|
|
10829
11870
|
}
|
|
10830
11871
|
function listFromDir(baseDir, source) {
|
|
10831
|
-
if (!
|
|
11872
|
+
if (!fs30.existsSync(baseDir)) {
|
|
10832
11873
|
return [];
|
|
10833
11874
|
}
|
|
10834
|
-
return
|
|
10835
|
-
const pluginDir =
|
|
11875
|
+
return fs30.readdirSync(baseDir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).flatMap((entry) => {
|
|
11876
|
+
const pluginDir = path32.join(baseDir, entry.name);
|
|
10836
11877
|
const manifestPath = findManifestPath(pluginDir);
|
|
10837
11878
|
if (!manifestPath) {
|
|
10838
11879
|
return [];
|
|
@@ -11182,9 +12223,9 @@ function disableCoordinatorMode() {
|
|
|
11182
12223
|
}
|
|
11183
12224
|
|
|
11184
12225
|
// src/app/agent/utils/blumamd.ts
|
|
11185
|
-
import
|
|
11186
|
-
import
|
|
11187
|
-
import
|
|
12226
|
+
import fs31 from "fs";
|
|
12227
|
+
import path33 from "path";
|
|
12228
|
+
import os20 from "os";
|
|
11188
12229
|
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.";
|
|
11189
12230
|
var TEXT_FILE_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
11190
12231
|
".md",
|
|
@@ -11312,12 +12353,12 @@ var TEXT_FILE_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
|
11312
12353
|
function expandIncludePath(includePath, baseDir) {
|
|
11313
12354
|
const cleanPath = includePath.startsWith("@") ? includePath.slice(1) : includePath;
|
|
11314
12355
|
if (cleanPath.startsWith("~")) {
|
|
11315
|
-
return
|
|
12356
|
+
return path33.join(os20.homedir(), cleanPath.slice(1));
|
|
11316
12357
|
}
|
|
11317
|
-
if (
|
|
12358
|
+
if (path33.isAbsolute(cleanPath)) {
|
|
11318
12359
|
return cleanPath;
|
|
11319
12360
|
}
|
|
11320
|
-
return
|
|
12361
|
+
return path33.resolve(baseDir, cleanPath);
|
|
11321
12362
|
}
|
|
11322
12363
|
function processIncludes(content, baseDir, processedFiles) {
|
|
11323
12364
|
const lines = content.split("\n");
|
|
@@ -11326,20 +12367,20 @@ function processIncludes(content, baseDir, processedFiles) {
|
|
|
11326
12367
|
const includeMatch = line.match(/^@\s*([^\s]+)/);
|
|
11327
12368
|
if (includeMatch) {
|
|
11328
12369
|
const includePath = expandIncludePath(includeMatch[1], baseDir);
|
|
11329
|
-
const normalizedPath =
|
|
12370
|
+
const normalizedPath = path33.normalize(includePath);
|
|
11330
12371
|
if (processedFiles.has(normalizedPath)) {
|
|
11331
12372
|
result.push(`<!-- Circular include prevented: ${includeMatch[1]} -->`);
|
|
11332
12373
|
continue;
|
|
11333
12374
|
}
|
|
11334
|
-
const ext =
|
|
12375
|
+
const ext = path33.extname(includePath).toLowerCase();
|
|
11335
12376
|
if (!TEXT_FILE_EXTENSIONS.has(ext)) {
|
|
11336
12377
|
result.push(`<!-- Include skipped (unsupported extension): ${includeMatch[1]} -->`);
|
|
11337
12378
|
continue;
|
|
11338
12379
|
}
|
|
11339
12380
|
try {
|
|
11340
|
-
const includedContent =
|
|
12381
|
+
const includedContent = fs31.readFileSync(includePath, "utf-8");
|
|
11341
12382
|
processedFiles.add(normalizedPath);
|
|
11342
|
-
const processedContent = processIncludes(includedContent,
|
|
12383
|
+
const processedContent = processIncludes(includedContent, path33.dirname(includePath), processedFiles);
|
|
11343
12384
|
result.push(`
|
|
11344
12385
|
<!-- BEGIN INCLUDE ${includeMatch[1]} -->
|
|
11345
12386
|
`);
|
|
@@ -11358,9 +12399,9 @@ function processIncludes(content, baseDir, processedFiles) {
|
|
|
11358
12399
|
}
|
|
11359
12400
|
function readMemoryFile(filePath, type, priority) {
|
|
11360
12401
|
try {
|
|
11361
|
-
const content =
|
|
11362
|
-
const baseDir =
|
|
11363
|
-
const processedFiles = /* @__PURE__ */ new Set([
|
|
12402
|
+
const content = fs31.readFileSync(filePath, "utf-8");
|
|
12403
|
+
const baseDir = path33.dirname(filePath);
|
|
12404
|
+
const processedFiles = /* @__PURE__ */ new Set([path33.normalize(filePath)]);
|
|
11364
12405
|
const processedContent = processIncludes(content, baseDir, processedFiles);
|
|
11365
12406
|
return {
|
|
11366
12407
|
path: filePath,
|
|
@@ -11377,33 +12418,33 @@ function readMemoryFile(filePath, type, priority) {
|
|
|
11377
12418
|
}
|
|
11378
12419
|
function findGitRoot(startDir) {
|
|
11379
12420
|
let current = startDir;
|
|
11380
|
-
while (current !==
|
|
11381
|
-
const gitPath =
|
|
12421
|
+
while (current !== path33.dirname(current)) {
|
|
12422
|
+
const gitPath = path33.join(current, ".git");
|
|
11382
12423
|
try {
|
|
11383
|
-
if (
|
|
12424
|
+
if (fs31.existsSync(gitPath)) {
|
|
11384
12425
|
return current;
|
|
11385
12426
|
}
|
|
11386
12427
|
} catch {
|
|
11387
12428
|
}
|
|
11388
|
-
current =
|
|
12429
|
+
current = path33.dirname(current);
|
|
11389
12430
|
}
|
|
11390
12431
|
return null;
|
|
11391
12432
|
}
|
|
11392
12433
|
function loadUserMemory() {
|
|
11393
12434
|
const files = [];
|
|
11394
|
-
const homeDir =
|
|
11395
|
-
const userBlumaDir =
|
|
11396
|
-
const userBlumaMd =
|
|
12435
|
+
const homeDir = os20.homedir();
|
|
12436
|
+
const userBlumaDir = path33.join(homeDir, ".bluma");
|
|
12437
|
+
const userBlumaMd = path33.join(userBlumaDir, "BLUMA.md");
|
|
11397
12438
|
const userFile = readMemoryFile(userBlumaMd, "user", 2);
|
|
11398
12439
|
if (userFile) {
|
|
11399
12440
|
files.push(userFile);
|
|
11400
12441
|
}
|
|
11401
|
-
const userRulesDir =
|
|
11402
|
-
if (
|
|
12442
|
+
const userRulesDir = path33.join(userBlumaDir, "rules");
|
|
12443
|
+
if (fs31.existsSync(userRulesDir)) {
|
|
11403
12444
|
try {
|
|
11404
|
-
const ruleFiles =
|
|
12445
|
+
const ruleFiles = fs31.readdirSync(userRulesDir).filter((f) => f.endsWith(".md")).sort();
|
|
11405
12446
|
for (const ruleFile of ruleFiles) {
|
|
11406
|
-
const rulePath =
|
|
12447
|
+
const rulePath = path33.join(userRulesDir, ruleFile);
|
|
11407
12448
|
const rule = readMemoryFile(rulePath, "rule", 2);
|
|
11408
12449
|
if (rule) {
|
|
11409
12450
|
files.push(rule);
|
|
@@ -11417,22 +12458,22 @@ function loadUserMemory() {
|
|
|
11417
12458
|
function loadProjectMemory(cwd) {
|
|
11418
12459
|
const files = [];
|
|
11419
12460
|
const gitRoot = findGitRoot(cwd) || cwd;
|
|
11420
|
-
const projectBlumaMd =
|
|
12461
|
+
const projectBlumaMd = path33.join(gitRoot, "BLUMA.md");
|
|
11421
12462
|
const projectFile = readMemoryFile(projectBlumaMd, "project", 3);
|
|
11422
12463
|
if (projectFile) {
|
|
11423
12464
|
files.push(projectFile);
|
|
11424
12465
|
}
|
|
11425
|
-
const blumaDirBlumaMd =
|
|
12466
|
+
const blumaDirBlumaMd = path33.join(gitRoot, ".bluma", "BLUMA.md");
|
|
11426
12467
|
const blumaDirFile = readMemoryFile(blumaDirBlumaMd, "project", 3);
|
|
11427
12468
|
if (blumaDirFile) {
|
|
11428
12469
|
files.push(blumaDirFile);
|
|
11429
12470
|
}
|
|
11430
|
-
const rulesDir =
|
|
11431
|
-
if (
|
|
12471
|
+
const rulesDir = path33.join(gitRoot, ".bluma", "rules");
|
|
12472
|
+
if (fs31.existsSync(rulesDir)) {
|
|
11432
12473
|
try {
|
|
11433
|
-
const ruleFiles =
|
|
12474
|
+
const ruleFiles = fs31.readdirSync(rulesDir).filter((f) => f.endsWith(".md")).sort();
|
|
11434
12475
|
for (const ruleFile of ruleFiles) {
|
|
11435
|
-
const rulePath =
|
|
12476
|
+
const rulePath = path33.join(rulesDir, ruleFile);
|
|
11436
12477
|
const rule = readMemoryFile(rulePath, "rule", 3);
|
|
11437
12478
|
if (rule) {
|
|
11438
12479
|
files.push(rule);
|
|
@@ -11441,7 +12482,7 @@ function loadProjectMemory(cwd) {
|
|
|
11441
12482
|
} catch {
|
|
11442
12483
|
}
|
|
11443
12484
|
}
|
|
11444
|
-
const localBlumaMd =
|
|
12485
|
+
const localBlumaMd = path33.join(gitRoot, "BLUMA.local.md");
|
|
11445
12486
|
const localFile = readMemoryFile(localBlumaMd, "local", 4);
|
|
11446
12487
|
if (localFile) {
|
|
11447
12488
|
files.push(localFile);
|
|
@@ -11562,6 +12603,149 @@ Since you are in an **isolated sandbox**, ALL tools are auto-approved:
|
|
|
11562
12603
|
|
|
11563
12604
|
---
|
|
11564
12605
|
|
|
12606
|
+
## \u{1F680} NEXT.JS DEPLOY WORKFLOW - SEVERINO INTEGRATION
|
|
12607
|
+
|
|
12608
|
+
You have access to **two specialized tools** for creating and deploying Next.js apps to Severino:
|
|
12609
|
+
|
|
12610
|
+
### Tool 1: \\\`create_next_app\\\`
|
|
12611
|
+
|
|
12612
|
+
**Purpose:** Instant scaffold of a complete Next.js project with App Router, shadcn/ui, and Tailwind CSS.
|
|
12613
|
+
|
|
12614
|
+
**Args:**
|
|
12615
|
+
- \\\`name\\\` (required): Project name (will be directory name)
|
|
12616
|
+
- \\\`template\\\` (optional): \\\`'minimal'\\\` or \\\`'full'\\\` (default: \\\`'full'\\\`)
|
|
12617
|
+
- \\\`directory\\\` (optional): Where to create (default: workspace root)
|
|
12618
|
+
|
|
12619
|
+
**Example:**
|
|
12620
|
+
\\\`\\\`\\\`typescript
|
|
12621
|
+
const result = await createNextApp({
|
|
12622
|
+
name: 'erp-dashboard',
|
|
12623
|
+
template: 'full',
|
|
12624
|
+
});
|
|
12625
|
+
// Creates: /workspace/session_id/erp-dashboard/
|
|
12626
|
+
// Includes: App Router, shadcn/ui (Button, Card, Input), Tailwind, TypeScript
|
|
12627
|
+
\\\`\\\`\\\`
|
|
12628
|
+
|
|
12629
|
+
**What it creates:**
|
|
12630
|
+
- \\\`package.json\\\` with Next.js, React, Tailwind dependencies
|
|
12631
|
+
- \\\`tsconfig.json\\\` configured for Next.js
|
|
12632
|
+
- \\\`next.config.js\\\` with \\\`output: 'standalone'\\\` (required for deploy)
|
|
12633
|
+
- \\\`tailwind.config.ts\\\`, \\\`postcss.config.js\\\`
|
|
12634
|
+
- \\\`app/layout.tsx\\\`, \\\`app/page.tsx\\\`, \\\`app/globals.css\\\`
|
|
12635
|
+
- \\\`components/ui/\\\` with shadcn/ui components (Button, Card, Input)
|
|
12636
|
+
- \\\`lib/utils.ts\\\` with \\\`cn()\\\` utility
|
|
12637
|
+
|
|
12638
|
+
**Auto-runs:** \\\`npm install\\\` after creating files
|
|
12639
|
+
|
|
12640
|
+
---
|
|
12641
|
+
|
|
12642
|
+
### Tool 2: \\\`deploy_app\\\`
|
|
12643
|
+
|
|
12644
|
+
**Purpose:** Zip and deploy a Next.js project to Severino for hosting.
|
|
12645
|
+
|
|
12646
|
+
**Args:**
|
|
12647
|
+
- \\\`projectDir\\\` (required): Path to the Next.js project
|
|
12648
|
+
- \\\`name\\\` (optional): App name (default: package.json name or directory name)
|
|
12649
|
+
- \\\`severinoUrl\\\` (optional): Auto-reads from \\\`SEVERINO_URL\\\` env var
|
|
12650
|
+
- \\\`apiKey\\\` (optional): Auto-reads from \\\`SEVERINO_API_KEY\\\` env var
|
|
12651
|
+
|
|
12652
|
+
**Example:**
|
|
12653
|
+
\\\`\\\`\\\`typescript
|
|
12654
|
+
const result = await deployApp({
|
|
12655
|
+
projectDir: './erp-dashboard',
|
|
12656
|
+
name: 'erp-dashboard',
|
|
12657
|
+
});
|
|
12658
|
+
// Returns: { appId: 'uuid', url: 'http://localhost:3000/app/uuid', status: 'building' }
|
|
12659
|
+
\\\`\\\`\\\`
|
|
12660
|
+
|
|
12661
|
+
**What it does:**
|
|
12662
|
+
1. Validates project (checks \\\`package.json\\\` and \\\`next\\\` dependency)
|
|
12663
|
+
2. Creates ZIP (excludes \\\`node_modules\\\`, \\\`.next\\\`, \\\`.env\\\`, \\\`.git\\\`)
|
|
12664
|
+
3. Uploads to \\\`POST {severinoUrl}/api/v1/deploy\\\`
|
|
12665
|
+
4. Returns \\\`appId\\\` and live URL
|
|
12666
|
+
|
|
12667
|
+
**Important:** The deploy is **asynchronous** - status starts as \\\`'building'\\\`. The app will be ready in ~30-60 seconds.
|
|
12668
|
+
|
|
12669
|
+
---
|
|
12670
|
+
|
|
12671
|
+
### Complete Workflow Example
|
|
12672
|
+
|
|
12673
|
+
\\\`\\\`\\\`typescript
|
|
12674
|
+
// Step 1: Create project
|
|
12675
|
+
message({ message_type: 'info', content: 'Step 1/3: Creating Next.js project...' });
|
|
12676
|
+
const scaffold = await createNextApp({
|
|
12677
|
+
name: 'erp-dashboard',
|
|
12678
|
+
template: 'full',
|
|
12679
|
+
});
|
|
12680
|
+
|
|
12681
|
+
// Step 2: Develop (customize the app)
|
|
12682
|
+
message({ message_type: 'info', content: 'Step 2/3: Developing components...' });
|
|
12683
|
+
await fileWrite({
|
|
12684
|
+
filepath: './erp-dashboard/app/dashboard/page.tsx',
|
|
12685
|
+
content: 'export default function Dashboard() { return <h1>ERP Dashboard</h1> }',
|
|
12686
|
+
});
|
|
12687
|
+
|
|
12688
|
+
// Step 3: Deploy
|
|
12689
|
+
message({ message_type: 'info', content: 'Step 3/3: Deploying to Severino...' });
|
|
12690
|
+
const deploy = await deployApp({
|
|
12691
|
+
projectDir: './erp-dashboard',
|
|
12692
|
+
name: 'erp-dashboard',
|
|
12693
|
+
});
|
|
12694
|
+
|
|
12695
|
+
// Step 4: Report result
|
|
12696
|
+
message({
|
|
12697
|
+
message_type: 'result',
|
|
12698
|
+
content: 'App criada e deployada com sucesso!',
|
|
12699
|
+
attachments: [{ path: deploy.url, description: 'URL da app live' }],
|
|
12700
|
+
});
|
|
12701
|
+
\\\`\\\`\\\`
|
|
12702
|
+
|
|
12703
|
+
---
|
|
12704
|
+
|
|
12705
|
+
### \u26A0\uFE0F Critical Requirements for Deploy
|
|
12706
|
+
|
|
12707
|
+
1. **\\\`output: 'standalone'\\\` in \\\`next.config.js\\\`**
|
|
12708
|
+
- The \\\`create_next_app\\\` tool already includes this
|
|
12709
|
+
- If you modify \\\`next.config.js\\\`, keep this setting
|
|
12710
|
+
|
|
12711
|
+
2. **Build before deploy (optional but recommended)**
|
|
12712
|
+
\\\`\\\`\\\`bash
|
|
12713
|
+
cd erp-dashboard && npm run build
|
|
12714
|
+
\\\`\\\`\\\`
|
|
12715
|
+
- Ensures no TypeScript errors
|
|
12716
|
+
- Creates \\\`.next/standalone/\\\` for optimized deploy
|
|
12717
|
+
|
|
12718
|
+
3. **Don't include sensitive files**
|
|
12719
|
+
- The tool automatically excludes \\\`.env\\\`, \\\`.env.local\\\`, \\\`node_modules\\\`
|
|
12720
|
+
- Never commit API keys or secrets to the project
|
|
12721
|
+
|
|
12722
|
+
4. **Test locally first (if possible)**
|
|
12723
|
+
\\\`\\\`\\\`bash
|
|
12724
|
+
cd erp-dashboard && npm run dev
|
|
12725
|
+
\\\`\\\`\\\`
|
|
12726
|
+
|
|
12727
|
+
---
|
|
12728
|
+
|
|
12729
|
+
### Troubleshooting
|
|
12730
|
+
|
|
12731
|
+
**Deploy fails with "ZIP too large":**
|
|
12732
|
+
- Remove large files (videos, images > 5MB)
|
|
12733
|
+
- Exclude \\\`coverage/\\\`, \\\`.turbo/\\\` directories
|
|
12734
|
+
|
|
12735
|
+
**Deploy fails with "next not found":**
|
|
12736
|
+
- Ensure \\\`next\\\` is in \\\`dependencies\\\` or \\\`devDependencies\\\`
|
|
12737
|
+
- Run \\\`npm install\\\` before deploy
|
|
12738
|
+
|
|
12739
|
+
**App returns 404 after deploy:**
|
|
12740
|
+
- Wait 30-60 seconds for build to complete
|
|
12741
|
+
- Check status: \\\`GET {severinoUrl}/api/v1/apps/:appId\\\`
|
|
12742
|
+
|
|
12743
|
+
**Build fails:**
|
|
12744
|
+
- Run \\\`npx tsc --noEmit\\\` to check TypeScript errors
|
|
12745
|
+
- Fix errors before deploy
|
|
12746
|
+
|
|
12747
|
+
---
|
|
12748
|
+
|
|
11565
12749
|
## \u{1F3AF} QUALITY STANDARDS - PRODUCTION GRADE
|
|
11566
12750
|
|
|
11567
12751
|
### Code Quality
|
|
@@ -11791,10 +12975,10 @@ function getGitBranch(dir) {
|
|
|
11791
12975
|
}
|
|
11792
12976
|
function getPackageManager(dir) {
|
|
11793
12977
|
try {
|
|
11794
|
-
if (
|
|
11795
|
-
if (
|
|
11796
|
-
if (
|
|
11797
|
-
if (
|
|
12978
|
+
if (fs32.existsSync(path34.join(dir, "pnpm-lock.yaml"))) return "pnpm";
|
|
12979
|
+
if (fs32.existsSync(path34.join(dir, "yarn.lock"))) return "yarn";
|
|
12980
|
+
if (fs32.existsSync(path34.join(dir, "bun.lockb"))) return "bun";
|
|
12981
|
+
if (fs32.existsSync(path34.join(dir, "package-lock.json"))) return "npm";
|
|
11798
12982
|
return "unknown";
|
|
11799
12983
|
} catch {
|
|
11800
12984
|
return "unknown";
|
|
@@ -11802,9 +12986,9 @@ function getPackageManager(dir) {
|
|
|
11802
12986
|
}
|
|
11803
12987
|
function getProjectType(dir) {
|
|
11804
12988
|
try {
|
|
11805
|
-
const files =
|
|
12989
|
+
const files = fs32.readdirSync(dir);
|
|
11806
12990
|
if (files.includes("package.json")) {
|
|
11807
|
-
const pkg = JSON.parse(
|
|
12991
|
+
const pkg = JSON.parse(fs32.readFileSync(path34.join(dir, "package.json"), "utf-8"));
|
|
11808
12992
|
if (pkg.dependencies?.next || pkg.devDependencies?.next) return "Next.js";
|
|
11809
12993
|
if (pkg.dependencies?.react || pkg.devDependencies?.react) return "React";
|
|
11810
12994
|
if (pkg.dependencies?.express || pkg.devDependencies?.express) return "Express";
|
|
@@ -11823,9 +13007,9 @@ function getProjectType(dir) {
|
|
|
11823
13007
|
}
|
|
11824
13008
|
function getTestFramework(dir) {
|
|
11825
13009
|
try {
|
|
11826
|
-
const pkgPath =
|
|
11827
|
-
if (
|
|
11828
|
-
const pkg = JSON.parse(
|
|
13010
|
+
const pkgPath = path34.join(dir, "package.json");
|
|
13011
|
+
if (fs32.existsSync(pkgPath)) {
|
|
13012
|
+
const pkg = JSON.parse(fs32.readFileSync(pkgPath, "utf-8"));
|
|
11829
13013
|
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
11830
13014
|
if (deps.jest) return "jest";
|
|
11831
13015
|
if (deps.vitest) return "vitest";
|
|
@@ -11834,7 +13018,7 @@ function getTestFramework(dir) {
|
|
|
11834
13018
|
if (deps["@playwright/test"]) return "playwright";
|
|
11835
13019
|
if (deps.cypress) return "cypress";
|
|
11836
13020
|
}
|
|
11837
|
-
if (
|
|
13021
|
+
if (fs32.existsSync(path34.join(dir, "pytest.ini")) || fs32.existsSync(path34.join(dir, "conftest.py"))) return "pytest";
|
|
11838
13022
|
return "unknown";
|
|
11839
13023
|
} catch {
|
|
11840
13024
|
return "unknown";
|
|
@@ -11842,9 +13026,9 @@ function getTestFramework(dir) {
|
|
|
11842
13026
|
}
|
|
11843
13027
|
function getTestCommand(dir) {
|
|
11844
13028
|
try {
|
|
11845
|
-
const pkgPath =
|
|
11846
|
-
if (
|
|
11847
|
-
const pkg = JSON.parse(
|
|
13029
|
+
const pkgPath = path34.join(dir, "package.json");
|
|
13030
|
+
if (fs32.existsSync(pkgPath)) {
|
|
13031
|
+
const pkg = JSON.parse(fs32.readFileSync(pkgPath, "utf-8"));
|
|
11848
13032
|
if (pkg.scripts?.test) return `npm test`;
|
|
11849
13033
|
if (pkg.scripts?.["test:unit"]) return `npm run test:unit`;
|
|
11850
13034
|
}
|
|
@@ -12005,12 +13189,12 @@ function getUnifiedSystemPrompt(availableSkills) {
|
|
|
12005
13189
|
const runtimeConfig = getRuntimeConfig();
|
|
12006
13190
|
const availablePlugins = listPlugins();
|
|
12007
13191
|
const env = {
|
|
12008
|
-
os_type:
|
|
12009
|
-
os_version:
|
|
12010
|
-
architecture:
|
|
13192
|
+
os_type: os21.type(),
|
|
13193
|
+
os_version: os21.release(),
|
|
13194
|
+
architecture: os21.arch(),
|
|
12011
13195
|
workdir: cwd,
|
|
12012
13196
|
shell_type: process.env.SHELL || process.env.COMSPEC || "unknown",
|
|
12013
|
-
username:
|
|
13197
|
+
username: os21.userInfo().username,
|
|
12014
13198
|
current_date: (/* @__PURE__ */ new Date()).toISOString().split("T")[0],
|
|
12015
13199
|
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
|
|
12016
13200
|
is_git_repo: isGitRepo(cwd) ? "yes" : "no",
|
|
@@ -12081,8 +13265,8 @@ ${blumaMdContent}
|
|
|
12081
13265
|
}
|
|
12082
13266
|
function isGitRepo(dir) {
|
|
12083
13267
|
try {
|
|
12084
|
-
const gitPath =
|
|
12085
|
-
return
|
|
13268
|
+
const gitPath = path34.join(dir, ".git");
|
|
13269
|
+
return fs32.existsSync(gitPath) && fs32.lstatSync(gitPath).isDirectory();
|
|
12086
13270
|
} catch {
|
|
12087
13271
|
return false;
|
|
12088
13272
|
}
|
|
@@ -12276,7 +13460,7 @@ async function createApiContextWindow(fullHistory, currentAnchor, compressedTurn
|
|
|
12276
13460
|
|
|
12277
13461
|
// src/app/agent/core/llm/llm.ts
|
|
12278
13462
|
init_runtime_config();
|
|
12279
|
-
import
|
|
13463
|
+
import os22 from "os";
|
|
12280
13464
|
import OpenAI from "openai";
|
|
12281
13465
|
function defaultBlumaUserContextInput(sessionId, userMessage) {
|
|
12282
13466
|
const msg = String(userMessage || "").slice(0, 300);
|
|
@@ -12293,7 +13477,7 @@ function defaultBlumaUserContextInput(sessionId, userMessage) {
|
|
|
12293
13477
|
}
|
|
12294
13478
|
function getPreferredMacAddress() {
|
|
12295
13479
|
try {
|
|
12296
|
-
const ifaces =
|
|
13480
|
+
const ifaces = os22.networkInterfaces();
|
|
12297
13481
|
for (const name of Object.keys(ifaces)) {
|
|
12298
13482
|
const addrs = ifaces[name];
|
|
12299
13483
|
if (!addrs) continue;
|
|
@@ -12308,7 +13492,7 @@ function getPreferredMacAddress() {
|
|
|
12308
13492
|
} catch {
|
|
12309
13493
|
}
|
|
12310
13494
|
try {
|
|
12311
|
-
return `host:${
|
|
13495
|
+
return `host:${os22.hostname()}`;
|
|
12312
13496
|
} catch {
|
|
12313
13497
|
return "unknown";
|
|
12314
13498
|
}
|
|
@@ -12318,7 +13502,7 @@ function defaultInteractiveCliUserContextInput(sessionId, userMessage) {
|
|
|
12318
13502
|
const machineId = getPreferredMacAddress();
|
|
12319
13503
|
let userName = null;
|
|
12320
13504
|
try {
|
|
12321
|
-
userName =
|
|
13505
|
+
userName = os22.userInfo().username || null;
|
|
12322
13506
|
} catch {
|
|
12323
13507
|
userName = null;
|
|
12324
13508
|
}
|
|
@@ -12788,8 +13972,8 @@ function classifyToolInvocation(input) {
|
|
|
12788
13972
|
|
|
12789
13973
|
// src/app/agent/runtime/hook_registry.ts
|
|
12790
13974
|
init_sandbox_policy();
|
|
12791
|
-
import
|
|
12792
|
-
import
|
|
13975
|
+
import fs33 from "fs";
|
|
13976
|
+
import path35 from "path";
|
|
12793
13977
|
var DEFAULT_STATE = {
|
|
12794
13978
|
enabled: true,
|
|
12795
13979
|
maxEvents: 120,
|
|
@@ -12800,7 +13984,7 @@ var cache2 = null;
|
|
|
12800
13984
|
var cachePath2 = null;
|
|
12801
13985
|
function getStatePath() {
|
|
12802
13986
|
const policy = getSandboxPolicy();
|
|
12803
|
-
return
|
|
13987
|
+
return path35.join(policy.workspaceRoot, ".bluma", "hooks.json");
|
|
12804
13988
|
}
|
|
12805
13989
|
function getHookStatePath() {
|
|
12806
13990
|
return getStatePath();
|
|
@@ -12819,8 +14003,8 @@ function ensureLoaded2() {
|
|
|
12819
14003
|
return cache2;
|
|
12820
14004
|
}
|
|
12821
14005
|
try {
|
|
12822
|
-
if (
|
|
12823
|
-
const parsed = JSON.parse(
|
|
14006
|
+
if (fs33.existsSync(statePath)) {
|
|
14007
|
+
const parsed = JSON.parse(fs33.readFileSync(statePath, "utf-8"));
|
|
12824
14008
|
cache2 = {
|
|
12825
14009
|
enabled: typeof parsed.enabled === "boolean" ? parsed.enabled : DEFAULT_STATE.enabled,
|
|
12826
14010
|
maxEvents: typeof parsed.maxEvents === "number" && Number.isFinite(parsed.maxEvents) && parsed.maxEvents > 0 ? Math.floor(parsed.maxEvents) : DEFAULT_STATE.maxEvents,
|
|
@@ -12846,9 +14030,9 @@ function ensureLoaded2() {
|
|
|
12846
14030
|
}
|
|
12847
14031
|
function persist2(state) {
|
|
12848
14032
|
const statePath = getStatePath();
|
|
12849
|
-
|
|
14033
|
+
fs33.mkdirSync(path35.dirname(statePath), { recursive: true });
|
|
12850
14034
|
state.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
12851
|
-
|
|
14035
|
+
fs33.writeFileSync(statePath, JSON.stringify(state, null, 2), "utf-8");
|
|
12852
14036
|
cache2 = state;
|
|
12853
14037
|
cachePath2 = statePath;
|
|
12854
14038
|
}
|
|
@@ -12945,11 +14129,11 @@ function effectiveToolAutoApprove(toolCall, sessionId, options) {
|
|
|
12945
14129
|
}
|
|
12946
14130
|
|
|
12947
14131
|
// src/app/agent/tools/natives/coding_memory_consolidate.ts
|
|
12948
|
-
import * as
|
|
12949
|
-
import * as
|
|
12950
|
-
import
|
|
14132
|
+
import * as fs34 from "fs";
|
|
14133
|
+
import * as path36 from "path";
|
|
14134
|
+
import os23 from "os";
|
|
12951
14135
|
function memoryPath2() {
|
|
12952
|
-
return
|
|
14136
|
+
return path36.join(process.env.HOME || os23.homedir(), ".bluma", "coding_memory.json");
|
|
12953
14137
|
}
|
|
12954
14138
|
function normalizeNote2(note) {
|
|
12955
14139
|
return note.trim().toLowerCase().replace(/\s+/g, " ");
|
|
@@ -12959,18 +14143,18 @@ function uniqTags(a, b) {
|
|
|
12959
14143
|
}
|
|
12960
14144
|
function consolidateCodingMemoryFile() {
|
|
12961
14145
|
const p = memoryPath2();
|
|
12962
|
-
if (!
|
|
14146
|
+
if (!fs34.existsSync(p)) {
|
|
12963
14147
|
return { success: true, removedDuplicates: 0, message: "no coding_memory.json" };
|
|
12964
14148
|
}
|
|
12965
14149
|
const bak = `${p}.bak`;
|
|
12966
14150
|
try {
|
|
12967
|
-
|
|
14151
|
+
fs34.copyFileSync(p, bak);
|
|
12968
14152
|
} catch (e) {
|
|
12969
14153
|
return { success: false, removedDuplicates: 0, message: `backup failed: ${e.message}` };
|
|
12970
14154
|
}
|
|
12971
14155
|
let data;
|
|
12972
14156
|
try {
|
|
12973
|
-
data = JSON.parse(
|
|
14157
|
+
data = JSON.parse(fs34.readFileSync(p, "utf-8"));
|
|
12974
14158
|
} catch (e) {
|
|
12975
14159
|
return { success: false, removedDuplicates: 0, message: `invalid json: ${e.message}` };
|
|
12976
14160
|
}
|
|
@@ -13005,7 +14189,7 @@ function consolidateCodingMemoryFile() {
|
|
|
13005
14189
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
13006
14190
|
};
|
|
13007
14191
|
try {
|
|
13008
|
-
|
|
14192
|
+
fs34.writeFileSync(p, JSON.stringify(out, null, 2), "utf-8");
|
|
13009
14193
|
} catch (e) {
|
|
13010
14194
|
return { success: false, removedDuplicates: 0, message: `write failed: ${e.message}` };
|
|
13011
14195
|
}
|
|
@@ -13603,7 +14787,7 @@ var BluMaAgent = class {
|
|
|
13603
14787
|
|
|
13604
14788
|
${editData.error.display}`;
|
|
13605
14789
|
}
|
|
13606
|
-
const filename =
|
|
14790
|
+
const filename = path37.basename(toolArgs.file_path);
|
|
13607
14791
|
return createDiff(filename, editData.currentContent || "", editData.newContent);
|
|
13608
14792
|
} catch (e) {
|
|
13609
14793
|
return `An unexpected error occurred while generating the edit preview: ${e.message}`;
|
|
@@ -13694,6 +14878,7 @@ ${editData.error.display}`;
|
|
|
13694
14878
|
});
|
|
13695
14879
|
await this.notifyFactorTurnEndIfNeeded("empty_reply_exhausted");
|
|
13696
14880
|
this.eventBus.emit("backend_message", { type: "done", status: "failed" });
|
|
14881
|
+
process.exit(1);
|
|
13697
14882
|
return;
|
|
13698
14883
|
}
|
|
13699
14884
|
await this._continueConversation();
|
|
@@ -13827,6 +15012,7 @@ ${editData.error.display}`;
|
|
|
13827
15012
|
});
|
|
13828
15013
|
await this.notifyFactorTurnEndIfNeeded("protocol_direct_text_exhausted");
|
|
13829
15014
|
this.emitTurnCompleted();
|
|
15015
|
+
process.exit(1);
|
|
13830
15016
|
return;
|
|
13831
15017
|
}
|
|
13832
15018
|
const feedback = this.feedbackSystem.generateFeedback({
|
|
@@ -13914,6 +15100,7 @@ ${editData.error.display}`;
|
|
|
13914
15100
|
});
|
|
13915
15101
|
await this.notifyFactorTurnEndIfNeeded("protocol_direct_text_exhausted");
|
|
13916
15102
|
this.emitTurnCompleted();
|
|
15103
|
+
process.exit(1);
|
|
13917
15104
|
return;
|
|
13918
15105
|
}
|
|
13919
15106
|
const feedback = this.feedbackSystem.generateFeedback({
|
|
@@ -13989,7 +15176,7 @@ import { v4 as uuidv411 } from "uuid";
|
|
|
13989
15176
|
import { v4 as uuidv410 } from "uuid";
|
|
13990
15177
|
|
|
13991
15178
|
// src/app/agent/subagents/init/init_system_prompt.ts
|
|
13992
|
-
import
|
|
15179
|
+
import os24 from "os";
|
|
13993
15180
|
var SYSTEM_PROMPT2 = `
|
|
13994
15181
|
|
|
13995
15182
|
### YOU ARE BluMa CLI \u2014 INIT SUBAGENT \u2014 AUTONOMOUS SENIOR SOFTWARE ENGINEER @ NOMADENGENUITY
|
|
@@ -14152,12 +15339,12 @@ Rule Summary:
|
|
|
14152
15339
|
function getInitPrompt() {
|
|
14153
15340
|
const now2 = /* @__PURE__ */ new Date();
|
|
14154
15341
|
const collectedData = {
|
|
14155
|
-
os_type:
|
|
14156
|
-
os_version:
|
|
14157
|
-
architecture:
|
|
15342
|
+
os_type: os24.type(),
|
|
15343
|
+
os_version: os24.release(),
|
|
15344
|
+
architecture: os24.arch(),
|
|
14158
15345
|
workdir: process.cwd(),
|
|
14159
15346
|
shell_type: process.env.SHELL || process.env.COMSPEC || "Unknown",
|
|
14160
|
-
username:
|
|
15347
|
+
username: os24.userInfo().username || "Unknown",
|
|
14161
15348
|
current_date: now2.toISOString().split("T")[0],
|
|
14162
15349
|
// Formato YYYY-MM-DD
|
|
14163
15350
|
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone || "Unknown",
|
|
@@ -14185,7 +15372,7 @@ function getInitPrompt() {
|
|
|
14185
15372
|
}
|
|
14186
15373
|
|
|
14187
15374
|
// src/app/agent/subagents/worker_system_prompt.ts
|
|
14188
|
-
import
|
|
15375
|
+
import os25 from "os";
|
|
14189
15376
|
var WORKER_SYSTEM_PROMPT = `
|
|
14190
15377
|
|
|
14191
15378
|
### YOU ARE BluMa CLI \u2014 WORKER AGENT \u2014 AUTONOMOUS SOFTWARE ENGINEERING SPECIALIST @ NOMADENGENUITY
|
|
@@ -14450,12 +15637,12 @@ You may be assigned different types of work:
|
|
|
14450
15637
|
function getWorkerPrompt() {
|
|
14451
15638
|
const now2 = /* @__PURE__ */ new Date();
|
|
14452
15639
|
const collectedData = {
|
|
14453
|
-
os_type:
|
|
14454
|
-
os_version:
|
|
14455
|
-
architecture:
|
|
15640
|
+
os_type: os25.type(),
|
|
15641
|
+
os_version: os25.release(),
|
|
15642
|
+
architecture: os25.arch(),
|
|
14456
15643
|
workdir: process.cwd(),
|
|
14457
15644
|
shell_type: process.env.SHELL || process.env.COMSPEC || "Unknown",
|
|
14458
|
-
username:
|
|
15645
|
+
username: os25.userInfo().username || "Unknown",
|
|
14459
15646
|
current_date: now2.toISOString().split("T")[0],
|
|
14460
15647
|
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone || "Unknown",
|
|
14461
15648
|
locale: process.env.LANG || process.env.LC_ALL || "Unknown"
|
|
@@ -14573,16 +15760,16 @@ async function fullCompact(messages, targetTokens, summarizer, llmClient) {
|
|
|
14573
15760
|
}
|
|
14574
15761
|
|
|
14575
15762
|
// src/app/agent/core/memory/session_memory.ts
|
|
14576
|
-
import
|
|
14577
|
-
import
|
|
14578
|
-
import
|
|
15763
|
+
import fs35 from "fs";
|
|
15764
|
+
import os26 from "os";
|
|
15765
|
+
import path38 from "path";
|
|
14579
15766
|
import { v4 as uuidv49 } from "uuid";
|
|
14580
15767
|
var SessionMemoryExtractor = class {
|
|
14581
15768
|
llmClient;
|
|
14582
15769
|
memoryFile;
|
|
14583
15770
|
constructor(options = {}) {
|
|
14584
15771
|
this.llmClient = options.llmClient;
|
|
14585
|
-
this.memoryFile = options.memoryFile ||
|
|
15772
|
+
this.memoryFile = options.memoryFile || path38.join(os26.homedir(), ".bluma", "session_memory.json");
|
|
14586
15773
|
}
|
|
14587
15774
|
/**
|
|
14588
15775
|
* Extract memories from conversation using LLM
|
|
@@ -14639,15 +15826,15 @@ ${messages.slice(-50).map((m) => `${m.role}: ${m.content.slice(0, 500)}`).join("
|
|
|
14639
15826
|
);
|
|
14640
15827
|
unique.sort((a, b) => b.accessCount - a.accessCount);
|
|
14641
15828
|
const trimmed = unique.slice(0, 200);
|
|
14642
|
-
|
|
15829
|
+
fs35.writeFileSync(this.memoryFile, JSON.stringify(trimmed, null, 2));
|
|
14643
15830
|
}
|
|
14644
15831
|
/**
|
|
14645
15832
|
* Load memories from disk
|
|
14646
15833
|
*/
|
|
14647
15834
|
async loadMemories() {
|
|
14648
15835
|
try {
|
|
14649
|
-
if (!
|
|
14650
|
-
const data =
|
|
15836
|
+
if (!fs35.existsSync(this.memoryFile)) return [];
|
|
15837
|
+
const data = fs35.readFileSync(this.memoryFile, "utf-8");
|
|
14651
15838
|
return JSON.parse(data);
|
|
14652
15839
|
} catch {
|
|
14653
15840
|
return [];
|
|
@@ -15184,14 +16371,14 @@ var RouteManager = class {
|
|
|
15184
16371
|
this.subAgents = subAgents;
|
|
15185
16372
|
this.core = core;
|
|
15186
16373
|
}
|
|
15187
|
-
registerRoute(
|
|
15188
|
-
this.routeHandlers.set(
|
|
16374
|
+
registerRoute(path43, handler) {
|
|
16375
|
+
this.routeHandlers.set(path43, handler);
|
|
15189
16376
|
}
|
|
15190
16377
|
async handleRoute(payload) {
|
|
15191
16378
|
const inputText = String(payload.content || "").trim();
|
|
15192
16379
|
const { userContext } = payload;
|
|
15193
|
-
for (const [
|
|
15194
|
-
if (inputText ===
|
|
16380
|
+
for (const [path43, handler] of this.routeHandlers) {
|
|
16381
|
+
if (inputText === path43 || inputText.startsWith(`${path43} `)) {
|
|
15195
16382
|
return handler({ content: inputText, userContext });
|
|
15196
16383
|
}
|
|
15197
16384
|
}
|
|
@@ -15200,13 +16387,13 @@ var RouteManager = class {
|
|
|
15200
16387
|
};
|
|
15201
16388
|
|
|
15202
16389
|
// src/app/agent/runtime/plugin_runtime.ts
|
|
15203
|
-
import
|
|
16390
|
+
import path39 from "path";
|
|
15204
16391
|
import { pathToFileURL as pathToFileURL2 } from "url";
|
|
15205
16392
|
async function loadPluginsAtStartup() {
|
|
15206
16393
|
for (const p of listPlugins()) {
|
|
15207
16394
|
const entry = p.manifest.entry?.trim();
|
|
15208
16395
|
if (!entry) continue;
|
|
15209
|
-
const abs =
|
|
16396
|
+
const abs = path39.resolve(p.root, entry);
|
|
15210
16397
|
try {
|
|
15211
16398
|
const href = pathToFileURL2(abs).href;
|
|
15212
16399
|
const mod = await import(href);
|
|
@@ -15227,7 +16414,7 @@ async function loadPluginsAtStartup() {
|
|
|
15227
16414
|
}
|
|
15228
16415
|
|
|
15229
16416
|
// src/app/agent/agent.ts
|
|
15230
|
-
var globalEnvPath =
|
|
16417
|
+
var globalEnvPath = path40.join(os27.homedir(), ".bluma", ".env");
|
|
15231
16418
|
dotenv.config({ path: globalEnvPath });
|
|
15232
16419
|
var Agent = class {
|
|
15233
16420
|
sessionId;
|
|
@@ -18467,16 +19654,16 @@ import latestVersion from "latest-version";
|
|
|
18467
19654
|
import semverGt from "semver/functions/gt.js";
|
|
18468
19655
|
import semverValid from "semver/functions/valid.js";
|
|
18469
19656
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
18470
|
-
import
|
|
18471
|
-
import
|
|
19657
|
+
import path41 from "path";
|
|
19658
|
+
import fs36 from "fs";
|
|
18472
19659
|
var BLUMA_PACKAGE_NAME = "@nomad-e/bluma-cli";
|
|
18473
19660
|
function findBlumaPackageJson(startDir) {
|
|
18474
19661
|
let dir = startDir;
|
|
18475
19662
|
for (let i = 0; i < 12; i++) {
|
|
18476
|
-
const candidate =
|
|
18477
|
-
if (
|
|
19663
|
+
const candidate = path41.join(dir, "package.json");
|
|
19664
|
+
if (fs36.existsSync(candidate)) {
|
|
18478
19665
|
try {
|
|
18479
|
-
const raw =
|
|
19666
|
+
const raw = fs36.readFileSync(candidate, "utf8");
|
|
18480
19667
|
const parsed = JSON.parse(raw);
|
|
18481
19668
|
if (parsed?.name === BLUMA_PACKAGE_NAME && parsed?.version) {
|
|
18482
19669
|
return { name: parsed.name, version: String(parsed.version) };
|
|
@@ -18484,7 +19671,7 @@ function findBlumaPackageJson(startDir) {
|
|
|
18484
19671
|
} catch {
|
|
18485
19672
|
}
|
|
18486
19673
|
}
|
|
18487
|
-
const parent =
|
|
19674
|
+
const parent = path41.dirname(dir);
|
|
18488
19675
|
if (parent === dir) break;
|
|
18489
19676
|
dir = parent;
|
|
18490
19677
|
}
|
|
@@ -18493,13 +19680,13 @@ function findBlumaPackageJson(startDir) {
|
|
|
18493
19680
|
function resolveInstalledBlumaPackage() {
|
|
18494
19681
|
const tried = /* @__PURE__ */ new Set();
|
|
18495
19682
|
const tryFrom = (dir) => {
|
|
18496
|
-
const abs =
|
|
19683
|
+
const abs = path41.resolve(dir);
|
|
18497
19684
|
if (tried.has(abs)) return null;
|
|
18498
19685
|
tried.add(abs);
|
|
18499
19686
|
return findBlumaPackageJson(abs);
|
|
18500
19687
|
};
|
|
18501
19688
|
try {
|
|
18502
|
-
const fromBundle = tryFrom(
|
|
19689
|
+
const fromBundle = tryFrom(path41.dirname(fileURLToPath5(import.meta.url)));
|
|
18503
19690
|
if (fromBundle) return fromBundle;
|
|
18504
19691
|
} catch {
|
|
18505
19692
|
}
|
|
@@ -18507,12 +19694,12 @@ function resolveInstalledBlumaPackage() {
|
|
|
18507
19694
|
if (argv1 && !argv1.startsWith("-")) {
|
|
18508
19695
|
try {
|
|
18509
19696
|
let resolved = argv1;
|
|
18510
|
-
if (
|
|
18511
|
-
resolved =
|
|
19697
|
+
if (path41.isAbsolute(argv1) && fs36.existsSync(argv1)) {
|
|
19698
|
+
resolved = fs36.realpathSync(argv1);
|
|
18512
19699
|
} else {
|
|
18513
|
-
resolved =
|
|
19700
|
+
resolved = path41.resolve(process.cwd(), argv1);
|
|
18514
19701
|
}
|
|
18515
|
-
const fromArgv = tryFrom(
|
|
19702
|
+
const fromArgv = tryFrom(path41.dirname(resolved));
|
|
18516
19703
|
if (fromArgv) return fromArgv;
|
|
18517
19704
|
} catch {
|
|
18518
19705
|
}
|
|
@@ -20052,9 +21239,9 @@ async function runAgentMode() {
|
|
|
20052
21239
|
try {
|
|
20053
21240
|
if (inputFileIndex !== -1 && args[inputFileIndex + 1]) {
|
|
20054
21241
|
const filePath = args[inputFileIndex + 1];
|
|
20055
|
-
rawPayload =
|
|
21242
|
+
rawPayload = fs37.readFileSync(filePath, "utf-8");
|
|
20056
21243
|
} else {
|
|
20057
|
-
rawPayload =
|
|
21244
|
+
rawPayload = fs37.readFileSync(0, "utf-8");
|
|
20058
21245
|
}
|
|
20059
21246
|
} catch (err) {
|
|
20060
21247
|
writeAgentEvent(registrySessionId, {
|
|
@@ -20252,9 +21439,9 @@ async function runAgentMode() {
|
|
|
20252
21439
|
}
|
|
20253
21440
|
function readCliPackageVersion() {
|
|
20254
21441
|
try {
|
|
20255
|
-
const base =
|
|
20256
|
-
const pkgPath =
|
|
20257
|
-
const j = JSON.parse(
|
|
21442
|
+
const base = path42.dirname(fileURLToPath6(import.meta.url));
|
|
21443
|
+
const pkgPath = path42.join(base, "..", "package.json");
|
|
21444
|
+
const j = JSON.parse(fs37.readFileSync(pkgPath, "utf8"));
|
|
20258
21445
|
return String(j.version || "0.0.0");
|
|
20259
21446
|
} catch {
|
|
20260
21447
|
return "0.0.0";
|
|
@@ -20377,7 +21564,7 @@ function startBackgroundAgent() {
|
|
|
20377
21564
|
process.exit(1);
|
|
20378
21565
|
}
|
|
20379
21566
|
const filePath = args[inputFileIndex + 1];
|
|
20380
|
-
const rawPayload =
|
|
21567
|
+
const rawPayload = fs37.readFileSync(filePath, "utf-8");
|
|
20381
21568
|
const envelope = JSON.parse(rawPayload);
|
|
20382
21569
|
const sessionId = envelope.session_id || envelope.message_id || uuidv412();
|
|
20383
21570
|
registerSession({
|
|
@@ -20394,7 +21581,7 @@ function startBackgroundAgent() {
|
|
|
20394
21581
|
}
|
|
20395
21582
|
});
|
|
20396
21583
|
const childArgs = [process.argv[1], "agent", "--input-file", filePath, "--background-worker", "--registry-session", sessionId];
|
|
20397
|
-
const child =
|
|
21584
|
+
const child = spawn6(process.execPath, childArgs, {
|
|
20398
21585
|
detached: true,
|
|
20399
21586
|
stdio: "ignore",
|
|
20400
21587
|
cwd: process.cwd(),
|