@bonginkan/maria 4.3.44 → 4.3.46

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.
@@ -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.44",
26070
- description: "\u{1F680} MARIA v4.3.44 - 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.46",
26070
+ description: "\u{1F680} MARIA v4.3.46 - 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",
@@ -26619,7 +26619,8 @@ var init_env_loader = __esm({
26619
26619
  var ThinkingAnimation, ProcessAnimation;
26620
26620
  var init_animations = __esm({
26621
26621
  "src/utils/animations.ts"() {
26622
- ThinkingAnimation = class {
26622
+ ThinkingAnimation = class _ThinkingAnimation {
26623
+ static current = null;
26623
26624
  frames = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
26624
26625
  currentFrame = 0;
26625
26626
  interval = null;
@@ -26628,6 +26629,13 @@ var init_animations = __esm({
26628
26629
  this.message = message;
26629
26630
  }
26630
26631
  start() {
26632
+ if (_ThinkingAnimation.current && _ThinkingAnimation.current !== this) {
26633
+ try {
26634
+ _ThinkingAnimation.current.stop();
26635
+ } catch {
26636
+ }
26637
+ }
26638
+ _ThinkingAnimation.current = this;
26631
26639
  this.interval = setInterval(() => {
26632
26640
  process.stdout.write(
26633
26641
  `\r${chalk14__default.default.cyan(this.frames[this.currentFrame])} ${chalk14__default.default.gray(this.message)}...`
@@ -26641,12 +26649,16 @@ var init_animations = __esm({
26641
26649
  this.interval = null;
26642
26650
  process.stdout.write("\r\x1B[K");
26643
26651
  }
26652
+ if (_ThinkingAnimation.current === this) {
26653
+ _ThinkingAnimation.current = null;
26654
+ }
26644
26655
  }
26645
26656
  updateMessage(message) {
26646
26657
  this.message = message;
26647
26658
  }
26648
26659
  };
26649
- ProcessAnimation = class {
26660
+ ProcessAnimation = class _ProcessAnimation {
26661
+ static current = null;
26650
26662
  stages = [
26651
26663
  { icon: "\u{1F9E0}", message: "Understanding your request" },
26652
26664
  { icon: "\u{1F50D}", message: "Analyzing context" },
@@ -26660,7 +26672,18 @@ var init_animations = __esm({
26660
26672
  interval = null;
26661
26673
  stageInterval = null;
26662
26674
  startTime = 0;
26675
+ // Expose whether any ProcessAnimation is currently active
26676
+ static hasActive() {
26677
+ return !!_ProcessAnimation.current;
26678
+ }
26663
26679
  start() {
26680
+ if (_ProcessAnimation.current && _ProcessAnimation.current !== this) {
26681
+ try {
26682
+ _ProcessAnimation.current.stop();
26683
+ } catch {
26684
+ }
26685
+ }
26686
+ _ProcessAnimation.current = this;
26664
26687
  this.startTime = Date.now();
26665
26688
  this.currentStage = 0;
26666
26689
  this.currentFrame = 0;
@@ -26688,6 +26711,9 @@ var init_animations = __esm({
26688
26711
  this.stageInterval = null;
26689
26712
  }
26690
26713
  process.stdout.write("\r\x1B[K");
26714
+ if (_ProcessAnimation.current === this) {
26715
+ _ProcessAnimation.current = null;
26716
+ }
26691
26717
  }
26692
26718
  setStage(stageIndex) {
26693
26719
  if (stageIndex >= 0 && stageIndex < this.stages.length) {
@@ -28104,7 +28130,7 @@ var init_AuthenticationManager = __esm({
28104
28130
  const response = await fetch(`${this.apiBase}/api/user/profile`, {
28105
28131
  headers: {
28106
28132
  "Authorization": `Bearer ${tokens2.accessToken}`,
28107
- "User-Agent": `maria-cli/${process.env.CLI_VERSION || "4.3.44"}`
28133
+ "User-Agent": `maria-cli/${process.env.CLI_VERSION || "4.3.46"}`
28108
28134
  }
28109
28135
  });
28110
28136
  if (response.status === 401) {
@@ -28758,7 +28784,7 @@ async function callApi(path65, init3 = {}) {
28758
28784
  "Authorization": `Bearer ${token}`,
28759
28785
  "X-Device-Id": getDeviceId(),
28760
28786
  "X-Session-Id": getSessionId() || "",
28761
- "User-Agent": `maria-cli/${process.env.CLI_VERSION || "4.3.44"}`,
28787
+ "User-Agent": `maria-cli/${process.env.CLI_VERSION || "4.3.46"}`,
28762
28788
  "Content-Type": init3.headers?.["Content-Type"] || "application/json"
28763
28789
  });
28764
28790
  const doFetch = async (token) => {
@@ -29102,15 +29128,27 @@ async function callAPI(endpoint, options = {}) {
29102
29128
  throw err;
29103
29129
  }
29104
29130
  }
29105
- async function executeChat(messages) {
29131
+ async function executeChat(messages, options) {
29106
29132
  const maxAttempts = 4;
29107
29133
  let lastErr;
29108
29134
  for (let attempt = 1; attempt <= maxAttempts; attempt++) {
29109
29135
  try {
29136
+ if (process.env.MARIA_DEBUG === "1") {
29137
+ try {
29138
+ console.log("[DEBUG/ai] chat.request", { attempt, provider: options?.provider, model: options?.model, messages: messages.slice(0, 3) });
29139
+ } catch {
29140
+ }
29141
+ }
29110
29142
  const response = await callAPI("/v1/ai-proxy", {
29111
29143
  method: "POST",
29112
- body: { messages, taskType: "chat" }
29144
+ body: { messages, taskType: "chat", ...options?.provider ? { provider: options.provider } : {}, ...options?.model ? { model: options.model } : {} }
29113
29145
  });
29146
+ if (process.env.MARIA_DEBUG === "1") {
29147
+ try {
29148
+ console.log("[DEBUG/ai] chat.response.head", String(response?.data?.content || response?.output || "").slice(0, 1200));
29149
+ } catch {
29150
+ }
29151
+ }
29114
29152
  return response;
29115
29153
  } catch (e2) {
29116
29154
  lastErr = e2;
@@ -29142,6 +29180,13 @@ async function executeCode(input3) {
29142
29180
  let lastErr;
29143
29181
  for (let attempt = 1; attempt <= maxAttempts; attempt++) {
29144
29182
  try {
29183
+ if (process.env.MARIA_DEBUG === "1") {
29184
+ try {
29185
+ const dbg = typeof input3 === "string" ? { prompt: String(input3).slice(0, 800) } : { prompt: input3.prompt.slice(0, 800), provider: input3.provider, model: input3.model, attachments: Array.isArray(input3.attachments) ? input3.attachments.length : 0 };
29186
+ console.log("[DEBUG/ai] code.request", { attempt, ...dbg });
29187
+ } catch {
29188
+ }
29189
+ }
29145
29190
  const response = await callAPI("/v1/ai-proxy", {
29146
29191
  method: "POST",
29147
29192
  body
@@ -29152,6 +29197,12 @@ async function executeCode(input3) {
29152
29197
  if (response.data?.content) {
29153
29198
  response.output = response.data.content;
29154
29199
  }
29200
+ if (process.env.MARIA_DEBUG === "1") {
29201
+ try {
29202
+ console.log("[DEBUG/ai] code.response.head", String(response?.output || "").slice(0, 1200));
29203
+ } catch {
29204
+ }
29205
+ }
29155
29206
  return response;
29156
29207
  } catch (e2) {
29157
29208
  lastErr = e2;
@@ -49569,7 +49620,10 @@ var init_video_command = __esm({
49569
49620
  const base = (process.env.MARIA_API_BASE || "https://api.maria-code.ai").replace(/\/$/, "");
49570
49621
  const savedPaths = [];
49571
49622
  const baseDir = "video";
49572
- const promptPrefix = (cli.prompt || "").slice(0, 20).replace(/\s+/g, "_").replace(/[^A-Za-z0-9_\-]/g, "_") || "untitled";
49623
+ const rawPrefix = (cli.prompt || "").slice(0, 20).replace(/\s+/g, "_");
49624
+ let promptPrefix = rawPrefix.replace(/[\x00-\x1F<>:"/\\|?*]/g, "_").replace(/[. ]+$/g, "");
49625
+ if (!promptPrefix) promptPrefix = "untitled";
49626
+ if (/^(con|prn|aux|nul|com[1-9]|lpt[1-9])$/i.test(promptPrefix)) promptPrefix = `${promptPrefix}_`;
49573
49627
  const utc = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
49574
49628
  let idx = 0;
49575
49629
  for (const relRaw of filesFromApi) {
@@ -51295,7 +51349,7 @@ var init_about_command = __esm({
51295
51349
  async execute(args2, context2) {
51296
51350
  const output3 = [];
51297
51351
  output3.push("");
51298
- output3.push(chalk14__default.default.cyan.bold("\u{1F916} About MARIA v4.3.44"));
51352
+ output3.push(chalk14__default.default.cyan.bold("\u{1F916} About MARIA v4.3.46"));
51299
51353
  output3.push(chalk14__default.default.gray("\u2550".repeat(40)));
51300
51354
  output3.push("");
51301
51355
  output3.push(chalk14__default.default.white.bold("MARIA - Minimal API, Maximum Power"));
@@ -55022,9 +55076,10 @@ function extractFirstJson5(text) {
55022
55076
  async function inferCodeArgs(rawText) {
55023
55077
  const system = [
55024
55078
  "You extract structured options for a code command.",
55025
- 'Return JSON only with keys: { "planOnly"?: boolean, "dryRun"?: boolean, "output"?: "names"|"summary"|"detail", "previewLines"?: number }.',
55079
+ 'Return JSON only with keys: { "planOnly"?: boolean, "dryRun"?: boolean, "output"?: "names"|"summary"|"detail", "previewLines"?: number, "onlyAttached"?: boolean }.',
55026
55080
  "Decide from the user text whether planOnly or dryRun should be true. Do not explain.",
55027
- "Only include output if the user requests preview detail or summary mode. Only include previewLines if a specific number of lines is requested."
55081
+ "Only include output if the user requests preview detail or summary mode. Only include previewLines if a specific number of lines is requested.",
55082
+ "Set onlyAttached=true when the user indicates editing only attached/uploaded/provided files, or restrict changes to referenced files."
55028
55083
  ].join("\n");
55029
55084
  const resp = await callAPI("/v1/ai-proxy", {
55030
55085
  method: "POST",
@@ -55045,11 +55100,19 @@ ${rawText}`,
55045
55100
  } catch {
55046
55101
  return {};
55047
55102
  }
55103
+ if (process.env.MARIA_DEBUG === "1") {
55104
+ try {
55105
+ console.log("[DEBUG/code] inferCodeArgs.response.raw", raw.slice(0, 1200));
55106
+ console.log("[DEBUG/code] inferCodeArgs.parsed", parsed);
55107
+ } catch {
55108
+ }
55109
+ }
55048
55110
  const out = {};
55049
55111
  if (typeof parsed.planOnly === "boolean") out.planOnly = parsed.planOnly;
55050
55112
  if (typeof parsed.dryRun === "boolean") out.dryRun = parsed.dryRun;
55051
55113
  if (typeof parsed.output === "string" && (parsed.output === "names" || parsed.output === "summary" || parsed.output === "detail")) out.output = parsed.output;
55052
55114
  if (typeof parsed.previewLines === "number" && Number.isFinite(parsed.previewLines) && parsed.previewLines > 0) out.previewLines = Math.min(2e3, Math.floor(parsed.previewLines));
55115
+ if (typeof parsed.onlyAttached === "boolean") out.onlyAttached = parsed.onlyAttached;
55053
55116
  if (out.planOnly) out.dryRun = false;
55054
55117
  return out;
55055
55118
  }
@@ -55197,6 +55260,12 @@ var init_FilePlanBuilder = __esm({
55197
55260
  }
55198
55261
  });
55199
55262
  async function validatePlan(plans, opts) {
55263
+ if (process.env.MARIA_DEBUG === "1") {
55264
+ try {
55265
+ console.log("[DEBUG/orchestrator] validatePlan.input.count", plans.length);
55266
+ } catch {
55267
+ }
55268
+ }
55200
55269
  const warnings = [];
55201
55270
  const skipped = [];
55202
55271
  const seenLC = /* @__PURE__ */ new Set();
@@ -55213,6 +55282,10 @@ async function validatePlan(plans, opts) {
55213
55282
  }
55214
55283
  const safe = [];
55215
55284
  for (const fp of outFiltered) {
55285
+ if (fp.action === "skip") {
55286
+ skipped.push(fp.path);
55287
+ continue;
55288
+ }
55216
55289
  const rel = fp.path.replace(/^\/+/, "");
55217
55290
  if (rel.includes("..")) {
55218
55291
  warnings.push(`Path traversal denied: ${fp.path}`);
@@ -55294,7 +55367,18 @@ async function validatePlan(plans, opts) {
55294
55367
  }
55295
55368
  result.push({ ...fp, action: willModify ? "modify" : "create" });
55296
55369
  }
55297
- return { files: result, skipped, warnings };
55370
+ const out = { files: result, skipped, warnings };
55371
+ if (process.env.MARIA_DEBUG === "1") {
55372
+ try {
55373
+ console.log("[DEBUG/orchestrator] validatePlan.output", {
55374
+ files: out.files.map((f3) => ({ path: f3.path, action: f3.action })),
55375
+ skipped: out.skipped,
55376
+ warnings: out.warnings
55377
+ });
55378
+ } catch {
55379
+ }
55380
+ }
55381
+ return out;
55298
55382
  }
55299
55383
  async function exists(p) {
55300
55384
  try {
@@ -56088,7 +56172,7 @@ ${h2.head}`);
56088
56172
  const resp = await executeChat([
56089
56173
  { role: "system", content: system },
56090
56174
  { role: "user", content: user }
56091
- ]);
56175
+ ], { provider: "google", model: "gemini-2.5-flash-lite" });
56092
56176
  const raw = (resp?.output || "").trim();
56093
56177
  const jsonText = extractJsonSafe(raw, "array") || raw;
56094
56178
  const arr = JSON.parse(jsonText);
@@ -56105,7 +56189,7 @@ ${h2.head}`);
56105
56189
  return [];
56106
56190
  }
56107
56191
  }
56108
- async function llmMapBlocksBatch(root, request, blocks, repoFiles) {
56192
+ async function llmMapBlocksBatch(root, request, blocks, repoFiles, opts) {
56109
56193
  try {
56110
56194
  const candidates = repoFiles.filter((p) => /\.(html|css|js|ts|tsx)$/i.test(p)).slice(0, 120);
56111
56195
  const blockSnippets = blocks.slice(0, 20).map((b, i2) => {
@@ -56123,26 +56207,43 @@ ${head2}
56123
56207
  ${h2.head}`);
56124
56208
  }
56125
56209
  const system = [
56126
- "For each provided code block, decide whether to MODIFY an existing repo file or CREATE a new file.",
56127
- 'Return JSON array of objects: [{ "index": number, "action": "modify"|"create", "path": string }].',
56128
- "When action is modify, path MUST be one of the candidate repo-relative paths listed."
56210
+ "You act as a precise file mapper for code edits.",
56211
+ "For each provided code block, decide to MODIFY an existing repo file or CREATE a new file.",
56212
+ "Rules:",
56213
+ "- Prefer MODIFY when an existing file in candidates plausibly matches the block (same technology, same area).",
56214
+ "- If any TargetDirHints are provided, prefer files under those directories when choosing MODIFY targets.",
56215
+ "- Only choose CREATE if NO suitable candidate exists. Do NOT invent frameworks or restructure.",
56216
+ "- When MODIFY, the path MUST be one of the candidate repo-relative paths listed.",
56217
+ 'Return JSON array: [{ "index": number, "action": "modify"|"create", "path": string }].'
56129
56218
  ].join("\n");
56130
56219
  const user = [
56131
56220
  `Request: ${request}`,
56132
56221
  "Blocks:",
56133
56222
  blockSnippets,
56134
56223
  "Candidates:",
56135
- samples.join("\n\n")
56224
+ samples.join("\n\n"),
56225
+ `TargetDirHints: ${(opts?.dirHints || []).join(", ")}`
56136
56226
  ].join("\n\n");
56137
- const spin = new ProcessAnimation();
56138
- spin.start();
56139
- const resp = await executeChat([
56140
- { role: "system", content: system },
56141
- { role: "user", content: user }
56142
- ]);
56227
+ let startedLocalSpinner = false;
56228
+ let spin = null;
56229
+ if (!ProcessAnimation.hasActive()) {
56230
+ spin = new ProcessAnimation();
56231
+ spin.start();
56232
+ startedLocalSpinner = true;
56233
+ }
56234
+ let resp;
56143
56235
  try {
56144
- spin.stop();
56145
- } catch {
56236
+ resp = await executeChat([
56237
+ { role: "system", content: system },
56238
+ { role: "user", content: user }
56239
+ ], { provider: "google", model: "gemini-2.5-flash-lite" });
56240
+ } finally {
56241
+ if (startedLocalSpinner && spin) {
56242
+ try {
56243
+ spin.stop();
56244
+ } catch {
56245
+ }
56246
+ }
56146
56247
  }
56147
56248
  const raw = (resp?.output || "").trim();
56148
56249
  const jsonText = extractJsonSafe(raw, "array") || raw;
@@ -56196,12 +56297,25 @@ function trackCodeFallback(event) {
56196
56297
  }
56197
56298
  }
56198
56299
  async function orchestrate(request, opts) {
56300
+ const dbg = (...a) => {
56301
+ if (process.env.MARIA_DEBUG === "1") {
56302
+ try {
56303
+ console.log("[DEBUG/orchestrator]", ...a);
56304
+ } catch {
56305
+ }
56306
+ }
56307
+ };
56199
56308
  const profile = await scanRepo(opts.root);
56309
+ dbg("start", { root: opts.root, flags: {
56310
+ ...opts.flags
56311
+ /* redact */
56312
+ }, attachedFiles: Array.isArray(opts.attachedFiles) ? opts.attachedFiles.length : 0 });
56200
56313
  const initial = [];
56201
56314
  const fallbackNotices = [];
56202
56315
  const withNotices = (base) => fallbackNotices.length > 0 ? [...fallbackNotices, ...base] : base;
56203
56316
  const explicitFilesRaw = parseExplicitFilenames(request);
56204
56317
  const explicitFiles = explicitFilesRaw.length > 0 ? await resolveExplicitPaths(opts.root, explicitFilesRaw, request) : [];
56318
+ dbg("explicitFiles", { raw: explicitFilesRaw, resolved: explicitFiles });
56205
56319
  const explicitAbsMap = /* @__PURE__ */ Object.create(null);
56206
56320
  if (explicitFiles.length > 0) {
56207
56321
  const pathMod = await import('path');
@@ -56213,12 +56327,14 @@ async function orchestrate(request, opts) {
56213
56327
  explicitFiles,
56214
56328
  attachmentsCount: Array.isArray(opts.attachedFiles) ? opts.attachedFiles.length : 0
56215
56329
  });
56330
+ dbg("intent", { isEditIntent });
56216
56331
  let editTargets = explicitFiles;
56217
56332
  if (isEditIntent && editTargets.length === 0) {
56218
56333
  try {
56219
56334
  const repoFiles = await getRepoFiles(opts.root);
56220
56335
  const llmTargets = await llmSelectEditTargets(opts.root, request, repoFiles);
56221
56336
  editTargets = llmTargets;
56337
+ dbg("llmSelectEditTargets", { editTargets });
56222
56338
  } catch {
56223
56339
  }
56224
56340
  }
@@ -56230,6 +56346,7 @@ async function orchestrate(request, opts) {
56230
56346
  maxAttachments: opts.flags.maxAttachments || 50,
56231
56347
  allowDotfiles: !!opts.flags.allowDotfiles
56232
56348
  });
56349
+ dbg("attachment.map", { mappedCount: mapRes.mapped.length, warnings: mapRes.warnings });
56233
56350
  mapRes.warnings.slice();
56234
56351
  for (const m2 of mapRes.mapped) {
56235
56352
  initial.push({
@@ -56241,7 +56358,7 @@ async function orchestrate(request, opts) {
56241
56358
  });
56242
56359
  }
56243
56360
  }
56244
- const onlyAttached = !!opts.flags.onlyAttached;
56361
+ const onlyAttached = !!(opts.flags.onlyAttached && Array.isArray(opts.attachedFiles) && opts.attachedFiles.length > 0);
56245
56362
  if (!onlyAttached) {
56246
56363
  let codeOutput = "";
56247
56364
  if (process.env.MARIA_E2E_FAKE_CODE === "1") {
@@ -56261,10 +56378,37 @@ async function orchestrate(request, opts) {
56261
56378
  "[BEGIN file: path]\n<content>\n[END]",
56262
56379
  "Do not include any prose before/after; no menus/questions/suggestions; start immediately with ``` or [BEGIN file: ...]."
56263
56380
  ].join("\n");
56381
+ let targetFilesAbs = [];
56382
+ try {
56383
+ const pathMod = await import('path');
56384
+ const fromExplicit = Array.isArray(explicitFiles) && explicitFiles.length > 0 ? explicitFiles.map((rel) => explicitAbsMap[rel] || pathMod.join(opts.root, rel)) : [];
56385
+ const fromEditTargets = Array.isArray(editTargets) && editTargets.length > 0 ? editTargets.map((rel) => pathMod.isAbsolute(rel) ? rel : pathMod.join(opts.root, rel)) : [];
56386
+ const seen = /* @__PURE__ */ new Set();
56387
+ for (const p of [...fromExplicit, ...fromEditTargets]) {
56388
+ const norm = (p || "").replace(/\\/g, "/");
56389
+ if (!norm) continue;
56390
+ if (seen.has(norm)) continue;
56391
+ seen.add(norm);
56392
+ targetFilesAbs.push(norm);
56393
+ }
56394
+ } catch {
56395
+ }
56396
+ const targetDirsAbs = Array.from(new Set(targetFilesAbs.map((p) => p.split("/").slice(0, -1).join("/")).filter(Boolean)));
56397
+ const targetFilesSection = targetFilesAbs.length > 0 ? ["// TARGET FILES (absolute):", ...targetFilesAbs.map((p) => `// - ${p}`)].join("\n") : "";
56398
+ const targetDirsSection = targetDirsAbs.length > 0 ? ["// TARGET DIRECTORIES (absolute):", ...targetDirsAbs.map((p) => `// - ${p}`)].join("\n") : "";
56264
56399
  const requestPreamble = isEditIntent ? [
56265
- "// EDIT MODE: modify existing files, preserve unrelated content.",
56266
- "// Follow existing structure and only touch requested files.",
56267
- editContext ? "// Current file snapshots provided below." : ""
56400
+ "// EDIT MODE RULES:",
56401
+ "// 1) Read the entire target file(s) BEFORE making changes. Assume omitted lines must remain exactly as-is.",
56402
+ "// 2) Preserve unrelated content and formatting (indentation, EOLs, imports order, license headers).",
56403
+ "// 3) Do NOT rename, move, or delete files unless explicitly requested.",
56404
+ "// 4) Apply the MINIMAL necessary change to achieve the request. Avoid broad refactors.",
56405
+ "// 5) When returning a whole file, keep everything identical except for the exact lines you changed.",
56406
+ "// 6) Do NOT introduce unrelated edits or code style churn.",
56407
+ "// 7) Edit ONLY the files listed under TARGET FILES or inside TARGET DIRECTORIES unless explicitly instructed otherwise.",
56408
+ "// 8) Do NOT create or scaffold new projects or files outside these targets (no package.json, no CRA/Vite scaffolds, etc.) unless such files already exist and are being modified.",
56409
+ editContext ? "// Current file snapshots provided below." : "",
56410
+ targetFilesSection,
56411
+ targetDirsSection
56268
56412
  ].filter(Boolean).join("\n") : "";
56269
56413
  const enriched = `${FILE_FORMAT_INSTRUCTIONS}
56270
56414
 
@@ -56272,6 +56416,7 @@ ${requestPreamble}
56272
56416
  ${request}
56273
56417
 
56274
56418
  ${editContext}`;
56419
+ dbg("executeCode.prompt.head", enriched.slice(0, 1400));
56275
56420
  const ctxAttachments = Array.isArray(opts.attachedFiles) && opts.attachedFiles.length > 0 ? opts.attachedFiles.map((f3) => ({
56276
56421
  name: f3.originalName,
56277
56422
  path: f3.pathHint,
@@ -56305,6 +56450,68 @@ ${editContext}`;
56305
56450
  } catch {
56306
56451
  }
56307
56452
  }
56453
+ try {
56454
+ const fs52 = await import('fs/promises');
56455
+ const pathMod = await import('path');
56456
+ const dirCandidates = Array.from(new Set(String(request).match(/[A-Za-z]:\\[^\s"']+|\.?\/?[^\s"']+[\/\\][^\s"']*/g) || []));
56457
+ const maxFilesPerDir = 80;
56458
+ for (const raw2 of dirCandidates) {
56459
+ try {
56460
+ const normalized2 = raw2.replace(/^"|"$/g, "").replace(/^'|'$/g, "");
56461
+ const abs = pathMod.isAbsolute(normalized2) ? normalized2 : pathMod.join(opts.root, normalized2);
56462
+ const st = await fs52.stat(abs).catch(() => null);
56463
+ if (!st || !st.isDirectory()) continue;
56464
+ const collected = [];
56465
+ const walk2 = async (d) => {
56466
+ if (collected.length >= maxFilesPerDir) return;
56467
+ let entries = [];
56468
+ try {
56469
+ entries = await fs52.readdir(d, { withFileTypes: true });
56470
+ } catch {
56471
+ return;
56472
+ }
56473
+ for (const e2 of entries) {
56474
+ const name2 = e2.name;
56475
+ if (name2 === ".git" || name2 === "node_modules" || name2 === "dist" || name2 === "build" || name2 === ".maria") continue;
56476
+ const full = pathMod.join(d, name2);
56477
+ if (e2.isDirectory()) {
56478
+ await walk2(full);
56479
+ if (collected.length >= maxFilesPerDir) break;
56480
+ continue;
56481
+ }
56482
+ collected.push(full);
56483
+ if (collected.length >= maxFilesPerDir) break;
56484
+ }
56485
+ };
56486
+ await walk2(abs);
56487
+ for (const f3 of collected) {
56488
+ try {
56489
+ const key = f3.toLowerCase();
56490
+ if (attachedPathSet.has(key)) continue;
56491
+ const buf = await fs52.readFile(f3);
56492
+ const head2 = buf.subarray(0, Math.min(buf.length, 4096));
56493
+ let binaryLike = false;
56494
+ for (let i2 = 0; i2 < head2.length; i2++) {
56495
+ if (head2[i2] === 0) {
56496
+ binaryLike = true;
56497
+ break;
56498
+ }
56499
+ }
56500
+ if (binaryLike) continue;
56501
+ const sample = buf.subarray(0, Math.min(buf.length, 8192)).toString("utf8");
56502
+ const printable = sample.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F]/g, "");
56503
+ const ratio = sample.length === 0 ? 0 : printable.length / sample.length;
56504
+ if (ratio < 0.6 && sample.length > 0) continue;
56505
+ pathAttachments.push({ name: pathMod.basename(f3), path: f3, mime: "text/plain", data_base64: buf.toString("base64") });
56506
+ attachedPathSet.add(key);
56507
+ } catch {
56508
+ }
56509
+ }
56510
+ } catch {
56511
+ }
56512
+ }
56513
+ } catch {
56514
+ }
56308
56515
  if (isEditIntent && Array.isArray(editTargets) && editTargets.length > 0) {
56309
56516
  try {
56310
56517
  const fs52 = await import('fs/promises');
@@ -56359,9 +56566,34 @@ ${editContext}`;
56359
56566
  hydratedCtx.push(...ctxAttachments);
56360
56567
  }
56361
56568
  }
56362
- const allAttachments = (hydratedCtx.length ? hydratedCtx : ctxAttachments).concat(pathAttachments);
56569
+ const pathMod2 = await import('path');
56570
+ const normalizeMime = (p, m2) => {
56571
+ if (!p) return m2 || "text/plain";
56572
+ const ext2 = pathMod2.extname(p).toLowerCase();
56573
+ if (m2 && m2 !== "application/octet-stream") return m2;
56574
+ if (ext2 === ".pdf") return "application/pdf";
56575
+ if (ext2 === ".png") return "image/png";
56576
+ if (ext2 === ".jpg" || ext2 === ".jpeg") return "image/jpeg";
56577
+ if (ext2 === ".webp") return "image/webp";
56578
+ if (ext2 === ".gif") return "image/gif";
56579
+ if (ext2 === ".bmp") return "image/bmp";
56580
+ if (ext2 === ".svg") return "image/svg+xml";
56581
+ if (ext2 === ".tif" || ext2 === ".tiff") return "image/tiff";
56582
+ if (ext2 === ".heic") return "image/heic";
56583
+ if (ext2 === ".heif") return "image/heif";
56584
+ return "text/plain";
56585
+ };
56586
+ const allAttachments = (hydratedCtx.length ? hydratedCtx : ctxAttachments).concat(pathAttachments).map((a) => ({
56587
+ ...a,
56588
+ mime: normalizeMime(a.path, a.mime)
56589
+ }));
56363
56590
  const response = await executeCode(allAttachments.length > 0 ? { prompt: enriched, provider: "google", model: "gemini-2.5-flash", attachments: allAttachments } : enriched);
56591
+ try {
56592
+ dbg("executeCode.attachments.meta", { ctx: (hydratedCtx.length ? hydratedCtx : ctxAttachments).length, path: pathAttachments.length });
56593
+ } catch {
56594
+ }
56364
56595
  const raw = (response.output || response?.data?.content || "").trim();
56596
+ dbg("executeCode.output.head", raw.slice(0, 1200));
56365
56597
  if (!raw) {
56366
56598
  return {
56367
56599
  ok: false,
@@ -56399,6 +56631,7 @@ ${editContext}`;
56399
56631
  codeOutput = outcome.data?.output || "";
56400
56632
  }
56401
56633
  const blocks = extractBlocks(codeOutput);
56634
+ dbg("extractBlocks.count", blocks.length);
56402
56635
  if (explicitFiles.length > 0 || isEditIntent && editTargets.length > 0) {
56403
56636
  const mapped = /* @__PURE__ */ new Set();
56404
56637
  const targets = explicitFiles.length > 0 ? explicitFiles : editTargets;
@@ -56436,23 +56669,49 @@ ${editContext}`;
56436
56669
  } else {
56437
56670
  try {
56438
56671
  const repoFiles = await getRepoFiles(opts.root);
56439
- const decisions = await llmMapBlocksBatch(opts.root, request, blocks, repoFiles);
56672
+ let dirHints = [];
56673
+ try {
56674
+ const fs52 = await import('fs/promises');
56675
+ const pathMod = await import('path');
56676
+ const rawDirs = Array.from(new Set(String(request).match(/[A-Za-z]:\\[^\s"']+|\.?\/?[^\s"']+[\/\\][^\s"']*/g) || []));
56677
+ for (const raw of rawDirs) {
56678
+ try {
56679
+ const normalized2 = raw.replace(/^"|"$/g, "").replace(/^'|'$/g, "");
56680
+ const abs = pathMod.isAbsolute(normalized2) ? normalized2 : pathMod.join(opts.root, normalized2);
56681
+ const st = await fs52.stat(abs).catch(() => null);
56682
+ if (!st || !st.isDirectory()) continue;
56683
+ const rel = pathMod.relative(opts.root, abs).replace(/\\/g, "/").replace(/^\/+/, "");
56684
+ if (!rel || rel.startsWith("..")) continue;
56685
+ dirHints.push(rel);
56686
+ } catch {
56687
+ }
56688
+ }
56689
+ if (dirHints.length === 0 && Array.isArray(editTargets) && editTargets.length > 0) {
56690
+ dirHints = Array.from(new Set(editTargets.map((p) => (p || "").replace(/^\/+/, "").split("/").slice(0, -1).join("/")).filter(Boolean)));
56691
+ }
56692
+ } catch {
56693
+ }
56694
+ const decisions = await llmMapBlocksBatch(opts.root, request, blocks, repoFiles, { dirHints });
56695
+ dbg("llmMapBlocksBatch.decisions", decisions);
56440
56696
  for (let i2 = 0; i2 < blocks.length; i2++) {
56441
56697
  const b = blocks[i2];
56442
56698
  const d = decisions[i2] || { action: "create", path: suggestName2(request, b.language, i2) };
56443
- if (d.action === "modify" && repoFiles.includes(d.path)) {
56699
+ const hinted = b.filename && String(b.filename).trim() || extractFilenameHintFromComment(b.code);
56700
+ const finalPath = hinted && hinted.trim() || d.path;
56701
+ if (d.action === "modify" && repoFiles.includes(finalPath)) {
56444
56702
  const lang = languageFromExt(d.path.replace(/^.*(\.[a-z0-9]+)$/i, "$1"));
56445
- initial.push({ path: d.path, kind: "source", action: "modify", description: "Modify existing file", language: lang, preview: b.code });
56703
+ initial.push({ path: finalPath, kind: "source", action: "modify", description: "Modify existing file", language: lang, preview: b.code, noNormalize: true });
56446
56704
  } else {
56447
- const pth = d.path || suggestName2(request, b.language, i2);
56448
- initial.push({ path: pth, kind: "source", action: "create", description: describe2(b.language, ""), language: b.language, preview: b.code });
56705
+ const pth = finalPath && finalPath.trim() || d.path || suggestName2(request, b.language, i2);
56706
+ initial.push({ path: pth, kind: "source", action: "create", description: describe2(b.language, ""), language: b.language, preview: b.code, noNormalize: true });
56449
56707
  }
56450
56708
  }
56451
56709
  } catch {
56452
56710
  for (let i2 = 0; i2 < blocks.length; i2++) {
56453
56711
  const b = blocks[i2];
56454
- const path65 = suggestName2(request, b.language, i2);
56455
- initial.push({ path: path65, kind: "source", action: "create", description: describe2(b.language, ""), language: b.language, preview: b.code });
56712
+ const hinted = b.filename && String(b.filename).trim() || extractFilenameHintFromComment(b.code);
56713
+ const path65 = hinted && hinted.trim() || suggestName2(request, b.language, i2);
56714
+ initial.push({ path: path65, kind: "source", action: "create", description: describe2(b.language, ""), language: b.language, preview: b.code, noNormalize: true });
56456
56715
  }
56457
56716
  }
56458
56717
  }
@@ -56468,13 +56727,13 @@ ${editContext}`;
56468
56727
  }
56469
56728
  }
56470
56729
  }
56471
- if (explicitFiles.length > 0 && initial.filter((f3) => !!f3.preview).length === 0) {
56730
+ if (!isEditIntent && explicitFiles.length > 0 && initial.filter((f3) => !!f3.preview).length === 0) {
56472
56731
  for (const f3 of explicitFiles) {
56473
56732
  initial.push(scaffoldForFilename(f3, explicitFiles));
56474
56733
  }
56475
56734
  }
56476
56735
  const normalized = await normalizePlans(
56477
- initial.map((p) => p.noNormalize ? p : p),
56736
+ initial.map((p) => p.noNormalize ? { ...p } : p),
56478
56737
  { root: opts.root }
56479
56738
  );
56480
56739
  try {
@@ -56499,11 +56758,26 @@ ${editContext}`;
56499
56758
  }
56500
56759
  } catch {
56501
56760
  }
56502
- const validated = await validatePlan(normalized, { root: opts.root, profile, flags: { maxFiles: opts.flags.maxFiles, yes: opts.flags.yes, interactive: !!opts.flags.interactive, ...opts.flags } });
56761
+ let filtered = normalized;
56762
+ if (isEditIntent) {
56763
+ const keepCreates = !!opts.flags.onlyAttached;
56764
+ if (!keepCreates) {
56765
+ filtered = normalized.map((f3) => f3.action === "create" ? { ...f3, action: "skip" } : f3);
56766
+ }
56767
+ }
56768
+ const baseFlags = { ...opts.flags };
56769
+ const effectiveFlags = {
56770
+ ...baseFlags,
56771
+ maxFiles: opts.flags.maxFiles,
56772
+ interactive: !!opts.flags.interactive,
56773
+ // Force yes when editing; if baseFlags.yes is already true, keep it true
56774
+ yes: baseFlags?.yes === true || isEditIntent
56775
+ };
56776
+ const validated = await validatePlan(filtered, { root: opts.root, profile, flags: effectiveFlags });
56503
56777
  const hasAnyModify = validated.files.some((f3) => f3.action === "modify") || isEditIntent;
56504
56778
  const outputMode = !opts.flags.hideCode && hasAnyModify ? "diff" : resolveOutputMode(opts.flags.output, validated.files.length, !!opts.flags.hideCode);
56505
56779
  const skippedSetForLookup = new Set(validated.skipped || []);
56506
- const skippedPlans = normalized.filter((f3) => skippedSetForLookup.has(f3.path));
56780
+ const skippedPlans = filtered.filter((f3) => skippedSetForLookup.has(f3.path));
56507
56781
  const remainingSkipped = (validated.skipped || []).filter((p) => !skippedPlans.some((sp) => sp.path === p)).map((p) => ({ path: p, kind: "source", action: "skip", description: "" }));
56508
56782
  const displayFiles = validated.files.concat(skippedPlans).concat(remainingSkipped);
56509
56783
  const summary = summarizePlan(displayFiles);
@@ -56696,6 +56970,21 @@ function extractBlocks(content) {
56696
56970
  if (blocks.length === 0 && looksLikeCode(content)) blocks.push({ language: detectLanguage(content), code: content.trim() });
56697
56971
  return blocks;
56698
56972
  }
56973
+ function extractFilenameHintFromComment(code) {
56974
+ try {
56975
+ const first = (code.split(/\r?\n/, 1)[0] || "").trim();
56976
+ let m2 = first.match(/^\/\/\s*filename:\s*(.+)$/i);
56977
+ if (m2?.[1]) return m2[1].trim();
56978
+ m2 = first.match(/^#\s*filename:\s*(.+)$/i);
56979
+ if (m2?.[1]) return m2[1].trim();
56980
+ m2 = first.match(/^<!--\s*filename:\s*(.+?)\s*-->$/i);
56981
+ if (m2?.[1]) return m2[1].trim();
56982
+ m2 = first.match(/^\/\*\s*filename:\s*(.+?)\s*\*\/$/i);
56983
+ if (m2?.[1]) return m2[1].trim();
56984
+ } catch {
56985
+ }
56986
+ return void 0;
56987
+ }
56699
56988
  function looksLikeCode(s2) {
56700
56989
  return ["function ", "const ", "let ", "var ", "class ", "def ", "import ", "export "].some((k) => s2.includes(k));
56701
56990
  }
@@ -56853,48 +57142,100 @@ function parseExplicitFilenames(request) {
56853
57142
  return out;
56854
57143
  }
56855
57144
  async function detectEditIntentLLM(root, request, ctx2) {
57145
+ let existingDirs = [];
57146
+ let existingFiles = [];
57147
+ let anyExistingPathMentioned = false;
56856
57148
  try {
57149
+ const fs52 = await import('fs/promises');
57150
+ const pathMod = await import('path');
57151
+ const rawPaths = Array.from(new Set(String(request).match(/[A-Za-z]:\\[^\s"']+|\.?\/?[^\s"']+[\/\\][^\s"']*/g) || []));
57152
+ existingDirs = [];
57153
+ existingFiles = [];
57154
+ for (const raw2 of rawPaths) {
57155
+ try {
57156
+ const normalized = raw2.replace(/^"|"$/g, "").replace(/^'|'$/g, "");
57157
+ const abs = pathMod.isAbsolute(normalized) ? normalized : pathMod.join(root, normalized);
57158
+ const st = await fs52.stat(abs).catch(() => null);
57159
+ if (!st) continue;
57160
+ anyExistingPathMentioned = true;
57161
+ const rel = pathMod.relative(root, abs).replace(/\\/g, "/");
57162
+ if (!rel || rel.startsWith("..")) continue;
57163
+ if (st.isDirectory()) existingDirs.push(rel);
57164
+ else if (st.isFile()) existingFiles.push(rel);
57165
+ } catch {
57166
+ }
57167
+ }
56857
57168
  const repoFiles = await getRepoFiles(root);
56858
- const candidates = repoFiles;
57169
+ let scope = [];
57170
+ if (existingDirs.length > 0) {
57171
+ const dirSet = existingDirs.map((d) => d.replace(/\\/g, "/").replace(/^\/+/, "").toLowerCase());
57172
+ scope = repoFiles.filter((p) => dirSet.some((d) => p.toLowerCase().startsWith(d + "/")));
57173
+ } else {
57174
+ scope = repoFiles;
57175
+ }
56859
57176
  const headSnippets = [];
56860
- for (const p of candidates) {
57177
+ for (const p of scope) {
56861
57178
  const h2 = await readHeadTail(root, p, 5);
56862
57179
  headSnippets.push(`- ${p}
56863
57180
  ${h2.head}`);
56864
57181
  }
56865
57182
  const system = [
56866
- "Classify the user intent for the MARIA code orchestrator.",
56867
- "Decide strictly between EDIT_EXISTING (modify existing files) or CREATE_NEW (generate new project/files).",
56868
- "User is likely to have EDIT_EXITING intent when:",
56869
- "- the coding language is not specified",
56870
- "- it has a clear and/or relevant path of the file/directory exists",
56871
- "- it has attachments",
56872
- "- the wording implies modifying existing files (ex. fix, improve, update, change, patch, make it, clean up, etc.)",
56873
- 'Return JSON: { "intent": "EDIT_EXISTING" | "CREATE_NEW" } only. No commentary.'
57183
+ "You classify the intent for a code operation in an existing repository.",
57184
+ "Choose strictly one: EDIT_EXISTING (modify existing files) or CREATE_NEW (generate a new project/files).",
57185
+ "Decision rules (apply in order):",
57186
+ "1) If the request references existing repo directory/file paths and does NOT explicitly say to create a new project/template/scaffold, prefer EDIT_EXISTING.",
57187
+ "2) Wording like fix/improve/update/change/patch/make it work/enable X implies EDIT_EXISTING.",
57188
+ "3) Wording like create/new project/scaffold/from scratch/template implies CREATE_NEW.",
57189
+ "4) If attachments or explicit file paths are present, that increases likelihood of EDIT_EXISTING.",
57190
+ 'Return ONLY compact JSON: { "intent": "EDIT_EXISTING" | "CREATE_NEW" }.'
56874
57191
  ].join("\n");
57192
+ const evidence = {
57193
+ explicitFilesCount: (ctx2.explicitFiles || []).length,
57194
+ attachmentsCount: ctx2.attachmentsCount || 0,
57195
+ existingDirCount: existingDirs.length,
57196
+ existingFileMentions: existingFiles.length,
57197
+ existingDirs,
57198
+ existingFiles
57199
+ };
56875
57200
  const user = [
56876
57201
  `Request: ${request}`,
56877
- `ExplicitFiles: ${JSON.stringify(ctx2.explicitFiles || [])}`,
56878
- `AttachmentsCount: ${ctx2.attachmentsCount}`,
56879
- "Repo snapshot (paths with file heads):",
57202
+ `Evidence: ${JSON.stringify(evidence)}`,
57203
+ "Repo snapshot (trimmed):",
56880
57204
  headSnippets.join("\n\n")
56881
57205
  ].join("\n\n");
56882
- const spin1 = new ProcessAnimation();
56883
- spin1.start();
56884
- const resp = await executeChat([
56885
- { role: "system", content: system },
56886
- { role: "user", content: user }
56887
- ]);
57206
+ if (existingDirs.length > 0 || existingFiles.length > 0 || ctx2.explicitFiles && ctx2.explicitFiles.length > 0 || ctx2.attachmentsCount > 0) {
57207
+ return true;
57208
+ }
57209
+ let startedLocalSpinner = false;
57210
+ let spin1 = null;
57211
+ if (!ProcessAnimation.hasActive()) {
57212
+ spin1 = new ProcessAnimation();
57213
+ spin1.start();
57214
+ startedLocalSpinner = true;
57215
+ }
57216
+ let resp;
56888
57217
  try {
56889
- spin1.stop();
56890
- } catch {
57218
+ resp = await executeChat([
57219
+ { role: "system", content: system },
57220
+ { role: "user", content: user }
57221
+ ], { provider: "google", model: "gemini-2.5-flash-lite" });
57222
+ } finally {
57223
+ if (startedLocalSpinner && spin1) {
57224
+ try {
57225
+ spin1.stop();
57226
+ } catch {
57227
+ }
57228
+ }
56891
57229
  }
56892
57230
  const raw = (resp?.output || "").trim();
56893
57231
  const jsonText = extractJsonSafe(raw, "object") || raw;
56894
57232
  const parsed = JSON.parse(jsonText);
57233
+ if (existingDirs.length > 0 || existingFiles.length > 0 || anyExistingPathMentioned || ctx2.explicitFiles && ctx2.explicitFiles.length > 0 || ctx2.attachmentsCount > 0) {
57234
+ return true;
57235
+ }
56895
57236
  return parsed?.intent === "EDIT_EXISTING";
56896
57237
  } catch {
56897
- return ctx2.explicitFiles && ctx2.explicitFiles.length > 0 || ctx2.attachmentsCount > 0;
57238
+ return ctx2.explicitFiles && ctx2.explicitFiles.length > 0 || ctx2.attachmentsCount > 0 || existingDirs.length > 0 || existingFiles.length > 0 || anyExistingPathMentioned;
56898
57239
  }
56899
57240
  }
56900
57241
  function sanitizeFolderName(name2) {
@@ -57062,7 +57403,7 @@ async function resolveExplicitPaths(root, files, hintText) {
57062
57403
  const chat = await executeChat([
57063
57404
  { role: "system", content: system },
57064
57405
  { role: "user", content: user }
57065
- ]);
57406
+ ], { provider: "google", model: "gemini-2.5-flash-lite" });
57066
57407
  const raw = (chat.output || "").trim();
57067
57408
  const pick = ranked.find((r2) => r2 === raw) || ranked.find((r2) => raw.includes(r2)) || ranked[0];
57068
57409
  return pick.replace(/^\/+/, "");
@@ -57237,7 +57578,16 @@ var init_code_command = __esm({
57237
57578
  }
57238
57579
  ];
57239
57580
  async execute(commandArgs, context2) {
57581
+ const debug = (...args2) => {
57582
+ if (process.env.MARIA_DEBUG === "1") {
57583
+ try {
57584
+ console.log("[DEBUG/code]", ...args2);
57585
+ } catch {
57586
+ }
57587
+ }
57588
+ };
57240
57589
  const request = await this.ensureLanguageDefaults(commandArgs.raw.join(" ").trim());
57590
+ debug("request", request);
57241
57591
  if (!request) {
57242
57592
  return this.error("Please provide a code request \xB7 Example: /code create button component\nTip: Use --plan-only to safely review the plan, or --output detail to preview snippet heads.");
57243
57593
  }
@@ -57249,6 +57599,7 @@ var init_code_command = __esm({
57249
57599
  const explicitDry = commandArgs.raw.includes("--dry-run");
57250
57600
  const explicitOutput = commandArgs.raw.some((x2) => x2.startsWith("--output") || x2 === "--verbose" || x2 === "-v");
57251
57601
  const explicitPreview = commandArgs.raw.some((x2) => x2.startsWith("--preview-lines"));
57602
+ const explicitOnlyAttached = commandArgs.raw.includes("--only-attached");
57252
57603
  const preSpin = new ProcessAnimation();
57253
57604
  preSpin.start();
57254
57605
  let inferred = {};
@@ -57260,6 +57611,8 @@ var init_code_command = __esm({
57260
57611
  } catch {
57261
57612
  }
57262
57613
  }
57614
+ debug("inferCodeArgs.raw", rawText);
57615
+ debug("inferCodeArgs.result", inferred);
57263
57616
  if (!explicitPlan && !explicitDry) {
57264
57617
  if (typeof inferred.planOnly === "boolean") opts.planOnly = inferred.planOnly;
57265
57618
  if (typeof inferred.dryRun === "boolean") opts.dryRun = inferred.dryRun;
@@ -57270,6 +57623,9 @@ var init_code_command = __esm({
57270
57623
  if (!explicitPreview && typeof inferred.previewLines === "number") {
57271
57624
  opts.previewLines = inferred.previewLines;
57272
57625
  }
57626
+ if (!explicitOnlyAttached && typeof inferred.onlyAttached === "boolean") {
57627
+ opts.onlyAttached = inferred.onlyAttached;
57628
+ }
57273
57629
  } catch {
57274
57630
  }
57275
57631
  if (opts.planOnly) {
@@ -57284,13 +57640,27 @@ var init_code_command = __esm({
57284
57640
  const root = opts.root || process.cwd();
57285
57641
  const { orchestrate: orchestrate2 } = await Promise.resolve().then(() => (init_Orchestrator(), Orchestrator_exports));
57286
57642
  const attachments = await this.collectAttachedFiles(context2).catch(() => []);
57643
+ try {
57644
+ if (process.env.MARIA_DEBUG === "1") {
57645
+ const attView = attachments.map((a) => ({ name: a.originalName, size: a.size, mime: a.mime, pathHint: a.pathHint })).slice(0, 50);
57646
+ console.log("[DEBUG/code] collected.attachments", { count: attachments.length, attachments: attView });
57647
+ }
57648
+ } catch {
57649
+ }
57287
57650
  const abort = new AbortController();
57288
57651
  const onSigint = () => abort.abort();
57289
57652
  process.once("SIGINT", onSigint);
57290
- const spinner = new ProcessAnimation();
57291
- spinner.start();
57653
+ let startedLocalSpinner = false;
57654
+ let spinner = null;
57655
+ if (!ProcessAnimation.hasActive()) {
57656
+ spinner = new ProcessAnimation();
57657
+ spinner.start();
57658
+ startedLocalSpinner = true;
57659
+ }
57292
57660
  try {
57293
- const res = await orchestrate2(request, { root, flags: { planOnly: opts.planOnly, apply: opts.apply, dryRun: opts.dryRun, interactive: opts.interactive, yes: opts.yes, maxFiles: opts.maxFiles, output: opts.output, hideCode: opts.noCode, previewLines: this.normalizePreviewLines(opts.previewLines), verbose: opts.verbose, onlyAttached: opts.onlyAttached, attachMode: opts.attachMode, maxAttachments: opts.maxAttachments, diffLines: opts.diffLines, diffBytes: opts.diffBytes, diffHunks: opts.diffHunks, diffGlobalMaxFiles: opts.diffGlobalMaxFiles, diffGlobalMaxBytes: opts.diffGlobalMaxBytes, allowDotfiles: opts.allowDotfiles }, abortSignal: abort.signal, attachedFiles: attachments });
57661
+ const effectiveOnlyAttached = opts.onlyAttached && attachments.length > 0;
57662
+ const res = await orchestrate2(request, { root, flags: { planOnly: opts.planOnly, apply: opts.apply, dryRun: opts.dryRun, interactive: opts.interactive, yes: opts.yes, maxFiles: opts.maxFiles, output: opts.output, hideCode: opts.noCode, previewLines: this.normalizePreviewLines(opts.previewLines), verbose: opts.verbose, onlyAttached: effectiveOnlyAttached, attachMode: opts.attachMode, maxAttachments: opts.maxAttachments, diffLines: opts.diffLines, diffBytes: opts.diffBytes, diffHunks: opts.diffHunks, diffGlobalMaxFiles: opts.diffGlobalMaxFiles, diffGlobalMaxBytes: opts.diffGlobalMaxBytes, allowDotfiles: opts.allowDotfiles }, abortSignal: abort.signal, attachedFiles: attachments });
57663
+ debug("orchestrate.summaryLines.head", Array.isArray(res?.summaryLines) ? res.summaryLines.slice(0, 10) : []);
57294
57664
  if (opts.planOnly) {
57295
57665
  const fs52 = await import('fs/promises');
57296
57666
  const path65 = await import('path');
@@ -57343,9 +57713,11 @@ var init_code_command = __esm({
57343
57713
  const out = Array.isArray(res?.summaryLines) ? res.summaryLines.join("\n") : "";
57344
57714
  return this.success(out);
57345
57715
  } finally {
57346
- try {
57347
- spinner.stop();
57348
- } catch {
57716
+ if (startedLocalSpinner && spinner) {
57717
+ try {
57718
+ spinner.stop();
57719
+ } catch {
57720
+ }
57349
57721
  }
57350
57722
  process.removeListener("SIGINT", onSigint);
57351
57723
  }
@@ -57468,12 +57840,6 @@ ${pretty}`);
57468
57840
  if (llmLang) {
57469
57841
  const hint2 = (() => {
57470
57842
  const l = llmLang.toLowerCase();
57471
- if (l === "tsx") return "TypeScript (React/TSX)";
57472
- if (l === "jsx") return "JavaScript (React/JSX)";
57473
- if (l === "typescript") return "TypeScript";
57474
- if (l === "javascript") return "JavaScript";
57475
- if (l === "html") return "HTML";
57476
- if (l === "css") return "CSS";
57477
57843
  return llmLang;
57478
57844
  })();
57479
57845
  return raw + ` (Use ${hint2})`;
@@ -57486,7 +57852,7 @@ ${pretty}`);
57486
57852
  preSpin.start();
57487
57853
  const system = [
57488
57854
  "You analyze a user's code-generation request.",
57489
- "Decide if the user explicitly specified a programming language or framework/tooling (e.g., TypeScript, Python, Rust, Java, React, Vue, Node, etc.).",
57855
+ "Decide if the user explicitly specified a programming language or framework/tooling.",
57490
57856
  'Return ONLY compact JSON with shape {"explicitLanguage": boolean, "language"?: string}.',
57491
57857
  "Do not add any commentary."
57492
57858
  ].join("\n");
@@ -57495,7 +57861,7 @@ ${pretty}`);
57495
57861
  method: "POST",
57496
57862
  body: {
57497
57863
  provider: "google",
57498
- model: "gemini-2.5-flash",
57864
+ model: "gemini-2.5-flash-lite",
57499
57865
  taskType: "chat",
57500
57866
  prompt: `${system}
57501
57867
 
@@ -57540,6 +57906,14 @@ ${user}`
57540
57906
  if (parsed && parsed.explicitLanguage) return raw;
57541
57907
  } catch {
57542
57908
  }
57909
+ try {
57910
+ const pathMod = await import('path');
57911
+ const hasPathToken = /[A-Za-z]:\\[^\s"']+|\.?\/?[^\s"']+[\/\\][^\s"']*/.test(raw);
57912
+ if (hasPathToken) {
57913
+ return raw;
57914
+ }
57915
+ } catch {
57916
+ }
57543
57917
  const hint = " (Use TypeScript and React; prefer functional components and node)";
57544
57918
  return raw + hint;
57545
57919
  }
@@ -57549,9 +57923,7 @@ ${user}`
57549
57923
  const system = [
57550
57924
  "You are a programming language classifier.",
57551
57925
  "Given multiple short code excerpts, determine the dominant language across them.",
57552
- "Respond with ONLY a single token language name from this set:",
57553
- "[typescript, tsx, javascript, jsx, python, java, go, rust, php, cpp, c, swift, kotlin, ruby, csharp, html, css, scss, json, yaml, markdown].",
57554
- "If unsure between tsx and jsx, choose tsx if TypeScript types appear, else jsx."
57926
+ "Respond with ONLY language name(s)"
57555
57927
  ].join("\n");
57556
57928
  const joined = samples.slice(0, 20).map((s2, i2) => `// sample ${i2 + 1}
57557
57929
  ${s2}`).join("\n\n");
@@ -57560,7 +57932,7 @@ ${s2}`).join("\n\n");
57560
57932
  method: "POST",
57561
57933
  body: {
57562
57934
  provider: "google",
57563
- model: "gemini-2.5-flash",
57935
+ model: "gemini-2.5-flash-lite",
57564
57936
  taskType: "chat",
57565
57937
  prompt: `${system}
57566
57938
 
@@ -57866,64 +58238,6 @@ ${joined}`
57866
58238
  return false;
57867
58239
  }
57868
58240
  }
57869
- /**
57870
- * Extract code blocks from AI response
57871
- */
57872
- extractCodeBlocks(content) {
57873
- const blocks = [];
57874
- const codeBlockRegex = /```(\w*)\n([\s\S]*?)```/g;
57875
- let match2;
57876
- while ((match2 = codeBlockRegex.exec(content)) !== null) {
57877
- blocks.push({
57878
- language: match2[1] || "javascript",
57879
- code: match2[2].trim()
57880
- });
57881
- }
57882
- if (blocks.length === 0 && this.looksLikeCode(content)) {
57883
- blocks.push({
57884
- code: content.trim(),
57885
- language: this.detectLanguage(content)
57886
- });
57887
- }
57888
- return blocks;
57889
- }
57890
- /**
57891
- * Check if content looks like code
57892
- */
57893
- looksLikeCode(content) {
57894
- const codeIndicators = [
57895
- "function ",
57896
- "const ",
57897
- "let ",
57898
- "var ",
57899
- "class ",
57900
- "def ",
57901
- "import ",
57902
- "export ",
57903
- "{",
57904
- "}",
57905
- ";",
57906
- "//",
57907
- "/*"
57908
- ];
57909
- return codeIndicators.some((indicator) => content.includes(indicator));
57910
- }
57911
- /**
57912
- * Detect programming language from content
57913
- */
57914
- detectLanguage(code) {
57915
- const hasReact = /(^|\s)from\s+['"]react['"]|^\s*import\s+React/m.test(code);
57916
- const hasJSX = /<([A-Za-z][\w:-]*)(\s|>|\/)>?/m.test(code);
57917
- const hasTS = /(\binterface\s+\w+\b|\btype\s+\w+\s*=|:\s*[A-Za-z_][\w<>\[\]| &?:]*)/m.test(code) || /React\.FC\s*</m.test(code);
57918
- if (hasReact || hasJSX) return hasTS ? "tsx" : "jsx";
57919
- if (code.includes("interface ") || code.includes(": string")) return "typescript";
57920
- if (code.includes("def ") || code.includes("print(")) return "python";
57921
- if (code.includes("func ") || code.includes("package main")) return "go";
57922
- if (code.includes("fn ") || code.includes("let mut")) return "rust";
57923
- if (code.includes("<?php")) return "php";
57924
- if (code.includes("#include")) return "cpp";
57925
- return "javascript";
57926
- }
57927
58241
  /**
57928
58242
  * Save code block to file
57929
58243
  */
@@ -63721,11 +64035,10 @@ var init_clients_safe = __esm({
63721
64035
  }
63722
64036
  });
63723
64037
  function createSpinner(text) {
63724
- let frame = 0;
63725
64038
  let active = false;
63726
- let timer;
63727
- const render = () => {
63728
- const f3 = SPINNER_FRAMES[frame = (frame + 1) % SPINNER_FRAMES.length];
64039
+ let frame = 0;
64040
+ const renderOnce = () => {
64041
+ const f3 = SPINNER_FRAMES[frame % SPINNER_FRAMES.length];
63729
64042
  process5__namespace.default.stdout.write(`\r ${chalk14__default.default.cyan(f3)} ${text}`);
63730
64043
  };
63731
64044
  return {
@@ -63735,13 +64048,11 @@ function createSpinner(text) {
63735
64048
  start() {
63736
64049
  if (active) return;
63737
64050
  active = true;
63738
- render();
63739
- timer = setInterval(render, 80);
64051
+ renderOnce();
63740
64052
  },
63741
64053
  stop(symbol = "\u2714") {
63742
64054
  if (!active) return;
63743
64055
  active = false;
63744
- if (timer) clearInterval(timer);
63745
64056
  const finalSymbol = symbol === "\u2714" ? chalk14__default.default.green(symbol) : symbol === "\u26A0" ? chalk14__default.default.yellow(symbol) : symbol === "\u2716" ? chalk14__default.default.red(symbol) : symbol;
63746
64057
  process5__namespace.default.stdout.write(`\r ${finalSymbol} ${text}
63747
64058
  `);