@persistmemory/cli 0.3.1 → 0.3.2

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/bin.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- // ../sdk-js/dist/index.js
3
+ // node_modules/@persistmemory/sdk/dist/index.js
4
4
  function encodeQuery(params) {
5
5
  if (!params) return "";
6
6
  const search = new URLSearchParams();
@@ -234,27 +234,6 @@ var HttpClient = class {
234
234
  ...options ? { options } : {}
235
235
  });
236
236
  }
237
- /** POST with a file as the body. The type describes the bytes, not JSON. */
238
- async postBytes(path, bytes, contentType, query, options) {
239
- return this.#request({
240
- method: "POST",
241
- path,
242
- rawBody: bytes,
243
- contentType,
244
- ...query ? { query } : {},
245
- ...options ? { options } : {}
246
- });
247
- }
248
- /** GET that returns bytes rather than JSON, for downloading a file. */
249
- async getBytes(path, query, options) {
250
- return this.#request({
251
- method: "GET",
252
- path,
253
- rawResponse: true,
254
- ...query ? { query } : {},
255
- ...options ? { options } : {}
256
- });
257
- }
258
237
  async patch(path, body, options) {
259
238
  return this.#request({
260
239
  method: "PATCH",
@@ -307,20 +286,11 @@ var HttpClient = class {
307
286
  this.#fetch(url, {
308
287
  method: request.method,
309
288
  headers: this.#headers(request),
310
- ...request.rawBody !== void 0 ? { body: request.rawBody } : request.body !== void 0 ? { body: JSON.stringify(request.body) } : {},
289
+ ...request.body !== void 0 ? { body: JSON.stringify(request.body) } : {},
311
290
  signal: deadline.signal
312
291
  }),
313
292
  deadline.signal
314
293
  );
315
- if (request.rawResponse && response.ok) {
316
- const disposition = response.headers.get("content-disposition") ?? "";
317
- const named = /filename="([^"]+)"/.exec(disposition)?.[1];
318
- return {
319
- bytes: new Uint8Array(await response.arrayBuffer()),
320
- contentType: response.headers.get("content-type") ?? "application/octet-stream",
321
- ...named ? { filename: named } : {}
322
- };
323
- }
324
294
  const payload = await readBody(response);
325
295
  if (!response.ok) throw errorFromResponse(response.status, payload, response.headers);
326
296
  return payload;
@@ -341,11 +311,9 @@ var HttpClient = class {
341
311
  return {
342
312
  // The only place the key is ever read.
343
313
  authorization: `Bearer ${this.#apiKey}`,
344
- // A download route answers with the file's own type, so `*/*` rather
345
- // than a promise to accept only JSON that the server would have to break.
346
- accept: request.rawResponse ? "*/*" : "application/json",
314
+ accept: "application/json",
347
315
  "user-agent": this.#userAgent,
348
- ...request.rawBody !== void 0 ? { "content-type": request.contentType ?? "application/octet-stream" } : request.body !== void 0 ? { "content-type": "application/json" } : {},
316
+ ...request.body !== void 0 ? { "content-type": "application/json" } : {},
349
317
  ...request.options?.idempotencyKey ? { "idempotency-key": request.options.idempotencyKey } : {}
350
318
  };
351
319
  }
@@ -922,119 +890,6 @@ var Conversations = class {
922
890
  );
923
891
  }
924
892
  };
