htmlhost-cli 2.11.0 โ†’ 2.12.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
@@ -174,7 +174,7 @@ htmlhost agents --no-claude # don't touch CLAUDE.md
174
174
  The same guide is at https://htmlhost.co/agents.md.
175
175
 
176
176
  ### `htmlhost list`
177
- List all your sites with titles, sizes, TTL, and expiry. Multi-page sites are marked with ๐Ÿ“„.
177
+ List all your sites with titles, sizes, TTL, and expiry. Multi-page sites are marked with ๐Ÿ“„. Sites shared with you as a collaborator follow under **Shared with you**, with their owner: `clone`, `deploy` and `versions` work on them with your own sign-in; only the owner can delete them.
178
178
 
179
179
  ### `htmlhost open <slug>`
180
180
  Open a deployed site in the default browser.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "htmlhost-cli",
3
- "version": "2.11.0",
3
+ "version": "2.12.0",
4
4
  "description": "Deploy HTML files from the terminal โ€” htmlhost.co CLI",
5
5
  "type": "module",
6
6
  "bin": {
package/src/cli.mjs CHANGED
@@ -5,7 +5,7 @@ import { bold, dim, cyan, err } from "./ui.mjs";
5
5
  import { ApiError } from "./api.mjs";
6
6
  import { startUpdateCheck, applyUpdate } from "./update.mjs";
7
7
 
8
- const VERSION = "2.11.0";
8
+ const VERSION = "2.12.0";
9
9
 
10
10
  const HELP = `
11
11
  ${bold("htmlhost")} ${dim(`v${VERSION}`)} โ€” deploy HTML from the terminal
@@ -17,11 +17,11 @@ const HELP = `
17
17
  ${cyan("htmlhost pull")} [slug] [opts] Pull remote changes to local
18
18
  ${cyan("htmlhost clone")} <slug> [dir] Clone a site to a local directory
19
19
  ${cyan("htmlhost agents")} [dir] Teach your AI coding tool htmlhost (AGENTS.md)
20
- ${cyan("htmlhost recipients")} [slug] [cmd] Manage form notification recipients
21
- ${cyan("htmlhost list")} List your sites
20
+ ${cyan("htmlhost recipients")} [slug] [cmd] Manage form notification recipients (owner)
21
+ ${cyan("htmlhost list")} List your sites and ones shared with you
22
22
  ${cyan("htmlhost versions")} [slug] List a site's published versions
23
23
  ${cyan("htmlhost rollback")} [slug] [ver] Make an earlier version live again (Pro)
24
- ${cyan("htmlhost delete")} <slug> Delete a site
24
+ ${cyan("htmlhost delete")} <slug> Delete a site (owner)
25
25
  ${cyan("htmlhost login")} Sign in (approve in your browser)
26
26
  ${cyan("htmlhost whoami")} Show current user
27
27
  ${cyan("htmlhost logout")} Remove saved token
@@ -1,5 +1,5 @@
1
1
  import { readFileSync, statSync, readdirSync, existsSync } from "node:fs";
2
- import { basename, resolve, dirname, join } from "node:path";
2
+ import { basename, resolve, dirname, join, sep } from "node:path";
3
3
  import { createInterface } from "node:readline";
4
4
  import { createHash } from "node:crypto";
5
5
  import { post } from "../api.mjs";
@@ -666,7 +666,9 @@ export function findAllFiles(baseDir, currentDir) {
666
666
  if (entry.isDirectory()) {
667
667
  results.push(...findAllFiles(baseDir, fullPath));
668
668
  } else if (entry.isFile()) {
669
- const relativePath = fullPath.slice(baseDir.length + 1);
669
+ // Always with "/": on Windows the path has "\", which would publish
670
+ // assets\logo.png, an address no browser can ask for.
671
+ const relativePath = fullPath.slice(baseDir.length + 1).split(sep).join("/");
670
672
  let size;
671
673
  try {
672
674
  size = statSync(fullPath).size;
@@ -2,7 +2,8 @@ import { get } from "../api.mjs";
2
2
  import { dim, cyan, bold, formatBytes, yellow } from "../ui.mjs";
3
3
 
4
4
  /**
5
- * htmlhost list โ€” show all sites.
5
+ * htmlhost list โ€” show all sites: your own, then the ones shared with you
6
+ * (you can clone, deploy and restore those, not delete them).
6
7
  */
7
8
  export async function list({ json = false } = {}) {
8
9
  const data = await get("/api/sites");
@@ -13,8 +14,9 @@ export async function list({ json = false } = {}) {
13
14
  }
14
15
 
15
16
  const sites = data.sites || [];
17
+ const shared = data.shared || [];
16
18
 
17
- if (sites.length === 0) {
19
+ if (sites.length === 0 && shared.length === 0) {
18
20
  console.log("");
19
21
  console.log(` ${dim("No sites yet.")} Deploy one with: ${cyan("htmlhost deploy index.html")}`);
20
22
  console.log("");
@@ -48,6 +50,17 @@ export async function list({ json = false } = {}) {
48
50
  );
49
51
  }
50
52
 
53
+ if (shared.length) {
54
+ const sharedSlugW = Math.max(14, ...shared.map((s) => s.slug.length)) + 2;
55
+ console.log("");
56
+ console.log(` ${bold("Shared with you")} ${dim("(clone, deploy and restore; only the owner can delete)")}`);
57
+ console.log(` ${dim(pad("SLUG", sharedSlugW) + pad("TITLE", 30) + "OWNER")}`);
58
+ for (const s of shared) {
59
+ const title = truncate(s.title && s.title !== s.slug ? s.title : "", 28);
60
+ console.log(` ${pad(cyan(s.slug), sharedSlugW)}${pad(dim(title), 30)}${dim(s.owner || "")}`);
61
+ }
62
+ }
63
+
51
64
  console.log("");
52
65
  console.log(
53
66
  ` ${bold(String(sites.length))} sites ยท ${formatBytes(data.usage.totalBytes)} used` +