@nomad-e/bluma-cli 0.1.71 → 0.1.72
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 +783 -253
- package/package.json +1 -1
package/dist/main.js
CHANGED
|
@@ -1737,8 +1737,8 @@ var init_themes = __esm({
|
|
|
1737
1737
|
import React19 from "react";
|
|
1738
1738
|
import { render } from "ink";
|
|
1739
1739
|
import { EventEmitter as EventEmitter4 } from "events";
|
|
1740
|
-
import
|
|
1741
|
-
import
|
|
1740
|
+
import fs39 from "fs";
|
|
1741
|
+
import path44 from "path";
|
|
1742
1742
|
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
1743
1743
|
import { spawn as spawn6 } from "child_process";
|
|
1744
1744
|
import { v4 as uuidv412 } from "uuid";
|
|
@@ -4438,12 +4438,12 @@ function EditToolDiffPanel({
|
|
|
4438
4438
|
maxHeight = EDIT_DIFF_PREVIEW_MAX_LINES,
|
|
4439
4439
|
fallbackSnippet
|
|
4440
4440
|
}) {
|
|
4441
|
-
const
|
|
4441
|
+
const path45 = filePath.trim() || "unknown file";
|
|
4442
4442
|
const diff = diffText?.trim() ?? "";
|
|
4443
4443
|
return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", children: [
|
|
4444
4444
|
/* @__PURE__ */ jsx5(Box5, { flexDirection: "row", flexWrap: "wrap", children: /* @__PURE__ */ jsxs5(Text5, { color: isNewFile ? BLUMA_TERMINAL.success : void 0, children: [
|
|
4445
4445
|
isNewFile ? "Created " : "Wrote to ",
|
|
4446
|
-
/* @__PURE__ */ jsx5(Text5, { bold: true, children:
|
|
4446
|
+
/* @__PURE__ */ jsx5(Text5, { bold: true, children: path45 })
|
|
4447
4447
|
] }) }),
|
|
4448
4448
|
description ? /* @__PURE__ */ jsx5(Text5, { dimColor: true, wrap: "wrap", children: description }) : null,
|
|
4449
4449
|
diff.length > 0 ? /* @__PURE__ */ jsx5(Box5, { marginTop: 0, children: /* @__PURE__ */ jsx5(SimpleDiff, { text: diff, maxHeight, frame: true }) }) : fallbackSnippet ? /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", marginTop: 0, children: [
|
|
@@ -4772,7 +4772,7 @@ var renderFindByName = ({ args }) => {
|
|
|
4772
4772
|
var renderGrepSearch = ({ args }) => {
|
|
4773
4773
|
const parsed = parseArgs(args);
|
|
4774
4774
|
const query = parsed.query || "";
|
|
4775
|
-
const
|
|
4775
|
+
const path45 = parsed.path || ".";
|
|
4776
4776
|
return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "row", flexWrap: "wrap", children: [
|
|
4777
4777
|
/* @__PURE__ */ jsxs8(Text8, { color: BLUMA_TERMINAL.muted, children: [
|
|
4778
4778
|
'"',
|
|
@@ -4781,7 +4781,7 @@ var renderGrepSearch = ({ args }) => {
|
|
|
4781
4781
|
] }),
|
|
4782
4782
|
/* @__PURE__ */ jsxs8(Text8, { color: BLUMA_TERMINAL.m3OnSurface, bold: true, children: [
|
|
4783
4783
|
" ",
|
|
4784
|
-
|
|
4784
|
+
path45
|
|
4785
4785
|
] })
|
|
4786
4786
|
] });
|
|
4787
4787
|
};
|
|
@@ -5207,12 +5207,12 @@ var ConfirmationPrompt = memo4(ConfirmationPromptComponent);
|
|
|
5207
5207
|
|
|
5208
5208
|
// src/app/agent/agent.ts
|
|
5209
5209
|
import * as dotenv from "dotenv";
|
|
5210
|
-
import
|
|
5210
|
+
import path42 from "path";
|
|
5211
5211
|
import os28 from "os";
|
|
5212
5212
|
|
|
5213
5213
|
// src/app/agent/tool_invoker.ts
|
|
5214
|
-
import { promises as
|
|
5215
|
-
import
|
|
5214
|
+
import { promises as fs26 } from "fs";
|
|
5215
|
+
import path28 from "path";
|
|
5216
5216
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
5217
5217
|
|
|
5218
5218
|
// src/app/agent/tools/natives/edit.ts
|
|
@@ -10308,19 +10308,86 @@ async function uploadToSeverino(zipPath, severinoUrl, name, apiKey, appId) {
|
|
|
10308
10308
|
}
|
|
10309
10309
|
const data = response.data || {};
|
|
10310
10310
|
const resolvedAppId = appId || data.appId;
|
|
10311
|
+
const appContext = data.appContext ? {
|
|
10312
|
+
appId: String(data.appContext.appId || resolvedAppId || "").trim(),
|
|
10313
|
+
tenantId: data.appContext.tenantId ?? null,
|
|
10314
|
+
projectId: data.appContext.projectId ?? null,
|
|
10315
|
+
workspaceId: data.appContext.workspaceId ?? null,
|
|
10316
|
+
revisionId: data.appContext.revisionId ?? null,
|
|
10317
|
+
deploymentId: data.appContext.deploymentId ?? null,
|
|
10318
|
+
buildJobId: data.appContext.buildJobId ?? null,
|
|
10319
|
+
manifestPath: data.appContext.manifestPath ?? "factorai.sh.json",
|
|
10320
|
+
manifestFile: data.appContext.manifestFile ?? "factorai.sh.json",
|
|
10321
|
+
appUrl: data.appContext.appUrl ?? `${severinoUrl.replace(/\/$/, "")}/app/${resolvedAppId}`
|
|
10322
|
+
} : {
|
|
10323
|
+
appId: String(resolvedAppId || "").trim(),
|
|
10324
|
+
tenantId: data.tenantId ?? null,
|
|
10325
|
+
projectId: data.projectId ?? null,
|
|
10326
|
+
workspaceId: data.workspaceId ?? null,
|
|
10327
|
+
revisionId: data.revisionId ?? null,
|
|
10328
|
+
deploymentId: data.deploymentId ?? null,
|
|
10329
|
+
buildJobId: data.buildJobId ?? null,
|
|
10330
|
+
manifestPath: "factorai.sh.json",
|
|
10331
|
+
manifestFile: "factorai.sh.json",
|
|
10332
|
+
appUrl: `${severinoUrl.replace(/\/$/, "")}/app/${resolvedAppId}`
|
|
10333
|
+
};
|
|
10311
10334
|
return {
|
|
10312
10335
|
success: true,
|
|
10313
10336
|
appId: resolvedAppId,
|
|
10314
10337
|
name: data.name,
|
|
10315
10338
|
status: data.status || "building",
|
|
10316
|
-
url: severinoUrl.replace(/\/$/, "") + `/app/${resolvedAppId}`,
|
|
10339
|
+
url: appContext.appUrl || severinoUrl.replace(/\/$/, "") + `/app/${resolvedAppId}`,
|
|
10317
10340
|
message: data.message || "Deploy iniciado",
|
|
10318
|
-
isRedeploy: !!appId
|
|
10341
|
+
isRedeploy: !!appId,
|
|
10342
|
+
appContext
|
|
10319
10343
|
};
|
|
10320
10344
|
} catch (parseError) {
|
|
10321
10345
|
throw new Error(`Failed to parse response: ${parseError.message}`);
|
|
10322
10346
|
}
|
|
10323
10347
|
}
|
|
10348
|
+
function buildFactorAiManifest(appContext, deployResult, appName) {
|
|
10349
|
+
return {
|
|
10350
|
+
version: 1,
|
|
10351
|
+
manifestFile: "factorai.sh.json",
|
|
10352
|
+
manifestPath: "factorai.sh.json",
|
|
10353
|
+
appContext: {
|
|
10354
|
+
appId: appContext.appId,
|
|
10355
|
+
tenantId: appContext.tenantId ?? null,
|
|
10356
|
+
projectId: appContext.projectId ?? null,
|
|
10357
|
+
workspaceId: appContext.workspaceId ?? null,
|
|
10358
|
+
revisionId: appContext.revisionId ?? null,
|
|
10359
|
+
deploymentId: appContext.deploymentId ?? null,
|
|
10360
|
+
buildJobId: appContext.buildJobId ?? null,
|
|
10361
|
+
manifestPath: "factorai.sh.json",
|
|
10362
|
+
manifestFile: "factorai.sh.json",
|
|
10363
|
+
appUrl: appContext.appUrl ?? deployResult.url ?? null
|
|
10364
|
+
},
|
|
10365
|
+
app: {
|
|
10366
|
+
name: appName,
|
|
10367
|
+
status: deployResult.status || "building",
|
|
10368
|
+
isRedeploy: deployResult.isRedeploy ?? false,
|
|
10369
|
+
url: deployResult.url || null,
|
|
10370
|
+
message: deployResult.message || null
|
|
10371
|
+
},
|
|
10372
|
+
agent: {
|
|
10373
|
+
provider: "bluma",
|
|
10374
|
+
mode: "tool-first",
|
|
10375
|
+
instructions: [
|
|
10376
|
+
"Read factorai.sh.json as the source of truth before editing files.",
|
|
10377
|
+
"Prefer incremental changes and preserve the existing deployment context.",
|
|
10378
|
+
"After edits, use the redeploy tool instead of rebuilding from scratch."
|
|
10379
|
+
]
|
|
10380
|
+
},
|
|
10381
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
10382
|
+
};
|
|
10383
|
+
}
|
|
10384
|
+
async function writeFactorAiManifest(projectDir, appContext, deployResult, appName) {
|
|
10385
|
+
const manifest = buildFactorAiManifest(appContext, deployResult, appName);
|
|
10386
|
+
const manifestPath = path26.join(projectDir, "factorai.sh.json");
|
|
10387
|
+
await fs24.writeFile(manifestPath, `${JSON.stringify(manifest, null, 2)}
|
|
10388
|
+
`, "utf-8");
|
|
10389
|
+
return manifest;
|
|
10390
|
+
}
|
|
10324
10391
|
async function deployApp(args) {
|
|
10325
10392
|
const envSeverinoUrl = process.env.SEVERINO_URL || "http://localhost:3000";
|
|
10326
10393
|
const envApiKey = process.env.SEVERINO_API_KEY || void 0;
|
|
@@ -10390,6 +10457,16 @@ async function deployApp(args) {
|
|
|
10390
10457
|
console.warn("[deploy-app] Cleanup warning:", e);
|
|
10391
10458
|
}
|
|
10392
10459
|
if (deployResult.success) {
|
|
10460
|
+
if (deployResult.appContext) {
|
|
10461
|
+
const manifest = await writeFactorAiManifest(
|
|
10462
|
+
resolvedProjectDir,
|
|
10463
|
+
deployResult.appContext,
|
|
10464
|
+
deployResult,
|
|
10465
|
+
appName
|
|
10466
|
+
);
|
|
10467
|
+
deployResult.factoraiManifest = manifest;
|
|
10468
|
+
deployResult.factoraiManifestPath = path26.join(resolvedProjectDir, "factorai.sh.json");
|
|
10469
|
+
}
|
|
10393
10470
|
console.log(`[deploy-app] Deploy iniciado: ${deployResult.appId}`);
|
|
10394
10471
|
}
|
|
10395
10472
|
return deployResult;
|
|
@@ -10402,8 +10479,389 @@ async function deployApp(args) {
|
|
|
10402
10479
|
}
|
|
10403
10480
|
}
|
|
10404
10481
|
|
|
10482
|
+
// src/app/agent/runtime/factorai_context.ts
|
|
10483
|
+
import fs25 from "fs";
|
|
10484
|
+
import path27 from "path";
|
|
10485
|
+
function normalizeContext(raw) {
|
|
10486
|
+
if (!raw || typeof raw.appId !== "string" || !raw.appId.trim()) {
|
|
10487
|
+
return null;
|
|
10488
|
+
}
|
|
10489
|
+
const appId = raw.appId.trim();
|
|
10490
|
+
return {
|
|
10491
|
+
appId,
|
|
10492
|
+
tenantId: typeof raw.tenantId === "string" ? raw.tenantId : null,
|
|
10493
|
+
projectId: typeof raw.projectId === "string" ? raw.projectId : null,
|
|
10494
|
+
workspaceId: typeof raw.workspaceId === "string" ? raw.workspaceId : null,
|
|
10495
|
+
revisionId: typeof raw.revisionId === "string" ? raw.revisionId : null,
|
|
10496
|
+
deploymentId: typeof raw.deploymentId === "string" ? raw.deploymentId : null,
|
|
10497
|
+
buildJobId: typeof raw.buildJobId === "string" ? raw.buildJobId : null,
|
|
10498
|
+
manifestPath: typeof raw.manifestPath === "string" ? raw.manifestPath : null,
|
|
10499
|
+
manifestFile: typeof raw.manifestFile === "string" ? raw.manifestFile : null,
|
|
10500
|
+
appUrl: typeof raw.appUrl === "string" ? raw.appUrl : null
|
|
10501
|
+
};
|
|
10502
|
+
}
|
|
10503
|
+
function readJsonFile(filePath) {
|
|
10504
|
+
try {
|
|
10505
|
+
if (!fs25.existsSync(filePath)) {
|
|
10506
|
+
return null;
|
|
10507
|
+
}
|
|
10508
|
+
const parsed = JSON.parse(fs25.readFileSync(filePath, "utf8"));
|
|
10509
|
+
if (parsed && typeof parsed === "object") {
|
|
10510
|
+
return parsed.appContext && typeof parsed.appContext === "object" ? parsed.appContext : parsed;
|
|
10511
|
+
}
|
|
10512
|
+
} catch {
|
|
10513
|
+
return null;
|
|
10514
|
+
}
|
|
10515
|
+
return null;
|
|
10516
|
+
}
|
|
10517
|
+
function readFactorAiWorkspaceManifest(projectDir = process.cwd()) {
|
|
10518
|
+
const manifestPath = path27.join(projectDir, "factorai.sh.json");
|
|
10519
|
+
try {
|
|
10520
|
+
if (!fs25.existsSync(manifestPath)) {
|
|
10521
|
+
return null;
|
|
10522
|
+
}
|
|
10523
|
+
const parsed = JSON.parse(fs25.readFileSync(manifestPath, "utf8"));
|
|
10524
|
+
return parsed && typeof parsed === "object" ? parsed : null;
|
|
10525
|
+
} catch {
|
|
10526
|
+
return null;
|
|
10527
|
+
}
|
|
10528
|
+
}
|
|
10529
|
+
function readContextFromWorkspace() {
|
|
10530
|
+
const candidate = path27.join(process.cwd(), "factorai.sh.json");
|
|
10531
|
+
const parsed = readJsonFile(candidate);
|
|
10532
|
+
if (!parsed) {
|
|
10533
|
+
return null;
|
|
10534
|
+
}
|
|
10535
|
+
const context = normalizeContext(parsed);
|
|
10536
|
+
return context;
|
|
10537
|
+
}
|
|
10538
|
+
function loadFactorAiAppContext() {
|
|
10539
|
+
return readContextFromWorkspace();
|
|
10540
|
+
}
|
|
10541
|
+
function formatFactorAiAppContextSummary(context) {
|
|
10542
|
+
if (!context) {
|
|
10543
|
+
return "";
|
|
10544
|
+
}
|
|
10545
|
+
const parts = [
|
|
10546
|
+
`appId=${context.appId}`,
|
|
10547
|
+
context.tenantId ? `tenantId=${context.tenantId}` : null,
|
|
10548
|
+
context.projectId ? `projectId=${context.projectId}` : null,
|
|
10549
|
+
context.workspaceId ? `workspaceId=${context.workspaceId}` : null,
|
|
10550
|
+
context.revisionId ? `revisionId=${context.revisionId}` : null,
|
|
10551
|
+
context.deploymentId ? `deploymentId=${context.deploymentId}` : null,
|
|
10552
|
+
context.buildJobId ? `buildJobId=${context.buildJobId}` : null,
|
|
10553
|
+
context.appUrl ? `appUrl=${context.appUrl}` : null
|
|
10554
|
+
].filter(Boolean);
|
|
10555
|
+
return parts.join(" | ");
|
|
10556
|
+
}
|
|
10557
|
+
function buildFactorAiWorkspaceManifest(input) {
|
|
10558
|
+
const projectDir = input.projectDir || process.cwd();
|
|
10559
|
+
const existing = readFactorAiWorkspaceManifest(projectDir) || {};
|
|
10560
|
+
const now2 = (/* @__PURE__ */ new Date()).toISOString();
|
|
10561
|
+
const nextAppContext = {
|
|
10562
|
+
...typeof existing.appContext === "object" && existing.appContext ? existing.appContext : {},
|
|
10563
|
+
appId: input.appContext.appId,
|
|
10564
|
+
tenantId: input.appContext.tenantId ?? null,
|
|
10565
|
+
projectId: input.appContext.projectId ?? null,
|
|
10566
|
+
workspaceId: input.appContext.workspaceId ?? null,
|
|
10567
|
+
revisionId: input.appContext.revisionId ?? null,
|
|
10568
|
+
deploymentId: input.appContext.deploymentId ?? null,
|
|
10569
|
+
buildJobId: input.appContext.buildJobId ?? null,
|
|
10570
|
+
manifestPath: "factorai.sh.json",
|
|
10571
|
+
manifestFile: "factorai.sh.json",
|
|
10572
|
+
appUrl: input.appContext.appUrl ?? null
|
|
10573
|
+
};
|
|
10574
|
+
return {
|
|
10575
|
+
...existing,
|
|
10576
|
+
version: 1,
|
|
10577
|
+
manifestFile: "factorai.sh.json",
|
|
10578
|
+
manifestPath: "factorai.sh.json",
|
|
10579
|
+
appContext: nextAppContext,
|
|
10580
|
+
app: {
|
|
10581
|
+
...typeof existing.app === "object" && existing.app ? existing.app : {},
|
|
10582
|
+
name: input.name ?? (typeof existing.app === "object" && existing.app ? existing.app.name : void 0) ?? null,
|
|
10583
|
+
status: input.status ?? (typeof existing.app === "object" && existing.app ? existing.app.status : void 0) ?? "building",
|
|
10584
|
+
isRedeploy: input.isRedeploy ?? (typeof existing.app === "object" && existing.app ? existing.app.isRedeploy : false),
|
|
10585
|
+
message: input.message ?? (typeof existing.app === "object" && existing.app ? existing.app.message : null),
|
|
10586
|
+
...input.app || {}
|
|
10587
|
+
},
|
|
10588
|
+
agent: {
|
|
10589
|
+
provider: "bluma",
|
|
10590
|
+
mode: "tool-first",
|
|
10591
|
+
instructions: [
|
|
10592
|
+
"Read factorai.sh.json as the source of truth before editing files.",
|
|
10593
|
+
"Prefer incremental changes and preserve the existing deployment context.",
|
|
10594
|
+
"After edits, use the redeploy tool instead of rebuilding from scratch."
|
|
10595
|
+
],
|
|
10596
|
+
...typeof existing.agent === "object" && existing.agent ? existing.agent : {},
|
|
10597
|
+
...input.agent || {}
|
|
10598
|
+
},
|
|
10599
|
+
sandbox: {
|
|
10600
|
+
...typeof existing.sandbox === "object" && existing.sandbox ? existing.sandbox : {},
|
|
10601
|
+
...input.sandbox || {}
|
|
10602
|
+
},
|
|
10603
|
+
source: {
|
|
10604
|
+
root: ".",
|
|
10605
|
+
publicDir: "./public",
|
|
10606
|
+
appDir: ".",
|
|
10607
|
+
...typeof existing.source === "object" && existing.source ? existing.source : {},
|
|
10608
|
+
...input.source || {}
|
|
10609
|
+
},
|
|
10610
|
+
updatedAt: now2,
|
|
10611
|
+
...input.extra || {}
|
|
10612
|
+
};
|
|
10613
|
+
}
|
|
10614
|
+
async function writeFactorAiWorkspaceManifest(input) {
|
|
10615
|
+
const projectDir = input.projectDir || process.cwd();
|
|
10616
|
+
const manifest = buildFactorAiWorkspaceManifest({ ...input, projectDir });
|
|
10617
|
+
const manifestPath = path27.join(projectDir, "factorai.sh.json");
|
|
10618
|
+
fs25.writeFileSync(manifestPath, `${JSON.stringify(manifest, null, 2)}
|
|
10619
|
+
`, "utf8");
|
|
10620
|
+
return { manifestPath, manifest };
|
|
10621
|
+
}
|
|
10622
|
+
|
|
10405
10623
|
// src/app/agent/runtime/native_tool_catalog.ts
|
|
10406
10624
|
init_sandbox_policy();
|
|
10625
|
+
function getFactorAiBaseUrl() {
|
|
10626
|
+
const value = process.env.FACTORAI_BASE_URL || process.env.FACTORAI_URL || "";
|
|
10627
|
+
const trimmed = value.trim();
|
|
10628
|
+
return trimmed || void 0;
|
|
10629
|
+
}
|
|
10630
|
+
function getFactorAiApiKey() {
|
|
10631
|
+
const value = process.env.FACTORAI_API_KEY || process.env.FACTORAI_TOKEN || "";
|
|
10632
|
+
const trimmed = value.trim();
|
|
10633
|
+
return trimmed || void 0;
|
|
10634
|
+
}
|
|
10635
|
+
function isFactorAiSandboxEnabled() {
|
|
10636
|
+
const policy = getSandboxPolicy();
|
|
10637
|
+
return policy.isSandbox && Boolean(getFactorAiBaseUrl());
|
|
10638
|
+
}
|
|
10639
|
+
async function requestFactorAi(pathname, init = {}) {
|
|
10640
|
+
const baseUrl = getFactorAiBaseUrl();
|
|
10641
|
+
if (!baseUrl) {
|
|
10642
|
+
throw new Error("FACTORAI_BASE_URL is not configured.");
|
|
10643
|
+
}
|
|
10644
|
+
const headers = new Headers(init.headers || {});
|
|
10645
|
+
headers.set("Content-Type", "application/json");
|
|
10646
|
+
const apiKey = getFactorAiApiKey();
|
|
10647
|
+
if (apiKey) {
|
|
10648
|
+
headers.set("Authorization", `Bearer ${apiKey}`);
|
|
10649
|
+
}
|
|
10650
|
+
const response = await fetch(new URL(pathname, baseUrl), {
|
|
10651
|
+
...init,
|
|
10652
|
+
headers
|
|
10653
|
+
});
|
|
10654
|
+
const text = await response.text();
|
|
10655
|
+
let payload = null;
|
|
10656
|
+
if (text) {
|
|
10657
|
+
try {
|
|
10658
|
+
payload = JSON.parse(text);
|
|
10659
|
+
} catch {
|
|
10660
|
+
payload = text;
|
|
10661
|
+
}
|
|
10662
|
+
}
|
|
10663
|
+
if (!response.ok) {
|
|
10664
|
+
const message2 = payload?.error?.message || payload?.message || payload?.error || `FactorAI request failed with status ${response.status}`;
|
|
10665
|
+
throw new Error(message2);
|
|
10666
|
+
}
|
|
10667
|
+
return payload;
|
|
10668
|
+
}
|
|
10669
|
+
async function factorAiGetAppStatus(args) {
|
|
10670
|
+
const appId = String(args?.appId || "").trim();
|
|
10671
|
+
if (!appId) {
|
|
10672
|
+
return { error: "appId is required." };
|
|
10673
|
+
}
|
|
10674
|
+
return requestFactorAi(`/api/v1/apps/${encodeURIComponent(appId)}`);
|
|
10675
|
+
}
|
|
10676
|
+
async function factorAiApplyAppChanges(args) {
|
|
10677
|
+
const appId = String(args?.appId || "").trim();
|
|
10678
|
+
if (!appId) {
|
|
10679
|
+
return { error: "appId is required." };
|
|
10680
|
+
}
|
|
10681
|
+
const files = Array.isArray(args?.files) ? args.files : Array.isArray(args?.changes) ? args.changes : [];
|
|
10682
|
+
if (files.length === 0) {
|
|
10683
|
+
return { error: "files or changes must be a non-empty array." };
|
|
10684
|
+
}
|
|
10685
|
+
const response = await requestFactorAi(`/api/v1/apps/${encodeURIComponent(appId)}/changes`, {
|
|
10686
|
+
method: "POST",
|
|
10687
|
+
body: JSON.stringify({
|
|
10688
|
+
files,
|
|
10689
|
+
deploy: args?.deploy !== false
|
|
10690
|
+
})
|
|
10691
|
+
});
|
|
10692
|
+
await persistFactorAiWorkspaceManifestFromResponse(response);
|
|
10693
|
+
return response;
|
|
10694
|
+
}
|
|
10695
|
+
async function factorAiRedeployApp(args) {
|
|
10696
|
+
const appId = String(args?.appId || "").trim();
|
|
10697
|
+
if (!appId) {
|
|
10698
|
+
return { error: "appId is required." };
|
|
10699
|
+
}
|
|
10700
|
+
const response = await requestFactorAi(`/api/v1/apps/${encodeURIComponent(appId)}/redeploy`, {
|
|
10701
|
+
method: "POST"
|
|
10702
|
+
});
|
|
10703
|
+
await persistFactorAiWorkspaceManifestFromResponse(response);
|
|
10704
|
+
return response;
|
|
10705
|
+
}
|
|
10706
|
+
function extractFactorAiResponseData(response) {
|
|
10707
|
+
if (response && typeof response === "object" && response.data && typeof response.data === "object") {
|
|
10708
|
+
return response.data;
|
|
10709
|
+
}
|
|
10710
|
+
return response;
|
|
10711
|
+
}
|
|
10712
|
+
async function persistFactorAiWorkspaceManifestFromResponse(response) {
|
|
10713
|
+
const data = extractFactorAiResponseData(response);
|
|
10714
|
+
const appContext = data?.appContext;
|
|
10715
|
+
if (!appContext || typeof appContext.appId !== "string" || !appContext.appId.trim()) {
|
|
10716
|
+
return;
|
|
10717
|
+
}
|
|
10718
|
+
await writeFactorAiWorkspaceManifest({
|
|
10719
|
+
projectDir: process.cwd(),
|
|
10720
|
+
appContext: {
|
|
10721
|
+
appId: String(appContext.appId).trim(),
|
|
10722
|
+
tenantId: appContext.tenantId ?? null,
|
|
10723
|
+
projectId: appContext.projectId ?? null,
|
|
10724
|
+
workspaceId: appContext.workspaceId ?? null,
|
|
10725
|
+
revisionId: appContext.revisionId ?? null,
|
|
10726
|
+
deploymentId: appContext.deploymentId ?? null,
|
|
10727
|
+
buildJobId: appContext.buildJobId ?? null,
|
|
10728
|
+
manifestPath: appContext.manifestPath ?? appContext.manifestFile ?? "factorai.sh.json",
|
|
10729
|
+
manifestFile: appContext.manifestFile ?? appContext.manifestPath ?? "factorai.sh.json",
|
|
10730
|
+
appUrl: appContext.appUrl ?? data?.url ?? null
|
|
10731
|
+
},
|
|
10732
|
+
name: data?.name ?? data?.app?.name ?? void 0,
|
|
10733
|
+
status: data?.status ?? "building",
|
|
10734
|
+
isRedeploy: Boolean(data?.isRedeploy),
|
|
10735
|
+
message: typeof data?.message === "string" ? data.message : null,
|
|
10736
|
+
app: {
|
|
10737
|
+
...typeof data?.app === "object" && data.app ? data.app : {},
|
|
10738
|
+
url: data?.url ?? data?.app?.url ?? null
|
|
10739
|
+
},
|
|
10740
|
+
agent: typeof data?.agent === "object" && data.agent ? data.agent : void 0,
|
|
10741
|
+
sandbox: typeof data?.sandbox === "object" && data.sandbox ? data.sandbox : void 0,
|
|
10742
|
+
source: typeof data?.source === "object" && data.source ? data.source : void 0,
|
|
10743
|
+
extra: {
|
|
10744
|
+
lastUpdatedFromTool: "factorai.sh.apply_app_changes"
|
|
10745
|
+
}
|
|
10746
|
+
});
|
|
10747
|
+
}
|
|
10748
|
+
function getFactorAiSandboxToolDefinitions() {
|
|
10749
|
+
if (!isFactorAiSandboxEnabled()) {
|
|
10750
|
+
return [];
|
|
10751
|
+
}
|
|
10752
|
+
return [
|
|
10753
|
+
{
|
|
10754
|
+
type: "function",
|
|
10755
|
+
function: {
|
|
10756
|
+
name: "factorai.sh.create_next_app",
|
|
10757
|
+
description: "Create a new Next.js project in the sandbox workspace for FactorAI deployments.",
|
|
10758
|
+
parameters: {
|
|
10759
|
+
type: "object",
|
|
10760
|
+
properties: {
|
|
10761
|
+
name: { type: "string", description: "Project name." },
|
|
10762
|
+
template: { type: "string", enum: ["minimal", "full"], description: "Project template." },
|
|
10763
|
+
directory: { type: "string", description: "Target directory for the project." }
|
|
10764
|
+
},
|
|
10765
|
+
required: ["name"],
|
|
10766
|
+
additionalProperties: false
|
|
10767
|
+
}
|
|
10768
|
+
}
|
|
10769
|
+
},
|
|
10770
|
+
{
|
|
10771
|
+
type: "function",
|
|
10772
|
+
function: {
|
|
10773
|
+
name: "factorai.sh.deploy_app",
|
|
10774
|
+
description: "Deploy a Next.js project from the sandbox to the FactorAI hosting backend. The returned metadata must be written into factorai.sh.json in the project root for future incremental edits.",
|
|
10775
|
+
parameters: {
|
|
10776
|
+
type: "object",
|
|
10777
|
+
properties: {
|
|
10778
|
+
projectDir: { type: "string", description: "Path to the Next.js project." },
|
|
10779
|
+
name: { type: "string", description: "App name." },
|
|
10780
|
+
severinoUrl: { type: "string", description: "Optional explicit backend URL." },
|
|
10781
|
+
apiKey: { type: "string", description: "Optional explicit API key." }
|
|
10782
|
+
},
|
|
10783
|
+
required: ["projectDir"],
|
|
10784
|
+
additionalProperties: false
|
|
10785
|
+
}
|
|
10786
|
+
}
|
|
10787
|
+
},
|
|
10788
|
+
{
|
|
10789
|
+
type: "function",
|
|
10790
|
+
function: {
|
|
10791
|
+
name: "factorai.sh.get_app_status",
|
|
10792
|
+
description: "Get the current status and contract for a FactorAI deployment in the sandbox.",
|
|
10793
|
+
parameters: {
|
|
10794
|
+
type: "object",
|
|
10795
|
+
properties: {
|
|
10796
|
+
appId: { type: "string", description: "FactorAI app identifier." }
|
|
10797
|
+
},
|
|
10798
|
+
required: ["appId"],
|
|
10799
|
+
additionalProperties: false
|
|
10800
|
+
}
|
|
10801
|
+
}
|
|
10802
|
+
},
|
|
10803
|
+
{
|
|
10804
|
+
type: "function",
|
|
10805
|
+
function: {
|
|
10806
|
+
name: "factorai.sh.apply_app_changes",
|
|
10807
|
+
description: "Apply incremental file changes to a FactorAI workspace and optionally redeploy.",
|
|
10808
|
+
parameters: {
|
|
10809
|
+
type: "object",
|
|
10810
|
+
properties: {
|
|
10811
|
+
appId: { type: "string", description: "FactorAI app identifier." },
|
|
10812
|
+
files: {
|
|
10813
|
+
type: "array",
|
|
10814
|
+
description: "List of changed files to apply.",
|
|
10815
|
+
items: {
|
|
10816
|
+
type: "object",
|
|
10817
|
+
properties: {
|
|
10818
|
+
path: { type: "string" },
|
|
10819
|
+
content: { type: "string" }
|
|
10820
|
+
},
|
|
10821
|
+
required: ["path", "content"],
|
|
10822
|
+
additionalProperties: false
|
|
10823
|
+
}
|
|
10824
|
+
},
|
|
10825
|
+
changes: {
|
|
10826
|
+
type: "array",
|
|
10827
|
+
description: "Alias for files.",
|
|
10828
|
+
items: {
|
|
10829
|
+
type: "object",
|
|
10830
|
+
properties: {
|
|
10831
|
+
path: { type: "string" },
|
|
10832
|
+
content: { type: "string" }
|
|
10833
|
+
},
|
|
10834
|
+
required: ["path", "content"],
|
|
10835
|
+
additionalProperties: false
|
|
10836
|
+
}
|
|
10837
|
+
},
|
|
10838
|
+
deploy: {
|
|
10839
|
+
type: "boolean",
|
|
10840
|
+
description: "Redeploy after applying changes. Defaults to true."
|
|
10841
|
+
}
|
|
10842
|
+
},
|
|
10843
|
+
required: ["appId"],
|
|
10844
|
+
additionalProperties: false
|
|
10845
|
+
}
|
|
10846
|
+
}
|
|
10847
|
+
},
|
|
10848
|
+
{
|
|
10849
|
+
type: "function",
|
|
10850
|
+
function: {
|
|
10851
|
+
name: "factorai.sh.redeploy_app",
|
|
10852
|
+
description: "Redeploy the current revision of a FactorAI app.",
|
|
10853
|
+
parameters: {
|
|
10854
|
+
type: "object",
|
|
10855
|
+
properties: {
|
|
10856
|
+
appId: { type: "string", description: "FactorAI app identifier." }
|
|
10857
|
+
},
|
|
10858
|
+
required: ["appId"],
|
|
10859
|
+
additionalProperties: false
|
|
10860
|
+
}
|
|
10861
|
+
}
|
|
10862
|
+
}
|
|
10863
|
+
];
|
|
10864
|
+
}
|
|
10407
10865
|
var NATIVE_TOOL_ENTRIES = [
|
|
10408
10866
|
{
|
|
10409
10867
|
metadata: {
|
|
@@ -10970,25 +11428,63 @@ var NATIVE_TOOL_ENTRIES = [
|
|
|
10970
11428
|
},
|
|
10971
11429
|
{
|
|
10972
11430
|
metadata: {
|
|
10973
|
-
name: "create_next_app",
|
|
11431
|
+
name: "factorai.sh.create_next_app",
|
|
10974
11432
|
category: "filesystem",
|
|
10975
11433
|
riskLevel: "write",
|
|
10976
11434
|
autoApproveInLocal: false,
|
|
10977
11435
|
autoApproveInSandbox: true,
|
|
11436
|
+
sandboxOnly: true,
|
|
10978
11437
|
description: "Create a new Next.js project instantly with App Router, shadcn/ui components, Tailwind CSS, and TypeScript. Templates: minimal (basic structure) or full (with pre-built UI components)."
|
|
10979
11438
|
},
|
|
10980
11439
|
implementation: createNextApp
|
|
10981
11440
|
},
|
|
10982
11441
|
{
|
|
10983
11442
|
metadata: {
|
|
10984
|
-
name: "deploy_app",
|
|
11443
|
+
name: "factorai.sh.deploy_app",
|
|
10985
11444
|
category: "execution",
|
|
10986
11445
|
riskLevel: "network",
|
|
10987
11446
|
autoApproveInLocal: false,
|
|
10988
11447
|
autoApproveInSandbox: true,
|
|
11448
|
+
sandboxOnly: true,
|
|
10989
11449
|
description: "Deploy a Next.js project to Severino. Zips the project (excluding node_modules, .next) and uploads to /api/v1/deploy. Returns appId and live URL."
|
|
10990
11450
|
},
|
|
10991
11451
|
implementation: deployApp
|
|
11452
|
+
},
|
|
11453
|
+
{
|
|
11454
|
+
metadata: {
|
|
11455
|
+
name: "factorai.sh.get_app_status",
|
|
11456
|
+
category: "knowledge",
|
|
11457
|
+
riskLevel: "network",
|
|
11458
|
+
autoApproveInLocal: false,
|
|
11459
|
+
autoApproveInSandbox: true,
|
|
11460
|
+
sandboxOnly: true,
|
|
11461
|
+
description: "Sandbox-only FactorAI tool. Fetch app status and sandbox contract from the deployed backend."
|
|
11462
|
+
},
|
|
11463
|
+
implementation: factorAiGetAppStatus
|
|
11464
|
+
},
|
|
11465
|
+
{
|
|
11466
|
+
metadata: {
|
|
11467
|
+
name: "factorai.sh.apply_app_changes",
|
|
11468
|
+
category: "filesystem",
|
|
11469
|
+
riskLevel: "write",
|
|
11470
|
+
autoApproveInLocal: false,
|
|
11471
|
+
autoApproveInSandbox: true,
|
|
11472
|
+
sandboxOnly: true,
|
|
11473
|
+
description: "Sandbox-only FactorAI tool. Apply file changes to a deployed app workspace and redeploy it."
|
|
11474
|
+
},
|
|
11475
|
+
implementation: factorAiApplyAppChanges
|
|
11476
|
+
},
|
|
11477
|
+
{
|
|
11478
|
+
metadata: {
|
|
11479
|
+
name: "factorai.sh.redeploy_app",
|
|
11480
|
+
category: "execution",
|
|
11481
|
+
riskLevel: "network",
|
|
11482
|
+
autoApproveInLocal: false,
|
|
11483
|
+
autoApproveInSandbox: true,
|
|
11484
|
+
sandboxOnly: true,
|
|
11485
|
+
description: "Sandbox-only FactorAI tool. Trigger redeploy for the current app revision."
|
|
11486
|
+
},
|
|
11487
|
+
implementation: factorAiRedeployApp
|
|
10992
11488
|
}
|
|
10993
11489
|
];
|
|
10994
11490
|
var TOOL_METADATA_MAP = new Map(
|
|
@@ -11004,11 +11500,10 @@ function getNativeToolImplementation(toolName) {
|
|
|
11004
11500
|
return TOOL_IMPLEMENTATION_MAP.get(toolName);
|
|
11005
11501
|
}
|
|
11006
11502
|
function getAllNativeToolMetadata() {
|
|
11007
|
-
|
|
11008
|
-
|
|
11009
|
-
|
|
11010
|
-
|
|
11011
|
-
return NATIVE_TOOL_ENTRIES.map((entry) => entry.metadata);
|
|
11503
|
+
return NATIVE_TOOL_ENTRIES.filter((entry) => !entry.metadata.sandboxOnly || isFactorAiSandboxEnabled()).map((entry) => entry.metadata);
|
|
11504
|
+
}
|
|
11505
|
+
function getSandboxOnlyNativeToolDefinitions() {
|
|
11506
|
+
return getFactorAiSandboxToolDefinitions();
|
|
11012
11507
|
}
|
|
11013
11508
|
function applyMetadataToToolDefinitions(toolDefinitions) {
|
|
11014
11509
|
return toolDefinitions.map((definition) => {
|
|
@@ -11032,12 +11527,14 @@ var ToolInvoker = class {
|
|
|
11032
11527
|
*/
|
|
11033
11528
|
async initialize() {
|
|
11034
11529
|
try {
|
|
11035
|
-
const
|
|
11036
|
-
const
|
|
11037
|
-
const configPath =
|
|
11038
|
-
const fileContent = await
|
|
11530
|
+
const currentFilePath = fileURLToPath2(import.meta.url);
|
|
11531
|
+
const currentDirPath = path28.dirname(currentFilePath);
|
|
11532
|
+
const configPath = path28.resolve(currentDirPath, "config", "native_tools.json");
|
|
11533
|
+
const fileContent = await fs26.readFile(configPath, "utf-8");
|
|
11039
11534
|
const config2 = JSON.parse(fileContent);
|
|
11040
11535
|
this.toolDefinitions = applyMetadataToToolDefinitions(config2.nativeTools);
|
|
11536
|
+
const sandboxOnlyTools = applyMetadataToToolDefinitions(getSandboxOnlyNativeToolDefinitions());
|
|
11537
|
+
this.toolDefinitions.push(...sandboxOnlyTools);
|
|
11041
11538
|
} catch (error) {
|
|
11042
11539
|
console.error("[ToolInvoker] Erro cr\xEDtico ao carregar 'native_tools.json'. As ferramentas nativas n\xE3o estar\xE3o dispon\xEDveis.", error);
|
|
11043
11540
|
this.toolDefinitions = [];
|
|
@@ -11077,8 +11574,8 @@ var ToolInvoker = class {
|
|
|
11077
11574
|
};
|
|
11078
11575
|
|
|
11079
11576
|
// src/app/agent/tools/mcp/mcp_client.ts
|
|
11080
|
-
import { promises as
|
|
11081
|
-
import
|
|
11577
|
+
import { promises as fs27 } from "fs";
|
|
11578
|
+
import path29 from "path";
|
|
11082
11579
|
import os16 from "os";
|
|
11083
11580
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
11084
11581
|
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
@@ -11106,9 +11603,9 @@ var MCPClient = class {
|
|
|
11106
11603
|
});
|
|
11107
11604
|
}
|
|
11108
11605
|
const __filename = fileURLToPath3(import.meta.url);
|
|
11109
|
-
const __dirname =
|
|
11110
|
-
const defaultConfigPath =
|
|
11111
|
-
const userConfigPath =
|
|
11606
|
+
const __dirname = path29.dirname(__filename);
|
|
11607
|
+
const defaultConfigPath = path29.resolve(__dirname, "config", "bluma-mcp.json");
|
|
11608
|
+
const userConfigPath = path29.join(os16.homedir(), ".bluma", "bluma-mcp.json");
|
|
11112
11609
|
const defaultConfig = await this.loadMcpConfig(defaultConfigPath, "Default");
|
|
11113
11610
|
const userConfig = await this.loadMcpConfig(userConfigPath, "User");
|
|
11114
11611
|
const mergedConfig = {
|
|
@@ -11142,7 +11639,7 @@ var MCPClient = class {
|
|
|
11142
11639
|
}
|
|
11143
11640
|
async loadMcpConfig(configPath, configType) {
|
|
11144
11641
|
try {
|
|
11145
|
-
const fileContent = await
|
|
11642
|
+
const fileContent = await fs27.readFile(configPath, "utf-8");
|
|
11146
11643
|
const processedContent = this.replaceEnvPlaceholders(fileContent);
|
|
11147
11644
|
return JSON.parse(processedContent);
|
|
11148
11645
|
} catch (error) {
|
|
@@ -11319,13 +11816,13 @@ PENALTY APPLIED: ${penalty.toFixed(1)} points deducted.
|
|
|
11319
11816
|
};
|
|
11320
11817
|
|
|
11321
11818
|
// src/app/agent/bluma/core/bluma.ts
|
|
11322
|
-
import
|
|
11819
|
+
import path39 from "path";
|
|
11323
11820
|
import { v4 as uuidv48 } from "uuid";
|
|
11324
11821
|
|
|
11325
11822
|
// src/app/agent/session_manager/session_manager.ts
|
|
11326
|
-
import
|
|
11823
|
+
import path30 from "path";
|
|
11327
11824
|
import os17 from "os";
|
|
11328
|
-
import { promises as
|
|
11825
|
+
import { promises as fs28 } from "fs";
|
|
11329
11826
|
var fileLocks = /* @__PURE__ */ new Map();
|
|
11330
11827
|
async function withFileLock(file, fn) {
|
|
11331
11828
|
const prev = fileLocks.get(file) || Promise.resolve();
|
|
@@ -11361,13 +11858,13 @@ function debouncedSave(sessionFile, history, memory) {
|
|
|
11361
11858
|
function expandHome(p) {
|
|
11362
11859
|
if (!p) return p;
|
|
11363
11860
|
if (p.startsWith("~")) {
|
|
11364
|
-
return
|
|
11861
|
+
return path30.join(os17.homedir(), p.slice(1));
|
|
11365
11862
|
}
|
|
11366
11863
|
return p;
|
|
11367
11864
|
}
|
|
11368
11865
|
function getPreferredAppDir() {
|
|
11369
|
-
const fixed =
|
|
11370
|
-
return
|
|
11866
|
+
const fixed = path30.join(os17.homedir(), ".bluma");
|
|
11867
|
+
return path30.resolve(expandHome(fixed));
|
|
11371
11868
|
}
|
|
11372
11869
|
async function safeRenameWithRetry(src, dest, maxRetries = 6) {
|
|
11373
11870
|
let attempt = 0;
|
|
@@ -11375,10 +11872,10 @@ async function safeRenameWithRetry(src, dest, maxRetries = 6) {
|
|
|
11375
11872
|
const isWin = process.platform === "win32";
|
|
11376
11873
|
while (attempt <= maxRetries) {
|
|
11377
11874
|
try {
|
|
11378
|
-
const dir =
|
|
11379
|
-
await
|
|
11875
|
+
const dir = path30.dirname(dest);
|
|
11876
|
+
await fs28.mkdir(dir, { recursive: true }).catch(() => {
|
|
11380
11877
|
});
|
|
11381
|
-
await
|
|
11878
|
+
await fs28.rename(src, dest);
|
|
11382
11879
|
return;
|
|
11383
11880
|
} catch (e) {
|
|
11384
11881
|
lastErr = e;
|
|
@@ -11391,13 +11888,13 @@ async function safeRenameWithRetry(src, dest, maxRetries = 6) {
|
|
|
11391
11888
|
}
|
|
11392
11889
|
}
|
|
11393
11890
|
try {
|
|
11394
|
-
await
|
|
11395
|
-
const data = await
|
|
11396
|
-
const dir =
|
|
11397
|
-
await
|
|
11891
|
+
await fs28.access(src);
|
|
11892
|
+
const data = await fs28.readFile(src);
|
|
11893
|
+
const dir = path30.dirname(dest);
|
|
11894
|
+
await fs28.mkdir(dir, { recursive: true }).catch(() => {
|
|
11398
11895
|
});
|
|
11399
|
-
await
|
|
11400
|
-
await
|
|
11896
|
+
await fs28.writeFile(dest, data);
|
|
11897
|
+
await fs28.unlink(src).catch(() => {
|
|
11401
11898
|
});
|
|
11402
11899
|
return;
|
|
11403
11900
|
} catch (fallbackErr) {
|
|
@@ -11410,16 +11907,16 @@ async function safeRenameWithRetry(src, dest, maxRetries = 6) {
|
|
|
11410
11907
|
}
|
|
11411
11908
|
async function ensureSessionDir() {
|
|
11412
11909
|
const appDir = getPreferredAppDir();
|
|
11413
|
-
const sessionDir =
|
|
11414
|
-
await
|
|
11910
|
+
const sessionDir = path30.join(appDir, "sessions");
|
|
11911
|
+
await fs28.mkdir(sessionDir, { recursive: true });
|
|
11415
11912
|
return sessionDir;
|
|
11416
11913
|
}
|
|
11417
11914
|
async function loadOrcreateSession(sessionId) {
|
|
11418
11915
|
const sessionDir = await ensureSessionDir();
|
|
11419
|
-
const sessionFile =
|
|
11916
|
+
const sessionFile = path30.join(sessionDir, `${sessionId}.json`);
|
|
11420
11917
|
try {
|
|
11421
|
-
await
|
|
11422
|
-
const fileContent = await
|
|
11918
|
+
await fs28.access(sessionFile);
|
|
11919
|
+
const fileContent = await fs28.readFile(sessionFile, "utf-8");
|
|
11423
11920
|
const sessionData = JSON.parse(fileContent);
|
|
11424
11921
|
const memory = {
|
|
11425
11922
|
historyAnchor: sessionData.history_anchor ?? null,
|
|
@@ -11432,7 +11929,7 @@ async function loadOrcreateSession(sessionId) {
|
|
|
11432
11929
|
created_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
11433
11930
|
conversation_history: []
|
|
11434
11931
|
};
|
|
11435
|
-
await
|
|
11932
|
+
await fs28.writeFile(sessionFile, JSON.stringify(newSessionData, null, 2), "utf-8");
|
|
11436
11933
|
const emptyMemory = {
|
|
11437
11934
|
historyAnchor: null,
|
|
11438
11935
|
compressedTurnSliceCount: 0
|
|
@@ -11444,12 +11941,12 @@ async function doSaveSessionHistory(sessionFile, history, memory) {
|
|
|
11444
11941
|
await withFileLock(sessionFile, async () => {
|
|
11445
11942
|
let sessionData;
|
|
11446
11943
|
try {
|
|
11447
|
-
const dir =
|
|
11448
|
-
await
|
|
11944
|
+
const dir = path30.dirname(sessionFile);
|
|
11945
|
+
await fs28.mkdir(dir, { recursive: true });
|
|
11449
11946
|
} catch {
|
|
11450
11947
|
}
|
|
11451
11948
|
try {
|
|
11452
|
-
const fileContent = await
|
|
11949
|
+
const fileContent = await fs28.readFile(sessionFile, "utf-8");
|
|
11453
11950
|
sessionData = JSON.parse(fileContent);
|
|
11454
11951
|
} catch (error) {
|
|
11455
11952
|
const code = error && error.code;
|
|
@@ -11460,14 +11957,14 @@ async function doSaveSessionHistory(sessionFile, history, memory) {
|
|
|
11460
11957
|
console.warn(`An unknown error occurred while reading ${sessionFile}. Re-initializing.`, error);
|
|
11461
11958
|
}
|
|
11462
11959
|
}
|
|
11463
|
-
const sessionId =
|
|
11960
|
+
const sessionId = path30.basename(sessionFile, ".json");
|
|
11464
11961
|
sessionData = {
|
|
11465
11962
|
session_id: sessionId,
|
|
11466
11963
|
created_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
11467
11964
|
conversation_history: []
|
|
11468
11965
|
};
|
|
11469
11966
|
try {
|
|
11470
|
-
await
|
|
11967
|
+
await fs28.writeFile(sessionFile, JSON.stringify(sessionData, null, 2), "utf-8");
|
|
11471
11968
|
} catch {
|
|
11472
11969
|
}
|
|
11473
11970
|
}
|
|
@@ -11483,7 +11980,7 @@ async function doSaveSessionHistory(sessionFile, history, memory) {
|
|
|
11483
11980
|
}
|
|
11484
11981
|
const tempSessionFile = `${sessionFile}.${Date.now()}.tmp`;
|
|
11485
11982
|
try {
|
|
11486
|
-
await
|
|
11983
|
+
await fs28.writeFile(tempSessionFile, JSON.stringify(sessionData, null, 2), "utf-8");
|
|
11487
11984
|
await safeRenameWithRetry(tempSessionFile, sessionFile);
|
|
11488
11985
|
} catch (writeError) {
|
|
11489
11986
|
if (writeError instanceof Error) {
|
|
@@ -11492,7 +11989,7 @@ async function doSaveSessionHistory(sessionFile, history, memory) {
|
|
|
11492
11989
|
console.error(`An unknown fatal error occurred while saving session to ${sessionFile}:`, writeError);
|
|
11493
11990
|
}
|
|
11494
11991
|
try {
|
|
11495
|
-
await
|
|
11992
|
+
await fs28.unlink(tempSessionFile);
|
|
11496
11993
|
} catch {
|
|
11497
11994
|
}
|
|
11498
11995
|
}
|
|
@@ -11510,13 +12007,13 @@ async function saveSessionHistory(sessionFile, history, memory) {
|
|
|
11510
12007
|
|
|
11511
12008
|
// src/app/agent/core/prompt/prompt_builder.ts
|
|
11512
12009
|
import os22 from "os";
|
|
11513
|
-
import
|
|
11514
|
-
import
|
|
12010
|
+
import fs35 from "fs";
|
|
12011
|
+
import path37 from "path";
|
|
11515
12012
|
import { execSync as execSync4 } from "child_process";
|
|
11516
12013
|
|
|
11517
12014
|
// src/app/agent/skills/skill_loader.ts
|
|
11518
|
-
import
|
|
11519
|
-
import
|
|
12015
|
+
import fs29 from "fs";
|
|
12016
|
+
import path31 from "path";
|
|
11520
12017
|
import os18 from "os";
|
|
11521
12018
|
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
11522
12019
|
var SkillLoader = class _SkillLoader {
|
|
@@ -11526,8 +12023,8 @@ var SkillLoader = class _SkillLoader {
|
|
|
11526
12023
|
cache = /* @__PURE__ */ new Map();
|
|
11527
12024
|
conflicts = [];
|
|
11528
12025
|
constructor(projectRoot, bundledDir) {
|
|
11529
|
-
this.projectSkillsDir =
|
|
11530
|
-
this.globalSkillsDir =
|
|
12026
|
+
this.projectSkillsDir = path31.join(projectRoot, ".bluma", "skills");
|
|
12027
|
+
this.globalSkillsDir = path31.join(os18.homedir(), ".bluma", "skills");
|
|
11531
12028
|
this.bundledSkillsDir = bundledDir || _SkillLoader.resolveBundledDir();
|
|
11532
12029
|
}
|
|
11533
12030
|
/**
|
|
@@ -11536,48 +12033,48 @@ var SkillLoader = class _SkillLoader {
|
|
|
11536
12033
|
*/
|
|
11537
12034
|
static resolveBundledDir() {
|
|
11538
12035
|
if (process.env.JEST_WORKER_ID !== void 0 || process.env.NODE_ENV === "test") {
|
|
11539
|
-
return
|
|
12036
|
+
return path31.join(process.cwd(), "dist", "config", "skills");
|
|
11540
12037
|
}
|
|
11541
12038
|
const candidates = [];
|
|
11542
12039
|
const push = (p) => {
|
|
11543
|
-
const abs =
|
|
12040
|
+
const abs = path31.resolve(p);
|
|
11544
12041
|
if (!candidates.includes(abs)) {
|
|
11545
12042
|
candidates.push(abs);
|
|
11546
12043
|
}
|
|
11547
12044
|
};
|
|
11548
12045
|
let argvBundled = null;
|
|
11549
12046
|
try {
|
|
11550
|
-
const bundleDir =
|
|
11551
|
-
push(
|
|
12047
|
+
const bundleDir = path31.dirname(fileURLToPath4(import.meta.url));
|
|
12048
|
+
push(path31.join(bundleDir, "config", "skills"));
|
|
11552
12049
|
} catch {
|
|
11553
12050
|
}
|
|
11554
12051
|
const argv1 = process.argv[1];
|
|
11555
12052
|
if (argv1 && !argv1.startsWith("-")) {
|
|
11556
12053
|
try {
|
|
11557
12054
|
let resolved = argv1;
|
|
11558
|
-
if (
|
|
11559
|
-
resolved =
|
|
11560
|
-
} else if (!
|
|
11561
|
-
resolved =
|
|
12055
|
+
if (path31.isAbsolute(argv1) && fs29.existsSync(argv1)) {
|
|
12056
|
+
resolved = fs29.realpathSync(argv1);
|
|
12057
|
+
} else if (!path31.isAbsolute(argv1)) {
|
|
12058
|
+
resolved = path31.resolve(process.cwd(), argv1);
|
|
11562
12059
|
}
|
|
11563
|
-
const scriptDir =
|
|
11564
|
-
argvBundled =
|
|
12060
|
+
const scriptDir = path31.dirname(resolved);
|
|
12061
|
+
argvBundled = path31.join(scriptDir, "config", "skills");
|
|
11565
12062
|
push(argvBundled);
|
|
11566
12063
|
} catch {
|
|
11567
12064
|
}
|
|
11568
12065
|
}
|
|
11569
12066
|
for (const abs of candidates) {
|
|
11570
|
-
if (
|
|
12067
|
+
if (fs29.existsSync(abs)) {
|
|
11571
12068
|
return abs;
|
|
11572
12069
|
}
|
|
11573
12070
|
}
|
|
11574
12071
|
try {
|
|
11575
|
-
return
|
|
12072
|
+
return path31.join(path31.dirname(fileURLToPath4(import.meta.url)), "config", "skills");
|
|
11576
12073
|
} catch {
|
|
11577
12074
|
if (argvBundled) {
|
|
11578
12075
|
return argvBundled;
|
|
11579
12076
|
}
|
|
11580
|
-
return
|
|
12077
|
+
return path31.join(os18.homedir(), ".bluma", "__bundled_skills_unresolved__");
|
|
11581
12078
|
}
|
|
11582
12079
|
}
|
|
11583
12080
|
/**
|
|
@@ -11606,8 +12103,8 @@ var SkillLoader = class _SkillLoader {
|
|
|
11606
12103
|
this.conflicts.push({
|
|
11607
12104
|
name: skill.name,
|
|
11608
12105
|
userSource: source,
|
|
11609
|
-
userPath:
|
|
11610
|
-
bundledPath:
|
|
12106
|
+
userPath: path31.join(dir, skill.name, "SKILL.md"),
|
|
12107
|
+
bundledPath: path31.join(this.bundledSkillsDir, skill.name, "SKILL.md")
|
|
11611
12108
|
});
|
|
11612
12109
|
continue;
|
|
11613
12110
|
}
|
|
@@ -11615,20 +12112,20 @@ var SkillLoader = class _SkillLoader {
|
|
|
11615
12112
|
}
|
|
11616
12113
|
}
|
|
11617
12114
|
listFromDir(dir, source) {
|
|
11618
|
-
if (!
|
|
12115
|
+
if (!fs29.existsSync(dir)) return [];
|
|
11619
12116
|
try {
|
|
11620
|
-
return
|
|
11621
|
-
const fullPath =
|
|
11622
|
-
return
|
|
11623
|
-
}).map((d) => this.loadMetadataFromPath(
|
|
12117
|
+
return fs29.readdirSync(dir).filter((d) => {
|
|
12118
|
+
const fullPath = path31.join(dir, d);
|
|
12119
|
+
return fs29.statSync(fullPath).isDirectory() && fs29.existsSync(path31.join(fullPath, "SKILL.md"));
|
|
12120
|
+
}).map((d) => this.loadMetadataFromPath(path31.join(dir, d, "SKILL.md"), d, source)).filter((m) => m !== null);
|
|
11624
12121
|
} catch {
|
|
11625
12122
|
return [];
|
|
11626
12123
|
}
|
|
11627
12124
|
}
|
|
11628
12125
|
loadMetadataFromPath(skillPath, skillName, source) {
|
|
11629
|
-
if (!
|
|
12126
|
+
if (!fs29.existsSync(skillPath)) return null;
|
|
11630
12127
|
try {
|
|
11631
|
-
const raw =
|
|
12128
|
+
const raw = fs29.readFileSync(skillPath, "utf-8");
|
|
11632
12129
|
const parsed = this.parseFrontmatter(raw);
|
|
11633
12130
|
return {
|
|
11634
12131
|
name: parsed.name || skillName,
|
|
@@ -11650,12 +12147,12 @@ var SkillLoader = class _SkillLoader {
|
|
|
11650
12147
|
*/
|
|
11651
12148
|
load(name) {
|
|
11652
12149
|
if (this.cache.has(name)) return this.cache.get(name);
|
|
11653
|
-
const bundledPath =
|
|
11654
|
-
const projectPath =
|
|
11655
|
-
const globalPath =
|
|
11656
|
-
const existsBundled =
|
|
11657
|
-
const existsProject =
|
|
11658
|
-
const existsGlobal =
|
|
12150
|
+
const bundledPath = path31.join(this.bundledSkillsDir, name, "SKILL.md");
|
|
12151
|
+
const projectPath = path31.join(this.projectSkillsDir, name, "SKILL.md");
|
|
12152
|
+
const globalPath = path31.join(this.globalSkillsDir, name, "SKILL.md");
|
|
12153
|
+
const existsBundled = fs29.existsSync(bundledPath);
|
|
12154
|
+
const existsProject = fs29.existsSync(projectPath);
|
|
12155
|
+
const existsGlobal = fs29.existsSync(globalPath);
|
|
11659
12156
|
if (existsBundled && (existsProject || existsGlobal)) {
|
|
11660
12157
|
const conflictSource = existsProject ? "project" : "global";
|
|
11661
12158
|
const conflictPath = existsProject ? projectPath : globalPath;
|
|
@@ -11694,9 +12191,9 @@ var SkillLoader = class _SkillLoader {
|
|
|
11694
12191
|
}
|
|
11695
12192
|
loadFromPath(skillPath, name, source) {
|
|
11696
12193
|
try {
|
|
11697
|
-
const raw =
|
|
12194
|
+
const raw = fs29.readFileSync(skillPath, "utf-8");
|
|
11698
12195
|
const parsed = this.parseFrontmatter(raw);
|
|
11699
|
-
const skillDir =
|
|
12196
|
+
const skillDir = path31.dirname(skillPath);
|
|
11700
12197
|
return {
|
|
11701
12198
|
name: parsed.name || name,
|
|
11702
12199
|
description: parsed.description || "",
|
|
@@ -11705,22 +12202,22 @@ var SkillLoader = class _SkillLoader {
|
|
|
11705
12202
|
version: parsed.version,
|
|
11706
12203
|
author: parsed.author,
|
|
11707
12204
|
license: parsed.license,
|
|
11708
|
-
references: this.scanAssets(
|
|
11709
|
-
scripts: this.scanAssets(
|
|
12205
|
+
references: this.scanAssets(path31.join(skillDir, "references")),
|
|
12206
|
+
scripts: this.scanAssets(path31.join(skillDir, "scripts"))
|
|
11710
12207
|
};
|
|
11711
12208
|
} catch {
|
|
11712
12209
|
return null;
|
|
11713
12210
|
}
|
|
11714
12211
|
}
|
|
11715
12212
|
scanAssets(dir) {
|
|
11716
|
-
if (!
|
|
12213
|
+
if (!fs29.existsSync(dir)) return [];
|
|
11717
12214
|
try {
|
|
11718
|
-
return
|
|
11719
|
-
const fp =
|
|
11720
|
-
return
|
|
12215
|
+
return fs29.readdirSync(dir).filter((f) => {
|
|
12216
|
+
const fp = path31.join(dir, f);
|
|
12217
|
+
return fs29.statSync(fp).isFile();
|
|
11721
12218
|
}).map((f) => ({
|
|
11722
12219
|
name: f,
|
|
11723
|
-
path:
|
|
12220
|
+
path: path31.resolve(dir, f)
|
|
11724
12221
|
}));
|
|
11725
12222
|
} catch {
|
|
11726
12223
|
return [];
|
|
@@ -11777,10 +12274,10 @@ var SkillLoader = class _SkillLoader {
|
|
|
11777
12274
|
this.cache.clear();
|
|
11778
12275
|
}
|
|
11779
12276
|
exists(name) {
|
|
11780
|
-
const bundledPath =
|
|
11781
|
-
const projectPath =
|
|
11782
|
-
const globalPath =
|
|
11783
|
-
return
|
|
12277
|
+
const bundledPath = path31.join(this.bundledSkillsDir, name, "SKILL.md");
|
|
12278
|
+
const projectPath = path31.join(this.projectSkillsDir, name, "SKILL.md");
|
|
12279
|
+
const globalPath = path31.join(this.globalSkillsDir, name, "SKILL.md");
|
|
12280
|
+
return fs29.existsSync(bundledPath) || fs29.existsSync(projectPath) || fs29.existsSync(globalPath);
|
|
11784
12281
|
}
|
|
11785
12282
|
/**
|
|
11786
12283
|
* Retorna conflitos detetados (skills do utilizador com mesmo nome de nativas).
|
|
@@ -11812,13 +12309,13 @@ var SkillLoader = class _SkillLoader {
|
|
|
11812
12309
|
};
|
|
11813
12310
|
|
|
11814
12311
|
// src/app/agent/core/prompt/workspace_snapshot.ts
|
|
11815
|
-
import
|
|
11816
|
-
import
|
|
12312
|
+
import fs31 from "fs";
|
|
12313
|
+
import path33 from "path";
|
|
11817
12314
|
import { execSync as execSync3 } from "child_process";
|
|
11818
12315
|
|
|
11819
12316
|
// src/app/agent/utils/blumamd.ts
|
|
11820
|
-
import
|
|
11821
|
-
import
|
|
12317
|
+
import fs30 from "fs";
|
|
12318
|
+
import path32 from "path";
|
|
11822
12319
|
import os19 from "os";
|
|
11823
12320
|
import { execSync as execSync2 } from "child_process";
|
|
11824
12321
|
var MEMORY_INSTRUCTION_PROMPT = "Instru\xE7\xF5es de mem\xF3ria do BluMa (BLUMA.md) est\xE3o abaixo. Siga estas instru\xE7\xF5es exatamente como escritas. Estas instru\xE7\xF5es OVERRIDE qualquer comportamento padr\xE3o.";
|
|
@@ -11948,12 +12445,12 @@ var TEXT_FILE_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
|
11948
12445
|
function expandIncludePath(includePath, baseDir) {
|
|
11949
12446
|
const cleanPath = includePath.startsWith("@") ? includePath.slice(1) : includePath;
|
|
11950
12447
|
if (cleanPath.startsWith("~")) {
|
|
11951
|
-
return
|
|
12448
|
+
return path32.join(os19.homedir(), cleanPath.slice(1));
|
|
11952
12449
|
}
|
|
11953
|
-
if (
|
|
12450
|
+
if (path32.isAbsolute(cleanPath)) {
|
|
11954
12451
|
return cleanPath;
|
|
11955
12452
|
}
|
|
11956
|
-
return
|
|
12453
|
+
return path32.resolve(baseDir, cleanPath);
|
|
11957
12454
|
}
|
|
11958
12455
|
function processIncludes(content, baseDir, processedFiles) {
|
|
11959
12456
|
const lines = content.split("\n");
|
|
@@ -11962,20 +12459,20 @@ function processIncludes(content, baseDir, processedFiles) {
|
|
|
11962
12459
|
const includeMatch = line.match(/^@\s*([^\s]+)/);
|
|
11963
12460
|
if (includeMatch) {
|
|
11964
12461
|
const includePath = expandIncludePath(includeMatch[1], baseDir);
|
|
11965
|
-
const normalizedPath =
|
|
12462
|
+
const normalizedPath = path32.normalize(includePath);
|
|
11966
12463
|
if (processedFiles.has(normalizedPath)) {
|
|
11967
12464
|
result.push(`<!-- Circular include prevented: ${includeMatch[1]} -->`);
|
|
11968
12465
|
continue;
|
|
11969
12466
|
}
|
|
11970
|
-
const ext =
|
|
12467
|
+
const ext = path32.extname(includePath).toLowerCase();
|
|
11971
12468
|
if (!TEXT_FILE_EXTENSIONS.has(ext)) {
|
|
11972
12469
|
result.push(`<!-- Include skipped (unsupported extension): ${includeMatch[1]} -->`);
|
|
11973
12470
|
continue;
|
|
11974
12471
|
}
|
|
11975
12472
|
try {
|
|
11976
|
-
const includedContent =
|
|
12473
|
+
const includedContent = fs30.readFileSync(includePath, "utf-8");
|
|
11977
12474
|
processedFiles.add(normalizedPath);
|
|
11978
|
-
const processedContent = processIncludes(includedContent,
|
|
12475
|
+
const processedContent = processIncludes(includedContent, path32.dirname(includePath), processedFiles);
|
|
11979
12476
|
result.push(`
|
|
11980
12477
|
<!-- BEGIN INCLUDE ${includeMatch[1]} -->
|
|
11981
12478
|
`);
|
|
@@ -12021,9 +12518,9 @@ function parseFrontmatterPaths(paths) {
|
|
|
12021
12518
|
}
|
|
12022
12519
|
function readMemoryFile(filePath, type, includeBasePath) {
|
|
12023
12520
|
try {
|
|
12024
|
-
const rawContent =
|
|
12025
|
-
const baseDir = includeBasePath ||
|
|
12026
|
-
const processedFiles = /* @__PURE__ */ new Set([
|
|
12521
|
+
const rawContent = fs30.readFileSync(filePath, "utf-8");
|
|
12522
|
+
const baseDir = includeBasePath || path32.dirname(filePath);
|
|
12523
|
+
const processedFiles = /* @__PURE__ */ new Set([path32.normalize(filePath)]);
|
|
12027
12524
|
const { frontmatter, content: withoutFrontmatter } = parseFrontmatter(rawContent);
|
|
12028
12525
|
const globs = parseFrontmatterPaths(frontmatter.paths);
|
|
12029
12526
|
const processedContent = processIncludes(withoutFrontmatter, baseDir, processedFiles);
|
|
@@ -12045,15 +12542,15 @@ function readMemoryFile(filePath, type, includeBasePath) {
|
|
|
12045
12542
|
}
|
|
12046
12543
|
function findGitRoot(startDir) {
|
|
12047
12544
|
let current = startDir;
|
|
12048
|
-
while (current !==
|
|
12049
|
-
const gitPath =
|
|
12545
|
+
while (current !== path32.dirname(current)) {
|
|
12546
|
+
const gitPath = path32.join(current, ".git");
|
|
12050
12547
|
try {
|
|
12051
|
-
if (
|
|
12548
|
+
if (fs30.existsSync(gitPath)) {
|
|
12052
12549
|
return current;
|
|
12053
12550
|
}
|
|
12054
12551
|
} catch {
|
|
12055
12552
|
}
|
|
12056
|
-
current =
|
|
12553
|
+
current = path32.dirname(current);
|
|
12057
12554
|
}
|
|
12058
12555
|
return null;
|
|
12059
12556
|
}
|
|
@@ -12078,17 +12575,17 @@ function getGitUserInfo(cwd) {
|
|
|
12078
12575
|
}
|
|
12079
12576
|
function processRulesDirectory(rulesDir, type, processedPaths, conditionalRule = false) {
|
|
12080
12577
|
const result = [];
|
|
12081
|
-
if (!
|
|
12578
|
+
if (!fs30.existsSync(rulesDir)) {
|
|
12082
12579
|
return result;
|
|
12083
12580
|
}
|
|
12084
12581
|
try {
|
|
12085
|
-
const entries =
|
|
12582
|
+
const entries = fs30.readdirSync(rulesDir, { withFileTypes: true });
|
|
12086
12583
|
for (const entry of entries) {
|
|
12087
|
-
const entryPath =
|
|
12584
|
+
const entryPath = path32.join(rulesDir, entry.name);
|
|
12088
12585
|
if (entry.isDirectory()) {
|
|
12089
12586
|
result.push(...processRulesDirectory(entryPath, type, processedPaths, conditionalRule));
|
|
12090
12587
|
} else if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
12091
|
-
const normalizedPath =
|
|
12588
|
+
const normalizedPath = path32.normalize(entryPath);
|
|
12092
12589
|
if (processedPaths.has(normalizedPath)) {
|
|
12093
12590
|
continue;
|
|
12094
12591
|
}
|
|
@@ -12124,13 +12621,13 @@ function loadManagedMemory() {
|
|
|
12124
12621
|
function loadUserMemory() {
|
|
12125
12622
|
const files = [];
|
|
12126
12623
|
const homeDir = os19.homedir();
|
|
12127
|
-
const userBlumaDir =
|
|
12128
|
-
const userBlumaMd =
|
|
12624
|
+
const userBlumaDir = path32.join(homeDir, ".bluma");
|
|
12625
|
+
const userBlumaMd = path32.join(userBlumaDir, "BLUMA.md");
|
|
12129
12626
|
const userFile = readMemoryFile(userBlumaMd, "User");
|
|
12130
12627
|
if (userFile && userFile.content.trim()) {
|
|
12131
12628
|
files.push(userFile);
|
|
12132
12629
|
}
|
|
12133
|
-
const userRulesDir =
|
|
12630
|
+
const userRulesDir = path32.join(userBlumaDir, "rules");
|
|
12134
12631
|
const processedPaths = /* @__PURE__ */ new Set();
|
|
12135
12632
|
files.push(...processRulesDirectory(userRulesDir, "User", processedPaths, false));
|
|
12136
12633
|
return files;
|
|
@@ -12142,10 +12639,10 @@ function loadProjectMemory(cwd) {
|
|
|
12142
12639
|
let currentDir = cwd;
|
|
12143
12640
|
const MAX_TRAVERSAL_DEPTH = 20;
|
|
12144
12641
|
let depth = 0;
|
|
12145
|
-
const normalizedGitRoot =
|
|
12146
|
-
while (currentDir !==
|
|
12642
|
+
const normalizedGitRoot = path32.resolve(gitRoot);
|
|
12643
|
+
while (currentDir !== path32.dirname(currentDir) && path32.resolve(currentDir).startsWith(normalizedGitRoot) && depth < MAX_TRAVERSAL_DEPTH) {
|
|
12147
12644
|
dirs.push(currentDir);
|
|
12148
|
-
currentDir =
|
|
12645
|
+
currentDir = path32.dirname(currentDir);
|
|
12149
12646
|
depth++;
|
|
12150
12647
|
}
|
|
12151
12648
|
if (!dirs.includes(gitRoot)) {
|
|
@@ -12153,7 +12650,7 @@ function loadProjectMemory(cwd) {
|
|
|
12153
12650
|
}
|
|
12154
12651
|
const processedPaths = /* @__PURE__ */ new Set();
|
|
12155
12652
|
for (const dir of dirs.reverse()) {
|
|
12156
|
-
const projectBlumaMd =
|
|
12653
|
+
const projectBlumaMd = path32.join(dir, "BLUMA.md");
|
|
12157
12654
|
if (!processedPaths.has(projectBlumaMd)) {
|
|
12158
12655
|
processedPaths.add(projectBlumaMd);
|
|
12159
12656
|
const projectFile = readMemoryFile(projectBlumaMd, "Project");
|
|
@@ -12161,7 +12658,7 @@ function loadProjectMemory(cwd) {
|
|
|
12161
12658
|
files.push(projectFile);
|
|
12162
12659
|
}
|
|
12163
12660
|
}
|
|
12164
|
-
const blumaDirBlumaMd =
|
|
12661
|
+
const blumaDirBlumaMd = path32.join(dir, ".bluma", "BLUMA.md");
|
|
12165
12662
|
if (!processedPaths.has(blumaDirBlumaMd)) {
|
|
12166
12663
|
processedPaths.add(blumaDirBlumaMd);
|
|
12167
12664
|
const blumaDirFile = readMemoryFile(blumaDirBlumaMd, "Project");
|
|
@@ -12169,10 +12666,10 @@ function loadProjectMemory(cwd) {
|
|
|
12169
12666
|
files.push(blumaDirFile);
|
|
12170
12667
|
}
|
|
12171
12668
|
}
|
|
12172
|
-
const rulesDir =
|
|
12669
|
+
const rulesDir = path32.join(dir, ".bluma", "rules");
|
|
12173
12670
|
files.push(...processRulesDirectory(rulesDir, "Project", processedPaths, false));
|
|
12174
12671
|
}
|
|
12175
|
-
const localBlumaMd =
|
|
12672
|
+
const localBlumaMd = path32.join(cwd, "BLUMA.local.md");
|
|
12176
12673
|
if (!processedPaths.has(localBlumaMd)) {
|
|
12177
12674
|
processedPaths.add(localBlumaMd);
|
|
12178
12675
|
const localFile = readMemoryFile(localBlumaMd, "Local");
|
|
@@ -12258,10 +12755,10 @@ var LIMITS = {
|
|
|
12258
12755
|
};
|
|
12259
12756
|
function safeReadFile(filePath, maxChars) {
|
|
12260
12757
|
try {
|
|
12261
|
-
if (!
|
|
12262
|
-
const st =
|
|
12758
|
+
if (!fs31.existsSync(filePath)) return null;
|
|
12759
|
+
const st = fs31.statSync(filePath);
|
|
12263
12760
|
if (!st.isFile()) return null;
|
|
12264
|
-
const raw =
|
|
12761
|
+
const raw = fs31.readFileSync(filePath, "utf8");
|
|
12265
12762
|
if (raw.includes("\0")) return null;
|
|
12266
12763
|
if (raw.length <= maxChars) return raw;
|
|
12267
12764
|
return `${raw.slice(0, maxChars)}
|
|
@@ -12273,7 +12770,7 @@ function safeReadFile(filePath, maxChars) {
|
|
|
12273
12770
|
}
|
|
12274
12771
|
function tryReadReadme(cwd) {
|
|
12275
12772
|
for (const name of ["README.md", "README.MD", "readme.md", "Readme.md"]) {
|
|
12276
|
-
const c = safeReadFile(
|
|
12773
|
+
const c = safeReadFile(path33.join(cwd, name), LIMITS.readme);
|
|
12277
12774
|
if (c) return `(${name})
|
|
12278
12775
|
${c}`;
|
|
12279
12776
|
}
|
|
@@ -12281,14 +12778,14 @@ ${c}`;
|
|
|
12281
12778
|
}
|
|
12282
12779
|
function tryReadBluMaMd(cwd) {
|
|
12283
12780
|
const paths = [
|
|
12284
|
-
|
|
12285
|
-
|
|
12286
|
-
|
|
12781
|
+
path33.join(cwd, "BluMa.md"),
|
|
12782
|
+
path33.join(cwd, "BLUMA.md"),
|
|
12783
|
+
path33.join(cwd, ".bluma", "BluMa.md")
|
|
12287
12784
|
];
|
|
12288
12785
|
for (const p of paths) {
|
|
12289
12786
|
const c = safeReadFile(p, LIMITS.blumaMd);
|
|
12290
12787
|
if (c) {
|
|
12291
|
-
const rel =
|
|
12788
|
+
const rel = path33.relative(cwd, p) || p;
|
|
12292
12789
|
return `(${rel})
|
|
12293
12790
|
${c}`;
|
|
12294
12791
|
}
|
|
@@ -12296,10 +12793,10 @@ ${c}`;
|
|
|
12296
12793
|
return null;
|
|
12297
12794
|
}
|
|
12298
12795
|
function summarizePackageJson(cwd) {
|
|
12299
|
-
const p =
|
|
12796
|
+
const p = path33.join(cwd, "package.json");
|
|
12300
12797
|
try {
|
|
12301
|
-
if (!
|
|
12302
|
-
const pkg = JSON.parse(
|
|
12798
|
+
if (!fs31.existsSync(p)) return null;
|
|
12799
|
+
const pkg = JSON.parse(fs31.readFileSync(p, "utf8"));
|
|
12303
12800
|
const scripts = pkg.scripts;
|
|
12304
12801
|
let scriptKeys = "";
|
|
12305
12802
|
if (scripts && typeof scripts === "object" && !Array.isArray(scripts)) {
|
|
@@ -12332,7 +12829,7 @@ function summarizePackageJson(cwd) {
|
|
|
12332
12829
|
}
|
|
12333
12830
|
function topLevelListing(cwd) {
|
|
12334
12831
|
try {
|
|
12335
|
-
const names =
|
|
12832
|
+
const names = fs31.readdirSync(cwd, { withFileTypes: true });
|
|
12336
12833
|
const sorted = [...names].sort((a, b) => a.name.localeCompare(b.name));
|
|
12337
12834
|
const limited = sorted.slice(0, LIMITS.topDirEntries);
|
|
12338
12835
|
const lines = limited.map((d) => `${d.name}${d.isDirectory() ? "/" : ""}`);
|
|
@@ -12390,7 +12887,7 @@ function buildWorkspaceSnapshot(cwd) {
|
|
|
12390
12887
|
parts.push(pkg);
|
|
12391
12888
|
parts.push("```\n");
|
|
12392
12889
|
}
|
|
12393
|
-
const py = safeReadFile(
|
|
12890
|
+
const py = safeReadFile(path33.join(cwd, "pyproject.toml"), LIMITS.pyproject);
|
|
12394
12891
|
if (py) {
|
|
12395
12892
|
parts.push("### pyproject.toml (excerpt)\n```toml");
|
|
12396
12893
|
parts.push(py);
|
|
@@ -12408,15 +12905,15 @@ function buildWorkspaceSnapshot(cwd) {
|
|
|
12408
12905
|
parts.push(bluma);
|
|
12409
12906
|
parts.push("```\n");
|
|
12410
12907
|
}
|
|
12411
|
-
const contrib = safeReadFile(
|
|
12908
|
+
const contrib = safeReadFile(path33.join(cwd, "CONTRIBUTING.md"), LIMITS.contributing);
|
|
12412
12909
|
if (contrib) {
|
|
12413
12910
|
parts.push("### CONTRIBUTING.md (excerpt)\n```markdown");
|
|
12414
12911
|
parts.push(contrib);
|
|
12415
12912
|
parts.push("```\n");
|
|
12416
12913
|
}
|
|
12417
|
-
const chlog = safeReadFile(
|
|
12914
|
+
const chlog = safeReadFile(path33.join(cwd, "CHANGELOG.md"), LIMITS.changelog);
|
|
12418
12915
|
if (!chlog) {
|
|
12419
|
-
const alt = safeReadFile(
|
|
12916
|
+
const alt = safeReadFile(path33.join(cwd, "CHANGES.md"), LIMITS.changelog);
|
|
12420
12917
|
if (alt) {
|
|
12421
12918
|
parts.push("### CHANGES.md (excerpt)\n```markdown");
|
|
12422
12919
|
parts.push(alt);
|
|
@@ -12452,14 +12949,14 @@ function buildWorkspaceSnapshot(cwd) {
|
|
|
12452
12949
|
} else {
|
|
12453
12950
|
parts.push("### Git\n(not a git work tree, or `git` unavailable)\n");
|
|
12454
12951
|
}
|
|
12455
|
-
const tsconfig = safeReadFile(
|
|
12952
|
+
const tsconfig = safeReadFile(path33.join(cwd, "tsconfig.json"), LIMITS.tsconfig);
|
|
12456
12953
|
if (tsconfig) {
|
|
12457
12954
|
parts.push("### tsconfig.json (excerpt)\n```json");
|
|
12458
12955
|
parts.push(tsconfig);
|
|
12459
12956
|
parts.push("```\n");
|
|
12460
12957
|
}
|
|
12461
12958
|
for (const name of ["Dockerfile", "dockerfile", "Dockerfile.prod", "Dockerfile.dev"]) {
|
|
12462
|
-
const df = safeReadFile(
|
|
12959
|
+
const df = safeReadFile(path33.join(cwd, name), LIMITS.dockerfile);
|
|
12463
12960
|
if (df) {
|
|
12464
12961
|
parts.push(`### ${name} (excerpt)
|
|
12465
12962
|
`);
|
|
@@ -12469,7 +12966,7 @@ function buildWorkspaceSnapshot(cwd) {
|
|
|
12469
12966
|
}
|
|
12470
12967
|
}
|
|
12471
12968
|
for (const name of ["docker-compose.yml", "docker-compose.yaml", "compose.yml", "compose.yaml"]) {
|
|
12472
|
-
const dc = safeReadFile(
|
|
12969
|
+
const dc = safeReadFile(path33.join(cwd, name), LIMITS.dockerfile);
|
|
12473
12970
|
if (dc) {
|
|
12474
12971
|
parts.push(`### ${name} (excerpt)
|
|
12475
12972
|
`);
|
|
@@ -12484,12 +12981,12 @@ function buildWorkspaceSnapshot(cwd) {
|
|
|
12484
12981
|
".circleci/config.yml",
|
|
12485
12982
|
"Jenkinsfile"
|
|
12486
12983
|
]) {
|
|
12487
|
-
const ciFile =
|
|
12488
|
-
if (
|
|
12489
|
-
const st =
|
|
12984
|
+
const ciFile = path33.join(cwd, ciPath);
|
|
12985
|
+
if (fs31.existsSync(ciFile)) {
|
|
12986
|
+
const st = fs31.statSync(ciFile);
|
|
12490
12987
|
if (st.isDirectory()) {
|
|
12491
12988
|
try {
|
|
12492
|
-
const wfFiles =
|
|
12989
|
+
const wfFiles = fs31.readdirSync(ciFile).filter((f) => f.endsWith(".yml") || f.endsWith(".yaml"));
|
|
12493
12990
|
if (wfFiles.length > 0) {
|
|
12494
12991
|
parts.push(`### GitHub Actions workflows
|
|
12495
12992
|
\`${wfFiles.join("`, `")}\`
|
|
@@ -12500,7 +12997,7 @@ function buildWorkspaceSnapshot(cwd) {
|
|
|
12500
12997
|
} else {
|
|
12501
12998
|
const ci = safeReadFile(ciFile, LIMITS.ciConfig);
|
|
12502
12999
|
if (ci) {
|
|
12503
|
-
parts.push(`### CI config (${
|
|
13000
|
+
parts.push(`### CI config (${path33.basename(ciPath)})
|
|
12504
13001
|
`);
|
|
12505
13002
|
parts.push(ci);
|
|
12506
13003
|
parts.push("\n");
|
|
@@ -12509,8 +13006,8 @@ function buildWorkspaceSnapshot(cwd) {
|
|
|
12509
13006
|
}
|
|
12510
13007
|
}
|
|
12511
13008
|
for (const depFile of ["requirements.txt", "Pipfile", "poetry.lock", "Gemfile", "go.sum", "Cargo.lock"]) {
|
|
12512
|
-
const depPath =
|
|
12513
|
-
if (
|
|
13009
|
+
const depPath = path33.join(cwd, depFile);
|
|
13010
|
+
if (fs31.existsSync(depPath)) {
|
|
12514
13011
|
const depContent = safeReadFile(depPath, 1500);
|
|
12515
13012
|
if (depContent) {
|
|
12516
13013
|
parts.push(`### ${depFile} (top entries)
|
|
@@ -12523,10 +13020,10 @@ function buildWorkspaceSnapshot(cwd) {
|
|
|
12523
13020
|
}
|
|
12524
13021
|
}
|
|
12525
13022
|
for (const envFile of [".env.example", ".env.sample", ".env.template"]) {
|
|
12526
|
-
const envPath =
|
|
12527
|
-
if (
|
|
13023
|
+
const envPath = path33.join(cwd, envFile);
|
|
13024
|
+
if (fs31.existsSync(envPath)) {
|
|
12528
13025
|
try {
|
|
12529
|
-
const raw =
|
|
13026
|
+
const raw = fs31.readFileSync(envPath, "utf-8");
|
|
12530
13027
|
const keys = raw.split("\n").map((l) => l.trim()).filter((l) => l && !l.startsWith("#")).map((l) => {
|
|
12531
13028
|
const eqIndex = l.indexOf("=");
|
|
12532
13029
|
return eqIndex >= 0 ? l.slice(0, eqIndex).trim() : l.trim();
|
|
@@ -12549,15 +13046,15 @@ init_runtime_config();
|
|
|
12549
13046
|
|
|
12550
13047
|
// src/app/agent/runtime/plugin_registry.ts
|
|
12551
13048
|
init_sandbox_policy();
|
|
12552
|
-
import
|
|
13049
|
+
import fs32 from "fs";
|
|
12553
13050
|
import os20 from "os";
|
|
12554
|
-
import
|
|
13051
|
+
import path34 from "path";
|
|
12555
13052
|
function getProjectPluginsDir() {
|
|
12556
13053
|
const policy = getSandboxPolicy();
|
|
12557
|
-
return
|
|
13054
|
+
return path34.join(policy.workspaceRoot, ".bluma", "plugins");
|
|
12558
13055
|
}
|
|
12559
13056
|
function getGlobalPluginsDir() {
|
|
12560
|
-
return
|
|
13057
|
+
return path34.join(process.env.HOME || os20.homedir(), ".bluma", "plugins");
|
|
12561
13058
|
}
|
|
12562
13059
|
function getPluginDirs() {
|
|
12563
13060
|
return {
|
|
@@ -12566,11 +13063,11 @@ function getPluginDirs() {
|
|
|
12566
13063
|
};
|
|
12567
13064
|
}
|
|
12568
13065
|
function readManifest(manifestPath, fallbackName) {
|
|
12569
|
-
if (!
|
|
13066
|
+
if (!fs32.existsSync(manifestPath)) {
|
|
12570
13067
|
return null;
|
|
12571
13068
|
}
|
|
12572
13069
|
try {
|
|
12573
|
-
const parsed = JSON.parse(
|
|
13070
|
+
const parsed = JSON.parse(fs32.readFileSync(manifestPath, "utf-8"));
|
|
12574
13071
|
return {
|
|
12575
13072
|
name: typeof parsed.name === "string" && parsed.name.trim() ? parsed.name.trim() : fallbackName,
|
|
12576
13073
|
description: typeof parsed.description === "string" ? parsed.description.trim() : void 0,
|
|
@@ -12583,22 +13080,22 @@ function readManifest(manifestPath, fallbackName) {
|
|
|
12583
13080
|
}
|
|
12584
13081
|
function findManifestPath(pluginDir) {
|
|
12585
13082
|
const candidates = [
|
|
12586
|
-
|
|
12587
|
-
|
|
13083
|
+
path34.join(pluginDir, ".codex-plugin", "plugin.json"),
|
|
13084
|
+
path34.join(pluginDir, "plugin.json")
|
|
12588
13085
|
];
|
|
12589
13086
|
for (const candidate of candidates) {
|
|
12590
|
-
if (
|
|
13087
|
+
if (fs32.existsSync(candidate)) {
|
|
12591
13088
|
return candidate;
|
|
12592
13089
|
}
|
|
12593
13090
|
}
|
|
12594
13091
|
return null;
|
|
12595
13092
|
}
|
|
12596
13093
|
function listFromDir(baseDir, source) {
|
|
12597
|
-
if (!
|
|
13094
|
+
if (!fs32.existsSync(baseDir)) {
|
|
12598
13095
|
return [];
|
|
12599
13096
|
}
|
|
12600
|
-
return
|
|
12601
|
-
const pluginDir =
|
|
13097
|
+
return fs32.readdirSync(baseDir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).flatMap((entry) => {
|
|
13098
|
+
const pluginDir = path34.join(baseDir, entry.name);
|
|
12602
13099
|
const manifestPath = findManifestPath(pluginDir);
|
|
12603
13100
|
if (!manifestPath) {
|
|
12604
13101
|
return [];
|
|
@@ -13041,13 +13538,23 @@ Since you are in an **isolated sandbox**, ALL tools are auto-approved:
|
|
|
13041
13538
|
- \\\`notebook_edit\\\` - Jupyter notebook editing (auto-approved)
|
|
13042
13539
|
- \\\`cron_create\\\` - Schedule reminders (auto-approved)
|
|
13043
13540
|
|
|
13541
|
+
### FactorAI Workspace Tools
|
|
13542
|
+
When a deployed app is attached to this sandbox, the following tools may appear and are sandbox-only:
|
|
13543
|
+
- \\\`factorai.sh.create_next_app\\\` - Create a new Next.js project in the sandbox
|
|
13544
|
+
- \\\`factorai.sh.deploy_app\\\` - Deploy a Next.js project from the sandbox to the hosting backend
|
|
13545
|
+
- \\\`factorai.sh.get_app_status\\\` - Read app status and contract context
|
|
13546
|
+
- \\\`factorai.sh.apply_app_changes\\\` - Apply incremental file changes to the app workspace
|
|
13547
|
+
- \\\`factorai.sh.redeploy_app\\\` - Redeploy the current app revision after edits
|
|
13548
|
+
|
|
13549
|
+
Use \\\`factorai.sh.json\\\` as a normal workspace file. Do not treat manifest reading as a tool call.
|
|
13550
|
+
|
|
13044
13551
|
---
|
|
13045
13552
|
|
|
13046
13553
|
## \u{1F680} NEXT.JS DEPLOY WORKFLOW - SEVERINO INTEGRATION
|
|
13047
13554
|
|
|
13048
13555
|
You have access to **two specialized tools** for creating and deploying Next.js apps to Severino:
|
|
13049
13556
|
|
|
13050
|
-
### Tool 1: \\\`create_next_app\\\`
|
|
13557
|
+
### Tool 1: \\\`factorai.sh.create_next_app\\\`
|
|
13051
13558
|
|
|
13052
13559
|
**Purpose:** Instant scaffold of a complete Next.js project with App Router, shadcn/ui, and Tailwind CSS.
|
|
13053
13560
|
|
|
@@ -13058,7 +13565,7 @@ You have access to **two specialized tools** for creating and deploying Next.js
|
|
|
13058
13565
|
|
|
13059
13566
|
**Example:**
|
|
13060
13567
|
\\\`\\\`\\\`typescript
|
|
13061
|
-
const result = await
|
|
13568
|
+
const result = await factorai.sh.create_next_app({
|
|
13062
13569
|
name: 'erp-dashboard',
|
|
13063
13570
|
template: 'full',
|
|
13064
13571
|
});
|
|
@@ -13079,7 +13586,7 @@ const result = await createNextApp({
|
|
|
13079
13586
|
|
|
13080
13587
|
---
|
|
13081
13588
|
|
|
13082
|
-
### Tool 2: \\\`deploy_app\\\`
|
|
13589
|
+
### Tool 2: \\\`factorai.sh.deploy_app\\\`
|
|
13083
13590
|
|
|
13084
13591
|
**Purpose:** Zip and deploy a Next.js project to Severino for hosting.
|
|
13085
13592
|
|
|
@@ -13091,7 +13598,7 @@ const result = await createNextApp({
|
|
|
13091
13598
|
|
|
13092
13599
|
**Example:**
|
|
13093
13600
|
\\\`\\\`\\\`typescript
|
|
13094
|
-
const result = await
|
|
13601
|
+
const result = await factorai.sh.deploy_app({
|
|
13095
13602
|
projectDir: './erp-dashboard',
|
|
13096
13603
|
name: 'erp-dashboard',
|
|
13097
13604
|
});
|
|
@@ -13112,10 +13619,17 @@ const result = await deployApp({
|
|
|
13112
13619
|
- O ZIP deve conter **apenas c\xF3digo fonte e configs**
|
|
13113
13620
|
- \\\`node_modules\\\` \xE9 recriado no servidor com \\\`npm install\\\`
|
|
13114
13621
|
- Incluir \\\`node_modules\\\` = ZIP de 200MB+ = deploy falha
|
|
13115
|
-
- A tool \\\`deploy_app\\\` j\xE1 exclui automaticamente, mas se fizeres ZIP manual: **exclui \\\`node_modules\\\`**
|
|
13622
|
+
- A tool \\\`factorai.sh.deploy_app\\\` j\xE1 exclui automaticamente, mas se fizeres ZIP manual: **exclui \\\`node_modules\\\`**
|
|
13116
13623
|
|
|
13117
13624
|
**Important:** The deploy is **asynchronous** - status starts as \\\`'building'\\\`. The app will be ready in ~30-60 seconds.
|
|
13118
13625
|
|
|
13626
|
+
**After this tool returns**
|
|
13627
|
+
- Read the returned metadata immediately.
|
|
13628
|
+
- Create or update \\\`factorai.sh.json\\\` in the project root.
|
|
13629
|
+
- Persist the deployment context there: \\\`appId\\\`, \\\`tenantId\\\`, \\\`projectId\\\`, \\\`workspaceId\\\`, \\\`revisionId\\\`, \\\`deploymentId\\\`, \\\`buildJobId\\\`, and \\\`appUrl\\\` when available.
|
|
13630
|
+
- Treat \\\`factorai.sh.json\\\` as the source of truth for future incremental edits and redeploys.
|
|
13631
|
+
- Do not invent a second manifest file or duplicate state elsewhere.
|
|
13632
|
+
|
|
13119
13633
|
---
|
|
13120
13634
|
|
|
13121
13635
|
### Complete Workflow Example
|
|
@@ -13123,7 +13637,7 @@ const result = await deployApp({
|
|
|
13123
13637
|
\\\`\\\`\\\`typescript
|
|
13124
13638
|
// Step 1: Create project
|
|
13125
13639
|
message({ message_type: 'info', content: 'Step 1/3: Creating Next.js project...' });
|
|
13126
|
-
const scaffold = await
|
|
13640
|
+
const scaffold = await factorai.sh.create_next_app({
|
|
13127
13641
|
name: 'erp-dashboard',
|
|
13128
13642
|
template: 'full',
|
|
13129
13643
|
});
|
|
@@ -13137,7 +13651,7 @@ await fileWrite({
|
|
|
13137
13651
|
|
|
13138
13652
|
// Step 3: Deploy
|
|
13139
13653
|
message({ message_type: 'info', content: 'Step 3/3: Deploying to Severino...' });
|
|
13140
|
-
const deploy = await
|
|
13654
|
+
const deploy = await factorai.sh.deploy_app({
|
|
13141
13655
|
projectDir: './erp-dashboard',
|
|
13142
13656
|
name: 'erp-dashboard',
|
|
13143
13657
|
});
|
|
@@ -13155,7 +13669,7 @@ message({
|
|
|
13155
13669
|
### \u26A0\uFE0F Critical Requirements for Deploy
|
|
13156
13670
|
|
|
13157
13671
|
1. **\\\`output: 'standalone'\\\` in \\\`next.config.js\\\`**
|
|
13158
|
-
- The \\\`create_next_app\\\` tool already includes this
|
|
13672
|
+
- The \\\`factorai.sh.create_next_app\\\` tool already includes this
|
|
13159
13673
|
- If you modify \\\`next.config.js\\\`, keep this setting
|
|
13160
13674
|
|
|
13161
13675
|
2. **Build before deploy (optional but recommended)**
|
|
@@ -13493,8 +14007,8 @@ function buildModelInfoSection(modelId) {
|
|
|
13493
14007
|
|
|
13494
14008
|
// src/app/agent/runtime/hook_registry.ts
|
|
13495
14009
|
init_sandbox_policy();
|
|
13496
|
-
import
|
|
13497
|
-
import
|
|
14010
|
+
import fs33 from "fs";
|
|
14011
|
+
import path35 from "path";
|
|
13498
14012
|
var DEFAULT_STATE = {
|
|
13499
14013
|
enabled: true,
|
|
13500
14014
|
maxEvents: 120,
|
|
@@ -13505,7 +14019,7 @@ var cache2 = null;
|
|
|
13505
14019
|
var cachePath2 = null;
|
|
13506
14020
|
function getStatePath() {
|
|
13507
14021
|
const policy = getSandboxPolicy();
|
|
13508
|
-
return
|
|
14022
|
+
return path35.join(policy.workspaceRoot, ".bluma", "hooks.json");
|
|
13509
14023
|
}
|
|
13510
14024
|
function getHookStatePath() {
|
|
13511
14025
|
return getStatePath();
|
|
@@ -13524,8 +14038,8 @@ function ensureLoaded2() {
|
|
|
13524
14038
|
return cache2;
|
|
13525
14039
|
}
|
|
13526
14040
|
try {
|
|
13527
|
-
if (
|
|
13528
|
-
const parsed = JSON.parse(
|
|
14041
|
+
if (fs33.existsSync(statePath)) {
|
|
14042
|
+
const parsed = JSON.parse(fs33.readFileSync(statePath, "utf-8"));
|
|
13529
14043
|
cache2 = {
|
|
13530
14044
|
enabled: typeof parsed.enabled === "boolean" ? parsed.enabled : DEFAULT_STATE.enabled,
|
|
13531
14045
|
maxEvents: typeof parsed.maxEvents === "number" && Number.isFinite(parsed.maxEvents) && parsed.maxEvents > 0 ? Math.floor(parsed.maxEvents) : DEFAULT_STATE.maxEvents,
|
|
@@ -13551,9 +14065,9 @@ function ensureLoaded2() {
|
|
|
13551
14065
|
}
|
|
13552
14066
|
function persist2(state) {
|
|
13553
14067
|
const statePath = getStatePath();
|
|
13554
|
-
|
|
14068
|
+
fs33.mkdirSync(path35.dirname(statePath), { recursive: true });
|
|
13555
14069
|
state.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
13556
|
-
|
|
14070
|
+
fs33.writeFileSync(statePath, JSON.stringify(state, null, 2), "utf-8");
|
|
13557
14071
|
cache2 = state;
|
|
13558
14072
|
cachePath2 = statePath;
|
|
13559
14073
|
}
|
|
@@ -13622,18 +14136,18 @@ function buildSystemRemindersSection() {
|
|
|
13622
14136
|
}
|
|
13623
14137
|
|
|
13624
14138
|
// src/app/agent/core/prompt/auto_memory.ts
|
|
13625
|
-
import
|
|
13626
|
-
import
|
|
14139
|
+
import fs34 from "fs";
|
|
14140
|
+
import path36 from "path";
|
|
13627
14141
|
import os21 from "os";
|
|
13628
|
-
var AUTO_MEMORY_FILE =
|
|
14142
|
+
var AUTO_MEMORY_FILE = path36.join(os21.homedir(), ".bluma", "auto_memory.md");
|
|
13629
14143
|
var MAX_AUTO_MEMORY_CHARS = 25e3;
|
|
13630
14144
|
var MAX_AUTO_MEMORY_LINES = 200;
|
|
13631
14145
|
function getAutoMemoryForPrompt() {
|
|
13632
14146
|
try {
|
|
13633
|
-
if (!
|
|
14147
|
+
if (!fs34.existsSync(AUTO_MEMORY_FILE)) {
|
|
13634
14148
|
return "";
|
|
13635
14149
|
}
|
|
13636
|
-
let content =
|
|
14150
|
+
let content = fs34.readFileSync(AUTO_MEMORY_FILE, "utf-8");
|
|
13637
14151
|
if (!content.trim()) {
|
|
13638
14152
|
return "";
|
|
13639
14153
|
}
|
|
@@ -13692,10 +14206,10 @@ function getGitBranch(dir) {
|
|
|
13692
14206
|
}
|
|
13693
14207
|
function getPackageManager(dir) {
|
|
13694
14208
|
try {
|
|
13695
|
-
if (
|
|
13696
|
-
if (
|
|
13697
|
-
if (
|
|
13698
|
-
if (
|
|
14209
|
+
if (fs35.existsSync(path37.join(dir, "pnpm-lock.yaml"))) return "pnpm";
|
|
14210
|
+
if (fs35.existsSync(path37.join(dir, "yarn.lock"))) return "yarn";
|
|
14211
|
+
if (fs35.existsSync(path37.join(dir, "bun.lockb"))) return "bun";
|
|
14212
|
+
if (fs35.existsSync(path37.join(dir, "package-lock.json"))) return "npm";
|
|
13699
14213
|
return "unknown";
|
|
13700
14214
|
} catch {
|
|
13701
14215
|
return "unknown";
|
|
@@ -13703,9 +14217,9 @@ function getPackageManager(dir) {
|
|
|
13703
14217
|
}
|
|
13704
14218
|
function getProjectType(dir) {
|
|
13705
14219
|
try {
|
|
13706
|
-
const files =
|
|
14220
|
+
const files = fs35.readdirSync(dir);
|
|
13707
14221
|
if (files.includes("package.json")) {
|
|
13708
|
-
const pkg = JSON.parse(
|
|
14222
|
+
const pkg = JSON.parse(fs35.readFileSync(path37.join(dir, "package.json"), "utf-8"));
|
|
13709
14223
|
if (pkg.dependencies?.next || pkg.devDependencies?.next) return "Next.js";
|
|
13710
14224
|
if (pkg.dependencies?.react || pkg.devDependencies?.react) return "React";
|
|
13711
14225
|
if (pkg.dependencies?.express || pkg.devDependencies?.express) return "Express";
|
|
@@ -13724,9 +14238,9 @@ function getProjectType(dir) {
|
|
|
13724
14238
|
}
|
|
13725
14239
|
function getTestFramework(dir) {
|
|
13726
14240
|
try {
|
|
13727
|
-
const pkgPath =
|
|
13728
|
-
if (
|
|
13729
|
-
const pkg = JSON.parse(
|
|
14241
|
+
const pkgPath = path37.join(dir, "package.json");
|
|
14242
|
+
if (fs35.existsSync(pkgPath)) {
|
|
14243
|
+
const pkg = JSON.parse(fs35.readFileSync(pkgPath, "utf-8"));
|
|
13730
14244
|
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
13731
14245
|
if (deps.jest) return "jest";
|
|
13732
14246
|
if (deps.vitest) return "vitest";
|
|
@@ -13735,7 +14249,7 @@ function getTestFramework(dir) {
|
|
|
13735
14249
|
if (deps["@playwright/test"]) return "playwright";
|
|
13736
14250
|
if (deps.cypress) return "cypress";
|
|
13737
14251
|
}
|
|
13738
|
-
if (
|
|
14252
|
+
if (fs35.existsSync(path37.join(dir, "pytest.ini")) || fs35.existsSync(path37.join(dir, "conftest.py"))) return "pytest";
|
|
13739
14253
|
return "unknown";
|
|
13740
14254
|
} catch {
|
|
13741
14255
|
return "unknown";
|
|
@@ -13743,9 +14257,9 @@ function getTestFramework(dir) {
|
|
|
13743
14257
|
}
|
|
13744
14258
|
function getTestCommand(dir) {
|
|
13745
14259
|
try {
|
|
13746
|
-
const pkgPath =
|
|
13747
|
-
if (
|
|
13748
|
-
const pkg = JSON.parse(
|
|
14260
|
+
const pkgPath = path37.join(dir, "package.json");
|
|
14261
|
+
if (fs35.existsSync(pkgPath)) {
|
|
14262
|
+
const pkg = JSON.parse(fs35.readFileSync(pkgPath, "utf-8"));
|
|
13749
14263
|
if (pkg.scripts?.test) return `npm test`;
|
|
13750
14264
|
if (pkg.scripts?.["test:unit"]) return `npm run test:unit`;
|
|
13751
14265
|
}
|
|
@@ -13937,7 +14451,15 @@ async function getUnifiedSystemPrompt(availableSkills, options) {
|
|
|
13937
14451
|
const fromAgent = process.env.BLUMA_FROM_AGENT || "severino";
|
|
13938
14452
|
const action = process.env.BLUMA_ACTION || "unknown";
|
|
13939
14453
|
const sessionId = process.env.BLUMA_SESSION_ID || "unknown";
|
|
14454
|
+
const factorAiAppContext = loadFactorAiAppContext();
|
|
13940
14455
|
prompt = prompt.replaceAll("{from_agent}", fromAgent).replaceAll("{action}", action).replaceAll("{session_id}", sessionId).replaceAll("{workspace_root}", env.workdir);
|
|
14456
|
+
if (factorAiAppContext) {
|
|
14457
|
+
prompt += `
|
|
14458
|
+
|
|
14459
|
+
<factorai_app_context>
|
|
14460
|
+
${formatFactorAiAppContextSummary(factorAiAppContext)}
|
|
14461
|
+
</factorai_app_context>`;
|
|
14462
|
+
}
|
|
13941
14463
|
}
|
|
13942
14464
|
prompt += buildOutputStylePrompt(runtimeConfig.outputStyle);
|
|
13943
14465
|
prompt += buildPermissionModePrompt(runtimeConfig.permissionMode);
|
|
@@ -14037,8 +14559,8 @@ ${blumaMdContent}
|
|
|
14037
14559
|
}
|
|
14038
14560
|
function isGitRepo(dir) {
|
|
14039
14561
|
try {
|
|
14040
|
-
const gitPath =
|
|
14041
|
-
return
|
|
14562
|
+
const gitPath = path37.join(dir, ".git");
|
|
14563
|
+
return fs35.existsSync(gitPath) && fs35.lstatSync(gitPath).isDirectory();
|
|
14042
14564
|
} catch {
|
|
14043
14565
|
return false;
|
|
14044
14566
|
}
|
|
@@ -14246,7 +14768,8 @@ function defaultBlumaUserContextInput(sessionId, userMessage) {
|
|
|
14246
14768
|
userName: null,
|
|
14247
14769
|
userEmail: null,
|
|
14248
14770
|
companyId: null,
|
|
14249
|
-
companyName: null
|
|
14771
|
+
companyName: null,
|
|
14772
|
+
appContext: loadFactorAiAppContext()
|
|
14250
14773
|
};
|
|
14251
14774
|
}
|
|
14252
14775
|
function getPreferredMacAddress() {
|
|
@@ -14784,11 +15307,11 @@ function effectiveToolAutoApprove(toolCall, sessionId, options) {
|
|
|
14784
15307
|
}
|
|
14785
15308
|
|
|
14786
15309
|
// src/app/agent/tools/natives/coding_memory_consolidate.ts
|
|
14787
|
-
import * as
|
|
14788
|
-
import * as
|
|
15310
|
+
import * as fs36 from "fs";
|
|
15311
|
+
import * as path38 from "path";
|
|
14789
15312
|
import os24 from "os";
|
|
14790
15313
|
function memoryPath2() {
|
|
14791
|
-
return
|
|
15314
|
+
return path38.join(process.env.HOME || os24.homedir(), ".bluma", "coding_memory.json");
|
|
14792
15315
|
}
|
|
14793
15316
|
function normalizeNote2(note) {
|
|
14794
15317
|
return note.trim().toLowerCase().replace(/\s+/g, " ");
|
|
@@ -14798,18 +15321,18 @@ function uniqTags(a, b) {
|
|
|
14798
15321
|
}
|
|
14799
15322
|
function consolidateCodingMemoryFile() {
|
|
14800
15323
|
const p = memoryPath2();
|
|
14801
|
-
if (!
|
|
15324
|
+
if (!fs36.existsSync(p)) {
|
|
14802
15325
|
return { success: true, removedDuplicates: 0, message: "no coding_memory.json" };
|
|
14803
15326
|
}
|
|
14804
15327
|
const bak = `${p}.bak`;
|
|
14805
15328
|
try {
|
|
14806
|
-
|
|
15329
|
+
fs36.copyFileSync(p, bak);
|
|
14807
15330
|
} catch (e) {
|
|
14808
15331
|
return { success: false, removedDuplicates: 0, message: `backup failed: ${e.message}` };
|
|
14809
15332
|
}
|
|
14810
15333
|
let data;
|
|
14811
15334
|
try {
|
|
14812
|
-
data = JSON.parse(
|
|
15335
|
+
data = JSON.parse(fs36.readFileSync(p, "utf-8"));
|
|
14813
15336
|
} catch (e) {
|
|
14814
15337
|
return { success: false, removedDuplicates: 0, message: `invalid json: ${e.message}` };
|
|
14815
15338
|
}
|
|
@@ -14844,7 +15367,7 @@ function consolidateCodingMemoryFile() {
|
|
|
14844
15367
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
14845
15368
|
};
|
|
14846
15369
|
try {
|
|
14847
|
-
|
|
15370
|
+
fs36.writeFileSync(p, JSON.stringify(out, null, 2), "utf-8");
|
|
14848
15371
|
} catch (e) {
|
|
14849
15372
|
return { success: false, removedDuplicates: 0, message: `write failed: ${e.message}` };
|
|
14850
15373
|
}
|
|
@@ -14887,7 +15410,8 @@ function buildTurnStartBackendMessage(params) {
|
|
|
14887
15410
|
type: "turn_start",
|
|
14888
15411
|
turnId: params.turnId,
|
|
14889
15412
|
sessionId: params.sessionId,
|
|
14890
|
-
userPromptPreview: buildUserPromptPreview(params.inputText)
|
|
15413
|
+
userPromptPreview: buildUserPromptPreview(params.inputText),
|
|
15414
|
+
appContext: params.appContext ?? null
|
|
14891
15415
|
};
|
|
14892
15416
|
}
|
|
14893
15417
|
|
|
@@ -15069,7 +15593,8 @@ var BluMaAgent = class {
|
|
|
15069
15593
|
buildTurnStartBackendMessage({
|
|
15070
15594
|
turnId: this.activeTurnContext.turnId,
|
|
15071
15595
|
sessionId: this.activeTurnContext.sessionId,
|
|
15072
|
-
inputText
|
|
15596
|
+
inputText,
|
|
15597
|
+
appContext: this.activeTurnContext.appContext ?? null
|
|
15073
15598
|
})
|
|
15074
15599
|
);
|
|
15075
15600
|
if (inputText === "/init") {
|
|
@@ -15449,7 +15974,7 @@ var BluMaAgent = class {
|
|
|
15449
15974
|
|
|
15450
15975
|
${editData.error.display}`;
|
|
15451
15976
|
}
|
|
15452
|
-
const filename =
|
|
15977
|
+
const filename = path39.basename(toolArgs.file_path);
|
|
15453
15978
|
return createDiff(filename, editData.currentContent || "", editData.newContent);
|
|
15454
15979
|
} catch (e) {
|
|
15455
15980
|
return `An unexpected error occurred while generating the edit preview: ${e.message}`;
|
|
@@ -16425,16 +16950,16 @@ async function fullCompact(messages, targetTokens, summarizer, llmClient) {
|
|
|
16425
16950
|
}
|
|
16426
16951
|
|
|
16427
16952
|
// src/app/agent/core/memory/session_memory.ts
|
|
16428
|
-
import
|
|
16953
|
+
import fs37 from "fs";
|
|
16429
16954
|
import os27 from "os";
|
|
16430
|
-
import
|
|
16955
|
+
import path40 from "path";
|
|
16431
16956
|
import { v4 as uuidv49 } from "uuid";
|
|
16432
16957
|
var SessionMemoryExtractor = class {
|
|
16433
16958
|
llmClient;
|
|
16434
16959
|
memoryFile;
|
|
16435
16960
|
constructor(options = {}) {
|
|
16436
16961
|
this.llmClient = options.llmClient;
|
|
16437
|
-
this.memoryFile = options.memoryFile ||
|
|
16962
|
+
this.memoryFile = options.memoryFile || path40.join(os27.homedir(), ".bluma", "session_memory.json");
|
|
16438
16963
|
}
|
|
16439
16964
|
/**
|
|
16440
16965
|
* Extract memories from conversation using LLM
|
|
@@ -16491,15 +17016,15 @@ ${messages.slice(-50).map((m) => `${m.role}: ${m.content.slice(0, 500)}`).join("
|
|
|
16491
17016
|
);
|
|
16492
17017
|
unique.sort((a, b) => b.accessCount - a.accessCount);
|
|
16493
17018
|
const trimmed = unique.slice(0, 200);
|
|
16494
|
-
|
|
17019
|
+
fs37.writeFileSync(this.memoryFile, JSON.stringify(trimmed, null, 2));
|
|
16495
17020
|
}
|
|
16496
17021
|
/**
|
|
16497
17022
|
* Load memories from disk
|
|
16498
17023
|
*/
|
|
16499
17024
|
async loadMemories() {
|
|
16500
17025
|
try {
|
|
16501
|
-
if (!
|
|
16502
|
-
const data =
|
|
17026
|
+
if (!fs37.existsSync(this.memoryFile)) return [];
|
|
17027
|
+
const data = fs37.readFileSync(this.memoryFile, "utf-8");
|
|
16503
17028
|
return JSON.parse(data);
|
|
16504
17029
|
} catch {
|
|
16505
17030
|
return [];
|
|
@@ -17036,14 +17561,14 @@ var RouteManager = class {
|
|
|
17036
17561
|
this.subAgents = subAgents;
|
|
17037
17562
|
this.core = core;
|
|
17038
17563
|
}
|
|
17039
|
-
registerRoute(
|
|
17040
|
-
this.routeHandlers.set(
|
|
17564
|
+
registerRoute(path45, handler) {
|
|
17565
|
+
this.routeHandlers.set(path45, handler);
|
|
17041
17566
|
}
|
|
17042
17567
|
async handleRoute(payload) {
|
|
17043
17568
|
const inputText = String(payload.content || "").trim();
|
|
17044
17569
|
const { userContext } = payload;
|
|
17045
|
-
for (const [
|
|
17046
|
-
if (inputText ===
|
|
17570
|
+
for (const [path45, handler] of this.routeHandlers) {
|
|
17571
|
+
if (inputText === path45 || inputText.startsWith(`${path45} `)) {
|
|
17047
17572
|
return handler({ content: inputText, userContext });
|
|
17048
17573
|
}
|
|
17049
17574
|
}
|
|
@@ -17052,13 +17577,13 @@ var RouteManager = class {
|
|
|
17052
17577
|
};
|
|
17053
17578
|
|
|
17054
17579
|
// src/app/agent/runtime/plugin_runtime.ts
|
|
17055
|
-
import
|
|
17580
|
+
import path41 from "path";
|
|
17056
17581
|
import { pathToFileURL as pathToFileURL2 } from "url";
|
|
17057
17582
|
async function loadPluginsAtStartup() {
|
|
17058
17583
|
for (const p of listPlugins()) {
|
|
17059
17584
|
const entry = p.manifest.entry?.trim();
|
|
17060
17585
|
if (!entry) continue;
|
|
17061
|
-
const abs =
|
|
17586
|
+
const abs = path41.resolve(p.root, entry);
|
|
17062
17587
|
try {
|
|
17063
17588
|
const href = pathToFileURL2(abs).href;
|
|
17064
17589
|
const mod = await import(href);
|
|
@@ -17079,7 +17604,7 @@ async function loadPluginsAtStartup() {
|
|
|
17079
17604
|
}
|
|
17080
17605
|
|
|
17081
17606
|
// src/app/agent/agent.ts
|
|
17082
|
-
var globalEnvPath =
|
|
17607
|
+
var globalEnvPath = path42.join(os28.homedir(), ".bluma", ".env");
|
|
17083
17608
|
dotenv.config({ path: globalEnvPath });
|
|
17084
17609
|
var Agent = class {
|
|
17085
17610
|
sessionId;
|
|
@@ -17091,9 +17616,11 @@ var Agent = class {
|
|
|
17091
17616
|
core;
|
|
17092
17617
|
subAgents;
|
|
17093
17618
|
toolInvoker;
|
|
17619
|
+
factorAiAppContext;
|
|
17094
17620
|
constructor(sessionId, eventBus) {
|
|
17095
17621
|
this.sessionId = sessionId;
|
|
17096
17622
|
this.eventBus = eventBus;
|
|
17623
|
+
this.factorAiAppContext = loadFactorAiAppContext();
|
|
17097
17624
|
const nativeToolInvoker = new ToolInvoker();
|
|
17098
17625
|
this.toolInvoker = nativeToolInvoker;
|
|
17099
17626
|
this.mcpClient = new MCPClient(nativeToolInvoker, eventBus);
|
|
@@ -17209,6 +17736,9 @@ var Agent = class {
|
|
|
17209
17736
|
async processTurn(userInput, userContextInput) {
|
|
17210
17737
|
const inputText = String(userInput.content || "").trim();
|
|
17211
17738
|
const resolvedUserContext = userContextInput ?? defaultInteractiveCliUserContextInput(this.sessionId, inputText.slice(0, 300));
|
|
17739
|
+
if (this.factorAiAppContext && !resolvedUserContext.appContext) {
|
|
17740
|
+
resolvedUserContext.appContext = this.factorAiAppContext;
|
|
17741
|
+
}
|
|
17212
17742
|
if (inputText === "/init" || inputText.startsWith("/init ")) {
|
|
17213
17743
|
this.routeManager.registerRoute("/init", this.dispatchToSubAgent);
|
|
17214
17744
|
}
|
|
@@ -21660,16 +22190,16 @@ import latestVersion from "latest-version";
|
|
|
21660
22190
|
import semverGt from "semver/functions/gt.js";
|
|
21661
22191
|
import semverValid from "semver/functions/valid.js";
|
|
21662
22192
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
21663
|
-
import
|
|
21664
|
-
import
|
|
22193
|
+
import path43 from "path";
|
|
22194
|
+
import fs38 from "fs";
|
|
21665
22195
|
var BLUMA_PACKAGE_NAME = "@nomad-e/bluma-cli";
|
|
21666
22196
|
function findBlumaPackageJson(startDir) {
|
|
21667
22197
|
let dir = startDir;
|
|
21668
22198
|
for (let i = 0; i < 12; i++) {
|
|
21669
|
-
const candidate =
|
|
21670
|
-
if (
|
|
22199
|
+
const candidate = path43.join(dir, "package.json");
|
|
22200
|
+
if (fs38.existsSync(candidate)) {
|
|
21671
22201
|
try {
|
|
21672
|
-
const raw =
|
|
22202
|
+
const raw = fs38.readFileSync(candidate, "utf8");
|
|
21673
22203
|
const parsed = JSON.parse(raw);
|
|
21674
22204
|
if (parsed?.name === BLUMA_PACKAGE_NAME && parsed?.version) {
|
|
21675
22205
|
return { name: parsed.name, version: String(parsed.version) };
|
|
@@ -21677,7 +22207,7 @@ function findBlumaPackageJson(startDir) {
|
|
|
21677
22207
|
} catch {
|
|
21678
22208
|
}
|
|
21679
22209
|
}
|
|
21680
|
-
const parent =
|
|
22210
|
+
const parent = path43.dirname(dir);
|
|
21681
22211
|
if (parent === dir) break;
|
|
21682
22212
|
dir = parent;
|
|
21683
22213
|
}
|
|
@@ -21686,13 +22216,13 @@ function findBlumaPackageJson(startDir) {
|
|
|
21686
22216
|
function resolveInstalledBlumaPackage() {
|
|
21687
22217
|
const tried = /* @__PURE__ */ new Set();
|
|
21688
22218
|
const tryFrom = (dir) => {
|
|
21689
|
-
const abs =
|
|
22219
|
+
const abs = path43.resolve(dir);
|
|
21690
22220
|
if (tried.has(abs)) return null;
|
|
21691
22221
|
tried.add(abs);
|
|
21692
22222
|
return findBlumaPackageJson(abs);
|
|
21693
22223
|
};
|
|
21694
22224
|
try {
|
|
21695
|
-
const fromBundle = tryFrom(
|
|
22225
|
+
const fromBundle = tryFrom(path43.dirname(fileURLToPath5(import.meta.url)));
|
|
21696
22226
|
if (fromBundle) return fromBundle;
|
|
21697
22227
|
} catch {
|
|
21698
22228
|
}
|
|
@@ -21700,12 +22230,12 @@ function resolveInstalledBlumaPackage() {
|
|
|
21700
22230
|
if (argv1 && !argv1.startsWith("-")) {
|
|
21701
22231
|
try {
|
|
21702
22232
|
let resolved = argv1;
|
|
21703
|
-
if (
|
|
21704
|
-
resolved =
|
|
22233
|
+
if (path43.isAbsolute(argv1) && fs38.existsSync(argv1)) {
|
|
22234
|
+
resolved = fs38.realpathSync(argv1);
|
|
21705
22235
|
} else {
|
|
21706
|
-
resolved =
|
|
22236
|
+
resolved = path43.resolve(process.cwd(), argv1);
|
|
21707
22237
|
}
|
|
21708
|
-
const fromArgv = tryFrom(
|
|
22238
|
+
const fromArgv = tryFrom(path43.dirname(resolved));
|
|
21709
22239
|
if (fromArgv) return fromArgv;
|
|
21710
22240
|
} catch {
|
|
21711
22241
|
}
|
|
@@ -23442,9 +23972,9 @@ async function runAgentMode() {
|
|
|
23442
23972
|
try {
|
|
23443
23973
|
if (inputFileIndex !== -1 && args[inputFileIndex + 1]) {
|
|
23444
23974
|
const filePath = args[inputFileIndex + 1];
|
|
23445
|
-
rawPayload =
|
|
23975
|
+
rawPayload = fs39.readFileSync(filePath, "utf-8");
|
|
23446
23976
|
} else {
|
|
23447
|
-
rawPayload =
|
|
23977
|
+
rawPayload = fs39.readFileSync(0, "utf-8");
|
|
23448
23978
|
}
|
|
23449
23979
|
} catch (err) {
|
|
23450
23980
|
writeAgentEvent(registrySessionId, {
|
|
@@ -23642,9 +24172,9 @@ async function runAgentMode() {
|
|
|
23642
24172
|
}
|
|
23643
24173
|
function readCliPackageVersion() {
|
|
23644
24174
|
try {
|
|
23645
|
-
const base =
|
|
23646
|
-
const pkgPath =
|
|
23647
|
-
const j = JSON.parse(
|
|
24175
|
+
const base = path44.dirname(fileURLToPath6(import.meta.url));
|
|
24176
|
+
const pkgPath = path44.join(base, "..", "package.json");
|
|
24177
|
+
const j = JSON.parse(fs39.readFileSync(pkgPath, "utf8"));
|
|
23648
24178
|
return String(j.version || "0.0.0");
|
|
23649
24179
|
} catch {
|
|
23650
24180
|
return "0.0.0";
|
|
@@ -23767,7 +24297,7 @@ function startBackgroundAgent() {
|
|
|
23767
24297
|
process.exit(1);
|
|
23768
24298
|
}
|
|
23769
24299
|
const filePath = args[inputFileIndex + 1];
|
|
23770
|
-
const rawPayload =
|
|
24300
|
+
const rawPayload = fs39.readFileSync(filePath, "utf-8");
|
|
23771
24301
|
const envelope = JSON.parse(rawPayload);
|
|
23772
24302
|
const sessionId = envelope.session_id || envelope.message_id || uuidv412();
|
|
23773
24303
|
registerSession({
|