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