@agenticmail/openclaw 0.5.41 → 0.5.42

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/README.md CHANGED
@@ -364,6 +364,38 @@ The plugin registers three OpenClaw lifecycle hooks:
364
364
 
365
365
  ---
366
366
 
367
+ ## Troubleshooting
368
+
369
+ ### Plugin ID mismatch warning
370
+
371
+ ```
372
+ plugins.entries.agenticmail: plugin agenticmail: plugin id mismatch
373
+ (manifest uses "agenticmail", entry hints "openclaw")
374
+ ```
375
+
376
+ This is a harmless warning. OpenClaw infers the expected plugin ID from the npm package name (`@agenticmail/openclaw`) and sees "openclaw", but the plugin manifest declares its ID as `"agenticmail"`. The plugin loads and works correctly — you can safely ignore this warning.
377
+
378
+ ### Plugin path not found
379
+
380
+ ```
381
+ plugins.load.paths: plugin: plugin path not found: /Users/you/node_modules/@agenticmail/openclaw
382
+ ```
383
+
384
+ This means the `plugins.load.paths` entry in your `~/.openclaw/openclaw.json` points to a location where the plugin isn't installed. Find the actual path:
385
+
386
+ ```bash
387
+ # If installed globally
388
+ npm prefix -g
389
+ # Plugin will be at: <prefix>/lib/node_modules/@agenticmail/openclaw
390
+
391
+ # Or search for it
392
+ find / -name "openclaw.plugin.json" -path "*@agenticmail*" 2>/dev/null
393
+ ```
394
+
395
+ Then update the path in `~/.openclaw/openclaw.json` under `plugins.load.paths`.
396
+
397
+ ---
398
+
367
399
  ## License
368
400
 
369
401
  [MIT](./LICENSE) - Ope Olatunji ([@ope-olatunji](https://github.com/ope-olatunji))
package/dist/index.cjs CHANGED
@@ -2188,6 +2188,154 @@ The agent must have browser access and a Google Voice session (logged into Googl
2188
2188
  }
2189
2189
  }
2190
2190
  });
