@massa-ai/tools-api 1.2.1 → 1.3.1

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 +136 -56
  2. package/package.json +3 -3
package/dist/index.js CHANGED
@@ -557,7 +557,8 @@ __export(exports_config_loader, {
557
557
  getConfigPath: () => getConfigPath,
558
558
  getConfigForEnv: () => getConfigForEnv,
559
559
  getConfigDir: () => getConfigDir,
560
- configExists: () => configExists
560
+ configExists: () => configExists,
561
+ __resetMigrationForTests: () => __resetMigrationForTests
561
562
  });
562
563
  import fs from "fs";
563
564
  import path3 from "path";
@@ -627,6 +628,9 @@ function migrateDataDirOnce() {
627
628
  console.error(`[massa-ai] Data directory migration skipped:`, err);
628
629
  }
629
630
  }
631
+ function __resetMigrationForTests() {
632
+ migrationAttempted = false;
633
+ }
630
634
  function saveConfig(config) {
631
635
  if (!fs.existsSync(CONFIG_DIR)) {
632
636
  fs.mkdirSync(CONFIG_DIR, { recursive: true });
@@ -636,7 +640,7 @@ function saveConfig(config) {
636
640
  function initConfig() {
637
641
  if (!fs.existsSync(CONFIG_FILE)) {
638
642
  saveConfig(defaultMassaAiConfig);
639
- console.log(`Created default config at ${CONFIG_FILE}`);
643
+ console.error(`Created default config at ${CONFIG_FILE}`);
640
644
  }
641
645
  }
642
646
  function getConfigForEnv() {
@@ -688,7 +692,7 @@ var import_dotenv, envPath;
688
692
  var init_env = __esm(() => {
689
693
  import_dotenv = __toESM(require_main(), 1);
690
694
  envPath = findEnvFile();
691
- import_dotenv.config({ path: envPath });
695
+ import_dotenv.config({ path: envPath, quiet: true });
692
696
  try {
693
697
  const { loadConfigSafe: loadConfigSafe2, migrateDataDirOnce: migrateDataDirOnce2 } = (init_config_loader(), __toCommonJS(exports_config_loader));
694
698
  migrateDataDirOnce2();
@@ -12168,11 +12172,7 @@ class Logger {
12168
12172
  return `[${timestamp}] [${level}] ${message}${metaStr}`;
12169
12173
  }
12170
12174
  write(message, level) {
12171
- if (level >= LogLevel.WARN) {
12172
- console.error(message);
12173
- } else {
12174
- console.log(message);
12175
- }
12175
+ console.error(message);
12176
12176
  }
12177
12177
  debug(message, meta) {
12178
12178
  if (this.shouldLog(LogLevel.DEBUG)) {
@@ -12616,8 +12616,9 @@ class FileFilterCache {
12616
12616
  }
12617
12617
  invalidateProject(projectId) {
12618
12618
  let removed = 0;
12619
+ const prefix = `project:${projectId}`;
12619
12620
  for (const [key, _entry] of this.cache.entries()) {
12620
- if (key.startsWith(`project:${projectId}|`)) {
12621
+ if (key === prefix || key.startsWith(`${prefix}|`)) {
12621
12622
  this.cache.delete(key);
12622
12623
  removed++;
12623
12624
  }
@@ -108648,9 +108649,9 @@ class SearchCachePg {
108648
108649
  if (this.l1Cache.size <= this.L1_MAX_SIZE)
108649
108650
  return;
108650
108651
  let oldestKey = null;
108651
- let oldestTime = Date.now();
108652
+ let oldestTime = Infinity;
108652
108653
  for (const [key, entry2] of this.l1Cache.entries()) {
108653
- if (entry2.lastAccessed < oldestTime) {
108654
+ if (entry2.lastAccessed <= oldestTime) {
108654
108655
  oldestTime = entry2.lastAccessed;
108655
108656
  oldestKey = key;
108656
108657
  }
@@ -109259,7 +109260,8 @@ function generationDefinitionIdentityColumns(def) {
109259
109260
  }
109260
109261
  if (parsed.kind !== def.kind)
109261
109262
  throw new TypeError(`definition_fqn_kind_mismatch:${def.id}`);
109262
- if (parsed.qualifiedName.split(".").at(-1) !== def.name) {
109263
+ const terminalMatchesName = parsed.qualifiedName === def.name || parsed.qualifiedName.endsWith(`.${def.name}`);
109264
+ if (!terminalMatchesName) {
109263
109265
  throw new TypeError(`definition_fqn_name_mismatch:${def.id}`);
109264
109266
  }
109265
109267
  if (def.qualified_name !== undefined && def.qualified_name !== parsed.qualifiedName) {
@@ -109546,11 +109548,24 @@ async function writeFileGeneration(input) {
109546
109548
  last_known_good_generation_id = EXCLUDED.last_known_good_generation_id,
109547
109549
  last_successful_at = EXCLUDED.last_successful_at
109548
109550
  `;
109549
- for (const definition of definitions) {
109551
+ const seenDefinitionIds = new Set;
109552
+ const uniqueDefinitions = definitions.filter((definition) => {
109553
+ if (seenDefinitionIds.has(definition.id))
109554
+ return false;
109555
+ seenDefinitionIds.add(definition.id);
109556
+ return true;
109557
+ });
109558
+ for (const definition of uniqueDefinitions) {
109550
109559
  const identity = generationDefinitionIdentityColumns(definition);
109551
109560
  await tx.$executeRaw`
109552
109561
  INSERT INTO symbol_definitions (id, project_id, generation_id, file_path, name, kind, line_start, line_end, exported, doc_comment, indexed_at, qualified_name, canonical_signature, signature_hash, legacy_fqn, source_span)
109553
109562
  VALUES (${definition.id}, ${lease.projectId}, ${lease.generationId}, ${file3.relative_path}, ${definition.name}, ${definition.kind}, ${definition.line_start}, ${definition.line_end}, ${definition.exported}, ${definition.doc_comment ?? null}, ${new Date(definition.indexed_at)}, ${identity.qualifiedName}, ${identity.canonicalSignature}, ${identity.signatureHash}, ${identity.legacyFqn}, ${identity.sourceSpan}::jsonb)
109563
+ ON CONFLICT (project_id, generation_id, id) DO UPDATE SET
109564
+ name = EXCLUDED.name, kind = EXCLUDED.kind, line_start = EXCLUDED.line_start,
109565
+ line_end = EXCLUDED.line_end, exported = EXCLUDED.exported, doc_comment = EXCLUDED.doc_comment,
109566
+ indexed_at = EXCLUDED.indexed_at, qualified_name = EXCLUDED.qualified_name,
109567
+ canonical_signature = EXCLUDED.canonical_signature, signature_hash = EXCLUDED.signature_hash,
109568
+ legacy_fqn = EXCLUDED.legacy_fqn, source_span = EXCLUDED.source_span
109554
109569
  `;
109555
109570
  }
109556
109571
  for (const reference of references) {
@@ -109801,7 +109816,7 @@ async function upsertWorkspace(ws) {
109801
109816
  AND generation.id = 'legacy-' || md5(current_workspace.project_id)
109802
109817
  AND generation.project_id = current_workspace.project_id
109803
109818
  `;
109804
- });
109819
+ }, { timeout: 60000, maxWait: 1e4 });
109805
109820
  }
109806
109821
  async function updateWorkspaceStatus(projectId, status2, opts) {
109807
109822
  const lastError = typeof opts === "string" ? opts : opts?.lastError ?? null;
@@ -109872,7 +109887,7 @@ async function updateWorkspaceStatus(projectId, status2, opts) {
109872
109887
  FROM active_counts c
109873
109888
  WHERE w.project_id = c.project_id AND EXISTS (SELECT 1 FROM updated_generation)
109874
109889
  `;
109875
- });
109890
+ }, { timeout: 60000, maxWait: 1e4 });
109876
109891
  }
109877
109892
  var init_symbol_repo_workspace = __esm(() => {
109878
109893
  init_prisma_client();
@@ -111481,7 +111496,7 @@ class MemoryRepositoryPg {
111481
111496
  importance: m2.importance,
111482
111497
  tags: JSON.stringify(tagsArr),
111483
111498
  embedding: m2.embedding,
111484
- metadata: m2.metadata ? JSON.stringify(m2.metadata) : null,
111499
+ metadata: m2.metadata == null ? null : typeof m2.metadata === "string" ? m2.metadata : JSON.stringify(m2.metadata),
111485
111500
  created_at: m2.created_at instanceof Date ? m2.created_at.getTime() : Number(m2.created_at),
111486
111501
  updated_at: m2.updated_at instanceof Date ? m2.updated_at.getTime() : Number(m2.updated_at),
111487
111502
  access_count: m2.access_count,
@@ -111675,7 +111690,7 @@ class MemoryRepositoryPg {
111675
111690
  pinned, deleted_at
111676
111691
  FROM memories
111677
111692
  WHERE deleted_at IS NULL
111678
- ORDER BY created_at DESC
111693
+ ORDER BY created_at DESC, id DESC
111679
111694
  LIMIT ${limit} OFFSET ${offset}
111680
111695
  `;
111681
111696
  return rows.map((r2) => this.toMemoryRow(r2));
@@ -111683,7 +111698,7 @@ class MemoryRepositoryPg {
111683
111698
  async findRecentByTag(tag, opts) {
111684
111699
  const since = new Date(opts.sinceMs);
111685
111700
  const conditions = [
111686
- import_prisma2.Prisma.sql`${tag} = ANY(tags)`,
111701
+ import_prisma2.Prisma.sql`${tag} = ANY(tags::text[])`,
111687
111702
  import_prisma2.Prisma.sql`created_at >= ${since}`
111688
111703
  ];
111689
111704
  if (opts.sessionId)
@@ -112226,7 +112241,8 @@ function restoreWorkingMemoryBuffer(snapshot) {
112226
112241
  for (const e of snapshot.entries) {
112227
112242
  if (!e || !e.result || typeof e.id !== "string")
112228
112243
  continue;
112229
- if (now2 - (e.lastAccessedAt ?? 0) >= snapshot.config.ttlMs)
112244
+ const lastAccessedAt = e.lastAccessedAt ?? now2;
112245
+ if (now2 - lastAccessedAt >= snapshot.config.ttlMs)
112230
112246
  continue;
112231
112247
  const result = e.result;
112232
112248
  buf.entries.set(e.id, {
@@ -112234,7 +112250,7 @@ function restoreWorkingMemoryBuffer(snapshot) {
112234
112250
  queryTokens: new Set,
112235
112251
  contentTokens: tokenize(result.content || ""),
112236
112252
  addedAt: e.addedAt ?? now2,
112237
- lastAccessedAt: e.lastAccessedAt ?? now2,
112253
+ lastAccessedAt,
112238
112254
  baselineScore: e.baselineScore ?? result.score
112239
112255
  });
112240
112256
  }
@@ -118797,6 +118813,7 @@ function buildStructuralResolverDefinitions(documents) {
118797
118813
  return Object.freeze(documents.flatMap((document2) => document2.structure.symbols.map((symbol27) => {
118798
118814
  const key = `${document2.file}\x00${symbol27.qualifiedName}\x00${symbol27.kind}`;
118799
118815
  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");
118816
+ const isExportMarker = symbol27.kind === "export";
118800
118817
  return Object.freeze({
118801
118818
  identity: Object.freeze({
118802
118819
  file: document2.file,
@@ -118809,7 +118826,7 @@ function buildStructuralResolverDefinitions(documents) {
118809
118826
  typeTokens: symbol27.signatureMaterial.typeTokens,
118810
118827
  modifiers: symbol27.signatureMaterial.modifiers,
118811
118828
  scope: symbol27.qualifiedName === symbol27.name ? "top_level" : "nested",
118812
- overload: (groups.get(key) ?? 0) > 1 ? "overloaded" : "unique"
118829
+ overload: (groups.get(key) ?? 0) > 1 || isExportMarker ? "overloaded" : "unique"
118813
118830
  }),
118814
118831
  exported: symbol27.exported || !symbol27.name.startsWith("#") && !symbol27.name.startsWith("%23") && visibleNested && exportedRoots.has(`${document2.file}\x00${symbol27.qualifiedName.split(".")[0]}`),
118815
118832
  defaultExport: symbol27.defaultExport
@@ -119478,6 +119495,7 @@ class ResolveStage {
119478
119495
  timestamp: Date.now()
119479
119496
  });
119480
119497
  }
119498
+ await new Promise((resolve5) => setTimeout(resolve5, 0));
119481
119499
  }
119482
119500
  const durationMs = Math.round(performance.now() - t0);
119483
119501
  ctx.emit({
@@ -119801,6 +119819,47 @@ var init_resolve = __esm(() => {
119801
119819
  STRUCTURAL_SEED_EXTENSIONS = new Set([".ts", ".tsx", ".js", ".jsx", ".py", ".rb", ".php", ".lua", ".c", ".h", ".cpp", ".hpp", ".go", ".rs", ".zig", ".java", ".kt", ".kts", ".scala", ".cs", ".swift", ".dart", ".ex", ".exs", ".erl", ".clj", ".ml", ".hs", ".vue", ".md", ".json", ".yaml", ".yml"]);
119802
119820
  });
119803
119821
 
119822
+ // ../../packages/core/dist/data/with-deadlock-retry.js
119823
+ function isRetriableTransactionError(error51) {
119824
+ if (!error51 || typeof error51 !== "object")
119825
+ return false;
119826
+ const code = error51.code;
119827
+ if (typeof code === "string" && RETRIABLE_SQLSTATES.has(code))
119828
+ return true;
119829
+ const message = error51.message;
119830
+ if (typeof message === "string" && /Code:\s*`(?:40P01|40001|40P02)`/.test(message)) {
119831
+ return true;
119832
+ }
119833
+ return false;
119834
+ }
119835
+ async function withDeadlockRetry(operation, options = {}) {
119836
+ const maxAttempts = options.maxAttempts ?? 5;
119837
+ const baseDelayMs = options.baseDelayMs ?? 75;
119838
+ for (let attempt = 1;attempt <= maxAttempts; attempt++) {
119839
+ try {
119840
+ return await operation();
119841
+ } catch (error51) {
119842
+ if (!isRetriableTransactionError(error51) || attempt === maxAttempts)
119843
+ throw error51;
119844
+ const delayMs = baseDelayMs * 2 ** (attempt - 1);
119845
+ logger.warn("Retriable DB lock cycle; retrying operation", {
119846
+ operation: options.operation ?? "unknown",
119847
+ attempt,
119848
+ maxAttempts,
119849
+ delayMs,
119850
+ error: error51?.message?.slice(0, 120)
119851
+ });
119852
+ await new Promise((resolve5) => setTimeout(resolve5, delayMs));
119853
+ }
119854
+ }
119855
+ throw new Error("withDeadlockRetry exhausted retries");
119856
+ }
119857
+ var RETRIABLE_SQLSTATES;
119858
+ var init_with_deadlock_retry = __esm(() => {
119859
+ init_dist();
119860
+ RETRIABLE_SQLSTATES = new Set(["40P01", "40001", "40P02"]);
119861
+ });
119862
+
119804
119863
  // ../../packages/core/dist/services/etl/stages/load.js
119805
119864
  import path15 from "path";
119806
119865
  function formatDuration(ms) {
@@ -119917,8 +119976,12 @@ class LoadStage {
119917
119976
  return;
119918
119977
  try {
119919
119978
  const [chunkCount, symCount] = await Promise.all([
119920
- mode === "structural" ? Promise.resolve(0) : this.loadToSearchStores(ctx, file3),
119921
- mode === "semantic" ? Promise.resolve(file3.symbols.length) : this.loadToSymbolDb(ctx, file3)
119979
+ mode === "structural" ? Promise.resolve(0) : withDeadlockRetry(() => this.loadToSearchStores(ctx, file3), {
119980
+ operation: "etl.loadToSearchStores"
119981
+ }),
119982
+ mode === "semantic" ? Promise.resolve(file3.symbols.length) : withDeadlockRetry(() => this.loadToSymbolDb(ctx, file3), {
119983
+ operation: "etl.loadToSymbolDb"
119984
+ })
119922
119985
  ]);
119923
119986
  if (!ctx.graphGenerationLease && mode !== "structural") {
119924
119987
  await getSymbolRepository().upsertFile({
@@ -120110,6 +120173,7 @@ class LoadStage {
120110
120173
  }
120111
120174
  var init_load = __esm(() => {
120112
120175
  init_dist();
120176
+ init_with_deadlock_retry();
120113
120177
  init_vector_store_factory();
120114
120178
  init_keyword_search_factory();
120115
120179
  init_symbol_repository_factory();
@@ -120307,7 +120371,7 @@ class GraphGenerationRepositoryPg {
120307
120371
  AND graph_lease_token = ${lease.leaseToken}
120308
120372
  `;
120309
120373
  return { status: "renewed", leaseExpiresAt: renewed[0].lease_expires_at.getTime() };
120310
- });
120374
+ }, { timeout: 60000, maxWait: 1e4 });
120311
120375
  }
120312
120376
  async complete(lease) {
120313
120377
  return getPrismaClient2().$transaction(async (tx) => {
@@ -120481,7 +120545,7 @@ class GraphGenerationCoordinator {
120481
120545
  } while (true);
120482
120546
  }
120483
120547
  async heartbeat(lease) {
120484
- const outcome2 = await this.repository.heartbeat(lease, GRAPH_GENERATION_LEASE_TTL_MS);
120548
+ const outcome2 = await withDeadlockRetry(() => this.repository.heartbeat(lease, GRAPH_GENERATION_LEASE_TTL_MS), { operation: "graph_generation.heartbeat", maxAttempts: 3 });
120485
120549
  if (outcome2.status !== "renewed")
120486
120550
  throw new Error("graph_generation_lease_lost");
120487
120551
  }
@@ -120517,6 +120581,7 @@ class GraphGenerationCoordinator {
120517
120581
  var GRAPH_GENERATION_LEASE_TTL_MS = 300000;
120518
120582
  var init_graph_generation_coordinator = __esm(() => {
120519
120583
  init_graph_generation_repository_factory();
120584
+ init_with_deadlock_retry();
120520
120585
  });
120521
120586
 
120522
120587
  // ../../packages/core/dist/services/etl/pipeline.js
@@ -120594,6 +120659,7 @@ var init_pipeline = __esm(() => {
120594
120659
  init_symbol_repository_factory();
120595
120660
  init_index_job_tracker();
120596
120661
  init_cache_factory();
120662
+ init_index_manager();
120597
120663
  init_vector_store_factory();
120598
120664
  init_keyword_search_factory();
120599
120665
  init_alias_resolver();
@@ -120885,6 +120951,16 @@ var init_pipeline = __esm(() => {
120885
120951
  }
120886
120952
  };
120887
120953
  await getSearchCache().invalidateProject(projectId);
120954
+ try {
120955
+ const admissionMarker = new IndexManager(await getVectorStore());
120956
+ await admissionMarker.updateIndexMetadata(projectId, projectPath, discovered.map((file3) => file3.relativePath));
120957
+ } catch (markerError) {
120958
+ logger.warn("EtlPipeline: search-admission marker write failed", {
120959
+ projectId,
120960
+ jobId,
120961
+ error: markerError.message.slice(0, 160)
120962
+ });
120963
+ }
120888
120964
  indexJobTracker.updateProgress(jobId, result.filesIndexed, result.filesIndexed);
120889
120965
  await indexJobTracker.setResultAndFlush(jobId, {
120890
120966
  filesIndexed: result.filesIndexed,
@@ -123045,10 +123121,10 @@ class GraphQueries {
123045
123121
  return new Map;
123046
123122
  }
123047
123123
  const rows = await getPrismaClient2().$queryRaw`
123048
- SELECT id, content, type, level, importance, array_to_json(tags)::text AS tags,
123124
+ SELECT id, content, type, level, importance, tags,
123049
123125
  created_at, updated_at, access_count, user_id, session_id, project_id, agent_id,
123050
123126
  NULL::bytea AS embedding, NULL::text AS metadata, NULL::timestamp AS last_accessed,
123051
- pinned::integer AS pinned, deleted_at
123127
+ CASE WHEN pinned THEN 1 ELSE 0 END AS pinned, deleted_at
123052
123128
  FROM memories WHERE id = ANY(${memoryIds}::text[])`;
123053
123129
  const result = new Map;
123054
123130
  for (const row of rows) {
@@ -125229,16 +125305,14 @@ var TOOL_NAME_NORMALIZE, classifyToolCall = (_source, payload) => {
125229
125305
  const cmdRaw = field2(payload, "command") ?? (toolInput && typeof toolInput === "object" ? toolInput.command : undefined);
125230
125306
  const cmd = lower(cmdRaw);
125231
125307
  if (cmd.startsWith("git ") || cmd.includes(" git ")) {
125232
- if (cmd.includes("commit") || cmd.includes("merge") || cmd.includes("rebase")) {
125233
- return "git-changes";
125234
- }
125235
125308
  return "git-changes";
125236
125309
  }
125237
125310
  return "tool-calls";
125238
125311
  }
125239
125312
  case "TodoWrite":
125240
- case "Task":
125241
125313
  return "tasks";
125314
+ case "Task":
125315
+ return "subagents-spawned";
125242
125316
  case "WebFetch":
125243
125317
  return "web-fetch";
125244
125318
  case "WebSearch":
@@ -125255,8 +125329,6 @@ var TOOL_NAME_NORMALIZE, classifyToolCall = (_source, payload) => {
125255
125329
  return "memories-stored";
125256
125330
  case "compact_snapshot":
125257
125331
  return "compaction-snapshots";
125258
- case "Task":
125259
- return "subagents-spawned";
125260
125332
  default:
125261
125333
  if (toolName.startsWith("mcp__"))
125262
125334
  return "mcp-calls";
@@ -172930,7 +173002,7 @@ class CompressContextTool {
172930
173002
  } catch (error51) {
172931
173003
  logger.error("Failed to compress context", error51, {
172932
173004
  strategy,
172933
- contentLength: content.length
173005
+ contentLength: typeof content === "string" ? content.length : 0
172934
173006
  });
172935
173007
  return {
172936
173008
  success: false,
@@ -177893,9 +177965,11 @@ var systemRoutes = new Elysia({ prefix: "/api/v1/system" }).get("/info", async (
177893
177965
  });
177894
177966
 
177895
177967
  // src/routes/events.ts
177896
- var HEARTBEAT_MS = 15000;
177897
- var MAX_DURATION_MS = 10 * 60 * 1000;
177968
+ var HEARTBEAT_MS_DEFAULT = 15000;
177969
+ var MAX_DURATION_MS_DEFAULT = 10 * 60 * 1000;
177898
177970
  var eventsRoutes = new Elysia({ prefix: "/api/v1" }).get("/events", async ({ query, set: set3 }) => {
177971
+ const HEARTBEAT_MS = Number(process.env.MASSA_AI_SSE_HEARTBEAT_MS) || HEARTBEAT_MS_DEFAULT;
177972
+ const MAX_DURATION_MS = Number(process.env.MASSA_AI_SSE_MAX_DURATION_MS) || MAX_DURATION_MS_DEFAULT;
177899
177973
  const projectIdFilter = query.projectId;
177900
177974
  const jobIdFilter = query.jobId;
177901
177975
  set3.headers["Content-Type"] = "text/event-stream";
@@ -177904,6 +177978,9 @@ var eventsRoutes = new Elysia({ prefix: "/api/v1" }).get("/events", async ({ que
177904
177978
  set3.headers["X-Accel-Buffering"] = "no";
177905
177979
  const encoder3 = new TextEncoder;
177906
177980
  let closed = false;
177981
+ let unsubscribers = [];
177982
+ let heartbeatTimer;
177983
+ let closeTimer;
177907
177984
  const stream2 = new ReadableStream({
177908
177985
  start(controller) {
177909
177986
  const enqueue = (data) => {
@@ -177925,14 +178002,14 @@ var eventsRoutes = new Elysia({ prefix: "/api/v1" }).get("/events", async ({ que
177925
178002
  "indexing:failed",
177926
178003
  "workspace:updated"
177927
178004
  ];
177928
- const unsubscribers = events.map((event) => eventBus.subscribe(event, (payload) => {
178005
+ unsubscribers = events.map((event) => eventBus.subscribe(event, (payload) => {
177929
178006
  if (projectIdFilter && payload.projectId !== projectIdFilter)
177930
178007
  return;
177931
178008
  if (jobIdFilter && payload.jobId !== jobIdFilter)
177932
178009
  return;
177933
178010
  enqueue({ event, payload, timestamp: new Date().toISOString() });
177934
178011
  }));
177935
- const heartbeatTimer = setInterval(() => {
178012
+ heartbeatTimer = setInterval(() => {
177936
178013
  if (closed) {
177937
178014
  clearInterval(heartbeatTimer);
177938
178015
  return;
@@ -177946,7 +178023,7 @@ var eventsRoutes = new Elysia({ prefix: "/api/v1" }).get("/events", async ({ que
177946
178023
  clearInterval(heartbeatTimer);
177947
178024
  }
177948
178025
  }, HEARTBEAT_MS);
177949
- const closeTimer = setTimeout(() => {
178026
+ closeTimer = setTimeout(() => {
177950
178027
  closed = true;
177951
178028
  unsubscribers.forEach((u) => u());
177952
178029
  clearInterval(heartbeatTimer);
@@ -177962,12 +178039,14 @@ var eventsRoutes = new Elysia({ prefix: "/api/v1" }).get("/events", async ({ que
177962
178039
  },
177963
178040
  timestamp: new Date().toISOString()
177964
178041
  });
177965
- return () => {
177966
- closed = true;
177967
- unsubscribers.forEach((u) => u());
178042
+ },
178043
+ cancel() {
178044
+ closed = true;
178045
+ unsubscribers.forEach((u) => u());
178046
+ if (heartbeatTimer)
177968
178047
  clearInterval(heartbeatTimer);
178048
+ if (closeTimer)
177969
178049
  clearTimeout(closeTimer);
177970
- };
177971
178050
  }
177972
178051
  });
177973
178052
  return new Response(stream2, {
@@ -179442,21 +179521,22 @@ var webRoutes = new Elysia({ prefix: "/api/v1/web" }).post("/fetch_and_index", a
179442
179521
  import fs17 from "fs/promises";
179443
179522
  import path27 from "path";
179444
179523
  import { fileURLToPath as fileURLToPath3 } from "url";
179445
- var STATIC_DIR_CANDIDATES = (() => {
179446
- const here = path27.dirname(fileURLToPath3(import.meta.url));
179524
+ function buildStaticDirCandidates(moduleDir, cwd) {
179447
179525
  const candidates2 = [];
179448
- candidates2.push(path27.resolve(here, "../../web-ui/src/static"));
179449
- candidates2.push(path27.resolve(here, "../web-ui/src/static"));
179450
- let dir = process.cwd();
179451
- for (let i = 0;i < 8; i++) {
179452
- candidates2.push(path27.resolve(dir, "apps/web-ui/src/static"));
179453
- const parent = path27.dirname(dir);
179454
- if (parent === dir)
179455
- break;
179456
- dir = parent;
179526
+ for (const root2 of [moduleDir, cwd]) {
179527
+ let dir = root2;
179528
+ for (let i = 0;i < 10; i++) {
179529
+ candidates2.push(path27.resolve(dir, "apps/web-ui/src/static"));
179530
+ candidates2.push(path27.resolve(dir, "web-ui/src/static"));
179531
+ const parent = path27.dirname(dir);
179532
+ if (parent === dir)
179533
+ break;
179534
+ dir = parent;
179535
+ }
179457
179536
  }
179458
- return candidates2;
179459
- })();
179537
+ return [...new Set(candidates2)];
179538
+ }
179539
+ var STATIC_DIR_CANDIDATES = buildStaticDirCandidates(path27.dirname(fileURLToPath3(import.meta.url)), process.cwd());
179460
179540
  async function resolveStaticDir() {
179461
179541
  for (const dir of STATIC_DIR_CANDIDATES) {
179462
179542
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@massa-ai/tools-api",
3
- "version": "1.2.1",
3
+ "version": "1.3.1",
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.2.1",
25
- "@massa-ai/shared": "^1.2.1",
24
+ "@massa-ai/core": "^1.3.1",
25
+ "@massa-ai/shared": "^1.3.1",
26
26
  "elysia": "^1.2.25",
27
27
  "@elysiajs/swagger": "^1.2.0",
28
28
  "@elysiajs/cors": "^1.2.0",