@mindstudio-ai/agent 0.1.21 → 0.1.22
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 +110 -12
- package/dist/index.d.ts +65 -14
- package/dist/index.js +85 -7
- package/dist/index.js.map +1 -1
- package/dist/postinstall.js +110 -12
- package/llms.txt +3 -3
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -612,6 +612,17 @@ interface TableConfig {
|
|
|
612
612
|
* (which need @@user@@ prefix handling) and for validation.
|
|
613
613
|
*/
|
|
614
614
|
columns: AppDatabaseColumnSchema[];
|
|
615
|
+
/**
|
|
616
|
+
* Unique constraints declared via defineTable options.
|
|
617
|
+
* Each entry is an array of column names that form a unique constraint.
|
|
618
|
+
* e.g. [['email'], ['userId', 'orgId']]
|
|
619
|
+
*/
|
|
620
|
+
unique?: string[][];
|
|
621
|
+
/**
|
|
622
|
+
* Default values for columns, applied client-side in push() and upsert().
|
|
623
|
+
* Explicit values in the input override defaults.
|
|
624
|
+
*/
|
|
625
|
+
defaults?: Record<string, unknown>;
|
|
615
626
|
/**
|
|
616
627
|
* Execute one or more SQL queries against the managed database in a
|
|
617
628
|
* single round trip. All queries run on the same SQLite connection,
|
|
@@ -716,6 +727,7 @@ declare class Query<T> implements PromiseLike<T[]> {
|
|
|
716
727
|
*/
|
|
717
728
|
static _processResults<T>(result: SqlResult, compiled: CompiledQuery<T>): T[];
|
|
718
729
|
then<TResult1 = T[], TResult2 = never>(onfulfilled?: ((value: T[]) => TResult1 | PromiseLike<TResult1>) | null, onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null): Promise<TResult1 | TResult2>;
|
|
730
|
+
catch<TResult2 = never>(onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null): Promise<T[] | TResult2>;
|
|
719
731
|
private _execute;
|
|
720
732
|
private _compilePredicates;
|
|
721
733
|
private _fetchAndFilterInJs;
|
|
@@ -794,6 +806,7 @@ declare class Mutation<TResult> implements PromiseLike<TResult> {
|
|
|
794
806
|
*/
|
|
795
807
|
static fromExecutor<T>(config: TableConfig, executor: () => Promise<T>): Mutation<T>;
|
|
796
808
|
then<T1 = TResult, T2 = never>(onfulfilled?: ((value: TResult) => T1 | PromiseLike<T1>) | null, onrejected?: ((reason: unknown) => T2 | PromiseLike<T2>) | null): Promise<T1 | T2>;
|
|
809
|
+
catch<T2 = never>(onrejected?: ((reason: unknown) => T2 | PromiseLike<T2>) | null): Promise<TResult | T2>;
|
|
797
810
|
/**
|
|
798
811
|
* @internal Compile this mutation into SQL for batch execution.
|
|
799
812
|
* Returns the queries and a result processor.
|
|
@@ -859,6 +872,20 @@ declare class Table<T> {
|
|
|
859
872
|
*/
|
|
860
873
|
removeAll(predicate: Predicate<T>): Mutation<number>;
|
|
861
874
|
clear(): Mutation<void>;
|
|
875
|
+
/**
|
|
876
|
+
* Insert a row, or update it if a row with the same unique key already
|
|
877
|
+
* exists. The conflict key must match a `unique` constraint declared in
|
|
878
|
+
* defineTable options. Returns the created or updated row.
|
|
879
|
+
*
|
|
880
|
+
* Uses SQLite's `INSERT ... ON CONFLICT ... DO UPDATE SET ... RETURNING *`.
|
|
881
|
+
*
|
|
882
|
+
* @param conflictKey - Column name(s) that form the unique constraint.
|
|
883
|
+
* Pass a single string for single-column unique, or an array for compound.
|
|
884
|
+
* @param data - Row data to insert (or update on conflict). Defaults apply.
|
|
885
|
+
*/
|
|
886
|
+
upsert(conflictKey: (keyof Omit<T, SystemFields> & string) | (keyof Omit<T, SystemFields> & string)[], data: PushInput<T>): Mutation<T>;
|
|
887
|
+
/** @internal Validate that the given columns match a declared unique constraint. */
|
|
888
|
+
private _validateUniqueConstraint;
|
|
862
889
|
}
|
|
863
890
|
|
|
864
891
|
/**
|
|
@@ -912,7 +939,7 @@ declare class Table<T> {
|
|
|
912
939
|
/**
|
|
913
940
|
* Options for `db.defineTable()`.
|
|
914
941
|
*/
|
|
915
|
-
interface DefineTableOptions {
|
|
942
|
+
interface DefineTableOptions<T = unknown> {
|
|
916
943
|
/**
|
|
917
944
|
* Database name or ID to target. Required when the app has multiple
|
|
918
945
|
* databases and the table name alone is ambiguous.
|
|
@@ -925,6 +952,39 @@ interface DefineTableOptions {
|
|
|
925
952
|
* - Multiple databases → searched by table name
|
|
926
953
|
*/
|
|
927
954
|
database?: string;
|
|
955
|
+
/**
|
|
956
|
+
* Unique constraints for the table. Each entry is an array of column
|
|
957
|
+
* names that together must be unique. The SDK communicates these to
|
|
958
|
+
* the platform which creates the corresponding SQLite UNIQUE indexes.
|
|
959
|
+
*
|
|
960
|
+
* Required for `upsert()` — the conflict key must match a declared
|
|
961
|
+
* unique constraint.
|
|
962
|
+
*
|
|
963
|
+
* @example
|
|
964
|
+
* ```ts
|
|
965
|
+
* // Single column unique
|
|
966
|
+
* db.defineTable<User>('users', { unique: [['email']] });
|
|
967
|
+
*
|
|
968
|
+
* // Compound unique
|
|
969
|
+
* db.defineTable<Membership>('memberships', { unique: [['userId', 'orgId']] });
|
|
970
|
+
*
|
|
971
|
+
* // Multiple constraints
|
|
972
|
+
* db.defineTable<User>('users', { unique: [['email'], ['slug']] });
|
|
973
|
+
* ```
|
|
974
|
+
*/
|
|
975
|
+
unique?: (keyof T & string)[][];
|
|
976
|
+
/**
|
|
977
|
+
* Default values for columns, applied client-side in `push()` and
|
|
978
|
+
* `upsert()`. Explicit values in the input override defaults.
|
|
979
|
+
*
|
|
980
|
+
* @example
|
|
981
|
+
* ```ts
|
|
982
|
+
* db.defineTable<Order>('orders', {
|
|
983
|
+
* defaults: { status: 'pending', retryCount: 0 },
|
|
984
|
+
* });
|
|
985
|
+
* ```
|
|
986
|
+
*/
|
|
987
|
+
defaults?: Partial<Omit<T, SystemFields>>;
|
|
928
988
|
}
|
|
929
989
|
|
|
930
990
|
/**
|
|
@@ -955,7 +1015,7 @@ interface Db {
|
|
|
955
1015
|
* const Orders = db.defineTable<Order>('orders', { database: 'main' });
|
|
956
1016
|
* ```
|
|
957
1017
|
*/
|
|
958
|
-
defineTable<T>(name: string, options?: DefineTableOptions): Table<T & SystemColumns>;
|
|
1018
|
+
defineTable<T>(name: string, options?: DefineTableOptions<T>): Table<T & SystemColumns>;
|
|
959
1019
|
/** Returns the current time as a unix timestamp (ms). Equivalent to `Date.now()`. */
|
|
960
1020
|
now(): number;
|
|
961
1021
|
/** Returns milliseconds for n days. Composable with `+`. */
|
|
@@ -2506,10 +2566,7 @@ interface FetchYoutubeChannelStepInput {
|
|
|
2506
2566
|
/** YouTube channel URL (e.g. https://www.youtube.com/@ChannelName or /channel/ID) */
|
|
2507
2567
|
channelUrl: string;
|
|
2508
2568
|
}
|
|
2509
|
-
|
|
2510
|
-
/** Channel metadata and video listings */
|
|
2511
|
-
channel: Record<string, unknown>;
|
|
2512
|
-
}
|
|
2569
|
+
type FetchYoutubeChannelStepOutput = Record<string, unknown>;
|
|
2513
2570
|
interface FetchYoutubeCommentsStepInput {
|
|
2514
2571
|
/** YouTube video URL to fetch comments for */
|
|
2515
2572
|
videoUrl: string;
|
|
@@ -2545,10 +2602,7 @@ interface FetchYoutubeVideoStepInput {
|
|
|
2545
2602
|
/** YouTube video URL to fetch metadata for */
|
|
2546
2603
|
videoUrl: string;
|
|
2547
2604
|
}
|
|
2548
|
-
|
|
2549
|
-
/** Video metadata including title, description, stats, and channel info */
|
|
2550
|
-
video: Record<string, unknown>;
|
|
2551
|
-
}
|
|
2605
|
+
type FetchYoutubeVideoStepOutput = Record<string, unknown>;
|
|
2552
2606
|
interface GenerateChartStepInput {
|
|
2553
2607
|
/** Chart configuration including type, data, and rendering options */
|
|
2554
2608
|
chart: {
|
|
@@ -4318,10 +4372,7 @@ interface SearchYoutubeTrendsStepInput {
|
|
|
4318
4372
|
/** Country code (e.g. "US") */
|
|
4319
4373
|
gl: string;
|
|
4320
4374
|
}
|
|
4321
|
-
|
|
4322
|
-
/** Trending video data for the selected category and region */
|
|
4323
|
-
trends: Record<string, unknown>;
|
|
4324
|
-
}
|
|
4375
|
+
type SearchYoutubeTrendsStepOutput = Record<string, unknown>;
|
|
4325
4376
|
interface SendEmailStepInput {
|
|
4326
4377
|
/** Email subject line */
|
|
4327
4378
|
subject: string;
|
package/dist/index.js
CHANGED
|
@@ -297,6 +297,18 @@ function buildUpdate(table, id, data, columns) {
|
|
|
297
297
|
params
|
|
298
298
|
};
|
|
299
299
|
}
|
|
300
|
+
function buildUpsert(table, data, conflictColumns, columns) {
|
|
301
|
+
const filtered = stripSystemColumns(data);
|
|
302
|
+
const keys = Object.keys(filtered);
|
|
303
|
+
const placeholders = keys.map(() => "?").join(", ");
|
|
304
|
+
const params = keys.map(
|
|
305
|
+
(k) => serializeColumnParam(filtered[k], k, columns)
|
|
306
|
+
);
|
|
307
|
+
const updateKeys = keys.filter((k) => !conflictColumns.includes(k));
|
|
308
|
+
const conflict = conflictColumns.join(", ");
|
|
309
|
+
const sql = updateKeys.length > 0 ? `INSERT INTO ${table} (${keys.join(", ")}) VALUES (${placeholders}) ON CONFLICT(${conflict}) DO UPDATE SET ${updateKeys.map((k) => `${k} = excluded.${k}`).join(", ")} RETURNING *` : `INSERT INTO ${table} (${keys.join(", ")}) VALUES (${placeholders}) ON CONFLICT(${conflict}) DO NOTHING RETURNING *`;
|
|
310
|
+
return { sql, params };
|
|
311
|
+
}
|
|
300
312
|
function buildDelete(table, where, whereParams) {
|
|
301
313
|
let sql = `DELETE FROM ${table}`;
|
|
302
314
|
if (where) sql += ` WHERE ${where}`;
|
|
@@ -1006,6 +1018,9 @@ var Query = class _Query {
|
|
|
1006
1018
|
then(onfulfilled, onrejected) {
|
|
1007
1019
|
return this._execute().then(onfulfilled, onrejected);
|
|
1008
1020
|
}
|
|
1021
|
+
catch(onrejected) {
|
|
1022
|
+
return this._execute().catch(onrejected);
|
|
1023
|
+
}
|
|
1009
1024
|
// -------------------------------------------------------------------------
|
|
1010
1025
|
// Execution internals
|
|
1011
1026
|
// -------------------------------------------------------------------------
|
|
@@ -1121,6 +1136,9 @@ var Mutation = class _Mutation {
|
|
|
1121
1136
|
then(onfulfilled, onrejected) {
|
|
1122
1137
|
return this._execute().then(onfulfilled, onrejected);
|
|
1123
1138
|
}
|
|
1139
|
+
catch(onrejected) {
|
|
1140
|
+
return this._execute().catch(onrejected);
|
|
1141
|
+
}
|
|
1124
1142
|
// -------------------------------------------------------------------------
|
|
1125
1143
|
// Batch compilation — used by db.batch()
|
|
1126
1144
|
// -------------------------------------------------------------------------
|
|
@@ -1227,7 +1245,9 @@ var Table = class {
|
|
|
1227
1245
|
}
|
|
1228
1246
|
push(data) {
|
|
1229
1247
|
const isArray = Array.isArray(data);
|
|
1230
|
-
const items = isArray ? data : [data]
|
|
1248
|
+
const items = (isArray ? data : [data]).map(
|
|
1249
|
+
(item) => this._config.defaults ? { ...this._config.defaults, ...item } : item
|
|
1250
|
+
);
|
|
1231
1251
|
const queries = items.map(
|
|
1232
1252
|
(item) => buildInsert(
|
|
1233
1253
|
this._config.tableName,
|
|
@@ -1306,6 +1326,60 @@ var Table = class {
|
|
|
1306
1326
|
const query = buildDelete(this._config.tableName);
|
|
1307
1327
|
return new Mutation(this._config, [query], () => void 0);
|
|
1308
1328
|
}
|
|
1329
|
+
/**
|
|
1330
|
+
* Insert a row, or update it if a row with the same unique key already
|
|
1331
|
+
* exists. The conflict key must match a `unique` constraint declared in
|
|
1332
|
+
* defineTable options. Returns the created or updated row.
|
|
1333
|
+
*
|
|
1334
|
+
* Uses SQLite's `INSERT ... ON CONFLICT ... DO UPDATE SET ... RETURNING *`.
|
|
1335
|
+
*
|
|
1336
|
+
* @param conflictKey - Column name(s) that form the unique constraint.
|
|
1337
|
+
* Pass a single string for single-column unique, or an array for compound.
|
|
1338
|
+
* @param data - Row data to insert (or update on conflict). Defaults apply.
|
|
1339
|
+
*/
|
|
1340
|
+
upsert(conflictKey, data) {
|
|
1341
|
+
const conflictColumns = Array.isArray(conflictKey) ? conflictKey : [conflictKey];
|
|
1342
|
+
this._validateUniqueConstraint(conflictColumns);
|
|
1343
|
+
const withDefaults = this._config.defaults ? { ...this._config.defaults, ...data } : data;
|
|
1344
|
+
const query = buildUpsert(
|
|
1345
|
+
this._config.tableName,
|
|
1346
|
+
withDefaults,
|
|
1347
|
+
conflictColumns,
|
|
1348
|
+
this._config.columns
|
|
1349
|
+
);
|
|
1350
|
+
return new Mutation(
|
|
1351
|
+
this._config,
|
|
1352
|
+
[query],
|
|
1353
|
+
(results) => deserializeRow(
|
|
1354
|
+
results[0].rows[0],
|
|
1355
|
+
this._config.columns
|
|
1356
|
+
)
|
|
1357
|
+
);
|
|
1358
|
+
}
|
|
1359
|
+
// -------------------------------------------------------------------------
|
|
1360
|
+
// Internal helpers
|
|
1361
|
+
// -------------------------------------------------------------------------
|
|
1362
|
+
/** @internal Validate that the given columns match a declared unique constraint. */
|
|
1363
|
+
_validateUniqueConstraint(columns) {
|
|
1364
|
+
if (!this._config.unique?.length) {
|
|
1365
|
+
throw new MindStudioError(
|
|
1366
|
+
`Cannot upsert on ${this._config.tableName}: no unique constraints declared. Add unique: [[${columns.map((c) => `'${c}'`).join(", ")}]] to defineTable options.`,
|
|
1367
|
+
"no_unique_constraint",
|
|
1368
|
+
400
|
|
1369
|
+
);
|
|
1370
|
+
}
|
|
1371
|
+
const sorted = [...columns].sort().join(",");
|
|
1372
|
+
const match = this._config.unique.some(
|
|
1373
|
+
(u) => [...u].sort().join(",") === sorted
|
|
1374
|
+
);
|
|
1375
|
+
if (!match) {
|
|
1376
|
+
throw new MindStudioError(
|
|
1377
|
+
`Cannot upsert on (${columns.join(", ")}): no matching unique constraint declared on ${this._config.tableName}.`,
|
|
1378
|
+
"no_unique_constraint",
|
|
1379
|
+
400
|
|
1380
|
+
);
|
|
1381
|
+
}
|
|
1382
|
+
}
|
|
1309
1383
|
};
|
|
1310
1384
|
|
|
1311
1385
|
// src/db/index.ts
|
|
@@ -1317,6 +1391,8 @@ function createDb(databases, executeBatch) {
|
|
|
1317
1391
|
databaseId: resolved.databaseId,
|
|
1318
1392
|
tableName: name,
|
|
1319
1393
|
columns: resolved.columns,
|
|
1394
|
+
unique: options?.unique,
|
|
1395
|
+
defaults: options?.defaults,
|
|
1320
1396
|
executeBatch: (queries) => executeBatch(resolved.databaseId, queries)
|
|
1321
1397
|
};
|
|
1322
1398
|
return new Table(config);
|
|
@@ -2516,6 +2592,8 @@ var MindStudioAgent = class {
|
|
|
2516
2592
|
databaseId: "",
|
|
2517
2593
|
tableName: name,
|
|
2518
2594
|
columns: [],
|
|
2595
|
+
unique: options?.unique,
|
|
2596
|
+
defaults: options?.defaults,
|
|
2519
2597
|
executeBatch: async (queries) => {
|
|
2520
2598
|
await agent.ensureContext();
|
|
2521
2599
|
const databases = agent._context.databases;
|
|
@@ -2754,9 +2832,9 @@ var monacoSnippets = {
|
|
|
2754
2832
|
"fetchGoogleSheet": { fields: [["spreadsheetId", "string"], ["range", "string"], ["exportType", ["csv", "json"]]], outputKeys: ["content"] },
|
|
2755
2833
|
"fetchSlackChannelHistory": { fields: [["channelId", "string"]], outputKeys: ["messages"] },
|
|
2756
2834
|
"fetchYoutubeCaptions": { fields: [["videoUrl", "string"], ["exportType", ["text", "json"]], ["language", "string"]], outputKeys: ["transcripts"] },
|
|
2757
|
-
"fetchYoutubeChannel": { fields: [["channelUrl", "string"]], outputKeys: [
|
|
2835
|
+
"fetchYoutubeChannel": { fields: [["channelUrl", "string"]], outputKeys: [] },
|
|
2758
2836
|
"fetchYoutubeComments": { fields: [["videoUrl", "string"], ["exportType", ["text", "json"]], ["limitPages", "string"]], outputKeys: ["comments"] },
|
|
2759
|
-
"fetchYoutubeVideo": { fields: [["videoUrl", "string"]], outputKeys: [
|
|
2837
|
+
"fetchYoutubeVideo": { fields: [["videoUrl", "string"]], outputKeys: [] },
|
|
2760
2838
|
"generateAsset": { fields: [["source", "string"], ["sourceType", ["html", "markdown", "spa", "raw", "dynamic", "customInterface"]], ["outputFormat", ["pdf", "png", "html", "mp4", "openGraph"]], ["pageSize", ["full", "letter", "A4", "custom"]], ["testData", "object"]], outputKeys: ["url"] },
|
|
2761
2839
|
"generateChart": { fields: [["chart", "object"]], outputKeys: ["chartUrl"] },
|
|
2762
2840
|
"generateImage": { fields: [["prompt", "string"]], outputKeys: ["imageUrl"] },
|
|
@@ -2840,7 +2918,7 @@ var monacoSnippets = {
|
|
|
2840
2918
|
"searchPerplexity": { fields: [["query", "string"], ["exportType", ["text", "json"]]], outputKeys: ["results"] },
|
|
2841
2919
|
"searchXPosts": { fields: [["query", "string"], ["scope", ["recent", "all"]], ["options", "object"]], outputKeys: ["posts"] },
|
|
2842
2920
|
"searchYoutube": { fields: [["query", "string"], ["limitPages", "string"], ["filter", "string"], ["filterType", "string"]], outputKeys: ["results"] },
|
|
2843
|
-
"searchYoutubeTrends": { fields: [["bp", ["now", "music", "gaming", "films"]], ["hl", "string"], ["gl", "string"]], outputKeys: [
|
|
2921
|
+
"searchYoutubeTrends": { fields: [["bp", ["now", "music", "gaming", "films"]], ["hl", "string"], ["gl", "string"]], outputKeys: [] },
|
|
2844
2922
|
"sendEmail": { fields: [["subject", "string"], ["body", "string"]], outputKeys: ["recipients"] },
|
|
2845
2923
|
"sendGmailDraft": { fields: [["draftId", "string"]], outputKeys: [] },
|
|
2846
2924
|
"sendGmailMessage": { fields: [["to", "string"], ["subject", "string"], ["message", "string"], ["messageType", ["plain", "html", "markdown"]]], outputKeys: ["messageId"] },
|
|
@@ -3188,7 +3266,7 @@ var stepMetadata = {
|
|
|
3188
3266
|
description: "Retrieve metadata and recent videos for a YouTube channel.",
|
|
3189
3267
|
usageNotes: "- Accepts a YouTube channel URL (e.g. https://www.youtube.com/@ChannelName or /channel/ID).\n- Returns channel info and video listings as a JSON object.",
|
|
3190
3268
|
inputSchema: { "type": "object", "properties": { "channelUrl": { "type": "string", "description": "YouTube channel URL (e.g. https://www.youtube.com/@ChannelName or /channel/ID)" } }, "required": ["channelUrl"] },
|
|
3191
|
-
outputSchema: { "type": "object"
|
|
3269
|
+
outputSchema: { "type": "object" }
|
|
3192
3270
|
},
|
|
3193
3271
|
"fetchYoutubeComments": {
|
|
3194
3272
|
stepType: "fetchYoutubeComments",
|
|
@@ -3202,7 +3280,7 @@ var stepMetadata = {
|
|
|
3202
3280
|
description: "Retrieve metadata for a YouTube video (title, description, stats, channel info).",
|
|
3203
3281
|
usageNotes: "- Returns video metadata, channel info, and engagement stats.\n- Video format data is excluded from the response.",
|
|
3204
3282
|
inputSchema: { "type": "object", "properties": { "videoUrl": { "type": "string", "description": "YouTube video URL to fetch metadata for" } }, "required": ["videoUrl"] },
|
|
3205
|
-
outputSchema: { "type": "object"
|
|
3283
|
+
outputSchema: { "type": "object" }
|
|
3206
3284
|
},
|
|
3207
3285
|
"generateAsset": {
|
|
3208
3286
|
stepType: "generatePdf",
|
|
@@ -3807,7 +3885,7 @@ var stepMetadata = {
|
|
|
3807
3885
|
description: "Retrieve trending videos on YouTube by category and region.",
|
|
3808
3886
|
usageNotes: '- Categories: "now" (trending now), "music", "gaming", "films".\n- Supports country and language filtering.',
|
|
3809
3887
|
inputSchema: { "type": "object", "properties": { "bp": { "enum": ["now", "music", "gaming", "films"], "type": "string", "description": 'Trending category: "now" (trending now), "music", "gaming", or "films"' }, "hl": { "type": "string", "description": 'Language code (e.g. "en")' }, "gl": { "type": "string", "description": 'Country code (e.g. "US")' } }, "required": ["bp", "hl", "gl"] },
|
|
3810
|
-
outputSchema: { "type": "object"
|
|
3888
|
+
outputSchema: { "type": "object" }
|
|
3811
3889
|
},
|
|
3812
3890
|
"sendEmail": {
|
|
3813
3891
|
stepType: "sendEmail",
|