2191
+ reg("agenticmail_storage", {
2192
+ description: `Full database management for agents. Create/alter/drop tables, CRUD rows, manage indexes, run aggregations, import/export data, execute raw SQL, optimize & analyze \u2014 all on whatever database the user deployed (SQLite, Postgres, MySQL, Turso).
2193
+
2194
+ Tables are sandboxed per-agent (agt_ prefix) or shared (shared_ prefix). Column types: text, integer, real, boolean, json, blob, timestamp. Auto-adds id + timestamps by default.
2195
+
2196
+ WHERE filters support operators: {column: value} for equality, {column: {$gt: 5, $lt: 10}} for comparisons, {column: {$like: "%foo%"}} for pattern matching, {column: {$in: [1,2,3]}} for IN, {column: {$between: [lo, hi]}} for ranges, {column: {$is_null: true}} for null checks. Also: $gte, $lte, $ne, $ilike, $not_like, $not_in.`,
2197
+ parameters: {
2198
+ action: { type: "string", required: true, description: "create_table, list_tables, describe_table, insert, upsert, query, aggregate, update, delete_rows, truncate, drop_table, clone_table, rename_table, rename_column, add_column, drop_column, create_index, list_indexes, drop_index, reindex, archive_table, unarchive_table, export, import, sql, stats, vacuum, analyze, explain" },
2199
+ table: { type: "string", description: "Table name (display name or internal prefixed name)" },
2200
+ description: { type: "string", description: "For create_table: human-readable description" },
2201
+ columns: { type: "array", description: "For create_table: [{name, type, required?, default?, unique?, primaryKey?, references?: {table, column, onDelete?}, check?}]" },
2202
+ indexes: { type: "array", description: "For create_table/create_index: [{columns: string[], unique?: boolean, name?: string, where?: string}]" },
2203
+ shared: { type: "boolean", description: "For create_table: accessible by all agents (default: false)" },
2204
+ timestamps: { type: "boolean", description: "For create_table: auto-add created_at/updated_at (default: true)" },
2205
+ rows: { type: "array", description: "For insert/upsert/import: array of row objects" },
2206
+ where: { type: "object", description: "For query/update/delete_rows/export: filter conditions. Supports operators: {$gt, $gte, $lt, $lte, $ne, $like, $ilike, $not_like, $in, $not_in, $is_null, $between}" },
2207
+ set: { type: "object", description: "For update: {column: newValue}" },
2208
+ orderBy: { type: "string", description: "For query: ORDER BY clause" },
2209
+ limit: { type: "number", description: "For query/export: max rows" },
2210
+ offset: { type: "number", description: "For query: skip N rows" },
2211
+ selectColumns: { type: "array", description: "For query: specific columns to select" },
2212
+ distinct: { type: "boolean", description: "For query: SELECT DISTINCT" },
2213
+ groupBy: { type: "string", description: "For query/aggregate: GROUP BY clause" },
2214
+ having: { type: "string", description: "For query: HAVING clause" },
2215
+ operations: { type: "array", description: 'For aggregate: [{fn: "count"|"sum"|"avg"|"min"|"max"|"count_distinct", column?, alias?}]' },
2216
+ column: { type: "object", description: "For add_column: {name, type, required?, default?, references?, check?}" },
2217
+ columnName: { type: "string", description: "For drop_column: column name to drop" },
2218
+ indexName: { type: "string", description: "For drop_index: index name" },
2219
+ indexColumns: { type: "array", description: "For create_index: column names" },
2220
+ indexUnique: { type: "boolean", description: "For create_index: unique index" },
2221
+ indexWhere: { type: "string", description: "For create_index: partial index condition" },
2222
+ newName: { type: "string", description: "For rename_table/rename_column: new name" },
2223
+ oldName: { type: "string", description: "For rename_column: old column name" },
2224
+ conflictColumn: { type: "string", description: "For upsert/import: column to detect conflicts on" },
2225
+ onConflict: { type: "string", description: 'For import: "skip"|"replace"|"error"' },
2226
+ includeData: { type: "boolean", description: "For clone_table: include data (default: true)" },
2227
+ format: { type: "string", description: 'For export: "json"|"csv"' },
2228
+ sql: { type: "string", description: "For sql/explain: raw SQL query" },
2229
+ params: { type: "array", description: "For sql/explain: query parameters" },
2230
+ includeShared: { type: "boolean", description: "For list_tables: include shared (default: true)" },
2231
+ includeArchived: { type: "boolean", description: "For list_tables: include archived" }
2232
+ },
2233
+ handler: async (params) => {
2234
+ try {
2235
+ const c = await ctxForParams(ctx, params);
2236
+ const action = params.action;
2237
+ const tbl = params.table ? encodeURIComponent(params.table) : "";
2238
+ switch (action) {
2239
+ // ── DDL: Schema Definition ──
2240
+ case "create_table":
2241
+ return await apiRequest(c, "POST", "/storage/tables", {
2242
+ name: params.table,
2243
+ columns: params.columns,
2244
+ indexes: params.indexes,
2245
+ shared: params.shared,
2246
+ description: params.description,
2247
+ timestamps: params.timestamps
2248
+ });
2249
+ case "list_tables":
2250
+ return await apiRequest(c, "GET", `/storage/tables?includeShared=${params.includeShared !== false}&includeArchived=${params.includeArchived === true}`);
2251
+ case "describe_table":
2252
+ return await apiRequest(c, "GET", `/storage/tables/${tbl}/describe`);
2253
+ case "add_column":
2254
+ return await apiRequest(c, "POST", `/storage/tables/${tbl}/columns`, { column: params.column });
2255
+ case "drop_column":
2256
+ return await apiRequest(c, "DELETE", `/storage/tables/${tbl}/columns/${encodeURIComponent(params.columnName)}`);
2257
+ case "rename_table":
2258
+ return await apiRequest(c, "POST", `/storage/tables/${tbl}/rename`, { newName: params.newName });
2259
+ case "rename_column":
2260
+ return await apiRequest(c, "POST", `/storage/tables/${tbl}/rename-column`, { oldName: params.oldName, newName: params.newName });
2261
+ case "drop_table":
2262
+ return await apiRequest(c, "DELETE", `/storage/tables/${tbl}`);
2263
+ case "clone_table":
2264
+ return await apiRequest(c, "POST", `/storage/tables/${tbl}/clone`, { newName: params.newName, includeData: params.includeData });
2265
+ case "truncate":
2266
+ return await apiRequest(c, "POST", `/storage/tables/${tbl}/truncate`);
2267
+ // ── Index Management ──
2268
+ case "create_index":
2269
+ return await apiRequest(c, "POST", `/storage/tables/${tbl}/indexes`, {
2270
+ columns: params.indexColumns || params.columns,
2271
+ unique: params.indexUnique,
2272
+ name: params.indexName,
2273
+ where: params.indexWhere
2274
+ });
2275
+ case "list_indexes":
2276
+ return await apiRequest(c, "GET", `/storage/tables/${tbl}/indexes`);
2277
+ case "drop_index":
2278
+ return await apiRequest(c, "DELETE", `/storage/tables/${tbl}/indexes/${encodeURIComponent(params.indexName)}`);
2279
+ case "reindex":
2280
+ return await apiRequest(c, "POST", `/storage/tables/${tbl}/reindex`);
2281
+ // ── DML: Data Manipulation ──
2282
+ case "insert":
2283
+ return await apiRequest(c, "POST", "/storage/insert", { table: params.table, rows: params.rows });
2284
+ case "upsert":
2285
+ return await apiRequest(c, "POST", "/storage/upsert", { table: params.table, rows: params.rows, conflictColumn: params.conflictColumn });
2286
+ case "query":
2287
+ return await apiRequest(c, "POST", "/storage/query", {
2288
+ table: params.table,
2289
+ where: params.where,
2290
+ orderBy: params.orderBy,
2291
+ limit: params.limit,
2292
+ offset: params.offset,
2293
+ columns: params.selectColumns,
2294
+ distinct: params.distinct,
2295
+ groupBy: params.groupBy,
2296
+ having: params.having
2297
+ });
2298
+ case "aggregate":
2299
+ return await apiRequest(c, "POST", "/storage/aggregate", {
2300
+ table: params.table,
2301
+ where: params.where,
2302
+ operations: params.operations,
2303
+ groupBy: params.groupBy
2304
+ });
2305
+ case "update":
2306
+ return await apiRequest(c, "POST", "/storage/update", { table: params.table, where: params.where, set: params.set });
2307
+ case "delete_rows":
2308
+ return await apiRequest(c, "POST", "/storage/delete-rows", { table: params.table, where: params.where });
2309
+ // ── Archive & Lifecycle ──
2310
+ case "archive_table":
2311
+ return await apiRequest(c, "POST", `/storage/tables/${tbl}/archive`);
2312
+ case "unarchive_table":
2313
+ return await apiRequest(c, "POST", `/storage/tables/${tbl}/unarchive`);
2314
+ // ── Import / Export ──
2315
+ case "export":
2316
+ return await apiRequest(c, "POST", `/storage/tables/${tbl}/export`, { format: params.format, where: params.where, limit: params.limit });
2317
+ case "import":
2318
+ return await apiRequest(c, "POST", `/storage/tables/${tbl}/import`, { rows: params.rows, onConflict: params.onConflict, conflictColumn: params.conflictColumn });
2319
+ // ── Raw SQL ──
2320
+ case "sql":
2321
+ return await apiRequest(c, "POST", "/storage/sql", { sql: params.sql, params: params.params });
2322
+ case "explain":
2323
+ return await apiRequest(c, "POST", "/storage/explain", { sql: params.sql, params: params.params });
2324
+ // ── Maintenance ──
2325
+ case "stats":
2326
+ return await apiRequest(c, "GET", "/storage/stats");
2327
+ case "vacuum":
2328
+ return await apiRequest(c, "POST", "/storage/vacuum");
2329
+ case "analyze":
2330
+ return await apiRequest(c, "POST", `/storage/tables/${tbl}/analyze`);
2331
+ default:
2332
+ return { error: `Unknown action "${action}". Valid actions: create_table, list_tables, describe_table, insert, upsert, query, aggregate, update, delete_rows, truncate, drop_table, clone_table, rename_table, rename_column, add_column, drop_column, create_index, list_indexes, drop_index, reindex, archive_table, unarchive_table, export, import, sql, stats, vacuum, analyze, explain` };
2333
+ }
2334
+ } catch (err) {
2335
+ return { success: false, error: err.message };
2336
+ }
2337
+ }
2338
+ });
2191
2339
  reg("agenticmail_sms_config", {
2192
2340
  description: "Get the current SMS/phone number configuration for this agent. Shows whether SMS is enabled, the phone number, and forwarding email.",
2193
2341
  parameters: {},
package/dist/index.js CHANGED
@@ -2152,6 +2152,154 @@ The agent must have browser access and a Google Voice session (logged into Googl
2152
2152
  }
2153
2153
  }
2154
2154
  });
