@bonginkan/maria 4.3.35 → 4.3.36

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.35",
26070
- description: "\u{1F680} MARIA v4.3.35 - 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.36",
26070
+ description: "\u{1F680} MARIA v4.3.36 - 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",
@@ -28104,7 +28104,7 @@ var init_AuthenticationManager = __esm({
28104
28104
  const response = await fetch(`${this.apiBase}/api/user/profile`, {
28105
28105
  headers: {
28106
28106
  "Authorization": `Bearer ${tokens2.accessToken}`,
28107
- "User-Agent": `maria-cli/${process.env.CLI_VERSION || "4.3.35"}`
28107
+ "User-Agent": `maria-cli/${process.env.CLI_VERSION || "4.3.36"}`
28108
28108
  }
28109
28109
  });
28110
28110
  if (response.status === 401) {
@@ -28714,6 +28714,17 @@ var init_withAuth = __esm({
28714
28714
  ];
28715
28715
  }
28716
28716
  });
28717
+
28718
+ // src/services/cli-auth/api-client.ts
28719
+ var api_client_exports = {};
28720
+ __export(api_client_exports, {
28721
+ ERR: () => ERR,
28722
+ callApi: () => callApi,
28723
+ callApiJson: () => callApiJson,
28724
+ clientThrottle: () => clientThrottle,
28725
+ streamApi: () => streamApi,
28726
+ uploadFile: () => uploadFile
28727
+ });
28717
28728
  function getDeviceId() {
28718
28729
  if (!global.MARIA_DEVICE_ID) {
28719
28730
  global.MARIA_DEVICE_ID = v4_default();
@@ -28723,6 +28734,17 @@ function getDeviceId() {
28723
28734
  function getSessionId() {
28724
28735
  return global.MARIA_SESSION_ID;
28725
28736
  }
28737
+ function clientThrottle(endpoint) {
28738
+ const now2 = Date.now();
28739
+ const lastCall = rateLimitMap.get(endpoint) || 0;
28740
+ const wait = MIN_GAP_MS - (now2 - lastCall);
28741
+ if (wait > 0) {
28742
+ const waitSeconds = Math.ceil(wait / 1e3);
28743
+ console.log(chalk14__default.default.yellow(`\u23F1\uFE0F Rate limit: wait ${waitSeconds}s`));
28744
+ throw { ...ERR.RATE, waitTime: waitSeconds };
28745
+ }
28746
+ rateLimitMap.set(endpoint, now2);
28747
+ }
28726
28748
  async function callApi(path64, init3 = {}) {
28727
28749
  const apiBase = process.env.MARIA_API_BASE || "https://api.maria-code.ai";
28728
28750
  const fullUrl = `${apiBase}${path64}`;
@@ -28736,7 +28758,7 @@ async function callApi(path64, init3 = {}) {
28736
28758
  "Authorization": `Bearer ${token}`,
28737
28759
  "X-Device-Id": getDeviceId(),
28738
28760
  "X-Session-Id": getSessionId() || "",
28739
- "User-Agent": `maria-cli/${process.env.CLI_VERSION || "4.3.35"}`,
28761
+ "User-Agent": `maria-cli/${process.env.CLI_VERSION || "4.3.36"}`,
28740
28762
  "Content-Type": init3.headers?.["Content-Type"] || "application/json"
28741
28763
  });
28742
28764
  const doFetch = async (token) => {
@@ -28804,7 +28826,48 @@ async function callApiJson(path64, init3 = {}) {
28804
28826
  }
28805
28827
  return response.json();
28806
28828
  }
28807
- var ERR;
28829
+ async function* streamApi(path64, init3 = {}) {
28830
+ const response = await callApi(path64, {
28831
+ ...init3,
28832
+ headers: {
28833
+ ...init3.headers,
28834
+ "Accept": "text/event-stream"
28835
+ }
28836
+ });
28837
+ if (!response.ok) {
28838
+ throw new Error(`Stream error: ${response.status}`);
28839
+ }
28840
+ const reader = response.body?.getReader();
28841
+ if (!reader) {
28842
+ throw new Error("No response body");
28843
+ }
28844
+ const decoder = new TextDecoder();
28845
+ try {
28846
+ while (true) {
28847
+ const { done, value } = await reader.read();
28848
+ if (done) break;
28849
+ const chunk = decoder.decode(value, { stream: true });
28850
+ yield chunk;
28851
+ }
28852
+ } finally {
28853
+ reader.releaseLock();
28854
+ }
28855
+ }
28856
+ async function uploadFile(path64, file, metadata5 = {}) {
28857
+ const formData = new FormData();
28858
+ formData.append("file", new Blob([file]));
28859
+ Object.entries(metadata5).forEach(([key, value]) => {
28860
+ formData.append(key, String(value));
28861
+ });
28862
+ return callApiJson(path64, {
28863
+ method: "POST",
28864
+ body: formData,
28865
+ headers: {
28866
+ // Don't set Content-Type, let browser set it with boundary
28867
+ }
28868
+ });
28869
+ }
28870
+ var ERR, rateLimitMap, MIN_GAP_MS;
28808
28871
  var init_api_client = __esm({
28809
28872
  "src/services/cli-auth/api-client.ts"() {
28810
28873
  init_AuthenticationManager();
@@ -28817,6 +28880,8 @@ var init_api_client = __esm({
28817
28880
  NETWORK: { msg: "\u{1F310} Network error, check connection", code: 1 },
28818
28881
  RATE: { msg: "\u23F3 Rate limited, retrying...", code: 1 }
28819
28882
  };
28883
+ rateLimitMap = /* @__PURE__ */ new Map();
28884
+ MIN_GAP_MS = 3e3;
28820
28885
  }
28821
28886
  });
28822
28887
 
@@ -37645,6 +37710,7 @@ var init_clear_command = __esm({
37645
37710
  init_telemetry_helper();
37646
37711
  init_subscription_manager();
37647
37712
  init_terminal();
37713
+ init_chat_context_service();
37648
37714
  ClearCommand = class extends BaseCommand {
37649
37715
  name = "clear";
37650
37716
  category = "conversation";
@@ -37661,34 +37727,46 @@ var init_clear_command = __esm({
37661
37727
  async execute(args2, context2) {
37662
37728
  const startTime = Date.now();
37663
37729
  try {
37730
+ let mode = "session";
37731
+ const idx = Array.isArray(args2.raw) ? args2.raw.indexOf("--mode") : -1;
37732
+ if (idx >= 0) {
37733
+ const val = String(args2.raw[idx + 1] || "").toLowerCase();
37734
+ if (val === "display" || val === "session" || val === "all") mode = val;
37735
+ }
37664
37736
  clearTerminal();
37665
- if (context2.session) {
37666
- if (context2.session.conversationHistory) {
37667
- context2.session.conversationHistory = [];
37668
- }
37669
- if (context2.session.context) {
37670
- context2.session.context = {};
37671
- }
37672
- if (context2.session.messages) {
37673
- context2.session.messages = [];
37674
- }
37737
+ const chat = ChatContextService.getInstance();
37738
+ if (mode === "display") {
37739
+ chat.clearContext({ soft: true });
37740
+ } else {
37741
+ chat.clearContext();
37675
37742
  }
37743
+ const quotaLeft = (() => {
37744
+ const rec = context2;
37745
+ const v = rec && typeof rec["quotaLeft"] === "number" ? rec["quotaLeft"] : 999;
37746
+ return v;
37747
+ })();
37676
37748
  await trackCommand({
37677
37749
  cmd: "clear",
37678
37750
  status: "success",
37679
37751
  latencyMs: Date.now() - startTime,
37680
- plan: getUserPlan(),
37681
- quotaLeft: context2.quotaLeft || 999
37752
+ plan: await getUserPlan(),
37753
+ quotaLeft
37682
37754
  });
37683
- const message = chalk14__default.default.green("\u2705 Cleared") + chalk14__default.default.gray(" \xB7 context reset");
37684
- return this.success(withQuotaFooter(message, context2.quotaLeft));
37755
+ const suffix = mode === "display" ? "display only" : "context reset";
37756
+ const message = chalk14__default.default.green("\u2705 Cleared") + chalk14__default.default.gray(` \xB7 ${suffix}`);
37757
+ return this.success(withQuotaFooter(message, quotaLeft));
37685
37758
  } catch (error2) {
37759
+ const quotaLeft = (() => {
37760
+ const rec = context2;
37761
+ const v = rec && typeof rec["quotaLeft"] === "number" ? rec["quotaLeft"] : 999;
37762
+ return v;
37763
+ })();
37686
37764
  await trackCommand({
37687
37765
  cmd: "clear",
37688
37766
  status: "error",
37689
37767
  latencyMs: Date.now() - startTime,
37690
- plan: getUserPlan(),
37691
- quotaLeft: context2.quotaLeft || 999
37768
+ plan: await getUserPlan(),
37769
+ quotaLeft
37692
37770
  });
37693
37771
  clearTerminal();
37694
37772
  return this.success(chalk14__default.default.green("\u2705 Cleared"));
@@ -38611,44 +38689,6 @@ var init_HelpCommand = __esm({
38611
38689
  * Show help for specific command
38612
38690
  */
38613
38691
  async showCommandHelp(commandName) {
38614
- if (commandName.replace(/^\//, "") === "code") {
38615
- const lines2 = [];
38616
- lines2.push("Usage: /code <request> [flags]");
38617
- lines2.push("");
38618
- lines2.push("Flags:");
38619
- lines2.push(" --plan-only|--sow Show plan only (no writes)");
38620
- lines2.push(" --apply Apply plan (use with --yes for non-interactive)");
38621
- lines2.push(" --dry-run No writes; render output and hints");
38622
- lines2.push(" --interactive Approve interactively (a=all s=skip v=view d=diff q=cancel)");
38623
- lines2.push(" --yes Approve all (including overwrites)");
38624
- lines2.push(" --max-files N Clamp number of files");
38625
- lines2.push(" --root DIR Output root directory");
38626
- lines2.push(" --rollback on|off Rollback on failure (default on)");
38627
- lines2.push(" --output names|summary|detail");
38628
- lines2.push(" --no-code Hide code blocks entirely");
38629
- lines2.push(" --preview-lines N Show head of code in detail mode");
38630
- lines2.push(" --git-guard on|off Check clean git tree before apply (CI default on)");
38631
- lines2.push(" --git-commit on|off Create a single git commit after apply");
38632
- lines2.push(" --git-branch <name> Create/switch branch before committing");
38633
- lines2.push(" --git-tag <name> Create an annotated tag after committing");
38634
- lines2.push(" --git-tag-prefix <pfx> Use standardized tag when --git-tag auto: <pfx><YYYYMMDD>-<shortsha>");
38635
- lines2.push(" --git-push on|off Push commit and tag to remote");
38636
- lines2.push(" --git-push-remote <name> Remote name for push (default origin)");
38637
- lines2.push(" --allow-dotfiles Allow writing dotfiles (default deny)");
38638
- lines2.push(" --confirm-overwrites <globs>");
38639
- lines2.push("");
38640
- lines2.push("Tips:");
38641
- lines2.push(' HINT: Try /code --plan-only "your request" before applying changes');
38642
- lines2.push(" Recipes:");
38643
- lines2.push(' \u2022 Plan only: /code --plan-only "create auth form + API"');
38644
- lines2.push(' \u2022 Apply with limit: /code --apply --yes --max-files 5 "react + test"');
38645
- lines2.push(' \u2022 Interactive: /code --interactive --output detail --preview-lines 20 "routes + guards"');
38646
- lines2.push(" \u2022 Apply + branch + auto tag + push:");
38647
- lines2.push(" /code --apply --yes --git-guard on --git-commit on \\");
38648
- lines2.push(" --git-branch feature/code-plan --git-tag auto --git-tag-prefix code-plan- \\");
38649
- lines2.push(' --git-push on --git-push-remote origin "implement auth + tests"');
38650
- return this.success(lines2.join("\n"));
38651
- }
38652
38692
  const command = await this.readyService.getCommand(commandName);
38653
38693
  if (!command) {
38654
38694
  const searchResults = await this.readyService.searchCommands(commandName, 3);
@@ -47421,6 +47461,333 @@ var init_types4 = __esm({
47421
47461
  ];
47422
47462
  }
47423
47463
  });
47464
+
47465
+ // src/services/media-orchestrator/NLInference.ts
47466
+ function clampSize(size) {
47467
+ const clamp = (n) => Math.min(2048, Math.max(256, Math.floor(n)));
47468
+ return [clamp(size[0]), clamp(size[1])];
47469
+ }
47470
+ function parseExplicitSize(text) {
47471
+ const m2 = /(\d{2,4})\s*[x×]\s*(\d{2,4})/i.exec(text);
47472
+ if (m2) {
47473
+ const w = Number(m2[1]);
47474
+ const h2 = Number(m2[2]);
47475
+ if (Number.isFinite(w) && Number.isFinite(h2)) return clampSize([w, h2]);
47476
+ }
47477
+ const p = /(2160|1440|1080|720)\s*p\b/i.exec(text);
47478
+ if (p) {
47479
+ const h2 = Number(p[1]);
47480
+ const map = {
47481
+ 2160: [3840, 2160],
47482
+ 1440: [2560, 1440],
47483
+ 1080: [1920, 1080],
47484
+ 720: [1280, 720]
47485
+ };
47486
+ return clampSize(map[h2]);
47487
+ }
47488
+ return void 0;
47489
+ }
47490
+ function parseAspect(text) {
47491
+ if (/16\s*:\s*9/.test(text)) return "16:9";
47492
+ if (/9\s*:\s*16/.test(text)) return "9:16";
47493
+ if (/1\s*:\s*1/.test(text)) return "1:1";
47494
+ if (/(wide|landscape)/i.test(text)) return "16:9";
47495
+ if (/(tall|portrait)/i.test(text)) return "9:16";
47496
+ if (/(landscape|横長|横向き)/i.test(text)) return "16:9";
47497
+ if (/(portrait|縦長|縦向き)/i.test(text)) return "9:16";
47498
+ if (/(square|正方形|スクエア)/i.test(text)) return "1:1";
47499
+ return void 0;
47500
+ }
47501
+ function deriveSizeFromAspect(aspect, base) {
47502
+ const side = 1024;
47503
+ if (aspect === "1:1") return clampSize([side, side]);
47504
+ if (aspect === "16:9") {
47505
+ const w2 = Math.max(side, 1280);
47506
+ const h3 = Math.round(w2 / 16 * 9);
47507
+ return clampSize([w2, h3]);
47508
+ }
47509
+ const h2 = Math.max(side, 1920);
47510
+ const w = Math.round(h2 / 16 * 9);
47511
+ return clampSize([w, h2]);
47512
+ }
47513
+ function parse4KHints(text, aspect) {
47514
+ if (/(\b4k\b|uhd|超高精細|超高解像度)/i.test(text)) {
47515
+ if (aspect === "1:1" || /square|正方形|スクエア/i.test(text)) return clampSize([2048, 2048]);
47516
+ if (aspect === "9:16" || /(portrait|縦長|縦向き)/i.test(text)) return clampSize([1152, 2048]);
47517
+ return clampSize([2048, 1152]);
47518
+ }
47519
+ if (/(2k|1440p)/i.test(text)) {
47520
+ if (aspect === "1:1") return clampSize([1440, 1440]);
47521
+ if (aspect === "9:16") return clampSize([810, 1440]);
47522
+ return clampSize([1440, 810]);
47523
+ }
47524
+ return void 0;
47525
+ }
47526
+ function parseUseCaseSize(text, aspectHint) {
47527
+ if (/(icon|アイコン)/i.test(text)) return [512, 512];
47528
+ if (/(thumbnail|サムネ)/i.test(text)) return [1280, 720];
47529
+ if (/(instagram\s*story|インスタ\s*ストーリー)/i.test(text)) return [1080, 1920];
47530
+ if (/(instagram\s*post|インスタ\s*投稿)/i.test(text)) return [1080, 1080];
47531
+ if (/(twitter\s*header|x\s*header)/i.test(text)) return [1500, 500];
47532
+ if (/(hd|フルhd)/i.test(text)) return [1920, 1080];
47533
+ if (aspectHint) return deriveSizeFromAspect(aspectHint);
47534
+ if (/(portrait|縦長|縦向き)/i.test(text)) return deriveSizeFromAspect("9:16");
47535
+ if (/(landscape|横長|横向き)/i.test(text)) return deriveSizeFromAspect("16:9");
47536
+ if (/(square|正方形|スクエア)/i.test(text)) return [1024, 1024];
47537
+ return void 0;
47538
+ }
47539
+ function inferFormat(text) {
47540
+ if (/(png|透過|alpha)/i.test(text)) return "png";
47541
+ if (/(webp|ウェブピー)/i.test(text)) return "webp";
47542
+ if (/(jpg|jpeg|写真|photo)/i.test(text)) return "jpg";
47543
+ return void 0;
47544
+ }
47545
+ function inferImageOptionsFromText(text) {
47546
+ const lower2 = text.toLowerCase();
47547
+ const aspect = parseAspect(lower2);
47548
+ const exp = parseExplicitSize(lower2);
47549
+ const k4 = parse4KHints(lower2, aspect);
47550
+ const use = parseUseCaseSize(lower2, aspect);
47551
+ const size = exp || k4 || use;
47552
+ const format = inferFormat(lower2);
47553
+ const out = {};
47554
+ if (size) out.size = size;
47555
+ if (format) out.format = format;
47556
+ return out;
47557
+ }
47558
+ var init_NLInference = __esm({
47559
+ "src/services/media-orchestrator/NLInference.ts"() {
47560
+ }
47561
+ });
47562
+
47563
+ // src/services/cli-auth/api-caller.ts
47564
+ var api_caller_exports = {};
47565
+ __export(api_caller_exports, {
47566
+ RateLimitError: () => RateLimitError2,
47567
+ callAPI: () => callAPI,
47568
+ executeAIProxy: () => executeAIProxy,
47569
+ executeChat: () => executeChat,
47570
+ executeCode: () => executeCode
47571
+ });
47572
+ async function callAPI(endpoint, options = {}) {
47573
+ const tokens2 = await authManager2.getValidTokens();
47574
+ if (!tokens2) {
47575
+ throw new Error("Authentication required. Please run /login first.");
47576
+ }
47577
+ const apiBase = process.env.MARIA_API_BASE || "https://api.maria-code.ai";
47578
+ const url2 = `${apiBase}${endpoint}`;
47579
+ const controller = new AbortController();
47580
+ const defaultMs = 6e5;
47581
+ const envMs = Number(process.env.MARIA_API_TIMEOUT_MS || process.env.MARIA_CODE_TIMEOUT_MS || defaultMs);
47582
+ const timeoutMs = Number.isFinite(envMs) && envMs > 0 ? envMs : defaultMs;
47583
+ const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
47584
+ try {
47585
+ const response = await fetch(url2, {
47586
+ method: options.method || "GET",
47587
+ headers: {
47588
+ "Authorization": `Bearer ${tokens2.accessToken}`,
47589
+ "Content-Type": "application/json",
47590
+ ...options.headers
47591
+ },
47592
+ body: options.body ? JSON.stringify(options.body) : void 0,
47593
+ // Note: fetch in Node doesn't accept 'agent' in our typing here; relying on global agent not necessary
47594
+ signal: controller.signal
47595
+ });
47596
+ clearTimeout(timeoutId);
47597
+ if (!response) {
47598
+ throw new Error("\u{1F310} Network error, check connection");
47599
+ }
47600
+ if (response.status === 401) {
47601
+ throw new Error("Session expired. Please run /login again.");
47602
+ }
47603
+ if (response.status === 402) {
47604
+ const data2 = await response.json().catch(() => ({}));
47605
+ throw new Error(`Quota exceeded: ${typeof data2?.message === "string" ? data2.message : "Please wait or /upgrade"}`);
47606
+ }
47607
+ if (response.status === 403) {
47608
+ const data2 = await response.json().catch(() => ({}));
47609
+ throw new Error(`Not available on Free plan: ${typeof data2?.message === "string" ? data2.message : "Run /upgrade"}`);
47610
+ }
47611
+ if (response.status === 429) {
47612
+ const h2 = response.headers;
47613
+ const ra = h2.get("Retry-After");
47614
+ const reset = h2.get("RateLimit-Reset") || h2.get("X-RateLimit-Reset");
47615
+ let waitSec = 3;
47616
+ if (ra && /^\d+$/.test(ra)) {
47617
+ waitSec = +ra;
47618
+ } else if (ra) {
47619
+ const t2 = Date.parse(ra);
47620
+ if (!isNaN(t2)) waitSec = Math.max(1, Math.ceil((t2 - Date.now()) / 1e3));
47621
+ } else if (reset) {
47622
+ waitSec = Math.max(1, Math.ceil((+reset - Date.now()) / 1e3));
47623
+ }
47624
+ throw new RateLimitError2(`\u23F1 Wait ${waitSec}s`, waitSec);
47625
+ }
47626
+ if (!response.ok) {
47627
+ const data2 = await response.json().catch(() => ({}));
47628
+ const msg = typeof data2?.error === "string" ? data2.error : `Request failed: ${response.statusText}`;
47629
+ throw new Error(msg);
47630
+ }
47631
+ const data = await response.json();
47632
+ return data;
47633
+ } catch (error2) {
47634
+ clearTimeout(timeoutId);
47635
+ const err = error2;
47636
+ if (err && err.name === "AbortError") {
47637
+ throw new Error("\u{1F310} Network error, check connection");
47638
+ }
47639
+ throw err;
47640
+ }
47641
+ }
47642
+ async function executeChat(messages) {
47643
+ const response = await callAPI("/v1/chat", {
47644
+ method: "POST",
47645
+ body: { messages }
47646
+ });
47647
+ return response;
47648
+ }
47649
+ async function executeCode(input3) {
47650
+ const isOptions = typeof input3 === "object";
47651
+ const prompt = isOptions ? input3.prompt : input3;
47652
+ const provider = isOptions ? input3.provider : void 0;
47653
+ const model = isOptions ? input3.model : void 0;
47654
+ const attachments = isOptions ? input3.attachments : void 0;
47655
+ const body = { prompt, taskType: "code" };
47656
+ if (provider) body.provider = provider;
47657
+ if (model) body.model = model;
47658
+ if (attachments && attachments.length > 0) {
47659
+ body.metadata = { attachments };
47660
+ }
47661
+ const response = await callAPI("/v1/ai-proxy", {
47662
+ method: "POST",
47663
+ body
47664
+ });
47665
+ if (response.data?.routedModel) {
47666
+ response.routedModel = response.data.routedModel;
47667
+ }
47668
+ if (response.data?.content) {
47669
+ response.output = response.data.content;
47670
+ }
47671
+ return response;
47672
+ }
47673
+ async function executeAIProxy(provider, model, messages, options) {
47674
+ return callAPI("/v1/ai-proxy", {
47675
+ method: "POST",
47676
+ body: { provider, model, messages, options }
47677
+ });
47678
+ }
47679
+ var authManager2, RateLimitError2;
47680
+ var init_api_caller = __esm({
47681
+ "src/services/cli-auth/api-caller.ts"() {
47682
+ init_AuthenticationManager();
47683
+ new https__default.default.Agent({ keepAlive: true });
47684
+ authManager2 = new AuthenticationManager();
47685
+ RateLimitError2 = class extends Error {
47686
+ constructor(message, retryAfter) {
47687
+ super(message);
47688
+ this.retryAfter = retryAfter;
47689
+ this.name = "RateLimitError";
47690
+ }
47691
+ };
47692
+ }
47693
+ });
47694
+
47695
+ // src/services/media-orchestrator/ImageArgumentInference.ts
47696
+ function extractFirstJson(text) {
47697
+ const fence = /```json\r?\n([\s\S]*?)```/i.exec(text);
47698
+ if (fence) return fence[1];
47699
+ const fencePlain = /```\s*\r?\n([\s\S]*?)```/i.exec(text);
47700
+ if (fencePlain) {
47701
+ try {
47702
+ JSON.parse(fencePlain[1]);
47703
+ return fencePlain[1];
47704
+ } catch {
47705
+ }
47706
+ }
47707
+ const start = text.indexOf("{");
47708
+ const end = text.lastIndexOf("}");
47709
+ if (start >= 0 && end > start) {
47710
+ const cand = text.slice(start, end + 1);
47711
+ try {
47712
+ JSON.parse(cand);
47713
+ return cand;
47714
+ } catch {
47715
+ }
47716
+ }
47717
+ return null;
47718
+ }
47719
+ function clampSize2(size) {
47720
+ const clamp = (n) => Math.min(4096, Math.max(256, Math.floor(n)));
47721
+ return [clamp(size[0]), clamp(size[1])];
47722
+ }
47723
+ function parseSizeAny(x2) {
47724
+ if (typeof x2 === "string") {
47725
+ const m2 = /^\s*(\d{2,4})x(\d{2,4})\s*$/i.exec(x2);
47726
+ if (m2) return clampSize2([Number(m2[1]), Number(m2[2])]);
47727
+ }
47728
+ if (x2 && typeof x2 === "object") {
47729
+ const any = x2;
47730
+ const w = Number(any.width ?? any.w);
47731
+ const h2 = Number(any.height ?? any.h);
47732
+ if (Number.isFinite(w) && Number.isFinite(h2)) return clampSize2([w, h2]);
47733
+ }
47734
+ return void 0;
47735
+ }
47736
+ function sanitizeFormat(fmt) {
47737
+ if (typeof fmt !== "string") return void 0;
47738
+ const f3 = fmt.toLowerCase();
47739
+ const mapped = f3 === "jpeg" ? "jpg" : f3;
47740
+ return ["png", "webp", "jpg"].includes(mapped) ? mapped : void 0;
47741
+ }
47742
+ async function inferImageArgsLLM(promptText) {
47743
+ const system = [
47744
+ "You extract image generation options from user natural language.",
47745
+ 'Return JSON only with keys: { "size"?: "WIDTHxHEIGHT", "format"?: "png|webp|jpg", "count"?: number }.',
47746
+ 'Only include "count" if the user explicitly specifies the number of images (e.g., "2 images"). Otherwise omit (default is 1).',
47747
+ 'Only include "format" if the user explicitly specifies a format (e.g., "png", "webp", "jpg", transparency). Otherwise omit (default is png).',
47748
+ 'Size must be a single string "WIDTHxHEIGHT". If the user implies aspect/resolution (e.g., "wide"/"landscape" => 16:9, "tall"/"portrait" => 9:16, "square" => 1:1, or 4K/UHD/1080p/720p), select a reasonable resolution within 256..4096 per side and return it as "WIDTHxHEIGHT".',
47749
+ "If size is not specified or implied, omit it (default is 1024x1024).",
47750
+ "Do NOT include model or keepExif unless the user explicitly specified them; otherwise omit.",
47751
+ "Do not include any explanation text; JSON only."
47752
+ ].join("\n");
47753
+ const user = promptText;
47754
+ const response = await callAPI("/v1/ai-proxy", {
47755
+ method: "POST",
47756
+ body: {
47757
+ prompt: `${system}
47758
+
47759
+ ---
47760
+
47761
+ ${user}`,
47762
+ taskType: "media"
47763
+ }
47764
+ });
47765
+ const raw = (response?.data?.content || response?.output || "").trim();
47766
+ const jsonText = extractFirstJson(raw) || raw;
47767
+ let parsed;
47768
+ try {
47769
+ parsed = JSON.parse(jsonText);
47770
+ } catch {
47771
+ return {};
47772
+ }
47773
+ const out = {};
47774
+ const size = parseSizeAny(parsed?.size);
47775
+ if (size) out.size = size;
47776
+ const fmt = sanitizeFormat(parsed?.format);
47777
+ if (fmt) out.format = fmt;
47778
+ if (Number.isFinite(Number(parsed?.count))) {
47779
+ const n = Math.max(1, Math.min(8, Math.floor(Number(parsed.count))));
47780
+ out.count = n;
47781
+ }
47782
+ if (typeof parsed?.model === "string" && parsed.model.trim()) out.model = String(parsed.model).trim();
47783
+ if (typeof parsed?.keepExif === "boolean") out.keepExif = parsed.keepExif;
47784
+ return out;
47785
+ }
47786
+ var init_ImageArgumentInference = __esm({
47787
+ "src/services/media-orchestrator/ImageArgumentInference.ts"() {
47788
+ init_api_caller();
47789
+ }
47790
+ });
47424
47791
  function parseSize(value) {
47425
47792
  const m2 = /^\s*(\d{2,4})x(\d{2,4})\s*$/i.exec(value || "");
47426
47793
  if (!m2) throw new Error(`invalid size: ${value}`);
@@ -47453,6 +47820,8 @@ function normalizeImageArgs(raw, root) {
47453
47820
  planOnly: false,
47454
47821
  dryRun: false
47455
47822
  };
47823
+ let explicitSize = false;
47824
+ let explicitFormat = false;
47456
47825
  while (args2.length) {
47457
47826
  const x2 = args2.shift();
47458
47827
  if (!x2.startsWith("--")) continue;
@@ -47461,12 +47830,14 @@ function normalizeImageArgs(raw, root) {
47461
47830
  switch (k) {
47462
47831
  case "size":
47463
47832
  out.size = parseSize(String(v));
47833
+ explicitSize = true;
47464
47834
  break;
47465
47835
  case "format": {
47466
47836
  const rawFmt = String(v).toLowerCase();
47467
47837
  const mapped = rawFmt === "jpeg" ? "jpg" : rawFmt;
47468
47838
  if (!["png", "webp", "jpg"].includes(mapped)) throw new Error("invalid format");
47469
47839
  out.format = mapped;
47840
+ explicitFormat = true;
47470
47841
  break;
47471
47842
  }
47472
47843
  case "count": {
@@ -47507,6 +47878,21 @@ function normalizeImageArgs(raw, root) {
47507
47878
  break;
47508
47879
  }
47509
47880
  }
47881
+ try {
47882
+ const inferred = inferImageOptionsFromText(prompt);
47883
+ if (!explicitSize && inferred.size) out.size = inferred.size;
47884
+ if (!explicitFormat && inferred.format) out.format = inferred.format;
47885
+ } catch {
47886
+ }
47887
+ try {
47888
+ if (String(process.env.MARIA_USE_LLM_INFER || "1") === "1" && (!explicitSize || !explicitFormat)) {
47889
+ global.__MARIA_IMAGE_LLM_INFER__ = async () => {
47890
+ const llm = await inferImageArgsLLM(prompt);
47891
+ return llm;
47892
+ };
47893
+ }
47894
+ } catch {
47895
+ }
47510
47896
  const pixels = out.size[0] * out.size[1] * out.count;
47511
47897
  if (pixels > (out.budgetPixels || 0)) throw new Error("budget exceeded");
47512
47898
  if (!out.apply && !out.planOnly && !out.dryRun) {
@@ -47539,7 +47925,8 @@ function normalizeVideoArgs(raw, root) {
47539
47925
  retry: 2,
47540
47926
  apply: false,
47541
47927
  planOnly: false,
47542
- dryRun: false
47928
+ dryRun: false,
47929
+ aspect: "16:9"
47543
47930
  };
47544
47931
  while (args2.length) {
47545
47932
  const x2 = args2.shift();
@@ -47553,9 +47940,43 @@ function normalizeVideoArgs(raw, root) {
47553
47940
  case "fps":
47554
47941
  out.fps = clampInt(v, 1, 60, "fps");
47555
47942
  break;
47556
- case "res":
47557
- out.size = parseSize(String(v));
47943
+ case "size": {
47944
+ const sz = parseSize(String(v));
47945
+ out.size = sz;
47946
+ out.aspect = sz[0] >= sz[1] ? "16:9" : "9:16";
47947
+ break;
47948
+ }
47949
+ case "res": {
47950
+ const sv = String(v).toLowerCase().replace(/p$/, "");
47951
+ if (/^\d+x\d+$/i.test(String(v))) {
47952
+ out.size = parseSize(String(v));
47953
+ out.aspect = out.size[0] >= out.size[1] ? "16:9" : "9:16";
47954
+ } else if (sv === "720") {
47955
+ out.size = out.aspect === "9:16" ? [720, 1280] : [1280, 720];
47956
+ } else if (sv === "1080") {
47957
+ out.size = out.aspect === "9:16" ? [1080, 1920] : [1920, 1080];
47958
+ } else {
47959
+ throw new Error("invalid res (use 720|1080 or WIDTHxHEIGHT)");
47960
+ }
47961
+ break;
47962
+ }
47963
+ case "aspect": {
47964
+ const a = String(v);
47965
+ if (a !== "16:9" && a !== "9:16") throw new Error("invalid aspect (use 16:9|9:16)");
47966
+ out.aspect = a;
47967
+ const [w, h2] = out.size;
47968
+ if (w === 1280 && h2 === 720 || w === 720 && h2 === 1280 || w === 1920 && h2 === 1080 || w === 1080 && h2 === 1920) {
47969
+ if (a === "9:16") {
47970
+ if (h2 === 720) out.size = [720, 1280];
47971
+ else if (h2 === 1080) out.size = [1080, 1920];
47972
+ } else {
47973
+ if (w === 720) out.size = [1280, 720];
47974
+ else if (w === 1080) out.size = [1920, 1080];
47975
+ if (w === 1080 && h2 === 1920) out.size = [1920, 1080];
47976
+ }
47977
+ }
47558
47978
  break;
47979
+ }
47559
47980
  case "format":
47560
47981
  if (!["mp4", "webm"].includes(String(v))) throw new Error("invalid format");
47561
47982
  out.format = v;
@@ -47591,7 +48012,11 @@ function normalizeVideoArgs(raw, root) {
47591
48012
  }
47592
48013
  const caps = chooseCaps("video", out.model);
47593
48014
  if (caps?.maxVideoSize) {
47594
- if (out.size[0] > caps.maxVideoSize[0] || out.size[1] > caps.maxVideoSize[1]) throw new Error("resolution exceeds model capability");
48015
+ const reqMax = Math.max(out.size[0], out.size[1]);
48016
+ const reqMin = Math.min(out.size[0], out.size[1]);
48017
+ const capMax = Math.max(caps.maxVideoSize[0], caps.maxVideoSize[1]);
48018
+ const capMin = Math.min(caps.maxVideoSize[0], caps.maxVideoSize[1]);
48019
+ if (reqMax > capMax || reqMin > capMin) throw new Error("resolution exceeds model capability");
47595
48020
  }
47596
48021
  if (caps?.maxDuration && out.duration > caps.maxDuration) throw new Error("duration exceeds model capability");
47597
48022
  if (caps?.maxFps && out.fps > caps.maxFps) throw new Error("fps exceeds model capability");
@@ -47619,6 +48044,8 @@ function sanitizeOut(outDir, root) {
47619
48044
  var init_Normalizer = __esm({
47620
48045
  "src/services/media-orchestrator/Normalizer.ts"() {
47621
48046
  init_types4();
48047
+ init_NLInference();
48048
+ init_ImageArgumentInference();
47622
48049
  }
47623
48050
  });
47624
48051
  function ensureDirSync(p) {
@@ -48480,6 +48907,19 @@ var init_image_command = __esm({
48480
48907
  const spinner = new ProcessAnimation();
48481
48908
  spinner.start();
48482
48909
  try {
48910
+ try {
48911
+ const hook = global.__MARIA_IMAGE_LLM_INFER__;
48912
+ if (hook) {
48913
+ const llm = await hook();
48914
+ if (llm) {
48915
+ if (llm.size && (!Array.isArray(cli.size) || cli.size.length !== 2)) cli.size = llm.size;
48916
+ if (llm.size && Array.isArray(llm.size)) cli.size = llm.size;
48917
+ if (llm.format) cli.format = llm.format;
48918
+ if (Number.isFinite(Number(llm.count))) cli.count = Math.max(1, Math.min(8, Math.floor(Number(llm.count))));
48919
+ }
48920
+ }
48921
+ } catch {
48922
+ }
48483
48923
  const useRemote = String(process.env.MARIA_USE_REMOTE_MEDIA || "").toLowerCase() === "1" && await authManager.isAuthenticated();
48484
48924
  if (useRemote) {
48485
48925
  try {
@@ -48791,12 +49231,18 @@ async function runVideoPipeline(params2, opts) {
48791
49231
  const { GoogleGenAI } = __require("@google/genai");
48792
49232
  const ai2 = new GoogleGenAI({ apiKey });
48793
49233
  const modelName = params2.model || "veo-3.0-generate-001";
48794
- const aspectRatio = params2.size[0] >= params2.size[1] ? "16:9" : "9:16";
49234
+ const aspectRatio = "16:9";
49235
+ const resolution = Math.max(params2.size[0], params2.size[1]) >= 1920 ? "1080p" : "720p";
48795
49236
  const effectiveDuration = 8;
48796
49237
  let operation = await ai2.models.generateVideos({
48797
49238
  model: modelName,
48798
49239
  prompt: String(params2.prompt),
48799
- config: { aspectRatio, durationSeconds: effectiveDuration, frameRate: params2.fps }
49240
+ config: {
49241
+ aspectRatio,
49242
+ /* resolution: resolution, */
49243
+ durationSeconds: effectiveDuration,
49244
+ frameRate: params2.fps
49245
+ }
48800
49246
  });
48801
49247
  const pollStart = Date.now();
48802
49248
  const maxWaitMs = 6 * 60 * 1e3;
@@ -48948,7 +49394,7 @@ var init_video_command = __esm({
48948
49394
  category = "media";
48949
49395
  description = "Generate videos using Gemini (frames fallback when mux unavailable)";
48950
49396
  aliases = [];
48951
- usage = '/video "prompt" [--duration 8] [--fps 24] [--res 1280x720] [--format mp4|webm] [--model gemini-...] [--seed N] [--out dir] [--apply|--plan-only|--dry-run] [--concurrency N] [--retry N]';
49397
+ usage = '/video "prompt" [--duration 8] [--fps 24] [--aspect 16:9|9:16] [--res 720|1080] [--format mp4|webm] [--model gemini-...] [--seed N] [--out dir] [--apply|--plan-only|--dry-run] [--concurrency N] [--retry N]';
48952
49398
  examples = [
48953
49399
  { input: '/video "product demo" --duration 8 --fps 24 --res 1280x720 --apply', description: "Generate a short demo video" }
48954
49400
  ];
@@ -48969,11 +49415,15 @@ var init_video_command = __esm({
48969
49415
  const useRemote = String(process.env.MARIA_USE_REMOTE_MEDIA || "").toLowerCase() === "1" && await authManager.isAuthenticated();
48970
49416
  if (useRemote) {
48971
49417
  try {
49418
+ const isPortrait = cli.size[1] > cli.size[0];
49419
+ const maxEdge = Math.max(cli.size[0], cli.size[1]);
49420
+ const discrete = maxEdge >= 1920 ? "1080" : maxEdge >= 1280 ? "720" : void 0;
48972
49421
  const body = {
48973
49422
  prompt: cli.prompt,
48974
49423
  duration: cli.duration,
48975
49424
  fps: cli.fps,
48976
- res: `${cli.size[0]}x${cli.size[1]}`,
49425
+ res: discrete ? discrete : `${cli.size[0]}x${cli.size[1]}`,
49426
+ aspect: isPortrait ? "9:16" : "16:9",
48977
49427
  format: cli.format,
48978
49428
  model: cli.model,
48979
49429
  seed: cli.seed
@@ -50769,7 +51219,7 @@ var init_about_command = __esm({
50769
51219
  async execute(args2, context2) {
50770
51220
  const output3 = [];
50771
51221
  output3.push("");
50772
- output3.push(chalk14__default.default.cyan.bold("\u{1F916} About MARIA v4.3.35"));
51222
+ output3.push(chalk14__default.default.cyan.bold("\u{1F916} About MARIA v4.3.36"));
50773
51223
  output3.push(chalk14__default.default.gray("\u2550".repeat(40)));
50774
51224
  output3.push("");
50775
51225
  output3.push(chalk14__default.default.white.bold("MARIA - Minimal API, Maximum Power"));
@@ -54432,7 +54882,8 @@ function formatPlan(summary, opts) {
54432
54882
  if (opts.requestText && opts.requestText.trim().length > 0) {
54433
54883
  lines.push(opts.requestText.trim(), "");
54434
54884
  }
54435
- lines.push(`Modified Artifacts (${summary.planned} files):`);
54885
+ const headerLabel = opts.planView ? "Planned Artifacts" : "Modified Artifacts";
54886
+ lines.push(`${headerLabel} (${summary.planned} files):`);
54436
54887
  const warnMap = buildPerFileWarnings(summary.files, opts.validated);
54437
54888
  const skippedSet = new Set(opts.validated?.skipped || []);
54438
54889
  for (const f3 of summary.files) {
@@ -54457,18 +54908,20 @@ function formatPlan(summary, opts) {
54457
54908
  lines.push(diff, "");
54458
54909
  }
54459
54910
  }
54460
- const created = summary.files.filter((f3) => f3.action === "create").length;
54461
- const modified = summary.files.filter((f3) => f3.action === "modify").length;
54462
- const skipped = opts.validated?.skipped?.length || 0;
54463
- const okPhrase = created > 0 ? `${created + modified} files created/modified` : `${modified} files modified`;
54464
- lines.push(`OK: ${okPhrase}`);
54465
- if (skipped > 0) lines.push(`WARN: ${skipped} file${skipped > 1 ? "s" : ""} skipped`);
54466
- lines.push("Next steps:");
54467
- if (large) {
54468
- lines.push('- Large output \u2013 previews suppressed. Use --output diff or press "d" in interactive mode');
54911
+ if (!opts.planView) {
54912
+ const created = summary.files.filter((f3) => f3.action === "create").length;
54913
+ const modified = summary.files.filter((f3) => f3.action === "modify").length;
54914
+ const skipped = opts.validated?.skipped?.length || 0;
54915
+ const okPhrase = created > 0 ? `${created + modified} files created/modified` : `${modified} files modified`;
54916
+ lines.push(`OK: ${okPhrase}`);
54917
+ if (skipped > 0) lines.push(`WARN: ${skipped} file${skipped > 1 ? "s" : ""} skipped`);
54918
+ lines.push("Next steps:");
54919
+ if (large) {
54920
+ lines.push('- Large output \u2013 previews suppressed. Use --output diff or press "d" in interactive mode');
54921
+ }
54922
+ lines.push("- If this looks correct, commit the changes");
54923
+ lines.push('- For a full diff: rerun with --output diff or press "d" in interactive mode');
54469
54924
  }
54470
- lines.push("- If this looks correct, commit the changes");
54471
- lines.push('- For a full diff: rerun with --output diff or press "d" in interactive mode');
54472
54925
  return lines.join("\n");
54473
54926
  }
54474
54927
  function okLine(text) {
@@ -54504,9 +54957,10 @@ function formatPlanAsDiff(files, opts) {
54504
54957
  bytesUsed += diffBytes;
54505
54958
  shownFiles++;
54506
54959
  }
54507
- if (files.length > shownFiles) {
54960
+ const totalDiffTargets = files.filter((f3) => f3.action === "modify").length;
54961
+ if (totalDiffTargets > shownFiles) {
54508
54962
  lines.push(`
54509
- [${files.length - shownFiles} more file(s) omitted; re-run with --output diff --diff-lines ${budget.diffLines ?? 200}]`);
54963
+ [${totalDiffTargets - shownFiles} more file(s) omitted; re-run with --output diff --diff-lines ${budget.diffLines ?? 200}]`);
54510
54964
  }
54511
54965
  return lines.join("\n");
54512
54966
  }
@@ -54748,129 +55202,6 @@ var init_InteractiveController = __esm({
54748
55202
  init_OutputFormatter();
54749
55203
  }
54750
55204
  });
54751
-
54752
- // src/services/cli-auth/api-caller.ts
54753
- var api_caller_exports = {};
54754
- __export(api_caller_exports, {
54755
- RateLimitError: () => RateLimitError2,
54756
- callAPI: () => callAPI,
54757
- executeAIProxy: () => executeAIProxy,
54758
- executeChat: () => executeChat,
54759
- executeCode: () => executeCode
54760
- });
54761
- async function callAPI(endpoint, options = {}) {
54762
- const tokens2 = await authManager2.getValidTokens();
54763
- if (!tokens2) {
54764
- throw new Error("Authentication required. Please run /login first.");
54765
- }
54766
- const apiBase = process.env.MARIA_API_BASE || "https://api.maria-code.ai";
54767
- const url2 = `${apiBase}${endpoint}`;
54768
- const controller = new AbortController();
54769
- const defaultMs = 6e5;
54770
- const envMs = Number(process.env.MARIA_API_TIMEOUT_MS || process.env.MARIA_CODE_TIMEOUT_MS || defaultMs);
54771
- const timeoutMs = Number.isFinite(envMs) && envMs > 0 ? envMs : defaultMs;
54772
- const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
54773
- try {
54774
- const response = await fetch(url2, {
54775
- method: options.method || "GET",
54776
- headers: {
54777
- "Authorization": `Bearer ${tokens2.accessToken}`,
54778
- "Content-Type": "application/json",
54779
- ...options.headers
54780
- },
54781
- body: options.body ? JSON.stringify(options.body) : void 0,
54782
- agent,
54783
- // Use keep-alive agent
54784
- signal: controller.signal
54785
- });
54786
- clearTimeout(timeoutId);
54787
- if (!response) {
54788
- throw new Error("\u{1F310} Network error, check connection");
54789
- }
54790
- if (response.status === 401) {
54791
- throw new Error("Session expired. Please run /login again.");
54792
- }
54793
- if (response.status === 402) {
54794
- const data2 = await response.json().catch(() => ({}));
54795
- throw new Error(`Quota exceeded: ${data2.message || "Please wait or /upgrade"}`);
54796
- }
54797
- if (response.status === 403) {
54798
- const data2 = await response.json().catch(() => ({}));
54799
- throw new Error(`Not available on Free plan: ${data2.message || "Run /upgrade"}`);
54800
- }
54801
- if (response.status === 429) {
54802
- const h2 = response.headers;
54803
- const ra = h2.get("Retry-After");
54804
- const reset = h2.get("RateLimit-Reset") || h2.get("X-RateLimit-Reset");
54805
- let waitSec = 3;
54806
- if (ra && /^\d+$/.test(ra)) {
54807
- waitSec = +ra;
54808
- } else if (ra) {
54809
- const t2 = Date.parse(ra);
54810
- if (!isNaN(t2)) waitSec = Math.max(1, Math.ceil((t2 - Date.now()) / 1e3));
54811
- } else if (reset) {
54812
- waitSec = Math.max(1, Math.ceil((+reset - Date.now()) / 1e3));
54813
- }
54814
- throw new RateLimitError2(`\u23F1 Wait ${waitSec}s`, waitSec);
54815
- }
54816
- if (!response.ok) {
54817
- const data2 = await response.json().catch(() => ({}));
54818
- throw new Error(data2.error || `Request failed: ${response.statusText}`);
54819
- }
54820
- const data = await response.json();
54821
- return data;
54822
- } catch (error2) {
54823
- clearTimeout(timeoutId);
54824
- if (error2.name === "AbortError") {
54825
- throw new Error("\u{1F310} Network error, check connection");
54826
- }
54827
- throw error2;
54828
- }
54829
- }
54830
- async function executeChat(messages) {
54831
- const response = await callAPI("/v1/chat", {
54832
- method: "POST",
54833
- body: { messages }
54834
- });
54835
- return response;
54836
- }
54837
- async function executeCode(prompt) {
54838
- const response = await callAPI("/v1/ai-proxy", {
54839
- method: "POST",
54840
- body: {
54841
- prompt,
54842
- taskType: "code"
54843
- }
54844
- });
54845
- if (response.data?.routedModel) {
54846
- response.routedModel = response.data.routedModel;
54847
- }
54848
- if (response.data?.content) {
54849
- response.output = response.data.content;
54850
- }
54851
- return response;
54852
- }
54853
- async function executeAIProxy(provider, model, messages, options) {
54854
- return callAPI("/v1/ai-proxy", {
54855
- method: "POST",
54856
- body: { provider, model, messages, options }
54857
- });
54858
- }
54859
- var agent, authManager2, RateLimitError2;
54860
- var init_api_caller = __esm({
54861
- "src/services/cli-auth/api-caller.ts"() {
54862
- init_AuthenticationManager();
54863
- agent = new https__default.default.Agent({ keepAlive: true });
54864
- authManager2 = new AuthenticationManager();
54865
- RateLimitError2 = class extends Error {
54866
- constructor(message, retryAfter) {
54867
- super(message);
54868
- this.retryAfter = retryAfter;
54869
- this.name = "RateLimitError";
54870
- }
54871
- };
54872
- }
54873
- });
54874
55205
  async function mapAttachmentsToTargets(attached, opts) {
54875
55206
  const warnings = [];
54876
55207
  const mapped = [];
@@ -55318,7 +55649,68 @@ ${requestPreamble}
55318
55649
  ${request}
55319
55650
 
55320
55651
  ${editContext}`;
55321
- const response = await executeCode(enriched);
55652
+ const ctxAttachments = Array.isArray(opts.attachedFiles) && opts.attachedFiles.length > 0 ? opts.attachedFiles.map((f3) => ({
55653
+ name: f3.originalName,
55654
+ path: f3.pathHint,
55655
+ mime: f3.mime || "text/plain",
55656
+ data_base64: f3.content ? Buffer.from(f3.content, "utf8").toString("base64") : void 0
55657
+ })).map((a) => a.data_base64 ? a : { ...a, data_base64: void 0 }) : [];
55658
+ const pathAttachments = [];
55659
+ if (explicitFiles.length > 0) {
55660
+ try {
55661
+ const fs51 = await import('fs/promises');
55662
+ const pathMod = await import('path');
55663
+ for (const rel of explicitFiles) {
55664
+ try {
55665
+ const full = explicitAbsMap[rel] || pathMod.join(opts.root, rel);
55666
+ const stat13 = await fs51.stat(full).catch(() => null);
55667
+ if (!stat13 || !stat13.isFile()) continue;
55668
+ const buf = await fs51.readFile(full);
55669
+ const ext2 = (pathMod.extname(full) || "").toLowerCase();
55670
+ const mime = ext2 === ".pdf" ? "application/pdf" : ext2 === ".png" ? "image/png" : ext2 === ".jpg" || ext2 === ".jpeg" ? "image/jpeg" : ext2 === ".webp" ? "image/webp" : ext2 === ".gif" ? "image/gif" : ext2 === ".bmp" ? "image/bmp" : ext2 === ".svg" ? "image/svg+xml" : ext2 === ".tif" || ext2 === ".tiff" ? "image/tiff" : ext2 === ".heic" ? "image/heic" : ext2 === ".heif" ? "image/heif" : "text/plain";
55671
+ pathAttachments.push({
55672
+ name: pathMod.basename(full),
55673
+ path: full,
55674
+ mime,
55675
+ data_base64: buf.toString("base64")
55676
+ });
55677
+ } catch {
55678
+ }
55679
+ }
55680
+ } catch {
55681
+ }
55682
+ }
55683
+ const hydratedCtx = [];
55684
+ if (ctxAttachments.length > 0) {
55685
+ try {
55686
+ const fs51 = await import('fs/promises');
55687
+ for (const a of ctxAttachments) {
55688
+ if (a.data_base64) {
55689
+ hydratedCtx.push(a);
55690
+ continue;
55691
+ }
55692
+ const p = a.path || "";
55693
+ if (!p) {
55694
+ continue;
55695
+ }
55696
+ try {
55697
+ const stat13 = await fs51.stat(p).catch(() => null);
55698
+ if (!stat13 || !stat13.isFile()) {
55699
+ hydratedCtx.push(a);
55700
+ continue;
55701
+ }
55702
+ const buf = await fs51.readFile(p);
55703
+ hydratedCtx.push({ ...a, data_base64: buf.toString("base64") });
55704
+ } catch {
55705
+ hydratedCtx.push(a);
55706
+ }
55707
+ }
55708
+ } catch {
55709
+ hydratedCtx.push(...ctxAttachments);
55710
+ }
55711
+ }
55712
+ const allAttachments = (hydratedCtx.length ? hydratedCtx : ctxAttachments).concat(pathAttachments);
55713
+ const response = await executeCode(allAttachments.length > 0 ? { prompt: enriched, provider: "google", model: "gemini-2.5-flash", attachments: allAttachments } : enriched);
55322
55714
  const raw = (response.output || response?.data?.content || "").trim();
55323
55715
  if (!raw) {
55324
55716
  return {
@@ -55447,6 +55839,7 @@ ${editContext}`;
55447
55839
  const remainingSkipped = (validated.skipped || []).filter((p) => !skippedPlans.some((sp) => sp.path === p)).map((p) => ({ path: p, kind: "source", action: "skip", description: "" }));
55448
55840
  const displayFiles = validated.files.concat(skippedPlans).concat(remainingSkipped);
55449
55841
  const summary = summarizePlan(displayFiles);
55842
+ const planView = opts.flags.planOnly || opts.flags.dryRun || !opts.flags.apply;
55450
55843
  const lines = [
55451
55844
  formatPlan(summary, {
55452
55845
  mode: outputMode,
@@ -55454,11 +55847,26 @@ ${editContext}`;
55454
55847
  diffBudget: collectDiffBudget(opts.flags),
55455
55848
  root: opts.root,
55456
55849
  requestText: request,
55457
- validated: { warnings: validated.warnings.slice(), skipped: validated.skipped.slice() }
55850
+ validated: { warnings: validated.warnings.slice(), skipped: validated.skipped.slice() },
55851
+ planView
55458
55852
  })
55459
55853
  ];
55460
55854
  if (opts.flags.planOnly || opts.flags.dryRun || !opts.flags.apply) {
55461
- return { plan: normalized, validated, summaryLines: withNotices(lines) };
55855
+ let specMarkdown;
55856
+ try {
55857
+ const prompt = buildSpecPrompt(request, normalized);
55858
+ const { callApiJson: callApiJson4 } = await Promise.resolve().then(() => (init_api_client(), api_client_exports));
55859
+ try {
55860
+ const resp = await callApiJson4("/v1/ai-proxy", { method: "POST", body: JSON.stringify({ prompt, taskType: "chat" }), headers: { "Content-Type": "application/json" } });
55861
+ const content = resp?.data?.content || resp?.content;
55862
+ if (content && typeof content === "string") specMarkdown = content;
55863
+ } catch {
55864
+ }
55865
+ } catch {
55866
+ }
55867
+ const res = { plan: normalized, validated, summaryLines: withNotices(lines) };
55868
+ if (specMarkdown && typeof specMarkdown === "string" && specMarkdown.trim()) res.specMarkdown = specMarkdown;
55869
+ return res;
55462
55870
  }
55463
55871
  if (opts.flags.interactive && !opts.flags.yes && !process.stdin.isTTY) {
55464
55872
  lines.push("", "WARN: Non-TTY interactive request downgraded to plan-only. Re-run with --yes to apply non-interactively.");
@@ -55538,6 +55946,36 @@ ${editContext}`;
55538
55946
  return { plan: normalized, validated, summaryLines: withNotices([errorLine(err)]) };
55539
55947
  }
55540
55948
  }
55949
+ function buildSpecPrompt(request, plan) {
55950
+ const tree = {};
55951
+ for (const f3 of plan) {
55952
+ const dir = f3.path.split("/").slice(0, -1).join("/") || ".";
55953
+ if (!tree[dir]) tree[dir] = [];
55954
+ tree[dir].push(`${f3.action} ${f3.path} ${f3.language ? "(" + f3.language + ")" : ""}`.trim());
55955
+ }
55956
+ const treeLines = [];
55957
+ for (const [dir, items] of Object.entries(tree)) {
55958
+ treeLines.push(`- ${dir}`);
55959
+ for (const it of items) treeLines.push(` - ${it}`);
55960
+ }
55961
+ return [
55962
+ "You are a senior staff engineer. Produce a concise, high-quality Markdown spec for the following code change plan.",
55963
+ "",
55964
+ "Sections:",
55965
+ "- Overview",
55966
+ "- File Tree",
55967
+ "- Per-file Rationale (what/why)",
55968
+ "- Next Steps",
55969
+ "",
55970
+ "Request:",
55971
+ "```",
55972
+ request,
55973
+ "```",
55974
+ "",
55975
+ "Planned files:",
55976
+ treeLines.join("\n")
55977
+ ].join("\n");
55978
+ }
55541
55979
  function normalizePreviewLines(n) {
55542
55980
  return typeof n === "number" && n > 0 ? n : void 0;
55543
55981
  }
@@ -55732,7 +56170,7 @@ function scanSoftIssues(files) {
55732
56170
  return { hasTrailingWhitespace: tw, hasConflictMarkers: cm };
55733
56171
  }
55734
56172
  function parseExplicitFilenames(request) {
55735
- const matches = request.match(/([\w.-]+\.(?:html|css|js|jsx|ts|tsx))/gi);
56173
+ const matches = request.match(/([\w\-./\\:]+\.[A-Za-z0-9]{1,10})/gi);
55736
56174
  if (!matches) return [];
55737
56175
  const seen = /* @__PURE__ */ new Set();
55738
56176
  const out = [];
@@ -56032,6 +56470,7 @@ var LANGUAGE_EXTENSIONS, CodeCommand, codeCommand, metadata3;
56032
56470
  var init_code_command = __esm({
56033
56471
  "src/slash-commands/categories/code/code.command.ts"() {
56034
56472
  init_base_command();
56473
+ init_api_caller();
56035
56474
  init_rate_limit_handler();
56036
56475
  init_animations();
56037
56476
  init_code_utils();
@@ -56053,7 +56492,7 @@ var init_code_command = __esm({
56053
56492
  name = "code";
56054
56493
  category = "implementation";
56055
56494
  description = "Generate code with AI";
56056
- usage = "<request> [--plan-only|--sow] [--apply] [--dry-run] [--interactive] [--yes] [--max-files N] [--root DIR] [--rollback on|off] [--output names|summary|detail|diff] [--no-code] [--preview-lines N] [--only-attached] [--attach-mode strict|assist] [--max-attachments N] [--diff-lines N] [--diff-bytes N] [--diff-hunks N]";
56495
+ usage = "<request> [--plan-only|--sow] [--apply] [--dry-run] [--interactive] [--yes] [--max-files N] [--root DIR] [--rollback on|off] [--output names|summary|detail|diff] [--no-code] [--preview-lines N] [--only-attached] [--attach-mode strict|assist] [--max-attachments N] [--diff-lines N] [--diff-bytes N] [--diff-hunks N] [--diff-global-max-files N] [--diff-global-max-bytes N]";
56057
56496
  aliases = ["c"];
56058
56497
  examples = [
56059
56498
  {
@@ -56068,12 +56507,21 @@ var init_code_command = __esm({
56068
56507
  }
56069
56508
  ];
56070
56509
  async execute(commandArgs, context2) {
56071
- const request = commandArgs.raw.join(" ").trim();
56510
+ const request = await this.ensureLanguageDefaults(commandArgs.raw.join(" ").trim());
56072
56511
  if (!request) {
56073
56512
  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.");
56074
56513
  }
56075
56514
  try {
56076
56515
  const opts = this.parseV2Options(commandArgs.raw);
56516
+ if (opts.planOnly) {
56517
+ opts.apply = false;
56518
+ opts.dryRun = false;
56519
+ }
56520
+ if (opts.dryRun) {
56521
+ opts.apply = false;
56522
+ }
56523
+ if (opts.dryRun && !opts.output) opts.output = "detail";
56524
+ if (opts.dryRun && !opts.previewLines) opts.previewLines = 50;
56077
56525
  const root = opts.root || process.cwd();
56078
56526
  const { orchestrate: orchestrate2 } = await Promise.resolve().then(() => (init_Orchestrator(), Orchestrator_exports));
56079
56527
  const attachments = await this.collectAttachedFiles(context2).catch(() => []);
@@ -56083,8 +56531,57 @@ var init_code_command = __esm({
56083
56531
  const spinner = new ProcessAnimation();
56084
56532
  spinner.start();
56085
56533
  try {
56086
- 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, allowDotfiles: opts.allowDotfiles }, abortSignal: abort.signal, attachedFiles: attachments });
56087
- const out = res.summaryLines.join("\n");
56534
+ 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 });
56535
+ if (opts.planOnly) {
56536
+ const fs51 = await import('fs/promises');
56537
+ const path64 = await import('path');
56538
+ const spec = res?.specMarkdown;
56539
+ const lines = Array.isArray(res?.summaryLines) ? res.summaryLines : [];
56540
+ const planItems = [];
56541
+ for (const l of lines) {
56542
+ const s2 = String(l).trim();
56543
+ if (!s2) continue;
56544
+ if (/^Modified Artifacts/i.test(s2)) continue;
56545
+ if (/^OK:/i.test(s2)) continue;
56546
+ if (/^Next steps:/i.test(s2)) continue;
56547
+ const m2 = /^-\s+(create|modify)\s+(.+)$/i.exec(s2);
56548
+ if (m2) {
56549
+ planItems.push(`- [plan] ${m2[1].toLowerCase()} ${m2[2]}`);
56550
+ continue;
56551
+ }
56552
+ planItems.push(`- ${s2}`);
56553
+ }
56554
+ const md = [];
56555
+ if (spec && spec.trim()) {
56556
+ md.push(spec.trim());
56557
+ } else {
56558
+ md.push("# Code Plan");
56559
+ md.push("");
56560
+ md.push("## Request");
56561
+ md.push("");
56562
+ md.push("```");
56563
+ md.push(request);
56564
+ md.push("```");
56565
+ md.push("");
56566
+ md.push("## Proposed Changes");
56567
+ md.push("");
56568
+ if (planItems.length) md.push(...planItems);
56569
+ else md.push("- (no summary available)");
56570
+ }
56571
+ const plansDir = path64.join(root, ".maria", "plans");
56572
+ await fs51.mkdir(plansDir, { recursive: true });
56573
+ const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
56574
+ const fileName = `code-plan-${ts}.md`;
56575
+ const outPath = path64.join(plansDir, fileName);
56576
+ await fs51.writeFile(outPath, md.join("\n") + "\n", "utf8");
56577
+ const rel = path64.relative(root, outPath);
56578
+ return this.success(`Code plan saved: ${rel}`);
56579
+ }
56580
+ const detail = res?.detailLines;
56581
+ if (opts.dryRun && Array.isArray(detail) && detail.length) {
56582
+ return this.success(detail.join("\n"));
56583
+ }
56584
+ const out = Array.isArray(res?.summaryLines) ? res.summaryLines.join("\n") : "";
56088
56585
  return this.success(out);
56089
56586
  } finally {
56090
56587
  try {
@@ -56134,9 +56631,68 @@ ${pretty}`);
56134
56631
  return this.error(parts.join("\n"));
56135
56632
  }
56136
56633
  }
56634
+ // Add default language hints when not specified by the user (LLM-assisted detection)
56635
+ async ensureLanguageDefaults(raw) {
56636
+ try {
56637
+ const system = [
56638
+ "You analyze a user's code-generation request.",
56639
+ "Decide if the user explicitly specified a programming language or framework/tooling (e.g., TypeScript, Python, Rust, Java, React, Vue, Node, etc.).",
56640
+ 'Return ONLY compact JSON with shape {"explicitLanguage": boolean, "language"?: string}.',
56641
+ "Do not add any commentary."
56642
+ ].join("\n");
56643
+ const user = `Request: ${raw}`;
56644
+ const resp = await callAPI("/v1/ai-proxy", {
56645
+ method: "POST",
56646
+ body: {
56647
+ provider: "google",
56648
+ model: "gemini-2.5-flash",
56649
+ taskType: "chat",
56650
+ prompt: `${system}
56651
+
56652
+ ${user}`
56653
+ }
56654
+ });
56655
+ const content = (resp?.data?.content || resp?.content || "").trim();
56656
+ const extractFirstJson3 = (text) => {
56657
+ const fence = /```\s*json\s*\r?\n([\s\S]*?)```/i.exec(text);
56658
+ if (fence) return fence[1];
56659
+ const generic = /```\s*\r?\n([\s\S]*?)```/i.exec(text);
56660
+ if (generic) {
56661
+ try {
56662
+ JSON.parse(generic[1]);
56663
+ return generic[1];
56664
+ } catch {
56665
+ }
56666
+ }
56667
+ const start = text.indexOf("{");
56668
+ const end = text.lastIndexOf("}");
56669
+ if (start >= 0 && end > start) {
56670
+ const cand = text.slice(start, end + 1);
56671
+ try {
56672
+ JSON.parse(cand);
56673
+ return cand;
56674
+ } catch {
56675
+ }
56676
+ }
56677
+ return null;
56678
+ };
56679
+ const jsonText = extractFirstJson3(content) || content;
56680
+ let parsed = {};
56681
+ try {
56682
+ parsed = JSON.parse(jsonText);
56683
+ } catch {
56684
+ parsed.explicitLanguage = /```\s*[a-zA-Z]/.test(raw) || /\.(ts|tsx|js|jsx|py|java|kt|go|rs|rb|swift|cs|c|cpp|hpp|php|scala|hs|ex|exs|dart|lua|zig|sol|sql)\b/i.test(raw);
56685
+ }
56686
+ if (parsed && parsed.explicitLanguage) return raw;
56687
+ } catch {
56688
+ }
56689
+ const hint = " (Use TypeScript and React; prefer functional components and node)";
56690
+ return raw + hint;
56691
+ }
56137
56692
  // v2.0 helpers
56138
56693
  parseV2Options(raw) {
56139
- const opts = { planOnly: false, apply: false, dryRun: false, interactive: false, yes: false, rollback: true, output: void 0, noCode: false, previewLines: 0, root: void 0, maxFiles: void 0, verbose: false, gitGuard: void 0, allowDotfiles: false, confirmOverwrites: [], gitCommit: void 0, gitBranch: void 0, gitTag: void 0, gitTagPrefix: void 0, gitPush: void 0, gitPushRemote: void 0, onlyAttached: false, attachMode: "assist", maxAttachments: 50, diffLines: void 0, diffBytes: void 0, diffHunks: void 0 };
56694
+ const opts = { planOnly: false, apply: false, dryRun: false, interactive: false, yes: false, rollback: true, output: void 0, noCode: false, previewLines: 0, root: void 0, maxFiles: void 0, verbose: false, gitGuard: void 0, allowDotfiles: false, confirmOverwrites: [], gitCommit: void 0, gitBranch: void 0, gitTag: void 0, gitTagPrefix: void 0, gitPush: void 0, gitPushRemote: void 0, onlyAttached: false, attachMode: "assist", maxAttachments: 50, diffLines: void 0, diffBytes: void 0, diffHunks: void 0, diffGlobalMaxFiles: void 0, diffGlobalMaxBytes: void 0 };
56695
+ const explicit = { apply: false, planOnly: false, dryRun: false };
56140
56696
  const a = raw.slice();
56141
56697
  while (a.length) {
56142
56698
  const x2 = a.shift();
@@ -56146,12 +56702,15 @@ ${pretty}`);
56146
56702
  case "plan-only":
56147
56703
  case "sow":
56148
56704
  opts.planOnly = true;
56705
+ explicit.planOnly = true;
56149
56706
  break;
56150
56707
  case "apply":
56151
56708
  opts.apply = true;
56709
+ explicit.apply = true;
56152
56710
  break;
56153
56711
  case "dry-run":
56154
56712
  opts.dryRun = true;
56713
+ explicit.dryRun = true;
56155
56714
  break;
56156
56715
  case "interactive":
56157
56716
  opts.interactive = true;
@@ -56211,6 +56770,12 @@ ${pretty}`);
56211
56770
  case "diff-hunks":
56212
56771
  opts.diffHunks = Number(v || a.shift());
56213
56772
  break;
56773
+ case "diff-global-max-files":
56774
+ opts.diffGlobalMaxFiles = Number(v || a.shift());
56775
+ break;
56776
+ case "diff-global-max-bytes":
56777
+ opts.diffGlobalMaxBytes = Number(v || a.shift());
56778
+ break;
56214
56779
  case "confirm-overwrites": {
56215
56780
  const list = (v || a.shift() || "").split(",").map((s2) => s2.trim()).filter(Boolean);
56216
56781
  opts.confirmOverwrites = list;
@@ -56244,8 +56809,16 @@ ${pretty}`);
56244
56809
  }
56245
56810
  }
56246
56811
  }
56247
- if (!opts.apply && !opts.planOnly && !opts.dryRun) {
56248
- opts.apply = true;
56812
+ if (explicit.planOnly || explicit.dryRun) {
56813
+ opts.apply = false;
56814
+ }
56815
+ if (explicit.planOnly) {
56816
+ opts.dryRun = false;
56817
+ }
56818
+ if (!explicit.apply && !explicit.planOnly && !explicit.dryRun) {
56819
+ if (!opts.apply && !opts.planOnly && !opts.dryRun) {
56820
+ opts.apply = true;
56821
+ }
56249
56822
  }
56250
56823
  return opts;
56251
56824
  }
@@ -71083,7 +71656,7 @@ ${user}`,
71083
71656
  };
71084
71657
  }
71085
71658
  });
71086
- function extractFirstJson(text) {
71659
+ function extractFirstJson2(text) {
71087
71660
  const fence = /```json\r?\n([\s\S]*?)```/i.exec(text);
71088
71661
  if (fence) return fence[1];
71089
71662
  const start = text.indexOf("{");
@@ -71130,7 +71703,7 @@ ${user}`,
71130
71703
  }
71131
71704
  });
71132
71705
  const raw = (response?.data?.content || response?.output || "").trim();
71133
- const jsonText = extractFirstJson(raw) || raw;
71706
+ const jsonText = extractFirstJson2(raw) || raw;
71134
71707
  let parsed = {};
71135
71708
  try {
71136
71709
  parsed = JSON.parse(jsonText);
@@ -72417,6 +72990,17 @@ var init_slash_commands = __esm({
72417
72990
  init_registry();
72418
72991
  }
72419
72992
  });
72993
+
72994
+ // src/cli/session-state.ts
72995
+ function clearSession() {
72996
+ while (session.length) session.pop();
72997
+ }
72998
+ var session;
72999
+ var init_session_state = __esm({
73000
+ "src/cli/session-state.ts"() {
73001
+ session = [];
73002
+ }
73003
+ });
72420
73004
  async function handleSlash(input3) {
72421
73005
  if (!input3.startsWith("/")) return false;
72422
73006
  const { cmd, args: args2, options, flags } = parseSlash(input3);
@@ -72425,7 +73009,10 @@ async function handleSlash(input3) {
72425
73009
  clearTerminal();
72426
73010
  } catch {
72427
73011
  }
72428
- return true;
73012
+ try {
73013
+ clearSession();
73014
+ } catch {
73015
+ }
72429
73016
  }
72430
73017
  if (cmd === "doctor") {
72431
73018
  console.log(chalk14__default.default.white("Run as subcommand: maria doctor"));
@@ -72477,6 +73064,7 @@ var init_handle_slash = __esm({
72477
73064
  init_slash_commands();
72478
73065
  init_cli_auth();
72479
73066
  init_terminal();
73067
+ init_session_state();
72480
73068
  }
72481
73069
  });
72482
73070
  function formatAnyError(err) {
@@ -74484,7 +75072,7 @@ var init_ai_response_service = __esm({
74484
75072
  */
74485
75073
  async callLLM(prompt, opts = {}) {
74486
75074
  const {
74487
- system = PLAIN_OUTPUT ? "Return ONLY the answer (or ONLY code). No menus, no lists, no guided flows. Always respond in English." : "You are a helpful senior engineer named Maria. Always respond in English. Provide direct, production-quality answers. Make sure you answer in plain text, as a natural chat. When asked about the model (not your name or who you are, but the model), say you are a large language model fully trained by Bonginkan.",
75075
+ system = PLAIN_OUTPUT ? "Return ONLY the answer (or ONLY code). No menus, no lists, no guided flows. Always respond in English. If a local file path is provided, make sure you read the uploaded file before taking any actions." : "You are a helpful senior engineer named Maria. Always respond in English. Provide direct, production-quality answers. Make sure you answer in plain text, as a natural chat. When asked about the model (not your name or who you are, but the model), say you are a large language model fully trained by Bonginkan. If a path is provided, return the path as a string. If a local file path is provided, make sure you read the uploaded/attached file (which is likely equivalent to the path) before taking any actions.",
74488
75076
  model = void 0,
74489
75077
  provider = DEFAULT_PROVIDER2,
74490
75078
  temperature = 0.2,
@@ -74492,14 +75080,63 @@ var init_ai_response_service = __esm({
74492
75080
  } = opts;
74493
75081
  process.env.MARIA_API_BASE || "https://api.maria-code.ai";
74494
75082
  const preferApi = String(process.env.MARIA_USE_API || "1") === "1";
75083
+ let effectiveAttachments = Array.isArray(opts.attachments) ? opts.attachments.slice() : [];
74495
75084
  if (preferApi) {
74496
75085
  try {
74497
75086
  const { callAPI: callAPI2 } = await Promise.resolve().then(() => (init_api_caller(), api_caller_exports));
75087
+ let autoAttachments = [];
75088
+ try {
75089
+ const pathPattern = /(?:^|\s)([\w\-\.\/\\:]+\.[A-Za-z0-9]{1,10})(?:\s|$)/gi;
75090
+ const candidates = /* @__PURE__ */ new Set();
75091
+ let m2;
75092
+ const textToScan = `${prompt}`;
75093
+ while ((m2 = pathPattern.exec(textToScan)) !== null) {
75094
+ const p = (m2[1] || "").trim();
75095
+ if (p) candidates.add(p);
75096
+ }
75097
+ if (candidates.size > 0) {
75098
+ const fs51 = await import('fs/promises');
75099
+ const pathMod = await import('path');
75100
+ const cwd2 = process.cwd();
75101
+ for (const cand of candidates) {
75102
+ try {
75103
+ const normalized = cand.replace(/^"|"$/g, "").replace(/^'|'$/g, "");
75104
+ const abs = pathMod.isAbsolute(normalized) ? normalized : pathMod.join(cwd2, normalized);
75105
+ const st = await fs51.stat(abs).catch(() => null);
75106
+ if (!st || !st.isFile()) continue;
75107
+ const buf = await fs51.readFile(abs);
75108
+ const ext2 = (pathMod.extname(abs) || "").toLowerCase();
75109
+ const mime = ext2 === ".pdf" ? "application/pdf" : ext2 === ".png" ? "image/png" : ext2 === ".jpg" || ext2 === ".jpeg" ? "image/jpeg" : ext2 === ".webp" ? "image/webp" : ext2 === ".gif" ? "image/gif" : ext2 === ".bmp" ? "image/bmp" : ext2 === ".svg" ? "image/svg+xml" : ext2 === ".tif" || ext2 === ".tiff" ? "image/tiff" : ext2 === ".heic" ? "image/heic" : ext2 === ".heif" ? "image/heif" : "text/plain";
75110
+ autoAttachments.push({ name: pathMod.basename(abs), path: abs, mime, data_base64: buf.toString("base64") });
75111
+ } catch {
75112
+ }
75113
+ }
75114
+ }
75115
+ } catch {
75116
+ }
75117
+ if (autoAttachments.length > 0) {
75118
+ const existing = new Set(effectiveAttachments.map((a) => (a.path || a.name || "").toLowerCase()));
75119
+ for (const a of autoAttachments) {
75120
+ const key = (a.path || a.name || "").toLowerCase();
75121
+ if (!existing.has(key)) {
75122
+ effectiveAttachments.push(a);
75123
+ existing.add(key);
75124
+ }
75125
+ }
75126
+ }
75127
+ const inlineSection = "";
74498
75128
  const r2 = await callAPI2("/v1/ai-proxy", {
74499
75129
  method: "POST",
74500
- body: { prompt: `${system}
75130
+ body: {
75131
+ // When attachments are present, force an attachments-capable route (mirror /evaluate)
75132
+ ...effectiveAttachments.length ? { provider: "google", model: "gemini-2.5-flash" } : {},
75133
+ prompt: `${system}
74501
75134
 
74502
- ${prompt}`, taskType: "chat" }
75135
+ ${prompt}${inlineSection}`,
75136
+ taskType: "chat",
75137
+ // mirror /evaluate: include attachments in metadata
75138
+ ...effectiveAttachments.length ? { metadata: { attachments: effectiveAttachments } } : {}
75139
+ }
74503
75140
  });
74504
75141
  const apiContent = r2?.data?.content || r2?.content;
74505
75142
  if (apiContent) return apiContent;
@@ -74512,10 +75149,42 @@ ${prompt}`, taskType: "chat" }
74512
75149
  } catch {
74513
75150
  }
74514
75151
  }
74515
- const res = await this.providerManager.complete({
74516
- prompt: `${system}
75152
+ let fallbackPrompt = `${system}
74517
75153
 
74518
- ${prompt}`,
75154
+ ${prompt}`;
75155
+ try {
75156
+ const attList = effectiveAttachments && effectiveAttachments.length ? effectiveAttachments : [];
75157
+ if (attList.length > 0) {
75158
+ const limitBytes = 128 * 1024;
75159
+ let used = 0;
75160
+ const sections = [];
75161
+ for (const a of attList) {
75162
+ if (!a?.data_base64) continue;
75163
+ try {
75164
+ const buf = Buffer.from(a.data_base64, "base64");
75165
+ const text = /^(application\/pdf)/i.test(String(a.mime || "")) ? "" : buf.toString("utf8");
75166
+ if (!text) continue;
75167
+ const remaining = Math.max(0, limitBytes - used);
75168
+ if (remaining <= 0) break;
75169
+ const slice = text.length > remaining ? text.slice(0, remaining) : text;
75170
+ used += Buffer.byteLength(slice, "utf8");
75171
+ sections.push(`[BEGIN file: ${a.path || a.name || "attachment.txt"}]
75172
+ ${slice}
75173
+ [END]`);
75174
+ } catch {
75175
+ }
75176
+ }
75177
+ if (sections.length > 0) {
75178
+ fallbackPrompt = `${fallbackPrompt}
75179
+
75180
+ [ATTACHMENTS]
75181
+ ${sections.join("\n\n")}`;
75182
+ }
75183
+ }
75184
+ } catch {
75185
+ }
75186
+ const res = await this.providerManager.complete({
75187
+ prompt: fallbackPrompt,
74519
75188
  model,
74520
75189
  temperature,
74521
75190
  maxTokens
@@ -75760,7 +76429,7 @@ async function init2() {
75760
76429
  ai = res.ai;
75761
76430
  res.ctx;
75762
76431
  store = res.store;
75763
- while (session.length) session.pop();
76432
+ clearSession();
75764
76433
  for (const m2 of res.session) session.push(m2);
75765
76434
  await loadServices2();
75766
76435
  }
@@ -75777,6 +76446,9 @@ async function streamAnswer(text, opts = {}) {
75777
76446
  s2 = s2.replace(/\[BEGIN\s+file:[^\]]+\][\s\S]*?\[END\]/g, "");
75778
76447
  return s2;
75779
76448
  };
76449
+ const removeAttachmentSections = (s2) => {
76450
+ return s2.replace(/\[ATTACHMENTS\][\s\S]*$/i, "");
76451
+ };
75780
76452
  const hasAnyCodeBlocks = (s2) => /```[\s\S]*?```|\[BEGIN\s+file:/i.test(s2);
75781
76453
  const envInt = (name2, def) => {
75782
76454
  const v = Number(process.env[name2]);
@@ -75802,10 +76474,11 @@ async function streamAnswer(text, opts = {}) {
75802
76474
  model: process.env.MARIA_MODEL || "gemini-2.5-flash"
75803
76475
  });
75804
76476
  animation.stop();
75805
- const containsCode = hasAnyCodeBlocks(resp || "");
75806
- if (containsCode) {
76477
+ const respForArtifactCheck = removeAttachmentSections(resp || "");
76478
+ const containsCode = hasAnyCodeBlocks(respForArtifactCheck);
76479
+ if (containsCode && opts.triage && opts.triage.type === "route-code") {
75807
76480
  try {
75808
- const artifacts = extractAllCodeInfos(resp);
76481
+ const artifacts = extractAllCodeInfos(respForArtifactCheck);
75809
76482
  const savedFiles = [];
75810
76483
  let okCount = 0, warnCount = 0, errCount = 0;
75811
76484
  for (const { language, code, extension, filename: suggested } of artifacts) {
@@ -75830,7 +76503,7 @@ async function streamAnswer(text, opts = {}) {
75830
76503
  console.log(chalk14__default.default.white(`ERROR: failed ${filepath} (${language}) - ${msg2}`));
75831
76504
  }
75832
76505
  }
75833
- const prose = stripMarkdownForPlainChat(removeCodeBlocks(resp)).trim();
76506
+ const prose = stripMarkdownForPlainChat(removeCodeBlocks(removeAttachmentSections(resp))).trim();
75834
76507
  if (prose) {
75835
76508
  console.log(chalk14__default.default.white(""));
75836
76509
  console.log(chalk14__default.default.white("Chat Response:"));
@@ -75915,7 +76588,10 @@ async function handleLine(line, options = {}) {
75915
76588
  locale: process.env.LANG,
75916
76589
  recentCommands: []
75917
76590
  });
75918
- if (triageResult.next?.route) {
76591
+ if (
76592
+ /*false && for debugging*/
76593
+ triageResult.next?.route
76594
+ ) {
75919
76595
  const commandParts = [
75920
76596
  triageResult.next.route,
75921
76597
  ...triageResult.next.args ?? []
@@ -76117,7 +76793,7 @@ MARIA v${getVersion()}
76117
76793
  registerDoctorSubcommand(program2);
76118
76794
  return program2;
76119
76795
  }
76120
- var InteractiveCLI, ai, store, session, commandManager, startupDisplayed, program;
76796
+ var InteractiveCLI, ai, store, commandManager, startupDisplayed, program;
76121
76797
  var init_cli = __esm({
76122
76798
  "src/cli.ts"() {
76123
76799
  init_env_loader();
@@ -76128,6 +76804,7 @@ var init_cli = __esm({
76128
76804
  init_choice_memory();
76129
76805
  init_triage_orchestrator();
76130
76806
  init_handle_slash();
76807
+ init_session_state();
76131
76808
  init_process_handlers();
76132
76809
  init_doctor();
76133
76810
  init_services_loader();
@@ -76135,7 +76812,6 @@ var init_cli = __esm({
76135
76812
  init_interactive_session2();
76136
76813
  init_server();
76137
76814
  init_code_utils();
76138
- session = [];
76139
76815
  commandManager = null;
76140
76816
  startupDisplayed = false;
76141
76817
  if (!process.env.GOOGLE_AUTH_DISABLE_GCE_CHECK) {