@nomad-e/bluma-cli 0.19.0 → 0.20.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 +416 -264
- package/package.json +1 -1
package/dist/main.js
CHANGED
|
@@ -3204,8 +3204,8 @@ __export(exportConversation_exports, {
|
|
|
3204
3204
|
formatConversationMarkdown: () => formatConversationMarkdown,
|
|
3205
3205
|
resolveExportOutputPath: () => resolveExportOutputPath
|
|
3206
3206
|
});
|
|
3207
|
-
import { promises as
|
|
3208
|
-
import
|
|
3207
|
+
import { promises as fs49 } from "fs";
|
|
3208
|
+
import path55 from "path";
|
|
3209
3209
|
function extractTextParts2(content) {
|
|
3210
3210
|
if (typeof content === "string") {
|
|
3211
3211
|
const trimmed = content.trim();
|
|
@@ -3363,12 +3363,12 @@ function resolveExportOutputPath(sessionId, options) {
|
|
|
3363
3363
|
const { outputPath, defaultExportDir } = options ?? {};
|
|
3364
3364
|
if (outputPath?.trim()) {
|
|
3365
3365
|
const raw = outputPath.trim();
|
|
3366
|
-
return
|
|
3366
|
+
return path55.isAbsolute(raw) ? raw : path55.resolve(process.cwd(), raw);
|
|
3367
3367
|
}
|
|
3368
3368
|
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").slice(0, 19);
|
|
3369
3369
|
const safeId = sessionId.replace(/[^a-zA-Z0-9_-]+/g, "_").slice(0, 48) || "session";
|
|
3370
3370
|
const baseDir = defaultExportDir ?? getSandboxPolicy().workspaceRoot;
|
|
3371
|
-
return
|
|
3371
|
+
return path55.join(baseDir, `bluma-export-${safeId}-${stamp}.md`);
|
|
3372
3372
|
}
|
|
3373
3373
|
async function resolveHistory(sessionId, fallbackHistory) {
|
|
3374
3374
|
const loaded2 = await loadSession(sessionId);
|
|
@@ -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(path55.dirname(filePath), { recursive: true });
|
|
3394
|
+
await fs49.writeFile(filePath, markdown, "utf-8");
|
|
3395
3395
|
return {
|
|
3396
3396
|
success: true,
|
|
3397
3397
|
filePath,
|
|
@@ -3916,11 +3916,11 @@ var NodeFsOperations = {
|
|
|
3916
3916
|
if (fd) fs.closeSync(fd);
|
|
3917
3917
|
}
|
|
3918
3918
|
},
|
|
3919
|
-
appendFileSync(
|
|
3920
|
-
const _ = slowLogging`fs.appendFileSync(${
|
|
3919
|
+
appendFileSync(path60, data, options) {
|
|
3920
|
+
const _ = slowLogging`fs.appendFileSync(${path60}, ${data.length} chars)`;
|
|
3921
3921
|
if (options?.mode !== void 0) {
|
|
3922
3922
|
try {
|
|
3923
|
-
const fd = fs.openSync(
|
|
3923
|
+
const fd = fs.openSync(path60, "ax", options.mode);
|
|
3924
3924
|
try {
|
|
3925
3925
|
fs.appendFileSync(fd, data);
|
|
3926
3926
|
} finally {
|
|
@@ -3931,35 +3931,35 @@ var NodeFsOperations = {
|
|
|
3931
3931
|
if (getErrnoCode(e) !== "EEXIST") throw e;
|
|
3932
3932
|
}
|
|
3933
3933
|
}
|
|
3934
|
-
fs.appendFileSync(
|
|
3934
|
+
fs.appendFileSync(path60, data);
|
|
3935
3935
|
},
|
|
3936
3936
|
copyFileSync(src, dest) {
|
|
3937
3937
|
const _ = slowLogging`fs.copyFileSync(${src} → ${dest})`;
|
|
3938
3938
|
fs.copyFileSync(src, dest);
|
|
3939
3939
|
},
|
|
3940
|
-
unlinkSync(
|
|
3941
|
-
const _ = slowLogging`fs.unlinkSync(${
|
|
3942
|
-
fs.unlinkSync(
|
|
3940
|
+
unlinkSync(path60) {
|
|
3941
|
+
const _ = slowLogging`fs.unlinkSync(${path60})`;
|
|
3942
|
+
fs.unlinkSync(path60);
|
|
3943
3943
|
},
|
|
3944
3944
|
renameSync(oldPath, newPath) {
|
|
3945
3945
|
const _ = slowLogging`fs.renameSync(${oldPath} → ${newPath})`;
|
|
3946
3946
|
fs.renameSync(oldPath, newPath);
|
|
3947
3947
|
},
|
|
3948
|
-
linkSync(target,
|
|
3949
|
-
const _ = slowLogging`fs.linkSync(${target} → ${
|
|
3950
|
-
fs.linkSync(target,
|
|
3948
|
+
linkSync(target, path60) {
|
|
3949
|
+
const _ = slowLogging`fs.linkSync(${target} → ${path60})`;
|
|
3950
|
+
fs.linkSync(target, path60);
|
|
3951
3951
|
},
|
|
3952
|
-
symlinkSync(target,
|
|
3953
|
-
const _ = slowLogging`fs.symlinkSync(${target} → ${
|
|
3954
|
-
fs.symlinkSync(target,
|
|
3952
|
+
symlinkSync(target, path60, type) {
|
|
3953
|
+
const _ = slowLogging`fs.symlinkSync(${target} → ${path60})`;
|
|
3954
|
+
fs.symlinkSync(target, path60, type);
|
|
3955
3955
|
},
|
|
3956
|
-
readlinkSync(
|
|
3957
|
-
const _ = slowLogging`fs.readlinkSync(${
|
|
3958
|
-
return fs.readlinkSync(
|
|
3956
|
+
readlinkSync(path60) {
|
|
3957
|
+
const _ = slowLogging`fs.readlinkSync(${path60})`;
|
|
3958
|
+
return fs.readlinkSync(path60);
|
|
3959
3959
|
},
|
|
3960
|
-
realpathSync(
|
|
3961
|
-
const _ = slowLogging`fs.realpathSync(${
|
|
3962
|
-
return fs.realpathSync(
|
|
3960
|
+
realpathSync(path60) {
|
|
3961
|
+
const _ = slowLogging`fs.realpathSync(${path60})`;
|
|
3962
|
+
return fs.realpathSync(path60).normalize("NFC");
|
|
3963
3963
|
},
|
|
3964
3964
|
mkdirSync(dirPath, options) {
|
|
3965
3965
|
const _ = slowLogging`fs.mkdirSync(${dirPath})`;
|
|
@@ -3992,12 +3992,12 @@ var NodeFsOperations = {
|
|
|
3992
3992
|
const _ = slowLogging`fs.rmdirSync(${dirPath})`;
|
|
3993
3993
|
fs.rmdirSync(dirPath);
|
|
3994
3994
|
},
|
|
3995
|
-
rmSync(
|
|
3996
|
-
const _ = slowLogging`fs.rmSync(${
|
|
3997
|
-
fs.rmSync(
|
|
3995
|
+
rmSync(path60, options) {
|
|
3996
|
+
const _ = slowLogging`fs.rmSync(${path60})`;
|
|
3997
|
+
fs.rmSync(path60, options);
|
|
3998
3998
|
},
|
|
3999
|
-
createWriteStream(
|
|
4000
|
-
return fs.createWriteStream(
|
|
3999
|
+
createWriteStream(path60) {
|
|
4000
|
+
return fs.createWriteStream(path60);
|
|
4001
4001
|
},
|
|
4002
4002
|
async readFileBytes(fsPath, maxBytes) {
|
|
4003
4003
|
if (maxBytes === void 0) {
|
|
@@ -4104,12 +4104,12 @@ function shouldLogDebugMessage(message2) {
|
|
|
4104
4104
|
var hasFormattedOutput = false;
|
|
4105
4105
|
var debugWriter = null;
|
|
4106
4106
|
var pendingWrite = Promise.resolve();
|
|
4107
|
-
async function appendAsync(needMkdir, dir,
|
|
4107
|
+
async function appendAsync(needMkdir, dir, path60, content) {
|
|
4108
4108
|
if (needMkdir) {
|
|
4109
4109
|
await mkdir(dir, { recursive: true }).catch(() => {
|
|
4110
4110
|
});
|
|
4111
4111
|
}
|
|
4112
|
-
await appendFile(
|
|
4112
|
+
await appendFile(path60, content);
|
|
4113
4113
|
void updateLatestDebugLogSymlink();
|
|
4114
4114
|
}
|
|
4115
4115
|
function noop() {
|
|
@@ -4119,8 +4119,8 @@ function getDebugWriter() {
|
|
|
4119
4119
|
let ensuredDir = null;
|
|
4120
4120
|
debugWriter = createBufferedWriter({
|
|
4121
4121
|
writeFn: (content) => {
|
|
4122
|
-
const
|
|
4123
|
-
const dir = dirname(
|
|
4122
|
+
const path60 = getDebugLogPath();
|
|
4123
|
+
const dir = dirname(path60);
|
|
4124
4124
|
const needMkdir = ensuredDir !== dir;
|
|
4125
4125
|
ensuredDir = dir;
|
|
4126
4126
|
if (isDebugMode()) {
|
|
@@ -4130,11 +4130,11 @@ function getDebugWriter() {
|
|
|
4130
4130
|
} catch {
|
|
4131
4131
|
}
|
|
4132
4132
|
}
|
|
4133
|
-
getFsImplementation().appendFileSync(
|
|
4133
|
+
getFsImplementation().appendFileSync(path60, content);
|
|
4134
4134
|
void updateLatestDebugLogSymlink();
|
|
4135
4135
|
return;
|
|
4136
4136
|
}
|
|
4137
|
-
pendingWrite = pendingWrite.then(appendAsync.bind(null, needMkdir, dir,
|
|
4137
|
+
pendingWrite = pendingWrite.then(appendAsync.bind(null, needMkdir, dir, path60, content)).catch(noop);
|
|
4138
4138
|
},
|
|
4139
4139
|
flushIntervalMs: 1e3,
|
|
4140
4140
|
maxBufferSize: 100,
|
|
@@ -10321,8 +10321,8 @@ import codeExcerpt from "code-excerpt";
|
|
|
10321
10321
|
import { readFileSync as readFileSync2 } from "fs";
|
|
10322
10322
|
import StackUtils from "stack-utils";
|
|
10323
10323
|
import { jsx as jsx6, jsxs } from "react/jsx-runtime";
|
|
10324
|
-
var cleanupPath = (
|
|
10325
|
-
return
|
|
10324
|
+
var cleanupPath = (path60) => {
|
|
10325
|
+
return path60?.replace(`file://${process.cwd()}/`, "");
|
|
10326
10326
|
};
|
|
10327
10327
|
var stackUtils;
|
|
10328
10328
|
function getStackUtils() {
|
|
@@ -14299,8 +14299,8 @@ var getInstance = (stdout, createInstance) => {
|
|
|
14299
14299
|
|
|
14300
14300
|
// src/main.ts
|
|
14301
14301
|
import { EventEmitter as EventEmitter7 } from "events";
|
|
14302
|
-
import
|
|
14303
|
-
import
|
|
14302
|
+
import fs53 from "fs";
|
|
14303
|
+
import path59 from "path";
|
|
14304
14304
|
import { fileURLToPath as fileURLToPath8 } from "url";
|
|
14305
14305
|
import { spawn as spawn6 } from "child_process";
|
|
14306
14306
|
import { v4 as uuidv412 } from "uuid";
|
|
@@ -14979,7 +14979,7 @@ function cancelSlashSubmenu() {
|
|
|
14979
14979
|
|
|
14980
14980
|
// src/app/agent/agent.ts
|
|
14981
14981
|
import * as dotenv from "dotenv";
|
|
14982
|
-
import
|
|
14982
|
+
import path49 from "path";
|
|
14983
14983
|
import os30 from "os";
|
|
14984
14984
|
|
|
14985
14985
|
// src/app/agent/tool_invoker.ts
|
|
@@ -22028,14 +22028,14 @@ PENALTY APPLIED: ${penalty.toFixed(1)} points deducted.
|
|
|
22028
22028
|
|
|
22029
22029
|
// src/app/agent/bluma/core/bluma.ts
|
|
22030
22030
|
init_session_manager();
|
|
22031
|
-
import
|
|
22032
|
-
import
|
|
22031
|
+
import path46 from "path";
|
|
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
|
|
22038
|
-
import
|
|
22037
|
+
import fs37 from "fs";
|
|
22038
|
+
import path40 from "path";
|
|
22039
22039
|
import { execSync as execSync3 } from "child_process";
|
|
22040
22040
|
|
|
22041
22041
|
// src/app/agent/skills/skill_loader.ts
|
|
@@ -23892,12 +23892,12 @@ init_session_memory_paths();
|
|
|
23892
23892
|
import { readFile as readFile3, writeFile as writeFile2 } from "fs/promises";
|
|
23893
23893
|
async function loadSessionMemoryForPrompt(sessionId, cwd2 = process.cwd()) {
|
|
23894
23894
|
if (!sessionId?.trim()) return "";
|
|
23895
|
-
const
|
|
23895
|
+
const path60 = getSessionMemoryPath(sessionId, cwd2);
|
|
23896
23896
|
try {
|
|
23897
|
-
const content = await readFile3(
|
|
23897
|
+
const content = await readFile3(path60, "utf-8");
|
|
23898
23898
|
if (!content.trim()) return "";
|
|
23899
23899
|
return `<session_memory>
|
|
23900
|
-
Notes for this conversation (${
|
|
23900
|
+
Notes for this conversation (${path60}):
|
|
23901
23901
|
|
|
23902
23902
|
${content.trim()}
|
|
23903
23903
|
</session_memory>`;
|
|
@@ -23907,11 +23907,11 @@ ${content.trim()}
|
|
|
23907
23907
|
}
|
|
23908
23908
|
async function initSessionMemoryFile(sessionId, cwd2 = process.cwd()) {
|
|
23909
23909
|
await ensureSessionMemoryDir(sessionId, cwd2);
|
|
23910
|
-
const
|
|
23910
|
+
const path60 = getSessionMemoryPath(sessionId, cwd2);
|
|
23911
23911
|
try {
|
|
23912
|
-
await readFile3(
|
|
23912
|
+
await readFile3(path60, "utf-8");
|
|
23913
23913
|
} catch {
|
|
23914
|
-
await writeFile2(
|
|
23914
|
+
await writeFile2(path60, `${DEFAULT_SESSION_MEMORY_TEMPLATE}
|
|
23915
23915
|
`, "utf-8");
|
|
23916
23916
|
}
|
|
23917
23917
|
}
|
|
@@ -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,6 +24013,146 @@ 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
|
+
import path39 from "path";
|
|
24069
|
+
function env2(key) {
|
|
24070
|
+
return String(process.env[key] ?? "").trim();
|
|
24071
|
+
}
|
|
24072
|
+
function listWorkspaceTopLevel(cwd2, max = 24) {
|
|
24073
|
+
try {
|
|
24074
|
+
return fs36.readdirSync(cwd2, { withFileTypes: true }).filter((e) => !e.name.startsWith(".")).slice(0, max).map((e) => e.isDirectory() ? `${e.name}/` : e.name);
|
|
24075
|
+
} catch {
|
|
24076
|
+
return [];
|
|
24077
|
+
}
|
|
24078
|
+
}
|
|
24079
|
+
function buildSandboxRuntimeContextBlock(cwd2) {
|
|
24080
|
+
const sessionId = env2("BLUMA_SESSION_ID") || "unknown";
|
|
24081
|
+
const sandboxName = env2("BLUMA_SANDBOX_NAME") || "sandbox-api";
|
|
24082
|
+
const fromAgent = env2("BLUMA_FROM_AGENT") || "orchestrator";
|
|
24083
|
+
const action = env2("BLUMA_ACTION") || "unknown";
|
|
24084
|
+
const severinoUrl = env2("SEVERINO_URL");
|
|
24085
|
+
const factoraiUrl = env2("FACTORAI_BASE_URL") || env2("FACTORAI_URL") || severinoUrl;
|
|
24086
|
+
const userRequest = env2("BLUMA_USER_REQUEST");
|
|
24087
|
+
const factoraiEnabled = isFactorAiShPromptEnabled();
|
|
24088
|
+
const top = listWorkspaceTopLevel(cwd2);
|
|
24089
|
+
const lines = [
|
|
24090
|
+
"<sandbox_runtime>",
|
|
24091
|
+
"## Ambiente atual (factos reais \u2014 usa isto para te orientares)",
|
|
24092
|
+
"",
|
|
24093
|
+
"Operas como **agente aut\xF3nomo** (estilo Manus): n\xE3o h\xE1 utilizador no terminal a responder. O orquestrador (Severino / sandbox-api) envia o pedido, observa o teu progresso via `message(info)` e s\xF3 encerra o job com `message(result)`.",
|
|
24094
|
+
"",
|
|
24095
|
+
"| Campo | Valor |",
|
|
24096
|
+
"|-------|-------|",
|
|
24097
|
+
`| sandbox | ${sandboxName} |`,
|
|
24098
|
+
`| session_id | ${sessionId} |`,
|
|
24099
|
+
`| workspace (cwd) | ${cwd2} |`,
|
|
24100
|
+
`| delegado por | ${fromAgent} |`,
|
|
24101
|
+
`| action | ${action} |`,
|
|
24102
|
+
`| node | ${process.version} |`,
|
|
24103
|
+
`| auto_approve_tools | sim (sandbox isolado) |`
|
|
24104
|
+
];
|
|
24105
|
+
if (severinoUrl) {
|
|
24106
|
+
lines.push(`| SEVERINO_URL (deploy ZIP) | ${severinoUrl} |`);
|
|
24107
|
+
}
|
|
24108
|
+
if (factoraiUrl) {
|
|
24109
|
+
lines.push(`| FACTORAI_BASE_URL (status/apply/redeploy) | ${factoraiUrl} |`);
|
|
24110
|
+
}
|
|
24111
|
+
if (severinoUrl && factoraiUrl && severinoUrl !== factoraiUrl) {
|
|
24112
|
+
lines.push("");
|
|
24113
|
+
lines.push(
|
|
24114
|
+
"\u26A0\uFE0F SEVERINO_URL e FACTORAI_BASE_URL diferem \u2014 confirma qual backend falhou se `get_app_status` der 404 ap\xF3s deploy."
|
|
24115
|
+
);
|
|
24116
|
+
}
|
|
24117
|
+
if (factoraiEnabled) {
|
|
24118
|
+
lines.push("");
|
|
24119
|
+
lines.push("**FactorAI.sh:** ativo nesta sess\xE3o (`factorai.sh.*` tools dispon\xEDveis).");
|
|
24120
|
+
} else {
|
|
24121
|
+
lines.push("");
|
|
24122
|
+
lines.push(
|
|
24123
|
+
"**FactorAI.sh:** n\xE3o configurado (falta `FACTORAI_BASE_URL` ou `BLUMA_SANDBOX`). Hosting Next.js via factorai.sh indispon\xEDvel at\xE9 o orquestrador definir env."
|
|
24124
|
+
);
|
|
24125
|
+
}
|
|
24126
|
+
if (top.length > 0) {
|
|
24127
|
+
lines.push("");
|
|
24128
|
+
lines.push(`**Raiz do workspace:** ${top.join(", ")}`);
|
|
24129
|
+
}
|
|
24130
|
+
const manifest = readFactorAiWorkspaceManifest(cwd2);
|
|
24131
|
+
if (manifest) {
|
|
24132
|
+
const ctx = manifest.appContext;
|
|
24133
|
+
const appId = ctx?.appId;
|
|
24134
|
+
const liveUrl = resolveFactorShAppLiveUrl(cwd2);
|
|
24135
|
+
lines.push("");
|
|
24136
|
+
lines.push("**App FactorAI nesta sess\xE3o (factorai.sh.json):**");
|
|
24137
|
+
if (appId) lines.push(`- appId: ${appId}`);
|
|
24138
|
+
if (liveUrl) lines.push(`- appUrl: ${liveUrl}`);
|
|
24139
|
+
const appDir = typeof manifest.app === "object" && manifest.app && typeof manifest.app.name === "string" ? manifest.app.name : null;
|
|
24140
|
+
if (appDir) {
|
|
24141
|
+
const projectPath = path39.join(cwd2, appDir);
|
|
24142
|
+
if (fs36.existsSync(projectPath)) {
|
|
24143
|
+
lines.push(`- project_dir: ${projectPath}`);
|
|
24144
|
+
}
|
|
24145
|
+
}
|
|
24146
|
+
}
|
|
24147
|
+
if (userRequest) {
|
|
24148
|
+
lines.push("");
|
|
24149
|
+
lines.push("**Pedido deste turno (resumo):**");
|
|
24150
|
+
lines.push(userRequest.length > 2500 ? `${userRequest.slice(0, 2500)}\u2026` : userRequest);
|
|
24151
|
+
}
|
|
24152
|
+
lines.push("</sandbox_runtime>");
|
|
24153
|
+
return lines.join("\n");
|
|
24154
|
+
}
|
|
24155
|
+
|
|
24016
24156
|
// src/app/agent/core/prompt/prompt_builder.ts
|
|
24017
24157
|
function getNodeVersion() {
|
|
24018
24158
|
return process.version;
|
|
@@ -24044,17 +24184,17 @@ function getGitBranch(dir) {
|
|
|
24044
24184
|
}
|
|
24045
24185
|
}
|
|
24046
24186
|
function getPackageManager(dir) {
|
|
24047
|
-
if (
|
|
24048
|
-
if (
|
|
24049
|
-
if (
|
|
24050
|
-
if (
|
|
24187
|
+
if (fs37.existsSync(path40.join(dir, "pnpm-lock.yaml"))) return "pnpm";
|
|
24188
|
+
if (fs37.existsSync(path40.join(dir, "yarn.lock"))) return "yarn";
|
|
24189
|
+
if (fs37.existsSync(path40.join(dir, "bun.lockb"))) return "bun";
|
|
24190
|
+
if (fs37.existsSync(path40.join(dir, "package-lock.json"))) return "npm";
|
|
24051
24191
|
return "unknown";
|
|
24052
24192
|
}
|
|
24053
24193
|
function getProjectType(dir) {
|
|
24054
24194
|
try {
|
|
24055
|
-
const files =
|
|
24195
|
+
const files = fs37.readdirSync(dir);
|
|
24056
24196
|
if (files.includes("package.json")) {
|
|
24057
|
-
const pkg = JSON.parse(
|
|
24197
|
+
const pkg = JSON.parse(fs37.readFileSync(path40.join(dir, "package.json"), "utf-8"));
|
|
24058
24198
|
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
24059
24199
|
if (deps.next) return "Next.js";
|
|
24060
24200
|
if (deps.react) return "React";
|
|
@@ -24074,9 +24214,9 @@ function getProjectType(dir) {
|
|
|
24074
24214
|
}
|
|
24075
24215
|
function getTestFramework(dir) {
|
|
24076
24216
|
try {
|
|
24077
|
-
const pkgPath =
|
|
24078
|
-
if (
|
|
24079
|
-
const pkg = JSON.parse(
|
|
24217
|
+
const pkgPath = path40.join(dir, "package.json");
|
|
24218
|
+
if (fs37.existsSync(pkgPath)) {
|
|
24219
|
+
const pkg = JSON.parse(fs37.readFileSync(pkgPath, "utf-8"));
|
|
24080
24220
|
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
24081
24221
|
if (deps.jest) return "jest";
|
|
24082
24222
|
if (deps.vitest) return "vitest";
|
|
@@ -24085,7 +24225,7 @@ function getTestFramework(dir) {
|
|
|
24085
24225
|
if (deps["@playwright/test"]) return "playwright";
|
|
24086
24226
|
if (deps.cypress) return "cypress";
|
|
24087
24227
|
}
|
|
24088
|
-
if (
|
|
24228
|
+
if (fs37.existsSync(path40.join(dir, "pytest.ini")) || fs37.existsSync(path40.join(dir, "conftest.py"))) return "pytest";
|
|
24089
24229
|
return "unknown";
|
|
24090
24230
|
} catch {
|
|
24091
24231
|
return "unknown";
|
|
@@ -24093,9 +24233,9 @@ function getTestFramework(dir) {
|
|
|
24093
24233
|
}
|
|
24094
24234
|
function getTestCommand(dir) {
|
|
24095
24235
|
try {
|
|
24096
|
-
const pkgPath =
|
|
24097
|
-
if (
|
|
24098
|
-
const pkg = JSON.parse(
|
|
24236
|
+
const pkgPath = path40.join(dir, "package.json");
|
|
24237
|
+
if (fs37.existsSync(pkgPath)) {
|
|
24238
|
+
const pkg = JSON.parse(fs37.readFileSync(pkgPath, "utf-8"));
|
|
24099
24239
|
if (pkg.scripts?.test) return "npm test";
|
|
24100
24240
|
if (pkg.scripts?.["test:unit"]) return "npm run test:unit";
|
|
24101
24241
|
}
|
|
@@ -24110,8 +24250,8 @@ function getTestCommand(dir) {
|
|
|
24110
24250
|
}
|
|
24111
24251
|
function isGitRepo(dir) {
|
|
24112
24252
|
try {
|
|
24113
|
-
const p =
|
|
24114
|
-
return
|
|
24253
|
+
const p = path40.join(dir, ".git");
|
|
24254
|
+
return fs37.existsSync(p) && fs37.lstatSync(p).isDirectory();
|
|
24115
24255
|
} catch {
|
|
24116
24256
|
return false;
|
|
24117
24257
|
}
|
|
@@ -24322,7 +24462,7 @@ async function getUnifiedSystemPrompt(availableSkills, options) {
|
|
|
24322
24462
|
const runtimeConfig = getRuntimeConfig();
|
|
24323
24463
|
const cwd2 = process.cwd();
|
|
24324
24464
|
const isSandbox = process.env.BLUMA_SANDBOX === "true";
|
|
24325
|
-
const
|
|
24465
|
+
const env3 = {
|
|
24326
24466
|
os_type: os23.type(),
|
|
24327
24467
|
os_version: os23.release(),
|
|
24328
24468
|
architecture: os23.arch(),
|
|
@@ -24347,7 +24487,7 @@ async function getUnifiedSystemPrompt(availableSkills, options) {
|
|
|
24347
24487
|
session_id: process.env.BLUMA_SESSION_ID || "unknown",
|
|
24348
24488
|
workspace_root: cwd2
|
|
24349
24489
|
};
|
|
24350
|
-
const interpolate = (template) => Object.entries(
|
|
24490
|
+
const interpolate = (template) => Object.entries(env3).reduce((s, [k, v]) => s.replaceAll(`{${k}}`, v), template);
|
|
24351
24491
|
let prompt = interpolate(SYSTEM_PROMPT).replace(
|
|
24352
24492
|
"<<<BLUMA_WORKSPACE_SNAPSHOT_BODY>>>",
|
|
24353
24493
|
buildWorkspaceSnapshot(cwd2)
|
|
@@ -24366,6 +24506,12 @@ async function getUnifiedSystemPrompt(availableSkills, options) {
|
|
|
24366
24506
|
prompt += `
|
|
24367
24507
|
|
|
24368
24508
|
${SUBJECT_MACHINE_MODEL_XML}`;
|
|
24509
|
+
prompt += `
|
|
24510
|
+
|
|
24511
|
+
${buildSandboxRuntimeContextBlock(cwd2)}`;
|
|
24512
|
+
prompt += `
|
|
24513
|
+
|
|
24514
|
+
${SANDBOX_AUTONOMY_SECTION}`;
|
|
24369
24515
|
prompt += interpolate(SANDBOX_SECTION);
|
|
24370
24516
|
if (isFactorAiShPromptEnabled()) {
|
|
24371
24517
|
prompt += `
|
|
@@ -25545,9 +25691,9 @@ var LLMService = class {
|
|
|
25545
25691
|
};
|
|
25546
25692
|
|
|
25547
25693
|
// src/app/agent/utils/user_message_images.ts
|
|
25548
|
-
import
|
|
25694
|
+
import fs38 from "fs";
|
|
25549
25695
|
import os25 from "os";
|
|
25550
|
-
import
|
|
25696
|
+
import path41 from "path";
|
|
25551
25697
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
25552
25698
|
var IMAGE_EXT = /\.(png|jpe?g|gif|webp|bmp)$/i;
|
|
25553
25699
|
var MAX_IMAGE_BYTES = 4 * 1024 * 1024;
|
|
@@ -25563,22 +25709,22 @@ var MIME = {
|
|
|
25563
25709
|
function expandUserPath(p) {
|
|
25564
25710
|
const t = p.trim();
|
|
25565
25711
|
if (t.startsWith("~")) {
|
|
25566
|
-
return
|
|
25712
|
+
return path41.join(os25.homedir(), t.slice(1).replace(/^\//, ""));
|
|
25567
25713
|
}
|
|
25568
25714
|
return t;
|
|
25569
25715
|
}
|
|
25570
25716
|
function isPathAllowed(absResolved, cwd2) {
|
|
25571
|
-
const resolved =
|
|
25572
|
-
const cwdR =
|
|
25573
|
-
const homeR =
|
|
25574
|
-
const tmpR =
|
|
25575
|
-
const underCwd = resolved === cwdR || resolved.startsWith(cwdR +
|
|
25576
|
-
const underHome = resolved === homeR || resolved.startsWith(homeR +
|
|
25577
|
-
const underTmp = resolved === tmpR || resolved.startsWith(tmpR +
|
|
25717
|
+
const resolved = path41.normalize(path41.resolve(absResolved));
|
|
25718
|
+
const cwdR = path41.normalize(path41.resolve(cwd2));
|
|
25719
|
+
const homeR = path41.normalize(path41.resolve(os25.homedir()));
|
|
25720
|
+
const tmpR = path41.normalize(path41.resolve(os25.tmpdir()));
|
|
25721
|
+
const underCwd = resolved === cwdR || resolved.startsWith(cwdR + path41.sep);
|
|
25722
|
+
const underHome = resolved === homeR || resolved.startsWith(homeR + path41.sep);
|
|
25723
|
+
const underTmp = resolved === tmpR || resolved.startsWith(tmpR + path41.sep);
|
|
25578
25724
|
return underCwd || underHome || underTmp;
|
|
25579
25725
|
}
|
|
25580
25726
|
function mimeFor(abs) {
|
|
25581
|
-
const ext =
|
|
25727
|
+
const ext = path41.extname(abs).toLowerCase();
|
|
25582
25728
|
return MIME[ext] || "application/octet-stream";
|
|
25583
25729
|
}
|
|
25584
25730
|
var IMAGE_EXT_SRC = String.raw`(?:png|jpe?g|gif|webp|bmp)`;
|
|
@@ -25622,10 +25768,10 @@ function collectImagePathStrings(raw) {
|
|
|
25622
25768
|
}
|
|
25623
25769
|
function resolveImagePath(candidate, cwd2) {
|
|
25624
25770
|
const expanded = expandUserPath(candidate);
|
|
25625
|
-
const abs =
|
|
25771
|
+
const abs = path41.isAbsolute(expanded) ? path41.normalize(expanded) : path41.normalize(path41.resolve(cwd2, expanded));
|
|
25626
25772
|
if (!isPathAllowed(abs, cwd2)) return null;
|
|
25627
25773
|
try {
|
|
25628
|
-
if (!
|
|
25774
|
+
if (!fs38.existsSync(abs) || !fs38.statSync(abs).isFile()) return null;
|
|
25629
25775
|
} catch {
|
|
25630
25776
|
return null;
|
|
25631
25777
|
}
|
|
@@ -25645,11 +25791,11 @@ function trySingleLineFileUriOrBareImagePath(line, cwd2) {
|
|
|
25645
25791
|
if (s.startsWith('"') && s.endsWith('"') || s.startsWith("'") && s.endsWith("'")) {
|
|
25646
25792
|
s = s.slice(1, -1).trim();
|
|
25647
25793
|
}
|
|
25648
|
-
if (!IMAGE_EXT.test(
|
|
25794
|
+
if (!IMAGE_EXT.test(path41.extname(s))) return null;
|
|
25649
25795
|
const abs = resolveImagePath(s, cwd2);
|
|
25650
25796
|
if (!abs) return null;
|
|
25651
25797
|
try {
|
|
25652
|
-
const st =
|
|
25798
|
+
const st = fs38.statSync(abs);
|
|
25653
25799
|
if (!st.isFile() || st.size > MAX_IMAGE_BYTES) {
|
|
25654
25800
|
return null;
|
|
25655
25801
|
}
|
|
@@ -25684,7 +25830,7 @@ function tryPasteChunkAsSingleImagePath(chunk, cwd2) {
|
|
|
25684
25830
|
return null;
|
|
25685
25831
|
}
|
|
25686
25832
|
try {
|
|
25687
|
-
const st =
|
|
25833
|
+
const st = fs38.statSync(abs);
|
|
25688
25834
|
if (!st.isFile() || st.size > MAX_IMAGE_BYTES) {
|
|
25689
25835
|
return null;
|
|
25690
25836
|
}
|
|
@@ -25713,7 +25859,7 @@ function buildUserMessageContent(raw, cwd2) {
|
|
|
25713
25859
|
const abs = resolveImagePath(c, cwd2);
|
|
25714
25860
|
if (!abs) continue;
|
|
25715
25861
|
try {
|
|
25716
|
-
const st =
|
|
25862
|
+
const st = fs38.statSync(abs);
|
|
25717
25863
|
if (st.size > MAX_IMAGE_BYTES) continue;
|
|
25718
25864
|
} catch {
|
|
25719
25865
|
continue;
|
|
@@ -25730,7 +25876,7 @@ function buildUserMessageContent(raw, cwd2) {
|
|
|
25730
25876
|
}
|
|
25731
25877
|
const parts = [{ type: "text", text: textPart }];
|
|
25732
25878
|
for (const abs of resolvedAbs) {
|
|
25733
|
-
const buf =
|
|
25879
|
+
const buf = fs38.readFileSync(abs);
|
|
25734
25880
|
const b64 = buf.toString("base64");
|
|
25735
25881
|
const mime = mimeFor(abs);
|
|
25736
25882
|
parts.push({
|
|
@@ -25748,7 +25894,7 @@ function buildUserMessageContent(raw, cwd2) {
|
|
|
25748
25894
|
init_sandbox_policy();
|
|
25749
25895
|
init_runtime_config();
|
|
25750
25896
|
init_permission_rules();
|
|
25751
|
-
import
|
|
25897
|
+
import path42 from "path";
|
|
25752
25898
|
var LOCAL_EDIT_TOOL_NAMES = /* @__PURE__ */ new Set(["edit_tool", "file_write", "notebook_edit"]);
|
|
25753
25899
|
function getToolPermissionLayer(metadata) {
|
|
25754
25900
|
if (metadata.riskLevel === "safe") return "read";
|
|
@@ -25763,11 +25909,11 @@ function checkFilePermissionRules(toolName, filePath, policy) {
|
|
|
25763
25909
|
if (!filePath) {
|
|
25764
25910
|
return { allowed: false, reason: "No file path provided for permission check." };
|
|
25765
25911
|
}
|
|
25766
|
-
const resolvedPath =
|
|
25912
|
+
const resolvedPath = path42.resolve(filePath);
|
|
25767
25913
|
if (!isPathInsideWorkspace(resolvedPath, policy)) {
|
|
25768
25914
|
return { allowed: false, reason: `File path "${filePath}" is outside workspace root.` };
|
|
25769
25915
|
}
|
|
25770
|
-
const relativePath =
|
|
25916
|
+
const relativePath = path42.relative(policy.workspaceRoot, resolvedPath);
|
|
25771
25917
|
const toolPattern = `${toolName}(${relativePath})`;
|
|
25772
25918
|
const ruleDecision = permissionRulesEngine.checkPermission(toolPattern, { filepath: filePath });
|
|
25773
25919
|
if (ruleDecision === "deny") {
|
|
@@ -25776,7 +25922,7 @@ function checkFilePermissionRules(toolName, filePath, policy) {
|
|
|
25776
25922
|
if (ruleDecision === "allow") {
|
|
25777
25923
|
return { allowed: true, reason: `File "${filePath}" allowed by permission rules.` };
|
|
25778
25924
|
}
|
|
25779
|
-
const dirPath =
|
|
25925
|
+
const dirPath = path42.dirname(relativePath);
|
|
25780
25926
|
const dirPattern = `${toolName}(${dirPath}/**)`;
|
|
25781
25927
|
const dirRuleDecision = permissionRulesEngine.checkPermission(dirPattern, { filepath: filePath });
|
|
25782
25928
|
if (dirRuleDecision === "allow") {
|
|
@@ -25993,11 +26139,11 @@ function effectiveToolAutoApprove(toolCall, sessionId, options) {
|
|
|
25993
26139
|
}
|
|
25994
26140
|
|
|
25995
26141
|
// src/app/agent/tools/CodingMemoryTool/CodingMemoryConsolidate.ts
|
|
25996
|
-
import * as
|
|
25997
|
-
import * as
|
|
26142
|
+
import * as fs39 from "fs";
|
|
26143
|
+
import * as path43 from "path";
|
|
25998
26144
|
import os26 from "os";
|
|
25999
26145
|
function memoryPath2() {
|
|
26000
|
-
return
|
|
26146
|
+
return path43.join(process.env.HOME || os26.homedir(), ".bluma", "coding_memory.json");
|
|
26001
26147
|
}
|
|
26002
26148
|
function normalizeNote2(note) {
|
|
26003
26149
|
return note.trim().toLowerCase().replace(/\s+/g, " ");
|
|
@@ -26007,18 +26153,18 @@ function uniqTags(a, b) {
|
|
|
26007
26153
|
}
|
|
26008
26154
|
function consolidateCodingMemoryFile() {
|
|
26009
26155
|
const p = memoryPath2();
|
|
26010
|
-
if (!
|
|
26156
|
+
if (!fs39.existsSync(p)) {
|
|
26011
26157
|
return { success: true, removedDuplicates: 0, message: "no coding_memory.json" };
|
|
26012
26158
|
}
|
|
26013
26159
|
const bak = `${p}.bak`;
|
|
26014
26160
|
try {
|
|
26015
|
-
|
|
26161
|
+
fs39.copyFileSync(p, bak);
|
|
26016
26162
|
} catch (e) {
|
|
26017
26163
|
return { success: false, removedDuplicates: 0, message: `backup failed: ${e.message}` };
|
|
26018
26164
|
}
|
|
26019
26165
|
let data;
|
|
26020
26166
|
try {
|
|
26021
|
-
data = JSON.parse(
|
|
26167
|
+
data = JSON.parse(fs39.readFileSync(p, "utf-8"));
|
|
26022
26168
|
} catch (e) {
|
|
26023
26169
|
return { success: false, removedDuplicates: 0, message: `invalid json: ${e.message}` };
|
|
26024
26170
|
}
|
|
@@ -26053,7 +26199,7 @@ function consolidateCodingMemoryFile() {
|
|
|
26053
26199
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
26054
26200
|
};
|
|
26055
26201
|
try {
|
|
26056
|
-
|
|
26202
|
+
fs39.writeFileSync(p, JSON.stringify(out, null, 2), "utf-8");
|
|
26057
26203
|
} catch (e) {
|
|
26058
26204
|
return { success: false, removedDuplicates: 0, message: `write failed: ${e.message}` };
|
|
26059
26205
|
}
|
|
@@ -26559,18 +26705,18 @@ var BluMaToolRunner = class {
|
|
|
26559
26705
|
|
|
26560
26706
|
// src/app/agent/session_manager/session_archive.ts
|
|
26561
26707
|
init_bluma_app_dir();
|
|
26562
|
-
import
|
|
26563
|
-
import { promises as
|
|
26708
|
+
import path44 from "path";
|
|
26709
|
+
import { promises as fs40 } from "fs";
|
|
26564
26710
|
async function archivePrunedConversationMessages(sessionId, messages) {
|
|
26565
26711
|
if (!sessionId || messages.length === 0) {
|
|
26566
26712
|
return null;
|
|
26567
26713
|
}
|
|
26568
26714
|
const appDir = getPreferredAppDir();
|
|
26569
|
-
const dir =
|
|
26570
|
-
await
|
|
26571
|
-
const archiveFile =
|
|
26715
|
+
const dir = path44.join(appDir, "sessions", "archive", sessionId);
|
|
26716
|
+
await fs40.mkdir(dir, { recursive: true });
|
|
26717
|
+
const archiveFile = path44.join(dir, `${Date.now()}.jsonl`);
|
|
26572
26718
|
const lines = messages.map((m) => JSON.stringify(m)).join("\n") + "\n";
|
|
26573
|
-
await
|
|
26719
|
+
await fs40.appendFile(archiveFile, lines, "utf-8");
|
|
26574
26720
|
return archiveFile;
|
|
26575
26721
|
}
|
|
26576
26722
|
|
|
@@ -27431,7 +27577,7 @@ Update existing files instead of duplicating.` : "";
|
|
|
27431
27577
|
|
|
27432
27578
|
// src/app/agent/memory/memory_tool_policy.ts
|
|
27433
27579
|
init_paths();
|
|
27434
|
-
import
|
|
27580
|
+
import path45 from "path";
|
|
27435
27581
|
var MEMORY_READ_TOOLS = /* @__PURE__ */ new Set([
|
|
27436
27582
|
"read_file_lines",
|
|
27437
27583
|
"grep_search",
|
|
@@ -27458,7 +27604,7 @@ function isReadOnlyShellCommand(command) {
|
|
|
27458
27604
|
return READ_ONLY_SHELL.test(trimmed);
|
|
27459
27605
|
}
|
|
27460
27606
|
function createAutoMemToolGate(memoryDir) {
|
|
27461
|
-
const memRoot = memoryDir.endsWith(
|
|
27607
|
+
const memRoot = memoryDir.endsWith(path45.sep) ? memoryDir : memoryDir + path45.sep;
|
|
27462
27608
|
return (toolName, args) => {
|
|
27463
27609
|
if (MEMORY_READ_TOOLS.has(toolName)) {
|
|
27464
27610
|
return { allowed: true };
|
|
@@ -27471,7 +27617,7 @@ function createAutoMemToolGate(memoryDir) {
|
|
|
27471
27617
|
}
|
|
27472
27618
|
if (MEMORY_WRITE_TOOLS.has(toolName)) {
|
|
27473
27619
|
const fp = extractFilePath(args);
|
|
27474
|
-
if (fp && isAutoMemPath(
|
|
27620
|
+
if (fp && isAutoMemPath(path45.resolve(fp))) {
|
|
27475
27621
|
return { allowed: true };
|
|
27476
27622
|
}
|
|
27477
27623
|
return { allowed: false, reason: `Writes must stay under ${memRoot}` };
|
|
@@ -27480,18 +27626,18 @@ function createAutoMemToolGate(memoryDir) {
|
|
|
27480
27626
|
};
|
|
27481
27627
|
}
|
|
27482
27628
|
function createSessionMemoryToolGate(sessionMemoryPath) {
|
|
27483
|
-
const resolvedTarget =
|
|
27629
|
+
const resolvedTarget = path45.resolve(sessionMemoryPath);
|
|
27484
27630
|
return (toolName, args) => {
|
|
27485
27631
|
if (toolName === "read_file_lines") {
|
|
27486
27632
|
const fp = extractFilePath(args);
|
|
27487
|
-
if (fp &&
|
|
27633
|
+
if (fp && path45.resolve(fp) === resolvedTarget) {
|
|
27488
27634
|
return { allowed: true };
|
|
27489
27635
|
}
|
|
27490
27636
|
return { allowed: false, reason: "Session memory subagent may only read the session summary file" };
|
|
27491
27637
|
}
|
|
27492
27638
|
if (toolName === "edit_tool") {
|
|
27493
27639
|
const fp = extractFilePath(args);
|
|
27494
|
-
if (fp &&
|
|
27640
|
+
if (fp && path45.resolve(fp) === resolvedTarget) {
|
|
27495
27641
|
return { allowed: true };
|
|
27496
27642
|
}
|
|
27497
27643
|
return { allowed: false, reason: "Session memory subagent may only edit the session summary file" };
|
|
@@ -27518,7 +27664,7 @@ function hasAutoMemWritesSinceHistory(history, sinceIndex) {
|
|
|
27518
27664
|
continue;
|
|
27519
27665
|
}
|
|
27520
27666
|
const fp = extractFilePath(args);
|
|
27521
|
-
if (fp && isAutoMemPath(
|
|
27667
|
+
if (fp && isAutoMemPath(path45.resolve(fp))) {
|
|
27522
27668
|
return true;
|
|
27523
27669
|
}
|
|
27524
27670
|
}
|
|
@@ -27986,13 +28132,13 @@ var BluMaAgent = class {
|
|
|
27986
28132
|
if (!this.sessionFile) return;
|
|
27987
28133
|
try {
|
|
27988
28134
|
const sessionData = {
|
|
27989
|
-
session_id:
|
|
28135
|
+
session_id: path46.basename(this.sessionFile, ".json"),
|
|
27990
28136
|
created_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
27991
28137
|
conversation_history: this.history,
|
|
27992
28138
|
last_updated: (/* @__PURE__ */ new Date()).toISOString(),
|
|
27993
28139
|
...this.compressor.getSnapshot()
|
|
27994
28140
|
};
|
|
27995
|
-
|
|
28141
|
+
fs41.writeFileSync(this.sessionFile, JSON.stringify(sessionData, null, 2), "utf-8");
|
|
27996
28142
|
} catch (error) {
|
|
27997
28143
|
console.error("[Bluma] Failed to persist session synchronously:", error);
|
|
27998
28144
|
}
|
|
@@ -28198,7 +28344,7 @@ var BluMaAgent = class {
|
|
|
28198
28344
|
|
|
28199
28345
|
${editData.error.display}`;
|
|
28200
28346
|
}
|
|
28201
|
-
const filename =
|
|
28347
|
+
const filename = path46.basename(toolArgs.file_path);
|
|
28202
28348
|
return createDiff(filename, editData.currentContent || "", editData.newContent);
|
|
28203
28349
|
} catch (e) {
|
|
28204
28350
|
return `An unexpected error occurred while generating the edit preview: ${e.message}`;
|
|
@@ -28933,16 +29079,16 @@ async function fullCompact(messages, targetTokens, summarizer, llmClient) {
|
|
|
28933
29079
|
}
|
|
28934
29080
|
|
|
28935
29081
|
// src/app/agent/core/memory/session_memory.ts
|
|
28936
|
-
import
|
|
29082
|
+
import fs42 from "fs";
|
|
28937
29083
|
import os29 from "os";
|
|
28938
|
-
import
|
|
29084
|
+
import path47 from "path";
|
|
28939
29085
|
import { v4 as uuidv49 } from "uuid";
|
|
28940
29086
|
var SessionMemoryExtractor = class {
|
|
28941
29087
|
llmClient;
|
|
28942
29088
|
memoryFile;
|
|
28943
29089
|
constructor(options = {}) {
|
|
28944
29090
|
this.llmClient = options.llmClient;
|
|
28945
|
-
this.memoryFile = options.memoryFile ||
|
|
29091
|
+
this.memoryFile = options.memoryFile || path47.join(os29.homedir(), ".bluma", "session_memory.json");
|
|
28946
29092
|
}
|
|
28947
29093
|
/**
|
|
28948
29094
|
* Extract memories from conversation using LLM
|
|
@@ -28999,15 +29145,15 @@ ${messages.slice(-50).map((m) => `${m.role}: ${m.content.slice(0, 500)}`).join("
|
|
|
28999
29145
|
);
|
|
29000
29146
|
unique.sort((a, b) => b.accessCount - a.accessCount);
|
|
29001
29147
|
const trimmed = unique.slice(0, 200);
|
|
29002
|
-
|
|
29148
|
+
fs42.writeFileSync(this.memoryFile, JSON.stringify(trimmed, null, 2));
|
|
29003
29149
|
}
|
|
29004
29150
|
/**
|
|
29005
29151
|
* Load memories from disk
|
|
29006
29152
|
*/
|
|
29007
29153
|
async loadMemories() {
|
|
29008
29154
|
try {
|
|
29009
|
-
if (!
|
|
29010
|
-
const data =
|
|
29155
|
+
if (!fs42.existsSync(this.memoryFile)) return [];
|
|
29156
|
+
const data = fs42.readFileSync(this.memoryFile, "utf-8");
|
|
29011
29157
|
return JSON.parse(data);
|
|
29012
29158
|
} catch {
|
|
29013
29159
|
return [];
|
|
@@ -29551,14 +29697,14 @@ var RouteManager = class {
|
|
|
29551
29697
|
this.subAgents = subAgents;
|
|
29552
29698
|
this.core = core;
|
|
29553
29699
|
}
|
|
29554
|
-
registerRoute(
|
|
29555
|
-
this.routeHandlers.set(
|
|
29700
|
+
registerRoute(path60, handler) {
|
|
29701
|
+
this.routeHandlers.set(path60, handler);
|
|
29556
29702
|
}
|
|
29557
29703
|
async handleRoute(payload) {
|
|
29558
29704
|
const inputText = String(payload.content || "").trim();
|
|
29559
29705
|
const { userContext, options } = payload;
|
|
29560
|
-
for (const [
|
|
29561
|
-
if (inputText ===
|
|
29706
|
+
for (const [path60, handler] of this.routeHandlers) {
|
|
29707
|
+
if (inputText === path60 || inputText.startsWith(`${path60} `)) {
|
|
29562
29708
|
return handler({ content: inputText, userContext });
|
|
29563
29709
|
}
|
|
29564
29710
|
}
|
|
@@ -29567,13 +29713,13 @@ var RouteManager = class {
|
|
|
29567
29713
|
};
|
|
29568
29714
|
|
|
29569
29715
|
// src/app/agent/runtime/plugin_runtime.ts
|
|
29570
|
-
import
|
|
29716
|
+
import path48 from "path";
|
|
29571
29717
|
import { pathToFileURL as pathToFileURL2 } from "url";
|
|
29572
29718
|
async function loadPluginsAtStartup() {
|
|
29573
29719
|
for (const p of listPlugins()) {
|
|
29574
29720
|
const entry = p.manifest.entry?.trim();
|
|
29575
29721
|
if (!entry) continue;
|
|
29576
|
-
const abs =
|
|
29722
|
+
const abs = path48.resolve(p.root, entry);
|
|
29577
29723
|
try {
|
|
29578
29724
|
const href = pathToFileURL2(abs).href;
|
|
29579
29725
|
const mod = await import(href);
|
|
@@ -29594,7 +29740,7 @@ async function loadPluginsAtStartup() {
|
|
|
29594
29740
|
}
|
|
29595
29741
|
|
|
29596
29742
|
// src/app/agent/agent.ts
|
|
29597
|
-
var globalEnvPath =
|
|
29743
|
+
var globalEnvPath = path49.join(os30.homedir(), ".bluma", ".env");
|
|
29598
29744
|
dotenv.config({ path: globalEnvPath });
|
|
29599
29745
|
var Agent = class {
|
|
29600
29746
|
sessionId;
|
|
@@ -31450,10 +31596,10 @@ function resolveToolPayload(result) {
|
|
|
31450
31596
|
|
|
31451
31597
|
// src/app/ui/components/FilePathLink.tsx
|
|
31452
31598
|
import { pathToFileURL as pathToFileURL3 } from "node:url";
|
|
31453
|
-
import
|
|
31599
|
+
import path51 from "node:path";
|
|
31454
31600
|
|
|
31455
31601
|
// src/app/ui/utils/pathDisplay.ts
|
|
31456
|
-
import
|
|
31602
|
+
import path50 from "node:path";
|
|
31457
31603
|
import os31 from "node:os";
|
|
31458
31604
|
function formatPathForDisplay(pathInput, cwd2 = process.cwd()) {
|
|
31459
31605
|
let s = String(pathInput ?? "").trim();
|
|
@@ -31461,17 +31607,17 @@ function formatPathForDisplay(pathInput, cwd2 = process.cwd()) {
|
|
|
31461
31607
|
s = s.replace(/[/\\]+$/, "");
|
|
31462
31608
|
}
|
|
31463
31609
|
if (!s) return "";
|
|
31464
|
-
const abs =
|
|
31465
|
-
const resolvedCwd =
|
|
31466
|
-
const rel =
|
|
31467
|
-
if (rel === "" || !rel.startsWith("..") && !
|
|
31610
|
+
const abs = path50.isAbsolute(s) ? path50.normalize(s) : path50.resolve(cwd2, s);
|
|
31611
|
+
const resolvedCwd = path50.resolve(cwd2);
|
|
31612
|
+
const rel = path50.relative(resolvedCwd, abs);
|
|
31613
|
+
if (rel === "" || !rel.startsWith("..") && !path50.isAbsolute(rel)) {
|
|
31468
31614
|
return rel === "" ? "." : rel;
|
|
31469
31615
|
}
|
|
31470
|
-
const home =
|
|
31471
|
-
if (abs === home || abs.startsWith(home +
|
|
31616
|
+
const home = path50.normalize(os31.homedir());
|
|
31617
|
+
if (abs === home || abs.startsWith(home + path50.sep)) {
|
|
31472
31618
|
return "~" + abs.slice(home.length);
|
|
31473
31619
|
}
|
|
31474
|
-
return
|
|
31620
|
+
return path50.basename(abs);
|
|
31475
31621
|
}
|
|
31476
31622
|
|
|
31477
31623
|
// src/app/ui/components/FilePathLink.tsx
|
|
@@ -31481,7 +31627,7 @@ function FilePathLink({ filePath, children, cwd: cwd2 = process.cwd(), color })
|
|
|
31481
31627
|
if (!raw) {
|
|
31482
31628
|
return null;
|
|
31483
31629
|
}
|
|
31484
|
-
const abs =
|
|
31630
|
+
const abs = path51.isAbsolute(raw) ? path51.normalize(raw) : path51.resolve(cwd2, raw);
|
|
31485
31631
|
const href = pathToFileURL3(abs).href;
|
|
31486
31632
|
const label = formatPathForDisplay(abs, cwd2);
|
|
31487
31633
|
const text = typeof children === "string" ? children : label;
|
|
@@ -32102,16 +32248,16 @@ function supportsHyperlinks(options) {
|
|
|
32102
32248
|
if (stdoutSupported) {
|
|
32103
32249
|
return true;
|
|
32104
32250
|
}
|
|
32105
|
-
const
|
|
32106
|
-
const termProgram =
|
|
32251
|
+
const env3 = options?.env ?? process.env;
|
|
32252
|
+
const termProgram = env3["TERM_PROGRAM"];
|
|
32107
32253
|
if (termProgram && ADDITIONAL_HYPERLINK_TERMINALS.includes(termProgram)) {
|
|
32108
32254
|
return true;
|
|
32109
32255
|
}
|
|
32110
|
-
const lcTerminal =
|
|
32256
|
+
const lcTerminal = env3["LC_TERMINAL"];
|
|
32111
32257
|
if (lcTerminal && ADDITIONAL_HYPERLINK_TERMINALS.includes(lcTerminal)) {
|
|
32112
32258
|
return true;
|
|
32113
32259
|
}
|
|
32114
|
-
const term =
|
|
32260
|
+
const term = env3["TERM"];
|
|
32115
32261
|
if (term?.includes("kitty")) {
|
|
32116
32262
|
return true;
|
|
32117
32263
|
}
|
|
@@ -33433,12 +33579,12 @@ function patchToUnifiedDiffText(filePath, patch) {
|
|
|
33433
33579
|
}
|
|
33434
33580
|
|
|
33435
33581
|
// src/app/ui/utils/readEditContext.ts
|
|
33436
|
-
import { promises as
|
|
33582
|
+
import { promises as fs43 } from "fs";
|
|
33437
33583
|
var CHUNK_SIZE = 64 * 1024;
|
|
33438
33584
|
var CONTEXT_LINES2 = 3;
|
|
33439
33585
|
async function openForScan(filePath) {
|
|
33440
33586
|
try {
|
|
33441
|
-
return await
|
|
33587
|
+
return await fs43.open(filePath, "r");
|
|
33442
33588
|
} catch (e) {
|
|
33443
33589
|
if (e.code === "ENOENT") return null;
|
|
33444
33590
|
throw e;
|
|
@@ -34116,13 +34262,13 @@ function EditToolDiffPanel({
|
|
|
34116
34262
|
newString,
|
|
34117
34263
|
replaceAll = false
|
|
34118
34264
|
}) {
|
|
34119
|
-
const
|
|
34265
|
+
const path60 = filePath.trim() || "unknown file";
|
|
34120
34266
|
const hasPreviewArgs = oldString !== void 0 && newString !== void 0;
|
|
34121
34267
|
const hasDiffText = diffText && diffText.trim().length > 0;
|
|
34122
34268
|
return /* @__PURE__ */ jsx43(Box_default, { flexDirection: "column", children: hasPreviewArgs ? /* @__PURE__ */ jsx43(Box_default, { marginTop: 0, children: /* @__PURE__ */ jsx43(
|
|
34123
34269
|
FileEditToolDiff,
|
|
34124
34270
|
{
|
|
34125
|
-
filePath:
|
|
34271
|
+
filePath: path60,
|
|
34126
34272
|
oldString,
|
|
34127
34273
|
newString,
|
|
34128
34274
|
replaceAll,
|
|
@@ -34160,7 +34306,7 @@ function renderToolUseMessage12({ args }) {
|
|
|
34160
34306
|
return /* @__PURE__ */ jsx44(Text, { color: BLUMA_TERMINAL.blue, children: p });
|
|
34161
34307
|
}
|
|
34162
34308
|
function renderToolHeader12({ args }) {
|
|
34163
|
-
const
|
|
34309
|
+
const path60 = args?.file_path ?? ".";
|
|
34164
34310
|
const oldText = typeof args?.old_string === "string" ? args.old_string : "";
|
|
34165
34311
|
const newText = typeof args?.new_string === "string" ? args.new_string : "";
|
|
34166
34312
|
const counts = countLineDiff(oldText, newText);
|
|
@@ -34170,7 +34316,7 @@ function renderToolHeader12({ args }) {
|
|
|
34170
34316
|
action,
|
|
34171
34317
|
/* @__PURE__ */ jsxs27(Text, { dimColor: true, children: [
|
|
34172
34318
|
" ",
|
|
34173
|
-
/* @__PURE__ */ jsx44(FilePathLink, { filePath:
|
|
34319
|
+
/* @__PURE__ */ jsx44(FilePathLink, { filePath: path60, color: BLUMA_TERMINAL.dim })
|
|
34174
34320
|
] })
|
|
34175
34321
|
] }),
|
|
34176
34322
|
/* @__PURE__ */ jsxs27(Text, { dimColor: true, children: [
|
|
@@ -34562,11 +34708,11 @@ function userFacingName13() {
|
|
|
34562
34708
|
}
|
|
34563
34709
|
function renderToolUseMessage14({ args }) {
|
|
34564
34710
|
const q = args?.query ? `"${args.query}"` : "...";
|
|
34565
|
-
const
|
|
34711
|
+
const path60 = args?.path || ".";
|
|
34566
34712
|
return /* @__PURE__ */ jsxs30(Box_default, { flexDirection: "row", flexWrap: "wrap", alignItems: "flex-end", children: [
|
|
34567
34713
|
/* @__PURE__ */ jsx47(Text, { color: BLUMA_TERMINAL.blue, children: q }),
|
|
34568
34714
|
/* @__PURE__ */ jsx47(Text, { color: BLUMA_TERMINAL.dim, children: " " }),
|
|
34569
|
-
/* @__PURE__ */ jsx47(FilePathLink, { filePath:
|
|
34715
|
+
/* @__PURE__ */ jsx47(FilePathLink, { filePath: path60, color: BLUMA_TERMINAL.dim })
|
|
34570
34716
|
] });
|
|
34571
34717
|
}
|
|
34572
34718
|
function renderToolHeader14({ args }) {
|
|
@@ -35088,7 +35234,7 @@ var loadSkillTool = createTool({
|
|
|
35088
35234
|
});
|
|
35089
35235
|
|
|
35090
35236
|
// src/app/agent/tools/FileWriteTool/UI.tsx
|
|
35091
|
-
import
|
|
35237
|
+
import fs44 from "fs";
|
|
35092
35238
|
import { diffLines as diffLines3 } from "diff";
|
|
35093
35239
|
import { jsx as jsx54, jsxs as jsxs37 } from "react/jsx-runtime";
|
|
35094
35240
|
function getFilePath(args) {
|
|
@@ -35103,7 +35249,7 @@ function getFilePath(args) {
|
|
|
35103
35249
|
function readExistingFileText(filePath) {
|
|
35104
35250
|
if (!filePath) return "";
|
|
35105
35251
|
try {
|
|
35106
|
-
return
|
|
35252
|
+
return fs44.readFileSync(filePath, "utf-8");
|
|
35107
35253
|
} catch {
|
|
35108
35254
|
return "";
|
|
35109
35255
|
}
|
|
@@ -38045,8 +38191,8 @@ import {
|
|
|
38045
38191
|
|
|
38046
38192
|
// src/app/ui/hooks/useAtCompletion.ts
|
|
38047
38193
|
import { useEffect as useEffect11, useRef as useRef4, useState as useState13 } from "react";
|
|
38048
|
-
import
|
|
38049
|
-
import
|
|
38194
|
+
import fs45 from "fs";
|
|
38195
|
+
import path52 from "path";
|
|
38050
38196
|
var MAX_RESULTS3 = 50;
|
|
38051
38197
|
var DEFAULT_RECURSIVE_DEPTH = 2;
|
|
38052
38198
|
function listPathSuggestions(baseDir, pattern) {
|
|
@@ -38054,7 +38200,7 @@ function listPathSuggestions(baseDir, pattern) {
|
|
|
38054
38200
|
const patternEndsWithSlash = raw.endsWith("/");
|
|
38055
38201
|
const relDir = raw.replace(/^\/+|\/+$/g, "");
|
|
38056
38202
|
const filterPrefix = patternEndsWithSlash ? "" : relDir.split("/").slice(-1)[0] || "";
|
|
38057
|
-
const listDir =
|
|
38203
|
+
const listDir = path52.resolve(baseDir, relDir || ".");
|
|
38058
38204
|
const results = [];
|
|
38059
38205
|
const IGNORED_DIRS = ["node_modules", ".git", ".venv", "dist", "build"];
|
|
38060
38206
|
const IGNORED_EXTS = [".pyc", ".class", ".o", ".map", ".log", ".tmp"];
|
|
@@ -38071,7 +38217,7 @@ function listPathSuggestions(baseDir, pattern) {
|
|
|
38071
38217
|
}
|
|
38072
38218
|
function pushEntry(entryPath, label, isDir) {
|
|
38073
38219
|
if (results.length >= MAX_RESULTS3) return;
|
|
38074
|
-
const clean = label.split(
|
|
38220
|
+
const clean = label.split(path52.sep).join("/").replace(/[]+/g, "");
|
|
38075
38221
|
results.push({ label: clean + (isDir ? "/" : ""), fullPath: entryPath, isDir });
|
|
38076
38222
|
}
|
|
38077
38223
|
try {
|
|
@@ -38080,11 +38226,11 @@ function listPathSuggestions(baseDir, pattern) {
|
|
|
38080
38226
|
while (queue.length && results.length < MAX_RESULTS3) {
|
|
38081
38227
|
const node = queue.shift();
|
|
38082
38228
|
try {
|
|
38083
|
-
const entries =
|
|
38229
|
+
const entries = fs45.readdirSync(node.dir, { withFileTypes: true });
|
|
38084
38230
|
for (const entry of entries) {
|
|
38085
38231
|
if (isIgnoredName(entry.name)) continue;
|
|
38086
|
-
const entryAbs =
|
|
38087
|
-
const entryRel = node.rel ?
|
|
38232
|
+
const entryAbs = path52.join(node.dir, entry.name);
|
|
38233
|
+
const entryRel = node.rel ? path52.posix.join(node.rel, entry.name) : entry.name;
|
|
38088
38234
|
if (entryRel.split("/").includes("node_modules")) continue;
|
|
38089
38235
|
if (!entry.isDirectory() && isIgnoredFile(entry.name)) continue;
|
|
38090
38236
|
pushEntry(entryAbs, entryRel, entry.isDirectory());
|
|
@@ -38097,13 +38243,13 @@ function listPathSuggestions(baseDir, pattern) {
|
|
|
38097
38243
|
}
|
|
38098
38244
|
}
|
|
38099
38245
|
} else {
|
|
38100
|
-
const entries =
|
|
38246
|
+
const entries = fs45.readdirSync(listDir, { withFileTypes: true });
|
|
38101
38247
|
for (const entry of entries) {
|
|
38102
38248
|
if (filterPrefix && !entry.name.startsWith(filterPrefix)) continue;
|
|
38103
38249
|
if (isIgnoredName(entry.name)) continue;
|
|
38104
38250
|
if (!entry.isDirectory() && isIgnoredFile(entry.name)) continue;
|
|
38105
|
-
const entryAbs =
|
|
38106
|
-
const label = relDir ?
|
|
38251
|
+
const entryAbs = path52.join(listDir, entry.name);
|
|
38252
|
+
const label = relDir ? path52.posix.join(relDir, entry.name) : entry.name;
|
|
38107
38253
|
pushEntry(entryAbs, label, entry.isDirectory());
|
|
38108
38254
|
if (results.length >= MAX_RESULTS3) break;
|
|
38109
38255
|
}
|
|
@@ -38304,9 +38450,9 @@ var SlashSubmenuInlineComponent = ({ menu }) => {
|
|
|
38304
38450
|
var SlashSubmenuInline = memo15(SlashSubmenuInlineComponent);
|
|
38305
38451
|
|
|
38306
38452
|
// src/app/ui/utils/clipboardImage.ts
|
|
38307
|
-
import
|
|
38453
|
+
import fs46 from "fs";
|
|
38308
38454
|
import os32 from "os";
|
|
38309
|
-
import
|
|
38455
|
+
import path53 from "path";
|
|
38310
38456
|
import { spawn as spawn5, execFile as execFileCb, execSync as execSync4 } from "child_process";
|
|
38311
38457
|
import { promisify as promisify2 } from "util";
|
|
38312
38458
|
|
|
@@ -38435,8 +38581,8 @@ function commandOnPath(cmd) {
|
|
|
38435
38581
|
function unixClipboardHelperDirs() {
|
|
38436
38582
|
const h = os32.homedir();
|
|
38437
38583
|
return [
|
|
38438
|
-
|
|
38439
|
-
|
|
38584
|
+
path53.join(h, ".local", "bin"),
|
|
38585
|
+
path53.join(h, "bin"),
|
|
38440
38586
|
"/usr/bin",
|
|
38441
38587
|
"/usr/local/bin",
|
|
38442
38588
|
"/bin",
|
|
@@ -38454,16 +38600,16 @@ function resolveHelperBinary(cmd) {
|
|
|
38454
38600
|
return cmd;
|
|
38455
38601
|
}
|
|
38456
38602
|
for (const dir of unixClipboardHelperDirs()) {
|
|
38457
|
-
const full =
|
|
38603
|
+
const full = path53.join(dir, cmd);
|
|
38458
38604
|
try {
|
|
38459
|
-
|
|
38605
|
+
fs46.accessSync(full, fs46.constants.X_OK);
|
|
38460
38606
|
return full;
|
|
38461
38607
|
} catch {
|
|
38462
38608
|
}
|
|
38463
38609
|
}
|
|
38464
38610
|
for (const dir of unixClipboardHelperDirs()) {
|
|
38465
|
-
const full =
|
|
38466
|
-
if (
|
|
38611
|
+
const full = path53.join(dir, cmd);
|
|
38612
|
+
if (fs46.existsSync(full)) {
|
|
38467
38613
|
return full;
|
|
38468
38614
|
}
|
|
38469
38615
|
}
|
|
@@ -38504,17 +38650,17 @@ function writeBufferIfImage(baseDir, buf) {
|
|
|
38504
38650
|
if (!ext) {
|
|
38505
38651
|
return null;
|
|
38506
38652
|
}
|
|
38507
|
-
const out =
|
|
38653
|
+
const out = path53.join(
|
|
38508
38654
|
baseDir,
|
|
38509
38655
|
`clip-${Date.now()}-${Math.random().toString(36).slice(2, 8)}${ext}`
|
|
38510
38656
|
);
|
|
38511
|
-
|
|
38657
|
+
fs46.writeFileSync(out, buf);
|
|
38512
38658
|
return out;
|
|
38513
38659
|
}
|
|
38514
38660
|
function unlinkQuiet(p) {
|
|
38515
38661
|
try {
|
|
38516
|
-
if (
|
|
38517
|
-
|
|
38662
|
+
if (fs46.existsSync(p)) {
|
|
38663
|
+
fs46.unlinkSync(p);
|
|
38518
38664
|
}
|
|
38519
38665
|
} catch {
|
|
38520
38666
|
}
|
|
@@ -38531,25 +38677,25 @@ async function tryDarwinClipboardy(baseDir) {
|
|
|
38531
38677
|
return null;
|
|
38532
38678
|
}
|
|
38533
38679
|
for (const src of tmpPaths) {
|
|
38534
|
-
if (!src || !
|
|
38680
|
+
if (!src || !fs46.existsSync(src)) {
|
|
38535
38681
|
continue;
|
|
38536
38682
|
}
|
|
38537
38683
|
let st;
|
|
38538
38684
|
try {
|
|
38539
|
-
st =
|
|
38685
|
+
st = fs46.statSync(src);
|
|
38540
38686
|
} catch {
|
|
38541
38687
|
continue;
|
|
38542
38688
|
}
|
|
38543
38689
|
if (st.size < 80 || st.size > CLIPBOARD_MAX_BYTES) {
|
|
38544
38690
|
continue;
|
|
38545
38691
|
}
|
|
38546
|
-
const ext =
|
|
38692
|
+
const ext = path53.extname(src).toLowerCase();
|
|
38547
38693
|
const safeExt = ext && /^\.(png|jpe?g|gif|webp)$/i.test(ext) ? ext : ".png";
|
|
38548
|
-
const out =
|
|
38694
|
+
const out = path53.join(
|
|
38549
38695
|
baseDir,
|
|
38550
38696
|
`clip-${Date.now()}-${Math.random().toString(36).slice(2, 8)}${safeExt}`
|
|
38551
38697
|
);
|
|
38552
|
-
|
|
38698
|
+
fs46.copyFileSync(src, out);
|
|
38553
38699
|
for (const p of tmpPaths) {
|
|
38554
38700
|
unlinkQuiet(p);
|
|
38555
38701
|
}
|
|
@@ -38563,14 +38709,14 @@ async function tryDarwinClipboardy(baseDir) {
|
|
|
38563
38709
|
return null;
|
|
38564
38710
|
}
|
|
38565
38711
|
async function tryWindowsPowerShell(outFile) {
|
|
38566
|
-
const ps = process.env.SystemRoot != null ?
|
|
38712
|
+
const ps = process.env.SystemRoot != null ? path53.join(
|
|
38567
38713
|
process.env.SystemRoot,
|
|
38568
38714
|
"System32",
|
|
38569
38715
|
"WindowsPowerShell",
|
|
38570
38716
|
"v1.0",
|
|
38571
38717
|
"powershell.exe"
|
|
38572
38718
|
) : "powershell.exe";
|
|
38573
|
-
if (!
|
|
38719
|
+
if (!fs46.existsSync(ps)) {
|
|
38574
38720
|
return false;
|
|
38575
38721
|
}
|
|
38576
38722
|
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 +38738,7 @@ async function tryWindowsPowerShell(outFile) {
|
|
|
38592
38738
|
return false;
|
|
38593
38739
|
}
|
|
38594
38740
|
try {
|
|
38595
|
-
const st =
|
|
38741
|
+
const st = fs46.statSync(outFile);
|
|
38596
38742
|
return st.size >= 80 && st.size <= CLIPBOARD_MAX_BYTES;
|
|
38597
38743
|
} catch {
|
|
38598
38744
|
return false;
|
|
@@ -38664,8 +38810,8 @@ function parseClipboardTextAsImagePath(raw) {
|
|
|
38664
38810
|
s = s.slice(1, -1);
|
|
38665
38811
|
}
|
|
38666
38812
|
s = s.trim();
|
|
38667
|
-
if (!CLIPBOARD_PATH_IMAGE_EXT.test(
|
|
38668
|
-
const abs =
|
|
38813
|
+
if (!CLIPBOARD_PATH_IMAGE_EXT.test(path53.extname(s))) return null;
|
|
38814
|
+
const abs = path53.isAbsolute(s) ? path53.normalize(s) : path53.resolve(process.cwd(), s);
|
|
38669
38815
|
return abs;
|
|
38670
38816
|
}
|
|
38671
38817
|
async function tryClipboardTextAsImageFile(baseDir) {
|
|
@@ -38679,19 +38825,19 @@ async function tryClipboardTextAsImageFile(baseDir) {
|
|
|
38679
38825
|
const abs = parseClipboardTextAsImagePath(t);
|
|
38680
38826
|
if (!abs) return null;
|
|
38681
38827
|
try {
|
|
38682
|
-
if (!
|
|
38683
|
-
const st =
|
|
38828
|
+
if (!fs46.existsSync(abs)) return null;
|
|
38829
|
+
const st = fs46.statSync(abs);
|
|
38684
38830
|
if (!st.isFile() || st.size > CLIPBOARD_MAX_BYTES || st.size < 20) return null;
|
|
38685
38831
|
} catch {
|
|
38686
38832
|
return null;
|
|
38687
38833
|
}
|
|
38688
|
-
const ext =
|
|
38689
|
-
const out =
|
|
38834
|
+
const ext = path53.extname(abs).toLowerCase();
|
|
38835
|
+
const out = path53.join(
|
|
38690
38836
|
baseDir,
|
|
38691
38837
|
`clip-${Date.now()}-${Math.random().toString(36).slice(2, 8)}${ext}`
|
|
38692
38838
|
);
|
|
38693
38839
|
try {
|
|
38694
|
-
|
|
38840
|
+
fs46.copyFileSync(abs, out);
|
|
38695
38841
|
return out;
|
|
38696
38842
|
} catch {
|
|
38697
38843
|
return null;
|
|
@@ -38701,7 +38847,7 @@ async function tryLinuxShellPipelineSave(baseDir) {
|
|
|
38701
38847
|
if (process.platform !== "linux" && process.platform !== "freebsd") {
|
|
38702
38848
|
return null;
|
|
38703
38849
|
}
|
|
38704
|
-
const outPath =
|
|
38850
|
+
const outPath = path53.join(
|
|
38705
38851
|
baseDir,
|
|
38706
38852
|
`clip-${Date.now()}-${Math.random().toString(36).slice(2, 8)}.tmp`
|
|
38707
38853
|
);
|
|
@@ -38723,11 +38869,11 @@ printf '%s' "$OUT"
|
|
|
38723
38869
|
maxBuffer: 4096
|
|
38724
38870
|
});
|
|
38725
38871
|
const written = String(stdout ?? "").trim();
|
|
38726
|
-
if (written !== outPath || !
|
|
38872
|
+
if (written !== outPath || !fs46.existsSync(outPath)) {
|
|
38727
38873
|
unlinkQuiet(outPath);
|
|
38728
38874
|
return null;
|
|
38729
38875
|
}
|
|
38730
|
-
const buf =
|
|
38876
|
+
const buf = fs46.readFileSync(outPath);
|
|
38731
38877
|
unlinkQuiet(outPath);
|
|
38732
38878
|
return writeBufferIfImage(baseDir, buf);
|
|
38733
38879
|
} catch {
|
|
@@ -38748,8 +38894,8 @@ async function tryNativeClipboardImage() {
|
|
|
38748
38894
|
}
|
|
38749
38895
|
try {
|
|
38750
38896
|
const result = readClipboardImageNative();
|
|
38751
|
-
if (
|
|
38752
|
-
const st =
|
|
38897
|
+
if (fs46.existsSync(result.path)) {
|
|
38898
|
+
const st = fs46.statSync(result.path);
|
|
38753
38899
|
if (st.size >= 80 && st.size <= CLIPBOARD_MAX_BYTES) {
|
|
38754
38900
|
return result.path;
|
|
38755
38901
|
}
|
|
@@ -38759,8 +38905,8 @@ async function tryNativeClipboardImage() {
|
|
|
38759
38905
|
return null;
|
|
38760
38906
|
}
|
|
38761
38907
|
async function readClipboardImageToTempFile() {
|
|
38762
|
-
const baseDir =
|
|
38763
|
-
|
|
38908
|
+
const baseDir = path53.join(os32.homedir(), ".cache", "bluma", "clipboard");
|
|
38909
|
+
fs46.mkdirSync(baseDir, { recursive: true });
|
|
38764
38910
|
const nativeResult = await tryNativeClipboardImage();
|
|
38765
38911
|
if (nativeResult) {
|
|
38766
38912
|
return nativeResult;
|
|
@@ -38778,7 +38924,7 @@ async function readClipboardImageToTempFile() {
|
|
|
38778
38924
|
}
|
|
38779
38925
|
}
|
|
38780
38926
|
if (process.platform === "win32") {
|
|
38781
|
-
const outFile =
|
|
38927
|
+
const outFile = path53.join(
|
|
38782
38928
|
baseDir,
|
|
38783
38929
|
`clip-${Date.now()}-${Math.random().toString(36).slice(2, 8)}.png`
|
|
38784
38930
|
);
|
|
@@ -38819,7 +38965,7 @@ function expandLargePastePlaceholder(value, pending) {
|
|
|
38819
38965
|
}
|
|
38820
38966
|
|
|
38821
38967
|
// src/app/ui/components/InputPrompt.tsx
|
|
38822
|
-
import
|
|
38968
|
+
import fs47 from "fs";
|
|
38823
38969
|
import { Fragment as Fragment7, jsx as jsx79, jsxs as jsxs62 } from "react/jsx-runtime";
|
|
38824
38970
|
var persistedInputState = { text: "", cursorPosition: 0 };
|
|
38825
38971
|
var StaticCursor = () => /* @__PURE__ */ jsx79(Box_default, { flexDirection: "row", flexWrap: "nowrap", children: /* @__PURE__ */ jsx79(Text, { bold: true, color: BLUMA_TERMINAL.m3OnSurface, children: "\u2588 " }) });
|
|
@@ -38986,7 +39132,7 @@ var InputPrompt = memo16(({
|
|
|
38986
39132
|
return;
|
|
38987
39133
|
}
|
|
38988
39134
|
if (routeText.startsWith("/")) {
|
|
38989
|
-
const isFilePath = map.size > 0 &&
|
|
39135
|
+
const isFilePath = map.size > 0 && fs47.existsSync(routeText.split(/\s+/)[0]);
|
|
38990
39136
|
if (isFilePath) {
|
|
38991
39137
|
uiEventBus.emit("user_overlay", {
|
|
38992
39138
|
kind: "message",
|
|
@@ -41154,8 +41300,8 @@ var renderSettingsEditUsage = () => {
|
|
|
41154
41300
|
|
|
41155
41301
|
// src/app/agent/core/thread/thread_store.ts
|
|
41156
41302
|
init_bluma_app_dir();
|
|
41157
|
-
import
|
|
41158
|
-
import { promises as
|
|
41303
|
+
import path54 from "path";
|
|
41304
|
+
import { promises as fs48 } from "fs";
|
|
41159
41305
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
41160
41306
|
var INDEX_VERSION = 1;
|
|
41161
41307
|
var fileLocks2 = /* @__PURE__ */ new Map();
|
|
@@ -41180,9 +41326,9 @@ var ThreadStore = class {
|
|
|
41180
41326
|
packageVersion;
|
|
41181
41327
|
constructor() {
|
|
41182
41328
|
const appDir = getPreferredAppDir();
|
|
41183
|
-
this.threadsDir =
|
|
41184
|
-
this.archiveDir =
|
|
41185
|
-
this.indexPath =
|
|
41329
|
+
this.threadsDir = path54.join(appDir, "threads");
|
|
41330
|
+
this.archiveDir = path54.join(this.threadsDir, "archive");
|
|
41331
|
+
this.indexPath = path54.join(this.threadsDir, "index.json");
|
|
41186
41332
|
this.packageVersion = process.env.npm_package_version || "0.0.0";
|
|
41187
41333
|
}
|
|
41188
41334
|
// ==================== Inicialização ====================
|
|
@@ -41190,10 +41336,10 @@ var ThreadStore = class {
|
|
|
41190
41336
|
* Inicializa o diretório de threads
|
|
41191
41337
|
*/
|
|
41192
41338
|
async initialize() {
|
|
41193
|
-
await
|
|
41194
|
-
await
|
|
41339
|
+
await fs48.mkdir(this.threadsDir, { recursive: true });
|
|
41340
|
+
await fs48.mkdir(this.archiveDir, { recursive: true });
|
|
41195
41341
|
try {
|
|
41196
|
-
await
|
|
41342
|
+
await fs48.access(this.indexPath);
|
|
41197
41343
|
} catch {
|
|
41198
41344
|
await this.saveIndex({ version: INDEX_VERSION, threads: [], lastUpdated: (/* @__PURE__ */ new Date()).toISOString() });
|
|
41199
41345
|
}
|
|
@@ -41222,7 +41368,7 @@ var ThreadStore = class {
|
|
|
41222
41368
|
async loadIndex() {
|
|
41223
41369
|
return withFileLock2(this.indexPath, async () => {
|
|
41224
41370
|
try {
|
|
41225
|
-
const content = await
|
|
41371
|
+
const content = await fs48.readFile(this.indexPath, "utf-8");
|
|
41226
41372
|
return JSON.parse(content);
|
|
41227
41373
|
} catch {
|
|
41228
41374
|
return { version: INDEX_VERSION, threads: [], lastUpdated: (/* @__PURE__ */ new Date()).toISOString() };
|
|
@@ -41233,8 +41379,8 @@ var ThreadStore = class {
|
|
|
41233
41379
|
return withFileLock2(this.indexPath, async () => {
|
|
41234
41380
|
index.lastUpdated = (/* @__PURE__ */ new Date()).toISOString();
|
|
41235
41381
|
const tempPath = `${this.indexPath}.${Date.now()}.tmp`;
|
|
41236
|
-
await
|
|
41237
|
-
await
|
|
41382
|
+
await fs48.writeFile(tempPath, JSON.stringify(index, null, 2), "utf-8");
|
|
41383
|
+
await fs48.rename(tempPath, this.indexPath);
|
|
41238
41384
|
});
|
|
41239
41385
|
}
|
|
41240
41386
|
// ==================== Git Info ====================
|
|
@@ -41304,7 +41450,7 @@ var ThreadStore = class {
|
|
|
41304
41450
|
messages: params.initialMessages || []
|
|
41305
41451
|
};
|
|
41306
41452
|
const historyPath = this.buildDatedThreadHistoryPath(threadId);
|
|
41307
|
-
await
|
|
41453
|
+
await fs48.mkdir(path54.dirname(historyPath), { recursive: true });
|
|
41308
41454
|
await this.saveHistoryAtPath(historyPath, history);
|
|
41309
41455
|
const index = await this.loadIndex();
|
|
41310
41456
|
index.threads.unshift({
|
|
@@ -41359,7 +41505,7 @@ var ThreadStore = class {
|
|
|
41359
41505
|
compressedSliceCount: source.history.compressedSliceCount
|
|
41360
41506
|
};
|
|
41361
41507
|
const historyPath = this.buildDatedThreadHistoryPath(newThreadId);
|
|
41362
|
-
await
|
|
41508
|
+
await fs48.mkdir(path54.dirname(historyPath), { recursive: true });
|
|
41363
41509
|
await this.saveHistoryAtPath(historyPath, history);
|
|
41364
41510
|
const index = await this.loadIndex();
|
|
41365
41511
|
index.threads.unshift({
|
|
@@ -41432,9 +41578,9 @@ var ThreadStore = class {
|
|
|
41432
41578
|
const entry = index.threads[entryIndex];
|
|
41433
41579
|
if (entry.status === "archived") return true;
|
|
41434
41580
|
const oldPath = entry.historyPath || this.getLegacyHistoryPath(threadId);
|
|
41435
|
-
const newPath =
|
|
41581
|
+
const newPath = path54.join(this.archiveDir, `${threadId}.jsonl`);
|
|
41436
41582
|
try {
|
|
41437
|
-
await
|
|
41583
|
+
await fs48.rename(oldPath, newPath);
|
|
41438
41584
|
} catch (e) {
|
|
41439
41585
|
if (e.code !== "ENOENT") throw e;
|
|
41440
41586
|
}
|
|
@@ -41455,11 +41601,11 @@ var ThreadStore = class {
|
|
|
41455
41601
|
if (entryIndex === -1) return false;
|
|
41456
41602
|
const entry = index.threads[entryIndex];
|
|
41457
41603
|
if (entry.status === "active") return true;
|
|
41458
|
-
const oldPath =
|
|
41604
|
+
const oldPath = path54.join(this.archiveDir, `${threadId}.jsonl`);
|
|
41459
41605
|
const newPath = this.buildDatedThreadHistoryPath(threadId);
|
|
41460
|
-
await
|
|
41606
|
+
await fs48.mkdir(path54.dirname(newPath), { recursive: true });
|
|
41461
41607
|
try {
|
|
41462
|
-
await
|
|
41608
|
+
await fs48.rename(oldPath, newPath);
|
|
41463
41609
|
} catch (e) {
|
|
41464
41610
|
if (e.code !== "ENOENT") throw e;
|
|
41465
41611
|
}
|
|
@@ -41480,7 +41626,7 @@ var ThreadStore = class {
|
|
|
41480
41626
|
if (entryIndex === -1) return false;
|
|
41481
41627
|
const entry = index.threads[entryIndex];
|
|
41482
41628
|
try {
|
|
41483
|
-
await
|
|
41629
|
+
await fs48.unlink(entry.historyPath);
|
|
41484
41630
|
} catch {
|
|
41485
41631
|
}
|
|
41486
41632
|
index.threads.splice(entryIndex, 1);
|
|
@@ -41490,28 +41636,28 @@ var ThreadStore = class {
|
|
|
41490
41636
|
}
|
|
41491
41637
|
// ==================== Histórico ====================
|
|
41492
41638
|
getLegacyHistoryPath(threadId) {
|
|
41493
|
-
return
|
|
41639
|
+
return path54.join(this.threadsDir, `${threadId}.jsonl`);
|
|
41494
41640
|
}
|
|
41495
41641
|
/** ~/.bluma/threads/YYYY/MM/DD/<threadId>.jsonl (data local de criação). */
|
|
41496
41642
|
buildDatedThreadHistoryPath(threadId, at = /* @__PURE__ */ new Date()) {
|
|
41497
41643
|
const y = String(at.getFullYear());
|
|
41498
41644
|
const mo = String(at.getMonth() + 1).padStart(2, "0");
|
|
41499
41645
|
const d = String(at.getDate()).padStart(2, "0");
|
|
41500
|
-
return
|
|
41646
|
+
return path54.join(this.threadsDir, y, mo, d, `${threadId}.jsonl`);
|
|
41501
41647
|
}
|
|
41502
41648
|
async resolveHistoryPath(threadId) {
|
|
41503
41649
|
const index = await this.loadIndex();
|
|
41504
41650
|
const entry = index.threads.find((t) => t.threadId === threadId);
|
|
41505
41651
|
if (entry?.historyPath) {
|
|
41506
41652
|
try {
|
|
41507
|
-
await
|
|
41653
|
+
await fs48.access(entry.historyPath);
|
|
41508
41654
|
return entry.historyPath;
|
|
41509
41655
|
} catch {
|
|
41510
41656
|
}
|
|
41511
41657
|
}
|
|
41512
41658
|
const legacy = this.getLegacyHistoryPath(threadId);
|
|
41513
41659
|
try {
|
|
41514
|
-
await
|
|
41660
|
+
await fs48.access(legacy);
|
|
41515
41661
|
return legacy;
|
|
41516
41662
|
} catch {
|
|
41517
41663
|
return entry?.historyPath ?? legacy;
|
|
@@ -41528,9 +41674,9 @@ var ThreadStore = class {
|
|
|
41528
41674
|
for (const msg of history.messages) {
|
|
41529
41675
|
lines.push(JSON.stringify({ type: "message", ...msg }));
|
|
41530
41676
|
}
|
|
41531
|
-
await
|
|
41677
|
+
await fs48.mkdir(path54.dirname(historyPath), { recursive: true }).catch(() => {
|
|
41532
41678
|
});
|
|
41533
|
-
await
|
|
41679
|
+
await fs48.writeFile(historyPath, lines.join("\n") + "\n", "utf-8");
|
|
41534
41680
|
}
|
|
41535
41681
|
/**
|
|
41536
41682
|
* Guarda o histórico de uma thread
|
|
@@ -41552,7 +41698,7 @@ var ThreadStore = class {
|
|
|
41552
41698
|
].filter((p, i, arr) => Boolean(p) && arr.indexOf(p) === i);
|
|
41553
41699
|
for (const historyPath of pathsToTry) {
|
|
41554
41700
|
try {
|
|
41555
|
-
const content = await
|
|
41701
|
+
const content = await fs48.readFile(historyPath, "utf-8");
|
|
41556
41702
|
const lines = content.split("\n").filter(Boolean);
|
|
41557
41703
|
const history = {
|
|
41558
41704
|
threadId,
|
|
@@ -41587,7 +41733,7 @@ var ThreadStore = class {
|
|
|
41587
41733
|
const entry = index.threads.find((t) => t.threadId === threadId);
|
|
41588
41734
|
if (!entry) throw new Error(`Thread not found: ${threadId}`);
|
|
41589
41735
|
const lines = messages.map((msg) => JSON.stringify({ type: "message", ...msg }));
|
|
41590
|
-
await
|
|
41736
|
+
await fs48.appendFile(entry.historyPath, lines.join("\n") + "\n", "utf-8");
|
|
41591
41737
|
entry.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
41592
41738
|
await this.saveIndex(index);
|
|
41593
41739
|
}
|
|
@@ -44024,16 +44170,16 @@ import latestVersion from "latest-version";
|
|
|
44024
44170
|
import semverGt from "semver/functions/gt.js";
|
|
44025
44171
|
import semverValid from "semver/functions/valid.js";
|
|
44026
44172
|
import { fileURLToPath as fileURLToPath7 } from "url";
|
|
44027
|
-
import
|
|
44028
|
-
import
|
|
44173
|
+
import path56 from "path";
|
|
44174
|
+
import fs50 from "fs";
|
|
44029
44175
|
var BLUMA_PACKAGE_NAME = "@nomad-e/bluma-cli";
|
|
44030
44176
|
function findBlumaPackageJson(startDir) {
|
|
44031
44177
|
let dir = startDir;
|
|
44032
44178
|
for (let i = 0; i < 12; i++) {
|
|
44033
|
-
const candidate =
|
|
44034
|
-
if (
|
|
44179
|
+
const candidate = path56.join(dir, "package.json");
|
|
44180
|
+
if (fs50.existsSync(candidate)) {
|
|
44035
44181
|
try {
|
|
44036
|
-
const raw =
|
|
44182
|
+
const raw = fs50.readFileSync(candidate, "utf8");
|
|
44037
44183
|
const parsed = JSON.parse(raw);
|
|
44038
44184
|
if (parsed?.name === BLUMA_PACKAGE_NAME && parsed?.version) {
|
|
44039
44185
|
return { name: parsed.name, version: String(parsed.version) };
|
|
@@ -44041,7 +44187,7 @@ function findBlumaPackageJson(startDir) {
|
|
|
44041
44187
|
} catch {
|
|
44042
44188
|
}
|
|
44043
44189
|
}
|
|
44044
|
-
const parent =
|
|
44190
|
+
const parent = path56.dirname(dir);
|
|
44045
44191
|
if (parent === dir) break;
|
|
44046
44192
|
dir = parent;
|
|
44047
44193
|
}
|
|
@@ -44050,13 +44196,13 @@ function findBlumaPackageJson(startDir) {
|
|
|
44050
44196
|
function resolveInstalledBlumaPackage() {
|
|
44051
44197
|
const tried = /* @__PURE__ */ new Set();
|
|
44052
44198
|
const tryFrom = (dir) => {
|
|
44053
|
-
const abs =
|
|
44199
|
+
const abs = path56.resolve(dir);
|
|
44054
44200
|
if (tried.has(abs)) return null;
|
|
44055
44201
|
tried.add(abs);
|
|
44056
44202
|
return findBlumaPackageJson(abs);
|
|
44057
44203
|
};
|
|
44058
44204
|
try {
|
|
44059
|
-
const fromBundle = tryFrom(
|
|
44205
|
+
const fromBundle = tryFrom(path56.dirname(fileURLToPath7(import.meta.url)));
|
|
44060
44206
|
if (fromBundle) return fromBundle;
|
|
44061
44207
|
} catch {
|
|
44062
44208
|
}
|
|
@@ -44064,12 +44210,12 @@ function resolveInstalledBlumaPackage() {
|
|
|
44064
44210
|
if (argv1 && !argv1.startsWith("-")) {
|
|
44065
44211
|
try {
|
|
44066
44212
|
let resolved = argv1;
|
|
44067
|
-
if (
|
|
44068
|
-
resolved =
|
|
44213
|
+
if (path56.isAbsolute(argv1) && fs50.existsSync(argv1)) {
|
|
44214
|
+
resolved = fs50.realpathSync(argv1);
|
|
44069
44215
|
} else {
|
|
44070
|
-
resolved =
|
|
44216
|
+
resolved = path56.resolve(process.cwd(), argv1);
|
|
44071
44217
|
}
|
|
44072
|
-
const fromArgv = tryFrom(
|
|
44218
|
+
const fromArgv = tryFrom(path56.dirname(resolved));
|
|
44073
44219
|
if (fromArgv) return fromArgv;
|
|
44074
44220
|
} catch {
|
|
44075
44221
|
}
|
|
@@ -44888,16 +45034,16 @@ function usePlanMode() {
|
|
|
44888
45034
|
|
|
44889
45035
|
// src/app/hooks/useAgentMode.ts
|
|
44890
45036
|
import { useState as useState22, useEffect as useEffect21, useCallback as useCallback9 } from "react";
|
|
44891
|
-
import * as
|
|
44892
|
-
import * as
|
|
45037
|
+
import * as fs51 from "fs";
|
|
45038
|
+
import * as path57 from "path";
|
|
44893
45039
|
import { homedir as homedir4 } from "os";
|
|
44894
|
-
var SETTINGS_PATH =
|
|
45040
|
+
var SETTINGS_PATH = path57.join(homedir4(), ".bluma", "settings.json");
|
|
44895
45041
|
function readAgentModeFromFile() {
|
|
44896
45042
|
try {
|
|
44897
|
-
if (!
|
|
45043
|
+
if (!fs51.existsSync(SETTINGS_PATH)) {
|
|
44898
45044
|
return "default";
|
|
44899
45045
|
}
|
|
44900
|
-
const content =
|
|
45046
|
+
const content = fs51.readFileSync(SETTINGS_PATH, "utf-8");
|
|
44901
45047
|
const settings = JSON.parse(content);
|
|
44902
45048
|
return settings.agentMode || "default";
|
|
44903
45049
|
} catch (error) {
|
|
@@ -44916,16 +45062,16 @@ function useAgentMode() {
|
|
|
44916
45062
|
}, []);
|
|
44917
45063
|
const updateAgentMode = useCallback9((mode) => {
|
|
44918
45064
|
try {
|
|
44919
|
-
if (!
|
|
44920
|
-
|
|
45065
|
+
if (!fs51.existsSync(SETTINGS_PATH)) {
|
|
45066
|
+
fs51.mkdirSync(path57.dirname(SETTINGS_PATH), { recursive: true });
|
|
44921
45067
|
}
|
|
44922
45068
|
let settings = {};
|
|
44923
|
-
if (
|
|
44924
|
-
const content =
|
|
45069
|
+
if (fs51.existsSync(SETTINGS_PATH)) {
|
|
45070
|
+
const content = fs51.readFileSync(SETTINGS_PATH, "utf-8");
|
|
44925
45071
|
settings = JSON.parse(content);
|
|
44926
45072
|
}
|
|
44927
45073
|
settings.agentMode = mode;
|
|
44928
|
-
|
|
45074
|
+
fs51.writeFileSync(SETTINGS_PATH, JSON.stringify(settings, null, 2), "utf-8");
|
|
44929
45075
|
setAgentMode(mode);
|
|
44930
45076
|
} catch (error) {
|
|
44931
45077
|
console.error("Failed to update agent mode:", error);
|
|
@@ -46189,10 +46335,10 @@ import { memo as memo26, useCallback as useCallback11, useEffect as useEffect23,
|
|
|
46189
46335
|
|
|
46190
46336
|
// src/app/agent/session_manager/session_resume_browser.ts
|
|
46191
46337
|
init_bluma_app_dir();
|
|
46192
|
-
import
|
|
46193
|
-
import { promises as
|
|
46338
|
+
import path58 from "path";
|
|
46339
|
+
import { promises as fs52 } from "fs";
|
|
46194
46340
|
function getSessionsRoot() {
|
|
46195
|
-
return
|
|
46341
|
+
return path58.join(getPreferredAppDir(), "sessions");
|
|
46196
46342
|
}
|
|
46197
46343
|
function normalizeSessionsCwd(cwd2) {
|
|
46198
46344
|
return cwd2.replace(/\\/g, "/").split("/").filter((p) => p && p !== "." && p !== "..").join("/");
|
|
@@ -46213,9 +46359,9 @@ async function sessionEntryFromFile(absPath, sessionId) {
|
|
|
46213
46359
|
let preview = "(no messages)";
|
|
46214
46360
|
let lastActivityMs = Date.now();
|
|
46215
46361
|
try {
|
|
46216
|
-
const st = await
|
|
46362
|
+
const st = await fs52.stat(absPath);
|
|
46217
46363
|
lastActivityMs = st.mtimeMs;
|
|
46218
|
-
const raw = await
|
|
46364
|
+
const raw = await fs52.readFile(absPath, "utf-8");
|
|
46219
46365
|
const data = JSON.parse(raw);
|
|
46220
46366
|
preview = previewFromHistory(data.conversation_history);
|
|
46221
46367
|
const iso = data.last_updated || data.created_at;
|
|
@@ -46243,15 +46389,15 @@ function compareDirNames(a, b) {
|
|
|
46243
46389
|
async function listSessionBrowserEntries(cwdRel) {
|
|
46244
46390
|
const cwd2 = normalizeSessionsCwd(cwdRel);
|
|
46245
46391
|
const root = getSessionsRoot();
|
|
46246
|
-
const absDir = cwd2 ?
|
|
46392
|
+
const absDir = cwd2 ? path58.join(root, ...cwd2.split("/")) : root;
|
|
46247
46393
|
const out = [];
|
|
46248
46394
|
if (cwd2) {
|
|
46249
46395
|
out.push({ kind: "up", label: ".." });
|
|
46250
46396
|
}
|
|
46251
46397
|
let dirents;
|
|
46252
46398
|
try {
|
|
46253
|
-
await
|
|
46254
|
-
dirents = await
|
|
46399
|
+
await fs52.mkdir(absDir, { recursive: true });
|
|
46400
|
+
dirents = await fs52.readdir(absDir, { withFileTypes: true });
|
|
46255
46401
|
} catch {
|
|
46256
46402
|
return out;
|
|
46257
46403
|
}
|
|
@@ -46260,7 +46406,7 @@ async function listSessionBrowserEntries(cwdRel) {
|
|
|
46260
46406
|
for (const e of dirents) {
|
|
46261
46407
|
const name = String(e.name);
|
|
46262
46408
|
if (name.startsWith(".")) continue;
|
|
46263
|
-
const full =
|
|
46409
|
+
const full = path58.join(absDir, name);
|
|
46264
46410
|
if (e.isDirectory()) {
|
|
46265
46411
|
dirNames.push(name);
|
|
46266
46412
|
} else if (e.isFile() && name.endsWith(".json") && !name.includes(".tmp")) {
|
|
@@ -46270,7 +46416,7 @@ async function listSessionBrowserEntries(cwdRel) {
|
|
|
46270
46416
|
dirNames.sort(compareDirNames);
|
|
46271
46417
|
const sessions = [];
|
|
46272
46418
|
for (const { name, full } of sessionFiles) {
|
|
46273
|
-
const sessionId =
|
|
46419
|
+
const sessionId = path58.basename(name, ".json");
|
|
46274
46420
|
sessions.push(await sessionEntryFromFile(full, sessionId));
|
|
46275
46421
|
}
|
|
46276
46422
|
sessions.sort((a, b) => {
|
|
@@ -46635,9 +46781,9 @@ async function runAgentMode() {
|
|
|
46635
46781
|
try {
|
|
46636
46782
|
if (inputFileIndex !== -1 && args[inputFileIndex + 1]) {
|
|
46637
46783
|
const filePath = args[inputFileIndex + 1];
|
|
46638
|
-
rawPayload =
|
|
46784
|
+
rawPayload = fs53.readFileSync(filePath, "utf-8");
|
|
46639
46785
|
} else {
|
|
46640
|
-
rawPayload =
|
|
46786
|
+
rawPayload = fs53.readFileSync(0, "utf-8");
|
|
46641
46787
|
}
|
|
46642
46788
|
} catch (err) {
|
|
46643
46789
|
writeAgentEvent(registrySessionId, {
|
|
@@ -46689,6 +46835,12 @@ async function runAgentMode() {
|
|
|
46689
46835
|
if (envelopeUserRequest.trim()) {
|
|
46690
46836
|
process.env.BLUMA_USER_REQUEST = envelopeUserRequest.trim();
|
|
46691
46837
|
}
|
|
46838
|
+
if (envelope.from_agent?.trim()) {
|
|
46839
|
+
process.env.BLUMA_FROM_AGENT = envelope.from_agent.trim();
|
|
46840
|
+
}
|
|
46841
|
+
if (envelope.action?.trim()) {
|
|
46842
|
+
process.env.BLUMA_ACTION = envelope.action.trim();
|
|
46843
|
+
}
|
|
46692
46844
|
const eventBus = new EventEmitter7();
|
|
46693
46845
|
const sessionId = registrySessionId || envelope.session_id || envelope.message_id || uuidv412();
|
|
46694
46846
|
process.env.BLUMA_SESSION_ID = sessionId;
|
|
@@ -46878,9 +47030,9 @@ async function runAgentMode() {
|
|
|
46878
47030
|
}
|
|
46879
47031
|
function readCliPackageVersion() {
|
|
46880
47032
|
try {
|
|
46881
|
-
const base =
|
|
46882
|
-
const pkgPath =
|
|
46883
|
-
const j = JSON.parse(
|
|
47033
|
+
const base = path59.dirname(fileURLToPath8(import.meta.url));
|
|
47034
|
+
const pkgPath = path59.join(base, "..", "package.json");
|
|
47035
|
+
const j = JSON.parse(fs53.readFileSync(pkgPath, "utf8"));
|
|
46884
47036
|
return String(j.version || "0.0.0");
|
|
46885
47037
|
} catch {
|
|
46886
47038
|
return "0.0.0";
|
|
@@ -47006,7 +47158,7 @@ function startBackgroundAgent() {
|
|
|
47006
47158
|
process.exit(1);
|
|
47007
47159
|
}
|
|
47008
47160
|
const filePath = args[inputFileIndex + 1];
|
|
47009
|
-
const rawPayload =
|
|
47161
|
+
const rawPayload = fs53.readFileSync(filePath, "utf-8");
|
|
47010
47162
|
const envelope = JSON.parse(rawPayload);
|
|
47011
47163
|
const sessionId = envelope.session_id || envelope.message_id || uuidv412();
|
|
47012
47164
|
registerSession({
|