@pantoken/scaffold 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 Danny Wahl
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,41 @@
1
+ # @pantoken/scaffold
2
+
3
+ Scaffold a starter project — with [pantoken](https://www.npmjs.com/package/@pantoken/pantoken)
4
+ (Instructure design tokens and icons) already installed and wired in.
5
+
6
+ ## Usage
7
+
8
+ ```sh
9
+ npx @pantoken/scaffold web # plain HTML/CSS (Vite + TS) + @pantoken/components
10
+ npx @pantoken/scaffold react # Vite + React + @pantoken/react
11
+ npx @pantoken/scaffold next # Next.js (App Router) + @pantoken/next
12
+
13
+ # Target a directory other than the current one:
14
+ npx @pantoken/scaffold react --dir ./my-app
15
+ ```
16
+
17
+ `npx` works regardless of which package manager you use. Substitute `pnpm dlx`, `yarn dlx`, or
18
+ `bunx` for `npx` if you prefer.
19
+
20
+ Or use it programmatically:
21
+
22
+ ```ts
23
+ import { scaffoldProject, SCAFFOLD_PLATFORMS } from "@pantoken/scaffold";
24
+
25
+ scaffoldProject("react", "./my-app");
26
+ ```
27
+
28
+ ## API
29
+
30
+ - **`scaffoldProject(platform, dir?): string[]`** — write a starter project template for a
31
+ `ScaffoldPlatform` into `dir` (defaults to `"."`). Its basename (or `"pantoken-app"` for `"."`)
32
+ is substituted for `{{projectName}}` in the template files. Returns the paths written.
33
+ - **`SCAFFOLD_PLATFORMS: readonly ScaffoldPlatform[]`** — every scaffoldable platform key.
34
+ - **`ScaffoldPlatform`** — the platform union: `"web"`, `"react"`, `"next"`.
35
+
36
+ `@pantoken/ai`'s `pantoken-ai scaffold <platform>` command wraps this package and additionally
37
+ installs pantoken's agent assets (AGENTS.md, editor/agent rules, skills) into the same directory.
38
+
39
+ ## License
40
+
41
+ MIT
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env node
2
+ import { SCAFFOLD_PLATFORMS, scaffoldProject } from "../dist/index.mjs";
3
+
4
+ const argv = process.argv.slice(2);
5
+ const PLATFORM_SET = new Set(SCAFFOLD_PLATFORMS);
6
+
7
+ const usage = () => `Usage: pantoken-scaffold <${SCAFFOLD_PLATFORMS.join("|")}> [--dir .]`;
8
+
9
+ const flag = (name) => {
10
+ const i = argv.indexOf(`--${name}`);
11
+ return i !== -1 ? argv[i + 1] : undefined;
12
+ };
13
+
14
+ if (argv[0] === "--help" || argv[0] === "-h") {
15
+ console.log(usage());
16
+ process.exit(0);
17
+ }
18
+
19
+ const platform = argv[0];
20
+ const dir = flag("dir") ?? ".";
21
+ if (!platform || !PLATFORM_SET.has(platform)) {
22
+ console.error(`Unknown platform "${platform ?? ""}".`);
23
+ console.error(usage());
24
+ process.exit(1);
25
+ }
26
+
27
+ const written = scaffoldProject(platform, dir);
28
+ for (const path of written) console.log(`✓ wrote ${path}`);
29
+ console.log(`\nNext: cd ${dir} && npm install (or pnpm/yarn/bun install)`);
@@ -0,0 +1,35 @@
1
+ //#region generated/scaffolds.d.ts
2
+ declare const SCAFFOLDS: Record<string, Record<string, string>>;
3
+ //#endregion
4
+ //#region src/index.d.ts
5
+ /** A platform pantoken can scaffold a starter project for. */
6
+ type ScaffoldPlatform = keyof typeof SCAFFOLDS;
7
+ /**
8
+ * Every scaffoldable platform key.
9
+ *
10
+ * @example List available platforms
11
+ * ```ts
12
+ * import { SCAFFOLD_PLATFORMS } from "@pantoken/scaffold";
13
+ *
14
+ * console.log(SCAFFOLD_PLATFORMS); // → ["web", "react", "next"]
15
+ * ```
16
+ */
17
+ declare const SCAFFOLD_PLATFORMS: readonly ScaffoldPlatform[];
18
+ /**
19
+ * Scaffold a starter project for a platform, with pantoken already installed and wired in.
20
+ *
21
+ * @param platform - A {@link ScaffoldPlatform}.
22
+ * @param dir - The target directory (default `"."`). Its basename (or `"pantoken-app"` for `"."`)
23
+ * is substituted for `{{projectName}}` in the template files.
24
+ * @returns The paths written.
25
+ *
26
+ * @example Scaffold a React starter
27
+ * ```ts
28
+ * import { scaffoldProject } from "@pantoken/scaffold";
29
+ *
30
+ * scaffoldProject("react", "./my-app");
31
+ * ```
32
+ */
33
+ declare function scaffoldProject(platform: string, dir?: string): string[];
34
+ //#endregion
35
+ export { SCAFFOLD_PLATFORMS, ScaffoldPlatform, scaffoldProject };
package/dist/index.mjs ADDED
@@ -0,0 +1,88 @@
1
+ import { mkdirSync, writeFileSync } from "node:fs";
2
+ import { dirname, join } from "node:path";
3
+ //#region generated/scaffolds.ts
4
+ const SCAFFOLDS = {
5
+ "next": {
6
+ ".gitignore": "node_modules\n.next\n",
7
+ "README.md": "# {{projectName}}\n\nScaffolded with `pantoken-scaffold next` (or `pantoken-ai scaffold next`) — a Next.js (App Router) app styled with\n[`@pantoken/next`](https://www.npmjs.com/package/@pantoken/next), Instructure's design tokens and\nicons.\n\n## Develop\n\n```sh\nnpm install\nnpm run dev\n```\n\n## What's here\n\n- `next.config.mjs` wraps the config with `withPantoken(...)` (adds pantoken to\n `transpilePackages`).\n- `app/layout.tsx` imports `@pantoken/css/inject`, which defines every `--instui-*` custom\n property, at the root so it's available on every page.\n- `app/page.tsx` references tokens with `var(--instui-*)`.\n",
8
+ "next.config.mjs": "import { withPantoken } from \"@pantoken/next\";\n\n/** @type {import('next').NextConfig} */\nconst nextConfig = {};\n\nexport default withPantoken(nextConfig);\n",
9
+ "package.json": "{\n \"name\": \"{{projectName}}\",\n \"version\": \"0.0.0\",\n \"private\": true,\n \"type\": \"module\",\n \"scripts\": {\n \"dev\": \"next dev\",\n \"build\": \"next build\",\n \"start\": \"next start\"\n },\n \"dependencies\": {\n \"@pantoken/next\": \"latest\",\n \"next\": \"^15.0.0\",\n \"react\": \"^19.0.0\",\n \"react-dom\": \"^19.0.0\"\n }\n}\n",
10
+ "tsconfig.json": "{\n \"compilerOptions\": {\n \"target\": \"ES2022\",\n \"lib\": [\"ES2022\", \"DOM\", \"DOM.Iterable\"],\n \"module\": \"ESNext\",\n \"moduleResolution\": \"Bundler\",\n \"jsx\": \"preserve\",\n \"strict\": true,\n \"skipLibCheck\": true,\n \"plugins\": [{ \"name\": \"next\" }]\n },\n \"include\": [\"app\", \"next-env.d.ts\"]\n}\n",
11
+ "app/layout.tsx": "import \"@pantoken/css/inject\";\n\nexport const metadata = {\n title: \"{{projectName}}\",\n};\n\nexport default function RootLayout({ children }: { children: React.ReactNode }) {\n return (\n <html lang=\"en\">\n <body>{children}</body>\n </html>\n );\n}\n",
12
+ "app/page.tsx": "export default function Page() {\n return (\n <main style={{ padding: \"var(--instui-spacing-space-lg)\" }}>\n <h1 style={{ color: \"var(--instui-color-text-primary)\" }}>{\"{{projectName}}\"}</h1>\n <p>\n Styled with <code>@pantoken/next</code> — Instructure design tokens and icons.\n </p>\n </main>\n );\n}\n"
13
+ },
14
+ "react": {
15
+ ".gitignore": "node_modules\ndist\n",
16
+ "README.md": "# {{projectName}}\n\nScaffolded with `pantoken-scaffold react` (or `pantoken-ai scaffold react`) — a Vite + React app styled with\n[`@pantoken/react`](https://www.npmjs.com/package/@pantoken/react) and\n[`@pantoken/css`](https://www.npmjs.com/package/@pantoken/css), Instructure's design tokens and\nicons.\n\n## Develop\n\n```sh\nnpm install\nnpm run dev\n```\n\n## What's here\n\n- `src/main.tsx` imports `@pantoken/css/inject`, which defines every `--instui-*` custom property.\n- `src/App.tsx` references tokens with `var(--instui-*)` and renders an icon via `@pantoken/react`'s\n `<Icon>`.\n- For InstUI's full React component library (buttons, modals, etc.), add the specific\n `@instructure/ui-*` packages you need — see <https://instructure.design>.\n",
17
+ "index.html": "<!doctype html>\n<html lang=\"en\">\n <head>\n <meta charset=\"UTF-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n <title>{{projectName}}</title>\n </head>\n <body>\n <div id=\"root\"></div>\n <script type=\"module\" src=\"/src/main.tsx\"><\/script>\n </body>\n</html>\n",
18
+ "package.json": "{\n \"name\": \"{{projectName}}\",\n \"version\": \"0.0.0\",\n \"private\": true,\n \"type\": \"module\",\n \"scripts\": {\n \"dev\": \"vite\",\n \"build\": \"vite build\",\n \"preview\": \"vite preview\"\n },\n \"dependencies\": {\n \"@pantoken/css\": \"latest\",\n \"@pantoken/react\": \"latest\",\n \"react\": \"^19.0.0\",\n \"react-dom\": \"^19.0.0\"\n },\n \"devDependencies\": {\n \"@types/react\": \"^19.0.0\",\n \"@types/react-dom\": \"^19.0.0\",\n \"@vitejs/plugin-react\": \"^4.3.0\",\n \"vite\": \"^6.0.0\"\n }\n}\n",
19
+ "tsconfig.json": "{\n \"compilerOptions\": {\n \"target\": \"ES2022\",\n \"lib\": [\"ES2022\", \"DOM\", \"DOM.Iterable\"],\n \"module\": \"ESNext\",\n \"moduleResolution\": \"Bundler\",\n \"jsx\": \"react-jsx\",\n \"strict\": true,\n \"skipLibCheck\": true\n },\n \"include\": [\"src\"]\n}\n",
20
+ "vite.config.ts": "import { defineConfig } from \"vite\";\nimport react from \"@vitejs/plugin-react\";\n\nexport default defineConfig({\n plugins: [react()],\n});\n",
21
+ "src/App.tsx": "import { Icon } from \"@pantoken/react\";\n\nexport function App() {\n return (\n <main style={{ padding: \"var(--instui-spacing-space-lg)\" }}>\n <h1 style={{ color: \"var(--instui-color-text-primary)\" }}>{\"{{projectName}}\"}</h1>\n <p>\n Styled with <code>@pantoken/react</code> and <code>@pantoken/css</code> — Instructure design\n tokens and icons.\n </p>\n <Icon name=\"check-mark\" />\n </main>\n );\n}\n",
22
+ "src/main.tsx": "import { StrictMode } from \"react\";\nimport { createRoot } from \"react-dom/client\";\n// Defines every --instui-* custom property this app can reference.\nimport \"@pantoken/css/inject\";\nimport { App } from \"./App.tsx\";\n\ncreateRoot(document.getElementById(\"root\")!).render(\n <StrictMode>\n <App />\n </StrictMode>,\n);\n"
23
+ },
24
+ "web": {
25
+ ".gitignore": "node_modules\ndist\n",
26
+ "README.md": "# {{projectName}}\n\nScaffolded with `pantoken-scaffold web` (or `pantoken-ai scaffold web`) — a plain TypeScript app (via Vite) styled with\n[`@pantoken/components`](https://www.npmjs.com/package/@pantoken/components), Instructure's\ndesign tokens and icons.\n\n## Develop\n\n```sh\nnpm install\nnpm run dev\n```\n\n## What's here\n\n- `src/main.ts` imports `@pantoken/components/base.css` (document defaults + focus ring) and\n `components.css` (`.instui-*` classes), then renders markup into `#app`.\n- Apply classes like `class=\"instui-button\"` to markup; see the\n [component reference](https://pantoken.iywahl.com/api/css) for the full class list.\n",
27
+ "index.html": "<!doctype html>\n<html lang=\"en\">\n <head>\n <meta charset=\"UTF-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n <title>{{projectName}}</title>\n </head>\n <body>\n <div id=\"app\"></div>\n <script type=\"module\" src=\"/src/main.ts\"><\/script>\n </body>\n</html>\n",
28
+ "package.json": "{\n \"name\": \"{{projectName}}\",\n \"version\": \"0.0.0\",\n \"private\": true,\n \"type\": \"module\",\n \"scripts\": {\n \"dev\": \"vite\",\n \"build\": \"vite build\",\n \"preview\": \"vite preview\"\n },\n \"dependencies\": {\n \"@pantoken/components\": \"latest\"\n },\n \"devDependencies\": {\n \"typescript\": \"^5.7.0\",\n \"vite\": \"^6.0.0\"\n }\n}\n",
29
+ "tsconfig.json": "{\n \"compilerOptions\": {\n \"target\": \"ES2022\",\n \"lib\": [\"ES2022\", \"DOM\", \"DOM.Iterable\"],\n \"module\": \"ESNext\",\n \"moduleResolution\": \"Bundler\",\n \"strict\": true,\n \"skipLibCheck\": true\n },\n \"include\": [\"src\"]\n}\n",
30
+ "vite.config.ts": "import { defineConfig } from \"vite\";\n\nexport default defineConfig({});\n",
31
+ "src/main.ts": "// Defines every --instui-* custom property this app can reference.\nimport \"@pantoken/components/base.css\";\nimport \"@pantoken/components/components.css\";\n\ndocument.querySelector<HTMLDivElement>(\"#app\")!.innerHTML = `\n <main class=\"instui-agent-shell -p-lg\">\n <h1 class=\"instui-heading\">{{projectName}}</h1>\n <p>Styled with <code>@pantoken/components</code> — Instructure design tokens and icons.</p>\n <button class=\"instui-button -color-primary\" type=\"button\">Get started</button>\n </main>\n`;\n"
32
+ }
33
+ };
34
+ //#endregion
35
+ //#region src/index.ts
36
+ /**
37
+ * `@pantoken/scaffold` — scaffold a starter project for a platform, with pantoken already
38
+ * installed and wired in. Standalone; usable via `npx @pantoken/scaffold <platform>` without
39
+ * `@pantoken/ai`.
40
+ *
41
+ * @module
42
+ * @alpha
43
+ */
44
+ /**
45
+ * Every scaffoldable platform key.
46
+ *
47
+ * @example List available platforms
48
+ * ```ts
49
+ * import { SCAFFOLD_PLATFORMS } from "@pantoken/scaffold";
50
+ *
51
+ * console.log(SCAFFOLD_PLATFORMS); // → ["web", "react", "next"]
52
+ * ```
53
+ */
54
+ const SCAFFOLD_PLATFORMS = Object.keys(SCAFFOLDS);
55
+ const SCAFFOLD_PLATFORM_SET = new Set(SCAFFOLD_PLATFORMS);
56
+ function ensureScaffoldPlatform(platform) {
57
+ if (SCAFFOLD_PLATFORM_SET.has(platform)) return;
58
+ throw new Error(`Unknown platform "${platform}". Expected one of: ${SCAFFOLD_PLATFORMS.join(", ")}.`);
59
+ }
60
+ /**
61
+ * Scaffold a starter project for a platform, with pantoken already installed and wired in.
62
+ *
63
+ * @param platform - A {@link ScaffoldPlatform}.
64
+ * @param dir - The target directory (default `"."`). Its basename (or `"pantoken-app"` for `"."`)
65
+ * is substituted for `{{projectName}}` in the template files.
66
+ * @returns The paths written.
67
+ *
68
+ * @example Scaffold a React starter
69
+ * ```ts
70
+ * import { scaffoldProject } from "@pantoken/scaffold";
71
+ *
72
+ * scaffoldProject("react", "./my-app");
73
+ * ```
74
+ */
75
+ function scaffoldProject(platform, dir = ".") {
76
+ ensureScaffoldPlatform(platform);
77
+ const projectName = dir === "." ? "pantoken-app" : dir.split("/").pop() ?? "pantoken-app";
78
+ const written = [];
79
+ for (const [file, content] of Object.entries(SCAFFOLDS[platform])) {
80
+ const path = join(dir, file);
81
+ mkdirSync(dirname(path), { recursive: true });
82
+ writeFileSync(path, content.split("{{projectName}}").join(projectName));
83
+ written.push(path);
84
+ }
85
+ return written;
86
+ }
87
+ //#endregion
88
+ export { SCAFFOLD_PLATFORMS, scaffoldProject };
package/package.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "@pantoken/scaffold",
3
+ "version": "0.1.0",
4
+ "description": "npx @pantoken/scaffold <platform> — scaffold a starter project (web, react, next, ...) with pantoken already installed and wired in.",
5
+ "homepage": "https://pantoken.iywahl.com",
6
+ "bugs": "https://github.com/thedannywahl/pantoken/issues",
7
+ "license": "MIT",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/thedannywahl/pantoken.git",
11
+ "directory": "packages/scaffold"
12
+ },
13
+ "bin": {
14
+ "pantoken-scaffold": "bin/pantoken-scaffold.mjs"
15
+ },
16
+ "files": [
17
+ "dist",
18
+ "bin"
19
+ ],
20
+ "type": "module",
21
+ "sideEffects": false,
22
+ "exports": {
23
+ ".": "./dist/index.mjs",
24
+ "./package.json": "./package.json"
25
+ },
26
+ "publishConfig": {
27
+ "access": "public",
28
+ "provenance": true
29
+ },
30
+ "devDependencies": {
31
+ "@types/node": "^24.13.3",
32
+ "typescript": "^7.0.2",
33
+ "vite": "npm:@voidzero-dev/vite-plus-core@0.2.9",
34
+ "vite-plus": "0.2.9"
35
+ },
36
+ "engines": {
37
+ "node": ">=22.18.0"
38
+ },
39
+ "scripts": {
40
+ "generate": "node scripts/generate.ts",
41
+ "dev": "vp pack --watch",
42
+ "test": "vp run generate && vp test",
43
+ "check": "vp check"
44
+ }
45
+ }