@mindstudio-ai/agent 0.1.10 → 0.1.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.
package/dist/cli.js CHANGED
@@ -1968,8 +1968,7 @@ var init_predicate = __esm({
1968
1968
  return PARSE_FAILED;
1969
1969
  }
1970
1970
  /**
1971
- * Attempt to resolve a closure variable by invoking the original function
1972
- * with a recording Proxy and inspecting what values it compares against.
1971
+ * Attempt to resolve a closure variable's value.
1973
1972
  *
1974
1973
  * This handles the common pattern:
1975
1974
  * ```ts
@@ -1977,40 +1976,28 @@ var init_predicate = __esm({
1977
1976
  * orders.filter(o => o.requestedBy === userId)
1978
1977
  * ```
1979
1978
  *
1980
- * The Proxy captures property accesses on the parameter and we can then
1981
- * extract the comparison value from the function's behavior. However,
1982
- * this approach has limitations if the function throws, has side effects,
1983
- * or uses the variable in a non-comparison context, we fall back to JS.
1979
+ * Closure variable resolution is fundamentally limited in JavaScript
1980
+ * we can't access another function's closure scope from outside without
1981
+ * `eval`. The `===` operator can't be overridden via Proxy or
1982
+ * Symbol.toPrimitive, so we can't intercept comparisons.
1983
+ *
1984
+ * For now, this falls back to JS execution. The predicate still works
1985
+ * correctly — it just scans all rows instead of generating SQL.
1986
+ * This is the most common reason for JS fallback in practice, since
1987
+ * almost every real-world filter references a variable like `userId`.
1988
+ *
1989
+ * A future improvement could accept an explicit `vars` argument:
1990
+ * ```ts
1991
+ * orders.filter(o => o.requestedBy === $userId, { $userId: auth.userId })
1992
+ * ```
1984
1993
  */
1985
1994
  resolveClosureVariable() {
1986
- const identToken = this.advance();
1987
- let closureExpr = identToken.value;
1995
+ this.advance();
1988
1996
  while (this.match("dot") && this.tokens[this.pos + 1]?.type === "identifier") {
1989
1997
  this.advance();
1990
- closureExpr += "." + this.advance().value;
1991
- }
1992
- try {
1993
- const MARKER = /* @__PURE__ */ Symbol("field_access_marker");
1994
- const accessed = [];
1995
- const proxy = new Proxy(
1996
- {},
1997
- {
1998
- get(_, prop) {
1999
- accessed.push(prop);
2000
- return new Proxy(() => MARKER, {
2001
- get(_2, nestedProp) {
2002
- accessed.push(nestedProp);
2003
- return MARKER;
2004
- }
2005
- });
2006
- }
2007
- }
2008
- );
2009
- void proxy;
2010
- return PARSE_FAILED;
2011
- } catch {
2012
- return PARSE_FAILED;
1998
+ this.advance();
2013
1999
  }
2000
+ return PARSE_FAILED;
2014
2001
  }
2015
2002
  /**
2016
2003
  * Look ahead to check if the next tokens form `.includes(`.
@@ -2169,6 +2156,76 @@ var init_query = __esm({
2169
2156
  return map;
2170
2157
  }
2171
2158
  // -------------------------------------------------------------------------
2159
+ // Batch compilation — used by db.batch() to extract SQL without executing
2160
+ // -------------------------------------------------------------------------
2161
+ /**
2162
+ * @internal Compile this query into a SqlQuery for batch execution.
2163
+ *
2164
+ * Returns the compiled SQL query (if all predicates compile to SQL),
2165
+ * or null (if JS fallback is needed). In the fallback case, a bare
2166
+ * `SELECT *` is returned as `fallbackQuery` so the batch can fetch
2167
+ * all rows and this query can filter them in JS post-fetch.
2168
+ */
2169
+ _compile() {
2170
+ const compiled = this._compilePredicates();
2171
+ const sortField = this._sortAccessor ? extractFieldName(this._sortAccessor) : void 0;
2172
+ if (compiled.allSql) {
2173
+ const query = buildSelect(this._config.tableName, {
2174
+ where: compiled.sqlWhere || void 0,
2175
+ orderBy: sortField ?? void 0,
2176
+ desc: this._reversed,
2177
+ limit: this._limit,
2178
+ offset: this._offset
2179
+ });
2180
+ return { query, fallbackQuery: null, config: this._config };
2181
+ }
2182
+ const fallbackQuery = buildSelect(this._config.tableName);
2183
+ return {
2184
+ query: null,
2185
+ fallbackQuery,
2186
+ config: this._config,
2187
+ predicates: this._predicates,
2188
+ sortAccessor: this._sortAccessor,
2189
+ reversed: this._reversed,
2190
+ limit: this._limit,
2191
+ offset: this._offset
2192
+ };
2193
+ }
2194
+ /**
2195
+ * @internal Process raw SQL results into typed rows. Used by db.batch()
2196
+ * after executing the compiled query.
2197
+ *
2198
+ * For SQL-compiled queries: just deserialize the rows.
2199
+ * For JS-fallback queries: filter, sort, and slice in JS.
2200
+ */
2201
+ static _processResults(result, compiled) {
2202
+ const rows = result.rows.map(
2203
+ (row) => deserializeRow(
2204
+ row,
2205
+ compiled.config.columns
2206
+ )
2207
+ );
2208
+ if (compiled.query) return rows;
2209
+ let filtered = compiled.predicates ? rows.filter((row) => compiled.predicates.every((pred) => pred(row))) : rows;
2210
+ if (compiled.sortAccessor) {
2211
+ const accessor = compiled.sortAccessor;
2212
+ const reversed = compiled.reversed ?? false;
2213
+ filtered.sort((a, b) => {
2214
+ const aVal = accessor(a);
2215
+ const bVal = accessor(b);
2216
+ if (aVal < bVal) return reversed ? 1 : -1;
2217
+ if (aVal > bVal) return reversed ? -1 : 1;
2218
+ return 0;
2219
+ });
2220
+ }
2221
+ if (compiled.offset != null || compiled.limit != null) {
2222
+ const start = compiled.offset ?? 0;
2223
+ const end = compiled.limit != null ? start + compiled.limit : void 0;
2224
+ filtered = filtered.slice(start, end);
2225
+ }
2226
+ return filtered;
2227
+ }
2228
+ // -------------------------------------------------------------------------
2172
2229
  // PromiseLike
2173
2230
  // -------------------------------------------------------------------------
2174
2231
  then(onfulfilled, onrejected) {
@@ -2418,7 +2475,49 @@ function createDb(databases, executeBatch) {
2418
2475
  hours: (n) => n * 36e5,
2419
2476
  minutes: (n) => n * 6e4,
2420
2477
  ago: (ms) => Date.now() - ms,
2421
- fromNow: (ms) => Date.now() + ms
2478
+ fromNow: (ms) => Date.now() + ms,
2479
+ // --- Batch execution ---
2480
+ batch: ((...queries) => {
2481
+ return (async () => {
2482
+ const compiled = queries.map((q) => {
2483
+ if (!(q instanceof Query)) {
2484
+ throw new MindStudioError(
2485
+ "db.batch() only accepts Query objects (from .filter(), .sortBy(), etc.)",
2486
+ "invalid_batch_query",
2487
+ 400
2488
+ );
2489
+ }
2490
+ return q._compile();
2491
+ });
2492
+ const groups = /* @__PURE__ */ new Map();
2493
+ for (let i = 0; i < compiled.length; i++) {
2494
+ const c = compiled[i];
2495
+ const dbId = c.config.databaseId;
2496
+ const sqlQuery = c.query ?? c.fallbackQuery;
2497
+ if (!groups.has(dbId)) groups.set(dbId, []);
2498
+ groups.get(dbId).push({ index: i, sqlQuery });
2499
+ }
2500
+ const allResults = new Array(compiled.length);
2501
+ await Promise.all(
2502
+ Array.from(groups.entries()).map(async ([dbId, entries]) => {
2503
+ const sqlQueries = entries.map((e) => e.sqlQuery);
2504
+ const results = await executeBatch(dbId, sqlQueries);
2505
+ for (let i = 0; i < entries.length; i++) {
2506
+ allResults[entries[i].index] = results[i];
2507
+ }
2508
+ })
2509
+ );
2510
+ return compiled.map((c, i) => {
2511
+ const result = allResults[i];
2512
+ if (!c.query && c.predicates?.length) {
2513
+ console.warn(
2514
+ `[mindstudio] db.batch(): filter on ${c.config.tableName} could not be compiled to SQL \u2014 processing in JS`
2515
+ );
2516
+ }
2517
+ return Query._processResults(result, c);
2518
+ });
2519
+ })();
2520
+ })
2422
2521
  };
2423
2522
  }
2424
2523
  function resolveTable(databases, tableName, databaseHint) {
@@ -2473,6 +2572,7 @@ var init_db = __esm({
2473
2572
  "use strict";
2474
2573
  init_errors();
2475
2574
  init_table();
2575
+ init_query();
2476
2576
  init_table();
2477
2577
  }
2478
2578
  });
@@ -3556,7 +3656,14 @@ var init_client = __esm({
3556
3656
  hours: (n) => n * 36e5,
3557
3657
  minutes: (n) => n * 6e4,
3558
3658
  ago: (ms) => Date.now() - ms,
3559
- fromNow: (ms) => Date.now() + ms
3659
+ fromNow: (ms) => Date.now() + ms,
3660
+ // Batch needs context — hydrate first, then delegate to real db
3661
+ batch: ((...queries) => {
3662
+ return (async () => {
3663
+ await agent.ensureContext();
3664
+ return agent._db.batch(...queries);
3665
+ })();
3666
+ })
3560
3667
  };
3561
3668
  }
3562
3669
  // -------------------------------------------------------------------------
@@ -3761,7 +3868,7 @@ async function startMcpServer(options) {
3761
3868
  capabilities: { tools: {} },
3762
3869
  serverInfo: {
3763
3870
  name: "mindstudio-agent",
3764
- version: "0.1.10"
3871
+ version: "0.1.11"
3765
3872
  },
3766
3873
  instructions: "Welcome to MindStudio \u2014 a platform with 200+ AI models, 850+ third-party integrations, and pre-built agents.\n\nGetting started:\n1. Call `listAgents` to verify your connection and see available agents.\n2. Call `changeName` to set your display name \u2014 use your name or whatever your user calls you. This is how you'll appear in MindStudio request logs.\n3. If you have a profile picture or icon, call `uploadFile` to upload it, then `changeProfilePicture` with the returned URL. This helps users identify your requests in their logs.\n4. Call `listActions` to discover all available actions.\n\nThen use the tools to generate text, images, video, audio, search the web, work with data sources, run agents, and more.\n\nImportant:\n- AI-powered actions (text generation, image generation, video, audio, etc.) cost money. Before running these, call `estimateActionCost` and confirm with the user before proceeding \u2014 unless they've explicitly told you to go ahead.\n- Not all agents from `listAgents` are configured for API use. Do not try to run an agent just because it appears in the list \u2014 it will likely fail. Only run agents the user specifically asks you to run."
3767
3874
  });
