pagecast 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/.codex/skills/publish-report/SKILL.md +140 -0
- package/.codex/skills/publish-report/agents/openai.yaml +7 -0
- package/LICENSE +21 -0
- package/README.md +318 -0
- package/llms.txt +50 -0
- package/package.json +51 -0
- package/plugin/.claude-plugin/plugin.json +10 -0
- package/plugin/README.md +99 -0
- package/plugin/hooks/detect-report.mjs +109 -0
- package/plugin/hooks/hooks.json +16 -0
- package/plugin/skills/publish-report/SKILL.md +117 -0
- package/public/assets/code-mirror-html-CwFouvGT.js +24 -0
- package/public/assets/dnd-vendor-BtfBOykZ.js +1 -0
- package/public/assets/index-BTCh8CIt.js +54 -0
- package/public/assets/index-XOrnLHdD.css +1 -0
- package/public/assets/inter-latin-400-normal-C38fXH4l.woff2 +0 -0
- package/public/assets/inter-latin-400-normal-CyCys3Eg.woff +0 -0
- package/public/assets/inter-latin-500-normal-BL9OpVg8.woff +0 -0
- package/public/assets/inter-latin-500-normal-Cerq10X2.woff2 +0 -0
- package/public/assets/inter-latin-600-normal-CiBQ2DWP.woff +0 -0
- package/public/assets/inter-latin-600-normal-LgqL8muc.woff2 +0 -0
- package/public/assets/inter-latin-700-normal-BLAVimhd.woff +0 -0
- package/public/assets/inter-latin-700-normal-Yt3aPRUw.woff2 +0 -0
- package/public/assets/motion-vendor-CDgKLzlB.js +9 -0
- package/public/index.html +16 -0
- package/src/cli.js +333 -0
- package/src/markdown.js +0 -0
- package/src/server.js +3918 -0
package/plugin/README.md
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# Pagecast — agent plugin
|
|
2
|
+
|
|
3
|
+
Lets your coding agent (Claude Code, Codex, or any Agent-Skills-compatible tool)
|
|
4
|
+
offer to publish a freshly created **HTML or Markdown** report, plan, or doc to a
|
|
5
|
+
shareable public URL.
|
|
6
|
+
|
|
7
|
+
How it works: a passive `PostToolUse` hook notices when an HTML/Markdown file is
|
|
8
|
+
written and hints the agent. The `publish-report` skill tells the agent to offer
|
|
9
|
+
(once, only for finished/shareable artifacts) *"Want me to publish this with
|
|
10
|
+
Pagecast?"* and, on an explicit **yes**, run the headless CLI:
|
|
11
|
+
|
|
12
|
+
```sh
|
|
13
|
+
npx pagecast publish "/absolute/path/file.md" --json
|
|
14
|
+
# → {"ok":true,"url":"https://pagecast.pages.dev/p/<token>/", ...}
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Setup (one time)
|
|
18
|
+
|
|
19
|
+
### 1. Install the agent integration
|
|
20
|
+
|
|
21
|
+
**Codex CLI / Codex desktop** — copy the Codex-native skill:
|
|
22
|
+
|
|
23
|
+
```sh
|
|
24
|
+
mkdir -p ~/.codex/skills
|
|
25
|
+
# from a clone of the repo:
|
|
26
|
+
cp -R .codex/skills/publish-report ~/.codex/skills/
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Start a new Codex session so the skill is discovered. Then you can ask:
|
|
30
|
+
|
|
31
|
+
```text
|
|
32
|
+
Use $publish-report to publish /absolute/path/report.md with Pagecast.
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
**Claude Code** — add the marketplace from the public repo, then install:
|
|
36
|
+
|
|
37
|
+
```sh
|
|
38
|
+
/plugin marketplace add Amal-David/pagecast
|
|
39
|
+
/plugin install pagecast@pagecast
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
This wires up both the `publish-report` skill and the report-detection hook.
|
|
43
|
+
|
|
44
|
+
**Other Agent-Skills tools** — copy the portable skill:
|
|
45
|
+
|
|
46
|
+
```sh
|
|
47
|
+
# from a clone of the repo:
|
|
48
|
+
cp plugin/skills/publish-report/SKILL.md /path/to/your-agent/skills/publish-report/SKILL.md
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
The portable `SKILL.md` is the Agent-Skills format. The detection hook is
|
|
52
|
+
Claude-Code-specific; elsewhere the skill still triggers when a report is created
|
|
53
|
+
or when you ask to publish one.
|
|
54
|
+
|
|
55
|
+
### 2. Connect Cloudflare
|
|
56
|
+
|
|
57
|
+
```sh
|
|
58
|
+
npx pagecast
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Click **Connect Cloudflare** in the panel. Or sign in directly:
|
|
62
|
+
|
|
63
|
+
```sh
|
|
64
|
+
npx pagecast pages setup --project pagecast
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
That's the whole setup. **After this, publishing is headless** — when your agent
|
|
68
|
+
makes a report and you say "yes", it publishes with no further prompts.
|
|
69
|
+
|
|
70
|
+
## What to expect
|
|
71
|
+
|
|
72
|
+
Once installed and connected: when your agent writes a report, plan, dashboard, or
|
|
73
|
+
other shareable HTML/Markdown, it offers *"Want me to publish this with Pagecast?"*
|
|
74
|
+
Say **yes** and you get back a public `pagecast.pages.dev` link you own. Say no and
|
|
75
|
+
it drops it — it won't nag. You can rename, re-sync, or revoke any link from
|
|
76
|
+
`npx pagecast`.
|
|
77
|
+
|
|
78
|
+
For static web projects that should get a new share link, build first and publish
|
|
79
|
+
the generated entry file, such as `dist/index.html`.
|
|
80
|
+
|
|
81
|
+
For whole-site Cloudflare Pages deploys, use Pagecast's Wrangler abstraction:
|
|
82
|
+
|
|
83
|
+
```sh
|
|
84
|
+
npx pagecast pages deploy "/absolute/path/dist" --project pagecasthq --branch main --json
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
If you omit `--branch`, Pagecast deploys to `main`:
|
|
88
|
+
|
|
89
|
+
```sh
|
|
90
|
+
npx pagecast pages deploy "/absolute/path/dist" --project pagecasthq --json
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Direct site deploys replace the target Pages project contents. Use `npx pagecast`
|
|
94
|
+
for source-folder build settings, URL renaming, re-sync, and revoke controls.
|
|
95
|
+
|
|
96
|
+
## Requirements
|
|
97
|
+
|
|
98
|
+
- Node.js >= 20 and `npx` (Wrangler is fetched via `npx` on first use).
|
|
99
|
+
- A Cloudflare account.
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Passive PostToolUse hook: when a Write/Edit/MultiEdit creates or updates an
|
|
3
|
+
// HTML or Markdown file (a report, plan, doc, or dashboard), inject a
|
|
4
|
+
// non-blocking hint so the agent can offer to publish it with Pagecast. This
|
|
5
|
+
// hook NEVER blocks and NEVER publishes anything — it only adds context, and the
|
|
6
|
+
// skill decides whether the file is actually worth offering. Any error exits 0
|
|
7
|
+
// silently so it can't disrupt the agent.
|
|
8
|
+
|
|
9
|
+
// Obvious non-artifacts the agent should not be nudged to publish. The skill
|
|
10
|
+
// applies the real judgment; this just keeps the common noise down.
|
|
11
|
+
const SKIP_BASENAMES = new Set([
|
|
12
|
+
"readme.md",
|
|
13
|
+
"readme.markdown",
|
|
14
|
+
"changelog.md",
|
|
15
|
+
"contributing.md",
|
|
16
|
+
"license.md",
|
|
17
|
+
"code_of_conduct.md",
|
|
18
|
+
"security.md",
|
|
19
|
+
"agents.md",
|
|
20
|
+
"claude.md",
|
|
21
|
+
"todo.md",
|
|
22
|
+
"tasks.md",
|
|
23
|
+
"notes.md"
|
|
24
|
+
]);
|
|
25
|
+
|
|
26
|
+
function readStdin() {
|
|
27
|
+
return new Promise((resolve) => {
|
|
28
|
+
let data = "";
|
|
29
|
+
if (process.stdin.isTTY) {
|
|
30
|
+
resolve("");
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
process.stdin.setEncoding("utf8");
|
|
34
|
+
process.stdin.on("data", (chunk) => {
|
|
35
|
+
data += chunk;
|
|
36
|
+
});
|
|
37
|
+
process.stdin.on("end", () => resolve(data));
|
|
38
|
+
process.stdin.on("error", () => resolve(""));
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function reportPathFrom(toolInput) {
|
|
43
|
+
if (!toolInput || typeof toolInput !== "object") {
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
const candidate = toolInput.file_path || toolInput.path || toolInput.filePath;
|
|
47
|
+
if (typeof candidate !== "string") {
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
const lower = candidate.toLowerCase();
|
|
51
|
+
const isPublishable =
|
|
52
|
+
lower.endsWith(".html") ||
|
|
53
|
+
lower.endsWith(".htm") ||
|
|
54
|
+
lower.endsWith(".md") ||
|
|
55
|
+
lower.endsWith(".markdown");
|
|
56
|
+
if (!isPublishable) {
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const base = candidate.split("/").pop() || "";
|
|
61
|
+
// Skip obvious non-artifacts: build/dependency dirs, hidden files, and common
|
|
62
|
+
// repo-meta files that nobody wants to publish.
|
|
63
|
+
if (
|
|
64
|
+
candidate.includes("/node_modules/") ||
|
|
65
|
+
candidate.includes("/dist/") ||
|
|
66
|
+
candidate.includes("/.git/") ||
|
|
67
|
+
base.startsWith(".") ||
|
|
68
|
+
SKIP_BASENAMES.has(base.toLowerCase())
|
|
69
|
+
) {
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
return candidate;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
async function main() {
|
|
76
|
+
try {
|
|
77
|
+
const raw = await readStdin();
|
|
78
|
+
if (!raw.trim()) {
|
|
79
|
+
process.exit(0);
|
|
80
|
+
}
|
|
81
|
+
const event = JSON.parse(raw);
|
|
82
|
+
const filePath = reportPathFrom(event.tool_input);
|
|
83
|
+
if (!filePath) {
|
|
84
|
+
process.exit(0);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const additionalContext =
|
|
88
|
+
`An HTML or Markdown file was just written at "${filePath}". ` +
|
|
89
|
+
`If it is a substantial, finished artifact worth sharing (a report, plan, doc, or dashboard) — ` +
|
|
90
|
+
`not a scratch/internal file — offer once: ask the user "Want me to publish this with Pagecast?" ` +
|
|
91
|
+
`and only on an explicit yes run \`npx pagecast publish "${filePath}" --json\` to get a shareable ` +
|
|
92
|
+
`public URL. Never publish without confirmation, and don't re-ask for this file.`;
|
|
93
|
+
|
|
94
|
+
process.stdout.write(
|
|
95
|
+
JSON.stringify({
|
|
96
|
+
hookSpecificOutput: {
|
|
97
|
+
hookEventName: "PostToolUse",
|
|
98
|
+
additionalContext
|
|
99
|
+
}
|
|
100
|
+
})
|
|
101
|
+
);
|
|
102
|
+
process.exit(0);
|
|
103
|
+
} catch {
|
|
104
|
+
// Never disrupt the agent loop.
|
|
105
|
+
process.exit(0);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
main();
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: publish-report
|
|
3
|
+
description: Use when an HTML or Markdown report, plan, doc, dashboard, or built static web project has just been created (or the user wants to share one) and it is worth publishing as a public link. Offers to publish it with Pagecast, then returns the URL.
|
|
4
|
+
version: 0.2.0
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Publish with Pagecast
|
|
8
|
+
|
|
9
|
+
Pagecast turns a local **HTML or Markdown** file (a report, plan, doc, or
|
|
10
|
+
dashboard) into a shareable public URL. Use this skill to offer that at the
|
|
11
|
+
right moment, then do it on a yes.
|
|
12
|
+
|
|
13
|
+
## When to offer
|
|
14
|
+
|
|
15
|
+
Offer **once** when a substantial, finished, shareable artifact appears:
|
|
16
|
+
|
|
17
|
+
- An `.html`/`.htm` or `.md`/`.markdown` file was just generated that a person
|
|
18
|
+
would actually want to share — a test/coverage/Lighthouse/Playwright report, a
|
|
19
|
+
data dashboard, a written plan or proposal, a "here's what I built" summary, a
|
|
20
|
+
design doc, release notes, etc.
|
|
21
|
+
- A static web project was just built and has a generated entry file such as
|
|
22
|
+
`dist/index.html`, `build/index.html`, `out/index.html`, or `public/index.html`.
|
|
23
|
+
- The user asks to "share", "publish", "make a link for", or "send" a report/doc.
|
|
24
|
+
- A `PostToolUse` hint says an HTML/Markdown file was created (the bundled hook).
|
|
25
|
+
|
|
26
|
+
**Use judgment — do not nag.** Offer only for finished, worth-sharing artifacts.
|
|
27
|
+
Do **not** offer for scratch notes, internal repo files (README, CHANGELOG,
|
|
28
|
+
CONTRIBUTING, LICENSE, AGENTS.md, TODO/tasks), config, source code, or anything
|
|
29
|
+
under `node_modules`/`dist`/`.git`. Ask **at most once per file**; if the user
|
|
30
|
+
declines or ignores it, drop it and don't re-ask.
|
|
31
|
+
|
|
32
|
+
## The one question to ask
|
|
33
|
+
|
|
34
|
+
> "Want me to publish this with Pagecast? It'll create a shareable public link."
|
|
35
|
+
|
|
36
|
+
Only on an explicit **yes** do you proceed. Publishing makes the file publicly
|
|
37
|
+
reachable — **never publish without confirmation.**
|
|
38
|
+
|
|
39
|
+
## How to publish
|
|
40
|
+
|
|
41
|
+
Run the headless CLI with the **absolute path** and `--json`:
|
|
42
|
+
|
|
43
|
+
```sh
|
|
44
|
+
npx pagecast publish "/absolute/path/to/file.md" --json
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
(HTML and Markdown both work — Markdown is rendered to a clean page. If `pagecast`
|
|
48
|
+
is installed globally/in the project, `pagecast publish "<path>" --json` is the same.)
|
|
49
|
+
|
|
50
|
+
For static web projects that should get a new shareable `/p/<token>/` link,
|
|
51
|
+
build first and publish the generated entry file:
|
|
52
|
+
|
|
53
|
+
```sh
|
|
54
|
+
npm run build
|
|
55
|
+
npx pagecast publish "/absolute/path/to/dist/index.html" --json
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
If the user asks to deploy or update an entire static site/project, deploy the
|
|
59
|
+
built folder directly to a named Cloudflare Pages project:
|
|
60
|
+
|
|
61
|
+
```sh
|
|
62
|
+
npx pagecast publish site "/absolute/path/to/dist" --project "project-name" --branch main --json
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
`--branch` is optional and defaults to `main`, so this also works:
|
|
66
|
+
|
|
67
|
+
```sh
|
|
68
|
+
npx pagecast pages deploy "/absolute/path/to/dist" --project "project-name" --json
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Use this instead of raw Wrangler commands like `npx wrangler pages deploy`.
|
|
72
|
+
Direct site deploys replace the target Pages project contents, so do not guess
|
|
73
|
+
the `--project`; use the user's named project or ask for it.
|
|
74
|
+
|
|
75
|
+
Parse the JSON on stdout:
|
|
76
|
+
|
|
77
|
+
- **Success** → `{ "ok": true, "url": "https://<project>.pages.dev/p/<token>/", ... }`
|
|
78
|
+
- Give the user the `url`. Offer to drop it into a PR/Slack message, and
|
|
79
|
+
mention they can rename the URL, re-sync, or revoke it from `npx pagecast`.
|
|
80
|
+
- **Not signed in** → `{ "ok": false, "statusCode": 401, ... }`
|
|
81
|
+
- This is the one-time setup. Tell the user to run
|
|
82
|
+
**`npx pagecast pages setup`** once, or run **`npx pagecast`** and click
|
|
83
|
+
**Connect Cloudflare**, then offer to retry. After that, publishing is
|
|
84
|
+
headless — a plain "yes" is enough every time.
|
|
85
|
+
- **Multiple accounts** → `{ "ok": false, "statusCode": 409, ... }`
|
|
86
|
+
- Tell the user to run `npx pagecast pages setup --account <account-id>` once,
|
|
87
|
+
or run `npx pagecast` to pick which Cloudflare account to publish from, then
|
|
88
|
+
retry.
|
|
89
|
+
- **Any other error** → relay `error` concisely and offer to retry.
|
|
90
|
+
|
|
91
|
+
## Cloudflare Pages commands
|
|
92
|
+
|
|
93
|
+
Use these lower-level commands when the user explicitly asks about Cloudflare
|
|
94
|
+
setup, status, project listing, or direct Pages deployment:
|
|
95
|
+
|
|
96
|
+
```sh
|
|
97
|
+
npx pagecast pages setup --project "project-name" --json
|
|
98
|
+
npx pagecast pages status --json
|
|
99
|
+
npx pagecast pages projects list --json
|
|
100
|
+
npx pagecast pages deploy "/absolute/path/to/dist" --project "project-name" --branch main --json
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
If the user does not specify a branch, omit `--branch`; Pagecast deploys to
|
|
104
|
+
`main`.
|
|
105
|
+
|
|
106
|
+
## Notes
|
|
107
|
+
|
|
108
|
+
- Always pass an **absolute** path (resolve relative paths against the cwd first).
|
|
109
|
+
- The first publish auto-creates the user's Pages project — no manual setup beyond
|
|
110
|
+
the one-time Connect Cloudflare login.
|
|
111
|
+
- Use `npx pagecast publish site` or `npx pagecast pages deploy` for direct
|
|
112
|
+
static-folder deploys to a named Pages project.
|
|
113
|
+
- Use `npx pagecast` for source-folder build settings, URL renaming, re-sync,
|
|
114
|
+
and revoke controls.
|
|
115
|
+
- To update a page **in place at the same URL**, the user can re-sync from the
|
|
116
|
+
Pagecast app; re-running `publish` creates a new link. Old links keep working
|
|
117
|
+
until revoked.
|