@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/bin.js +50 -164
- package/dist/bin.js.map +4 -4
- package/dist/index.js +50 -164
- package/dist/index.js.map +4 -4
- package/package.json +1 -1
package/dist/bin.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
//
|
|
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.
|
|
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
|
-
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1099
|
+
set(body, next);
|
|
1240
1100
|
index += 2;
|
|
1241
1101
|
continue;
|
|
1242
1102
|
}
|
|
1243
|
-
|
|
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
|
-
|
|
1111
|
+
set(body, next);
|
|
1252
1112
|
index += 2;
|
|
1253
1113
|
continue;
|
|
1254
1114
|
}
|
|
1255
|
-
|
|
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
|
|
1292
|
-
|
|
1293
|
-
|
|
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.
|
|
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);
|
|
@@ -2496,10 +2378,14 @@ async function agentCommand(context) {
|
|
|
2496
2378
|
};
|
|
2497
2379
|
process.on("SIGINT", stop);
|
|
2498
2380
|
process.on("SIGTERM", stop);
|
|
2381
|
+
const authorization = async () => {
|
|
2382
|
+
const held = await currentCredential(context.resolved, context.session);
|
|
2383
|
+
return held.token;
|
|
2384
|
+
};
|
|
2499
2385
|
const call = async (path, body) => fetch(`${apiUrl}/api/v1/agent/${path}`, {
|
|
2500
2386
|
method: "POST",
|
|
2501
2387
|
headers: {
|
|
2502
|
-
authorization: `Bearer ${
|
|
2388
|
+
authorization: `Bearer ${await authorization()}`,
|
|
2503
2389
|
"content-type": "application/json"
|
|
2504
2390
|
},
|
|
2505
2391
|
body: JSON.stringify(body)
|
|
@@ -2540,7 +2426,7 @@ async function agentCommand(context) {
|
|
|
2540
2426
|
const { items } = await claimed.json();
|
|
2541
2427
|
for (const request of items) {
|
|
2542
2428
|
context.print(`Reading ${request.path}`);
|
|
2543
|
-
const outcome = await answer(context, apiUrl,
|
|
2429
|
+
const outcome = await answer(context, apiUrl, await authorization(), roots, request);
|
|
2544
2430
|
const done = await call(
|
|
2545
2431
|
`complete/${encodeURIComponent(request.id)}`,
|
|
2546
2432
|
outcome.ok ? { result: { attachToken: outcome.attachToken } } : { error: outcome.error }
|