mirror of
https://github.com/getpaseo/paseo.git
synced 2026-11-10 10:25:03 +00:00
Scaffold author overviews for plugin listings (#6226)
* feat(plugins): scaffold author listing overviews * docs(plugins): refine the author overview contract * docs(plugins): require repository overviews for registry listings * docs(plugins): keep listing guidance focused on authors
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { execFile } from "node:child_process";
|
||||
import { exec, execFile } from "node:child_process";
|
||||
import { mkdtemp, readFile, readdir, rm, writeFile } from "node:fs/promises";
|
||||
import { createRequire } from "node:module";
|
||||
import path from "node:path";
|
||||
@@ -9,6 +9,7 @@ import { scaffoldPluginDirectory } from "./scaffold.js";
|
||||
|
||||
const directories: string[] = [];
|
||||
const execFileAsync = promisify(execFile);
|
||||
const execAsync = promisify(exec);
|
||||
const tscPath = createRequire(import.meta.url).resolve("typescript/bin/tsc");
|
||||
|
||||
async function typecheckPlugin(directory: string): Promise<void> {
|
||||
@@ -28,6 +29,47 @@ afterEach(async () => {
|
||||
});
|
||||
|
||||
describe("plugin scaffold", () => {
|
||||
it("creates an author overview beside the manifest", async () => {
|
||||
const parent = await mkdtemp(path.join(tmpdir(), "paseo-plugin-scaffold-"));
|
||||
directories.push(parent);
|
||||
const directory = path.join(parent, "hello-plugin");
|
||||
await scaffoldPluginDirectory(directory);
|
||||
|
||||
const overview = await readFile(path.join(directory, "OVERVIEW.md"), "utf8");
|
||||
const comments = overview.match(/<!--[\s\S]*?-->/g) ?? [];
|
||||
expect(comments).toHaveLength(1);
|
||||
expect(overview.replace(/<!--[\s\S]*?-->/g, "").trim()).toBe("");
|
||||
expect(overview).toContain("required to list");
|
||||
expect(overview).toContain("README");
|
||||
expect(overview).toContain("choosing a plugin in Paseo");
|
||||
expect(overview).toContain("Length follows complexity");
|
||||
expect(overview).toContain("1. Describe what your plugin is and does");
|
||||
expect(overview).toContain("2. Explain how it works only when it is not obvious");
|
||||
expect(overview).toContain("3. Explain setup when needed");
|
||||
expect(overview).toContain("4. Explain capabilities and settings");
|
||||
expect(overview).toContain("permissions");
|
||||
expect(overview).toContain("known limits");
|
||||
expect(overview).not.toContain("This plugin entry was imported");
|
||||
const packageJson = JSON.parse(await readFile(path.join(directory, "package.json"), "utf8"));
|
||||
expect(packageJson.files).toContain("OVERVIEW.md");
|
||||
expect(await readdir(directory)).toContain("paseo-plugin.json");
|
||||
});
|
||||
|
||||
it("includes the author overview in the packed npm artifact", async () => {
|
||||
const parent = await mkdtemp(path.join(tmpdir(), "paseo-plugin-scaffold-"));
|
||||
directories.push(parent);
|
||||
const directory = path.join(parent, "packed-plugin");
|
||||
await scaffoldPluginDirectory(directory);
|
||||
|
||||
const { stdout } = await execAsync("npm pack --dry-run --ignore-scripts --json", {
|
||||
cwd: directory,
|
||||
});
|
||||
const [artifact] = JSON.parse(stdout) as { files: { path: string }[] }[];
|
||||
expect(artifact.files.map((file) => file.path)).toEqual(
|
||||
expect.arrayContaining(["OVERVIEW.md", "paseo-plugin.json"]),
|
||||
);
|
||||
});
|
||||
|
||||
it(
|
||||
"creates a standalone split-runtime project that typechecks",
|
||||
{ timeout: 15_000 },
|
||||
@@ -60,6 +102,7 @@ describe("plugin scaffold", () => {
|
||||
version: "0.0.0",
|
||||
files: [
|
||||
"paseo-plugin.json",
|
||||
"OVERVIEW.md",
|
||||
"index.client.ts",
|
||||
"index.client.tsx",
|
||||
"index.server.ts",
|
||||
|
||||
@@ -3,6 +3,34 @@ import path from "node:path";
|
||||
import { PluginIdSchema } from "@getpaseo/protocol/messages";
|
||||
import { resolveCliVersion } from "../../version.js";
|
||||
|
||||
const OVERVIEW = `<!--
|
||||
OVERVIEW.md is required to list your plugin in the registry. Keep it beside
|
||||
paseo-plugin.json in your repository at the pinned commit and in your npm package.
|
||||
Replace this comment with useful facts before publishing.
|
||||
|
||||
This overview is for people choosing a plugin in Paseo, on the plugin page under
|
||||
its install command. README assumes a GitHub audience and includes technical
|
||||
details, installation instructions, and badges. Long, AI-generated READMEs leave
|
||||
people reading past that material to understand what the plugin does.
|
||||
|
||||
Write these parts in order, including only what helps someone decide to install:
|
||||
|
||||
1. Describe what your plugin is and does in plain terms first.
|
||||
2. Explain how it works only when it is not obvious.
|
||||
3. Explain setup when needed: settings, accounts, tokens, providers, tools, or
|
||||
other plugins. Include applicable daemon version and operating system
|
||||
requirements. Setup guidance is allowed; installation instructions are not.
|
||||
4. Explain capabilities and settings worth understanding, what each option does,
|
||||
what the plugin reads or sends and where, permissions, and known limits.
|
||||
|
||||
Length follows complexity; a theme needs one paragraph. Choose headings only
|
||||
when they help. Use sentence case and plain factual language, with no em dashes.
|
||||
Omit installation commands, badges, changelog, contributing or license sections,
|
||||
marketing, and unsupported claims. Avoid implementation filler such as empty
|
||||
cleanup functions, theme-token field lists, or lists of absent features.
|
||||
-->
|
||||
`;
|
||||
|
||||
const TSCONFIG = {
|
||||
compilerOptions: {
|
||||
target: "ES2020",
|
||||
@@ -155,6 +183,7 @@ export async function scaffoldPluginDirectory(
|
||||
version: "0.0.0",
|
||||
files: [
|
||||
"paseo-plugin.json",
|
||||
"OVERVIEW.md",
|
||||
"index.client.ts",
|
||||
"index.client.tsx",
|
||||
"index.server.ts",
|
||||
@@ -179,6 +208,7 @@ export async function scaffoldPluginDirectory(
|
||||
"paseo-plugin.json",
|
||||
`${JSON.stringify({ id, requirements: { paseo: `>=${version}` } }, null, 2)}\n`,
|
||||
],
|
||||
["OVERVIEW.md", OVERVIEW],
|
||||
["package.json", `${JSON.stringify(packageJson, null, 2)}\n`],
|
||||
["tsconfig.json", `${JSON.stringify(TSCONFIG, null, 2)}\n`],
|
||||
["index.client.tsx", CLIENT_ENTRY],
|
||||
|
||||
Reference in New Issue
Block a user