@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/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # MARIA - AI Development Platform v4.3.27
1
+ # MARIA - AI Development Platform v4.3.28
2
2
 
3
3
  [![npm version](https://img.shields.io/npm/v/@bonginkan/maria.svg)](https://www.npmjs.com/package/@bonginkan/maria)
4
4
  [![License](https://img.shields.io/badge/license-Multi--tier-blue.svg)](LICENSE)
@@ -10,7 +10,7 @@
10
10
 
11
11
  > **Enterprise-grade AI development platform with 100% command availability and comprehensive fallback support**
12
12
 
13
- ## 🚀 What's New in v4.3.27 (September 16, 2025)
13
+ ## 🚀 What's New in v4.3.28 (September 16, 2025)
14
14
 
15
15
  ### 🎯 Interactive Improvements & Choice Memory
16
16
  - **Choice Memory System**: Smart persistence of user selections across sessions
@@ -922,7 +922,7 @@ await secureWorkflow.executeWithAuth(workflowDefinition, securityContext);
922
922
  ### Quick Installation
923
923
  ```bash
924
924
  # Install globally (recommended)
925
- npm install -g @bonginkan/maria@4.3.27
925
+ npm install -g @bonginkan/maria@4.3.28
926
926
 
927
927
  # Verify installation
928
928
  maria --version # Should show v4.3.9
@@ -1126,7 +1126,7 @@ MARIA CODE is distributed under a comprehensive licensing system designed for in
1126
1126
 
1127
1127
  *MARIA v4.1.4 represents the pinnacle of multimodal AI development platform evolution - combining revolutionary voice-to-code capabilities, advanced memory systems, and comprehensive command ecosystems with enterprise-grade security and performance. This release establishes MARIA as the definitive choice for developers and Fortune 500 enterprises seeking intelligent, multimodal development experiences with GraphRAG intelligence, multilingual support, and zero-anxiety coding workflows.*
1128
1128
 
1129
- **Transform your development experience today**: `npm install -g @bonginkan/maria@4.3.27`
1129
+ **Transform your development experience today**: `npm install -g @bonginkan/maria@4.3.28`
1130
1130
 
1131
1131
  🌐 **Official Website**: [https://maria-code.ai](https://maria-code.ai)
1132
1132
  💬 **Community**: [https://discord.gg/SMSmSGcEQy](https://discord.gg/SMSmSGcEQy)
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "version": "lite-1.0.0",
3
- "generatedAt": "2025-09-26T02:10:52.909Z",
3
+ "generatedAt": "2025-09-26T05:40:48.488Z",
4
4
  "totalCommands": 16,
5
5
  "readyCount": 16,
6
6
  "partialCount": 0,
@@ -26066,8 +26066,8 @@ var require_package = __commonJS({
26066
26066
  "package.json"(exports, module) {
26067
26067
  module.exports = {
26068
26068
  name: "@bonginkan/maria",
26069
- version: "4.3.27",
26070
- 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.",
26069
+ version: "4.3.28",
26070
+ 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.",
26071
26071
  keywords: [
26072
26072
  "ai",
26073
26073
  "cli",
@@ -28099,7 +28099,7 @@ var init_AuthenticationManager = __esm({
28099
28099
  const response = await fetch(`${this.apiBase}/api/user/profile`, {
28100
28100
  headers: {
28101
28101
  "Authorization": `Bearer ${tokens2.accessToken}`,
28102
- "User-Agent": `maria-cli/${process.env.CLI_VERSION || "4.3.27"}`
28102
+ "User-Agent": `maria-cli/${process.env.CLI_VERSION || "4.3.28"}`
28103
28103
  }
28104
28104
  });
28105
28105
  if (response.status === 401) {
@@ -28731,7 +28731,7 @@ async function callApi(path60, init3 = {}) {
28731
28731
  "Authorization": `Bearer ${token}`,
28732
28732
  "X-Device-Id": getDeviceId(),
28733
28733
  "X-Session-Id": getSessionId() || "",
28734
- "User-Agent": `maria-cli/${process.env.CLI_VERSION || "4.3.27"}`,
28734
+ "User-Agent": `maria-cli/${process.env.CLI_VERSION || "4.3.28"}`,
28735
28735
  "Content-Type": init3.headers?.["Content-Type"] || "application/json"
28736
28736
  });
28737
28737
  const doFetch = async (token) => {
@@ -44443,7 +44443,7 @@ async function applyPlans(plans, opts) {
44443
44443
  try {
44444
44444
  for (const plan of plans) {
44445
44445
  if (opts.signal?.aborted) throw abortErr();
44446
- const target = path11__namespace.default.join(opts.root, plan.path);
44446
+ const target = plan.absPath ? plan.absPath : path11__namespace.default.join(opts.root, plan.path);
44447
44447
  const dir = path11__namespace.default.dirname(target);
44448
44448
  await fs21.promises.mkdir(dir, { recursive: true });
44449
44449
  const exists2 = await fileExists(target);
@@ -50625,7 +50625,7 @@ var init_about_command = __esm({
50625
50625
  async execute(args2, context2) {
50626
50626
  const output3 = [];
50627
50627
  output3.push("");
50628
- output3.push(chalk14__default.default.cyan.bold("\u{1F916} About MARIA v4.3.27"));
50628
+ output3.push(chalk14__default.default.cyan.bold("\u{1F916} About MARIA v4.3.28"));
50629
50629
  output3.push(chalk14__default.default.gray("\u2550".repeat(40)));
50630
50630
  output3.push("");
50631
50631
  output3.push(chalk14__default.default.white.bold("MARIA - Minimal API, Maximum Power"));
@@ -54127,6 +54127,10 @@ async function normalizePlans(plans, opts) {
54127
54127
  const profile = await scanRepo(opts.root);
54128
54128
  const out = [];
54129
54129
  for (const fp of plans) {
54130
+ if (fp.noNormalize) {
54131
+ out.push(fp);
54132
+ continue;
54133
+ }
54130
54134
  const n = normalizePlanItem(fp, profile);
54131
54135
  if (!n.kind) n.kind = guessKindByPath(n.path);
54132
54136
  out.push(n);
@@ -54171,7 +54175,7 @@ async function validatePlan(plans, opts) {
54171
54175
  skipped.push(fp.path);
54172
54176
  continue;
54173
54177
  }
54174
- const full = path11__namespace.default.join(opts.root, rel);
54178
+ const full = fp.absPath ? fp.absPath : path11__namespace.default.join(opts.root, rel);
54175
54179
  if (!full.startsWith(path11__namespace.default.resolve(opts.root))) {
54176
54180
  warnings.push(`Outside root denied: ${fp.path}`);
54177
54181
  skipped.push(fp.path);
@@ -54302,10 +54306,10 @@ function formatPlan(summary, opts) {
54302
54306
  budget.diffLines = Math.min(budget.diffLines, 20);
54303
54307
  lines.push("", `Diff preview (truncated to ${budget.diffLines} lines per file):`);
54304
54308
  for (const f3 of summary.files) {
54305
- if (f3.action === "skip") continue;
54306
- const before = readCurrentFileSafe(opts.root, f3.path);
54309
+ if (f3.action !== "modify") continue;
54310
+ const before = readCurrentFileSafe(opts.root, f3.path, f3.absPath);
54307
54311
  const after = f3.preview || "";
54308
- const diff = buildUnifiedDiff(f3.path, before, after, budget);
54312
+ const diff = buildUnifiedDiff(f3.path, before, after, budget, f3.absPath);
54309
54313
  lines.push(diff, "");
54310
54314
  }
54311
54315
  }
@@ -54342,9 +54346,10 @@ function formatPlanAsDiff(files, opts) {
54342
54346
  let shownFiles = 0;
54343
54347
  for (const f3 of files) {
54344
54348
  if (budget.globalMaxFiles !== void 0 && shownFiles >= budget.globalMaxFiles) break;
54345
- const before = readCurrentFileSafe(opts.root, f3.path);
54349
+ if (f3.action !== "modify") continue;
54350
+ const before = readCurrentFileSafe(opts.root, f3.path, f3.absPath);
54346
54351
  const after = f3.preview || "";
54347
- const diff = buildUnifiedDiff(f3.path, before, after, budget);
54352
+ const diff = buildUnifiedDiff(f3.path, before, after, budget, f3.absPath);
54348
54353
  const diffBytes = Buffer.byteLength(diff, "utf8");
54349
54354
  if (budget.globalMaxBytes !== void 0 && bytesUsed + diffBytes > budget.globalMaxBytes && shownFiles > 0) {
54350
54355
  lines.push(`
@@ -54361,11 +54366,11 @@ function formatPlanAsDiff(files, opts) {
54361
54366
  }
54362
54367
  return lines.join("\n");
54363
54368
  }
54364
- function readCurrentFileSafe(root, rel) {
54365
- if (!root) return "";
54369
+ function readCurrentFileSafe(root, rel, abs) {
54370
+ if (!root && !abs) return "";
54366
54371
  try {
54367
54372
  const fs49 = __require("fs");
54368
- const p = __require("path").join(root, rel);
54373
+ const p = abs ? abs : __require("path").join(root, rel);
54369
54374
  return fs49.existsSync(p) ? fs49.readFileSync(p, "utf8") : "";
54370
54375
  } catch {
54371
54376
  return "";
@@ -54382,7 +54387,7 @@ function normalizeDiffBudget(b) {
54382
54387
  globalMaxFiles: Number.isFinite(b?.globalMaxFiles) ? b.globalMaxFiles : envGlobalFiles
54383
54388
  };
54384
54389
  }
54385
- function buildUnifiedDiff(relPath, before, after, b) {
54390
+ function buildUnifiedDiff(relPath, before, after, b, abs) {
54386
54391
  const beforeLines = before.split(/\r?\n/);
54387
54392
  const afterLines = after.split(/\r?\n/);
54388
54393
  let i2 = 0;
@@ -54391,14 +54396,15 @@ function buildUnifiedDiff(relPath, before, after, b) {
54391
54396
  while (j < beforeLines.length - i2 && j < afterLines.length - i2 && beforeLines[beforeLines.length - 1 - j] === afterLines[afterLines.length - 1 - j]) j++;
54392
54397
  const oldMid = beforeLines.slice(i2, beforeLines.length - j);
54393
54398
  const newMid = afterLines.slice(i2, afterLines.length - j);
54394
- const header = [`--- a/${relPath}`, `+++ b/${relPath}`];
54399
+ const headerPath = abs ? abs : relPath;
54400
+ const header = [`--- ${headerPath}`, `+++ ${headerPath}`];
54395
54401
  const body = [];
54396
54402
  const ctxPrefix = Math.max(0, i2 - 3);
54397
54403
  Math.min(beforeLines.length, beforeLines.length - j + 3);
54398
54404
  const preCtx = beforeLines.slice(ctxPrefix, i2).map((l) => ` ${l}`);
54399
54405
  const postCtx = beforeLines.slice(beforeLines.length - j, Math.min(beforeLines.length - j + 3, beforeLines.length)).map((l) => ` ${l}`);
54400
- const del = oldMid.map((l) => `-${l}`);
54401
- const add = newMid.map((l) => `+${l}`);
54406
+ const del = oldMid.map((l) => colorRed(`-${l}`));
54407
+ const add = newMid.map((l) => colorGreen(`+${l}`));
54402
54408
  body.push(...preCtx);
54403
54409
  body.push(...del);
54404
54410
  body.push(...add);
@@ -54415,6 +54421,22 @@ function buildUnifiedDiff(relPath, before, after, b) {
54415
54421
  }
54416
54422
  return out;
54417
54423
  }
54424
+ function colorGreen(s2) {
54425
+ try {
54426
+ const chalk44 = __require("chalk");
54427
+ return chalk44.green(s2);
54428
+ } catch {
54429
+ return s2;
54430
+ }
54431
+ }
54432
+ function colorRed(s2) {
54433
+ try {
54434
+ const chalk44 = __require("chalk");
54435
+ return chalk44.red(s2);
54436
+ } catch {
54437
+ return s2;
54438
+ }
54439
+ }
54418
54440
  function languageLabel(lang, filePath) {
54419
54441
  if (lang) {
54420
54442
  const l = lang.toLowerCase();
@@ -55041,6 +55063,20 @@ var init_policy = __esm({
55041
55063
  }
55042
55064
  });
55043
55065
 
55066
+ // src/utils/esm-compat.ts
55067
+ var esm_compat_exports = {};
55068
+ __export(esm_compat_exports, {
55069
+ loadGlobby: () => loadGlobby
55070
+ });
55071
+ async function loadGlobby() {
55072
+ const mod = await import('globby');
55073
+ return mod?.globby ?? mod?.default ?? mod;
55074
+ }
55075
+ var init_esm_compat = __esm({
55076
+ "src/utils/esm-compat.ts"() {
55077
+ }
55078
+ });
55079
+
55044
55080
  // src/services/code-orchestrator/Orchestrator.ts
55045
55081
  var Orchestrator_exports = {};
55046
55082
  __export(Orchestrator_exports, {
@@ -55075,6 +55111,20 @@ async function orchestrate(request, opts) {
55075
55111
  const initial = [];
55076
55112
  const fallbackNotices = [];
55077
55113
  const withNotices = (base) => fallbackNotices.length > 0 ? [...fallbackNotices, ...base] : base;
55114
+ const explicitFilesRaw = parseExplicitFilenames(request);
55115
+ const explicitFiles = explicitFilesRaw.length > 0 ? await resolveExplicitPaths(opts.root, explicitFilesRaw, request) : [];
55116
+ const explicitAbsMap = /* @__PURE__ */ Object.create(null);
55117
+ if (explicitFiles.length > 0) {
55118
+ const pathMod = await import('path');
55119
+ for (const rel of explicitFiles) {
55120
+ explicitAbsMap[rel] = pathMod.join(opts.root, rel);
55121
+ }
55122
+ }
55123
+ const isEditIntent = detectEditIntent(request, {
55124
+ hasAttachments: !!(opts.attachedFiles && opts.attachedFiles.length > 0),
55125
+ explicitFilesCount: explicitFiles.length
55126
+ });
55127
+ const editContext = isEditIntent && explicitFiles.length > 0 ? await buildEditContext(opts.root, explicitFiles, 200, 512 * 1024) : "";
55078
55128
  if (opts.attachedFiles && opts.attachedFiles.length > 0) {
55079
55129
  const mapRes = await mapAttachmentsToTargets(opts.attachedFiles, {
55080
55130
  root: opts.root,
@@ -55094,7 +55144,6 @@ async function orchestrate(request, opts) {
55094
55144
  }
55095
55145
  }
55096
55146
  const onlyAttached = !!opts.flags.onlyAttached;
55097
- const explicitFiles = parseExplicitFilenames(request);
55098
55147
  if (!onlyAttached) {
55099
55148
  let codeOutput = "";
55100
55149
  if (process.env.MARIA_E2E_FAKE_CODE === "1") {
@@ -55114,9 +55163,17 @@ async function orchestrate(request, opts) {
55114
55163
  "[BEGIN file: path]\n<content>\n[END]",
55115
55164
  "Do not include any prose before/after; no menus/questions/suggestions; start immediately with ``` or [BEGIN file: ...]."
55116
55165
  ].join("\n");
55166
+ const requestPreamble = isEditIntent ? [
55167
+ "// EDIT MODE: modify existing files, preserve unrelated content.",
55168
+ "// Follow existing structure and only touch requested files.",
55169
+ editContext ? "// Current file snapshots provided below." : ""
55170
+ ].filter(Boolean).join("\n") : "";
55117
55171
  const enriched = `${FILE_FORMAT_INSTRUCTIONS}
55118
55172
 
55119
- ${request}`;
55173
+ ${requestPreamble}
55174
+ ${request}
55175
+
55176
+ ${editContext}`;
55120
55177
  const response = await executeCode(enriched);
55121
55178
  const raw = (response.output || response?.data?.content || "").trim();
55122
55179
  if (!raw) {
@@ -55161,24 +55218,27 @@ ${request}`;
55161
55218
  const htmlIdx = blocks.findIndex((b) => /html/i.test(b.language));
55162
55219
  const htmlFile = explicitFiles.find((f3) => f3.toLowerCase().endsWith(".html"));
55163
55220
  if (htmlIdx >= 0 && htmlFile) {
55164
- initial.push({ path: htmlFile, kind: "source", action: "create", description: "HTML page", language: "html", preview: blocks[htmlIdx].code });
55221
+ initial.push({ path: htmlFile, absPath: explicitAbsMap[htmlFile], noNormalize: true, kind: "source", action: "create", description: "HTML page", language: "html", preview: blocks[htmlIdx].code });
55165
55222
  mapped.add(htmlFile);
55166
55223
  }
55167
55224
  const jsIdx = blocks.findIndex((b) => /(ts|tsx|jsx|javascript|js)/i.test(b.language));
55168
55225
  const jsFile = explicitFiles.find((f3) => f3.toLowerCase().endsWith(".js"));
55169
55226
  if (jsIdx >= 0 && jsFile && !mapped.has(jsFile)) {
55170
- initial.push({ path: jsFile, kind: "source", action: "create", description: "Script", language: "javascript", preview: blocks[jsIdx].code });
55227
+ initial.push({ path: jsFile, absPath: explicitAbsMap[jsFile], noNormalize: true, kind: "source", action: "create", description: "Script", language: "javascript", preview: blocks[jsIdx].code });
55171
55228
  mapped.add(jsFile);
55172
55229
  }
55173
55230
  const cssIdx = blocks.findIndex((b) => /css/i.test(b.language));
55174
55231
  const cssFile = explicitFiles.find((f3) => f3.toLowerCase().endsWith(".css"));
55175
55232
  if (cssIdx >= 0 && cssFile && !mapped.has(cssFile)) {
55176
- initial.push({ path: cssFile, kind: "source", action: "create", description: "Stylesheet", language: "css", preview: blocks[cssIdx].code });
55233
+ initial.push({ path: cssFile, absPath: explicitAbsMap[cssFile], noNormalize: true, kind: "source", action: "create", description: "Stylesheet", language: "css", preview: blocks[cssIdx].code });
55177
55234
  mapped.add(cssFile);
55178
55235
  }
55179
55236
  for (const f3 of explicitFiles) {
55180
55237
  if (mapped.has(f3)) continue;
55181
- initial.push(scaffoldForFilename(f3, explicitFiles));
55238
+ const plan = scaffoldForFilename(f3, explicitFiles);
55239
+ plan.absPath = explicitAbsMap[f3];
55240
+ plan.noNormalize = true;
55241
+ initial.push(plan);
55182
55242
  }
55183
55243
  } else {
55184
55244
  for (let i2 = 0; i2 < blocks.length; i2++) {
@@ -55196,12 +55256,26 @@ ${request}`;
55196
55256
  }
55197
55257
  }
55198
55258
  }
55259
+ if (!isEditIntent) {
55260
+ const proposedTop = deriveProjectFolderName(request);
55261
+ const { folderName, detectedTop } = await ensureTopFolder(opts.root, proposedTop, initial);
55262
+ if (folderName) {
55263
+ for (const p of initial) {
55264
+ if (!startsWithTopFolder(p.path, detectedTop || folderName)) {
55265
+ p.path = prefixWithTopFolder(p.path, folderName);
55266
+ }
55267
+ }
55268
+ }
55269
+ }
55199
55270
  if (explicitFiles.length > 0 && initial.filter((f3) => !!f3.preview).length === 0) {
55200
55271
  for (const f3 of explicitFiles) {
55201
55272
  initial.push(scaffoldForFilename(f3, explicitFiles));
55202
55273
  }
55203
55274
  }
55204
- const normalized = await normalizePlans(initial, { root: opts.root });
55275
+ const normalized = await normalizePlans(
55276
+ initial.map((p) => p.noNormalize ? p : p),
55277
+ { root: opts.root }
55278
+ );
55205
55279
  try {
55206
55280
  const [{ access: access18 }, path60] = await Promise.all([
55207
55281
  import('fs/promises'),
@@ -55209,8 +55283,12 @@ ${request}`;
55209
55283
  ]);
55210
55284
  for (const p of normalized) {
55211
55285
  try {
55212
- await access18(path60.join(opts.root, p.path));
55286
+ const absCandidate = p.absPath ? p.absPath : path60.join(opts.root, p.path);
55287
+ await access18(absCandidate);
55213
55288
  p.action = "modify";
55289
+ if (isEditIntent) {
55290
+ p.overwritePolicy = "allow";
55291
+ }
55214
55292
  } catch {
55215
55293
  p.action = "create";
55216
55294
  }
@@ -55218,10 +55296,12 @@ ${request}`;
55218
55296
  } catch {
55219
55297
  }
55220
55298
  const validated = await validatePlan(normalized, { root: opts.root, profile, flags: { maxFiles: opts.flags.maxFiles, yes: opts.flags.yes, interactive: !!opts.flags.interactive, ...opts.flags } });
55221
- const outputMode = resolveOutputMode(opts.flags.output, validated.files.length, !!opts.flags.hideCode);
55222
- const displayFiles = validated.files.concat(
55223
- (validated.skipped || []).map((p) => ({ path: p, kind: "source", action: "skip", description: "" }))
55224
- );
55299
+ const hasAnyModify = validated.files.some((f3) => f3.action === "modify") || isEditIntent;
55300
+ const outputMode = !opts.flags.hideCode && hasAnyModify ? "diff" : resolveOutputMode(opts.flags.output, validated.files.length, !!opts.flags.hideCode);
55301
+ const skippedSetForLookup = new Set(validated.skipped || []);
55302
+ const skippedPlans = normalized.filter((f3) => skippedSetForLookup.has(f3.path));
55303
+ const remainingSkipped = (validated.skipped || []).filter((p) => !skippedPlans.some((sp) => sp.path === p)).map((p) => ({ path: p, kind: "source", action: "skip", description: "" }));
55304
+ const displayFiles = validated.files.concat(skippedPlans).concat(remainingSkipped);
55225
55305
  const summary = summarizePlan(displayFiles);
55226
55306
  const lines = [
55227
55307
  formatPlan(summary, {
@@ -55259,6 +55339,7 @@ ${request}`;
55259
55339
  if (softIssues.hasTrailingWhitespace) lines.push(warnLine("Proposed changes contain trailing whitespace"));
55260
55340
  if (softIssues.hasConflictMarkers) lines.push(warnLine("Proposed changes contain conflict markers"));
55261
55341
  }
55342
+ const preApplyOutput = withNotices(lines);
55262
55343
  let appliedCount = 0;
55263
55344
  let durationMs = 0;
55264
55345
  let rolledBack = false;
@@ -55270,7 +55351,7 @@ ${request}`;
55270
55351
  return { plan: normalized, validated, summaryLines: withNotices([errorLine("working tree not clean (commit or stash first). Re-run after cleaning your git status.")]) };
55271
55352
  }
55272
55353
  }
55273
- const allowOverwrite = opts.flags.overwriteAllowed === true || !!opts.flags.yes;
55354
+ const allowOverwrite = opts.flags.overwriteAllowed === true || !!opts.flags.yes || isEditIntent;
55274
55355
  const applyRes = await applyPlans(approved, { root: opts.root, overwriteAllowed: allowOverwrite, rollback: opts.flags.rollback !== false, signal: opts.abortSignal, onProgress: (w, t2) => {
55275
55356
  }, eol: profile.eol });
55276
55357
  appliedCount = applyRes.appliedCount;
@@ -55300,7 +55381,7 @@ ${request}`;
55300
55381
  const savedList = [].concat(applyRes.created, applyRes.modified);
55301
55382
  const savedAbs = savedList.map((rel) => path11__namespace.default.resolve(opts.root, rel));
55302
55383
  const footer = savedAbs.length > 0 ? ["Saved files (full paths):", ...savedAbs.map((p) => `- ${p}`)] : [];
55303
- return { plan: normalized, validated, applied: { count: appliedCount, durationMs, rolledBack }, summaryLines: withNotices([msg, ...footer]) };
55384
+ return { plan: normalized, validated, applied: { count: appliedCount, durationMs, rolledBack }, summaryLines: [...preApplyOutput, "", msg, ...footer] };
55304
55385
  } catch (e2) {
55305
55386
  if (e2?.name === "AbortError") {
55306
55387
  await journalResume(opts.root, request, validated.files);
@@ -55521,6 +55602,218 @@ function parseExplicitFilenames(request) {
55521
55602
  }
55522
55603
  return out;
55523
55604
  }
55605
+ function detectEditIntent(request, ctx2) {
55606
+ const r2 = request.toLowerCase();
55607
+ const editKeywords = ["modify", "edit", "update", "fix", "refactor", "change", "patch", "\u5DEE\u5206", "\u4FEE\u6B63", "\u5909\u66F4", "\u65E2\u5B58", "\u8FFD\u8A18"];
55608
+ const mentionsEdit = editKeywords.some((k) => r2.includes(k));
55609
+ return ctx2.hasAttachments || ctx2.explicitFilesCount > 0 || mentionsEdit;
55610
+ }
55611
+ function sanitizeFolderName(name2) {
55612
+ const base = name2.toLowerCase().replace(/[`~!@#$%^&*()+=\[\]{}|;:'",<>/?\\]/g, " ").replace(/\s+/g, "-").replace(/^-+|-+$/g, "").slice(0, 48);
55613
+ return base || "project";
55614
+ }
55615
+ function deriveProjectFolderName(request) {
55616
+ const words = request.toLowerCase().replace(/[^a-z0-9\s-]/g, " ").split(/\s+/).filter((w) => w.length > 2).slice(0, 4).join("-");
55617
+ return sanitizeFolderName(words || "project");
55618
+ }
55619
+ function startsWithTopFolder(p, folder) {
55620
+ if (!folder) return false;
55621
+ const seg = p.replace(/^\/+/, "").split("/")[0];
55622
+ return seg.toLowerCase() === folder.toLowerCase();
55623
+ }
55624
+ function prefixWithTopFolder(p, folder) {
55625
+ const rel = p.replace(/^\/+/, "");
55626
+ return `${folder}/${rel}`;
55627
+ }
55628
+ async function ensureTopFolder(root, proposed, plans) {
55629
+ const tops = /* @__PURE__ */ new Set();
55630
+ for (const p of plans) {
55631
+ const seg = p.path.replace(/^\/+/, "").split("/")[0] || "";
55632
+ if (seg) tops.add(seg);
55633
+ }
55634
+ if (tops.size === 1) {
55635
+ const only = Array.from(tops)[0];
55636
+ const unique2 = await ensureUniqueFolder(root, only);
55637
+ return { folderName: unique2, detectedTop: only };
55638
+ }
55639
+ const unique = await ensureUniqueFolder(root, proposed);
55640
+ return { folderName: unique };
55641
+ }
55642
+ async function ensureUniqueFolder(root, base) {
55643
+ const fs49 = await import('fs/promises');
55644
+ const pathMod = await import('path');
55645
+ let name2 = sanitizeFolderName(base);
55646
+ let suffix = 0;
55647
+ for (; suffix < Number.MAX_SAFE_INTEGER; ) {
55648
+ const candidate = suffix === 0 ? name2 : `${name2}-${String(suffix).padStart(2, "0")}`;
55649
+ try {
55650
+ await fs49.access(pathMod.join(root, candidate));
55651
+ suffix += 1;
55652
+ } catch {
55653
+ return candidate;
55654
+ }
55655
+ }
55656
+ throw new Error("ensureUniqueFolder: exhausted attempts to find a unique folder name");
55657
+ }
55658
+ async function buildEditContext(root, files, maxLines, maxBytes) {
55659
+ try {
55660
+ const fs49 = await import('fs/promises');
55661
+ const pathMod = await import('path');
55662
+ const sections = [];
55663
+ for (const rel of files) {
55664
+ const full = pathMod.join(root, rel);
55665
+ try {
55666
+ const buf = await fs49.readFile(full);
55667
+ const clipped = buf.length > maxBytes ? buf.subarray(0, maxBytes) : buf;
55668
+ const text = clipped.toString("utf8").replace(/\r\n/g, "\n");
55669
+ const lines = text.split("\n").slice(0, maxLines).join("\n");
55670
+ sections.push(`[BEGIN file: ${rel}]
55671
+ ${lines}
55672
+ [END]`);
55673
+ } catch {
55674
+ }
55675
+ }
55676
+ if (sections.length === 0) return "";
55677
+ return ["// Current repository files (read-only context):", ...sections].join("\n");
55678
+ } catch {
55679
+ return "";
55680
+ }
55681
+ }
55682
+ async function resolveExplicitPaths(root, files, hintText) {
55683
+ const fs49 = await import('fs/promises');
55684
+ const pathMod = await import('path');
55685
+ const { loadGlobby: loadGlobby2 } = await Promise.resolve().then(() => (init_esm_compat(), esm_compat_exports));
55686
+ const globby = await loadGlobby2();
55687
+ const ignore = [
55688
+ "**/node_modules/**",
55689
+ "**/.git/**",
55690
+ "**/dist/**",
55691
+ "**/build/**",
55692
+ "**/.maria/**",
55693
+ "**/.next/**",
55694
+ "**/coverage/**"
55695
+ ];
55696
+ const hintTokens = Array.from(new Set(hintText.toLowerCase().replace(/[^a-z0-9_/.-]+/g, " ").split(/\s+/).filter(Boolean)));
55697
+ async function findBest(rel) {
55698
+ const normalized = rel.replace(/^\/+/, "").replace(/\\/g, "/");
55699
+ const fullExact = pathMod.join(root, normalized);
55700
+ try {
55701
+ await fs49.access(fullExact);
55702
+ return normalized;
55703
+ } catch {
55704
+ }
55705
+ const lowerRel = normalized.toLowerCase();
55706
+ const ext2 = (pathMod.extname(normalized) || "").toLowerCase();
55707
+ const base = pathMod.basename(normalized);
55708
+ const nameNoExt = base.replace(/\.[^.]+$/, "").toLowerCase();
55709
+ const parentPath = pathMod.dirname(normalized);
55710
+ const parent = parentPath.split("/").pop() || "";
55711
+ const dirParts = parentPath === "." ? [] : parentPath.split("/").filter(Boolean).map((s2) => s2.toLowerCase());
55712
+ const patterns = [];
55713
+ patterns.push(`**/${normalized}`);
55714
+ if (parent && parent !== "." && parent !== "/") patterns.push(`**/${parent}/${base}`);
55715
+ if (base) patterns.push(`**/${base}`);
55716
+ patterns.push(`**/*${base}`);
55717
+ if (!ext2) {
55718
+ patterns.push(`**/${nameNoExt}.*`);
55719
+ }
55720
+ const uniqPatterns = Array.from(new Set(patterns));
55721
+ const candidatesSet = /* @__PURE__ */ new Set();
55722
+ for (const pat of uniqPatterns) {
55723
+ const found = await globby(pat, { cwd: root, absolute: false, gitignore: true, ignore });
55724
+ for (const f3 of found) {
55725
+ candidatesSet.add(f3.replace(/\\/g, "/"));
55726
+ }
55727
+ if (candidatesSet.size > 200) break;
55728
+ }
55729
+ let candidates = Array.from(candidatesSet);
55730
+ if (dirParts.length > 0) {
55731
+ const filtered = candidates.filter((relp) => {
55732
+ const segs = relp.toLowerCase().split("/");
55733
+ let pos = -1;
55734
+ for (const part of dirParts) {
55735
+ const next = segs.indexOf(part, pos + 1);
55736
+ if (next === -1) return false;
55737
+ pos = next;
55738
+ }
55739
+ return true;
55740
+ });
55741
+ if (filtered.length > 0) candidates = filtered;
55742
+ }
55743
+ if (candidates.length === 0) {
55744
+ const prefixes = ["", "src/", "app/", "pages/"];
55745
+ for (const pre of prefixes) {
55746
+ const cand = pathMod.join(root, pre + normalized);
55747
+ try {
55748
+ await fs49.access(cand);
55749
+ return (pre + normalized).replace(/^\/+/, "");
55750
+ } catch {
55751
+ }
55752
+ }
55753
+ if (dirParts.length > 0) {
55754
+ if (/^(src|app|pages)\//i.test(normalized)) return normalized;
55755
+ const pref = await pickExistingFolderPrefix(root, parentPath);
55756
+ const combined = (pref + normalized).replace(/^\/+/, "").replace(/^(src\/)src\//i, "$1");
55757
+ return combined;
55758
+ }
55759
+ return normalized.replace(/^(src\/)src\//i, "$1");
55760
+ }
55761
+ function score(relPath) {
55762
+ const lower2 = relPath.toLowerCase();
55763
+ let s2 = 0;
55764
+ if (lower2.endsWith(lowerRel)) s2 += 80;
55765
+ if (lower2.split("/").pop() === base.toLowerCase()) s2 += 40;
55766
+ if (ext2 && lower2.endsWith(ext2)) s2 += 10;
55767
+ if (lower2.startsWith("src/")) s2 += 18;
55768
+ if (parent && lower2.includes(`/${parent.toLowerCase()}/`)) s2 += 15;
55769
+ if (parentPath && lower2.endsWith(`/${parentPath.toLowerCase()}/${base.toLowerCase()}`)) s2 += 40;
55770
+ if (dirParts.length > 0) {
55771
+ for (const part of dirParts) {
55772
+ if (lower2.includes(`/${part}/`)) s2 += 20;
55773
+ else s2 -= 120;
55774
+ }
55775
+ }
55776
+ for (const t2 of hintTokens) {
55777
+ if (t2.length >= 3 && lower2.includes(`/${t2}/`)) {
55778
+ s2 += 2;
55779
+ }
55780
+ }
55781
+ s2 -= Math.min(10, Math.floor(relPath.length / 80));
55782
+ return s2;
55783
+ }
55784
+ let best = candidates[0];
55785
+ let bestScore = score(best);
55786
+ for (let i2 = 1; i2 < candidates.length; i2++) {
55787
+ const c = candidates[i2];
55788
+ const sc = score(c);
55789
+ if (sc > bestScore) {
55790
+ best = c;
55791
+ bestScore = sc;
55792
+ }
55793
+ }
55794
+ return best.replace(/^\/+/, "");
55795
+ }
55796
+ const out = [];
55797
+ for (const f3 of files) {
55798
+ out.push(await findBest(f3));
55799
+ }
55800
+ return out;
55801
+ }
55802
+ async function pickExistingFolderPrefix(root, parentPath) {
55803
+ const fs49 = await import('fs/promises');
55804
+ const pathMod = await import('path');
55805
+ const parts = parentPath.replace(/^\/+/, "").split("/").filter(Boolean);
55806
+ const prefixes = ["src", "app", "pages", ""];
55807
+ for (const pre of prefixes) {
55808
+ const test = pre ? pathMod.join(root, pre, ...parts) : pathMod.join(root, ...parts);
55809
+ try {
55810
+ await fs49.access(test);
55811
+ return pre ? `${pre}/` : "";
55812
+ } catch {
55813
+ }
55814
+ }
55815
+ return "src/";
55816
+ }
55524
55817
  function scaffoldForFilename(filename, all) {
55525
55818
  const lower2 = filename.toLowerCase();
55526
55819
  if (lower2.endsWith(".html")) {
@@ -56495,16 +56788,6 @@ var init_resume_command = __esm({
56495
56788
  }
56496
56789
  });
56497
56790
 
56498
- // src/utils/esm-compat.ts
56499
- async function loadGlobby() {
56500
- const mod = await import('globby');
56501
- return mod?.globby ?? mod?.default ?? mod;
56502
- }
56503
- var init_esm_compat = __esm({
56504
- "src/utils/esm-compat.ts"() {
56505
- }
56506
- });
56507
-
56508
56791
  // src/services/init/scanner.ts
56509
56792
  var scanner_exports = {};
56510
56793
  __export(scanner_exports, {