925
- var Google = class {
926
- #http;
927
- constructor(http) {
928
- this.#http = http;
929
- }
930
- /** Files by name, newest first. Omit the query for recently changed ones. */
931
- async searchDrive(params = {}, options) {
932
- return this.#http.get(
933
- "/api/v1/google/drive/files",
934
- {
935
- ...params.query !== void 0 ? { query: params.query } : {},
936
- ...params.limit !== void 0 ? { limit: params.limit } : {}
937
- },
938
- options
939
- );
940
- }
941
- async getDriveFile(fileId, options) {
942
- return this.#http.get(
943
- `/api/v1/google/drive/files/${encodeURIComponent(fileId)}`,
944
- void 0,
945
- options
946
- );
947
- }
948
- /**
949
- * The bytes of a Drive file.
950
- *
951
- * A Google Doc, Sheet or Slide holds no bytes of its own and is exported on
952
- * the way - a document as PDF, a spreadsheet as CSV - so `filename` comes
953
- * back describing what it BECAME. Writing it under the id instead produces a
954
- * file nothing will open.
955
- */
956
- async downloadDriveFile(fileId, options) {
957
- return this.#http.getBytes(
958
- `/api/v1/google/drive/files/${encodeURIComponent(fileId)}/content`,
959
- void 0,
960
- options
961
- );
962
- }
963
- /**
964
- * Writes a file into the user's Drive.
965
- *
966
- * Needs one of the Drive write permissions on their connection. A read-only
967
- * grant is refused by Google, and the error names the missing permission
968
- * rather than reporting a failed upload - one is fixed with a checkbox and
969
- * the other sends somebody looking for a bug.
970
- */
971
- async saveToDrive(params, options) {
972
- return this.#http.postBytes(
973
- "/api/v1/google/drive/files",
974
- params.bytes,
975
- params.contentType ?? "application/octet-stream",
976
- {
977
- name: params.name,
978
- ...params.folderId !== void 0 ? { folderId: params.folderId } : {}
979
- },
980
- options
981
- );
982
- }
983
- /**
984
- * Recent messages - senders, subjects and a one-line preview, never bodies.
985
- *
986
- * `query` is Gmail's own syntax passed through as written: `from:priya`,
987
- * `has:attachment`, `newer_than:7d`. It selects within the connected mailbox
988
- * and cannot reach another one.
989
- */
990
- async searchMail(params = {}, options) {
991
- return this.#http.get(
992
- "/api/v1/google/mail",
993
- {
994
- ...params.query !== void 0 ? { query: params.query } : {},
995
- ...params.limit !== void 0 ? { limit: params.limit } : {}
996
- },
997
- options
998
- );
999
- }
1000
- /** One message, with its body and the names of what is attached. */
1001
- async readMail(messageId, options) {
1002
- return this.#http.get(
1003
- `/api/v1/google/mail/${encodeURIComponent(messageId)}`,
1004
- void 0,
1005
- options
1006
- );
1007
- }
1008
- /**
1009
- * The bytes of one attachment.
1010
- *
1011
- * Separate from `readMail` so listing a mailbox never drags attachments
1012
- * across the network: a message with a 40 MB deck should not cost 40 MB to
1013
- * summarise.
1014
- */
1015
- async downloadAttachment(messageId, attachmentId, options) {
1016
- return this.#http.getBytes(
1017
- `/api/v1/google/mail/${encodeURIComponent(messageId)}/attachments/${encodeURIComponent(attachmentId)}`,
1018
- void 0,
1019
- options
1020
- );
1021
- }
1022
- /** Sends as the connected account. Needs the send permission. */
1023
- async sendMail(params, options) {
1024
- return this.#http.post("/api/v1/google/mail/send", params, options);
1025
- }
1026
- /** People in the user's contacts. Omit the query to list them. */
1027
- async contacts(params = {}, options) {
1028
- return this.#http.get(
1029
- "/api/v1/google/contacts",
1030
- {
1031
- ...params.query !== void 0 ? { query: params.query } : {},
1032
- ...params.limit !== void 0 ? { limit: params.limit } : {}
1033
- },
1034
- options
1035
- );
1036
- }
1037
- };
1038
893
  var Integrations = class {
1039
894
  #http;
1040
895
  constructor(http) {
@@ -1165,8 +1020,6 @@ var PersistMemory = class {
1165
1020
  conflicts;
1166
1021
  conversations;
1167
1022
  integrations;
1168
- /** Drive, mail and contacts on the user's connected Google account. */
1169
- google;
1170
1023
  health;
1171
1024
  agent;
1172
1025
  #http;
@@ -1183,7 +1036,6 @@ var PersistMemory = class {
1183
1036
  this.conflicts = new Conflicts(this.#http);
1184
1037
  this.conversations = new Conversations(this.#http);
1185
1038
  this.integrations = new Integrations(this.#http);
1186
- this.google = new Google(this.#http);
1187
1039
  this.health = new Health(this.#http);
1188
1040
  this.agent = new Agent(this.#http);
1189
1041
  }
@@ -1214,6 +1066,14 @@ function parseArgs(argv) {
1214
1066
  const words = [];
1215
1067
  const flags = {};
1216
1068
  const rest = [];
1069
+ const set = (name, value) => {
1070
+ const held = flags[name];
1071
+ if (typeof value === "boolean" || held === void 0 || typeof held === "boolean") {
1072
+ flags[name] = value;
1073
+ return;
1074
+ }
1075
+ flags[name] = typeof held === "string" ? [held, value] : [...held, value];
1076
+ };
1217
1077
  let index = 0;
1218
1078
  while (index < argv.length) {
1219
1079
  const token = argv[index];
@@ -1225,22 +1085,22 @@ function parseArgs(argv) {
1225
1085
  const body = token.slice(2);
1226
1086
  const equals = body.indexOf("=");
1227
1087
  if (equals !== -1) {
1228
- flags[body.slice(0, equals)] = body.slice(equals + 1);
1088
+ set(body.slice(0, equals), body.slice(equals + 1));
1229
1089
  index += 1;
1230
1090
  continue;
1231
1091
  }
1232
1092
  if (body.startsWith("no-")) {
1233
- flags[body.slice(3)] = false;
1093
+ set(body.slice(3), false);
1234
1094
  index += 1;
1235
1095
  continue;
1236
1096
  }
1237
1097
  const next = argv[index + 1];
1238
1098
  if (next !== void 0 && !next.startsWith("-")) {
1239
- flags[body] = next;
1099
+ set(body, next);
1240
1100
  index += 2;
1241
1101
  continue;
1242
1102
  }
1243
- flags[body] = true;
1103
+ set(body, true);
1244
1104
  index += 1;
1245
1105
  continue;
1246
1106
  }
@@ -1248,11 +1108,11 @@ function parseArgs(argv) {
1248
1108
  const body = token.slice(1);
1249
1109
  const next = argv[index + 1];
1250
1110
  if (next !== void 0 && !next.startsWith("-")) {
1251
- flags[body] = next;
1111
+ set(body, next);
1252
1112
  index += 2;
1253
1113
  continue;
1254
1114
  }
1255
- flags[body] = true;
1115
+ set(body, true);
1256
1116
  index += 1;
1257
1117
  continue;
1258
1118
  }
@@ -1265,12 +1125,14 @@ function stringFlag(args, ...names) {
1265
1125
  for (const name of names) {
1266
1126
  const value = args.flags[name];
1267
1127
  if (typeof value === "string") return value;
1128
+ if (Array.isArray(value) && value.length > 0) return value[value.length - 1];
1268
1129
  }
1269
1130
  return void 0;
1270
1131
  }
1271
1132
  function boolFlag(args, ...names) {
1272
1133
  for (const name of names) {
1273
1134
  const value = args.flags[name];
1135
+ if (Array.isArray(value)) continue;
1274
1136
  if (typeof value === "boolean") return value;
1275
1137
  if (value === "true") return true;
1276
1138
  if (value === "false") return false;
@@ -1281,6 +1143,13 @@ function numberFlag(args, ...names) {
1281
1143
  for (const name of names) {
1282
1144
  const value = args.flags[name];
1283
1145
  if (value === void 0 || typeof value === "boolean") continue;
1146
+ if (Array.isArray(value)) {
1147
+ const last = value[value.length - 1];
1148
+ if (last === void 0) continue;
1149
+ const parsed2 = Number(last);
1150
+ if (!Number.isFinite(parsed2)) return "invalid";
1151
+ return parsed2;
1152
+ }
1284
1153
  const parsed = Number(value);
1285
1154
  if (!Number.isFinite(parsed)) return "invalid";
1286
1155
  return parsed;
@@ -1288,9 +1157,17 @@ function numberFlag(args, ...names) {
1288
1157
  return void 0;
1289
1158
  }
1290
1159
  function listFlag(args, ...names) {
1291
- const raw = stringFlag(args, ...names);
1292
- if (raw === void 0) return void 0;
1293
- const items = raw.split(",").map((one) => one.trim()).filter((one) => one.length > 0);
1160
+ const items = [];
1161
+ for (const name of names) {
1162
+ const value = args.flags[name];
1163
+ if (value === void 0 || typeof value === "boolean") continue;
1164
+ for (const one of Array.isArray(value) ? value : [value]) {
1165
+ for (const part of one.split(",")) {
1166
+ const trimmed = part.trim();
1167
+ if (trimmed.length > 0) items.push(trimmed);
1168
+ }
1169
+ }
1170
+ }
1294
1171
  return items.length > 0 ? items : void 0;
1295
1172
  }
1296
1173
 
@@ -1527,7 +1404,7 @@ function shortDate(iso) {
1527
1404
  }
1528
1405
 
1529
1406
  // src/help.ts
1530
- var VERSION = true ? "0.3.1" : versionFromManifest();
1407
+ var VERSION = true ? "0.3.2" : versionFromManifest();
1531
1408
  var PACKAGE = "@persistmemory/cli";
1532
1409
  var HELP = `
1533
1410
  pm \u2014 PersistMemory from your terminal
@@ -2305,6 +2182,11 @@ async function said(response, fallback) {
2305
2182
  }
2306
2183
  function locate(roots, requested) {
2307
2184
  const expanded = requested.startsWith("~") ? resolve3(homedir2(), requested.slice(1).replace(/^[/\\]/, "")) : requested;
2185
+ if (!expanded.includes("/") && !expanded.includes("\\")) {
2186
+ const wanted2 = expanded.trim().toLowerCase();
2187
+ const named = roots.find((root) => basename(root).toLowerCase() === wanted2);
2188
+ if (named) return within(named, named);
2189
+ }
2308
2190
  for (const root of roots) {
2309
2191
  try {
2310
2192
  return within(root, expanded);