@persistmemory/cli 0.2.0 → 0.2.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 +90 -20
- package/dist/bin.js.map +3 -3
- package/dist/index.js +90 -20
- package/dist/index.js.map +3 -3
- package/package.json +1 -1
package/dist/bin.js
CHANGED
|
@@ -1527,7 +1527,7 @@ function shortDate(iso) {
|
|
|
1527
1527
|
}
|
|
1528
1528
|
|
|
1529
1529
|
// src/help.ts
|
|
1530
|
-
var VERSION = "0.
|
|
1530
|
+
var VERSION = true ? "0.2.2" : versionFromManifest();
|
|
1531
1531
|
var PACKAGE = "@persistmemory/cli";
|
|
1532
1532
|
var HELP = `
|
|
1533
1533
|
pm \u2014 PersistMemory from your terminal
|
|
@@ -1746,7 +1746,17 @@ async function startLoopback(options = {}) {
|
|
|
1746
1746
|
// This page is one-use and holds a result; nothing should keep it.
|
|
1747
1747
|
"cache-control": "no-store",
|
|
1748
1748
|
// It never loads anything, so it is not allowed to.
|
|
1749
|
-
"content-security-policy": "default-src 'none'; style-src 'unsafe-inline'"
|
|
1749
|
+
"content-security-policy": "default-src 'none'; style-src 'unsafe-inline'",
|
|
1750
|
+
/*
|
|
1751
|
+
Not kept alive, because a kept socket keeps the PROCESS alive.
|
|
1752
|
+
|
|
1753
|
+
`server.close()` stops new connections and leaves established ones
|
|
1754
|
+
open, and a browser holds this one open by default — so `pm auth login`
|
|
1755
|
+
printed "Signed in" and then sat there until somebody pressed Ctrl+C.
|
|
1756
|
+
The page is the last thing this server ever serves; there is nothing to
|
|
1757
|
+
reuse the connection for.
|
|
1758
|
+
*/
|
|
1759
|
+
connection: "close"
|
|
1750
1760
|
});
|
|
1751
1761
|
response.end(donePage(callback));
|
|
1752
1762
|
resolveCallback?.(callback);
|
|
@@ -1778,7 +1788,9 @@ async function startLoopback(options = {}) {
|
|
|
1778
1788
|
},
|
|
1779
1789
|
close() {
|
|
1780
1790
|
clearTimeout(timer);
|
|
1791
|
+
server.closeAllConnections?.();
|
|
1781
1792
|
server.close();
|
|
1793
|
+
server.unref();
|
|
1782
1794
|
}
|
|
1783
1795
|
};
|
|
1784
1796
|
}
|
|
@@ -2064,7 +2076,7 @@ async function clientFor(resolved, deps) {
|
|
|
2064
2076
|
});
|
|
2065
2077
|
}
|
|
2066
2078
|
async function currentCredential(resolved, deps) {
|
|
2067
|
-
const credential = resolved.credential;
|
|
2079
|
+
const credential = resolved.fromEnvironment ? resolved.credential : readCredentials(deps.paths)[resolved.profile] ?? resolved.credential;
|
|
2068
2080
|
if (!credential) throw new NotSignedIn();
|
|
2069
2081
|
if (!isExpired(credential, deps.now?.() ?? Date.now())) return credential;
|
|
2070
2082
|
if (!credential.refreshToken || !resolved.clientId) {
|
|
@@ -2159,8 +2171,8 @@ async function readStdin() {
|
|
|
2159
2171
|
// src/commands/agent.ts
|
|
2160
2172
|
import { hostname } from "node:os";
|
|
2161
2173
|
import { homedir as homedir2 } from "node:os";
|
|
2162
|
-
import { join as join4, resolve as resolve3 } from "node:path";
|
|
2163
|
-
import { readFileSync as readFileSync4, readdirSync, statSync as statSync2 } from "node:fs";
|
|
2174
|
+
import { basename, join as join4, resolve as resolve3 } from "node:path";
|
|
2175
|
+
import { existsSync as existsSync4, readFileSync as readFileSync4, readdirSync, statSync as statSync2, writeFileSync as writeFileSync4 } from "node:fs";
|
|
2164
2176
|
|
|
2165
2177
|
// src/files.ts
|
|
2166
2178
|
import { existsSync as existsSync3, readFileSync as readFileSync3, realpathSync, statSync, writeFileSync as writeFileSync3 } from "node:fs";
|
|
@@ -2285,6 +2297,17 @@ function locate(roots, requested) {
|
|
|
2285
2297
|
}
|
|
2286
2298
|
throw new Error(`${requested} is not inside any allowed folder (${roots.join(", ")})`);
|
|
2287
2299
|
}
|
|
2300
|
+
function uncontested(target) {
|
|
2301
|
+
if (!existsSync4(target)) return target;
|
|
2302
|
+
const dot = target.lastIndexOf(".");
|
|
2303
|
+
const stem = dot > target.lastIndexOf("/") && dot !== -1 ? target.slice(0, dot) : target;
|
|
2304
|
+
const extension = stem === target ? "" : target.slice(dot);
|
|
2305
|
+
for (let n = 1; n < 1e3; n += 1) {
|
|
2306
|
+
const candidate = `${stem} (${n})${extension}`;
|
|
2307
|
+
if (!existsSync4(candidate)) return candidate;
|
|
2308
|
+
}
|
|
2309
|
+
throw new Error(`${target} and a thousand names beside it are taken.`);
|
|
2310
|
+
}
|
|
2288
2311
|
async function answer(context, apiUrl, token, roots, request) {
|
|
2289
2312
|
let located;
|
|
2290
2313
|
try {
|
|
@@ -2292,6 +2315,43 @@ async function answer(context, apiUrl, token, roots, request) {
|
|
|
2292
2315
|
} catch (error) {
|
|
2293
2316
|
return { ok: false, error: error instanceof Error ? error.message : "refused" };
|
|
2294
2317
|
}
|
|
2318
|
+
if (request.kind === "write_file") {
|
|
2319
|
+
if (!request.sourceUrl) return { ok: false, error: "There was nothing to write." };
|
|
2320
|
+
let downloaded;
|
|
2321
|
+
let fetched;
|
|
2322
|
+
try {
|
|
2323
|
+
fetched = await fetch(request.sourceUrl);
|
|
2324
|
+
if (!fetched.ok) {
|
|
2325
|
+
return { ok: false, error: await said(fetched, "The file could not be fetched") };
|
|
2326
|
+
}
|
|
2327
|
+
downloaded = Buffer.from(await fetched.arrayBuffer());
|
|
2328
|
+
} catch {
|
|
2329
|
+
return { ok: false, error: "The file could not be fetched from the service." };
|
|
2330
|
+
}
|
|
2331
|
+
try {
|
|
2332
|
+
let target = located;
|
|
2333
|
+
if (existsSync4(located) && statSync2(located).isDirectory()) {
|
|
2334
|
+
const disposition = fetched.headers.get("content-disposition") ?? "";
|
|
2335
|
+
const named = /filename="([^"]+)"/.exec(disposition)?.[1];
|
|
2336
|
+
target = join4(located, basename(named ?? "file"));
|
|
2337
|
+
}
|
|
2338
|
+
target = uncontested(target);
|
|
2339
|
+
writeFileSync4(target, downloaded, { flag: "wx" });
|
|
2340
|
+
return upload(
|
|
2341
|
+
apiUrl,
|
|
2342
|
+
token,
|
|
2343
|
+
"written.txt",
|
|
2344
|
+
Buffer.from(`Saved to ${target}
|
|
2345
|
+
${downloaded.length} bytes
|
|
2346
|
+
`, "utf8")
|
|
2347
|
+
);
|
|
2348
|
+
} catch (error) {
|
|
2349
|
+
return {
|
|
2350
|
+
ok: false,
|
|
2351
|
+
error: error instanceof Error ? error.message : "could not write it"
|
|
2352
|
+
};
|
|
2353
|
+
}
|
|
2354
|
+
}
|
|
2295
2355
|
let bytes;
|
|
2296
2356
|
let filename = request.path.split("/").pop() ?? "file";
|
|
2297
2357
|
if (request.kind === "list_dir") {
|
|
@@ -2477,8 +2537,8 @@ async function agentCommand(context) {
|
|
|
2477
2537
|
}
|
|
2478
2538
|
|
|
2479
2539
|
// src/commands/google.ts
|
|
2480
|
-
import { writeFileSync as
|
|
2481
|
-
import { basename, resolve as resolve4 } from "node:path";
|
|
2540
|
+
import { writeFileSync as writeFileSync5 } from "node:fs";
|
|
2541
|
+
import { basename as basename2, resolve as resolve4 } from "node:path";
|
|
2482
2542
|
import { readFileSync as readFileSync5 } from "node:fs";
|
|
2483
2543
|
async function callApi(context, path, init = {}) {
|
|
2484
2544
|
const credential = context.resolved.credential;
|
|
@@ -2544,8 +2604,8 @@ async function driveGet(context, fileId) {
|
|
|
2544
2604
|
const disposition = response.headers.get("content-disposition") ?? "";
|
|
2545
2605
|
const named = /filename="([^"]+)"/.exec(disposition)?.[1];
|
|
2546
2606
|
const out = stringFlag(context.args, "out");
|
|
2547
|
-
const target = resolve4(out ??
|
|
2548
|
-
|
|
2607
|
+
const target = resolve4(out ?? basename2(named ?? fileId));
|
|
2608
|
+
writeFileSync5(target, Buffer.from(await response.arrayBuffer()));
|
|
2549
2609
|
context.print(target);
|
|
2550
2610
|
return 0;
|
|
2551
2611
|
}
|
|
@@ -2561,7 +2621,7 @@ async function drivePut(context, path) {
|
|
|
2561
2621
|
context.error(`Cannot read ${path}.`);
|
|
2562
2622
|
return 1;
|
|
2563
2623
|
}
|
|
2564
|
-
const name = stringFlag(context.args, "name") ??
|
|
2624
|
+
const name = stringFlag(context.args, "name") ?? basename2(path);
|
|
2565
2625
|
const response = await callApi(
|
|
2566
2626
|
context,
|
|
2567
2627
|
`/api/v1/google/drive/files?name=${encodeURIComponent(name)}`,
|
|
@@ -2640,7 +2700,7 @@ async function mailCommand(context) {
|
|
|
2640
2700
|
}
|
|
2641
2701
|
|
|
2642
2702
|
// src/commands/requests.ts
|
|
2643
|
-
import { existsSync as
|
|
2703
|
+
import { existsSync as existsSync5, writeFileSync as writeFileSync6 } from "node:fs";
|
|
2644
2704
|
import { resolve as resolve5 } from "node:path";
|
|
2645
2705
|
async function requestsCommand(context) {
|
|
2646
2706
|
if (context.args.words[1] === "get") return collectCommand(context);
|
|
@@ -2710,24 +2770,24 @@ async function collectCommand(context) {
|
|
|
2710
2770
|
}
|
|
2711
2771
|
const name = stringFlag(context.args, "output", "o") ?? filename;
|
|
2712
2772
|
const target = resolve5(name);
|
|
2713
|
-
if (
|
|
2773
|
+
if (existsSync5(target)) {
|
|
2714
2774
|
context.error(`${target} already exists. Pass --output to write somewhere else.`);
|
|
2715
2775
|
return 1;
|
|
2716
2776
|
}
|
|
2717
|
-
|
|
2777
|
+
writeFileSync6(target, new Uint8Array(await file.arrayBuffer()));
|
|
2718
2778
|
context.print(`Wrote ${target}`);
|
|
2719
2779
|
return 0;
|
|
2720
2780
|
}
|
|
2721
2781
|
|
|
2722
2782
|
// src/workspace.ts
|
|
2723
|
-
import { existsSync as
|
|
2783
|
+
import { existsSync as existsSync6, readFileSync as readFileSync6, writeFileSync as writeFileSync7 } from "node:fs";
|
|
2724
2784
|
import { dirname as dirname3, join as join5, resolve as resolvePath } from "node:path";
|
|
2725
2785
|
var WORKSPACE_FILE = ".persistmemory.json";
|
|
2726
2786
|
function findWorkspace(from = process.cwd()) {
|
|
2727
2787
|
let dir = resolvePath(from);
|
|
2728
2788
|
for (; ; ) {
|
|
2729
2789
|
const file = join5(dir, WORKSPACE_FILE);
|
|
2730
|
-
if (
|
|
2790
|
+
if (existsSync6(file)) {
|
|
2731
2791
|
const config = readWorkspace(file);
|
|
2732
2792
|
if (config) return { file, dir, config };
|
|
2733
2793
|
}
|
|
@@ -2750,7 +2810,7 @@ function readWorkspace(file) {
|
|
|
2750
2810
|
}
|
|
2751
2811
|
function writeWorkspace(dir, config) {
|
|
2752
2812
|
const file = join5(dir, WORKSPACE_FILE);
|
|
2753
|
-
|
|
2813
|
+
writeFileSync7(file, `${JSON.stringify(config, null, 2)}
|
|
2754
2814
|
`, "utf8");
|
|
2755
2815
|
return file;
|
|
2756
2816
|
}
|
|
@@ -3019,7 +3079,7 @@ function message(error) {
|
|
|
3019
3079
|
}
|
|
3020
3080
|
|
|
3021
3081
|
// src/commands/maintain.ts
|
|
3022
|
-
import { existsSync as
|
|
3082
|
+
import { existsSync as existsSync7, rmSync } from "node:fs";
|
|
3023
3083
|
import { spawnSync } from "node:child_process";
|
|
3024
3084
|
import { dirname as dirname4, resolve as resolve7 } from "node:path";
|
|
3025
3085
|
import { fileURLToPath } from "node:url";
|
|
@@ -3063,7 +3123,7 @@ Delete the file it runs from: ${processPath()}`
|
|
|
3063
3123
|
return 0;
|
|
3064
3124
|
}
|
|
3065
3125
|
async function deleteCommand(context) {
|
|
3066
|
-
if (!
|
|
3126
|
+
if (!existsSync7(context.paths.dir)) {
|
|
3067
3127
|
context.print(`Nothing to delete: ${context.paths.dir} does not exist.`);
|
|
3068
3128
|
return 0;
|
|
3069
3129
|
}
|
|
@@ -3116,7 +3176,7 @@ import { randomUUID } from "node:crypto";
|
|
|
3116
3176
|
import { relative as relative2 } from "node:path";
|
|
3117
3177
|
|
|
3118
3178
|
// src/events.ts
|
|
3119
|
-
import { appendFileSync, existsSync as
|
|
3179
|
+
import { appendFileSync, existsSync as existsSync8, mkdirSync as mkdirSync3, readFileSync as readFileSync7 } from "node:fs";
|
|
3120
3180
|
import { join as join6 } from "node:path";
|
|
3121
3181
|
function openSessionLog(paths, id) {
|
|
3122
3182
|
const directory = join6(paths.dir, "sessions");
|
|
@@ -3133,7 +3193,7 @@ function openSessionLog(paths, id) {
|
|
|
3133
3193
|
}
|
|
3134
3194
|
},
|
|
3135
3195
|
read() {
|
|
3136
|
-
if (!
|
|
3196
|
+
if (!existsSync8(path)) return [];
|
|
3137
3197
|
return readFileSync7(path, "utf8").split("\n").filter((line) => line.trim() !== "").flatMap((line) => {
|
|
3138
3198
|
try {
|
|
3139
3199
|
return [JSON.parse(line)];
|
|
@@ -3749,6 +3809,16 @@ async function dispatch(context) {
|
|
|
3749
3809
|
case "setup":
|
|
3750
3810
|
case "init":
|
|
3751
3811
|
return setupCommand(context);
|
|
3812
|
+
/*
|
|
3813
|
+
`pm version` as well as `--version`.
|
|
3814
|
+
|
|
3815
|
+
It is what people type, and answering "Unknown command" to somebody
|
|
3816
|
+
asking which version they are running — while a flag two characters away
|
|
3817
|
+
answers it — is a needless dead end.
|
|
3818
|
+
*/
|
|
3819
|
+
case "version":
|
|
3820
|
+
context.print(VERSION);
|
|
3821
|
+
return 0;
|
|
3752
3822
|
case "update":
|
|
3753
3823
|
case "upgrade":
|
|
3754
3824
|
return updateCommand(context);
|