memorix 1.9.10 → 1.9.11

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.
Files changed (53) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/README.md +2 -0
  3. package/README.zh-CN.md +2 -0
  4. package/dist/cli/index.js +766 -210
  5. package/dist/index.js +195 -56
  6. package/dist/maintenance-runner.js +74 -20
  7. package/dist/media-audio-runner.js +74 -20
  8. package/dist/media-video-runner.js +74 -20
  9. package/dist/memcode/index.js +1532 -1002
  10. package/dist/memcode-runtime/CHANGELOG.md +33 -0
  11. package/dist/memcode-runtime/package.json +4 -4
  12. package/dist/sdk.js +194 -55
  13. package/dist/vector-backfill-runner.js +74 -20
  14. package/docs/CONFIGURATION.md +26 -0
  15. package/docs/DEVELOPMENT.md +3 -2
  16. package/docs/INTEGRATIONS.md +2 -0
  17. package/docs/README.md +2 -1
  18. package/docs/hooks-architecture.md +5 -0
  19. package/package.json +18 -11
  20. package/plugins/antigravity/memorix/plugin.json +1 -1
  21. package/plugins/claude/memorix/.claude-plugin/plugin.json +1 -1
  22. package/plugins/codebuddy/memorix/.codebuddy-plugin/plugin.json +1 -1
  23. package/plugins/codex/memorix/.codex-plugin/plugin.json +1 -1
  24. package/plugins/copilot/memorix/plugin.json +1 -1
  25. package/plugins/gemini/memorix/gemini-extension.json +1 -1
  26. package/plugins/hermes/memorix/plugin.yaml +1 -1
  27. package/plugins/omp/memorix/package.json +1 -1
  28. package/plugins/openclaw/memorix/.codex-plugin/plugin.json +1 -1
  29. package/plugins/pi/memorix/package.json +1 -1
  30. package/server.json +2 -2
  31. package/src/cli/commands/hooks-install.ts +2 -0
  32. package/src/cli/commands/init.ts +6 -2
  33. package/src/cli/commands/integrate.ts +2 -0
  34. package/src/cli/commands/setup.ts +1 -1
  35. package/src/cli/index.ts +2 -2
  36. package/src/cli/tui/ConfigureView.tsx +2 -0
  37. package/src/config/dotenv-loader.ts +1 -0
  38. package/src/config/resolved-config.ts +7 -3
  39. package/src/config/yaml-loader.ts +2 -2
  40. package/src/dashboard/server.ts +3 -0
  41. package/src/hooks/installers/index.ts +130 -10
  42. package/src/hooks/lifecycle.ts +4 -9
  43. package/src/hooks/normalizer.ts +6 -1
  44. package/src/hooks/types.ts +3 -1
  45. package/src/llm/provider.ts +2 -1
  46. package/src/memory/observations.ts +11 -0
  47. package/src/memory/session.ts +4 -13
  48. package/src/memory/visibility.ts +8 -2
  49. package/src/multimodal/image-loader.ts +6 -5
  50. package/src/server.ts +8 -4
  51. package/src/store/obs-store.ts +3 -0
  52. package/src/store/orama-store.ts +43 -6
  53. package/src/store/sqlite-store.ts +15 -0
package/dist/cli/index.js CHANGED
@@ -3232,7 +3232,7 @@ ${import_picocolors.default.gray(m3)} ${s4}
3232
3232
 
3233
3233
  // src/cli/version.ts
3234
3234
  function getCliVersion() {
3235
- return true ? "1.9.10" : pkg.version;
3235
+ return true ? "1.9.11" : pkg.version;
3236
3236
  }
