@bonginkan/maria 4.3.27 → 4.3.28

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/cli.cjs CHANGED
@@ -1704,7 +1704,7 @@ var init_AuthenticationManager = __esm({
1704
1704
  const response = await fetch(`${this.apiBase}/api/user/profile`, {
1705
1705
  headers: {
1706
1706
  "Authorization": `Bearer ${tokens2.accessToken}`,
1707
- "User-Agent": `maria-cli/${process.env.CLI_VERSION || "4.3.27"}`
1707
+ "User-Agent": `maria-cli/${process.env.CLI_VERSION || "4.3.28"}`
1708
1708
  }
1709
1709
  });
1710
1710
  if (response.status === 401) {
@@ -2407,7 +2407,7 @@ async function callApi(path60, init3 = {}) {
2407
2407
  "Authorization": `Bearer ${token}`,
2408
2408
  "X-Device-Id": getDeviceId(),
2409
2409
  "X-Session-Id": getSessionId() || "",
2410
- "User-Agent": `maria-cli/${process.env.CLI_VERSION || "4.3.27"}`,
2410
+ "User-Agent": `maria-cli/${process.env.CLI_VERSION || "4.3.28"}`,
2411
2411
  "Content-Type": init3.headers?.["Content-Type"] || "application/json"
2412
2412
  });
2413
2413
  const doFetch = async (token) => {
@@ -16121,8 +16121,8 @@ var require_package = __commonJS({
16121
16121
  "package.json"(exports, module) {
16122
16122
  module.exports = {
16123
16123
  name: "@bonginkan/maria",
16124
- version: "4.3.27",
16125
- description: "\u{1F680} MARIA v4.3.27 - Enterprise AI Development Platform with identity system and character voice implementation. Features 74 production-ready commands with comprehensive fallback implementation, local LLM support, and zero external dependencies. Includes natural language coding, AI safety evaluation, intelligent evolution system, episodic memory with PII masking, and real-time monitoring dashboard. Built with TypeScript AST-powered code generation, OAuth2.0 + PKCE authentication, quantum-resistant cryptography, and enterprise-grade performance.",
16124
+ version: "4.3.28",
16125
+ description: "\u{1F680} MARIA v4.3.28 - Enterprise AI Development Platform with identity system and character voice implementation. Features 74 production-ready commands with comprehensive fallback implementation, local LLM support, and zero external dependencies. Includes natural language coding, AI safety evaluation, intelligent evolution system, episodic memory with PII masking, and real-time monitoring dashboard. Built with TypeScript AST-powered code generation, OAuth2.0 + PKCE authentication, quantum-resistant cryptography, and enterprise-grade performance.",
16126
16126
  keywords: [
16127
16127
  "ai",
16128
16128
  "cli",
@@ -19285,7 +19285,7 @@ async function applyPlans(plans, opts) {
19285
19285
  try {
19286
19286
  for (const plan of plans) {
19287
19287
  if (opts.signal?.aborted) throw abortErr();
19288
- const target = path10__namespace.default.join(opts.root, plan.path);
19288
+ const target = plan.absPath ? plan.absPath : path10__namespace.default.join(opts.root, plan.path);
19289
19289
  const dir = path10__namespace.default.dirname(target);
19290
19290
  await fs19.promises.mkdir(dir, { recursive: true });
19291
19291
  const exists2 = await fileExists(target);
@@ -25753,7 +25753,7 @@ var init_about_command = __esm({
25753
25753
  async execute(args2, context2) {
25754
25754
  const output3 = [];
25755
25755
  output3.push("");
25756
- output3.push(chalk40__default.default.cyan.bold("\u{1F916} About MARIA v4.3.27"));
25756
+ output3.push(chalk40__default.default.cyan.bold("\u{1F916} About MARIA v4.3.28"));
25757
25757
  output3.push(chalk40__default.default.gray("\u2550".repeat(40)));
25758
25758
  output3.push("");
25759
25759
  output3.push(chalk40__default.default.white.bold("MARIA - Minimal API, Maximum Power"));
@@ -38018,6 +38018,10 @@ async function normalizePlans(plans, opts) {
38018
38018
  const profile = await scanRepo(opts.root);
38019
38019
  const out = [];
38020
38020
  for (const fp of plans) {
38021
+ if (fp.noNormalize) {
38022
+ out.push(fp);
38023
+ continue;
38024
+ }
38021
38025
  const n = normalizePlanItem(fp, profile);
38022
38026
  if (!n.kind) n.kind = guessKindByPath(n.path);
38023
38027
  out.push(n);
@@ -38062,7 +38066,7 @@ async function validatePlan(plans, opts) {
38062
38066
  skipped.push(fp.path);
38063
38067
  continue;
38064
38068
  }
38065
- const full = path10__namespace.default.join(opts.root, rel);
38069
+ const full = fp.absPath ? fp.absPath : path10__namespace.default.join(opts.root, rel);
38066
38070
  if (!full.startsWith(path10__namespace.default.resolve(opts.root))) {
38067
38071
  warnings.push(`Outside root denied: ${fp.path}`);
38068
38072
  skipped.push(fp.path);
@@ -38193,10 +38197,10 @@ function formatPlan(summary, opts) {
38193
38197
  budget.diffLines = Math.min(budget.diffLines, 20);
38194
38198
  lines.push("", `Diff preview (truncated to ${budget.diffLines} lines per file):`);
38195
38199
  for (const f3 of summary.files) {
38196
- if (f3.action === "skip") continue;
38197
- const before = readCurrentFileSafe(opts.root, f3.path);
38200
+ if (f3.action !== "modify") continue;
38201
+ const before = readCurrentFileSafe(opts.root, f3.path, f3.absPath);
38198
38202
  const after = f3.preview || "";
38199
- const diff = buildUnifiedDiff(f3.path, before, after, budget);
38203
+ const diff = buildUnifiedDiff(f3.path, before, after, budget, f3.absPath);
38200
38204
  lines.push(diff, "");
38201
38205
  }
38202
38206
  }
@@ -38233,9 +38237,10 @@ function formatPlanAsDiff(files, opts) {
38233
38237
  let shownFiles = 0;
38234
38238
  for (const f3 of files) {
38235
38239
  if (budget.globalMaxFiles !== void 0 && shownFiles >= budget.globalMaxFiles) break;
38236
- const before = readCurrentFileSafe(opts.root, f3.path);
38240
+ if (f3.action !== "modify") continue;
38241
+ const before = readCurrentFileSafe(opts.root, f3.path, f3.absPath);
38237
38242
  const after = f3.preview || "";
38238
- const diff = buildUnifiedDiff(f3.path, before, after, budget);
38243
+ const diff = buildUnifiedDiff(f3.path, before, after, budget, f3.absPath);
38239
38244
  const diffBytes = Buffer.byteLength(diff, "utf8");
38240
38245
  if (budget.globalMaxBytes !== void 0 && bytesUsed + diffBytes > budget.globalMaxBytes && shownFiles > 0) {
38241
38246
  lines.push(`
@@ -38252,11 +38257,11 @@ function formatPlanAsDiff(files, opts) {
38252
38257
  }
38253
38258
  return lines.join("\n");
38254
38259
  }
38255
- function readCurrentFileSafe(root, rel) {
38256
- if (!root) return "";
38260
+ function readCurrentFileSafe(root, rel, abs) {
38261
+ if (!root && !abs) return "";
38257
38262
  try {
38258
38263
  const fs49 = __require("fs");
38259
- const p = __require("path").join(root, rel);
38264
+ const p = abs ? abs : __require("path").join(root, rel);
38260
38265
  return fs49.existsSync(p) ? fs49.readFileSync(p, "utf8") : "";
38261
38266
  } catch {
38262
38267
  return "";
@@ -38273,7 +38278,7 @@ function normalizeDiffBudget(b) {
38273
38278
  globalMaxFiles: Number.isFinite(b?.globalMaxFiles) ? b.globalMaxFiles : envGlobalFiles
38274
38279
  };
38275
38280
  }
38276
- function buildUnifiedDiff(relPath, before, after, b) {
38281
+ function buildUnifiedDiff(relPath, before, after, b, abs) {
38277
38282
  const beforeLines = before.split(/\r?\n/);
38278
38283
  const afterLines = after.split(/\r?\n/);
38279
38284
  let i2 = 0;
@@ -38282,14 +38287,15 @@ function buildUnifiedDiff(relPath, before, after, b) {
38282
38287
  while (j < beforeLines.length - i2 && j < afterLines.length - i2 && beforeLines[beforeLines.length - 1 - j] === afterLines[afterLines.length - 1 - j]) j++;
38283
38288
  const oldMid = beforeLines.slice(i2, beforeLines.length - j);
38284
38289
  const newMid = afterLines.slice(i2, afterLines.length - j);
38285
- const header = [`--- a/${relPath}`, `+++ b/${relPath}`];
38290
+ const headerPath = abs ? abs : relPath;
38291
+ const header = [`--- ${headerPath}`, `+++ ${headerPath}`];
38286
38292
  const body = [];
38287
38293
  const ctxPrefix = Math.max(0, i2 - 3);
38288
38294
  Math.min(beforeLines.length, beforeLines.length - j + 3);
38289
38295
  const preCtx = beforeLines.slice(ctxPrefix, i2).map((l) => ` ${l}`);
38290
38296
  const postCtx = beforeLines.slice(beforeLines.length - j, Math.min(beforeLines.length - j + 3, beforeLines.length)).map((l) => ` ${l}`);
38291
- const del = oldMid.map((l) => `-${l}`);
38292
- const add = newMid.map((l) => `+${l}`);
38297
+ const del = oldMid.map((l) => colorRed(`-${l}`));
38298
+ const add = newMid.map((l) => colorGreen(`+${l}`));
38293
38299
  body.push(...preCtx);
38294
38300
  body.push(...del);
38295
38301
  body.push(...add);
@@ -38306,6 +38312,22 @@ function buildUnifiedDiff(relPath, before, after, b) {
38306
38312
  }
38307
38313
  return out;
38308
38314
  }
38315
+ function colorGreen(s2) {
38316
+ try {
38317
+ const chalk43 = __require("chalk");
38318
+ return chalk43.green(s2);
38319
+ } catch {
38320
+ return s2;
38321
+ }
38322
+ }
38323
+ function colorRed(s2) {
38324
+ try {
38325
+ const chalk43 = __require("chalk");
38326
+ return chalk43.red(s2);
38327
+ } catch {
38328
+ return s2;
38329
+ }
38330
+ }
38309
38331
  function languageLabel(lang, filePath) {
38310
38332
  if (lang) {
38311
38333
  const l = lang.toLowerCase();
@@ -38932,6 +38954,20 @@ var init_policy = __esm({
38932
38954
  }
38933
38955
  });
38934
38956
 
38957
+ // src/utils/esm-compat.ts
38958
+ var esm_compat_exports = {};
38959
+ __export(esm_compat_exports, {
38960
+ loadGlobby: () => loadGlobby
38961
+ });
38962
+ async function loadGlobby() {
38963
+ const mod = await import('globby');
38964
+ return mod?.globby ?? mod?.default ?? mod;
38965
+ }
38966
+ var init_esm_compat = __esm({
38967
+ "src/utils/esm-compat.ts"() {
38968
+ }
38969
+ });
38970
+
38935
38971
  // src/services/code-orchestrator/Orchestrator.ts
38936
38972
  var Orchestrator_exports = {};
38937
38973
  __export(Orchestrator_exports, {
@@ -38966,6 +39002,20 @@ async function orchestrate(request, opts) {
38966
39002
  const initial = [];
38967
39003
  const fallbackNotices = [];
38968
39004
  const withNotices = (base) => fallbackNotices.length > 0 ? [...fallbackNotices, ...base] : base;
39005
+ const explicitFilesRaw = parseExplicitFilenames(request);
39006
+ const explicitFiles = explicitFilesRaw.length > 0 ? await resolveExplicitPaths(opts.root, explicitFilesRaw, request) : [];
39007
+ const explicitAbsMap = /* @__PURE__ */ Object.create(null);
39008
+ if (explicitFiles.length > 0) {
39009
+ const pathMod = await import('path');
39010
+ for (const rel of explicitFiles) {
39011
+ explicitAbsMap[rel] = pathMod.join(opts.root, rel);
39012
+ }
39013
+ }
39014
+ const isEditIntent = detectEditIntent(request, {
39015
+ hasAttachments: !!(opts.attachedFiles && opts.attachedFiles.length > 0),
39016
+ explicitFilesCount: explicitFiles.length
39017
+ });
39018
+ const editContext = isEditIntent && explicitFiles.length > 0 ? await buildEditContext(opts.root, explicitFiles, 200, 512 * 1024) : "";
38969
39019
  if (opts.attachedFiles && opts.attachedFiles.length > 0) {
38970
39020
  const mapRes = await mapAttachmentsToTargets(opts.attachedFiles, {
38971
39021
  root: opts.root,
@@ -38985,7 +39035,6 @@ async function orchestrate(request, opts) {
38985
39035
  }
38986
39036
  }
38987
39037
  const onlyAttached = !!opts.flags.onlyAttached;
38988
- const explicitFiles = parseExplicitFilenames(request);
38989
39038
  if (!onlyAttached) {
38990
39039
  let codeOutput = "";
38991
39040
  if (process.env.MARIA_E2E_FAKE_CODE === "1") {
@@ -39005,9 +39054,17 @@ async function orchestrate(request, opts) {
39005
39054
  "[BEGIN file: path]\n<content>\n[END]",
39006
39055
  "Do not include any prose before/after; no menus/questions/suggestions; start immediately with ``` or [BEGIN file: ...]."
39007
39056
  ].join("\n");
39057
+ const requestPreamble = isEditIntent ? [
39058
+ "// EDIT MODE: modify existing files, preserve unrelated content.",
39059
+ "// Follow existing structure and only touch requested files.",
39060
+ editContext ? "// Current file snapshots provided below." : ""
39061
+ ].filter(Boolean).join("\n") : "";
39008
39062
  const enriched = `${FILE_FORMAT_INSTRUCTIONS}
39009
39063
 
39010
- ${request}`;
39064
+ ${requestPreamble}
39065
+ ${request}
39066
+
39067
+ ${editContext}`;
39011
39068
  const response = await executeCode(enriched);
39012
39069
  const raw = (response.output || response?.data?.content || "").trim();
39013
39070
  if (!raw) {
@@ -39052,24 +39109,27 @@ ${request}`;
39052
39109
  const htmlIdx = blocks.findIndex((b) => /html/i.test(b.language));
39053
39110
  const htmlFile = explicitFiles.find((f3) => f3.toLowerCase().endsWith(".html"));
39054
39111
  if (htmlIdx >= 0 && htmlFile) {
39055
- initial.push({ path: htmlFile, kind: "source", action: "create", description: "HTML page", language: "html", preview: blocks[htmlIdx].code });
39112
+ initial.push({ path: htmlFile, absPath: explicitAbsMap[htmlFile], noNormalize: true, kind: "source", action: "create", description: "HTML page", language: "html", preview: blocks[htmlIdx].code });
39056
39113
  mapped.add(htmlFile);
39057
39114
  }
39058
39115
  const jsIdx = blocks.findIndex((b) => /(ts|tsx|jsx|javascript|js)/i.test(b.language));
39059
39116
  const jsFile = explicitFiles.find((f3) => f3.toLowerCase().endsWith(".js"));
39060
39117
  if (jsIdx >= 0 && jsFile && !mapped.has(jsFile)) {
39061
- initial.push({ path: jsFile, kind: "source", action: "create", description: "Script", language: "javascript", preview: blocks[jsIdx].code });
39118
+ initial.push({ path: jsFile, absPath: explicitAbsMap[jsFile], noNormalize: true, kind: "source", action: "create", description: "Script", language: "javascript", preview: blocks[jsIdx].code });
39062
39119
  mapped.add(jsFile);
39063
39120
  }
39064
39121
  const cssIdx = blocks.findIndex((b) => /css/i.test(b.language));
39065
39122
  const cssFile = explicitFiles.find((f3) => f3.toLowerCase().endsWith(".css"));
39066
39123
  if (cssIdx >= 0 && cssFile && !mapped.has(cssFile)) {
39067
- initial.push({ path: cssFile, kind: "source", action: "create", description: "Stylesheet", language: "css", preview: blocks[cssIdx].code });
39124
+ initial.push({ path: cssFile, absPath: explicitAbsMap[cssFile], noNormalize: true, kind: "source", action: "create", description: "Stylesheet", language: "css", preview: blocks[cssIdx].code });
39068
39125
  mapped.add(cssFile);
39069
39126
  }
39070
39127
  for (const f3 of explicitFiles) {
39071
39128
  if (mapped.has(f3)) continue;
39072
- initial.push(scaffoldForFilename(f3, explicitFiles));
39129
+ const plan = scaffoldForFilename(f3, explicitFiles);
39130
+ plan.absPath = explicitAbsMap[f3];
39131
+ plan.noNormalize = true;
39132
+ initial.push(plan);
39073
39133
  }
39074
39134
  } else {
39075
39135
  for (let i2 = 0; i2 < blocks.length; i2++) {
@@ -39087,12 +39147,26 @@ ${request}`;
39087
39147
  }
39088
39148
  }
39089
39149
  }
39150
+ if (!isEditIntent) {
39151
+ const proposedTop = deriveProjectFolderName(request);
39152
+ const { folderName, detectedTop } = await ensureTopFolder(opts.root, proposedTop, initial);
39153
+ if (folderName) {
39154
+ for (const p of initial) {
39155
+ if (!startsWithTopFolder(p.path, detectedTop || folderName)) {
39156
+ p.path = prefixWithTopFolder(p.path, folderName);
39157
+ }
39158
+ }
39159
+ }
39160
+ }
39090
39161
  if (explicitFiles.length > 0 && initial.filter((f3) => !!f3.preview).length === 0) {
39091
39162
  for (const f3 of explicitFiles) {
39092
39163
  initial.push(scaffoldForFilename(f3, explicitFiles));
39093
39164
  }
39094
39165
  }
39095
- const normalized = await normalizePlans(initial, { root: opts.root });
39166
+ const normalized = await normalizePlans(
39167
+ initial.map((p) => p.noNormalize ? p : p),
39168
+ { root: opts.root }
39169
+ );
39096
39170
  try {
39097
39171
  const [{ access: access18 }, path60] = await Promise.all([
39098
39172
  import('fs/promises'),
@@ -39100,8 +39174,12 @@ ${request}`;
39100
39174
  ]);
39101
39175
  for (const p of normalized) {
39102
39176
  try {
39103
- await access18(path60.join(opts.root, p.path));
39177
+ const absCandidate = p.absPath ? p.absPath : path60.join(opts.root, p.path);
39178
+ await access18(absCandidate);
39104
39179
  p.action = "modify";
39180
+ if (isEditIntent) {
39181
+ p.overwritePolicy = "allow";
39182
+ }
39105
39183
  } catch {
39106
39184
  p.action = "create";
39107
39185
  }
@@ -39109,10 +39187,12 @@ ${request}`;
39109
39187
  } catch {
39110
39188
  }
39111
39189
  const validated = await validatePlan(normalized, { root: opts.root, profile, flags: { maxFiles: opts.flags.maxFiles, yes: opts.flags.yes, interactive: !!opts.flags.interactive, ...opts.flags } });
39112
- const outputMode = resolveOutputMode(opts.flags.output, validated.files.length, !!opts.flags.hideCode);
39113
- const displayFiles = validated.files.concat(
39114
- (validated.skipped || []).map((p) => ({ path: p, kind: "source", action: "skip", description: "" }))
39115
- );
39190
+ const hasAnyModify = validated.files.some((f3) => f3.action === "modify") || isEditIntent;
39191
+ const outputMode = !opts.flags.hideCode && hasAnyModify ? "diff" : resolveOutputMode(opts.flags.output, validated.files.length, !!opts.flags.hideCode);
39192
+ const skippedSetForLookup = new Set(validated.skipped || []);
39193
+ const skippedPlans = normalized.filter((f3) => skippedSetForLookup.has(f3.path));
39194
+ const remainingSkipped = (validated.skipped || []).filter((p) => !skippedPlans.some((sp) => sp.path === p)).map((p) => ({ path: p, kind: "source", action: "skip", description: "" }));
39195
+ const displayFiles = validated.files.concat(skippedPlans).concat(remainingSkipped);
39116
39196
  const summary = summarizePlan(displayFiles);
39117
39197
  const lines = [
39118
39198
  formatPlan(summary, {
@@ -39150,6 +39230,7 @@ ${request}`;
39150
39230
  if (softIssues.hasTrailingWhitespace) lines.push(warnLine("Proposed changes contain trailing whitespace"));
39151
39231
  if (softIssues.hasConflictMarkers) lines.push(warnLine("Proposed changes contain conflict markers"));
39152
39232
  }
39233
+ const preApplyOutput = withNotices(lines);
39153
39234
  let appliedCount = 0;
39154
39235
  let durationMs = 0;
39155
39236
  let rolledBack = false;
@@ -39161,7 +39242,7 @@ ${request}`;
39161
39242
  return { plan: normalized, validated, summaryLines: withNotices([errorLine("working tree not clean (commit or stash first). Re-run after cleaning your git status.")]) };
39162
39243
  }
39163
39244
  }
39164
- const allowOverwrite = opts.flags.overwriteAllowed === true || !!opts.flags.yes;
39245
+ const allowOverwrite = opts.flags.overwriteAllowed === true || !!opts.flags.yes || isEditIntent;
39165
39246
  const applyRes = await applyPlans(approved, { root: opts.root, overwriteAllowed: allowOverwrite, rollback: opts.flags.rollback !== false, signal: opts.abortSignal, onProgress: (w, t2) => {
39166
39247
  }, eol: profile.eol });
39167
39248
  appliedCount = applyRes.appliedCount;
@@ -39191,7 +39272,7 @@ ${request}`;
39191
39272
  const savedList = [].concat(applyRes.created, applyRes.modified);
39192
39273
  const savedAbs = savedList.map((rel) => path10__namespace.default.resolve(opts.root, rel));
39193
39274
  const footer = savedAbs.length > 0 ? ["Saved files (full paths):", ...savedAbs.map((p) => `- ${p}`)] : [];
39194
- return { plan: normalized, validated, applied: { count: appliedCount, durationMs, rolledBack }, summaryLines: withNotices([msg, ...footer]) };
39275
+ return { plan: normalized, validated, applied: { count: appliedCount, durationMs, rolledBack }, summaryLines: [...preApplyOutput, "", msg, ...footer] };
39195
39276
  } catch (e2) {
39196
39277
  if (e2?.name === "AbortError") {
39197
39278
  await journalResume(opts.root, request, validated.files);
@@ -39412,6 +39493,218 @@ function parseExplicitFilenames(request) {
39412
39493
  }
39413
39494
  return out;
39414
39495
  }
39496
+ function detectEditIntent(request, ctx2) {
39497
+ const r2 = request.toLowerCase();
39498
+ const editKeywords = ["modify", "edit", "update", "fix", "refactor", "change", "patch", "\u5DEE\u5206", "\u4FEE\u6B63", "\u5909\u66F4", "\u65E2\u5B58", "\u8FFD\u8A18"];
39499
+ const mentionsEdit = editKeywords.some((k) => r2.includes(k));
39500
+ return ctx2.hasAttachments || ctx2.explicitFilesCount > 0 || mentionsEdit;
39501
+ }
39502
+ function sanitizeFolderName(name2) {
39503
+ const base = name2.toLowerCase().replace(/[`~!@#$%^&*()+=\[\]{}|;:'",<>/?\\]/g, " ").replace(/\s+/g, "-").replace(/^-+|-+$/g, "").slice(0, 48);
39504
+ return base || "project";
39505
+ }
39506
+ function deriveProjectFolderName(request) {
39507
+ const words = request.toLowerCase().replace(/[^a-z0-9\s-]/g, " ").split(/\s+/).filter((w) => w.length > 2).slice(0, 4).join("-");
39508
+ return sanitizeFolderName(words || "project");
39509
+ }
39510
+ function startsWithTopFolder(p, folder) {
39511
+ if (!folder) return false;
39512
+ const seg = p.replace(/^\/+/, "").split("/")[0];
39513
+ return seg.toLowerCase() === folder.toLowerCase();
39514
+ }
39515
+ function prefixWithTopFolder(p, folder) {
39516
+ const rel = p.replace(/^\/+/, "");
39517
+ return `${folder}/${rel}`;
39518
+ }
39519
+ async function ensureTopFolder(root, proposed, plans) {
39520
+ const tops = /* @__PURE__ */ new Set();
39521
+ for (const p of plans) {
39522
+ const seg = p.path.replace(/^\/+/, "").split("/")[0] || "";
39523
+ if (seg) tops.add(seg);
39524
+ }
39525
+ if (tops.size === 1) {
39526
+ const only = Array.from(tops)[0];
39527
+ const unique2 = await ensureUniqueFolder(root, only);
39528
+ return { folderName: unique2, detectedTop: only };
39529
+ }
39530
+ const unique = await ensureUniqueFolder(root, proposed);
39531
+ return { folderName: unique };
39532
+ }
39533
+ async function ensureUniqueFolder(root, base) {
39534
+ const fs49 = await import('fs/promises');
39535
+ const pathMod = await import('path');
39536
+ let name2 = sanitizeFolderName(base);
39537
+ let suffix = 0;
39538
+ for (; suffix < Number.MAX_SAFE_INTEGER; ) {
39539
+ const candidate = suffix === 0 ? name2 : `${name2}-${String(suffix).padStart(2, "0")}`;
39540
+ try {
39541
+ await fs49.access(pathMod.join(root, candidate));
39542
+ suffix += 1;
39543
+ } catch {
39544
+ return candidate;
39545
+ }
39546
+ }
39547
+ throw new Error("ensureUniqueFolder: exhausted attempts to find a unique folder name");
39548
+ }
39549
+ async function buildEditContext(root, files, maxLines, maxBytes) {
39550
+ try {
39551
+ const fs49 = await import('fs/promises');
39552
+ const pathMod = await import('path');
39553
+ const sections = [];
39554
+ for (const rel of files) {
39555
+ const full = pathMod.join(root, rel);
39556
+ try {
39557
+ const buf = await fs49.readFile(full);
39558
+ const clipped = buf.length > maxBytes ? buf.subarray(0, maxBytes) : buf;
39559
+ const text = clipped.toString("utf8").replace(/\r\n/g, "\n");
39560
+ const lines = text.split("\n").slice(0, maxLines).join("\n");
39561
+ sections.push(`[BEGIN file: ${rel}]
39562
+ ${lines}
39563
+ [END]`);
39564
+ } catch {
39565
+ }
39566
+ }
39567
+ if (sections.length === 0) return "";
39568
+ return ["// Current repository files (read-only context):", ...sections].join("\n");
39569
+ } catch {
39570
+ return "";
39571
+ }
39572
+ }
39573
+ async function resolveExplicitPaths(root, files, hintText) {
39574
+ const fs49 = await import('fs/promises');
39575
+ const pathMod = await import('path');
39576
+ const { loadGlobby: loadGlobby2 } = await Promise.resolve().then(() => (init_esm_compat(), esm_compat_exports));
39577
+ const globby = await loadGlobby2();
39578
+ const ignore = [
39579
+ "**/node_modules/**",
39580
+ "**/.git/**",
39581
+ "**/dist/**",
39582
+ "**/build/**",
39583
+ "**/.maria/**",
39584
+ "**/.next/**",
39585
+ "**/coverage/**"
39586
+ ];
39587
+ const hintTokens = Array.from(new Set(hintText.toLowerCase().replace(/[^a-z0-9_/.-]+/g, " ").split(/\s+/).filter(Boolean)));
39588
+ async function findBest(rel) {
39589
+ const normalized = rel.replace(/^\/+/, "").replace(/\\/g, "/");
39590
+ const fullExact = pathMod.join(root, normalized);
39591
+ try {
39592
+ await fs49.access(fullExact);
39593
+ return normalized;
39594
+ } catch {
39595
+ }
39596
+ const lowerRel = normalized.toLowerCase();
39597
+ const ext2 = (pathMod.extname(normalized) || "").toLowerCase();
39598
+ const base = pathMod.basename(normalized);
39599
+ const nameNoExt = base.replace(/\.[^.]+$/, "").toLowerCase();
39600
+ const parentPath = pathMod.dirname(normalized);
39601
+ const parent = parentPath.split("/").pop() || "";
39602
+ const dirParts = parentPath === "." ? [] : parentPath.split("/").filter(Boolean).map((s2) => s2.toLowerCase());
39603
+ const patterns = [];
39604
+ patterns.push(`**/${normalized}`);
39605
+ if (parent && parent !== "." && parent !== "/") patterns.push(`**/${parent}/${base}`);
39606
+ if (base) patterns.push(`**/${base}`);
39607
+ patterns.push(`**/*${base}`);
39608
+ if (!ext2) {
39609
+ patterns.push(`**/${nameNoExt}.*`);
39610
+ }
39611
+ const uniqPatterns = Array.from(new Set(patterns));
39612
+ const candidatesSet = /* @__PURE__ */ new Set();
39613
+ for (const pat of uniqPatterns) {
39614
+ const found = await globby(pat, { cwd: root, absolute: false, gitignore: true, ignore });
39615
+ for (const f3 of found) {
39616
+ candidatesSet.add(f3.replace(/\\/g, "/"));
39617
+ }
39618
+ if (candidatesSet.size > 200) break;
39619
+ }
39620
+ let candidates = Array.from(candidatesSet);
39621
+ if (dirParts.length > 0) {
39622
+ const filtered = candidates.filter((relp) => {
39623
+ const segs = relp.toLowerCase().split("/");
39624
+ let pos = -1;
39625
+ for (const part of dirParts) {
39626
+ const next = segs.indexOf(part, pos + 1);
39627
+ if (next === -1) return false;
39628
+ pos = next;
39629
+ }
39630
+ return true;
39631
+ });
39632
+ if (filtered.length > 0) candidates = filtered;
39633
+ }
39634
+ if (candidates.length === 0) {
39635
+ const prefixes = ["", "src/", "app/", "pages/"];
39636
+ for (const pre of prefixes) {
39637
+ const cand = pathMod.join(root, pre + normalized);
39638
+ try {
39639
+ await fs49.access(cand);
39640
+ return (pre + normalized).replace(/^\/+/, "");
39641
+ } catch {
39642
+ }
39643
+ }
39644
+ if (dirParts.length > 0) {
39645
+ if (/^(src|app|pages)\//i.test(normalized)) return normalized;
39646
+ const pref = await pickExistingFolderPrefix(root, parentPath);
39647
+ const combined = (pref + normalized).replace(/^\/+/, "").replace(/^(src\/)src\//i, "$1");
39648
+ return combined;
39649
+ }
39650
+ return normalized.replace(/^(src\/)src\//i, "$1");
39651
+ }
39652
+ function score(relPath) {
39653
+ const lower2 = relPath.toLowerCase();
39654
+ let s2 = 0;
39655
+ if (lower2.endsWith(lowerRel)) s2 += 80;
39656
+ if (lower2.split("/").pop() === base.toLowerCase()) s2 += 40;
39657
+ if (ext2 && lower2.endsWith(ext2)) s2 += 10;
39658
+ if (lower2.startsWith("src/")) s2 += 18;
39659
+ if (parent && lower2.includes(`/${parent.toLowerCase()}/`)) s2 += 15;
39660
+ if (parentPath && lower2.endsWith(`/${parentPath.toLowerCase()}/${base.toLowerCase()}`)) s2 += 40;
39661
+ if (dirParts.length > 0) {
39662
+ for (const part of dirParts) {
39663
+ if (lower2.includes(`/${part}/`)) s2 += 20;
39664
+ else s2 -= 120;
39665
+ }
39666
+ }
39667
+ for (const t2 of hintTokens) {
39668
+ if (t2.length >= 3 && lower2.includes(`/${t2}/`)) {
39669
+ s2 += 2;
39670
+ }
39671
+ }
39672
+ s2 -= Math.min(10, Math.floor(relPath.length / 80));
39673
+ return s2;
39674
+ }
39675
+ let best = candidates[0];
39676
+ let bestScore = score(best);
39677
+ for (let i2 = 1; i2 < candidates.length; i2++) {
39678
+ const c = candidates[i2];
39679
+ const sc = score(c);
39680
+ if (sc > bestScore) {
39681
+ best = c;
39682
+ bestScore = sc;
39683
+ }
39684
+ }
39685
+ return best.replace(/^\/+/, "");
39686
+ }
39687
+ const out = [];
39688
+ for (const f3 of files) {
39689
+ out.push(await findBest(f3));
39690
+ }
39691
+ return out;
39692
+ }
39693
+ async function pickExistingFolderPrefix(root, parentPath) {
39694
+ const fs49 = await import('fs/promises');
39695
+ const pathMod = await import('path');
39696
+ const parts = parentPath.replace(/^\/+/, "").split("/").filter(Boolean);
39697
+ const prefixes = ["src", "app", "pages", ""];
39698
+ for (const pre of prefixes) {
39699
+ const test = pre ? pathMod.join(root, pre, ...parts) : pathMod.join(root, ...parts);
39700
+ try {
39701
+ await fs49.access(test);
39702
+ return pre ? `${pre}/` : "";
39703
+ } catch {
39704
+ }
39705
+ }
39706
+ return "src/";
39707
+ }
39415
39708
  function scaffoldForFilename(filename, all) {
39416
39709
  const lower2 = filename.toLowerCase();
39417
39710
  if (lower2.endsWith(".html")) {
@@ -40625,16 +40918,6 @@ var init_loader = __esm({
40625
40918
  }
40626
40919
  });
40627
40920
 
40628
- // src/utils/esm-compat.ts
40629
- async function loadGlobby() {
40630
- const mod = await import('globby');
40631
- return mod?.globby ?? mod?.default ?? mod;
40632
- }
40633
- var init_esm_compat = __esm({
40634
- "src/utils/esm-compat.ts"() {
40635
- }
40636
- });
40637
-
40638
40921
  // src/services/init/scanner.ts
40639
40922
  var scanner_exports = {};
40640
40923
  __export(scanner_exports, {