@@ -4669,7 +4776,7 @@ function isNewerVersion(current, latest) {
4669
4776
  return false;
4670
4777
  }
4671
4778
  async function checkForUpdate() {
4672
- const currentVersion = "0.1.10";
4779
+ const currentVersion = "0.1.11";
4673
4780
  if (!currentVersion) return null;
4674
4781
  try {
4675
4782
  const { loadConfig: loadConfig2, saveConfig: saveConfig2 } = await Promise.resolve().then(() => (init_config(), config_exports));
@@ -4698,7 +4805,7 @@ async function checkForUpdate() {
4698
4805
  }
4699
4806
  }
4700
4807
  function printUpdateNotice(latestVersion) {
4701
- const currentVersion = "0.1.10";
4808
+ const currentVersion = "0.1.11";
4702
4809
  process.stderr.write(
4703
4810
  `
4704
4811
  ${ansi.cyanBright("Update available")} ${ansi.gray(currentVersion + " \u2192")} ${ansi.cyanBold(latestVersion)}
@@ -4773,7 +4880,7 @@ async function cmdLogin(options) {
4773
4880
  process.stderr.write("\n");
4774
4881
  printLogo();
4775
4882
  process.stderr.write("\n");
4776
- const ver = "0.1.10";
4883
+ const ver = "0.1.11";
4777
4884
  process.stderr.write(
4778
4885
  ` ${ansi.bold("MindStudio Agent")} ${ver ? " " + ansi.gray("v" + ver) : ""}
4779
4886
  `
package/dist/index.d.ts CHANGED
@@ -156,9 +156,7 @@ interface UserInfoResult {
156
156
  * }
157
157
  * ```
158
158
  */
159
- type User = string & {
160
- readonly __brand: 'User';
161
- };
159
+ type User = string;
162
160
  /**
163
161
  * Resolved display info for a platform user. Returned by `resolveUser()`
164
162
  * and `resolveUsers()`.
@@ -682,12 +680,51 @@ declare class Query<T> implements PromiseLike<T[]> {
682
680
  min(accessor: Accessor<T, number>): Promise<T | null>;
683
681
  max(accessor: Accessor<T, number>): Promise<T | null>;
684
682
  groupBy<K extends string | number>(accessor: Accessor<T, K>): Promise<Map<K, T[]>>;
683
+ /**
684
+ * @internal Compile this query into a SqlQuery for batch execution.
685
+ *
686
+ * Returns the compiled SQL query (if all predicates compile to SQL),
687
+ * or null (if JS fallback is needed). In the fallback case, a bare
688
+ * `SELECT *` is returned as `fallbackQuery` so the batch can fetch
689
+ * all rows and this query can filter them in JS post-fetch.
690
+ */
691
+ _compile(): CompiledQuery<T>;
692
+ /**
693
+ * @internal Process raw SQL results into typed rows. Used by db.batch()
694
+ * after executing the compiled query.
695
+ *
696
+ * For SQL-compiled queries: just deserialize the rows.
697
+ * For JS-fallback queries: filter, sort, and slice in JS.
698
+ */
699
+ static _processResults<T>(result: SqlResult, compiled: CompiledQuery<T>): T[];
685
700
  then<TResult1 = T[], TResult2 = never>(onfulfilled?: ((value: T[]) => TResult1 | PromiseLike<TResult1>) | null, onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null): Promise<TResult1 | TResult2>;
686
701
  private _execute;
687
702
  private _compilePredicates;
688
703
  private _fetchAndFilterInJs;
689
704
  private _fetchAllRows;
690
705
  }
706
+ /**
707
+ * Result of Query._compile(). Contains either a compiled SQL query
708
+ * (fast path) or a fallback SELECT * with JS processing metadata.
709
+ */
710
+ interface CompiledQuery<T> {
711
+ /** Compiled SQL query, or null if JS fallback needed. */
712
+ query: SqlQuery | null;
713
+ /** SELECT * fallback query, or null if SQL compiled. */
714
+ fallbackQuery: SqlQuery | null;
715
+ /** Table config for deserialization. */
716
+ config: TableConfig;
717
+ /** JS predicates (only for fallback). */
718
+ predicates?: Predicate<T>[];
719
+ /** Sort accessor (only for fallback). */
720
+ sortAccessor?: Accessor<T>;
721
+ /** Sort direction (only for fallback). */
722
+ reversed?: boolean;
723
+ /** Limit (only for fallback). */
724
+ limit?: number;
725
+ /** Offset (only for fallback). */
726
+ offset?: number;
727
+ }
691
728
 
692
729
  /**
693
730
  * Table<T> — a typed persistent collection backed by SQLite.
@@ -848,6 +885,28 @@ interface Db {
848
885
  ago(ms: number): number;
849
886
  /** Returns a unix timestamp for (now + duration). Use with days/hours/minutes. */
850
887
  fromNow(ms: number): number;
888
+ /**
889
+ * Execute multiple queries in a single round trip. All queries run on
890
+ * the same database connection, eliminating per-query HTTP overhead.
891
+ *
892
+ * Accepts Query objects (lazy, not yet executed). Compiles them to SQL,
893
+ * sends all in one batch request, and returns typed results.
894
+ *
895
+ * @example
896
+ * ```ts
897
+ * const [orders, approvals, vendors] = await db.batch(
898
+ * Orders.filter(o => o.status === 'active').take(10),
899
+ * Approvals.filter(a => a.status === 'pending').take(25),
900
+ * Vendors.sortBy(v => v.createdAt).reverse().take(5),
901
+ * );
902
+ * ```
903
+ */
904
+ batch<A>(q1: PromiseLike<A>): Promise<[A]>;
905
+ batch<A, B>(q1: PromiseLike<A>, q2: PromiseLike<B>): Promise<[A, B]>;
906
+ batch<A, B, C>(q1: PromiseLike<A>, q2: PromiseLike<B>, q3: PromiseLike<C>): Promise<[A, B, C]>;
907
+ batch<A, B, C, D>(q1: PromiseLike<A>, q2: PromiseLike<B>, q3: PromiseLike<C>, q4: PromiseLike<D>): Promise<[A, B, C, D]>;
908
+ batch<A, B, C, D, E>(q1: PromiseLike<A>, q2: PromiseLike<B>, q3: PromiseLike<C>, q4: PromiseLike<D>, q5: PromiseLike<E>): Promise<[A, B, C, D, E]>;
909
+ batch(...queries: PromiseLike<unknown>[]): Promise<unknown[]>;
851
910
  }
852
911
 
853
912
  /**
package/dist/index.js CHANGED
@@ -716,8 +716,7 @@ var Parser = class {
716
716
  return PARSE_FAILED;
717
717
  }
718
718
  /**
719
- * Attempt to resolve a closure variable by invoking the original function
720
- * with a recording Proxy and inspecting what values it compares against.
719
+ * Attempt to resolve a closure variable's value.
721
720
  *
722
721
  * This handles the common pattern:
723
722
  * ```ts
@@ -725,40 +724,28 @@ var Parser = class {
725
724
  * orders.filter(o => o.requestedBy === userId)
726
725
  * ```
727
726
  *
728
- * The Proxy captures property accesses on the parameter and we can then
729
- * extract the comparison value from the function's behavior. However,
730
- * this approach has limitations if the function throws, has side effects,
731
- * or uses the variable in a non-comparison context, we fall back to JS.
727
+ * Closure variable resolution is fundamentally limited in JavaScript
728
+ * we can't access another function's closure scope from outside without
729
+ * `eval`. The `===` operator can't be overridden via Proxy or
730
+ * Symbol.toPrimitive, so we can't intercept comparisons.
731
+ *
732
+ * For now, this falls back to JS execution. The predicate still works
733
+ * correctly — it just scans all rows instead of generating SQL.
734
+ * This is the most common reason for JS fallback in practice, since
735
+ * almost every real-world filter references a variable like `userId`.
736
+ *
737
+ * A future improvement could accept an explicit `vars` argument:
738
+ * ```ts
739
+ * orders.filter(o => o.requestedBy === $userId, { $userId: auth.userId })
740
+ * ```
732
741
  */
733
742
  resolveClosureVariable() {
734
- const identToken = this.advance();
735
- let closureExpr = identToken.value;
743
+ this.advance();
736
744
  while (this.match("dot") && this.tokens[this.pos + 1]?.type === "identifier") {
737
745
  this.advance();
738
- closureExpr += "." + this.advance().value;
739
- }
740
- try {
741
- const MARKER = /* @__PURE__ */ Symbol("field_access_marker");
742
- const accessed = [];
743
- const proxy = new Proxy(
744
- {},
745
- {
746
- get(_, prop) {
747
- accessed.push(prop);
748
- return new Proxy(() => MARKER, {
749
- get(_2, nestedProp) {
750
- accessed.push(nestedProp);
751
- return MARKER;
752
- }
753
- });
754
- }
755
- }
756
- );
757
- void proxy;
758
- return PARSE_FAILED;
759
- } catch {
760
- return PARSE_FAILED;
746
+ this.advance();
761
747
  }
748
+ return PARSE_FAILED;
762
749
  }
763
750
  /**
764
751
  * Look ahead to check if the next tokens form `.includes(`.
@@ -935,6 +922,76 @@ var Query = class _Query {
935
922
  return map;
936
923
  }
937
924
  // -------------------------------------------------------------------------
925
+ // Batch compilation — used by db.batch() to extract SQL without executing
926
+ // -------------------------------------------------------------------------
927
+ /**
928
+ * @internal Compile this query into a SqlQuery for batch execution.
929
+ *
930
+ * Returns the compiled SQL query (if all predicates compile to SQL),
931
+ * or null (if JS fallback is needed). In the fallback case, a bare
932
+ * `SELECT *` is returned as `fallbackQuery` so the batch can fetch
933
+ * all rows and this query can filter them in JS post-fetch.
934
+ */
935
+ _compile() {
936
+ const compiled = this._compilePredicates();
937
+ const sortField = this._sortAccessor ? extractFieldName(this._sortAccessor) : void 0;
938
+ if (compiled.allSql) {
939
+ const query = buildSelect(this._config.tableName, {
940
+ where: compiled.sqlWhere || void 0,
941
+ orderBy: sortField ?? void 0,
942
+ desc: this._reversed,
943
+ limit: this._limit,
944
+ offset: this._offset
945
+ });
946
+ return { query, fallbackQuery: null, config: this._config };
947
+ }
948
+ const fallbackQuery = buildSelect(this._config.tableName);
949
+ return {
950
+ query: null,
951
+ fallbackQuery,
952
+ config: this._config,
953
+ predicates: this._predicates,
954
+ sortAccessor: this._sortAccessor,
955
+ reversed: this._reversed,
956
+ limit: this._limit,
957
+ offset: this._offset
958
+ };
959
+ }
960
+ /**
961
+ * @internal Process raw SQL results into typed rows. Used by db.batch()
962
+ * after executing the compiled query.
963
+ *
964
+ * For SQL-compiled queries: just deserialize the rows.
965
+ * For JS-fallback queries: filter, sort, and slice in JS.
966
+ */
967
+ static _processResults(result, compiled) {
968
+ const rows = result.rows.map(
969
+ (row) => deserializeRow(
970
+ row,
971
+ compiled.config.columns
972
+ )
973
+ );
974
+ if (compiled.query) return rows;
975
+ let filtered = compiled.predicates ? rows.filter((row) => compiled.predicates.every((pred) => pred(row))) : rows;
976
+ if (compiled.sortAccessor) {
977
+ const accessor = compiled.sortAccessor;
978
+ const reversed = compiled.reversed ?? false;
979
+ filtered.sort((a, b) => {
980
+ const aVal = accessor(a);
981
+ const bVal = accessor(b);
982
+ if (aVal < bVal) return reversed ? 1 : -1;
983
+ if (aVal > bVal) return reversed ? -1 : 1;
984
+ return 0;
985
+ });
986
+ }
987
+ if (compiled.offset != null || compiled.limit != null) {
988
+ const start = compiled.offset ?? 0;
989
+ const end = compiled.limit != null ? start + compiled.limit : void 0;
990
+ filtered = filtered.slice(start, end);
991
+ }
992
+ return filtered;
993
+ }
994
+ // -------------------------------------------------------------------------
938
995
  // PromiseLike
939
996
  // -------------------------------------------------------------------------
940
997
  then(onfulfilled, onrejected) {
@@ -1180,7 +1237,49 @@ function createDb(databases, executeBatch) {
1180
1237
  hours: (n) => n * 36e5,
1181
1238
  minutes: (n) => n * 6e4,
1182
1239
  ago: (ms) => Date.now() - ms,
1183
- fromNow: (ms) => Date.now() + ms
1240
+ fromNow: (ms) => Date.now() + ms,
1241
+ // --- Batch execution ---
1242
+ batch: ((...queries) => {
1243
+ return (async () => {
1244
+ const compiled = queries.map((q) => {
1245
+ if (!(q instanceof Query)) {
1246
+ throw new MindStudioError(
1247
+ "db.batch() only accepts Query objects (from .filter(), .sortBy(), etc.)",
1248
+ "invalid_batch_query",
1249
+ 400
1250
+ );
1251
+ }
1252
+ return q._compile();
1253
+ });
1254
+ const groups = /* @__PURE__ */ new Map();
1255
+ for (let i = 0; i < compiled.length; i++) {
1256
+ const c = compiled[i];
1257
+ const dbId = c.config.databaseId;
1258
+ const sqlQuery = c.query ?? c.fallbackQuery;
1259
+ if (!groups.has(dbId)) groups.set(dbId, []);
1260
+ groups.get(dbId).push({ index: i, sqlQuery });
1261
+ }
1262
+ const allResults = new Array(compiled.length);
1263
+ await Promise.all(
1264
+ Array.from(groups.entries()).map(async ([dbId, entries]) => {
1265
+ const sqlQueries = entries.map((e) => e.sqlQuery);
1266
+ const results = await executeBatch(dbId, sqlQueries);
1267
+ for (let i = 0; i < entries.length; i++) {
1268
+ allResults[entries[i].index] = results[i];
1269
+ }
1270
+ })
1271
+ );
1272
+ return compiled.map((c, i) => {
1273
+ const result = allResults[i];
1274
+ if (!c.query && c.predicates?.length) {
1275
+ console.warn(
1276
+ `[mindstudio] db.batch(): filter on ${c.config.tableName} could not be compiled to SQL \u2014 processing in JS`
1277
+ );
1278
+ }
1279
+ return Query._processResults(result, c);
1280
+ });
1281
+ })();
1282
+ })
1184
1283
  };
1185
1284
  }
1186
1285
  function resolveTable(databases, tableName, databaseHint) {
@@ -2269,7 +2368,14 @@ var MindStudioAgent = class {
2269
2368
  hours: (n) => n * 36e5,
2270
2369
  minutes: (n) => n * 6e4,
2271
2370
  ago: (ms) => Date.now() - ms,
2272
- fromNow: (ms) => Date.now() + ms
2371
+ fromNow: (ms) => Date.now() + ms,
2372
+ // Batch needs context — hydrate first, then delegate to real db
2373
+ batch: ((...queries) => {
2374
+ return (async () => {
2375
+ await agent.ensureContext();
2376
+ return agent._db.batch(...queries);
2377
+ })();
2378
+ })
2273
2379
  };
2274
2380
  }
2275
2381
  // -------------------------------------------------------------------------