@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.
package/dist/cli.cjs CHANGED
@@ -19,12 +19,12 @@ var fs6 = require('fs-extra');
19
19
  var util = require('util');
20
20
  var promises = require('timers/promises');
21
21
  var dns = require('dns/promises');
22
+ var https = require('https');
22
23
  var zod = require('zod');
23
24
  var process6 = require('process');
24
25
  var readline = require('readline');
25
26
  var buffer = require('buffer');
26
27
  var net = require('net');
27
- var https = require('https');
28
28
  var zlib = require('zlib');
29
29
  var yaml = require('js-yaml');
30
30
  var neo4j = require('neo4j-driver');
@@ -66,9 +66,9 @@ var fsp__namespace = /*#__PURE__*/_interopNamespace(fsp);
66
66
  var Stream2__default = /*#__PURE__*/_interopDefault(Stream2);
67
67
  var fs6__namespace = /*#__PURE__*/_interopNamespace(fs6);
68
68
  var dns__default = /*#__PURE__*/_interopDefault(dns);
69
+ var https__default = /*#__PURE__*/_interopDefault(https);
69
70
  var process6__namespace = /*#__PURE__*/_interopNamespace(process6);
70
71
  var readline__namespace = /*#__PURE__*/_interopNamespace(readline);
71
- var https__default = /*#__PURE__*/_interopDefault(https);
72
72
  var zlib__default = /*#__PURE__*/_interopDefault(zlib);
73
73
  var yaml__namespace = /*#__PURE__*/_interopNamespace(yaml);
74
74
  var neo4j__default = /*#__PURE__*/_interopDefault(neo4j);
