@vttforge/cli 0.0.0 → 0.5.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.
Files changed (67) hide show
  1. package/CHANGELOG.md +364 -0
  2. package/LICENSE +21 -0
  3. package/README.md +33 -5
  4. package/dist/bin.d.mts +1 -0
  5. package/dist/bin.mjs +201 -0
  6. package/dist/bin.mjs.map +1 -0
  7. package/dist/index.d.mts +496 -0
  8. package/dist/index.mjs +2 -0
  9. package/dist/src-CWhUNM__.mjs +2443 -0
  10. package/dist/src-CWhUNM__.mjs.map +1 -0
  11. package/package.json +62 -9
  12. package/templates/module-js/.github/workflows/release.yml +92 -0
  13. package/templates/module-js/README.md +57 -0
  14. package/templates/module-js/_gitignore +12 -0
  15. package/templates/module-js/lang/en.json +11 -0
  16. package/templates/module-js/module.json +20 -0
  17. package/templates/module-js/package.json +24 -0
  18. package/templates/module-js/scripts/main.mjs +65 -0
  19. package/templates/module-js/styles/main.css +16 -0
  20. package/templates/module-js/vite.config.mjs +13 -0
  21. package/templates/module-ts/.github/workflows/release.yml +92 -0
  22. package/templates/module-ts/README.md +57 -0
  23. package/templates/module-ts/_gitignore +12 -0
  24. package/templates/module-ts/lang/en.json +11 -0
  25. package/templates/module-ts/module.json +20 -0
  26. package/templates/module-ts/package.json +26 -0
  27. package/templates/module-ts/scripts/foundry-globals.ts +23 -0
  28. package/templates/module-ts/scripts/main.ts +71 -0
  29. package/templates/module-ts/styles/main.css +16 -0
  30. package/templates/module-ts/tsconfig.json +18 -0
  31. package/templates/module-ts/vite.config.mjs +13 -0
  32. package/templates/system-js/.github/workflows/release.yml +92 -0
  33. package/templates/system-js/README.md +57 -0
  34. package/templates/system-js/_gitignore +12 -0
  35. package/templates/system-js/lang/en.json +55 -0
  36. package/templates/system-js/package.json +25 -0
  37. package/templates/system-js/scripts/data/character-data.mjs +79 -0
  38. package/templates/system-js/scripts/data/gear-data.mjs +37 -0
  39. package/templates/system-js/scripts/main.mjs +79 -0
  40. package/templates/system-js/scripts/migrations.mjs +43 -0
  41. package/templates/system-js/scripts/sheets/character-sheet.mjs +164 -0
  42. package/templates/system-js/scripts/sheets/gear-sheet.mjs +65 -0
  43. package/templates/system-js/styles/main.css +495 -0
  44. package/templates/system-js/system.json +44 -0
  45. package/templates/system-js/template.json +8 -0
  46. package/templates/system-js/templates/actor/character-sheet.hbs +168 -0
  47. package/templates/system-js/templates/item/gear-sheet.hbs +54 -0
  48. package/templates/system-js/vite.config.mjs +16 -0
  49. package/templates/system-ts/.github/workflows/release.yml +92 -0
  50. package/templates/system-ts/README.md +57 -0
  51. package/templates/system-ts/_gitignore +12 -0
  52. package/templates/system-ts/lang/en.json +55 -0
  53. package/templates/system-ts/package.json +27 -0
  54. package/templates/system-ts/scripts/data/character-data.ts +81 -0
  55. package/templates/system-ts/scripts/data/gear-data.ts +37 -0
  56. package/templates/system-ts/scripts/foundry-globals.ts +33 -0
  57. package/templates/system-ts/scripts/main.ts +82 -0
  58. package/templates/system-ts/scripts/migrations.ts +43 -0
  59. package/templates/system-ts/scripts/sheets/character-sheet.ts +202 -0
  60. package/templates/system-ts/scripts/sheets/gear-sheet.ts +68 -0
  61. package/templates/system-ts/styles/main.css +495 -0
  62. package/templates/system-ts/system.json +44 -0
  63. package/templates/system-ts/template.json +8 -0
  64. package/templates/system-ts/templates/actor/character-sheet.hbs +168 -0
  65. package/templates/system-ts/templates/item/gear-sheet.hbs +54 -0
  66. package/templates/system-ts/tsconfig.json +18 -0
  67. package/templates/system-ts/vite.config.mjs +16 -0
