@nomad-e/bluma-cli 0.19.0 → 0.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/main.js +322 -116
- package/package.json +1 -1
package/dist/main.js
CHANGED
|
@@ -3204,7 +3204,7 @@ __export(exportConversation_exports, {
|
|
|
3204
3204
|
formatConversationMarkdown: () => formatConversationMarkdown,
|
|
3205
3205
|
resolveExportOutputPath: () => resolveExportOutputPath
|
|
3206
3206
|
});
|
|
3207
|
-
import { promises as
|
|
3207
|
+
import { promises as fs49 } from "fs";
|
|
3208
3208
|
import path54 from "path";
|
|
3209
3209
|
function extractTextParts2(content) {
|
|
3210
3210
|
if (typeof content === "string") {
|
|
@@ -3390,8 +3390,8 @@ async function exportConversationToFile(options) {
|
|
|
3390
3390
|
}
|
|
3391
3391
|
const markdown = formatConversationMarkdown(sessionId, history);
|
|
3392
3392
|
const filePath = resolveExportOutputPath(sessionId, { outputPath, defaultExportDir });
|
|
3393
|
-
await
|
|
3394
|
-
await
|
|
3393
|
+
await fs49.mkdir(path54.dirname(filePath), { recursive: true });
|
|
3394
|
+
await fs49.writeFile(filePath, markdown, "utf-8");
|
|
3395
3395
|
return {
|
|
3396
3396
|
success: true,
|
|
3397
3397
|
filePath,
|
|
@@ -14299,7 +14299,7 @@ var getInstance = (stdout, createInstance) => {
|
|
|
14299
14299
|
|
|
14300
14300
|
// src/main.ts
|
|
14301
14301
|
import { EventEmitter as EventEmitter7 } from "events";
|
|
14302
|
-
import
|
|
14302
|
+
import fs53 from "fs";
|
|
14303
14303
|
import path58 from "path";
|
|
14304
14304
|
import { fileURLToPath as fileURLToPath8 } from "url";
|
|
14305
14305
|
import { spawn as spawn6 } from "child_process";
|
|
@@ -22029,12 +22029,12 @@ PENALTY APPLIED: ${penalty.toFixed(1)} points deducted.
|
|
|
22029
22029
|
// src/app/agent/bluma/core/bluma.ts
|
|
22030
22030
|
init_session_manager();
|
|
22031
22031
|
import path45 from "path";
|
|
22032
|
-
import
|
|
22032
|
+
import fs41 from "fs";
|
|
22033
22033
|
import { v4 as uuidv48 } from "uuid";
|
|
22034
22034
|
|
|
22035
22035
|
// src/app/agent/core/prompt/prompt_builder.ts
|
|
22036
22036
|
import os23 from "os";
|
|
22037
|
-
import
|
|
22037
|
+
import fs37 from "fs";
|
|
22038
22038
|
import path39 from "path";
|
|
22039
22039
|
import { execSync as execSync3 } from "child_process";
|
|
22040
22040
|
|
|
@@ -23923,14 +23923,14 @@ var FACTORAI_SH_SECTION = `
|
|
|
23923
23923
|
|
|
23924
23924
|
**When to load full checklist:** \`load_skill("factorai-sh")\` before any create/deploy/edit/redeploy task.
|
|
23925
23925
|
|
|
23926
|
-
### Backend URL (
|
|
23926
|
+
### Backend URL (see also \`<sandbox_runtime>\` table)
|
|
23927
23927
|
| Variable | Used by |
|
|
23928
23928
|
|----------|---------|
|
|
23929
23929
|
| \`FACTORAI_BASE_URL\` | \`factorai.sh.get_app_status\`, \`factorai.sh.apply_app_changes\`, \`factorai.sh.redeploy_app\` |
|
|
23930
23930
|
| \`SEVERINO_URL\` | \`factorai.sh.deploy_app\` (ZIP upload to \`/api/v1/deploy\`) |
|
|
23931
23931
|
| \`FACTORAI_API_KEY\` / \`SEVERINO_API_KEY\` | Optional Bearer on write endpoints |
|
|
23932
23932
|
|
|
23933
|
-
The orchestrator configures these \u2014 **use the values
|
|
23933
|
+
The orchestrator configures these \u2014 **use the values in \`<sandbox_runtime>\`**, not invented hosts. Autonomous loop: \`tsc --noEmit\` locally \u2192 \`deploy_app\` \u2192 \`get_app_status({ wait: true })\` \u2192 fix on \`failed\` \u2192 only then \`message(result)\`.
|
|
23934
23934
|
|
|
23935
23935
|
### Source of truth: \`factorai.sh.json\`
|
|
23936
23936
|
- Written/updated by \`factorai.sh.deploy_app\` and FactorAI tools \u2014 **read with normal file tools**, never a separate manifest tool.
|
|
@@ -24013,7 +24013,196 @@ function isFactorAiShPromptEnabled() {
|
|
|
24013
24013
|
return isSandbox && Boolean(baseUrl);
|
|
24014
24014
|
}
|
|
24015
24015
|
|
|
24016
|
+
// src/app/agent/core/prompt/sandbox_autonomy_prompt.ts
|
|
24017
|
+
var SANDBOX_AUTONOMY_SECTION = `
|
|
24018
|
+
<sandbox_autonomy>
|
|
24019
|
+
## Modo aut\xF3nomo (como Manus / agente de engenharia)
|
|
24020
|
+
|
|
24021
|
+
Tu **n\xE3o** est\xE1s num chat interativo com humano ao teclado. Est\xE1s num **worker** com um objetivo, ferramentas, e um prazo. Comportamento esperado:
|
|
24022
|
+
|
|
24023
|
+
### 1. Orientar-te (sempre primeiro)
|
|
24024
|
+
- L\xEA \`<sandbox_runtime>\` \u2014 session, cwd, URLs, pedido, \`factorai.sh.json\` se existir.
|
|
24025
|
+
- Se o pedido envolve Next.js / site / deploy: \`load_skill("factorai-sh")\`.
|
|
24026
|
+
- Lista o diret\xF3rio relevante (\`ls_tool\`) antes de assumir estrutura de ficheiros.
|
|
24027
|
+
|
|
24028
|
+
### 2. Planear em sil\xEAncio \xFAtil
|
|
24029
|
+
- Usa \`todo\` ou \`task_create\` para 3\u20138 passos concretos (n\xE3o gen\xE9ricos).
|
|
24030
|
+
- \`message({ message_type: "info" })\` a cada fase importante \u2014 o orquestrador v\xEA progresso.
|
|
24031
|
+
|
|
24032
|
+
### 3. Implementar como humano s\xE9nior
|
|
24033
|
+
- Edita com \`edit_tool\` / \`file_write\`; l\xEA ficheiros completos antes de patch grande.
|
|
24034
|
+
- UI Next: \`@/components/ui/*\` do scaffold; n\xE3o reinventar componentes.
|
|
24035
|
+
- Subtarefas paralelas: \`spawn_agent\` + \`wait_agent\` quando fizer sentido.
|
|
24036
|
+
|
|
24037
|
+
### 4. Verificar **antes** de deploy (obrigat\xF3rio para apps Next)
|
|
24038
|
+
No diret\xF3rio do projeto (ex. \`./my-app\`):
|
|
24039
|
+
1. \`npx tsc --noEmit\` \u2014 corrige todos os erros TypeScript.
|
|
24040
|
+
2. Opcional: \`npm run lint\` se existir script.
|
|
24041
|
+
3. **Evita** \`npm run build\` local **antes do primeiro** \`deploy_app\` (cria \`.next/\` e incha o ZIP). O build de produ\xE7\xE3o corre no FactorAI.sh.
|
|
24042
|
+
|
|
24043
|
+
### 5. Deploy e valida\xE7\xE3o remota
|
|
24044
|
+
1. \`factorai.sh.deploy_app({ projectDir, name })\` \u2014 primeiro deploy.
|
|
24045
|
+
2. \`factorai.sh.get_app_status({ appId, wait: true })\` \u2014 espera \`ready\` ou \`failed\`.
|
|
24046
|
+
3. Se \`failed\`: l\xEA \`typescriptErrors\`, \`buildLogTail\`, \`summary\` no resultado; corrige c\xF3digo; \`apply_app_changes\` ou novo deploy; **nunca** digas que est\xE1 online.
|
|
24047
|
+
4. S\xF3 depois de \`ready\`: confirma URL (curl ou l\xF3gica) e \`message(result)\` com \`factor-sh-url-app\`.
|
|
24048
|
+
|
|
24049
|
+
### 6. Edi\xE7\xF5es em app j\xE1 online (esta sess\xE3o)
|
|
24050
|
+
- \`factorai.sh.apply_app_changes\` com ficheiro **completo** em cada \`files[].content\`.
|
|
24051
|
+
- Volta a \`get_app_status({ wait: true })\` ap\xF3s rebuild.
|
|
24052
|
+
|
|
24053
|
+
### 7. Entregar como produto acabado
|
|
24054
|
+
- Ficheiros: \`message(result)\` + \`attachments\` em \`.bluma/artifacts/\`.
|
|
24055
|
+
- App live: \`factor-sh-url-app\` com URL absoluta.
|
|
24056
|
+
- Resumo em portugu\xEAs claro: o que fizeste, URL, pr\xF3ximos passos se falhou.
|
|
24057
|
+
|
|
24058
|
+
### Proibido no sandbox worker
|
|
24059
|
+
- Pedir confirma\xE7\xE3o ao utilizador (\`ask_user_question\`) salvo bloqueio real de credencial em falta no env.
|
|
24060
|
+
- Inventar URLs, appIds, ou hosts \u2014 usa s\xF3 \`<sandbox_runtime>\` e \`factorai.sh.json\`.
|
|
24061
|
+
- \`message(result)\` com sucesso se deploy/build falhou.
|
|
24062
|
+
- Ignorar erros de compila\xE7\xE3o (\u201Cvou deploy na mesma\u201D).
|
|
24063
|
+
</sandbox_autonomy>
|
|
24064
|
+
`;
|
|
24065
|
+
|
|
24066
|
+
// src/app/agent/runtime/sandbox_runtime_context.ts
|
|
24067
|
+
import fs36 from "fs";
|
|
24068
|
+
function env2(key) {
|
|
24069
|
+
return String(process.env[key] ?? "").trim();
|
|
24070
|
+
}
|
|
24071
|
+
function pickRuntime(cwd2, injected) {
|
|
24072
|
+
const severinoUrl = injected?.severinoUrl || env2("SEVERINO_URL");
|
|
24073
|
+
const factoraiBaseUrl = injected?.factoraiBaseUrl || env2("FACTORAI_BASE_URL") || env2("FACTORAI_URL") || severinoUrl;
|
|
24074
|
+
return {
|
|
24075
|
+
sandboxName: injected?.sandboxName || env2("BLUMA_SANDBOX_NAME") || "sandbox-api",
|
|
24076
|
+
sessionId: injected?.sessionId || env2("BLUMA_SESSION_ID") || "unknown",
|
|
24077
|
+
workspaceRoot: injected?.workspaceRoot || cwd2,
|
|
24078
|
+
fromAgent: injected?.fromAgent || env2("BLUMA_FROM_AGENT") || "orchestrator",
|
|
24079
|
+
action: injected?.action || env2("BLUMA_ACTION") || "unknown",
|
|
24080
|
+
severinoUrl: severinoUrl || void 0,
|
|
24081
|
+
factoraiBaseUrl: factoraiBaseUrl || void 0,
|
|
24082
|
+
severinoApiKeyConfigured: injected?.severinoApiKeyConfigured ?? Boolean(env2("SEVERINO_API_KEY") || env2("SEVERINO_TOKEN")),
|
|
24083
|
+
factoraiApiKeyConfigured: injected?.factoraiApiKeyConfigured ?? Boolean(env2("FACTORAI_API_KEY") || env2("FACTORAI_TOKEN")),
|
|
24084
|
+
timeoutSeconds: injected?.timeoutSeconds,
|
|
24085
|
+
userRequest: injected?.userRequest || env2("BLUMA_USER_REQUEST") || void 0,
|
|
24086
|
+
operatorMode: injected?.operatorMode || "autonomous_worker",
|
|
24087
|
+
injectedAt: injected?.injectedAt
|
|
24088
|
+
};
|
|
24089
|
+
}
|
|
24090
|
+
function applySandboxRuntimeFromEnvelope(envelope) {
|
|
24091
|
+
const rt = envelope.sandbox_runtime;
|
|
24092
|
+
if (!rt || typeof rt !== "object") {
|
|
24093
|
+
return null;
|
|
24094
|
+
}
|
|
24095
|
+
process.env.BLUMA_SANDBOX = "true";
|
|
24096
|
+
if (rt.sandboxName) process.env.BLUMA_SANDBOX_NAME = rt.sandboxName;
|
|
24097
|
+
if (rt.sessionId) process.env.BLUMA_SESSION_ID = rt.sessionId;
|
|
24098
|
+
if (rt.fromAgent) process.env.BLUMA_FROM_AGENT = rt.fromAgent;
|
|
24099
|
+
if (rt.action) process.env.BLUMA_ACTION = rt.action;
|
|
24100
|
+
if (rt.severinoUrl) process.env.SEVERINO_URL = rt.severinoUrl.replace(/\/$/, "");
|
|
24101
|
+
if (rt.factoraiBaseUrl) {
|
|
24102
|
+
process.env.FACTORAI_BASE_URL = rt.factoraiBaseUrl.replace(/\/$/, "");
|
|
24103
|
+
} else if (rt.severinoUrl && !env2("FACTORAI_BASE_URL")) {
|
|
24104
|
+
process.env.FACTORAI_BASE_URL = rt.severinoUrl.replace(/\/$/, "");
|
|
24105
|
+
}
|
|
24106
|
+
if (rt.userRequest?.trim()) {
|
|
24107
|
+
process.env.BLUMA_USER_REQUEST = rt.userRequest.trim();
|
|
24108
|
+
}
|
|
24109
|
+
if (typeof rt.timeoutSeconds === "number" && rt.timeoutSeconds > 0) {
|
|
24110
|
+
process.env.BLUMA_JOB_TIMEOUT_SECONDS = String(rt.timeoutSeconds);
|
|
24111
|
+
}
|
|
24112
|
+
if (rt.workspaceRoot) {
|
|
24113
|
+
process.env.BLUMA_SANDBOX_WORKSPACE = rt.workspaceRoot;
|
|
24114
|
+
}
|
|
24115
|
+
if (envelope.metadata?.sandbox === true && !process.env.BLUMA_SANDBOX_NAME?.trim()) {
|
|
24116
|
+
process.env.BLUMA_SANDBOX_NAME = String(envelope.metadata.sandbox_name || "sandbox-api");
|
|
24117
|
+
}
|
|
24118
|
+
return rt;
|
|
24119
|
+
}
|
|
24120
|
+
function listWorkspaceTopLevel(cwd2, max = 24) {
|
|
24121
|
+
try {
|
|
24122
|
+
return fs36.readdirSync(cwd2, { withFileTypes: true }).filter((e) => !e.name.startsWith(".")).slice(0, max).map((e) => e.isDirectory() ? `${e.name}/` : e.name);
|
|
24123
|
+
} catch {
|
|
24124
|
+
return [];
|
|
24125
|
+
}
|
|
24126
|
+
}
|
|
24127
|
+
function buildSandboxRuntimeContextBlock(cwd2, injected) {
|
|
24128
|
+
const rt = pickRuntime(cwd2, injected);
|
|
24129
|
+
const factoraiEnabled = isFactorAiShPromptEnabled();
|
|
24130
|
+
const top = listWorkspaceTopLevel(cwd2);
|
|
24131
|
+
const lines = [
|
|
24132
|
+
"<sandbox_runtime>",
|
|
24133
|
+
"## Ambiente atual (injetado pelo orquestrador \u2014 factos autoritativos)",
|
|
24134
|
+
"",
|
|
24135
|
+
rt.injectedAt ? `_Atualizado: ${rt.injectedAt}_` : "_Dados do envelope stdin + env da sess\xE3o_",
|
|
24136
|
+
"",
|
|
24137
|
+
`Modo: **${rt.operatorMode || "autonomous_worker"}** (sem humano no terminal; progresso via \`message(info)\`, fim via \`message(result)\`).`,
|
|
24138
|
+
"",
|
|
24139
|
+
"| Campo | Valor |",
|
|
24140
|
+
"|-------|-------|",
|
|
24141
|
+
`| sandbox | ${rt.sandboxName} |`,
|
|
24142
|
+
`| session_id | ${rt.sessionId} |`,
|
|
24143
|
+
`| workspace (cwd) | ${rt.workspaceRoot || cwd2} |`,
|
|
24144
|
+
`| delegado por | ${rt.fromAgent} |`,
|
|
24145
|
+
`| action | ${rt.action} |`,
|
|
24146
|
+
`| node | ${process.version} |`,
|
|
24147
|
+
`| job_timeout_seconds | ${rt.timeoutSeconds ?? (env2("BLUMA_JOB_TIMEOUT_SECONDS") || "\u2014")} |`,
|
|
24148
|
+
`| auto_approve_tools | sim |`
|
|
24149
|
+
];
|
|
24150
|
+
if (rt.severinoUrl) {
|
|
24151
|
+
lines.push(`| SEVERINO_URL (deploy ZIP) | ${rt.severinoUrl} |`);
|
|
24152
|
+
lines.push(`| SEVERINO_API_KEY | ${rt.severinoApiKeyConfigured ? "configurada" : "ausente"} |`);
|
|
24153
|
+
}
|
|
24154
|
+
if (rt.factoraiBaseUrl) {
|
|
24155
|
+
lines.push(`| FACTORAI_BASE_URL | ${rt.factoraiBaseUrl} |`);
|
|
24156
|
+
lines.push(`| FACTORAI_API_KEY | ${rt.factoraiApiKeyConfigured ? "configurada" : "ausente"} |`);
|
|
24157
|
+
}
|
|
24158
|
+
if (rt.severinoUrl && rt.factoraiBaseUrl && rt.severinoUrl !== rt.factoraiBaseUrl) {
|
|
24159
|
+
lines.push("");
|
|
24160
|
+
lines.push("\u26A0\uFE0F SEVERINO_URL \u2260 FACTORAI_BASE_URL \u2014 usa o host certo por tool.");
|
|
24161
|
+
}
|
|
24162
|
+
lines.push("");
|
|
24163
|
+
lines.push(
|
|
24164
|
+
factoraiEnabled ? "**FactorAI.sh:** ativo (`factorai.sh.*` dispon\xEDveis)." : "**FactorAI.sh:** inativo \u2014 orquestrador deve definir FACTORAI_BASE_URL + BLUMA_SANDBOX."
|
|
24165
|
+
);
|
|
24166
|
+
if (top.length > 0) {
|
|
24167
|
+
lines.push("");
|
|
24168
|
+
lines.push(`**Raiz do workspace:** ${top.join(", ")}`);
|
|
24169
|
+
}
|
|
24170
|
+
const manifest = readFactorAiWorkspaceManifest(cwd2);
|
|
24171
|
+
if (manifest) {
|
|
24172
|
+
const ctx = manifest.appContext;
|
|
24173
|
+
const liveUrl = resolveFactorShAppLiveUrl(cwd2);
|
|
24174
|
+
lines.push("");
|
|
24175
|
+
lines.push("**App FactorAI (factorai.sh.json no workspace):**");
|
|
24176
|
+
if (ctx?.appId) lines.push(`- appId: ${ctx.appId}`);
|
|
24177
|
+
if (liveUrl) lines.push(`- appUrl: ${liveUrl}`);
|
|
24178
|
+
}
|
|
24179
|
+
if (rt.userRequest) {
|
|
24180
|
+
lines.push("");
|
|
24181
|
+
lines.push("**Pedido deste job (user_request):**");
|
|
24182
|
+
lines.push(rt.userRequest.length > 4e3 ? `${rt.userRequest.slice(0, 4e3)}\u2026` : rt.userRequest);
|
|
24183
|
+
}
|
|
24184
|
+
lines.push("</sandbox_runtime>");
|
|
24185
|
+
return lines.join("\n");
|
|
24186
|
+
}
|
|
24187
|
+
function formatSandboxRuntimeUserTurnPrefix(rt) {
|
|
24188
|
+
const parts = [
|
|
24189
|
+
"<sandbox_runtime_injected>",
|
|
24190
|
+
`session=${rt.sessionId ?? "?"}`,
|
|
24191
|
+
`action=${rt.action ?? "?"}`,
|
|
24192
|
+
`from=${rt.fromAgent ?? "?"}`,
|
|
24193
|
+
rt.severinoUrl ? `SEVERINO_URL=${rt.severinoUrl}` : null,
|
|
24194
|
+
rt.factoraiBaseUrl ? `FACTORAI_BASE_URL=${rt.factoraiBaseUrl}` : null,
|
|
24195
|
+
typeof rt.timeoutSeconds === "number" ? `timeout_seconds=${rt.timeoutSeconds}` : null,
|
|
24196
|
+
"</sandbox_runtime_injected>"
|
|
24197
|
+
].filter(Boolean);
|
|
24198
|
+
return parts.join("\n");
|
|
24199
|
+
}
|
|
24200
|
+
|
|
24016
24201
|
// src/app/agent/core/prompt/prompt_builder.ts
|
|
24202
|
+
var _injectedSandboxRuntime = null;
|
|
24203
|
+
function setInjectedSandboxRuntimeForPrompt(rt) {
|
|
24204
|
+
_injectedSandboxRuntime = rt;
|
|
24205
|
+
}
|
|
24017
24206
|
function getNodeVersion() {
|
|
24018
24207
|
return process.version;
|
|
24019
24208
|
}
|
|
@@ -24044,17 +24233,17 @@ function getGitBranch(dir) {
|
|
|
24044
24233
|
}
|
|
24045
24234
|
}
|
|
24046
24235
|
function getPackageManager(dir) {
|
|
24047
|
-
if (
|
|
24048
|
-
if (
|
|
24049
|
-
if (
|
|
24050
|
-
if (
|
|
24236
|
+
if (fs37.existsSync(path39.join(dir, "pnpm-lock.yaml"))) return "pnpm";
|
|
24237
|
+
if (fs37.existsSync(path39.join(dir, "yarn.lock"))) return "yarn";
|
|
24238
|
+
if (fs37.existsSync(path39.join(dir, "bun.lockb"))) return "bun";
|
|
24239
|
+
if (fs37.existsSync(path39.join(dir, "package-lock.json"))) return "npm";
|
|
24051
24240
|
return "unknown";
|
|
24052
24241
|
}
|
|
24053
24242
|
function getProjectType(dir) {
|
|
24054
24243
|
try {
|
|
24055
|
-
const files =
|
|
24244
|
+
const files = fs37.readdirSync(dir);
|
|
24056
24245
|
if (files.includes("package.json")) {
|
|
24057
|
-
const pkg = JSON.parse(
|
|
24246
|
+
const pkg = JSON.parse(fs37.readFileSync(path39.join(dir, "package.json"), "utf-8"));
|
|
24058
24247
|
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
24059
24248
|
if (deps.next) return "Next.js";
|
|
24060
24249
|
if (deps.react) return "React";
|
|
@@ -24075,8 +24264,8 @@ function getProjectType(dir) {
|
|
|
24075
24264
|
function getTestFramework(dir) {
|
|
24076
24265
|
try {
|
|
24077
24266
|
const pkgPath = path39.join(dir, "package.json");
|
|
24078
|
-
if (
|
|
24079
|
-
const pkg = JSON.parse(
|
|
24267
|
+
if (fs37.existsSync(pkgPath)) {
|
|
24268
|
+
const pkg = JSON.parse(fs37.readFileSync(pkgPath, "utf-8"));
|
|
24080
24269
|
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
24081
24270
|
if (deps.jest) return "jest";
|
|
24082
24271
|
if (deps.vitest) return "vitest";
|
|
@@ -24085,7 +24274,7 @@ function getTestFramework(dir) {
|
|
|
24085
24274
|
if (deps["@playwright/test"]) return "playwright";
|
|
24086
24275
|
if (deps.cypress) return "cypress";
|
|
24087
24276
|
}
|
|
24088
|
-
if (
|
|
24277
|
+
if (fs37.existsSync(path39.join(dir, "pytest.ini")) || fs37.existsSync(path39.join(dir, "conftest.py"))) return "pytest";
|
|
24089
24278
|
return "unknown";
|
|
24090
24279
|
} catch {
|
|
24091
24280
|
return "unknown";
|
|
@@ -24094,8 +24283,8 @@ function getTestFramework(dir) {
|
|
|
24094
24283
|
function getTestCommand(dir) {
|
|
24095
24284
|
try {
|
|
24096
24285
|
const pkgPath = path39.join(dir, "package.json");
|
|
24097
|
-
if (
|
|
24098
|
-
const pkg = JSON.parse(
|
|
24286
|
+
if (fs37.existsSync(pkgPath)) {
|
|
24287
|
+
const pkg = JSON.parse(fs37.readFileSync(pkgPath, "utf-8"));
|
|
24099
24288
|
if (pkg.scripts?.test) return "npm test";
|
|
24100
24289
|
if (pkg.scripts?.["test:unit"]) return "npm run test:unit";
|
|
24101
24290
|
}
|
|
@@ -24111,7 +24300,7 @@ function getTestCommand(dir) {
|
|
|
24111
24300
|
function isGitRepo(dir) {
|
|
24112
24301
|
try {
|
|
24113
24302
|
const p = path39.join(dir, ".git");
|
|
24114
|
-
return
|
|
24303
|
+
return fs37.existsSync(p) && fs37.lstatSync(p).isDirectory();
|
|
24115
24304
|
} catch {
|
|
24116
24305
|
return false;
|
|
24117
24306
|
}
|
|
@@ -24322,7 +24511,7 @@ async function getUnifiedSystemPrompt(availableSkills, options) {
|
|
|
24322
24511
|
const runtimeConfig = getRuntimeConfig();
|
|
24323
24512
|
const cwd2 = process.cwd();
|
|
24324
24513
|
const isSandbox = process.env.BLUMA_SANDBOX === "true";
|
|
24325
|
-
const
|
|
24514
|
+
const env3 = {
|
|
24326
24515
|
os_type: os23.type(),
|
|
24327
24516
|
os_version: os23.release(),
|
|
24328
24517
|
architecture: os23.arch(),
|
|
@@ -24347,7 +24536,7 @@ async function getUnifiedSystemPrompt(availableSkills, options) {
|
|
|
24347
24536
|
session_id: process.env.BLUMA_SESSION_ID || "unknown",
|
|
24348
24537
|
workspace_root: cwd2
|
|
24349
24538
|
};
|
|
24350
|
-
const interpolate = (template) => Object.entries(
|
|
24539
|
+
const interpolate = (template) => Object.entries(env3).reduce((s, [k, v]) => s.replaceAll(`{${k}}`, v), template);
|
|
24351
24540
|
let prompt = interpolate(SYSTEM_PROMPT).replace(
|
|
24352
24541
|
"<<<BLUMA_WORKSPACE_SNAPSHOT_BODY>>>",
|
|
24353
24542
|
buildWorkspaceSnapshot(cwd2)
|
|
@@ -24366,6 +24555,12 @@ async function getUnifiedSystemPrompt(availableSkills, options) {
|
|
|
24366
24555
|
prompt += `
|
|
24367
24556
|
|
|
24368
24557
|
${SUBJECT_MACHINE_MODEL_XML}`;
|
|
24558
|
+
prompt += `
|
|
24559
|
+
|
|
24560
|
+
${buildSandboxRuntimeContextBlock(cwd2, _injectedSandboxRuntime ?? void 0)}`;
|
|
24561
|
+
prompt += `
|
|
24562
|
+
|
|
24563
|
+
${SANDBOX_AUTONOMY_SECTION}`;
|
|
24369
24564
|
prompt += interpolate(SANDBOX_SECTION);
|
|
24370
24565
|
if (isFactorAiShPromptEnabled()) {
|
|
24371
24566
|
prompt += `
|
|
@@ -25545,7 +25740,7 @@ var LLMService = class {
|
|
|
25545
25740
|
};
|
|
25546
25741
|
|
|
25547
25742
|
// src/app/agent/utils/user_message_images.ts
|
|
25548
|
-
import
|
|
25743
|
+
import fs38 from "fs";
|
|
25549
25744
|
import os25 from "os";
|
|
25550
25745
|
import path40 from "path";
|
|
25551
25746
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
@@ -25625,7 +25820,7 @@ function resolveImagePath(candidate, cwd2) {
|
|
|
25625
25820
|
const abs = path40.isAbsolute(expanded) ? path40.normalize(expanded) : path40.normalize(path40.resolve(cwd2, expanded));
|
|
25626
25821
|
if (!isPathAllowed(abs, cwd2)) return null;
|
|
25627
25822
|
try {
|
|
25628
|
-
if (!
|
|
25823
|
+
if (!fs38.existsSync(abs) || !fs38.statSync(abs).isFile()) return null;
|
|
25629
25824
|
} catch {
|
|
25630
25825
|
return null;
|
|
25631
25826
|
}
|
|
@@ -25649,7 +25844,7 @@ function trySingleLineFileUriOrBareImagePath(line, cwd2) {
|
|
|
25649
25844
|
const abs = resolveImagePath(s, cwd2);
|
|
25650
25845
|
if (!abs) return null;
|
|
25651
25846
|
try {
|
|
25652
|
-
const st =
|
|
25847
|
+
const st = fs38.statSync(abs);
|
|
25653
25848
|
if (!st.isFile() || st.size > MAX_IMAGE_BYTES) {
|
|
25654
25849
|
return null;
|
|
25655
25850
|
}
|
|
@@ -25684,7 +25879,7 @@ function tryPasteChunkAsSingleImagePath(chunk, cwd2) {
|
|
|
25684
25879
|
return null;
|
|
25685
25880
|
}
|
|
25686
25881
|
try {
|
|
25687
|
-
const st =
|
|
25882
|
+
const st = fs38.statSync(abs);
|
|
25688
25883
|
if (!st.isFile() || st.size > MAX_IMAGE_BYTES) {
|
|
25689
25884
|
return null;
|
|
25690
25885
|
}
|
|
@@ -25713,7 +25908,7 @@ function buildUserMessageContent(raw, cwd2) {
|
|
|
25713
25908
|
const abs = resolveImagePath(c, cwd2);
|
|
25714
25909
|
if (!abs) continue;
|
|
25715
25910
|
try {
|
|
25716
|
-
const st =
|
|
25911
|
+
const st = fs38.statSync(abs);
|
|
25717
25912
|
if (st.size > MAX_IMAGE_BYTES) continue;
|
|
25718
25913
|
} catch {
|
|
25719
25914
|
continue;
|
|
@@ -25730,7 +25925,7 @@ function buildUserMessageContent(raw, cwd2) {
|
|
|
25730
25925
|
}
|
|
25731
25926
|
const parts = [{ type: "text", text: textPart }];
|
|
25732
25927
|
for (const abs of resolvedAbs) {
|
|
25733
|
-
const buf =
|
|
25928
|
+
const buf = fs38.readFileSync(abs);
|
|
25734
25929
|
const b64 = buf.toString("base64");
|
|
25735
25930
|
const mime = mimeFor(abs);
|
|
25736
25931
|
parts.push({
|
|
@@ -25993,7 +26188,7 @@ function effectiveToolAutoApprove(toolCall, sessionId, options) {
|
|
|
25993
26188
|
}
|
|
25994
26189
|
|
|
25995
26190
|
// src/app/agent/tools/CodingMemoryTool/CodingMemoryConsolidate.ts
|
|
25996
|
-
import * as
|
|
26191
|
+
import * as fs39 from "fs";
|
|
25997
26192
|
import * as path42 from "path";
|
|
25998
26193
|
import os26 from "os";
|
|
25999
26194
|
function memoryPath2() {
|
|
@@ -26007,18 +26202,18 @@ function uniqTags(a, b) {
|
|
|
26007
26202
|
}
|
|
26008
26203
|
function consolidateCodingMemoryFile() {
|
|
26009
26204
|
const p = memoryPath2();
|
|
26010
|
-
if (!
|
|
26205
|
+
if (!fs39.existsSync(p)) {
|
|
26011
26206
|
return { success: true, removedDuplicates: 0, message: "no coding_memory.json" };
|
|
26012
26207
|
}
|
|
26013
26208
|
const bak = `${p}.bak`;
|
|
26014
26209
|
try {
|
|
26015
|
-
|
|
26210
|
+
fs39.copyFileSync(p, bak);
|
|
26016
26211
|
} catch (e) {
|
|
26017
26212
|
return { success: false, removedDuplicates: 0, message: `backup failed: ${e.message}` };
|
|
26018
26213
|
}
|
|
26019
26214
|
let data;
|
|
26020
26215
|
try {
|
|
26021
|
-
data = JSON.parse(
|
|
26216
|
+
data = JSON.parse(fs39.readFileSync(p, "utf-8"));
|
|
26022
26217
|
} catch (e) {
|
|
26023
26218
|
return { success: false, removedDuplicates: 0, message: `invalid json: ${e.message}` };
|
|
26024
26219
|
}
|
|
@@ -26053,7 +26248,7 @@ function consolidateCodingMemoryFile() {
|
|
|
26053
26248
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
26054
26249
|
};
|
|
26055
26250
|
try {
|
|
26056
|
-
|
|
26251
|
+
fs39.writeFileSync(p, JSON.stringify(out, null, 2), "utf-8");
|
|
26057
26252
|
} catch (e) {
|
|
26058
26253
|
return { success: false, removedDuplicates: 0, message: `write failed: ${e.message}` };
|
|
26059
26254
|
}
|
|
@@ -26560,17 +26755,17 @@ var BluMaToolRunner = class {
|
|
|
26560
26755
|
// src/app/agent/session_manager/session_archive.ts
|
|
26561
26756
|
init_bluma_app_dir();
|
|
26562
26757
|
import path43 from "path";
|
|
26563
|
-
import { promises as
|
|
26758
|
+
import { promises as fs40 } from "fs";
|
|
26564
26759
|
async function archivePrunedConversationMessages(sessionId, messages) {
|
|
26565
26760
|
if (!sessionId || messages.length === 0) {
|
|
26566
26761
|
return null;
|
|
26567
26762
|
}
|
|
26568
26763
|
const appDir = getPreferredAppDir();
|
|
26569
26764
|
const dir = path43.join(appDir, "sessions", "archive", sessionId);
|
|
26570
|
-
await
|
|
26765
|
+
await fs40.mkdir(dir, { recursive: true });
|
|
26571
26766
|
const archiveFile = path43.join(dir, `${Date.now()}.jsonl`);
|
|
26572
26767
|
const lines = messages.map((m) => JSON.stringify(m)).join("\n") + "\n";
|
|
26573
|
-
await
|
|
26768
|
+
await fs40.appendFile(archiveFile, lines, "utf-8");
|
|
26574
26769
|
return archiveFile;
|
|
26575
26770
|
}
|
|
26576
26771
|
|
|
@@ -27992,7 +28187,7 @@ var BluMaAgent = class {
|
|
|
27992
28187
|
last_updated: (/* @__PURE__ */ new Date()).toISOString(),
|
|
27993
28188
|
...this.compressor.getSnapshot()
|
|
27994
28189
|
};
|
|
27995
|
-
|
|
28190
|
+
fs41.writeFileSync(this.sessionFile, JSON.stringify(sessionData, null, 2), "utf-8");
|
|
27996
28191
|
} catch (error) {
|
|
27997
28192
|
console.error("[Bluma] Failed to persist session synchronously:", error);
|
|
27998
28193
|
}
|
|
@@ -28933,7 +29128,7 @@ async function fullCompact(messages, targetTokens, summarizer, llmClient) {
|
|
|
28933
29128
|
}
|
|
28934
29129
|
|
|
28935
29130
|
// src/app/agent/core/memory/session_memory.ts
|
|
28936
|
-
import
|
|
29131
|
+
import fs42 from "fs";
|
|
28937
29132
|
import os29 from "os";
|
|
28938
29133
|
import path46 from "path";
|
|
28939
29134
|
import { v4 as uuidv49 } from "uuid";
|
|
@@ -28999,15 +29194,15 @@ ${messages.slice(-50).map((m) => `${m.role}: ${m.content.slice(0, 500)}`).join("
|
|
|
28999
29194
|
);
|
|
29000
29195
|
unique.sort((a, b) => b.accessCount - a.accessCount);
|
|
29001
29196
|
const trimmed = unique.slice(0, 200);
|
|
29002
|
-
|
|
29197
|
+
fs42.writeFileSync(this.memoryFile, JSON.stringify(trimmed, null, 2));
|
|
29003
29198
|
}
|
|
29004
29199
|
/**
|
|
29005
29200
|
* Load memories from disk
|
|
29006
29201
|
*/
|
|
29007
29202
|
async loadMemories() {
|
|
29008
29203
|
try {
|
|
29009
|
-
if (!
|
|
29010
|
-
const data =
|
|
29204
|
+
if (!fs42.existsSync(this.memoryFile)) return [];
|
|
29205
|
+
const data = fs42.readFileSync(this.memoryFile, "utf-8");
|
|
29011
29206
|
return JSON.parse(data);
|
|
29012
29207
|
} catch {
|
|
29013
29208
|
return [];
|
|
@@ -32102,16 +32297,16 @@ function supportsHyperlinks(options) {
|
|
|
32102
32297
|
if (stdoutSupported) {
|
|
32103
32298
|
return true;
|
|
32104
32299
|
}
|
|
32105
|
-
const
|
|
32106
|
-
const termProgram =
|
|
32300
|
+
const env3 = options?.env ?? process.env;
|
|
32301
|
+
const termProgram = env3["TERM_PROGRAM"];
|
|
32107
32302
|
if (termProgram && ADDITIONAL_HYPERLINK_TERMINALS.includes(termProgram)) {
|
|
32108
32303
|
return true;
|
|
32109
32304
|
}
|
|
32110
|
-
const lcTerminal =
|
|
32305
|
+
const lcTerminal = env3["LC_TERMINAL"];
|
|
32111
32306
|
if (lcTerminal && ADDITIONAL_HYPERLINK_TERMINALS.includes(lcTerminal)) {
|
|
32112
32307
|
return true;
|
|
32113
32308
|
}
|
|
32114
|
-
const term =
|
|
32309
|
+
const term = env3["TERM"];
|
|
32115
32310
|
if (term?.includes("kitty")) {
|
|
32116
32311
|
return true;
|
|
32117
32312
|
}
|
|
@@ -33433,12 +33628,12 @@ function patchToUnifiedDiffText(filePath, patch) {
|
|
|
33433
33628
|
}
|
|
33434
33629
|
|
|
33435
33630
|
// src/app/ui/utils/readEditContext.ts
|
|
33436
|
-
import { promises as
|
|
33631
|
+
import { promises as fs43 } from "fs";
|
|
33437
33632
|
var CHUNK_SIZE = 64 * 1024;
|
|
33438
33633
|
var CONTEXT_LINES2 = 3;
|
|
33439
33634
|
async function openForScan(filePath) {
|
|
33440
33635
|
try {
|
|
33441
|
-
return await
|
|
33636
|
+
return await fs43.open(filePath, "r");
|
|
33442
33637
|
} catch (e) {
|
|
33443
33638
|
if (e.code === "ENOENT") return null;
|
|
33444
33639
|
throw e;
|
|
@@ -35088,7 +35283,7 @@ var loadSkillTool = createTool({
|
|
|
35088
35283
|
});
|
|
35089
35284
|
|
|
35090
35285
|
// src/app/agent/tools/FileWriteTool/UI.tsx
|
|
35091
|
-
import
|
|
35286
|
+
import fs44 from "fs";
|
|
35092
35287
|
import { diffLines as diffLines3 } from "diff";
|
|
35093
35288
|
import { jsx as jsx54, jsxs as jsxs37 } from "react/jsx-runtime";
|
|
35094
35289
|
function getFilePath(args) {
|
|
@@ -35103,7 +35298,7 @@ function getFilePath(args) {
|
|
|
35103
35298
|
function readExistingFileText(filePath) {
|
|
35104
35299
|
if (!filePath) return "";
|
|
35105
35300
|
try {
|
|
35106
|
-
return
|
|
35301
|
+
return fs44.readFileSync(filePath, "utf-8");
|
|
35107
35302
|
} catch {
|
|
35108
35303
|
return "";
|
|
35109
35304
|
}
|
|
@@ -38045,7 +38240,7 @@ import {
|
|
|
38045
38240
|
|
|
38046
38241
|
// src/app/ui/hooks/useAtCompletion.ts
|
|
38047
38242
|
import { useEffect as useEffect11, useRef as useRef4, useState as useState13 } from "react";
|
|
38048
|
-
import
|
|
38243
|
+
import fs45 from "fs";
|
|
38049
38244
|
import path51 from "path";
|
|
38050
38245
|
var MAX_RESULTS3 = 50;
|
|
38051
38246
|
var DEFAULT_RECURSIVE_DEPTH = 2;
|
|
@@ -38080,7 +38275,7 @@ function listPathSuggestions(baseDir, pattern) {
|
|
|
38080
38275
|
while (queue.length && results.length < MAX_RESULTS3) {
|
|
38081
38276
|
const node = queue.shift();
|
|
38082
38277
|
try {
|
|
38083
|
-
const entries =
|
|
38278
|
+
const entries = fs45.readdirSync(node.dir, { withFileTypes: true });
|
|
38084
38279
|
for (const entry of entries) {
|
|
38085
38280
|
if (isIgnoredName(entry.name)) continue;
|
|
38086
38281
|
const entryAbs = path51.join(node.dir, entry.name);
|
|
@@ -38097,7 +38292,7 @@ function listPathSuggestions(baseDir, pattern) {
|
|
|
38097
38292
|
}
|
|
38098
38293
|
}
|
|
38099
38294
|
} else {
|
|
38100
|
-
const entries =
|
|
38295
|
+
const entries = fs45.readdirSync(listDir, { withFileTypes: true });
|
|
38101
38296
|
for (const entry of entries) {
|
|
38102
38297
|
if (filterPrefix && !entry.name.startsWith(filterPrefix)) continue;
|
|
38103
38298
|
if (isIgnoredName(entry.name)) continue;
|
|
@@ -38304,7 +38499,7 @@ var SlashSubmenuInlineComponent = ({ menu }) => {
|
|
|
38304
38499
|
var SlashSubmenuInline = memo15(SlashSubmenuInlineComponent);
|
|
38305
38500
|
|
|
38306
38501
|
// src/app/ui/utils/clipboardImage.ts
|
|
38307
|
-
import
|
|
38502
|
+
import fs46 from "fs";
|
|
38308
38503
|
import os32 from "os";
|
|
38309
38504
|
import path52 from "path";
|
|
38310
38505
|
import { spawn as spawn5, execFile as execFileCb, execSync as execSync4 } from "child_process";
|
|
@@ -38456,14 +38651,14 @@ function resolveHelperBinary(cmd) {
|
|
|
38456
38651
|
for (const dir of unixClipboardHelperDirs()) {
|
|
38457
38652
|
const full = path52.join(dir, cmd);
|
|
38458
38653
|
try {
|
|
38459
|
-
|
|
38654
|
+
fs46.accessSync(full, fs46.constants.X_OK);
|
|
38460
38655
|
return full;
|
|
38461
38656
|
} catch {
|
|
38462
38657
|
}
|
|
38463
38658
|
}
|
|
38464
38659
|
for (const dir of unixClipboardHelperDirs()) {
|
|
38465
38660
|
const full = path52.join(dir, cmd);
|
|
38466
|
-
if (
|
|
38661
|
+
if (fs46.existsSync(full)) {
|
|
38467
38662
|
return full;
|
|
38468
38663
|
}
|
|
38469
38664
|
}
|
|
@@ -38508,13 +38703,13 @@ function writeBufferIfImage(baseDir, buf) {
|
|
|
38508
38703
|
baseDir,
|
|
38509
38704
|
`clip-${Date.now()}-${Math.random().toString(36).slice(2, 8)}${ext}`
|
|
38510
38705
|
);
|
|
38511
|
-
|
|
38706
|
+
fs46.writeFileSync(out, buf);
|
|
38512
38707
|
return out;
|
|
38513
38708
|
}
|
|
38514
38709
|
function unlinkQuiet(p) {
|
|
38515
38710
|
try {
|
|
38516
|
-
if (
|
|
38517
|
-
|
|
38711
|
+
if (fs46.existsSync(p)) {
|
|
38712
|
+
fs46.unlinkSync(p);
|
|
38518
38713
|
}
|
|
38519
38714
|
} catch {
|
|
38520
38715
|
}
|
|
@@ -38531,12 +38726,12 @@ async function tryDarwinClipboardy(baseDir) {
|
|
|
38531
38726
|
return null;
|
|
38532
38727
|
}
|
|
38533
38728
|
for (const src of tmpPaths) {
|
|
38534
|
-
if (!src || !
|
|
38729
|
+
if (!src || !fs46.existsSync(src)) {
|
|
38535
38730
|
continue;
|
|
38536
38731
|
}
|
|
38537
38732
|
let st;
|
|
38538
38733
|
try {
|
|
38539
|
-
st =
|
|
38734
|
+
st = fs46.statSync(src);
|
|
38540
38735
|
} catch {
|
|
38541
38736
|
continue;
|
|
38542
38737
|
}
|
|
@@ -38549,7 +38744,7 @@ async function tryDarwinClipboardy(baseDir) {
|
|
|
38549
38744
|
baseDir,
|
|
38550
38745
|
`clip-${Date.now()}-${Math.random().toString(36).slice(2, 8)}${safeExt}`
|
|
38551
38746
|
);
|
|
38552
|
-
|
|
38747
|
+
fs46.copyFileSync(src, out);
|
|
38553
38748
|
for (const p of tmpPaths) {
|
|
38554
38749
|
unlinkQuiet(p);
|
|
38555
38750
|
}
|
|
@@ -38570,7 +38765,7 @@ async function tryWindowsPowerShell(outFile) {
|
|
|
38570
38765
|
"v1.0",
|
|
38571
38766
|
"powershell.exe"
|
|
38572
38767
|
) : "powershell.exe";
|
|
38573
|
-
if (!
|
|
38768
|
+
if (!fs46.existsSync(ps)) {
|
|
38574
38769
|
return false;
|
|
38575
38770
|
}
|
|
38576
38771
|
const script = "$ErrorActionPreference='Stop';Add-Type -AssemblyName System.Windows.Forms;Add-Type -AssemblyName System.Drawing;$img=[System.Windows.Forms.Clipboard]::GetImage();if($null -eq $img){exit 2};$img.Save($env:BLUMA_CLIP_OUT,[System.Drawing.Imaging.ImageFormat]::Png);exit 0";
|
|
@@ -38592,7 +38787,7 @@ async function tryWindowsPowerShell(outFile) {
|
|
|
38592
38787
|
return false;
|
|
38593
38788
|
}
|
|
38594
38789
|
try {
|
|
38595
|
-
const st =
|
|
38790
|
+
const st = fs46.statSync(outFile);
|
|
38596
38791
|
return st.size >= 80 && st.size <= CLIPBOARD_MAX_BYTES;
|
|
38597
38792
|
} catch {
|
|
38598
38793
|
return false;
|
|
@@ -38679,8 +38874,8 @@ async function tryClipboardTextAsImageFile(baseDir) {
|
|
|
38679
38874
|
const abs = parseClipboardTextAsImagePath(t);
|
|
38680
38875
|
if (!abs) return null;
|
|
38681
38876
|
try {
|
|
38682
|
-
if (!
|
|
38683
|
-
const st =
|
|
38877
|
+
if (!fs46.existsSync(abs)) return null;
|
|
38878
|
+
const st = fs46.statSync(abs);
|
|
38684
38879
|
if (!st.isFile() || st.size > CLIPBOARD_MAX_BYTES || st.size < 20) return null;
|
|
38685
38880
|
} catch {
|
|
38686
38881
|
return null;
|
|
@@ -38691,7 +38886,7 @@ async function tryClipboardTextAsImageFile(baseDir) {
|
|
|
38691
38886
|
`clip-${Date.now()}-${Math.random().toString(36).slice(2, 8)}${ext}`
|
|
38692
38887
|
);
|
|
38693
38888
|
try {
|
|
38694
|
-
|
|
38889
|
+
fs46.copyFileSync(abs, out);
|
|
38695
38890
|
return out;
|
|
38696
38891
|
} catch {
|
|
38697
38892
|
return null;
|
|
@@ -38723,11 +38918,11 @@ printf '%s' "$OUT"
|
|
|
38723
38918
|
maxBuffer: 4096
|
|
38724
38919
|
});
|
|
38725
38920
|
const written = String(stdout ?? "").trim();
|
|
38726
|
-
if (written !== outPath || !
|
|
38921
|
+
if (written !== outPath || !fs46.existsSync(outPath)) {
|
|
38727
38922
|
unlinkQuiet(outPath);
|
|
38728
38923
|
return null;
|
|
38729
38924
|
}
|
|
38730
|
-
const buf =
|
|
38925
|
+
const buf = fs46.readFileSync(outPath);
|
|
38731
38926
|
unlinkQuiet(outPath);
|
|
38732
38927
|
return writeBufferIfImage(baseDir, buf);
|
|
38733
38928
|
} catch {
|
|
@@ -38748,8 +38943,8 @@ async function tryNativeClipboardImage() {
|
|
|
38748
38943
|
}
|
|
38749
38944
|
try {
|
|
38750
38945
|
const result = readClipboardImageNative();
|
|
38751
|
-
if (
|
|
38752
|
-
const st =
|
|
38946
|
+
if (fs46.existsSync(result.path)) {
|
|
38947
|
+
const st = fs46.statSync(result.path);
|
|
38753
38948
|
if (st.size >= 80 && st.size <= CLIPBOARD_MAX_BYTES) {
|
|
38754
38949
|
return result.path;
|
|
38755
38950
|
}
|
|
@@ -38760,7 +38955,7 @@ async function tryNativeClipboardImage() {
|
|
|
38760
38955
|
}
|
|
38761
38956
|
async function readClipboardImageToTempFile() {
|
|
38762
38957
|
const baseDir = path52.join(os32.homedir(), ".cache", "bluma", "clipboard");
|
|
38763
|
-
|
|
38958
|
+
fs46.mkdirSync(baseDir, { recursive: true });
|
|
38764
38959
|
const nativeResult = await tryNativeClipboardImage();
|
|
38765
38960
|
if (nativeResult) {
|
|
38766
38961
|
return nativeResult;
|
|
@@ -38819,7 +39014,7 @@ function expandLargePastePlaceholder(value, pending) {
|
|
|
38819
39014
|
}
|
|
38820
39015
|
|
|
38821
39016
|
// src/app/ui/components/InputPrompt.tsx
|
|
38822
|
-
import
|
|
39017
|
+
import fs47 from "fs";
|
|
38823
39018
|
import { Fragment as Fragment7, jsx as jsx79, jsxs as jsxs62 } from "react/jsx-runtime";
|
|
38824
39019
|
var persistedInputState = { text: "", cursorPosition: 0 };
|
|
38825
39020
|
var StaticCursor = () => /* @__PURE__ */ jsx79(Box_default, { flexDirection: "row", flexWrap: "nowrap", children: /* @__PURE__ */ jsx79(Text, { bold: true, color: BLUMA_TERMINAL.m3OnSurface, children: "\u2588 " }) });
|
|
@@ -38986,7 +39181,7 @@ var InputPrompt = memo16(({
|
|
|
38986
39181
|
return;
|
|
38987
39182
|
}
|
|
38988
39183
|
if (routeText.startsWith("/")) {
|
|
38989
|
-
const isFilePath = map.size > 0 &&
|
|
39184
|
+
const isFilePath = map.size > 0 && fs47.existsSync(routeText.split(/\s+/)[0]);
|
|
38990
39185
|
if (isFilePath) {
|
|
38991
39186
|
uiEventBus.emit("user_overlay", {
|
|
38992
39187
|
kind: "message",
|
|
@@ -41155,7 +41350,7 @@ var renderSettingsEditUsage = () => {
|
|
|
41155
41350
|
// src/app/agent/core/thread/thread_store.ts
|
|
41156
41351
|
init_bluma_app_dir();
|
|
41157
41352
|
import path53 from "path";
|
|
41158
|
-
import { promises as
|
|
41353
|
+
import { promises as fs48 } from "fs";
|
|
41159
41354
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
41160
41355
|
var INDEX_VERSION = 1;
|
|
41161
41356
|
var fileLocks2 = /* @__PURE__ */ new Map();
|
|
@@ -41190,10 +41385,10 @@ var ThreadStore = class {
|
|
|
41190
41385
|
* Inicializa o diretório de threads
|
|
41191
41386
|
*/
|
|
41192
41387
|
async initialize() {
|
|
41193
|
-
await
|
|
41194
|
-
await
|
|
41388
|
+
await fs48.mkdir(this.threadsDir, { recursive: true });
|
|
41389
|
+
await fs48.mkdir(this.archiveDir, { recursive: true });
|
|
41195
41390
|
try {
|
|
41196
|
-
await
|
|
41391
|
+
await fs48.access(this.indexPath);
|
|
41197
41392
|
} catch {
|
|
41198
41393
|
await this.saveIndex({ version: INDEX_VERSION, threads: [], lastUpdated: (/* @__PURE__ */ new Date()).toISOString() });
|
|
41199
41394
|
}
|
|
@@ -41222,7 +41417,7 @@ var ThreadStore = class {
|
|
|
41222
41417
|
async loadIndex() {
|
|
41223
41418
|
return withFileLock2(this.indexPath, async () => {
|
|
41224
41419
|
try {
|
|
41225
|
-
const content = await
|
|
41420
|
+
const content = await fs48.readFile(this.indexPath, "utf-8");
|
|
41226
41421
|
return JSON.parse(content);
|
|
41227
41422
|
} catch {
|
|
41228
41423
|
return { version: INDEX_VERSION, threads: [], lastUpdated: (/* @__PURE__ */ new Date()).toISOString() };
|
|
@@ -41233,8 +41428,8 @@ var ThreadStore = class {
|
|
|
41233
41428
|
return withFileLock2(this.indexPath, async () => {
|
|
41234
41429
|
index.lastUpdated = (/* @__PURE__ */ new Date()).toISOString();
|
|
41235
41430
|
const tempPath = `${this.indexPath}.${Date.now()}.tmp`;
|
|
41236
|
-
await
|
|
41237
|
-
await
|
|
41431
|
+
await fs48.writeFile(tempPath, JSON.stringify(index, null, 2), "utf-8");
|
|
41432
|
+
await fs48.rename(tempPath, this.indexPath);
|
|
41238
41433
|
});
|
|
41239
41434
|
}
|
|
41240
41435
|
// ==================== Git Info ====================
|
|
@@ -41304,7 +41499,7 @@ var ThreadStore = class {
|
|
|
41304
41499
|
messages: params.initialMessages || []
|
|
41305
41500
|
};
|
|
41306
41501
|
const historyPath = this.buildDatedThreadHistoryPath(threadId);
|
|
41307
|
-
await
|
|
41502
|
+
await fs48.mkdir(path53.dirname(historyPath), { recursive: true });
|
|
41308
41503
|
await this.saveHistoryAtPath(historyPath, history);
|
|
41309
41504
|
const index = await this.loadIndex();
|
|
41310
41505
|
index.threads.unshift({
|
|
@@ -41359,7 +41554,7 @@ var ThreadStore = class {
|
|
|
41359
41554
|
compressedSliceCount: source.history.compressedSliceCount
|
|
41360
41555
|
};
|
|
41361
41556
|
const historyPath = this.buildDatedThreadHistoryPath(newThreadId);
|
|
41362
|
-
await
|
|
41557
|
+
await fs48.mkdir(path53.dirname(historyPath), { recursive: true });
|
|
41363
41558
|
await this.saveHistoryAtPath(historyPath, history);
|
|
41364
41559
|
const index = await this.loadIndex();
|
|
41365
41560
|
index.threads.unshift({
|
|
@@ -41434,7 +41629,7 @@ var ThreadStore = class {
|
|
|
41434
41629
|
const oldPath = entry.historyPath || this.getLegacyHistoryPath(threadId);
|
|
41435
41630
|
const newPath = path53.join(this.archiveDir, `${threadId}.jsonl`);
|
|
41436
41631
|
try {
|
|
41437
|
-
await
|
|
41632
|
+
await fs48.rename(oldPath, newPath);
|
|
41438
41633
|
} catch (e) {
|
|
41439
41634
|
if (e.code !== "ENOENT") throw e;
|
|
41440
41635
|
}
|
|
@@ -41457,9 +41652,9 @@ var ThreadStore = class {
|
|
|
41457
41652
|
if (entry.status === "active") return true;
|
|
41458
41653
|
const oldPath = path53.join(this.archiveDir, `${threadId}.jsonl`);
|
|
41459
41654
|
const newPath = this.buildDatedThreadHistoryPath(threadId);
|
|
41460
|
-
await
|
|
41655
|
+
await fs48.mkdir(path53.dirname(newPath), { recursive: true });
|
|
41461
41656
|
try {
|
|
41462
|
-
await
|
|
41657
|
+
await fs48.rename(oldPath, newPath);
|
|
41463
41658
|
} catch (e) {
|
|
41464
41659
|
if (e.code !== "ENOENT") throw e;
|
|
41465
41660
|
}
|
|
@@ -41480,7 +41675,7 @@ var ThreadStore = class {
|
|
|
41480
41675
|
if (entryIndex === -1) return false;
|
|
41481
41676
|
const entry = index.threads[entryIndex];
|
|
41482
41677
|
try {
|
|
41483
|
-
await
|
|
41678
|
+
await fs48.unlink(entry.historyPath);
|
|
41484
41679
|
} catch {
|
|
41485
41680
|
}
|
|
41486
41681
|
index.threads.splice(entryIndex, 1);
|
|
@@ -41504,14 +41699,14 @@ var ThreadStore = class {
|
|
|
41504
41699
|
const entry = index.threads.find((t) => t.threadId === threadId);
|
|
41505
41700
|
if (entry?.historyPath) {
|
|
41506
41701
|
try {
|
|
41507
|
-
await
|
|
41702
|
+
await fs48.access(entry.historyPath);
|
|
41508
41703
|
return entry.historyPath;
|
|
41509
41704
|
} catch {
|
|
41510
41705
|
}
|
|
41511
41706
|
}
|
|
41512
41707
|
const legacy = this.getLegacyHistoryPath(threadId);
|
|
41513
41708
|
try {
|
|
41514
|
-
await
|
|
41709
|
+
await fs48.access(legacy);
|
|
41515
41710
|
return legacy;
|
|
41516
41711
|
} catch {
|
|
41517
41712
|
return entry?.historyPath ?? legacy;
|
|
@@ -41528,9 +41723,9 @@ var ThreadStore = class {
|
|
|
41528
41723
|
for (const msg of history.messages) {
|
|
41529
41724
|
lines.push(JSON.stringify({ type: "message", ...msg }));
|
|
41530
41725
|
}
|
|
41531
|
-
await
|
|
41726
|
+
await fs48.mkdir(path53.dirname(historyPath), { recursive: true }).catch(() => {
|
|
41532
41727
|
});
|
|
41533
|
-
await
|
|
41728
|
+
await fs48.writeFile(historyPath, lines.join("\n") + "\n", "utf-8");
|
|
41534
41729
|
}
|
|
41535
41730
|
/**
|
|
41536
41731
|
* Guarda o histórico de uma thread
|
|
@@ -41552,7 +41747,7 @@ var ThreadStore = class {
|
|
|
41552
41747
|
].filter((p, i, arr) => Boolean(p) && arr.indexOf(p) === i);
|
|
41553
41748
|
for (const historyPath of pathsToTry) {
|
|
41554
41749
|
try {
|
|
41555
|
-
const content = await
|
|
41750
|
+
const content = await fs48.readFile(historyPath, "utf-8");
|
|
41556
41751
|
const lines = content.split("\n").filter(Boolean);
|
|
41557
41752
|
const history = {
|
|
41558
41753
|
threadId,
|
|
@@ -41587,7 +41782,7 @@ var ThreadStore = class {
|
|
|
41587
41782
|
const entry = index.threads.find((t) => t.threadId === threadId);
|
|
41588
41783
|
if (!entry) throw new Error(`Thread not found: ${threadId}`);
|
|
41589
41784
|
const lines = messages.map((msg) => JSON.stringify({ type: "message", ...msg }));
|
|
41590
|
-
await
|
|
41785
|
+
await fs48.appendFile(entry.historyPath, lines.join("\n") + "\n", "utf-8");
|
|
41591
41786
|
entry.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
41592
41787
|
await this.saveIndex(index);
|
|
41593
41788
|
}
|
|
@@ -44025,15 +44220,15 @@ import semverGt from "semver/functions/gt.js";
|
|
|
44025
44220
|
import semverValid from "semver/functions/valid.js";
|
|
44026
44221
|
import { fileURLToPath as fileURLToPath7 } from "url";
|
|
44027
44222
|
import path55 from "path";
|
|
44028
|
-
import
|
|
44223
|
+
import fs50 from "fs";
|
|
44029
44224
|
var BLUMA_PACKAGE_NAME = "@nomad-e/bluma-cli";
|
|
44030
44225
|
function findBlumaPackageJson(startDir) {
|
|
44031
44226
|
let dir = startDir;
|
|
44032
44227
|
for (let i = 0; i < 12; i++) {
|
|
44033
44228
|
const candidate = path55.join(dir, "package.json");
|
|
44034
|
-
if (
|
|
44229
|
+
if (fs50.existsSync(candidate)) {
|
|
44035
44230
|
try {
|
|
44036
|
-
const raw =
|
|
44231
|
+
const raw = fs50.readFileSync(candidate, "utf8");
|
|
44037
44232
|
const parsed = JSON.parse(raw);
|
|
44038
44233
|
if (parsed?.name === BLUMA_PACKAGE_NAME && parsed?.version) {
|
|
44039
44234
|
return { name: parsed.name, version: String(parsed.version) };
|
|
@@ -44064,8 +44259,8 @@ function resolveInstalledBlumaPackage() {
|
|
|
44064
44259
|
if (argv1 && !argv1.startsWith("-")) {
|
|
44065
44260
|
try {
|
|
44066
44261
|
let resolved = argv1;
|
|
44067
|
-
if (path55.isAbsolute(argv1) &&
|
|
44068
|
-
resolved =
|
|
44262
|
+
if (path55.isAbsolute(argv1) && fs50.existsSync(argv1)) {
|
|
44263
|
+
resolved = fs50.realpathSync(argv1);
|
|
44069
44264
|
} else {
|
|
44070
44265
|
resolved = path55.resolve(process.cwd(), argv1);
|
|
44071
44266
|
}
|
|
@@ -44888,16 +45083,16 @@ function usePlanMode() {
|
|
|
44888
45083
|
|
|
44889
45084
|
// src/app/hooks/useAgentMode.ts
|
|
44890
45085
|
import { useState as useState22, useEffect as useEffect21, useCallback as useCallback9 } from "react";
|
|
44891
|
-
import * as
|
|
45086
|
+
import * as fs51 from "fs";
|
|
44892
45087
|
import * as path56 from "path";
|
|
44893
45088
|
import { homedir as homedir4 } from "os";
|
|
44894
45089
|
var SETTINGS_PATH = path56.join(homedir4(), ".bluma", "settings.json");
|
|
44895
45090
|
function readAgentModeFromFile() {
|
|
44896
45091
|
try {
|
|
44897
|
-
if (!
|
|
45092
|
+
if (!fs51.existsSync(SETTINGS_PATH)) {
|
|
44898
45093
|
return "default";
|
|
44899
45094
|
}
|
|
44900
|
-
const content =
|
|
45095
|
+
const content = fs51.readFileSync(SETTINGS_PATH, "utf-8");
|
|
44901
45096
|
const settings = JSON.parse(content);
|
|
44902
45097
|
return settings.agentMode || "default";
|
|
44903
45098
|
} catch (error) {
|
|
@@ -44916,16 +45111,16 @@ function useAgentMode() {
|
|
|
44916
45111
|
}, []);
|
|
44917
45112
|
const updateAgentMode = useCallback9((mode) => {
|
|
44918
45113
|
try {
|
|
44919
|
-
if (!
|
|
44920
|
-
|
|
45114
|
+
if (!fs51.existsSync(SETTINGS_PATH)) {
|
|
45115
|
+
fs51.mkdirSync(path56.dirname(SETTINGS_PATH), { recursive: true });
|
|
44921
45116
|
}
|
|
44922
45117
|
let settings = {};
|
|
44923
|
-
if (
|
|
44924
|
-
const content =
|
|
45118
|
+
if (fs51.existsSync(SETTINGS_PATH)) {
|
|
45119
|
+
const content = fs51.readFileSync(SETTINGS_PATH, "utf-8");
|
|
44925
45120
|
settings = JSON.parse(content);
|
|
44926
45121
|
}
|
|
44927
45122
|
settings.agentMode = mode;
|
|
44928
|
-
|
|
45123
|
+
fs51.writeFileSync(SETTINGS_PATH, JSON.stringify(settings, null, 2), "utf-8");
|
|
44929
45124
|
setAgentMode(mode);
|
|
44930
45125
|
} catch (error) {
|
|
44931
45126
|
console.error("Failed to update agent mode:", error);
|
|
@@ -46142,7 +46337,7 @@ Dados do utilizador final / pedido \u2014 n\xE3o confundir com o sandbox onde o
|
|
|
46142
46337
|
${JSON.stringify(extra, null, 2)}
|
|
46143
46338
|
</${label}>`;
|
|
46144
46339
|
}
|
|
46145
|
-
function buildAgentTurnUserContent(context) {
|
|
46340
|
+
function buildAgentTurnUserContent(context, sandboxRuntime) {
|
|
46146
46341
|
if (context == null) return "";
|
|
46147
46342
|
if (typeof context === "string") {
|
|
46148
46343
|
return enrichSandboxUserTurn(context.trim());
|
|
@@ -46161,6 +46356,9 @@ function buildAgentTurnUserContent(context) {
|
|
|
46161
46356
|
const extra = extractExtraContextFields(ctx);
|
|
46162
46357
|
const hasMachineSpecs = looksLikeMachineSpecs(extra.machine_specs) || looksLikeMachineSpecs(extra.machineSpecs) || looksLikeMachineSpecs(extra.client_machine) || looksLikeMachineSpecs(extra.target_machine) || looksLikeMachineSpecs(extra.hardware) || Object.values(extra).some(looksLikeMachineSpecs);
|
|
46163
46358
|
const parts = [];
|
|
46359
|
+
if (sandboxRuntime && typeof sandboxRuntime === "object") {
|
|
46360
|
+
parts.push(formatSandboxRuntimeUserTurnPrefix(sandboxRuntime));
|
|
46361
|
+
}
|
|
46164
46362
|
if (userRequest) parts.push(userRequest);
|
|
46165
46363
|
if (coordinatorText) {
|
|
46166
46364
|
parts.push(`<contexto_adicional>
|
|
@@ -46190,7 +46388,7 @@ import { memo as memo26, useCallback as useCallback11, useEffect as useEffect23,
|
|
|
46190
46388
|
// src/app/agent/session_manager/session_resume_browser.ts
|
|
46191
46389
|
init_bluma_app_dir();
|
|
46192
46390
|
import path57 from "path";
|
|
46193
|
-
import { promises as
|
|
46391
|
+
import { promises as fs52 } from "fs";
|
|
46194
46392
|
function getSessionsRoot() {
|
|
46195
46393
|
return path57.join(getPreferredAppDir(), "sessions");
|
|
46196
46394
|
}
|
|
@@ -46213,9 +46411,9 @@ async function sessionEntryFromFile(absPath, sessionId) {
|
|
|
46213
46411
|
let preview = "(no messages)";
|
|
46214
46412
|
let lastActivityMs = Date.now();
|
|
46215
46413
|
try {
|
|
46216
|
-
const st = await
|
|
46414
|
+
const st = await fs52.stat(absPath);
|
|
46217
46415
|
lastActivityMs = st.mtimeMs;
|
|
46218
|
-
const raw = await
|
|
46416
|
+
const raw = await fs52.readFile(absPath, "utf-8");
|
|
46219
46417
|
const data = JSON.parse(raw);
|
|
46220
46418
|
preview = previewFromHistory(data.conversation_history);
|
|
46221
46419
|
const iso = data.last_updated || data.created_at;
|
|
@@ -46250,8 +46448,8 @@ async function listSessionBrowserEntries(cwdRel) {
|
|
|
46250
46448
|
}
|
|
46251
46449
|
let dirents;
|
|
46252
46450
|
try {
|
|
46253
|
-
await
|
|
46254
|
-
dirents = await
|
|
46451
|
+
await fs52.mkdir(absDir, { recursive: true });
|
|
46452
|
+
dirents = await fs52.readdir(absDir, { withFileTypes: true });
|
|
46255
46453
|
} catch {
|
|
46256
46454
|
return out;
|
|
46257
46455
|
}
|
|
@@ -46635,9 +46833,9 @@ async function runAgentMode() {
|
|
|
46635
46833
|
try {
|
|
46636
46834
|
if (inputFileIndex !== -1 && args[inputFileIndex + 1]) {
|
|
46637
46835
|
const filePath = args[inputFileIndex + 1];
|
|
46638
|
-
rawPayload =
|
|
46836
|
+
rawPayload = fs53.readFileSync(filePath, "utf-8");
|
|
46639
46837
|
} else {
|
|
46640
|
-
rawPayload =
|
|
46838
|
+
rawPayload = fs53.readFileSync(0, "utf-8");
|
|
46641
46839
|
}
|
|
46642
46840
|
} catch (err) {
|
|
46643
46841
|
writeAgentEvent(registrySessionId, {
|
|
@@ -46689,6 +46887,14 @@ async function runAgentMode() {
|
|
|
46689
46887
|
if (envelopeUserRequest.trim()) {
|
|
46690
46888
|
process.env.BLUMA_USER_REQUEST = envelopeUserRequest.trim();
|
|
46691
46889
|
}
|
|
46890
|
+
if (envelope.from_agent?.trim()) {
|
|
46891
|
+
process.env.BLUMA_FROM_AGENT = envelope.from_agent.trim();
|
|
46892
|
+
}
|
|
46893
|
+
if (envelope.action?.trim()) {
|
|
46894
|
+
process.env.BLUMA_ACTION = envelope.action.trim();
|
|
46895
|
+
}
|
|
46896
|
+
const injectedRuntime = applySandboxRuntimeFromEnvelope(envelope);
|
|
46897
|
+
setInjectedSandboxRuntimeForPrompt(injectedRuntime);
|
|
46692
46898
|
const eventBus = new EventEmitter7();
|
|
46693
46899
|
const sessionId = registrySessionId || envelope.session_id || envelope.message_id || uuidv412();
|
|
46694
46900
|
process.env.BLUMA_SESSION_ID = sessionId;
|
|
@@ -46831,7 +47037,7 @@ async function runAgentMode() {
|
|
|
46831
47037
|
const agent = new Agent(sessionId, eventBus);
|
|
46832
47038
|
agentRef = agent;
|
|
46833
47039
|
await agent.initialize();
|
|
46834
|
-
const userContent = buildAgentTurnUserContent(envelope.context) || JSON.stringify({
|
|
47040
|
+
const userContent = buildAgentTurnUserContent(envelope.context, injectedRuntime) || JSON.stringify({
|
|
46835
47041
|
message_id: envelope.message_id || sessionId,
|
|
46836
47042
|
from_agent: envelope.from_agent || "unknown",
|
|
46837
47043
|
to_agent: envelope.to_agent || "bluma",
|
|
@@ -46880,7 +47086,7 @@ function readCliPackageVersion() {
|
|
|
46880
47086
|
try {
|
|
46881
47087
|
const base = path58.dirname(fileURLToPath8(import.meta.url));
|
|
46882
47088
|
const pkgPath = path58.join(base, "..", "package.json");
|
|
46883
|
-
const j = JSON.parse(
|
|
47089
|
+
const j = JSON.parse(fs53.readFileSync(pkgPath, "utf8"));
|
|
46884
47090
|
return String(j.version || "0.0.0");
|
|
46885
47091
|
} catch {
|
|
46886
47092
|
return "0.0.0";
|
|
@@ -47006,7 +47212,7 @@ function startBackgroundAgent() {
|
|
|
47006
47212
|
process.exit(1);
|
|
47007
47213
|
}
|
|
47008
47214
|
const filePath = args[inputFileIndex + 1];
|
|
47009
|
-
const rawPayload =
|
|
47215
|
+
const rawPayload = fs53.readFileSync(filePath, "utf-8");
|
|
47010
47216
|
const envelope = JSON.parse(rawPayload);
|
|
47011
47217
|
const sessionId = envelope.session_id || envelope.message_id || uuidv412();
|
|
47012
47218
|
registerSession({
|