@bonginkan/maria 4.3.35 → 4.3.37

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.37",
26070
+ description: "\u{1F680} MARIA v4.3.37 - 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.37"}`
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.37"}`,
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
 
@@ -28958,109 +29023,199 @@ var init_choice_memory = __esm({
28958
29023
  }
28959
29024
  });
28960
29025
 
28961
- // src/services/interactive/triage-orchestrator.ts
28962
- function getConfidenceBand(score) {
28963
- if (score >= TRIAGE_THRESHOLDS.high) {
28964
- return "high";
29026
+ // src/services/cli-auth/api-caller.ts
29027
+ var api_caller_exports = {};
29028
+ __export(api_caller_exports, {
29029
+ RateLimitError: () => RateLimitError,
29030
+ callAPI: () => callAPI,
29031
+ executeAIProxy: () => executeAIProxy,
29032
+ executeChat: () => executeChat,
29033
+ executeCode: () => executeCode
29034
+ });
29035
+ async function callAPI(endpoint, options = {}) {
29036
+ const tokens2 = await authManager2.getValidTokens();
29037
+ if (!tokens2) {
29038
+ throw new Error("Authentication required. Please run /login first.");
28965
29039
  }
28966
- if (score >= TRIAGE_THRESHOLDS.mid) {
28967
- return "mid";
29040
+ const apiBase = process.env.MARIA_API_BASE || "https://api.maria-code.ai";
29041
+ const url2 = `${apiBase}${endpoint}`;
29042
+ const controller = new AbortController();
29043
+ const defaultMs = 6e5;
29044
+ const envMs = Number(process.env.MARIA_API_TIMEOUT_MS || process.env.MARIA_CODE_TIMEOUT_MS || defaultMs);
29045
+ const timeoutMs = Number.isFinite(envMs) && envMs > 0 ? envMs : defaultMs;
29046
+ const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
29047
+ try {
29048
+ const response = await fetch(url2, {
29049
+ method: options.method || "GET",
29050
+ headers: {
29051
+ "Authorization": `Bearer ${tokens2.accessToken}`,
29052
+ "Content-Type": "application/json",
29053
+ ...options.headers
29054
+ },
29055
+ body: options.body ? JSON.stringify(options.body) : void 0,
29056
+ // Note: fetch in Node doesn't accept 'agent' in our typing here; relying on global agent not necessary
29057
+ signal: controller.signal
29058
+ });
29059
+ clearTimeout(timeoutId);
29060
+ if (!response) {
29061
+ throw new Error("\u{1F310} Network error, check connection");
29062
+ }
29063
+ if (response.status === 401) {
29064
+ throw new Error("Session expired. Please run /login again.");
29065
+ }
29066
+ if (response.status === 402) {
29067
+ const data2 = await response.json().catch(() => ({}));
29068
+ throw new Error(`Quota exceeded: ${typeof data2?.message === "string" ? data2.message : "Please wait or /upgrade"}`);
29069
+ }
29070
+ if (response.status === 403) {
29071
+ const data2 = await response.json().catch(() => ({}));
29072
+ throw new Error(`Not available on Free plan: ${typeof data2?.message === "string" ? data2.message : "Run /upgrade"}`);
29073
+ }
29074
+ if (response.status === 429) {
29075
+ const h2 = response.headers;
29076
+ const ra = h2.get("Retry-After");
29077
+ const reset = h2.get("RateLimit-Reset") || h2.get("X-RateLimit-Reset");
29078
+ let waitSec = 3;
29079
+ if (ra && /^\d+$/.test(ra)) {
29080
+ waitSec = +ra;
29081
+ } else if (ra) {
29082
+ const t2 = Date.parse(ra);
29083
+ if (!isNaN(t2)) waitSec = Math.max(1, Math.ceil((t2 - Date.now()) / 1e3));
29084
+ } else if (reset) {
29085
+ waitSec = Math.max(1, Math.ceil((+reset - Date.now()) / 1e3));
29086
+ }
29087
+ throw new RateLimitError(`\u23F1 Wait ${waitSec}s`, waitSec);
29088
+ }
29089
+ if (!response.ok) {
29090
+ const data2 = await response.json().catch(() => ({}));
29091
+ const msg = typeof data2?.error === "string" ? data2.error : `Request failed: ${response.statusText}`;
29092
+ throw new Error(msg);
29093
+ }
29094
+ const data = await response.json();
29095
+ return data;
29096
+ } catch (error2) {
29097
+ clearTimeout(timeoutId);
29098
+ const err = error2;
29099
+ if (err && err.name === "AbortError") {
29100
+ throw new Error("\u{1F310} Network error, check connection");
29101
+ }
29102
+ throw err;
28968
29103
  }
28969
- return "low";
28970
29104
  }
28971
- async function triage(input3, ctx2 = {}) {
28972
- const question = (input3 || "").trim();
28973
- if (!question) {
28974
- return {
28975
- type: "simple",
28976
- confidence: 0.3,
28977
- rationale: ["empty"],
28978
- band: "low"
28979
- };
29105
+ async function executeChat(messages) {
29106
+ const response = await callAPI("/v1/chat", {
29107
+ method: "POST",
29108
+ body: { messages }
29109
+ });
29110
+ return response;
29111
+ }
29112
+ async function executeCode(input3) {
29113
+ const isOptions = typeof input3 === "object";
29114
+ const prompt = isOptions ? input3.prompt : input3;
29115
+ const provider = isOptions ? input3.provider : void 0;
29116
+ const model = isOptions ? input3.model : void 0;
29117
+ const attachments = isOptions ? input3.attachments : void 0;
29118
+ const body = { prompt, taskType: "code" };
29119
+ if (provider) body.provider = provider;
29120
+ if (model) body.model = model;
29121
+ if (attachments && attachments.length > 0) {
29122
+ body.metadata = { attachments };
28980
29123
  }
28981
- const lower2 = question.toLowerCase();
28982
- const rationale = [];
28983
- if (ctx2.recentCommands?.length) {
28984
- const last = ctx2.recentCommands[ctx2.recentCommands.length - 1];
28985
- if (typeof last === "string" && last.startsWith("/code")) {
28986
- rationale.push("recent:/code");
28987
- }
29124
+ const response = await callAPI("/v1/ai-proxy", {
29125
+ method: "POST",
29126
+ body
29127
+ });
29128
+ if (response.data?.routedModel) {
29129
+ response.routedModel = response.data.routedModel;
28988
29130
  }
28989
- if (IMAGE_REGEX.test(lower2)) {
28990
- rationale.push("match:image");
28991
- return {
28992
- type: "route-image",
28993
- confidence: 0.82,
28994
- rationale,
28995
- band: "high",
28996
- next: { route: "/image", args: [question] }
28997
- };
29131
+ if (response.data?.content) {
29132
+ response.output = response.data.content;
28998
29133
  }
28999
- if (VIDEO_REGEX.test(lower2)) {
29000
- rationale.push("match:video");
29001
- return {
29002
- type: "route-video",
29003
- confidence: 0.82,
29004
- rationale,
29005
- band: "high",
29006
- next: { route: "/video", args: [question] }
29134
+ return response;
29135
+ }
29136
+ async function executeAIProxy(provider, model, messages, options) {
29137
+ return callAPI("/v1/ai-proxy", {
29138
+ method: "POST",
29139
+ body: { provider, model, messages, options }
29140
+ });
29141
+ }
29142
+ var authManager2, RateLimitError;
29143
+ var init_api_caller = __esm({
29144
+ "src/services/cli-auth/api-caller.ts"() {
29145
+ init_AuthenticationManager();
29146
+ new https__default.default.Agent({ keepAlive: true });
29147
+ authManager2 = new AuthenticationManager();
29148
+ RateLimitError = class extends Error {
29149
+ constructor(message, retryAfter) {
29150
+ super(message);
29151
+ this.retryAfter = retryAfter;
29152
+ this.name = "RateLimitError";
29153
+ }
29007
29154
  };
29008
29155
  }
29009
- if (CODE_REGEX.test(lower2)) {
29010
- rationale.push("match:code");
29011
- const args2 = normalizeRouteArgs(["--plan-only", question]);
29012
- return {
29013
- type: "route-code",
29014
- confidence: 0.78,
29015
- rationale,
29016
- band: "high",
29017
- next: { route: "/code", args: args2 }
29018
- };
29156
+ });
29157
+
29158
+ // src/services/intelligent-router/LlmTopLevelRouter.ts
29159
+ function extractFirstJson(text) {
29160
+ const fence = /```json\r?\n([\s\S]*?)```/i.exec(text);
29161
+ if (fence) return fence[1];
29162
+ const start = text.indexOf("{");
29163
+ const end = text.lastIndexOf("}");
29164
+ if (start >= 0 && end > start) {
29165
+ const cand = text.slice(start, end + 1);
29166
+ try {
29167
+ JSON.parse(cand);
29168
+ return cand;
29169
+ } catch {
29170
+ }
29019
29171
  }
29020
- if (question.length > 220 || MULTI_SCOPE_REGEX.test(lower2) || /\b(ui|api|backend|database|テスト|設計|要件)\b/.test(lower2)) {
29021
- rationale.push("scope:multi");
29022
- const confidence = question.length > 220 ? 0.72 : 0.6;
29023
- return {
29024
- type: "complex",
29025
- confidence,
29026
- rationale,
29027
- band: getConfidenceBand(confidence)
29028
- };
29172
+ return null;
29173
+ }
29174
+ async function mapInputToTopLevelCommand(input3) {
29175
+ const system = [
29176
+ "You are a router for the MARIA CLI.",
29177
+ "Decide the best command for a single user input.",
29178
+ "Allowed commands: /help, /image, /code, /video, /whoami, /login, /logout, /evaluate, chat.",
29179
+ "Note that /image and /video are for generating them. If a path of a file is provided, you should double think why it's referenced (it may be for coding or chatting or other commands, regarding on the context).",
29180
+ 'Return JSON only with keys: { "command": string, "args"?: string[], "confidence": number }.',
29181
+ "Select chat when the input is a general question or conversation rather than a specific slash command.",
29182
+ "Make sure you set the confidence between 0 and 1.",
29183
+ "Only include args if necessary to pass user content to the command. Do not explain."
29184
+ ].join("\n");
29185
+ const resp = await callAPI("/v1/ai-proxy", {
29186
+ method: "POST",
29187
+ body: {
29188
+ prompt: `${system}
29189
+
29190
+ ---
29191
+
29192
+ ${input3}`,
29193
+ taskType: "routing"
29194
+ }
29195
+ });
29196
+ const raw = (resp?.data?.content || resp?.output || "").trim();
29197
+ const jsonText = extractFirstJson(raw) || raw;
29198
+ let parsed = {};
29199
+ try {
29200
+ parsed = JSON.parse(jsonText);
29201
+ } catch {
29202
+ return null;
29029
29203
  }
29030
- if (question.length <= 140 && QUESTION_REGEX.test(lower2)) {
29031
- rationale.push("short+qa");
29032
- const confidence = question.length < 80 ? 0.72 : 0.62;
29033
- return {
29034
- type: "simple",
29035
- confidence,
29036
- rationale,
29037
- band: getConfidenceBand(confidence)
29038
- };
29204
+ if (!parsed || typeof parsed.command !== "string") return null;
29205
+ const cmd = parsed.command;
29206
+ if (!["/help", "/image", "/code", "/video", "/whoami", "/login", "/logout", "/evaluate", "chat"].includes(cmd)) return null;
29207
+ const out = { command: cmd };
29208
+ if (Array.isArray(parsed.args)) {
29209
+ out.args = parsed.args.filter((a) => typeof a === "string" && a.trim()).map((s2) => s2.trim());
29039
29210
  }
29040
- rationale.push("default:complex");
29041
- const fallbackConfidence = question.length > 80 ? 0.5 : 0.4;
29042
- return {
29043
- type: "complex",
29044
- confidence: fallbackConfidence,
29045
- rationale,
29046
- band: getConfidenceBand(fallbackConfidence)
29047
- };
29048
- }
29049
- function normalizeRouteArgs(args2 = []) {
29050
- return args2.map((arg) => arg.trim()).filter((arg) => arg.length > 0);
29211
+ if (typeof parsed.confidence === "number") {
29212
+ out.confidence = Math.max(0, Math.min(1, parsed.confidence));
29213
+ }
29214
+ return out;
29051
29215
  }
29052
- var TRIAGE_THRESHOLDS, QUESTION_REGEX, CODE_REGEX, IMAGE_REGEX, VIDEO_REGEX, MULTI_SCOPE_REGEX;
29053
- var init_triage_orchestrator = __esm({
29054
- "src/services/interactive/triage-orchestrator.ts"() {
29055
- TRIAGE_THRESHOLDS = Object.freeze({
29056
- high: 0.7,
29057
- mid: 0.35
29058
- });
29059
- QUESTION_REGEX = /(how|what|why|when|どの|どう|なぜ|いつ|とは)\b/i;
29060
- CODE_REGEX = /(create|generate|add|refactor|fix|test|route|build|component|migration|implement|実装|生成|追加|修正)/i;
29061
- IMAGE_REGEX = /(image|画像|svg|png|webp|thumbnail|illustration|アート|描いて)/i;
29062
- VIDEO_REGEX = /(video|動画|mp4|webm|frames|storyboard|アニメーション)/i;
29063
- MULTI_SCOPE_REGEX = /(\band\b|\balso\b|\s+,+\s+)/i;
29216
+ var init_LlmTopLevelRouter = __esm({
29217
+ "src/services/intelligent-router/LlmTopLevelRouter.ts"() {
29218
+ init_api_caller();
29064
29219
  }
29065
29220
  });
29066
29221
 
@@ -29282,7 +29437,7 @@ var init_unknown_command = __esm({
29282
29437
  });
29283
29438
 
29284
29439
  // src/slash-commands/types.ts
29285
- var CommandError, ValidationError, PermissionError, RateLimitError;
29440
+ var CommandError, ValidationError, PermissionError, RateLimitError2;
29286
29441
  var init_types2 = __esm({
29287
29442
  "src/slash-commands/types.ts"() {
29288
29443
  CommandError = class extends Error {
@@ -29308,7 +29463,7 @@ var init_types2 = __esm({
29308
29463
  this.name = "PermissionError";
29309
29464
  }
29310
29465
  };
29311
- RateLimitError = class extends CommandError {
29466
+ RateLimitError2 = class extends CommandError {
29312
29467
  constructor(message, retryAfter) {
29313
29468
  super(message, "RATE_LIMIT_ERROR", 429);
29314
29469
  this.retryAfter = retryAfter;
@@ -36605,8 +36760,7 @@ var init_registry = __esm({
36605
36760
  const { ChatContextService: ChatContextService3 } = await Promise.resolve().then(() => (init_chat_context_service(), chat_context_service_exports));
36606
36761
  const ctxSvc = ChatContextService3.getInstance();
36607
36762
  const usageLine = ctxSvc.getSessionUsageLine();
36608
- const suffix = `
36609
- ${usageLine}`;
36763
+ const suffix = ``;
36610
36764
  result.message = (result.message || "").concat(suffix);
36611
36765
  } catch {
36612
36766
  }
@@ -36670,7 +36824,7 @@ ${usageLine}`;
36670
36824
  }
36671
36825
  }
36672
36826
  } catch (innerError) {
36673
- logger.error(`Failed to load command from ${file}:`, error);
36827
+ logger.error(`Failed to load command from ${file}:`, innerError);
36674
36828
  }
36675
36829
  }
36676
36830
  this.initialized = true;
@@ -36707,8 +36861,8 @@ ${usageLine}`;
36707
36861
  try {
36708
36862
  return await next();
36709
36863
  } catch (innerError) {
36710
- logger.error(`Command ${command.name} failed:`, error);
36711
- throw error;
36864
+ logger.error(`Command ${command.name} failed:`, innerError);
36865
+ throw innerError;
36712
36866
  }
36713
36867
  }
36714
36868
  });
@@ -37645,6 +37799,7 @@ var init_clear_command = __esm({
37645
37799
  init_telemetry_helper();
37646
37800
  init_subscription_manager();
37647
37801
  init_terminal();
37802
+ init_chat_context_service();
37648
37803
  ClearCommand = class extends BaseCommand {
37649
37804
  name = "clear";
37650
37805
  category = "conversation";
@@ -37661,34 +37816,46 @@ var init_clear_command = __esm({
37661
37816
  async execute(args2, context2) {
37662
37817
  const startTime = Date.now();
37663
37818
  try {
37819
+ let mode = "session";
37820
+ const idx = Array.isArray(args2.raw) ? args2.raw.indexOf("--mode") : -1;
37821
+ if (idx >= 0) {
37822
+ const val = String(args2.raw[idx + 1] || "").toLowerCase();
37823
+ if (val === "display" || val === "session" || val === "all") mode = val;
37824
+ }
37664
37825
  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
- }
37826
+ const chat = ChatContextService.getInstance();
37827
+ if (mode === "display") {
37828
+ chat.clearContext({ soft: true });
37829
+ } else {
37830
+ chat.clearContext();
37675
37831
  }
37832
+ const quotaLeft = (() => {
37833
+ const rec = context2;
37834
+ const v = rec && typeof rec["quotaLeft"] === "number" ? rec["quotaLeft"] : 999;
37835
+ return v;
37836
+ })();
37676
37837
  await trackCommand({
37677
37838
  cmd: "clear",
37678
37839
  status: "success",
37679
37840
  latencyMs: Date.now() - startTime,
37680
- plan: getUserPlan(),
37681
- quotaLeft: context2.quotaLeft || 999
37841
+ plan: await getUserPlan(),
37842
+ quotaLeft
37682
37843
  });
37683
- const message = chalk14__default.default.green("\u2705 Cleared") + chalk14__default.default.gray(" \xB7 context reset");
37684
- return this.success(withQuotaFooter(message, context2.quotaLeft));
37844
+ const suffix = mode === "display" ? "display only" : "context reset";
37845
+ const message = chalk14__default.default.green("\u2705 Cleared") + chalk14__default.default.gray(` \xB7 ${suffix}`);
37846
+ return this.success(withQuotaFooter(message, quotaLeft));
37685
37847
  } catch (error2) {
37848
+ const quotaLeft = (() => {
37849
+ const rec = context2;
37850
+ const v = rec && typeof rec["quotaLeft"] === "number" ? rec["quotaLeft"] : 999;
37851
+ return v;
37852
+ })();
37686
37853
  await trackCommand({
37687
37854
  cmd: "clear",
37688
37855
  status: "error",
37689
37856
  latencyMs: Date.now() - startTime,
37690
- plan: getUserPlan(),
37691
- quotaLeft: context2.quotaLeft || 999
37857
+ plan: await getUserPlan(),
37858
+ quotaLeft
37692
37859
  });
37693
37860
  clearTerminal();
37694
37861
  return this.success(chalk14__default.default.green("\u2705 Cleared"));
@@ -37738,7 +37905,7 @@ var init_clear_auto_command = __esm({
37738
37905
  const args2 = mode === "display" ? ["--mode", "display"] : [];
37739
37906
  const res = await commandRegistry2.execute("/clear", args2, context2);
37740
37907
  const line = ctx2.getSessionUsageLine();
37741
- const banner = `Auto clear mode: ${mode} \xB7 ${line}`;
37908
+ const banner = `Auto clear mode: ${mode}`;
37742
37909
  if (res?.success) {
37743
37910
  return this.success(`${banner}
37744
37911
  ${res.message || ""}`.trim());
@@ -38404,6 +38571,69 @@ var init_ReadyCommandsService = __esm({
38404
38571
  }
38405
38572
  });
38406
38573
 
38574
+ // src/services/help/HelpArgumentInference.ts
38575
+ function extractFirstJson2(text) {
38576
+ const fence = /```json\r?\n([\s\S]*?)```/i.exec(text);
38577
+ if (fence) return fence[1];
38578
+ const start = text.indexOf("{");
38579
+ const end = text.lastIndexOf("}");
38580
+ if (start >= 0 && end > start) {
38581
+ const cand = text.slice(start, end + 1);
38582
+ try {
38583
+ JSON.parse(cand);
38584
+ return cand;
38585
+ } catch {
38586
+ }
38587
+ }
38588
+ return null;
38589
+ }
38590
+ async function inferHelpTarget(rawText, allowedCommands) {
38591
+ const allowList = allowedCommands.filter((n) => typeof n === "string" && n.trim()).map((n) => n.trim()).slice(0, 200);
38592
+ const system = [
38593
+ "You decide which help to show for the MARIA CLI.",
38594
+ 'Allowed results: { target: "general" } or { target: "command", commandName: <one of allowed> }.',
38595
+ 'Return JSON only with keys: { "target": "general"|"command", "commandName"?: string, "confidence": number }.',
38596
+ "If the user asks about a specific command (by name or description), select that command. Otherwise choose general.",
38597
+ "Use confidence between 0 and 1. Do not explain."
38598
+ ].join("\n");
38599
+ const user = [
38600
+ "User input:",
38601
+ rawText || "(empty)",
38602
+ "",
38603
+ "Allowed command names:",
38604
+ allowList.join(", ")
38605
+ ].join("\n");
38606
+ const resp = await callAPI("/v1/ai-proxy", {
38607
+ method: "POST",
38608
+ body: {
38609
+ prompt: `${system}
38610
+
38611
+ ---
38612
+
38613
+ ${user}`,
38614
+ taskType: "help"
38615
+ }
38616
+ });
38617
+ const raw = (resp?.data?.content || resp?.output || "").trim();
38618
+ const jsonText = extractFirstJson2(raw) || raw;
38619
+ let parsed = {};
38620
+ try {
38621
+ parsed = JSON.parse(jsonText);
38622
+ } catch {
38623
+ return {};
38624
+ }
38625
+ const out = {};
38626
+ if (parsed.target === "general" || parsed.target === "command") out.target = parsed.target;
38627
+ if (typeof parsed.commandName === "string" && parsed.commandName.trim()) out.commandName = parsed.commandName.trim();
38628
+ if (typeof parsed.confidence === "number") out.confidence = Math.max(0, Math.min(1, parsed.confidence));
38629
+ return out;
38630
+ }
38631
+ var init_HelpArgumentInference = __esm({
38632
+ "src/services/help/HelpArgumentInference.ts"() {
38633
+ init_api_caller();
38634
+ }
38635
+ });
38636
+
38407
38637
  // src/slash-commands/categories/core/handlers/HelpCommand.ts
38408
38638
  var HelpCommand_exports = {};
38409
38639
  __export(HelpCommand_exports, {
@@ -38417,6 +38647,8 @@ var init_HelpCommand = __esm({
38417
38647
  init_ReadyCommandsService();
38418
38648
  init_telemetry_helper();
38419
38649
  init_subscription_manager();
38650
+ init_HelpArgumentInference();
38651
+ init_animations();
38420
38652
  HelpCommand = class extends BaseCommand {
38421
38653
  name = "help";
38422
38654
  category = "core";
@@ -38465,6 +38697,26 @@ var init_HelpCommand = __esm({
38465
38697
  await this.trackSuccess(startTime, context2);
38466
38698
  return result2;
38467
38699
  }
38700
+ const text = (args2.raw || []).join(" ").trim();
38701
+ if (text) {
38702
+ const commandsList = (await this.readyService.getAllReadyCommands()).map((c) => c.name);
38703
+ const spin = new ProcessAnimation();
38704
+ spin.start();
38705
+ try {
38706
+ const inferred = await inferHelpTarget(text, commandsList);
38707
+ const threshold = Number(process.env.MARIA_HELP_CONFIDENCE || "0.7");
38708
+ if (inferred && inferred.target === "command" && inferred.commandName && (inferred.confidence ?? 1) >= threshold) {
38709
+ const result2 = await this.showCommandHelp(inferred.commandName);
38710
+ await this.trackSuccess(startTime, context2);
38711
+ return result2;
38712
+ }
38713
+ } finally {
38714
+ try {
38715
+ spin.stop();
38716
+ } catch {
38717
+ }
38718
+ }
38719
+ }
38468
38720
  if (_positional.length > 0) {
38469
38721
  const commandName = _positional[0];
38470
38722
  if (commandName) {
@@ -38611,44 +38863,6 @@ var init_HelpCommand = __esm({
38611
38863
  * Show help for specific command
38612
38864
  */
38613
38865
  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
38866
  const command = await this.readyService.getCommand(commandName);
38653
38867
  if (!command) {
38654
38868
  const searchResults = await this.readyService.searchCommands(commandName, 3);
@@ -47421,6 +47635,201 @@ var init_types4 = __esm({
47421
47635
  ];
47422
47636
  }
47423
47637
  });
47638
+
47639
+ // src/services/media-orchestrator/NLInference.ts
47640
+ function clampSize(size) {
47641
+ const clamp = (n) => Math.min(2048, Math.max(256, Math.floor(n)));
47642
+ return [clamp(size[0]), clamp(size[1])];
47643
+ }
47644
+ function parseExplicitSize(text) {
47645
+ const m2 = /(\d{2,4})\s*[x×]\s*(\d{2,4})/i.exec(text);
47646
+ if (m2) {
47647
+ const w = Number(m2[1]);
47648
+ const h2 = Number(m2[2]);
47649
+ if (Number.isFinite(w) && Number.isFinite(h2)) return clampSize([w, h2]);
47650
+ }
47651
+ const p = /(2160|1440|1080|720)\s*p\b/i.exec(text);
47652
+ if (p) {
47653
+ const h2 = Number(p[1]);
47654
+ const map = {
47655
+ 2160: [3840, 2160],
47656
+ 1440: [2560, 1440],
47657
+ 1080: [1920, 1080],
47658
+ 720: [1280, 720]
47659
+ };
47660
+ return clampSize(map[h2]);
47661
+ }
47662
+ return void 0;
47663
+ }
47664
+ function parseAspect(text) {
47665
+ if (/16\s*:\s*9/.test(text)) return "16:9";
47666
+ if (/9\s*:\s*16/.test(text)) return "9:16";
47667
+ if (/1\s*:\s*1/.test(text)) return "1:1";
47668
+ if (/(wide|landscape)/i.test(text)) return "16:9";
47669
+ if (/(tall|portrait)/i.test(text)) return "9:16";
47670
+ if (/(landscape|横長|横向き)/i.test(text)) return "16:9";
47671
+ if (/(portrait|縦長|縦向き)/i.test(text)) return "9:16";
47672
+ if (/(square|正方形|スクエア)/i.test(text)) return "1:1";
47673
+ return void 0;
47674
+ }
47675
+ function deriveSizeFromAspect(aspect, base) {
47676
+ const side = 1024;
47677
+ if (aspect === "1:1") return clampSize([side, side]);
47678
+ if (aspect === "16:9") {
47679
+ const w2 = Math.max(side, 1280);
47680
+ const h3 = Math.round(w2 / 16 * 9);
47681
+ return clampSize([w2, h3]);
47682
+ }
47683
+ const h2 = Math.max(side, 1920);
47684
+ const w = Math.round(h2 / 16 * 9);
47685
+ return clampSize([w, h2]);
47686
+ }
47687
+ function parse4KHints(text, aspect) {
47688
+ if (/(\b4k\b|uhd|超高精細|超高解像度)/i.test(text)) {
47689
+ if (aspect === "1:1" || /square|正方形|スクエア/i.test(text)) return clampSize([2048, 2048]);
47690
+ if (aspect === "9:16" || /(portrait|縦長|縦向き)/i.test(text)) return clampSize([1152, 2048]);
47691
+ return clampSize([2048, 1152]);
47692
+ }
47693
+ if (/(2k|1440p)/i.test(text)) {
47694
+ if (aspect === "1:1") return clampSize([1440, 1440]);
47695
+ if (aspect === "9:16") return clampSize([810, 1440]);
47696
+ return clampSize([1440, 810]);
47697
+ }
47698
+ return void 0;
47699
+ }
47700
+ function parseUseCaseSize(text, aspectHint) {
47701
+ if (/(icon|アイコン)/i.test(text)) return [512, 512];
47702
+ if (/(thumbnail|サムネ)/i.test(text)) return [1280, 720];
47703
+ if (/(instagram\s*story|インスタ\s*ストーリー)/i.test(text)) return [1080, 1920];
47704
+ if (/(instagram\s*post|インスタ\s*投稿)/i.test(text)) return [1080, 1080];
47705
+ if (/(twitter\s*header|x\s*header)/i.test(text)) return [1500, 500];
47706
+ if (/(hd|フルhd)/i.test(text)) return [1920, 1080];
47707
+ if (aspectHint) return deriveSizeFromAspect(aspectHint);
47708
+ if (/(portrait|縦長|縦向き)/i.test(text)) return deriveSizeFromAspect("9:16");
47709
+ if (/(landscape|横長|横向き)/i.test(text)) return deriveSizeFromAspect("16:9");
47710
+ if (/(square|正方形|スクエア)/i.test(text)) return [1024, 1024];
47711
+ return void 0;
47712
+ }
47713
+ function inferFormat(text) {
47714
+ if (/(png|透過|alpha)/i.test(text)) return "png";
47715
+ if (/(webp|ウェブピー)/i.test(text)) return "webp";
47716
+ if (/(jpg|jpeg|写真|photo)/i.test(text)) return "jpg";
47717
+ return void 0;
47718
+ }
47719
+ function inferImageOptionsFromText(text) {
47720
+ const lower2 = text.toLowerCase();
47721
+ const aspect = parseAspect(lower2);
47722
+ const exp = parseExplicitSize(lower2);
47723
+ const k4 = parse4KHints(lower2, aspect);
47724
+ const use = parseUseCaseSize(lower2, aspect);
47725
+ const size = exp || k4 || use;
47726
+ const format = inferFormat(lower2);
47727
+ const out = {};
47728
+ if (size) out.size = size;
47729
+ if (format) out.format = format;
47730
+ return out;
47731
+ }
47732
+ var init_NLInference = __esm({
47733
+ "src/services/media-orchestrator/NLInference.ts"() {
47734
+ }
47735
+ });
47736
+
47737
+ // src/services/media-orchestrator/ImageArgumentInference.ts
47738
+ function extractFirstJson3(text) {
47739
+ const fence = /```json\r?\n([\s\S]*?)```/i.exec(text);
47740
+ if (fence) return fence[1];
47741
+ const fencePlain = /```\s*\r?\n([\s\S]*?)```/i.exec(text);
47742
+ if (fencePlain) {
47743
+ try {
47744
+ JSON.parse(fencePlain[1]);
47745
+ return fencePlain[1];
47746
+ } catch {
47747
+ }
47748
+ }
47749
+ const start = text.indexOf("{");
47750
+ const end = text.lastIndexOf("}");
47751
+ if (start >= 0 && end > start) {
47752
+ const cand = text.slice(start, end + 1);
47753
+ try {
47754
+ JSON.parse(cand);
47755
+ return cand;
47756
+ } catch {
47757
+ }
47758
+ }
47759
+ return null;
47760
+ }
47761
+ function clampSize2(size) {
47762
+ const clamp = (n) => Math.min(4096, Math.max(256, Math.floor(n)));
47763
+ return [clamp(size[0]), clamp(size[1])];
47764
+ }
47765
+ function parseSizeAny(x2) {
47766
+ if (typeof x2 === "string") {
47767
+ const m2 = /^\s*(\d{2,4})x(\d{2,4})\s*$/i.exec(x2);
47768
+ if (m2) return clampSize2([Number(m2[1]), Number(m2[2])]);
47769
+ }
47770
+ if (x2 && typeof x2 === "object") {
47771
+ const any = x2;
47772
+ const w = Number(any.width ?? any.w);
47773
+ const h2 = Number(any.height ?? any.h);
47774
+ if (Number.isFinite(w) && Number.isFinite(h2)) return clampSize2([w, h2]);
47775
+ }
47776
+ return void 0;
47777
+ }
47778
+ function sanitizeFormat(fmt) {
47779
+ if (typeof fmt !== "string") return void 0;
47780
+ const f3 = fmt.toLowerCase();
47781
+ const mapped = f3 === "jpeg" ? "jpg" : f3;
47782
+ return ["png", "webp", "jpg"].includes(mapped) ? mapped : void 0;
47783
+ }
47784
+ async function inferImageArgsLLM(promptText) {
47785
+ const system = [
47786
+ "You extract image generation options from user natural language.",
47787
+ 'Return JSON only with keys: { "size"?: "WIDTHxHEIGHT", "format"?: "png|webp|jpg", "count"?: number }.',
47788
+ 'Only include "count" if the user explicitly specifies the number of images (e.g., "2 images"). Otherwise omit (default is 1).',
47789
+ 'Only include "format" if the user explicitly specifies a format (e.g., "png", "webp", "jpg", transparency). Otherwise omit (default is png).',
47790
+ '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".',
47791
+ "If size is not specified or implied, omit it (default is 1024x1024).",
47792
+ "Do NOT include model or keepExif unless the user explicitly specified them; otherwise omit.",
47793
+ "Do not include any explanation text; JSON only."
47794
+ ].join("\n");
47795
+ const user = promptText;
47796
+ const response = await callAPI("/v1/ai-proxy", {
47797
+ method: "POST",
47798
+ body: {
47799
+ prompt: `${system}
47800
+
47801
+ ---
47802
+
47803
+ ${user}`,
47804
+ taskType: "media"
47805
+ }
47806
+ });
47807
+ const raw = (response?.data?.content || response?.output || "").trim();
47808
+ const jsonText = extractFirstJson3(raw) || raw;
47809
+ let parsed;
47810
+ try {
47811
+ parsed = JSON.parse(jsonText);
47812
+ } catch {
47813
+ return {};
47814
+ }
47815
+ const out = {};
47816
+ const size = parseSizeAny(parsed?.size);
47817
+ if (size) out.size = size;
47818
+ const fmt = sanitizeFormat(parsed?.format);
47819
+ if (fmt) out.format = fmt;
47820
+ if (Number.isFinite(Number(parsed?.count))) {
47821
+ const n = Math.max(1, Math.min(8, Math.floor(Number(parsed.count))));
47822
+ out.count = n;
47823
+ }
47824
+ if (typeof parsed?.model === "string" && parsed.model.trim()) out.model = String(parsed.model).trim();
47825
+ if (typeof parsed?.keepExif === "boolean") out.keepExif = parsed.keepExif;
47826
+ return out;
47827
+ }
47828
+ var init_ImageArgumentInference = __esm({
47829
+ "src/services/media-orchestrator/ImageArgumentInference.ts"() {
47830
+ init_api_caller();
47831
+ }
47832
+ });
47424
47833
  function parseSize(value) {
47425
47834
  const m2 = /^\s*(\d{2,4})x(\d{2,4})\s*$/i.exec(value || "");
47426
47835
  if (!m2) throw new Error(`invalid size: ${value}`);
@@ -47453,6 +47862,8 @@ function normalizeImageArgs(raw, root) {
47453
47862
  planOnly: false,
47454
47863
  dryRun: false
47455
47864
  };
47865
+ let explicitSize = false;
47866
+ let explicitFormat = false;
47456
47867
  while (args2.length) {
47457
47868
  const x2 = args2.shift();
47458
47869
  if (!x2.startsWith("--")) continue;
@@ -47461,12 +47872,14 @@ function normalizeImageArgs(raw, root) {
47461
47872
  switch (k) {
47462
47873
  case "size":
47463
47874
  out.size = parseSize(String(v));
47875
+ explicitSize = true;
47464
47876
  break;
47465
47877
  case "format": {
47466
47878
  const rawFmt = String(v).toLowerCase();
47467
47879
  const mapped = rawFmt === "jpeg" ? "jpg" : rawFmt;
47468
47880
  if (!["png", "webp", "jpg"].includes(mapped)) throw new Error("invalid format");
47469
47881
  out.format = mapped;
47882
+ explicitFormat = true;
47470
47883
  break;
47471
47884
  }
47472
47885
  case "count": {
@@ -47507,6 +47920,21 @@ function normalizeImageArgs(raw, root) {
47507
47920
  break;
47508
47921
  }
47509
47922
  }
47923
+ try {
47924
+ const inferred = inferImageOptionsFromText(prompt);
47925
+ if (!explicitSize && inferred.size) out.size = inferred.size;
47926
+ if (!explicitFormat && inferred.format) out.format = inferred.format;
47927
+ } catch {
47928
+ }
47929
+ try {
47930
+ if (String(process.env.MARIA_USE_LLM_INFER || "1") === "1" && (!explicitSize || !explicitFormat)) {
47931
+ global.__MARIA_IMAGE_LLM_INFER__ = async () => {
47932
+ const llm = await inferImageArgsLLM(prompt);
47933
+ return llm;
47934
+ };
47935
+ }
47936
+ } catch {
47937
+ }
47510
47938
  const pixels = out.size[0] * out.size[1] * out.count;
47511
47939
  if (pixels > (out.budgetPixels || 0)) throw new Error("budget exceeded");
47512
47940
  if (!out.apply && !out.planOnly && !out.dryRun) {
@@ -47539,7 +47967,8 @@ function normalizeVideoArgs(raw, root) {
47539
47967
  retry: 2,
47540
47968
  apply: false,
47541
47969
  planOnly: false,
47542
- dryRun: false
47970
+ dryRun: false,
47971
+ aspect: "16:9"
47543
47972
  };
47544
47973
  while (args2.length) {
47545
47974
  const x2 = args2.shift();
@@ -47553,9 +47982,43 @@ function normalizeVideoArgs(raw, root) {
47553
47982
  case "fps":
47554
47983
  out.fps = clampInt(v, 1, 60, "fps");
47555
47984
  break;
47556
- case "res":
47557
- out.size = parseSize(String(v));
47985
+ case "size": {
47986
+ const sz = parseSize(String(v));
47987
+ out.size = sz;
47988
+ out.aspect = sz[0] >= sz[1] ? "16:9" : "9:16";
47558
47989
  break;
47990
+ }
47991
+ case "res": {
47992
+ const sv = String(v).toLowerCase().replace(/p$/, "");
47993
+ if (/^\d+x\d+$/i.test(String(v))) {
47994
+ out.size = parseSize(String(v));
47995
+ out.aspect = out.size[0] >= out.size[1] ? "16:9" : "9:16";
47996
+ } else if (sv === "720") {
47997
+ out.size = out.aspect === "9:16" ? [720, 1280] : [1280, 720];
47998
+ } else if (sv === "1080") {
47999
+ out.size = out.aspect === "9:16" ? [1080, 1920] : [1920, 1080];
48000
+ } else {
48001
+ throw new Error("invalid res (use 720|1080 or WIDTHxHEIGHT)");
48002
+ }
48003
+ break;
48004
+ }
48005
+ case "aspect": {
48006
+ const a = String(v);
48007
+ if (a !== "16:9" && a !== "9:16") throw new Error("invalid aspect (use 16:9|9:16)");
48008
+ out.aspect = a;
48009
+ const [w, h2] = out.size;
48010
+ if (w === 1280 && h2 === 720 || w === 720 && h2 === 1280 || w === 1920 && h2 === 1080 || w === 1080 && h2 === 1920) {
48011
+ if (a === "9:16") {
48012
+ if (h2 === 720) out.size = [720, 1280];
48013
+ else if (h2 === 1080) out.size = [1080, 1920];
48014
+ } else {
48015
+ if (w === 720) out.size = [1280, 720];
48016
+ else if (w === 1080) out.size = [1920, 1080];
48017
+ if (w === 1080 && h2 === 1920) out.size = [1920, 1080];
48018
+ }
48019
+ }
48020
+ break;
48021
+ }
47559
48022
  case "format":
47560
48023
  if (!["mp4", "webm"].includes(String(v))) throw new Error("invalid format");
47561
48024
  out.format = v;
@@ -47591,7 +48054,11 @@ function normalizeVideoArgs(raw, root) {
47591
48054
  }
47592
48055
  const caps = chooseCaps("video", out.model);
47593
48056
  if (caps?.maxVideoSize) {
47594
- if (out.size[0] > caps.maxVideoSize[0] || out.size[1] > caps.maxVideoSize[1]) throw new Error("resolution exceeds model capability");
48057
+ const reqMax = Math.max(out.size[0], out.size[1]);
48058
+ const reqMin = Math.min(out.size[0], out.size[1]);
48059
+ const capMax = Math.max(caps.maxVideoSize[0], caps.maxVideoSize[1]);
48060
+ const capMin = Math.min(caps.maxVideoSize[0], caps.maxVideoSize[1]);
48061
+ if (reqMax > capMax || reqMin > capMin) throw new Error("resolution exceeds model capability");
47595
48062
  }
47596
48063
  if (caps?.maxDuration && out.duration > caps.maxDuration) throw new Error("duration exceeds model capability");
47597
48064
  if (caps?.maxFps && out.fps > caps.maxFps) throw new Error("fps exceeds model capability");
@@ -47619,6 +48086,8 @@ function sanitizeOut(outDir, root) {
47619
48086
  var init_Normalizer = __esm({
47620
48087
  "src/services/media-orchestrator/Normalizer.ts"() {
47621
48088
  init_types4();
48089
+ init_NLInference();
48090
+ init_ImageArgumentInference();
47622
48091
  }
47623
48092
  });
47624
48093
  function ensureDirSync(p) {
@@ -48480,6 +48949,19 @@ var init_image_command = __esm({
48480
48949
  const spinner = new ProcessAnimation();
48481
48950
  spinner.start();
48482
48951
  try {
48952
+ try {
48953
+ const hook = global.__MARIA_IMAGE_LLM_INFER__;
48954
+ if (hook) {
48955
+ const llm = await hook();
48956
+ if (llm) {
48957
+ if (llm.size && (!Array.isArray(cli.size) || cli.size.length !== 2)) cli.size = llm.size;
48958
+ if (llm.size && Array.isArray(llm.size)) cli.size = llm.size;
48959
+ if (llm.format) cli.format = llm.format;
48960
+ if (Number.isFinite(Number(llm.count))) cli.count = Math.max(1, Math.min(8, Math.floor(Number(llm.count))));
48961
+ }
48962
+ }
48963
+ } catch {
48964
+ }
48483
48965
  const useRemote = String(process.env.MARIA_USE_REMOTE_MEDIA || "").toLowerCase() === "1" && await authManager.isAuthenticated();
48484
48966
  if (useRemote) {
48485
48967
  try {
@@ -48791,12 +49273,18 @@ async function runVideoPipeline(params2, opts) {
48791
49273
  const { GoogleGenAI } = __require("@google/genai");
48792
49274
  const ai2 = new GoogleGenAI({ apiKey });
48793
49275
  const modelName = params2.model || "veo-3.0-generate-001";
48794
- const aspectRatio = params2.size[0] >= params2.size[1] ? "16:9" : "9:16";
49276
+ const aspectRatio = "16:9";
49277
+ const resolution = Math.max(params2.size[0], params2.size[1]) >= 1920 ? "1080p" : "720p";
48795
49278
  const effectiveDuration = 8;
48796
49279
  let operation = await ai2.models.generateVideos({
48797
49280
  model: modelName,
48798
49281
  prompt: String(params2.prompt),
48799
- config: { aspectRatio, durationSeconds: effectiveDuration, frameRate: params2.fps }
49282
+ config: {
49283
+ aspectRatio,
49284
+ /* resolution: resolution, */
49285
+ durationSeconds: effectiveDuration,
49286
+ frameRate: params2.fps
49287
+ }
48800
49288
  });
48801
49289
  const pollStart = Date.now();
48802
49290
  const maxWaitMs = 6 * 60 * 1e3;
@@ -48948,7 +49436,7 @@ var init_video_command = __esm({
48948
49436
  category = "media";
48949
49437
  description = "Generate videos using Gemini (frames fallback when mux unavailable)";
48950
49438
  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]';
49439
+ 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
49440
  examples = [
48953
49441
  { input: '/video "product demo" --duration 8 --fps 24 --res 1280x720 --apply', description: "Generate a short demo video" }
48954
49442
  ];
@@ -48969,11 +49457,15 @@ var init_video_command = __esm({
48969
49457
  const useRemote = String(process.env.MARIA_USE_REMOTE_MEDIA || "").toLowerCase() === "1" && await authManager.isAuthenticated();
48970
49458
  if (useRemote) {
48971
49459
  try {
49460
+ const isPortrait = cli.size[1] > cli.size[0];
49461
+ const maxEdge = Math.max(cli.size[0], cli.size[1]);
49462
+ const discrete = maxEdge >= 1920 ? "1080" : maxEdge >= 1280 ? "720" : void 0;
48972
49463
  const body = {
48973
49464
  prompt: cli.prompt,
48974
49465
  duration: cli.duration,
48975
49466
  fps: cli.fps,
48976
- res: `${cli.size[0]}x${cli.size[1]}`,
49467
+ res: discrete ? discrete : `${cli.size[0]}x${cli.size[1]}`,
49468
+ aspect: isPortrait ? "9:16" : "16:9",
48977
49469
  format: cli.format,
48978
49470
  model: cli.model,
48979
49471
  seed: cli.seed
@@ -50769,7 +51261,7 @@ var init_about_command = __esm({
50769
51261
  async execute(args2, context2) {
50770
51262
  const output3 = [];
50771
51263
  output3.push("");
50772
- output3.push(chalk14__default.default.cyan.bold("\u{1F916} About MARIA v4.3.35"));
51264
+ output3.push(chalk14__default.default.cyan.bold("\u{1F916} About MARIA v4.3.37"));
50773
51265
  output3.push(chalk14__default.default.gray("\u2550".repeat(40)));
50774
51266
  output3.push("");
50775
51267
  output3.push(chalk14__default.default.white.bold("MARIA - Minimal API, Maximum Power"));
@@ -54158,6 +54650,62 @@ var init_code_utils = __esm({
54158
54650
  ]);
54159
54651
  }
54160
54652
  });
54653
+
54654
+ // src/services/code-orchestrator/ArgumentInference.ts
54655
+ function extractFirstJson4(text) {
54656
+ const fence = /```json\r?\n([\s\S]*?)```/i.exec(text);
54657
+ if (fence) return fence[1];
54658
+ const start = text.indexOf("{");
54659
+ const end = text.lastIndexOf("}");
54660
+ if (start >= 0 && end > start) {
54661
+ const cand = text.slice(start, end + 1);
54662
+ try {
54663
+ JSON.parse(cand);
54664
+ return cand;
54665
+ } catch {
54666
+ }
54667
+ }
54668
+ return null;
54669
+ }
54670
+ async function inferCodeArgs(rawText) {
54671
+ const system = [
54672
+ "You extract structured options for a code command.",
54673
+ 'Return JSON only with keys: { "planOnly"?: boolean, "dryRun"?: boolean, "output"?: "names"|"summary"|"detail", "previewLines"?: number }.',
54674
+ "Decide from the user text whether planOnly or dryRun should be true. Do not explain.",
54675
+ "Only include output if the user requests preview detail or summary mode. Only include previewLines if a specific number of lines is requested."
54676
+ ].join("\n");
54677
+ const resp = await callAPI("/v1/ai-proxy", {
54678
+ method: "POST",
54679
+ body: {
54680
+ prompt: `${system}
54681
+
54682
+ ---
54683
+
54684
+ ${rawText}`,
54685
+ taskType: "code"
54686
+ }
54687
+ });
54688
+ const raw = (resp?.data?.content || resp?.output || "").trim();
54689
+ const jsonText = extractFirstJson4(raw) || raw;
54690
+ let parsed = {};
54691
+ try {
54692
+ parsed = JSON.parse(jsonText);
54693
+ } catch {
54694
+ return {};
54695
+ }
54696
+ const out = {};
54697
+ if (typeof parsed.planOnly === "boolean") out.planOnly = parsed.planOnly;
54698
+ if (typeof parsed.dryRun === "boolean") out.dryRun = parsed.dryRun;
54699
+ if (typeof parsed.output === "string" && (parsed.output === "names" || parsed.output === "summary" || parsed.output === "detail")) out.output = parsed.output;
54700
+ if (typeof parsed.previewLines === "number" && Number.isFinite(parsed.previewLines) && parsed.previewLines > 0) out.previewLines = Math.min(2e3, Math.floor(parsed.previewLines));
54701
+ if (out.planOnly) out.dryRun = false;
54702
+ return out;
54703
+ }
54704
+ var init_ArgumentInference = __esm({
54705
+ "src/services/code-orchestrator/ArgumentInference.ts"() {
54706
+ init_api_caller();
54707
+ }
54708
+ });
54161
54709
  async function scanRepo(cwd2) {
54162
54710
  if (_cache && _cache.root === cwd2) return _cache;
54163
54711
  const root = cwd2;
@@ -54432,7 +54980,8 @@ function formatPlan(summary, opts) {
54432
54980
  if (opts.requestText && opts.requestText.trim().length > 0) {
54433
54981
  lines.push(opts.requestText.trim(), "");
54434
54982
  }
54435
- lines.push(`Modified Artifacts (${summary.planned} files):`);
54983
+ const headerLabel = opts.planView ? "Planned Artifacts" : "Modified Artifacts";
54984
+ lines.push(`${headerLabel} (${summary.planned} files):`);
54436
54985
  const warnMap = buildPerFileWarnings(summary.files, opts.validated);
54437
54986
  const skippedSet = new Set(opts.validated?.skipped || []);
54438
54987
  for (const f3 of summary.files) {
@@ -54457,18 +55006,20 @@ function formatPlan(summary, opts) {
54457
55006
  lines.push(diff, "");
54458
55007
  }
54459
55008
  }
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');
55009
+ if (!opts.planView) {
55010
+ const created = summary.files.filter((f3) => f3.action === "create").length;
55011
+ const modified = summary.files.filter((f3) => f3.action === "modify").length;
55012
+ const skipped = opts.validated?.skipped?.length || 0;
55013
+ const okPhrase = created > 0 ? `${created + modified} files created/modified` : `${modified} files modified`;
55014
+ lines.push(`OK: ${okPhrase}`);
55015
+ if (skipped > 0) lines.push(`WARN: ${skipped} file${skipped > 1 ? "s" : ""} skipped`);
55016
+ lines.push("Next steps:");
55017
+ if (large) {
55018
+ lines.push('- Large output \u2013 previews suppressed. Use --output diff or press "d" in interactive mode');
55019
+ }
55020
+ lines.push("- If this looks correct, commit the changes");
55021
+ lines.push('- For a full diff: rerun with --output diff or press "d" in interactive mode');
54469
55022
  }
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
55023
  return lines.join("\n");
54473
55024
  }
54474
55025
  function okLine(text) {
@@ -54504,9 +55055,10 @@ function formatPlanAsDiff(files, opts) {
54504
55055
  bytesUsed += diffBytes;
54505
55056
  shownFiles++;
54506
55057
  }
54507
- if (files.length > shownFiles) {
55058
+ const totalDiffTargets = files.filter((f3) => f3.action === "modify").length;
55059
+ if (totalDiffTargets > shownFiles) {
54508
55060
  lines.push(`
54509
- [${files.length - shownFiles} more file(s) omitted; re-run with --output diff --diff-lines ${budget.diffLines ?? 200}]`);
55061
+ [${totalDiffTargets - shownFiles} more file(s) omitted; re-run with --output diff --diff-lines ${budget.diffLines ?? 200}]`);
54510
55062
  }
54511
55063
  return lines.join("\n");
54512
55064
  }
@@ -54748,129 +55300,6 @@ var init_InteractiveController = __esm({
54748
55300
  init_OutputFormatter();
54749
55301
  }
54750
55302
  });
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
55303
  async function mapAttachmentsToTargets(attached, opts) {
54875
55304
  const warnings = [];
54876
55305
  const mapped = [];
@@ -55318,7 +55747,68 @@ ${requestPreamble}
55318
55747
  ${request}
55319
55748
 
55320
55749
  ${editContext}`;
55321
- const response = await executeCode(enriched);
55750
+ const ctxAttachments = Array.isArray(opts.attachedFiles) && opts.attachedFiles.length > 0 ? opts.attachedFiles.map((f3) => ({
55751
+ name: f3.originalName,
55752
+ path: f3.pathHint,
55753
+ mime: f3.mime || "text/plain",
55754
+ data_base64: f3.content ? Buffer.from(f3.content, "utf8").toString("base64") : void 0
55755
+ })).map((a) => a.data_base64 ? a : { ...a, data_base64: void 0 }) : [];
55756
+ const pathAttachments = [];
55757
+ if (explicitFiles.length > 0) {
55758
+ try {
55759
+ const fs51 = await import('fs/promises');
55760
+ const pathMod = await import('path');
55761
+ for (const rel of explicitFiles) {
55762
+ try {
55763
+ const full = explicitAbsMap[rel] || pathMod.join(opts.root, rel);
55764
+ const stat13 = await fs51.stat(full).catch(() => null);
55765
+ if (!stat13 || !stat13.isFile()) continue;
55766
+ const buf = await fs51.readFile(full);
55767
+ const ext2 = (pathMod.extname(full) || "").toLowerCase();
55768
+ 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";
55769
+ pathAttachments.push({
55770
+ name: pathMod.basename(full),
55771
+ path: full,
55772
+ mime,
55773
+ data_base64: buf.toString("base64")
55774
+ });
55775
+ } catch {
55776
+ }
55777
+ }
55778
+ } catch {
55779
+ }
55780
+ }
55781
+ const hydratedCtx = [];
55782
+ if (ctxAttachments.length > 0) {
55783
+ try {
55784
+ const fs51 = await import('fs/promises');
55785
+ for (const a of ctxAttachments) {
55786
+ if (a.data_base64) {
55787
+ hydratedCtx.push(a);
55788
+ continue;
55789
+ }
55790
+ const p = a.path || "";
55791
+ if (!p) {
55792
+ continue;
55793
+ }
55794
+ try {
55795
+ const stat13 = await fs51.stat(p).catch(() => null);
55796
+ if (!stat13 || !stat13.isFile()) {
55797
+ hydratedCtx.push(a);
55798
+ continue;
55799
+ }
55800
+ const buf = await fs51.readFile(p);
55801
+ hydratedCtx.push({ ...a, data_base64: buf.toString("base64") });
55802
+ } catch {
55803
+ hydratedCtx.push(a);
55804
+ }
55805
+ }
55806
+ } catch {
55807
+ hydratedCtx.push(...ctxAttachments);
55808
+ }
55809
+ }
55810
+ const allAttachments = (hydratedCtx.length ? hydratedCtx : ctxAttachments).concat(pathAttachments);
55811
+ const response = await executeCode(allAttachments.length > 0 ? { prompt: enriched, provider: "google", model: "gemini-2.5-flash", attachments: allAttachments } : enriched);
55322
55812
  const raw = (response.output || response?.data?.content || "").trim();
55323
55813
  if (!raw) {
55324
55814
  return {
@@ -55447,6 +55937,7 @@ ${editContext}`;
55447
55937
  const remainingSkipped = (validated.skipped || []).filter((p) => !skippedPlans.some((sp) => sp.path === p)).map((p) => ({ path: p, kind: "source", action: "skip", description: "" }));
55448
55938
  const displayFiles = validated.files.concat(skippedPlans).concat(remainingSkipped);
55449
55939
  const summary = summarizePlan(displayFiles);
55940
+ const planView = opts.flags.planOnly || opts.flags.dryRun || !opts.flags.apply;
55450
55941
  const lines = [
55451
55942
  formatPlan(summary, {
55452
55943
  mode: outputMode,
@@ -55454,11 +55945,26 @@ ${editContext}`;
55454
55945
  diffBudget: collectDiffBudget(opts.flags),
55455
55946
  root: opts.root,
55456
55947
  requestText: request,
55457
- validated: { warnings: validated.warnings.slice(), skipped: validated.skipped.slice() }
55948
+ validated: { warnings: validated.warnings.slice(), skipped: validated.skipped.slice() },
55949
+ planView
55458
55950
  })
55459
55951
  ];
55460
55952
  if (opts.flags.planOnly || opts.flags.dryRun || !opts.flags.apply) {
55461
- return { plan: normalized, validated, summaryLines: withNotices(lines) };
55953
+ let specMarkdown;
55954
+ try {
55955
+ const prompt = buildSpecPrompt(request, normalized);
55956
+ const { callApiJson: callApiJson4 } = await Promise.resolve().then(() => (init_api_client(), api_client_exports));
55957
+ try {
55958
+ const resp = await callApiJson4("/v1/ai-proxy", { method: "POST", body: JSON.stringify({ prompt, taskType: "chat" }), headers: { "Content-Type": "application/json" } });
55959
+ const content = resp?.data?.content || resp?.content;
55960
+ if (content && typeof content === "string") specMarkdown = content;
55961
+ } catch {
55962
+ }
55963
+ } catch {
55964
+ }
55965
+ const res = { plan: normalized, validated, summaryLines: withNotices(lines) };
55966
+ if (specMarkdown && typeof specMarkdown === "string" && specMarkdown.trim()) res.specMarkdown = specMarkdown;
55967
+ return res;
55462
55968
  }
55463
55969
  if (opts.flags.interactive && !opts.flags.yes && !process.stdin.isTTY) {
55464
55970
  lines.push("", "WARN: Non-TTY interactive request downgraded to plan-only. Re-run with --yes to apply non-interactively.");
@@ -55538,6 +56044,36 @@ ${editContext}`;
55538
56044
  return { plan: normalized, validated, summaryLines: withNotices([errorLine(err)]) };
55539
56045
  }
55540
56046
  }
56047
+ function buildSpecPrompt(request, plan) {
56048
+ const tree = {};
56049
+ for (const f3 of plan) {
56050
+ const dir = f3.path.split("/").slice(0, -1).join("/") || ".";
56051
+ if (!tree[dir]) tree[dir] = [];
56052
+ tree[dir].push(`${f3.action} ${f3.path} ${f3.language ? "(" + f3.language + ")" : ""}`.trim());
56053
+ }
56054
+ const treeLines = [];
56055
+ for (const [dir, items] of Object.entries(tree)) {
56056
+ treeLines.push(`- ${dir}`);
56057
+ for (const it of items) treeLines.push(` - ${it}`);
56058
+ }
56059
+ return [
56060
+ "You are a senior staff engineer. Produce a concise, high-quality Markdown spec for the following code change plan.",
56061
+ "",
56062
+ "Sections:",
56063
+ "- Overview",
56064
+ "- File Tree",
56065
+ "- Per-file Rationale (what/why)",
56066
+ "- Next Steps",
56067
+ "",
56068
+ "Request:",
56069
+ "```",
56070
+ request,
56071
+ "```",
56072
+ "",
56073
+ "Planned files:",
56074
+ treeLines.join("\n")
56075
+ ].join("\n");
56076
+ }
55541
56077
  function normalizePreviewLines(n) {
55542
56078
  return typeof n === "number" && n > 0 ? n : void 0;
55543
56079
  }
@@ -55559,7 +56095,7 @@ function mapCodeErrorToReason(err) {
55559
56095
  const error2 = err;
55560
56096
  const message = typeof error2?.message === "string" ? error2.message.toLowerCase() : "";
55561
56097
  const code = typeof error2?.code === "string" ? error2.code.toLowerCase() : "";
55562
- if (error2 instanceof RateLimitError2 || message.includes("rate") && message.includes("limit")) {
56098
+ if (error2 instanceof RateLimitError || message.includes("rate") && message.includes("limit")) {
55563
56099
  return "rate-limit";
55564
56100
  }
55565
56101
  if (message.includes("timeout") || code === "etimedout") {
@@ -55732,7 +56268,7 @@ function scanSoftIssues(files) {
55732
56268
  return { hasTrailingWhitespace: tw, hasConflictMarkers: cm };
55733
56269
  }
55734
56270
  function parseExplicitFilenames(request) {
55735
- const matches = request.match(/([\w.-]+\.(?:html|css|js|jsx|ts|tsx))/gi);
56271
+ const matches = request.match(/([\w\-./\\:]+\.[A-Za-z0-9]{1,10})/gi);
55736
56272
  if (!matches) return [];
55737
56273
  const seen = /* @__PURE__ */ new Set();
55738
56274
  const out = [];
@@ -56032,9 +56568,11 @@ var LANGUAGE_EXTENSIONS, CodeCommand, codeCommand, metadata3;
56032
56568
  var init_code_command = __esm({
56033
56569
  "src/slash-commands/categories/code/code.command.ts"() {
56034
56570
  init_base_command();
56571
+ init_api_caller();
56035
56572
  init_rate_limit_handler();
56036
56573
  init_animations();
56037
56574
  init_code_utils();
56575
+ init_ArgumentInference();
56038
56576
  LANGUAGE_EXTENSIONS = {
56039
56577
  javascript: ".js",
56040
56578
  typescript: ".ts",
@@ -56053,7 +56591,7 @@ var init_code_command = __esm({
56053
56591
  name = "code";
56054
56592
  category = "implementation";
56055
56593
  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]";
56594
+ 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
56595
  aliases = ["c"];
56058
56596
  examples = [
56059
56597
  {
@@ -56068,12 +56606,50 @@ var init_code_command = __esm({
56068
56606
  }
56069
56607
  ];
56070
56608
  async execute(commandArgs, context2) {
56071
- const request = commandArgs.raw.join(" ").trim();
56609
+ const request = await this.ensureLanguageDefaults(commandArgs.raw.join(" ").trim());
56072
56610
  if (!request) {
56073
56611
  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
56612
  }
56075
56613
  try {
56076
56614
  const opts = this.parseV2Options(commandArgs.raw);
56615
+ try {
56616
+ const rawText = commandArgs.raw.join(" ");
56617
+ const explicitPlan = commandArgs.raw.includes("--plan-only") || commandArgs.raw.includes("--sow");
56618
+ const explicitDry = commandArgs.raw.includes("--dry-run");
56619
+ const explicitOutput = commandArgs.raw.some((x2) => x2.startsWith("--output") || x2 === "--verbose" || x2 === "-v");
56620
+ const explicitPreview = commandArgs.raw.some((x2) => x2.startsWith("--preview-lines"));
56621
+ const preSpin = new ProcessAnimation();
56622
+ preSpin.start();
56623
+ let inferred = {};
56624
+ try {
56625
+ inferred = await inferCodeArgs(rawText);
56626
+ } finally {
56627
+ try {
56628
+ preSpin.stop();
56629
+ } catch {
56630
+ }
56631
+ }
56632
+ if (!explicitPlan && !explicitDry) {
56633
+ if (typeof inferred.planOnly === "boolean") opts.planOnly = inferred.planOnly;
56634
+ if (typeof inferred.dryRun === "boolean") opts.dryRun = inferred.dryRun;
56635
+ }
56636
+ if (!explicitOutput && inferred.output) {
56637
+ opts.output = inferred.output;
56638
+ }
56639
+ if (!explicitPreview && typeof inferred.previewLines === "number") {
56640
+ opts.previewLines = inferred.previewLines;
56641
+ }
56642
+ } catch {
56643
+ }
56644
+ if (opts.planOnly) {
56645
+ opts.apply = false;
56646
+ opts.dryRun = false;
56647
+ }
56648
+ if (opts.dryRun) {
56649
+ opts.apply = false;
56650
+ }
56651
+ if (opts.dryRun && !opts.output) opts.output = "detail";
56652
+ if (opts.dryRun && !opts.previewLines) opts.previewLines = 50;
56077
56653
  const root = opts.root || process.cwd();
56078
56654
  const { orchestrate: orchestrate2 } = await Promise.resolve().then(() => (init_Orchestrator(), Orchestrator_exports));
56079
56655
  const attachments = await this.collectAttachedFiles(context2).catch(() => []);
@@ -56083,8 +56659,57 @@ var init_code_command = __esm({
56083
56659
  const spinner = new ProcessAnimation();
56084
56660
  spinner.start();
56085
56661
  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");
56662
+ 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 });
56663
+ if (opts.planOnly) {
56664
+ const fs51 = await import('fs/promises');
56665
+ const path64 = await import('path');
56666
+ const spec = res?.specMarkdown;
56667
+ const lines = Array.isArray(res?.summaryLines) ? res.summaryLines : [];
56668
+ const planItems = [];
56669
+ for (const l of lines) {
56670
+ const s2 = String(l).trim();
56671
+ if (!s2) continue;
56672
+ if (/^Modified Artifacts/i.test(s2)) continue;
56673
+ if (/^OK:/i.test(s2)) continue;
56674
+ if (/^Next steps:/i.test(s2)) continue;
56675
+ const m2 = /^-\s+(create|modify)\s+(.+)$/i.exec(s2);
56676
+ if (m2) {
56677
+ planItems.push(`- [plan] ${m2[1].toLowerCase()} ${m2[2]}`);
56678
+ continue;
56679
+ }
56680
+ planItems.push(`- ${s2}`);
56681
+ }
56682
+ const md = [];
56683
+ if (spec && spec.trim()) {
56684
+ md.push(spec.trim());
56685
+ } else {
56686
+ md.push("# Code Plan");
56687
+ md.push("");
56688
+ md.push("## Request");
56689
+ md.push("");
56690
+ md.push("```");
56691
+ md.push(request);
56692
+ md.push("```");
56693
+ md.push("");
56694
+ md.push("## Proposed Changes");
56695
+ md.push("");
56696
+ if (planItems.length) md.push(...planItems);
56697
+ else md.push("- (no summary available)");
56698
+ }
56699
+ const plansDir = path64.join(root, ".maria", "plans");
56700
+ await fs51.mkdir(plansDir, { recursive: true });
56701
+ const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
56702
+ const fileName = `code-plan-${ts}.md`;
56703
+ const outPath = path64.join(plansDir, fileName);
56704
+ await fs51.writeFile(outPath, md.join("\n") + "\n", "utf8");
56705
+ const rel = path64.relative(root, outPath);
56706
+ return this.success(`Code plan saved: ${rel}`);
56707
+ }
56708
+ const detail = res?.detailLines;
56709
+ if (opts.dryRun && Array.isArray(detail) && detail.length) {
56710
+ return this.success(detail.join("\n"));
56711
+ }
56712
+ const out = Array.isArray(res?.summaryLines) ? res.summaryLines.join("\n") : "";
56088
56713
  return this.success(out);
56089
56714
  } finally {
56090
56715
  try {
@@ -56134,9 +56759,68 @@ ${pretty}`);
56134
56759
  return this.error(parts.join("\n"));
56135
56760
  }
56136
56761
  }
56762
+ // Add default language hints when not specified by the user (LLM-assisted detection)
56763
+ async ensureLanguageDefaults(raw) {
56764
+ try {
56765
+ const system = [
56766
+ "You analyze a user's code-generation request.",
56767
+ "Decide if the user explicitly specified a programming language or framework/tooling (e.g., TypeScript, Python, Rust, Java, React, Vue, Node, etc.).",
56768
+ 'Return ONLY compact JSON with shape {"explicitLanguage": boolean, "language"?: string}.',
56769
+ "Do not add any commentary."
56770
+ ].join("\n");
56771
+ const user = `Request: ${raw}`;
56772
+ const resp = await callAPI("/v1/ai-proxy", {
56773
+ method: "POST",
56774
+ body: {
56775
+ provider: "google",
56776
+ model: "gemini-2.5-flash",
56777
+ taskType: "chat",
56778
+ prompt: `${system}
56779
+
56780
+ ${user}`
56781
+ }
56782
+ });
56783
+ const content = (resp?.data?.content || resp?.content || "").trim();
56784
+ const extractFirstJson6 = (text) => {
56785
+ const fence = /```\s*json\s*\r?\n([\s\S]*?)```/i.exec(text);
56786
+ if (fence) return fence[1];
56787
+ const generic = /```\s*\r?\n([\s\S]*?)```/i.exec(text);
56788
+ if (generic) {
56789
+ try {
56790
+ JSON.parse(generic[1]);
56791
+ return generic[1];
56792
+ } catch {
56793
+ }
56794
+ }
56795
+ const start = text.indexOf("{");
56796
+ const end = text.lastIndexOf("}");
56797
+ if (start >= 0 && end > start) {
56798
+ const cand = text.slice(start, end + 1);
56799
+ try {
56800
+ JSON.parse(cand);
56801
+ return cand;
56802
+ } catch {
56803
+ }
56804
+ }
56805
+ return null;
56806
+ };
56807
+ const jsonText = extractFirstJson6(content) || content;
56808
+ let parsed = {};
56809
+ try {
56810
+ parsed = JSON.parse(jsonText);
56811
+ } catch {
56812
+ 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);
56813
+ }
56814
+ if (parsed && parsed.explicitLanguage) return raw;
56815
+ } catch {
56816
+ }
56817
+ const hint = " (Use TypeScript and React; prefer functional components and node)";
56818
+ return raw + hint;
56819
+ }
56137
56820
  // v2.0 helpers
56138
56821
  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 };
56822
+ 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 };
56823
+ const explicit = { apply: false, planOnly: false, dryRun: false };
56140
56824
  const a = raw.slice();
56141
56825
  while (a.length) {
56142
56826
  const x2 = a.shift();
@@ -56146,12 +56830,15 @@ ${pretty}`);
56146
56830
  case "plan-only":
56147
56831
  case "sow":
56148
56832
  opts.planOnly = true;
56833
+ explicit.planOnly = true;
56149
56834
  break;
56150
56835
  case "apply":
56151
56836
  opts.apply = true;
56837
+ explicit.apply = true;
56152
56838
  break;
56153
56839
  case "dry-run":
56154
56840
  opts.dryRun = true;
56841
+ explicit.dryRun = true;
56155
56842
  break;
56156
56843
  case "interactive":
56157
56844
  opts.interactive = true;
@@ -56211,6 +56898,12 @@ ${pretty}`);
56211
56898
  case "diff-hunks":
56212
56899
  opts.diffHunks = Number(v || a.shift());
56213
56900
  break;
56901
+ case "diff-global-max-files":
56902
+ opts.diffGlobalMaxFiles = Number(v || a.shift());
56903
+ break;
56904
+ case "diff-global-max-bytes":
56905
+ opts.diffGlobalMaxBytes = Number(v || a.shift());
56906
+ break;
56214
56907
  case "confirm-overwrites": {
56215
56908
  const list = (v || a.shift() || "").split(",").map((s2) => s2.trim()).filter(Boolean);
56216
56909
  opts.confirmOverwrites = list;
@@ -56244,8 +56937,16 @@ ${pretty}`);
56244
56937
  }
56245
56938
  }
56246
56939
  }
56247
- if (!opts.apply && !opts.planOnly && !opts.dryRun) {
56248
- opts.apply = true;
56940
+ if (explicit.planOnly || explicit.dryRun) {
56941
+ opts.apply = false;
56942
+ }
56943
+ if (explicit.planOnly) {
56944
+ opts.dryRun = false;
56945
+ }
56946
+ if (!explicit.apply && !explicit.planOnly && !explicit.dryRun) {
56947
+ if (!opts.apply && !opts.planOnly && !opts.dryRun) {
56948
+ opts.apply = true;
56949
+ }
56249
56950
  }
56250
56951
  return opts;
56251
56952
  }
@@ -71083,7 +71784,7 @@ ${user}`,
71083
71784
  };
71084
71785
  }
71085
71786
  });
71086
- function extractFirstJson(text) {
71787
+ function extractFirstJson5(text) {
71087
71788
  const fence = /```json\r?\n([\s\S]*?)```/i.exec(text);
71088
71789
  if (fence) return fence[1];
71089
71790
  const start = text.indexOf("{");
@@ -71130,7 +71831,7 @@ ${user}`,
71130
71831
  }
71131
71832
  });
71132
71833
  const raw = (response?.data?.content || response?.output || "").trim();
71133
- const jsonText = extractFirstJson(raw) || raw;
71834
+ const jsonText = extractFirstJson5(raw) || raw;
71134
71835
  let parsed = {};
71135
71836
  try {
71136
71837
  parsed = JSON.parse(jsonText);
@@ -71151,7 +71852,7 @@ ${user}`,
71151
71852
  }
71152
71853
  return out;
71153
71854
  }
71154
- var init_ArgumentInference = __esm({
71855
+ var init_ArgumentInference2 = __esm({
71155
71856
  "src/services/evaluation/ArgumentInference.ts"() {
71156
71857
  init_api_caller();
71157
71858
  }
@@ -71172,7 +71873,7 @@ var init_evaluate_command = __esm({
71172
71873
  init_EvaluationOrchestrator();
71173
71874
  init_api_caller();
71174
71875
  init_animations();
71175
- init_ArgumentInference();
71876
+ init_ArgumentInference2();
71176
71877
  EvaluateCommand = class extends BaseCommand {
71177
71878
  name = "evaluate";
71178
71879
  category = "evaluation";
@@ -71855,7 +72556,7 @@ __export(slash_commands_exports, {
71855
72556
  MemoryStatusCommand: () => MemoryStatusCommand,
71856
72557
  PermissionError: () => PermissionError,
71857
72558
  PlanCommand: () => PlanCommand,
71858
- RateLimitError: () => RateLimitError,
72559
+ RateLimitError: () => RateLimitError2,
71859
72560
  RateLimitMiddleware: () => RateLimitMiddleware,
71860
72561
  RecallCommand: () => RecallCommand,
71861
72562
  RememberCommand: () => RememberCommand,
@@ -72417,6 +73118,17 @@ var init_slash_commands = __esm({
72417
73118
  init_registry();
72418
73119
  }
72419
73120
  });
73121
+
73122
+ // src/cli/session-state.ts
73123
+ function clearSession() {
73124
+ while (session.length) session.pop();
73125
+ }
73126
+ var session;
73127
+ var init_session_state = __esm({
73128
+ "src/cli/session-state.ts"() {
73129
+ session = [];
73130
+ }
73131
+ });
72420
73132
  async function handleSlash(input3) {
72421
73133
  if (!input3.startsWith("/")) return false;
72422
73134
  const { cmd, args: args2, options, flags } = parseSlash(input3);
@@ -72425,7 +73137,10 @@ async function handleSlash(input3) {
72425
73137
  clearTerminal();
72426
73138
  } catch {
72427
73139
  }
72428
- return true;
73140
+ try {
73141
+ clearSession();
73142
+ } catch {
73143
+ }
72429
73144
  }
72430
73145
  if (cmd === "doctor") {
72431
73146
  console.log(chalk14__default.default.white("Run as subcommand: maria doctor"));
@@ -72477,6 +73192,7 @@ var init_handle_slash = __esm({
72477
73192
  init_slash_commands();
72478
73193
  init_cli_auth();
72479
73194
  init_terminal();
73195
+ init_session_state();
72480
73196
  }
72481
73197
  });
72482
73198
  function formatAnyError(err) {
@@ -74484,7 +75200,7 @@ var init_ai_response_service = __esm({
74484
75200
  */
74485
75201
  async callLLM(prompt, opts = {}) {
74486
75202
  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.",
75203
+ 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
75204
  model = void 0,
74489
75205
  provider = DEFAULT_PROVIDER2,
74490
75206
  temperature = 0.2,
@@ -74492,14 +75208,63 @@ var init_ai_response_service = __esm({
74492
75208
  } = opts;
74493
75209
  process.env.MARIA_API_BASE || "https://api.maria-code.ai";
74494
75210
  const preferApi = String(process.env.MARIA_USE_API || "1") === "1";
75211
+ let effectiveAttachments = Array.isArray(opts.attachments) ? opts.attachments.slice() : [];
74495
75212
  if (preferApi) {
74496
75213
  try {
74497
75214
  const { callAPI: callAPI2 } = await Promise.resolve().then(() => (init_api_caller(), api_caller_exports));
75215
+ let autoAttachments = [];
75216
+ try {
75217
+ const pathPattern = /(?:^|\s)([\w\-\.\/\\:]+\.[A-Za-z0-9]{1,10})(?:\s|$)/gi;
75218
+ const candidates = /* @__PURE__ */ new Set();
75219
+ let m2;
75220
+ const textToScan = `${prompt}`;
75221
+ while ((m2 = pathPattern.exec(textToScan)) !== null) {
75222
+ const p = (m2[1] || "").trim();
75223
+ if (p) candidates.add(p);
75224
+ }
75225
+ if (candidates.size > 0) {
75226
+ const fs51 = await import('fs/promises');
75227
+ const pathMod = await import('path');
75228
+ const cwd2 = process.cwd();
75229
+ for (const cand of candidates) {
75230
+ try {
75231
+ const normalized = cand.replace(/^"|"$/g, "").replace(/^'|'$/g, "");
75232
+ const abs = pathMod.isAbsolute(normalized) ? normalized : pathMod.join(cwd2, normalized);
75233
+ const st = await fs51.stat(abs).catch(() => null);
75234
+ if (!st || !st.isFile()) continue;
75235
+ const buf = await fs51.readFile(abs);
75236
+ const ext2 = (pathMod.extname(abs) || "").toLowerCase();
75237
+ 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";
75238
+ autoAttachments.push({ name: pathMod.basename(abs), path: abs, mime, data_base64: buf.toString("base64") });
75239
+ } catch {
75240
+ }
75241
+ }
75242
+ }
75243
+ } catch {
75244
+ }
75245
+ if (autoAttachments.length > 0) {
75246
+ const existing = new Set(effectiveAttachments.map((a) => (a.path || a.name || "").toLowerCase()));
75247
+ for (const a of autoAttachments) {
75248
+ const key = (a.path || a.name || "").toLowerCase();
75249
+ if (!existing.has(key)) {
75250
+ effectiveAttachments.push(a);
75251
+ existing.add(key);
75252
+ }
75253
+ }
75254
+ }
75255
+ const inlineSection = "";
74498
75256
  const r2 = await callAPI2("/v1/ai-proxy", {
74499
75257
  method: "POST",
74500
- body: { prompt: `${system}
75258
+ body: {
75259
+ // When attachments are present, force an attachments-capable route (mirror /evaluate)
75260
+ ...effectiveAttachments.length ? { provider: "google", model: "gemini-2.5-flash" } : {},
75261
+ prompt: `${system}
74501
75262
 
74502
- ${prompt}`, taskType: "chat" }
75263
+ ${prompt}${inlineSection}`,
75264
+ taskType: "chat",
75265
+ // mirror /evaluate: include attachments in metadata
75266
+ ...effectiveAttachments.length ? { metadata: { attachments: effectiveAttachments } } : {}
75267
+ }
74503
75268
  });
74504
75269
  const apiContent = r2?.data?.content || r2?.content;
74505
75270
  if (apiContent) return apiContent;
@@ -74512,10 +75277,42 @@ ${prompt}`, taskType: "chat" }
74512
75277
  } catch {
74513
75278
  }
74514
75279
  }
74515
- const res = await this.providerManager.complete({
74516
- prompt: `${system}
75280
+ let fallbackPrompt = `${system}
74517
75281
 
74518
- ${prompt}`,
75282
+ ${prompt}`;
75283
+ try {
75284
+ const attList = effectiveAttachments && effectiveAttachments.length ? effectiveAttachments : [];
75285
+ if (attList.length > 0) {
75286
+ const limitBytes = 128 * 1024;
75287
+ let used = 0;
75288
+ const sections = [];
75289
+ for (const a of attList) {
75290
+ if (!a?.data_base64) continue;
75291
+ try {
75292
+ const buf = Buffer.from(a.data_base64, "base64");
75293
+ const text = /^(application\/pdf)/i.test(String(a.mime || "")) ? "" : buf.toString("utf8");
75294
+ if (!text) continue;
75295
+ const remaining = Math.max(0, limitBytes - used);
75296
+ if (remaining <= 0) break;
75297
+ const slice = text.length > remaining ? text.slice(0, remaining) : text;
75298
+ used += Buffer.byteLength(slice, "utf8");
75299
+ sections.push(`[BEGIN file: ${a.path || a.name || "attachment.txt"}]
75300
+ ${slice}
75301
+ [END]`);
75302
+ } catch {
75303
+ }
75304
+ }
75305
+ if (sections.length > 0) {
75306
+ fallbackPrompt = `${fallbackPrompt}
75307
+
75308
+ [ATTACHMENTS]
75309
+ ${sections.join("\n\n")}`;
75310
+ }
75311
+ }
75312
+ } catch {
75313
+ }
75314
+ const res = await this.providerManager.complete({
75315
+ prompt: fallbackPrompt,
74519
75316
  model,
74520
75317
  temperature,
74521
75318
  maxTokens
@@ -75760,7 +76557,7 @@ async function init2() {
75760
76557
  ai = res.ai;
75761
76558
  res.ctx;
75762
76559
  store = res.store;
75763
- while (session.length) session.pop();
76560
+ clearSession();
75764
76561
  for (const m2 of res.session) session.push(m2);
75765
76562
  await loadServices2();
75766
76563
  }
@@ -75777,6 +76574,9 @@ async function streamAnswer(text, opts = {}) {
75777
76574
  s2 = s2.replace(/\[BEGIN\s+file:[^\]]+\][\s\S]*?\[END\]/g, "");
75778
76575
  return s2;
75779
76576
  };
76577
+ const removeAttachmentSections = (s2) => {
76578
+ return s2.replace(/\[ATTACHMENTS\][\s\S]*$/i, "");
76579
+ };
75780
76580
  const hasAnyCodeBlocks = (s2) => /```[\s\S]*?```|\[BEGIN\s+file:/i.test(s2);
75781
76581
  const envInt = (name2, def) => {
75782
76582
  const v = Number(process.env[name2]);
@@ -75802,10 +76602,11 @@ async function streamAnswer(text, opts = {}) {
75802
76602
  model: process.env.MARIA_MODEL || "gemini-2.5-flash"
75803
76603
  });
75804
76604
  animation.stop();
75805
- const containsCode = hasAnyCodeBlocks(resp || "");
75806
- if (containsCode) {
76605
+ const respForArtifactCheck = removeAttachmentSections(resp || "");
76606
+ const containsCode = hasAnyCodeBlocks(respForArtifactCheck);
76607
+ if (containsCode && opts.triage && opts.triage.type === "route-code") {
75807
76608
  try {
75808
- const artifacts = extractAllCodeInfos(resp);
76609
+ const artifacts = extractAllCodeInfos(respForArtifactCheck);
75809
76610
  const savedFiles = [];
75810
76611
  let okCount = 0, warnCount = 0, errCount = 0;
75811
76612
  for (const { language, code, extension, filename: suggested } of artifacts) {
@@ -75830,7 +76631,7 @@ async function streamAnswer(text, opts = {}) {
75830
76631
  console.log(chalk14__default.default.white(`ERROR: failed ${filepath} (${language}) - ${msg2}`));
75831
76632
  }
75832
76633
  }
75833
- const prose = stripMarkdownForPlainChat(removeCodeBlocks(resp)).trim();
76634
+ const prose = stripMarkdownForPlainChat(removeCodeBlocks(removeAttachmentSections(resp))).trim();
75834
76635
  if (prose) {
75835
76636
  console.log(chalk14__default.default.white(""));
75836
76637
  console.log(chalk14__default.default.white("Chat Response:"));
@@ -75909,44 +76710,23 @@ async function handleLine(line, options = {}) {
75909
76710
  }
75910
76711
  const consumed = await handleSlash(input3);
75911
76712
  if (consumed) return;
75912
- let triageResult = options.triageResult ?? null;
75913
- if (!options.skipTriage) {
75914
- triageResult = await triage(input3, {
75915
- locale: process.env.LANG,
75916
- recentCommands: []
75917
- });
75918
- if (triageResult.next?.route) {
75919
- const commandParts = [
75920
- triageResult.next.route,
75921
- ...triageResult.next.args ?? []
75922
- ];
75923
- const routedLine = commandParts.join(" ").trim();
75924
- console.log(chalk14__default.default.white("Routed:"));
75925
- console.log(chalk14__default.default.white(routedLine));
75926
- await handleLine(routedLine, {
75927
- skipChoiceResolution: true,
75928
- skipTriage: true
75929
- });
75930
- console.log(chalk14__default.default.white(""));
75931
- console.log(chalk14__default.default.white("Summary:"));
75932
- if (triageResult.type === "route-code") {
75933
- console.log(chalk14__default.default.white("OK: routed to /code plan-only"));
75934
- console.log(chalk14__default.default.white("Next steps:"));
75935
- console.log(chalk14__default.default.white("- Run /code --apply --yes after reviewing the plan"));
75936
- } else if (triageResult.type === "route-image") {
75937
- console.log(chalk14__default.default.white("OK: routed to /image"));
75938
- console.log(chalk14__default.default.white("Next steps:"));
75939
- console.log(chalk14__default.default.white("- Review generated images and iterate if needed"));
75940
- } else if (triageResult.type === "route-video") {
75941
- console.log(chalk14__default.default.white("OK: routed to /video"));
75942
- console.log(chalk14__default.default.white("Next steps:"));
75943
- console.log(chalk14__default.default.white("- Inspect the storyboard or render output"));
75944
- } else {
75945
- console.log(chalk14__default.default.white("OK: routed"));
75946
- console.log(chalk14__default.default.white("Next steps:"));
75947
- console.log(chalk14__default.default.white("- Follow the routed workflow"));
76713
+ if (!input3.startsWith("/")) {
76714
+ const mapped = await mapInputToTopLevelCommand(input3);
76715
+ if (process.env.MARIA_DEBUG === "1") {
76716
+ console.log(chalk14__default.default.white(`Command: {command: '${mapped.command}', args: '${mapped.args}', confidence: '${mapped.confidence}'}`));
76717
+ }
76718
+ try {
76719
+ const threshold = Number(process.env.MARIA_ROUTE_CONFIDENCE || "0.7");
76720
+ if (mapped && mapped.command) {
76721
+ const conf = typeof mapped.confidence === "number" ? mapped.confidence : 1;
76722
+ if (mapped.command === "chat") {
76723
+ } else if (conf >= threshold) {
76724
+ const routed = [mapped.command, ...mapped.args || [input3]].join(" ").trim();
76725
+ await handleLine(routed, { skipChoiceResolution: true, skipTriage: true });
76726
+ return;
76727
+ }
75948
76728
  }
75949
- return;
76729
+ } finally {
75950
76730
  }
75951
76731
  }
75952
76732
  const isAuthenticated = await authManager.isAuthenticated();
@@ -75959,73 +76739,7 @@ async function handleLine(line, options = {}) {
75959
76739
  const user = { role: "user", content: input3, timestamp: /* @__PURE__ */ new Date() };
75960
76740
  session.push(user);
75961
76741
  if (store?.addMessage) await store.addMessage(user);
75962
- if (triageResult?.type === "complex") {
75963
- await handleComplexChat(input3, triageResult);
75964
- return;
75965
- }
75966
- await streamAnswer(input3, { triage: triageResult });
75967
- }
75968
- async function handleComplexChat(request, triageResult) {
75969
- const animation = new ProcessAnimation();
75970
- animation.start();
75971
- try {
75972
- const authed = await authManager.isAuthenticated();
75973
- let content = "";
75974
- if (authed) {
75975
- try {
75976
- const resp = await callApiJson("/api/ai", {
75977
- method: "POST",
75978
- body: JSON.stringify({ prompt: request, taskType: "planning" }),
75979
- headers: { "Content-Type": "application/json" }
75980
- });
75981
- content = resp?.data?.response || resp?.data?.content || "";
75982
- } catch {
75983
- }
75984
- }
75985
- if (!content) {
75986
- animation.stop();
75987
- await streamAnswer(request, { triage: triageResult });
75988
- return;
75989
- }
75990
- animation.stop();
75991
- const cleaned = content && typeof content === "string" ? content : buildComplexPlanSteps(request).join("\n");
75992
- console.log(chalk14__default.default.white(cleaned));
75993
- const planMessage = {
75994
- role: "assistant",
75995
- content: cleaned,
75996
- timestamp: /* @__PURE__ */ new Date(),
75997
- metadata: { tag: "complex-chat", triage: triageResult }
75998
- };
75999
- session.push(planMessage);
76000
- if (store?.addMessage) await store.addMessage(planMessage);
76001
- console.log(chalk14__default.default.white(""));
76002
- console.log(chalk14__default.default.white("Summary:"));
76003
- console.log(chalk14__default.default.white("OK: plan prepared"));
76004
- console.log(chalk14__default.default.white("Next steps:"));
76005
- console.log(chalk14__default.default.white("- Ask to apply or adjust the plan"));
76006
- } finally {
76007
- try {
76008
- animation.stop();
76009
- } catch {
76010
- }
76011
- }
76012
- }
76013
- function buildComplexPlanSteps(request) {
76014
- const scoped = request.trim();
76015
- const steps = [
76016
- `Clarify scope, constraints, and success criteria for "${scoped}"`,
76017
- `Review existing modules in src/ and docs/ for related work`,
76018
- `Design the solution with safe defaults and feature flags if needed`,
76019
- `Implement changes and document decisions`,
76020
- `Validate with pnpm test and peer review artifacts`
76021
- ];
76022
- if (/(test|spec|verify|検証)/i.test(scoped)) {
76023
- steps.push("Extend or add Vitest coverage for new behaviour");
76024
- }
76025
- if (/(ui|frontend|component|画面)/i.test(scoped)) {
76026
- steps.push("Capture CLI or UI snapshots to confirm UX changes");
76027
- }
76028
- return steps;
76742
+ await streamAnswer(input3, {});
76029
76743
  }
76030
76744
  async function tryResolveChoice(rawLine) {
76031
76745
  const resolution = choiceMemory.resolve(rawLine);
@@ -76117,17 +76831,17 @@ MARIA v${getVersion()}
76117
76831
  registerDoctorSubcommand(program2);
76118
76832
  return program2;
76119
76833
  }
76120
- var InteractiveCLI, ai, store, session, commandManager, startupDisplayed, program;
76834
+ var InteractiveCLI, ai, store, commandManager, startupDisplayed, program;
76121
76835
  var init_cli = __esm({
76122
76836
  "src/cli.ts"() {
76123
76837
  init_env_loader();
76124
76838
  init_version();
76125
76839
  init_animations();
76126
76840
  init_cli_auth();
76127
- init_api_client();
76128
76841
  init_choice_memory();
76129
- init_triage_orchestrator();
76842
+ init_LlmTopLevelRouter();
76130
76843
  init_handle_slash();
76844
+ init_session_state();
76131
76845
  init_process_handlers();
76132
76846
  init_doctor();
76133
76847
  init_services_loader();
@@ -76135,7 +76849,6 @@ var init_cli = __esm({
76135
76849
  init_interactive_session2();
76136
76850
  init_server();
76137
76851
  init_code_utils();
76138
- session = [];
76139
76852
  commandManager = null;
76140
76853
  startupDisplayed = false;
76141
76854
  if (!process.env.GOOGLE_AUTH_DISABLE_GCE_CHECK) {