@rubar/lavish-publish-cf 0.1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Nathan Kettles
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,83 @@
1
+ # lavish-publish-cf
2
+
3
+ Self-host a Cloudflare Worker that publishes themed HTML pages on your own domain — plus the Claude Code skill that drives it.
4
+
5
+ ![Brief in, themed Cloudflare-hosted page out](explainer-image.png)
6
+
7
+ API-compatible with [htmlship.com](https://htmlship.com) (same shape, same CLI verbs), but runs on **your** Cloudflare account with **your** KV. No third party in the loop, no monthly fee, no vendor lock-in.
8
+
9
+ ```
10
+ lavish-publish-cf/
11
+ ├── worker/ ← Cloudflare Worker (src/index.ts) + Node CLI (cli/index.js)
12
+ └── skill/ ← /publish Claude Code skill
13
+ ```
14
+
15
+ ## What you get
16
+
17
+ - A **Worker** (`worker/`) that accepts `POST /api/v1/pages` and serves the resulting page at `/v/<slug>` under a strict CSP (`script-src 'none'`).
18
+ - A zero-dep **CLI** (`worker/cli/index.js`, installs as `publish-cf`) that handles publish, update, delete, list-mine, plus per-page inline comments.
19
+ - An inline **comment** UI on `/v/<slug>` — viewers select text and leave anchored comments; the owner addresses them and runs `publish-cf comments resolve <slug> <id>`.
20
+ - A **Claude Code skill** (`skill/`) that goes from "a markdown brief" / "a description" / "an existing HTML file" to a themed, published page in one command. Picks a theme from [`lavish-themes`](https://github.com/natekettles/lavish-themes), inlines the styling, calls the CLI, reports the URL.
21
+
22
+ ## Install
23
+
24
+ **Just the CLI** (talks to a worker you've already deployed, or any compatible API):
25
+
26
+ ```sh
27
+ npm install -g @rubar/lavish-publish-cf
28
+ publish-cf config set --api-base https://your-worker.workers.dev
29
+ publish-cf --help
30
+ ```
31
+
32
+ Or use it without install: `npx @rubar/lavish-publish-cf publish my-page.html`.
33
+
34
+ **Full self-host** (deploy your own Worker + KV):
35
+
36
+ ```sh
37
+ git clone https://github.com/natekettles/lavish-publish-cf.git
38
+ cd lavish-publish-cf
39
+ ./scripts/install.sh
40
+ ```
41
+
42
+ The installer walks through:
43
+
44
+ 1. `npm install` at the repo root (Wrangler + nothing else)
45
+ 2. `npx wrangler login` (interactive — opens browser)
46
+ 3. `npx wrangler kv namespace create PAGES` and patches `worker/wrangler.toml`
47
+ 4. `npm run deploy` — your worker goes live on `*.workers.dev`
48
+ 5. `npm install -g .` so `publish-cf` is on your PATH
49
+ 6. Optional: symlink `skill/` into `~/.claude/skills/publish` so Claude Code can find it
50
+
51
+ Steps that need your input pause and ask. Steps that don't, run. Re-running is safe — every step detects "already done" and skips.
52
+
53
+ After install, see [`worker/README.md`](worker/README.md) for the full Worker + CLI reference.
54
+
55
+ ## How the pieces talk to each other
56
+
57
+ ```
58
+ You ──/publish brief.md──▶ Claude Code
59
+
60
+ │ reads ~/.lavish-themes/tier{1,2}/<slug>.html
61
+ │ (from lavish-themes)
62
+
63
+ themed HTML
64
+
65
+ │ publish-cf publish report.html …
66
+
67
+ your Worker (workers.dev or custom domain)
68
+
69
+ │ KV: PAGES namespace
70
+
71
+ https://<your-worker>/v/<slug>
72
+ ```
73
+
74
+ The skill assumes `~/.lavish-themes` exists (the install location used by [`lavish-themes`](https://github.com/natekettles/lavish-themes)). If you skip themes installation, the skill will still work for HTML you supply pre-styled — it just can't pick a theme for you.
75
+
76
+ ## Related projects
77
+
78
+ - [`lavish-axi`](https://github.com/kunchenguid/lavish-axi) — local editor and review surface. `/publish loc <source>` (handled by the same skill in `skill/`) saves to `.lavish/` and opens with `lavish-axi` instead of publishing.
79
+ - [`@rubar/lavish-themes`](https://www.npmjs.com/package/@rubar/lavish-themes) — the six theme shells the skill picks from. `npm i -g @rubar/lavish-themes` to get the `lavish-themes` CLI (`list`, `path <slug>`, `copy <slug> [dest]`).
80
+
81
+ ## Licence
82
+
83
+ MIT — see [`LICENSE`](LICENSE).
Binary file
package/package.json ADDED
@@ -0,0 +1,58 @@
1
+ {
2
+ "name": "@rubar/lavish-publish-cf",
3
+ "version": "0.1.0",
4
+ "description": "CLI for the lavish-publish-cf Cloudflare Worker — publish themed HTML pages with inline comments to your own worker.",
5
+ "bin": {
6
+ "publish-cf": "worker/cli/index.js",
7
+ "lavish-publish-cf": "worker/cli/index.js"
8
+ },
9
+ "files": [
10
+ "worker/cli",
11
+ "worker/src",
12
+ "worker/wrangler.toml",
13
+ "worker/tsconfig.json",
14
+ "worker/README.md",
15
+ "worker/CLAUDE.md",
16
+ "scripts",
17
+ "skill",
18
+ "README.md",
19
+ "LICENSE",
20
+ "explainer-image.png"
21
+ ],
22
+ "scripts": {
23
+ "dev": "wrangler dev --config worker/wrangler.toml",
24
+ "deploy": "wrangler deploy --config worker/wrangler.toml",
25
+ "tail": "wrangler tail --config worker/wrangler.toml",
26
+ "types": "wrangler types --config worker/wrangler.toml"
27
+ },
28
+ "devDependencies": {
29
+ "@cloudflare/workers-types": "^4.20260101.0",
30
+ "typescript": "^5.6.0",
31
+ "wrangler": "^4.0.0"
32
+ },
33
+ "engines": {
34
+ "node": ">=18"
35
+ },
36
+ "repository": {
37
+ "type": "git",
38
+ "url": "git+https://github.com/natekettles/lavish-publish-cf.git"
39
+ },
40
+ "homepage": "https://github.com/natekettles/lavish-publish-cf#readme",
41
+ "bugs": {
42
+ "url": "https://github.com/natekettles/lavish-publish-cf/issues"
43
+ },
44
+ "keywords": [
45
+ "cloudflare",
46
+ "cloudflare-workers",
47
+ "publish",
48
+ "html",
49
+ "static-site",
50
+ "lavish",
51
+ "htmlship"
52
+ ],
53
+ "author": "Nathan Kettles",
54
+ "license": "MIT",
55
+ "publishConfig": {
56
+ "access": "public"
57
+ }
58
+ }
@@ -0,0 +1,168 @@
1
+ #!/usr/bin/env bash
2
+ # install.sh — set up the lavish-publish-cf worker + CLI + Claude Code skills.
3
+ #
4
+ # Idempotent. Each step detects "already done" and skips. Safe to re-run.
5
+ #
6
+ # Steps:
7
+ # 1. cd worker && npm install
8
+ # 2. npx wrangler login (only if not already logged in)
9
+ # 3. Create the PAGES KV namespace and patch wrangler.toml
10
+ # 4. npx wrangler deploy
11
+ # 5. npm install -g . (puts `publish-cf` on your PATH)
12
+ # 6. Optionally symlink skill/ into ~/.claude/skills/publish
13
+ #
14
+ # Env overrides:
15
+ # LAVISH_PUBLISH_CF_DIR — repo location (default: $(dirname $(dirname $(realpath $0))))
16
+ # SKIP_GLOBAL_CLI=1 — skip step 5 (the global npm install)
17
+ # SKIP_SKILLS=1 — skip step 6 (the Claude Code skill symlinks)
18
+
19
+ set -euo pipefail
20
+
21
+ REPO_DIR="${LAVISH_PUBLISH_CF_DIR:-$(cd "$(dirname "$0")/.." && pwd)}"
22
+ WORKER_DIR="$REPO_DIR/worker"
23
+ SKILL_DIR="$REPO_DIR/skill"
24
+ SKILLS_HOME="$HOME/.claude/skills"
25
+
26
+ # package.json moved to repo root in v0.1.0 — wrangler runs against worker/wrangler.toml.
27
+ PKG_DIR="$REPO_DIR"
28
+
29
+ bold() { printf "\033[1m%s\033[0m\n" "$*"; }
30
+ dim() { printf "\033[2m%s\033[0m\n" "$*"; }
31
+ warn() { printf "\033[33m%s\033[0m\n" "$*"; }
32
+ ok() { printf "\033[32m✓\033[0m %s\n" "$*"; }
33
+ err() { printf "\033[31m✗\033[0m %s\n" "$*" >&2; }
34
+
35
+ ask() {
36
+ local prompt="$1" default="${2:-Y}" reply
37
+ read -r -p "$prompt " reply
38
+ reply="${reply:-$default}"
39
+ [[ "$reply" =~ ^[Yy] ]]
40
+ }
41
+
42
+ require() {
43
+ command -v "$1" >/dev/null 2>&1 || { err "Missing dependency: $1"; exit 1; }
44
+ }
45
+
46
+ bold "lavish-publish-cf installer"
47
+ echo "Repo: $REPO_DIR"
48
+ echo
49
+
50
+ require node
51
+ require npm
52
+ require git
53
+
54
+ # ---- step 1: install worker deps -------------------------------------------
55
+ bold "Step 1: install worker dependencies"
56
+ cd "$PKG_DIR"
57
+ if [[ -d node_modules && -f node_modules/.package-lock.json ]]; then
58
+ ok "node_modules already in place — skipping"
59
+ else
60
+ npm install
61
+ ok "Installed"
62
+ fi
63
+ echo
64
+
65
+ # ---- step 2: wrangler login -------------------------------------------------
66
+ bold "Step 2: authenticate with Cloudflare"
67
+ if npx --no-install wrangler whoami >/dev/null 2>&1; then
68
+ ok "Already logged in: $(npx --no-install wrangler whoami 2>/dev/null | tail -1)"
69
+ else
70
+ warn "Wrangler needs to authenticate. A browser window will open."
71
+ if ask "Run \`npx wrangler login\` now? [Y/n]"; then
72
+ npx wrangler login
73
+ else
74
+ warn "Skipped login. Re-run this script after you've authenticated."
75
+ exit 1
76
+ fi
77
+ fi
78
+ echo
79
+
80
+ # ---- step 3: create KV namespace + patch wrangler.toml ----------------------
81
+ bold "Step 3: create the PAGES KV namespace"
82
+ WRANGLER_TOML="$WORKER_DIR/wrangler.toml"
83
+ if grep -q 'REPLACE_WITH_KV_NAMESPACE_ID' "$WRANGLER_TOML"; then
84
+ dim "Creating namespace…"
85
+ ns_output="$(npx wrangler kv namespace create PAGES 2>&1)"
86
+ ns_id="$(printf "%s" "$ns_output" | grep -oE 'id = "[a-f0-9]+"' | head -1 | sed -E 's/id = "([a-f0-9]+)"/\1/')"
87
+ if [[ -z "$ns_id" ]]; then
88
+ err "Could not parse KV namespace id from wrangler output:"
89
+ printf "%s\n" "$ns_output" >&2
90
+ exit 1
91
+ fi
92
+ # macOS sed needs the empty -i argument
93
+ if [[ "$(uname)" == "Darwin" ]]; then
94
+ sed -i '' "s/REPLACE_WITH_KV_NAMESPACE_ID/$ns_id/" "$WRANGLER_TOML"
95
+ else
96
+ sed -i "s/REPLACE_WITH_KV_NAMESPACE_ID/$ns_id/" "$WRANGLER_TOML"
97
+ fi
98
+ ok "Namespace $ns_id wired into wrangler.toml"
99
+ else
100
+ ok "wrangler.toml already has a KV namespace id — skipping"
101
+ fi
102
+ echo
103
+
104
+ # ---- step 4: deploy ---------------------------------------------------------
105
+ bold "Step 4: deploy the worker"
106
+ cd "$PKG_DIR"
107
+ if ask "Run \`npx wrangler deploy --config worker/wrangler.toml\` now? [Y/n]"; then
108
+ npx wrangler deploy --config worker/wrangler.toml
109
+ ok "Deployed"
110
+ else
111
+ warn "Skipped deploy. Run \`cd $PKG_DIR && npm run deploy\` when ready."
112
+ fi
113
+ echo
114
+
115
+ # ---- step 5: global CLI install --------------------------------------------
116
+ if [[ "${SKIP_GLOBAL_CLI:-0}" != "1" ]]; then
117
+ bold "Step 5: install the publish-cf CLI globally"
118
+ if command -v publish-cf >/dev/null 2>&1; then
119
+ ok "publish-cf already on PATH ($(command -v publish-cf))"
120
+ elif ask "Run \`npm install -g .\` from $PKG_DIR? [Y/n]"; then
121
+ cd "$PKG_DIR"
122
+ npm install -g .
123
+ ok "publish-cf installed globally"
124
+ else
125
+ dim "Skipped. You can call it directly: node $WORKER_DIR/cli/index.js …"
126
+ fi
127
+ echo
128
+ fi
129
+
130
+ # ---- step 6: skill symlink --------------------------------------------------
131
+ if [[ "${SKIP_SKILLS:-0}" != "1" ]]; then
132
+ bold "Step 6: register the /publish Claude Code skill"
133
+ if [[ -d "$SKILLS_HOME" ]]; then
134
+ link="$SKILLS_HOME/publish"
135
+ if [[ -L "$link" ]]; then
136
+ current="$(readlink "$link")"
137
+ if [[ "$current" == "$SKILL_DIR" ]]; then
138
+ ok "$link → $SKILL_DIR (already correct)"
139
+ else
140
+ warn "$link points elsewhere ($current). Re-pointing."
141
+ ln -sfn "$SKILL_DIR" "$link"
142
+ ok "$link → $SKILL_DIR (updated)"
143
+ fi
144
+ elif [[ -e "$link" ]]; then
145
+ warn "$link exists and is not a symlink. Skipping — move it manually to register the skill."
146
+ elif ask "Symlink $link → $SKILL_DIR? [Y/n]"; then
147
+ ln -s "$SKILL_DIR" "$link"
148
+ ok "$link → $SKILL_DIR"
149
+ else
150
+ dim "Skipped skill registration."
151
+ fi
152
+ else
153
+ dim "~/.claude/skills not found — install Claude Code first if you want skill discovery."
154
+ fi
155
+ echo
156
+ fi
157
+
158
+ # ---- next steps -------------------------------------------------------------
159
+ bold "What's next"
160
+ echo " publish-cf --help CLI reference"
161
+ echo " /publish cf <source> via Claude Code, after symlinking the skill"
162
+ echo " /publish loc <source> same skill, local-only with lavish-axi"
163
+ echo
164
+ bold "Related projects"
165
+ echo " lavish-themes https://github.com/natekettles/lavish-themes (themes/ library)"
166
+ echo " lavish-axi https://github.com/kunchenguid/lavish-axi (local editor)"
167
+ echo
168
+ ok "Install complete."
package/skill/SKILL.md ADDED
@@ -0,0 +1,128 @@
1
+ ---
2
+ name: publish
3
+ description: "Generate a styled HTML page from a description, file path, or URL and either open it locally in `lavish-axi` for review or publish it to a self-hosted Cloudflare worker. Use whenever the user asks for a lavish page, styled brief, runbook, mock, prototype, report, manifesto, or any HTML artifact they want to view or share. Default theme is light — never dark unless the prompt explicitly says so. Also handles `/publish list` to manage existing CF pages."
4
+ argument-hint: "[cf|loc] <source-path | url | description> | list"
5
+ user-invocable: true
6
+ ---
7
+
8
+ # publish
9
+
10
+ One skill, two modes:
11
+
12
+ - **Local** (`/publish loc <source>` or `/publish <source>` when local-ish keywords are present) — generate the HTML, save under `.lavish/`, and open it in `lavish-axi` for review. No Cloudflare involved.
13
+ - **CF** (`/publish cf <source>`) — same generate-and-save, then publish to the self-hosted Cloudflare worker. See `references/cloudflare.md`.
14
+
15
+ Pairs with `/address-comments <slug>` for the reviewer-feedback loop on CF-published pages.
16
+
17
+ If the argument is exactly `list` (or `manage` / `pages`), jump to `references/manage.md`.
18
+
19
+ ## Mode resolution
20
+
21
+ Read the first positional token of the argument:
22
+
23
+ - `loc` / `local` → **local** mode. Strip the token; treat the remainder as the source.
24
+ - `cf` / `cloudflare` / `publish` → **CF** mode. Strip the token.
25
+ - `list` / `manage` / `pages` → load `references/manage.md` and follow it.
26
+
27
+ If no mode token is present, scan the rest of the prompt for keywords (case-insensitive):
28
+
29
+ - "publish to cloudflare", "ship", "deploy", "share publicly" → CF.
30
+ - "view locally", "open in lavish", "preview", "review locally" → local.
31
+
32
+ If neither token nor keyword resolves the mode, fire `AskUserQuestion` **once** with destination as the question (Local recommended; CF as the alternative). Do **not** default silently — the whole point of asking once is to avoid accidental publishing.
33
+
34
+ ## Inputs
35
+
36
+ The argument (after stripping the mode token) is required and can be:
37
+
38
+ | Form | Example | Treatment |
39
+ | --------------------- | ---------------------------------- | ------------------------------------------------------ |
40
+ | Existing file path | `/path/to/brief.md` | Read it. Use as the source. |
41
+ | HTTP(S) URL | `https://example.com/article` | Fetch via WebFetch; on error fall back to `/crawl4ai`. |
42
+ | Prose / "describe it" | `a 1-page brief comparing X and Y` | Generate content from scratch from the description. |
43
+
44
+ If invoked with no argument at all, prompt with `AskUserQuestion` for a source — do not start generating from an empty prompt.
45
+
46
+ ## Check for a project DESIGN.md (before picking a theme)
47
+
48
+ Walk up from `cwd` (bounded by the repo root — stop at `.git`) looking for `DESIGN.md`, `design.md`, or `Design.md`. If one exists, the project's design system is the source of truth — load `references/design-md.md` and follow it. An explicit theme slug in the prompt still overrides DESIGN.md.
49
+
50
+ ## Theme inference (aggressive — ask only as a last resort)
51
+
52
+ If the prompt names a theme slug verbatim (`latex`, `terminal`, `water`, `swiss`, `handwritten`, `zine`), use it. Skip the rest of this section.
53
+
54
+ Otherwise, match the prompt against this table and pick silently:
55
+
56
+ | Prompt signal | Theme |
57
+ | ------------------------------------------------------------------------ | --------------- |
58
+ | "runbook", "postmortem", "RFC", CLI/terminal-flavored | **terminal** |
59
+ | "brief", "strategy", "decision", "memo", decisive product/strategy prose | **swiss** |
60
+ | "research", "paper", "abstract", citations, academic | **latex** |
61
+ | "manifesto", "launch", "announcement", marketing-loud | **zine** |
62
+ | "letter", "note", "personal", "journal", handwritten feel | **handwritten** |
63
+ | Generic / neutral / no signal but theme is fine | **water** |
64
+
65
+ If the prompt gives **zero** signal AND there is no DESIGN.md, fire `AskUserQuestion` once with three bucket options:
66
+
67
+ - **Recommended: Editorial** — serif and typographic (maps to `swiss`; `latex` for research-feeling pieces).
68
+ - **Utility** — neutral or technical (maps to `water`; `terminal` for runbooks/CLI).
69
+ - **Expressive** — unconventional (maps to `zine`; `handwritten` for personal notes).
70
+
71
+ All three buckets resolve to **light themes** by default. The user can override by typing a theme slug as `Other`.
72
+
73
+ ## Build the page
74
+
75
+ 1. Read the matching shell at `~/.lavish-themes/tier{1,2}/<slug>.html` (Tier 1: latex, terminal, water. Tier 2: swiss, handwritten, zine). The themes library installs there via [lavish-themes](https://github.com/natekettles/lavish-themes); if it is missing, point the user at that repo's `scripts/install.sh`.
76
+ 2. Replace the body content with the user's actual content, **keeping theme-specific markup conventions intact**.
77
+ 3. Overwrite every placeholder string (title, masthead, sample copy).
78
+
79
+ For the per-theme markup rules and the placeholder-replacement checklist, load `references/themes.md` once before authoring.
80
+
81
+ ## Save the file
82
+
83
+ - If `cwd/.lavish/` exists or `cwd` is writable, save to `<cwd>/.lavish/<kebab-slug>.html`. Create `.lavish/` if missing.
84
+ - Otherwise, save to `~/.lavish/throwaway/<YYYY-MM-DD>-<kebab-slug>.html` (create the dir if needed).
85
+ - `kebab-slug` derived from the page title — short, lowercase, alphanumeric + hyphens. Match the input file's basename when there is one.
86
+
87
+ ## Local mode — open in lavish-axi
88
+
89
+ ```bash
90
+ lavish-axi <path>
91
+ ```
92
+
93
+ That's it. The CLI starts (or reuses) the local server and opens the browser at the right session URL. Per global CLAUDE.md, observe the rendered page before reporting done — confirm it loaded, confirm the theme is light, confirm the content replaced cleanly. No Cloudflare, no public URL.
94
+
95
+ Reply to the user with:
96
+
97
+ - Local file path
98
+ - Theme used
99
+ - Any design decision worth review (one-liner, optional)
100
+
101
+ ## CF mode — publish to Cloudflare
102
+
103
+ Before publishing, load `references/cloudflare.md`. It covers:
104
+
105
+ - Opt-in keyword/flag triggers for password, comments, and expiry (all off by default)
106
+ - `publish-cf publish` command + flag mapping
107
+ - Post-publish report shape
108
+ - CSP / self-containment rules
109
+ - "When the deploy is stale" recovery
110
+
111
+ After publishing, run `open <url>` and reply with the tight summary described in the reference.
112
+
113
+ ## Trigger phrases
114
+
115
+ Match on:
116
+
117
+ - "publish this as a lavish page", "make a lavish page", "ship this as a styled page"
118
+ - "deploy this brief", "share this as a published page"
119
+ - "view this locally", "preview this in lavish", "open this in the lavish editor"
120
+ - "/publish list", "manage my published pages", "list my pages"
121
+
122
+ ## What NOT to do
123
+
124
+ - Do **not** spawn a subagent for any flow in this skill. `AskUserQuestion` renders in the main thread; subagents can't reach the user.
125
+ - Do **not** publish to CF without an explicit `cf` token or a CF keyword (or a user pick in the destination question). The default route is local.
126
+ - Do **not** publish before opening the file locally to verify it renders.
127
+ - Do **not** use markdown tables in the user-facing reply (the CLI doesn't render them). For long structured output use a `.lavish/` HTML file and `lavish-axi <file>` per global CLAUDE.md.
128
+ - Do **not** improvise a custom palette. Use the chosen theme shell as-is and only swap content. DESIGN.md is the one sanctioned override; see `references/design-md.md`.
@@ -0,0 +1,99 @@
1
+ # Cloudflare publish reference
2
+
3
+ Load when running the `cf` mode of `/publish`. Covers opt-in flags, the publish command, the post-publish report, CSP rules, and recovery when the deployed worker is stale.
4
+
5
+ ## Defaults (CF mode)
6
+
7
+ Unless the user opts in (see triggers below):
8
+
9
+ - **Comments: off** — page serves directly under strict CSP, no sidebar.
10
+ - **Password: off** — anyone with the URL can view.
11
+ - **Expiry: none** — page stays up until deleted.
12
+
13
+ ## Opt-in triggers in the prompt
14
+
15
+ Detect any of the following (case-insensitive). Strip matched tokens from the source string before treating the remainder as the source-path / URL / description.
16
+
17
+ | Dimension | Keyword triggers | Inline flag form | Effect |
18
+ | --------- | ------------------------------------------------------------------- | ---------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- |
19
+ | Password | "with password", "add password", "password on", "enable password" | `password=<value>` / `--password <value>` | Turns password on. Keyword with no value → generate one and share back. Inline value → use it; **do not** echo it back. |
20
+ | Comments | "with comments", "allow comments", "enable comments", "comments on" | `comments=on` | Turns comments on. |
21
+ | Expiry | n/a (too ambiguous in natural language) | `expires=<value>` (`1d` / `7d` / `30d` / `none`, or raw minutes) | Sets expiry. |
22
+
23
+ ## Generating passwords
24
+
25
+ When the user opted in by keyword (no value supplied), generate one with:
26
+
27
+ ```bash
28
+ openssl rand -base64 12 | tr -d '=+/' | cut -c1-12
29
+ ```
30
+
31
+ Pass it via `--password`. Then **share it back in the final reply** — the user has no other way to recover it.
32
+
33
+ The "never echo a user-supplied password" rule applies only when the user typed the password into their prompt. Generated passwords must be shared, otherwise they are useless.
34
+
35
+ ## Publish command
36
+
37
+ ```bash
38
+ publish-cf publish <path> [--password "..."] [--expires-in <minutes>] [--no-comments]
39
+ ```
40
+
41
+ Flag mapping from the resolved opt-in state:
42
+
43
+ - **Password opted in** (keyword or inline value) → `--password "<value>"`. If opted in by keyword only, generate the value first.
44
+ - **Comments not opted in** (the default) → always pass `--no-comments`. Comments opted in → omit the flag.
45
+ - **Expiry**: `1d` → `--expires-in 1440`; `7d` → `--expires-in 10080`; `30d` → `--expires-in 43200`; none → omit the flag.
46
+
47
+ After publish:
48
+
49
+ - The URL prints to stdout and auto-copies to clipboard.
50
+ - The `owner_key` and `source_path` are written to `~/.publish-cloudflare/keys.json` automatically — `/address-comments` reads `source_path` later to find the local file.
51
+
52
+ ## Open and report
53
+
54
+ ```bash
55
+ open <url>
56
+ ```
57
+
58
+ Per global CLAUDE.md, observe the page in the browser before reporting done.
59
+
60
+ Reply to the user with a tight summary:
61
+
62
+ - The URL (one line, no fluff)
63
+ - Slug
64
+ - Password (if set) — quote it so the user can copy it (only when generated by us)
65
+ - Expiry (if set) — human-readable
66
+ - Comments — on/off
67
+ - Local file path
68
+ - _Optional one-liner if you'd like to call out a design decision worth review._
69
+
70
+ ## Self-containment / CSP rules
71
+
72
+ The artifact is served under a strict CSP:
73
+
74
+ - `script-src 'none'` — inline `<script>` and external CDN scripts will not execute.
75
+ - `style-src 'self' 'unsafe-inline' https:` — inline CSS is fine, HTTPS CDN stylesheets are fine, relative paths are not.
76
+
77
+ Practical rules:
78
+
79
+ - Inline all CSS, or load it via `<link>` to a public HTTPS CDN. Both work.
80
+ - Don't reference local images or relative paths — they won't resolve on the worker.
81
+ - Every Tier 1 / Tier 2 theme shell already satisfies this.
82
+
83
+ If the artifact relies on JS to function (a chart library, an interactive widget), warn the user before publishing — it will render as a static skeleton, not as the live version.
84
+
85
+ ## When the deploy is stale
86
+
87
+ If `publish-cf publish` returns a 404 on the comments endpoint after publish, the worker is older than the comments feature:
88
+
89
+ ```bash
90
+ cd ~/.lavish-publish-cf/worker && npx wrangler deploy
91
+ ```
92
+
93
+ Then retry.
94
+
95
+ ## Related references
96
+
97
+ - `references/manage.md` — list/manage existing CF pages.
98
+ - `references/themes.md` — placeholder-replacement checklist (CSP requires sample copy be purged).
99
+ - `references/design-md.md` — when a project's DESIGN.md drives styling instead of a theme shell.
@@ -0,0 +1,56 @@
1
+ # DESIGN.md handling
2
+
3
+ Load when a project DESIGN.md was found during the walk-up step in `SKILL.md`. The project's design system wins over the six Lavish theme shells — its tokens, fonts, colors, and components are the source of truth.
4
+
5
+ ## Walk-up algorithm
6
+
7
+ From `cwd`, walk **upward** looking for any of:
8
+
9
+ - `DESIGN.md`
10
+ - `design.md`
11
+ - `Design.md`
12
+
13
+ Stop at the first hit. Bound the search by the nearest `.git` directory — don't escape the repo. `lavish-axi` and `lavish-axi design` both surface this path; you can also `grep` for it directly.
14
+
15
+ ## Override hierarchy
16
+
17
+ ```
18
+ explicit theme slug in user prompt → use that slug, ignore DESIGN.md
19
+ DESIGN.md exists → build from DESIGN.md, skip the theme picker
20
+ neither → fall through to theme inference in SKILL.md
21
+ ```
22
+
23
+ If the user explicitly names one of the six theme slugs (`latex`, `terminal`, `water`, `swiss`, `handwritten`, `zine`) in their original prompt, that overrides DESIGN.md — proceed with the named template.
24
+
25
+ ## When DESIGN.md is present and not overridden
26
+
27
+ Surface DESIGN.md as the recommended option in the style question instead of the Editorial/Utility/Expressive buckets:
28
+
29
+ ```
30
+ header: "Style"
31
+ - label: "Recommended: Use <repo>'s DESIGN.md"
32
+ description: "Build the page from the project's design system. Tokens, fonts, and components come from DESIGN.md."
33
+ - label: "Editorial"
34
+ description: "Serif and typographic Lavish theme. LaTeX or Swiss depending on content."
35
+ - label: "Utility"
36
+ description: "Neutral or technical Lavish theme. Water or Terminal depending on content."
37
+ - label: "Expressive"
38
+ description: "Unconventional Lavish theme. Handwritten or Zine depending on content."
39
+ multiSelect: false
40
+ ```
41
+
42
+ If the prompt provided **no theme signal at all**, you can skip this question and proceed directly with DESIGN.md — the walk-up itself is a strong signal that the user wants project-system styling.
43
+
44
+ ## "Build from DESIGN.md" semantics
45
+
46
+ If the user picks the DESIGN.md option (or it's used by default per above), skip the template-shell flow entirely. Build the page directly from the project's design system:
47
+
48
+ - Copy its tokens, components, and markup conventions.
49
+ - Inline the relevant CSS or load the project's stylesheet via HTTPS CDN (subject to the same CSP constraints described in `references/cloudflare.md` if publishing).
50
+ - Keep `<meta name="lavish-design" content="off">` in the head so DaisyUI isn't injected on top.
51
+
52
+ Read DESIGN.md once at the start of authoring. Treat it as opinionated and prescriptive — don't mix Lavish theme conventions in.
53
+
54
+ ## Local vs CF mode interaction
55
+
56
+ The DESIGN.md path works identically in both `loc` and `cf` modes. In CF mode, the CSP constraints in `references/cloudflare.md` still apply — inline the CSS or use an HTTPS CDN, never relative paths.