@bonginkan/maria 4.3.38 → 4.3.40

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.
@@ -235,13 +235,13 @@ function getPackageJson() {
235
235
  )
236
236
  ];
237
237
  let packageJsonPath = null;
238
- for (const path64 of possiblePaths) {
239
- if (fs21.existsSync(path64)) {
238
+ for (const path65 of possiblePaths) {
239
+ if (fs21.existsSync(path65)) {
240
240
  try {
241
- const content = fs21.readFileSync(path64, "utf-8");
241
+ const content = fs21.readFileSync(path65, "utf-8");
242
242
  const parsed = JSON.parse(content);
243
243
  if (parsed.name === "@bonginkan/maria") {
244
- packageJsonPath = path64;
244
+ packageJsonPath = path65;
245
245
  break;
246
246
  }
247
247
  } catch {
@@ -5314,22 +5314,22 @@ var init_from = __esm({
5314
5314
  init_file();
5315
5315
  init_fetch_blob();
5316
5316
  ({ stat } = fs21.promises);
5317
- blobFromSync = (path64, type) => fromBlob(fs21.statSync(path64), path64, type);
5318
- blobFrom = (path64, type) => stat(path64).then((stat13) => fromBlob(stat13, path64, type));
5319
- fileFrom = (path64, type) => stat(path64).then((stat13) => fromFile(stat13, path64, type));
5320
- fileFromSync = (path64, type) => fromFile(fs21.statSync(path64), path64, type);
5321
- fromBlob = (stat13, path64, type = "") => new fetch_blob_default([new BlobDataItem({
5322
- path: path64,
5317
+ blobFromSync = (path65, type) => fromBlob(fs21.statSync(path65), path65, type);
5318
+ blobFrom = (path65, type) => stat(path65).then((stat13) => fromBlob(stat13, path65, type));
5319
+ fileFrom = (path65, type) => stat(path65).then((stat13) => fromFile(stat13, path65, type));
5320
+ fileFromSync = (path65, type) => fromFile(fs21.statSync(path65), path65, type);
5321
+ fromBlob = (stat13, path65, type = "") => new fetch_blob_default([new BlobDataItem({
5322
+ path: path65,
5323
5323
  size: stat13.size,
5324
5324
  lastModified: stat13.mtimeMs,
5325
5325
  start: 0
5326
5326
  })], { type });
5327
- fromFile = (stat13, path64, type = "") => new file_default([new BlobDataItem({
5328
- path: path64,
5327
+ fromFile = (stat13, path65, type = "") => new file_default([new BlobDataItem({
5328
+ path: path65,
5329
5329
  size: stat13.size,
5330
5330
  lastModified: stat13.mtimeMs,
5331
5331
  start: 0
5332
- })], path11.basename(path64), { type, lastModified: stat13.mtimeMs });
5332
+ })], path11.basename(path65), { type, lastModified: stat13.mtimeMs });
5333
5333
  BlobDataItem = class _BlobDataItem {
5334
5334
  #path;
5335
5335
  #start;
@@ -9563,12 +9563,12 @@ ${this.toYamlLike(value, indent + 1)}`;
9563
9563
  }
9564
9564
  static async loadFromFile(configPath) {
9565
9565
  const { importNodeBuiltin: importNodeBuiltin2 } = await Promise.resolve().then(() => (init_import_helper(), import_helper_exports));
9566
- const fs51 = await importNodeBuiltin2("fs");
9566
+ const fs52 = await importNodeBuiltin2("fs");
9567
9567
  const _path = await importNodeBuiltin2("_path");
9568
9568
  const os23 = await importNodeBuiltin2("os");
9569
9569
  const targetPath = configPath || _path.join(os23.homedir(), ".maria", "config.json");
9570
9570
  try {
9571
- const data = await fs51.promises.readFile(targetPath, "utf-8");
9571
+ const data = await fs52.promises.readFile(targetPath, "utf-8");
9572
9572
  return JSON.parse(data);
9573
9573
  } catch (innerError) {
9574
9574
  if (innerError?.code === "ENOENT") {
@@ -9582,25 +9582,25 @@ ${this.toYamlLike(value, indent + 1)}`;
9582
9582
  }
9583
9583
  async save(configPath, options) {
9584
9584
  const { importNodeBuiltin: importNodeBuiltin2 } = await Promise.resolve().then(() => (init_import_helper(), import_helper_exports));
9585
- const fs51 = await importNodeBuiltin2("fs");
9585
+ const fs52 = await importNodeBuiltin2("fs");
9586
9586
  const _path = await importNodeBuiltin2("_path");
9587
9587
  const os23 = await importNodeBuiltin2("os");
9588
9588
  const targetPath = configPath || _path.join(os23.homedir(), ".maria", "config.json");
9589
9589
  try {
9590
9590
  if (options?.backup) {
9591
9591
  try {
9592
- await fs51.promises.access(targetPath);
9592
+ await fs52.promises.access(targetPath);
9593
9593
  const backupPath = `${targetPath}.backup.${Date.now()}`;
9594
- await fs51.promises.copyFile(targetPath, backupPath);
9594
+ await fs52.promises.copyFile(targetPath, backupPath);
9595
9595
  } catch {
9596
9596
  }
9597
9597
  }
9598
- await fs51.promises.mkdir(_path.dirname(targetPath), { recursive: true });
9598
+ await fs52.promises.mkdir(_path.dirname(targetPath), { recursive: true });
9599
9599
  const dataToSave = this.getAll({
9600
9600
  maskSensitive: options?.maskSensitive ?? true,
9601
9601
  includeSourceMap: options?.includeSourceMap ?? false
9602
9602
  });
9603
- await fs51.promises.writeFile(
9603
+ await fs52.promises.writeFile(
9604
9604
  targetPath,
9605
9605
  JSON.stringify(dataToSave, null, 2),
9606
9606
  { mode: 384 }
@@ -9644,12 +9644,12 @@ ${this.toYamlLike(value, indent + 1)}`;
9644
9644
  }
9645
9645
  if (outputPath) {
9646
9646
  const { importNodeBuiltin: importNodeBuiltin2 } = await Promise.resolve().then(() => (init_import_helper(), import_helper_exports));
9647
- const fs51 = await importNodeBuiltin2("fs");
9647
+ const fs52 = await importNodeBuiltin2("fs");
9648
9648
  const _path = await importNodeBuiltin2(
9649
9649
  "_path"
9650
9650
  );
9651
- await fs51.promises.mkdir(_path.dirname(outputPath), { recursive: true });
9652
- await fs51.promises.writeFile(outputPath, content, "utf-8");
9651
+ await fs52.promises.mkdir(_path.dirname(outputPath), { recursive: true });
9652
+ await fs52.promises.writeFile(outputPath, content, "utf-8");
9653
9653
  console.log(`\u2705 Configuration exported to ${outputPath}`);
9654
9654
  }
9655
9655
  return content;
@@ -9958,13 +9958,13 @@ async function loadEnvironmentConfig() {
9958
9958
  }
9959
9959
  try {
9960
9960
  const { importNodeBuiltin: importNodeBuiltin2, safeDynamicImport: safeDynamicImport2 } = await Promise.resolve().then(() => (init_import_helper(), import_helper_exports));
9961
- const fs51 = await safeDynamicImport2("fs-extra").catch(
9961
+ const fs52 = await safeDynamicImport2("fs-extra").catch(
9962
9962
  () => importNodeBuiltin2("fs")
9963
9963
  );
9964
9964
  const _path = await importNodeBuiltin2("_path");
9965
9965
  const _envPath = _path.join(process.cwd(), ".env.local");
9966
- if (await fs51.pathExists(_envPath)) {
9967
- const _envContent = await fs51.readFile(_envPath, "utf-8");
9966
+ if (await fs52.pathExists(_envPath)) {
9967
+ const _envContent = await fs52.readFile(_envPath, "utf-8");
9968
9968
  console.log("Loading environment from:", _envPath);
9969
9969
  environmentLoaded = true;
9970
9970
  const _lines = _envContent.split("\n");
@@ -19536,8 +19536,8 @@ var init_ConfigService = __esm({
19536
19536
  /**
19537
19537
  * ネストされた設定値の取得
19538
19538
  */
19539
- getNestedValue(path64) {
19540
- const keys = path64.split(".");
19539
+ getNestedValue(path65) {
19540
+ const keys = path65.split(".");
19541
19541
  let value = this._config;
19542
19542
  for (const key of keys) {
19543
19543
  if (value && typeof value === "object" && key in value) {
@@ -19567,8 +19567,8 @@ var init_ConfigService = __esm({
19567
19567
  /**
19568
19568
  * ネストされた設定値の更新
19569
19569
  */
19570
- async setNestedValue(path64, value) {
19571
- const keys = path64.split(".");
19570
+ async setNestedValue(path65, value) {
19571
+ const keys = path65.split(".");
19572
19572
  const lastKey = keys.pop();
19573
19573
  let target = this._config;
19574
19574
  for (const key of keys) {
@@ -19581,7 +19581,7 @@ var init_ConfigService = __esm({
19581
19581
  target[lastKey] = value;
19582
19582
  this.validateConfig();
19583
19583
  this.emitChange({
19584
- path: path64,
19584
+ path: path65,
19585
19585
  oldValue,
19586
19586
  newValue: value,
19587
19587
  timestamp: /* @__PURE__ */ new Date()
@@ -19626,8 +19626,8 @@ var init_ConfigService = __esm({
19626
19626
  setupAutoSave() {
19627
19627
  process.on("exit", () => {
19628
19628
  if (this._isDirty) {
19629
- const fs51 = __require("fs");
19630
- fs51.writeFileSync(
19629
+ const fs52 = __require("fs");
19630
+ fs52.writeFileSync(
19631
19631
  this._userConfigPath,
19632
19632
  JSON.stringify(this._config, null, 2),
19633
19633
  "utf-8"
@@ -19638,13 +19638,13 @@ var init_ConfigService = __esm({
19638
19638
  /**
19639
19639
  * 変更リスナーの登録
19640
19640
  */
19641
- onChange(path64, listener) {
19642
- if (!this._listeners.has(path64)) {
19643
- this._listeners.set(path64, []);
19641
+ onChange(path65, listener) {
19642
+ if (!this._listeners.has(path65)) {
19643
+ this._listeners.set(path65, []);
19644
19644
  }
19645
- this._listeners.get(path64).push(listener);
19645
+ this._listeners.get(path65).push(listener);
19646
19646
  return () => {
19647
- const listeners = this._listeners.get(path64);
19647
+ const listeners = this._listeners.get(path65);
19648
19648
  if (listeners) {
19649
19649
  const index = listeners.indexOf(listener);
19650
19650
  if (index !== -1) {
@@ -20133,7 +20133,7 @@ var init_ValidationService = __esm({
20133
20133
  );
20134
20134
  this._schemas.set(
20135
20135
  "filePath",
20136
- zod.z.string().min(1).max(this._config.maxFilePathLength).refine((path64) => !this.containsPathTraversal(path64), {
20136
+ zod.z.string().min(1).max(this._config.maxFilePathLength).refine((path65) => !this.containsPathTraversal(path65), {
20137
20137
  message: "Path traversal detected"
20138
20138
  })
20139
20139
  );
@@ -20272,11 +20272,11 @@ var init_ValidationService = __esm({
20272
20272
  /**
20273
20273
  * ファイルパス検証
20274
20274
  */
20275
- validateFilePath(path64) {
20275
+ validateFilePath(path65) {
20276
20276
  try {
20277
20277
  const schema = this._schemas.get("filePath");
20278
- const result = schema.parse(path64);
20279
- if (this.isSystemPath(path64)) {
20278
+ const result = schema.parse(path65);
20279
+ if (this.isSystemPath(path65)) {
20280
20280
  return {
20281
20281
  valid: false,
20282
20282
  errors: [
@@ -20422,8 +20422,8 @@ var init_ValidationService = __esm({
20422
20422
  /**
20423
20423
  * パストラバーサルの検出
20424
20424
  */
20425
- containsPathTraversal(path64) {
20426
- return /\.\.[/\\]/.test(path64) || path64.includes("..\\") || path64.includes("../");
20425
+ containsPathTraversal(path65) {
20426
+ return /\.\.[/\\]/.test(path65) || path65.includes("..\\") || path65.includes("../");
20427
20427
  }
20428
20428
  /**
20429
20429
  * 危険なコマンドの判定
@@ -20450,7 +20450,7 @@ var init_ValidationService = __esm({
20450
20450
  /**
20451
20451
  * システムパスの判定
20452
20452
  */
20453
- isSystemPath(path64) {
20453
+ isSystemPath(path65) {
20454
20454
  const systemPaths = [
20455
20455
  "/etc",
20456
20456
  "/sys",
@@ -20464,7 +20464,7 @@ var init_ValidationService = __esm({
20464
20464
  "/sbin"
20465
20465
  ];
20466
20466
  return systemPaths.some(
20467
- (sysPath) => path64.toLowerCase().startsWith(sysPath.toLowerCase())
20467
+ (sysPath) => path65.toLowerCase().startsWith(sysPath.toLowerCase())
20468
20468
  );
20469
20469
  }
20470
20470
  /**
@@ -25440,10 +25440,10 @@ Run /doctor --fix to automatically fix ${fixableCount} issue(s)`
25440
25440
  const finalize = async (text, data) => {
25441
25441
  if (outputPath) {
25442
25442
  try {
25443
- const fs51 = await import('fs/promises');
25444
- const path64 = await import('path');
25445
- const abs = path64.resolve(outputPath);
25446
- await fs51.writeFile(abs, text, "utf-8");
25443
+ const fs52 = await import('fs/promises');
25444
+ const path65 = await import('path');
25445
+ const abs = path65.resolve(outputPath);
25446
+ await fs52.writeFile(abs, text, "utf-8");
25447
25447
  const msg = `Saved doctor report to ${abs}`;
25448
25448
  return { ok: true, message: msg, data: { path: abs, bytes: Buffer.byteLength(text, "utf-8") } };
25449
25449
  } catch (e2) {
@@ -25533,10 +25533,10 @@ Run /doctor --fix to automatically fix ${fixableCount} issue(s)`
25533
25533
  const finalize = async (text, data) => {
25534
25534
  if (outputPath) {
25535
25535
  try {
25536
- const fs51 = await import('fs/promises');
25537
- const path64 = await import('path');
25538
- const abs = path64.resolve(outputPath);
25539
- await fs51.writeFile(abs, text, "utf-8");
25536
+ const fs52 = await import('fs/promises');
25537
+ const path65 = await import('path');
25538
+ const abs = path65.resolve(outputPath);
25539
+ await fs52.writeFile(abs, text, "utf-8");
25540
25540
  const msg = `Saved metrics to ${abs}`;
25541
25541
  return { ok: true, message: msg, data: { path: abs, bytes: Buffer.byteLength(text, "utf-8") } };
25542
25542
  } catch (e2) {
@@ -25925,15 +25925,15 @@ var init_SessionOrchestrator = __esm({
25925
25925
  /**
25926
25926
  * 設定の取得
25927
25927
  */
25928
- getConfig(path64) {
25929
- return this._configService?.getNestedValue(path64);
25928
+ getConfig(path65) {
25929
+ return this._configService?.getNestedValue(path65);
25930
25930
  }
25931
25931
  /**
25932
25932
  * 設定の更新
25933
25933
  */
25934
- async setConfig(path64, value) {
25934
+ async setConfig(path65, value) {
25935
25935
  if (this._configService) {
25936
- await this._configService.setNestedValue(path64, value);
25936
+ await this._configService.setNestedValue(path65, value);
25937
25937
  }
25938
25938
  }
25939
25939
  /**
@@ -26051,11 +26051,11 @@ var init_interactive_session = __esm({
26051
26051
  getStats() {
26052
26052
  return this.orchestrator.getSessionStats();
26053
26053
  }
26054
- getConfig(path64) {
26055
- return this.orchestrator.getConfig(path64);
26054
+ getConfig(path65) {
26055
+ return this.orchestrator.getConfig(path65);
26056
26056
  }
26057
- async setConfig(path64, value) {
26058
- await this.orchestrator.setConfig(path64, value);
26057
+ async setConfig(path65, value) {
26058
+ await this.orchestrator.setConfig(path65, value);
26059
26059
  }
26060
26060
  };
26061
26061
  }
@@ -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.38",
26070
- description: "\u{1F680} MARIA v4.3.38 - 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.40",
26070
+ description: "\u{1F680} MARIA v4.3.40 - 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.38"}`
28107
+ "User-Agent": `maria-cli/${process.env.CLI_VERSION || "4.3.40"}`
28108
28108
  }
28109
28109
  });
28110
28110
  if (response.status === 401) {
@@ -28745,9 +28745,9 @@ function clientThrottle(endpoint) {
28745
28745
  }
28746
28746
  rateLimitMap.set(endpoint, now2);
28747
28747
  }
28748
- async function callApi(path64, init3 = {}) {
28748
+ async function callApi(path65, init3 = {}) {
28749
28749
  const apiBase = process.env.MARIA_API_BASE || "https://api.maria-code.ai";
28750
- const fullUrl = `${apiBase}${path64}`;
28750
+ const fullUrl = `${apiBase}${path65}`;
28751
28751
  let tokens2 = await authManager.getValidTokens();
28752
28752
  if (!tokens2) {
28753
28753
  console.log(chalk14__default.default.red(ERR.AUTH_REQUIRED.msg));
@@ -28758,7 +28758,7 @@ async function callApi(path64, init3 = {}) {
28758
28758
  "Authorization": `Bearer ${token}`,
28759
28759
  "X-Device-Id": getDeviceId(),
28760
28760
  "X-Session-Id": getSessionId() || "",
28761
- "User-Agent": `maria-cli/${process.env.CLI_VERSION || "4.3.38"}`,
28761
+ "User-Agent": `maria-cli/${process.env.CLI_VERSION || "4.3.40"}`,
28762
28762
  "Content-Type": init3.headers?.["Content-Type"] || "application/json"
28763
28763
  });
28764
28764
  const doFetch = async (token) => {
@@ -28816,8 +28816,8 @@ async function callApi(path64, init3 = {}) {
28816
28816
  }
28817
28817
  return response;
28818
28818
  }
28819
- async function callApiJson(path64, init3 = {}) {
28820
- const response = await callApi(path64, init3);
28819
+ async function callApiJson(path65, init3 = {}) {
28820
+ const response = await callApi(path65, init3);
28821
28821
  if (!response.ok) {
28822
28822
  const error2 = await response.json().catch(() => ({
28823
28823
  message: `API error: ${response.status} ${response.statusText}`
@@ -28826,8 +28826,8 @@ async function callApiJson(path64, init3 = {}) {
28826
28826
  }
28827
28827
  return response.json();
28828
28828
  }
28829
- async function* streamApi(path64, init3 = {}) {
28830
- const response = await callApi(path64, {
28829
+ async function* streamApi(path65, init3 = {}) {
28830
+ const response = await callApi(path65, {
28831
28831
  ...init3,
28832
28832
  headers: {
28833
28833
  ...init3.headers,
@@ -28853,13 +28853,13 @@ async function* streamApi(path64, init3 = {}) {
28853
28853
  reader.releaseLock();
28854
28854
  }
28855
28855
  }
28856
- async function uploadFile(path64, file, metadata5 = {}) {
28856
+ async function uploadFile(path65, file, metadata5 = {}) {
28857
28857
  const formData = new FormData();
28858
28858
  formData.append("file", new Blob([file]));
28859
28859
  Object.entries(metadata5).forEach(([key, value]) => {
28860
28860
  formData.append(key, String(value));
28861
28861
  });
28862
- return callApiJson(path64, {
28862
+ return callApiJson(path65, {
28863
28863
  method: "POST",
28864
28864
  body: formData,
28865
28865
  headers: {
@@ -29175,7 +29175,7 @@ async function mapInputToTopLevelCommand(input3) {
29175
29175
  const system = [
29176
29176
  "You are a router for the MARIA CLI.",
29177
29177
  "Decide the best command for a single user input.",
29178
- "Allowed commands: /help, /image, /code, /video, /whoami, /login, /logout, /evaluate, /research, chat.",
29178
+ "Allowed commands: /help, /image, /code, /video, /whoami, /login, /logout, /evaluate, /research, /novel, chat.",
29179
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
29180
  'Return JSON only with keys: { "command": string, "args"?: string[], "confidence": number }.',
29181
29181
  "Select chat when the input is a general question or conversation rather than a specific slash command.",
@@ -29203,7 +29203,7 @@ ${input3}`,
29203
29203
  }
29204
29204
  if (!parsed || typeof parsed.command !== "string") return null;
29205
29205
  const cmd = parsed.command;
29206
- if (!["/help", "/image", "/code", "/video", "/whoami", "/login", "/logout", "/evaluate", "/research", "chat"].includes(cmd)) return null;
29206
+ if (!["/help", "/image", "/code", "/video", "/whoami", "/login", "/logout", "/evaluate", "/research", "/novel", "chat"].includes(cmd)) return null;
29207
29207
  const out = { command: cmd };
29208
29208
  if (Array.isArray(parsed.args)) {
29209
29209
  out.args = parsed.args.filter((a) => typeof a === "string" && a.trim()).map((s2) => s2.trim());
@@ -33819,12 +33819,12 @@ var init_esm4 = __esm({
33819
33819
  /**
33820
33820
  * Get the Path object referenced by the string path, resolved from this Path
33821
33821
  */
33822
- resolve(path64) {
33823
- if (!path64) {
33822
+ resolve(path65) {
33823
+ if (!path65) {
33824
33824
  return this;
33825
33825
  }
33826
- const rootPath = this.getRootString(path64);
33827
- const dir = path64.substring(rootPath.length);
33826
+ const rootPath = this.getRootString(path65);
33827
+ const dir = path65.substring(rootPath.length);
33828
33828
  const dirParts = dir.split(this.splitSep);
33829
33829
  const result = rootPath ? this.getRoot(rootPath).#resolveParts(dirParts) : this.#resolveParts(dirParts);
33830
33830
  return result;
@@ -34576,8 +34576,8 @@ var init_esm4 = __esm({
34576
34576
  /**
34577
34577
  * @internal
34578
34578
  */
34579
- getRootString(path64) {
34580
- return path11.win32.parse(path64).root;
34579
+ getRootString(path65) {
34580
+ return path11.win32.parse(path65).root;
34581
34581
  }
34582
34582
  /**
34583
34583
  * @internal
@@ -34623,8 +34623,8 @@ var init_esm4 = __esm({
34623
34623
  /**
34624
34624
  * @internal
34625
34625
  */
34626
- getRootString(path64) {
34627
- return path64.startsWith("/") ? "/" : "";
34626
+ getRootString(path65) {
34627
+ return path65.startsWith("/") ? "/" : "";
34628
34628
  }
34629
34629
  /**
34630
34630
  * @internal
@@ -34673,8 +34673,8 @@ var init_esm4 = __esm({
34673
34673
  *
34674
34674
  * @internal
34675
34675
  */
34676
- constructor(cwd2 = process.cwd(), pathImpl, sep4, { nocase, childrenCacheSize = 16 * 1024, fs: fs51 = defaultFS } = {}) {
34677
- this.#fs = fsFromOption(fs51);
34676
+ constructor(cwd2 = process.cwd(), pathImpl, sep4, { nocase, childrenCacheSize = 16 * 1024, fs: fs52 = defaultFS } = {}) {
34677
+ this.#fs = fsFromOption(fs52);
34678
34678
  if (cwd2 instanceof URL || cwd2.startsWith("file://")) {
34679
34679
  cwd2 = url.fileURLToPath(cwd2);
34680
34680
  }
@@ -34713,11 +34713,11 @@ var init_esm4 = __esm({
34713
34713
  /**
34714
34714
  * Get the depth of a provided path, string, or the cwd
34715
34715
  */
34716
- depth(path64 = this.cwd) {
34717
- if (typeof path64 === "string") {
34718
- path64 = this.cwd.resolve(path64);
34716
+ depth(path65 = this.cwd) {
34717
+ if (typeof path65 === "string") {
34718
+ path65 = this.cwd.resolve(path65);
34719
34719
  }
34720
- return path64.depth();
34720
+ return path65.depth();
34721
34721
  }
34722
34722
  /**
34723
34723
  * Return the cache of child entries. Exposed so subclasses can create
@@ -35204,9 +35204,9 @@ var init_esm4 = __esm({
35204
35204
  process11();
35205
35205
  return results;
35206
35206
  }
35207
- chdir(path64 = this.cwd) {
35207
+ chdir(path65 = this.cwd) {
35208
35208
  const oldCwd = this.cwd;
35209
- this.cwd = typeof path64 === "string" ? this.cwd.resolve(path64) : path64;
35209
+ this.cwd = typeof path65 === "string" ? this.cwd.resolve(path65) : path65;
35210
35210
  this.cwd[setAsCwd](oldCwd);
35211
35211
  }
35212
35212
  };
@@ -35232,8 +35232,8 @@ var init_esm4 = __esm({
35232
35232
  /**
35233
35233
  * @internal
35234
35234
  */
35235
- newRoot(fs51) {
35236
- return new PathWin32(this.rootPath, IFDIR, void 0, this.roots, this.nocase, this.childrenCache(), { fs: fs51 });
35235
+ newRoot(fs52) {
35236
+ return new PathWin32(this.rootPath, IFDIR, void 0, this.roots, this.nocase, this.childrenCache(), { fs: fs52 });
35237
35237
  }
35238
35238
  /**
35239
35239
  * Return true if the provided path string is an absolute path
@@ -35261,8 +35261,8 @@ var init_esm4 = __esm({
35261
35261
  /**
35262
35262
  * @internal
35263
35263
  */
35264
- newRoot(fs51) {
35265
- return new PathPosix(this.rootPath, IFDIR, void 0, this.roots, this.nocase, this.childrenCache(), { fs: fs51 });
35264
+ newRoot(fs52) {
35265
+ return new PathPosix(this.rootPath, IFDIR, void 0, this.roots, this.nocase, this.childrenCache(), { fs: fs52 });
35266
35266
  }
35267
35267
  /**
35268
35268
  * Return true if the provided path string is an absolute path
@@ -35581,8 +35581,8 @@ var init_processor = __esm({
35581
35581
  }
35582
35582
  // match, absolute, ifdir
35583
35583
  entries() {
35584
- return [...this.store.entries()].map(([path64, n]) => [
35585
- path64,
35584
+ return [...this.store.entries()].map(([path65, n]) => [
35585
+ path65,
35586
35586
  !!(n & 2),
35587
35587
  !!(n & 1)
35588
35588
  ]);
@@ -35795,9 +35795,9 @@ var init_walker = __esm({
35795
35795
  signal;
35796
35796
  maxDepth;
35797
35797
  includeChildMatches;
35798
- constructor(patterns, path64, opts) {
35798
+ constructor(patterns, path65, opts) {
35799
35799
  this.patterns = patterns;
35800
- this.path = path64;
35800
+ this.path = path65;
35801
35801
  this.opts = opts;
35802
35802
  this.#sep = !opts.posix && opts.platform === "win32" ? "\\" : "/";
35803
35803
  this.includeChildMatches = opts.includeChildMatches !== false;
@@ -35816,11 +35816,11 @@ var init_walker = __esm({
35816
35816
  });
35817
35817
  }
35818
35818
  }
35819
- #ignored(path64) {
35820
- return this.seen.has(path64) || !!this.#ignore?.ignored?.(path64);
35819
+ #ignored(path65) {
35820
+ return this.seen.has(path65) || !!this.#ignore?.ignored?.(path65);
35821
35821
  }
35822
- #childrenIgnored(path64) {
35823
- return !!this.#ignore?.childrenIgnored?.(path64);
35822
+ #childrenIgnored(path65) {
35823
+ return !!this.#ignore?.childrenIgnored?.(path65);
35824
35824
  }
35825
35825
  // backpressure mechanism
35826
35826
  pause() {
@@ -36035,8 +36035,8 @@ var init_walker = __esm({
36035
36035
  };
36036
36036
  GlobWalker = class extends GlobUtil {
36037
36037
  matches = /* @__PURE__ */ new Set();
36038
- constructor(patterns, path64, opts) {
36039
- super(patterns, path64, opts);
36038
+ constructor(patterns, path65, opts) {
36039
+ super(patterns, path65, opts);
36040
36040
  }
36041
36041
  matchEmit(e2) {
36042
36042
  this.matches.add(e2);
@@ -36073,8 +36073,8 @@ var init_walker = __esm({
36073
36073
  };
36074
36074
  GlobStream = class extends GlobUtil {
36075
36075
  results;
36076
- constructor(patterns, path64, opts) {
36077
- super(patterns, path64, opts);
36076
+ constructor(patterns, path65, opts) {
36077
+ super(patterns, path65, opts);
36078
36078
  this.results = new Minipass({
36079
36079
  signal: this.signal,
36080
36080
  objectMode: true
@@ -41909,9 +41909,9 @@ var init_SafetyGuard = __esm({
41909
41909
  }
41910
41910
  }
41911
41911
  if (action.args.paths && Array.isArray(action.args.paths)) {
41912
- for (const path64 of action.args.paths) {
41913
- if (!this.validatePath(path64)) {
41914
- violations.push(`Invalid path: ${path64}`);
41912
+ for (const path65 of action.args.paths) {
41913
+ if (!this.validatePath(path65)) {
41914
+ violations.push(`Invalid path: ${path65}`);
41915
41915
  }
41916
41916
  }
41917
41917
  }
@@ -41967,15 +41967,15 @@ var init_SafetyGuard = __esm({
41967
41967
  * Validate file path against allowed/blocked lists
41968
41968
  */
41969
41969
  validatePath(filePath) {
41970
- const path64 = __require("path");
41971
- const resolvedPath = path64.resolve(filePath);
41970
+ const path65 = __require("path");
41971
+ const resolvedPath = path65.resolve(filePath);
41972
41972
  for (const blockedPath of this.constraints.blockedPaths) {
41973
- if (resolvedPath.startsWith(path64.resolve(blockedPath))) {
41973
+ if (resolvedPath.startsWith(path65.resolve(blockedPath))) {
41974
41974
  return false;
41975
41975
  }
41976
41976
  }
41977
41977
  for (const allowedPath of this.constraints.allowedPaths) {
41978
- if (resolvedPath.startsWith(path64.resolve(allowedPath))) {
41978
+ if (resolvedPath.startsWith(path65.resolve(allowedPath))) {
41979
41979
  return true;
41980
41980
  }
41981
41981
  }
@@ -42004,9 +42004,9 @@ var init_SafetyGuard = __esm({
42004
42004
  violations.push(`Invalid path in ${action.type}: ${action.args.path}`);
42005
42005
  }
42006
42006
  if (action.args.paths && Array.isArray(action.args.paths)) {
42007
- for (const path64 of action.args.paths) {
42008
- if (!this.validatePath(path64)) {
42009
- violations.push(`Invalid path in ${action.type}: ${path64}`);
42007
+ for (const path65 of action.args.paths) {
42008
+ if (!this.validatePath(path65)) {
42009
+ violations.push(`Invalid path in ${action.type}: ${path65}`);
42010
42010
  }
42011
42011
  }
42012
42012
  }
@@ -42975,8 +42975,8 @@ var init_ConfigActionExecutor = __esm({
42975
42975
  /**
42976
42976
  * Set nested configuration value using dot notation
42977
42977
  */
42978
- setNestedValue(obj, path64, value) {
42979
- const keys = path64.split(".");
42978
+ setNestedValue(obj, path65, value) {
42979
+ const keys = path65.split(".");
42980
42980
  let current = obj;
42981
42981
  for (let i2 = 0; i2 < keys.length - 1; i2++) {
42982
42982
  const key = keys[i2];
@@ -51261,7 +51261,7 @@ var init_about_command = __esm({
51261
51261
  async execute(args2, context2) {
51262
51262
  const output3 = [];
51263
51263
  output3.push("");
51264
- output3.push(chalk14__default.default.cyan.bold("\u{1F916} About MARIA v4.3.38"));
51264
+ output3.push(chalk14__default.default.cyan.bold("\u{1F916} About MARIA v4.3.40"));
51265
51265
  output3.push(chalk14__default.default.gray("\u2550".repeat(40)));
51266
51266
  output3.push("");
51267
51267
  output3.push(chalk14__default.default.white.bold("MARIA - Minimal API, Maximum Power"));
@@ -54325,88 +54325,6 @@ var init_SystemCommandFactory = __esm({
54325
54325
  };
54326
54326
  }
54327
54327
  });
54328
- function handleRateLimitError(error2) {
54329
- console.log();
54330
- console.log(chalk14__default.default.yellow("\u23F1\uFE0F Rate Limit Exceeded"));
54331
- console.log(chalk14__default.default.gray("\u2501".repeat(50)));
54332
- const route = error2.route || error2.details?.endpoint || "API";
54333
- const plan = error2.plan || error2.details?.plan || "Unknown";
54334
- const limit = error2.limit || (error2.details?.limit ? parseInt(error2.details.limit) : null);
54335
- const retryAfter = error2.retryAfter || error2.details?.retryAfterSeconds;
54336
- const resetAt = error2.resetAt || (error2.details?.resetAt ? Date.parse(error2.details.resetAt) : null);
54337
- const waitTime = Number.isFinite(retryAfter) ? `${retryAfter} second${retryAfter > 1 ? "s" : ""}` : "a few seconds";
54338
- let resetTime = "";
54339
- if (resetAt && Number.isFinite(resetAt)) {
54340
- const resetDate = new Date(resetAt);
54341
- const now2 = /* @__PURE__ */ new Date();
54342
- const diffMs = resetDate.getTime() - now2.getTime();
54343
- if (diffMs > 0 && diffMs < 6e4) {
54344
- resetTime = `in ${Math.ceil(diffMs / 1e3)} seconds`;
54345
- } else if (diffMs > 0) {
54346
- resetTime = `at ${resetDate.toLocaleTimeString()}`;
54347
- }
54348
- }
54349
- console.log(chalk14__default.default.white(`Plan: ${chalk14__default.default.bold(plan)}`));
54350
- console.log(chalk14__default.default.white(`Endpoint: ${chalk14__default.default.bold(route)}`));
54351
- if (limit !== null) {
54352
- console.log(chalk14__default.default.white(`Limit: ${chalk14__default.default.bold(limit)} requests`));
54353
- }
54354
- if (error2.remaining !== void 0) {
54355
- console.log(chalk14__default.default.white(`Remaining: ${chalk14__default.default.bold(error2.remaining)} requests`));
54356
- }
54357
- console.log();
54358
- console.log(chalk14__default.default.cyan(`Please wait ${chalk14__default.default.bold(waitTime)} before trying again`));
54359
- if (resetTime) {
54360
- console.log(chalk14__default.default.gray(`Rate limit resets ${resetTime}`));
54361
- }
54362
- if (error2.hint) {
54363
- console.log();
54364
- console.log(chalk14__default.default.magenta("\u{1F4A1} " + error2.hint));
54365
- }
54366
- console.log(chalk14__default.default.gray("\u2501".repeat(50)));
54367
- console.log();
54368
- }
54369
- async function parseRateLimitResponse(response) {
54370
- if (response.status !== 429) {
54371
- return null;
54372
- }
54373
- const rateLimitInfo = {
54374
- limit: parseInt(response.headers.get("RateLimit-Limit") || "0") || void 0,
54375
- remaining: parseInt(response.headers.get("RateLimit-Remaining") || "0") || void 0,
54376
- resetAt: parseInt(response.headers.get("RateLimit-Reset") || "0") || void 0,
54377
- retryAfter: parseInt(response.headers.get("Retry-After") || "0") || void 0
54378
- };
54379
- try {
54380
- const data = await response.json();
54381
- if (data.error === "rate_limited" || data.error === "rate_limit_exceeded") {
54382
- return {
54383
- ...data,
54384
- // Merge header info if not in body
54385
- limit: data.limit || rateLimitInfo.limit,
54386
- remaining: data.remaining || rateLimitInfo.remaining,
54387
- resetAt: data.resetAt || rateLimitInfo.resetAt,
54388
- retryAfter: data.retryAfter || rateLimitInfo.retryAfter
54389
- };
54390
- }
54391
- return {
54392
- error: "rate_limited",
54393
- message: data.message || "Rate limit exceeded. Please wait and try again.",
54394
- hint: data.hint || "Consider upgrading your plan for higher limits.",
54395
- ...rateLimitInfo
54396
- };
54397
- } catch {
54398
- return {
54399
- error: "rate_limited",
54400
- message: "Rate limit exceeded. Please wait and try again.",
54401
- hint: "Consider upgrading your plan for higher limits.",
54402
- ...rateLimitInfo
54403
- };
54404
- }
54405
- }
54406
- var init_rate_limit_handler = __esm({
54407
- "src/services/api-client/rate-limit-handler.ts"() {
54408
- }
54409
- });
54410
54328
  function extractCodeInfo(codeBlock) {
54411
54329
  const match2 = codeBlock.match(/```([^\n]*)\n?([\s\S]*?)```/);
54412
54330
  if (!match2) {
@@ -54651,8 +54569,408 @@ var init_code_utils = __esm({
54651
54569
  }
54652
54570
  });
54653
54571
 
54654
- // src/services/code-orchestrator/ArgumentInference.ts
54572
+ // src/services/creative/NovelArgumentInference.ts
54655
54573
  function extractFirstJson4(text) {
54574
+ if (!text) return null;
54575
+ const start = text.indexOf("{");
54576
+ const end = text.lastIndexOf("}");
54577
+ if (start !== -1 && end !== -1 && end > start) {
54578
+ const cand = text.slice(start, end + 1);
54579
+ try {
54580
+ JSON.parse(cand);
54581
+ return cand;
54582
+ } catch {
54583
+ }
54584
+ }
54585
+ return null;
54586
+ }
54587
+ async function inferNovelArgs(rawText) {
54588
+ const system = [
54589
+ "You extract structured options for a novel generation command.",
54590
+ 'Return JSON ONLY with keys among: { "title"?: string, "lang"?: string, "format"?: "md"|"markdown"|"txt"|"plaintext", "genre"?: string, "planOnly"?: boolean, "chapters"?: number }.',
54591
+ 'Infer reasonable values from natural language. Keep chapters between 3 and 50 if specified. If format suggests plain text, choose "plaintext".',
54592
+ "If the user requests outline only, set planOnly=true.",
54593
+ "Do not add commentary."
54594
+ ].join("\n");
54595
+ const resp = await callAPI("/v1/ai-proxy", {
54596
+ method: "POST",
54597
+ body: {
54598
+ prompt: `${system}
54599
+
54600
+ ---
54601
+
54602
+ ${rawText}`,
54603
+ taskType: "creative"
54604
+ }
54605
+ });
54606
+ const raw = (resp?.data?.content || resp?.output || "").trim();
54607
+ const jsonText = extractFirstJson4(raw) || raw;
54608
+ let parsed = {};
54609
+ try {
54610
+ parsed = JSON.parse(jsonText);
54611
+ } catch {
54612
+ return {};
54613
+ }
54614
+ const out = {};
54615
+ if (typeof parsed.title === "string" && parsed.title.trim()) out.title = parsed.title.trim();
54616
+ if (typeof parsed.lang === "string" && parsed.lang.trim()) out.lang = parsed.lang.trim().toLowerCase();
54617
+ if (typeof parsed.format === "string") {
54618
+ const f3 = parsed.format.toLowerCase();
54619
+ if (f3 === "md" || f3 === "markdown") out.format = "md";
54620
+ else if (f3 === "txt" || f3 === "plaintext" || f3 === "text") out.format = "txt";
54621
+ }
54622
+ if (typeof parsed.genre === "string" && parsed.genre.trim()) out.genre = parsed.genre.trim();
54623
+ if (typeof parsed.planOnly === "boolean") out.planOnly = parsed.planOnly;
54624
+ if (typeof parsed.chapters === "number" && Number.isFinite(parsed.chapters)) {
54625
+ const n = Math.max(1, Math.min(100, Math.floor(parsed.chapters)));
54626
+ out.chapters = n;
54627
+ }
54628
+ return out;
54629
+ }
54630
+ var init_NovelArgumentInference = __esm({
54631
+ "src/services/creative/NovelArgumentInference.ts"() {
54632
+ init_api_caller();
54633
+ }
54634
+ });
54635
+
54636
+ // src/slash-commands/categories/creative/novel.command.ts
54637
+ var novel_command_exports = {};
54638
+ __export(novel_command_exports, {
54639
+ NovelCommand: () => NovelCommand,
54640
+ default: () => novel_command_default
54641
+ });
54642
+ function normalizeFormat(fmt) {
54643
+ const f3 = (fmt).toLowerCase();
54644
+ if (f3 === "txt" || f3 === "plaintext" || f3 === "text") return "txt";
54645
+ return "md";
54646
+ }
54647
+ function normalizeLang(lang) {
54648
+ const l = (lang).toLowerCase();
54649
+ if (!l) return "en";
54650
+ if (["en", "ja", "jp", "zh", "ko", "fr", "de", "es", "it", "pt"].includes(l)) {
54651
+ return l === "jp" ? "ja" : l;
54652
+ }
54653
+ return "en";
54654
+ }
54655
+ async function writeText(filePath, content) {
54656
+ const dir = path11__namespace.dirname(filePath);
54657
+ await fsp__namespace.mkdir(dir, { recursive: true });
54658
+ await fsp__namespace.writeFile(filePath, content, "utf8");
54659
+ }
54660
+ function extractFirstJsonArray(text) {
54661
+ if (!text) return null;
54662
+ const t2 = text.trim();
54663
+ const fenced = t2.match(/```json\s*([\s\S]*?)```/i) || t2.match(/```\s*([\s\S]*?)```/);
54664
+ if (fenced && fenced[1]) {
54665
+ const body = fenced[1].trim();
54666
+ try {
54667
+ const arr = JSON.parse(body);
54668
+ return Array.isArray(arr) ? arr : null;
54669
+ } catch {
54670
+ }
54671
+ }
54672
+ const defenced = t2.replace(/```json|```/gi, "").trim();
54673
+ try {
54674
+ const arr = JSON.parse(defenced);
54675
+ return Array.isArray(arr) ? arr : null;
54676
+ } catch {
54677
+ }
54678
+ const s2 = t2.indexOf("[");
54679
+ const e2 = t2.lastIndexOf("]");
54680
+ if (s2 !== -1 && e2 !== -1 && e2 > s2) {
54681
+ const slice = t2.slice(s2, e2 + 1);
54682
+ try {
54683
+ const arr = JSON.parse(slice);
54684
+ return Array.isArray(arr) ? arr : null;
54685
+ } catch {
54686
+ }
54687
+ }
54688
+ return null;
54689
+ }
54690
+ async function generatePlan(prompt, lang, title, genre) {
54691
+ const system = [
54692
+ "You generate a detailed novel outline (plot).",
54693
+ "Return Markdown with clear sections: Title, Logline, Themes, Characters, Chapter Outline.",
54694
+ "The language should match the requested language."
54695
+ ].join("\n");
54696
+ const user = [
54697
+ `Language: ${lang}`,
54698
+ `Title: ${title}`,
54699
+ genre ? `Genre: ${genre}` : "",
54700
+ "Prompt:",
54701
+ prompt
54702
+ ].filter(Boolean).join("\n");
54703
+ const resp = await callAPI("/v1/ai-proxy", { method: "POST", body: { prompt: `${system}
54704
+
54705
+ ---
54706
+
54707
+ ${user}`, taskType: "creative" } });
54708
+ const out = (resp?.data?.content || resp?.output || "").trim();
54709
+ return out;
54710
+ }
54711
+ async function generateChapters(planMarkdown, lang, chapters) {
54712
+ const system = [
54713
+ "You expand a novel outline into chapter texts.",
54714
+ "Return only JSON array: [{ index: number, title: string, content: string }].",
54715
+ "Write in the requested language and maintain consistency with the outline."
54716
+ ].join("\n");
54717
+ const prompt = `${system}
54718
+
54719
+ LANG=${lang}
54720
+ CHAPTERS=${chapters}
54721
+
54722
+ OUTLINE:
54723
+ ${planMarkdown}`;
54724
+ const resp = await callAPI("/v1/ai-proxy", { method: "POST", body: { prompt, taskType: "creative" } });
54725
+ const raw = (resp?.data?.content || resp?.output || "").trim();
54726
+ const arr = extractFirstJsonArray(raw);
54727
+ if (Array.isArray(arr)) {
54728
+ return arr.map((it, i2) => ({
54729
+ index: typeof it.index === "number" ? it.index : i2,
54730
+ title: typeof it.title === "string" ? it.title : `Chapter ${i2 + 1}`,
54731
+ content: typeof it.content === "string" ? it.content : ""
54732
+ }));
54733
+ }
54734
+ return [{ index: 0, title: "Chapter 1", content: raw }];
54735
+ }
54736
+ async function generateTitle(idea, lang, genre) {
54737
+ const system = [
54738
+ "You craft a concise, compelling novel title. Return only the title string.",
54739
+ "Consider the idea and genre. Use the requested language."
54740
+ ].join("\n");
54741
+ const user = [
54742
+ `Language: ${lang}`,
54743
+ genre ? `Genre: ${genre}` : "",
54744
+ "Idea:",
54745
+ idea
54746
+ ].filter(Boolean).join("\n");
54747
+ const resp = await callAPI("/v1/ai-proxy", { method: "POST", body: { prompt: `${system}
54748
+
54749
+ ---
54750
+
54751
+ ${user}`, taskType: "creative" } });
54752
+ const raw = (resp?.data?.content || resp?.output || "").trim();
54753
+ try {
54754
+ const obj = JSON.parse(raw);
54755
+ if (typeof obj?.title === "string") return obj.title.trim();
54756
+ } catch {
54757
+ }
54758
+ const matched = raw.match(/```[a-z]*\s*([\s\S]*?)```/i);
54759
+ const text = matched ? matched[1].trim() : raw;
54760
+ return text.split("\n")[0].trim();
54761
+ }
54762
+ var NovelCommand, novel_command_default;
54763
+ var init_novel_command = __esm({
54764
+ "src/slash-commands/categories/creative/novel.command.ts"() {
54765
+ init_base_command();
54766
+ init_code_utils();
54767
+ init_api_caller();
54768
+ init_NovelArgumentInference();
54769
+ init_animations();
54770
+ NovelCommand = class extends BaseCommand {
54771
+ name = "novel";
54772
+ category = "creative";
54773
+ description = "Generate a novel: outline plan and full chapters with language/format options";
54774
+ aliases = ["story"];
54775
+ usage = "<idea or title> [--lang <code>] [--format md|txt] [--genre <name>] [--plan-only] [--chapters <n>]";
54776
+ examples = [
54777
+ { input: "/novel cyberpunk heist in Tokyo --lang ja", description: "\u65E5\u672C\u8A9E\u3067\u30B5\u30A4\u30D0\u30FC\u30D1\u30F3\u30AF\u5C0F\u8AAC\u3092\u751F\u6210" },
54778
+ { input: '/novel "A voyage to Europa" --format txt --genre sci-fi', description: "\u82F1\u8A9E\u30FB\u30D7\u30EC\u30FC\u30F3\u30C6\u30AD\u30B9\u30C8\u3067\u751F\u6210" },
54779
+ { input: "/novel detective mystery --plan-only", description: "\u30D7\u30ED\u30C3\u30C8\u306E\u307F\u3092\u4F5C\u6210\u3057\u3066\u4FDD\u5B58" }
54780
+ ];
54781
+ async execute(args2, context2) {
54782
+ const raw = Array.isArray(args2.raw) ? args2.raw : [];
54783
+ const ideaText = raw.join(" ").trim();
54784
+ if (!ideaText) {
54785
+ return this.error("Usage: /novel <idea or title> [--lang <code>] [--format md|txt] [--genre <name>] [--plan-only] [--chapters <n>]");
54786
+ }
54787
+ const explicit = {
54788
+ lang: typeof args2.options["lang"] === "string" ? String(args2.options["lang"]) : void 0,
54789
+ format: typeof args2.options["format"] === "string" ? String(args2.options["format"]) : void 0,
54790
+ genre: typeof args2.options["genre"] === "string" ? String(args2.options["genre"]) : void 0,
54791
+ chapters: typeof args2.options["chapters"] === "string" ? Number(args2.options["chapters"]) : void 0,
54792
+ planOnly: args2.flags["plan-only"] === true || args2.flags["sow"] === true
54793
+ };
54794
+ let inferred = {};
54795
+ try {
54796
+ const spin = new ProcessAnimation();
54797
+ spin.start();
54798
+ try {
54799
+ inferred = await inferNovelArgs(ideaText);
54800
+ } finally {
54801
+ try {
54802
+ spin.stop();
54803
+ } catch {
54804
+ }
54805
+ }
54806
+ } catch {
54807
+ }
54808
+ const lang = normalizeLang(explicit.lang || inferred.lang || "en");
54809
+ const format = normalizeFormat(explicit.format || inferred.format || "md");
54810
+ const planOnly = explicit.planOnly || inferred.planOnly === true;
54811
+ const chapters = Number.isFinite(explicit.chapters) && explicit.chapters > 0 ? Math.floor(explicit.chapters) : typeof inferred.chapters === "number" && inferred.chapters > 0 ? Math.floor(inferred.chapters) : 8;
54812
+ const genre = explicit.genre || inferred.genre;
54813
+ let generatedTitle = inferred.title;
54814
+ if (!generatedTitle) {
54815
+ const spin = new ProcessAnimation();
54816
+ spin.start();
54817
+ try {
54818
+ generatedTitle = await generateTitle(ideaText, lang, genre);
54819
+ } finally {
54820
+ try {
54821
+ spin.stop();
54822
+ } catch {
54823
+ }
54824
+ }
54825
+ }
54826
+ const titleRaw = (generatedTitle || "novel").slice(0, 120);
54827
+ const title = sanitizeFilenameStrict(titleRaw);
54828
+ const root = process.cwd();
54829
+ const novelDir = await ensureUniquePath(safeResolve(root, path11__namespace.join("novel", title)));
54830
+ await fsp__namespace.mkdir(novelDir, { recursive: true });
54831
+ let plan = "";
54832
+ {
54833
+ const spin = new ProcessAnimation();
54834
+ spin.start();
54835
+ try {
54836
+ plan = await generatePlan(ideaText, lang, title, genre);
54837
+ } finally {
54838
+ try {
54839
+ spin.stop();
54840
+ } catch {
54841
+ }
54842
+ }
54843
+ }
54844
+ const planExt = format === "txt" ? ".txt" : ".md";
54845
+ const planPath = await ensureUniquePath(path11__namespace.join(novelDir, `00_plan${planExt}`));
54846
+ await writeText(planPath, plan);
54847
+ if (planOnly) {
54848
+ const msg2 = [`Saved plan to ${planPath}`, "", "Files:", `- ${planPath}`].join("\n");
54849
+ return this.success(msg2, { dir: novelDir, plan: planPath });
54850
+ }
54851
+ const chapterObjs = await (async () => {
54852
+ const spin = new ProcessAnimation();
54853
+ spin.start();
54854
+ try {
54855
+ return await generateChapters(plan, lang, chapters);
54856
+ } finally {
54857
+ try {
54858
+ spin.stop();
54859
+ } catch {
54860
+ }
54861
+ }
54862
+ })();
54863
+ let index = 1;
54864
+ const saved = [planPath];
54865
+ for (const ch of chapterObjs) {
54866
+ const num = String(index).padStart(2, "0");
54867
+ const chTitle = sanitizeFilenameStrict(ch.title || `chapter-${index}`);
54868
+ const file = path11__namespace.join(novelDir, `${num}_${chTitle}${planExt}`);
54869
+ const finalPath = await ensureUniquePath(file);
54870
+ const content = format === "md" ? `# ${ch.title}
54871
+
54872
+ ${ch.content}` : ch.content;
54873
+ await writeText(finalPath, content);
54874
+ saved.push(finalPath);
54875
+ index++;
54876
+ }
54877
+ const msg = [
54878
+ `Saved novel to ${novelDir}`,
54879
+ "",
54880
+ "Files:",
54881
+ ...saved.map((p) => `- ${p}`)
54882
+ ].join("\n");
54883
+ return this.success(msg, { dir: novelDir, files: saved });
54884
+ }
54885
+ };
54886
+ novel_command_default = NovelCommand;
54887
+ }
54888
+ });
54889
+ function handleRateLimitError(error2) {
54890
+ console.log();
54891
+ console.log(chalk14__default.default.yellow("\u23F1\uFE0F Rate Limit Exceeded"));
54892
+ console.log(chalk14__default.default.gray("\u2501".repeat(50)));
54893
+ const route = error2.route || error2.details?.endpoint || "API";
54894
+ const plan = error2.plan || error2.details?.plan || "Unknown";
54895
+ const limit = error2.limit || (error2.details?.limit ? parseInt(error2.details.limit) : null);
54896
+ const retryAfter = error2.retryAfter || error2.details?.retryAfterSeconds;
54897
+ const resetAt = error2.resetAt || (error2.details?.resetAt ? Date.parse(error2.details.resetAt) : null);
54898
+ const waitTime = Number.isFinite(retryAfter) ? `${retryAfter} second${retryAfter > 1 ? "s" : ""}` : "a few seconds";
54899
+ let resetTime = "";
54900
+ if (resetAt && Number.isFinite(resetAt)) {
54901
+ const resetDate = new Date(resetAt);
54902
+ const now2 = /* @__PURE__ */ new Date();
54903
+ const diffMs = resetDate.getTime() - now2.getTime();
54904
+ if (diffMs > 0 && diffMs < 6e4) {
54905
+ resetTime = `in ${Math.ceil(diffMs / 1e3)} seconds`;
54906
+ } else if (diffMs > 0) {
54907
+ resetTime = `at ${resetDate.toLocaleTimeString()}`;
54908
+ }
54909
+ }
54910
+ console.log(chalk14__default.default.white(`Plan: ${chalk14__default.default.bold(plan)}`));
54911
+ console.log(chalk14__default.default.white(`Endpoint: ${chalk14__default.default.bold(route)}`));
54912
+ if (limit !== null) {
54913
+ console.log(chalk14__default.default.white(`Limit: ${chalk14__default.default.bold(limit)} requests`));
54914
+ }
54915
+ if (error2.remaining !== void 0) {
54916
+ console.log(chalk14__default.default.white(`Remaining: ${chalk14__default.default.bold(error2.remaining)} requests`));
54917
+ }
54918
+ console.log();
54919
+ console.log(chalk14__default.default.cyan(`Please wait ${chalk14__default.default.bold(waitTime)} before trying again`));
54920
+ if (resetTime) {
54921
+ console.log(chalk14__default.default.gray(`Rate limit resets ${resetTime}`));
54922
+ }
54923
+ if (error2.hint) {
54924
+ console.log();
54925
+ console.log(chalk14__default.default.magenta("\u{1F4A1} " + error2.hint));
54926
+ }
54927
+ console.log(chalk14__default.default.gray("\u2501".repeat(50)));
54928
+ console.log();
54929
+ }
54930
+ async function parseRateLimitResponse(response) {
54931
+ if (response.status !== 429) {
54932
+ return null;
54933
+ }
54934
+ const rateLimitInfo = {
54935
+ limit: parseInt(response.headers.get("RateLimit-Limit") || "0") || void 0,
54936
+ remaining: parseInt(response.headers.get("RateLimit-Remaining") || "0") || void 0,
54937
+ resetAt: parseInt(response.headers.get("RateLimit-Reset") || "0") || void 0,
54938
+ retryAfter: parseInt(response.headers.get("Retry-After") || "0") || void 0
54939
+ };
54940
+ try {
54941
+ const data = await response.json();
54942
+ if (data.error === "rate_limited" || data.error === "rate_limit_exceeded") {
54943
+ return {
54944
+ ...data,
54945
+ // Merge header info if not in body
54946
+ limit: data.limit || rateLimitInfo.limit,
54947
+ remaining: data.remaining || rateLimitInfo.remaining,
54948
+ resetAt: data.resetAt || rateLimitInfo.resetAt,
54949
+ retryAfter: data.retryAfter || rateLimitInfo.retryAfter
54950
+ };
54951
+ }
54952
+ return {
54953
+ error: "rate_limited",
54954
+ message: data.message || "Rate limit exceeded. Please wait and try again.",
54955
+ hint: data.hint || "Consider upgrading your plan for higher limits.",
54956
+ ...rateLimitInfo
54957
+ };
54958
+ } catch {
54959
+ return {
54960
+ error: "rate_limited",
54961
+ message: "Rate limit exceeded. Please wait and try again.",
54962
+ hint: "Consider upgrading your plan for higher limits.",
54963
+ ...rateLimitInfo
54964
+ };
54965
+ }
54966
+ }
54967
+ var init_rate_limit_handler = __esm({
54968
+ "src/services/api-client/rate-limit-handler.ts"() {
54969
+ }
54970
+ });
54971
+
54972
+ // src/services/code-orchestrator/ArgumentInference.ts
54973
+ function extractFirstJson5(text) {
54656
54974
  const fence = /```json\r?\n([\s\S]*?)```/i.exec(text);
54657
54975
  if (fence) return fence[1];
54658
54976
  const start = text.indexOf("{");
@@ -54686,7 +55004,7 @@ ${rawText}`,
54686
55004
  }
54687
55005
  });
54688
55006
  const raw = (resp?.data?.content || resp?.output || "").trim();
54689
- const jsonText = extractFirstJson4(raw) || raw;
55007
+ const jsonText = extractFirstJson5(raw) || raw;
54690
55008
  let parsed = {};
54691
55009
  try {
54692
55010
  parsed = JSON.parse(jsonText);
@@ -54798,10 +55116,10 @@ function suggestName(fp, p) {
54798
55116
  const base = (fp.description || "file").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
54799
55117
  return base || "file";
54800
55118
  }
54801
- function guessKindByPath(path64) {
54802
- if (/__tests__|\.spec\.(t|j)sx?$|^tests\//.test(path64)) return "test";
54803
- if (/^docs\//.test(path64) || /\.md$/.test(path64)) return "doc";
54804
- if (/\.(json|cjs|js|ts)$/.test(path64) && !/src\//.test(path64)) return "config";
55119
+ function guessKindByPath(path65) {
55120
+ if (/__tests__|\.spec\.(t|j)sx?$|^tests\//.test(path65)) return "test";
55121
+ if (/^docs\//.test(path65) || /\.md$/.test(path65)) return "doc";
55122
+ if (/\.(json|cjs|js|ts)$/.test(path65) && !/src\//.test(path65)) return "config";
54805
55123
  return "source";
54806
55124
  }
54807
55125
  var init_PathInferencer = __esm({
@@ -55065,9 +55383,9 @@ function formatPlanAsDiff(files, opts) {
55065
55383
  function readCurrentFileSafe(root, rel, abs) {
55066
55384
  if (!root && !abs) return "";
55067
55385
  try {
55068
- const fs51 = __require("fs");
55386
+ const fs52 = __require("fs");
55069
55387
  const p = abs ? abs : __require("path").join(root, rel);
55070
- return fs51.existsSync(p) ? fs51.readFileSync(p, "utf8") : "";
55388
+ return fs52.existsSync(p) ? fs52.readFileSync(p, "utf8") : "";
55071
55389
  } catch {
55072
55390
  return "";
55073
55391
  }
@@ -55402,7 +55720,8 @@ async function listRepoFiles(root) {
55402
55720
  }
55403
55721
  for (const e2 of entries) {
55404
55722
  const name2 = e2.name;
55405
- if (name2 === ".git" || name2 === "node_modules" || name2 === "dist" || name2 === ".maria") continue;
55723
+ if (name2 === ".git" || name2 === "node_modules" || name2 === "dist" || name2 === ".maria" || // macOS system/hidden dirs that shouldn't be scanned
55724
+ name2 === ".DS_Store" || name2 === ".Spotlight-V100" || name2 === ".Trashes" || name2 === ".fseventsd" || name2 === ".TemporaryItems") continue;
55406
55725
  const full = path11__namespace.default.join(dir, name2);
55407
55726
  const rel = path11__namespace.default.relative(root, full).replace(/\\/g, "/");
55408
55727
  if (e2.isDirectory()) {
@@ -55655,6 +55974,168 @@ var Orchestrator_exports = {};
55655
55974
  __export(Orchestrator_exports, {
55656
55975
  orchestrate: () => orchestrate
55657
55976
  });
55977
+ async function getRepoFiles(root) {
55978
+ if (_repoFileIndexCache && _repoFileIndexCache.root === root) return _repoFileIndexCache.files;
55979
+ const fs52 = await import('fs/promises');
55980
+ const pathMod = await import('path');
55981
+ const ignoreDir = /* @__PURE__ */ new Set([
55982
+ ".git",
55983
+ "node_modules",
55984
+ "dist",
55985
+ "build",
55986
+ ".maria",
55987
+ ".next",
55988
+ "coverage",
55989
+ ".DS_Store",
55990
+ ".Spotlight-V100",
55991
+ ".Trashes",
55992
+ ".fseventsd",
55993
+ ".TemporaryItems"
55994
+ ]);
55995
+ const out = [];
55996
+ async function walk2(dir) {
55997
+ let entries = [];
55998
+ try {
55999
+ entries = await fs52.readdir(dir, { withFileTypes: true });
56000
+ } catch {
56001
+ return;
56002
+ }
56003
+ for (const e2 of entries) {
56004
+ const name2 = e2.name;
56005
+ if (ignoreDir.has(name2)) continue;
56006
+ const full = pathMod.join(dir, name2);
56007
+ if (e2.isDirectory()) {
56008
+ await walk2(full);
56009
+ continue;
56010
+ }
56011
+ out.push(pathMod.relative(root, full).replace(/\\/g, "/"));
56012
+ }
56013
+ }
56014
+ await walk2(root);
56015
+ _repoFileIndexCache = { root, files: out };
56016
+ return out;
56017
+ }
56018
+ function languageFromExt(ext2) {
56019
+ const e2 = ext2.toLowerCase().replace(/^\./, "");
56020
+ if (e2 === "ts") return "typescript";
56021
+ if (e2 === "tsx") return "tsx";
56022
+ if (e2 === "js" || e2 === "mjs" || e2 === "cjs") return "javascript";
56023
+ if (e2 === "jsx") return "jsx";
56024
+ if (e2 === "json") return "json";
56025
+ if (e2 === "html") return "html";
56026
+ if (e2 === "css" || e2 === "scss") return "css";
56027
+ if (e2 === "md") return "markdown";
56028
+ if (e2 === "yaml" || e2 === "yml") return "yaml";
56029
+ return void 0;
56030
+ }
56031
+ async function readHeadTail(root, rel, n) {
56032
+ try {
56033
+ const fs52 = await import('fs/promises');
56034
+ const pathMod = await import('path');
56035
+ const full = pathMod.join(root, rel);
56036
+ const buf = await fs52.readFile(full, "utf8");
56037
+ const lines = buf.split(/\r?\n/);
56038
+ const head2 = lines.slice(0, n).join("\n");
56039
+ const tail = lines.slice(Math.max(0, lines.length - n)).join("\n");
56040
+ return { head: head2, tail };
56041
+ } catch {
56042
+ return { head: "", tail: "" };
56043
+ }
56044
+ }
56045
+ async function llmSelectEditTargets(root, request, repoFiles) {
56046
+ try {
56047
+ const candidates = repoFiles.filter((p) => /\.(html|css|js|ts|tsx)$/i.test(p)).slice(0, 150);
56048
+ const samples = [];
56049
+ for (const p of candidates.slice(0, 60)) {
56050
+ const h2 = await readHeadTail(root, p, 5);
56051
+ samples.push(`- ${p}
56052
+ ${h2.head}`);
56053
+ }
56054
+ const system = [
56055
+ "You select existing repository files that should be EDITED to satisfy a user request.",
56056
+ "Consider path names and the first lines. Return JSON array of repo-relative paths to edit.",
56057
+ "Keep the list short (<= 10). If none are relevant, return []. Do not invent paths."
56058
+ ].join("\n");
56059
+ const user = [`Request: ${request}`, "Candidates:", samples.join("\n\n")].join("\n\n");
56060
+ const resp = await executeChat([
56061
+ { role: "system", content: system },
56062
+ { role: "user", content: user }
56063
+ ]);
56064
+ const raw = (resp?.output || "").trim();
56065
+ const jsonText = (() => {
56066
+ try {
56067
+ const m2 = raw.match(/\[[\s\S]*\]/);
56068
+ return m2 ? m2[0] : raw;
56069
+ } catch {
56070
+ return raw;
56071
+ }
56072
+ })();
56073
+ const arr = JSON.parse(jsonText);
56074
+ const set = new Set(candidates.map((c) => c.toLowerCase()));
56075
+ const out = [];
56076
+ if (Array.isArray(arr)) {
56077
+ for (const v of arr) {
56078
+ if (typeof v === "string" && set.has(v.toLowerCase())) out.push(v);
56079
+ if (out.length >= 10) break;
56080
+ }
56081
+ }
56082
+ return out;
56083
+ } catch {
56084
+ return [];
56085
+ }
56086
+ }
56087
+ async function llmMapBlockToFile(root, request, block, repoFiles) {
56088
+ try {
56089
+ const lang = (block.language || "").toLowerCase();
56090
+ const extFilter = lang.includes("html") ? /\.html$/i : /(ts|tsx)/.test(lang) ? /\.(ts|tsx)$/i : /(js|jsx)/.test(lang) ? /\.(js|jsx)$/i : /\.css$/i;
56091
+ const candidates = repoFiles.filter((p) => extFilter.test(p)).slice(0, 80);
56092
+ const head2 = block.code.split(/\r?\n/).slice(0, 20).join("\n");
56093
+ const samples = [];
56094
+ for (const p of candidates.slice(0, 40)) {
56095
+ const h2 = await readHeadTail(root, p, 8);
56096
+ samples.push(`- ${p}
56097
+ ${h2.head}`);
56098
+ }
56099
+ const system = [
56100
+ "Decide where to apply an EDIT vs CREATE for a code block within an existing repository.",
56101
+ 'Return JSON: { "action": "modify"|"create", "path": string }.',
56102
+ "If modify, path must be one of the candidate repo-relative paths. If create, propose a sensible repo-relative path."
56103
+ ].join("\n");
56104
+ const user = [
56105
+ `Request: ${request}`,
56106
+ "Block:",
56107
+ "```",
56108
+ head2,
56109
+ "```",
56110
+ "Candidates:",
56111
+ samples.join("\n\n")
56112
+ ].join("\n");
56113
+ const resp = await executeChat([
56114
+ { role: "system", content: system },
56115
+ { role: "user", content: user }
56116
+ ]);
56117
+ const raw = (resp?.output || "").trim();
56118
+ const jsonText = (() => {
56119
+ try {
56120
+ const m2 = raw.match(/\{[\s\S]*\}/);
56121
+ return m2 ? m2[0] : raw;
56122
+ } catch {
56123
+ return raw;
56124
+ }
56125
+ })();
56126
+ const parsed = JSON.parse(jsonText);
56127
+ if (parsed && (parsed.action === "modify" || parsed.action === "create") && typeof parsed.path === "string") {
56128
+ return { action: parsed.action, path: parsed.path.replace(/^\/+/, "") };
56129
+ }
56130
+ } catch {
56131
+ }
56132
+ const desired = typeof block.filename === "string" && block.filename.trim() ? block.filename.trim() : null;
56133
+ const fallback2 = desired || suggestName2(request, block.language, 0);
56134
+ return { action: "create", path: fallback2 };
56135
+ }
56136
+ function tokenizeRequest(text) {
56137
+ return Array.from(new Set(text.toLowerCase().replace(/[^a-z0-9_-]+/g, " ").split(/\s+/).filter((t2) => t2.length >= 3)));
56138
+ }
55658
56139
  async function ensureCodeFallbackManager() {
55659
56140
  const policy = await loadFallbackPolicy().catch(() => getDefaultFallbackPolicy());
55660
56141
  const signature = JSON.stringify(policy);
@@ -55693,11 +56174,19 @@ async function orchestrate(request, opts) {
55693
56174
  explicitAbsMap[rel] = pathMod.join(opts.root, rel);
55694
56175
  }
55695
56176
  }
55696
- const isEditIntent = detectEditIntent(request, {
56177
+ const isEditIntent = await detectEditIntentEnhanced(opts.root, request, {
55697
56178
  hasAttachments: !!(opts.attachedFiles && opts.attachedFiles.length > 0),
55698
- explicitFilesCount: explicitFiles.length
55699
- });
55700
- const editContext = isEditIntent && explicitFiles.length > 0 ? await buildEditContext(opts.root, explicitFiles, 200, 512 * 1024) : "";
56179
+ explicitFiles});
56180
+ let editTargets = explicitFiles;
56181
+ if (isEditIntent && editTargets.length === 0) {
56182
+ try {
56183
+ const repoFiles = await getRepoFiles(opts.root);
56184
+ const llmTargets = await llmSelectEditTargets(opts.root, request, repoFiles);
56185
+ editTargets = llmTargets;
56186
+ } catch {
56187
+ }
56188
+ }
56189
+ const editContext = isEditIntent && editTargets.length > 0 ? await buildEditContext(opts.root, editTargets, 200, 512 * 1024) : "";
55701
56190
  if (opts.attachedFiles && opts.attachedFiles.length > 0) {
55702
56191
  const mapRes = await mapAttachmentsToTargets(opts.attachedFiles, {
55703
56192
  root: opts.root,
@@ -55754,16 +56243,17 @@ ${editContext}`;
55754
56243
  data_base64: f3.content ? Buffer.from(f3.content, "utf8").toString("base64") : void 0
55755
56244
  })).map((a) => a.data_base64 ? a : { ...a, data_base64: void 0 }) : [];
55756
56245
  const pathAttachments = [];
56246
+ const attachedPathSet = /* @__PURE__ */ new Set();
55757
56247
  if (explicitFiles.length > 0) {
55758
56248
  try {
55759
- const fs51 = await import('fs/promises');
56249
+ const fs52 = await import('fs/promises');
55760
56250
  const pathMod = await import('path');
55761
56251
  for (const rel of explicitFiles) {
55762
56252
  try {
55763
56253
  const full = explicitAbsMap[rel] || pathMod.join(opts.root, rel);
55764
- const stat13 = await fs51.stat(full).catch(() => null);
56254
+ const stat13 = await fs52.stat(full).catch(() => null);
55765
56255
  if (!stat13 || !stat13.isFile()) continue;
55766
- const buf = await fs51.readFile(full);
56256
+ const buf = await fs52.readFile(full);
55767
56257
  const ext2 = (pathMod.extname(full) || "").toLowerCase();
55768
56258
  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
56259
  pathAttachments.push({
@@ -55772,6 +56262,33 @@ ${editContext}`;
55772
56262
  mime,
55773
56263
  data_base64: buf.toString("base64")
55774
56264
  });
56265
+ attachedPathSet.add(full.toLowerCase());
56266
+ } catch {
56267
+ }
56268
+ }
56269
+ } catch {
56270
+ }
56271
+ }
56272
+ if (isEditIntent && Array.isArray(editTargets) && editTargets.length > 0) {
56273
+ try {
56274
+ const fs52 = await import('fs/promises');
56275
+ const pathMod = await import('path');
56276
+ for (const rel of editTargets) {
56277
+ try {
56278
+ const full = pathMod.isAbsolute(rel) ? rel : pathMod.join(opts.root, rel);
56279
+ const key = full.toLowerCase();
56280
+ if (attachedPathSet.has(key)) continue;
56281
+ const stat13 = await fs52.stat(full).catch(() => null);
56282
+ if (!stat13 || !stat13.isFile()) continue;
56283
+ const ext2 = (pathMod.extname(full) || "").toLowerCase();
56284
+ const buf = await fs52.readFile(full);
56285
+ pathAttachments.push({
56286
+ name: pathMod.basename(full),
56287
+ path: full,
56288
+ mime: "text/plain",
56289
+ data_base64: buf.toString("base64")
56290
+ });
56291
+ attachedPathSet.add(key);
55775
56292
  } catch {
55776
56293
  }
55777
56294
  }
@@ -55781,7 +56298,7 @@ ${editContext}`;
55781
56298
  const hydratedCtx = [];
55782
56299
  if (ctxAttachments.length > 0) {
55783
56300
  try {
55784
- const fs51 = await import('fs/promises');
56301
+ const fs52 = await import('fs/promises');
55785
56302
  for (const a of ctxAttachments) {
55786
56303
  if (a.data_base64) {
55787
56304
  hydratedCtx.push(a);
@@ -55792,12 +56309,12 @@ ${editContext}`;
55792
56309
  continue;
55793
56310
  }
55794
56311
  try {
55795
- const stat13 = await fs51.stat(p).catch(() => null);
56312
+ const stat13 = await fs52.stat(p).catch(() => null);
55796
56313
  if (!stat13 || !stat13.isFile()) {
55797
56314
  hydratedCtx.push(a);
55798
56315
  continue;
55799
56316
  }
55800
- const buf = await fs51.readFile(p);
56317
+ const buf = await fs52.readFile(p);
55801
56318
  hydratedCtx.push({ ...a, data_base64: buf.toString("base64") });
55802
56319
  } catch {
55803
56320
  hydratedCtx.push(a);
@@ -55847,46 +56364,60 @@ ${editContext}`;
55847
56364
  codeOutput = outcome.data?.output || "";
55848
56365
  }
55849
56366
  const blocks = extractBlocks(codeOutput);
55850
- if (explicitFiles.length > 0) {
56367
+ if (explicitFiles.length > 0 || isEditIntent && editTargets.length > 0) {
55851
56368
  const mapped = /* @__PURE__ */ new Set();
56369
+ const targets = explicitFiles.length > 0 ? explicitFiles : editTargets;
56370
+ const absMap = explicitFiles.length > 0 ? explicitAbsMap : /* @__PURE__ */ Object.create(null);
55852
56371
  const htmlIdx = blocks.findIndex((b) => /html/i.test(b.language));
55853
- const htmlFile = explicitFiles.find((f3) => f3.toLowerCase().endsWith(".html"));
56372
+ const htmlFile = targets.find((f3) => f3.toLowerCase().endsWith(".html"));
55854
56373
  if (htmlIdx >= 0 && htmlFile) {
55855
- initial.push({ path: htmlFile, absPath: explicitAbsMap[htmlFile], noNormalize: true, kind: "source", action: "create", description: "HTML page", language: "html", preview: blocks[htmlIdx].code });
56374
+ initial.push({ path: htmlFile, absPath: absMap[htmlFile], noNormalize: true, kind: "source", action: "modify", description: "HTML page", language: "html", preview: blocks[htmlIdx].code });
55856
56375
  mapped.add(htmlFile);
55857
56376
  }
55858
56377
  const jsIdx = blocks.findIndex((b) => /(ts|tsx|jsx|javascript|js)/i.test(b.language));
55859
- const jsFile = explicitFiles.find((f3) => f3.toLowerCase().endsWith(".js"));
56378
+ const jsFile = targets.find((f3) => f3.toLowerCase().endsWith(".js"));
55860
56379
  if (jsIdx >= 0 && jsFile && !mapped.has(jsFile)) {
55861
- initial.push({ path: jsFile, absPath: explicitAbsMap[jsFile], noNormalize: true, kind: "source", action: "create", description: "Script", language: "javascript", preview: blocks[jsIdx].code });
56380
+ initial.push({ path: jsFile, absPath: absMap[jsFile], noNormalize: true, kind: "source", action: "modify", description: "Script", language: "javascript", preview: blocks[jsIdx].code });
55862
56381
  mapped.add(jsFile);
55863
56382
  }
55864
56383
  const cssIdx = blocks.findIndex((b) => /css/i.test(b.language));
55865
- const cssFile = explicitFiles.find((f3) => f3.toLowerCase().endsWith(".css"));
56384
+ const cssFile = targets.find((f3) => f3.toLowerCase().endsWith(".css"));
55866
56385
  if (cssIdx >= 0 && cssFile && !mapped.has(cssFile)) {
55867
- initial.push({ path: cssFile, absPath: explicitAbsMap[cssFile], noNormalize: true, kind: "source", action: "create", description: "Stylesheet", language: "css", preview: blocks[cssIdx].code });
56386
+ initial.push({ path: cssFile, absPath: absMap[cssFile], noNormalize: true, kind: "source", action: "modify", description: "Stylesheet", language: "css", preview: blocks[cssIdx].code });
55868
56387
  mapped.add(cssFile);
55869
56388
  }
55870
- for (const f3 of explicitFiles) {
56389
+ for (const f3 of targets) {
55871
56390
  if (mapped.has(f3)) continue;
55872
- const plan = scaffoldForFilename(f3, explicitFiles);
55873
- plan.absPath = explicitAbsMap[f3];
55874
- plan.noNormalize = true;
55875
- initial.push(plan);
56391
+ const ext2 = (() => {
56392
+ const m2 = f3.lastIndexOf(".");
56393
+ return m2 >= 0 ? f3.slice(m2) : "";
56394
+ })();
56395
+ const lang = languageFromExt(ext2);
56396
+ const strongMatch = /pong|retro|game|index\.(html)$|script\.(js|ts)$|style\.css/i.test(f3) || tokenizeRequest(request).some((t2) => f3.toLowerCase().includes(t2));
56397
+ if (strongMatch) {
56398
+ initial.push({ path: f3, absPath: absMap[f3], noNormalize: true, kind: "source", action: "modify", description: "Edit target", language: lang, preview: "" });
56399
+ }
55876
56400
  }
55877
56401
  } else {
55878
- for (let i2 = 0; i2 < blocks.length; i2++) {
55879
- const b = blocks[i2];
55880
- const desired = typeof b.filename === "string" && b.filename.trim() ? b.filename.trim() : null;
55881
- const path64 = desired || suggestName2(request, b.language, i2);
55882
- initial.push({
55883
- path: path64,
55884
- kind: "source",
55885
- action: "create",
55886
- description: describe2(b.language, ""),
55887
- language: b.language,
55888
- preview: b.code
55889
- });
56402
+ try {
56403
+ const repoFiles = await getRepoFiles(opts.root);
56404
+ for (let i2 = 0; i2 < blocks.length; i2++) {
56405
+ const b = blocks[i2];
56406
+ const decision = await llmMapBlockToFile(opts.root, request, b, repoFiles);
56407
+ if (decision.action === "modify" && repoFiles.includes(decision.path)) {
56408
+ const lang = languageFromExt(decision.path.replace(/^.*(\.[a-z0-9]+)$/i, "$1"));
56409
+ initial.push({ path: decision.path, kind: "source", action: "modify", description: "Modify existing file", language: lang, preview: b.code });
56410
+ } else {
56411
+ const path65 = decision.path || suggestName2(request, b.language, i2);
56412
+ initial.push({ path: path65, kind: "source", action: "create", description: describe2(b.language, ""), language: b.language, preview: b.code });
56413
+ }
56414
+ }
56415
+ } catch {
56416
+ for (let i2 = 0; i2 < blocks.length; i2++) {
56417
+ const b = blocks[i2];
56418
+ const path65 = suggestName2(request, b.language, i2);
56419
+ initial.push({ path: path65, kind: "source", action: "create", description: describe2(b.language, ""), language: b.language, preview: b.code });
56420
+ }
55890
56421
  }
55891
56422
  }
55892
56423
  }
@@ -55911,13 +56442,13 @@ ${editContext}`;
55911
56442
  { root: opts.root }
55912
56443
  );
55913
56444
  try {
55914
- const [{ access: access18 }, path64] = await Promise.all([
56445
+ const [{ access: access18 }, path65] = await Promise.all([
55915
56446
  import('fs/promises'),
55916
56447
  import('path')
55917
56448
  ]);
55918
56449
  for (const p of normalized) {
55919
56450
  try {
55920
- const absCandidate = p.absPath ? p.absPath : path64.join(opts.root, p.path);
56451
+ const absCandidate = p.absPath ? p.absPath : path65.join(opts.root, p.path);
55921
56452
  await access18(absCandidate);
55922
56453
  p.action = "modify";
55923
56454
  if (isEditIntent) {
@@ -55926,6 +56457,9 @@ ${editContext}`;
55926
56457
  } catch {
55927
56458
  p.action = "create";
55928
56459
  }
56460
+ if (p.action === "modify" && (!p.preview || p.preview.length === 0)) {
56461
+ p.action = "skip";
56462
+ }
55929
56463
  }
55930
56464
  } catch {
55931
56465
  }
@@ -56155,12 +56689,12 @@ function languageExt(lang) {
56155
56689
  }
56156
56690
  async function journalResume(root, request, files) {
56157
56691
  try {
56158
- const fs51 = await import('fs/promises');
56692
+ const fs52 = await import('fs/promises');
56159
56693
  const dir = path11__namespace.default.join(root, ".maria", "memory");
56160
- await fs51.mkdir(dir, { recursive: true });
56694
+ await fs52.mkdir(dir, { recursive: true });
56161
56695
  const out = path11__namespace.default.join(dir, "resume-plan.json");
56162
56696
  const payload = { request, createdAt: (/* @__PURE__ */ new Date()).toISOString(), files };
56163
- await fs51.writeFile(out, JSON.stringify(payload, null, 2), "utf8");
56697
+ await fs52.writeFile(out, JSON.stringify(payload, null, 2), "utf8");
56164
56698
  } catch {
56165
56699
  }
56166
56700
  }
@@ -56288,6 +56822,68 @@ function detectEditIntent(request, ctx2) {
56288
56822
  const mentionsEdit = editKeywords.some((k) => r2.includes(k));
56289
56823
  return ctx2.hasAttachments || ctx2.explicitFilesCount > 0 || mentionsEdit;
56290
56824
  }
56825
+ async function detectEditIntentEnhanced(root, request, ctx2) {
56826
+ const baseline = detectEditIntent(request, { hasAttachments: ctx2.hasAttachments, explicitFilesCount: ctx2.explicitFiles.length });
56827
+ if (baseline) return true;
56828
+ const r2 = request.toLowerCase();
56829
+ const softHints = ["improve", "enhance", "make it", "change the", "adjust", "tweak", "rework", "revamp", "retro", "modernize", "clean up", "polish"];
56830
+ const hasSoftHint = softHints.some((k) => r2.includes(k));
56831
+ if (!hasSoftHint) return false;
56832
+ try {
56833
+ const fs52 = await import('fs/promises');
56834
+ const pathMod = await import('path');
56835
+ const { loadGlobby: loadGlobby2 } = await Promise.resolve().then(() => (init_esm_compat(), esm_compat_exports));
56836
+ const globby = await loadGlobby2();
56837
+ const ignore = [
56838
+ "**/node_modules/**",
56839
+ "**/.git/**",
56840
+ "**/dist/**",
56841
+ "**/build/**",
56842
+ "**/.maria/**",
56843
+ "**/.next/**",
56844
+ "**/coverage/**",
56845
+ "**/.DS_Store/**",
56846
+ "**/.DS_Store",
56847
+ "**/.Spotlight-V100/**",
56848
+ "**/.Spotlight-V100",
56849
+ "**/.Trashes/**",
56850
+ "**/.Trashes",
56851
+ "**/.fseventsd/**",
56852
+ "**/.fseventsd",
56853
+ "**/.TemporaryItems/**",
56854
+ "**/.TemporaryItems"
56855
+ ];
56856
+ const candidates = await globby(["**/*.{html,css,js,ts,tsx}"], { cwd: root, absolute: true, gitignore: true, ignore, deep: 3 });
56857
+ if (candidates && candidates.length > 0) return true;
56858
+ } catch {
56859
+ }
56860
+ try {
56861
+ const short = request.trim().length <= 160;
56862
+ if (!short) return false;
56863
+ const system = [
56864
+ "You are classifying whether the user intends to EDIT existing files vs CREATE a new project.",
56865
+ 'Return JSON: { "edit": true|false } only.'
56866
+ ].join("\n");
56867
+ const user = `Instruction: ${request}`;
56868
+ const resp = await executeChat([
56869
+ { role: "system", content: system },
56870
+ { role: "user", content: user }
56871
+ ]);
56872
+ const raw = (resp?.output || "").trim();
56873
+ const jsonText = (() => {
56874
+ try {
56875
+ const m2 = raw.match(/\{[\s\S]*\}/);
56876
+ return m2 ? m2[0] : raw;
56877
+ } catch {
56878
+ return raw;
56879
+ }
56880
+ })();
56881
+ const parsed = JSON.parse(jsonText);
56882
+ if (typeof parsed?.edit === "boolean") return !!parsed.edit;
56883
+ } catch {
56884
+ }
56885
+ return false;
56886
+ }
56291
56887
  function sanitizeFolderName(name2) {
56292
56888
  const base = name2.toLowerCase().replace(/[`~!@#$%^&*()+=\[\]{}|;:'",<>/?\\]/g, " ").replace(/\s+/g, "-").replace(/^-+|-+$/g, "").slice(0, 48);
56293
56889
  return base || "project";
@@ -56320,14 +56916,14 @@ async function ensureTopFolder(root, proposed, plans) {
56320
56916
  return { folderName: unique };
56321
56917
  }
56322
56918
  async function ensureUniqueFolder(root, base) {
56323
- const fs51 = await import('fs/promises');
56919
+ const fs52 = await import('fs/promises');
56324
56920
  const pathMod = await import('path');
56325
56921
  let name2 = sanitizeFolderName(base);
56326
56922
  let suffix = 0;
56327
56923
  for (; suffix < Number.MAX_SAFE_INTEGER; ) {
56328
56924
  const candidate = suffix === 0 ? name2 : `${name2}-${String(suffix).padStart(2, "0")}`;
56329
56925
  try {
56330
- await fs51.access(pathMod.join(root, candidate));
56926
+ await fs52.access(pathMod.join(root, candidate));
56331
56927
  suffix += 1;
56332
56928
  } catch {
56333
56929
  return candidate;
@@ -56337,13 +56933,13 @@ async function ensureUniqueFolder(root, base) {
56337
56933
  }
56338
56934
  async function buildEditContext(root, files, maxLines, maxBytes) {
56339
56935
  try {
56340
- const fs51 = await import('fs/promises');
56936
+ const fs52 = await import('fs/promises');
56341
56937
  const pathMod = await import('path');
56342
56938
  const sections = [];
56343
56939
  for (const rel of files) {
56344
56940
  const full = pathMod.join(root, rel);
56345
56941
  try {
56346
- const buf = await fs51.readFile(full);
56942
+ const buf = await fs52.readFile(full);
56347
56943
  const clipped = buf.length > maxBytes ? buf.subarray(0, maxBytes) : buf;
56348
56944
  const text = clipped.toString("utf8").replace(/\r\n/g, "\n");
56349
56945
  const lines = text.split("\n").slice(0, maxLines).join("\n");
@@ -56360,84 +56956,58 @@ ${lines}
56360
56956
  }
56361
56957
  }
56362
56958
  async function resolveExplicitPaths(root, files, hintText) {
56363
- const fs51 = await import('fs/promises');
56959
+ const fs52 = await import('fs/promises');
56364
56960
  const pathMod = await import('path');
56365
- const { loadGlobby: loadGlobby2 } = await Promise.resolve().then(() => (init_esm_compat(), esm_compat_exports));
56366
- const globby = await loadGlobby2();
56367
- const ignore = [
56368
- "**/node_modules/**",
56369
- "**/.git/**",
56370
- "**/dist/**",
56371
- "**/build/**",
56372
- "**/.maria/**",
56373
- "**/.next/**",
56374
- "**/coverage/**"
56375
- ];
56376
- const hintTokens = Array.from(new Set(hintText.toLowerCase().replace(/[^a-z0-9_/.-]+/g, " ").split(/\s+/).filter(Boolean)));
56377
- async function findBest(rel) {
56378
- const normalized = rel.replace(/^\/+/, "").replace(/\\/g, "/");
56379
- const fullExact = pathMod.join(root, normalized);
56380
- try {
56381
- await fs51.access(fullExact);
56382
- return normalized;
56383
- } catch {
56961
+ const ignoreDir = /* @__PURE__ */ new Set([
56962
+ ".git",
56963
+ "node_modules",
56964
+ "dist",
56965
+ "build",
56966
+ ".maria",
56967
+ ".next",
56968
+ "coverage",
56969
+ ".DS_Store",
56970
+ ".Spotlight-V100",
56971
+ ".Trashes",
56972
+ ".fseventsd",
56973
+ ".TemporaryItems"
56974
+ ]);
56975
+ async function buildRepoIndex() {
56976
+ if (_repoFileIndexCache && _repoFileIndexCache.root === root) return _repoFileIndexCache.files;
56977
+ const out2 = [];
56978
+ async function walk2(dir) {
56979
+ let entries = [];
56980
+ try {
56981
+ entries = await fs52.readdir(dir, { withFileTypes: true });
56982
+ } catch {
56983
+ return;
56984
+ }
56985
+ for (const e2 of entries) {
56986
+ const name2 = e2.name;
56987
+ if (ignoreDir.has(name2)) continue;
56988
+ const full = pathMod.join(dir, name2);
56989
+ if (e2.isDirectory()) {
56990
+ await walk2(full);
56991
+ continue;
56992
+ }
56993
+ out2.push(pathMod.relative(root, full).replace(/\\/g, "/"));
56994
+ }
56384
56995
  }
56996
+ await walk2(root);
56997
+ _repoFileIndexCache = { root, files: out2 };
56998
+ return out2;
56999
+ }
57000
+ const allFiles = await buildRepoIndex();
57001
+ const hintTokens = Array.from(new Set(hintText.toLowerCase().replace(/[^a-z0-9_/.-]+/g, " ").split(/\s+/).filter(Boolean)));
57002
+ async function rankCandidates(candidates, desired) {
57003
+ const normalized = desired.replace(/^\/+/, "").replace(/\\/g, "/");
56385
57004
  const lowerRel = normalized.toLowerCase();
56386
57005
  const ext2 = (pathMod.extname(normalized) || "").toLowerCase();
56387
57006
  const base = pathMod.basename(normalized);
56388
- const nameNoExt = base.replace(/\.[^.]+$/, "").toLowerCase();
57007
+ base.replace(/\.[^.]+$/, "").toLowerCase();
56389
57008
  const parentPath = pathMod.dirname(normalized);
56390
57009
  const parent = parentPath.split("/").pop() || "";
56391
57010
  const dirParts = parentPath === "." ? [] : parentPath.split("/").filter(Boolean).map((s2) => s2.toLowerCase());
56392
- const patterns = [];
56393
- patterns.push(`**/${normalized}`);
56394
- if (parent && parent !== "." && parent !== "/") patterns.push(`**/${parent}/${base}`);
56395
- if (base) patterns.push(`**/${base}`);
56396
- patterns.push(`**/*${base}`);
56397
- if (!ext2) {
56398
- patterns.push(`**/${nameNoExt}.*`);
56399
- }
56400
- const uniqPatterns = Array.from(new Set(patterns));
56401
- const candidatesSet = /* @__PURE__ */ new Set();
56402
- for (const pat of uniqPatterns) {
56403
- const found = await globby(pat, { cwd: root, absolute: false, gitignore: true, ignore });
56404
- for (const f3 of found) {
56405
- candidatesSet.add(f3.replace(/\\/g, "/"));
56406
- }
56407
- if (candidatesSet.size > 200) break;
56408
- }
56409
- let candidates = Array.from(candidatesSet);
56410
- if (dirParts.length > 0) {
56411
- const filtered = candidates.filter((relp) => {
56412
- const segs = relp.toLowerCase().split("/");
56413
- let pos = -1;
56414
- for (const part of dirParts) {
56415
- const next = segs.indexOf(part, pos + 1);
56416
- if (next === -1) return false;
56417
- pos = next;
56418
- }
56419
- return true;
56420
- });
56421
- if (filtered.length > 0) candidates = filtered;
56422
- }
56423
- if (candidates.length === 0) {
56424
- const prefixes = ["", "src/", "app/", "pages/"];
56425
- for (const pre of prefixes) {
56426
- const cand = pathMod.join(root, pre + normalized);
56427
- try {
56428
- await fs51.access(cand);
56429
- return (pre + normalized).replace(/^\/+/, "");
56430
- } catch {
56431
- }
56432
- }
56433
- if (dirParts.length > 0) {
56434
- if (/^(src|app|pages)\//i.test(normalized)) return normalized;
56435
- const pref = await pickExistingFolderPrefix(root, parentPath);
56436
- const combined = (pref + normalized).replace(/^\/+/, "").replace(/^(src\/)src\//i, "$1");
56437
- return combined;
56438
- }
56439
- return normalized.replace(/^(src\/)src\//i, "$1");
56440
- }
56441
57011
  function score(relPath) {
56442
57012
  const lower2 = relPath.toLowerCase();
56443
57013
  let s2 = 0;
@@ -56461,10 +57031,36 @@ async function resolveExplicitPaths(root, files, hintText) {
56461
57031
  s2 -= Math.min(10, Math.floor(relPath.length / 80));
56462
57032
  return s2;
56463
57033
  }
56464
- let best = candidates[0];
57034
+ const limited = candidates.slice(0, Math.min(50, candidates.length));
57035
+ if (limited.length > 1) {
57036
+ try {
57037
+ const ranked = limited.map((p) => ({ p, s: score(p) })).sort((a, b) => b.s - a.s).slice(0, 5).map((x2) => x2.p);
57038
+ const system = [
57039
+ "You are helping choose the most relevant target file path for an edit operation.",
57040
+ "Given a user request and several candidate repo-relative paths, pick ONE best path.",
57041
+ "Return ONLY the raw path text. No code blocks. No explanations."
57042
+ ].join("\n");
57043
+ const user = [
57044
+ `User request: ${hintText}`,
57045
+ "Candidates:",
57046
+ ...ranked.map((r2, i2) => `${i2 + 1}. ${r2}`),
57047
+ "",
57048
+ "Answer with exactly one of the candidate paths."
57049
+ ].join("\n");
57050
+ const chat = await executeChat([
57051
+ { role: "system", content: system },
57052
+ { role: "user", content: user }
57053
+ ]);
57054
+ const raw = (chat.output || "").trim();
57055
+ const pick = ranked.find((r2) => r2 === raw) || ranked.find((r2) => raw.includes(r2)) || ranked[0];
57056
+ return pick.replace(/^\/+/, "");
57057
+ } catch {
57058
+ }
57059
+ }
57060
+ let best = limited[0];
56465
57061
  let bestScore = score(best);
56466
- for (let i2 = 1; i2 < candidates.length; i2++) {
56467
- const c = candidates[i2];
57062
+ for (let i2 = 1; i2 < limited.length; i2++) {
57063
+ const c = limited[i2];
56468
57064
  const sc = score(c);
56469
57065
  if (sc > bestScore) {
56470
57066
  best = c;
@@ -56474,20 +57070,41 @@ async function resolveExplicitPaths(root, files, hintText) {
56474
57070
  return best.replace(/^\/+/, "");
56475
57071
  }
56476
57072
  const out = [];
56477
- for (const f3 of files) {
56478
- out.push(await findBest(f3));
57073
+ for (const desired of files) {
57074
+ const normalized = desired.replace(/^\/+/, "").replace(/\\/g, "/");
57075
+ if (allFiles.includes(normalized)) {
57076
+ out.push(normalized);
57077
+ continue;
57078
+ }
57079
+ const base = pathMod.basename(normalized).toLowerCase();
57080
+ const nameNoExt = base.replace(/\.[^.]+$/, "");
57081
+ const candidates = allFiles.filter((p) => {
57082
+ const b = pathMod.basename(p).toLowerCase();
57083
+ return b === base || b.includes(base) || !base.includes(".") && (b === `${nameNoExt}.ts` || b === `${nameNoExt}.js` || b.startsWith(nameNoExt));
57084
+ });
57085
+ if (candidates.length === 0) {
57086
+ const parentPath = pathMod.dirname(normalized);
57087
+ if (parentPath && parentPath !== ".") {
57088
+ const pref = await pickExistingFolderPrefix(root, parentPath);
57089
+ out.push((pref + normalized).replace(/^\/+/, "").replace(/^(src\/)src\//i, "$1"));
57090
+ } else {
57091
+ out.push(normalized.replace(/^(src\/)src\//i, "$1"));
57092
+ }
57093
+ continue;
57094
+ }
57095
+ out.push(await rankCandidates(candidates, normalized));
56479
57096
  }
56480
57097
  return out;
56481
57098
  }
56482
57099
  async function pickExistingFolderPrefix(root, parentPath) {
56483
- const fs51 = await import('fs/promises');
57100
+ const fs52 = await import('fs/promises');
56484
57101
  const pathMod = await import('path');
56485
57102
  const parts = parentPath.replace(/^\/+/, "").split("/").filter(Boolean);
56486
57103
  const prefixes = ["src", "app", "pages", ""];
56487
57104
  for (const pre of prefixes) {
56488
57105
  const test = pre ? pathMod.join(root, pre, ...parts) : pathMod.join(root, ...parts);
56489
57106
  try {
56490
- await fs51.access(test);
57107
+ await fs52.access(test);
56491
57108
  return pre ? `${pre}/` : "";
56492
57109
  } catch {
56493
57110
  }
@@ -56534,7 +57151,7 @@ requestAnimationFrame(step);`;
56534
57151
  }
56535
57152
  return { path: filename, kind: "source", action: "create", description: "Source file", preview: "" };
56536
57153
  }
56537
- var codeFallbackManager, codeFallbackPolicySignature;
57154
+ var codeFallbackManager, _repoFileIndexCache, codeFallbackPolicySignature;
56538
57155
  var init_Orchestrator = __esm({
56539
57156
  "src/services/code-orchestrator/Orchestrator.ts"() {
56540
57157
  init_RepoScanner();
@@ -56549,6 +57166,7 @@ var init_Orchestrator = __esm({
56549
57166
  init_FallbackManager();
56550
57167
  init_policy();
56551
57168
  codeFallbackManager = null;
57169
+ _repoFileIndexCache = null;
56552
57170
  codeFallbackPolicySignature = null;
56553
57171
  }
56554
57172
  });
@@ -56661,8 +57279,8 @@ var init_code_command = __esm({
56661
57279
  try {
56662
57280
  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
57281
  if (opts.planOnly) {
56664
- const fs51 = await import('fs/promises');
56665
- const path64 = await import('path');
57282
+ const fs52 = await import('fs/promises');
57283
+ const path65 = await import('path');
56666
57284
  const spec = res?.specMarkdown;
56667
57285
  const lines = Array.isArray(res?.summaryLines) ? res.summaryLines : [];
56668
57286
  const planItems = [];
@@ -56696,13 +57314,13 @@ var init_code_command = __esm({
56696
57314
  if (planItems.length) md.push(...planItems);
56697
57315
  else md.push("- (no summary available)");
56698
57316
  }
56699
- const plansDir = path64.join(root, ".maria", "plans");
56700
- await fs51.mkdir(plansDir, { recursive: true });
57317
+ const plansDir = path65.join(root, ".maria", "plans");
57318
+ await fs52.mkdir(plansDir, { recursive: true });
56701
57319
  const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
56702
57320
  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);
57321
+ const outPath = path65.join(plansDir, fileName);
57322
+ await fs52.writeFile(outPath, md.join("\n") + "\n", "utf8");
57323
+ const rel = path65.relative(root, outPath);
56706
57324
  return this.success(`Code plan saved: ${rel}`);
56707
57325
  }
56708
57326
  const detail = res?.detailLines;
@@ -56762,6 +57380,97 @@ ${pretty}`);
56762
57380
  // Add default language hints when not specified by the user (LLM-assisted detection)
56763
57381
  async ensureLanguageDefaults(raw) {
56764
57382
  try {
57383
+ const fs52 = await import('fs/promises');
57384
+ const pathMod = await import('path');
57385
+ const cwd2 = process.cwd();
57386
+ const ignoreDir = /* @__PURE__ */ new Set([".git", "node_modules", "dist", "build", ".maria", ".next", "coverage", ".DS_Store", ".Spotlight-V100", ".Trashes", ".fseventsd", ".TemporaryItems"]);
57387
+ const pathTokens = /* @__PURE__ */ new Set();
57388
+ const fileLike = raw.match(/([\w\-./\\:]+\.[A-Za-z0-9]{1,10})/g) || [];
57389
+ for (const t2 of fileLike) pathTokens.add(t2);
57390
+ const slashLike = raw.match(/[^\s"']*[\\/][^\s"']+/g) || [];
57391
+ for (const t2 of slashLike) pathTokens.add(t2);
57392
+ const listFilesUnder = async (dir, maxCount) => {
57393
+ const out = [];
57394
+ const walk2 = async (d) => {
57395
+ if (out.length >= maxCount) return;
57396
+ let entries = [];
57397
+ try {
57398
+ entries = await fs52.readdir(d, { withFileTypes: true });
57399
+ } catch {
57400
+ return;
57401
+ }
57402
+ for (const e2 of entries) {
57403
+ const name2 = e2.name;
57404
+ if (ignoreDir.has(name2)) continue;
57405
+ const full = pathMod.join(d, name2);
57406
+ if (e2.isDirectory()) {
57407
+ await walk2(full);
57408
+ if (out.length >= maxCount) break;
57409
+ continue;
57410
+ }
57411
+ if (/\.(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|html|css|scss|md|json)$/i.test(name2)) {
57412
+ out.push(full);
57413
+ if (out.length >= maxCount) break;
57414
+ }
57415
+ }
57416
+ };
57417
+ await walk2(dir);
57418
+ return out;
57419
+ };
57420
+ const readHead = async (full, lines) => {
57421
+ try {
57422
+ const buf = await fs52.readFile(full, "utf8");
57423
+ return buf.split(/\r?\n/).slice(0, lines).join("\n");
57424
+ } catch {
57425
+ return "";
57426
+ }
57427
+ };
57428
+ const samples = [];
57429
+ for (const tok of Array.from(pathTokens)) {
57430
+ const abs = pathMod.isAbsolute(tok) ? tok : pathMod.join(cwd2, tok);
57431
+ try {
57432
+ const st = await fs52.stat(abs);
57433
+ if (st.isFile()) {
57434
+ samples.push(await readHead(abs, 10));
57435
+ } else if (st.isDirectory()) {
57436
+ const files = await listFilesUnder(abs, 25);
57437
+ for (const f3 of files) samples.push(await readHead(f3, 10));
57438
+ }
57439
+ } catch {
57440
+ }
57441
+ if (samples.length >= 50) break;
57442
+ }
57443
+ if (samples.length > 0) {
57444
+ const preSpin = new ProcessAnimation();
57445
+ preSpin.start();
57446
+ let llmLang = null;
57447
+ try {
57448
+ llmLang = await this.detectLanguageLLMFromSamples(samples);
57449
+ } finally {
57450
+ try {
57451
+ preSpin.stop();
57452
+ } catch {
57453
+ }
57454
+ }
57455
+ if (llmLang) {
57456
+ const hint2 = (() => {
57457
+ const l = llmLang.toLowerCase();
57458
+ if (l === "tsx") return "TypeScript (React/TSX)";
57459
+ if (l === "jsx") return "JavaScript (React/JSX)";
57460
+ if (l === "typescript") return "TypeScript";
57461
+ if (l === "javascript") return "JavaScript";
57462
+ if (l === "html") return "HTML";
57463
+ if (l === "css") return "CSS";
57464
+ return llmLang;
57465
+ })();
57466
+ return raw + ` (Use ${hint2})`;
57467
+ }
57468
+ }
57469
+ } catch {
57470
+ }
57471
+ try {
57472
+ const preSpin = new ProcessAnimation();
57473
+ preSpin.start();
56765
57474
  const system = [
56766
57475
  "You analyze a user's code-generation request.",
56767
57476
  "Decide if the user explicitly specified a programming language or framework/tooling (e.g., TypeScript, Python, Rust, Java, React, Vue, Node, etc.).",
@@ -56780,8 +57489,12 @@ ${pretty}`);
56780
57489
  ${user}`
56781
57490
  }
56782
57491
  });
57492
+ try {
57493
+ preSpin.stop();
57494
+ } catch {
57495
+ }
56783
57496
  const content = (resp?.data?.content || resp?.content || "").trim();
56784
- const extractFirstJson6 = (text) => {
57497
+ const extractFirstJson7 = (text) => {
56785
57498
  const fence = /```\s*json\s*\r?\n([\s\S]*?)```/i.exec(text);
56786
57499
  if (fence) return fence[1];
56787
57500
  const generic = /```\s*\r?\n([\s\S]*?)```/i.exec(text);
@@ -56804,7 +57517,7 @@ ${user}`
56804
57517
  }
56805
57518
  return null;
56806
57519
  };
56807
- const jsonText = extractFirstJson6(content) || content;
57520
+ const jsonText = extractFirstJson7(content) || content;
56808
57521
  let parsed = {};
56809
57522
  try {
56810
57523
  parsed = JSON.parse(jsonText);
@@ -56817,6 +57530,76 @@ ${user}`
56817
57530
  const hint = " (Use TypeScript and React; prefer functional components and node)";
56818
57531
  return raw + hint;
56819
57532
  }
57533
+ // LLM-based language detection from sample code heads (top-10 lines per file)
57534
+ async detectLanguageLLMFromSamples(samples) {
57535
+ try {
57536
+ const system = [
57537
+ "You are a programming language classifier.",
57538
+ "Given multiple short code excerpts, determine the dominant language across them.",
57539
+ "Respond with ONLY a single token language name from this set:",
57540
+ "[typescript, tsx, javascript, jsx, python, java, go, rust, php, cpp, c, swift, kotlin, ruby, csharp, html, css, scss, json, yaml, markdown].",
57541
+ "If unsure between tsx and jsx, choose tsx if TypeScript types appear, else jsx."
57542
+ ].join("\n");
57543
+ const joined = samples.slice(0, 20).map((s2, i2) => `// sample ${i2 + 1}
57544
+ ${s2}`).join("\n\n");
57545
+ const { callAPI: callAPI2 } = await Promise.resolve().then(() => (init_api_caller(), api_caller_exports));
57546
+ const resp = await callAPI2("/v1/ai-proxy", {
57547
+ method: "POST",
57548
+ body: {
57549
+ provider: "google",
57550
+ model: "gemini-2.5-flash",
57551
+ taskType: "chat",
57552
+ prompt: `${system}
57553
+
57554
+ ${joined}`
57555
+ }
57556
+ });
57557
+ const content = (resp?.data?.content || resp?.content || "").trim();
57558
+ const token = content.replace(/```[\s\S]*?```/g, "").trim().toLowerCase();
57559
+ const norm = this.normalizeLanguageName(token);
57560
+ return norm || null;
57561
+ } catch {
57562
+ return null;
57563
+ }
57564
+ }
57565
+ normalizeLanguageName(lang) {
57566
+ const l = (lang || "").toLowerCase().trim();
57567
+ if (!l) return null;
57568
+ const map = {
57569
+ "ts": "typescript",
57570
+ "typescript": "typescript",
57571
+ "tsx": "tsx",
57572
+ "jsx": "jsx",
57573
+ "js": "javascript",
57574
+ "javascript": "javascript",
57575
+ "py": "python",
57576
+ "python": "python",
57577
+ "java": "java",
57578
+ "go": "go",
57579
+ "rust": "rust",
57580
+ "rs": "rust",
57581
+ "php": "php",
57582
+ "c++": "cpp",
57583
+ "cpp": "cpp",
57584
+ "c": "c",
57585
+ "swift": "swift",
57586
+ "kotlin": "kotlin",
57587
+ "rb": "ruby",
57588
+ "ruby": "ruby",
57589
+ "cs": "csharp",
57590
+ "c#": "csharp",
57591
+ "csharp": "csharp",
57592
+ "html": "html",
57593
+ "css": "css",
57594
+ "scss": "scss",
57595
+ "json": "json",
57596
+ "yaml": "yaml",
57597
+ "yml": "yaml",
57598
+ "markdown": "markdown",
57599
+ "md": "markdown"
57600
+ };
57601
+ return map[l] || null;
57602
+ }
56820
57603
  // v2.0 helpers
56821
57604
  parseV2Options(raw) {
56822
57605
  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 };
@@ -57012,16 +57795,16 @@ ${user}`
57012
57795
  }
57013
57796
  async persistLastPlan(root, plans) {
57014
57797
  try {
57015
- const fs51 = await import('fs/promises');
57798
+ const fs52 = await import('fs/promises');
57016
57799
  const p = path11__namespace.join(root, ".maria");
57017
- await fs51.mkdir(p, { recursive: true });
57800
+ await fs52.mkdir(p, { recursive: true });
57018
57801
  const out = path11__namespace.join(p, "last-plan.json");
57019
- await fs51.writeFile(out, JSON.stringify({ createdAt: (/* @__PURE__ */ new Date()).toISOString(), plans }, null, 2), "utf8");
57802
+ await fs52.writeFile(out, JSON.stringify({ createdAt: (/* @__PURE__ */ new Date()).toISOString(), plans }, null, 2), "utf8");
57020
57803
  } catch {
57021
57804
  }
57022
57805
  }
57023
57806
  async applyPlan(plans, options) {
57024
- const fs51 = await import('fs/promises');
57807
+ const fs52 = await import('fs/promises');
57025
57808
  const created = [];
57026
57809
  const modified = [];
57027
57810
  const skipped = [];
@@ -57040,9 +57823,9 @@ ${user}`
57040
57823
  continue;
57041
57824
  }
57042
57825
  const tmp = full + `.tmp-${process.pid}-${Date.now()}`;
57043
- await fs51.mkdir(path11__namespace.dirname(full), { recursive: true });
57044
- await fs51.writeFile(tmp, plan.preview || "", "utf8");
57045
- await fs51.rename(tmp, full);
57826
+ await fs52.mkdir(path11__namespace.dirname(full), { recursive: true });
57827
+ await fs52.writeFile(tmp, plan.preview || "", "utf8");
57828
+ await fs52.rename(tmp, full);
57046
57829
  if (exists2) modified.push(plan.path);
57047
57830
  else created.push(plan.path);
57048
57831
  written++;
@@ -57053,7 +57836,7 @@ ${user}`
57053
57836
  if (options.rollback) {
57054
57837
  for (const p of [...created, ...modified]) {
57055
57838
  try {
57056
- await fs51.unlink(path11__namespace.join(options.root, p));
57839
+ await fs52.unlink(path11__namespace.join(options.root, p));
57057
57840
  } catch {
57058
57841
  }
57059
57842
  }
@@ -57063,8 +57846,8 @@ ${user}`
57063
57846
  }
57064
57847
  async pathExists(p) {
57065
57848
  try {
57066
- const fs51 = await import('fs/promises');
57067
- await fs51.access(p);
57849
+ const fs52 = await import('fs/promises');
57850
+ await fs52.access(p);
57068
57851
  return true;
57069
57852
  } catch {
57070
57853
  return false;
@@ -57175,17 +57958,17 @@ ${user}`
57175
57958
  // Attempt to collect attached files from context; map to AttachedFileContext
57176
57959
  async collectAttachedFiles(context2) {
57177
57960
  const list = [];
57178
- const fs51 = await import('fs/promises');
57179
- const path64 = await import('path');
57961
+ const fs52 = await import('fs/promises');
57962
+ const path65 = await import('path');
57180
57963
  const att = context2 && (context2.attachments || context2.input?.attachments) || [];
57181
57964
  for (const a of att) {
57182
57965
  try {
57183
57966
  const p = a.path || a.filePath || a.name || "";
57184
- const originalName = a.name || path64.basename(p || `attachment_${Date.now().toString(36)}`);
57967
+ const originalName = a.name || path65.basename(p || `attachment_${Date.now().toString(36)}`);
57185
57968
  let content = a.content;
57186
57969
  if (!content && p) {
57187
- const abs = path64.isAbsolute(p) ? p : path64.join(process.cwd(), p);
57188
- content = await fs51.readFile(abs, "utf8");
57970
+ const abs = path65.isAbsolute(p) ? p : path65.join(process.cwd(), p);
57971
+ content = await fs52.readFile(abs, "utf8");
57189
57972
  }
57190
57973
  if (!content) continue;
57191
57974
  list.push({ originalName, pathHint: p || void 0, content, size: Buffer.byteLength(content, "utf8"), mime: a.mime || a.type });
@@ -63874,17 +64657,17 @@ var init_GraphEngine = __esm({
63874
64657
  const visited = /* @__PURE__ */ new Set();
63875
64658
  const queue = [{ id: from, path: [from] }];
63876
64659
  while (queue.length) {
63877
- const { id, path: path64 } = queue.shift();
64660
+ const { id, path: path65 } = queue.shift();
63878
64661
  if (visited.has(id)) continue;
63879
64662
  visited.add(id);
63880
64663
  const neighbors = this.edges.get(id) || /* @__PURE__ */ new Set();
63881
64664
  for (const e2 of neighbors) {
63882
64665
  if (e2.to === to) {
63883
- const res = [...path64, to];
64666
+ const res = [...path65, to];
63884
64667
  this.recordQueryTime(Date.now() - start);
63885
64668
  return res;
63886
64669
  }
63887
- if (!visited.has(e2.to)) queue.push({ id: e2.to, path: [...path64, e2.to] });
64670
+ if (!visited.has(e2.to)) queue.push({ id: e2.to, path: [...path65, e2.to] });
63888
64671
  }
63889
64672
  }
63890
64673
  this.recordQueryTime(Date.now() - start);
@@ -66551,12 +67334,12 @@ This will:
66551
67334
  };
66552
67335
  const result = await this.deltaDetector.detectDelta(root, deltaOptions);
66553
67336
  const files = [
66554
- ...result.changed.map((path64) => ({
66555
- _path: path64,
66556
- type: previousState?.fileHashes?.[path64] ? "modified" : "added"
67337
+ ...result.changed.map((path65) => ({
67338
+ _path: path65,
67339
+ type: previousState?.fileHashes?.[path65] ? "modified" : "added"
66557
67340
  })),
66558
- ...result.deleted.map((path64) => ({
66559
- _path: path64,
67341
+ ...result.deleted.map((path65) => ({
67342
+ _path: path65,
66560
67343
  type: "deleted"
66561
67344
  }))
66562
67345
  ];
@@ -69992,13 +70775,13 @@ async function checkShield(commandName, userPlan = "free") {
69992
70775
  }
69993
70776
  async function loadManifest() {
69994
70777
  try {
69995
- const fs51 = await import('fs');
69996
- const path64 = await import('path');
69997
- const manifestPath = path64.join(
70778
+ const fs52 = await import('fs');
70779
+ const path65 = await import('path');
70780
+ const manifestPath = path65.join(
69998
70781
  __dirname,
69999
70782
  "../command-manifest-v2.1.json"
70000
70783
  );
70001
- const content = fs51.readFileSync(manifestPath, "utf-8");
70784
+ const content = fs52.readFileSync(manifestPath, "utf-8");
70002
70785
  return JSON.parse(content);
70003
70786
  } catch {
70004
70787
  return { commands: [] };
@@ -71493,7 +72276,7 @@ ${user}`,
71493
72276
  };
71494
72277
  }
71495
72278
  });
71496
- function extractFirstJson5(text) {
72279
+ function extractFirstJson6(text) {
71497
72280
  const fence = /```json\r?\n([\s\S]*?)```/i.exec(text);
71498
72281
  if (fence) return fence[1];
71499
72282
  const start = text.indexOf("{");
@@ -71540,7 +72323,7 @@ ${user}`,
71540
72323
  }
71541
72324
  });
71542
72325
  const raw = (response?.data?.content || response?.output || "").trim();
71543
- const jsonText = extractFirstJson5(raw) || raw;
72326
+ const jsonText = extractFirstJson6(raw) || raw;
71544
72327
  let parsed = {};
71545
72328
  try {
71546
72329
  parsed = JSON.parse(jsonText);
@@ -72400,6 +73183,15 @@ async function registerBuiltInCommands() {
72400
73183
  } catch (error2) {
72401
73184
  console.error("Failed to register media commands:", error2);
72402
73185
  }
73186
+ try {
73187
+ const NovelModule = await Promise.resolve().then(() => (init_novel_command(), novel_command_exports));
73188
+ const NovelClass = NovelModule.NovelCommand || NovelModule.default;
73189
+ const novel = new NovelClass();
73190
+ if (novel.initialize) await novel.initialize();
73191
+ commandRegistry.register(novel);
73192
+ } catch (error2) {
73193
+ console.error("Failed to register novel command:", error2);
73194
+ }
72403
73195
  try {
72404
73196
  const { codeCommand: codeCommand2 } = await Promise.resolve().then(() => (init_code_command(), code_command_exports));
72405
73197
  try {
@@ -74932,16 +75724,16 @@ var init_ai_response_service = __esm({
74932
75724
  if (p) candidates.add(p);
74933
75725
  }
74934
75726
  if (candidates.size > 0) {
74935
- const fs51 = await import('fs/promises');
75727
+ const fs52 = await import('fs/promises');
74936
75728
  const pathMod = await import('path');
74937
75729
  const cwd2 = process.cwd();
74938
75730
  for (const cand of candidates) {
74939
75731
  try {
74940
75732
  const normalized = cand.replace(/^"|"$/g, "").replace(/^'|'$/g, "");
74941
75733
  const abs = pathMod.isAbsolute(normalized) ? normalized : pathMod.join(cwd2, normalized);
74942
- const st = await fs51.stat(abs).catch(() => null);
75734
+ const st = await fs52.stat(abs).catch(() => null);
74943
75735
  if (!st || !st.isFile()) continue;
74944
- const buf = await fs51.readFile(abs);
75736
+ const buf = await fs52.readFile(abs);
74945
75737
  const ext2 = (pathMod.extname(abs) || "").toLowerCase();
74946
75738
  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";
74947
75739
  autoAttachments.push({ name: pathMod.basename(abs), path: abs, mime, data_base64: buf.toString("base64") });