@massa-ai/tools-api 1.9.0 → 1.9.2

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 (2) hide show
  1. package/dist/index.js +174 -14
  2. package/package.json +3 -3
package/dist/index.js CHANGED
@@ -938,6 +938,20 @@ function validateCapturePolicyConfig(raw2) {
938
938
  ...p.maxIgnorePatterns !== undefined && { maxIgnorePatterns: p.maxIgnorePatterns }
939
939
  };
940
940
  }
941
+ function validateAllowedExtensionsConfig(raw2) {
942
+ if (!Array.isArray(raw2)) {
943
+ throw new TypeError("security.allowedExtensions must be an array of strings");
944
+ }
945
+ if (raw2.length === 0) {
946
+ throw new TypeError("security.allowedExtensions must not be empty \u2014 an empty allow-list indexes nothing; omit the key to use the defaults");
947
+ }
948
+ for (const ext of raw2) {
949
+ if (typeof ext !== "string" || !ext.startsWith(".") || ext.length < 2) {
950
+ throw new TypeError(`security.allowedExtensions[] must be dot-prefixed extensions (got ${JSON.stringify(ext)})`);
951
+ }
952
+ }
953
+ return [...raw2];
954
+ }
941
955
  function getGlobalDataDir() {
942
956
  const envOverride = process.env.MASSA_AI_DATA_DIR;
943
957
  if (envOverride && envOverride.trim())
@@ -1233,7 +1247,7 @@ var init_config = __esm(() => {
1233
1247
  sanitizeInputs: process.env.SANITIZE_INPUTS !== "false",
1234
1248
  maxIndexSize: 1e5,
1235
1249
  maxFileSize: 1024 * 1024,
1236
- allowedExtensions: [...DEFAULT_ALLOWED_EXTENSIONS],
1250
+ allowedExtensions: fileConfig.security?.allowedExtensions ? validateAllowedExtensionsConfig(fileConfig.security.allowedExtensions) : [...DEFAULT_ALLOWED_EXTENSIONS],
1237
1251
  excludePatterns: [
1238
1252
  "node_modules/**",
1239
1253
  ".git/**",
@@ -106605,14 +106619,140 @@ var require_ignore = __commonJS((exports, module) => {
106605
106619
  });
106606
106620
 
106607
106621
  // ../../packages/core/dist/services/search/capture-policy.js
106608
- var regexCache;
106622
+ function globToRegex(pattern) {
106623
+ let re = "^";
106624
+ let i = 0;
106625
+ while (i < pattern.length) {
106626
+ const ch = pattern[i];
106627
+ if (ch === "*") {
106628
+ if (pattern[i + 1] === "*") {
106629
+ re += ".*";
106630
+ i += 2;
106631
+ if (pattern[i] === "/")
106632
+ i += 1;
106633
+ } else {
106634
+ re += "[^/]*";
106635
+ i += 1;
106636
+ }
106637
+ } else if (ch === "?") {
106638
+ re += "[^/]";
106639
+ i += 1;
106640
+ } else if (ch === ".") {
106641
+ re += "\\.";
106642
+ i += 1;
106643
+ } else if ("+()^${}|[]\\".includes(ch)) {
106644
+ re += "\\" + ch;
106645
+ i += 1;
106646
+ } else {
106647
+ re += ch;
106648
+ i += 1;
106649
+ }
106650
+ }
106651
+ re += "$";
106652
+ return new RegExp(re);
106653
+ }
106654
+ function validatePolicy(policy, opts = {}) {
106655
+ if (!policy || typeof policy !== "object")
106656
+ throw new TypeError("policy must be an object");
106657
+ const p = policy;
106658
+ const allowedKeys = new Set(["rules", "maxMatchWork", "maxIgnorePatterns"]);
106659
+ if (opts.denyUnknownFields) {
106660
+ for (const key of Object.keys(p)) {
106661
+ if (!allowedKeys.has(key)) {
106662
+ throw new TypeError(`policy: unknown field "${key}" (denyUnknownFields=true)`);
106663
+ }
106664
+ }
106665
+ }
106666
+ if (!Array.isArray(p.rules))
106667
+ throw new TypeError("policy.rules must be an array");
106668
+ const dropCount = p.rules.filter((r2) => r2?.disposition === "Drop").length;
106669
+ const maxIgnore = typeof p.maxIgnorePatterns === "number" ? p.maxIgnorePatterns : MAX_IGNORE_PATTERNS2;
106670
+ if (dropCount > maxIgnore) {
106671
+ throw new TypeError(`policy: ${dropCount} Drop rules exceed maxIgnorePatterns=${maxIgnore}`);
106672
+ }
106673
+ if (p.maxMatchWork !== undefined) {
106674
+ if (typeof p.maxMatchWork !== "number" || p.maxMatchWork < 0) {
106675
+ throw new TypeError("policy.maxMatchWork must be a non-negative number");
106676
+ }
106677
+ }
106678
+ }
106679
+ function matchesGlob(path8, pattern) {
106680
+ let re = regexCache.get(pattern);
106681
+ if (!re) {
106682
+ re = globToRegex(pattern);
106683
+ regexCache.set(pattern, re);
106684
+ }
106685
+ return re.test(path8);
106686
+ }
106687
+ var MAX_MATCH_WORK = 1e5, MAX_IGNORE_PATTERNS2 = 1024, DEFAULT_POLICY, applyPolicy = (filePath, policy) => {
106688
+ const normalized = filePath.trim();
106689
+ for (const rule of policy.rules) {
106690
+ if (matchesGlob(normalized, rule.pattern))
106691
+ return rule.disposition;
106692
+ }
106693
+ return "Keep";
106694
+ }, regexCache;
106609
106695
  var init_capture_policy = __esm(() => {
106696
+ DEFAULT_POLICY = {
106697
+ rules: [
106698
+ { pattern: "**/node_modules/**", disposition: "Drop" },
106699
+ { pattern: "**/.git/**", disposition: "Drop" },
106700
+ { pattern: "**/dist/**", disposition: "Drop" },
106701
+ { pattern: "**/build/**", disposition: "Drop" },
106702
+ { pattern: "**/coverage/**", disposition: "Drop" },
106703
+ { pattern: ".env", disposition: "Drop" },
106704
+ { pattern: ".env.*", disposition: "Drop" },
106705
+ { pattern: "**/generated/**", disposition: "Drop" },
106706
+ { pattern: "**/*.generated.*", disposition: "Drop" },
106707
+ { pattern: "**/*.d.ts", disposition: "Drop" },
106708
+ { pattern: "**/__tests__/**", disposition: "Drop" },
106709
+ { pattern: "**/tests/**", disposition: "Drop" },
106710
+ { pattern: "**/*.test.ts", disposition: "Drop" },
106711
+ { pattern: "**/*.test.tsx", disposition: "Drop" },
106712
+ { pattern: "**/*.test.js", disposition: "Drop" },
106713
+ { pattern: "**/*.test.jsx", disposition: "Drop" },
106714
+ { pattern: "**/*.spec.ts", disposition: "Drop" },
106715
+ { pattern: "**/*.spec.tsx", disposition: "Drop" },
106716
+ { pattern: "**/*.spec.js", disposition: "Drop" },
106717
+ { pattern: "**/*.spec.jsx", disposition: "Drop" },
106718
+ { pattern: "**/benchmarks/**", disposition: "Drop" },
106719
+ { pattern: "**/fixtures/**", disposition: "Drop" },
106720
+ { pattern: "**/*.wasm*", disposition: "Drop" },
106721
+ { pattern: "**/*.min.*", disposition: "Drop" },
106722
+ { pattern: "**/*.map", disposition: "Drop" },
106723
+ { pattern: "**/lock.yaml", disposition: "Drop" },
106724
+ { pattern: "**/pnpm-lock.yaml", disposition: "Drop" },
106725
+ { pattern: "**/package-lock.json", disposition: "Drop" },
106726
+ { pattern: "**/bun.lockb", disposition: "Drop" },
106727
+ { pattern: "**/yarn.lock", disposition: "Drop" }
106728
+ ],
106729
+ maxMatchWork: MAX_MATCH_WORK,
106730
+ maxIgnorePatterns: MAX_IGNORE_PATTERNS2
106731
+ };
106610
106732
  regexCache = new Map;
106611
106733
  });
106612
106734
 
106613
106735
  // ../../packages/core/dist/services/search/ignore-patterns.js
106614
106736
  import fs3 from "fs/promises";
106615
106737
  import path8 from "path";
106738
+ function buildExtensionGlob(extensions2) {
106739
+ return extensions2.map((ext2) => `**/*${ext2}`);
106740
+ }
106741
+ function getActivePolicy() {
106742
+ if (cachedPolicy)
106743
+ return cachedPolicy;
106744
+ const fromConfig = config.get("capturePolicy");
106745
+ if (!fromConfig) {
106746
+ cachedPolicy = DEFAULT_POLICY;
106747
+ return cachedPolicy;
106748
+ }
106749
+ validatePolicy(fromConfig, { denyUnknownFields: true });
106750
+ cachedPolicy = fromConfig;
106751
+ return cachedPolicy;
106752
+ }
106753
+ function getActiveCapturePolicy() {
106754
+ return getActivePolicy();
106755
+ }
106616
106756
  async function loadProjectIgnore(projectPath) {
106617
106757
  const ig = ignore();
106618
106758
  ig.add(DEFAULT_IGNORES);
@@ -106631,7 +106771,7 @@ async function loadProjectIgnore(projectPath) {
106631
106771
  }
106632
106772
  return ig;
106633
106773
  }
106634
- var import_ignore3, ignore, DEFAULT_EXTENSIONS, DEFAULT_IGNORES;
106774
+ var import_ignore3, ignore, DEFAULT_EXTENSIONS, DEFAULT_IGNORES, cachedPolicy;
106635
106775
  var init_ignore_patterns = __esm(() => {
106636
106776
  init_dist();
106637
106777
  init_capture_policy();
@@ -106923,9 +107063,9 @@ class IndexManager {
106923
107063
  try {
106924
107064
  const securityConfig = config.get("security");
106925
107065
  const allowedExtensions = securityConfig.allowedExtensions || DEFAULT_ALLOWED_EXTENSIONS;
106926
- const combinedPattern = `**/*{${allowedExtensions.join(",")}}`;
107066
+ const patterns = buildExtensionGlob(allowedExtensions);
106927
107067
  const ig = await this.loadGitignore(projectPath);
106928
- const matches = await globAsync(combinedPattern, {
107068
+ const matches = await globAsync(patterns, {
106929
107069
  cwd: projectPath,
106930
107070
  nodir: true,
106931
107071
  dot: false
@@ -111224,7 +111364,7 @@ async function _indexProjectInternalImpl(rlm, projectPath, projectId, options =
111224
111364
  ];
111225
111365
  try {
111226
111366
  const ig = await loadGitignoreImpl(projectPath);
111227
- const files = await globAsync2(`**/*{${allowedExtensions.join(",")}}`, {
111367
+ const files = await globAsync2(buildExtensionGlob(allowedExtensions), {
111228
111368
  cwd: projectPath,
111229
111369
  absolute: true,
111230
111370
  nodir: true,
@@ -111676,6 +111816,9 @@ class MemoryRepositoryPg {
111676
111816
  if (filters.types && filters.types.length > 0) {
111677
111817
  conditions.push(import_prisma2.Prisma.sql`type = ANY(${filters.types}::text[])`);
111678
111818
  }
111819
+ if (filters.includePersistent === false) {
111820
+ conditions.push(import_prisma2.Prisma.sql`level <> ${MemoryLevel.PERSISTENT}`);
111821
+ }
111679
111822
  const whereClause = import_prisma2.Prisma.sql`WHERE ${import_prisma2.Prisma.join(conditions, " AND ")}`;
111680
111823
  const rows = await this.prisma.$queryRaw`
111681
111824
  SELECT id, content, type, level,
@@ -111710,6 +111853,8 @@ class MemoryRepositoryPg {
111710
111853
  conditions.push(import_prisma2.Prisma.sql`importance >= ${filters.minImportance}`);
111711
111854
  if (filters?.types && filters.types.length > 0)
111712
111855
  conditions.push(import_prisma2.Prisma.sql`type = ANY(${filters.types}::text[])`);
111856
+ if (filters?.includePersistent === false)
111857
+ conditions.push(import_prisma2.Prisma.sql`level <> ${MemoryLevel.PERSISTENT}`);
111713
111858
  const whereClause = import_prisma2.Prisma.sql`WHERE ${import_prisma2.Prisma.join(conditions, " AND ")}
111714
111859
  AND NOT EXISTS (
111715
111860
  SELECT 1 FROM memory_edges me
@@ -115957,20 +116102,21 @@ class DiscoverStage {
115957
116102
  payload: { projectId: ctx.projectId, projectPath: ctx.projectPath },
115958
116103
  timestamp: Date.now()
115959
116104
  });
115960
- const ig = await this.loadIgnore(ctx.projectPath, opts.includeTests ?? false);
116105
+ const includeTests = opts.includeTests ?? false;
116106
+ const ig = await this.loadIgnore(ctx.projectPath, includeTests);
116107
+ const policy = this.loadPolicy(includeTests);
115961
116108
  const allowedExts = config.get("security").allowedExtensions ?? DEFAULT_EXTENSIONS;
115962
116109
  let relPaths;
115963
116110
  if (opts.filesToProcess && opts.filesToProcess.length > 0) {
115964
116111
  relPaths = opts.filesToProcess;
115965
116112
  } else {
115966
- const pattern = `**/*{${allowedExts.join(",")}}`;
115967
- const found = await glob(pattern, {
116113
+ const found = await glob(buildExtensionGlob(allowedExts), {
115968
116114
  cwd: ctx.projectPath,
115969
116115
  nodir: true,
115970
116116
  dot: false,
115971
116117
  absolute: false
115972
116118
  });
115973
- relPaths = found.map((p) => path11.isAbsolute(p) ? path11.relative(ctx.projectPath, p) : p).filter((p) => !ig.ignores(p));
116119
+ relPaths = found.map((p) => path11.isAbsolute(p) ? path11.relative(ctx.projectPath, p) : p).filter((p) => !ig.ignores(p) && applyPolicy(p, policy) !== "Drop");
115974
116120
  }
115975
116121
  if (ctx.resumeCursor?.path) {
115976
116122
  const cursorPath = ctx.resumeCursor.path;
@@ -116056,6 +116202,15 @@ class DiscoverStage {
116056
116202
  throw new Error(`required_file_unreadable:${relativePath}:${err.message}`);
116057
116203
  }
116058
116204
  }
116205
+ loadPolicy(includeTests) {
116206
+ const policy = getActiveCapturePolicy();
116207
+ if (!includeTests)
116208
+ return policy;
116209
+ return {
116210
+ ...policy,
116211
+ rules: policy.rules.filter((rule) => !(rule.disposition === "Drop" && TEST_IGNORE_PATTERNS.has(rule.pattern)))
116212
+ };
116213
+ }
116059
116214
  async loadIgnore(projectPath, includeTests) {
116060
116215
  if (!includeTests)
116061
116216
  return loadProjectIgnore(projectPath);
@@ -116081,6 +116236,7 @@ var init_discover = __esm(() => {
116081
116236
  init_dist();
116082
116237
  init_symbol_repository_factory();
116083
116238
  init_ignore_patterns();
116239
+ init_capture_policy();
116084
116240
  import_ignore4 = __toESM(require_ignore(), 1);
116085
116241
  ignore2 = import_ignore4.default.default ?? import_ignore4.default;
116086
116242
  TEST_IGNORE_PATTERNS = new Set([
@@ -118910,19 +119066,22 @@ class StructuralResolverRegistry {
118910
119066
  return resolver;
118911
119067
  }
118912
119068
  }
119069
+ function declarationGroupKey(file3, qualifiedName) {
119070
+ return `${file3}\x00${qualifiedName}`;
119071
+ }
118913
119072
  function buildStructuralResolverDefinitions(documents) {
118914
119073
  const groups = new Map;
118915
119074
  const exportedRoots = new Set;
118916
119075
  for (const document2 of documents)
118917
119076
  for (const symbol27 of document2.structure.symbols) {
118918
- const key = `${document2.file}\x00${symbol27.qualifiedName}\x00${symbol27.kind}`;
119077
+ const key = declarationGroupKey(document2.file, symbol27.qualifiedName);
118919
119078
  groups.set(key, (groups.get(key) ?? 0) + 1);
118920
119079
  if (symbol27.exported && symbol27.qualifiedName === symbol27.name) {
118921
119080
  exportedRoots.add(`${document2.file}\x00${symbol27.qualifiedName.split(".")[0]}`);
118922
119081
  }
118923
119082
  }
118924
119083
  return Object.freeze(documents.flatMap((document2) => document2.structure.symbols.map((symbol27) => {
118925
- const key = `${document2.file}\x00${symbol27.qualifiedName}\x00${symbol27.kind}`;
119084
+ const key = declarationGroupKey(document2.file, symbol27.qualifiedName);
118926
119085
  const visibleNested = document2.dialect === "java" ? symbol27.signatureMaterial.modifiers.includes("public") && (["class", "interface", "enum"].includes(symbol27.kind) || symbol27.signatureMaterial.modifiers.includes("static")) : !symbol27.signatureMaterial.modifiers.includes("private");
118927
119086
  const isExportMarker = symbol27.kind === "export";
118928
119087
  return Object.freeze({
@@ -123959,7 +124118,7 @@ class MemoryController {
123959
124118
  types: types6,
123960
124119
  minImportance = 0.3,
123961
124120
  limit = 10,
123962
- includePersistent: _includePersistent = true,
124121
+ includePersistent = true,
123963
124122
  includeRelated = false
123964
124123
  } = input;
123965
124124
  logger.info("Searching memories", {
@@ -123977,7 +124136,8 @@ class MemoryController {
123977
124136
  projectId,
123978
124137
  agentId,
123979
124138
  minImportance,
123980
- types: types6
124139
+ types: types6,
124140
+ includePersistent
123981
124141
  });
123982
124142
  logger.info("FTS search completed", {
123983
124143
  foundResults: ftsRows.length,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@massa-ai/tools-api",
3
- "version": "1.9.0",
3
+ "version": "1.9.2",
4
4
  "author": "luizgmassa",
5
5
  "description": "massa-ai REST API server - Semantic code search, memory, and context compression",
6
6
  "type": "module",
@@ -21,8 +21,8 @@
21
21
  "test": "bun scripts/run-tests-isolated.ts"
22
22
  },
23
23
  "dependencies": {
24
- "@massa-ai/core": "^1.9.0",
25
- "@massa-ai/shared": "^1.9.0",
24
+ "@massa-ai/core": "^1.9.2",
25
+ "@massa-ai/shared": "^1.9.2",
26
26
  "elysia": "^1.2.25",
27
27
  "@elysiajs/swagger": "^1.2.0",
28
28
  "@elysiajs/cors": "^1.2.0",