2155
+ reg("agenticmail_storage", {
2156
+ description: `Full database management for agents. Create/alter/drop tables, CRUD rows, manage indexes, run aggregations, import/export data, execute raw SQL, optimize & analyze \u2014 all on whatever database the user deployed (SQLite, Postgres, MySQL, Turso).
2157
+
2158
+ Tables are sandboxed per-agent (agt_ prefix) or shared (shared_ prefix). Column types: text, integer, real, boolean, json, blob, timestamp. Auto-adds id + timestamps by default.
2159
+
2160
+ WHERE filters support operators: {column: value} for equality, {column: {$gt: 5, $lt: 10}} for comparisons, {column: {$like: "%foo%"}} for pattern matching, {column: {$in: [1,2,3]}} for IN, {column: {$between: [lo, hi]}} for ranges, {column: {$is_null: true}} for null checks. Also: $gte, $lte, $ne, $ilike, $not_like, $not_in.`,
2161
+ parameters: {
2162
+ action: { type: "string", required: true, description: "create_table, list_tables, describe_table, insert, upsert, query, aggregate, update, delete_rows, truncate, drop_table, clone_table, rename_table, rename_column, add_column, drop_column, create_index, list_indexes, drop_index, reindex, archive_table, unarchive_table, export, import, sql, stats, vacuum, analyze, explain" },
2163
+ table: { type: "string", description: "Table name (display name or internal prefixed name)" },
2164
+ description: { type: "string", description: "For create_table: human-readable description" },
2165
+ columns: { type: "array", description: "For create_table: [{name, type, required?, default?, unique?, primaryKey?, references?: {table, column, onDelete?}, check?}]" },
2166
+ indexes: { type: "array", description: "For create_table/create_index: [{columns: string[], unique?: boolean, name?: string, where?: string}]" },
2167
+ shared: { type: "boolean", description: "For create_table: accessible by all agents (default: false)" },
2168
+ timestamps: { type: "boolean", description: "For create_table: auto-add created_at/updated_at (default: true)" },
2169
+ rows: { type: "array", description: "For insert/upsert/import: array of row objects" },
2170
+ where: { type: "object", description: "For query/update/delete_rows/export: filter conditions. Supports operators: {$gt, $gte, $lt, $lte, $ne, $like, $ilike, $not_like, $in, $not_in, $is_null, $between}" },
2171
+ set: { type: "object", description: "For update: {column: newValue}" },
2172
+ orderBy: { type: "string", description: "For query: ORDER BY clause" },
2173
+ limit: { type: "number", description: "For query/export: max rows" },
2174
+ offset: { type: "number", description: "For query: skip N rows" },
2175
+ selectColumns: { type: "array", description: "For query: specific columns to select" },
2176
+ distinct: { type: "boolean", description: "For query: SELECT DISTINCT" },
2177
+ groupBy: { type: "string", description: "For query/aggregate: GROUP BY clause" },
2178
+ having: { type: "string", description: "For query: HAVING clause" },
2179
+ operations: { type: "array", description: 'For aggregate: [{fn: "count"|"sum"|"avg"|"min"|"max"|"count_distinct", column?, alias?}]' },
2180
+ column: { type: "object", description: "For add_column: {name, type, required?, default?, references?, check?}" },
2181
+ columnName: { type: "string", description: "For drop_column: column name to drop" },
2182
+ indexName: { type: "string", description: "For drop_index: index name" },
2183
+ indexColumns: { type: "array", description: "For create_index: column names" },
2184
+ indexUnique: { type: "boolean", description: "For create_index: unique index" },
2185
+ indexWhere: { type: "string", description: "For create_index: partial index condition" },
2186
+ newName: { type: "string", description: "For rename_table/rename_column: new name" },
2187
+ oldName: { type: "string", description: "For rename_column: old column name" },
2188
+ conflictColumn: { type: "string", description: "For upsert/import: column to detect conflicts on" },
2189
+ onConflict: { type: "string", description: 'For import: "skip"|"replace"|"error"' },
2190
+ includeData: { type: "boolean", description: "For clone_table: include data (default: true)" },
2191
+ format: { type: "string", description: 'For export: "json"|"csv"' },
2192
+ sql: { type: "string", description: "For sql/explain: raw SQL query" },
2193
+ params: { type: "array", description: "For sql/explain: query parameters" },
2194
+ includeShared: { type: "boolean", description: "For list_tables: include shared (default: true)" },
2195
+ includeArchived: { type: "boolean", description: "For list_tables: include archived" }
2196
+ },
2197
+ handler: async (params) => {
2198
+ try {
2199
+ const c = await ctxForParams(ctx, params);
2200
+ const action = params.action;
2201
+ const tbl = params.table ? encodeURIComponent(params.table) : "";
2202
+ switch (action) {
2203
+ // ── DDL: Schema Definition ──
2204
+ case "create_table":
2205
+ return await apiRequest(c, "POST", "/storage/tables", {
2206
+ name: params.table,
2207
+ columns: params.columns,
2208
+ indexes: params.indexes,
2209
+ shared: params.shared,
2210
+ description: params.description,
2211
+ timestamps: params.timestamps
2212
+ });
2213
+ case "list_tables":
2214
+ return await apiRequest(c, "GET", `/storage/tables?includeShared=${params.includeShared !== false}&includeArchived=${params.includeArchived === true}`);
2215
+ case "describe_table":
2216
+ return await apiRequest(c, "GET", `/storage/tables/${tbl}/describe`);
2217
+ case "add_column":
2218
+ return await apiRequest(c, "POST", `/storage/tables/${tbl}/columns`, { column: params.column });
2219
+ case "drop_column":
2220
+ return await apiRequest(c, "DELETE", `/storage/tables/${tbl}/columns/${encodeURIComponent(params.columnName)}`);
2221
+ case "rename_table":
2222
+ return await apiRequest(c, "POST", `/storage/tables/${tbl}/rename`, { newName: params.newName });
2223
+ case "rename_column":
2224
+ return await apiRequest(c, "POST", `/storage/tables/${tbl}/rename-column`, { oldName: params.oldName, newName: params.newName });
2225
+ case "drop_table":
2226
+ return await apiRequest(c, "DELETE", `/storage/tables/${tbl}`);
2227
+ case "clone_table":
2228
+ return await apiRequest(c, "POST", `/storage/tables/${tbl}/clone`, { newName: params.newName, includeData: params.includeData });
2229
+ case "truncate":
2230
+ return await apiRequest(c, "POST", `/storage/tables/${tbl}/truncate`);
2231
+ // ── Index Management ──
2232
+ case "create_index":
2233
+ return await apiRequest(c, "POST", `/storage/tables/${tbl}/indexes`, {
2234
+ columns: params.indexColumns || params.columns,
2235
+ unique: params.indexUnique,
2236
+ name: params.indexName,
2237
+ where: params.indexWhere
2238
+ });
2239
+ case "list_indexes":
2240
+ return await apiRequest(c, "GET", `/storage/tables/${tbl}/indexes`);
2241
+ case "drop_index":
2242
+ return await apiRequest(c, "DELETE", `/storage/tables/${tbl}/indexes/${encodeURIComponent(params.indexName)}`);
2243
+ case "reindex":
2244
+ return await apiRequest(c, "POST", `/storage/tables/${tbl}/reindex`);
2245
+ // ── DML: Data Manipulation ──
2246
+ case "insert":
2247
+ return await apiRequest(c, "POST", "/storage/insert", { table: params.table, rows: params.rows });
2248
+ case "upsert":
2249
+ return await apiRequest(c, "POST", "/storage/upsert", { table: params.table, rows: params.rows, conflictColumn: params.conflictColumn });
2250
+ case "query":
2251
+ return await apiRequest(c, "POST", "/storage/query", {
2252
+ table: params.table,
2253
+ where: params.where,
2254
+ orderBy: params.orderBy,
2255
+ limit: params.limit,
2256
+ offset: params.offset,
2257
+ columns: params.selectColumns,
2258
+ distinct: params.distinct,
2259
+ groupBy: params.groupBy,
2260
+ having: params.having
2261
+ });
2262
+ case "aggregate":
2263
+ return await apiRequest(c, "POST", "/storage/aggregate", {
2264
+ table: params.table,
2265
+ where: params.where,
2266
+ operations: params.operations,
2267
+ groupBy: params.groupBy
2268
+ });
2269
+ case "update":
2270
+ return await apiRequest(c, "POST", "/storage/update", { table: params.table, where: params.where, set: params.set });
2271
+ case "delete_rows":
2272
+ return await apiRequest(c, "POST", "/storage/delete-rows", { table: params.table, where: params.where });
2273
+ // ── Archive & Lifecycle ──
2274
+ case "archive_table":
2275
+ return await apiRequest(c, "POST", `/storage/tables/${tbl}/archive`);
2276
+ case "unarchive_table":
2277
+ return await apiRequest(c, "POST", `/storage/tables/${tbl}/unarchive`);
2278
+ // ── Import / Export ──
2279
+ case "export":
2280
+ return await apiRequest(c, "POST", `/storage/tables/${tbl}/export`, { format: params.format, where: params.where, limit: params.limit });
2281
+ case "import":
2282
+ return await apiRequest(c, "POST", `/storage/tables/${tbl}/import`, { rows: params.rows, onConflict: params.onConflict, conflictColumn: params.conflictColumn });
2283
+ // ── Raw SQL ──
2284
+ case "sql":
2285
+ return await apiRequest(c, "POST", "/storage/sql", { sql: params.sql, params: params.params });
2286
+ case "explain":
2287
+ return await apiRequest(c, "POST", "/storage/explain", { sql: params.sql, params: params.params });
2288
+ // ── Maintenance ──
2289
+ case "stats":
2290
+ return await apiRequest(c, "GET", "/storage/stats");
2291
+ case "vacuum":
2292
+ return await apiRequest(c, "POST", "/storage/vacuum");
2293
+ case "analyze":
2294
+ return await apiRequest(c, "POST", `/storage/tables/${tbl}/analyze`);
2295
+ default:
2296
+ return { error: `Unknown action "${action}". Valid actions: create_table, list_tables, describe_table, insert, upsert, query, aggregate, update, delete_rows, truncate, drop_table, clone_table, rename_table, rename_column, add_column, drop_column, create_index, list_indexes, drop_index, reindex, archive_table, unarchive_table, export, import, sql, stats, vacuum, analyze, explain` };
2297
+ }
2298
+ } catch (err) {
2299
+ return { success: false, error: err.message };
2300
+ }
2301
+ }
2302
+ });
2155
2303
  reg("agenticmail_sms_config", {
2156
2304
  description: "Get the current SMS/phone number configuration for this agent. Shows whether SMS is enabled, the phone number, and forwarding email.",
2157
2305
  parameters: {},
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@agenticmail/openclaw",
3
- "version": "0.5.41",
4
- "description": "OpenClaw plugin for AgenticMail \u2014 email, SMS, and phone number access for OpenClaw agents",
3
+ "version": "0.5.42",
4
+ "description": "OpenClaw plugin for AgenticMail email, SMS, and phone number access for OpenClaw agents",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",
@@ -68,4 +68,4 @@
68
68
  },
69
69
  "author": "Ope Olatunji",
70
70
  "license": "MIT"
71
- }
71
+ }