@mindstudio-ai/agent 0.1.9 → 0.1.10

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
@@ -1419,6 +1419,19 @@ var init_auth = __esm({
1419
1419
  });
1420
1420
 
1421
1421
  // src/db/sql.ts
1422
+ function serializeParam(val) {
1423
+ if (val === null || val === void 0) return null;
1424
+ if (typeof val === "boolean") return val ? 1 : 0;
1425
+ if (typeof val === "number" || typeof val === "string") return val;
1426
+ return JSON.stringify(val);
1427
+ }
1428
+ function serializeColumnParam(val, columnName, columns) {
1429
+ const col = columns.find((c) => c.name === columnName);
1430
+ if (col?.type === "user" && typeof val === "string") {
1431
+ return `@@user@@${val}`;
1432
+ }
1433
+ return serializeParam(val);
1434
+ }
1422
1435
  function escapeValue(val) {
1423
1436
  if (val === null || val === void 0) return "NULL";
1424
1437
  if (typeof val === "boolean") return val ? "1" : "0";
@@ -1427,13 +1440,6 @@ function escapeValue(val) {
1427
1440
  const json = JSON.stringify(val);
1428
1441
  return `'${json.replace(/'/g, "''")}'`;
1429
1442
  }
1430
- function serializeValue(val, columnName, columns) {
1431
- const col = columns.find((c) => c.name === columnName);
1432
- if (col?.type === "user" && typeof val === "string") {
1433
- return escapeValue(`@@user@@${val}`);
1434
- }
1435
- return escapeValue(val);
1436
- }
1437
1443
  function deserializeRow(row, columns) {
1438
1444
  const result = {};
1439
1445
  for (const [key, value] of Object.entries(row)) {
@@ -1454,37 +1460,54 @@ function deserializeRow(row, columns) {
1454
1460
  }
1455
1461
  function buildSelect(table, options = {}) {
1456
1462
  let sql = `SELECT * FROM ${table}`;
1457
- if (options.where) sql += ` WHERE ${options.where}`;
1463
+ const params = [];
1464
+ if (options.where) {
1465
+ sql += ` WHERE ${options.where}`;
1466
+ if (options.whereParams) params.push(...options.whereParams);
1467
+ }
1458
1468
  if (options.orderBy) sql += ` ORDER BY ${options.orderBy}${options.desc ? " DESC" : " ASC"}`;
1459
1469
  if (options.limit != null) sql += ` LIMIT ${options.limit}`;
1460
1470
  if (options.offset != null) sql += ` OFFSET ${options.offset}`;
1461
- return sql;
1471
+ return { sql, params: params.length > 0 ? params : void 0 };
1462
1472
  }
1463
- function buildCount(table, where) {
1473
+ function buildCount(table, where, whereParams) {
1464
1474
  let sql = `SELECT COUNT(*) as count FROM ${table}`;
1465
1475
  if (where) sql += ` WHERE ${where}`;
1466
- return sql;
1476
+ return { sql, params: whereParams?.length ? whereParams : void 0 };
1467
1477
  }
1468
- function buildExists(table, where, negate) {
1478
+ function buildExists(table, where, whereParams, negate) {
1469
1479
  const inner = where ? `SELECT 1 FROM ${table} WHERE ${where}` : `SELECT 1 FROM ${table}`;
1470
1480
  const fn = negate ? "NOT EXISTS" : "EXISTS";
1471
- return `SELECT ${fn}(${inner}) as result`;
1481
+ return { sql: `SELECT ${fn}(${inner}) as result`, params: whereParams?.length ? whereParams : void 0 };
1472
1482
  }
1473
1483
  function buildInsert(table, data, columns) {
1474
1484
  const filtered = stripSystemColumns(data);
1475
1485
  const keys = Object.keys(filtered);
1476
- const vals = keys.map((k) => serializeValue(filtered[k], k, columns));
1477
- return `INSERT INTO ${table} (${keys.join(", ")}) VALUES (${vals.join(", ")})`;
1486
+ const placeholders = keys.map(() => "?").join(", ");
1487
+ const params = keys.map((k) => serializeColumnParam(filtered[k], k, columns));
1488
+ return {
1489
+ sql: `INSERT INTO ${table} (${keys.join(", ")}) VALUES (${placeholders}) RETURNING *`,
1490
+ params
1491
+ };
1478
1492
  }
1479
1493
  function buildUpdate(table, id, data, columns) {
1480
1494
  const filtered = stripSystemColumns(data);
1481
- const assignments = Object.entries(filtered).map(([k, v]) => `${k} = ${serializeValue(v, k, columns)}`).join(", ");
1482
- return `UPDATE ${table} SET ${assignments} WHERE id = ${escapeValue(id)}`;
1495
+ const keys = Object.keys(filtered);
1496
+ const assignments = keys.map((k) => `${k} = ?`).join(", ");
1497
+ const params = [
1498
+ ...keys.map((k) => serializeColumnParam(filtered[k], k, columns)),
1499
+ id
1500
+ // for WHERE id = ?
1501
+ ];
1502
+ return {
1503
+ sql: `UPDATE ${table} SET ${assignments} WHERE id = ? RETURNING *`,
1504
+ params
1505
+ };
1483
1506
  }
1484
- function buildDelete(table, where) {
1507
+ function buildDelete(table, where, whereParams) {
1485
1508
  let sql = `DELETE FROM ${table}`;
1486
1509
  if (where) sql += ` WHERE ${where}`;
1487
- return sql;
1510
+ return { sql, params: whereParams?.length ? whereParams : void 0 };
1488
1511
  }
1489
1512
  function stripSystemColumns(data) {
1490
1513
  const result = {};
@@ -2026,17 +2049,11 @@ var init_query = __esm({
2026
2049
  init_predicate();
2027
2050
  init_sql();
2028
2051
  Query = class _Query {
2029
- /** @internal Accumulated predicate functions to filter by. */
2030
2052
  _predicates;
2031
- /** @internal The field accessor for sorting, if set. */
2032
2053
  _sortAccessor;
2033
- /** @internal Whether the sort order is reversed (DESC). */
2034
2054
  _reversed;
2035
- /** @internal Maximum number of results (SQL LIMIT). */
2036
2055
  _limit;
2037
- /** @internal Number of results to skip (SQL OFFSET). */
2038
2056
  _offset;
2039
- /** @internal Binding to the database execution layer. */
2040
2057
  _config;
2041
2058
  constructor(config, options) {
2042
2059
  this._config = config;
@@ -2046,10 +2063,6 @@ var init_query = __esm({
2046
2063
  this._limit = options?.limit;
2047
2064
  this._offset = options?.offset;
2048
2065
  }
2049
- /**
2050
- * Create a clone of this query with some options overridden.
2051
- * Used internally by chain methods to maintain immutability.
2052
- */
2053
2066
  _clone(overrides) {
2054
2067
  return new _Query(this._config, {
2055
2068
  predicates: overrides.predicates ?? this._predicates,
@@ -2060,126 +2073,73 @@ var init_query = __esm({
2060
2073
  });
2061
2074
  }
2062
2075
  // -------------------------------------------------------------------------
2063
- // Chain methods — return new Query instances
2076
+ // Chain methods
2064
2077
  // -------------------------------------------------------------------------
2065
- /**
2066
- * Add a filter predicate. Multiple filters are ANDed together.
2067
- *
2068
- * @example
2069
- * ```ts
2070
- * const active = Orders.filter(o => o.status === 'active');
2071
- * const expensive = active.filter(o => o.amount > 5000);
2072
- * // WHERE status = 'active' AND amount > 5000
2073
- * ```
2074
- */
2075
2078
  filter(predicate) {
2076
- return this._clone({
2077
- predicates: [...this._predicates, predicate]
2078
- });
2079
+ return this._clone({ predicates: [...this._predicates, predicate] });
2079
2080
  }
2080
- /**
2081
- * Sort results by a field (ascending by default).
2082
- * Use `.reverse()` after `.sortBy()` for descending order.
2083
- *
2084
- * @example
2085
- * ```ts
2086
- * const newest = Orders.sortBy(o => o.createdAt).reverse();
2087
- * ```
2088
- */
2089
2081
  sortBy(accessor) {
2090
2082
  return this._clone({ sortAccessor: accessor });
2091
2083
  }
2092
- /**
2093
- * Reverse the current sort order. If no sort is set, this has no effect.
2094
- */
2095
2084
  reverse() {
2096
2085
  return this._clone({ reversed: !this._reversed });
2097
2086
  }
2098
- /**
2099
- * Limit the number of results returned.
2100
- *
2101
- * @example
2102
- * ```ts
2103
- * const top10 = Orders.sortBy(o => o.amount).reverse().take(10);
2104
- * ```
2105
- */
2106
2087
  take(n) {
2107
2088
  return this._clone({ limit: n });
2108
2089
  }
2109
- /**
2110
- * Skip the first n results. Use with `.take()` for pagination.
2111
- *
2112
- * @example
2113
- * ```ts
2114
- * const page2 = Orders.sortBy(o => o.createdAt).skip(50).take(50);
2115
- * ```
2116
- */
2117
2090
  skip(n) {
2118
2091
  return this._clone({ offset: n });
2119
2092
  }
2120
2093
  // -------------------------------------------------------------------------
2121
- // Terminal methods — execute the query and return results
2094
+ // Terminal methods
2122
2095
  // -------------------------------------------------------------------------
2123
- /**
2124
- * Return the first matching row, or null if no rows match.
2125
- * Applies the current sort order before taking the first result.
2126
- */
2127
2096
  async first() {
2128
2097
  const rows = await this._clone({ limit: 1 })._execute();
2129
2098
  return rows[0] ?? null;
2130
2099
  }
2131
- /**
2132
- * Return the last matching row (per current sort), or null.
2133
- * Flips the sort direction and takes 1 row.
2134
- */
2135
2100
  async last() {
2136
2101
  const rows = await this._clone({ limit: 1, reversed: !this._reversed })._execute();
2137
2102
  return rows[0] ?? null;
2138
2103
  }
2139
- /**
2140
- * Count matching rows. Returns a number, not the rows themselves.
2141
- * Executes as `SELECT COUNT(*)` when predicates compile to SQL.
2142
- */
2143
2104
  async count() {
2144
2105
  const compiled = this._compilePredicates();
2145
2106
  if (compiled.allSql) {
2146
- const where = compiled.sqlWhere || void 0;
2147
- const sql = buildCount(this._config.tableName, where);
2148
- const result = await this._config.executeQuery(sql);
2149
- const row = result.rows[0];
2107
+ const query = buildCount(
2108
+ this._config.tableName,
2109
+ compiled.sqlWhere || void 0
2110
+ );
2111
+ const results = await this._config.executeBatch([query]);
2112
+ const row = results[0]?.rows[0];
2150
2113
  return row?.count ?? 0;
2151
2114
  }
2152
2115
  const rows = await this._fetchAndFilterInJs(compiled);
2153
2116
  return rows.length;
2154
2117
  }
2155
- /**
2156
- * Check if any row matches the current filters. Short-circuits —
2157
- * doesn't load all rows when using SQL.
2158
- */
2159
2118
  async some() {
2160
2119
  const compiled = this._compilePredicates();
2161
2120
  if (compiled.allSql) {
2162
- const where = compiled.sqlWhere || void 0;
2163
- const sql = buildExists(this._config.tableName, where);
2164
- const result = await this._config.executeQuery(sql);
2165
- const row = result.rows[0];
2121
+ const query = buildExists(
2122
+ this._config.tableName,
2123
+ compiled.sqlWhere || void 0
2124
+ );
2125
+ const results = await this._config.executeBatch([query]);
2126
+ const row = results[0]?.rows[0];
2166
2127
  return row?.result === 1;
2167
2128
  }
2168
2129
  const rows = await this._fetchAndFilterInJs(compiled);
2169
2130
  return rows.length > 0;
2170
2131
  }
2171
- /**
2172
- * Check if all rows match the current filters. Short-circuits on false.
2173
- *
2174
- * Implemented as NOT EXISTS(... WHERE NOT predicate) — returns true
2175
- * if no rows fail the predicate.
2176
- */
2177
2132
  async every() {
2178
2133
  const compiled = this._compilePredicates();
2179
2134
  if (compiled.allSql && compiled.sqlWhere) {
2180
- const sql = buildExists(this._config.tableName, `NOT (${compiled.sqlWhere})`, true);
2181
- const result = await this._config.executeQuery(sql);
2182
- const row = result.rows[0];
2135
+ const query = buildExists(
2136
+ this._config.tableName,
2137
+ `NOT (${compiled.sqlWhere})`,
2138
+ void 0,
2139
+ true
2140
+ );
2141
+ const results = await this._config.executeBatch([query]);
2142
+ const row = results[0]?.rows[0];
2183
2143
  return row?.result === 1;
2184
2144
  }
2185
2145
  if (this._predicates.length === 0) return true;
@@ -2188,24 +2148,12 @@ var init_query = __esm({
2188
2148
  (row) => this._predicates.every((pred) => pred(row))
2189
2149
  );
2190
2150
  }
2191
- /**
2192
- * Return the row with the minimum value for the given field.
2193
- * Executes as `ORDER BY field ASC LIMIT 1` in SQL.
2194
- */
2195
2151
  async min(accessor) {
2196
2152
  return this.sortBy(accessor).first();
2197
2153
  }
2198
- /**
2199
- * Return the row with the maximum value for the given field.
2200
- * Executes as `ORDER BY field DESC LIMIT 1` in SQL.
2201
- */
2202
2154
  async max(accessor) {
2203
2155
  return this.sortBy(accessor).reverse().first();
2204
2156
  }
2205
- /**
2206
- * Group rows by a field value. Returns a Map.
2207
- * Always executes in JS (no SQL equivalent for grouping into a Map).
2208
- */
2209
2157
  async groupBy(accessor) {
2210
2158
  const rows = await this._execute();
2211
2159
  const map = /* @__PURE__ */ new Map();
@@ -2221,40 +2169,27 @@ var init_query = __esm({
2221
2169
  return map;
2222
2170
  }
2223
2171
  // -------------------------------------------------------------------------
2224
- // PromiseLike implementation — makes `await query` work
2172
+ // PromiseLike
2225
2173
  // -------------------------------------------------------------------------
2226
- /**
2227
- * PromiseLike.then() — executes the query and pipes the result.
2228
- * This is what makes `const rows = await query` work.
2229
- */
2230
2174
  then(onfulfilled, onrejected) {
2231
2175
  return this._execute().then(onfulfilled, onrejected);
2232
2176
  }
2233
2177
  // -------------------------------------------------------------------------
2234
2178
  // Execution internals
2235
2179
  // -------------------------------------------------------------------------
2236
- /**
2237
- * Execute the query and return typed result rows.
2238
- *
2239
- * This is the core execution method. It:
2240
- * 1. Tries to compile all predicates to SQL
2241
- * 2. If all compile → builds and executes a single SQL query
2242
- * 3. If any fail → fetches all rows and processes in JS
2243
- * 4. Deserializes rows (user prefix stripping, JSON parsing)
2244
- */
2245
2180
  async _execute() {
2246
2181
  const compiled = this._compilePredicates();
2247
2182
  if (compiled.allSql) {
2248
2183
  const sortField = this._sortAccessor ? extractFieldName(this._sortAccessor) : void 0;
2249
- const sql = buildSelect(this._config.tableName, {
2184
+ const query = buildSelect(this._config.tableName, {
2250
2185
  where: compiled.sqlWhere || void 0,
2251
2186
  orderBy: sortField ?? void 0,
2252
2187
  desc: this._reversed,
2253
2188
  limit: this._limit,
2254
2189
  offset: this._offset
2255
2190
  });
2256
- const result = await this._config.executeQuery(sql);
2257
- return result.rows.map(
2191
+ const results = await this._config.executeBatch([query]);
2192
+ return results[0].rows.map(
2258
2193
  (row) => deserializeRow(
2259
2194
  row,
2260
2195
  this._config.columns
@@ -2279,14 +2214,6 @@ var init_query = __esm({
2279
2214
  }
2280
2215
  return rows;
2281
2216
  }
2282
- /**
2283
- * Compile all accumulated predicates and determine the execution strategy.
2284
- *
2285
- * Returns an object with:
2286
- * - `allSql`: whether all predicates compiled to SQL
2287
- * - `sqlWhere`: combined WHERE clause (ANDed) if all compiled
2288
- * - `compiled`: individual compilation results
2289
- */
2290
2217
  _compilePredicates() {
2291
2218
  if (this._predicates.length === 0) {
2292
2219
  return { allSql: true, sqlWhere: "", compiled: [] };
@@ -2299,12 +2226,6 @@ var init_query = __esm({
2299
2226
  }
2300
2227
  return { allSql, sqlWhere, compiled };
2301
2228
  }
2302
- /**
2303
- * Fetch all rows from the table and apply JS predicates.
2304
- * This is the fallback path when SQL compilation fails.
2305
- *
2306
- * Logs a warning to stderr so developers know they're on the slow path.
2307
- */
2308
2229
  async _fetchAndFilterInJs(compiled) {
2309
2230
  const allRows = await this._fetchAllRows();
2310
2231
  if (compiled.compiled.some((c) => c.type === "js")) {
@@ -2316,14 +2237,10 @@ var init_query = __esm({
2316
2237
  (row) => this._predicates.every((pred) => pred(row))
2317
2238
  );
2318
2239
  }
2319
- /**
2320
- * Fetch all rows from the table (SELECT * with no WHERE).
2321
- * Used by the JS fallback path.
2322
- */
2323
2240
  async _fetchAllRows() {
2324
- const sql = buildSelect(this._config.tableName);
2325
- const result = await this._config.executeQuery(sql);
2326
- return result.rows.map(
2241
+ const query = buildSelect(this._config.tableName);
2242
+ const results = await this._config.executeBatch([query]);
2243
+ return results[0].rows.map(
2327
2244
  (row) => deserializeRow(row, this._config.columns)
2328
2245
  );
2329
2246
  }
@@ -2340,300 +2257,149 @@ var init_table = __esm({
2340
2257
  init_predicate();
2341
2258
  init_sql();
2342
2259
  Table = class {
2343
- /** @internal Runtime config binding this table to the execution layer. */
2260
+ /** @internal */
2344
2261
  _config;
2345
2262
  constructor(config) {
2346
2263
  this._config = config;
2347
2264
  }
2348
2265
  // -------------------------------------------------------------------------
2349
- // Reads — direct (return Promises)
2266
+ // Reads — direct
2350
2267
  // -------------------------------------------------------------------------
2351
- /**
2352
- * Get a single row by ID. Returns null if not found.
2353
- *
2354
- * @example
2355
- * ```ts
2356
- * const order = await Orders.get('abc-123');
2357
- * if (order) console.log(order.status);
2358
- * ```
2359
- */
2360
2268
  async get(id) {
2361
- const sql = buildSelect(this._config.tableName, {
2362
- where: `id = ${escapeValue(id)}`,
2269
+ const query = buildSelect(this._config.tableName, {
2270
+ where: `id = ?`,
2271
+ whereParams: [id],
2363
2272
  limit: 1
2364
2273
  });
2365
- const result = await this._config.executeQuery(sql);
2366
- if (result.rows.length === 0) return null;
2274
+ const results = await this._config.executeBatch([query]);
2275
+ if (results[0].rows.length === 0) return null;
2367
2276
  return deserializeRow(
2368
- result.rows[0],
2277
+ results[0].rows[0],
2369
2278
  this._config.columns
2370
2279
  );
2371
2280
  }
2372
- /**
2373
- * Find the first row matching a predicate. Returns null if none match.
2374
- *
2375
- * @example
2376
- * ```ts
2377
- * const activeOrder = await Orders.findOne(o => o.status === 'active');
2378
- * ```
2379
- */
2380
2281
  async findOne(predicate) {
2381
2282
  return this.filter(predicate).first();
2382
2283
  }
2383
- /**
2384
- * Count rows, optionally filtered by a predicate.
2385
- *
2386
- * @example
2387
- * ```ts
2388
- * const total = await Orders.count();
2389
- * const pending = await Orders.count(o => o.status === 'pending');
2390
- * ```
2391
- */
2392
2284
  async count(predicate) {
2393
- if (predicate) {
2394
- return this.filter(predicate).count();
2395
- }
2396
- const sql = buildCount(this._config.tableName);
2397
- const result = await this._config.executeQuery(sql);
2398
- const row = result.rows[0];
2285
+ if (predicate) return this.filter(predicate).count();
2286
+ const query = buildCount(this._config.tableName);
2287
+ const results = await this._config.executeBatch([query]);
2288
+ const row = results[0]?.rows[0];
2399
2289
  return row?.count ?? 0;
2400
2290
  }
2401
- /**
2402
- * Check if any row matches a predicate. Short-circuits.
2403
- *
2404
- * @example
2405
- * ```ts
2406
- * const hasActive = await Orders.some(o => o.status === 'active');
2407
- * ```
2408
- */
2409
2291
  async some(predicate) {
2410
2292
  return this.filter(predicate).some();
2411
2293
  }
2412
- /**
2413
- * Check if all rows match a predicate.
2414
- *
2415
- * @example
2416
- * ```ts
2417
- * const allComplete = await Orders.every(o => o.status === 'completed');
2418
- * ```
2419
- */
2420
2294
  async every(predicate) {
2421
2295
  return this.filter(predicate).every();
2422
2296
  }
2423
- /**
2424
- * Check if the table has zero rows.
2425
- *
2426
- * @example
2427
- * ```ts
2428
- * if (await Orders.isEmpty()) console.log('No orders yet');
2429
- * ```
2430
- */
2431
2297
  async isEmpty() {
2432
- const sql = buildExists(this._config.tableName, void 0, true);
2433
- const result = await this._config.executeQuery(sql);
2434
- const row = result.rows[0];
2298
+ const query = buildExists(this._config.tableName, void 0, void 0, true);
2299
+ const results = await this._config.executeBatch([query]);
2300
+ const row = results[0]?.rows[0];
2435
2301
  return row?.result === 1;
2436
2302
  }
2437
- /**
2438
- * Return the row with the minimum value for a field.
2439
- * Executes as `ORDER BY field ASC LIMIT 1`.
2440
- *
2441
- * @example
2442
- * ```ts
2443
- * const cheapest = await Orders.min(o => o.amount);
2444
- * ```
2445
- */
2446
2303
  async min(accessor) {
2447
2304
  return this.sortBy(accessor).first();
2448
2305
  }
2449
- /**
2450
- * Return the row with the maximum value for a field.
2451
- * Executes as `ORDER BY field DESC LIMIT 1`.
2452
- *
2453
- * @example
2454
- * ```ts
2455
- * const mostExpensive = await Orders.max(o => o.amount);
2456
- * ```
2457
- */
2458
2306
  async max(accessor) {
2459
2307
  return this.sortBy(accessor).reverse().first();
2460
2308
  }
2461
- /**
2462
- * Group all rows by a field value. Returns a Map.
2463
- *
2464
- * @example
2465
- * ```ts
2466
- * const byStatus = await Orders.groupBy(o => o.status);
2467
- * // Map { 'pending' => [...], 'approved' => [...] }
2468
- * ```
2469
- */
2470
2309
  async groupBy(accessor) {
2471
2310
  return new Query(this._config).groupBy(accessor);
2472
2311
  }
2473
2312
  // -------------------------------------------------------------------------
2474
- // Reads — chainable (return Query<T>)
2313
+ // Reads — chainable
2475
2314
  // -------------------------------------------------------------------------
2476
- /**
2477
- * Filter rows by a predicate. Returns a chainable Query.
2478
- *
2479
- * The predicate is compiled to SQL when possible. If compilation fails,
2480
- * the query falls back to fetching all rows and filtering in JS.
2481
- *
2482
- * @example
2483
- * ```ts
2484
- * const active = await Orders.filter(o => o.status === 'active');
2485
- * const recentActive = await Orders
2486
- * .filter(o => o.status === 'active')
2487
- * .sortBy(o => o.createdAt)
2488
- * .reverse()
2489
- * .take(10);
2490
- * ```
2491
- */
2492
2315
  filter(predicate) {
2493
2316
  return new Query(this._config).filter(predicate);
2494
2317
  }
2495
- /**
2496
- * Sort all rows by a field. Returns a chainable Query.
2497
- *
2498
- * @example
2499
- * ```ts
2500
- * const newest = await Orders.sortBy(o => o.createdAt).reverse().take(5);
2501
- * ```
2502
- */
2503
2318
  sortBy(accessor) {
2504
2319
  return new Query(this._config).sortBy(accessor);
2505
2320
  }
2506
2321
  async push(data) {
2507
2322
  const isArray = Array.isArray(data);
2508
2323
  const items = isArray ? data : [data];
2509
- const results = [];
2510
- for (const item of items) {
2511
- const insertSql = buildInsert(
2324
+ const queries = items.map(
2325
+ (item) => buildInsert(
2512
2326
  this._config.tableName,
2513
2327
  item,
2514
2328
  this._config.columns
2515
- );
2516
- await this._config.executeQuery(insertSql);
2517
- const fetchSql = `SELECT * FROM ${this._config.tableName} WHERE rowid = last_insert_rowid()`;
2518
- const fetchResult = await this._config.executeQuery(fetchSql);
2519
- if (fetchResult.rows.length > 0) {
2520
- results.push(
2521
- deserializeRow(
2522
- fetchResult.rows[0],
2523
- this._config.columns
2524
- )
2329
+ )
2330
+ );
2331
+ const results = await this._config.executeBatch(queries);
2332
+ const rows = results.map((r) => {
2333
+ if (r.rows.length > 0) {
2334
+ return deserializeRow(
2335
+ r.rows[0],
2336
+ this._config.columns
2525
2337
  );
2526
2338
  }
2527
- }
2528
- return isArray ? results : results[0];
2339
+ return void 0;
2340
+ });
2341
+ return isArray ? rows : rows[0];
2529
2342
  }
2530
2343
  /**
2531
2344
  * Update a row by ID. Only the provided fields are changed.
2532
- * Returns the updated row.
2533
- *
2534
- * System columns cannot be updated — they're stripped automatically.
2535
- * `updatedAt` and `lastUpdatedBy` are set by the platform.
2536
- *
2537
- * @example
2538
- * ```ts
2539
- * const updated = await Orders.update(order.id, { status: 'approved' });
2540
- * console.log(updated.updatedAt); // freshly updated
2541
- * ```
2345
+ * Returns the updated row via `UPDATE ... RETURNING *`.
2542
2346
  */
2543
2347
  async update(id, data) {
2544
- const updateSql = buildUpdate(
2348
+ const query = buildUpdate(
2545
2349
  this._config.tableName,
2546
2350
  id,
2547
2351
  data,
2548
2352
  this._config.columns
2549
2353
  );
2550
- await this._config.executeQuery(updateSql);
2551
- const fetchSql = buildSelect(this._config.tableName, {
2552
- where: `id = ${escapeValue(id)}`,
2553
- limit: 1
2554
- });
2555
- const result = await this._config.executeQuery(fetchSql);
2354
+ const results = await this._config.executeBatch([query]);
2556
2355
  return deserializeRow(
2557
- result.rows[0],
2356
+ results[0].rows[0],
2558
2357
  this._config.columns
2559
2358
  );
2560
2359
  }
2561
- /**
2562
- * Remove a row by ID.
2563
- *
2564
- * @example
2565
- * ```ts
2566
- * await Orders.remove('abc-123');
2567
- * ```
2568
- */
2569
2360
  async remove(id) {
2570
- const sql = buildDelete(
2571
- this._config.tableName,
2572
- `id = ${escapeValue(id)}`
2573
- );
2574
- await this._config.executeQuery(sql);
2361
+ const query = buildDelete(this._config.tableName, `id = ?`, [id]);
2362
+ await this._config.executeBatch([query]);
2575
2363
  }
2576
2364
  /**
2577
2365
  * Remove all rows matching a predicate. Returns the count removed.
2578
- *
2579
- * The predicate is compiled to SQL when possible. If compilation fails,
2580
- * the function fetches all matching rows, collects their IDs, and
2581
- * deletes them individually.
2582
- *
2583
- * @example
2584
- * ```ts
2585
- * const removed = await Orders.removeAll(o => o.status === 'rejected');
2586
- * console.log(`Removed ${removed} orders`);
2587
- * ```
2588
2366
  */
2589
2367
  async removeAll(predicate) {
2590
2368
  const compiled = compilePredicate(predicate);
2591
2369
  if (compiled.type === "sql") {
2592
- const sql = buildDelete(this._config.tableName, compiled.where);
2593
- const result = await this._config.executeQuery(sql);
2594
- return result.changes;
2370
+ const query = buildDelete(this._config.tableName, compiled.where);
2371
+ const results = await this._config.executeBatch([query]);
2372
+ return results[0].changes;
2595
2373
  }
2596
2374
  console.warn(
2597
2375
  `[mindstudio] removeAll predicate on ${this._config.tableName} could not be compiled to SQL \u2014 fetching all rows first`
2598
2376
  );
2599
- const allSql = buildSelect(this._config.tableName);
2600
- const allResult = await this._config.executeQuery(allSql);
2601
- const allRows = allResult.rows.map(
2377
+ const allQuery = buildSelect(this._config.tableName);
2378
+ const allResults = await this._config.executeBatch([allQuery]);
2379
+ const allRows = allResults[0].rows.map(
2602
2380
  (r) => deserializeRow(
2603
2381
  r,
2604
2382
  this._config.columns
2605
2383
  )
2606
2384
  );
2607
2385
  const matching = allRows.filter((row) => predicate(row));
2608
- let count = 0;
2609
- for (const row of matching) {
2610
- const id = row.id;
2611
- if (id) {
2612
- const sql = buildDelete(this._config.tableName, `id = ${escapeValue(id)}`);
2613
- await this._config.executeQuery(sql);
2614
- count++;
2615
- }
2386
+ if (matching.length === 0) return 0;
2387
+ const deleteQueries = matching.filter((row) => row.id).map((row) => buildDelete(this._config.tableName, `id = ?`, [row.id]));
2388
+ if (deleteQueries.length > 0) {
2389
+ await this._config.executeBatch(deleteQueries);
2616
2390
  }
2617
- return count;
2391
+ return matching.length;
2618
2392
  }
2619
- /**
2620
- * Remove all rows from the table.
2621
- *
2622
- * @example
2623
- * ```ts
2624
- * await Orders.clear();
2625
- * ```
2626
- */
2627
2393
  async clear() {
2628
- const sql = buildDelete(this._config.tableName);
2629
- await this._config.executeQuery(sql);
2394
+ const query = buildDelete(this._config.tableName);
2395
+ await this._config.executeBatch([query]);
2630
2396
  }
2631
2397
  };
2632
2398
  }
2633
2399
  });
2634
2400
 
2635
2401
  // src/db/index.ts
2636
- function createDb(databases, executeQuery) {
2402
+ function createDb(databases, executeBatch) {
2637
2403
  return {
2638
2404
  defineTable(name, options) {
2639
2405
  const resolved = resolveTable(databases, name, options?.database);
@@ -2641,7 +2407,7 @@ function createDb(databases, executeQuery) {
2641
2407
  databaseId: resolved.databaseId,
2642
2408
  tableName: name,
2643
2409
  columns: resolved.columns,
2644
- executeQuery: (sql) => executeQuery(resolved.databaseId, sql)
2410
+ executeBatch: (queries) => executeBatch(resolved.databaseId, queries)
2645
2411
  };
2646
2412
  return new Table(config);
2647
2413
  },
@@ -3612,6 +3378,9 @@ var init_client = __esm({
3612
3378
  * ```
3613
3379
  */
3614
3380
  get auth() {
3381
+ if (!this._auth) {
3382
+ this._trySandboxHydration();
3383
+ }
3615
3384
  if (!this._auth) {
3616
3385
  throw new MindStudioError(
3617
3386
  "Auth context not yet loaded. Call `await agent.ensureContext()` or perform any db operation first (which auto-hydrates context). Inside the MindStudio sandbox, context is loaded automatically.",
@@ -3637,6 +3406,9 @@ var init_client = __esm({
3637
3406
  * ```
3638
3407
  */
3639
3408
  get db() {
3409
+ if (!this._db) {
3410
+ this._trySandboxHydration();
3411
+ }
3640
3412
  if (this._db) return this._db;
3641
3413
  return this._createLazyDb();
3642
3414
  }
@@ -3694,7 +3466,7 @@ var init_client = __esm({
3694
3466
  this._auth = new AuthContext(context.auth);
3695
3467
  this._db = createDb(
3696
3468
  context.databases,
3697
- this._executeDbQuery.bind(this)
3469
+ this._executeDbBatch.bind(this)
3698
3470
  );
3699
3471
  }
3700
3472
  /**
@@ -3715,25 +3487,40 @@ var init_client = __esm({
3715
3487
  }
3716
3488
  }
3717
3489
  /**
3718
- * @internal Execute a SQL query against a managed database.
3719
- * Used as the `executeQuery` callback for Table instances.
3490
+ * @internal Execute a batch of SQL queries against a managed database.
3491
+ * Used as the `executeBatch` callback for Table/Query instances.
3720
3492
  *
3721
- * Calls the `queryAppDatabase` step with `parameterize: false`
3722
- * (the SDK builds fully-formed SQL with escaped inline values).
3493
+ * Calls `POST /_internal/v2/db/query` directly with the hook token
3494
+ * (raw, no Bearer prefix). All queries run on a single SQLite connection,
3495
+ * enabling RETURNING clauses and multi-statement batches.
3723
3496
  */
3724
- async _executeDbQuery(databaseId, sql) {
3725
- const result = await this.executeStep("queryAppDatabase", {
3726
- databaseId,
3727
- sql,
3728
- parameterize: false
3497
+ async _executeDbBatch(databaseId, queries) {
3498
+ const url = `${this._httpConfig.baseUrl}/_internal/v2/db/query`;
3499
+ const res = await fetch(url, {
3500
+ method: "POST",
3501
+ headers: {
3502
+ "Content-Type": "application/json",
3503
+ Authorization: this._httpConfig.token
3504
+ },
3505
+ body: JSON.stringify({ databaseId, queries })
3729
3506
  });
3730
- return { rows: result.rows ?? [], changes: result.changes ?? 0 };
3507
+ if (!res.ok) {
3508
+ let message = `Database query failed: ${res.status} ${res.statusText}`;
3509
+ try {
3510
+ const body = await res.json();
3511
+ if (body.error) message = body.error;
3512
+ } catch {
3513
+ }
3514
+ throw new MindStudioError(message, "db_query_error", res.status);
3515
+ }
3516
+ const data = await res.json();
3517
+ return data.results;
3731
3518
  }
3732
3519
  /**
3733
3520
  * @internal Create a lazy Db proxy that auto-hydrates context.
3734
3521
  *
3735
3522
  * defineTable() returns Table instances immediately (no async needed).
3736
- * But the Table's executeQuery callback is wrapped to call ensureContext()
3523
+ * But the Table's executeBatch callback is wrapped to call ensureContext()
3737
3524
  * before the first query, so context is fetched lazily.
3738
3525
  */
3739
3526
  _createLazyDb() {
@@ -3745,7 +3532,7 @@ var init_client = __esm({
3745
3532
  databaseId: "",
3746
3533
  tableName: name,
3747
3534
  columns: [],
3748
- executeQuery: async (sql) => {
3535
+ executeBatch: async (queries) => {
3749
3536
  await agent.ensureContext();
3750
3537
  const databases = agent._context.databases;
3751
3538
  let targetDb;
@@ -3759,7 +3546,7 @@ var init_client = __esm({
3759
3546
  );
3760
3547
  }
3761
3548
  const databaseId = targetDb?.id ?? databases[0]?.id ?? "";
3762
- return agent._executeDbQuery(databaseId, sql);
3549
+ return agent._executeDbBatch(databaseId, queries);
3763
3550
  }
3764
3551
  });
3765
3552
  },
@@ -3974,7 +3761,7 @@ async function startMcpServer(options) {
3974
3761
  capabilities: { tools: {} },
3975
3762
  serverInfo: {
3976
3763
  name: "mindstudio-agent",
3977
- version: "0.1.9"
3764
+ version: "0.1.10"
3978
3765
  },
3979
3766
  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."
3980
3767
  });
@@ -4882,7 +4669,7 @@ function isNewerVersion(current, latest) {
4882
4669
  return false;
4883
4670
  }
4884
4671
  async function checkForUpdate() {
4885
- const currentVersion = "0.1.9";
4672
+ const currentVersion = "0.1.10";
4886
4673
  if (!currentVersion) return null;
4887
4674
  try {
4888
4675
  const { loadConfig: loadConfig2, saveConfig: saveConfig2 } = await Promise.resolve().then(() => (init_config(), config_exports));
@@ -4911,7 +4698,7 @@ async function checkForUpdate() {
4911
4698
  }
4912
4699
  }
4913
4700
  function printUpdateNotice(latestVersion) {
4914
- const currentVersion = "0.1.9";
4701
+ const currentVersion = "0.1.10";
4915
4702
  process.stderr.write(
4916
4703
  `
4917
4704
  ${ansi.cyanBright("Update available")} ${ansi.gray(currentVersion + " \u2192")} ${ansi.cyanBold(latestVersion)}
@@ -4986,7 +4773,7 @@ async function cmdLogin(options) {
4986
4773
  process.stderr.write("\n");
4987
4774
  printLogo();
4988
4775
  process.stderr.write("\n");
4989
- const ver = "0.1.9";
4776
+ const ver = "0.1.10";
4990
4777
  process.stderr.write(
4991
4778
  ` ${ansi.bold("MindStudio Agent")} ${ver ? " " + ansi.gray("v" + ver) : ""}
4992
4779
  `
@@ -5069,6 +4856,9 @@ async function cmdLogin(options) {
5069
4856
  ` ${ansi.greenBold("\u2714")} Authenticated successfully!
5070
4857
  ${ansi.gray("Credentials saved to")} ${getConfigPath2()}
5071
4858
 
4859
+ ${ansi.bold("Using with Claude Code?")} Run once to enable the MCP server:
4860
+ ${ansi.cyan("claude mcp add mindstudio -- mindstudio mcp")}
4861
+
5072
4862
  `
5073
4863
  );
5074
4864
  return;