@nomad-e/bluma-cli 0.11.2 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/main.js CHANGED
@@ -2684,11 +2684,11 @@ var NodeFsOperations = {
2684
2684
  if (fd) fs.closeSync(fd);
2685
2685
  }
2686
2686
  },
2687
- appendFileSync(path57, data, options) {
2688
- const _ = slowLogging`fs.appendFileSync(${path57}, ${data.length} chars)`;
2687
+ appendFileSync(path58, data, options) {
2688
+ const _ = slowLogging`fs.appendFileSync(${path58}, ${data.length} chars)`;
2689
2689
  if (options?.mode !== void 0) {
2690
2690
  try {
2691
- const fd = fs.openSync(path57, "ax", options.mode);
2691
+ const fd = fs.openSync(path58, "ax", options.mode);
2692
2692
  try {
2693
2693
  fs.appendFileSync(fd, data);
2694
2694
  } finally {
@@ -2699,35 +2699,35 @@ var NodeFsOperations = {
2699
2699
  if (getErrnoCode(e) !== "EEXIST") throw e;
2700
2700
  }
2701
2701
  }
2702
- fs.appendFileSync(path57, data);
2702
+ fs.appendFileSync(path58, data);
2703
2703
  },
2704
2704
  copyFileSync(src, dest) {
2705
2705
  const _ = slowLogging`fs.copyFileSync(${src} → ${dest})`;
2706
2706
  fs.copyFileSync(src, dest);
2707
2707
  },
2708
- unlinkSync(path57) {
2709
- const _ = slowLogging`fs.unlinkSync(${path57})`;
2710
- fs.unlinkSync(path57);
2708
+ unlinkSync(path58) {
2709
+ const _ = slowLogging`fs.unlinkSync(${path58})`;
2710
+ fs.unlinkSync(path58);
2711
2711
  },
2712
2712
  renameSync(oldPath, newPath) {
2713
2713
  const _ = slowLogging`fs.renameSync(${oldPath} → ${newPath})`;
2714
2714
  fs.renameSync(oldPath, newPath);
2715
2715
  },
2716
- linkSync(target, path57) {
2717
- const _ = slowLogging`fs.linkSync(${target} → ${path57})`;
2718
- fs.linkSync(target, path57);
2716
+ linkSync(target, path58) {
2717
+ const _ = slowLogging`fs.linkSync(${target} → ${path58})`;
2718
+ fs.linkSync(target, path58);
2719
2719
  },
2720
- symlinkSync(target, path57, type) {
2721
- const _ = slowLogging`fs.symlinkSync(${target} → ${path57})`;
2722
- fs.symlinkSync(target, path57, type);
2720
+ symlinkSync(target, path58, type) {
2721
+ const _ = slowLogging`fs.symlinkSync(${target} → ${path58})`;
2722
+ fs.symlinkSync(target, path58, type);
2723
2723
  },
2724
- readlinkSync(path57) {
2725
- const _ = slowLogging`fs.readlinkSync(${path57})`;
2726
- return fs.readlinkSync(path57);
2724
+ readlinkSync(path58) {
2725
+ const _ = slowLogging`fs.readlinkSync(${path58})`;
2726
+ return fs.readlinkSync(path58);
2727
2727
  },
2728
- realpathSync(path57) {
2729
- const _ = slowLogging`fs.realpathSync(${path57})`;
2730
- return fs.realpathSync(path57).normalize("NFC");
2728
+ realpathSync(path58) {
2729
+ const _ = slowLogging`fs.realpathSync(${path58})`;
2730
+ return fs.realpathSync(path58).normalize("NFC");
2731
2731
  },
2732
2732
  mkdirSync(dirPath, options) {
2733
2733
  const _ = slowLogging`fs.mkdirSync(${dirPath})`;
@@ -2760,12 +2760,12 @@ var NodeFsOperations = {
2760
2760
  const _ = slowLogging`fs.rmdirSync(${dirPath})`;
2761
2761
  fs.rmdirSync(dirPath);
2762
2762
  },
2763
- rmSync(path57, options) {
2764
- const _ = slowLogging`fs.rmSync(${path57})`;
2765
- fs.rmSync(path57, options);
2763
+ rmSync(path58, options) {
2764
+ const _ = slowLogging`fs.rmSync(${path58})`;
2765
+ fs.rmSync(path58, options);
2766
2766
  },
2767
- createWriteStream(path57) {
2768
- return fs.createWriteStream(path57);
2767
+ createWriteStream(path58) {
2768
+ return fs.createWriteStream(path58);
2769
2769
  },
2770
2770
  async readFileBytes(fsPath, maxBytes) {
2771
2771
  if (maxBytes === void 0) {
@@ -2872,12 +2872,12 @@ function shouldLogDebugMessage(message2) {
2872
2872
  var hasFormattedOutput = false;
2873
2873
  var debugWriter = null;
2874
2874
  var pendingWrite = Promise.resolve();
2875
- async function appendAsync(needMkdir, dir, path57, content) {
2875
+ async function appendAsync(needMkdir, dir, path58, content) {
2876
2876
  if (needMkdir) {
2877
2877
  await mkdir(dir, { recursive: true }).catch(() => {
2878
2878
  });
2879
2879
  }
2880
- await appendFile(path57, content);
2880
+ await appendFile(path58, content);
2881
2881
  void updateLatestDebugLogSymlink();
2882
2882
  }
2883
2883
  function noop() {
@@ -2887,8 +2887,8 @@ function getDebugWriter() {
2887
2887
  let ensuredDir = null;
2888
2888
  debugWriter = createBufferedWriter({
2889
2889
  writeFn: (content) => {
2890
- const path57 = getDebugLogPath();
2891
- const dir = dirname(path57);
2890
+ const path58 = getDebugLogPath();
2891
+ const dir = dirname(path58);
2892
2892
  const needMkdir = ensuredDir !== dir;
2893
2893
  ensuredDir = dir;
2894
2894
  if (isDebugMode()) {
@@ -2898,11 +2898,11 @@ function getDebugWriter() {
2898
2898
  } catch {
2899
2899
  }
2900
2900
  }
2901
- getFsImplementation().appendFileSync(path57, content);
2901
+ getFsImplementation().appendFileSync(path58, content);
2902
2902
  void updateLatestDebugLogSymlink();
2903
2903
  return;
2904
2904
  }
2905
- pendingWrite = pendingWrite.then(appendAsync.bind(null, needMkdir, dir, path57, content)).catch(noop);
2905
+ pendingWrite = pendingWrite.then(appendAsync.bind(null, needMkdir, dir, path58, content)).catch(noop);
2906
2906
  },
2907
2907
  flushIntervalMs: 1e3,
2908
2908
  maxBufferSize: 100,
@@ -9089,8 +9089,8 @@ import codeExcerpt from "code-excerpt";
9089
9089
  import { readFileSync as readFileSync2 } from "fs";
9090
9090
  import StackUtils from "stack-utils";
9091
9091
  import { jsx as jsx6, jsxs } from "react/jsx-runtime";
9092
- var cleanupPath = (path57) => {
9093
- return path57?.replace(`file://${process.cwd()}/`, "");
9092
+ var cleanupPath = (path58) => {
9093
+ return path58?.replace(`file://${process.cwd()}/`, "");
9094
9094
  };
9095
9095
  var stackUtils;
9096
9096
  function getStackUtils() {
@@ -13067,9 +13067,9 @@ var getInstance = (stdout, createInstance) => {
13067
13067
 
13068
13068
  // src/main.ts
13069
13069
  import { EventEmitter as EventEmitter7 } from "events";
13070
- import fs50 from "fs";
13071
- import path56 from "path";
13072
- import { fileURLToPath as fileURLToPath7 } from "url";
13070
+ import fs51 from "fs";
13071
+ import path57 from "path";
13072
+ import { fileURLToPath as fileURLToPath8 } from "url";
13073
13073
  import { spawn as spawn6 } from "child_process";
13074
13074
  import { v4 as uuidv412 } from "uuid";
13075
13075
  import chalk3 from "chalk";
@@ -13962,13 +13962,13 @@ function cancelSlashSubmenu() {
13962
13962
 
13963
13963
  // src/app/agent/agent.ts
13964
13964
  import * as dotenv from "dotenv";
13965
- import path47 from "path";
13965
+ import path48 from "path";
13966
13966
  import os30 from "os";
13967
13967
 
13968
13968
  // src/app/agent/tool_invoker.ts
13969
- import { promises as fs25 } from "fs";
13970
- import path28 from "path";
13971
- import { fileURLToPath } from "url";
13969
+ import { promises as fs26 } from "fs";
13970
+ import path29 from "path";
13971
+ import { fileURLToPath as fileURLToPath2 } from "url";
13972
13972
 
13973
13973
  // src/app/agent/tools/EditTool/EditTool.ts
13974
13974
  init_sandbox_policy();
@@ -18664,8 +18664,9 @@ async function context_collapse(args = {}) {
18664
18664
 
18665
18665
  // src/app/agent/tools/CreateNextAppTool/CreateNextAppTool.ts
18666
18666
  init_sandbox_policy();
18667
- import { promises as fs23 } from "fs";
18668
- import path25 from "path";
18667
+ import { promises as fs24 } from "fs";
18668
+ import path26 from "path";
18669
+ import { fileURLToPath } from "url";
18669
18670
 
18670
18671
  // src/app/agent/tools/ShellCommandTool/ShellCommandTool.ts
18671
18672
  init_sandbox_policy();
@@ -18966,516 +18967,271 @@ function formatResult(result, verbose) {
18966
18967
  return JSON.stringify(output, null, 2);
18967
18968
  }
18968
18969
 
18969
- // src/app/agent/tools/CreateNextAppTool/CreateNextAppTool.ts
18970
- var MINIMAL_FILES = {
18971
- "package.json": `{
18972
- "name": "{{NAME}}",
18973
- "version": "0.1.0",
18974
- "private": true,
18975
- "scripts": {
18976
- "dev": "next dev",
18977
- "build": "next build",
18978
- "start": "next start",
18979
- "lint": "next lint"
18980
- },
18981
- "dependencies": {
18982
- "next": "^14.1.0",
18983
- "react": "^18.2.0",
18984
- "react-dom": "^18.2.0"
18985
- },
18986
- "devDependencies": {
18987
- "@types/node": "^20.11.0",
18988
- "@types/react": "^18.2.0",
18989
- "@types/react-dom": "^18.2.0",
18990
- "typescript": "^5.3.0",
18991
- "tailwindcss": "^3.4.0",
18992
- "postcss": "^8.4.0",
18993
- "autoprefixer": "^10.4.0",
18994
- "eslint": "^8.56.0",
18995
- "eslint-config-next": "^14.1.0"
18996
- }
18997
- }
18998
- `,
18999
- "tsconfig.json": `{
19000
- "compilerOptions": {
19001
- "lib": ["dom", "dom.iterable", "esnext"],
19002
- "allowJs": true,
19003
- "skipLibCheck": true,
19004
- "strict": true,
19005
- "noEmit": true,
19006
- "esModuleInterop": true,
19007
- "module": "esnext",
19008
- "moduleResolution": "bundler",
19009
- "resolveJsonModule": true,
19010
- "isolatedModules": true,
19011
- "jsx": "preserve",
19012
- "incremental": true,
19013
- "plugins": [
19014
- {
19015
- "name": "next"
19016
- }
19017
- ],
19018
- "paths": {
19019
- "@/*": ["./*"]
18970
+ // src/app/agent/tools/CreateNextAppTool/scaffold_agent_guide.ts
18971
+ import { promises as fs23 } from "fs";
18972
+ import path25 from "path";
18973
+ var DESIGN_DOC_FILENAME = "DESIGN.md";
18974
+ var UI_GROUPS = {
18975
+ "Actions & inputs": [
18976
+ "button",
18977
+ "input",
18978
+ "textarea",
18979
+ "checkbox",
18980
+ "radio-group",
18981
+ "switch",
18982
+ "slider",
18983
+ "select",
18984
+ "input-otp",
18985
+ "form",
18986
+ "label"
18987
+ ],
18988
+ "Layout & navigation": [
18989
+ "card",
18990
+ "separator",
18991
+ "tabs",
18992
+ "accordion",
18993
+ "collapsible",
18994
+ "breadcrumb",
18995
+ "navigation-menu",
18996
+ "menubar",
18997
+ "pagination",
18998
+ "resizable",
18999
+ "scroll-area",
19000
+ "aspect-ratio"
19001
+ ],
19002
+ "Overlays & feedback": [
19003
+ "dialog",
19004
+ "alert-dialog",
19005
+ "sheet",
19006
+ "drawer",
19007
+ "popover",
19008
+ "hover-card",
19009
+ "tooltip",
19010
+ "alert",
19011
+ "toast",
19012
+ "toaster",
19013
+ "sonner",
19014
+ "progress",
19015
+ "skeleton"
19016
+ ],
19017
+ "Data & media": [
19018
+ "table",
19019
+ "chart",
19020
+ "calendar",
19021
+ "carousel",
19022
+ "avatar",
19023
+ "badge",
19024
+ "command",
19025
+ "context-menu",
19026
+ "dropdown-menu"
19027
+ ]
19028
+ };
19029
+ async function listUiComponents(projectPath) {
19030
+ const uiDir = path25.join(projectPath, "components", "ui");
19031
+ try {
19032
+ const entries = await fs23.readdir(uiDir);
19033
+ return entries.filter((f) => f.endsWith(".jsx") || f.endsWith(".tsx")).map((f) => f.replace(/\.(jsx|tsx)$/, "")).sort();
19034
+ } catch {
19035
+ return [];
19036
+ }
19037
+ }
19038
+ function hslTokenRows() {
19039
+ return [
19040
+ { name: "Canvas", varName: "--background", role: "Page background (`bg-background`)" },
19041
+ { name: "Frost", varName: "--foreground", role: "Primary text (`text-foreground`)" },
19042
+ { name: "Card", varName: "--card", role: "Elevated panels (`bg-card`, `text-card-foreground`)" },
19043
+ { name: "Muted", varName: "--muted", role: "Secondary surfaces (`bg-muted`, `text-muted-foreground`)" },
19044
+ { name: "Primary", varName: "--primary", role: "Primary actions (`bg-primary`, `text-primary-foreground`)" },
19045
+ { name: "Accent", varName: "--accent", role: "Hover states (`bg-accent`, `text-accent-foreground`)" },
19046
+ { name: "Border", varName: "--border", role: "Dividers and outlines (`border-border`)" },
19047
+ { name: "Ring", varName: "--ring", role: "Focus rings (`ring-ring`)" },
19048
+ { name: "Destructive", varName: "--destructive", role: "Errors and destructive actions" }
19049
+ ];
19050
+ }
19051
+ function componentInventoryMarkdown(components) {
19052
+ const lines = [];
19053
+ for (const [group, names] of Object.entries(UI_GROUPS)) {
19054
+ const present = names.filter((n) => components.includes(n));
19055
+ if (present.length === 0) continue;
19056
+ lines.push(`### ${group}`);
19057
+ for (const n of present) {
19058
+ lines.push(`- \`@/components/ui/${n}\` \u2014 \`${toPascal(n)}\``);
19020
19059
  }
19021
- },
19022
- "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
19023
- "exclude": ["node_modules"]
19060
+ lines.push("");
19061
+ }
19062
+ const uncategorized = components.filter(
19063
+ (c) => !Object.values(UI_GROUPS).flat().includes(c)
19064
+ );
19065
+ if (uncategorized.length > 0) {
19066
+ lines.push("### Other");
19067
+ for (const n of uncategorized) {
19068
+ lines.push(`- \`@/components/ui/${n}\``);
19069
+ }
19070
+ lines.push("");
19071
+ }
19072
+ return lines.join("\n");
19024
19073
  }
19025
- `,
19026
- "next.config.js": `/** @type {import('next').NextConfig} */
19027
- const nextConfig = {
19028
- output: 'standalone',
19029
- reactStrictMode: true,
19074
+ function toPascal(slug) {
19075
+ return slug.split("-").map((p) => p.charAt(0).toUpperCase() + p.slice(1)).join("");
19030
19076
  }
19077
+ async function buildScaffoldAgentGuide(projectName, projectPath) {
19078
+ const uiComponents = await listUiComponents(projectPath);
19079
+ const uiCount = uiComponents.length;
19080
+ const tokenTable = hslTokenRows().map((t) => `| ${t.name} | \`hsl(var(${t.varName}))\` | ${t.role} |`).join("\n");
19081
+ const markdown = `# ${projectName} \u2014 FactorAI App Scaffold
19031
19082
 
19032
- module.exports = nextConfig
19033
- `,
19034
- "tailwind.config.ts": `import type { Config } from 'tailwindcss'
19083
+ > Dark command-center aesthetic: near-black canvas, high-contrast type, restrained accents. Default home is a **Refero-style landing** (hero, feature cards, nav) \u2014 customize \`app/page.tsx\` for your product.
19035
19084
 
19036
- const config: Config = {
19037
- content: [
19038
- './pages/**/*.{js,ts,jsx,tsx,mdx}',
19039
- './components/**/*.{js,ts,jsx,tsx,mdx}',
19040
- './app/**/*.{js,ts,jsx,tsx,mdx}',
19041
- ],
19042
- theme: {
19043
- extend: {
19044
- backgroundImage: {
19045
- 'gradient-radial': 'radial-gradient(var(--tw-gradient-stops))',
19046
- 'gradient-conic':
19047
- 'conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))',
19048
- },
19049
- },
19050
- },
19051
- plugins: [],
19052
- }
19053
- export default config
19054
- `,
19055
- "postcss.config.js": `module.exports = {
19056
- plugins: {
19057
- tailwindcss: {},
19058
- autoprefixer: {},
19059
- },
19060
- }
19061
- `,
19062
- ".eslintrc.json": `{
19063
- "extends": "next/core-web-vitals"
19064
- }
19065
- `,
19066
- ".gitignore": `# dependencies
19067
- /node_modules
19068
- /.pnp
19069
- .pnp.js
19085
+ **Theme:** dark
19086
+ **Stack:** Next.js 14 App Router \xB7 \`output: 'standalone'\` (FactorAI deploy) \xB7 Tailwind 3 \xB7 shadcn/ui (${uiCount} components)
19087
+ **Path alias:** \`@/*\` \u2192 project root
19070
19088
 
19071
- # testing
19072
- /coverage
19089
+ ---
19073
19090
 
19074
- # next.js
19075
- /.next/
19076
- /out/
19091
+ ## Architecture
19077
19092
 
19078
- # production
19079
- /build
19093
+ | Area | Path | Notes |
19094
+ |------|------|-------|
19095
+ | Home (starter UI) | \`app/page.tsx\` | Dark landing: hero glow, badge, CTAs, 3 feature cards, footer |
19096
+ | Root layout | \`app/layout.tsx\` | Metadata title = project name |
19097
+ | Global styles | \`app/globals.css\` | shadcn HSL tokens (see below) |
19098
+ | UI kit | \`components/ui/*\` | Same set as factorai.sh \u2014 import, do not recreate |
19099
+ | Utilities | \`lib/utils.ts\` | \`cn()\` for class merging |
19100
+ | Toasts | \`hooks/use-toast.ts\` | Pair with \`components/ui/toaster\` or \`sonner\` |
19101
+ | Config | \`next.config.js\`, \`tailwind.config.ts\` | Standalone build required for hosting |
19080
19102
 
19081
- # misc
19082
- .DS_Store
19083
- *.pem
19103
+ ---
19084
19104
 
19085
- # debug
19086
- npm-debug.log*
19087
- yarn-debug.log*
19088
- yarn-error.log*
19105
+ ## Tokens \u2014 Colors
19089
19106
 
19090
- # local env files
19091
- .env*.local
19092
- .env
19107
+ | Name | Value | Role |
19108
+ |------|-------|------|
19109
+ ${tokenTable}
19093
19110
 
19094
- # typescript
19095
- *.tsbuildinfo
19096
- next-env.d.ts
19097
- `,
19098
- // App Router mínimo (obrigatório para next build / deploy no Severino)
19099
- "app/layout.tsx": `import type { Metadata } from 'next';
19100
- import './globals.css';
19111
+ Use Tailwind semantic classes (\`bg-background\`, \`text-muted-foreground\`, \`border-border\`) \u2014 not raw hex in JSX unless defining a one-off gradient.
19101
19112
 
19102
- export const metadata: Metadata = {
19103
- title: '{{NAME}}',
19104
- description: 'Generated by create-next-app',
19105
- };
19113
+ ---
19106
19114
 
19107
- export default function RootLayout({
19108
- children,
19109
- }: Readonly<{
19110
- children: React.ReactNode;
19111
- }>) {
19112
- return (
19113
- <html lang="en">
19114
- <body>{children}</body>
19115
- </html>
19116
- );
19117
- }
19118
- `,
19119
- "app/page.tsx": `export default function Home() {
19120
- return (
19121
- <main className="flex min-h-screen flex-col items-center justify-center p-8">
19122
- <h1 className="text-2xl font-semibold">{{NAME}}</h1>
19123
- <p className="mt-2 text-sm text-gray-600">Next.js app ready for deploy.</p>
19124
- </main>
19125
- );
19126
- }
19127
- `,
19128
- "app/globals.css": `@tailwind base;
19129
- @tailwind components;
19130
- @tailwind utilities;
19131
- `
19132
- };
19133
- var FULL_FILES = {
19134
- ...MINIMAL_FILES,
19135
- // App Router structure
19136
- "app/layout.tsx": `import type { Metadata } from "next";
19137
- import { Inter } from "next/font/google";
19138
- import "./globals.css";
19139
-
19140
- const inter = Inter({ subsets: ["latin"] });
19141
-
19142
- export const metadata: Metadata = {
19143
- title: "{{NAME}}",
19144
- description: "Generated by create-next-app",
19145
- };
19115
+ ## Tokens \u2014 Typography & spacing
19146
19116
 
19147
- export default function RootLayout({
19148
- children,
19149
- }: Readonly<{
19150
- children: React.ReactNode;
19151
- }>) {
19152
- return (
19153
- <html lang="en">
19154
- <body className={inter.className}>{children}</body>
19155
- </html>
19156
- );
19157
- }
19158
- `,
19159
- "app/page.tsx": `export default function Home() {
19160
- return (
19161
- <main className="flex min-h-screen flex-col items-center justify-between p-24">
19162
- <div className="z-10 w-full max-w-5xl items-center justify-between font-mono text-sm lg:flex">
19163
- <p className="fixed left-0 top-0 flex w-full justify-center border-b border-gray-300 bg-gradient-to-b from-zinc-200 pb-6 pt-8 backdrop-blur-2xl dark:border-neutral-800 dark:bg-zinc-800/30 dark:from-inherit lg:static lg:w-auto lg:rounded-xl lg:border lg:bg-gray-200 lg:p-4 lg:dark:bg-zinc-800/30">
19164
- Welcome to <code className="font-mono font-bold">{{NAME}}</code>
19165
- </p>
19166
- </div>
19167
-
19168
- <div className="mb-32 grid text-center lg:max-w-5xl lg:w-full lg:mb-0 lg:grid-cols-4 lg:text-left">
19169
- <a
19170
- href="https://nextjs.org/docs"
19171
- className="group rounded-lg border border-transparent px-5 py-4 transition-colors hover:border-gray-300 hover:bg-gray-100 hover:dark:border-neutral-700 hover:dark:bg-neutral-800/30"
19172
- target="_blank"
19173
- rel="noopener noreferrer"
19174
- >
19175
- <h2 className={\`mb-3 text-2xl font-semibold\`}>
19176
- Docs{" "}
19177
- <span className="inline-block transition-transform group-hover:translate-x-1 motion-reduce:transform-none">
19178
- -&gt;
19179
- </span>
19180
- </h2>
19181
- <p className={\`m-0 max-w-[30ch] text-sm opacity-50\`}>
19182
- Find in-depth information about Next.js features and API.
19183
- </p>
19184
- </a>
19185
-
19186
- <a
19187
- href="https://nextjs.org/learn"
19188
- className="group rounded-lg border border-transparent px-5 py-4 transition-colors hover:border-gray-300 hover:bg-gray-100 hover:dark:border-neutral-700 hover:dark:bg-neutral-800/30"
19189
- target="_blank"
19190
- rel="noopener noreferrer"
19191
- >
19192
- <h2 className={\`mb-3 text-2xl font-semibold\`}>
19193
- Learn{" "}
19194
- <span className="inline-block transition-transform group-hover:translate-x-1 motion-reduce:transform-none">
19195
- -&gt;
19196
- </span>
19197
- </h2>
19198
- <p className={\`m-0 max-w-[30ch] text-sm opacity-50\`}>
19199
- Learn about Next.js in an interactive course with&nbsp;quizzes!
19200
- </p>
19201
- </a>
19202
-
19203
- <a
19204
- href="https://vercel.com/templates"
19205
- className="group rounded-lg border border-transparent px-5 py-4 transition-colors hover:border-gray-300 hover:bg-gray-100 hover:dark:border-neutral-700 hover:dark:bg-neutral-800/30"
19206
- target="_blank"
19207
- rel="noopener noreferrer"
19208
- >
19209
- <h2 className={\`mb-3 text-2xl font-semibold\`}>
19210
- Templates{" "}
19211
- <span className="inline-block transition-transform group-hover:translate-x-1 motion-reduce:transform-none">
19212
- -&gt;
19213
- </span>
19214
- </h2>
19215
- <p className={\`m-0 max-w-[30ch] text-sm opacity-50\`}>
19216
- Explore starter templates for Next.js.
19217
- </p>
19218
- </a>
19219
-
19220
- <a
19221
- href="https://vercel.com/new"
19222
- className="group rounded-lg border border-transparent px-5 py-4 transition-colors hover:border-gray-300 hover:bg-gray-100 hover:dark:border-neutral-700 hover:dark:bg-neutral-800/30"
19223
- target="_blank"
19224
- rel="noopener noreferrer"
19225
- >
19226
- <h2 className={\`mb-3 text-2xl font-semibold\`}>
19227
- Deploy{" "}
19228
- <span className="inline-block transition-transform group-hover:translate-x-1 motion-reduce:transform-none">
19229
- -&gt;
19230
- </span>
19231
- </h2>
19232
- <p className={\`m-0 max-w-[30ch] text-sm opacity-50 text-balance\`}>
19233
- Instantly deploy your Next.js site to a shareable URL with Vercel.
19234
- </p>
19235
- </a>
19236
- </div>
19237
- </main>
19238
- );
19239
- }
19240
- `,
19241
- "app/globals.css": `@tailwind base;
19242
- @tailwind components;
19243
- @tailwind utilities;
19117
+ - **Fonts:** system UI stack (add Inter/Geist in \`layout.tsx\` if you want a product-specific voice).
19118
+ - **Scale:** \`text-sm\` body, \`text-lg\`/\`text-xl\` subheads, \`text-3xl\`\u2013\`text-5xl\` hero with \`tracking-tight\`.
19119
+ - **Density:** comfortable \u2014 \`section\` gaps \`py-16\`\u2013\`py-24\`, card padding \`p-6\`, inline gaps \`gap-3\`/\`gap-4\`.
19120
+ - **Radius:** \`--radius: 0.5rem\` \u2014 buttons/inputs \`rounded-md\`, pills \`rounded-full\`.
19244
19121
 
19245
- :root {
19246
- --foreground-rgb: 0, 0, 0;
19247
- --background-start-rgb: 214, 219, 220;
19248
- --background-end-rgb: 255, 255, 255;
19249
- }
19122
+ ---
19250
19123
 
19251
- @media (prefers-color-scheme: dark) {
19252
- :root {
19253
- --foreground-rgb: 255, 255, 255;
19254
- --background-start-rgb: 0, 0, 0;
19255
- --background-end-rgb: 0, 0, 0;
19256
- }
19257
- }
19124
+ ## UI components available (${uiCount})
19258
19125
 
19259
- body {
19260
- color: rgb(var(--foreground-rgb));
19261
- background: linear-gradient(
19262
- to bottom,
19263
- transparent,
19264
- rgb(var(--background-end-rgb))
19265
- )
19266
- rgb(var(--background-start-rgb));
19267
- }
19126
+ Import from \`@/components/ui/<file>\`. Compose with \`cn()\` from \`@/lib/utils\`.
19268
19127
 
19269
- @layer utilities {
19270
- .text-balance {
19271
- text-wrap: balance;
19272
- }
19128
+ ${componentInventoryMarkdown(uiComponents)}
19129
+
19130
+ **Quick import examples:**
19131
+
19132
+ \`\`\`tsx
19133
+ import { Button } from "@/components/ui/button";
19134
+ import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/components/ui/card";
19135
+ import { Input } from "@/components/ui/input";
19136
+ import { Badge } from "@/components/ui/badge";
19137
+ import { Separator } from "@/components/ui/separator";
19138
+ \`\`\`
19139
+
19140
+ ---
19141
+
19142
+ ## Do's and Don'ts (polished interfaces)
19143
+
19144
+ ### Do
19145
+ - Keep **one dominant background** (\`bg-background\`) and **one accent discipline** (primary buttons + ring on focus).
19146
+ - Use **clear hierarchy**: display headline \u2192 subheading (\`text-muted-foreground\`) \u2192 body; max width \`max-w-2xl\` or \`max-w-3xl\` for prose.
19147
+ - Build **sections** with \`py-16 md:py-24\` and centered containers \`mx-auto max-w-6xl px-4 md:px-6\`.
19148
+ - Prefer **Card** for feature groupings; use **ghost/outline** buttons for secondary actions.
19149
+ - Add **generous whitespace**; empty space signals quality (see [Refero Styles](https://styles.refero.design/) references).
19150
+ - Use **Sonner** or **Toast** for async feedback after deploy-worthy flows.
19151
+ - Run \`npm run build\` before deploy; keep standalone output intact.
19152
+
19153
+ ### Don't
19154
+ - Customize the default landing copy and sections for your product before production.
19155
+ - Keep the starter layout patterns (hero glow, pill buttons, card grid) when extending \u2014 do not regress to generic Next.js marketing grids.
19156
+ - Do not invent parallel design systems \u2014 use existing \`components/ui\` tokens.
19157
+ - Do not saturate the UI with many accent colors; stay monochromatic + primary/ destructive only.
19158
+ - Do not use tiny touch targets \u2014 buttons \`h-10\` minimum, adequate \`px-4\`.
19159
+ - Do not add new npm UI libraries without strong reason \u2014 kit is already complete.
19160
+
19161
+ ---
19162
+
19163
+ ## Layout patterns (recommended)
19164
+
19165
+ 1. **Hero:** full-width \`min-h-[80vh]\`, centered headline, single primary CTA, optional subtle gradient \`bg-gradient-to-b from-background to-muted/30\`.
19166
+ 2. **Feature grid:** \`grid md:grid-cols-2 lg:grid-cols-3 gap-6\` of Cards.
19167
+ 3. **Split section:** \`grid lg:grid-cols-2 gap-12 items-center\` text + visual.
19168
+ 4. **Sticky nav:** \`border-b border-border/40 backdrop-blur\` bar with ghost nav + one filled CTA.
19169
+
19170
+ ---
19171
+
19172
+ ## Agent prompt guide (copy into your planning)
19173
+
19174
+ **Quick color reference:** text \`text-foreground\`, background \`bg-background\`, borders \`border-border\`, primary CTA \`bg-primary text-primary-foreground\`.
19175
+
19176
+ **Example prompts for this codebase:**
19177
+
19178
+ 1. *Hero:* \`min-h-screen bg-background flex flex-col items-center justify-center px-6\`. Headline \`text-4xl md:text-6xl font-medium tracking-tight text-foreground\`. Subtext \`text-muted-foreground text-lg mt-4 max-w-xl text-center\`. Primary \`Button\` mt-8.
19179
+ 2. *Feature card:* \`Card\` with \`CardHeader\` + \`CardTitle\` + \`CardDescription\`; \`CardContent\` with short copy; optional \`Badge\` for labels.
19180
+ 3. *Form block:* \`Input\` + \`Label\` in a \`Card\`; submit \`Button\` full width on mobile; inline \`text-sm text-muted-foreground\` helpers.
19181
+
19182
+ For external visual direction, browse dark/productivity references on [Refero Styles](https://styles.refero.design/) (e.g. Linear, xAI, Stripe) \u2014 adapt tokens above, do not copy unrelated fonts wholesale.
19183
+
19184
+ ---
19185
+
19186
+ ## What to do next
19187
+
19188
+ 1. Edit \`app/page.tsx\` (and add routes under \`app/\` as needed).
19189
+ 2. \`npm run dev\` \u2014 preview locally.
19190
+ 3. \`factorai.sh.deploy_app\` when ready \u2014 ZIP excludes \`node_modules\` and \`.next\`.
19191
+
19192
+ ---
19193
+
19194
+ *Generated by BluMa \`factorai.sh.create_next_app\` \xB7 re-read this file at \`${DESIGN_DOC_FILENAME}\` in the project root.*
19195
+ `;
19196
+ return { markdown, uiComponents };
19197
+ }
19198
+ async function writeDesignDoc(projectPath, markdown) {
19199
+ const docPath = path25.join(projectPath, DESIGN_DOC_FILENAME);
19200
+ await fs23.writeFile(docPath, markdown, "utf-8");
19201
+ return docPath;
19273
19202
  }
19274
- `,
19275
- // shadcn/ui base components (sem @radix-ui/react-slot — evita falha de build no deploy)
19276
- "components/ui/button.tsx": `import * as React from "react"
19277
- import { cva, type VariantProps } from "class-variance-authority"
19278
- import { cn } from "@/lib/utils"
19279
19203
 
19280
- const buttonVariants = cva(
19281
- "inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-zinc-400 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
19282
- {
19283
- variants: {
19284
- variant: {
19285
- default: "bg-zinc-900 text-white hover:bg-zinc-800",
19286
- destructive: "bg-red-600 text-white hover:bg-red-700",
19287
- outline: "border border-zinc-200 bg-white hover:bg-zinc-50",
19288
- secondary: "bg-zinc-100 text-zinc-900 hover:bg-zinc-200",
19289
- ghost: "hover:bg-zinc-100",
19290
- link: "text-zinc-900 underline-offset-4 hover:underline",
19291
- },
19292
- size: {
19293
- default: "h-10 px-4 py-2",
19294
- sm: "h-9 rounded-md px-3",
19295
- lg: "h-11 rounded-md px-8",
19296
- icon: "h-10 w-10",
19297
- },
19298
- },
19299
- defaultVariants: {
19300
- variant: "default",
19301
- size: "default",
19302
- },
19303
- }
19304
- )
19305
-
19306
- export interface ButtonProps
19307
- extends React.ButtonHTMLAttributes<HTMLButtonElement>,
19308
- VariantProps<typeof buttonVariants> {}
19309
-
19310
- const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
19311
- ({ className, variant, size, ...props }, ref) => (
19312
- <button
19313
- className={cn(buttonVariants({ variant, size, className }))}
19314
- ref={ref}
19315
- {...props}
19316
- />
19317
- )
19318
- )
19319
- Button.displayName = "Button"
19320
-
19321
- export { Button, buttonVariants }
19322
- `,
19323
- "components/ui/card.tsx": `import * as React from "react"
19324
- import { cn } from "@/lib/utils"
19325
-
19326
- const Card = React.forwardRef<
19327
- HTMLDivElement,
19328
- React.HTMLAttributes<HTMLDivElement>
19329
- >(({ className, ...props }, ref) => (
19330
- <div
19331
- ref={ref}
19332
- className={cn(
19333
- "rounded-lg border border-zinc-200 bg-white text-zinc-950 shadow-sm",
19334
- className
19335
- )}
19336
- {...props}
19337
- />
19338
- ))
19339
- Card.displayName = "Card"
19340
-
19341
- const CardHeader = React.forwardRef<
19342
- HTMLDivElement,
19343
- React.HTMLAttributes<HTMLDivElement>
19344
- >(({ className, ...props }, ref) => (
19345
- <div
19346
- ref={ref}
19347
- className={cn("flex flex-col space-y-1.5 p-6", className)}
19348
- {...props}
19349
- />
19350
- ))
19351
- CardHeader.displayName = "CardHeader"
19352
-
19353
- const CardTitle = React.forwardRef<
19354
- HTMLParagraphElement,
19355
- React.HTMLAttributes<HTMLHeadingElement>
19356
- >(({ className, ...props }, ref) => (
19357
- <h3
19358
- ref={ref}
19359
- className={cn(
19360
- "text-2xl font-semibold leading-none tracking-tight",
19361
- className
19362
- )}
19363
- {...props}
19364
- />
19365
- ))
19366
- CardTitle.displayName = "CardTitle"
19367
-
19368
- const CardDescription = React.forwardRef<
19369
- HTMLParagraphElement,
19370
- React.HTMLAttributes<HTMLParagraphElement>
19371
- >(({ className, ...props }, ref) => (
19372
- <p
19373
- ref={ref}
19374
- className={cn("text-sm text-zinc-500", className)}
19375
- {...props}
19376
- />
19377
- ))
19378
- CardDescription.displayName = "CardDescription"
19379
-
19380
- const CardContent = React.forwardRef<
19381
- HTMLDivElement,
19382
- React.HTMLAttributes<HTMLDivElement>
19383
- >(({ className, ...props }, ref) => (
19384
- <div ref={ref} className={cn("p-6 pt-0", className)} {...props} />
19385
- ))
19386
- CardContent.displayName = "CardContent"
19387
-
19388
- const CardFooter = React.forwardRef<
19389
- HTMLDivElement,
19390
- React.HTMLAttributes<HTMLDivElement>
19391
- >(({ className, ...props }, ref) => (
19392
- <div
19393
- ref={ref}
19394
- className={cn("flex items-center p-6 pt-0", className)}
19395
- {...props}
19396
- />
19397
- ))
19398
- CardFooter.displayName = "CardFooter"
19399
-
19400
- export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent }
19401
- `,
19402
- "components/ui/input.tsx": `import * as React from "react"
19403
- import { cn } from "@/lib/utils"
19404
-
19405
- export interface InputProps
19406
- extends React.InputHTMLAttributes<HTMLInputElement> {}
19407
-
19408
- const Input = React.forwardRef<HTMLInputElement, InputProps>(
19409
- ({ className, type, ...props }, ref) => {
19410
- return (
19411
- <input
19412
- type={type}
19413
- className={cn(
19414
- "flex h-10 w-full rounded-md border border-zinc-200 bg-white px-3 py-2 text-sm file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-zinc-400 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-zinc-400 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
19415
- className
19416
- )}
19417
- ref={ref}
19418
- {...props}
19419
- />
19420
- )
19421
- }
19422
- )
19423
- Input.displayName = "Input"
19424
-
19425
- export { Input }
19426
- `,
19427
- "lib/utils.ts": `import { type ClassValue, clsx } from "clsx"
19428
- import { twMerge } from "tailwind-merge"
19429
-
19430
- export function cn(...inputs: ClassValue[]) {
19431
- return twMerge(clsx(inputs))
19432
- }
19433
- `,
19434
- // Add clsx and tailwind-merge to package.json dependencies
19435
- "package.json.full": `{
19436
- "name": "{{NAME}}",
19437
- "version": "0.1.0",
19438
- "private": true,
19439
- "scripts": {
19440
- "dev": "next dev",
19441
- "build": "next build",
19442
- "start": "next start",
19443
- "lint": "next lint"
19444
- },
19445
- "dependencies": {
19446
- "next": "^14.1.0",
19447
- "react": "^18.2.0",
19448
- "react-dom": "^18.2.0",
19449
- "class-variance-authority": "^0.7.0",
19450
- "clsx": "^2.1.0",
19451
- "tailwind-merge": "^2.2.0"
19452
- },
19453
- "devDependencies": {
19454
- "@types/node": "^20.11.0",
19455
- "@types/react": "^18.2.0",
19456
- "@types/react-dom": "^18.2.0",
19457
- "typescript": "^5.3.0",
19458
- "tailwindcss": "^3.4.0",
19459
- "postcss": "^8.4.0",
19460
- "autoprefixer": "^10.4.0",
19461
- "eslint": "^8.56.0",
19462
- "eslint-config-next": "^14.1.0"
19204
+ // src/app/agent/tools/CreateNextAppTool/CreateNextAppTool.ts
19205
+ var SCAFFOLD_DIR = path26.join(
19206
+ path26.dirname(fileURLToPath(import.meta.url)),
19207
+ "scaffold"
19208
+ );
19209
+ async function copyScaffoldTree(projectPath, projectName) {
19210
+ const filesCreated = [];
19211
+ async function walk(relativeDir) {
19212
+ const srcDir = path26.join(SCAFFOLD_DIR, relativeDir);
19213
+ const entries = await fs24.readdir(srcDir, { withFileTypes: true });
19214
+ for (const entry of entries) {
19215
+ const relPath = relativeDir ? `${relativeDir}/${entry.name}` : entry.name;
19216
+ const srcPath = path26.join(SCAFFOLD_DIR, relPath);
19217
+ const destPath = path26.join(projectPath, relPath);
19218
+ if (entry.isDirectory()) {
19219
+ await fs24.mkdir(destPath, { recursive: true });
19220
+ await walk(relPath);
19221
+ continue;
19222
+ }
19223
+ const raw = await fs24.readFile(srcPath, "utf-8");
19224
+ const content = raw.replace(/\{\{NAME\}\}/g, projectName);
19225
+ await fs24.mkdir(path26.dirname(destPath), { recursive: true });
19226
+ await fs24.writeFile(destPath, content, "utf-8");
19227
+ filesCreated.push(relPath);
19228
+ }
19463
19229
  }
19464
- }
19465
- `
19466
- };
19467
- async function createFile(filePath, content, projectName) {
19468
- const dir = path25.dirname(filePath);
19469
- await fs23.mkdir(dir, { recursive: true });
19470
- const replacedContent = content.replace(/{{NAME}}/g, projectName);
19471
- await fs23.writeFile(filePath, replacedContent, "utf-8");
19230
+ await walk("");
19231
+ return filesCreated;
19472
19232
  }
19473
19233
  async function createNextApp(args) {
19474
- const {
19475
- name,
19476
- directory,
19477
- template = "full"
19478
- } = args;
19234
+ const { name, directory } = args;
19479
19235
  try {
19480
19236
  if (!name || typeof name !== "string") {
19481
19237
  return { success: false, error: "name is required and must be a string" };
@@ -19487,73 +19243,66 @@ async function createNextApp(args) {
19487
19243
  };
19488
19244
  }
19489
19245
  const baseDir = directory ? resolveWorkspacePath(directory) : resolveWorkspacePath(".");
19490
- const projectPath = path25.join(baseDir, name);
19246
+ const projectPath = path26.join(baseDir, name);
19491
19247
  try {
19492
- await fs23.access(projectPath);
19248
+ await fs24.access(projectPath);
19493
19249
  return {
19494
19250
  success: false,
19495
19251
  error: `Directory already exists: ${projectPath}. Remove it first or choose a different name.`
19496
19252
  };
19497
19253
  } catch {
19498
19254
  }
19499
- await fs23.mkdir(projectPath, { recursive: true });
19500
- const filesToCreate = template === "minimal" ? MINIMAL_FILES : FULL_FILES;
19501
- const filesCreated = [];
19502
- for (const [relativePath, content] of Object.entries(filesToCreate)) {
19503
- if (relativePath === "package.json.full") continue;
19504
- const fullPath = path25.join(projectPath, relativePath);
19505
- await createFile(fullPath, content, name);
19506
- filesCreated.push(relativePath);
19507
- }
19508
- if (template === "full") {
19509
- const packageJsonPath = path25.join(projectPath, "package.json");
19510
- const fullPackageJson = FULL_FILES["package.json.full"];
19511
- if (fullPackageJson) {
19512
- await createFile(packageJsonPath, fullPackageJson, name);
19513
- }
19514
- }
19255
+ await fs24.mkdir(projectPath, { recursive: true });
19256
+ const filesCreated = await copyScaffoldTree(projectPath, name);
19515
19257
  console.log(`[create-next-app] Installing dependencies in ${projectPath}...`);
19516
19258
  const installResult = await shellCommand({
19517
19259
  command: "npm install",
19518
19260
  cwd: projectPath,
19519
19261
  timeout: 300
19520
- // 5 minutos
19521
19262
  });
19522
19263
  const installJson = JSON.parse(installResult);
19523
19264
  if (installJson.status !== "success") {
19524
19265
  console.warn("[create-next-app] npm install warnings:", installJson.stderr);
19525
19266
  }
19267
+ const { markdown: agentGuide, uiComponents } = await buildScaffoldAgentGuide(
19268
+ name,
19269
+ projectPath
19270
+ );
19271
+ const designDocPath = await writeDesignDoc(projectPath, agentGuide);
19526
19272
  const nextSteps = [
19527
- `cd ${name}`,
19528
- "npm run dev",
19529
- "Open http://localhost:3000",
19530
- template === "full" ? "Components shadcn/ui dispon\xEDveis em components/ui/" : "Adicione componentes conforme necess\xE1rio"
19273
+ `Read ${DESIGN_DOC_FILENAME} (or tool result agentGuide) before editing UI`,
19274
+ `cd ${name} && npm run dev \u2014 default landing shows "Power by FactorAI"`,
19275
+ `Edit app/page.tsx; use @/components/ui/* (${uiComponents.length} components)`,
19276
+ "Deploy with factorai.sh.deploy_app when ready"
19531
19277
  ];
19278
+ const summary = `Created "${name}" at ${projectPath}: Next.js 14 + ${uiComponents.length} shadcn/ui components, dark FactorAI tokens, standalone deploy. Default landing is ready \u2014 customize app/page.tsx for your product.`;
19532
19279
  console.log(`[create-next-app] Projeto criado: ${projectPath}`);
19533
19280
  return {
19534
19281
  success: true,
19535
19282
  projectPath,
19536
19283
  directory: name,
19537
19284
  filesCreated,
19285
+ agentGuide,
19286
+ designDocPath,
19287
+ uiComponentCount: uiComponents.length,
19288
+ summary,
19538
19289
  nextSteps
19539
19290
  };
19540
19291
  } catch (error) {
19541
- console.error("[create-next-app] Error:", error.message);
19542
- return {
19543
- success: false,
19544
- error: error.message || String(error)
19545
- };
19292
+ const message2 = error instanceof Error ? error.message : String(error);
19293
+ console.error("[create-next-app] Error:", message2);
19294
+ return { success: false, error: message2 };
19546
19295
  }
19547
19296
  }
19548
19297
 
19549
19298
  // src/app/agent/tools/DeployAppTool/DeployAppTool.ts
19550
19299
  init_sandbox_policy();
19551
- import { promises as fs24 } from "fs";
19552
- import path27 from "path";
19300
+ import { promises as fs25 } from "fs";
19301
+ import path28 from "path";
19553
19302
 
19554
19303
  // src/app/agent/tools/DeployAppTool/createDeployProjectZip.ts
19555
19304
  import { lstat, readdir, readFile as readFile2, writeFile } from "fs/promises";
19556
- import path26 from "path";
19305
+ import path27 from "path";
19557
19306
  import { minimatch as minimatch2 } from "minimatch";
19558
19307
  var DEPLOY_ZIP_EXCLUDE_PATTERNS = [
19559
19308
  "node_modules",
@@ -19578,7 +19327,7 @@ function shouldExcludeFromDeployZip(relativePosix, isDirectory) {
19578
19327
  const rel = relativePosix.replace(/\\/g, "/").replace(/^\.\//, "");
19579
19328
  if (!rel) return false;
19580
19329
  const segments = pathSegments(rel);
19581
- const baseName = path26.posix.basename(rel);
19330
+ const baseName = path27.posix.basename(rel);
19582
19331
  for (const pattern of DEPLOY_ZIP_EXCLUDE_PATTERNS) {
19583
19332
  if (pattern.includes("*")) {
19584
19333
  if (minimatch2(rel, pattern) || minimatch2(baseName, pattern)) {
@@ -19596,7 +19345,7 @@ function shouldExcludeFromDeployZip(relativePosix, isDirectory) {
19596
19345
  return false;
19597
19346
  }
19598
19347
  async function collectDeployZipEntries(projectDir, files) {
19599
- const base = path26.resolve(projectDir);
19348
+ const base = path27.resolve(projectDir);
19600
19349
  async function walk(currentDir) {
19601
19350
  let entries;
19602
19351
  try {
@@ -19605,8 +19354,8 @@ async function collectDeployZipEntries(projectDir, files) {
19605
19354
  return;
19606
19355
  }
19607
19356
  for (const entry of entries) {
19608
- const fullPath = path26.join(currentDir, entry.name);
19609
- const rel = path26.relative(base, fullPath).replace(/\\/g, "/");
19357
+ const fullPath = path27.join(currentDir, entry.name);
19358
+ const rel = path27.relative(base, fullPath).replace(/\\/g, "/");
19610
19359
  if (shouldExcludeFromDeployZip(rel, entry.isDirectory())) {
19611
19360
  continue;
19612
19361
  }
@@ -19650,12 +19399,12 @@ async function createDeployProjectZip(projectDir, zipPath) {
19650
19399
  // src/app/agent/tools/DeployAppTool/DeployAppTool.ts
19651
19400
  async function uploadToSeverino(zipPath, severinoUrl, name, apiKey, appId) {
19652
19401
  const deployUrl = `${severinoUrl.replace(/\/$/, "")}/api/v1/deploy`;
19653
- const zipBytes = await fs24.readFile(zipPath);
19402
+ const zipBytes = await fs25.readFile(zipPath);
19654
19403
  const form = new FormData();
19655
19404
  form.append(
19656
19405
  "file",
19657
19406
  new Blob([zipBytes], { type: "application/zip" }),
19658
- path27.basename(zipPath)
19407
+ path28.basename(zipPath)
19659
19408
  );
19660
19409
  if (name) form.append("name", name);
19661
19410
  if (appId) form.append("appId", appId);
@@ -19764,8 +19513,8 @@ function buildFactorAiManifest(appContext, deployResult, appName) {
19764
19513
  }
19765
19514
  async function writeFactorAiManifest(projectDir, appContext, deployResult, appName) {
19766
19515
  const manifest = buildFactorAiManifest(appContext, deployResult, appName);
19767
- const manifestPath = path27.join(projectDir, "factorai.sh.json");
19768
- await fs24.writeFile(manifestPath, `${JSON.stringify(manifest, null, 2)}
19516
+ const manifestPath = path28.join(projectDir, "factorai.sh.json");
19517
+ await fs25.writeFile(manifestPath, `${JSON.stringify(manifest, null, 2)}
19769
19518
  `, "utf-8");
19770
19519
  return manifest;
19771
19520
  }
@@ -19785,23 +19534,23 @@ async function deployApp(args) {
19785
19534
  }
19786
19535
  const resolvedProjectDir = resolveWorkspacePath(projectDir);
19787
19536
  try {
19788
- await fs24.access(resolvedProjectDir);
19537
+ await fs25.access(resolvedProjectDir);
19789
19538
  } catch {
19790
19539
  return {
19791
19540
  success: false,
19792
19541
  error: `Project directory not found: ${resolvedProjectDir}`
19793
19542
  };
19794
19543
  }
19795
- const packageJsonPath = path27.join(resolvedProjectDir, "package.json");
19544
+ const packageJsonPath = path28.join(resolvedProjectDir, "package.json");
19796
19545
  try {
19797
- await fs24.access(packageJsonPath);
19546
+ await fs25.access(packageJsonPath);
19798
19547
  } catch {
19799
19548
  return {
19800
19549
  success: false,
19801
19550
  error: "Not a Next.js project: package.json not found"
19802
19551
  };
19803
19552
  }
19804
- const packageJsonContent = await fs24.readFile(packageJsonPath, "utf-8");
19553
+ const packageJsonContent = await fs25.readFile(packageJsonPath, "utf-8");
19805
19554
  const packageJson = JSON.parse(packageJsonContent);
19806
19555
  const hasNext = packageJson.dependencies?.next || packageJson.devDependencies?.next;
19807
19556
  if (!hasNext) {
@@ -19810,18 +19559,18 @@ async function deployApp(args) {
19810
19559
  error: "Not a Next.js project: next not found in dependencies"
19811
19560
  };
19812
19561
  }
19813
- const appName = name || packageJson.name || path27.basename(resolvedProjectDir);
19814
- const tempDir = path27.join(resolvedProjectDir, ".tmp");
19815
- await fs24.mkdir(tempDir, { recursive: true });
19816
- const zipPath = path27.join(tempDir, `${appName}-${Date.now()}.zip`);
19562
+ const appName = name || packageJson.name || path28.basename(resolvedProjectDir);
19563
+ const tempDir = path28.join(resolvedProjectDir, ".tmp");
19564
+ await fs25.mkdir(tempDir, { recursive: true });
19565
+ const zipPath = path28.join(tempDir, `${appName}-${Date.now()}.zip`);
19817
19566
  console.log(`[deploy-app] Creating ZIP: ${zipPath}`);
19818
19567
  await createDeployProjectZip(resolvedProjectDir, zipPath);
19819
- const zipStats = await fs24.stat(zipPath);
19568
+ const zipStats = await fs25.stat(zipPath);
19820
19569
  const zipSizeMB = zipStats.size / 1024 / 1024;
19821
19570
  if (zipSizeMB > 50) {
19822
- await fs24.unlink(zipPath).catch(() => {
19571
+ await fs25.unlink(zipPath).catch(() => {
19823
19572
  });
19824
- await fs24.rmdir(tempDir).catch(() => {
19573
+ await fs25.rmdir(tempDir).catch(() => {
19825
19574
  });
19826
19575
  return {
19827
19576
  success: false,
@@ -19832,8 +19581,8 @@ async function deployApp(args) {
19832
19581
  console.log(`[deploy-app] Uploading to ${severinoUrl}...`);
19833
19582
  const deployResult = await uploadToSeverino(zipPath, severinoUrl, appName, apiKey, appId);
19834
19583
  try {
19835
- await fs24.unlink(zipPath);
19836
- await fs24.rmdir(tempDir);
19584
+ await fs25.unlink(zipPath);
19585
+ await fs25.rmdir(tempDir);
19837
19586
  } catch (e) {
19838
19587
  console.warn("[deploy-app] Cleanup warning:", e);
19839
19588
  }
@@ -19846,7 +19595,7 @@ async function deployApp(args) {
19846
19595
  appName
19847
19596
  );
19848
19597
  deployResult.factoraiManifest = manifest;
19849
- deployResult.factoraiManifestPath = path27.join(resolvedProjectDir, "factorai.sh.json");
19598
+ deployResult.factoraiManifestPath = path28.join(resolvedProjectDir, "factorai.sh.json");
19850
19599
  }
19851
19600
  console.log(`[deploy-app] Deploy iniciado: ${deployResult.appId}`);
19852
19601
  }
@@ -19994,12 +19743,11 @@ function getFactorAiSandboxToolDefinitions() {
19994
19743
  type: "function",
19995
19744
  function: {
19996
19745
  name: "factorai.sh.create_next_app",
19997
- description: "Create a new Next.js project in the sandbox workspace for FactorAI deployments.",
19746
+ description: "Create a Next.js 14 project (App Router, standalone, full shadcn/ui kit). Returns agentGuide (Refero-style DESIGN brief: tokens, UI inventory, do/don't) and writes DESIGN.md \u2014 read agentGuide before editing UI.",
19998
19747
  parameters: {
19999
19748
  type: "object",
20000
19749
  properties: {
20001
19750
  name: { type: "string", description: "Project name." },
20002
- template: { type: "string", enum: ["minimal", "full"], description: "Project template." },
20003
19751
  directory: { type: "string", description: "Target directory for the project." }
20004
19752
  },
20005
19753
  required: ["name"],
@@ -20672,7 +20420,7 @@ var NATIVE_TOOL_ENTRIES = [
20672
20420
  autoApproveInLocal: false,
20673
20421
  autoApproveInSandbox: true,
20674
20422
  sandboxOnly: true,
20675
- 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)."
20423
+ description: "Create Next.js 14 + full shadcn/ui kit. Returns agentGuide + DESIGN.md. Default page: polished dark landing (Refero-style) \u2014 read agentGuide before extending UI."
20676
20424
  },
20677
20425
  implementation: createNextApp
20678
20426
  },
@@ -20927,10 +20675,10 @@ var ToolInvoker = class {
20927
20675
  */
20928
20676
  async initialize() {
20929
20677
  try {
20930
- const currentFilePath = fileURLToPath(import.meta.url);
20931
- const currentDirPath = path28.dirname(currentFilePath);
20932
- const configPath = path28.resolve(currentDirPath, "config", "native_tools.json");
20933
- const fileContent = await fs25.readFile(configPath, "utf-8");
20678
+ const currentFilePath = fileURLToPath2(import.meta.url);
20679
+ const currentDirPath = path29.dirname(currentFilePath);
20680
+ const configPath = path29.resolve(currentDirPath, "config", "native_tools.json");
20681
+ const fileContent = await fs26.readFile(configPath, "utf-8");
20934
20682
  const config3 = JSON.parse(fileContent);
20935
20683
  this.toolDefinitions = applyMetadataToToolDefinitions(config3.nativeTools);
20936
20684
  const sandboxOnlyTools = applyMetadataToToolDefinitions(getSandboxOnlyNativeToolDefinitions());
@@ -20977,10 +20725,10 @@ var ToolInvoker = class {
20977
20725
  };
20978
20726
 
20979
20727
  // src/app/agent/tools/mcp/mcp_client.ts
20980
- import { promises as fs26 } from "fs";
20981
- import path29 from "path";
20728
+ import { promises as fs27 } from "fs";
20729
+ import path30 from "path";
20982
20730
  import os19 from "os";
20983
- import { fileURLToPath as fileURLToPath2 } from "url";
20731
+ import { fileURLToPath as fileURLToPath3 } from "url";
20984
20732
  import { Client } from "@modelcontextprotocol/sdk/client/index.js";
20985
20733
  import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
20986
20734
  var MCPClient = class {
@@ -21005,10 +20753,10 @@ var MCPClient = class {
21005
20753
  originalName: toolName
21006
20754
  });
21007
20755
  }
21008
- const __filename = fileURLToPath2(import.meta.url);
21009
- const __dirname2 = path29.dirname(__filename);
21010
- const defaultConfigPath = path29.resolve(__dirname2, "config", "bluma-mcp.json");
21011
- const userConfigPath = path29.join(os19.homedir(), ".bluma", "bluma-mcp.json");
20756
+ const __filename = fileURLToPath3(import.meta.url);
20757
+ const __dirname2 = path30.dirname(__filename);
20758
+ const defaultConfigPath = path30.resolve(__dirname2, "config", "bluma-mcp.json");
20759
+ const userConfigPath = path30.join(os19.homedir(), ".bluma", "bluma-mcp.json");
21012
20760
  const defaultConfig = await this.loadMcpConfig(defaultConfigPath, "Default");
21013
20761
  const userConfig = await this.loadMcpConfig(userConfigPath, "User");
21014
20762
  const mergedConfig = {
@@ -21042,7 +20790,7 @@ var MCPClient = class {
21042
20790
  }
21043
20791
  async loadMcpConfig(configPath, configType) {
21044
20792
  try {
21045
- const fileContent = await fs26.readFile(configPath, "utf-8");
20793
+ const fileContent = await fs27.readFile(configPath, "utf-8");
21046
20794
  const processedContent = this.replaceEnvPlaceholders(fileContent);
21047
20795
  return JSON.parse(processedContent);
21048
20796
  } catch (error) {
@@ -21254,24 +21002,24 @@ PENALTY APPLIED: ${penalty.toFixed(1)} points deducted.
21254
21002
  };
21255
21003
 
21256
21004
  // src/app/agent/bluma/core/bluma.ts
21257
- import path44 from "path";
21258
- import fs39 from "fs";
21005
+ import path45 from "path";
21006
+ import fs40 from "fs";
21259
21007
  import { v4 as uuidv48 } from "uuid";
21260
21008
 
21261
21009
  // src/app/agent/session_manager/session_manager.ts
21262
- import path32 from "path";
21263
- import { promises as fs29 } from "fs";
21010
+ import path33 from "path";
21011
+ import { promises as fs30 } from "fs";
21264
21012
 
21265
21013
  // src/app/agent/session_manager/agent_session_paths.ts
21266
21014
  init_bluma_app_dir();
21267
- import path31 from "path";
21268
- import { promises as fs28 } from "fs";
21015
+ import path32 from "path";
21016
+ import { promises as fs29 } from "fs";
21269
21017
 
21270
21018
  // src/app/agent/session_manager/session_index_db.ts
21271
21019
  init_bluma_app_dir();
21272
- import path30 from "path";
21020
+ import path31 from "path";
21273
21021
  import { mkdirSync as mkdirSync3 } from "fs";
21274
- import { promises as fs27 } from "fs";
21022
+ import { promises as fs28 } from "fs";
21275
21023
  import { createRequire } from "module";
21276
21024
  var AGENT_SESSION_PATHS_JSONL = "agent_session_paths.jsonl";
21277
21025
  var BLUMA_SESSION_DB_FILE = "bluma.sqlite";
@@ -21284,21 +21032,21 @@ function loadSqlite() {
21284
21032
  return nodeRequire("better-sqlite3");
21285
21033
  }
21286
21034
  function getSessionDbPath(appDir = getPreferredAppDir()) {
21287
- return path30.join(appDir, BLUMA_SESSION_DB_FILE);
21035
+ return path31.join(appDir, BLUMA_SESSION_DB_FILE);
21288
21036
  }
21289
21037
  function normalizeRelativePath(relativePath) {
21290
- return relativePath.split(path30.sep).join("/");
21038
+ return relativePath.split(path31.sep).join("/");
21291
21039
  }
21292
21040
  async function walkSessionJsonFiles(dir, onFile) {
21293
21041
  let entries;
21294
21042
  try {
21295
- entries = await fs27.readdir(dir, { withFileTypes: true });
21043
+ entries = await fs28.readdir(dir, { withFileTypes: true });
21296
21044
  } catch {
21297
21045
  return;
21298
21046
  }
21299
21047
  for (const e of entries) {
21300
21048
  const name = String(e.name);
21301
- const full = path30.join(dir, name);
21049
+ const full = path31.join(dir, name);
21302
21050
  if (e.isDirectory()) {
21303
21051
  await walkSessionJsonFiles(full, onFile);
21304
21052
  } else if (e.isFile() && name.endsWith(".json") && !name.includes(".tmp")) {
@@ -21308,10 +21056,10 @@ async function walkSessionJsonFiles(dir, onFile) {
21308
21056
  }
21309
21057
  async function loadJsonlEntries(appDir) {
21310
21058
  const map = /* @__PURE__ */ new Map();
21311
- const indexFile = path30.join(appDir, AGENT_SESSION_PATHS_JSONL);
21059
+ const indexFile = path31.join(appDir, AGENT_SESSION_PATHS_JSONL);
21312
21060
  let raw;
21313
21061
  try {
21314
- raw = await fs27.readFile(indexFile, "utf-8");
21062
+ raw = await fs28.readFile(indexFile, "utf-8");
21315
21063
  } catch {
21316
21064
  return map;
21317
21065
  }
@@ -21350,7 +21098,7 @@ async function readSessionMetaFromJson(absPath) {
21350
21098
  updatedAt: (/* @__PURE__ */ new Date(0)).toISOString()
21351
21099
  };
21352
21100
  try {
21353
- const raw = await fs27.readFile(absPath, "utf-8");
21101
+ const raw = await fs28.readFile(absPath, "utf-8");
21354
21102
  const data = JSON.parse(raw);
21355
21103
  const createdAt = data.created_at ?? fallback.createdAt;
21356
21104
  const updatedAt = data.last_updated ?? data.created_at ?? fallback.updatedAt;
@@ -21361,7 +21109,7 @@ async function readSessionMetaFromJson(absPath) {
21361
21109
  };
21362
21110
  } catch {
21363
21111
  try {
21364
- const st = await fs27.stat(absPath);
21112
+ const st = await fs28.stat(absPath);
21365
21113
  const iso = new Date(st.mtimeMs).toISOString();
21366
21114
  return { preview: fallback.preview, createdAt: iso, updatedAt: iso };
21367
21115
  } catch {
@@ -21388,7 +21136,7 @@ async function runMigrationV1(db, appDir) {
21388
21136
  const insertFromPath = async (sessionId, absPath, jsonlUpdatedAt) => {
21389
21137
  let rel;
21390
21138
  try {
21391
- rel = normalizeRelativePath(path30.relative(appDir, absPath));
21139
+ rel = normalizeRelativePath(path31.relative(appDir, absPath));
21392
21140
  } catch {
21393
21141
  return;
21394
21142
  }
@@ -21403,9 +21151,9 @@ async function runMigrationV1(db, appDir) {
21403
21151
  });
21404
21152
  };
21405
21153
  for (const [sessionId, entry] of jsonl) {
21406
- const full = path30.join(appDir, entry.relativePath.replace(/\//g, path30.sep));
21154
+ const full = path31.join(appDir, entry.relativePath.replace(/\//g, path31.sep));
21407
21155
  try {
21408
- await fs27.access(full);
21156
+ await fs28.access(full);
21409
21157
  await insertFromPath(sessionId, full, entry.updatedAt);
21410
21158
  } catch {
21411
21159
  upsert.run({
@@ -21417,11 +21165,11 @@ async function runMigrationV1(db, appDir) {
21417
21165
  });
21418
21166
  }
21419
21167
  }
21420
- const sessionsRoot = path30.join(appDir, "sessions");
21168
+ const sessionsRoot = path31.join(appDir, "sessions");
21421
21169
  const existing = db.prepare("SELECT session_id FROM agent_sessions").all();
21422
21170
  const seen = new Set(existing.map((r) => r.session_id));
21423
21171
  await walkSessionJsonFiles(sessionsRoot, async (absPath) => {
21424
- const sessionId = path30.basename(absPath, ".json");
21172
+ const sessionId = path31.basename(absPath, ".json");
21425
21173
  if (!sessionId || seen.has(sessionId)) return;
21426
21174
  seen.add(sessionId);
21427
21175
  await insertFromPath(sessionId, absPath);
@@ -21456,7 +21204,7 @@ async function ensureSessionIndexDb(appDir = getPreferredAppDir()) {
21456
21204
  }
21457
21205
  const BetterSqlite3 = loadSqlite();
21458
21206
  const dbPath = getSessionDbPath(appDir);
21459
- mkdirSync3(path30.dirname(dbPath), { recursive: true });
21207
+ mkdirSync3(path31.dirname(dbPath), { recursive: true });
21460
21208
  const db = new BetterSqlite3(dbPath);
21461
21209
  db.pragma("journal_mode = WAL");
21462
21210
  applySchema(db);
@@ -21492,7 +21240,7 @@ async function upsertSessionIndexRow(row, appDir = getPreferredAppDir()) {
21492
21240
  async function getSessionPathFromIndex(sessionId, appDir = getPreferredAppDir()) {
21493
21241
  const db = await ensureSessionIndexDb(appDir);
21494
21242
  const row = db.prepare("SELECT relative_path FROM agent_sessions WHERE session_id = ?").get(sessionId);
21495
- return row?.relative_path?.replace(/\//g, path30.sep) ?? null;
21243
+ return row?.relative_path?.replace(/\//g, path31.sep) ?? null;
21496
21244
  }
21497
21245
  async function listSessionsFromIndex(limit = 50, appDir = getPreferredAppDir()) {
21498
21246
  const db = await ensureSessionIndexDb(appDir);
@@ -21504,7 +21252,7 @@ async function listSessionsFromIndex(limit = 50, appDir = getPreferredAppDir())
21504
21252
  ).all(limit);
21505
21253
  return rows.map((r) => ({
21506
21254
  sessionId: r.session_id,
21507
- relativePath: r.relative_path.replace(/\//g, path30.sep),
21255
+ relativePath: r.relative_path.replace(/\//g, path31.sep),
21508
21256
  createdAt: r.created_at,
21509
21257
  updatedAt: r.updated_at,
21510
21258
  preview: r.preview
@@ -21516,7 +21264,7 @@ var AGENT_SESSION_PATHS_JSONL2 = "agent_session_paths.jsonl";
21516
21264
  async function appendAgentSessionPath(sessionId, relativePath) {
21517
21265
  const app = getPreferredAppDir();
21518
21266
  const now2 = (/* @__PURE__ */ new Date()).toISOString();
21519
- const rel = relativePath.split(path31.sep).join("/");
21267
+ const rel = relativePath.split(path32.sep).join("/");
21520
21268
  await upsertSessionIndexRow({
21521
21269
  sessionId,
21522
21270
  relativePath: rel,
@@ -21526,10 +21274,10 @@ async function appendAgentSessionPath(sessionId, relativePath) {
21526
21274
  });
21527
21275
  }
21528
21276
  async function resolveSessionRelativePathFromJsonl(sessionId) {
21529
- const indexFile = path31.join(getPreferredAppDir(), AGENT_SESSION_PATHS_JSONL2);
21277
+ const indexFile = path32.join(getPreferredAppDir(), AGENT_SESSION_PATHS_JSONL2);
21530
21278
  let raw;
21531
21279
  try {
21532
- raw = await fs28.readFile(indexFile, "utf-8");
21280
+ raw = await fs29.readFile(indexFile, "utf-8");
21533
21281
  } catch {
21534
21282
  return null;
21535
21283
  }
@@ -21538,7 +21286,7 @@ async function resolveSessionRelativePathFromJsonl(sessionId) {
21538
21286
  try {
21539
21287
  const row = JSON.parse(lines[i]);
21540
21288
  if (row.sessionId === sessionId && typeof row.relativePath === "string") {
21541
- return row.relativePath.replace(/\//g, path31.sep);
21289
+ return row.relativePath.replace(/\//g, path32.sep);
21542
21290
  }
21543
21291
  } catch {
21544
21292
  }
@@ -21553,13 +21301,13 @@ async function resolveSessionRelativePathFromIndex(sessionId) {
21553
21301
  async function walkSessionJsonFiles2(dir, onFile) {
21554
21302
  let entries;
21555
21303
  try {
21556
- entries = await fs28.readdir(dir, { withFileTypes: true });
21304
+ entries = await fs29.readdir(dir, { withFileTypes: true });
21557
21305
  } catch {
21558
21306
  return;
21559
21307
  }
21560
21308
  for (const e of entries) {
21561
21309
  const name = String(e.name);
21562
- const full = path31.join(dir, name);
21310
+ const full = path32.join(dir, name);
21563
21311
  if (e.isDirectory()) {
21564
21312
  await walkSessionJsonFiles2(full, onFile);
21565
21313
  } else if (e.isFile() && name.endsWith(".json") && !name.includes(".tmp")) {
@@ -21568,12 +21316,12 @@ async function walkSessionJsonFiles2(dir, onFile) {
21568
21316
  }
21569
21317
  }
21570
21318
  async function findSessionFileGlobFallback(sessionId) {
21571
- const sessionsRoot = path31.join(getPreferredAppDir(), "sessions");
21319
+ const sessionsRoot = path32.join(getPreferredAppDir(), "sessions");
21572
21320
  const state2 = { best: null };
21573
21321
  await walkSessionJsonFiles2(sessionsRoot, async (abs) => {
21574
- if (path31.basename(abs, ".json") !== sessionId) return;
21322
+ if (path32.basename(abs, ".json") !== sessionId) return;
21575
21323
  try {
21576
- const st = await fs28.stat(abs);
21324
+ const st = await fs29.stat(abs);
21577
21325
  if (!st.isFile()) return;
21578
21326
  if (!state2.best || st.mtimeMs > state2.best.m) {
21579
21327
  state2.best = { p: abs, m: st.mtimeMs };
@@ -21584,11 +21332,11 @@ async function findSessionFileGlobFallback(sessionId) {
21584
21332
  return state2.best !== null ? state2.best.p : null;
21585
21333
  }
21586
21334
  async function loadLatestIndexEntriesBySessionId() {
21587
- const indexFile = path31.join(getPreferredAppDir(), AGENT_SESSION_PATHS_JSONL2);
21335
+ const indexFile = path32.join(getPreferredAppDir(), AGENT_SESSION_PATHS_JSONL2);
21588
21336
  const map = /* @__PURE__ */ new Map();
21589
21337
  let raw;
21590
21338
  try {
21591
- raw = await fs28.readFile(indexFile, "utf-8");
21339
+ raw = await fs29.readFile(indexFile, "utf-8");
21592
21340
  } catch {
21593
21341
  return map;
21594
21342
  }
@@ -21624,11 +21372,11 @@ function dateFolderFromRelativePath(relativePath) {
21624
21372
  async function enrichCandidateFromFile(absPath, sessionId, lastMtimeMs, opts) {
21625
21373
  let rel;
21626
21374
  try {
21627
- rel = path31.relative(getPreferredAppDir(), absPath);
21375
+ rel = path32.relative(getPreferredAppDir(), absPath);
21628
21376
  } catch {
21629
21377
  rel = absPath;
21630
21378
  }
21631
- const dateFolder = dateFolderFromRelativePath(rel.split(path31.sep).join("/"));
21379
+ const dateFolder = dateFolderFromRelativePath(rel.split(path32.sep).join("/"));
21632
21380
  let preview = opts?.preview ?? "(no messages)";
21633
21381
  let lastActivityMs = lastMtimeMs;
21634
21382
  if (opts?.updatedAtIso) {
@@ -21639,7 +21387,7 @@ async function enrichCandidateFromFile(absPath, sessionId, lastMtimeMs, opts) {
21639
21387
  }
21640
21388
  if (!opts?.preview || opts.preview === "(no messages)") {
21641
21389
  try {
21642
- const raw = await fs28.readFile(absPath, "utf-8");
21390
+ const raw = await fs29.readFile(absPath, "utf-8");
21643
21391
  const data = JSON.parse(raw);
21644
21392
  preview = previewFromConversationHistory(data.conversation_history);
21645
21393
  const iso = data.last_updated || data.created_at;
@@ -21667,9 +21415,9 @@ async function listAgentSessionsForResume(limit = 50) {
21667
21415
  const fromIndex = await listSessionsFromIndex(limit * 2, appDir);
21668
21416
  const map = /* @__PURE__ */ new Map();
21669
21417
  for (const row of fromIndex) {
21670
- const full = path31.join(appDir, row.relativePath);
21418
+ const full = path32.join(appDir, row.relativePath);
21671
21419
  try {
21672
- const st = await fs28.stat(full);
21420
+ const st = await fs29.stat(full);
21673
21421
  if (!st.isFile()) continue;
21674
21422
  map.set(row.sessionId, {
21675
21423
  path: full,
@@ -21680,12 +21428,12 @@ async function listAgentSessionsForResume(limit = 50) {
21680
21428
  } catch {
21681
21429
  }
21682
21430
  }
21683
- const sessionsRoot = path31.join(appDir, "sessions");
21431
+ const sessionsRoot = path32.join(appDir, "sessions");
21684
21432
  await walkSessionJsonFiles2(sessionsRoot, async (absPath) => {
21685
- const id = path31.basename(absPath, ".json");
21433
+ const id = path32.basename(absPath, ".json");
21686
21434
  if (!id) return;
21687
21435
  try {
21688
- const st = await fs28.stat(absPath);
21436
+ const st = await fs29.stat(absPath);
21689
21437
  if (!st.isFile()) return;
21690
21438
  const cur = map.get(id);
21691
21439
  if (!cur || st.mtimeMs > cur.lastMtimeMs) {
@@ -21697,9 +21445,9 @@ async function listAgentSessionsForResume(limit = 50) {
21697
21445
  const index = await loadLatestIndexEntriesBySessionId();
21698
21446
  for (const [sessionId, entry] of index) {
21699
21447
  if (map.has(sessionId)) continue;
21700
- const full = path31.join(appDir, entry.relativePath.replace(/\//g, path31.sep));
21448
+ const full = path32.join(appDir, entry.relativePath.replace(/\//g, path32.sep));
21701
21449
  try {
21702
- const st = await fs28.stat(full);
21450
+ const st = await fs29.stat(full);
21703
21451
  if (st.isFile()) {
21704
21452
  map.set(sessionId, { path: full, lastMtimeMs: st.mtimeMs });
21705
21453
  }
@@ -21758,10 +21506,10 @@ async function safeRenameWithRetry(src, dest, maxRetries = 6) {
21758
21506
  const isWin = process.platform === "win32";
21759
21507
  while (attempt <= maxRetries) {
21760
21508
  try {
21761
- const dir = path32.dirname(dest);
21762
- await fs29.mkdir(dir, { recursive: true }).catch(() => {
21509
+ const dir = path33.dirname(dest);
21510
+ await fs30.mkdir(dir, { recursive: true }).catch(() => {
21763
21511
  });
21764
- await fs29.rename(src, dest);
21512
+ await fs30.rename(src, dest);
21765
21513
  return;
21766
21514
  } catch (e) {
21767
21515
  lastErr = e;
@@ -21774,13 +21522,13 @@ async function safeRenameWithRetry(src, dest, maxRetries = 6) {
21774
21522
  }
21775
21523
  }
21776
21524
  try {
21777
- await fs29.access(src);
21778
- const data = await fs29.readFile(src);
21779
- const dir = path32.dirname(dest);
21780
- await fs29.mkdir(dir, { recursive: true }).catch(() => {
21525
+ await fs30.access(src);
21526
+ const data = await fs30.readFile(src);
21527
+ const dir = path33.dirname(dest);
21528
+ await fs30.mkdir(dir, { recursive: true }).catch(() => {
21781
21529
  });
21782
- await fs29.writeFile(dest, data);
21783
- await fs29.unlink(src).catch(() => {
21530
+ await fs30.writeFile(dest, data);
21531
+ await fs30.unlink(src).catch(() => {
21784
21532
  });
21785
21533
  return;
21786
21534
  } catch (fallbackErr) {
@@ -21793,23 +21541,23 @@ async function safeRenameWithRetry(src, dest, maxRetries = 6) {
21793
21541
  }
21794
21542
  async function ensureSessionDir() {
21795
21543
  const appDir = getPreferredAppDir();
21796
- const sessionDir = path32.join(appDir, "sessions");
21797
- await fs29.mkdir(sessionDir, { recursive: true });
21544
+ const sessionDir = path33.join(appDir, "sessions");
21545
+ await fs30.mkdir(sessionDir, { recursive: true });
21798
21546
  return sessionDir;
21799
21547
  }
21800
21548
  async function resolveAgentSessionFilePath(sessionId) {
21801
21549
  const appDir = getPreferredAppDir();
21802
- const legacy = path32.join(appDir, "sessions", `${sessionId}.json`);
21550
+ const legacy = path33.join(appDir, "sessions", `${sessionId}.json`);
21803
21551
  try {
21804
- await fs29.access(legacy);
21552
+ await fs30.access(legacy);
21805
21553
  return legacy;
21806
21554
  } catch {
21807
21555
  }
21808
21556
  const rel = await resolveSessionRelativePathFromIndex(sessionId);
21809
21557
  if (rel) {
21810
- const full = path32.join(appDir, rel);
21558
+ const full = path33.join(appDir, rel);
21811
21559
  try {
21812
- await fs29.access(full);
21560
+ await fs30.access(full);
21813
21561
  return full;
21814
21562
  } catch {
21815
21563
  }
@@ -21822,7 +21570,7 @@ async function loadSession(sessionId) {
21822
21570
  return null;
21823
21571
  }
21824
21572
  try {
21825
- const fileContent = await fs29.readFile(sessionFile, "utf-8");
21573
+ const fileContent = await fs30.readFile(sessionFile, "utf-8");
21826
21574
  const sessionData = JSON.parse(fileContent);
21827
21575
  const memory = {
21828
21576
  historyAnchor: sessionData.history_anchor ?? null,
@@ -21843,16 +21591,16 @@ async function loadOrcreateSession(sessionId) {
21843
21591
  const y = String(now2.getFullYear());
21844
21592
  const mo = String(now2.getMonth() + 1).padStart(2, "0");
21845
21593
  const d = String(now2.getDate()).padStart(2, "0");
21846
- const datedDir = path32.join(sessionsRoot, y, mo, d);
21847
- await fs29.mkdir(datedDir, { recursive: true });
21848
- const sessionFile = path32.join(datedDir, `${sessionId}.json`);
21594
+ const datedDir = path33.join(sessionsRoot, y, mo, d);
21595
+ await fs30.mkdir(datedDir, { recursive: true });
21596
+ const sessionFile = path33.join(datedDir, `${sessionId}.json`);
21849
21597
  const newSessionData = {
21850
21598
  session_id: sessionId,
21851
21599
  created_at: now2.toISOString(),
21852
21600
  conversation_history: []
21853
21601
  };
21854
- await fs29.writeFile(sessionFile, JSON.stringify(newSessionData, null, 2), "utf-8");
21855
- const relToApp = path32.relative(getPreferredAppDir(), sessionFile);
21602
+ await fs30.writeFile(sessionFile, JSON.stringify(newSessionData, null, 2), "utf-8");
21603
+ const relToApp = path33.relative(getPreferredAppDir(), sessionFile);
21856
21604
  await appendAgentSessionPath(sessionId, relToApp);
21857
21605
  const emptyMemory = {
21858
21606
  historyAnchor: null,
@@ -21864,12 +21612,12 @@ async function doSaveSessionHistory(sessionFile, history, memory) {
21864
21612
  await withFileLock(sessionFile, async () => {
21865
21613
  let sessionData;
21866
21614
  try {
21867
- const dir = path32.dirname(sessionFile);
21868
- await fs29.mkdir(dir, { recursive: true });
21615
+ const dir = path33.dirname(sessionFile);
21616
+ await fs30.mkdir(dir, { recursive: true });
21869
21617
  } catch {
21870
21618
  }
21871
21619
  try {
21872
- const fileContent = await fs29.readFile(sessionFile, "utf-8");
21620
+ const fileContent = await fs30.readFile(sessionFile, "utf-8");
21873
21621
  sessionData = JSON.parse(fileContent);
21874
21622
  } catch (error) {
21875
21623
  const code = error && error.code;
@@ -21880,14 +21628,14 @@ async function doSaveSessionHistory(sessionFile, history, memory) {
21880
21628
  console.warn(`An unknown error occurred while reading ${sessionFile}. Re-initializing.`, error);
21881
21629
  }
21882
21630
  }
21883
- const sessionId = path32.basename(sessionFile, ".json");
21631
+ const sessionId = path33.basename(sessionFile, ".json");
21884
21632
  sessionData = {
21885
21633
  session_id: sessionId,
21886
21634
  created_at: (/* @__PURE__ */ new Date()).toISOString(),
21887
21635
  conversation_history: []
21888
21636
  };
21889
21637
  try {
21890
- await fs29.writeFile(sessionFile, JSON.stringify(sessionData, null, 2), "utf-8");
21638
+ await fs30.writeFile(sessionFile, JSON.stringify(sessionData, null, 2), "utf-8");
21891
21639
  } catch {
21892
21640
  }
21893
21641
  }
@@ -21903,14 +21651,14 @@ async function doSaveSessionHistory(sessionFile, history, memory) {
21903
21651
  }
21904
21652
  const tempSessionFile = `${sessionFile}.${Date.now()}.tmp`;
21905
21653
  try {
21906
- await fs29.writeFile(tempSessionFile, JSON.stringify(sessionData, null, 2), "utf-8");
21654
+ await fs30.writeFile(tempSessionFile, JSON.stringify(sessionData, null, 2), "utf-8");
21907
21655
  await safeRenameWithRetry(tempSessionFile, sessionFile);
21908
- const sessionId = sessionData.session_id ?? path32.basename(sessionFile, ".json");
21656
+ const sessionId = sessionData.session_id ?? path33.basename(sessionFile, ".json");
21909
21657
  const updatedAt = sessionData.last_updated ?? (/* @__PURE__ */ new Date()).toISOString();
21910
21658
  const createdAt = sessionData.created_at ?? updatedAt;
21911
21659
  let relToApp;
21912
21660
  try {
21913
- relToApp = path32.relative(getPreferredAppDir(), sessionFile);
21661
+ relToApp = path33.relative(getPreferredAppDir(), sessionFile);
21914
21662
  } catch {
21915
21663
  relToApp = sessionFile;
21916
21664
  }
@@ -21930,7 +21678,7 @@ async function doSaveSessionHistory(sessionFile, history, memory) {
21930
21678
  console.error(`An unknown fatal error occurred while saving session to ${sessionFile}:`, writeError);
21931
21679
  }
21932
21680
  try {
21933
- await fs29.unlink(tempSessionFile);
21681
+ await fs30.unlink(tempSessionFile);
21934
21682
  } catch {
21935
21683
  }
21936
21684
  }
@@ -21962,15 +21710,15 @@ async function saveSessionHistoryNow(sessionFile, history, memory) {
21962
21710
 
21963
21711
  // src/app/agent/core/prompt/prompt_builder.ts
21964
21712
  import os23 from "os";
21965
- import fs35 from "fs";
21966
- import path38 from "path";
21713
+ import fs36 from "fs";
21714
+ import path39 from "path";
21967
21715
  import { execSync as execSync3 } from "child_process";
21968
21716
 
21969
21717
  // src/app/agent/skills/skill_loader.ts
21970
- import fs30 from "fs";
21971
- import path33 from "path";
21718
+ import fs31 from "fs";
21719
+ import path34 from "path";
21972
21720
  import os20 from "os";
21973
- import { fileURLToPath as fileURLToPath3 } from "node:url";
21721
+ import { fileURLToPath as fileURLToPath4 } from "node:url";
21974
21722
  var SkillLoader = class _SkillLoader {
21975
21723
  bundledSkillsDir;
21976
21724
  projectSkillsDir;
@@ -21978,8 +21726,8 @@ var SkillLoader = class _SkillLoader {
21978
21726
  cache = /* @__PURE__ */ new Map();
21979
21727
  conflicts = [];
21980
21728
  constructor(projectRoot, bundledDir) {
21981
- this.projectSkillsDir = path33.join(projectRoot, ".bluma", "skills");
21982
- this.globalSkillsDir = path33.join(os20.homedir(), ".bluma", "skills");
21729
+ this.projectSkillsDir = path34.join(projectRoot, ".bluma", "skills");
21730
+ this.globalSkillsDir = path34.join(os20.homedir(), ".bluma", "skills");
21983
21731
  this.bundledSkillsDir = bundledDir || _SkillLoader.resolveBundledDir();
21984
21732
  }
21985
21733
  /**
@@ -21988,48 +21736,48 @@ var SkillLoader = class _SkillLoader {
21988
21736
  */
21989
21737
  static resolveBundledDir() {
21990
21738
  if (process.env.JEST_WORKER_ID !== void 0 || process.env.NODE_ENV === "test") {
21991
- return path33.join(process.cwd(), "dist", "config", "skills");
21739
+ return path34.join(process.cwd(), "dist", "config", "skills");
21992
21740
  }
21993
21741
  const candidates = [];
21994
21742
  const push = (p) => {
21995
- const abs = path33.resolve(p);
21743
+ const abs = path34.resolve(p);
21996
21744
  if (!candidates.includes(abs)) {
21997
21745
  candidates.push(abs);
21998
21746
  }
21999
21747
  };
22000
21748
  let argvBundled = null;
22001
21749
  try {
22002
- const bundleDir = path33.dirname(fileURLToPath3(import.meta.url));
22003
- push(path33.join(bundleDir, "config", "skills"));
21750
+ const bundleDir = path34.dirname(fileURLToPath4(import.meta.url));
21751
+ push(path34.join(bundleDir, "config", "skills"));
22004
21752
  } catch {
22005
21753
  }
22006
21754
  const argv1 = process.argv[1];
22007
21755
  if (argv1 && !argv1.startsWith("-")) {
22008
21756
  try {
22009
21757
  let resolved = argv1;
22010
- if (path33.isAbsolute(argv1) && fs30.existsSync(argv1)) {
22011
- resolved = fs30.realpathSync(argv1);
22012
- } else if (!path33.isAbsolute(argv1)) {
22013
- resolved = path33.resolve(process.cwd(), argv1);
21758
+ if (path34.isAbsolute(argv1) && fs31.existsSync(argv1)) {
21759
+ resolved = fs31.realpathSync(argv1);
21760
+ } else if (!path34.isAbsolute(argv1)) {
21761
+ resolved = path34.resolve(process.cwd(), argv1);
22014
21762
  }
22015
- const scriptDir = path33.dirname(resolved);
22016
- argvBundled = path33.join(scriptDir, "config", "skills");
21763
+ const scriptDir = path34.dirname(resolved);
21764
+ argvBundled = path34.join(scriptDir, "config", "skills");
22017
21765
  push(argvBundled);
22018
21766
  } catch {
22019
21767
  }
22020
21768
  }
22021
21769
  for (const abs of candidates) {
22022
- if (fs30.existsSync(abs)) {
21770
+ if (fs31.existsSync(abs)) {
22023
21771
  return abs;
22024
21772
  }
22025
21773
  }
22026
21774
  try {
22027
- return path33.join(path33.dirname(fileURLToPath3(import.meta.url)), "config", "skills");
21775
+ return path34.join(path34.dirname(fileURLToPath4(import.meta.url)), "config", "skills");
22028
21776
  } catch {
22029
21777
  if (argvBundled) {
22030
21778
  return argvBundled;
22031
21779
  }
22032
- return path33.join(os20.homedir(), ".bluma", "__bundled_skills_unresolved__");
21780
+ return path34.join(os20.homedir(), ".bluma", "__bundled_skills_unresolved__");
22033
21781
  }
22034
21782
  }
22035
21783
  /**
@@ -22058,8 +21806,8 @@ var SkillLoader = class _SkillLoader {
22058
21806
  this.conflicts.push({
22059
21807
  name: skill.name,
22060
21808
  userSource: source,
22061
- userPath: path33.join(dir, skill.name, "SKILL.md"),
22062
- bundledPath: path33.join(this.bundledSkillsDir, skill.name, "SKILL.md")
21809
+ userPath: path34.join(dir, skill.name, "SKILL.md"),
21810
+ bundledPath: path34.join(this.bundledSkillsDir, skill.name, "SKILL.md")
22063
21811
  });
22064
21812
  continue;
22065
21813
  }
@@ -22067,20 +21815,20 @@ var SkillLoader = class _SkillLoader {
22067
21815
  }
22068
21816
  }
22069
21817
  listFromDir(dir, source) {
22070
- if (!fs30.existsSync(dir)) return [];
21818
+ if (!fs31.existsSync(dir)) return [];
22071
21819
  try {
22072
- return fs30.readdirSync(dir).filter((d) => {
22073
- const fullPath = path33.join(dir, d);
22074
- return fs30.statSync(fullPath).isDirectory() && fs30.existsSync(path33.join(fullPath, "SKILL.md"));
22075
- }).map((d) => this.loadMetadataFromPath(path33.join(dir, d, "SKILL.md"), d, source)).filter((m) => m !== null);
21820
+ return fs31.readdirSync(dir).filter((d) => {
21821
+ const fullPath = path34.join(dir, d);
21822
+ return fs31.statSync(fullPath).isDirectory() && fs31.existsSync(path34.join(fullPath, "SKILL.md"));
21823
+ }).map((d) => this.loadMetadataFromPath(path34.join(dir, d, "SKILL.md"), d, source)).filter((m) => m !== null);
22076
21824
  } catch {
22077
21825
  return [];
22078
21826
  }
22079
21827
  }
22080
21828
  loadMetadataFromPath(skillPath, skillName, source) {
22081
- if (!fs30.existsSync(skillPath)) return null;
21829
+ if (!fs31.existsSync(skillPath)) return null;
22082
21830
  try {
22083
- const raw = fs30.readFileSync(skillPath, "utf-8");
21831
+ const raw = fs31.readFileSync(skillPath, "utf-8");
22084
21832
  const parsed = this.parseFrontmatter(raw);
22085
21833
  return {
22086
21834
  name: parsed.name || skillName,
@@ -22102,12 +21850,12 @@ var SkillLoader = class _SkillLoader {
22102
21850
  */
22103
21851
  load(name) {
22104
21852
  if (this.cache.has(name)) return this.cache.get(name);
22105
- const bundledPath = path33.join(this.bundledSkillsDir, name, "SKILL.md");
22106
- const projectPath = path33.join(this.projectSkillsDir, name, "SKILL.md");
22107
- const globalPath = path33.join(this.globalSkillsDir, name, "SKILL.md");
22108
- const existsBundled = fs30.existsSync(bundledPath);
22109
- const existsProject = fs30.existsSync(projectPath);
22110
- const existsGlobal = fs30.existsSync(globalPath);
21853
+ const bundledPath = path34.join(this.bundledSkillsDir, name, "SKILL.md");
21854
+ const projectPath = path34.join(this.projectSkillsDir, name, "SKILL.md");
21855
+ const globalPath = path34.join(this.globalSkillsDir, name, "SKILL.md");
21856
+ const existsBundled = fs31.existsSync(bundledPath);
21857
+ const existsProject = fs31.existsSync(projectPath);
21858
+ const existsGlobal = fs31.existsSync(globalPath);
22111
21859
  if (existsBundled && (existsProject || existsGlobal)) {
22112
21860
  const conflictSource = existsProject ? "project" : "global";
22113
21861
  const conflictPath = existsProject ? projectPath : globalPath;
@@ -22146,9 +21894,9 @@ var SkillLoader = class _SkillLoader {
22146
21894
  }
22147
21895
  loadFromPath(skillPath, name, source) {
22148
21896
  try {
22149
- const raw = fs30.readFileSync(skillPath, "utf-8");
21897
+ const raw = fs31.readFileSync(skillPath, "utf-8");
22150
21898
  const parsed = this.parseFrontmatter(raw);
22151
- const skillDir = path33.dirname(skillPath);
21899
+ const skillDir = path34.dirname(skillPath);
22152
21900
  return {
22153
21901
  name: parsed.name || name,
22154
21902
  description: parsed.description || "",
@@ -22157,22 +21905,22 @@ var SkillLoader = class _SkillLoader {
22157
21905
  version: parsed.version,
22158
21906
  author: parsed.author,
22159
21907
  license: parsed.license,
22160
- references: this.scanAssets(path33.join(skillDir, "references")),
22161
- scripts: this.scanAssets(path33.join(skillDir, "scripts"))
21908
+ references: this.scanAssets(path34.join(skillDir, "references")),
21909
+ scripts: this.scanAssets(path34.join(skillDir, "scripts"))
22162
21910
  };
22163
21911
  } catch {
22164
21912
  return null;
22165
21913
  }
22166
21914
  }
22167
21915
  scanAssets(dir) {
22168
- if (!fs30.existsSync(dir)) return [];
21916
+ if (!fs31.existsSync(dir)) return [];
22169
21917
  try {
22170
- return fs30.readdirSync(dir).filter((f) => {
22171
- const fp = path33.join(dir, f);
22172
- return fs30.statSync(fp).isFile();
21918
+ return fs31.readdirSync(dir).filter((f) => {
21919
+ const fp = path34.join(dir, f);
21920
+ return fs31.statSync(fp).isFile();
22173
21921
  }).map((f) => ({
22174
21922
  name: f,
22175
- path: path33.resolve(dir, f)
21923
+ path: path34.resolve(dir, f)
22176
21924
  }));
22177
21925
  } catch {
22178
21926
  return [];
@@ -22229,10 +21977,10 @@ var SkillLoader = class _SkillLoader {
22229
21977
  this.cache.clear();
22230
21978
  }
22231
21979
  exists(name) {
22232
- const bundledPath = path33.join(this.bundledSkillsDir, name, "SKILL.md");
22233
- const projectPath = path33.join(this.projectSkillsDir, name, "SKILL.md");
22234
- const globalPath = path33.join(this.globalSkillsDir, name, "SKILL.md");
22235
- return fs30.existsSync(bundledPath) || fs30.existsSync(projectPath) || fs30.existsSync(globalPath);
21980
+ const bundledPath = path34.join(this.bundledSkillsDir, name, "SKILL.md");
21981
+ const projectPath = path34.join(this.projectSkillsDir, name, "SKILL.md");
21982
+ const globalPath = path34.join(this.globalSkillsDir, name, "SKILL.md");
21983
+ return fs31.existsSync(bundledPath) || fs31.existsSync(projectPath) || fs31.existsSync(globalPath);
22236
21984
  }
22237
21985
  /**
22238
21986
  * Retorna conflitos detetados (skills do utilizador com mesmo nome de nativas).
@@ -22264,13 +22012,13 @@ var SkillLoader = class _SkillLoader {
22264
22012
  };
22265
22013
 
22266
22014
  // src/app/agent/core/prompt/workspace_snapshot.ts
22267
- import fs32 from "fs";
22268
- import path35 from "path";
22015
+ import fs33 from "fs";
22016
+ import path36 from "path";
22269
22017
  import { execSync as execSync2 } from "child_process";
22270
22018
 
22271
22019
  // src/app/agent/utils/blumamd.ts
22272
- import fs31 from "fs";
22273
- import path34 from "path";
22020
+ import fs32 from "fs";
22021
+ import path35 from "path";
22274
22022
  import os21 from "os";
22275
22023
  import { execSync } from "child_process";
22276
22024
  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.";
@@ -22400,12 +22148,12 @@ var TEXT_FILE_EXTENSIONS = /* @__PURE__ */ new Set([
22400
22148
  function expandIncludePath(includePath, baseDir) {
22401
22149
  const cleanPath = includePath.startsWith("@") ? includePath.slice(1) : includePath;
22402
22150
  if (cleanPath.startsWith("~")) {
22403
- return path34.join(os21.homedir(), cleanPath.slice(1));
22151
+ return path35.join(os21.homedir(), cleanPath.slice(1));
22404
22152
  }
22405
- if (path34.isAbsolute(cleanPath)) {
22153
+ if (path35.isAbsolute(cleanPath)) {
22406
22154
  return cleanPath;
22407
22155
  }
22408
- return path34.resolve(baseDir, cleanPath);
22156
+ return path35.resolve(baseDir, cleanPath);
22409
22157
  }
22410
22158
  function processIncludes(content, baseDir, processedFiles) {
22411
22159
  const lines = content.split("\n");
@@ -22414,20 +22162,20 @@ function processIncludes(content, baseDir, processedFiles) {
22414
22162
  const includeMatch = line.match(/^@\s*([^\s]+)/);
22415
22163
  if (includeMatch) {
22416
22164
  const includePath = expandIncludePath(includeMatch[1], baseDir);
22417
- const normalizedPath = path34.normalize(includePath);
22165
+ const normalizedPath = path35.normalize(includePath);
22418
22166
  if (processedFiles.has(normalizedPath)) {
22419
22167
  result.push(`<!-- Circular include prevented: ${includeMatch[1]} -->`);
22420
22168
  continue;
22421
22169
  }
22422
- const ext = path34.extname(includePath).toLowerCase();
22170
+ const ext = path35.extname(includePath).toLowerCase();
22423
22171
  if (!TEXT_FILE_EXTENSIONS.has(ext)) {
22424
22172
  result.push(`<!-- Include skipped (unsupported extension): ${includeMatch[1]} -->`);
22425
22173
  continue;
22426
22174
  }
22427
22175
  try {
22428
- const includedContent = fs31.readFileSync(includePath, "utf-8");
22176
+ const includedContent = fs32.readFileSync(includePath, "utf-8");
22429
22177
  processedFiles.add(normalizedPath);
22430
- const processedContent = processIncludes(includedContent, path34.dirname(includePath), processedFiles);
22178
+ const processedContent = processIncludes(includedContent, path35.dirname(includePath), processedFiles);
22431
22179
  result.push(`
22432
22180
  <!-- BEGIN INCLUDE ${includeMatch[1]} -->
22433
22181
  `);
@@ -22473,9 +22221,9 @@ function parseFrontmatterPaths(paths2) {
22473
22221
  }
22474
22222
  function readMemoryFile(filePath, type, includeBasePath) {
22475
22223
  try {
22476
- const rawContent = fs31.readFileSync(filePath, "utf-8");
22477
- const baseDir = includeBasePath || path34.dirname(filePath);
22478
- const processedFiles = /* @__PURE__ */ new Set([path34.normalize(filePath)]);
22224
+ const rawContent = fs32.readFileSync(filePath, "utf-8");
22225
+ const baseDir = includeBasePath || path35.dirname(filePath);
22226
+ const processedFiles = /* @__PURE__ */ new Set([path35.normalize(filePath)]);
22479
22227
  const { frontmatter, content: withoutFrontmatter } = parseFrontmatter(rawContent);
22480
22228
  const globs = parseFrontmatterPaths(frontmatter.paths);
22481
22229
  const processedContent = processIncludes(withoutFrontmatter, baseDir, processedFiles);
@@ -22497,15 +22245,15 @@ function readMemoryFile(filePath, type, includeBasePath) {
22497
22245
  }
22498
22246
  function findGitRoot(startDir) {
22499
22247
  let current = startDir;
22500
- while (current !== path34.dirname(current)) {
22501
- const gitPath = path34.join(current, ".git");
22248
+ while (current !== path35.dirname(current)) {
22249
+ const gitPath = path35.join(current, ".git");
22502
22250
  try {
22503
- if (fs31.existsSync(gitPath)) {
22251
+ if (fs32.existsSync(gitPath)) {
22504
22252
  return current;
22505
22253
  }
22506
22254
  } catch {
22507
22255
  }
22508
- current = path34.dirname(current);
22256
+ current = path35.dirname(current);
22509
22257
  }
22510
22258
  return null;
22511
22259
  }
@@ -22530,17 +22278,17 @@ function getGitUserInfo(cwd2) {
22530
22278
  }
22531
22279
  function processRulesDirectory(rulesDir, type, processedPaths, conditionalRule = false) {
22532
22280
  const result = [];
22533
- if (!fs31.existsSync(rulesDir)) {
22281
+ if (!fs32.existsSync(rulesDir)) {
22534
22282
  return result;
22535
22283
  }
22536
22284
  try {
22537
- const entries = fs31.readdirSync(rulesDir, { withFileTypes: true });
22285
+ const entries = fs32.readdirSync(rulesDir, { withFileTypes: true });
22538
22286
  for (const entry of entries) {
22539
- const entryPath = path34.join(rulesDir, entry.name);
22287
+ const entryPath = path35.join(rulesDir, entry.name);
22540
22288
  if (entry.isDirectory()) {
22541
22289
  result.push(...processRulesDirectory(entryPath, type, processedPaths, conditionalRule));
22542
22290
  } else if (entry.isFile() && entry.name.endsWith(".md")) {
22543
- const normalizedPath = path34.normalize(entryPath);
22291
+ const normalizedPath = path35.normalize(entryPath);
22544
22292
  if (processedPaths.has(normalizedPath)) {
22545
22293
  continue;
22546
22294
  }
@@ -22576,13 +22324,13 @@ function loadManagedMemory() {
22576
22324
  function loadUserMemory() {
22577
22325
  const files = [];
22578
22326
  const homeDir = os21.homedir();
22579
- const userBlumaDir = path34.join(homeDir, ".bluma");
22580
- const userBlumaMd = path34.join(userBlumaDir, "BLUMA.md");
22327
+ const userBlumaDir = path35.join(homeDir, ".bluma");
22328
+ const userBlumaMd = path35.join(userBlumaDir, "BLUMA.md");
22581
22329
  const userFile = readMemoryFile(userBlumaMd, "User");
22582
22330
  if (userFile && userFile.content.trim()) {
22583
22331
  files.push(userFile);
22584
22332
  }
22585
- const userRulesDir = path34.join(userBlumaDir, "rules");
22333
+ const userRulesDir = path35.join(userBlumaDir, "rules");
22586
22334
  const processedPaths = /* @__PURE__ */ new Set();
22587
22335
  files.push(...processRulesDirectory(userRulesDir, "User", processedPaths, false));
22588
22336
  return files;
@@ -22594,10 +22342,10 @@ function loadProjectMemory(cwd2) {
22594
22342
  let currentDir = cwd2;
22595
22343
  const MAX_TRAVERSAL_DEPTH = 20;
22596
22344
  let depth = 0;
22597
- const normalizedGitRoot = path34.resolve(gitRoot);
22598
- while (currentDir !== path34.dirname(currentDir) && path34.resolve(currentDir).startsWith(normalizedGitRoot) && depth < MAX_TRAVERSAL_DEPTH) {
22345
+ const normalizedGitRoot = path35.resolve(gitRoot);
22346
+ while (currentDir !== path35.dirname(currentDir) && path35.resolve(currentDir).startsWith(normalizedGitRoot) && depth < MAX_TRAVERSAL_DEPTH) {
22599
22347
  dirs.push(currentDir);
22600
- currentDir = path34.dirname(currentDir);
22348
+ currentDir = path35.dirname(currentDir);
22601
22349
  depth++;
22602
22350
  }
22603
22351
  if (!dirs.includes(gitRoot)) {
@@ -22605,7 +22353,7 @@ function loadProjectMemory(cwd2) {
22605
22353
  }
22606
22354
  const processedPaths = /* @__PURE__ */ new Set();
22607
22355
  for (const dir of dirs.reverse()) {
22608
- const projectBlumaMd = path34.join(dir, "BLUMA.md");
22356
+ const projectBlumaMd = path35.join(dir, "BLUMA.md");
22609
22357
  if (!processedPaths.has(projectBlumaMd)) {
22610
22358
  processedPaths.add(projectBlumaMd);
22611
22359
  const projectFile = readMemoryFile(projectBlumaMd, "Project");
@@ -22613,7 +22361,7 @@ function loadProjectMemory(cwd2) {
22613
22361
  files.push(projectFile);
22614
22362
  }
22615
22363
  }
22616
- const blumaDirBlumaMd = path34.join(dir, ".bluma", "BLUMA.md");
22364
+ const blumaDirBlumaMd = path35.join(dir, ".bluma", "BLUMA.md");
22617
22365
  if (!processedPaths.has(blumaDirBlumaMd)) {
22618
22366
  processedPaths.add(blumaDirBlumaMd);
22619
22367
  const blumaDirFile = readMemoryFile(blumaDirBlumaMd, "Project");
@@ -22621,10 +22369,10 @@ function loadProjectMemory(cwd2) {
22621
22369
  files.push(blumaDirFile);
22622
22370
  }
22623
22371
  }
22624
- const rulesDir = path34.join(dir, ".bluma", "rules");
22372
+ const rulesDir = path35.join(dir, ".bluma", "rules");
22625
22373
  files.push(...processRulesDirectory(rulesDir, "Project", processedPaths, false));
22626
22374
  }
22627
- const localBlumaMd = path34.join(cwd2, "BLUMA.local.md");
22375
+ const localBlumaMd = path35.join(cwd2, "BLUMA.local.md");
22628
22376
  if (!processedPaths.has(localBlumaMd)) {
22629
22377
  processedPaths.add(localBlumaMd);
22630
22378
  const localFile = readMemoryFile(localBlumaMd, "Local");
@@ -22710,10 +22458,10 @@ var LIMITS = {
22710
22458
  };
22711
22459
  function safeReadFile(filePath, maxChars) {
22712
22460
  try {
22713
- if (!fs32.existsSync(filePath)) return null;
22714
- const st = fs32.statSync(filePath);
22461
+ if (!fs33.existsSync(filePath)) return null;
22462
+ const st = fs33.statSync(filePath);
22715
22463
  if (!st.isFile()) return null;
22716
- const raw = fs32.readFileSync(filePath, "utf8");
22464
+ const raw = fs33.readFileSync(filePath, "utf8");
22717
22465
  if (raw.includes("\0")) return null;
22718
22466
  if (raw.length <= maxChars) return raw;
22719
22467
  return `${raw.slice(0, maxChars)}
@@ -22725,7 +22473,7 @@ function safeReadFile(filePath, maxChars) {
22725
22473
  }
22726
22474
  function tryReadReadme(cwd2) {
22727
22475
  for (const name of ["README.md", "README.MD", "readme.md", "Readme.md"]) {
22728
- const c = safeReadFile(path35.join(cwd2, name), LIMITS.readme);
22476
+ const c = safeReadFile(path36.join(cwd2, name), LIMITS.readme);
22729
22477
  if (c) return `(${name})
22730
22478
  ${c}`;
22731
22479
  }
@@ -22733,14 +22481,14 @@ ${c}`;
22733
22481
  }
22734
22482
  function tryReadBluMaMd(cwd2) {
22735
22483
  const paths2 = [
22736
- path35.join(cwd2, "BluMa.md"),
22737
- path35.join(cwd2, "BLUMA.md"),
22738
- path35.join(cwd2, ".bluma", "BluMa.md")
22484
+ path36.join(cwd2, "BluMa.md"),
22485
+ path36.join(cwd2, "BLUMA.md"),
22486
+ path36.join(cwd2, ".bluma", "BluMa.md")
22739
22487
  ];
22740
22488
  for (const p of paths2) {
22741
22489
  const c = safeReadFile(p, LIMITS.blumaMd);
22742
22490
  if (c) {
22743
- const rel = path35.relative(cwd2, p) || p;
22491
+ const rel = path36.relative(cwd2, p) || p;
22744
22492
  return `(${rel})
22745
22493
  ${c}`;
22746
22494
  }
@@ -22748,10 +22496,10 @@ ${c}`;
22748
22496
  return null;
22749
22497
  }
22750
22498
  function summarizePackageJson(cwd2) {
22751
- const p = path35.join(cwd2, "package.json");
22499
+ const p = path36.join(cwd2, "package.json");
22752
22500
  try {
22753
- if (!fs32.existsSync(p)) return null;
22754
- const pkg = JSON.parse(fs32.readFileSync(p, "utf8"));
22501
+ if (!fs33.existsSync(p)) return null;
22502
+ const pkg = JSON.parse(fs33.readFileSync(p, "utf8"));
22755
22503
  const scripts = pkg.scripts;
22756
22504
  let scriptKeys = "";
22757
22505
  if (scripts && typeof scripts === "object" && !Array.isArray(scripts)) {
@@ -22784,7 +22532,7 @@ function summarizePackageJson(cwd2) {
22784
22532
  }
22785
22533
  function topLevelListing(cwd2) {
22786
22534
  try {
22787
- const names = fs32.readdirSync(cwd2, { withFileTypes: true });
22535
+ const names = fs33.readdirSync(cwd2, { withFileTypes: true });
22788
22536
  const sorted = [...names].sort((a, b) => a.name.localeCompare(b.name));
22789
22537
  const limited = sorted.slice(0, LIMITS.topDirEntries);
22790
22538
  const lines = limited.map((d) => `${d.name}${d.isDirectory() ? "/" : ""}`);
@@ -22842,7 +22590,7 @@ function buildWorkspaceSnapshot(cwd2) {
22842
22590
  parts.push(pkg);
22843
22591
  parts.push("```\n");
22844
22592
  }
22845
- const py = safeReadFile(path35.join(cwd2, "pyproject.toml"), LIMITS.pyproject);
22593
+ const py = safeReadFile(path36.join(cwd2, "pyproject.toml"), LIMITS.pyproject);
22846
22594
  if (py) {
22847
22595
  parts.push("### pyproject.toml (excerpt)\n```toml");
22848
22596
  parts.push(py);
@@ -22860,15 +22608,15 @@ function buildWorkspaceSnapshot(cwd2) {
22860
22608
  parts.push(bluma);
22861
22609
  parts.push("```\n");
22862
22610
  }
22863
- const contrib = safeReadFile(path35.join(cwd2, "CONTRIBUTING.md"), LIMITS.contributing);
22611
+ const contrib = safeReadFile(path36.join(cwd2, "CONTRIBUTING.md"), LIMITS.contributing);
22864
22612
  if (contrib) {
22865
22613
  parts.push("### CONTRIBUTING.md (excerpt)\n```markdown");
22866
22614
  parts.push(contrib);
22867
22615
  parts.push("```\n");
22868
22616
  }
22869
- const chlog = safeReadFile(path35.join(cwd2, "CHANGELOG.md"), LIMITS.changelog);
22617
+ const chlog = safeReadFile(path36.join(cwd2, "CHANGELOG.md"), LIMITS.changelog);
22870
22618
  if (!chlog) {
22871
- const alt = safeReadFile(path35.join(cwd2, "CHANGES.md"), LIMITS.changelog);
22619
+ const alt = safeReadFile(path36.join(cwd2, "CHANGES.md"), LIMITS.changelog);
22872
22620
  if (alt) {
22873
22621
  parts.push("### CHANGES.md (excerpt)\n```markdown");
22874
22622
  parts.push(alt);
@@ -22904,14 +22652,14 @@ function buildWorkspaceSnapshot(cwd2) {
22904
22652
  } else {
22905
22653
  parts.push("### Git\n(not a git work tree, or `git` unavailable)\n");
22906
22654
  }
22907
- const tsconfig = safeReadFile(path35.join(cwd2, "tsconfig.json"), LIMITS.tsconfig);
22655
+ const tsconfig = safeReadFile(path36.join(cwd2, "tsconfig.json"), LIMITS.tsconfig);
22908
22656
  if (tsconfig) {
22909
22657
  parts.push("### tsconfig.json (excerpt)\n```json");
22910
22658
  parts.push(tsconfig);
22911
22659
  parts.push("```\n");
22912
22660
  }
22913
22661
  for (const name of ["Dockerfile", "dockerfile", "Dockerfile.prod", "Dockerfile.dev"]) {
22914
- const df = safeReadFile(path35.join(cwd2, name), LIMITS.dockerfile);
22662
+ const df = safeReadFile(path36.join(cwd2, name), LIMITS.dockerfile);
22915
22663
  if (df) {
22916
22664
  parts.push(`### ${name} (excerpt)
22917
22665
  `);
@@ -22921,7 +22669,7 @@ function buildWorkspaceSnapshot(cwd2) {
22921
22669
  }
22922
22670
  }
22923
22671
  for (const name of ["docker-compose.yml", "docker-compose.yaml", "compose.yml", "compose.yaml"]) {
22924
- const dc = safeReadFile(path35.join(cwd2, name), LIMITS.dockerfile);
22672
+ const dc = safeReadFile(path36.join(cwd2, name), LIMITS.dockerfile);
22925
22673
  if (dc) {
22926
22674
  parts.push(`### ${name} (excerpt)
22927
22675
  `);
@@ -22936,12 +22684,12 @@ function buildWorkspaceSnapshot(cwd2) {
22936
22684
  ".circleci/config.yml",
22937
22685
  "Jenkinsfile"
22938
22686
  ]) {
22939
- const ciFile = path35.join(cwd2, ciPath);
22940
- if (fs32.existsSync(ciFile)) {
22941
- const st = fs32.statSync(ciFile);
22687
+ const ciFile = path36.join(cwd2, ciPath);
22688
+ if (fs33.existsSync(ciFile)) {
22689
+ const st = fs33.statSync(ciFile);
22942
22690
  if (st.isDirectory()) {
22943
22691
  try {
22944
- const wfFiles = fs32.readdirSync(ciFile).filter((f) => f.endsWith(".yml") || f.endsWith(".yaml"));
22692
+ const wfFiles = fs33.readdirSync(ciFile).filter((f) => f.endsWith(".yml") || f.endsWith(".yaml"));
22945
22693
  if (wfFiles.length > 0) {
22946
22694
  parts.push(`### GitHub Actions workflows
22947
22695
  \`${wfFiles.join("`, `")}\`
@@ -22952,7 +22700,7 @@ function buildWorkspaceSnapshot(cwd2) {
22952
22700
  } else {
22953
22701
  const ci = safeReadFile(ciFile, LIMITS.ciConfig);
22954
22702
  if (ci) {
22955
- parts.push(`### CI config (${path35.basename(ciPath)})
22703
+ parts.push(`### CI config (${path36.basename(ciPath)})
22956
22704
  `);
22957
22705
  parts.push(ci);
22958
22706
  parts.push("\n");
@@ -22961,8 +22709,8 @@ function buildWorkspaceSnapshot(cwd2) {
22961
22709
  }
22962
22710
  }
22963
22711
  for (const depFile of ["requirements.txt", "Pipfile", "poetry.lock", "Gemfile", "go.sum", "Cargo.lock"]) {
22964
- const depPath = path35.join(cwd2, depFile);
22965
- if (fs32.existsSync(depPath)) {
22712
+ const depPath = path36.join(cwd2, depFile);
22713
+ if (fs33.existsSync(depPath)) {
22966
22714
  const depContent = safeReadFile(depPath, 1500);
22967
22715
  if (depContent) {
22968
22716
  parts.push(`### ${depFile} (top entries)
@@ -22975,10 +22723,10 @@ function buildWorkspaceSnapshot(cwd2) {
22975
22723
  }
22976
22724
  }
22977
22725
  for (const envFile of [".env.example", ".env.sample", ".env.template"]) {
22978
- const envPath = path35.join(cwd2, envFile);
22979
- if (fs32.existsSync(envPath)) {
22726
+ const envPath = path36.join(cwd2, envFile);
22727
+ if (fs33.existsSync(envPath)) {
22980
22728
  try {
22981
- const raw = fs32.readFileSync(envPath, "utf-8");
22729
+ const raw = fs33.readFileSync(envPath, "utf-8");
22982
22730
  const keys = raw.split("\n").map((l) => l.trim()).filter((l) => l && !l.startsWith("#")).map((l) => {
22983
22731
  const eqIndex = l.indexOf("=");
22984
22732
  return eqIndex >= 0 ? l.slice(0, eqIndex).trim() : l.trim();
@@ -23001,15 +22749,15 @@ init_runtime_config();
23001
22749
 
23002
22750
  // src/app/agent/runtime/plugin_registry.ts
23003
22751
  init_sandbox_policy();
23004
- import fs33 from "fs";
22752
+ import fs34 from "fs";
23005
22753
  import os22 from "os";
23006
- import path36 from "path";
22754
+ import path37 from "path";
23007
22755
  function getProjectPluginsDir() {
23008
22756
  const policy = getSandboxPolicy();
23009
- return path36.join(policy.workspaceRoot, ".bluma", "plugins");
22757
+ return path37.join(policy.workspaceRoot, ".bluma", "plugins");
23010
22758
  }
23011
22759
  function getGlobalPluginsDir() {
23012
- return path36.join(process.env.HOME || os22.homedir(), ".bluma", "plugins");
22760
+ return path37.join(process.env.HOME || os22.homedir(), ".bluma", "plugins");
23013
22761
  }
23014
22762
  function getPluginDirs() {
23015
22763
  return {
@@ -23018,11 +22766,11 @@ function getPluginDirs() {
23018
22766
  };
23019
22767
  }
23020
22768
  function readManifest(manifestPath, fallbackName) {
23021
- if (!fs33.existsSync(manifestPath)) {
22769
+ if (!fs34.existsSync(manifestPath)) {
23022
22770
  return null;
23023
22771
  }
23024
22772
  try {
23025
- const parsed = JSON.parse(fs33.readFileSync(manifestPath, "utf-8"));
22773
+ const parsed = JSON.parse(fs34.readFileSync(manifestPath, "utf-8"));
23026
22774
  return {
23027
22775
  name: typeof parsed.name === "string" && parsed.name.trim() ? parsed.name.trim() : fallbackName,
23028
22776
  description: typeof parsed.description === "string" ? parsed.description.trim() : void 0,
@@ -23035,22 +22783,22 @@ function readManifest(manifestPath, fallbackName) {
23035
22783
  }
23036
22784
  function findManifestPath(pluginDir) {
23037
22785
  const candidates = [
23038
- path36.join(pluginDir, ".codex-plugin", "plugin.json"),
23039
- path36.join(pluginDir, "plugin.json")
22786
+ path37.join(pluginDir, ".codex-plugin", "plugin.json"),
22787
+ path37.join(pluginDir, "plugin.json")
23040
22788
  ];
23041
22789
  for (const candidate of candidates) {
23042
- if (fs33.existsSync(candidate)) {
22790
+ if (fs34.existsSync(candidate)) {
23043
22791
  return candidate;
23044
22792
  }
23045
22793
  }
23046
22794
  return null;
23047
22795
  }
23048
22796
  function listFromDir(baseDir, source) {
23049
- if (!fs33.existsSync(baseDir)) {
22797
+ if (!fs34.existsSync(baseDir)) {
23050
22798
  return [];
23051
22799
  }
23052
- return fs33.readdirSync(baseDir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).flatMap((entry) => {
23053
- const pluginDir = path36.join(baseDir, entry.name);
22800
+ return fs34.readdirSync(baseDir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).flatMap((entry) => {
22801
+ const pluginDir = path37.join(baseDir, entry.name);
23054
22802
  const manifestPath = findManifestPath(pluginDir);
23055
22803
  if (!manifestPath) {
23056
22804
  return [];
@@ -23495,8 +23243,8 @@ function buildModelInfoSection(modelId) {
23495
23243
 
23496
23244
  // src/app/agent/runtime/hook_registry.ts
23497
23245
  init_sandbox_policy();
23498
- import fs34 from "fs";
23499
- import path37 from "path";
23246
+ import fs35 from "fs";
23247
+ import path38 from "path";
23500
23248
  var DEFAULT_STATE = {
23501
23249
  enabled: true,
23502
23250
  maxEvents: 120,
@@ -23507,7 +23255,7 @@ var cache3 = null;
23507
23255
  var cachePath2 = null;
23508
23256
  function getStatePath() {
23509
23257
  const policy = getSandboxPolicy();
23510
- return path37.join(policy.workspaceRoot, ".bluma", "hooks.json");
23258
+ return path38.join(policy.workspaceRoot, ".bluma", "hooks.json");
23511
23259
  }
23512
23260
  function getHookStatePath() {
23513
23261
  return getStatePath();
@@ -23526,8 +23274,8 @@ function ensureLoaded2() {
23526
23274
  return cache3;
23527
23275
  }
23528
23276
  try {
23529
- if (fs34.existsSync(statePath)) {
23530
- const parsed = JSON.parse(fs34.readFileSync(statePath, "utf-8"));
23277
+ if (fs35.existsSync(statePath)) {
23278
+ const parsed = JSON.parse(fs35.readFileSync(statePath, "utf-8"));
23531
23279
  cache3 = {
23532
23280
  enabled: typeof parsed.enabled === "boolean" ? parsed.enabled : DEFAULT_STATE.enabled,
23533
23281
  maxEvents: typeof parsed.maxEvents === "number" && Number.isFinite(parsed.maxEvents) && parsed.maxEvents > 0 ? Math.floor(parsed.maxEvents) : DEFAULT_STATE.maxEvents,
@@ -23553,9 +23301,9 @@ function ensureLoaded2() {
23553
23301
  }
23554
23302
  function persist2(state2) {
23555
23303
  const statePath = getStatePath();
23556
- fs34.mkdirSync(path37.dirname(statePath), { recursive: true });
23304
+ fs35.mkdirSync(path38.dirname(statePath), { recursive: true });
23557
23305
  state2.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
23558
- fs34.writeFileSync(statePath, JSON.stringify(state2, null, 2), "utf-8");
23306
+ fs35.writeFileSync(statePath, JSON.stringify(state2, null, 2), "utf-8");
23559
23307
  cache3 = state2;
23560
23308
  cachePath2 = statePath;
23561
23309
  }
@@ -23820,12 +23568,12 @@ init_session_memory_paths();
23820
23568
  import { readFile as readFile3, writeFile as writeFile2 } from "fs/promises";
23821
23569
  async function loadSessionMemoryForPrompt(sessionId, cwd2 = process.cwd()) {
23822
23570
  if (!sessionId?.trim()) return "";
23823
- const path57 = getSessionMemoryPath(sessionId, cwd2);
23571
+ const path58 = getSessionMemoryPath(sessionId, cwd2);
23824
23572
  try {
23825
- const content = await readFile3(path57, "utf-8");
23573
+ const content = await readFile3(path58, "utf-8");
23826
23574
  if (!content.trim()) return "";
23827
23575
  return `<session_memory>
23828
- Notes for this conversation (${path57}):
23576
+ Notes for this conversation (${path58}):
23829
23577
 
23830
23578
  ${content.trim()}
23831
23579
  </session_memory>`;
@@ -23835,11 +23583,11 @@ ${content.trim()}
23835
23583
  }
23836
23584
  async function initSessionMemoryFile(sessionId, cwd2 = process.cwd()) {
23837
23585
  await ensureSessionMemoryDir(sessionId, cwd2);
23838
- const path57 = getSessionMemoryPath(sessionId, cwd2);
23586
+ const path58 = getSessionMemoryPath(sessionId, cwd2);
23839
23587
  try {
23840
- await readFile3(path57, "utf-8");
23588
+ await readFile3(path58, "utf-8");
23841
23589
  } catch {
23842
- await writeFile2(path57, `${DEFAULT_SESSION_MEMORY_TEMPLATE}
23590
+ await writeFile2(path58, `${DEFAULT_SESSION_MEMORY_TEMPLATE}
23843
23591
  `, "utf-8");
23844
23592
  }
23845
23593
  }
@@ -23878,8 +23626,8 @@ The orchestrator configures these \u2014 **use the values already set**. Do not
23878
23626
 
23879
23627
  ## Flow A \u2014 New app (no \`factorai.sh.json\` yet)
23880
23628
 
23881
- 1. \`factorai.sh.create_next_app({ name, template: "full" })\` \u2014 prefer **full** for deploy (App Router + \`app/\` + shadcn base). Minimal also includes \`app/\` but full is safer for UI tasks.
23882
- 2. Customize with \`edit_tool\` / \`file_write\` / \`shell_command\` in the project directory (e.g. \`./{name}/app/page.tsx\`).
23629
+ 1. \`factorai.sh.create_next_app({ name })\` \u2014 scaffold completo (App Router + \`components/ui/*\` factorai.sh). **L\xEA o campo \`agentGuide\` do resultado** (ou \`DESIGN.md\` na raiz) antes de editar UI. A home j\xE1 \xE9 uma landing escura polida (hero + cards); personaliza \`app/page.tsx\` para o produto (ver Refero Styles para refer\xEAncia visual).
23630
+ 2. Customize with \`edit_tool\` / \`file_write\` / \`shell_command\` usando \`@/components/ui/*\` e classes sem\xE2nticas (\`bg-background\`, \`text-muted-foreground\`, etc.).
23883
23631
  3. Optional: \`npx tsc --noEmit\` to catch TS errors \u2014 **avoid** \`npm run build\` before deploy (creates \`.next/\` and inflates the ZIP).
23884
23632
  4. \`factorai.sh.deploy_app({ projectDir: "./{name}", name })\` \u2014 tool excludes \`node_modules\`, \`.next\`, \`.env*\` automatically. **Never** manual \`zip\` including \`node_modules\` or \`.next\`.
23885
23633
  5. Persist returned IDs into \`factorai.sh.json\` (tool does this when possible). Report live URL in \`message(result)\` via \`factor-sh-url-app\` (from manifest \`appUrl\`, absolute URL \u2014 prefix with \`SEVERINO_URL\` only when manifest has a path).
@@ -23972,17 +23720,17 @@ function getGitBranch(dir) {
23972
23720
  }
23973
23721
  }
23974
23722
  function getPackageManager(dir) {
23975
- if (fs35.existsSync(path38.join(dir, "pnpm-lock.yaml"))) return "pnpm";
23976
- if (fs35.existsSync(path38.join(dir, "yarn.lock"))) return "yarn";
23977
- if (fs35.existsSync(path38.join(dir, "bun.lockb"))) return "bun";
23978
- if (fs35.existsSync(path38.join(dir, "package-lock.json"))) return "npm";
23723
+ if (fs36.existsSync(path39.join(dir, "pnpm-lock.yaml"))) return "pnpm";
23724
+ if (fs36.existsSync(path39.join(dir, "yarn.lock"))) return "yarn";
23725
+ if (fs36.existsSync(path39.join(dir, "bun.lockb"))) return "bun";
23726
+ if (fs36.existsSync(path39.join(dir, "package-lock.json"))) return "npm";
23979
23727
  return "unknown";
23980
23728
  }
23981
23729
  function getProjectType(dir) {
23982
23730
  try {
23983
- const files = fs35.readdirSync(dir);
23731
+ const files = fs36.readdirSync(dir);
23984
23732
  if (files.includes("package.json")) {
23985
- const pkg = JSON.parse(fs35.readFileSync(path38.join(dir, "package.json"), "utf-8"));
23733
+ const pkg = JSON.parse(fs36.readFileSync(path39.join(dir, "package.json"), "utf-8"));
23986
23734
  const deps = { ...pkg.dependencies, ...pkg.devDependencies };
23987
23735
  if (deps.next) return "Next.js";
23988
23736
  if (deps.react) return "React";
@@ -24002,9 +23750,9 @@ function getProjectType(dir) {
24002
23750
  }
24003
23751
  function getTestFramework(dir) {
24004
23752
  try {
24005
- const pkgPath = path38.join(dir, "package.json");
24006
- if (fs35.existsSync(pkgPath)) {
24007
- const pkg = JSON.parse(fs35.readFileSync(pkgPath, "utf-8"));
23753
+ const pkgPath = path39.join(dir, "package.json");
23754
+ if (fs36.existsSync(pkgPath)) {
23755
+ const pkg = JSON.parse(fs36.readFileSync(pkgPath, "utf-8"));
24008
23756
  const deps = { ...pkg.dependencies, ...pkg.devDependencies };
24009
23757
  if (deps.jest) return "jest";
24010
23758
  if (deps.vitest) return "vitest";
@@ -24013,7 +23761,7 @@ function getTestFramework(dir) {
24013
23761
  if (deps["@playwright/test"]) return "playwright";
24014
23762
  if (deps.cypress) return "cypress";
24015
23763
  }
24016
- if (fs35.existsSync(path38.join(dir, "pytest.ini")) || fs35.existsSync(path38.join(dir, "conftest.py"))) return "pytest";
23764
+ if (fs36.existsSync(path39.join(dir, "pytest.ini")) || fs36.existsSync(path39.join(dir, "conftest.py"))) return "pytest";
24017
23765
  return "unknown";
24018
23766
  } catch {
24019
23767
  return "unknown";
@@ -24021,9 +23769,9 @@ function getTestFramework(dir) {
24021
23769
  }
24022
23770
  function getTestCommand(dir) {
24023
23771
  try {
24024
- const pkgPath = path38.join(dir, "package.json");
24025
- if (fs35.existsSync(pkgPath)) {
24026
- const pkg = JSON.parse(fs35.readFileSync(pkgPath, "utf-8"));
23772
+ const pkgPath = path39.join(dir, "package.json");
23773
+ if (fs36.existsSync(pkgPath)) {
23774
+ const pkg = JSON.parse(fs36.readFileSync(pkgPath, "utf-8"));
24027
23775
  if (pkg.scripts?.test) return "npm test";
24028
23776
  if (pkg.scripts?.["test:unit"]) return "npm run test:unit";
24029
23777
  }
@@ -24038,8 +23786,8 @@ function getTestCommand(dir) {
24038
23786
  }
24039
23787
  function isGitRepo(dir) {
24040
23788
  try {
24041
- const p = path38.join(dir, ".git");
24042
- return fs35.existsSync(p) && fs35.lstatSync(p).isDirectory();
23789
+ const p = path39.join(dir, ".git");
23790
+ return fs36.existsSync(p) && fs36.lstatSync(p).isDirectory();
24043
23791
  } catch {
24044
23792
  return false;
24045
23793
  }
@@ -25472,10 +25220,10 @@ var LLMService = class {
25472
25220
  };
25473
25221
 
25474
25222
  // src/app/agent/utils/user_message_images.ts
25475
- import fs36 from "fs";
25223
+ import fs37 from "fs";
25476
25224
  import os25 from "os";
25477
- import path39 from "path";
25478
- import { fileURLToPath as fileURLToPath4 } from "url";
25225
+ import path40 from "path";
25226
+ import { fileURLToPath as fileURLToPath5 } from "url";
25479
25227
  var IMAGE_EXT = /\.(png|jpe?g|gif|webp|bmp)$/i;
25480
25228
  var MAX_IMAGE_BYTES = 4 * 1024 * 1024;
25481
25229
  var MAX_IMAGES = 6;
@@ -25490,22 +25238,22 @@ var MIME = {
25490
25238
  function expandUserPath(p) {
25491
25239
  const t = p.trim();
25492
25240
  if (t.startsWith("~")) {
25493
- return path39.join(os25.homedir(), t.slice(1).replace(/^\//, ""));
25241
+ return path40.join(os25.homedir(), t.slice(1).replace(/^\//, ""));
25494
25242
  }
25495
25243
  return t;
25496
25244
  }
25497
25245
  function isPathAllowed(absResolved, cwd2) {
25498
- const resolved = path39.normalize(path39.resolve(absResolved));
25499
- const cwdR = path39.normalize(path39.resolve(cwd2));
25500
- const homeR = path39.normalize(path39.resolve(os25.homedir()));
25501
- const tmpR = path39.normalize(path39.resolve(os25.tmpdir()));
25502
- const underCwd = resolved === cwdR || resolved.startsWith(cwdR + path39.sep);
25503
- const underHome = resolved === homeR || resolved.startsWith(homeR + path39.sep);
25504
- const underTmp = resolved === tmpR || resolved.startsWith(tmpR + path39.sep);
25246
+ const resolved = path40.normalize(path40.resolve(absResolved));
25247
+ const cwdR = path40.normalize(path40.resolve(cwd2));
25248
+ const homeR = path40.normalize(path40.resolve(os25.homedir()));
25249
+ const tmpR = path40.normalize(path40.resolve(os25.tmpdir()));
25250
+ const underCwd = resolved === cwdR || resolved.startsWith(cwdR + path40.sep);
25251
+ const underHome = resolved === homeR || resolved.startsWith(homeR + path40.sep);
25252
+ const underTmp = resolved === tmpR || resolved.startsWith(tmpR + path40.sep);
25505
25253
  return underCwd || underHome || underTmp;
25506
25254
  }
25507
25255
  function mimeFor(abs) {
25508
- const ext = path39.extname(abs).toLowerCase();
25256
+ const ext = path40.extname(abs).toLowerCase();
25509
25257
  return MIME[ext] || "application/octet-stream";
25510
25258
  }
25511
25259
  var IMAGE_EXT_SRC = String.raw`(?:png|jpe?g|gif|webp|bmp)`;
@@ -25549,10 +25297,10 @@ function collectImagePathStrings(raw) {
25549
25297
  }
25550
25298
  function resolveImagePath(candidate, cwd2) {
25551
25299
  const expanded = expandUserPath(candidate);
25552
- const abs = path39.isAbsolute(expanded) ? path39.normalize(expanded) : path39.normalize(path39.resolve(cwd2, expanded));
25300
+ const abs = path40.isAbsolute(expanded) ? path40.normalize(expanded) : path40.normalize(path40.resolve(cwd2, expanded));
25553
25301
  if (!isPathAllowed(abs, cwd2)) return null;
25554
25302
  try {
25555
- if (!fs36.existsSync(abs) || !fs36.statSync(abs).isFile()) return null;
25303
+ if (!fs37.existsSync(abs) || !fs37.statSync(abs).isFile()) return null;
25556
25304
  } catch {
25557
25305
  return null;
25558
25306
  }
@@ -25564,7 +25312,7 @@ function trySingleLineFileUriOrBareImagePath(line, cwd2) {
25564
25312
  if (!s) return null;
25565
25313
  if (s.startsWith("file:")) {
25566
25314
  try {
25567
- s = fileURLToPath4(s);
25315
+ s = fileURLToPath5(s);
25568
25316
  } catch {
25569
25317
  return null;
25570
25318
  }
@@ -25572,11 +25320,11 @@ function trySingleLineFileUriOrBareImagePath(line, cwd2) {
25572
25320
  if (s.startsWith('"') && s.endsWith('"') || s.startsWith("'") && s.endsWith("'")) {
25573
25321
  s = s.slice(1, -1).trim();
25574
25322
  }
25575
- if (!IMAGE_EXT.test(path39.extname(s))) return null;
25323
+ if (!IMAGE_EXT.test(path40.extname(s))) return null;
25576
25324
  const abs = resolveImagePath(s, cwd2);
25577
25325
  if (!abs) return null;
25578
25326
  try {
25579
- const st = fs36.statSync(abs);
25327
+ const st = fs37.statSync(abs);
25580
25328
  if (!st.isFile() || st.size > MAX_IMAGE_BYTES) {
25581
25329
  return null;
25582
25330
  }
@@ -25611,7 +25359,7 @@ function tryPasteChunkAsSingleImagePath(chunk, cwd2) {
25611
25359
  return null;
25612
25360
  }
25613
25361
  try {
25614
- const st = fs36.statSync(abs);
25362
+ const st = fs37.statSync(abs);
25615
25363
  if (!st.isFile() || st.size > MAX_IMAGE_BYTES) {
25616
25364
  return null;
25617
25365
  }
@@ -25640,7 +25388,7 @@ function buildUserMessageContent(raw, cwd2) {
25640
25388
  const abs = resolveImagePath(c, cwd2);
25641
25389
  if (!abs) continue;
25642
25390
  try {
25643
- const st = fs36.statSync(abs);
25391
+ const st = fs37.statSync(abs);
25644
25392
  if (st.size > MAX_IMAGE_BYTES) continue;
25645
25393
  } catch {
25646
25394
  continue;
@@ -25657,7 +25405,7 @@ function buildUserMessageContent(raw, cwd2) {
25657
25405
  }
25658
25406
  const parts = [{ type: "text", text: textPart }];
25659
25407
  for (const abs of resolvedAbs) {
25660
- const buf = fs36.readFileSync(abs);
25408
+ const buf = fs37.readFileSync(abs);
25661
25409
  const b64 = buf.toString("base64");
25662
25410
  const mime = mimeFor(abs);
25663
25411
  parts.push({
@@ -25675,7 +25423,7 @@ function buildUserMessageContent(raw, cwd2) {
25675
25423
  init_sandbox_policy();
25676
25424
  init_runtime_config();
25677
25425
  init_permission_rules();
25678
- import path40 from "path";
25426
+ import path41 from "path";
25679
25427
  var LOCAL_EDIT_TOOL_NAMES = /* @__PURE__ */ new Set(["edit_tool", "file_write", "notebook_edit"]);
25680
25428
  function getToolPermissionLayer(metadata) {
25681
25429
  if (metadata.riskLevel === "safe") return "read";
@@ -25690,11 +25438,11 @@ function checkFilePermissionRules(toolName, filePath, policy) {
25690
25438
  if (!filePath) {
25691
25439
  return { allowed: false, reason: "No file path provided for permission check." };
25692
25440
  }
25693
- const resolvedPath = path40.resolve(filePath);
25441
+ const resolvedPath = path41.resolve(filePath);
25694
25442
  if (!isPathInsideWorkspace(resolvedPath, policy)) {
25695
25443
  return { allowed: false, reason: `File path "${filePath}" is outside workspace root.` };
25696
25444
  }
25697
- const relativePath = path40.relative(policy.workspaceRoot, resolvedPath);
25445
+ const relativePath = path41.relative(policy.workspaceRoot, resolvedPath);
25698
25446
  const toolPattern = `${toolName}(${relativePath})`;
25699
25447
  const ruleDecision = permissionRulesEngine.checkPermission(toolPattern, { filepath: filePath });
25700
25448
  if (ruleDecision === "deny") {
@@ -25703,7 +25451,7 @@ function checkFilePermissionRules(toolName, filePath, policy) {
25703
25451
  if (ruleDecision === "allow") {
25704
25452
  return { allowed: true, reason: `File "${filePath}" allowed by permission rules.` };
25705
25453
  }
25706
- const dirPath = path40.dirname(relativePath);
25454
+ const dirPath = path41.dirname(relativePath);
25707
25455
  const dirPattern = `${toolName}(${dirPath}/**)`;
25708
25456
  const dirRuleDecision = permissionRulesEngine.checkPermission(dirPattern, { filepath: filePath });
25709
25457
  if (dirRuleDecision === "allow") {
@@ -25920,11 +25668,11 @@ function effectiveToolAutoApprove(toolCall, sessionId, options) {
25920
25668
  }
25921
25669
 
25922
25670
  // src/app/agent/tools/CodingMemoryTool/CodingMemoryConsolidate.ts
25923
- import * as fs37 from "fs";
25924
- import * as path41 from "path";
25671
+ import * as fs38 from "fs";
25672
+ import * as path42 from "path";
25925
25673
  import os26 from "os";
25926
25674
  function memoryPath2() {
25927
- return path41.join(process.env.HOME || os26.homedir(), ".bluma", "coding_memory.json");
25675
+ return path42.join(process.env.HOME || os26.homedir(), ".bluma", "coding_memory.json");
25928
25676
  }
25929
25677
  function normalizeNote2(note) {
25930
25678
  return note.trim().toLowerCase().replace(/\s+/g, " ");
@@ -25934,18 +25682,18 @@ function uniqTags(a, b) {
25934
25682
  }
25935
25683
  function consolidateCodingMemoryFile() {
25936
25684
  const p = memoryPath2();
25937
- if (!fs37.existsSync(p)) {
25685
+ if (!fs38.existsSync(p)) {
25938
25686
  return { success: true, removedDuplicates: 0, message: "no coding_memory.json" };
25939
25687
  }
25940
25688
  const bak = `${p}.bak`;
25941
25689
  try {
25942
- fs37.copyFileSync(p, bak);
25690
+ fs38.copyFileSync(p, bak);
25943
25691
  } catch (e) {
25944
25692
  return { success: false, removedDuplicates: 0, message: `backup failed: ${e.message}` };
25945
25693
  }
25946
25694
  let data;
25947
25695
  try {
25948
- data = JSON.parse(fs37.readFileSync(p, "utf-8"));
25696
+ data = JSON.parse(fs38.readFileSync(p, "utf-8"));
25949
25697
  } catch (e) {
25950
25698
  return { success: false, removedDuplicates: 0, message: `invalid json: ${e.message}` };
25951
25699
  }
@@ -25980,7 +25728,7 @@ function consolidateCodingMemoryFile() {
25980
25728
  updatedAt: (/* @__PURE__ */ new Date()).toISOString()
25981
25729
  };
25982
25730
  try {
25983
- fs37.writeFileSync(p, JSON.stringify(out, null, 2), "utf-8");
25731
+ fs38.writeFileSync(p, JSON.stringify(out, null, 2), "utf-8");
25984
25732
  } catch (e) {
25985
25733
  return { success: false, removedDuplicates: 0, message: `write failed: ${e.message}` };
25986
25734
  }
@@ -26486,18 +26234,18 @@ var BluMaToolRunner = class {
26486
26234
 
26487
26235
  // src/app/agent/session_manager/session_archive.ts
26488
26236
  init_bluma_app_dir();
26489
- import path42 from "path";
26490
- import { promises as fs38 } from "fs";
26237
+ import path43 from "path";
26238
+ import { promises as fs39 } from "fs";
26491
26239
  async function archivePrunedConversationMessages(sessionId, messages) {
26492
26240
  if (!sessionId || messages.length === 0) {
26493
26241
  return null;
26494
26242
  }
26495
26243
  const appDir = getPreferredAppDir();
26496
- const dir = path42.join(appDir, "sessions", "archive", sessionId);
26497
- await fs38.mkdir(dir, { recursive: true });
26498
- const archiveFile = path42.join(dir, `${Date.now()}.jsonl`);
26244
+ const dir = path43.join(appDir, "sessions", "archive", sessionId);
26245
+ await fs39.mkdir(dir, { recursive: true });
26246
+ const archiveFile = path43.join(dir, `${Date.now()}.jsonl`);
26499
26247
  const lines = messages.map((m) => JSON.stringify(m)).join("\n") + "\n";
26500
- await fs38.appendFile(archiveFile, lines, "utf-8");
26248
+ await fs39.appendFile(archiveFile, lines, "utf-8");
26501
26249
  return archiveFile;
26502
26250
  }
26503
26251
 
@@ -27358,7 +27106,7 @@ Update existing files instead of duplicating.` : "";
27358
27106
 
27359
27107
  // src/app/agent/memory/memory_tool_policy.ts
27360
27108
  init_paths();
27361
- import path43 from "path";
27109
+ import path44 from "path";
27362
27110
  var MEMORY_READ_TOOLS = /* @__PURE__ */ new Set([
27363
27111
  "read_file_lines",
27364
27112
  "grep_search",
@@ -27385,7 +27133,7 @@ function isReadOnlyShellCommand(command) {
27385
27133
  return READ_ONLY_SHELL.test(trimmed);
27386
27134
  }
27387
27135
  function createAutoMemToolGate(memoryDir) {
27388
- const memRoot = memoryDir.endsWith(path43.sep) ? memoryDir : memoryDir + path43.sep;
27136
+ const memRoot = memoryDir.endsWith(path44.sep) ? memoryDir : memoryDir + path44.sep;
27389
27137
  return (toolName, args) => {
27390
27138
  if (MEMORY_READ_TOOLS.has(toolName)) {
27391
27139
  return { allowed: true };
@@ -27398,7 +27146,7 @@ function createAutoMemToolGate(memoryDir) {
27398
27146
  }
27399
27147
  if (MEMORY_WRITE_TOOLS.has(toolName)) {
27400
27148
  const fp = extractFilePath(args);
27401
- if (fp && isAutoMemPath(path43.resolve(fp))) {
27149
+ if (fp && isAutoMemPath(path44.resolve(fp))) {
27402
27150
  return { allowed: true };
27403
27151
  }
27404
27152
  return { allowed: false, reason: `Writes must stay under ${memRoot}` };
@@ -27407,18 +27155,18 @@ function createAutoMemToolGate(memoryDir) {
27407
27155
  };
27408
27156
  }
27409
27157
  function createSessionMemoryToolGate(sessionMemoryPath) {
27410
- const resolvedTarget = path43.resolve(sessionMemoryPath);
27158
+ const resolvedTarget = path44.resolve(sessionMemoryPath);
27411
27159
  return (toolName, args) => {
27412
27160
  if (toolName === "read_file_lines") {
27413
27161
  const fp = extractFilePath(args);
27414
- if (fp && path43.resolve(fp) === resolvedTarget) {
27162
+ if (fp && path44.resolve(fp) === resolvedTarget) {
27415
27163
  return { allowed: true };
27416
27164
  }
27417
27165
  return { allowed: false, reason: "Session memory subagent may only read the session summary file" };
27418
27166
  }
27419
27167
  if (toolName === "edit_tool") {
27420
27168
  const fp = extractFilePath(args);
27421
- if (fp && path43.resolve(fp) === resolvedTarget) {
27169
+ if (fp && path44.resolve(fp) === resolvedTarget) {
27422
27170
  return { allowed: true };
27423
27171
  }
27424
27172
  return { allowed: false, reason: "Session memory subagent may only edit the session summary file" };
@@ -27445,7 +27193,7 @@ function hasAutoMemWritesSinceHistory(history, sinceIndex) {
27445
27193
  continue;
27446
27194
  }
27447
27195
  const fp = extractFilePath(args);
27448
- if (fp && isAutoMemPath(path43.resolve(fp))) {
27196
+ if (fp && isAutoMemPath(path44.resolve(fp))) {
27449
27197
  return true;
27450
27198
  }
27451
27199
  }
@@ -27913,13 +27661,13 @@ var BluMaAgent = class {
27913
27661
  if (!this.sessionFile) return;
27914
27662
  try {
27915
27663
  const sessionData = {
27916
- session_id: path44.basename(this.sessionFile, ".json"),
27664
+ session_id: path45.basename(this.sessionFile, ".json"),
27917
27665
  created_at: (/* @__PURE__ */ new Date()).toISOString(),
27918
27666
  conversation_history: this.history,
27919
27667
  last_updated: (/* @__PURE__ */ new Date()).toISOString(),
27920
27668
  ...this.compressor.getSnapshot()
27921
27669
  };
27922
- fs39.writeFileSync(this.sessionFile, JSON.stringify(sessionData, null, 2), "utf-8");
27670
+ fs40.writeFileSync(this.sessionFile, JSON.stringify(sessionData, null, 2), "utf-8");
27923
27671
  } catch (error) {
27924
27672
  console.error("[Bluma] Failed to persist session synchronously:", error);
27925
27673
  }
@@ -28125,7 +27873,7 @@ var BluMaAgent = class {
28125
27873
 
28126
27874
  ${editData.error.display}`;
28127
27875
  }
28128
- const filename = path44.basename(toolArgs.file_path);
27876
+ const filename = path45.basename(toolArgs.file_path);
28129
27877
  return createDiff(filename, editData.currentContent || "", editData.newContent);
28130
27878
  } catch (e) {
28131
27879
  return `An unexpected error occurred while generating the edit preview: ${e.message}`;
@@ -28859,16 +28607,16 @@ async function fullCompact(messages, targetTokens, summarizer, llmClient) {
28859
28607
  }
28860
28608
 
28861
28609
  // src/app/agent/core/memory/session_memory.ts
28862
- import fs40 from "fs";
28610
+ import fs41 from "fs";
28863
28611
  import os29 from "os";
28864
- import path45 from "path";
28612
+ import path46 from "path";
28865
28613
  import { v4 as uuidv49 } from "uuid";
28866
28614
  var SessionMemoryExtractor = class {
28867
28615
  llmClient;
28868
28616
  memoryFile;
28869
28617
  constructor(options = {}) {
28870
28618
  this.llmClient = options.llmClient;
28871
- this.memoryFile = options.memoryFile || path45.join(os29.homedir(), ".bluma", "session_memory.json");
28619
+ this.memoryFile = options.memoryFile || path46.join(os29.homedir(), ".bluma", "session_memory.json");
28872
28620
  }
28873
28621
  /**
28874
28622
  * Extract memories from conversation using LLM
@@ -28925,15 +28673,15 @@ ${messages.slice(-50).map((m) => `${m.role}: ${m.content.slice(0, 500)}`).join("
28925
28673
  );
28926
28674
  unique.sort((a, b) => b.accessCount - a.accessCount);
28927
28675
  const trimmed = unique.slice(0, 200);
28928
- fs40.writeFileSync(this.memoryFile, JSON.stringify(trimmed, null, 2));
28676
+ fs41.writeFileSync(this.memoryFile, JSON.stringify(trimmed, null, 2));
28929
28677
  }
28930
28678
  /**
28931
28679
  * Load memories from disk
28932
28680
  */
28933
28681
  async loadMemories() {
28934
28682
  try {
28935
- if (!fs40.existsSync(this.memoryFile)) return [];
28936
- const data = fs40.readFileSync(this.memoryFile, "utf-8");
28683
+ if (!fs41.existsSync(this.memoryFile)) return [];
28684
+ const data = fs41.readFileSync(this.memoryFile, "utf-8");
28937
28685
  return JSON.parse(data);
28938
28686
  } catch {
28939
28687
  return [];
@@ -29477,14 +29225,14 @@ var RouteManager = class {
29477
29225
  this.subAgents = subAgents;
29478
29226
  this.core = core;
29479
29227
  }
29480
- registerRoute(path57, handler) {
29481
- this.routeHandlers.set(path57, handler);
29228
+ registerRoute(path58, handler) {
29229
+ this.routeHandlers.set(path58, handler);
29482
29230
  }
29483
29231
  async handleRoute(payload) {
29484
29232
  const inputText = String(payload.content || "").trim();
29485
29233
  const { userContext, options } = payload;
29486
- for (const [path57, handler] of this.routeHandlers) {
29487
- if (inputText === path57 || inputText.startsWith(`${path57} `)) {
29234
+ for (const [path58, handler] of this.routeHandlers) {
29235
+ if (inputText === path58 || inputText.startsWith(`${path58} `)) {
29488
29236
  return handler({ content: inputText, userContext });
29489
29237
  }
29490
29238
  }
@@ -29493,13 +29241,13 @@ var RouteManager = class {
29493
29241
  };
29494
29242
 
29495
29243
  // src/app/agent/runtime/plugin_runtime.ts
29496
- import path46 from "path";
29244
+ import path47 from "path";
29497
29245
  import { pathToFileURL as pathToFileURL2 } from "url";
29498
29246
  async function loadPluginsAtStartup() {
29499
29247
  for (const p of listPlugins()) {
29500
29248
  const entry = p.manifest.entry?.trim();
29501
29249
  if (!entry) continue;
29502
- const abs = path46.resolve(p.root, entry);
29250
+ const abs = path47.resolve(p.root, entry);
29503
29251
  try {
29504
29252
  const href = pathToFileURL2(abs).href;
29505
29253
  const mod = await import(href);
@@ -29520,7 +29268,7 @@ async function loadPluginsAtStartup() {
29520
29268
  }
29521
29269
 
29522
29270
  // src/app/agent/agent.ts
29523
- var globalEnvPath = path47.join(os30.homedir(), ".bluma", ".env");
29271
+ var globalEnvPath = path48.join(os30.homedir(), ".bluma", ".env");
29524
29272
  dotenv.config({ path: globalEnvPath });
29525
29273
  var Agent = class {
29526
29274
  sessionId;
@@ -31376,10 +31124,10 @@ function resolveToolPayload(result) {
31376
31124
 
31377
31125
  // src/app/ui/components/FilePathLink.tsx
31378
31126
  import { pathToFileURL as pathToFileURL3 } from "node:url";
31379
- import path49 from "node:path";
31127
+ import path50 from "node:path";
31380
31128
 
31381
31129
  // src/app/ui/utils/pathDisplay.ts
31382
- import path48 from "node:path";
31130
+ import path49 from "node:path";
31383
31131
  import os31 from "node:os";
31384
31132
  function formatPathForDisplay(pathInput, cwd2 = process.cwd()) {
31385
31133
  let s = String(pathInput ?? "").trim();
@@ -31387,17 +31135,17 @@ function formatPathForDisplay(pathInput, cwd2 = process.cwd()) {
31387
31135
  s = s.replace(/[/\\]+$/, "");
31388
31136
  }
31389
31137
  if (!s) return "";
31390
- const abs = path48.isAbsolute(s) ? path48.normalize(s) : path48.resolve(cwd2, s);
31391
- const resolvedCwd = path48.resolve(cwd2);
31392
- const rel = path48.relative(resolvedCwd, abs);
31393
- if (rel === "" || !rel.startsWith("..") && !path48.isAbsolute(rel)) {
31138
+ const abs = path49.isAbsolute(s) ? path49.normalize(s) : path49.resolve(cwd2, s);
31139
+ const resolvedCwd = path49.resolve(cwd2);
31140
+ const rel = path49.relative(resolvedCwd, abs);
31141
+ if (rel === "" || !rel.startsWith("..") && !path49.isAbsolute(rel)) {
31394
31142
  return rel === "" ? "." : rel;
31395
31143
  }
31396
- const home = path48.normalize(os31.homedir());
31397
- if (abs === home || abs.startsWith(home + path48.sep)) {
31144
+ const home = path49.normalize(os31.homedir());
31145
+ if (abs === home || abs.startsWith(home + path49.sep)) {
31398
31146
  return "~" + abs.slice(home.length);
31399
31147
  }
31400
- return path48.basename(abs);
31148
+ return path49.basename(abs);
31401
31149
  }
31402
31150
 
31403
31151
  // src/app/ui/components/FilePathLink.tsx
@@ -31407,7 +31155,7 @@ function FilePathLink({ filePath, children, cwd: cwd2 = process.cwd(), color })
31407
31155
  if (!raw) {
31408
31156
  return null;
31409
31157
  }
31410
- const abs = path49.isAbsolute(raw) ? path49.normalize(raw) : path49.resolve(cwd2, raw);
31158
+ const abs = path50.isAbsolute(raw) ? path50.normalize(raw) : path50.resolve(cwd2, raw);
31411
31159
  const href = pathToFileURL3(abs).href;
31412
31160
  const label = formatPathForDisplay(abs, cwd2);
31413
31161
  const text = typeof children === "string" ? children : label;
@@ -33359,12 +33107,12 @@ function patchToUnifiedDiffText(filePath, patch) {
33359
33107
  }
33360
33108
 
33361
33109
  // src/app/ui/utils/readEditContext.ts
33362
- import { promises as fs41 } from "fs";
33110
+ import { promises as fs42 } from "fs";
33363
33111
  var CHUNK_SIZE = 64 * 1024;
33364
33112
  var CONTEXT_LINES2 = 3;
33365
33113
  async function openForScan(filePath) {
33366
33114
  try {
33367
- return await fs41.open(filePath, "r");
33115
+ return await fs42.open(filePath, "r");
33368
33116
  } catch (e) {
33369
33117
  if (e.code === "ENOENT") return null;
33370
33118
  throw e;
@@ -34042,13 +33790,13 @@ function EditToolDiffPanel({
34042
33790
  newString,
34043
33791
  replaceAll = false
34044
33792
  }) {
34045
- const path57 = filePath.trim() || "unknown file";
33793
+ const path58 = filePath.trim() || "unknown file";
34046
33794
  const hasPreviewArgs = oldString !== void 0 && newString !== void 0;
34047
33795
  const hasDiffText = diffText && diffText.trim().length > 0;
34048
33796
  return /* @__PURE__ */ jsx43(Box_default, { flexDirection: "column", children: hasPreviewArgs ? /* @__PURE__ */ jsx43(Box_default, { marginTop: 0, children: /* @__PURE__ */ jsx43(
34049
33797
  FileEditToolDiff,
34050
33798
  {
34051
- filePath: path57,
33799
+ filePath: path58,
34052
33800
  oldString,
34053
33801
  newString,
34054
33802
  replaceAll,
@@ -34086,7 +33834,7 @@ function renderToolUseMessage12({ args }) {
34086
33834
  return /* @__PURE__ */ jsx44(Text, { color: BLUMA_TERMINAL.blue, children: p });
34087
33835
  }
34088
33836
  function renderToolHeader12({ args }) {
34089
- const path57 = args?.file_path ?? ".";
33837
+ const path58 = args?.file_path ?? ".";
34090
33838
  const oldText = typeof args?.old_string === "string" ? args.old_string : "";
34091
33839
  const newText = typeof args?.new_string === "string" ? args.new_string : "";
34092
33840
  const counts = countLineDiff(oldText, newText);
@@ -34096,7 +33844,7 @@ function renderToolHeader12({ args }) {
34096
33844
  action,
34097
33845
  /* @__PURE__ */ jsxs27(Text, { dimColor: true, children: [
34098
33846
  " ",
34099
- /* @__PURE__ */ jsx44(FilePathLink, { filePath: path57, color: BLUMA_TERMINAL.dim })
33847
+ /* @__PURE__ */ jsx44(FilePathLink, { filePath: path58, color: BLUMA_TERMINAL.dim })
34100
33848
  ] })
34101
33849
  ] }),
34102
33850
  /* @__PURE__ */ jsxs27(Text, { dimColor: true, children: [
@@ -34488,11 +34236,11 @@ function userFacingName13() {
34488
34236
  }
34489
34237
  function renderToolUseMessage14({ args }) {
34490
34238
  const q = args?.query ? `"${args.query}"` : "...";
34491
- const path57 = args?.path || ".";
34239
+ const path58 = args?.path || ".";
34492
34240
  return /* @__PURE__ */ jsxs30(Box_default, { flexDirection: "row", flexWrap: "wrap", alignItems: "flex-end", children: [
34493
34241
  /* @__PURE__ */ jsx47(Text, { color: BLUMA_TERMINAL.blue, children: q }),
34494
34242
  /* @__PURE__ */ jsx47(Text, { color: BLUMA_TERMINAL.dim, children: " " }),
34495
- /* @__PURE__ */ jsx47(FilePathLink, { filePath: path57, color: BLUMA_TERMINAL.dim })
34243
+ /* @__PURE__ */ jsx47(FilePathLink, { filePath: path58, color: BLUMA_TERMINAL.dim })
34496
34244
  ] });
34497
34245
  }
34498
34246
  function renderToolHeader14({ args }) {
@@ -35014,7 +34762,7 @@ var loadSkillTool = createTool({
35014
34762
  });
35015
34763
 
35016
34764
  // src/app/agent/tools/FileWriteTool/UI.tsx
35017
- import fs42 from "fs";
34765
+ import fs43 from "fs";
35018
34766
  import { diffLines as diffLines3 } from "diff";
35019
34767
  import { jsx as jsx54, jsxs as jsxs37 } from "react/jsx-runtime";
35020
34768
  function getFilePath(args) {
@@ -35029,7 +34777,7 @@ function getFilePath(args) {
35029
34777
  function readExistingFileText(filePath) {
35030
34778
  if (!filePath) return "";
35031
34779
  try {
35032
- return fs42.readFileSync(filePath, "utf-8");
34780
+ return fs43.readFileSync(filePath, "utf-8");
35033
34781
  } catch {
35034
34782
  return "";
35035
34783
  }
@@ -36345,7 +36093,7 @@ function renderToolUseMessage35({ args }) {
36345
36093
  function renderToolHeader35({ args }) {
36346
36094
  return /* @__PURE__ */ jsxs51(Box_default, { flexDirection: "row", gap: 1, alignItems: "flex-end", children: [
36347
36095
  /* @__PURE__ */ jsx68(Text, { bold: true, color: BLUMA_TERMINAL.m3OnSurface, children: "Create App" }),
36348
- /* @__PURE__ */ jsx68(Text, { color: BLUMA_TERMINAL.dim, children: args?.template ?? "full" })
36096
+ /* @__PURE__ */ jsx68(Text, { color: BLUMA_TERMINAL.dim, children: "FactorAI scaffold" })
36349
36097
  ] });
36350
36098
  }
36351
36099
  function renderToolMessage34({
@@ -36370,11 +36118,20 @@ function renderToolResultMessage35(result) {
36370
36118
  ] });
36371
36119
  }
36372
36120
  return /* @__PURE__ */ jsxs51(Box_default, { flexDirection: "column", children: [
36121
+ result.summary && /* @__PURE__ */ jsx68(Text, { color: BLUMA_TERMINAL.m3OnSurface, wrap: "wrap", children: result.summary }),
36373
36122
  result.projectPath && /* @__PURE__ */ jsxs51(Box_default, { flexDirection: "row", children: [
36374
36123
  /* @__PURE__ */ jsx68(Text, { color: BLUMA_TERMINAL.dim, children: "\u2514\u2500 " }),
36375
36124
  /* @__PURE__ */ jsx68(FilePathLink, { filePath: result.projectPath, color: BLUMA_TERMINAL.dim })
36376
36125
  ] }),
36377
- Array.isArray(result.filesCreated) && result.filesCreated.length > 0 && /* @__PURE__ */ jsxs51(Text, { color: BLUMA_TERMINAL.m3OnSurface, children: [
36126
+ typeof result.uiComponentCount === "number" && /* @__PURE__ */ jsxs51(Text, { color: BLUMA_TERMINAL.dim, children: [
36127
+ result.uiComponentCount,
36128
+ " UI components \xB7 DESIGN.md written"
36129
+ ] }),
36130
+ result.designDocPath && /* @__PURE__ */ jsxs51(Box_default, { flexDirection: "row", children: [
36131
+ /* @__PURE__ */ jsx68(Text, { color: BLUMA_TERMINAL.dim, children: "\u2514\u2500 " }),
36132
+ /* @__PURE__ */ jsx68(FilePathLink, { filePath: result.designDocPath, color: BLUMA_TERMINAL.dim })
36133
+ ] }),
36134
+ Array.isArray(result.filesCreated) && result.filesCreated.length > 0 && /* @__PURE__ */ jsxs51(Text, { color: BLUMA_TERMINAL.dim, children: [
36378
36135
  result.filesCreated.length,
36379
36136
  " files created"
36380
36137
  ] }),
@@ -37959,8 +37716,8 @@ import {
37959
37716
 
37960
37717
  // src/app/ui/hooks/useAtCompletion.ts
37961
37718
  import { useEffect as useEffect11, useRef as useRef4, useState as useState13 } from "react";
37962
- import fs43 from "fs";
37963
- import path50 from "path";
37719
+ import fs44 from "fs";
37720
+ import path51 from "path";
37964
37721
  var MAX_RESULTS3 = 50;
37965
37722
  var DEFAULT_RECURSIVE_DEPTH = 2;
37966
37723
  function listPathSuggestions(baseDir, pattern) {
@@ -37968,7 +37725,7 @@ function listPathSuggestions(baseDir, pattern) {
37968
37725
  const patternEndsWithSlash = raw.endsWith("/");
37969
37726
  const relDir = raw.replace(/^\/+|\/+$/g, "");
37970
37727
  const filterPrefix = patternEndsWithSlash ? "" : relDir.split("/").slice(-1)[0] || "";
37971
- const listDir = path50.resolve(baseDir, relDir || ".");
37728
+ const listDir = path51.resolve(baseDir, relDir || ".");
37972
37729
  const results = [];
37973
37730
  const IGNORED_DIRS = ["node_modules", ".git", ".venv", "dist", "build"];
37974
37731
  const IGNORED_EXTS = [".pyc", ".class", ".o", ".map", ".log", ".tmp"];
@@ -37985,7 +37742,7 @@ function listPathSuggestions(baseDir, pattern) {
37985
37742
  }
37986
37743
  function pushEntry(entryPath, label, isDir) {
37987
37744
  if (results.length >= MAX_RESULTS3) return;
37988
- const clean = label.split(path50.sep).join("/").replace(/[]+/g, "");
37745
+ const clean = label.split(path51.sep).join("/").replace(/[]+/g, "");
37989
37746
  results.push({ label: clean + (isDir ? "/" : ""), fullPath: entryPath, isDir });
37990
37747
  }
37991
37748
  try {
@@ -37994,11 +37751,11 @@ function listPathSuggestions(baseDir, pattern) {
37994
37751
  while (queue.length && results.length < MAX_RESULTS3) {
37995
37752
  const node = queue.shift();
37996
37753
  try {
37997
- const entries = fs43.readdirSync(node.dir, { withFileTypes: true });
37754
+ const entries = fs44.readdirSync(node.dir, { withFileTypes: true });
37998
37755
  for (const entry of entries) {
37999
37756
  if (isIgnoredName(entry.name)) continue;
38000
- const entryAbs = path50.join(node.dir, entry.name);
38001
- const entryRel = node.rel ? path50.posix.join(node.rel, entry.name) : entry.name;
37757
+ const entryAbs = path51.join(node.dir, entry.name);
37758
+ const entryRel = node.rel ? path51.posix.join(node.rel, entry.name) : entry.name;
38002
37759
  if (entryRel.split("/").includes("node_modules")) continue;
38003
37760
  if (!entry.isDirectory() && isIgnoredFile(entry.name)) continue;
38004
37761
  pushEntry(entryAbs, entryRel, entry.isDirectory());
@@ -38011,13 +37768,13 @@ function listPathSuggestions(baseDir, pattern) {
38011
37768
  }
38012
37769
  }
38013
37770
  } else {
38014
- const entries = fs43.readdirSync(listDir, { withFileTypes: true });
37771
+ const entries = fs44.readdirSync(listDir, { withFileTypes: true });
38015
37772
  for (const entry of entries) {
38016
37773
  if (filterPrefix && !entry.name.startsWith(filterPrefix)) continue;
38017
37774
  if (isIgnoredName(entry.name)) continue;
38018
37775
  if (!entry.isDirectory() && isIgnoredFile(entry.name)) continue;
38019
- const entryAbs = path50.join(listDir, entry.name);
38020
- const label = relDir ? path50.posix.join(relDir, entry.name) : entry.name;
37776
+ const entryAbs = path51.join(listDir, entry.name);
37777
+ const label = relDir ? path51.posix.join(relDir, entry.name) : entry.name;
38021
37778
  pushEntry(entryAbs, label, entry.isDirectory());
38022
37779
  if (results.length >= MAX_RESULTS3) break;
38023
37780
  }
@@ -38218,9 +37975,9 @@ var SlashSubmenuInlineComponent = ({ menu }) => {
38218
37975
  var SlashSubmenuInline = memo15(SlashSubmenuInlineComponent);
38219
37976
 
38220
37977
  // src/app/ui/utils/clipboardImage.ts
38221
- import fs44 from "fs";
37978
+ import fs45 from "fs";
38222
37979
  import os32 from "os";
38223
- import path51 from "path";
37980
+ import path52 from "path";
38224
37981
  import { spawn as spawn5, execFile as execFileCb, execSync as execSync4 } from "child_process";
38225
37982
  import { promisify as promisify2 } from "util";
38226
37983
 
@@ -38228,12 +37985,12 @@ import { promisify as promisify2 } from "util";
38228
37985
  import { existsSync as existsSync7 } from "fs";
38229
37986
  import { createRequire as createRequire2 } from "module";
38230
37987
  import { dirname as dirname4, join as join13 } from "path";
38231
- import { fileURLToPath as fileURLToPath5 } from "url";
37988
+ import { fileURLToPath as fileURLToPath6 } from "url";
38232
37989
  var __dirname;
38233
37990
  function getDirname() {
38234
37991
  if (!__dirname) {
38235
37992
  try {
38236
- __dirname = dirname4(fileURLToPath5(import.meta.url));
37993
+ __dirname = dirname4(fileURLToPath6(import.meta.url));
38237
37994
  } catch {
38238
37995
  __dirname = process.cwd();
38239
37996
  }
@@ -38349,8 +38106,8 @@ function commandOnPath(cmd) {
38349
38106
  function unixClipboardHelperDirs() {
38350
38107
  const h = os32.homedir();
38351
38108
  return [
38352
- path51.join(h, ".local", "bin"),
38353
- path51.join(h, "bin"),
38109
+ path52.join(h, ".local", "bin"),
38110
+ path52.join(h, "bin"),
38354
38111
  "/usr/bin",
38355
38112
  "/usr/local/bin",
38356
38113
  "/bin",
@@ -38368,16 +38125,16 @@ function resolveHelperBinary(cmd) {
38368
38125
  return cmd;
38369
38126
  }
38370
38127
  for (const dir of unixClipboardHelperDirs()) {
38371
- const full = path51.join(dir, cmd);
38128
+ const full = path52.join(dir, cmd);
38372
38129
  try {
38373
- fs44.accessSync(full, fs44.constants.X_OK);
38130
+ fs45.accessSync(full, fs45.constants.X_OK);
38374
38131
  return full;
38375
38132
  } catch {
38376
38133
  }
38377
38134
  }
38378
38135
  for (const dir of unixClipboardHelperDirs()) {
38379
- const full = path51.join(dir, cmd);
38380
- if (fs44.existsSync(full)) {
38136
+ const full = path52.join(dir, cmd);
38137
+ if (fs45.existsSync(full)) {
38381
38138
  return full;
38382
38139
  }
38383
38140
  }
@@ -38418,17 +38175,17 @@ function writeBufferIfImage(baseDir, buf) {
38418
38175
  if (!ext) {
38419
38176
  return null;
38420
38177
  }
38421
- const out = path51.join(
38178
+ const out = path52.join(
38422
38179
  baseDir,
38423
38180
  `clip-${Date.now()}-${Math.random().toString(36).slice(2, 8)}${ext}`
38424
38181
  );
38425
- fs44.writeFileSync(out, buf);
38182
+ fs45.writeFileSync(out, buf);
38426
38183
  return out;
38427
38184
  }
38428
38185
  function unlinkQuiet(p) {
38429
38186
  try {
38430
- if (fs44.existsSync(p)) {
38431
- fs44.unlinkSync(p);
38187
+ if (fs45.existsSync(p)) {
38188
+ fs45.unlinkSync(p);
38432
38189
  }
38433
38190
  } catch {
38434
38191
  }
@@ -38445,25 +38202,25 @@ async function tryDarwinClipboardy(baseDir) {
38445
38202
  return null;
38446
38203
  }
38447
38204
  for (const src of tmpPaths) {
38448
- if (!src || !fs44.existsSync(src)) {
38205
+ if (!src || !fs45.existsSync(src)) {
38449
38206
  continue;
38450
38207
  }
38451
38208
  let st;
38452
38209
  try {
38453
- st = fs44.statSync(src);
38210
+ st = fs45.statSync(src);
38454
38211
  } catch {
38455
38212
  continue;
38456
38213
  }
38457
38214
  if (st.size < 80 || st.size > CLIPBOARD_MAX_BYTES) {
38458
38215
  continue;
38459
38216
  }
38460
- const ext = path51.extname(src).toLowerCase();
38217
+ const ext = path52.extname(src).toLowerCase();
38461
38218
  const safeExt = ext && /^\.(png|jpe?g|gif|webp)$/i.test(ext) ? ext : ".png";
38462
- const out = path51.join(
38219
+ const out = path52.join(
38463
38220
  baseDir,
38464
38221
  `clip-${Date.now()}-${Math.random().toString(36).slice(2, 8)}${safeExt}`
38465
38222
  );
38466
- fs44.copyFileSync(src, out);
38223
+ fs45.copyFileSync(src, out);
38467
38224
  for (const p of tmpPaths) {
38468
38225
  unlinkQuiet(p);
38469
38226
  }
@@ -38477,14 +38234,14 @@ async function tryDarwinClipboardy(baseDir) {
38477
38234
  return null;
38478
38235
  }
38479
38236
  async function tryWindowsPowerShell(outFile) {
38480
- const ps = process.env.SystemRoot != null ? path51.join(
38237
+ const ps = process.env.SystemRoot != null ? path52.join(
38481
38238
  process.env.SystemRoot,
38482
38239
  "System32",
38483
38240
  "WindowsPowerShell",
38484
38241
  "v1.0",
38485
38242
  "powershell.exe"
38486
38243
  ) : "powershell.exe";
38487
- if (!fs44.existsSync(ps)) {
38244
+ if (!fs45.existsSync(ps)) {
38488
38245
  return false;
38489
38246
  }
38490
38247
  const script = "$ErrorActionPreference='Stop';Add-Type -AssemblyName System.Windows.Forms;Add-Type -AssemblyName System.Drawing;$img=[System.Windows.Forms.Clipboard]::GetImage();if($null -eq $img){exit 2};$img.Save($env:BLUMA_CLIP_OUT,[System.Drawing.Imaging.ImageFormat]::Png);exit 0";
@@ -38506,7 +38263,7 @@ async function tryWindowsPowerShell(outFile) {
38506
38263
  return false;
38507
38264
  }
38508
38265
  try {
38509
- const st = fs44.statSync(outFile);
38266
+ const st = fs45.statSync(outFile);
38510
38267
  return st.size >= 80 && st.size <= CLIPBOARD_MAX_BYTES;
38511
38268
  } catch {
38512
38269
  return false;
@@ -38578,8 +38335,8 @@ function parseClipboardTextAsImagePath(raw) {
38578
38335
  s = s.slice(1, -1);
38579
38336
  }
38580
38337
  s = s.trim();
38581
- if (!CLIPBOARD_PATH_IMAGE_EXT.test(path51.extname(s))) return null;
38582
- const abs = path51.isAbsolute(s) ? path51.normalize(s) : path51.resolve(process.cwd(), s);
38338
+ if (!CLIPBOARD_PATH_IMAGE_EXT.test(path52.extname(s))) return null;
38339
+ const abs = path52.isAbsolute(s) ? path52.normalize(s) : path52.resolve(process.cwd(), s);
38583
38340
  return abs;
38584
38341
  }
38585
38342
  async function tryClipboardTextAsImageFile(baseDir) {
@@ -38593,19 +38350,19 @@ async function tryClipboardTextAsImageFile(baseDir) {
38593
38350
  const abs = parseClipboardTextAsImagePath(t);
38594
38351
  if (!abs) return null;
38595
38352
  try {
38596
- if (!fs44.existsSync(abs)) return null;
38597
- const st = fs44.statSync(abs);
38353
+ if (!fs45.existsSync(abs)) return null;
38354
+ const st = fs45.statSync(abs);
38598
38355
  if (!st.isFile() || st.size > CLIPBOARD_MAX_BYTES || st.size < 20) return null;
38599
38356
  } catch {
38600
38357
  return null;
38601
38358
  }
38602
- const ext = path51.extname(abs).toLowerCase();
38603
- const out = path51.join(
38359
+ const ext = path52.extname(abs).toLowerCase();
38360
+ const out = path52.join(
38604
38361
  baseDir,
38605
38362
  `clip-${Date.now()}-${Math.random().toString(36).slice(2, 8)}${ext}`
38606
38363
  );
38607
38364
  try {
38608
- fs44.copyFileSync(abs, out);
38365
+ fs45.copyFileSync(abs, out);
38609
38366
  return out;
38610
38367
  } catch {
38611
38368
  return null;
@@ -38615,7 +38372,7 @@ async function tryLinuxShellPipelineSave(baseDir) {
38615
38372
  if (process.platform !== "linux" && process.platform !== "freebsd") {
38616
38373
  return null;
38617
38374
  }
38618
- const outPath = path51.join(
38375
+ const outPath = path52.join(
38619
38376
  baseDir,
38620
38377
  `clip-${Date.now()}-${Math.random().toString(36).slice(2, 8)}.tmp`
38621
38378
  );
@@ -38637,11 +38394,11 @@ printf '%s' "$OUT"
38637
38394
  maxBuffer: 4096
38638
38395
  });
38639
38396
  const written = String(stdout ?? "").trim();
38640
- if (written !== outPath || !fs44.existsSync(outPath)) {
38397
+ if (written !== outPath || !fs45.existsSync(outPath)) {
38641
38398
  unlinkQuiet(outPath);
38642
38399
  return null;
38643
38400
  }
38644
- const buf = fs44.readFileSync(outPath);
38401
+ const buf = fs45.readFileSync(outPath);
38645
38402
  unlinkQuiet(outPath);
38646
38403
  return writeBufferIfImage(baseDir, buf);
38647
38404
  } catch {
@@ -38662,8 +38419,8 @@ async function tryNativeClipboardImage() {
38662
38419
  }
38663
38420
  try {
38664
38421
  const result = readClipboardImageNative();
38665
- if (fs44.existsSync(result.path)) {
38666
- const st = fs44.statSync(result.path);
38422
+ if (fs45.existsSync(result.path)) {
38423
+ const st = fs45.statSync(result.path);
38667
38424
  if (st.size >= 80 && st.size <= CLIPBOARD_MAX_BYTES) {
38668
38425
  return result.path;
38669
38426
  }
@@ -38673,8 +38430,8 @@ async function tryNativeClipboardImage() {
38673
38430
  return null;
38674
38431
  }
38675
38432
  async function readClipboardImageToTempFile() {
38676
- const baseDir = path51.join(os32.homedir(), ".cache", "bluma", "clipboard");
38677
- fs44.mkdirSync(baseDir, { recursive: true });
38433
+ const baseDir = path52.join(os32.homedir(), ".cache", "bluma", "clipboard");
38434
+ fs45.mkdirSync(baseDir, { recursive: true });
38678
38435
  const nativeResult = await tryNativeClipboardImage();
38679
38436
  if (nativeResult) {
38680
38437
  return nativeResult;
@@ -38692,7 +38449,7 @@ async function readClipboardImageToTempFile() {
38692
38449
  }
38693
38450
  }
38694
38451
  if (process.platform === "win32") {
38695
- const outFile = path51.join(
38452
+ const outFile = path52.join(
38696
38453
  baseDir,
38697
38454
  `clip-${Date.now()}-${Math.random().toString(36).slice(2, 8)}.png`
38698
38455
  );
@@ -38733,7 +38490,7 @@ function expandLargePastePlaceholder(value, pending) {
38733
38490
  }
38734
38491
 
38735
38492
  // src/app/ui/components/InputPrompt.tsx
38736
- import fs45 from "fs";
38493
+ import fs46 from "fs";
38737
38494
  import { Fragment as Fragment7, jsx as jsx79, jsxs as jsxs62 } from "react/jsx-runtime";
38738
38495
  var persistedInputState = { text: "", cursorPosition: 0 };
38739
38496
  var StaticCursor = () => /* @__PURE__ */ jsx79(Box_default, { flexDirection: "row", flexWrap: "nowrap", children: /* @__PURE__ */ jsx79(Text, { bold: true, color: BLUMA_TERMINAL.m3OnSurface, children: "\u2588 " }) });
@@ -38900,7 +38657,7 @@ var InputPrompt = memo16(({
38900
38657
  return;
38901
38658
  }
38902
38659
  if (routeText.startsWith("/")) {
38903
- const isFilePath = map.size > 0 && fs45.existsSync(routeText.split(/\s+/)[0]);
38660
+ const isFilePath = map.size > 0 && fs46.existsSync(routeText.split(/\s+/)[0]);
38904
38661
  if (isFilePath) {
38905
38662
  uiEventBus.emit("user_overlay", {
38906
38663
  kind: "message",
@@ -41181,8 +40938,8 @@ var renderCode = () => {
41181
40938
 
41182
40939
  // src/app/agent/core/thread/thread_store.ts
41183
40940
  init_bluma_app_dir();
41184
- import path52 from "path";
41185
- import { promises as fs46 } from "fs";
40941
+ import path53 from "path";
40942
+ import { promises as fs47 } from "fs";
41186
40943
  import { randomUUID as randomUUID2 } from "crypto";
41187
40944
  var INDEX_VERSION = 1;
41188
40945
  var fileLocks2 = /* @__PURE__ */ new Map();
@@ -41207,9 +40964,9 @@ var ThreadStore = class {
41207
40964
  packageVersion;
41208
40965
  constructor() {
41209
40966
  const appDir = getPreferredAppDir();
41210
- this.threadsDir = path52.join(appDir, "threads");
41211
- this.archiveDir = path52.join(this.threadsDir, "archive");
41212
- this.indexPath = path52.join(this.threadsDir, "index.json");
40967
+ this.threadsDir = path53.join(appDir, "threads");
40968
+ this.archiveDir = path53.join(this.threadsDir, "archive");
40969
+ this.indexPath = path53.join(this.threadsDir, "index.json");
41213
40970
  this.packageVersion = process.env.npm_package_version || "0.0.0";
41214
40971
  }
41215
40972
  // ==================== Inicialização ====================
@@ -41217,10 +40974,10 @@ var ThreadStore = class {
41217
40974
  * Inicializa o diretório de threads
41218
40975
  */
41219
40976
  async initialize() {
41220
- await fs46.mkdir(this.threadsDir, { recursive: true });
41221
- await fs46.mkdir(this.archiveDir, { recursive: true });
40977
+ await fs47.mkdir(this.threadsDir, { recursive: true });
40978
+ await fs47.mkdir(this.archiveDir, { recursive: true });
41222
40979
  try {
41223
- await fs46.access(this.indexPath);
40980
+ await fs47.access(this.indexPath);
41224
40981
  } catch {
41225
40982
  await this.saveIndex({ version: INDEX_VERSION, threads: [], lastUpdated: (/* @__PURE__ */ new Date()).toISOString() });
41226
40983
  }
@@ -41249,7 +41006,7 @@ var ThreadStore = class {
41249
41006
  async loadIndex() {
41250
41007
  return withFileLock2(this.indexPath, async () => {
41251
41008
  try {
41252
- const content = await fs46.readFile(this.indexPath, "utf-8");
41009
+ const content = await fs47.readFile(this.indexPath, "utf-8");
41253
41010
  return JSON.parse(content);
41254
41011
  } catch {
41255
41012
  return { version: INDEX_VERSION, threads: [], lastUpdated: (/* @__PURE__ */ new Date()).toISOString() };
@@ -41260,8 +41017,8 @@ var ThreadStore = class {
41260
41017
  return withFileLock2(this.indexPath, async () => {
41261
41018
  index.lastUpdated = (/* @__PURE__ */ new Date()).toISOString();
41262
41019
  const tempPath = `${this.indexPath}.${Date.now()}.tmp`;
41263
- await fs46.writeFile(tempPath, JSON.stringify(index, null, 2), "utf-8");
41264
- await fs46.rename(tempPath, this.indexPath);
41020
+ await fs47.writeFile(tempPath, JSON.stringify(index, null, 2), "utf-8");
41021
+ await fs47.rename(tempPath, this.indexPath);
41265
41022
  });
41266
41023
  }
41267
41024
  // ==================== Git Info ====================
@@ -41331,7 +41088,7 @@ var ThreadStore = class {
41331
41088
  messages: params.initialMessages || []
41332
41089
  };
41333
41090
  const historyPath = this.buildDatedThreadHistoryPath(threadId);
41334
- await fs46.mkdir(path52.dirname(historyPath), { recursive: true });
41091
+ await fs47.mkdir(path53.dirname(historyPath), { recursive: true });
41335
41092
  await this.saveHistoryAtPath(historyPath, history);
41336
41093
  const index = await this.loadIndex();
41337
41094
  index.threads.unshift({
@@ -41386,7 +41143,7 @@ var ThreadStore = class {
41386
41143
  compressedSliceCount: source.history.compressedSliceCount
41387
41144
  };
41388
41145
  const historyPath = this.buildDatedThreadHistoryPath(newThreadId);
41389
- await fs46.mkdir(path52.dirname(historyPath), { recursive: true });
41146
+ await fs47.mkdir(path53.dirname(historyPath), { recursive: true });
41390
41147
  await this.saveHistoryAtPath(historyPath, history);
41391
41148
  const index = await this.loadIndex();
41392
41149
  index.threads.unshift({
@@ -41459,9 +41216,9 @@ var ThreadStore = class {
41459
41216
  const entry = index.threads[entryIndex];
41460
41217
  if (entry.status === "archived") return true;
41461
41218
  const oldPath = entry.historyPath || this.getLegacyHistoryPath(threadId);
41462
- const newPath = path52.join(this.archiveDir, `${threadId}.jsonl`);
41219
+ const newPath = path53.join(this.archiveDir, `${threadId}.jsonl`);
41463
41220
  try {
41464
- await fs46.rename(oldPath, newPath);
41221
+ await fs47.rename(oldPath, newPath);
41465
41222
  } catch (e) {
41466
41223
  if (e.code !== "ENOENT") throw e;
41467
41224
  }
@@ -41482,11 +41239,11 @@ var ThreadStore = class {
41482
41239
  if (entryIndex === -1) return false;
41483
41240
  const entry = index.threads[entryIndex];
41484
41241
  if (entry.status === "active") return true;
41485
- const oldPath = path52.join(this.archiveDir, `${threadId}.jsonl`);
41242
+ const oldPath = path53.join(this.archiveDir, `${threadId}.jsonl`);
41486
41243
  const newPath = this.buildDatedThreadHistoryPath(threadId);
41487
- await fs46.mkdir(path52.dirname(newPath), { recursive: true });
41244
+ await fs47.mkdir(path53.dirname(newPath), { recursive: true });
41488
41245
  try {
41489
- await fs46.rename(oldPath, newPath);
41246
+ await fs47.rename(oldPath, newPath);
41490
41247
  } catch (e) {
41491
41248
  if (e.code !== "ENOENT") throw e;
41492
41249
  }
@@ -41507,7 +41264,7 @@ var ThreadStore = class {
41507
41264
  if (entryIndex === -1) return false;
41508
41265
  const entry = index.threads[entryIndex];
41509
41266
  try {
41510
- await fs46.unlink(entry.historyPath);
41267
+ await fs47.unlink(entry.historyPath);
41511
41268
  } catch {
41512
41269
  }
41513
41270
  index.threads.splice(entryIndex, 1);
@@ -41517,28 +41274,28 @@ var ThreadStore = class {
41517
41274
  }
41518
41275
  // ==================== Histórico ====================
41519
41276
  getLegacyHistoryPath(threadId) {
41520
- return path52.join(this.threadsDir, `${threadId}.jsonl`);
41277
+ return path53.join(this.threadsDir, `${threadId}.jsonl`);
41521
41278
  }
41522
41279
  /** ~/.bluma/threads/YYYY/MM/DD/<threadId>.jsonl (data local de criação). */
41523
41280
  buildDatedThreadHistoryPath(threadId, at = /* @__PURE__ */ new Date()) {
41524
41281
  const y = String(at.getFullYear());
41525
41282
  const mo = String(at.getMonth() + 1).padStart(2, "0");
41526
41283
  const d = String(at.getDate()).padStart(2, "0");
41527
- return path52.join(this.threadsDir, y, mo, d, `${threadId}.jsonl`);
41284
+ return path53.join(this.threadsDir, y, mo, d, `${threadId}.jsonl`);
41528
41285
  }
41529
41286
  async resolveHistoryPath(threadId) {
41530
41287
  const index = await this.loadIndex();
41531
41288
  const entry = index.threads.find((t) => t.threadId === threadId);
41532
41289
  if (entry?.historyPath) {
41533
41290
  try {
41534
- await fs46.access(entry.historyPath);
41291
+ await fs47.access(entry.historyPath);
41535
41292
  return entry.historyPath;
41536
41293
  } catch {
41537
41294
  }
41538
41295
  }
41539
41296
  const legacy = this.getLegacyHistoryPath(threadId);
41540
41297
  try {
41541
- await fs46.access(legacy);
41298
+ await fs47.access(legacy);
41542
41299
  return legacy;
41543
41300
  } catch {
41544
41301
  return entry?.historyPath ?? legacy;
@@ -41555,9 +41312,9 @@ var ThreadStore = class {
41555
41312
  for (const msg of history.messages) {
41556
41313
  lines.push(JSON.stringify({ type: "message", ...msg }));
41557
41314
  }
41558
- await fs46.mkdir(path52.dirname(historyPath), { recursive: true }).catch(() => {
41315
+ await fs47.mkdir(path53.dirname(historyPath), { recursive: true }).catch(() => {
41559
41316
  });
41560
- await fs46.writeFile(historyPath, lines.join("\n") + "\n", "utf-8");
41317
+ await fs47.writeFile(historyPath, lines.join("\n") + "\n", "utf-8");
41561
41318
  }
41562
41319
  /**
41563
41320
  * Guarda o histórico de uma thread
@@ -41579,7 +41336,7 @@ var ThreadStore = class {
41579
41336
  ].filter((p, i, arr) => Boolean(p) && arr.indexOf(p) === i);
41580
41337
  for (const historyPath of pathsToTry) {
41581
41338
  try {
41582
- const content = await fs46.readFile(historyPath, "utf-8");
41339
+ const content = await fs47.readFile(historyPath, "utf-8");
41583
41340
  const lines = content.split("\n").filter(Boolean);
41584
41341
  const history = {
41585
41342
  threadId,
@@ -41614,7 +41371,7 @@ var ThreadStore = class {
41614
41371
  const entry = index.threads.find((t) => t.threadId === threadId);
41615
41372
  if (!entry) throw new Error(`Thread not found: ${threadId}`);
41616
41373
  const lines = messages.map((msg) => JSON.stringify({ type: "message", ...msg }));
41617
- await fs46.appendFile(entry.historyPath, lines.join("\n") + "\n", "utf-8");
41374
+ await fs47.appendFile(entry.historyPath, lines.join("\n") + "\n", "utf-8");
41618
41375
  entry.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
41619
41376
  await this.saveIndex(index);
41620
41377
  }
@@ -44486,17 +44243,17 @@ var SlashCommands_default = SlashCommands;
44486
44243
  import latestVersion from "latest-version";
44487
44244
  import semverGt from "semver/functions/gt.js";
44488
44245
  import semverValid from "semver/functions/valid.js";
44489
- import { fileURLToPath as fileURLToPath6 } from "url";
44490
- import path53 from "path";
44491
- import fs47 from "fs";
44246
+ import { fileURLToPath as fileURLToPath7 } from "url";
44247
+ import path54 from "path";
44248
+ import fs48 from "fs";
44492
44249
  var BLUMA_PACKAGE_NAME = "@nomad-e/bluma-cli";
44493
44250
  function findBlumaPackageJson(startDir) {
44494
44251
  let dir = startDir;
44495
44252
  for (let i = 0; i < 12; i++) {
44496
- const candidate = path53.join(dir, "package.json");
44497
- if (fs47.existsSync(candidate)) {
44253
+ const candidate = path54.join(dir, "package.json");
44254
+ if (fs48.existsSync(candidate)) {
44498
44255
  try {
44499
- const raw = fs47.readFileSync(candidate, "utf8");
44256
+ const raw = fs48.readFileSync(candidate, "utf8");
44500
44257
  const parsed = JSON.parse(raw);
44501
44258
  if (parsed?.name === BLUMA_PACKAGE_NAME && parsed?.version) {
44502
44259
  return { name: parsed.name, version: String(parsed.version) };
@@ -44504,7 +44261,7 @@ function findBlumaPackageJson(startDir) {
44504
44261
  } catch {
44505
44262
  }
44506
44263
  }
44507
- const parent = path53.dirname(dir);
44264
+ const parent = path54.dirname(dir);
44508
44265
  if (parent === dir) break;
44509
44266
  dir = parent;
44510
44267
  }
@@ -44513,13 +44270,13 @@ function findBlumaPackageJson(startDir) {
44513
44270
  function resolveInstalledBlumaPackage() {
44514
44271
  const tried = /* @__PURE__ */ new Set();
44515
44272
  const tryFrom = (dir) => {
44516
- const abs = path53.resolve(dir);
44273
+ const abs = path54.resolve(dir);
44517
44274
  if (tried.has(abs)) return null;
44518
44275
  tried.add(abs);
44519
44276
  return findBlumaPackageJson(abs);
44520
44277
  };
44521
44278
  try {
44522
- const fromBundle = tryFrom(path53.dirname(fileURLToPath6(import.meta.url)));
44279
+ const fromBundle = tryFrom(path54.dirname(fileURLToPath7(import.meta.url)));
44523
44280
  if (fromBundle) return fromBundle;
44524
44281
  } catch {
44525
44282
  }
@@ -44527,12 +44284,12 @@ function resolveInstalledBlumaPackage() {
44527
44284
  if (argv1 && !argv1.startsWith("-")) {
44528
44285
  try {
44529
44286
  let resolved = argv1;
44530
- if (path53.isAbsolute(argv1) && fs47.existsSync(argv1)) {
44531
- resolved = fs47.realpathSync(argv1);
44287
+ if (path54.isAbsolute(argv1) && fs48.existsSync(argv1)) {
44288
+ resolved = fs48.realpathSync(argv1);
44532
44289
  } else {
44533
- resolved = path53.resolve(process.cwd(), argv1);
44290
+ resolved = path54.resolve(process.cwd(), argv1);
44534
44291
  }
44535
- const fromArgv = tryFrom(path53.dirname(resolved));
44292
+ const fromArgv = tryFrom(path54.dirname(resolved));
44536
44293
  if (fromArgv) return fromArgv;
44537
44294
  } catch {
44538
44295
  }
@@ -45351,16 +45108,16 @@ function usePlanMode() {
45351
45108
 
45352
45109
  // src/app/hooks/useAgentMode.ts
45353
45110
  import { useState as useState22, useEffect as useEffect21, useCallback as useCallback9 } from "react";
45354
- import * as fs48 from "fs";
45355
- import * as path54 from "path";
45111
+ import * as fs49 from "fs";
45112
+ import * as path55 from "path";
45356
45113
  import { homedir as homedir4 } from "os";
45357
- var SETTINGS_PATH = path54.join(homedir4(), ".bluma", "settings.json");
45114
+ var SETTINGS_PATH = path55.join(homedir4(), ".bluma", "settings.json");
45358
45115
  function readAgentModeFromFile() {
45359
45116
  try {
45360
- if (!fs48.existsSync(SETTINGS_PATH)) {
45117
+ if (!fs49.existsSync(SETTINGS_PATH)) {
45361
45118
  return "default";
45362
45119
  }
45363
- const content = fs48.readFileSync(SETTINGS_PATH, "utf-8");
45120
+ const content = fs49.readFileSync(SETTINGS_PATH, "utf-8");
45364
45121
  const settings = JSON.parse(content);
45365
45122
  return settings.agentMode || "default";
45366
45123
  } catch (error) {
@@ -45379,16 +45136,16 @@ function useAgentMode() {
45379
45136
  }, []);
45380
45137
  const updateAgentMode = useCallback9((mode) => {
45381
45138
  try {
45382
- if (!fs48.existsSync(SETTINGS_PATH)) {
45383
- fs48.mkdirSync(path54.dirname(SETTINGS_PATH), { recursive: true });
45139
+ if (!fs49.existsSync(SETTINGS_PATH)) {
45140
+ fs49.mkdirSync(path55.dirname(SETTINGS_PATH), { recursive: true });
45384
45141
  }
45385
45142
  let settings = {};
45386
- if (fs48.existsSync(SETTINGS_PATH)) {
45387
- const content = fs48.readFileSync(SETTINGS_PATH, "utf-8");
45143
+ if (fs49.existsSync(SETTINGS_PATH)) {
45144
+ const content = fs49.readFileSync(SETTINGS_PATH, "utf-8");
45388
45145
  settings = JSON.parse(content);
45389
45146
  }
45390
45147
  settings.agentMode = mode;
45391
- fs48.writeFileSync(SETTINGS_PATH, JSON.stringify(settings, null, 2), "utf-8");
45148
+ fs49.writeFileSync(SETTINGS_PATH, JSON.stringify(settings, null, 2), "utf-8");
45392
45149
  setAgentMode(mode);
45393
45150
  } catch (error) {
45394
45151
  console.error("Failed to update agent mode:", error);
@@ -46652,10 +46409,10 @@ import { memo as memo26, useCallback as useCallback11, useEffect as useEffect23,
46652
46409
 
46653
46410
  // src/app/agent/session_manager/session_resume_browser.ts
46654
46411
  init_bluma_app_dir();
46655
- import path55 from "path";
46656
- import { promises as fs49 } from "fs";
46412
+ import path56 from "path";
46413
+ import { promises as fs50 } from "fs";
46657
46414
  function getSessionsRoot() {
46658
- return path55.join(getPreferredAppDir(), "sessions");
46415
+ return path56.join(getPreferredAppDir(), "sessions");
46659
46416
  }
46660
46417
  function normalizeSessionsCwd(cwd2) {
46661
46418
  return cwd2.replace(/\\/g, "/").split("/").filter((p) => p && p !== "." && p !== "..").join("/");
@@ -46676,9 +46433,9 @@ async function sessionEntryFromFile(absPath, sessionId) {
46676
46433
  let preview = "(no messages)";
46677
46434
  let lastActivityMs = Date.now();
46678
46435
  try {
46679
- const st = await fs49.stat(absPath);
46436
+ const st = await fs50.stat(absPath);
46680
46437
  lastActivityMs = st.mtimeMs;
46681
- const raw = await fs49.readFile(absPath, "utf-8");
46438
+ const raw = await fs50.readFile(absPath, "utf-8");
46682
46439
  const data = JSON.parse(raw);
46683
46440
  preview = previewFromHistory(data.conversation_history);
46684
46441
  const iso = data.last_updated || data.created_at;
@@ -46706,15 +46463,15 @@ function compareDirNames(a, b) {
46706
46463
  async function listSessionBrowserEntries(cwdRel) {
46707
46464
  const cwd2 = normalizeSessionsCwd(cwdRel);
46708
46465
  const root = getSessionsRoot();
46709
- const absDir = cwd2 ? path55.join(root, ...cwd2.split("/")) : root;
46466
+ const absDir = cwd2 ? path56.join(root, ...cwd2.split("/")) : root;
46710
46467
  const out = [];
46711
46468
  if (cwd2) {
46712
46469
  out.push({ kind: "up", label: ".." });
46713
46470
  }
46714
46471
  let dirents;
46715
46472
  try {
46716
- await fs49.mkdir(absDir, { recursive: true });
46717
- dirents = await fs49.readdir(absDir, { withFileTypes: true });
46473
+ await fs50.mkdir(absDir, { recursive: true });
46474
+ dirents = await fs50.readdir(absDir, { withFileTypes: true });
46718
46475
  } catch {
46719
46476
  return out;
46720
46477
  }
@@ -46723,7 +46480,7 @@ async function listSessionBrowserEntries(cwdRel) {
46723
46480
  for (const e of dirents) {
46724
46481
  const name = String(e.name);
46725
46482
  if (name.startsWith(".")) continue;
46726
- const full = path55.join(absDir, name);
46483
+ const full = path56.join(absDir, name);
46727
46484
  if (e.isDirectory()) {
46728
46485
  dirNames.push(name);
46729
46486
  } else if (e.isFile() && name.endsWith(".json") && !name.includes(".tmp")) {
@@ -46733,7 +46490,7 @@ async function listSessionBrowserEntries(cwdRel) {
46733
46490
  dirNames.sort(compareDirNames);
46734
46491
  const sessions = [];
46735
46492
  for (const { name, full } of sessionFiles) {
46736
- const sessionId = path55.basename(name, ".json");
46493
+ const sessionId = path56.basename(name, ".json");
46737
46494
  sessions.push(await sessionEntryFromFile(full, sessionId));
46738
46495
  }
46739
46496
  sessions.sort((a, b) => {
@@ -47098,9 +46855,9 @@ async function runAgentMode() {
47098
46855
  try {
47099
46856
  if (inputFileIndex !== -1 && args[inputFileIndex + 1]) {
47100
46857
  const filePath = args[inputFileIndex + 1];
47101
- rawPayload = fs50.readFileSync(filePath, "utf-8");
46858
+ rawPayload = fs51.readFileSync(filePath, "utf-8");
47102
46859
  } else {
47103
- rawPayload = fs50.readFileSync(0, "utf-8");
46860
+ rawPayload = fs51.readFileSync(0, "utf-8");
47104
46861
  }
47105
46862
  } catch (err) {
47106
46863
  writeAgentEvent(registrySessionId, {
@@ -47341,9 +47098,9 @@ async function runAgentMode() {
47341
47098
  }
47342
47099
  function readCliPackageVersion() {
47343
47100
  try {
47344
- const base = path56.dirname(fileURLToPath7(import.meta.url));
47345
- const pkgPath = path56.join(base, "..", "package.json");
47346
- const j = JSON.parse(fs50.readFileSync(pkgPath, "utf8"));
47101
+ const base = path57.dirname(fileURLToPath8(import.meta.url));
47102
+ const pkgPath = path57.join(base, "..", "package.json");
47103
+ const j = JSON.parse(fs51.readFileSync(pkgPath, "utf8"));
47347
47104
  return String(j.version || "0.0.0");
47348
47105
  } catch {
47349
47106
  return "0.0.0";
@@ -47469,7 +47226,7 @@ function startBackgroundAgent() {
47469
47226
  process.exit(1);
47470
47227
  }
47471
47228
  const filePath = args[inputFileIndex + 1];
47472
- const rawPayload = fs50.readFileSync(filePath, "utf-8");
47229
+ const rawPayload = fs51.readFileSync(filePath, "utf-8");
47473
47230
  const envelope = JSON.parse(rawPayload);
47474
47231
  const sessionId = envelope.session_id || envelope.message_id || uuidv412();
47475
47232
  registerSession({