@@ -1709,7 +1709,7 @@ var init_AuthenticationManager = __esm({
1709
1709
  const response = await fetch(`${this.apiBase}/api/user/profile`, {
1710
1710
  headers: {
1711
1711
  "Authorization": `Bearer ${tokens2.accessToken}`,
1712
- "User-Agent": `maria-cli/${process.env.CLI_VERSION || "4.3.35"}`
1712
+ "User-Agent": `maria-cli/${process.env.CLI_VERSION || "4.3.36"}`
1713
1713
  }
1714
1714
  });
1715
1715
  if (response.status === 401) {
@@ -2390,6 +2390,17 @@ var init_esm_node = __esm({
2390
2390
  init_v4();
2391
2391
  }
2392
2392
  });
2393
+
2394
+ // src/services/cli-auth/api-client.ts
2395
+ var api_client_exports = {};
2396
+ __export(api_client_exports, {
2397
+ ERR: () => ERR,
2398
+ callApi: () => callApi,
2399
+ callApiJson: () => callApiJson,
2400
+ clientThrottle: () => clientThrottle,
2401
+ streamApi: () => streamApi,
2402
+ uploadFile: () => uploadFile
2403
+ });
2393
2404
  function getDeviceId() {
2394
2405
  if (!global.MARIA_DEVICE_ID) {
2395
2406
  global.MARIA_DEVICE_ID = v4_default();
@@ -2399,6 +2410,17 @@ function getDeviceId() {
2399
2410
  function getSessionId() {
2400
2411
  return global.MARIA_SESSION_ID;
2401
2412
  }
2413
+ function clientThrottle(endpoint) {
2414
+ const now2 = Date.now();
2415
+ const lastCall = rateLimitMap.get(endpoint) || 0;
2416
+ const wait = MIN_GAP_MS - (now2 - lastCall);
2417
+ if (wait > 0) {
2418
+ const waitSeconds = Math.ceil(wait / 1e3);
2419
+ console.log(chalk40__default.default.yellow(`\u23F1\uFE0F Rate limit: wait ${waitSeconds}s`));
2420
+ throw { ...ERR.RATE, waitTime: waitSeconds };
2421
+ }
2422
+ rateLimitMap.set(endpoint, now2);
2423
+ }
2402
2424
  async function callApi(path64, init3 = {}) {
2403
2425
  const apiBase = process.env.MARIA_API_BASE || "https://api.maria-code.ai";
2404
2426
  const fullUrl = `${apiBase}${path64}`;
@@ -2412,7 +2434,7 @@ async function callApi(path64, init3 = {}) {
2412
2434
  "Authorization": `Bearer ${token}`,
2413
2435
  "X-Device-Id": getDeviceId(),
2414
2436
  "X-Session-Id": getSessionId() || "",
2415
- "User-Agent": `maria-cli/${process.env.CLI_VERSION || "4.3.35"}`,
2437
+ "User-Agent": `maria-cli/${process.env.CLI_VERSION || "4.3.36"}`,
2416
2438
  "Content-Type": init3.headers?.["Content-Type"] || "application/json"
2417
2439
  });
2418
2440
  const doFetch = async (token) => {
@@ -2480,7 +2502,48 @@ async function callApiJson(path64, init3 = {}) {
2480
2502
  }
2481
2503
  return response.json();
2482
2504
  }
2483
- var ERR;
2505
+ async function* streamApi(path64, init3 = {}) {
2506
+ const response = await callApi(path64, {
2507
+ ...init3,
2508
+ headers: {
2509
+ ...init3.headers,
2510
+ "Accept": "text/event-stream"
2511
+ }
2512
+ });
2513
+ if (!response.ok) {
2514
+ throw new Error(`Stream error: ${response.status}`);
2515
+ }
2516
+ const reader = response.body?.getReader();
2517
+ if (!reader) {
2518
+ throw new Error("No response body");
2519
+ }
2520
+ const decoder = new TextDecoder();
2521
+ try {
2522
+ while (true) {
2523
+ const { done, value } = await reader.read();
2524
+ if (done) break;
2525
+ const chunk = decoder.decode(value, { stream: true });
2526
+ yield chunk;
2527
+ }
2528
+ } finally {
2529
+ reader.releaseLock();
2530
+ }
2531
+ }
2532
+ async function uploadFile(path64, file, metadata5 = {}) {
2533
+ const formData = new FormData();
2534
+ formData.append("file", new Blob([file]));
2535
+ Object.entries(metadata5).forEach(([key, value]) => {
2536
+ formData.append(key, String(value));
2537
+ });
2538
+ return callApiJson(path64, {
2539
+ method: "POST",
2540
+ body: formData,
2541
+ headers: {
2542
+ // Don't set Content-Type, let browser set it with boundary
2543
+ }
2544
+ });
2545
+ }
2546
+ var ERR, rateLimitMap, MIN_GAP_MS;
2484
2547
  var init_api_client = __esm({
2485
2548
  "src/services/cli-auth/api-client.ts"() {
2486
2549
  init_AuthenticationManager();
@@ -2493,6 +2556,8 @@ var init_api_client = __esm({
2493
2556
  NETWORK: { msg: "\u{1F310} Network error, check connection", code: 1 },
2494
2557
  RATE: { msg: "\u23F3 Rate limited, retrying...", code: 1 }
2495
2558
  };
2559
+ rateLimitMap = /* @__PURE__ */ new Map();
2560
+ MIN_GAP_MS = 3e3;
2496
2561
  }
2497
2562
  });
2498
2563
 
@@ -11961,6 +12026,7 @@ var init_clear_command = __esm({
11961
12026
  init_telemetry_helper();
11962
12027
  init_subscription_manager();
11963
12028
  init_terminal();
12029
+ init_chat_context_service();
11964
12030
  ClearCommand = class extends BaseCommand {
11965
12031
  name = "clear";
11966
12032
  category = "conversation";
@@ -11977,34 +12043,46 @@ var init_clear_command = __esm({
11977
12043
  async execute(args2, context2) {
11978
12044
  const startTime = Date.now();
11979
12045
  try {
12046
+ let mode = "session";
12047
+ const idx = Array.isArray(args2.raw) ? args2.raw.indexOf("--mode") : -1;
12048
+ if (idx >= 0) {
12049
+ const val = String(args2.raw[idx + 1] || "").toLowerCase();
12050
+ if (val === "display" || val === "session" || val === "all") mode = val;
12051
+ }
11980
12052
  clearTerminal();
11981
- if (context2.session) {
11982
- if (context2.session.conversationHistory) {
11983
- context2.session.conversationHistory = [];
11984
- }
11985
- if (context2.session.context) {
11986
- context2.session.context = {};
11987
- }
11988
- if (context2.session.messages) {
11989
- context2.session.messages = [];
11990
- }
12053
+ const chat = ChatContextService.getInstance();
12054
+ if (mode === "display") {
12055
+ chat.clearContext({ soft: true });
12056
+ } else {
12057
+ chat.clearContext();
11991
12058
  }
12059
+ const quotaLeft = (() => {
12060
+ const rec = context2;
12061
+ const v = rec && typeof rec["quotaLeft"] === "number" ? rec["quotaLeft"] : 999;
12062
+ return v;
12063
+ })();
11992
12064
  await trackCommand({
11993
12065
  cmd: "clear",
11994
12066
  status: "success",
11995
12067
  latencyMs: Date.now() - startTime,
11996
- plan: getUserPlan(),
11997
- quotaLeft: context2.quotaLeft || 999
12068
+ plan: await getUserPlan(),
12069
+ quotaLeft
11998
12070
  });
11999
- const message = chalk40__default.default.green("\u2705 Cleared") + chalk40__default.default.gray(" \xB7 context reset");
12000
- return this.success(withQuotaFooter(message, context2.quotaLeft));
12071
+ const suffix = mode === "display" ? "display only" : "context reset";
12072
+ const message = chalk40__default.default.green("\u2705 Cleared") + chalk40__default.default.gray(` \xB7 ${suffix}`);
12073
+ return this.success(withQuotaFooter(message, quotaLeft));
12001
12074
  } catch (error2) {
12075
+ const quotaLeft = (() => {
12076
+ const rec = context2;
12077
+ const v = rec && typeof rec["quotaLeft"] === "number" ? rec["quotaLeft"] : 999;
12078
+ return v;
12079
+ })();
12002
12080
  await trackCommand({
12003
12081
  cmd: "clear",
12004
12082
  status: "error",
12005
12083
  latencyMs: Date.now() - startTime,
12006
- plan: getUserPlan(),
12007
- quotaLeft: context2.quotaLeft || 999
12084
+ plan: await getUserPlan(),
12085
+ quotaLeft
12008
12086
  });
12009
12087
  clearTerminal();
12010
12088
  return this.success(chalk40__default.default.green("\u2705 Cleared"));
@@ -12927,44 +13005,6 @@ var init_HelpCommand = __esm({
12927
13005
  * Show help for specific command
12928
13006
  */
12929
13007
  async showCommandHelp(commandName) {
12930
- if (commandName.replace(/^\//, "") === "code") {
12931
- const lines2 = [];
12932
- lines2.push("Usage: /code <request> [flags]");
12933
- lines2.push("");
12934
- lines2.push("Flags:");
12935
- lines2.push(" --plan-only|--sow Show plan only (no writes)");
12936
- lines2.push(" --apply Apply plan (use with --yes for non-interactive)");
12937
- lines2.push(" --dry-run No writes; render output and hints");
12938
- lines2.push(" --interactive Approve interactively (a=all s=skip v=view d=diff q=cancel)");
12939
- lines2.push(" --yes Approve all (including overwrites)");
12940
- lines2.push(" --max-files N Clamp number of files");
12941
- lines2.push(" --root DIR Output root directory");
12942
- lines2.push(" --rollback on|off Rollback on failure (default on)");
12943
- lines2.push(" --output names|summary|detail");
12944
- lines2.push(" --no-code Hide code blocks entirely");
12945
- lines2.push(" --preview-lines N Show head of code in detail mode");
12946
- lines2.push(" --git-guard on|off Check clean git tree before apply (CI default on)");
12947
- lines2.push(" --git-commit on|off Create a single git commit after apply");
12948
- lines2.push(" --git-branch <name> Create/switch branch before committing");
12949
- lines2.push(" --git-tag <name> Create an annotated tag after committing");
12950
- lines2.push(" --git-tag-prefix <pfx> Use standardized tag when --git-tag auto: <pfx><YYYYMMDD>-<shortsha>");
12951
- lines2.push(" --git-push on|off Push commit and tag to remote");
12952
- lines2.push(" --git-push-remote <name> Remote name for push (default origin)");
12953
- lines2.push(" --allow-dotfiles Allow writing dotfiles (default deny)");
12954
- lines2.push(" --confirm-overwrites <globs>");
12955
- lines2.push("");
12956
- lines2.push("Tips:");
12957
- lines2.push(' HINT: Try /code --plan-only "your request" before applying changes');
12958
- lines2.push(" Recipes:");
12959
- lines2.push(' \u2022 Plan only: /code --plan-only "create auth form + API"');
12960
- lines2.push(' \u2022 Apply with limit: /code --apply --yes --max-files 5 "react + test"');
12961
- lines2.push(' \u2022 Interactive: /code --interactive --output detail --preview-lines 20 "routes + guards"');
12962
- lines2.push(" \u2022 Apply + branch + auto tag + push:");
12963
- lines2.push(" /code --apply --yes --git-guard on --git-commit on \\");
12964
- lines2.push(" --git-branch feature/code-plan --git-tag auto --git-tag-prefix code-plan- \\");
12965
- lines2.push(' --git-push on --git-push-remote origin "implement auth + tests"');
12966
- return this.success(lines2.join("\n"));
12967
- }
12968
13008
  const command = await this.readyService.getCommand(commandName);
12969
13009
  if (!command) {
12970
13010
  const searchResults = await this.readyService.searchCommands(commandName, 3);
@@ -16168,8 +16208,8 @@ var require_package = __commonJS({
16168
16208
  "package.json"(exports, module) {
16169
16209
  module.exports = {
16170
16210
  name: "@bonginkan/maria",
16171
- version: "4.3.35",
16172
- 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.",
16211
+ version: "4.3.36",
16212
+ 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.",
16173
16213
  keywords: [
16174
16214
  "ai",
16175
16215
  "cli",
@@ -22263,6 +22303,333 @@ var init_types4 = __esm({
22263
22303
  ];
22264
22304
  }
22265
22305
  });
22306
+
22307
+ // src/services/media-orchestrator/NLInference.ts
22308
+ function clampSize(size) {
22309
+ const clamp = (n) => Math.min(2048, Math.max(256, Math.floor(n)));
22310
+ return [clamp(size[0]), clamp(size[1])];
22311
+ }
22312
+ function parseExplicitSize(text) {
22313
+ const m2 = /(\d{2,4})\s*[x×]\s*(\d{2,4})/i.exec(text);
22314
+ if (m2) {
22315
+ const w = Number(m2[1]);
22316
+ const h2 = Number(m2[2]);
22317
+ if (Number.isFinite(w) && Number.isFinite(h2)) return clampSize([w, h2]);
22318
+ }
22319
+ const p = /(2160|1440|1080|720)\s*p\b/i.exec(text);
22320
+ if (p) {
22321
+ const h2 = Number(p[1]);
22322
+ const map = {
22323
+ 2160: [3840, 2160],
22324
+ 1440: [2560, 1440],
22325
+ 1080: [1920, 1080],
22326
+ 720: [1280, 720]
22327
+ };
22328
+ return clampSize(map[h2]);
22329
+ }
22330
+ return void 0;
22331
+ }
22332
+ function parseAspect(text) {
22333
+ if (/16\s*:\s*9/.test(text)) return "16:9";
22334
+ if (/9\s*:\s*16/.test(text)) return "9:16";
22335
+ if (/1\s*:\s*1/.test(text)) return "1:1";
22336
+ if (/(wide|landscape)/i.test(text)) return "16:9";
22337
+ if (/(tall|portrait)/i.test(text)) return "9:16";
22338
+ if (/(landscape|横長|横向き)/i.test(text)) return "16:9";
22339
+ if (/(portrait|縦長|縦向き)/i.test(text)) return "9:16";
22340
+ if (/(square|正方形|スクエア)/i.test(text)) return "1:1";
22341
+ return void 0;
22342
+ }
22343
+ function deriveSizeFromAspect(aspect, base) {
22344
+ const side = 1024;
22345
+ if (aspect === "1:1") return clampSize([side, side]);
22346
+ if (aspect === "16:9") {
22347
+ const w2 = Math.max(side, 1280);
22348
+ const h3 = Math.round(w2 / 16 * 9);
22349
+ return clampSize([w2, h3]);
22350
+ }
22351
+ const h2 = Math.max(side, 1920);
22352
+ const w = Math.round(h2 / 16 * 9);
22353
+ return clampSize([w, h2]);
22354
+ }
22355
+ function parse4KHints(text, aspect) {
22356
+ if (/(\b4k\b|uhd|超高精細|超高解像度)/i.test(text)) {
22357
+ if (aspect === "1:1" || /square|正方形|スクエア/i.test(text)) return clampSize([2048, 2048]);
22358
+ if (aspect === "9:16" || /(portrait|縦長|縦向き)/i.test(text)) return clampSize([1152, 2048]);
22359
+ return clampSize([2048, 1152]);
22360
+ }
22361
+ if (/(2k|1440p)/i.test(text)) {
22362
+ if (aspect === "1:1") return clampSize([1440, 1440]);
22363
+ if (aspect === "9:16") return clampSize([810, 1440]);
22364
+ return clampSize([1440, 810]);
22365
+ }
22366
+ return void 0;
22367
+ }
22368
+ function parseUseCaseSize(text, aspectHint) {
22369
+ if (/(icon|アイコン)/i.test(text)) return [512, 512];
22370
+ if (/(thumbnail|サムネ)/i.test(text)) return [1280, 720];
22371
+ if (/(instagram\s*story|インスタ\s*ストーリー)/i.test(text)) return [1080, 1920];
22372
+ if (/(instagram\s*post|インスタ\s*投稿)/i.test(text)) return [1080, 1080];
22373
+ if (/(twitter\s*header|x\s*header)/i.test(text)) return [1500, 500];
22374
+ if (/(hd|フルhd)/i.test(text)) return [1920, 1080];
22375
+ if (aspectHint) return deriveSizeFromAspect(aspectHint);
22376
+ if (/(portrait|縦長|縦向き)/i.test(text)) return deriveSizeFromAspect("9:16");
22377
+ if (/(landscape|横長|横向き)/i.test(text)) return deriveSizeFromAspect("16:9");
22378
+ if (/(square|正方形|スクエア)/i.test(text)) return [1024, 1024];
22379
+ return void 0;
22380
+ }
22381
+ function inferFormat(text) {
22382
+ if (/(png|透過|alpha)/i.test(text)) return "png";
22383
+ if (/(webp|ウェブピー)/i.test(text)) return "webp";
22384
+ if (/(jpg|jpeg|写真|photo)/i.test(text)) return "jpg";
22385
+ return void 0;
22386
+ }
22387
+ function inferImageOptionsFromText(text) {
22388
+ const lower2 = text.toLowerCase();
22389
+ const aspect = parseAspect(lower2);
22390
+ const exp = parseExplicitSize(lower2);
22391
+ const k4 = parse4KHints(lower2, aspect);
22392
+ const use = parseUseCaseSize(lower2, aspect);
22393
+ const size = exp || k4 || use;
22394
+ const format = inferFormat(lower2);
22395
+ const out = {};
22396
+ if (size) out.size = size;
22397
+ if (format) out.format = format;
22398
+ return out;
22399
+ }
22400
+ var init_NLInference = __esm({
22401
+ "src/services/media-orchestrator/NLInference.ts"() {
22402
+ }
22403
+ });
22404
+
22405
+ // src/services/cli-auth/api-caller.ts
22406
+ var api_caller_exports = {};
22407
+ __export(api_caller_exports, {
22408
+ RateLimitError: () => RateLimitError2,
22409
+ callAPI: () => callAPI,
22410
+ executeAIProxy: () => executeAIProxy,
22411
+ executeChat: () => executeChat,
22412
+ executeCode: () => executeCode
22413
+ });
22414
+ async function callAPI(endpoint, options = {}) {
22415
+ const tokens2 = await authManager2.getValidTokens();
22416
+ if (!tokens2) {
22417
+ throw new Error("Authentication required. Please run /login first.");
22418
+ }
22419
+ const apiBase = process.env.MARIA_API_BASE || "https://api.maria-code.ai";
22420
+ const url2 = `${apiBase}${endpoint}`;
22421
+ const controller = new AbortController();
22422
+ const defaultMs = 6e5;
22423
+ const envMs = Number(process.env.MARIA_API_TIMEOUT_MS || process.env.MARIA_CODE_TIMEOUT_MS || defaultMs);
22424
+ const timeoutMs = Number.isFinite(envMs) && envMs > 0 ? envMs : defaultMs;
22425
+ const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
22426
+ try {
22427
+ const response = await fetch(url2, {
22428
+ method: options.method || "GET",
22429
+ headers: {
22430
+ "Authorization": `Bearer ${tokens2.accessToken}`,
22431
+ "Content-Type": "application/json",
22432
+ ...options.headers
22433
+ },
22434
+ body: options.body ? JSON.stringify(options.body) : void 0,
22435
+ // Note: fetch in Node doesn't accept 'agent' in our typing here; relying on global agent not necessary
22436
+ signal: controller.signal
22437
+ });
22438
+ clearTimeout(timeoutId);
22439
+ if (!response) {
22440
+ throw new Error("\u{1F310} Network error, check connection");
22441
+ }
22442
+ if (response.status === 401) {
22443
+ throw new Error("Session expired. Please run /login again.");
22444
+ }
22445
+ if (response.status === 402) {
22446
+ const data2 = await response.json().catch(() => ({}));
22447
+ throw new Error(`Quota exceeded: ${typeof data2?.message === "string" ? data2.message : "Please wait or /upgrade"}`);
22448
+ }
22449
+ if (response.status === 403) {
22450
+ const data2 = await response.json().catch(() => ({}));
22451
+ throw new Error(`Not available on Free plan: ${typeof data2?.message === "string" ? data2.message : "Run /upgrade"}`);
22452
+ }
22453
+ if (response.status === 429) {
22454
+ const h2 = response.headers;
22455
+ const ra = h2.get("Retry-After");
22456
+ const reset = h2.get("RateLimit-Reset") || h2.get("X-RateLimit-Reset");
22457
+ let waitSec = 3;
22458
+ if (ra && /^\d+$/.test(ra)) {
22459
+ waitSec = +ra;
22460
+ } else if (ra) {
22461
+ const t2 = Date.parse(ra);
22462
+ if (!isNaN(t2)) waitSec = Math.max(1, Math.ceil((t2 - Date.now()) / 1e3));
22463
+ } else if (reset) {
22464
+ waitSec = Math.max(1, Math.ceil((+reset - Date.now()) / 1e3));
22465
+ }
22466
+ throw new RateLimitError2(`\u23F1 Wait ${waitSec}s`, waitSec);
22467
+ }
22468
+ if (!response.ok) {
22469
+ const data2 = await response.json().catch(() => ({}));
22470
+ const msg = typeof data2?.error === "string" ? data2.error : `Request failed: ${response.statusText}`;
22471
+ throw new Error(msg);
22472
+ }
22473
+ const data = await response.json();
22474
+ return data;
22475
+ } catch (error2) {
22476
+ clearTimeout(timeoutId);
22477
+ const err = error2;
22478
+ if (err && err.name === "AbortError") {
22479
+ throw new Error("\u{1F310} Network error, check connection");
22480
+ }
22481
+ throw err;
22482
+ }
22483
+ }
22484
+ async function executeChat(messages) {
22485
+ const response = await callAPI("/v1/chat", {
22486
+ method: "POST",
22487
+ body: { messages }
22488
+ });
22489
+ return response;
22490
+ }
22491
+ async function executeCode(input3) {
22492
+ const isOptions = typeof input3 === "object";
22493
+ const prompt = isOptions ? input3.prompt : input3;
22494
+ const provider = isOptions ? input3.provider : void 0;
22495
+ const model = isOptions ? input3.model : void 0;
22496
+ const attachments = isOptions ? input3.attachments : void 0;
22497
+ const body = { prompt, taskType: "code" };
22498
+ if (provider) body.provider = provider;
22499
+ if (model) body.model = model;
22500
+ if (attachments && attachments.length > 0) {
22501
+ body.metadata = { attachments };
22502
+ }
22503
+ const response = await callAPI("/v1/ai-proxy", {
22504
+ method: "POST",
22505
+ body
22506
+ });
22507
+ if (response.data?.routedModel) {
22508
+ response.routedModel = response.data.routedModel;
22509
+ }
22510
+ if (response.data?.content) {
22511
+ response.output = response.data.content;
22512
+ }
22513
+ return response;
22514
+ }
22515
+ async function executeAIProxy(provider, model, messages, options) {
22516
+ return callAPI("/v1/ai-proxy", {
22517
+ method: "POST",
22518
+ body: { provider, model, messages, options }
22519
+ });
22520
+ }
22521
+ var authManager2, RateLimitError2;
22522
+ var init_api_caller = __esm({
22523
+ "src/services/cli-auth/api-caller.ts"() {
22524
+ init_AuthenticationManager();
22525
+ new https__default.default.Agent({ keepAlive: true });
22526
+ authManager2 = new AuthenticationManager();
22527
+ RateLimitError2 = class extends Error {
22528
+ constructor(message, retryAfter) {
22529
+ super(message);
22530
+ this.retryAfter = retryAfter;
22531
+ this.name = "RateLimitError";
22532
+ }
22533
+ };
22534
+ }
22535
+ });
22536
+
22537
+ // src/services/media-orchestrator/ImageArgumentInference.ts
22538
+ function extractFirstJson(text) {
22539
+ const fence = /```json\r?\n([\s\S]*?)```/i.exec(text);
22540
+ if (fence) return fence[1];
22541
+ const fencePlain = /```\s*\r?\n([\s\S]*?)```/i.exec(text);
22542
+ if (fencePlain) {
22543
+ try {
22544
+ JSON.parse(fencePlain[1]);
22545
+ return fencePlain[1];
22546
+ } catch {
22547
+ }
22548
+ }
22549
+ const start = text.indexOf("{");
22550
+ const end = text.lastIndexOf("}");
22551
+ if (start >= 0 && end > start) {
22552
+ const cand = text.slice(start, end + 1);
22553
+ try {
22554
+ JSON.parse(cand);
22555
+ return cand;
22556
+ } catch {
22557
+ }
22558
+ }
22559
+ return null;
22560
+ }
22561
+ function clampSize2(size) {
22562
+ const clamp = (n) => Math.min(4096, Math.max(256, Math.floor(n)));
22563
+ return [clamp(size[0]), clamp(size[1])];
22564
+ }
22565
+ function parseSizeAny(x2) {
22566
+ if (typeof x2 === "string") {
22567
+ const m2 = /^\s*(\d{2,4})x(\d{2,4})\s*$/i.exec(x2);
22568
+ if (m2) return clampSize2([Number(m2[1]), Number(m2[2])]);
22569
+ }
22570
+ if (x2 && typeof x2 === "object") {
22571
+ const any = x2;
22572
+ const w = Number(any.width ?? any.w);
22573
+ const h2 = Number(any.height ?? any.h);
22574
+ if (Number.isFinite(w) && Number.isFinite(h2)) return clampSize2([w, h2]);
22575
+ }
22576
+ return void 0;
22577
+ }
22578
+ function sanitizeFormat(fmt) {
22579
+ if (typeof fmt !== "string") return void 0;
22580
+ const f3 = fmt.toLowerCase();
22581
+ const mapped = f3 === "jpeg" ? "jpg" : f3;
22582
+ return ["png", "webp", "jpg"].includes(mapped) ? mapped : void 0;
22583
+ }
22584
+ async function inferImageArgsLLM(promptText) {
22585
+ const system = [
22586
+ "You extract image generation options from user natural language.",
22587
+ 'Return JSON only with keys: { "size"?: "WIDTHxHEIGHT", "format"?: "png|webp|jpg", "count"?: number }.',
22588
+ 'Only include "count" if the user explicitly specifies the number of images (e.g., "2 images"). Otherwise omit (default is 1).',
22589
+ 'Only include "format" if the user explicitly specifies a format (e.g., "png", "webp", "jpg", transparency). Otherwise omit (default is png).',
22590
+ '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".',
22591
+ "If size is not specified or implied, omit it (default is 1024x1024).",
22592
+ "Do NOT include model or keepExif unless the user explicitly specified them; otherwise omit.",
22593
+ "Do not include any explanation text; JSON only."
22594
+ ].join("\n");
22595
+ const user = promptText;
22596
+ const response = await callAPI("/v1/ai-proxy", {
22597
+ method: "POST",
22598
+ body: {
22599
+ prompt: `${system}
22600
+
22601
+ ---
22602
+
22603
+ ${user}`,
22604
+ taskType: "media"
22605
+ }
22606
+ });
22607
+ const raw = (response?.data?.content || response?.output || "").trim();
22608
+ const jsonText = extractFirstJson(raw) || raw;
22609
+ let parsed;
22610
+ try {
22611
+ parsed = JSON.parse(jsonText);
22612
+ } catch {
22613
+ return {};
22614
+ }
22615
+ const out = {};
22616
+ const size = parseSizeAny(parsed?.size);
22617
+ if (size) out.size = size;
22618
+ const fmt = sanitizeFormat(parsed?.format);
22619
+ if (fmt) out.format = fmt;
22620
+ if (Number.isFinite(Number(parsed?.count))) {
22621
+ const n = Math.max(1, Math.min(8, Math.floor(Number(parsed.count))));
22622
+ out.count = n;
22623
+ }
22624
+ if (typeof parsed?.model === "string" && parsed.model.trim()) out.model = String(parsed.model).trim();
22625
+ if (typeof parsed?.keepExif === "boolean") out.keepExif = parsed.keepExif;
22626
+ return out;
22627
+ }
22628
+ var init_ImageArgumentInference = __esm({
22629
+ "src/services/media-orchestrator/ImageArgumentInference.ts"() {
22630
+ init_api_caller();
22631
+ }
22632
+ });
22266
22633
  function parseSize(value) {
22267
22634
  const m2 = /^\s*(\d{2,4})x(\d{2,4})\s*$/i.exec(value || "");
22268
22635
  if (!m2) throw new Error(`invalid size: ${value}`);
@@ -22295,6 +22662,8 @@ function normalizeImageArgs(raw, root) {
22295
22662
  planOnly: false,
22296
22663
  dryRun: false
22297
22664
  };
22665
+ let explicitSize = false;
22666
+ let explicitFormat = false;
22298
22667
  while (args2.length) {
22299
22668
  const x2 = args2.shift();
22300
22669
  if (!x2.startsWith("--")) continue;
@@ -22303,12 +22672,14 @@ function normalizeImageArgs(raw, root) {
22303
22672
  switch (k) {
22304
22673
  case "size":
22305
22674
  out.size = parseSize(String(v));
22675
+ explicitSize = true;
22306
22676
  break;
22307
22677
  case "format": {
22308
22678
  const rawFmt = String(v).toLowerCase();
22309
22679
  const mapped = rawFmt === "jpeg" ? "jpg" : rawFmt;
22310
22680
  if (!["png", "webp", "jpg"].includes(mapped)) throw new Error("invalid format");
22311
22681
  out.format = mapped;
22682
+ explicitFormat = true;
22312
22683
  break;
22313
22684
  }
22314
22685
  case "count": {
@@ -22349,6 +22720,21 @@ function normalizeImageArgs(raw, root) {
22349
22720
  break;
22350
22721
  }
22351
22722
  }
22723
+ try {
22724
+ const inferred = inferImageOptionsFromText(prompt);
22725
+ if (!explicitSize && inferred.size) out.size = inferred.size;
22726
+ if (!explicitFormat && inferred.format) out.format = inferred.format;
22727
+ } catch {
22728
+ }
22729
+ try {
22730
+ if (String(process.env.MARIA_USE_LLM_INFER || "1") === "1" && (!explicitSize || !explicitFormat)) {
22731
+ global.__MARIA_IMAGE_LLM_INFER__ = async () => {
22732
+ const llm = await inferImageArgsLLM(prompt);
22733
+ return llm;
22734
+ };
22735
+ }
22736
+ } catch {
22737
+ }
22352
22738
  const pixels = out.size[0] * out.size[1] * out.count;
22353
22739
  if (pixels > (out.budgetPixels || 0)) throw new Error("budget exceeded");
22354
22740
  if (!out.apply && !out.planOnly && !out.dryRun) {
@@ -22381,7 +22767,8 @@ function normalizeVideoArgs(raw, root) {
22381
22767
  retry: 2,
22382
22768
  apply: false,
22383
22769
  planOnly: false,
22384
- dryRun: false
22770
+ dryRun: false,
22771
+ aspect: "16:9"
22385
22772
  };
22386
22773
  while (args2.length) {
22387
22774
  const x2 = args2.shift();
@@ -22395,9 +22782,43 @@ function normalizeVideoArgs(raw, root) {
22395
22782
  case "fps":
22396
22783
  out.fps = clampInt(v, 1, 60, "fps");
22397
22784
  break;
22398
- case "res":
22399
- out.size = parseSize(String(v));
22785
+ case "size": {
22786
+ const sz = parseSize(String(v));
22787
+ out.size = sz;
22788
+ out.aspect = sz[0] >= sz[1] ? "16:9" : "9:16";
22789
+ break;
22790
+ }
22791
+ case "res": {
22792
+ const sv = String(v).toLowerCase().replace(/p$/, "");
22793
+ if (/^\d+x\d+$/i.test(String(v))) {
22794
+ out.size = parseSize(String(v));
22795
+ out.aspect = out.size[0] >= out.size[1] ? "16:9" : "9:16";
22796
+ } else if (sv === "720") {
22797
+ out.size = out.aspect === "9:16" ? [720, 1280] : [1280, 720];
22798
+ } else if (sv === "1080") {
22799
+ out.size = out.aspect === "9:16" ? [1080, 1920] : [1920, 1080];
22800
+ } else {
22801
+ throw new Error("invalid res (use 720|1080 or WIDTHxHEIGHT)");
22802
+ }
22803
+ break;
22804
+ }
22805
+ case "aspect": {
22806
+ const a = String(v);
22807
+ if (a !== "16:9" && a !== "9:16") throw new Error("invalid aspect (use 16:9|9:16)");
22808
+ out.aspect = a;
22809
+ const [w, h2] = out.size;
22810
+ if (w === 1280 && h2 === 720 || w === 720 && h2 === 1280 || w === 1920 && h2 === 1080 || w === 1080 && h2 === 1920) {
22811
+ if (a === "9:16") {
22812
+ if (h2 === 720) out.size = [720, 1280];
22813
+ else if (h2 === 1080) out.size = [1080, 1920];
22814
+ } else {
22815
+ if (w === 720) out.size = [1280, 720];
22816
+ else if (w === 1080) out.size = [1920, 1080];
22817
+ if (w === 1080 && h2 === 1920) out.size = [1920, 1080];
22818
+ }
22819
+ }
22400
22820
  break;
22821
+ }
22401
22822
  case "format":
22402
22823
  if (!["mp4", "webm"].includes(String(v))) throw new Error("invalid format");
22403
22824
  out.format = v;
@@ -22433,7 +22854,11 @@ function normalizeVideoArgs(raw, root) {
22433
22854
  }
22434
22855
  const caps = chooseCaps("video", out.model);
22435
22856
  if (caps?.maxVideoSize) {
22436
- if (out.size[0] > caps.maxVideoSize[0] || out.size[1] > caps.maxVideoSize[1]) throw new Error("resolution exceeds model capability");
22857
+ const reqMax = Math.max(out.size[0], out.size[1]);
22858
+ const reqMin = Math.min(out.size[0], out.size[1]);
22859
+ const capMax = Math.max(caps.maxVideoSize[0], caps.maxVideoSize[1]);
22860
+ const capMin = Math.min(caps.maxVideoSize[0], caps.maxVideoSize[1]);
22861
+ if (reqMax > capMax || reqMin > capMin) throw new Error("resolution exceeds model capability");
22437
22862
  }
22438
22863
  if (caps?.maxDuration && out.duration > caps.maxDuration) throw new Error("duration exceeds model capability");
22439
22864
  if (caps?.maxFps && out.fps > caps.maxFps) throw new Error("fps exceeds model capability");
@@ -22461,6 +22886,8 @@ function sanitizeOut(outDir, root) {
22461
22886
  var init_Normalizer = __esm({
22462
22887
  "src/services/media-orchestrator/Normalizer.ts"() {
22463
22888
  init_types4();
22889
+ init_NLInference();
22890
+ init_ImageArgumentInference();
22464
22891
  }
22465
22892
  });
22466
22893
  function ensureDirSync(p) {
@@ -23322,6 +23749,19 @@ var init_image_command = __esm({
23322
23749
  const spinner = new ProcessAnimation();
23323
23750
  spinner.start();
23324
23751
  try {
23752
+ try {
23753
+ const hook = global.__MARIA_IMAGE_LLM_INFER__;
23754
+ if (hook) {
23755
+ const llm = await hook();
23756
+ if (llm) {
23757
+ if (llm.size && (!Array.isArray(cli.size) || cli.size.length !== 2)) cli.size = llm.size;
23758
+ if (llm.size && Array.isArray(llm.size)) cli.size = llm.size;
23759
+ if (llm.format) cli.format = llm.format;
23760
+ if (Number.isFinite(Number(llm.count))) cli.count = Math.max(1, Math.min(8, Math.floor(Number(llm.count))));
23761
+ }
23762
+ }
23763
+ } catch {
23764
+ }
23325
23765
  const useRemote = String(process.env.MARIA_USE_REMOTE_MEDIA || "").toLowerCase() === "1" && await authManager.isAuthenticated();
23326
23766
  if (useRemote) {
23327
23767
  try {
@@ -23633,12 +24073,18 @@ async function runVideoPipeline(params2, opts) {
23633
24073
  const { GoogleGenAI } = __require("@google/genai");
23634
24074
  const ai2 = new GoogleGenAI({ apiKey });
23635
24075
  const modelName = params2.model || "veo-3.0-generate-001";
23636
- const aspectRatio = params2.size[0] >= params2.size[1] ? "16:9" : "9:16";
24076
+ const aspectRatio = "16:9";
24077
+ const resolution = Math.max(params2.size[0], params2.size[1]) >= 1920 ? "1080p" : "720p";
23637
24078
  const effectiveDuration = 8;
23638
24079
  let operation = await ai2.models.generateVideos({
23639
24080
  model: modelName,
23640
24081
  prompt: String(params2.prompt),
23641
- config: { aspectRatio, durationSeconds: effectiveDuration, frameRate: params2.fps }
24082
+ config: {
24083
+ aspectRatio,
24084
+ /* resolution: resolution, */
24085
+ durationSeconds: effectiveDuration,
24086
+ frameRate: params2.fps
24087
+ }
23642
24088
  });
23643
24089
  const pollStart = Date.now();
23644
24090
  const maxWaitMs = 6 * 60 * 1e3;
@@ -23790,7 +24236,7 @@ var init_video_command = __esm({
23790
24236
  category = "media";
23791
24237
  description = "Generate videos using Gemini (frames fallback when mux unavailable)";
23792
24238
  aliases = [];
23793
- 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]';
24239
+ 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]';
23794
24240
  examples = [
23795
24241
  { input: '/video "product demo" --duration 8 --fps 24 --res 1280x720 --apply', description: "Generate a short demo video" }
23796
24242
  ];
@@ -23811,11 +24257,15 @@ var init_video_command = __esm({
23811
24257
  const useRemote = String(process.env.MARIA_USE_REMOTE_MEDIA || "").toLowerCase() === "1" && await authManager.isAuthenticated();
23812
24258
  if (useRemote) {
23813
24259
  try {
24260
+ const isPortrait = cli.size[1] > cli.size[0];
24261
+ const maxEdge = Math.max(cli.size[0], cli.size[1]);
24262
+ const discrete = maxEdge >= 1920 ? "1080" : maxEdge >= 1280 ? "720" : void 0;
23814
24263
  const body = {
23815
24264
  prompt: cli.prompt,
23816
24265
  duration: cli.duration,
23817
24266
  fps: cli.fps,
23818
- res: `${cli.size[0]}x${cli.size[1]}`,
24267
+ res: discrete ? discrete : `${cli.size[0]}x${cli.size[1]}`,
24268
+ aspect: isPortrait ? "9:16" : "16:9",
23819
24269
  format: cli.format,
23820
24270
  model: cli.model,
23821
24271
  seed: cli.seed
@@ -25897,7 +26347,7 @@ var init_about_command = __esm({
25897
26347
  async execute(args2, context2) {
25898
26348
  const output3 = [];
25899
26349
  output3.push("");
25900
- output3.push(chalk40__default.default.cyan.bold("\u{1F916} About MARIA v4.3.35"));
26350
+ output3.push(chalk40__default.default.cyan.bold("\u{1F916} About MARIA v4.3.36"));
25901
26351
  output3.push(chalk40__default.default.gray("\u2550".repeat(40)));
25902
26352
  output3.push("");
25903
26353
  output3.push(chalk40__default.default.white.bold("MARIA - Minimal API, Maximum Power"));
@@ -38323,7 +38773,8 @@ function formatPlan(summary, opts) {
38323
38773
  if (opts.requestText && opts.requestText.trim().length > 0) {
38324
38774
  lines.push(opts.requestText.trim(), "");
38325
38775
  }
38326
- lines.push(`Modified Artifacts (${summary.planned} files):`);
38776
+ const headerLabel = opts.planView ? "Planned Artifacts" : "Modified Artifacts";
38777
+ lines.push(`${headerLabel} (${summary.planned} files):`);
38327
38778
  const warnMap = buildPerFileWarnings(summary.files, opts.validated);
38328
38779
  const skippedSet = new Set(opts.validated?.skipped || []);
38329
38780
  for (const f3 of summary.files) {
@@ -38348,18 +38799,20 @@ function formatPlan(summary, opts) {
38348
38799
  lines.push(diff, "");
38349
38800
  }
38350
38801
  }
38351
- const created = summary.files.filter((f3) => f3.action === "create").length;
38352
- const modified = summary.files.filter((f3) => f3.action === "modify").length;
38353
- const skipped = opts.validated?.skipped?.length || 0;
38354
- const okPhrase = created > 0 ? `${created + modified} files created/modified` : `${modified} files modified`;
38355
- lines.push(`OK: ${okPhrase}`);
38356
- if (skipped > 0) lines.push(`WARN: ${skipped} file${skipped > 1 ? "s" : ""} skipped`);
38357
- lines.push("Next steps:");
38358
- if (large) {
38359
- lines.push('- Large output \u2013 previews suppressed. Use --output diff or press "d" in interactive mode');
38802
+ if (!opts.planView) {
38803
+ const created = summary.files.filter((f3) => f3.action === "create").length;
38804
+ const modified = summary.files.filter((f3) => f3.action === "modify").length;
38805
+ const skipped = opts.validated?.skipped?.length || 0;
38806
+ const okPhrase = created > 0 ? `${created + modified} files created/modified` : `${modified} files modified`;
38807
+ lines.push(`OK: ${okPhrase}`);
38808
+ if (skipped > 0) lines.push(`WARN: ${skipped} file${skipped > 1 ? "s" : ""} skipped`);
38809
+ lines.push("Next steps:");
38810
+ if (large) {
38811
+ lines.push('- Large output \u2013 previews suppressed. Use --output diff or press "d" in interactive mode');
38812
+ }
38813
+ lines.push("- If this looks correct, commit the changes");
38814
+ lines.push('- For a full diff: rerun with --output diff or press "d" in interactive mode');
38360
38815
  }
38361
- lines.push("- If this looks correct, commit the changes");
38362
- lines.push('- For a full diff: rerun with --output diff or press "d" in interactive mode');
38363
38816
  return lines.join("\n");
38364
38817
  }
38365
38818
  function okLine(text) {
@@ -38395,9 +38848,10 @@ function formatPlanAsDiff(files, opts) {
38395
38848
  bytesUsed += diffBytes;
38396
38849
  shownFiles++;
38397
38850
  }
38398
- if (files.length > shownFiles) {
38851
+ const totalDiffTargets = files.filter((f3) => f3.action === "modify").length;
38852
+ if (totalDiffTargets > shownFiles) {
38399
38853
  lines.push(`
38400
- [${files.length - shownFiles} more file(s) omitted; re-run with --output diff --diff-lines ${budget.diffLines ?? 200}]`);
38854
+ [${totalDiffTargets - shownFiles} more file(s) omitted; re-run with --output diff --diff-lines ${budget.diffLines ?? 200}]`);
38401
38855
  }
38402
38856
  return lines.join("\n");
38403
38857
  }
@@ -38639,129 +39093,6 @@ var init_InteractiveController = __esm({
38639
39093
  init_OutputFormatter();
38640
39094
  }
38641
39095
  });
38642
-
38643
- // src/services/cli-auth/api-caller.ts
38644
- var api_caller_exports = {};
38645
- __export(api_caller_exports, {
38646
- RateLimitError: () => RateLimitError2,
38647
- callAPI: () => callAPI,
38648
- executeAIProxy: () => executeAIProxy,
38649
- executeChat: () => executeChat,
38650
- executeCode: () => executeCode
38651
- });
38652
- async function callAPI(endpoint, options = {}) {
38653
- const tokens2 = await authManager2.getValidTokens();
38654
- if (!tokens2) {
38655
- throw new Error("Authentication required. Please run /login first.");
38656
- }
38657
- const apiBase = process.env.MARIA_API_BASE || "https://api.maria-code.ai";
38658
- const url2 = `${apiBase}${endpoint}`;
38659
- const controller = new AbortController();
38660
- const defaultMs = 6e5;
38661
- const envMs = Number(process.env.MARIA_API_TIMEOUT_MS || process.env.MARIA_CODE_TIMEOUT_MS || defaultMs);
38662
- const timeoutMs = Number.isFinite(envMs) && envMs > 0 ? envMs : defaultMs;
38663
- const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
38664
- try {
38665
- const response = await fetch(url2, {
38666
- method: options.method || "GET",
38667
- headers: {
38668
- "Authorization": `Bearer ${tokens2.accessToken}`,
38669
- "Content-Type": "application/json",
38670
- ...options.headers
38671
- },
38672
- body: options.body ? JSON.stringify(options.body) : void 0,
38673
- agent,
38674
- // Use keep-alive agent
38675
- signal: controller.signal
38676
- });
38677
- clearTimeout(timeoutId);
38678
- if (!response) {
38679
- throw new Error("\u{1F310} Network error, check connection");
38680
- }
38681
- if (response.status === 401) {
38682
- throw new Error("Session expired. Please run /login again.");
38683
- }
38684
- if (response.status === 402) {
38685
- const data2 = await response.json().catch(() => ({}));
38686
- throw new Error(`Quota exceeded: ${data2.message || "Please wait or /upgrade"}`);
38687
- }
38688
- if (response.status === 403) {
38689
- const data2 = await response.json().catch(() => ({}));
38690
- throw new Error(`Not available on Free plan: ${data2.message || "Run /upgrade"}`);
38691
- }
38692
- if (response.status === 429) {
38693
- const h2 = response.headers;
38694
- const ra = h2.get("Retry-After");
38695
- const reset = h2.get("RateLimit-Reset") || h2.get("X-RateLimit-Reset");
38696
- let waitSec = 3;
38697
- if (ra && /^\d+$/.test(ra)) {
38698
- waitSec = +ra;
38699
- } else if (ra) {
38700
- const t2 = Date.parse(ra);
38701
- if (!isNaN(t2)) waitSec = Math.max(1, Math.ceil((t2 - Date.now()) / 1e3));
38702
- } else if (reset) {
38703
- waitSec = Math.max(1, Math.ceil((+reset - Date.now()) / 1e3));
38704
- }
38705
- throw new RateLimitError2(`\u23F1 Wait ${waitSec}s`, waitSec);
38706
- }
38707
- if (!response.ok) {
38708
- const data2 = await response.json().catch(() => ({}));
38709
- throw new Error(data2.error || `Request failed: ${response.statusText}`);
38710
- }
38711
- const data = await response.json();
38712
- return data;
38713
- } catch (error2) {
38714
- clearTimeout(timeoutId);
38715
- if (error2.name === "AbortError") {
38716
- throw new Error("\u{1F310} Network error, check connection");
38717
- }
38718
- throw error2;
38719
- }
38720
- }
38721
- async function executeChat(messages) {
38722
- const response = await callAPI("/v1/chat", {
38723
- method: "POST",
38724
- body: { messages }
38725
- });
38726
- return response;
38727
- }
38728
- async function executeCode(prompt) {
38729
- const response = await callAPI("/v1/ai-proxy", {
38730
- method: "POST",
38731
- body: {
38732
- prompt,
38733
- taskType: "code"
38734
- }
38735
- });
38736
- if (response.data?.routedModel) {
38737
- response.routedModel = response.data.routedModel;
38738
- }
38739
- if (response.data?.content) {
38740
- response.output = response.data.content;
38741
- }
38742
- return response;
38743
- }
38744
- async function executeAIProxy(provider, model, messages, options) {
38745
- return callAPI("/v1/ai-proxy", {
38746
- method: "POST",
38747
- body: { provider, model, messages, options }
38748
- });
38749
- }
38750
- var agent, authManager2, RateLimitError2;
38751
- var init_api_caller = __esm({
38752
- "src/services/cli-auth/api-caller.ts"() {
38753
- init_AuthenticationManager();
38754
- agent = new https__default.default.Agent({ keepAlive: true });
38755
- authManager2 = new AuthenticationManager();
38756
- RateLimitError2 = class extends Error {
38757
- constructor(message, retryAfter) {
38758
- super(message);
38759
- this.retryAfter = retryAfter;
38760
- this.name = "RateLimitError";
38761
- }
38762
- };
38763
- }
38764
- });
38765
39096
  async function mapAttachmentsToTargets(attached, opts) {
38766
39097
  const warnings = [];
38767
39098
  const mapped = [];
@@ -39209,7 +39540,68 @@ ${requestPreamble}
39209
39540
  ${request}
39210
39541
 
39211
39542
  ${editContext}`;
39212
- const response = await executeCode(enriched);
39543
+ const ctxAttachments = Array.isArray(opts.attachedFiles) && opts.attachedFiles.length > 0 ? opts.attachedFiles.map((f3) => ({
39544
+ name: f3.originalName,
39545
+ path: f3.pathHint,
39546
+ mime: f3.mime || "text/plain",
39547
+ data_base64: f3.content ? Buffer.from(f3.content, "utf8").toString("base64") : void 0
39548
+ })).map((a) => a.data_base64 ? a : { ...a, data_base64: void 0 }) : [];
39549
+ const pathAttachments = [];
39550
+ if (explicitFiles.length > 0) {
39551
+ try {
39552
+ const fs51 = await import('fs/promises');
39553
+ const pathMod = await import('path');
39554
+ for (const rel of explicitFiles) {
39555
+ try {
39556
+ const full = explicitAbsMap[rel] || pathMod.join(opts.root, rel);
39557
+ const stat13 = await fs51.stat(full).catch(() => null);
39558
+ if (!stat13 || !stat13.isFile()) continue;
39559
+ const buf = await fs51.readFile(full);
39560
+ const ext2 = (pathMod.extname(full) || "").toLowerCase();
39561
+ 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";
39562
+ pathAttachments.push({
39563
+ name: pathMod.basename(full),
39564
+ path: full,
39565
+ mime,
39566
+ data_base64: buf.toString("base64")
39567
+ });
39568
+ } catch {
39569
+ }
39570
+ }
39571
+ } catch {
39572
+ }
39573
+ }
39574
+ const hydratedCtx = [];
39575
+ if (ctxAttachments.length > 0) {
39576
+ try {
39577
+ const fs51 = await import('fs/promises');
39578
+ for (const a of ctxAttachments) {
39579
+ if (a.data_base64) {
39580
+ hydratedCtx.push(a);
39581
+ continue;
39582
+ }
39583
+ const p = a.path || "";
39584
+ if (!p) {
39585
+ continue;
39586
+ }
39587
+ try {
39588
+ const stat13 = await fs51.stat(p).catch(() => null);
39589
+ if (!stat13 || !stat13.isFile()) {
39590
+ hydratedCtx.push(a);
39591
+ continue;
39592
+ }
39593
+ const buf = await fs51.readFile(p);
39594
+ hydratedCtx.push({ ...a, data_base64: buf.toString("base64") });
39595
+ } catch {
39596
+ hydratedCtx.push(a);
39597
+ }
39598
+ }
39599
+ } catch {
39600
+ hydratedCtx.push(...ctxAttachments);
39601
+ }
39602
+ }
39603
+ const allAttachments = (hydratedCtx.length ? hydratedCtx : ctxAttachments).concat(pathAttachments);
39604
+ const response = await executeCode(allAttachments.length > 0 ? { prompt: enriched, provider: "google", model: "gemini-2.5-flash", attachments: allAttachments } : enriched);
39213
39605
  const raw = (response.output || response?.data?.content || "").trim();
39214
39606
  if (!raw) {
39215
39607
  return {
@@ -39338,6 +39730,7 @@ ${editContext}`;
39338
39730
  const remainingSkipped = (validated.skipped || []).filter((p) => !skippedPlans.some((sp) => sp.path === p)).map((p) => ({ path: p, kind: "source", action: "skip", description: "" }));
39339
39731
  const displayFiles = validated.files.concat(skippedPlans).concat(remainingSkipped);
39340
39732
  const summary = summarizePlan(displayFiles);
39733
+ const planView = opts.flags.planOnly || opts.flags.dryRun || !opts.flags.apply;
39341
39734
  const lines = [
39342
39735
  formatPlan(summary, {
39343
39736
  mode: outputMode,
@@ -39345,11 +39738,26 @@ ${editContext}`;
39345
39738
  diffBudget: collectDiffBudget(opts.flags),
39346
39739
  root: opts.root,
39347
39740
  requestText: request,
39348
- validated: { warnings: validated.warnings.slice(), skipped: validated.skipped.slice() }
39741
+ validated: { warnings: validated.warnings.slice(), skipped: validated.skipped.slice() },
39742
+ planView
39349
39743
  })
39350
39744
  ];
39351
39745
  if (opts.flags.planOnly || opts.flags.dryRun || !opts.flags.apply) {
39352
- return { plan: normalized, validated, summaryLines: withNotices(lines) };
39746
+ let specMarkdown;
39747
+ try {
39748
+ const prompt = buildSpecPrompt(request, normalized);
39749
+ const { callApiJson: callApiJson4 } = await Promise.resolve().then(() => (init_api_client(), api_client_exports));
39750
+ try {
39751
+ const resp = await callApiJson4("/v1/ai-proxy", { method: "POST", body: JSON.stringify({ prompt, taskType: "chat" }), headers: { "Content-Type": "application/json" } });
39752
+ const content = resp?.data?.content || resp?.content;
39753
+ if (content && typeof content === "string") specMarkdown = content;
39754
+ } catch {
39755
+ }
39756
+ } catch {
39757
+ }
39758
+ const res = { plan: normalized, validated, summaryLines: withNotices(lines) };
39759
+ if (specMarkdown && typeof specMarkdown === "string" && specMarkdown.trim()) res.specMarkdown = specMarkdown;
39760
+ return res;
39353
39761
  }
39354
39762
  if (opts.flags.interactive && !opts.flags.yes && !process.stdin.isTTY) {
39355
39763
  lines.push("", "WARN: Non-TTY interactive request downgraded to plan-only. Re-run with --yes to apply non-interactively.");
@@ -39429,6 +39837,36 @@ ${editContext}`;
39429
39837
  return { plan: normalized, validated, summaryLines: withNotices([errorLine(err)]) };
39430
39838
  }
39431
39839
  }
39840
+ function buildSpecPrompt(request, plan) {
39841
+ const tree = {};
39842
+ for (const f3 of plan) {
39843
+ const dir = f3.path.split("/").slice(0, -1).join("/") || ".";
39844
+ if (!tree[dir]) tree[dir] = [];
39845
+ tree[dir].push(`${f3.action} ${f3.path} ${f3.language ? "(" + f3.language + ")" : ""}`.trim());
39846
+ }
39847
+ const treeLines = [];
39848
+ for (const [dir, items] of Object.entries(tree)) {
39849
+ treeLines.push(`- ${dir}`);
39850
+ for (const it of items) treeLines.push(` - ${it}`);
39851
+ }
39852
+ return [
39853
+ "You are a senior staff engineer. Produce a concise, high-quality Markdown spec for the following code change plan.",
39854
+ "",
39855
+ "Sections:",
39856
+ "- Overview",
39857
+ "- File Tree",
39858
+ "- Per-file Rationale (what/why)",
39859
+ "- Next Steps",
39860
+ "",
39861
+ "Request:",
39862
+ "```",
39863
+ request,
39864
+ "```",
39865
+ "",
39866
+ "Planned files:",
39867
+ treeLines.join("\n")
39868
+ ].join("\n");
39869
+ }
39432
39870
  function normalizePreviewLines(n) {
39433
39871
  return typeof n === "number" && n > 0 ? n : void 0;
39434
39872
  }
@@ -39623,7 +40061,7 @@ function scanSoftIssues(files) {
39623
40061
  return { hasTrailingWhitespace: tw, hasConflictMarkers: cm };
39624
40062
  }
39625
40063
  function parseExplicitFilenames(request) {
39626
- const matches = request.match(/([\w.-]+\.(?:html|css|js|jsx|ts|tsx))/gi);
40064
+ const matches = request.match(/([\w\-./\\:]+\.[A-Za-z0-9]{1,10})/gi);
39627
40065
  if (!matches) return [];
39628
40066
  const seen = /* @__PURE__ */ new Set();
39629
40067
  const out = [];
@@ -39923,6 +40361,7 @@ var LANGUAGE_EXTENSIONS, CodeCommand, codeCommand, metadata3;
39923
40361
  var init_code_command = __esm({
39924
40362
  "src/slash-commands/categories/code/code.command.ts"() {
39925
40363
  init_base_command();
40364
+ init_api_caller();
39926
40365
  init_rate_limit_handler();
39927
40366
  init_animations();
39928
40367
  init_code_utils();
@@ -39944,7 +40383,7 @@ var init_code_command = __esm({
39944
40383
  name = "code";
39945
40384
  category = "implementation";
39946
40385
  description = "Generate code with AI";
39947
- 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]";
40386
+ 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]";
39948
40387
  aliases = ["c"];
39949
40388
  examples = [
39950
40389
  {
@@ -39959,12 +40398,21 @@ var init_code_command = __esm({
39959
40398
  }
39960
40399
  ];
39961
40400
  async execute(commandArgs, context2) {
39962
- const request = commandArgs.raw.join(" ").trim();
40401
+ const request = await this.ensureLanguageDefaults(commandArgs.raw.join(" ").trim());
39963
40402
  if (!request) {
39964
40403
  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.");
39965
40404
  }
39966
40405
  try {
39967
40406
  const opts = this.parseV2Options(commandArgs.raw);
40407
+ if (opts.planOnly) {
40408
+ opts.apply = false;
40409
+ opts.dryRun = false;
40410
+ }
40411
+ if (opts.dryRun) {
40412
+ opts.apply = false;
40413
+ }
40414
+ if (opts.dryRun && !opts.output) opts.output = "detail";
40415
+ if (opts.dryRun && !opts.previewLines) opts.previewLines = 50;
39968
40416
  const root = opts.root || process.cwd();
39969
40417
  const { orchestrate: orchestrate2 } = await Promise.resolve().then(() => (init_Orchestrator(), Orchestrator_exports));
39970
40418
  const attachments = await this.collectAttachedFiles(context2).catch(() => []);
@@ -39974,8 +40422,57 @@ var init_code_command = __esm({
39974
40422
  const spinner = new ProcessAnimation();
39975
40423
  spinner.start();
39976
40424
  try {
39977
- 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 });
39978
- const out = res.summaryLines.join("\n");
40425
+ 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 });
40426
+ if (opts.planOnly) {
40427
+ const fs51 = await import('fs/promises');
40428
+ const path64 = await import('path');
40429
+ const spec = res?.specMarkdown;
40430
+ const lines = Array.isArray(res?.summaryLines) ? res.summaryLines : [];
40431
+ const planItems = [];
40432
+ for (const l of lines) {
40433
+ const s2 = String(l).trim();
40434
+ if (!s2) continue;
40435
+ if (/^Modified Artifacts/i.test(s2)) continue;
40436
+ if (/^OK:/i.test(s2)) continue;
40437
+ if (/^Next steps:/i.test(s2)) continue;
40438
+ const m2 = /^-\s+(create|modify)\s+(.+)$/i.exec(s2);
40439
+ if (m2) {
40440
+ planItems.push(`- [plan] ${m2[1].toLowerCase()} ${m2[2]}`);
40441
+ continue;
40442
+ }
40443
+ planItems.push(`- ${s2}`);
40444
+ }
40445
+ const md = [];
40446
+ if (spec && spec.trim()) {
40447
+ md.push(spec.trim());
40448
+ } else {
40449
+ md.push("# Code Plan");
40450
+ md.push("");
40451
+ md.push("## Request");
40452
+ md.push("");
40453
+ md.push("```");
40454
+ md.push(request);
40455
+ md.push("```");
40456
+ md.push("");
40457
+ md.push("## Proposed Changes");
40458
+ md.push("");
40459
+ if (planItems.length) md.push(...planItems);
40460
+ else md.push("- (no summary available)");
40461
+ }
40462
+ const plansDir = path64.join(root, ".maria", "plans");
40463
+ await fs51.mkdir(plansDir, { recursive: true });
40464
+ const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
40465
+ const fileName = `code-plan-${ts}.md`;
40466
+ const outPath = path64.join(plansDir, fileName);
40467
+ await fs51.writeFile(outPath, md.join("\n") + "\n", "utf8");
40468
+ const rel = path64.relative(root, outPath);
40469
+ return this.success(`Code plan saved: ${rel}`);
40470
+ }
40471
+ const detail = res?.detailLines;
40472
+ if (opts.dryRun && Array.isArray(detail) && detail.length) {
40473
+ return this.success(detail.join("\n"));
40474
+ }
40475
+ const out = Array.isArray(res?.summaryLines) ? res.summaryLines.join("\n") : "";
39979
40476
  return this.success(out);
39980
40477
  } finally {
39981
40478
  try {
@@ -40025,9 +40522,68 @@ ${pretty}`);
40025
40522
  return this.error(parts.join("\n"));
40026
40523
  }
40027
40524
  }
40525
+ // Add default language hints when not specified by the user (LLM-assisted detection)
40526
+ async ensureLanguageDefaults(raw) {
40527
+ try {
40528
+ const system = [
40529
+ "You analyze a user's code-generation request.",
40530
+ "Decide if the user explicitly specified a programming language or framework/tooling (e.g., TypeScript, Python, Rust, Java, React, Vue, Node, etc.).",
40531
+ 'Return ONLY compact JSON with shape {"explicitLanguage": boolean, "language"?: string}.',
40532
+ "Do not add any commentary."
40533
+ ].join("\n");
40534
+ const user = `Request: ${raw}`;
40535
+ const resp = await callAPI("/v1/ai-proxy", {
40536
+ method: "POST",
40537
+ body: {
40538
+ provider: "google",
40539
+ model: "gemini-2.5-flash",
40540
+ taskType: "chat",
40541
+ prompt: `${system}
40542
+
40543
+ ${user}`
40544
+ }
40545
+ });
40546
+ const content = (resp?.data?.content || resp?.content || "").trim();
40547
+ const extractFirstJson3 = (text) => {
40548
+ const fence = /```\s*json\s*\r?\n([\s\S]*?)```/i.exec(text);
40549
+ if (fence) return fence[1];
40550
+ const generic = /```\s*\r?\n([\s\S]*?)```/i.exec(text);
40551
+ if (generic) {
40552
+ try {
40553
+ JSON.parse(generic[1]);
40554
+ return generic[1];
40555
+ } catch {
40556
+ }
40557
+ }
40558
+ const start = text.indexOf("{");
40559
+ const end = text.lastIndexOf("}");
40560
+ if (start >= 0 && end > start) {
40561
+ const cand = text.slice(start, end + 1);
40562
+ try {
40563
+ JSON.parse(cand);
40564
+ return cand;
40565
+ } catch {
40566
+ }
40567
+ }
40568
+ return null;
40569
+ };
40570
+ const jsonText = extractFirstJson3(content) || content;
40571
+ let parsed = {};
40572
+ try {
40573
+ parsed = JSON.parse(jsonText);
40574
+ } catch {
40575
+ 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);
40576
+ }
40577
+ if (parsed && parsed.explicitLanguage) return raw;
40578
+ } catch {
40579
+ }
40580
+ const hint = " (Use TypeScript and React; prefer functional components and node)";
40581
+ return raw + hint;
40582
+ }
40028
40583
  // v2.0 helpers
40029
40584
  parseV2Options(raw) {
40030
- 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 };
40585
+ 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 };
40586
+ const explicit = { apply: false, planOnly: false, dryRun: false };
40031
40587
  const a = raw.slice();
40032
40588
  while (a.length) {
40033
40589
  const x2 = a.shift();
@@ -40037,12 +40593,15 @@ ${pretty}`);
40037
40593
  case "plan-only":
40038
40594
  case "sow":
40039
40595
  opts.planOnly = true;
40596
+ explicit.planOnly = true;
40040
40597
  break;
40041
40598
  case "apply":
40042
40599
  opts.apply = true;
40600
+ explicit.apply = true;
40043
40601
  break;
40044
40602
  case "dry-run":
40045
40603
  opts.dryRun = true;
40604
+ explicit.dryRun = true;
40046
40605
  break;
40047
40606
  case "interactive":
40048
40607
  opts.interactive = true;
@@ -40102,6 +40661,12 @@ ${pretty}`);
40102
40661
  case "diff-hunks":
40103
40662
  opts.diffHunks = Number(v || a.shift());
40104
40663
  break;
40664
+ case "diff-global-max-files":
40665
+ opts.diffGlobalMaxFiles = Number(v || a.shift());
40666
+ break;
40667
+ case "diff-global-max-bytes":
40668
+ opts.diffGlobalMaxBytes = Number(v || a.shift());
40669
+ break;
40105
40670
  case "confirm-overwrites": {
40106
40671
  const list = (v || a.shift() || "").split(",").map((s2) => s2.trim()).filter(Boolean);
40107
40672
  opts.confirmOverwrites = list;
@@ -40135,8 +40700,16 @@ ${pretty}`);
40135
40700
  }
40136
40701
  }
40137
40702
  }
40138
- if (!opts.apply && !opts.planOnly && !opts.dryRun) {
40139
- opts.apply = true;
40703
+ if (explicit.planOnly || explicit.dryRun) {
40704
+ opts.apply = false;
40705
+ }
40706
+ if (explicit.planOnly) {
40707
+ opts.dryRun = false;
40708
+ }
40709
+ if (!explicit.apply && !explicit.planOnly && !explicit.dryRun) {
40710
+ if (!opts.apply && !opts.planOnly && !opts.dryRun) {
40711
+ opts.apply = true;
40712
+ }
40140
40713
  }
40141
40714
  return opts;
40142
40715
  }
@@ -57868,7 +58441,7 @@ ${user}`,
57868
58441
  };
57869
58442
  }
57870
58443
  });
57871
- function extractFirstJson(text) {
58444
+ function extractFirstJson2(text) {
57872
58445
  const fence = /```json\r?\n([\s\S]*?)```/i.exec(text);
57873
58446
  if (fence) return fence[1];
57874
58447
  const start = text.indexOf("{");
@@ -57915,7 +58488,7 @@ ${user}`,
57915
58488
  }
57916
58489
  });
57917
58490
  const raw = (response?.data?.content || response?.output || "").trim();
57918
- const jsonText = extractFirstJson(raw) || raw;
58491
+ const jsonText = extractFirstJson2(raw) || raw;
57919
58492
  let parsed = {};
57920
58493
  try {
57921
58494
  parsed = JSON.parse(jsonText);
@@ -59202,6 +59775,17 @@ var init_slash_commands = __esm({
59202
59775
  init_registry();
59203
59776
  }
59204
59777
  });
59778
+
59779
+ // src/cli/session-state.ts
59780
+ function clearSession() {
59781
+ while (session.length) session.pop();
59782
+ }
59783
+ var session;
59784
+ var init_session_state = __esm({
59785
+ "src/cli/session-state.ts"() {
59786
+ session = [];
59787
+ }
59788
+ });
59205
59789
  async function handleSlash(input3) {
59206
59790
  if (!input3.startsWith("/")) return false;
59207
59791
  const { cmd, args: args2, options, flags } = parseSlash(input3);
@@ -59210,7 +59794,10 @@ async function handleSlash(input3) {
59210
59794
  clearTerminal();
59211
59795
  } catch {
59212
59796
  }
59213
- return true;
59797
+ try {
59798
+ clearSession();
59799
+ } catch {
59800
+ }
59214
59801
  }
59215
59802
  if (cmd === "doctor") {
59216
59803
  console.log(chalk40__default.default.white("Run as subcommand: maria doctor"));
@@ -59262,6 +59849,7 @@ var init_handle_slash = __esm({
59262
59849
  init_slash_commands();
59263
59850
  init_cli_auth();
59264
59851
  init_terminal();
59852
+ init_session_state();
59265
59853
  }
59266
59854
  });
59267
59855
  function formatAnyError(err) {
@@ -61332,7 +61920,7 @@ var init_ai_response_service = __esm({
61332
61920
  */
61333
61921
  async callLLM(prompt, opts = {}) {
61334
61922
  const {
61335
- 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.",
61923
+ 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.",
61336
61924
  model = void 0,
61337
61925
  provider = DEFAULT_PROVIDER2,
61338
61926
  temperature = 0.2,
@@ -61340,14 +61928,63 @@ var init_ai_response_service = __esm({
61340
61928
  } = opts;
61341
61929
  process.env.MARIA_API_BASE || "https://api.maria-code.ai";
61342
61930
  const preferApi = String(process.env.MARIA_USE_API || "1") === "1";
61931
+ let effectiveAttachments = Array.isArray(opts.attachments) ? opts.attachments.slice() : [];
61343
61932
  if (preferApi) {
61344
61933
  try {
61345
61934
  const { callAPI: callAPI2 } = await Promise.resolve().then(() => (init_api_caller(), api_caller_exports));
61935
+ let autoAttachments = [];
61936
+ try {
61937
+ const pathPattern = /(?:^|\s)([\w\-\.\/\\:]+\.[A-Za-z0-9]{1,10})(?:\s|$)/gi;
61938
+ const candidates = /* @__PURE__ */ new Set();
61939
+ let m2;
61940
+ const textToScan = `${prompt}`;
61941
+ while ((m2 = pathPattern.exec(textToScan)) !== null) {
61942
+ const p = (m2[1] || "").trim();
61943
+ if (p) candidates.add(p);
61944
+ }
61945
+ if (candidates.size > 0) {
61946
+ const fs51 = await import('fs/promises');
61947
+ const pathMod = await import('path');
61948
+ const cwd2 = process.cwd();
61949
+ for (const cand of candidates) {
61950
+ try {
61951
+ const normalized = cand.replace(/^"|"$/g, "").replace(/^'|'$/g, "");
61952
+ const abs = pathMod.isAbsolute(normalized) ? normalized : pathMod.join(cwd2, normalized);
61953
+ const st = await fs51.stat(abs).catch(() => null);
61954
+ if (!st || !st.isFile()) continue;
61955
+ const buf = await fs51.readFile(abs);
61956
+ const ext2 = (pathMod.extname(abs) || "").toLowerCase();
61957
+ 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";
61958
+ autoAttachments.push({ name: pathMod.basename(abs), path: abs, mime, data_base64: buf.toString("base64") });
61959
+ } catch {
61960
+ }
61961
+ }
61962
+ }
61963
+ } catch {
61964
+ }
61965
+ if (autoAttachments.length > 0) {
61966
+ const existing = new Set(effectiveAttachments.map((a) => (a.path || a.name || "").toLowerCase()));
61967
+ for (const a of autoAttachments) {
61968
+ const key = (a.path || a.name || "").toLowerCase();
61969
+ if (!existing.has(key)) {
61970
+ effectiveAttachments.push(a);
61971
+ existing.add(key);
61972
+ }
61973
+ }
61974
+ }
61975
+ const inlineSection = "";
61346
61976
  const r2 = await callAPI2("/v1/ai-proxy", {
61347
61977
  method: "POST",
61348
- body: { prompt: `${system}
61978
+ body: {
61979
+ // When attachments are present, force an attachments-capable route (mirror /evaluate)
61980
+ ...effectiveAttachments.length ? { provider: "google", model: "gemini-2.5-flash" } : {},
61981
+ prompt: `${system}
61349
61982
 
61350
- ${prompt}`, taskType: "chat" }
61983
+ ${prompt}${inlineSection}`,
61984
+ taskType: "chat",
61985
+ // mirror /evaluate: include attachments in metadata
61986
+ ...effectiveAttachments.length ? { metadata: { attachments: effectiveAttachments } } : {}
61987
+ }
61351
61988
  });
61352
61989
  const apiContent = r2?.data?.content || r2?.content;
61353
61990
  if (apiContent) return apiContent;
@@ -61360,10 +61997,42 @@ ${prompt}`, taskType: "chat" }
61360
61997
  } catch {
61361
61998
  }
61362
61999
  }
61363
- const res = await this.providerManager.complete({
61364
- prompt: `${system}
62000
+ let fallbackPrompt = `${system}
61365
62001
 
61366
- ${prompt}`,
62002
+ ${prompt}`;
62003
+ try {
62004
+ const attList = effectiveAttachments && effectiveAttachments.length ? effectiveAttachments : [];
62005
+ if (attList.length > 0) {
62006
+ const limitBytes = 128 * 1024;
62007
+ let used = 0;
62008
+ const sections = [];
62009
+ for (const a of attList) {
62010
+ if (!a?.data_base64) continue;
62011
+ try {
62012
+ const buf = Buffer.from(a.data_base64, "base64");
62013
+ const text = /^(application\/pdf)/i.test(String(a.mime || "")) ? "" : buf.toString("utf8");
62014
+ if (!text) continue;
62015
+ const remaining = Math.max(0, limitBytes - used);
62016
+ if (remaining <= 0) break;
62017
+ const slice = text.length > remaining ? text.slice(0, remaining) : text;
62018
+ used += Buffer.byteLength(slice, "utf8");
62019
+ sections.push(`[BEGIN file: ${a.path || a.name || "attachment.txt"}]
62020
+ ${slice}
62021
+ [END]`);
62022
+ } catch {
62023
+ }
62024
+ }
62025
+ if (sections.length > 0) {
62026
+ fallbackPrompt = `${fallbackPrompt}
62027
+
62028
+ [ATTACHMENTS]
62029
+ ${sections.join("\n\n")}`;
62030
+ }
62031
+ }
62032
+ } catch {
62033
+ }
62034
+ const res = await this.providerManager.complete({
62035
+ prompt: fallbackPrompt,
61367
62036
  model,
61368
62037
  temperature,
61369
62038
  maxTokens
@@ -75818,7 +76487,7 @@ async function init2() {
75818
76487
  ai = res.ai;
75819
76488
  res.ctx;
75820
76489
  store = res.store;
75821
- while (session.length) session.pop();
76490
+ clearSession();
75822
76491
  for (const m2 of res.session) session.push(m2);
75823
76492
  await loadServices2();
75824
76493
  }
@@ -75835,6 +76504,9 @@ async function streamAnswer(text, opts = {}) {
75835
76504
  s2 = s2.replace(/\[BEGIN\s+file:[^\]]+\][\s\S]*?\[END\]/g, "");
75836
76505
  return s2;
75837
76506
  };
76507
+ const removeAttachmentSections = (s2) => {
76508
+ return s2.replace(/\[ATTACHMENTS\][\s\S]*$/i, "");
76509
+ };
75838
76510
  const hasAnyCodeBlocks = (s2) => /```[\s\S]*?```|\[BEGIN\s+file:/i.test(s2);
75839
76511
  const envInt = (name2, def) => {
75840
76512
  const v = Number(process.env[name2]);
@@ -75860,10 +76532,11 @@ async function streamAnswer(text, opts = {}) {
75860
76532
  model: process.env.MARIA_MODEL || "gemini-2.5-flash"
75861
76533
  });
75862
76534
  animation.stop();
75863
- const containsCode = hasAnyCodeBlocks(resp || "");
75864
- if (containsCode) {
76535
+ const respForArtifactCheck = removeAttachmentSections(resp || "");
76536
+ const containsCode = hasAnyCodeBlocks(respForArtifactCheck);
76537
+ if (containsCode && opts.triage && opts.triage.type === "route-code") {
75865
76538
  try {
75866
- const artifacts = extractAllCodeInfos(resp);
76539
+ const artifacts = extractAllCodeInfos(respForArtifactCheck);
75867
76540
  const savedFiles = [];
75868
76541
  let okCount = 0, warnCount = 0, errCount = 0;
75869
76542
  for (const { language, code, extension, filename: suggested } of artifacts) {
@@ -75888,7 +76561,7 @@ async function streamAnswer(text, opts = {}) {
75888
76561
  console.log(chalk40__default.default.white(`ERROR: failed ${filepath} (${language}) - ${msg2}`));
75889
76562
  }
75890
76563
  }
75891
- const prose = stripMarkdownForPlainChat(removeCodeBlocks(resp)).trim();
76564
+ const prose = stripMarkdownForPlainChat(removeCodeBlocks(removeAttachmentSections(resp))).trim();
75892
76565
  if (prose) {
75893
76566
  console.log(chalk40__default.default.white(""));
75894
76567
  console.log(chalk40__default.default.white("Chat Response:"));
@@ -75973,7 +76646,10 @@ async function handleLine(line, options = {}) {
75973
76646
  locale: process.env.LANG,
75974
76647
  recentCommands: []
75975
76648
  });
75976
- if (triageResult.next?.route) {
76649
+ if (
76650
+ /*false && for debugging*/
76651
+ triageResult.next?.route
76652
+ ) {
75977
76653
  const commandParts = [
75978
76654
  triageResult.next.route,
75979
76655
  ...triageResult.next.args ?? []
@@ -76175,7 +76851,7 @@ MARIA v${getVersion()}
76175
76851
  registerDoctorSubcommand(program2);
76176
76852
  return program2;
76177
76853
  }
76178
- var InteractiveCLI, ai, store, session, commandManager, startupDisplayed, program;
76854
+ var InteractiveCLI, ai, store, commandManager, startupDisplayed, program;
76179
76855
  var init_cli = __esm({
76180
76856
  "src/cli.ts"() {
76181
76857
  init_env_loader();
@@ -76186,6 +76862,7 @@ var init_cli = __esm({
76186
76862
  init_choice_memory();
76187
76863
  init_triage_orchestrator();
76188
76864
  init_handle_slash();
76865
+ init_session_state();
76189
76866
  init_process_handlers();
76190
76867
  init_doctor();
76191
76868
  init_services_loader();
@@ -76193,7 +76870,6 @@ var init_cli = __esm({
76193
76870
  init_interactive_session();
76194
76871
  init_server();
76195
76872
  init_code_utils();
76196
- session = [];
76197
76873
  commandManager = null;
76198
76874
  startupDisplayed = false;
76199
76875
  if (!process.env.GOOGLE_AUTH_DISABLE_GCE_CHECK) {