promaster 1.2.0 → 1.4.0

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
@@ -2,7 +2,8 @@
2
2
 
3
3
  Interactive CLI to browse Markdown from a **public GitHub repo**, grouped into
4
4
  three categories: **blog**, **memory**, **books**. Each selected file is
5
- rendered to a styled, standalone **HTML** page click it to open in a browser.
5
+ rendered to a styled, standalone **HTML** page and opened in your browser
6
+ nothing is saved to disk.
6
7
 
7
8
  The package ships only the CLI. Your Markdown content lives in your own GitHub
8
9
  repo and is fetched at runtime — it is never bundled into npm.
@@ -33,12 +34,12 @@ promaster list
33
34
  1. Pick a category: `blog` / `memory` / `books`.
34
35
  2. Files are listed newest → oldest (by last git commit date).
35
36
  3. Toggle one or more with space, confirm with enter.
36
- 4. Each selection is converted to HTML and saved to
37
- `./promaster-data/<category>/<name>.html`.
38
- 5. The CLI then offers to open the saved file(s) in your default browser.
37
+ 4. Each selection is rendered to HTML in a temporary directory and opened in
38
+ your default browser right away.
39
+ 5. Press Enter in the CLI when you're done the temporary files are deleted.
40
+ Nothing is ever written to your project directory.
39
41
 
40
- Open any saved `.html` later by double-clicking it it renders fully offline
41
- (styles are inlined, with light/dark support).
42
+ The pages render fully offline (styles are inlined, with light/dark support).
42
43
 
43
44
  ## Configuration
44
45
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "promaster",
3
- "version": "1.2.0",
3
+ "version": "1.4.0",
4
4
  "description": "Interactive CLI to browse Markdown (blog/memory/books) from a public GitHub repo and save it as browser-ready HTML.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,8 +1,9 @@
1
- import { select, checkbox, confirm } from "@inquirer/prompts";
2
- import { resolve, dirname } from "node:path";
1
+ import { select, checkbox, input } from "@inquirer/prompts";
2
+ import { rmSync } from "node:fs";
3
+ import { rm } from "node:fs/promises";
3
4
  import { resolveRepo, CATEGORIES } from "../config.js";
4
5
  import { listMarkdown, lastCommitDate, fetchRaw, HttpError } from "../github.js";
5
- import { save, OUTPUT_ROOT } from "../download.js";
6
+ import { saveTemp } from "../download.js";
6
7
  import { openInBrowser } from "../open.js";
7
8
 
8
9
  const CONCURRENCY = 5;
@@ -54,22 +55,50 @@ export async function runList() {
54
55
  return;
55
56
  }
56
57
 
57
- const saved = [];
58
- for (const file of picked) {
59
- const content = await fetchRaw(file.download_url, ctx);
60
- saved.push(await save(category, file, content));
61
- }
58
+ // All categories open immediately, never persist — temp files deleted on exit.
59
+ await openEphemeral(picked, ctx);
60
+ }
62
61
 
63
- console.log("\nSaved (HTML click to open in a browser):");
64
- for (const p of saved) console.log(` ${p}`);
65
- console.log(`\nOutput dir: ${resolve(process.cwd(), OUTPUT_ROOT, category)}`);
62
+ // Render picks to OS temp, auto-open in the browser, then delete once the
63
+ // user is done (Enter) or aborts (Ctrl+C). Nothing is left on disk.
64
+ async function openEphemeral(picked, ctx) {
65
+ const dirs = [];
66
+ const cleanup = () => {
67
+ while (dirs.length) {
68
+ try {
69
+ rmSync(dirs.pop(), { recursive: true, force: true });
70
+ } catch {
71
+ /* best effort */
72
+ }
73
+ }
74
+ };
66
75
 
67
- const open = await confirm({
68
- message: `Open ${saved.length === 1 ? "it" : "them"} in your browser now?`,
69
- default: true,
70
- });
71
- if (open) {
72
- for (const p of saved) openInBrowser(p);
76
+ const onSigint = () => {
77
+ cleanup();
78
+ process.exit(130);
79
+ };
80
+ process.on("SIGINT", onSigint);
81
+
82
+ try {
83
+ for (const file of picked) {
84
+ const content = await fetchRaw(file.download_url, ctx);
85
+ const { path, dir } = await saveTemp(file, content);
86
+ dirs.push(dir);
87
+ openInBrowser(path);
88
+ console.log(`Opened in browser: ${file.name}`);
89
+ }
90
+
91
+ console.log("\nThese are temporary — nothing is saved to disk.");
92
+ await input({
93
+ message: `Press Enter when you're done to delete the temporary file${
94
+ picked.length === 1 ? "" : "s"
95
+ }`,
96
+ });
97
+ } finally {
98
+ process.off("SIGINT", onSigint);
99
+ for (const dir of dirs.splice(0)) {
100
+ await rm(dir, { recursive: true, force: true }).catch(() => {});
101
+ }
73
102
  }
74
103
  }
75
104
 
package/src/download.js CHANGED
@@ -1,5 +1,6 @@
1
- import { mkdir, writeFile } from "node:fs/promises";
1
+ import { mkdir, mkdtemp, writeFile } from "node:fs/promises";
2
2
  import { basename, extname, resolve } from "node:path";
3
+ import { tmpdir } from "node:os";
3
4
  import { mdToHtml } from "./render.js";
4
5
 
5
6
  export const OUTPUT_ROOT = "promaster-data";
@@ -40,3 +41,19 @@ export async function save(category, file, content) {
40
41
  await writeFile(dest, html, "utf8");
41
42
  return dest;
42
43
  }
44
+
45
+ /**
46
+ * Render markdown to HTML in a fresh OS temp directory (never under
47
+ * promaster-data). Returns { path, dir } so the caller can delete `dir`
48
+ * once the user is done viewing — nothing is persisted.
49
+ */
50
+ export async function saveTemp(file, content) {
51
+ const dir = await mkdtemp(resolve(tmpdir(), "promaster-"));
52
+ const base = safeName(file.name);
53
+ const ext = extname(base);
54
+ const title = ext ? base.slice(0, -ext.length) : base;
55
+ const html = mdToHtml(content, { title });
56
+ const path = resolve(dir, htmlName(file.name));
57
+ await writeFile(path, html, "utf8");
58
+ return { path, dir };
59
+ }