3237
3237
  var init_version = __esm({
3238
3238
  "src/cli/version.ts"() {
@@ -13748,9 +13748,9 @@ function sharedAgentIds(record2) {
13748
13748
  return [];
13749
13749
  }
13750
13750
  }
13751
- function canReadObservation(record2, reader2) {
13751
+ function canReadObservation(record2, reader2, allowedProjectIds) {
13752
13752
  if (!reader2) return true;
13753
- const sameProject = reader2.projectId === record2.projectId;
13753
+ const sameProject = allowedProjectIds ? allowedProjectIds.includes(record2.projectId) : reader2.projectId === record2.projectId;
13754
13754
  const visibility = resolveObservationVisibility(record2);
13755
13755
  if (visibility === "project") return !reader2.projectId || sameProject;
13756
13756
  if (!sameProject || !reader2.agentId) return false;
@@ -22144,15 +22144,16 @@ function getResolvedConfig(options = {}) {
22144
22144
  const openRouterMemoryLlmApiKey = isOpenRouterMemoryLane(memoryLlmProvider, memoryLlmBaseUrl) ? process.env.OPENROUTER_API_KEY : void 0;
22145
22145
  const isAtlasCloud = memoryLlmProvider === "atlascloud";
22146
22146
  const isRequesty = memoryLlmProvider === "requesty";
22147
- const usesPresetKeyOnly = isAtlasCloud || isRequesty;
22147
+ const isApiRoute = memoryLlmProvider === "apiroute";
22148
+ const usesPresetKeyOnly = isAtlasCloud || isRequesty || isApiRoute;
22148
22149
  const memoryLlmApiKey = first(
22149
22150
  process.env.MEMORIX_LLM_API_KEY,
22150
22151
  process.env.MEMORIX_API_KEY,
22151
22152
  toml.memory?.llm?.api_key,
22152
22153
  yaml.llm?.apiKey,
22153
22154
  legacy.llm?.apiKey,
22154
- // Never borrow another provider's credentials for the Atlas Cloud or Requesty presets.
22155
- isAtlasCloud ? process.env.ATLASCLOUD_API_KEY : isRequesty ? process.env.REQUESTY_API_KEY : process.env.OPENAI_API_KEY,
22155
+ // Never borrow another provider's credentials for these gateway presets.
22156
+ isAtlasCloud ? process.env.ATLASCLOUD_API_KEY : isRequesty ? process.env.REQUESTY_API_KEY : isApiRoute ? process.env.API_ROUTE_API_KEY : process.env.OPENAI_API_KEY,
22156
22157
  usesPresetKeyOnly ? void 0 : process.env.ANTHROPIC_API_KEY,
22157
22158
  usesPresetKeyOnly ? void 0 : openRouterMemoryLlmApiKey
22158
22159
  );
@@ -22335,6 +22336,7 @@ function getEnvSourceNames() {
22335
22336
  "MEMORIX_CODEGRAPH_EXTERNAL_TIMEOUT_MS",
22336
22337
  "OPENROUTER_API_KEY",
22337
22338
  "REQUESTY_API_KEY",
22339
+ "API_ROUTE_API_KEY",
22338
22340
  "ATLASCLOUD_API_KEY"
22339
22341
  ].filter((name) => process.env[name]);
22340
22342
  }
@@ -25328,6 +25330,7 @@ var init_provider2 = __esm({
25328
25330
  anthropic: { baseUrl: "https://api.anthropic.com/v1", model: "claude-3-5-haiku-latest" },
25329
25331
  openrouter: { baseUrl: "https://openrouter.ai/api/v1", model: "openai/gpt-4.1-nano" },
25330
25332
  requesty: { baseUrl: "https://router.requesty.ai/v1", model: "openai/gpt-4.1-nano" },
25333
+ apiroute: { baseUrl: "https://global.api-route.com/v1", model: "deepseek-v4.1-flash" },
25331
25334
  atlascloud: { baseUrl: "https://api.atlascloud.ai/v1", model: "deepseek-ai/deepseek-v3.2" },
25332
25335
  custom: { baseUrl: "http://localhost:11434/v1", model: "llama3" }
25333
25336
  };
@@ -25822,6 +25825,19 @@ var init_sqlite_store = __esm({
25822
25825
  async listProjectIds() {
25823
25826
  return this.db.prepare("SELECT DISTINCT projectId FROM observations ORDER BY projectId").all().map((row) => row.projectId).filter((projectId) => Boolean(projectId));
25824
25827
  }
25828
+ async migrateProjectIds(aliasIds, canonicalId) {
25829
+ const sourceIds = [...new Set(aliasIds.filter((projectId) => projectId && projectId !== canonicalId))];
25830
+ if (sourceIds.length === 0) return 0;
25831
+ return retrySqliteBusy(async () => {
25832
+ const placeholders = sourceIds.map(() => "?").join(", ");
25833
+ const result = this.db.prepare(
25834
+ `UPDATE observations SET projectId = ? WHERE projectId IN (${placeholders})`
25835
+ ).run(canonicalId, ...sourceIds);
25836
+ const migrated = Number(result.changes ?? 0);
25837
+ if (migrated > 0) this.bumpGeneration();
25838
+ return migrated;
25839
+ }, "Migrate observation project IDs");
25840
+ }
25825
25841
  async searchLexical(options) {
25826
25842
  return searchObservationLexically(this.db, options).map((hit) => ({
25827
25843
  observation: rowToObs(hit.row),
@@ -186704,6 +186720,16 @@ function getProjectObservations(projectId) {
186704
186720
  async function migrateProjectIds(aliasIds, canonicalId) {
186705
186721
  const nonCanonical = new Set(aliasIds.filter((id) => id !== canonicalId));
186706
186722
  if (nonCanonical.size === 0) return 0;
186723
+ const store2 = projectDir ? getObservationStore() : null;
186724
+ if (store2?.migrateProjectIds) {
186725
+ const migrated2 = await store2.migrateProjectIds(aliasIds, canonicalId);
186726
+ if (migrated2 > 0 && corpusLoaded) {
186727
+ for (const observation of observations) {
186728
+ if (nonCanonical.has(observation.projectId)) observation.projectId = canonicalId;
186729
+ }
186730
+ }
186731
+ return migrated2;
186732
+ }
186707
186733
  let migrated = 0;
186708
186734
  const changed = [];
186709
186735
  for (const obs of observations) {
@@ -186714,8 +186740,8 @@ async function migrateProjectIds(aliasIds, canonicalId) {
186714
186740
  }
186715
186741
  }
186716
186742
  if (migrated > 0 && projectDir) {
186717
- const store2 = getObservationStore();
186718
- await store2.atomic(async (tx) => {
186743
+ const store3 = getObservationStore();
186744
+ await store3.atomic(async (tx) => {
186719
186745
  await Promise.all(changed.map((observation) => tx.update(observation)));
186720
186746
  });
186721
186747
  }
@@ -187668,6 +187694,7 @@ var orama_store_exports = {};
187668
187694
  __export(orama_store_exports, {
187669
187695
  _classifyQueryTier: () => classifyQueryTier,
187670
187696
  batchGenerateEmbeddings: () => batchGenerateEmbeddings,
187697
+ createSearchTokenizer: () => createSearchTokenizer,
187671
187698
  generateEmbedding: () => generateEmbedding,
187672
187699
  generateEmbeddingInput: () => generateEmbeddingInput,
187673
187700
  getActiveSemanticIndexProfile: () => getActiveSemanticIndexProfile,
@@ -187708,6 +187735,26 @@ function getOptionalObservationStore() {
187708
187735
  return null;
187709
187736
  }
187710
187737
  }
187738
+ function createSearchTokenizer() {
187739
+ const defaultTokenizer = components_exports2.tokenizer.createTokenizer({ language: "english" });
187740
+ return {
187741
+ language: defaultTokenizer.language,
187742
+ normalizationCache: defaultTokenizer.normalizationCache,
187743
+ tokenize(raw, language, prop, withCache = true) {
187744
+ const defaultTokens = defaultTokenizer.tokenize(raw, language, prop, withCache);
187745
+ const cjkTokens = [];
187746
+ const normalized = raw.normalize("NFKC").toLowerCase();
187747
+ for (const match2 of normalized.matchAll(CJK_RUN)) {
187748
+ const characters = Array.from(match2[0]);
187749
+ cjkTokens.push(...characters);
187750
+ for (let index = 0; index + 1 < characters.length; index++) {
187751
+ cjkTokens.push(`${characters[index]}${characters[index + 1]}`);
187752
+ }
187753
+ }
187754
+ return [.../* @__PURE__ */ new Set([...defaultTokens, ...cjkTokens])];
187755
+ }
187756
+ };
187757
+ }
187711
187758
  async function shouldUsePersistentSearch(projectIds, projectId) {
187712
187759
  const store2 = getOptionalObservationStore();
187713
187760
  if (!store2?.hasLexicalIndex?.()) return false;
@@ -187808,6 +187855,7 @@ async function searchPersistentSemantically(options, projectIds, limit2, queryVe
187808
187855
  const lexical = await searchPersistentLexically(options, projectIds, limit2);
187809
187856
  const store2 = getObservationStore();
187810
187857
  const documents = /* @__PURE__ */ new Map();
187858
+ const vectorDocumentKeys = /* @__PURE__ */ new Map();
187811
187859
  const addObservation = (observation) => {
187812
187860
  const document2 = observationToSearchDocument(observation);
187813
187861
  documents.set(makeEntryKey(document2.projectId, document2.observationId), document2);
@@ -187823,6 +187871,7 @@ async function searchPersistentSemantically(options, projectIds, limit2, queryVe
187823
187871
  if (options.type && observation.type !== options.type) return null;
187824
187872
  if (options.source && observation.source !== options.source) return null;
187825
187873
  addObservation(observation);
187874
+ vectorDocumentKeys.set(hit.observationId, makeEntryKey(observation.projectId, observation.id));
187826
187875
  return observation;
187827
187876
  }));
187828
187877
  const RRF_K = 60;
@@ -187832,7 +187881,7 @@ async function searchPersistentSemantically(options, projectIds, limit2, queryVe
187832
187881
  scores.set(key, (scores.get(key) ?? 0) + 0.6 / (RRF_K + index + 1));
187833
187882
  }
187834
187883
  for (const [index, hit] of vectorHits.entries()) {
187835
- const key = makeEntryKey(hit.projectId, hit.observationId);
187884
+ const key = vectorDocumentKeys.get(hit.observationId) ?? makeEntryKey(hit.projectId, hit.observationId);
187836
187885
  if (!documents.has(key)) continue;
187837
187886
  scores.set(key, (scores.get(key) ?? 0) + 0.4 / (RRF_K + index + 1));
187838
187887
  }
@@ -187845,12 +187894,13 @@ async function searchPersistentSemantically(options, projectIds, limit2, queryVe
187845
187894
  return {
187846
187895
  count: vectorHits.length,
187847
187896
  hits: vectorHits.map((hit, index) => {
187848
- const key = makeEntryKey(hit.projectId, hit.observationId);
187897
+ const key = vectorDocumentKeys.get(hit.observationId) ?? makeEntryKey(hit.projectId, hit.observationId);
187849
187898
  const document2 = documents.get(key);
187850
187899
  return document2 ? { id: document2.id, score: 0.4 / (RRF_K + index + 1), document: document2 } : null;
187851
187900
  }).filter((hit) => hit !== null).slice(0, limit2)
187852
187901
  };
187853
187902
  }
187903
+ if (hits.length === 0) return null;
187854
187904
  return { count: hits.length, hits };
187855
187905
  } catch {
187856
187906
  return null;
@@ -187925,7 +187975,10 @@ async function initializeDb(options, generation) {
187925
187975
  };
187926
187976
  const dims = nextEmbeddingDimensions ?? 384;
187927
187977
  const schema = nextEmbeddingEnabled ? { ...baseSchema, embedding: `vector[${dims}]` } : baseSchema;
187928
- const nextDb = await create5({ schema });
187978
+ const nextDb = await create5({
187979
+ schema,
187980
+ components: { tokenizer: createSearchTokenizer() }
187981
+ });
187929
187982
  if (generation !== dbGeneration) {
187930
187983
  return getDb(options);
187931
187984
  }
@@ -188359,7 +188412,7 @@ async function searchObservations(options) {
188359
188412
  if (!projectIds) return true;
188360
188413
  const doc = hit.document;
188361
188414
  return projectIds.includes(doc.projectId);
188362
- }).filter((hit) => canReadObservation(hit.document, options.reader)).filter((hit) => {
188415
+ }).filter((hit) => canReadObservation(hit.document, options.reader, projectIds ?? void 0)).filter((hit) => {
188363
188416
  if (statusFilter === "all") return true;
188364
188417
  const doc = hit.document;
188365
188418
  return (doc.status || "active") === statusFilter;
@@ -188625,7 +188678,7 @@ async function searchObservations(options) {
188625
188678
  let entries = intermediate.map(({ rawTime: _5, _isCommandLog: _c, ...rest }) => rest);
188626
188679
  for (const hit of results.hits) {
188627
188680
  const doc = hit.document;
188628
- if (canReadObservation(doc, options.reader)) rememberObservationDoc(doc);
188681
+ if (canReadObservation(doc, options.reader, projectIds ?? void 0)) rememberObservationDoc(doc);
188629
188682
  }
188630
188683
  if (hasQuery && originalQuery) {
188631
188684
  const queryLower = originalQuery.toLowerCase();
@@ -188783,7 +188836,7 @@ function formatTime(isoDate) {
188783
188836
  return isoDate;
188784
188837
  }
188785
188838
  }
188786
- var db, dbInitPromise, dbGeneration, embeddingEnabled, embeddingDimensions, indexEmbeddingProvider, deferredCachedVectorHydration, NON_CJK_HYBRID_SIMILARITY, lastSearchModeByProject, SEARCH_MODE_DEFAULT_KEY, MAX_SEARCH_MODE_KEYS, COMMAND_LOG_TITLE2, COMMAND_STYLE_TITLE, COMMAND_LIKE_QUERY2, COMMAND_INTENT_QUERY, NATURAL_LANGUAGE_MARKERS;
188839
+ var db, dbInitPromise, dbGeneration, embeddingEnabled, embeddingDimensions, indexEmbeddingProvider, deferredCachedVectorHydration, NON_CJK_HYBRID_SIMILARITY, CJK_RUN, lastSearchModeByProject, SEARCH_MODE_DEFAULT_KEY, MAX_SEARCH_MODE_KEYS, COMMAND_LOG_TITLE2, COMMAND_STYLE_TITLE, COMMAND_LIKE_QUERY2, COMMAND_INTENT_QUERY, NATURAL_LANGUAGE_MARKERS;
188787
188840
  var init_orama_store = __esm({
188788
188841
  "src/store/orama-store.ts"() {
188789
188842
  "use strict";
@@ -188808,6 +188861,7 @@ var init_orama_store = __esm({
188808
188861
  indexEmbeddingProvider = null;
188809
188862
  deferredCachedVectorHydration = null;
188810
188863
  NON_CJK_HYBRID_SIMILARITY = 0.45;
188864
+ CJK_RUN = /[\u3400-\u4dbf\u4e00-\u9fff\u3040-\u30ff\uac00-\ud7af]+/gu;
188811
188865
  lastSearchModeByProject = /* @__PURE__ */ new Map();
188812
188866
  SEARCH_MODE_DEFAULT_KEY = "__global__";
188813
188867
  MAX_SEARCH_MODE_KEYS = 4096;
@@ -193112,6 +193166,8 @@ function buildInitTomlConfig(options) {
193112
193166
  lines.push('# model = "openai/gpt-4o-mini"');
193113
193167
  } else if (options.llmProvider === "requesty") {
193114
193168
  lines.push('# model = "openai/gpt-4o-mini"');
193169
+ } else if (options.llmProvider === "apiroute") {
193170
+ lines.push('model = "deepseek-v4.1-flash"');
193115
193171
  } else if (options.llmProvider === "atlascloud") {
193116
193172
  lines.push('model = "deepseek-ai/deepseek-v3.2"');
193117
193173
  }
@@ -193247,6 +193303,7 @@ var init_init = __esm({
193247
193303
  { value: "anthropic", label: "Anthropic", hint: "claude-3-haiku" },
193248
193304
  { value: "openrouter", label: "OpenRouter", hint: "multi-provider" },
193249
193305
  { value: "requesty", label: "Requesty", hint: "multi-provider" },
193306
+ { value: "apiroute", label: "API Route", hint: "multi-provider" },
193250
193307
  { value: "atlascloud", label: "Atlas Cloud", hint: "DeepSeek V3.2" },
193251
193308
  { value: "custom", label: "Custom", hint: "OpenAI-compatible endpoint" }
193252
193309
  ]
@@ -193301,7 +193358,7 @@ var init_init = __esm({
193301
193358
  ];
193302
193359
  if (llmProvider !== "none") {
193303
193360
  envLines.push("# LLM API key");
193304
- if (llmProvider === "openai" || llmProvider === "custom" || llmProvider === "atlascloud") {
193361
+ if (llmProvider === "openai" || llmProvider === "custom" || llmProvider === "atlascloud" || llmProvider === "apiroute") {
193305
193362
  envLines.push("MEMORIX_LLM_API_KEY=sk-your-key-here");
193306
193363
  } else if (llmProvider === "anthropic") {
193307
193364
  envLines.push("MEMORIX_LLM_API_KEY=sk-ant-your-key-here");
@@ -193336,6 +193393,7 @@ var init_init = __esm({
193336
193393
  envLines.push("# ANTHROPIC_API_KEY=sk-ant-...");
193337
193394
  envLines.push("# OPENROUTER_API_KEY=sk-or-...");
193338
193395
  envLines.push("# REQUESTY_API_KEY=rqsty-...");
193396
+ envLines.push("# API_ROUTE_API_KEY=sk-...");
193339
193397
  envLines.push("");
193340
193398
  mkdirSync3(targetDir, { recursive: true });
193341
193399
  writeFileSync3(targetPath, tomlContent, "utf-8");
@@ -195224,6 +195282,26 @@ function generateClaudeConfig() {
195224
195282
  }
195225
195283
  };
195226
195284
  }
195285
+ function generateQwenConfig() {
195286
+ const cmd = `${resolveHookCommand()} hook --agent qwen`;
195287
+ const hookEntry = {
195288
+ type: "command",
195289
+ command: cmd,
195290
+ timeout: 10
195291
+ };
195292
+ return {
195293
+ hooks: {
195294
+ SessionStart: [{ hooks: [hookEntry] }],
195295
+ SessionEnd: [{ hooks: [hookEntry] }],
195296
+ PostToolUse: [{ hooks: [hookEntry] }],
195297
+ PostToolUseFailure: [{ hooks: [hookEntry] }],
195298
+ UserPromptSubmit: [{ hooks: [hookEntry] }],
195299
+ PreCompact: [{ hooks: [hookEntry] }],
195300
+ PostCompact: [{ hooks: [hookEntry] }],
195301
+ Stop: [{ hooks: [hookEntry] }]
195302
+ }
195303
+ };
195304
+ }
195227
195305
  function generateGrokConfig() {
195228
195306
  const cmd = `${resolveHookCommand()} hook --agent grok`;
195229
195307
  const hookEntry = {
@@ -195254,7 +195332,13 @@ function isMemorixGrokCommand(value) {
195254
195332
  function isMemorixGrokHook(value) {
195255
195333
  return isJsonRecord(value) && value.type === "command" && isMemorixGrokCommand(value.command);
195256
195334
  }
195257
- function mergeGrokHookConfig(existing, generated) {
195335
+ function isMemorixQwenCommand(value) {
195336
+ return value === "memorix hook --agent qwen" || value === "memorix.cmd hook --agent qwen";
195337
+ }
195338
+ function isMemorixQwenHook(value) {
195339
+ return isJsonRecord(value) && value.type === "command" && isMemorixQwenCommand(value.command);
195340
+ }
195341
+ function mergeCommandHookConfig(existing, generated, isOwnedHook) {
195258
195342
  const merged = { ...existing };
195259
195343
  const existingHooks = isJsonRecord(existing.hooks) ? { ...existing.hooks } : {};
195260
195344
  const generatedHooks = isJsonRecord(generated.hooks) ? generated.hooks : {};
@@ -195262,7 +195346,7 @@ function mergeGrokHookConfig(existing, generated) {
195262
195346
  const currentGroups = Array.isArray(existingHooks[event]) ? existingHooks[event] : [];
195263
195347
  const preservedGroups = currentGroups.flatMap((group) => {
195264
195348
  if (!isJsonRecord(group) || !Array.isArray(group.hooks)) return [group];
195265
- const preservedHooks = group.hooks.filter((hook) => !isMemorixGrokHook(hook));
195349
+ const preservedHooks = group.hooks.filter((hook) => !isOwnedHook(hook));
195266
195350
  if (preservedHooks.length === 0) return [];
195267
195351
  return [{ ...group, hooks: preservedHooks }];
195268
195352
  });
@@ -195271,7 +195355,13 @@ function mergeGrokHookConfig(existing, generated) {
195271
195355
  merged.hooks = existingHooks;
195272
195356
  return merged;
195273
195357
  }
195274
- function removeMemorixGrokHooks(config2) {
195358
+ function mergeGrokHookConfig(existing, generated) {
195359
+ return mergeCommandHookConfig(existing, generated, isMemorixGrokHook);
195360
+ }
195361
+ function mergeQwenHookConfig(existing, generated) {
195362
+ return mergeCommandHookConfig(existing, generated, isMemorixQwenHook);
195363
+ }
195364
+ function removeCommandHooks(config2, isOwnedHook) {
195275
195365
  const cleaned = { ...config2 };
195276
195366
  const hooks = isJsonRecord(config2.hooks) ? { ...config2.hooks } : null;
195277
195367
  if (!hooks) return cleaned;
@@ -195279,7 +195369,7 @@ function removeMemorixGrokHooks(config2) {
195279
195369
  if (!Array.isArray(groups)) continue;
195280
195370
  const preservedGroups = groups.flatMap((group) => {
195281
195371
  if (!isJsonRecord(group) || !Array.isArray(group.hooks)) return [group];
195282
- const preservedHooks = group.hooks.filter((hook) => !isMemorixGrokHook(hook));
195372
+ const preservedHooks = group.hooks.filter((hook) => !isOwnedHook(hook));
195283
195373
  if (preservedHooks.length === 0) return [];
195284
195374
  return [{ ...group, hooks: preservedHooks }];
195285
195375
  });
@@ -195290,6 +195380,12 @@ function removeMemorixGrokHooks(config2) {
195290
195380
  else delete cleaned.hooks;
195291
195381
  return cleaned;
195292
195382
  }
195383
+ function removeMemorixGrokHooks(config2) {
195384
+ return removeCommandHooks(config2, isMemorixGrokHook);
195385
+ }
195386
+ function removeMemorixQwenHooks(config2) {
195387
+ return removeCommandHooks(config2, isMemorixQwenHook);
195388
+ }
195293
195389
  async function readGrokHookConfig(configPath) {
195294
195390
  let content;
195295
195391
  try {
@@ -195308,6 +195404,24 @@ async function readGrokHookConfig(configPath) {
195308
195404
  throw new Error(`Cannot safely update Grok hook config ${configPath}: ${reason}`);
195309
195405
  }
195310
195406
  }
195407
+ async function readQwenHookConfig(configPath) {
195408
+ let content;
195409
+ try {
195410
+ content = await fs19.readFile(configPath, "utf-8");
195411
+ } catch (error40) {
195412
+ if (error40.code === "ENOENT") return {};
195413
+ throw error40;
195414
+ }
195415
+ if (!content.trim()) return {};
195416
+ try {
195417
+ const parsed = JSON.parse(content);
195418
+ if (!isJsonRecord(parsed)) throw new Error("top-level value must be an object");
195419
+ return parsed;
195420
+ } catch (error40) {
195421
+ const reason = error40 instanceof Error ? error40.message : String(error40);
195422
+ throw new Error(`Cannot safely update Qwen hook config ${configPath}: ${reason}`);
195423
+ }
195424
+ }
195311
195425
  function generateCopilotConfig() {
195312
195426
  const cmd = `${resolveHookCommand()} hook`;
195313
195427
  const hasPwsh = detectPwsh();
@@ -195922,6 +196036,8 @@ function getProjectConfigPath(agent, projectRoot) {
195922
196036
  switch (agent) {
195923
196037
  case "claude":
195924
196038
  return path31.join(projectRoot, ".claude", "settings.local.json");
196039
+ case "qwen":
196040
+ return path31.join(projectRoot, ".qwen", "settings.json");
195925
196041
  case "copilot":
195926
196042
  return path31.join(projectRoot, ".github", "hooks", "memorix.json");
195927
196043
  case "windsurf":
@@ -195963,6 +196079,8 @@ function getGlobalConfigPath(agent) {
195963
196079
  switch (agent) {
195964
196080
  case "claude":
195965
196081
  return path31.join(home, ".claude", "settings.json");
196082
+ case "qwen":
196083
+ return path31.join(home, ".qwen", "settings.json");
195966
196084
  case "copilot":
195967
196085
  return "";
195968
196086
  case "windsurf":
@@ -196004,6 +196122,8 @@ function getAgentRulesPath(agent, root, global2 = false) {
196004
196122
  return path31.join(root, ".cursor", "rules", "memorix.mdc");
196005
196123
  case "claude":
196006
196124
  return path31.join(root, ".claude", "CLAUDE.md");
196125
+ case "qwen":
196126
+ return path31.join(root, ".qwen", "QWEN.md");
196007
196127
  case "codex":
196008
196128
  return path31.join(root, ".codex", "AGENTS.md");
196009
196129
  case "kiro":
@@ -196032,6 +196152,8 @@ function getAgentRulesPath(agent, root, global2 = false) {
196032
196152
  return path31.join(root, ".cursor", "rules", "memorix.mdc");
196033
196153
  case "claude":
196034
196154
  return path31.join(root, "CLAUDE.md");
196155
+ case "qwen":
196156
+ return path31.join(root, "QWEN.md");
196035
196157
  case "copilot":
196036
196158
  return path31.join(root, ".github", "copilot-instructions.md");
196037
196159
  case "codex":
@@ -196108,6 +196230,12 @@ async function detectInstalledAgents() {
196108
196230
  agents.push("grok");
196109
196231
  } catch {
196110
196232
  }
196233
+ const qwenDir = path31.join(home, ".qwen");
196234
+ try {
196235
+ await fs19.access(qwenDir);
196236
+ agents.push("qwen");
196237
+ } catch {
196238
+ }
196111
196239
  const codexDir = path31.join(home, ".codex");
196112
196240
  try {
196113
196241
  await fs19.access(codexDir);
@@ -196191,10 +196319,10 @@ async function installHooks(agent, projectRoot, global2 = false) {
196191
196319
  const { access: access5, unlink: unlink3 } = await import("fs/promises");
196192
196320
  await access5(entry.path);
196193
196321
  const basename7 = path31.basename(entry.path);
196194
- if (basename7 === "AGENTS.md" || basename7 === "GEMINI.md" || basename7 === "CONTEXT.md") {
196322
+ if (basename7 === "AGENTS.md" || basename7 === "GEMINI.md" || basename7 === "QWEN.md" || basename7 === "CONTEXT.md") {
196195
196323
  continue;
196196
196324
  }
196197
- if (agent === "grok" && path31.resolve(entry.path) === path31.resolve(configPath)) {
196325
+ if ((agent === "grok" || agent === "qwen") && path31.resolve(entry.path) === path31.resolve(configPath)) {
196198
196326
  continue;
196199
196327
  }
196200
196328
  await unlink3(entry.path);
@@ -196209,6 +196337,9 @@ async function installHooks(agent, projectRoot, global2 = false) {
196209
196337
  case "claude":
196210
196338
  generated = generateClaudeConfig();
196211
196339
  break;
196340
+ case "qwen":
196341
+ generated = generateQwenConfig();
196342
+ break;
196212
196343
  case "grok":
196213
196344
  generated = generateGrokConfig();
196214
196345
  break;
@@ -196315,6 +196446,15 @@ async function installHooks(agent, projectRoot, global2 = false) {
196315
196446
  await recordFile2(projectRoot, "hook", configPath, agent);
196316
196447
  } catch {
196317
196448
  }
196449
+ } else if (agent === "qwen") {
196450
+ const existing = await readQwenHookConfig(configPath);
196451
+ const merged = mergeQwenHookConfig(existing, generated);
196452
+ await fs19.writeFile(configPath, JSON.stringify(merged, null, 2), "utf-8");
196453
+ try {
196454
+ const { recordFile: recordFile2 } = await Promise.resolve().then(() => (init_audit(), audit_exports));
196455
+ await recordFile2(projectRoot, "hook", configPath, agent);
196456
+ } catch {
196457
+ }
196318
196458
  } else if (agent === "kiro") {
196319
196459
  const hookFiles = generateKiroHookFiles();
196320
196460
  const hooksDir = path31.join(path31.dirname(configPath));
@@ -196378,6 +196518,9 @@ async function installHooks(agent, projectRoot, global2 = false) {
196378
196518
  case "claude":
196379
196519
  events.push("session_start", "post_tool", "user_prompt", "pre_compact", "session_end");
196380
196520
  break;
196521
+ case "qwen":
196522
+ events.push("session_start", "session_end", "user_prompt", "post_tool", "pre_compact", "post_compact");
196523
+ break;
196381
196524
  case "copilot":
196382
196525
  events.push("session_start", "session_end", "user_prompt", "post_tool");
196383
196526
  break;
@@ -196419,7 +196562,7 @@ async function installAgentRules(agent, projectRoot, global2 = false) {
196419
196562
  const rulesPath = getAgentRulesPath(agent, rulesRoot, global2);
196420
196563
  try {
196421
196564
  await fs19.mkdir(path31.dirname(rulesPath), { recursive: true });
196422
- if (agent === "claude" || agent === "codex" || agent === "opencode" || agent === "antigravity" || agent === "gemini-cli" || agent === "dsh" || agent === "grok") {
196565
+ if (agent === "claude" || agent === "qwen" || agent === "codex" || agent === "opencode" || agent === "antigravity" || agent === "gemini-cli" || agent === "dsh" || agent === "grok") {
196423
196566
  try {
196424
196567
  const existing = await fs19.readFile(rulesPath, "utf-8");
196425
196568
  await fs19.writeFile(rulesPath, mergeMemorixRulesContent(existing, rulesContent), "utf-8");
@@ -196597,6 +196740,15 @@ async function uninstallHooks(agent, projectRoot, global2 = false) {
196597
196740
  await fs19.writeFile(configPath, JSON.stringify(cleaned, null, 2), "utf-8");
196598
196741
  }
196599
196742
  success2 = true;
196743
+ } else if (agent === "qwen") {
196744
+ const config2 = await readQwenHookConfig(configPath);
196745
+ const cleaned = removeMemorixQwenHooks(config2);
196746
+ if (Object.keys(cleaned).length === 0) {
196747
+ await fs19.unlink(configPath);
196748
+ } else {
196749
+ await fs19.writeFile(configPath, JSON.stringify(cleaned, null, 2), "utf-8");
196750
+ }
196751
+ success2 = true;
196600
196752
  } else if (agent === "kiro" || agent === "opencode") {
196601
196753
  await fs19.unlink(configPath);
196602
196754
  success2 = true;
@@ -196620,13 +196772,13 @@ async function uninstallHooks(agent, projectRoot, global2 = false) {
196620
196772
  const agentFiles = prevFiles.filter((e5) => e5.agent === agent);
196621
196773
  for (const entry of agentFiles) {
196622
196774
  try {
196623
- if (agent === "grok" && path31.resolve(entry.path) === path31.resolve(configPath)) {
196775
+ if ((agent === "grok" || agent === "qwen") && path31.resolve(entry.path) === path31.resolve(configPath)) {
196624
196776
  await removeFile2(projectRoot, entry.path);
196625
196777
  auditCleaned = true;
196626
196778
  continue;
196627
196779
  }
196628
196780
  const basename7 = path31.basename(entry.path);
196629
- if (basename7 === "AGENTS.md" || basename7 === "GEMINI.md" || basename7 === "CONTEXT.md") {
196781
+ if (basename7 === "AGENTS.md" || basename7 === "GEMINI.md" || basename7 === "QWEN.md" || basename7 === "CONTEXT.md") {
196630
196782
  try {
196631
196783
  const content = await fs19.readFile(entry.path, "utf-8");
196632
196784
  const memorixStart = content.indexOf("# Memorix");
@@ -196685,7 +196837,7 @@ async function uninstallHooks(agent, projectRoot, global2 = false) {
196685
196837
  }
196686
196838
  async function getHookStatus(projectRoot) {
196687
196839
  const results = [];
196688
- const agents = ["claude", "copilot", "windsurf", "cursor", "kiro", "codex", "antigravity", "gemini-cli", "opencode", "pi", "trae", "grok"];
196840
+ const agents = ["claude", "qwen", "copilot", "windsurf", "cursor", "kiro", "codex", "antigravity", "gemini-cli", "opencode", "pi", "trae", "grok"];
196689
196841
  for (const agent of agents) {
196690
196842
  const projectPath = getProjectConfigPath(agent, projectRoot);
196691
196843
  const globalPath = getGlobalConfigPath(agent);
@@ -198447,6 +198599,7 @@ async function installSingleAgent(installHooks2, agent, targetRoot, global2) {
198447
198599
  function getAgentLabel(agent) {
198448
198600
  const labels = {
198449
198601
  claude: "Claude Code",
198602
+ qwen: "Qwen Code",
198450
198603
  windsurf: "Windsurf",
198451
198604
  cursor: "Cursor",
198452
198605
  copilot: "GitHub Copilot",
@@ -198465,6 +198618,7 @@ function getAgentLabel(agent) {
198465
198618
  function getAgentHint(agent) {
198466
198619
  const hints = {
198467
198620
  claude: "settings + instructions",
198621
+ qwen: "settings.json hooks + QWEN.md guidance",
198468
198622
  windsurf: "hooks + rules",
198469
198623
  cursor: "hooks + rules",
198470
198624
  copilot: "hooks + instructions",
@@ -201625,7 +201779,7 @@ async function getSessionContext(projectDir2, projectId, limit2 = 3, reader2) {
201625
201779
  lines.push("## Key Project Memories");
201626
201780
  lines.push("*Durable working context \u2014 explicit decisions, gotchas, and discoveries.*");
201627
201781
  for (const obs of l2Obs) {
201628
- const emoji3 = TYPE_EMOJI[obs.type] ?? "[PIN]";
201782
+ const emoji3 = OBSERVATION_ICONS[obs.type] ?? "[PIN]";
201629
201783
  const fact = obs.facts?.[0] ? ` \u2014 ${redactCredentials(obs.facts[0])}` : "";
201630
201784
  lines.push(`${emoji3} ${redactCredentials(obs.title)}${fact}`);
201631
201785
  }
@@ -201673,11 +201827,12 @@ async function getActiveSession(projectDir2, projectId) {
201673
201827
  const sessions = await loadAliasActiveSessions(aliasSet);
201674
201828
  return sessions.sort((a4, b4) => new Date(b4.startedAt).getTime() - new Date(a4.startedAt).getTime())[0] ?? null;
201675
201829
  }
201676
- var PRIORITY_TYPES, RESUME_TYPES, TYPE_EMOJI, TYPE_WEIGHTS, NOISE_PATTERNS, COMMAND_TRACE_PATTERNS, SYSTEM_SELF_PATTERNS, SESSION_RESUME_OBSERVATION_LIMIT, SESSION_CONTEXT_OBSERVATION_LIMIT, AUTO_RESUME_SUMMARY_LIMIT, AUTO_RESUME_TITLE_LIMIT;
201830
+ var PRIORITY_TYPES, RESUME_TYPES, TYPE_WEIGHTS, NOISE_PATTERNS, COMMAND_TRACE_PATTERNS, SYSTEM_SELF_PATTERNS, SESSION_RESUME_OBSERVATION_LIMIT, SESSION_CONTEXT_OBSERVATION_LIMIT, AUTO_RESUME_SUMMARY_LIMIT, AUTO_RESUME_TITLE_LIMIT;
201677
201831
  var init_session = __esm({
201678
201832
  "src/memory/session.ts"() {
201679
201833
  "use strict";
201680
201834
  init_esm_shims();
201835
+ init_types2();
201681
201836
  init_admission();
201682
201837
  init_disclosure_policy();
201683
201838
  init_aliases();
@@ -201705,18 +201860,6 @@ var init_session = __esm({
201705
201860
  "what-changed",
201706
201861
  "reasoning"
201707
201862
  ]);
201708
- TYPE_EMOJI = {
201709
- "gotcha": "[DISCOVERY]",
201710
- "decision": "[WHY]",
201711
- "problem-solution": "[FIX]",
201712
- "trade-off": "[TRADEOFF]",
201713
- "discovery": "[DISCOVERY]",
201714
- "how-it-works": "[INFO]",
201715
- "what-changed": "[CHANGE]",
201716
- "why-it-exists": "[DECISION]",
201717
- "session-request": "[SESSION]",
201718
- "probe": "[PROBE]"
201719
- };
201720
201863
  TYPE_WEIGHTS = {
201721
201864
  "gotcha": 6,
201722
201865
  "decision": 5.5,
@@ -209265,7 +209408,7 @@ var init_tool_profile = __esm({
209265
209408
  function getMcpServerInfo() {
209266
209409
  return {
209267
209410
  name: "memorix",
209268
- version: true ? "1.9.10" : "1.0.1"
209411
+ version: true ? "1.9.11" : "1.0.1"
209269
209412
  };
209270
209413
  }
209271
209414
  function createMcpDiscoverResult(capabilities, serverInfo) {
@@ -211718,6 +211861,9 @@ var init_protocol = __esm({
211718
211861
  this.setRequestHandler(GetTaskPayloadRequestSchema, async (request, extra) => {
211719
211862
  const handleTaskResult = async () => {
211720
211863
  const taskId = request.params.taskId;
211864
+ if (!await this._taskStore.getTask(taskId, extra.sessionId)) {
211865
+ throw new McpError(ErrorCode.InvalidParams, `Task not found: ${taskId}`);
211866
+ }
211721
211867
  if (this._taskMessageQueue) {
211722
211868
  let queuedMessage;
211723
211869
  while (queuedMessage = await this._taskMessageQueue.dequeue(taskId, extra.sessionId)) {
@@ -211748,12 +211894,12 @@ var init_protocol = __esm({
211748
211894
  throw new McpError(ErrorCode.InvalidParams, `Task not found: ${taskId}`);
211749
211895
  }
211750
211896
  if (!isTerminal(task.status)) {
211751
- await this._waitForTaskUpdate(taskId, extra.signal);
211897
+ await this._waitForTaskUpdate(taskId, extra.signal, extra.sessionId);
211752
211898
  return await handleTaskResult();
211753
211899
  }
211754
211900
  if (isTerminal(task.status)) {
211755
211901
  const result = await this._taskStore.getTaskResult(taskId, extra.sessionId);
211756
- this._clearTaskQueue(taskId);
211902
+ this._clearTaskQueue(taskId, extra.sessionId);
211757
211903
  return {
211758
211904
  ...result,
211759
211905
  _meta: {
@@ -211790,7 +211936,7 @@ var init_protocol = __esm({
211790
211936
  throw new McpError(ErrorCode.InvalidParams, `Cannot cancel task in terminal status: ${task.status}`);
211791
211937
  }
211792
211938
  await this._taskStore.updateTaskStatus(request.params.taskId, "cancelled", "Client cancelled task execution.", extra.sessionId);
211793
- this._clearTaskQueue(request.params.taskId);
211939
+ this._clearTaskQueue(request.params.taskId, extra.sessionId);
211794
211940
  const cancelledTask = await this._taskStore.getTask(request.params.taskId, extra.sessionId);
211795
211941
  if (!cancelledTask) {
211796
211942
  throw new McpError(ErrorCode.InvalidParams, `Task not found after cancellation: ${request.params.taskId}`);
@@ -211918,6 +212064,19 @@ var init_protocol = __esm({
211918
212064
  const handler = this._requestHandlers.get(request.method) ?? this.fallbackRequestHandler;
211919
212065
  const capturedTransport = this._transport;
211920
212066
  const relatedTaskId = request.params?._meta?.[RELATED_TASK_META_KEY]?.taskId;
212067
+ const sessionId = capturedTransport?.sessionId;
212068
+ const store2 = this._taskStore;
212069
+ let relatedTaskFound = true;
212070
+ let relatedTaskLookup;
212071
+ if (relatedTaskId && store2 && this._taskMessageQueue && sessionId !== void 0) {
212072
+ relatedTaskFound = false;
212073
+ relatedTaskLookup = (async () => {
212074
+ if (!await store2.getTask(relatedTaskId, sessionId)) {
212075
+ throw new McpError(ErrorCode.InvalidParams, `Task not found: ${relatedTaskId}`);
212076
+ }
212077
+ relatedTaskFound = true;
212078
+ })();
212079
+ }
211921
212080
  if (handler === void 0) {
211922
212081
  const errorResponse = {
211923
212082
  jsonrpc: "2.0",
@@ -211927,7 +212086,10 @@ var init_protocol = __esm({
211927
212086
  message: "Method not found"
211928
212087
  }
211929
212088
  };
211930
- if (relatedTaskId && this._taskMessageQueue) {
212089
+ if (relatedTaskId && relatedTaskLookup) {
212090
+ const queuedError = { type: "error", message: errorResponse, timestamp: Date.now() };
212091
+ relatedTaskLookup.then(() => this._enqueueTaskMessage(relatedTaskId, queuedError, sessionId), () => capturedTransport?.send(errorResponse)).catch((error40) => this._onerror(new Error(`Failed to send an error response: ${error40}`)));
212092
+ } else if (relatedTaskId && this._taskMessageQueue) {
211931
212093
  this._enqueueTaskMessage(relatedTaskId, {
211932
212094
  type: "error",
211933
212095
  message: errorResponse,
@@ -211978,7 +212140,10 @@ var init_protocol = __esm({
211978
212140
  closeSSEStream: extra?.closeSSEStream,
211979
212141
  closeStandaloneSSEStream: extra?.closeStandaloneSSEStream
211980
212142
  };
211981
- Promise.resolve().then(() => {
212143
+ (relatedTaskLookup ?? Promise.resolve()).then(() => {
212144
+ if (relatedTaskLookup && abortController.signal.aborted) {
212145
+ throw new McpError(ErrorCode.ConnectionClosed, "Request was cancelled");
212146
+ }
211982
212147
  if (taskCreationParams) {
211983
212148
  this.assertTaskHandlerCapability(request.method);
211984
212149
  }
@@ -212013,7 +212178,7 @@ var init_protocol = __esm({
212013
212178
  ...error40["data"] !== void 0 && { data: error40["data"] }
212014
212179
  }
212015
212180
  };
212016
- if (relatedTaskId && this._taskMessageQueue) {
212181
+ if (relatedTaskId && this._taskMessageQueue && relatedTaskFound) {
212017
212182
  await this._enqueueTaskMessage(relatedTaskId, {
212018
212183
  type: "error",
212019
212184
  message: errorResponse,
@@ -212493,7 +212658,7 @@ var init_protocol = __esm({
212493
212658
  throw new Error("Cannot enqueue task message: taskStore and taskMessageQueue are not configured");
212494
212659
  }
212495
212660
  const maxQueueSize = this._options?.maxTaskQueueSize;
212496
- await this._taskMessageQueue.enqueue(taskId, message, sessionId, maxQueueSize);
212661
+ await this._taskMessageQueue.enqueue(taskId, message, sessionId ?? this._transport?.sessionId, maxQueueSize);
212497
212662
  }
212498
212663
  /**
212499
212664
  * Clears the message queue for a task and rejects any pending request resolvers.
@@ -212522,12 +212687,13 @@ var init_protocol = __esm({
212522
212687
  * Uses polling to check for updates at the task's configured poll interval.
212523
212688
  * @param taskId The task ID to wait for
212524
212689
  * @param signal Abort signal to cancel the wait
212690
+ * @param sessionId Session of the request that waits, passed to the task store
212525
212691
  * @returns Promise that resolves when an update occurs or rejects if aborted
212526
212692
  */
212527
- async _waitForTaskUpdate(taskId, signal) {
212693
+ async _waitForTaskUpdate(taskId, signal, sessionId) {
212528
212694
  let interval = this._options?.defaultTaskPollInterval ?? 1e3;
212529
212695
  try {
212530
- const task = await this._taskStore?.getTask(taskId);
212696
+ const task = await this._taskStore?.getTask(taskId, sessionId);
212531
212697
  if (task?.pollInterval) {
212532
212698
  interval = task.pollInterval;
212533
212699
  }
@@ -215712,9 +215878,28 @@ var require_utils = __commonJS({
215712
215878
  init_esm_shims();
215713
215879
  var isUUID = RegExp.prototype.test.bind(/^[\da-f]{8}-[\da-f]{4}-[\da-f]{4}-[\da-f]{4}-[\da-f]{12}$/iu);
215714
215880
  var isIPv4 = RegExp.prototype.test.bind(/^(?:(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)$/u);
215881
+ var isPort = RegExp.prototype.test.bind(/^\d*$/u);
215715
215882
  var isHexPair = RegExp.prototype.test.bind(/^[\da-f]{2}$/iu);
215716
215883
  var isUnreserved = RegExp.prototype.test.bind(/^[\da-z\-._~]$/iu);
215717
- var isPathCharacter = RegExp.prototype.test.bind(/^[\da-z\-._~!$&'()*+,;=:@/]$/iu);
215884
+ var isPathCharacter = RegExp.prototype.test.bind(/^[A-Za-z0-9\-._~!$&'()*+,;=:@/]$/u);
215885
+ var isQueryFragmentCharacter = RegExp.prototype.test.bind(/^[A-Za-z0-9\-._~!$&'()*+,;=:@/?]$/u);
215886
+ var isUserinfoCharacter = RegExp.prototype.test.bind(/^[A-Za-z0-9\-._~!$&'()*+,;=:]$/u);
215887
+ var BYTE_HEX = new Array(256);
215888
+ {
215889
+ const HEX_DIGITS = "0123456789ABCDEF";
215890
+ for (let i4 = 0; i4 < 256; i4++) {
215891
+ BYTE_HEX[i4] = "%" + HEX_DIGITS[i4 >> 4] + HEX_DIGITS[i4 & 15];
215892
+ }
215893
+ }
215894
+ function percentEncodeNonAscii(cp) {
215895
+ if (cp < 2048) {
215896
+ return BYTE_HEX[192 | cp >> 6] + BYTE_HEX[128 | cp & 63];
215897
+ }
215898
+ if (cp < 65536) {
215899
+ return BYTE_HEX[224 | cp >> 12] + BYTE_HEX[128 | cp >> 6 & 63] + BYTE_HEX[128 | cp & 63];
215900
+ }
215901
+ return BYTE_HEX[240 | cp >> 18] + BYTE_HEX[128 | cp >> 12 & 63] + BYTE_HEX[128 | cp >> 6 & 63] + BYTE_HEX[128 | cp & 63];
215902
+ }
215718
215903
  function stringArrayToHexStripped(input) {
215719
215904
  let acc = "";
215720
215905
  let code = 0;
@@ -215739,91 +215924,105 @@ var require_utils = __commonJS({
215739
215924
  }
215740
215925
  return acc;
215741
215926
  }
215927
+ var isHextet = RegExp.prototype.test.bind(/^[\dA-Fa-f]{1,4}$/);
215928
+ var isIPvFuture = RegExp.prototype.test.bind(/^[vV][\dA-Fa-f]+\.[A-Za-z\d\-._~!$&'()*+,;=:]+$/);
215929
+ var isZoneCharacter = RegExp.prototype.test.bind(/^[A-Za-z\d\-._~]$/);
215742
215930
  var nonSimpleDomain = RegExp.prototype.test.bind(/[^!"$&'()*+,\-.;=_`a-z{}~]/u);
215743
- function consumeIsZone(buffer) {
215744
- buffer.length = 0;
215745
- return true;
215746
- }
215747
- function consumeHextets(buffer, address, output) {
215748
- if (buffer.length) {
215749
- const hex = stringArrayToHexStripped(buffer);
215750
- if (hex !== "") {
215751
- address.push(hex);
215752
- } else {
215753
- output.error = true;
215754
- return false;
215931
+ function isZoneIdentifier(zone) {
215932
+ if (zone.length === 0) return false;
215933
+ for (let i4 = 0; i4 < zone.length; i4++) {
215934
+ if (isZoneCharacter(zone[i4])) continue;
215935
+ if (zone[i4] === "%" && i4 + 2 < zone.length && isHexPair(zone.slice(i4 + 1, i4 + 3))) {
215936
+ i4 += 2;
215937
+ continue;
215755
215938
  }
215756
- buffer.length = 0;
215939
+ return false;
215757
215940
  }
215758
215941
  return true;
215759
215942
  }
215760
- function getIPV6(input) {
215761
- let tokenCount = 0;
215762
- const output = { error: false, address: "", zone: "" };
215763
- const address = [];
215764
- const buffer = [];
215765
- let endipv6Encountered = false;
215766
- let endIpv6 = false;
215767
- let consume = consumeHextets;
215768
- for (let i4 = 0; i4 < input.length; i4++) {
215769
- const cursor = input[i4];
215770
- if (cursor === "[" || cursor === "]") {
215771
- continue;
215772
- }
215773
- if (cursor === ":") {
215774
- if (endipv6Encountered === true) {
215775
- endIpv6 = true;
215943
+ function compressIPv6ZeroRun(hextets) {
215944
+ let bestStart = -1;
215945
+ let bestLength = 0;
215946
+ let runStart = -1;
215947
+ let runLength = 0;
215948
+ for (let i4 = 0; i4 < hextets.length; i4++) {
215949
+ if (hextets[i4] === "0") {
215950
+ if (runStart === -1) runStart = i4;
215951
+ runLength++;
215952
+ if (runLength > bestLength) {
215953
+ bestLength = runLength;
215954
+ bestStart = runStart;
215776
215955
  }
215777
- if (!consume(buffer, address, output)) {
215778
- break;
215779
- }
215780
- if (++tokenCount > 7) {
215781
- output.error = true;
215782
- break;
215783
- }
215784
- if (i4 > 0 && input[i4 - 1] === ":") {
215785
- endipv6Encountered = true;
215786
- }
215787
- address.push(":");
215788
- continue;
215789
- } else if (cursor === "%") {
215790
- if (!consume(buffer, address, output)) {
215791
- break;
215792
- }
215793
- consume = consumeIsZone;
215794
215956
  } else {
215795
- buffer.push(cursor);
215957
+ runStart = -1;
215958
+ runLength = 0;
215959
+ }
215960
+ }
215961
+ if (bestLength < 2) return hextets.join(":");
215962
+ const head = hextets.slice(0, bestStart).join(":");
215963
+ const tail = hextets.slice(bestStart + bestLength).join(":");
215964
+ return head + "::" + tail;
215965
+ }
215966
+ function normalizeIPv6Address(input) {
215967
+ const compression = input.indexOf("::");
215968
+ if (compression !== -1 && input.indexOf("::", compression + 1) !== -1) return void 0;
215969
+ const left = compression === -1 ? input.split(":") : input.slice(0, compression).split(":");
215970
+ const right = compression === -1 ? [] : input.slice(compression + 2).split(":");
215971
+ if (compression !== -1) {
215972
+ if (left.length === 1 && left[0] === "") left.length = 0;
215973
+ if (right.length === 1 && right[0] === "") right.length = 0;
215974
+ }
215975
+ const parts = left.concat(right);
215976
+ let hextetCount = 0;
215977
+ for (let i4 = 0; i4 < parts.length; i4++) {
215978
+ const part = parts[i4];
215979
+ if (part === "") return void 0;
215980
+ if (part.indexOf(".") !== -1) {
215981
+ if (i4 !== parts.length - 1 || compression !== -1 && right.length === 0 || !isIPv4(part)) return void 0;
215982
+ hextetCount += 2;
215796
215983
  continue;
215797
215984
  }
215985
+ if (!isHextet(part)) return void 0;
215986
+ parts[i4] = parseInt(part, 16).toString(16);
215987
+ hextetCount++;
215798
215988
  }
215799
- if (buffer.length) {
215800
- if (consume === consumeIsZone) {
215801
- output.zone = buffer.join("");
215802
- } else if (endIpv6) {
215803
- address.push(buffer.join(""));
215804
- } else {
215805
- address.push(stringArrayToHexStripped(buffer));
215806
- }
215989
+ if (compression === -1) {
215990
+ if (hextetCount !== 8) return void 0;
215991
+ return compressIPv6ZeroRun(parts);
215807
215992
  }
215808
- output.address = address.join("");
215809
- return output;
215993
+ if (hextetCount >= 8) return void 0;
215994
+ const expanded = parts.slice(0, left.length);
215995
+ for (let i4 = hextetCount; i4 < 8; i4++) expanded.push("0");
215996
+ for (let i4 = left.length; i4 < parts.length; i4++) expanded.push(parts[i4]);
215997
+ return compressIPv6ZeroRun(expanded);
215810
215998
  }
215811
215999
  function normalizeIPv6(host) {
215812
- if (findToken(host, ":") < 2) {
215813
- return { host, isIPV6: false };
215814
- }
215815
- const ipv63 = getIPV6(host);
215816
- if (!ipv63.error) {
215817
- let newHost = ipv63.address;
215818
- let escapedHost = ipv63.address;
215819
- if (ipv63.zone) {
215820
- newHost += "%" + ipv63.zone;
215821
- escapedHost += "%25" + ipv63.zone;
215822
- }
215823
- return { host: newHost, isIPV6: true, escapedHost };
215824
- } else {
215825
- return { host, isIPV6: false };
215826
- }
216000
+ const bracketed = host[0] === "[" && host[host.length - 1] === "]";
216001
+ const hasBracket = host[0] === "[" || host[host.length - 1] === "]";
216002
+ if (hasBracket && !bracketed) return { host, isIPV6: false, error: true };
216003
+ let input = bracketed ? host.slice(1, -1) : host;
216004
+ if (bracketed && isIPvFuture(input)) {
216005
+ input = input.toLowerCase();
216006
+ return { host: `[${input}]`, escapedHost: input, isIPV6: false, isIPVFuture: true };
216007
+ }
216008
+ if (findToken(input, ":") < 2) {
216009
+ return { host, isIPV6: false, error: bracketed };
216010
+ }
216011
+ let zoneIdentifier = "";
216012
+ const zoneSeparator = input.indexOf("%");
216013
+ if (zoneSeparator !== -1) {
216014
+ const separatorLength = input.slice(zoneSeparator, zoneSeparator + 3).toLowerCase() === "%25" ? 3 : 1;
216015
+ zoneIdentifier = input.slice(zoneSeparator + separatorLength);
216016
+ if (!isZoneIdentifier(zoneIdentifier)) return { host, isIPV6: false, error: true };
216017
+ input = input.slice(0, zoneSeparator);
216018
+ }
216019
+ const address = normalizeIPv6Address(input);
216020
+ if (address === void 0) return { host, isIPV6: false, error: true };
216021
+ return {
216022
+ host: address + (zoneIdentifier ? "%" + zoneIdentifier : ""),
216023
+ escapedHost: address + (zoneIdentifier ? "%25" + zoneIdentifier : ""),
216024
+ isIPV6: true
216025
+ };
215827
216026
  }
215828
216027
  function findToken(str2, token) {
215829
216028
  let ind = 0;
@@ -215942,7 +216141,8 @@ var require_utils = __commonJS({
215942
216141
  function normalizePathEncoding(input) {
215943
216142
  let output = "";
215944
216143
  for (let i4 = 0; i4 < input.length; i4++) {
215945
- if (input[i4] === "%" && i4 + 2 < input.length) {
216144
+ const ch2 = input[i4];
216145
+ if (ch2 === "%" && i4 + 2 < input.length) {
215946
216146
  const hex = input.slice(i4 + 1, i4 + 3);
215947
216147
  if (isHexPair(hex)) {
215948
216148
  const normalizedHex = hex.toUpperCase();
@@ -215956,10 +216156,152 @@ var require_utils = __commonJS({
215956
216156
  continue;
215957
216157
  }
215958
216158
  }
215959
- if (isPathCharacter(input[i4])) {
215960
- output += input[i4];
216159
+ if (isPathCharacter(ch2)) {
216160
+ output += ch2;
216161
+ } else {
216162
+ const code = input.charCodeAt(i4);
216163
+ if (code < 128) {
216164
+ output += isEscapeSafe(code) ? ch2 : BYTE_HEX[code];
216165
+ } else if (code < 55296 || code > 57343) {
216166
+ output += percentEncodeNonAscii(code);
216167
+ } else if (code <= 56319 && i4 + 1 < input.length) {
216168
+ const low = input.charCodeAt(i4 + 1);
216169
+ if (low >= 56320 && low <= 57343) {
216170
+ output += percentEncodeNonAscii(65536 + (code - 55296 << 10) + (low - 56320));
216171
+ i4++;
216172
+ } else {
216173
+ output += percentEncodeNonAscii(65533);
216174
+ }
216175
+ } else {
216176
+ output += percentEncodeNonAscii(65533);
216177
+ }
216178
+ }
216179
+ }
216180
+ return output;
216181
+ }
216182
+ function serializePathEncoding(input, pathNoScheme = false) {
216183
+ let output = "";
216184
+ let firstSegment = pathNoScheme && input[0] !== "/";
216185
+ for (let i4 = 0; i4 < input.length; i4++) {
216186
+ const ch2 = input[i4];
216187
+ if (ch2 === "%" && i4 + 2 < input.length) {
216188
+ const hex = input.slice(i4 + 1, i4 + 3);
216189
+ if (isHexPair(hex)) {
216190
+ output += "%" + hex.toUpperCase();
216191
+ i4 += 2;
216192
+ continue;
216193
+ }
216194
+ }
216195
+ if (ch2 === "/") {
216196
+ firstSegment = false;
216197
+ }
216198
+ if (isPathCharacter(ch2) && (ch2 !== ":" || !firstSegment)) {
216199
+ output += ch2;
216200
+ } else {
216201
+ const code = input.charCodeAt(i4);
216202
+ if (code < 128) {
216203
+ output += BYTE_HEX[code];
216204
+ } else if (code < 55296 || code > 57343) {
216205
+ output += percentEncodeNonAscii(code);
216206
+ } else if (code <= 56319 && i4 + 1 < input.length) {
216207
+ const low = input.charCodeAt(i4 + 1);
216208
+ if (low >= 56320 && low <= 57343) {
216209
+ output += percentEncodeNonAscii(65536 + (code - 55296 << 10) + (low - 56320));
216210
+ i4++;
216211
+ } else {
216212
+ output += percentEncodeNonAscii(65533);
216213
+ }
216214
+ } else {
216215
+ output += percentEncodeNonAscii(65533);
216216
+ }
216217
+ }
216218
+ }
216219
+ return output;
216220
+ }
216221
+ function encodeComponent(input, isAllowed) {
216222
+ let output = "";
216223
+ for (let i4 = 0; i4 < input.length; i4++) {
216224
+ const ch2 = input[i4];
216225
+ if (ch2 === "%" && i4 + 2 < input.length) {
216226
+ const hex = input.slice(i4 + 1, i4 + 3);
216227
+ if (isHexPair(hex)) {
216228
+ output += "%" + hex.toUpperCase();
216229
+ i4 += 2;
216230
+ continue;
216231
+ }
216232
+ }
216233
+ if (isAllowed(ch2)) {
216234
+ output += ch2;
216235
+ } else {
216236
+ const code = input.charCodeAt(i4);
216237
+ if (code < 128) {
216238
+ output += BYTE_HEX[code];
216239
+ } else if (code < 55296 || code > 57343) {
216240
+ output += percentEncodeNonAscii(code);
216241
+ } else if (code <= 56319 && i4 + 1 < input.length) {
216242
+ const low = input.charCodeAt(i4 + 1);
216243
+ if (low >= 56320 && low <= 57343) {
216244
+ output += percentEncodeNonAscii(65536 + (code - 55296 << 10) + (low - 56320));
216245
+ i4++;
216246
+ } else {
216247
+ output += percentEncodeNonAscii(65533);
216248
+ }
216249
+ } else {
216250
+ output += percentEncodeNonAscii(65533);
216251
+ }
216252
+ }
216253
+ }
216254
+ return output;
216255
+ }
216256
+ function encodeUserinfo(input) {
216257
+ return encodeComponent(input, isUserinfoCharacter);
216258
+ }
216259
+ function encodeQuery(input) {
216260
+ return encodeComponent(input, isQueryFragmentCharacter);
216261
+ }
216262
+ function encodeFragment(input) {
216263
+ return encodeComponent(input, isQueryFragmentCharacter);
216264
+ }
216265
+ function isEscapeSafe(cp) {
216266
+ return cp >= 48 && cp <= 57 || cp >= 65 && cp <= 90 || cp >= 97 && cp <= 122 || cp === 42 || cp === 43 || cp === 45 || cp === 46 || cp === 47 || cp === 64 || cp === 95;
216267
+ }
216268
+ function normalizeQueryFragmentEncoding(input) {
216269
+ let output = "";
216270
+ for (let i4 = 0; i4 < input.length; i4++) {
216271
+ const ch2 = input[i4];
216272
+ if (ch2 === "%" && i4 + 2 < input.length) {
216273
+ const hex = input.slice(i4 + 1, i4 + 3);
216274
+ if (isHexPair(hex)) {
216275
+ const normalizedHex = hex.toUpperCase();
216276
+ const decoded = String.fromCharCode(parseInt(normalizedHex, 16));
216277
+ if (isUnreserved(decoded)) {
216278
+ output += decoded;
216279
+ } else {
216280
+ output += "%" + normalizedHex;
216281
+ }
216282
+ i4 += 2;
216283
+ continue;
216284
+ }
216285
+ }
216286
+ if (isQueryFragmentCharacter(ch2)) {
216287
+ output += ch2;
215961
216288
  } else {
215962
- output += escape(input[i4]);
216289
+ const code = input.charCodeAt(i4);
216290
+ if (code < 128) {
216291
+ output += isEscapeSafe(code) ? ch2 : BYTE_HEX[code];
216292
+ } else if (code < 55296 || code > 57343) {
216293
+ output += percentEncodeNonAscii(code);
216294
+ } else if (code <= 56319 && i4 + 1 < input.length) {
216295
+ const low = input.charCodeAt(i4 + 1);
216296
+ if (low >= 56320 && low <= 57343) {
216297
+ output += percentEncodeNonAscii(65536 + (code - 55296 << 10) + (low - 56320));
216298
+ i4++;
216299
+ } else {
216300
+ output += percentEncodeNonAscii(65533);
216301
+ }
216302
+ } else {
216303
+ output += percentEncodeNonAscii(65533);
216304
+ }
215963
216305
  }
215964
216306
  }
215965
216307
  return output;
@@ -215982,14 +216324,18 @@ var require_utils = __commonJS({
215982
216324
  function recomposeAuthority(component) {
215983
216325
  const uriTokens = [];
215984
216326
  if (component.userinfo !== void 0) {
215985
- uriTokens.push(component.userinfo);
216327
+ uriTokens.push(encodeUserinfo(component.userinfo));
215986
216328
  uriTokens.push("@");
215987
216329
  }
215988
216330
  if (component.host !== void 0) {
215989
- let host = unescape(component.host);
216331
+ let host = component.host;
215990
216332
  if (!isIPv4(host)) {
215991
- const ipV6res = normalizeIPv6(host);
215992
- if (ipV6res.isIPV6 === true) {
216333
+ let ipV6res = normalizeIPv6(host);
216334
+ if (ipV6res.isIPV6 !== true && ipV6res.isIPVFuture !== true) {
216335
+ host = normalizePercentEncoding(host, true);
216336
+ ipV6res = normalizeIPv6(host);
216337
+ }
216338
+ if (ipV6res.isIPV6 === true || ipV6res.isIPVFuture === true) {
215993
216339
  host = `[${ipV6res.escapedHost}]`;
215994
216340
  } else {
215995
216341
  host = reescapeHostDelimiters(host, false);
@@ -215998,8 +216344,12 @@ var require_utils = __commonJS({
215998
216344
  uriTokens.push(host);
215999
216345
  }
216000
216346
  if (typeof component.port === "number" || typeof component.port === "string") {
216347
+ const port = String(component.port);
216348
+ if (!isPort(port)) {
216349
+ throw new TypeError("URI port is malformed.");
216350
+ }
216001
216351
  uriTokens.push(":");
216002
- uriTokens.push(String(component.port));
216352
+ uriTokens.push(port);
216003
216353
  }
216004
216354
  return uriTokens.length ? uriTokens.join("") : void 0;
216005
216355
  }
@@ -216009,6 +216359,11 @@ var require_utils = __commonJS({
216009
216359
  reescapeHostDelimiters,
216010
216360
  normalizePercentEncoding,
216011
216361
  normalizePathEncoding,
216362
+ serializePathEncoding,
216363
+ normalizeQueryFragmentEncoding,
216364
+ encodeUserinfo,
216365
+ encodeQuery,
216366
+ encodeFragment,
216012
216367
  escapePreservingEscapes,
216013
216368
  removeDotSegments,
216014
216369
  isIPv4,
@@ -216025,7 +216380,7 @@ var require_schemes = __commonJS({
216025
216380
  "use strict";
216026
216381
  init_esm_shims();
216027
216382
  var { isUUID } = require_utils();
216028
- var URN_REG = /([\da-z][\d\-a-z]{0,31}):((?:[\w!$'()*+,\-.:;=@]|%[\da-f]{2})+)/iu;
216383
+ var URN_REG = /^([\da-z][\d\-a-z]{0,31}):((?:[\w!$'()*+,\-./:;=@]|%[\da-f]{2})+)$/iu;
216029
216384
  var supportedSchemeNames = (
216030
216385
  /** @type {const} */
216031
216386
  [
@@ -216086,9 +216441,10 @@ var require_schemes = __commonJS({
216086
216441
  wsComponent.secure = void 0;
216087
216442
  }
216088
216443
  if (wsComponent.resourceName) {
216089
- const [path50, query] = wsComponent.resourceName.split("?");
216444
+ const queryIndex = wsComponent.resourceName.indexOf("?");
216445
+ const path50 = queryIndex === -1 ? wsComponent.resourceName : wsComponent.resourceName.slice(0, queryIndex);
216090
216446
  wsComponent.path = path50 && path50 !== "/" ? path50 : void 0;
216091
- wsComponent.query = query;
216447
+ wsComponent.query = queryIndex === -1 ? void 0 : wsComponent.resourceName.slice(queryIndex + 1);
216092
216448
  wsComponent.resourceName = void 0;
216093
216449
  }
216094
216450
  wsComponent.fragment = void 0;
@@ -216100,7 +216456,7 @@ var require_schemes = __commonJS({
216100
216456
  return urnComponent;
216101
216457
  }
216102
216458
  const matches = urnComponent.path.match(URN_REG);
216103
- if (matches) {
216459
+ if (matches && matches[0] === urnComponent.path) {
216104
216460
  const scheme = options.scheme || urnComponent.scheme || "urn";
216105
216461
  urnComponent.nid = matches[1].toLowerCase();
216106
216462
  urnComponent.nss = matches[2];
@@ -216235,8 +216591,17 @@ var require_fast_uri = __commonJS({
216235
216591
  "node_modules/fast-uri/index.js"(exports, module) {
216236
216592
  "use strict";
216237
216593
  init_esm_shims();
216238
- var { normalizeIPv6, removeDotSegments, recomposeAuthority, normalizePercentEncoding, normalizePathEncoding, escapePreservingEscapes, reescapeHostDelimiters, isIPv4, nonSimpleDomain } = require_utils();
216594
+ var { normalizeIPv6, removeDotSegments, recomposeAuthority, normalizePercentEncoding, normalizePathEncoding, serializePathEncoding, normalizeQueryFragmentEncoding, encodeQuery, encodeFragment, reescapeHostDelimiters, isIPv4, nonSimpleDomain } = require_utils();
216239
216595
  var { SCHEMES, getSchemeHandler } = require_schemes();
216596
+ var VALID_SCHEME = /^[A-Za-z][A-Za-z0-9+.-]*$/u;
216597
+ var MALFORMED_SCHEME_ERROR = "URI scheme is malformed.";
216598
+ function decodeValidScheme(scheme) {
216599
+ const decodedScheme = unescape(String(scheme));
216600
+ if (!VALID_SCHEME.test(decodedScheme)) {
216601
+ throw new TypeError(MALFORMED_SCHEME_ERROR);
216602
+ }
216603
+ return decodedScheme;
216604
+ }
216240
216605
  function normalize(uri, options) {
216241
216606
  if (typeof uri === "string") {
216242
216607
  uri = /** @type {T} */
@@ -216249,12 +216614,34 @@ var require_fast_uri = __commonJS({
216249
216614
  }
216250
216615
  function resolve9(baseURI, relativeURI, options) {
216251
216616
  const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
216252
- const { parsed: baseParsed, malformedAuthorityOrPort: baseMalformed } = parseWithStatus(baseURI, schemelessOptions);
216253
- const { parsed: relativeParsed, malformedAuthorityOrPort: relativeMalformed } = parseWithStatus(relativeURI, schemelessOptions);
216254
- if (baseMalformed || relativeMalformed) {
216617
+ const {
216618
+ parsed: baseParsed,
216619
+ malformedAuthorityOrPort: baseMalformed,
216620
+ malformedPercentEncoding: baseMalformedPercentEncoding,
216621
+ malformedSchemeSpecific: baseMalformedSchemeSpecific,
216622
+ malformedHost: baseMalformedHost,
216623
+ malformedScheme: baseMalformedScheme
216624
+ } = parseWithStatus(baseURI, schemelessOptions);
216625
+ const {
216626
+ parsed: relativeParsed,
216627
+ malformedAuthorityOrPort: relativeMalformed,
216628
+ malformedPercentEncoding: relativeMalformedPercentEncoding,
216629
+ malformedSchemeSpecific: relativeMalformedSchemeSpecific,
216630
+ malformedHost: relativeMalformedHost,
216631
+ malformedScheme: relativeMalformedScheme
216632
+ } = parseWithStatus(relativeURI, schemelessOptions);
216633
+ if (baseMalformed || relativeMalformed || baseMalformedPercentEncoding || relativeMalformedPercentEncoding || baseMalformedSchemeSpecific || relativeMalformedSchemeSpecific || baseMalformedHost || relativeMalformedHost || baseMalformedScheme || relativeMalformedScheme) {
216255
216634
  throw new Error(baseParsed.error || relativeParsed.error || "URI is malformed.");
216256
216635
  }
216257
216636
  const resolved = resolveComponent(baseParsed, relativeParsed, schemelessOptions, true);
216637
+ const resolvedSchemeHandler = getSchemeHandler(options && options.scheme || resolved.scheme);
216638
+ const resolvedHost = resolved.host;
216639
+ const resolvedHostIsIP = resolvedHost !== void 0 && resolvedHost !== "" && (isIPv4(resolvedHost) || normalizeIPv6(resolvedHost).isIPV6);
216640
+ canonicalizeHost(resolved, options || {}, resolvedSchemeHandler, resolvedHostIsIP);
216641
+ const encodedASCIIHost = resolvedHost && resolvedHost.indexOf("%") !== -1 && !new RegExp("\\P{ASCII}", "u").test(resolvedHost);
216642
+ if (resolved.error && !encodedASCIIHost) {
216643
+ throw new Error(resolved.error);
216644
+ }
216258
216645
  schemelessOptions.skipEscape = true;
216259
216646
  return serialize(resolved, schemelessOptions);
216260
216647
  }
@@ -216314,7 +216701,7 @@ var require_fast_uri = __commonJS({
216314
216701
  function equal(uriA, uriB, options) {
216315
216702
  const normalizedA = normalizeComparableURI(uriA, options);
216316
216703
  const normalizedB = normalizeComparableURI(uriB, options);
216317
- return normalizedA !== void 0 && normalizedB !== void 0 && normalizedA.toLowerCase() === normalizedB.toLowerCase();
216704
+ return normalizedA !== void 0 && normalizedB !== void 0 && normalizedA === normalizedB;
216318
216705
  }
216319
216706
  function serialize(cmpts, opts) {
216320
216707
  const component = {
@@ -216335,19 +216722,22 @@ var require_fast_uri = __commonJS({
216335
216722
  };
216336
216723
  const options = Object.assign({}, opts);
216337
216724
  const uriTokens = [];
216725
+ if (component.scheme) {
216726
+ component.scheme = decodeValidScheme(component.scheme);
216727
+ }
216338
216728
  const schemeHandler = getSchemeHandler(options.scheme || component.scheme);
216339
216729
  if (schemeHandler && schemeHandler.serialize) schemeHandler.serialize(component, options);
216730
+ const hasAuthority = component.userinfo !== void 0 || component.host !== void 0 || component.port !== void 0;
216731
+ const pathNoScheme = !options.skipEscape && component.scheme === void 0 && !hasAuthority;
216340
216732
  if (component.path !== void 0) {
216341
216733
  if (!options.skipEscape) {
216342
- component.path = escapePreservingEscapes(component.path);
216343
- if (component.scheme !== void 0) {
216344
- component.path = component.path.split("%3A").join(":");
216345
- }
216734
+ component.path = serializePathEncoding(component.path, pathNoScheme);
216346
216735
  } else {
216347
216736
  component.path = normalizePercentEncoding(component.path);
216348
216737
  }
216349
216738
  }
216350
216739
  if (options.reference !== "suffix" && component.scheme) {
216740
+ component.scheme = decodeValidScheme(component.scheme);
216351
216741
  uriTokens.push(component.scheme, ":");
216352
216742
  }
216353
216743
  const authority = recomposeAuthority(component);
@@ -216365,16 +216755,19 @@ var require_fast_uri = __commonJS({
216365
216755
  if (!options.absolutePath && (!schemeHandler || !schemeHandler.absolutePath)) {
216366
216756
  s4 = removeDotSegments(s4);
216367
216757
  }
216758
+ if (pathNoScheme) {
216759
+ s4 = serializePathEncoding(s4, true);
216760
+ }
216368
216761
  if (authority === void 0 && s4[0] === "/" && s4[1] === "/") {
216369
216762
  s4 = "/%2F" + s4.slice(2);
216370
216763
  }
216371
216764
  uriTokens.push(s4);
216372
216765
  }
216373
216766
  if (component.query !== void 0) {
216374
- uriTokens.push("?", component.query);
216767
+ uriTokens.push("?", encodeQuery(component.query));
216375
216768
  }
216376
216769
  if (component.fragment !== void 0) {
216377
- uriTokens.push("#", component.fragment);
216770
+ uriTokens.push("#", encodeFragment(component.fragment));
216378
216771
  }
216379
216772
  return uriTokens.join("");
216380
216773
  }
@@ -216390,6 +216783,35 @@ var require_fast_uri = __commonJS({
216390
216783
  }
216391
216784
  return void 0;
216392
216785
  }
216786
+ function hasMalformedPercentEncoding(component) {
216787
+ if (component === void 0) return false;
216788
+ let percent = component.indexOf("%");
216789
+ while (percent !== -1) {
216790
+ if (percent + 2 >= component.length || !/^[\da-f]{2}$/iu.test(component.slice(percent + 1, percent + 3))) {
216791
+ return true;
216792
+ }
216793
+ percent = component.indexOf("%", percent + 3);
216794
+ }
216795
+ return false;
216796
+ }
216797
+ function isIPLiteral(host) {
216798
+ return host[0] === "[" && host[host.length - 1] === "]";
216799
+ }
216800
+ function hasMalformedComponentPercentEncoding(matches) {
216801
+ const host = matches[4];
216802
+ return hasMalformedPercentEncoding(matches[3]) || host !== void 0 && !isIPLiteral(host) && hasMalformedPercentEncoding(host) || hasMalformedPercentEncoding(matches[6]) || hasMalformedPercentEncoding(matches[7]) || hasMalformedPercentEncoding(matches[8]);
216803
+ }
216804
+ function canonicalizeHost(parsed, options, schemeHandler, isIP5) {
216805
+ if (!options.unicodeSupport && (!schemeHandler || !schemeHandler.unicodeSupport) && parsed.host && !isIPLiteral(parsed.host) && (options.domainHost || schemeHandler && schemeHandler.domainHost) && isIP5 === false && nonSimpleDomain(parsed.host)) {
216806
+ try {
216807
+ parsed.host = new URL("http://" + parsed.host).hostname;
216808
+ } catch (e5) {
216809
+ parsed.error = parsed.error || "Host's domain name can not be converted to ASCII: " + e5;
216810
+ return true;
216811
+ }
216812
+ }
216813
+ return false;
216814
+ }
216393
216815
  function parseWithStatus(uri, opts) {
216394
216816
  const options = Object.assign({}, opts);
216395
216817
  const parsed = {
@@ -216402,6 +216824,11 @@ var require_fast_uri = __commonJS({
216402
216824
  fragment: void 0
216403
216825
  };
216404
216826
  let malformedAuthorityOrPort = false;
216827
+ let malformedPercentEncoding = false;
216828
+ let malformedSchemeSpecific = false;
216829
+ let malformedHost = false;
216830
+ let malformedIPLiteral = false;
216831
+ let malformedScheme = false;
216405
216832
  let isIP5 = false;
216406
216833
  if (options.reference === "suffix") {
216407
216834
  if (options.scheme) {
@@ -216438,6 +216865,19 @@ var require_fast_uri = __commonJS({
216438
216865
  parsed.path = matches[6] || "";
216439
216866
  parsed.query = matches[7];
216440
216867
  parsed.fragment = matches[8];
216868
+ if (parsed.scheme !== void 0) {
216869
+ const decodedScheme = unescape(parsed.scheme);
216870
+ if (VALID_SCHEME.test(decodedScheme)) {
216871
+ parsed.scheme = decodedScheme.toLowerCase();
216872
+ } else {
216873
+ parsed.error = parsed.error || MALFORMED_SCHEME_ERROR;
216874
+ malformedScheme = true;
216875
+ }
216876
+ }
216877
+ malformedPercentEncoding = hasMalformedComponentPercentEncoding(matches);
216878
+ if (malformedPercentEncoding) {
216879
+ parsed.error = parsed.error || "URI contains malformed percent-encoding.";
216880
+ }
216441
216881
  if (isNaN(parsed.port)) {
216442
216882
  parsed.port = matches[5];
216443
216883
  }
@@ -216449,9 +216889,16 @@ var require_fast_uri = __commonJS({
216449
216889
  if (parsed.host) {
216450
216890
  const ipv4result = isIPv4(parsed.host);
216451
216891
  if (ipv4result === false) {
216892
+ const bracketedIPLiteral = isIPLiteral(parsed.host);
216893
+ const hasIPLiteralBracket = parsed.host.indexOf("[") !== -1 || parsed.host.indexOf("]") !== -1;
216452
216894
  const ipv6result = normalizeIPv6(parsed.host);
216453
- parsed.host = ipv6result.host.toLowerCase();
216454
- isIP5 = ipv6result.isIPV6;
216895
+ isIP5 = ipv6result.isIPV6 || ipv6result.isIPVFuture === true;
216896
+ malformedIPLiteral = hasIPLiteralBracket && (!bracketedIPLiteral || ipv6result.error === true);
216897
+ parsed.host = isIP5 ? ipv6result.host : ipv6result.host.toLowerCase();
216898
+ if (malformedIPLiteral) {
216899
+ parsed.error = parsed.error || "URI host is malformed.";
216900
+ malformedAuthorityOrPort = true;
216901
+ }
216455
216902
  } else {
216456
216903
  isIP5 = true;
216457
216904
  }
@@ -216469,42 +216916,37 @@ var require_fast_uri = __commonJS({
216469
216916
  parsed.error = parsed.error || "URI is not a " + options.reference + " reference.";
216470
216917
  }
216471
216918
  const schemeHandler = getSchemeHandler(options.scheme || parsed.scheme);
216472
- if (!options.unicodeSupport && (!schemeHandler || !schemeHandler.unicodeSupport)) {
216473
- if (parsed.host && (options.domainHost || schemeHandler && schemeHandler.domainHost) && isIP5 === false && nonSimpleDomain(parsed.host)) {
216474
- try {
216475
- parsed.host = new URL("http://" + parsed.host).hostname;
216476
- } catch (e5) {
216477
- parsed.error = parsed.error || "Host's domain name can not be converted to ASCII: " + e5;
216478
- }
216919
+ if (!malformedIPLiteral) {
216920
+ malformedHost = canonicalizeHost(parsed, options, schemeHandler, isIP5);
216921
+ }
216922
+ if (uri.indexOf("%") !== -1 && parsed.host !== void 0 && !malformedIPLiteral) {
216923
+ let host = isIP5 ? parsed.host : normalizePercentEncoding(parsed.host, true);
216924
+ if (!isIP5) {
216925
+ host = normalizePercentEncoding(host.toLowerCase());
216479
216926
  }
216927
+ parsed.host = reescapeHostDelimiters(host, isIP5);
216480
216928
  }
216481
216929
  if (!schemeHandler || schemeHandler && !schemeHandler.skipNormalize) {
216482
- if (uri.indexOf("%") !== -1) {
216483
- if (parsed.scheme !== void 0) {
216484
- parsed.scheme = unescape(parsed.scheme);
216485
- }
216486
- if (parsed.host !== void 0) {
216487
- parsed.host = reescapeHostDelimiters(unescape(parsed.host), isIP5);
216488
- }
216489
- }
216490
216930
  if (parsed.path) {
216491
216931
  parsed.path = normalizePathEncoding(parsed.path);
216492
216932
  }
216933
+ if (parsed.query) {
216934
+ parsed.query = normalizeQueryFragmentEncoding(parsed.query);
216935
+ }
216493
216936
  if (parsed.fragment) {
216494
- try {
216495
- parsed.fragment = encodeURI(decodeURIComponent(parsed.fragment));
216496
- } catch {
216497
- parsed.error = parsed.error || "URI malformed";
216498
- }
216937
+ parsed.fragment = normalizeQueryFragmentEncoding(parsed.fragment);
216499
216938
  }
216500
216939
  }
216501
216940
  if (schemeHandler && schemeHandler.parse) {
216502
216941
  schemeHandler.parse(parsed, options);
216942
+ if (schemeHandler === SCHEMES.urn && parsed.nid === void 0) {
216943
+ malformedSchemeSpecific = true;
216944
+ }
216503
216945
  }
216504
216946
  } else {
216505
216947
  parsed.error = parsed.error || "URI can not be parsed.";
216506
216948
  }
216507
- return { parsed, malformedAuthorityOrPort };
216949
+ return { parsed, malformedAuthorityOrPort, malformedPercentEncoding, malformedSchemeSpecific, malformedHost, malformedScheme };
216508
216950
  }
216509
216951
  function parse5(uri, opts) {
216510
216952
  return parseWithStatus(uri, opts).parsed;
@@ -216513,20 +216955,28 @@ var require_fast_uri = __commonJS({
216513
216955
  return normalizeStringWithStatus(uri, opts).normalized;
216514
216956
  }
216515
216957
  function normalizeStringWithStatus(uri, opts) {
216516
- const { parsed, malformedAuthorityOrPort } = parseWithStatus(uri, opts);
216958
+ const { parsed, malformedAuthorityOrPort, malformedPercentEncoding, malformedSchemeSpecific, malformedHost, malformedScheme } = parseWithStatus(uri, opts);
216517
216959
  return {
216518
- normalized: malformedAuthorityOrPort ? uri : serialize(parsed, opts),
216519
- malformedAuthorityOrPort
216960
+ normalized: malformedAuthorityOrPort || malformedPercentEncoding || malformedSchemeSpecific || malformedHost || malformedScheme ? uri : serialize(parsed, opts),
216961
+ malformedAuthorityOrPort,
216962
+ malformedPercentEncoding,
216963
+ malformedSchemeSpecific,
216964
+ malformedHost,
216965
+ malformedScheme
216520
216966
  };
216521
216967
  }
216522
216968
  function normalizeComparableURI(uri, opts) {
216523
- if (typeof uri === "string") {
216524
- const { normalized, malformedAuthorityOrPort } = normalizeStringWithStatus(uri, opts);
216525
- return malformedAuthorityOrPort ? void 0 : normalized;
216969
+ if (typeof uri !== "string" && typeof uri !== "object") {
216970
+ return void 0;
216526
216971
  }
216527
- if (typeof uri === "object") {
216528
- return serialize(uri, opts);
216972
+ let value;
216973
+ try {
216974
+ value = typeof uri === "string" ? uri : serialize(uri, opts);
216975
+ } catch {
216976
+ return void 0;
216529
216977
  }
216978
+ const { normalized, malformedAuthorityOrPort, malformedPercentEncoding, malformedSchemeSpecific, malformedHost, malformedScheme } = normalizeStringWithStatus(value, opts);
216979
+ return malformedAuthorityOrPort || malformedPercentEncoding || malformedSchemeSpecific || malformedHost || malformedScheme ? void 0 : normalized;
216530
216980
  }
216531
216981
  var fastUri = {
216532
216982
  SCHEMES,
@@ -221138,6 +221588,42 @@ var init_mcp_server = __esm({
221138
221588
  });
221139
221589
 
221140
221590
  // node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js
221591
+ function toolInputElementCount(value, max) {
221592
+ let count3 = 0;
221593
+ const stack = [value];
221594
+ while (stack.length > 0) {
221595
+ const node = stack.pop();
221596
+ if (node === null || typeof node !== "object")
221597
+ continue;
221598
+ if (Array.isArray(node)) {
221599
+ for (const child of node) {
221600
+ if (++count3 > max)
221601
+ return count3;
221602
+ if (child !== null && typeof child === "object")
221603
+ stack.push(child);
221604
+ }
221605
+ } else {
221606
+ for (const key in node) {
221607
+ if (!Object.prototype.hasOwnProperty.call(node, key))
221608
+ continue;
221609
+ if (++count3 > max)
221610
+ return count3;
221611
+ const child = node[key];
221612
+ if (child !== null && typeof child === "object")
221613
+ stack.push(child);
221614
+ }
221615
+ }
221616
+ }
221617
+ return count3;
221618
+ }
221619
+ function resolveMaxToolInputElements(value) {
221620
+ if (value === void 0 || value === Infinity)
221621
+ return void 0;
221622
+ if (typeof value !== "number" || Number.isNaN(value) || value < 1) {
221623
+ throw new RangeError(`maxToolInputElements must be a number of at least 1, or Infinity, got ${String(value)}`);
221624
+ }
221625
+ return value;
221626
+ }
221141
221627
  function isZodTypeLike(value) {
221142
221628
  return value !== null && typeof value === "object" && "parse" in value && typeof value.parse === "function" && "safeParse" in value && typeof value.safeParse === "function";
221143
221629
  }
@@ -221228,6 +221714,7 @@ var init_mcp = __esm({
221228
221714
  this._resourceHandlersInitialized = false;
221229
221715
  this._promptHandlersInitialized = false;
221230
221716
  this.server = new Server(serverInfo, options);
221717
+ this._maxToolInputElements = resolveMaxToolInputElements(options?.maxToolInputElements);
221231
221718
  }
221232
221719
  /**
221233
221720
  * Access experimental features.
@@ -221358,12 +221845,15 @@ var init_mcp = __esm({
221358
221845
  * Validates tool input arguments against the tool's input schema.
221359
221846
  */
221360
221847
  async validateToolInput(tool, args, toolName) {
221848
+ if (this._maxToolInputElements !== void 0 && toolInputElementCount(args, this._maxToolInputElements) > this._maxToolInputElements) {
221849
+ throw new McpError(ErrorCode.InvalidParams, `Invalid arguments for tool ${toolName}: arguments contain more than the maximum of ${this._maxToolInputElements} elements`);
221850
+ }
221361
221851
  if (!tool.inputSchema) {
221362
221852
  return void 0;
221363
221853
  }
221364
221854
  const inputObj = normalizeObjectSchema(tool.inputSchema);
221365
221855
  const schemaToParse = inputObj ?? tool.inputSchema;
221366
- const parseResult = await safeParseAsync3(schemaToParse, args);
221856
+ const parseResult = await safeParseAsync3(schemaToParse, args ?? {});
221367
221857
  if (!parseResult.success) {
221368
221858
  const error40 = "error" in parseResult ? parseResult.error : "Unknown error";
221369
221859
  const errorMessage = getParseErrorMessage(error40);
@@ -221601,7 +222091,7 @@ var init_mcp = __esm({
221601
222091
  }
221602
222092
  if (prompt2.argsSchema) {
221603
222093
  const argsObj = normalizeObjectSchema(prompt2.argsSchema);
221604
- const parseResult = await safeParseAsync3(argsObj, request.params.arguments);
222094
+ const parseResult = await safeParseAsync3(argsObj, request.params.arguments ?? {});
221605
222095
  if (!parseResult.success) {
221606
222096
  const error40 = "error" in parseResult ? parseResult.error : "Unknown error";
221607
222097
  const errorMessage = getParseErrorMessage(error40);
@@ -225198,7 +225688,8 @@ async function handleApi(req, res, dataDir, projectId, projectName, baseDir, pro
225198
225688
  "OPENAI_API_KEY",
225199
225689
  "ANTHROPIC_API_KEY",
225200
225690
  ...resolved.memory.llm.provider === "openrouter" || resolved.memory.llm.baseUrl?.includes("openrouter.ai") ? ["OPENROUTER_API_KEY"] : [],
225201
- ...resolved.memory.llm.provider === "requesty" ? ["REQUESTY_API_KEY"] : []
225691
+ ...resolved.memory.llm.provider === "requesty" ? ["REQUESTY_API_KEY"] : [],
225692
+ ...resolved.memory.llm.provider === "apiroute" ? ["API_ROUTE_API_KEY"] : []
225202
225693
  ];
225203
225694
  if (llmKey) {
225204
225695
  const src2 = resolveDashboardKeySource({ value: llmKey, envKeys: memoryKeyEnv, configSource });
@@ -265529,12 +266020,13 @@ __export(image_loader_exports, {
265529
266020
  analyzeImage: () => analyzeImage
265530
266021
  });
265531
266022
  async function callVisionLLM(systemPrompt, imageBase64, mimeType) {
265532
- const apiKey = getLLMApiKey();
266023
+ const config2 = getLLMConfig();
266024
+ const apiKey = config2?.apiKey ?? getLLMApiKey();
265533
266025
  if (!apiKey) {
265534
266026
  throw new Error("No LLM API key configured for image analysis.");
265535
266027
  }
265536
- const baseUrl = normalizeOpenAICompatibleBaseUrl(getLLMBaseUrl("https://api.openai.com/v1"));
265537
- const model = getLLMModel("gpt-4o");
266028
+ const baseUrl = normalizeOpenAICompatibleBaseUrl(config2?.baseUrl ?? getLLMBaseUrl("https://api.openai.com/v1"));
266029
+ const model = config2?.model ?? getLLMModel("gpt-4o");
265538
266030
  const response = await fetch(`${baseUrl}/chat/completions`, {
265539
266031
  method: "POST",
265540
266032
  headers: {
@@ -265589,7 +266081,7 @@ async function analyzeImage(input) {
265589
266081
  const config2 = getLLMConfig();
265590
266082
  if (!OPENAI_COMPATIBLE_PROVIDERS.has(config2.provider)) {
265591
266083
  throw new Error(
265592
- `Image analysis requires an OpenAI-compatible provider (openai, openrouter, requesty, or custom). Current provider "${config2.provider}" uses a different API shape. Set MEMORIX_LLM_PROVIDER=openai or configure an OpenAI-compatible base URL.`
266084
+ `Image analysis requires an OpenAI-compatible provider (openai, openrouter, requesty, apiroute, or custom). Current provider "${config2.provider}" uses a different API shape. Set MEMORIX_LLM_PROVIDER=openai or configure an OpenAI-compatible base URL.`
265593
266085
  );
265594
266086
  }
265595
266087
  const bytes = decodeBase64ImagePayload(input.base64, MAX_VISION_IMAGE_BYTES);
@@ -265628,7 +266120,7 @@ var init_image_loader = __esm({
265628
266120
  init_provider2();
265629
266121
  init_secret_filter();
265630
266122
  init_image_payload();
265631
- OPENAI_COMPATIBLE_PROVIDERS = /* @__PURE__ */ new Set(["openai", "openrouter", "requesty", "custom"]);
266123
+ OPENAI_COMPATIBLE_PROVIDERS = /* @__PURE__ */ new Set(["openai", "openrouter", "requesty", "apiroute", "custom"]);
265632
266124
  MAX_VISION_PROMPT_CHARS = 12e3;
265633
266125
  MAX_VISION_DESCRIPTION_CHARS = 12e3;
265634
266126
  MAX_VISION_LABELS = 50;
@@ -265910,8 +266402,8 @@ async function createMemorixServer(cwd, existingServer, sharedTeam, options = {}
265910
266402
  if (!lightweightUnresolvedSession && !deferProjectRuntimeInit) {
265911
266403
  try {
265912
266404
  const { getAllObservations: getAllObservations2 } = await Promise.resolve().then(() => (init_observations(), observations_exports));
265913
- const allObs = getAllObservations2();
265914
- const observedIds = [...new Set(allObs.map((o4) => o4.projectId))];
266405
+ const store2 = getObservationStore();
266406
+ const observedIds = store2.listProjectIds ? await store2.listProjectIds() : [...new Set(getAllObservations2().map((o4) => o4.projectId))];
265915
266407
  const merged = await autoMergeByBaseName(observedIds);
265916
266408
  if (merged > 0) {
265917
266409
  console.error(`[memorix] Auto-merged ${merged} alias group(s) by base name`);
@@ -265952,8 +266444,8 @@ async function createMemorixServer(cwd, existingServer, sharedTeam, options = {}
265952
266444
  try {
265953
266445
  const { getAllObservations: getAllObservations2 } = await Promise.resolve().then(() => (init_observations(), observations_exports));
265954
266446
  await initObservations(projectDir2);
265955
- const allObs = getAllObservations2();
265956
- const observedIds = [...new Set(allObs.map((o4) => o4.projectId))];
266447
+ const store2 = getObservationStore();
266448
+ const observedIds = store2.listProjectIds ? await store2.listProjectIds() : [...new Set(getAllObservations2().map((o4) => o4.projectId))];
265957
266449
  const merged = await autoMergeByBaseName(observedIds);
265958
266450
  if (merged > 0) {
265959
266451
  console.error(`[memorix] Auto-merged ${merged} alias group(s) by base name`);
@@ -271324,20 +271816,15 @@ var init_websocket = __esm({
271324
271816
  if (typeof args[0] === "function") {
271325
271817
  const [createEvents, options] = args;
271326
271818
  return async function upgradeWebSocket2(c6, next) {
271327
- const events = await createEvents(c6);
271328
- const result = await handler(c6, events, options);
271329
- if (result) {
271330
- return result;
271331
- }
271819
+ const result = await handler(c6, await createEvents(c6), options);
271820
+ if (result) return result;
271332
271821
  await next();
271333
271822
  };
271334
271823
  } else {
271335
271824
  const [c6, events, options] = args;
271336
271825
  return (async () => {
271337
271826
  const upgraded = await handler(c6, events, options);
271338
- if (!upgraded) {
271339
- throw new Error("Failed to upgrade WebSocket");
271340
- }
271827
+ if (!upgraded) throw new Error("Failed to upgrade WebSocket");
271341
271828
  return upgraded;
271342
271829
  })();
271343
271830
  }
@@ -272496,6 +272983,57 @@ var init_mediaType = __esm({
272496
272983
  }
272497
272984
  });
272498
272985
 
272986
+ // node_modules/@modelcontextprotocol/sdk/dist/esm/server/requestBody.js
272987
+ function requestBodyTooLargeMessage(maxBytes) {
272988
+ return `Payload Too Large: Request body must not exceed ${maxBytes} bytes`;
272989
+ }
272990
+ function resolveMaxRequestBodySize(value) {
272991
+ if (value === void 0) {
272992
+ return DEFAULT_MAX_REQUEST_BODY_SIZE;
272993
+ }
272994
+ if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) {
272995
+ throw new RangeError(`maxRequestBodySize must be a positive number of bytes, got ${String(value)}`);
272996
+ }
272997
+ return value;
272998
+ }
272999
+ async function readRequestBody(request, maxBytes = DEFAULT_MAX_REQUEST_BODY_SIZE) {
273000
+ if (Number(request.headers.get("content-length")) > maxBytes) {
273001
+ return { tooLarge: true };
273002
+ }
273003
+ if (request.body === null) {
273004
+ return { tooLarge: false, text: "" };
273005
+ }
273006
+ const reader2 = request.body.getReader();
273007
+ const decoder2 = new TextDecoder();
273008
+ let received = 0;
273009
+ let text3 = "";
273010
+ try {
273011
+ for (; ; ) {
273012
+ const { done, value } = await reader2.read();
273013
+ if (done) {
273014
+ break;
273015
+ }
273016
+ received += value.byteLength;
273017
+ if (received > maxBytes) {
273018
+ return { tooLarge: true };
273019
+ }
273020
+ text3 += decoder2.decode(value, { stream: true });
273021
+ }
273022
+ } finally {
273023
+ reader2.releaseLock();
273024
+ }
273025
+ return { tooLarge: false, text: text3 + decoder2.decode() };
273026
+ }
273027
+ var DEFAULT_MAX_REQUEST_BODY_SIZE, MAX_BATCH_SIZE2;
273028
+ var init_requestBody = __esm({
273029
+ "node_modules/@modelcontextprotocol/sdk/dist/esm/server/requestBody.js"() {
273030
+ "use strict";
273031
+ init_esm_shims();
273032
+ DEFAULT_MAX_REQUEST_BODY_SIZE = 4 * 1024 * 1024;
273033
+ MAX_BATCH_SIZE2 = 100;
273034
+ }
273035
+ });
273036
+
272499
273037
  // node_modules/@modelcontextprotocol/sdk/dist/esm/server/sseKeepAlive.js
272500
273038
  function armSseKeepAlive(intervalMs, onTick) {
272501
273039
  if (!Number.isFinite(intervalMs) || intervalMs < 1) {
@@ -272522,6 +273060,7 @@ var init_webStandardStreamableHttp = __esm({
272522
273060
  "use strict";
272523
273061
  init_esm_shims();
272524
273062
  init_mediaType();
273063
+ init_requestBody();
272525
273064
  init_sseKeepAlive();
272526
273065
  init_types8();
272527
273066
  WebStandardStreamableHTTPServerTransport = class {
@@ -272546,6 +273085,7 @@ var init_webStandardStreamableHttp = __esm({
272546
273085
  this._enableDnsRebindingProtection = options.enableDnsRebindingProtection ?? false;
272547
273086
  this._retryInterval = options.retryInterval;
272548
273087
  this._keepAliveMs = options.keepAliveMs ?? DEFAULT_SSE_KEEP_ALIVE_MS;
273088
+ this._maxRequestBodySize = resolveMaxRequestBodySize(options.maxRequestBodySize);
272549
273089
  }
272550
273090
  /**
272551
273091
  * Arms a keep-alive interval for an SSE stream that periodically writes an SSE
@@ -272907,12 +273447,22 @@ data:
272907
273447
  rawMessage = options.parsedBody;
272908
273448
  } else {
272909
273449
  try {
272910
- rawMessage = await req.json();
273450
+ const body = await readRequestBody(req, this._maxRequestBodySize);
273451
+ if (body.tooLarge) {
273452
+ const message = requestBodyTooLargeMessage(this._maxRequestBodySize);
273453
+ this.onerror?.(new Error(message));
273454
+ return this.createJsonErrorResponse(413, -32e3, message);
273455
+ }
273456
+ rawMessage = JSON.parse(body.text);
272911
273457
  } catch {
272912
273458
  this.onerror?.(new Error("Parse error: Invalid JSON"));
272913
273459
  return this.createJsonErrorResponse(400, -32700, "Parse error: Invalid JSON");
272914
273460
  }
272915
273461
  }
273462
+ if (Array.isArray(rawMessage) && rawMessage.length > MAX_BATCH_SIZE2) {
273463
+ this.onerror?.(new Error(`Invalid Request: Batch must not exceed ${MAX_BATCH_SIZE2} messages`));
273464
+ return this.createJsonErrorResponse(400, -32600, `Invalid Request: Batch must not exceed ${MAX_BATCH_SIZE2} messages`);
273465
+ }
272916
273466
  let messages;
272917
273467
  try {
272918
273468
  if (Array.isArray(rawMessage)) {
@@ -278211,6 +278761,7 @@ function extractEventName(payload, agent) {
278211
278761
  case "cursor":
278212
278762
  return payload.hook_event_name ?? inferCursorEvent(payload);
278213
278763
  case "claude":
278764
+ case "qwen":
278214
278765
  return payload.hook_event_name ?? "";
278215
278766
  case "codex":
278216
278767
  return payload.hook_event_name ?? "";
@@ -278259,7 +278810,7 @@ function normalizeClaude(payload, event) {
278259
278810
  if (/^bash$/i.test(toolName) && toolInput?.command) {
278260
278811
  result.command = toolInput.command;
278261
278812
  }
278262
- if (/^(write|edit|multi_edit|multiedittool)$/i.test(toolName)) {
278813
+ if (/^(write|write_file|edit|edit_file|multi_edit|multiedittool)$/i.test(toolName)) {
278263
278814
  result.filePath = toolInput?.file_path ?? toolInput?.filePath;
278264
278815
  }
278265
278816
  }
@@ -278549,6 +279100,7 @@ function normalizeHookInput(payload) {
278549
279100
  let agentSpecific = {};
278550
279101
  switch (agent) {
278551
279102
  case "claude":
279103
+ case "qwen":
278552
279104
  agentSpecific = normalizeClaude(payload, event);
278553
279105
  break;
278554
279106
  case "copilot":
@@ -278632,9 +279184,12 @@ var init_normalizer = __esm({
278632
279184
  PreToolUse: "post_tool",
278633
279185
  // we handle pre as post for memory purposes
278634
279186
  PostToolUse: "post_tool",
279187
+ PostToolUseFailure: "post_tool",
278635
279188
  PreCompact: "pre_compact",
279189
+ PostCompact: "post_compact",
278636
279190
  Stop: "session_end",
278637
279191
  SessionEnd: "session_end",
279192
+ SessionDelete: "session_end",
278638
279193
  // Grok Build (Claude-compatible PascalCase plus snake_case hookEventName)
278639
279194
  user_prompt_submit: "user_prompt",
278640
279195
  pre_tool_use: "post_tool",
@@ -278915,11 +279470,7 @@ async function readHookStdin(stdin2, timeoutMs) {
278915
279470
  stdin2.removeListener("end", finish);
278916
279471
  stdin2.removeListener("error", finish);
278917
279472
  stdin2.pause?.();
278918
- if (!stdin2.isTTY) {
278919
- stdin2.destroy?.();
278920
- } else {
278921
- stdin2.unref?.();
278922
- }
279473
+ stdin2.unref?.();
278923
279474
  resolve9(Buffer.concat(chunks).toString("utf-8").trim());
278924
279475
  };
278925
279476
  const onData = (chunk) => {
@@ -279000,7 +279551,7 @@ var init_lifecycle2 = __esm({
279000
279551
  // src/hooks/handler.ts
279001
279552
  var handler_exports = {};
279002
279553
  __export(handler_exports, {
279003
- TYPE_EMOJI: () => TYPE_EMOJI2,
279554
+ TYPE_EMOJI: () => TYPE_EMOJI,
279004
279555
  formatHookOutput: () => formatHookOutput,
279005
279556
  handleHookEvent: () => handleHookEvent,
279006
279557
  resetCooldowns: () => resetCooldowns,
@@ -279564,7 +280115,7 @@ function toAntigravityHookOutput(rawEventName, output) {
279564
280115
  return {};
279565
280116
  }
279566
280117
  }
279567
- var TYPE_EMOJI2, cooldowns, COOLDOWN_MS, MIN_PROMPT_LENGTH, MAX_CONTENT_LENGTH, STORAGE_POLICY;
280118
+ var TYPE_EMOJI, cooldowns, COOLDOWN_MS, MIN_PROMPT_LENGTH, MAX_CONTENT_LENGTH, STORAGE_POLICY;
279568
280119
  var init_handler = __esm({
279569
280120
  "src/hooks/handler.ts"() {
279570
280121
  "use strict";
@@ -279574,7 +280125,7 @@ var init_handler = __esm({
279574
280125
  init_pattern_detector();
279575
280126
  init_significance_filter();
279576
280127
  init_lifecycle2();
279577
- TYPE_EMOJI2 = {
280128
+ TYPE_EMOJI = {
279578
280129
  "gotcha": "[GOTCHA]",
279579
280130
  "decision": "[DECISION]",
279580
280131
  "problem-solution": "[FIX]",
@@ -279668,7 +280219,8 @@ var init_types9 = __esm({
279668
280219
  pi: "community",
279669
280220
  omp: "community",
279670
280221
  antigravity: "community",
279671
- grok: "community"
280222
+ grok: "community",
280223
+ qwen: "extended"
279672
280224
  };
279673
280225
  }
279674
280226
  });
@@ -279718,6 +280270,7 @@ async function installSingleAgent2(agent, cwd, global2) {
279718
280270
  function getAgentLabel2(agent) {
279719
280271
  const labels = {
279720
280272
  claude: "Claude Code",
280273
+ qwen: "Qwen Code",
279721
280274
  codex: "Codex",
279722
280275
  windsurf: "Windsurf",
279723
280276
  cursor: "Cursor",
@@ -279739,6 +280292,7 @@ function getAgentLabel2(agent) {
279739
280292
  function getAgentHint2(agent) {
279740
280293
  const hints = {
279741
280294
  claude: ".claude/settings.json",
280295
+ qwen: ".qwen/settings.json",
279742
280296
  windsurf: ".windsurf/hooks.json",
279743
280297
  cursor: ".cursor/hooks.json",
279744
280298
  copilot: ".github/hooks/memorix.json (project-only, no global)",
@@ -289775,6 +290329,7 @@ function ConfigureView({ onBack }) {
289775
290329
  { key: "anthropic", label: "Anthropic", hint: "claude-3-haiku" },
289776
290330
  { key: "openrouter", label: "OpenRouter", hint: "multi-provider" },
289777
290331
  { key: "requesty", label: "Requesty", hint: "multi-provider" },
290332
+ { key: "apiroute", label: "API Route", hint: "multi-provider" },
289778
290333
  { key: "atlascloud", label: "Atlas Cloud", hint: "DeepSeek V3.2" },
289779
290334
  { key: "custom", label: "Custom endpoint", hint: "OpenAI-compatible" },
289780
290335
  { key: "disable", label: "Disable LLM", hint: "free heuristic mode", color: COLORS.warning },
@@ -290069,6 +290624,7 @@ function getDefaultModel(provider2) {
290069
290624
  if (provider2 === "anthropic") return "claude-3-haiku-20240307";
290070
290625
  if (provider2 === "openrouter") return "openai/gpt-4o-mini";
290071
290626
  if (provider2 === "requesty") return "openai/gpt-4o-mini";
290627
+ if (provider2 === "apiroute") return "deepseek-v4.1-flash";
290072
290628
  if (provider2 === "atlascloud") return "deepseek-ai/deepseek-v3.2";
290073
290629
  return "gpt-4o-mini";
290074
290630
  }
@@ -293626,14 +294182,14 @@ var main2 = defineCommand({
293626
294182
  search: () => Promise.resolve(defineCommand({
293627
294183
  meta: { name: "search", description: "Shortcut for `memorix memory search`" },
293628
294184
  args: {
293629
- query: { type: "positional", description: "Search query", required: true },
294185
+ query: { type: "string", description: "Search query (also accepts the first positional argument)", required: false },
293630
294186
  limit: { type: "string", description: "Maximum results" },
293631
294187
  quality: { type: "string", description: "Retrieval profile: fast, balanced (default), or thorough" },
293632
294188
  json: { type: "boolean", description: "Emit machine-readable JSON output" }
293633
294189
  },
293634
294190
  async run({ args }) {
293635
294191
  await runMemoryShortcut("search", {
293636
- query: args.query,
294192
+ query: args.query ?? args._?.[0],
293637
294193
  limit: args.limit,
293638
294194
  quality: args.quality,
293639
294195
  json: args.json