@slicemedia/create-devkit 0.0.0-bootstrap.0 → 0.1.1

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
@@ -1,4 +1,46 @@
1
- # @slicemedia/create-devkit bootstrap placeholder
1
+ # `@slicemedia/create-devkit`
2
2
 
3
- This is a non-functional identity placeholder used only to configure npm trusted publishing.
4
- Do not install this version. Use a later Slice Media project creator release from the `next` or `latest` tag.
3
+ Starts an interactive wizard for a new neutral TypeScript Webflow project. The optional directory
4
+ argument follows the convention used by established project creators. Run the `0.1.0` release
5
+ candidate through the npm `next` tag with any supported package manager:
6
+
7
+ ```sh
8
+ npm create @slicemedia/devkit@next my-webflow-project
9
+ pnpm dlx @slicemedia/create-devkit@next my-webflow-project
10
+ yarn dlx @slicemedia/create-devkit@next my-webflow-project
11
+ ```
12
+
13
+ Without a directory argument, the wizard proposes `webflow-project`. A literal `.` selects the
14
+ current directory, which must be empty. The wizard asks for the npm name, package manager (pnpm,
15
+ npm, or Yarn), optional capabilities, agent instruction targets, dependency installation, and final
16
+ confirmation. Use Space to select or clear items in the multi-select lists, then press Enter to
17
+ continue. It never overwrites a non-empty directory. Capabilities are opt-in and generate typed
18
+ integration modules that remain disconnected from the project entry until the project chooses to
19
+ compose them.
20
+
21
+ Agent targets add the independent `@slicemedia/agent-kit` package and a deterministic
22
+ `agents:generate` script. Run it through the selected package manager after installation to create
23
+ only the selected platform files; DevKit does not bundle the Agent Kit source.
24
+
25
+ The **Webflow Agent Instructions** target does not install another AI service or MCP server. It
26
+ generates an importable Markdown ZIP and integrity manifest under `.slicemedia/agent-kit/`. After
27
+ review, the ZIP can be imported into the intended Webflow site's Instructions panel so Webflow AI
28
+ and external agents connected through the official Webflow MCP server can use the site-stored rules
29
+ and skills.
30
+
31
+ The package also exports the deterministic `scaffoldProject()` API with schema-v2 options and
32
+ receipts for programmatic consumers, including the chosen package manager. DevKit source is MIT
33
+ licensed; generated client projects remain project-owned and receive no automatic license.
34
+
35
+ ## Support and security
36
+
37
+ See Slice Media's [support policy](https://github.com/slicemedia/.github/blob/main/SUPPORT.md) for
38
+ help and maintenance expectations. Report vulnerabilities through the
39
+ [DevKit security policy](../../SECURITY.md), not a public issue.
40
+
41
+ ## Project notice
42
+
43
+ This package is independently developed by Slice Media and is not affiliated with, endorsed by, or
44
+ sponsored by Webflow, Inc. Webflow and related marks belong to their respective owners. AI tools
45
+ materially assisted its implementation and documentation; production use still requires human
46
+ review, accessibility and security checks, and project-specific testing.
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ import "../dist/bin.js";
package/dist/bin.d.ts ADDED
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env node
2
+ import { type PackageManager } from "./scaffold.js";
3
+ export declare const usage = "Usage: create-slicemedia-devkit [directory]\n\nStarts an interactive wizard for a new Webflow project. If no directory is provided, the wizard\nsuggests webflow-project. Use . to initialize the current directory. Existing non-empty directories\nare never overwritten.\n\nOptions:\n -h, --help Show this help message.";
4
+ export interface ParsedCliArgs {
5
+ readonly help: boolean;
6
+ readonly targetDirectory?: string;
7
+ }
8
+ export interface SpawnedCommand {
9
+ once(event: "error", listener: (error: Error) => void): this;
10
+ once(event: "close", listener: (code: number | null, signal: NodeJS.Signals | null) => void): this;
11
+ }
12
+ export type CommandSpawner = (command: string, args: string[], options: {
13
+ cwd: string;
14
+ shell: false;
15
+ stdio: "inherit";
16
+ }) => SpawnedCommand;
17
+ export declare function parseCliArgs(argv: readonly string[]): ParsedCliArgs;
18
+ export declare function multiSelectPromptMessage(label: string): string;
19
+ export declare function installProjectDependencies(packageManager: PackageManager, targetDirectory: string, spawnCommand?: CommandSpawner): Promise<void>;
20
+ export declare function followUpCommands(packageManager: PackageManager, options: {
21
+ readonly includeInstall: boolean;
22
+ readonly includeAgentGeneration: boolean;
23
+ }): string[];
24
+ export declare function installFailureMessage(packageManager: PackageManager, targetDirectory: string, error: unknown): string;
25
+ export declare function runWizard(cliTargetDirectory?: string): Promise<void>;
26
+ export declare function runCli(argv: readonly string[]): Promise<void>;
27
+ //# sourceMappingURL=bin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bin.d.ts","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":";AAMA,OAAO,EAML,KAAK,cAAc,EAEpB,MAAM,eAAe,CAAC;AAEvB,eAAO,MAAM,KAAK,mUAOoB,CAAC;AAEvC,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;CACnC;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,GAAG,IAAI,CAAC;IAC7D,IAAI,CACF,KAAK,EAAE,OAAO,EACd,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,OAAO,GAAG,IAAI,KAAK,IAAI,GACrE,IAAI,CAAC;CACT;AAED,MAAM,MAAM,cAAc,GAAG,CAC3B,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EAAE,EACd,OAAO,EAAE;IACP,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,KAAK,CAAC;IACb,KAAK,EAAE,SAAS,CAAC;CAClB,KACE,cAAc,CAAC;AAgDpB,wBAAgB,YAAY,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,aAAa,CA8BnE;AAYD,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE9D;AAUD,wBAAsB,0BAA0B,CAC9C,cAAc,EAAE,cAAc,EAC9B,eAAe,EAAE,MAAM,EACvB,YAAY,GAAE,cAAoC,GACjD,OAAO,CAAC,IAAI,CAAC,CAiBf;AAED,wBAAgB,gBAAgB,CAC9B,cAAc,EAAE,cAAc,EAC9B,OAAO,EAAE;IAAE,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,sBAAsB,EAAE,OAAO,CAAA;CAAE,GACtF,MAAM,EAAE,CAOV;AAED,wBAAgB,qBAAqB,CACnC,cAAc,EAAE,cAAc,EAC9B,eAAe,EAAE,MAAM,EACvB,KAAK,EAAE,OAAO,GACb,MAAM,CAGR;AAED,wBAAsB,SAAS,CAAC,kBAAkB,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAwG1E;AAED,wBAAsB,MAAM,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAOnE"}
package/dist/bin.js ADDED
@@ -0,0 +1,240 @@
1
+ #!/usr/bin/env node
2
+ import Enquirer from "enquirer";
3
+ import { spawn } from "node:child_process";
4
+ import { basename, resolve } from "node:path";
5
+ import { fileURLToPath } from "node:url";
6
+ import { AGENT_TARGETS, PACKAGE_MANAGERS, PROJECT_CAPABILITIES, scaffoldProject, } from "./scaffold.js";
7
+ export const usage = `Usage: create-slicemedia-devkit [directory]
8
+
9
+ Starts an interactive wizard for a new Webflow project. If no directory is provided, the wizard
10
+ suggests webflow-project. Use . to initialize the current directory. Existing non-empty directories
11
+ are never overwritten.
12
+
13
+ Options:
14
+ -h, --help Show this help message.`;
15
+ const capabilityLabels = {
16
+ slider: "Responsive slider (Swiper)",
17
+ animations: "Animations (GSAP)",
18
+ tooltips: "Tooltips (Tippy.js)",
19
+ "digitalocean-spaces": "DigitalOcean Spaces deployment",
20
+ };
21
+ const agentTargetLabels = {
22
+ codex: "Codex",
23
+ claude: "Claude",
24
+ cursor: "Cursor",
25
+ copilot: "GitHub Copilot",
26
+ webflow: "Webflow Agent Instructions",
27
+ };
28
+ const agentTargetHints = {
29
+ webflow: "Importable Markdown ZIP stored with the Webflow site",
30
+ };
31
+ const packageManagerLabels = {
32
+ pnpm: "pnpm",
33
+ npm: "npm",
34
+ yarn: "Yarn",
35
+ };
36
+ const packageManagerCommands = {
37
+ pnpm: {
38
+ install: "pnpm install",
39
+ agentsGenerate: "pnpm agents:generate",
40
+ dev: "pnpm dev",
41
+ },
42
+ npm: {
43
+ install: "npm install",
44
+ agentsGenerate: "npm run agents:generate",
45
+ dev: "npm run dev",
46
+ },
47
+ yarn: {
48
+ install: "yarn install",
49
+ agentsGenerate: "yarn agents:generate",
50
+ dev: "yarn dev",
51
+ },
52
+ };
53
+ export function parseCliArgs(argv) {
54
+ const positionals = [];
55
+ let help = false;
56
+ let positionalOnly = false;
57
+ for (const value of argv) {
58
+ if (!positionalOnly && value === "--") {
59
+ positionalOnly = true;
60
+ continue;
61
+ }
62
+ if (!positionalOnly && (value === "--help" || value === "-h")) {
63
+ help = true;
64
+ continue;
65
+ }
66
+ if (!positionalOnly && value.startsWith("-")) {
67
+ throw new Error(`Unknown option: ${value}`);
68
+ }
69
+ if (value.trim() === "")
70
+ throw new Error("Project directory must not be empty.");
71
+ positionals.push(value);
72
+ }
73
+ if (positionals.length > 1) {
74
+ throw new Error("Expected at most one project directory.");
75
+ }
76
+ const targetDirectory = positionals[0];
77
+ return {
78
+ help,
79
+ ...(targetDirectory === undefined ? {} : { targetDirectory }),
80
+ };
81
+ }
82
+ function npmProjectName(value) {
83
+ return /^(?:@[a-z0-9][a-z0-9._-]*\/)?[a-z0-9][a-z0-9._-]*$/u.test(value)
84
+ ? true
85
+ : "Enter a valid lowercase npm package name.";
86
+ }
87
+ function selectedLabel(values) {
88
+ return values.length === 0 ? "none" : values.join(", ");
89
+ }
90
+ export function multiSelectPromptMessage(label) {
91
+ return `${label} (use Space to select one or more; press Enter to continue)`;
92
+ }
93
+ function defaultSpawnCommand(command, args, options) {
94
+ return spawn(command, args, options);
95
+ }
96
+ export async function installProjectDependencies(packageManager, targetDirectory, spawnCommand = defaultSpawnCommand) {
97
+ await new Promise((resolvePromise, rejectPromise) => {
98
+ const child = spawnCommand(packageManager, ["install"], {
99
+ cwd: resolve(targetDirectory),
100
+ shell: false,
101
+ stdio: "inherit",
102
+ });
103
+ child.once("error", rejectPromise);
104
+ child.once("close", (code, signal) => {
105
+ if (code === 0) {
106
+ resolvePromise();
107
+ return;
108
+ }
109
+ const outcome = code === null ? `signal ${signal ?? "unknown"}` : `exit code ${code}`;
110
+ rejectPromise(new Error(`${packageManager} install failed with ${outcome}.`));
111
+ });
112
+ });
113
+ }
114
+ export function followUpCommands(packageManager, options) {
115
+ const commands = packageManagerCommands[packageManager];
116
+ return [
117
+ ...(options.includeInstall ? [commands.install] : []),
118
+ ...(options.includeAgentGeneration ? [commands.agentsGenerate] : []),
119
+ commands.dev,
120
+ ];
121
+ }
122
+ export function installFailureMessage(packageManager, targetDirectory, error) {
123
+ const detail = error instanceof Error ? error.message : String(error);
124
+ return `Project was created at ${targetDirectory}, but dependency installation failed: ${detail}\nThe generated files remain in place. Run "${packageManagerCommands[packageManager].install}" manually in ${targetDirectory}.`;
125
+ }
126
+ export async function runWizard(cliTargetDirectory) {
127
+ const targetDirectory = cliTargetDirectory ??
128
+ (await Enquirer.prompt({
129
+ type: "input",
130
+ name: "targetDirectory",
131
+ message: "Project directory",
132
+ initial: "webflow-project",
133
+ validate: (value) => (value.trim() === "" ? "Enter a project directory." : true),
134
+ })).targetDirectory;
135
+ const { projectName } = await Enquirer.prompt({
136
+ type: "input",
137
+ name: "projectName",
138
+ message: "npm project name",
139
+ initial: basename(resolve(targetDirectory)),
140
+ validate: npmProjectName,
141
+ });
142
+ const { capabilities } = await Enquirer.prompt({
143
+ type: "multiselect",
144
+ name: "capabilities",
145
+ message: multiSelectPromptMessage("Optional capabilities"),
146
+ choices: PROJECT_CAPABILITIES.map((capability) => ({
147
+ name: capability,
148
+ message: capabilityLabels[capability],
149
+ })),
150
+ });
151
+ const { agentTargets } = await Enquirer.prompt({
152
+ type: "multiselect",
153
+ name: "agentTargets",
154
+ message: multiSelectPromptMessage("Agent instruction targets"),
155
+ choices: AGENT_TARGETS.map((target) => ({
156
+ name: target,
157
+ message: agentTargetLabels[target],
158
+ ...(agentTargetHints[target] === undefined ? {} : { hint: agentTargetHints[target] }),
159
+ })),
160
+ });
161
+ const { packageManager } = await Enquirer.prompt({
162
+ type: "select",
163
+ name: "packageManager",
164
+ message: "Package manager",
165
+ choices: PACKAGE_MANAGERS.map((manager) => ({
166
+ name: manager,
167
+ message: packageManagerLabels[manager],
168
+ })),
169
+ initial: PACKAGE_MANAGERS.indexOf("pnpm"),
170
+ });
171
+ const { shouldInstall } = await Enquirer.prompt({
172
+ type: "confirm",
173
+ name: "shouldInstall",
174
+ message: `Install dependencies with ${packageManager}?`,
175
+ initial: true,
176
+ });
177
+ const destination = resolve(targetDirectory);
178
+ const { confirmed } = await Enquirer.prompt({
179
+ type: "confirm",
180
+ name: "confirmed",
181
+ message: `Create ${projectName} at ${destination}? Capabilities: ${selectedLabel(capabilities.map((capability) => capabilityLabels[capability]))}. Agents: ${selectedLabel(agentTargets.map((target) => agentTargetLabels[target]))}. Package manager: ${packageManager}. Install dependencies: ${shouldInstall ? "yes" : "no"}.`,
182
+ initial: true,
183
+ });
184
+ if (!confirmed) {
185
+ console.info("Project creation cancelled; no files were written.");
186
+ return;
187
+ }
188
+ const receipt = await scaffoldProject({
189
+ targetDirectory: destination,
190
+ projectName,
191
+ capabilities,
192
+ agentTargets,
193
+ packageManager,
194
+ });
195
+ console.info(`Created ${receipt.projectName} at ${receipt.targetDirectory} with ${selectedLabel(receipt.capabilities.map((capability) => capabilityLabels[capability]))} capabilities.`);
196
+ if (shouldInstall) {
197
+ console.info(`Installing dependencies with ${packageManager}...`);
198
+ try {
199
+ await installProjectDependencies(packageManager, receipt.targetDirectory);
200
+ }
201
+ catch (error) {
202
+ throw new Error(installFailureMessage(packageManager, receipt.targetDirectory, error), {
203
+ cause: error,
204
+ });
205
+ }
206
+ console.info(`Installed dependencies with ${packageManager}.`);
207
+ }
208
+ const commands = followUpCommands(packageManager, {
209
+ includeInstall: !shouldInstall,
210
+ includeAgentGeneration: receipt.agentTargets.length > 0,
211
+ });
212
+ console.info(`Next steps (run in ${receipt.targetDirectory}):\n${commands
213
+ .map((command) => ` ${command}`)
214
+ .join("\n")}`);
215
+ }
216
+ export async function runCli(argv) {
217
+ const parsed = parseCliArgs(argv);
218
+ if (parsed.help) {
219
+ console.info(usage);
220
+ return;
221
+ }
222
+ await runWizard(parsed.targetDirectory);
223
+ }
224
+ function isCliEntrypoint() {
225
+ const invokedPath = process.argv[1];
226
+ if (invokedPath === undefined)
227
+ return false;
228
+ if (resolve(invokedPath) === resolve(fileURLToPath(import.meta.url)))
229
+ return true;
230
+ return /^create-slicemedia-devkit(?:\.js)?$/u.test(basename(invokedPath));
231
+ }
232
+ if (isCliEntrypoint()) {
233
+ try {
234
+ await runCli(process.argv.slice(2));
235
+ }
236
+ catch (error) {
237
+ console.error(error instanceof Error ? error.message : String(error));
238
+ process.exitCode = 1;
239
+ }
240
+ }
@@ -0,0 +1,2 @@
1
+ export { AGENT_TARGETS, PACKAGE_MANAGERS, PROJECT_CAPABILITIES, scaffoldProject, type AgentTarget, type PackageManager, type ProjectCapability, type ScaffoldOptions, type ScaffoldReceipt, } from "./scaffold.js";
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EACb,gBAAgB,EAChB,oBAAoB,EACpB,eAAe,EACf,KAAK,WAAW,EAChB,KAAK,cAAc,EACnB,KAAK,iBAAiB,EACtB,KAAK,eAAe,EACpB,KAAK,eAAe,GACrB,MAAM,eAAe,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1 @@
1
+ export { AGENT_TARGETS, PACKAGE_MANAGERS, PROJECT_CAPABILITIES, scaffoldProject, } from "./scaffold.js";
@@ -0,0 +1,33 @@
1
+ export declare const PROJECT_CAPABILITIES: readonly ["slider", "animations", "tooltips", "digitalocean-spaces"];
2
+ export type ProjectCapability = (typeof PROJECT_CAPABILITIES)[number];
3
+ export declare const AGENT_TARGETS: readonly ["codex", "claude", "cursor", "copilot", "webflow"];
4
+ export type AgentTarget = (typeof AGENT_TARGETS)[number];
5
+ export declare const PACKAGE_MANAGERS: readonly ["pnpm", "npm", "yarn"];
6
+ export type PackageManager = (typeof PACKAGE_MANAGERS)[number];
7
+ export interface ScaffoldOptions {
8
+ targetDirectory: string;
9
+ projectName: string;
10
+ packageManager: PackageManager;
11
+ capabilities: readonly ProjectCapability[];
12
+ agentTargets: readonly AgentTarget[];
13
+ devkitVersion?: string;
14
+ agentKitVersion?: string;
15
+ swiperAdapterVersion?: string;
16
+ spacesDeployerVersion?: string;
17
+ templateRoot?: string;
18
+ }
19
+ export interface ScaffoldReceipt {
20
+ schemaVersion: 2;
21
+ projectName: string;
22
+ targetDirectory: string;
23
+ packageManager: PackageManager;
24
+ capabilities: readonly ProjectCapability[];
25
+ agentTargets: readonly AgentTarget[];
26
+ dependencies: Readonly<Record<string, string>>;
27
+ devDependencies: Readonly<Record<string, string>>;
28
+ integrationFiles: readonly string[];
29
+ agentGenerateCommand?: string;
30
+ writtenFiles: readonly string[];
31
+ }
32
+ export declare function scaffoldProject(options: ScaffoldOptions): Promise<ScaffoldReceipt>;
33
+ //# sourceMappingURL=scaffold.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scaffold.d.ts","sourceRoot":"","sources":["../src/scaffold.ts"],"names":[],"mappings":"AAmBA,eAAO,MAAM,oBAAoB,sEAKvB,CAAC;AAEX,MAAM,MAAM,iBAAiB,GAAG,CAAC,OAAO,oBAAoB,CAAC,CAAC,MAAM,CAAC,CAAC;AAEtE,eAAO,MAAM,aAAa,8DAA+D,CAAC;AAE1F,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,aAAa,CAAC,CAAC,MAAM,CAAC,CAAC;AAEzD,eAAO,MAAM,gBAAgB,kCAAmC,CAAC;AAEjE,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,gBAAgB,CAAC,CAAC,MAAM,CAAC,CAAC;AAE/D,MAAM,WAAW,eAAe;IAC9B,eAAe,EAAE,MAAM,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,cAAc,CAAC;IAC/B,YAAY,EAAE,SAAS,iBAAiB,EAAE,CAAC;IAC3C,YAAY,EAAE,SAAS,WAAW,EAAE,CAAC;IACrC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,eAAe;IAC9B,aAAa,EAAE,CAAC,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;IACxB,cAAc,EAAE,cAAc,CAAC;IAC/B,YAAY,EAAE,SAAS,iBAAiB,EAAE,CAAC;IAC3C,YAAY,EAAE,SAAS,WAAW,EAAE,CAAC;IACrC,YAAY,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAC/C,eAAe,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAClD,gBAAgB,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,YAAY,EAAE,SAAS,MAAM,EAAE,CAAC;CACjC;AAkcD,wBAAsB,eAAe,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,eAAe,CAAC,CAyDxF"}
@@ -0,0 +1,408 @@
1
+ import { lstat, mkdir, readdir, readFile, unlink, writeFile } from "node:fs/promises";
2
+ import { createRequire } from "node:module";
3
+ import { dirname, join, parse, relative, resolve } from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
+ import { DEFAULT_DEVKIT_VERSION_RANGE, EXTERNAL_PRODUCT_VERSION_RANGES, } from "./versions.generated.js";
6
+ const requireModule = createRequire(import.meta.url);
7
+ const semver = requireModule("semver");
8
+ const explicitSemverVersion = /^(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)(?:-[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/u;
9
+ const explicitSemverComparator = /^(?:[<>]=?|[=~^])?(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)(?:-[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/u;
10
+ export const PROJECT_CAPABILITIES = [
11
+ "slider",
12
+ "animations",
13
+ "tooltips",
14
+ "digitalocean-spaces",
15
+ ];
16
+ export const AGENT_TARGETS = ["codex", "claude", "cursor", "copilot", "webflow"];
17
+ export const PACKAGE_MANAGERS = ["pnpm", "npm", "yarn"];
18
+ const packageManagerMetadata = {
19
+ pnpm: "pnpm@11.21.0",
20
+ npm: "npm@10.9.8",
21
+ yarn: "yarn@4.18.0",
22
+ };
23
+ const packageManagerCommands = {
24
+ pnpm: {
25
+ install: "pnpm install",
26
+ dev: "pnpm dev",
27
+ typecheck: "pnpm typecheck",
28
+ build: "pnpm build",
29
+ catalog: "pnpm catalog -- --json",
30
+ devkit: "pnpm devkit -- <command>",
31
+ agentsGenerate: "pnpm agents:generate",
32
+ },
33
+ npm: {
34
+ install: "npm install",
35
+ dev: "npm run dev",
36
+ typecheck: "npm run typecheck",
37
+ build: "npm run build",
38
+ catalog: "npm run catalog -- --json",
39
+ devkit: "npm run devkit -- <command>",
40
+ agentsGenerate: "npm run agents:generate",
41
+ },
42
+ yarn: {
43
+ install: "yarn install",
44
+ dev: "yarn dev",
45
+ typecheck: "yarn typecheck",
46
+ build: "yarn build",
47
+ catalog: "yarn catalog --json",
48
+ devkit: "yarn devkit <command>",
49
+ agentsGenerate: "yarn agents:generate",
50
+ },
51
+ };
52
+ const baseDependencies = (versions) => ({
53
+ "@slicemedia/devkit-core": versions.devkit,
54
+ });
55
+ const capabilityDefinitions = {
56
+ slider: {
57
+ dependencies: (versions) => ({
58
+ "@slicemedia/swiper-adapter": versions.swiperAdapter,
59
+ swiper: "^14.1.0",
60
+ }),
61
+ integrationFile: "src/integrations/slider.ts",
62
+ renderIntegration: () => `import {
63
+ createResponsiveSwiper,
64
+ type ResponsiveSwiperController,
65
+ type ResponsiveSwiperOptions,
66
+ } from "@slicemedia/swiper-adapter";
67
+ import "swiper/css";
68
+
69
+ export const PROJECT_SLIDER_SELECTOR = "[data-wft-slider]" as const;
70
+
71
+ export type ProjectSliderOptions = Omit<ResponsiveSwiperOptions, "target"> & {
72
+ target?: ResponsiveSwiperOptions["target"];
73
+ };
74
+
75
+ export function createProjectSlider(
76
+ options: ProjectSliderOptions = {},
77
+ ): ResponsiveSwiperController {
78
+ const { target = PROJECT_SLIDER_SELECTOR, ...swiperOptions } = options;
79
+ return createResponsiveSwiper({
80
+ target,
81
+ observeMutations: true,
82
+ ...swiperOptions,
83
+ });
84
+ }
85
+ `,
86
+ },
87
+ animations: {
88
+ dependencies: () => ({ gsap: "^3.13.0" }),
89
+ integrationFile: "src/integrations/animations.ts",
90
+ renderIntegration: () => `import { gsap } from "gsap";
91
+
92
+ /** Project-owned GSAP entry point. Import this module from main.ts when the composition is ready. */
93
+ export { gsap };
94
+ `,
95
+ },
96
+ tooltips: {
97
+ dependencies: () => ({ "tippy.js": "^6.3.7" }),
98
+ integrationFile: "src/integrations/tooltips.ts",
99
+ renderIntegration: () => `import tippy, { type Instance, type MultipleTargets, type Props } from "tippy.js";
100
+ import "tippy.js/dist/tippy.css";
101
+
102
+ export const PROJECT_TOOLTIP_SELECTOR = "[data-wft-tooltip]" as const;
103
+
104
+ export function createProjectTooltips(
105
+ targets: MultipleTargets = PROJECT_TOOLTIP_SELECTOR,
106
+ options: Partial<Props> = {},
107
+ ): Instance[] {
108
+ return tippy(targets, options);
109
+ }
110
+ `,
111
+ },
112
+ "digitalocean-spaces": {
113
+ dependencies: (versions) => ({
114
+ "@slicemedia/spaces-deployer": versions.spacesDeployer,
115
+ }),
116
+ environmentVariables: [
117
+ "DIGITALOCEAN_SPACES_ACCESS_KEY_ID",
118
+ "DIGITALOCEAN_SPACES_SECRET_ACCESS_KEY",
119
+ "DIGITALOCEAN_SPACES_SESSION_TOKEN",
120
+ ],
121
+ integrationFile: "src/integrations/spaces-deployment.ts",
122
+ renderIntegration: () => `import {
123
+ applyDeploymentPlan,
124
+ createDeploymentPlan,
125
+ type SpacesDeploymentPlan,
126
+ type SpacesDeploymentReceipt,
127
+ } from "@slicemedia/spaces-deployer";
128
+
129
+ export interface ProjectSpacesPlanConfig {
130
+ directory: string;
131
+ endpoint: string;
132
+ region: string;
133
+ bucket: string;
134
+ prefix: string;
135
+ releaseVersion: string;
136
+ }
137
+
138
+ /** All deployment values are explicit; this helper supplies no account or project defaults. */
139
+ export function createProjectDeploymentPlan(
140
+ config: ProjectSpacesPlanConfig,
141
+ ): Promise<SpacesDeploymentPlan> {
142
+ return createDeploymentPlan(config);
143
+ }
144
+
145
+ export { applyDeploymentPlan };
146
+ export type { SpacesDeploymentPlan, SpacesDeploymentReceipt };
147
+ `,
148
+ },
149
+ };
150
+ function assertProjectName(name) {
151
+ if (!/^(?:@[a-z0-9][a-z0-9._-]*\/)?[a-z0-9][a-z0-9._-]*$/u.test(name)) {
152
+ throw new Error(`Invalid npm project name: ${name}`);
153
+ }
154
+ }
155
+ function hasExplicitSemverSyntax(value) {
156
+ const clauses = value.split(/\s*\|\|\s*/u);
157
+ return clauses.every((clause) => {
158
+ if (clause === "")
159
+ return false;
160
+ const hyphenRange = clause.match(/^(\S+)\s+-\s+(\S+)$/u);
161
+ if (hyphenRange !== null) {
162
+ return (explicitSemverVersion.test(hyphenRange[1] ?? "") &&
163
+ explicitSemverVersion.test(hyphenRange[2] ?? ""));
164
+ }
165
+ return clause.split(/\s+/u).every((token) => explicitSemverComparator.test(token));
166
+ });
167
+ }
168
+ function assertNpmSemverRange(value, label) {
169
+ if (typeof value !== "string" || value !== value.trim() || !hasExplicitSemverSyntax(value)) {
170
+ throw new Error(`${label} must be a controlled npm semantic-version range.`);
171
+ }
172
+ const normalizedRange = semver.validRange(value);
173
+ if (normalizedRange === null || normalizedRange === "*") {
174
+ throw new Error(`${label} must be a controlled npm semantic-version range.`);
175
+ }
176
+ }
177
+ function resolveVersions(options) {
178
+ const versions = {
179
+ devkit: options.devkitVersion ?? DEFAULT_DEVKIT_VERSION_RANGE,
180
+ agentKit: options.agentKitVersion ?? EXTERNAL_PRODUCT_VERSION_RANGES.agentKit,
181
+ swiperAdapter: options.swiperAdapterVersion ?? EXTERNAL_PRODUCT_VERSION_RANGES.swiperAdapter,
182
+ spacesDeployer: options.spacesDeployerVersion ?? EXTERNAL_PRODUCT_VERSION_RANGES.spacesDeployer,
183
+ };
184
+ for (const [name, version] of Object.entries(versions)) {
185
+ assertNpmSemverRange(version, `${name} version`);
186
+ }
187
+ return versions;
188
+ }
189
+ function defaultTemplateRoot() {
190
+ return resolve(dirname(fileURLToPath(import.meta.url)), "template");
191
+ }
192
+ function isMissing(error) {
193
+ return (typeof error === "object" &&
194
+ error !== null &&
195
+ "code" in error &&
196
+ error.code === "ENOENT");
197
+ }
198
+ function selectKnown(requested, supported, label) {
199
+ const unsupported = requested.filter((value) => !supported.includes(value));
200
+ if (unsupported.length > 0)
201
+ throw new Error(`Unsupported ${label}: ${unsupported.join(", ")}`);
202
+ const selected = new Set(requested);
203
+ return supported.filter((value) => selected.has(value));
204
+ }
205
+ async function assertNewProjectTarget(target) {
206
+ const targetStat = await lstat(target).catch((error) => {
207
+ if (isMissing(error))
208
+ return undefined;
209
+ throw error;
210
+ });
211
+ if (targetStat === undefined)
212
+ return;
213
+ if (!targetStat.isDirectory() || targetStat.isSymbolicLink()) {
214
+ throw new Error("Target must be a new directory or an existing empty directory.");
215
+ }
216
+ if ((await readdir(target)).length > 0) {
217
+ throw new Error("Target directory is not empty. Choose a new project directory.");
218
+ }
219
+ }
220
+ async function copyTree(source, destination) {
221
+ await mkdir(destination, { recursive: true });
222
+ for (const entry of await readdir(source, { withFileTypes: true })) {
223
+ if (["node_modules", "dist", ".slicemedia"].includes(entry.name))
224
+ continue;
225
+ const from = join(source, entry.name);
226
+ const destinationName = entry.name === "gitignore.template"
227
+ ? ".gitignore"
228
+ : entry.name === "npmrc.template"
229
+ ? ".npmrc"
230
+ : entry.name;
231
+ const to = join(destination, destinationName);
232
+ if (entry.isDirectory()) {
233
+ await copyTree(from, to);
234
+ continue;
235
+ }
236
+ await mkdir(dirname(to), { recursive: true });
237
+ await writeFile(to, await readFile(from), { flag: "wx" });
238
+ }
239
+ }
240
+ async function listFiles(root) {
241
+ const files = [];
242
+ async function visit(directory) {
243
+ for (const entry of await readdir(directory, { withFileTypes: true })) {
244
+ const path = join(directory, entry.name);
245
+ if (entry.isDirectory())
246
+ await visit(path);
247
+ else if (entry.isFile())
248
+ files.push(relative(root, path));
249
+ }
250
+ }
251
+ await visit(root);
252
+ return files.sort();
253
+ }
254
+ async function removeFileIfPresent(path) {
255
+ await unlink(path).catch((error) => {
256
+ if (!isMissing(error))
257
+ throw error;
258
+ });
259
+ }
260
+ async function configurePackageManagerFiles(target, packageManager) {
261
+ const npmrcPath = join(target, ".npmrc");
262
+ const yarnrcPath = join(target, ".yarnrc.yml");
263
+ if (packageManager === "pnpm") {
264
+ await removeFileIfPresent(yarnrcPath);
265
+ await writeFile(npmrcPath, "engine-strict=true\nminimum-release-age-strict=true\nsave-exact=true\n");
266
+ return;
267
+ }
268
+ if (packageManager === "npm") {
269
+ await removeFileIfPresent(yarnrcPath);
270
+ await writeFile(npmrcPath, "engine-strict=true\nsave-exact=true\n");
271
+ return;
272
+ }
273
+ await removeFileIfPresent(npmrcPath);
274
+ await writeFile(yarnrcPath, "nodeLinker: node-modules\n");
275
+ const gitignorePath = join(target, ".gitignore");
276
+ const gitignore = await readFile(gitignorePath, "utf8");
277
+ if (!gitignore.split(/\r?\n/u).includes(".yarn/install-state.gz")) {
278
+ const separator = gitignore.endsWith("\n") ? "" : "\n";
279
+ await writeFile(gitignorePath, `${gitignore}${separator}.yarn/install-state.gz\n`);
280
+ }
281
+ }
282
+ async function configureReadme(target, packageManager) {
283
+ if (packageManager === "pnpm")
284
+ return;
285
+ const readmePath = join(target, "README.md");
286
+ let readme = await readFile(readmePath, "utf8");
287
+ const pnpmCommands = packageManagerCommands.pnpm;
288
+ const selectedCommands = packageManagerCommands[packageManager];
289
+ const replacements = Object.keys(pnpmCommands).map((command) => [pnpmCommands[command], selectedCommands[command]]);
290
+ replacements.sort(([left], [right]) => right.length - left.length);
291
+ for (const [pnpmCommand, selectedCommand] of replacements) {
292
+ readme = readme.replaceAll(pnpmCommand, selectedCommand);
293
+ }
294
+ await writeFile(readmePath, readme);
295
+ }
296
+ function capabilityDependencies(capabilities, versions) {
297
+ const dependencies = Object.assign({}, baseDependencies(versions), ...capabilities.map((capability) => capabilityDefinitions[capability].dependencies(versions)));
298
+ return Object.fromEntries(Object.entries(dependencies).sort(([left], [right]) => left.localeCompare(right)));
299
+ }
300
+ async function configureEnvironment(target, capabilities) {
301
+ const variables = capabilities.flatMap((capability) => capabilityDefinitions[capability].environmentVariables ?? []);
302
+ if (variables.length === 0)
303
+ return;
304
+ const environmentPath = join(target, ".env.example");
305
+ const source = await readFile(environmentPath, "utf8");
306
+ const separator = source.endsWith("\n") ? "\n" : "\n\n";
307
+ await writeFile(environmentPath, `${source}${separator}${variables.map((variable) => `${variable}=`).join("\n")}\n`);
308
+ }
309
+ async function configurePackage(target, projectName, packageManager, capabilities, agentTargets, versions) {
310
+ const packagePath = join(target, "package.json");
311
+ const packageJson = JSON.parse(await readFile(packagePath, "utf8"));
312
+ const dependencies = capabilityDependencies(capabilities, versions);
313
+ const devDependencies = { ...packageJson.devDependencies };
314
+ for (const dependency of Object.keys(devDependencies)) {
315
+ if (dependency.startsWith("@slicemedia/"))
316
+ delete devDependencies[dependency];
317
+ }
318
+ devDependencies["@slicemedia/devkit-cli"] = versions.devkit;
319
+ const agentGenerateCommand = agentTargets.length === 0
320
+ ? undefined
321
+ : `slicemedia-agent-kit generate --root . --profile project --targets ${agentTargets.join(",")}`;
322
+ if (agentGenerateCommand !== undefined) {
323
+ devDependencies["@slicemedia/agent-kit"] = versions.agentKit;
324
+ }
325
+ packageJson.name = projectName;
326
+ packageJson.packageManager = packageManagerMetadata[packageManager];
327
+ packageJson.dependencies = dependencies;
328
+ packageJson.devDependencies = Object.fromEntries(Object.entries(devDependencies).sort(([left], [right]) => left.localeCompare(right)));
329
+ packageJson.scripts = { ...packageJson.scripts };
330
+ if (agentGenerateCommand === undefined)
331
+ delete packageJson.scripts["agents:generate"];
332
+ else
333
+ packageJson.scripts["agents:generate"] = agentGenerateCommand;
334
+ await writeFile(packagePath, `${JSON.stringify(packageJson, null, 2)}\n`);
335
+ return {
336
+ dependencies,
337
+ devDependencies: packageJson.devDependencies,
338
+ ...(agentGenerateCommand === undefined ? {} : { agentGenerateCommand }),
339
+ };
340
+ }
341
+ async function writeIntegrations(target, capabilities) {
342
+ const files = [];
343
+ for (const capability of capabilities) {
344
+ const definition = capabilityDefinitions[capability];
345
+ const path = join(target, definition.integrationFile);
346
+ await mkdir(dirname(path), { recursive: true });
347
+ await writeFile(path, definition.renderIntegration(), { flag: "wx" });
348
+ files.push(definition.integrationFile);
349
+ }
350
+ return files;
351
+ }
352
+ async function configureDevKitEntry(target, capabilities) {
353
+ const configPath = join(target, "devkit.config.json");
354
+ const config = JSON.parse(await readFile(configPath, "utf8"));
355
+ if (config.entries?.length !== 1 || config.entries[0] === undefined) {
356
+ throw new Error("Starter devkit.config.json must declare exactly one project entry.");
357
+ }
358
+ config.entries[0].api = { ...config.entries[0].api, capabilities };
359
+ await writeFile(configPath, `${JSON.stringify(config, null, 2)}\n`);
360
+ }
361
+ export async function scaffoldProject(options) {
362
+ if (options.targetDirectory.trim() === "")
363
+ throw new Error("Target directory must not be empty.");
364
+ const target = resolve(options.targetDirectory);
365
+ if (target === parse(target).root) {
366
+ throw new Error("Refusing to scaffold into a filesystem root.");
367
+ }
368
+ assertProjectName(options.projectName);
369
+ if (options.packageManager === undefined)
370
+ throw new Error("Package manager must be selected.");
371
+ const [packageManager] = selectKnown([options.packageManager], PACKAGE_MANAGERS, "package manager");
372
+ if (packageManager === undefined)
373
+ throw new Error("Package manager must be selected.");
374
+ const capabilities = selectKnown(options.capabilities, PROJECT_CAPABILITIES, "capabilities");
375
+ const agentTargets = selectKnown(options.agentTargets, AGENT_TARGETS, "agent targets");
376
+ const versions = resolveVersions(options);
377
+ await assertNewProjectTarget(target);
378
+ await mkdir(target, { recursive: true });
379
+ await copyTree(options.templateRoot ?? defaultTemplateRoot(), target);
380
+ await configurePackageManagerFiles(target, packageManager);
381
+ await configureReadme(target, packageManager);
382
+ const configuredPackage = await configurePackage(target, options.projectName, packageManager, capabilities, agentTargets, versions);
383
+ const integrationFiles = await writeIntegrations(target, capabilities);
384
+ await configureEnvironment(target, capabilities);
385
+ await configureDevKitEntry(target, capabilities);
386
+ const receiptPath = ".slicemedia/devkit/scaffold-receipt.json";
387
+ await mkdir(join(target, ".slicemedia", "devkit"), { recursive: true });
388
+ const writtenFiles = [...(await listFiles(target)), receiptPath].sort();
389
+ const receipt = {
390
+ schemaVersion: 2,
391
+ projectName: options.projectName,
392
+ targetDirectory: target,
393
+ packageManager,
394
+ capabilities,
395
+ agentTargets,
396
+ dependencies: configuredPackage.dependencies,
397
+ devDependencies: configuredPackage.devDependencies,
398
+ integrationFiles,
399
+ ...(configuredPackage.agentGenerateCommand === undefined
400
+ ? {}
401
+ : { agentGenerateCommand: configuredPackage.agentGenerateCommand }),
402
+ writtenFiles,
403
+ };
404
+ await writeFile(join(target, receiptPath), `${JSON.stringify(receipt, null, 2)}\n`, {
405
+ flag: "wx",
406
+ });
407
+ return receipt;
408
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=sync-template.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync-template.d.ts","sourceRoot":"","sources":["../src/sync-template.ts"],"names":[],"mappings":""}
@@ -0,0 +1,25 @@
1
+ import { cp, mkdir, readdir, rm } from "node:fs/promises";
2
+ import { dirname, join, resolve } from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ const output = resolve(dirname(fileURLToPath(import.meta.url)), "template");
5
+ const source = resolve(dirname(fileURLToPath(import.meta.url)), "../../../templates/starter");
6
+ async function copy(sourceDirectory, outputDirectory) {
7
+ await mkdir(outputDirectory, { recursive: true });
8
+ for (const entry of await readdir(sourceDirectory, { withFileTypes: true })) {
9
+ if (["node_modules", "dist", ".slicemedia"].includes(entry.name))
10
+ continue;
11
+ const from = join(sourceDirectory, entry.name);
12
+ const packagedName = entry.name === ".gitignore"
13
+ ? "gitignore.template"
14
+ : entry.name === ".npmrc"
15
+ ? "npmrc.template"
16
+ : entry.name;
17
+ const to = join(outputDirectory, packagedName);
18
+ if (entry.isDirectory())
19
+ await copy(from, to);
20
+ else
21
+ await cp(from, to);
22
+ }
23
+ }
24
+ await rm(output, { recursive: true, force: true });
25
+ await copy(source, output);
@@ -0,0 +1,4 @@
1
+ SLICEMEDIA_WEBFLOW_SITE_ID=
2
+ WEBFLOW_STAGING_DOMAIN=
3
+ WEBFLOW_OAUTH_ACCESS_TOKEN=
4
+ WEBFLOW_API_TOKEN=
@@ -0,0 +1 @@
1
+ 22.23.2
@@ -0,0 +1,30 @@
1
+ # Webflow project
2
+
3
+ This project owns its Webflow markup, composition, configuration, and deployment choices. The base
4
+ starter is deliberately neutral: no optional capability is imported by `src/main.ts`.
5
+
6
+ ## Local development
7
+
8
+ 1. Run `pnpm install`.
9
+ 2. Run `pnpm dev` for the CORS-enabled local development server.
10
+ 3. Author the Webflow markup contract with `data-wft-*` behavior hooks.
11
+ 4. Import only the generated files under `src/integrations/` that the project is ready to compose.
12
+ 5. Run `pnpm typecheck` and `pnpm build`.
13
+
14
+ The build emits one project-owned ES2018 IIFE at `dist/project.js` and, when styles are imported,
15
+ `dist/project.css`. `pnpm catalog -- --json` inspects the single project entry. Use
16
+ `pnpm devkit -- <command>` for other DevKit commands.
17
+
18
+ The project-owned `WEBFLOW_PROJECT.md` is always present. If agent targets were selected, run
19
+ `pnpm agents:generate` after installation. Slice Media Agent Kit preserves that guide and creates
20
+ only the requested Codex, Claude, Cursor, Copilot, or Webflow files; it is maintained in a separate
21
+ repository.
22
+
23
+ Connect an AI client to the official Webflow MCP server at `https://mcp.webflow.com/mcp`. Generated
24
+ Agent Kit guidance directs most page, component, style, CMS, asset, and script work through
25
+ headless tools. Open the Webflow MCP Bridge App only for live selection, canvas, mode, branch,
26
+ breakpoint, or visual snapshot context. Remote writes and publishing require an explicit request
27
+ and the matching generated skill.
28
+
29
+ Copy `.env.example` to an ignored local file only when needed, and load it through your shell or CI.
30
+ Never commit site IDs, domains, tokens, deployment credentials, or client fixtures.
@@ -0,0 +1,15 @@
1
+ # Webflow project guidance
2
+
3
+ Webflow owns editable structure, components, styles, CMS content, forms, and native interactions.
4
+ This project owns only the browser enhancements explicitly composed in `src/main.ts`.
5
+
6
+ - Prefer native Webflow features before adding code.
7
+ - Use documented, scoped `data-wft-*` hooks instead of generated classes or guessed identifiers.
8
+ - Keep optional files under `src/integrations/` disconnected until their markup contract is ready.
9
+ - Make initialization idempotent and restore owned DOM, attributes, listeners, observers, and timers
10
+ during teardown.
11
+ - Inspect before remote work. Webflow writes and publishing require an explicit request, review,
12
+ read-back, and verification through the official Webflow MCP server.
13
+
14
+ Install Slice Media Agent Kit only when this project needs platform-specific agent instructions.
15
+ Generate only the targets used by the team.
@@ -0,0 +1,18 @@
1
+ {
2
+ "entries": [
3
+ {
4
+ "name": "project",
5
+ "input": "src/main.ts",
6
+ "version": "0.1.0",
7
+ "description": "Project-owned Webflow browser entry.",
8
+ "placement": "body-end",
9
+ "dependencies": [],
10
+ "attributes": [],
11
+ "scriptAttributes": {},
12
+ "api": {
13
+ "entry": "webflow-project",
14
+ "capabilities": []
15
+ }
16
+ }
17
+ ]
18
+ }
@@ -0,0 +1,8 @@
1
+ node_modules/
2
+ dist/
3
+ .env
4
+ .env.*
5
+ !.env.example
6
+ .webflow/
7
+ .slicemedia/
8
+ *.local
@@ -0,0 +1,11 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>Webflow project</title>
7
+ </head>
8
+ <body>
9
+ <script type="module" src="/src/main.ts"></script>
10
+ </body>
11
+ </html>
@@ -0,0 +1,3 @@
1
+ engine-strict=true
2
+ minimum-release-age-strict=true
3
+ save-exact=true
@@ -0,0 +1,26 @@
1
+ {
2
+ "name": "webflow-project",
3
+ "version": "0.1.0",
4
+ "private": true,
5
+ "description": "Neutral project generated by Slice Media DevKit.",
6
+ "type": "module",
7
+ "packageManager": "pnpm@11.21.0",
8
+ "scripts": {
9
+ "build": "slicemedia-devkit build --entry src/main.ts --out-dir dist --script-file project.js --css-file project.css",
10
+ "catalog": "slicemedia-devkit catalog --root .",
11
+ "dev": "slicemedia-devkit dev",
12
+ "sanitize": "slicemedia-devkit sanitize --root .",
13
+ "devkit": "slicemedia-devkit",
14
+ "typecheck": "tsc --noEmit"
15
+ },
16
+ "dependencies": {
17
+ "@slicemedia/devkit-core": "workspace:*"
18
+ },
19
+ "devDependencies": {
20
+ "@slicemedia/devkit-cli": "workspace:*",
21
+ "typescript": "6.0.3"
22
+ },
23
+ "engines": {
24
+ "node": ">=22.13.0 <23 || >=24.0.0 <25"
25
+ }
26
+ }
@@ -0,0 +1,12 @@
1
+ import "./styles.css";
2
+ import { initProject } from "./project.js";
3
+
4
+ const start = (): void => {
5
+ initProject();
6
+ };
7
+
8
+ if (document.readyState === "loading") {
9
+ document.addEventListener("DOMContentLoaded", start, { once: true });
10
+ } else {
11
+ start();
12
+ }
@@ -0,0 +1,16 @@
1
+ let initialized = false;
2
+
3
+ /** Compose project-owned integrations here when their Webflow markup contract is ready. */
4
+ export function initProject(): void {
5
+ if (initialized) return;
6
+ initialized = true;
7
+ }
8
+
9
+ export function refreshProject(): void {
10
+ if (!initialized) return;
11
+ }
12
+
13
+ export function destroyProject(): void {
14
+ if (!initialized) return;
15
+ initialized = false;
16
+ }
@@ -0,0 +1 @@
1
+ /* Add project-owned styles only when the Webflow composition requires them. */
@@ -0,0 +1 @@
1
+ declare module "*.css";
@@ -0,0 +1,16 @@
1
+ {
2
+ "compilerOptions": {
3
+ "exactOptionalPropertyTypes": true,
4
+ "lib": ["ES2022", "DOM", "DOM.Iterable"],
5
+ "module": "ESNext",
6
+ "moduleResolution": "Bundler",
7
+ "noEmit": true,
8
+ "noUncheckedIndexedAccess": true,
9
+ "skipLibCheck": true,
10
+ "strict": true,
11
+ "target": "ES2022",
12
+ "useDefineForClassFields": true,
13
+ "verbatimModuleSyntax": true
14
+ },
15
+ "include": ["src/**/*.ts"]
16
+ }
@@ -0,0 +1,9 @@
1
+ /** Generated by scripts/sync-versions.mjs. Do not edit by hand. */
2
+ export declare const DEVKIT_PACKAGE_VERSION = "0.1.1";
3
+ export declare const DEFAULT_DEVKIT_VERSION_RANGE = "^0.1.1";
4
+ export declare const EXTERNAL_PRODUCT_VERSION_RANGES: {
5
+ readonly agentKit: "^0.1.0";
6
+ readonly swiperAdapter: "^0.1.0";
7
+ readonly spacesDeployer: "^0.1.0";
8
+ };
9
+ //# sourceMappingURL=versions.generated.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"versions.generated.d.ts","sourceRoot":"","sources":["../src/versions.generated.ts"],"names":[],"mappings":"AAAA,mEAAmE;AACnE,eAAO,MAAM,sBAAsB,UAAU,CAAC;AAC9C,eAAO,MAAM,4BAA4B,WAAW,CAAC;AAErD,eAAO,MAAM,+BAA+B;;;;CAIlC,CAAC"}
@@ -0,0 +1,8 @@
1
+ /** Generated by scripts/sync-versions.mjs. Do not edit by hand. */
2
+ export const DEVKIT_PACKAGE_VERSION = "0.1.1";
3
+ export const DEFAULT_DEVKIT_VERSION_RANGE = "^0.1.1";
4
+ export const EXTERNAL_PRODUCT_VERSION_RANGES = {
5
+ agentKit: "^0.1.0",
6
+ swiperAdapter: "^0.1.0",
7
+ spacesDeployer: "^0.1.0",
8
+ };
package/package.json CHANGED
@@ -1,20 +1,60 @@
1
1
  {
2
2
  "name": "@slicemedia/create-devkit",
3
- "version": "0.0.0-bootstrap.0",
4
- "description": "Bootstrap placeholder for the @slicemedia/create-devkit package identity; not a functional release.",
5
- "private": false,
6
- "license": "MIT",
3
+ "version": "0.1.1",
4
+ "description": "Interactive project wizard for Slice Media DevKit.",
7
5
  "author": "Slice Media",
8
- "files": ["README.md", "LICENSE"],
9
6
  "repository": {
10
7
  "type": "git",
11
- "url": "git+https://github.com/slicemedia/devkit.git"
8
+ "url": "git+https://github.com/slicemedia/devkit.git",
9
+ "directory": "packages/create-devkit"
12
10
  },
13
- "homepage": "https://github.com/slicemedia/devkit#readme",
11
+ "homepage": "https://github.com/slicemedia/devkit/tree/main/packages/create-devkit#readme",
14
12
  "bugs": {
15
13
  "url": "https://github.com/slicemedia/devkit/issues"
16
14
  },
15
+ "keywords": [
16
+ "slicemedia",
17
+ "webflow",
18
+ "starter",
19
+ "scaffolding",
20
+ "typescript"
21
+ ],
22
+ "type": "module",
23
+ "private": false,
24
+ "license": "MIT",
25
+ "files": [
26
+ "bin",
27
+ "dist",
28
+ "README.md",
29
+ "LICENSE"
30
+ ],
31
+ "bin": {
32
+ "create-slicemedia-devkit": "./bin/create-slicemedia-devkit.js"
33
+ },
34
+ "exports": {
35
+ ".": {
36
+ "types": "./dist/index.d.ts",
37
+ "import": "./dist/index.js"
38
+ }
39
+ },
40
+ "dependencies": {
41
+ "enquirer": "2.4.1",
42
+ "semver": "7.8.5"
43
+ },
44
+ "devDependencies": {
45
+ "@types/node": "^22.20.1"
46
+ },
47
+ "engines": {
48
+ "node": ">=22.13.0 <23 || >=24.0.0 <25"
49
+ },
17
50
  "publishConfig": {
18
- "access": "public"
51
+ "access": "public",
52
+ "provenance": true
53
+ },
54
+ "scripts": {
55
+ "build": "tsc -p tsconfig.build.json && node dist/sync-template.js",
56
+ "lint": "eslint src",
57
+ "test": "vitest run --root ../.. packages/create-devkit/src",
58
+ "typecheck": "tsc -p tsconfig.json --noEmit"
19
59
  }
20
- }
60
+ }