@@ -0,0 +1,496 @@
1
+ import { ChildProcess } from "node:child_process";
2
+ //#region src/audit/types.d.ts
3
+ /**
4
+ * Shared types for the `vttforge audit` rule engine.
5
+ *
6
+ * The audit catalog covers seven v13 footguns from the VTTForge audit
7
+ * spec. Each rule produces zero or more `RuleResult` entries; the
8
+ * orchestrator aggregates them into an `AuditReport` which the reporter
9
+ * renders as JSON or markdown.
10
+ *
11
+ * The CLI never touches the source tree — audit is purely read-only.
12
+ */
13
+ type Severity = 'HIGH' | 'MEDIUM' | 'LOW';
14
+ interface RuleResult {
15
+ /** Stable identifier — used by users to suppress / pin / look up specific rules. */
16
+ ruleId: string;
17
+ /** Human title. Shown in markdown report headers. */
18
+ title: string;
19
+ severity: Severity;
20
+ /** Absolute or project-relative path of the file the finding refers to. */
21
+ filePath: string;
22
+ /** Optional line number (1-based) inside `filePath`. */
23
+ line?: number;
24
+ /** One-line description of what was found. */
25
+ message: string;
26
+ /** Optional follow-up describing how to fix it. */
27
+ remediation?: string;
28
+ }
29
+ interface AuditReport {
30
+ /** Project root the audit ran against. */
31
+ cwd: string;
32
+ /** ISO timestamp of when the run started. */
33
+ startedAt: string;
34
+ /** Findings, ordered by severity then by ruleId. */
35
+ findings: ReadonlyArray<RuleResult>;
36
+ /** Per-severity tallies, for exit-code logic and report headers. */
37
+ counts: {
38
+ HIGH: number;
39
+ MEDIUM: number;
40
+ LOW: number;
41
+ };
42
+ }
43
+ /** Severity rank for sorting (HIGH first). */
44
+ declare const SEVERITY_RANK: Record<Severity, number>;
45
+ /**
46
+ * A rule is a plain function over the project root. Manifest rules parse
47
+ * `system.json` / `module.json`; source rules walk `scripts/` / `src/`.
48
+ * Rules return their own findings — the orchestrator stitches them
49
+ * together. Pure functions over the filesystem so tests inject tmp dirs.
50
+ */
51
+ type RuleFn = (cwd: string) => Promise<RuleResult[]> | RuleResult[];
52
+ //#endregion
53
+ //#region src/audit/index.d.ts
54
+ interface RunAuditOptions {
55
+ cwd: string;
56
+ }
57
+ declare function runAudit(options: RunAuditOptions): Promise<AuditReport>;
58
+ //#endregion
59
+ //#region src/audit/manifest-rules.d.ts
60
+ /**
61
+ * Entry point: run every manifest rule against every manifest at the
62
+ * project root.
63
+ */
64
+ declare function runManifestRules(cwd: string): Promise<RuleResult[]>;
65
+ //#endregion
66
+ //#region src/audit/reporter.d.ts
67
+ type ReportFormat = 'json' | 'markdown';
68
+ declare function formatReport(report: AuditReport, format: ReportFormat): string;
69
+ //#endregion
70
+ //#region src/audit/source-rules.d.ts
71
+ /** Entry point: gather everything once, then dispatch to the per-file rules. */
72
+ declare function runSourceRules(cwd: string): Promise<RuleResult[]>;
73
+ //#endregion
74
+ //#region src/commands/audit.d.ts
75
+ interface AuditOptions {
76
+ /** Project root to scan. Defaults to `process.cwd()`. */
77
+ cwd?: string;
78
+ /** Output format. Default: 'markdown'. */
79
+ format?: ReportFormat;
80
+ /**
81
+ * When true, MEDIUM and LOW findings also trigger a non-zero exit.
82
+ * Default false — HIGH-only is the canonical "block CI" line.
83
+ */
84
+ strict?: boolean;
85
+ /** Custom writer (tests). Defaults to process.stdout.write. */
86
+ write?: (chunk: string) => void;
87
+ }
88
+ interface AuditResult {
89
+ report: AuditReport;
90
+ /** Suggested exit code under the current strictness setting. */
91
+ exitCode: 0 | 1;
92
+ }
93
+ declare function runAuditCommand(options?: AuditOptions): Promise<AuditResult>;
94
+ //#endregion
95
+ //#region src/manifest.d.ts
96
+ /**
97
+ * Read a built manifest (`dist/system.json` or `dist/module.json`).
98
+ *
99
+ * The vite plugin emits the manifest into `dist/` during build, so the CLI
100
+ * commands that come after a build (dev's initial symlink, build's release
101
+ * zip) read from there rather than walking source. This file is intentionally
102
+ * tiny — we extract just the fields the CLI cares about and surface the
103
+ * rest as `raw` for any consumer that wants more.
104
+ */
105
+ type PackageType = 'system' | 'module';
106
+ interface FoundryManifest {
107
+ /** Manifest id — folder name Foundry serves the package under. */
108
+ id: string;
109
+ /** Semver-ish version string from the manifest. */
110
+ version: string;
111
+ /** Detected from which filename was present in dist/. */
112
+ type: PackageType;
113
+ /** Full parsed JSON for callers that need extra fields (compatibility, etc.). */
114
+ raw: Record<string, unknown>;
115
+ }
116
+ /**
117
+ * Locate and parse the Foundry manifest inside the given dist directory.
118
+ * Prefers `system.json`, falls back to `module.json` (a single dist can't
119
+ * be both — the vite plugin emits exactly one based on the project type).
120
+ *
121
+ * Throws if neither file exists, required fields are missing/non-string,
122
+ * or the id/version contain characters that would let downstream `join()`
123
+ * calls escape their intended directory.
124
+ */
125
+ declare function readManifest(distDir: string): Promise<FoundryManifest>;
126
+ //#endregion
127
+ //#region src/commands/build.d.ts
128
+ interface BuildOptions {
129
+ /** Override the project root. Defaults to `process.cwd()`. */
130
+ cwd?: string;
131
+ }
132
+ /**
133
+ * Internal building block exposed for tests: assumes dist/ is already
134
+ * populated (vite has run, manifest is present) and just emits the zip.
135
+ */
136
+ declare function emitReleaseZip(opts: {
137
+ cwd: string;
138
+ }): Promise<{
139
+ zipFile: string;
140
+ byteSize: number;
141
+ manifest: FoundryManifest;
142
+ }>;
143
+ declare function runBuild(options?: BuildOptions): Promise<void>;
144
+ //#endregion
145
+ //#region src/commands/dev.d.ts
146
+ interface DevOptions {
147
+ /** Override the project root. Defaults to `process.cwd()`. */
148
+ cwd?: string;
149
+ /** `--data-dir` flag value. Skips env/config/prompt lookup when set. */
150
+ dataDir?: string;
151
+ /** Port for the hot reload bridge. */
152
+ hmrPort?: number;
153
+ }
154
+ declare function runDev(options?: DevOptions): Promise<void>;
155
+ /**
156
+ * Internal building block exposed for tests: given an already-built `dist/`
157
+ * (vite has run, manifest is present) and a resolved Foundry data dir,
158
+ * create the symlink and return the target path + manifest. Skips the
159
+ * vite spawn and the signal-loop, so tests can drive the orchestration
160
+ * deterministically.
161
+ */
162
+ declare function setupDevSymlink(opts: {
163
+ cwd: string;
164
+ dataRoot: string;
165
+ }): Promise<{
166
+ target: string;
167
+ manifest: Awaited<ReturnType<typeof readManifest>>;
168
+ childProcess?: ChildProcess;
169
+ }>;
170
+ /**
171
+ * Tear down a dev symlink iff it still points at the expected source.
172
+ * Refuses to remove a symlink that another `vttforge dev` session (or a
173
+ * manual `ln -s`) has since redirected — that link doesn't belong to us
174
+ * and removing it would silently disconnect their setup.
175
+ */
176
+ declare function cleanupDevSymlink(opts: {
177
+ target: string;
178
+ expectedSource: string;
179
+ }): Promise<void>;
180
+ //#endregion
181
+ //#region src/commands/init.d.ts
182
+ /**
183
+ * `vttforge init` — interactive scaffolder.
184
+ *
185
+ * Honors CLI flags first, prompts for everything missing, then copies the
186
+ * matching template into the destination directory. Optionally `git init`s
187
+ * and runs the detected package manager's install command at the end.
188
+ */
189
+ interface InitOptions {
190
+ name?: string;
191
+ type?: 'system' | 'module';
192
+ lang?: 'ts' | 'js';
193
+ /** Manifest id. Defaults to a slug of the directory name. */
194
+ id?: string;
195
+ /** Human-readable title shown in Foundry's setup screens. */
196
+ title?: string;
197
+ /** One-line description for the manifest. */
198
+ description?: string;
199
+ /** Author name for the manifest. Defaults to the local git author. */
200
+ author?: string;
201
+ /** SPDX license id written to package.json. */
202
+ license?: string;
203
+ /**
204
+ * Take the default for anything not supplied instead of asking.
205
+ *
206
+ * Required to scaffold without a terminal — a prompt with nothing to read
207
+ * from waits forever, which is no way to fail.
208
+ */
209
+ yes?: boolean;
210
+ noInstall?: boolean;
211
+ noGit?: boolean;
212
+ /** Override the working directory (test hook). Defaults to `process.cwd()`. */
213
+ cwd?: string;
214
+ }
215
+ interface ResolvedInitOptions extends Required<Omit<InitOptions, 'cwd' | 'id' | 'title' | 'description' | 'author' | 'license' | 'yes'>> {
216
+ cwd: string;
217
+ dest: string;
218
+ id: string;
219
+ title: string;
220
+ description: string;
221
+ author: string;
222
+ license: string;
223
+ foundryMinVersion: string;
224
+ foundryVerifiedVersion: string;
225
+ templateVariant: TemplateVariant;
226
+ }
227
+ type TemplateVariant = 'system-ts' | 'system-js' | 'module-ts' | 'module-js';
228
+ /**
229
+ * Thrown when the scaffolder cannot continue — bad input, an existing
230
+ * destination, a cancelled prompt, etc. `runInit` propagates these instead
231
+ * of calling `process.exit`, so library consumers (tests, other CLIs) can
232
+ * catch and recover. The `vttforge` bin wraps `runInit` in a top-level
233
+ * handler that prints the message and exits with code 1.
234
+ */
235
+ declare class ScaffoldError extends Error {
236
+ constructor(message: string);
237
+ }
238
+ declare function runInit(options?: InitOptions): Promise<void>;
239
+ //#endregion
240
+ //#region src/foundry-data-dir.d.ts
241
+ /**
242
+ * Foundry user-data directory discovery + persistence.
243
+ *
244
+ * Foundry stores worlds, systems, and modules under a single user-data
245
+ * directory (`Data/` lives at its root). `vttforge dev` needs to know where
246
+ * that is so it can symlink the built `dist/` into `Data/systems/<id>/` or
247
+ * `Data/modules/<id>/` and let Foundry pick it up.
248
+ *
249
+ * Precedence (top wins):
250
+ * 1. Explicit `--data-dir` flag passed to the command
251
+ * 2. `FOUNDRY_DATA_DIR` env var (useful in Docker/CI)
252
+ * 3. `<project>/.vttforge/config.json :: foundryDataDir`
253
+ * 4. OS default + interactive prompt that saves to (3) for next time
254
+ *
255
+ * The OS-default detection treats `XDG_DATA_HOME` (Linux) and `%LOCALAPPDATA%`
256
+ * (Windows) as part of the OS convention, not as Foundry-specific overrides.
257
+ *
258
+ * Everything here is pure — `platform`, `env`, and `home` flow through
259
+ * options so tests can drive every branch without monkey-patching globals.
260
+ */
261
+ /** Shape persisted to `<project>/.vttforge/config.json`. */
262
+ interface VTTForgeConfig {
263
+ foundryDataDir?: string;
264
+ }
265
+ /**
266
+ * Return the OS-default Foundry user-data directory, or `null` on unknown
267
+ * platforms / missing platform-specific env vars. Does NOT check existence —
268
+ * callers prompt the user when the suggested path doesn't resolve.
269
+ */
270
+ declare function autoDetectFoundryDataDir(platform?: NodeJS.Platform, env?: NodeJS.ProcessEnv, home?: string): string | null;
271
+ /**
272
+ * Heuristic: a path looks like a Foundry user-data root if it contains a
273
+ * `Data/` subdirectory (canonical Foundry layout) OR if it already contains
274
+ * `systems/` or `modules/` (the path is already the Data folder itself).
275
+ */
276
+ declare function looksLikeFoundryDataDir(path: string): boolean;
277
+ /** Absolute path to the project-local config file (whether or not it exists). */
278
+ declare function configPath(cwd: string): string;
279
+ /** Load `<cwd>/.vttforge/config.json` if it exists and is valid JSON. */
280
+ declare function loadConfig(cwd: string): Promise<VTTForgeConfig | null>;
281
+ /** Persist `<cwd>/.vttforge/config.json`. Creates the `.vttforge/` dir as needed. */
282
+ declare function saveConfig(cwd: string, config: VTTForgeConfig): Promise<void>;
283
+ /**
284
+ * Resolve the packages directory (`Data/systems/` or `Data/modules/`) under
285
+ * the given Foundry user-data root. Accepts the path Foundry itself runs
286
+ * with (the user-data folder, which contains `Data/`) OR the `Data/` folder
287
+ * directly — both are common in muscle memory.
288
+ *
289
+ * The returned path is not guaranteed to exist yet; callers `mkdir -p` it
290
+ * before creating the symlink.
291
+ */
292
+ declare function foundryPackagesDir(dataRoot: string, type: 'system' | 'module'): string;
293
+ interface ResolveDataDirOptions {
294
+ /** Project root — also where `.vttforge/config.json` is read/written. */
295
+ cwd: string;
296
+ /** `--data-dir` flag value. Skips persistence and prompting when present. */
297
+ override?: string;
298
+ /**
299
+ * Interactive prompt for the first run. Receives the OS-default path
300
+ * (may be `null` on unknown platforms) and resolves with the chosen path,
301
+ * or `null` if the user cancelled. When undefined, the function refuses
302
+ * to ask and throws — appropriate for non-TTY contexts (CI, scripts).
303
+ */
304
+ prompt?: (autoDetected: string | null) => Promise<string | null>;
305
+ /** Override `process.platform` (tests). */
306
+ platform?: NodeJS.Platform;
307
+ /** Override `process.env` (tests). */
308
+ env?: NodeJS.ProcessEnv;
309
+ /** Override `os.homedir()` (tests). */
310
+ home?: string;
311
+ }
312
+ /**
313
+ * Walk the precedence chain and return the chosen Foundry user-data path.
314
+ * Saves the user's choice to the project config on first interactive run so
315
+ * subsequent invocations skip the prompt.
316
+ */
317
+ declare function resolveFoundryDataDir(opts: ResolveDataDirOptions): Promise<string>;
318
+ //#endregion
319
+ //#region src/package-manager.d.ts
320
+ /**
321
+ * Detect which package manager invoked the CLI so we can run the right
322
+ * `install` command after scaffolding.
323
+ *
324
+ * Strategy: read `npm_config_user_agent`, which pnpm/npm/bun/yarn all set when
325
+ * they spawn a child process (including `pnpm dlx`, `pnpm create`, etc.).
326
+ * Falls back to `pnpm` because that's the VTTForge house default and the
327
+ * most common Foundry-developer choice — but any concrete signal in the
328
+ * environment wins over the default.
329
+ */
330
+ type PackageManager = 'pnpm' | 'npm' | 'bun' | 'yarn';
331
+ declare function detectPackageManager(env?: NodeJS.ProcessEnv): PackageManager;
332
+ declare function installCommand(pm: PackageManager): string;
333
+ /**
334
+ * Detect a project's package manager by looking at which lockfile it
335
+ * ships. `dev` and `build` need this — by the time the user runs
336
+ * `vttforge dev`, npm_config_user_agent reflects whatever shell launched
337
+ * the binary (often nothing in a global install), not how the project
338
+ * was bootstrapped. The lockfile is the project's own contract.
339
+ *
340
+ * Falls back to {@link detectPackageManager} for fresh checkouts that
341
+ * haven't been installed yet.
342
+ */
343
+ declare function detectProjectPackageManager(cwd: string, env?: NodeJS.ProcessEnv): PackageManager;
344
+ /**
345
+ * Argument vector to invoke `vite` (or any other locally-installed CLI)
346
+ * via the project's package manager. We always shell out through `<pm>
347
+ * exec` so the call works regardless of the linker's choices — Yarn 4
348
+ * Plug'n'Play, pnpm's symlinked layout, npm's flattened node_modules,
349
+ * Bun's symlinked node_modules. Each manager exposes a uniform "run a
350
+ * locally-resolved binary in the project's dependency graph" command.
351
+ */
352
+ declare function execInvocation(pm: PackageManager, bin: string): [string, string[]];
353
+ //#endregion
354
+ //#region src/scaffold.d.ts
355
+ /**
356
+ * Template copy with `{{var}}` placeholder substitution.
357
+ *
358
+ * Templates live under `packages/cli/templates/<variant>/` and are shipped
359
+ * inside the published tarball (see the `files` array in package.json).
360
+ * Each file is read, substituted, and written to the destination directory
361
+ * preserving the relative path. Directories are created lazily on first
362
+ * write.
363
+ *
364
+ * We intentionally avoid Handlebars or any other template engine — the
365
+ * substitution surface is small (a flat string-to-string map), and bundling
366
+ * a dependency for ten lines of regex would be wasteful in a tool whose
367
+ * value is being fast to invoke.
368
+ */
369
+ interface ScaffoldVars {
370
+ ID: string;
371
+ TITLE: string;
372
+ DESCRIPTION: string;
373
+ AUTHOR: string;
374
+ LICENSE: string;
375
+ FOUNDRY_MIN_VERSION: string;
376
+ FOUNDRY_VERIFIED_VERSION: string;
377
+ LOCALE_PREFIX: string;
378
+ YEAR: string;
379
+ }
380
+ interface ScaffoldOptions {
381
+ /** Absolute path to the template root (e.g. `<cli-pkg>/templates/system-ts`). */
382
+ templateDir: string;
383
+ /** Absolute path to the destination directory. Created if it doesn't exist. */
384
+ destDir: string;
385
+ /** Variables to substitute into `{{NAME}}` placeholders inside template files. */
386
+ vars: ScaffoldVars;
387
+ }
388
+ /**
389
+ * Replace `{{NAME}}` placeholders in `content` using the `vars` map.
390
+ * Unknown placeholders are passed through unchanged so partially-templated
391
+ * files (e.g. a snippet that contains `{{handlebarsLikeSyntax}}` as literal
392
+ * content) still scaffold without surprises.
393
+ */
394
+ declare function substitute(content: string, vars: ScaffoldVars): string;
395
+ declare function scaffold({ templateDir, destDir, vars }: ScaffoldOptions): Promise<void>;
396
+ /**
397
+ * Resolve the templates directory relative to this module's file URL. tsdown
398
+ * emits `dist/scaffold.mjs`, so `import.meta.url` points there at runtime;
399
+ * we walk up two segments to land at the package root, then descend into
400
+ * `templates/`.
401
+ */
402
+ declare function templatesRoot(): string;
403
+ //#endregion
404
+ //#region src/symlink.d.ts
405
+ /**
406
+ * Cross-platform symlink helpers for `vttforge dev`.
407
+ *
408
+ * The dev loop drops a symlink from Foundry's `Data/<systems|modules>/<id>/`
409
+ * back to the project's `dist/` so Foundry serves freshly-built files as
410
+ * vite writes them. The win32 path matters: with `type: 'junction'` the
411
+ * operation works on standard Windows shells without Developer Mode, while
412
+ * `type: 'dir'` requires admin. We never silently fall back to copying —
413
+ * Foundry's HMR relies on live file mutation, and a copy snapshot defeats
414
+ * the loop. If the symlink fails, we surface the platform-specific fix.
415
+ */
416
+ interface CreateLinkOptions {
417
+ /**
418
+ * Overwrite an existing symlink that points elsewhere. Real files and
419
+ * directories are never overwritten — that path needs explicit user
420
+ * action outside the tool.
421
+ */
422
+ overwrite?: boolean;
423
+ }
424
+ /**
425
+ * Read a symlink target. Returns the absolute path the link points at, or
426
+ * `null` if `path` doesn't exist or isn't a symlink. Relative symlink
427
+ * targets are resolved against the link's own directory (matches the
428
+ * semantics callers expect when comparing to a known absolute source).
429
+ */
430
+ declare function readLinkTarget(path: string): Promise<string | null>;
431
+ /**
432
+ * Create a symlink at `target` pointing to `source`. Win32 uses `'junction'`
433
+ * so the call succeeds without elevation; everywhere else uses `'dir'`.
434
+ *
435
+ * Idempotency:
436
+ * - target already points to source → no-op
437
+ * - target points elsewhere → throws unless `options.overwrite`
438
+ * - target is a real file/dir → throws unconditionally
439
+ */
440
+ declare function createLink(target: string, source: string, options?: CreateLinkOptions): Promise<void>;
441
+ /**
442
+ * Remove a symlink at `path`. No-ops when the path doesn't exist. Throws
443
+ * when the path exists but isn't a symlink — we never unlink real files
444
+ * or directories.
445
+ */
446
+ declare function removeLink(path: string): Promise<void>;
447
+ //#endregion
448
+ //#region src/vite-runner.d.ts
449
+ declare class ViteNotInstalledError extends Error {
450
+ constructor(message: string);
451
+ }
452
+ /** Spawn args for invoking the user's vite (e.g. `["pnpm", ["exec", "vite"]]`). */
453
+ declare function resolveViteInvocation(cwd: string): [string, string[]];
454
+ /** Run `vite build` once and wait for it to exit. Throws on non-zero exit. */
455
+ declare function runViteBuildOnce(cwd: string): Promise<void>;
456
+ /**
457
+ * Spawn `vite build --watch` and return the child process. The caller is
458
+ * responsible for waiting on it and tearing it down (the dev command kills
459
+ * it on SIGINT).
460
+ */
461
+ declare function spawnViteWatch(cwd: string): ChildProcess;
462
+ //#endregion
463
+ //#region src/zip.d.ts
464
+ /**
465
+ * Emit a foundryvtt.com-compatible release zip.
466
+ *
467
+ * foundryvtt.com expects the package contents at the zip root (no wrapper
468
+ * folder), so `unzip release.zip` produces `system.json`, `scripts/`, etc.
469
+ * directly. The vite build output already matches that layout, so we feed
470
+ * `dist/` straight into archiver with `false` as the second arg to disable
471
+ * the wrap-with-source-dir-name default.
472
+ *
473
+ * Optional extras (LICENSE / README / CHANGELOG) ride along when present at
474
+ * the project root and not already inside `dist/`. We never duplicate.
475
+ */
476
+ interface EmitZipOptions {
477
+ /** Directory whose contents go into the zip at root. */
478
+ sourceDir: string;
479
+ /** Output zip path. Parent directory must exist. */
480
+ outFile: string;
481
+ /** Filenames (relative to extrasFrom) to add at the zip root if present. */
482
+ extras?: string[];
483
+ /** Where to look for `extras`. Required when `extras` is non-empty. */
484
+ extrasFrom?: string;
485
+ }
486
+ interface EmitZipResult {
487
+ outFile: string;
488
+ byteSize: number;
489
+ }
490
+ declare function emitZip(opts: EmitZipOptions): Promise<EmitZipResult>;
491
+ //#endregion
492
+ //#region src/index.d.ts
493
+ declare const VTTFORGE_CLI_VERSION = "0.1.0";
494
+ //#endregion
495
+ export { type AuditOptions, type AuditReport, type AuditResult, type BuildOptions, type CreateLinkOptions, type DevOptions, type EmitZipOptions, type EmitZipResult, type FoundryManifest, type InitOptions, type PackageManager, type PackageType, type ReportFormat, type ResolveDataDirOptions, type ResolvedInitOptions, type RuleFn, type RuleResult, SEVERITY_RANK, ScaffoldError, type ScaffoldOptions, type ScaffoldVars, type Severity, type TemplateVariant, VTTFORGE_CLI_VERSION, type VTTForgeConfig, ViteNotInstalledError, autoDetectFoundryDataDir, cleanupDevSymlink, configPath, createLink, detectPackageManager, detectProjectPackageManager, emitReleaseZip, emitZip, execInvocation, formatReport, foundryPackagesDir, installCommand, loadConfig, looksLikeFoundryDataDir, readLinkTarget, readManifest, removeLink, resolveFoundryDataDir, resolveViteInvocation, runAudit, runAuditCommand, runBuild, runDev, runInit, runManifestRules, runSourceRules, runViteBuildOnce, saveConfig, scaffold, setupDevSymlink, spawnViteWatch, substitute, templatesRoot };
496
+ //# sourceMappingURL=index.d.mts.map
package/dist/index.mjs ADDED
@@ -0,0 +1,2 @@
1
+ import { A as installCommand, C as ViteNotInstalledError, D as detectPackageManager, E as spawnViteWatch, F as SEVERITY_RANK, I as runSourceRules, L as runManifestRules, M as runAuditCommand, N as formatReport, O as detectProjectPackageManager, P as runAudit, S as emitZip, T as runViteBuildOnce, _ as createLink, a as substitute, b as emitReleaseZip, c as runDev, d as configPath, f as foundryPackagesDir, g as saveConfig, h as resolveFoundryDataDir, i as scaffold, j as readManifest, k as execInvocation, l as setupDevSymlink, m as looksLikeFoundryDataDir, n as ScaffoldError, o as templatesRoot, p as loadConfig, r as runInit, s as cleanupDevSymlink, t as VTTFORGE_CLI_VERSION, u as autoDetectFoundryDataDir, v as readLinkTarget, w as resolveViteInvocation, x as runBuild, y as removeLink } from "./src-CWhUNM__.mjs";
2
+ export { SEVERITY_RANK, ScaffoldError, VTTFORGE_CLI_VERSION, ViteNotInstalledError, autoDetectFoundryDataDir, cleanupDevSymlink, configPath, createLink, detectPackageManager, detectProjectPackageManager, emitReleaseZip, emitZip, execInvocation, formatReport, foundryPackagesDir, installCommand, loadConfig, looksLikeFoundryDataDir, readLinkTarget, readManifest, removeLink, resolveFoundryDataDir, resolveViteInvocation, runAudit, runAuditCommand, runBuild, runDev, runInit, runManifestRules, runSourceRules, runViteBuildOnce, saveConfig, scaffold, setupDevSymlink, spawnViteWatch, substitute, templatesRoot };