@foxsell/foxkit-cli 0.0.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/dist/cli.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
package/dist/cli.js ADDED
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env node
2
+ import { defineCommand, runMain } from "citty";
3
+ import { addCommand } from "./commands/add/index.js";
4
+ const main = defineCommand({
5
+ meta: {
6
+ name: "foxkit",
7
+ version: "0.0.1",
8
+ description: "Hello world CLI",
9
+ },
10
+ subCommands: {
11
+ add: addCommand,
12
+ },
13
+ });
14
+ runMain(main);
15
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AAC/C,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAErD,MAAM,IAAI,GAAG,aAAa,CAAC;IACzB,IAAI,EAAE;QACJ,IAAI,EAAE,QAAQ;QACd,OAAO,EAAE,OAAO;QAChB,WAAW,EAAE,iBAAiB;KAC/B;IACD,WAAW,EAAE;QACX,GAAG,EAAE,UAAU;KAChB;CACF,CAAC,CAAC;AAEH,OAAO,CAAC,IAAI,CAAC,CAAC"}
@@ -0,0 +1,9 @@
1
+ export declare const addCommand: import("citty").CommandDef<{
2
+ readonly template: {
3
+ readonly type: "string";
4
+ readonly description: "Giget source (skips prompt): gh:org/repo/path, GitHub /tree/… link, or tarball URL";
5
+ readonly alias: ["t", "u"];
6
+ readonly valueHint: "source";
7
+ };
8
+ }>;
9
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/add/index.ts"],"names":[],"mappings":"AAMA,eAAO,MAAM,UAAU;;;;;;;EAmCrB,CAAC"}
@@ -0,0 +1,42 @@
1
+ import inquirer from "inquirer";
2
+ import { defineCommand } from "citty";
3
+ import { TEMPLATES } from "../../constants.js";
4
+ import { applyTemplate } from "../../utils/apply-template.js";
5
+ import { exitOnPromptInterrupt } from "../../utils/prompt-interrupt.js";
6
+ export const addCommand = defineCommand({
7
+ meta: {
8
+ name: "add",
9
+ description: "Add a template to the theme.",
10
+ },
11
+ args: {
12
+ template: {
13
+ type: "string",
14
+ description: "Giget source (skips prompt): gh:org/repo/path, GitHub /tree/… link, or tarball URL",
15
+ alias: ["t", "u"],
16
+ valueHint: "source",
17
+ },
18
+ },
19
+ async run({ args }) {
20
+ const raw = args.template;
21
+ let url = typeof raw === "string" ? raw.trim() : "";
22
+ // citty / parseArgs can leave `-t=https://…` as `=https://…`
23
+ if (url.startsWith("="))
24
+ url = url.slice(1).trim();
25
+ if (url) {
26
+ await applyTemplate({ url });
27
+ return;
28
+ }
29
+ let template;
30
+ try {
31
+ ({ template } = await inquirer.prompt([
32
+ { type: "select", name: "template", message: "Which template do you want to add?", choices: [...TEMPLATES] },
33
+ ]));
34
+ }
35
+ catch (err) {
36
+ exitOnPromptInterrupt(err);
37
+ throw err;
38
+ }
39
+ await applyTemplate({ template });
40
+ },
41
+ });
42
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/commands/add/index.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,UAAU,CAAC;AAChC,OAAO,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AACtC,OAAO,EAAE,SAAS,EAAiB,MAAM,oBAAoB,CAAC;AAC9D,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAC9D,OAAO,EAAE,qBAAqB,EAAE,MAAM,iCAAiC,CAAC;AAExE,MAAM,CAAC,MAAM,UAAU,GAAG,aAAa,CAAC;IACtC,IAAI,EAAE;QACJ,IAAI,EAAE,KAAK;QACX,WAAW,EAAE,8BAA8B;KAC5C;IACD,IAAI,EAAE;QACJ,QAAQ,EAAE;YACR,IAAI,EAAE,QAAQ;YACd,WAAW,EACT,oFAAoF;YACtF,KAAK,EAAE,CAAC,GAAG,EAAE,GAAG,CAAC;YACjB,SAAS,EAAE,QAAQ;SACpB;KACF;IACD,KAAK,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE;QAChB,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC;QAC1B,IAAI,GAAG,GAAG,OAAO,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACpD,6DAA6D;QAC7D,IAAI,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,GAAG,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QACnD,IAAI,GAAG,EAAE,CAAC;YACR,MAAM,aAAa,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC;YAC7B,OAAO;QACT,CAAC;QAED,IAAI,QAAkB,CAAC;QACvB,IAAI,CAAC;YACH,CAAC,EAAE,QAAQ,EAAE,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAyB;gBAC5D,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,oCAAoC,EAAE,OAAO,EAAE,CAAC,GAAG,SAAS,CAAC,EAAE;aAC7G,CAAC,CAAC,CAAC;QACN,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,qBAAqB,CAAC,GAAG,CAAC,CAAC;YAC3B,MAAM,GAAG,CAAC;QACZ,CAAC;QACD,MAAM,aAAa,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC;IACpC,CAAC;CACF,CAAC,CAAC"}
@@ -0,0 +1,10 @@
1
+ /** Prebuilt theme templates available via the CLI. */
2
+ export declare const TEMPLATES: readonly ["Glow", "Shade", "Skeleton", "Step"];
3
+ export type Template = (typeof TEMPLATES)[number];
4
+ /**
5
+ * Giget template sources — subfolders of `templates/` in foxkit-bundle-templates.
6
+ * @see https://github.com/FoxSellApp/foxkit-bundle-templates/tree/main/templates
7
+ * @see https://github.com/unjs/giget
8
+ */
9
+ export declare const TEMPLATE_SOURCES: Record<Template, string>;
10
+ //# sourceMappingURL=constants.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,sDAAsD;AACtD,eAAO,MAAM,SAAS,gDAAiD,CAAC;AACxE,MAAM,MAAM,QAAQ,GAAG,CAAC,OAAO,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC;AAElD;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,EAAE,MAAM,CAAC,QAAQ,EAAE,MAAM,CAKrD,CAAC"}
@@ -0,0 +1,14 @@
1
+ /** Prebuilt theme templates available via the CLI. */
2
+ export const TEMPLATES = ["Glow", "Shade", "Skeleton", "Step"];
3
+ /**
4
+ * Giget template sources — subfolders of `templates/` in foxkit-bundle-templates.
5
+ * @see https://github.com/FoxSellApp/foxkit-bundle-templates/tree/main/templates
6
+ * @see https://github.com/unjs/giget
7
+ */
8
+ export const TEMPLATE_SOURCES = {
9
+ Glow: "gh:FoxSellApp/foxkit-bundle-templates/templates/glow",
10
+ Shade: "gh:FoxSellApp/foxkit-bundle-templates/templates/shade",
11
+ Skeleton: "gh:FoxSellApp/foxkit-bundle-templates/templates/skeleton",
12
+ Step: "gh:FoxSellApp/foxkit-bundle-templates/templates/step",
13
+ };
14
+ //# sourceMappingURL=constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,sDAAsD;AACtD,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,CAAU,CAAC;AAGxE;;;;GAIG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAA6B;IACxD,IAAI,EAAE,sDAAsD;IAC5D,KAAK,EAAE,uDAAuD;IAC9D,QAAQ,EAAE,0DAA0D;IACpE,IAAI,EAAE,sDAAsD;CAC7D,CAAC"}
@@ -0,0 +1,16 @@
1
+ import { type Template } from "../constants.js";
2
+ export type ApplyTemplateOptions = {
3
+ template: Template;
4
+ themeRoot?: string;
5
+ } | {
6
+ url: string;
7
+ themeRoot?: string;
8
+ };
9
+ /** Turn a GitHub browser "tree" URL into a giget `gh:owner/repo/path#ref` source. */
10
+ export declare function normalizeGigetSource(raw: string): string;
11
+ /**
12
+ * Download a template with giget (preset name or custom URL/source), detect path conflicts
13
+ * with `themeRoot`, optionally confirm overwrite, then merge files into the theme.
14
+ */
15
+ export declare function applyTemplate(options: ApplyTemplateOptions): Promise<void>;
16
+ //# sourceMappingURL=apply-template.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apply-template.d.ts","sourceRoot":"","sources":["../../src/utils/apply-template.ts"],"names":[],"mappings":"AAMA,OAAO,EAAoB,KAAK,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAOlE,MAAM,MAAM,oBAAoB,GAC5B;IAAE,QAAQ,EAAE,QAAQ,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GAC1C;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAExC,qFAAqF;AACrF,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CASxD;AAYD;;;GAGG;AACH,wBAAsB,aAAa,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC,CAsDhF"}
@@ -0,0 +1,107 @@
1
+ import { cp, mkdtemp, rm } from "node:fs/promises";
2
+ import { basename, dirname, join } from "node:path";
3
+ import { tmpdir } from "node:os";
4
+ import { downloadTemplate } from "giget";
5
+ import inquirer from "inquirer";
6
+ import { createSpinner } from "nanospinner";
7
+ import { TEMPLATE_SOURCES } from "../constants.js";
8
+ import { findConflictingPaths, listRelativeFiles } from "./conflicts.js";
9
+ import { isPromptInterrupt } from "./prompt-interrupt.js";
10
+ const MAX_CONFLICTS_SHOWN = 25;
11
+ const rmrf = (dir) => rm(dir, { recursive: true, force: true }).catch(() => { });
12
+ /** Turn a GitHub browser "tree" URL into a giget `gh:owner/repo/path#ref` source. */
13
+ export function normalizeGigetSource(raw) {
14
+ let s = raw.trim();
15
+ if (s.startsWith("="))
16
+ s = s.slice(1).trim();
17
+ const m = s.match(/^https:\/\/github\.com\/([^/]+)\/([^/]+)\/tree\/([^/]+)\/(.+?)\/?$/);
18
+ if (m) {
19
+ const [, owner, repo, ref, pathInRepo] = m;
20
+ return `gh:${owner}/${repo}/${pathInRepo}#${ref}`;
21
+ }
22
+ return s;
23
+ }
24
+ function resolveSource(options) {
25
+ if ("template" in options) {
26
+ const name = options.template;
27
+ return { source: TEMPLATE_SOURCES[name], label: name };
28
+ }
29
+ const label = options.url.trim();
30
+ const source = normalizeGigetSource(options.url);
31
+ return { source, label };
32
+ }
33
+ /**
34
+ * Download a template with giget (preset name or custom URL/source), detect path conflicts
35
+ * with `themeRoot`, optionally confirm overwrite, then merge files into the theme.
36
+ */
37
+ export async function applyTemplate(options) {
38
+ const themeRoot = options.themeRoot ?? process.cwd();
39
+ const { source, label } = resolveSource(options);
40
+ const tempDir = await mkdtemp(join(tmpdir(), "foxkit-add-"));
41
+ const extractDir = await downloadExtracted(source, label, tempDir);
42
+ const conflicts = await findConflictingPaths(themeRoot, await listRelativeFiles(extractDir));
43
+ if (conflicts.length > 0) {
44
+ console.error("\nError: Some files from this template already exist in the theme directory:\n");
45
+ conflicts.slice(0, MAX_CONFLICTS_SHOWN).forEach((p) => console.error(` ${p}`));
46
+ console.error(conflicts.length > MAX_CONFLICTS_SHOWN
47
+ ? ` ... and ${conflicts.length - MAX_CONFLICTS_SHOWN} more\n`
48
+ : "\n");
49
+ let proceed;
50
+ try {
51
+ ({ proceed } = await inquirer.prompt([
52
+ { type: "confirm", name: "proceed", default: false, message: "Overwrite existing files and continue?" },
53
+ ]));
54
+ }
55
+ catch (err) {
56
+ if (isPromptInterrupt(err)) {
57
+ await rmrf(tempDir);
58
+ console.error("\nCancelled.");
59
+ process.exit(0);
60
+ }
61
+ throw err;
62
+ }
63
+ if (!proceed) {
64
+ await rmrf(tempDir);
65
+ console.error("Aborted. No files were changed.\n");
66
+ process.exit(0);
67
+ }
68
+ }
69
+ const spin = createSpinner(`Installing "${label}"...`);
70
+ spin.start();
71
+ try {
72
+ await cp(extractDir, themeRoot, { recursive: true, force: true });
73
+ await rmrf(tempDir);
74
+ spin.success({
75
+ text: conflicts.length > 0
76
+ ? `Template "${label}" installed (overwrote ${conflicts.length} existing file(s)).`
77
+ : `Template "${label}" added to ${themeRoot}`,
78
+ });
79
+ }
80
+ catch (err) {
81
+ spin.error({ text: `Failed to install template "${label}"` });
82
+ console.error(err);
83
+ await rmrf(tempDir);
84
+ process.exit(1);
85
+ }
86
+ }
87
+ async function downloadExtracted(source, label, tempDir) {
88
+ const spin = createSpinner(`Downloading "${label}"...`);
89
+ spin.start();
90
+ try {
91
+ const { dir } = await downloadTemplate(source, {
92
+ cwd: dirname(tempDir),
93
+ dir: basename(tempDir),
94
+ force: true,
95
+ silent: true,
96
+ });
97
+ spin.success({ text: `Downloaded "${label}".` });
98
+ return dir;
99
+ }
100
+ catch (err) {
101
+ spin.error({ text: `Failed to download template "${label}"` });
102
+ console.error(err);
103
+ await rmrf(tempDir);
104
+ process.exit(1);
105
+ }
106
+ }
107
+ //# sourceMappingURL=apply-template.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apply-template.js","sourceRoot":"","sources":["../../src/utils/apply-template.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ /** All file paths relative to `root` (POSIX-style separators for display). */
2
+ export declare function listRelativeFiles(root: string): Promise<string[]>;
3
+ /** Paths that already exist under `targetDir` (files or directories). */
4
+ export declare function findConflictingPaths(targetDir: string, relativePaths: string[]): Promise<string[]>;
5
+ //# sourceMappingURL=conflicts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conflicts.d.ts","sourceRoot":"","sources":["../../src/utils/conflicts.ts"],"names":[],"mappings":"AAGA,8EAA8E;AAC9E,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAcvE;AAED,yEAAyE;AACzE,wBAAsB,oBAAoB,CACxC,SAAS,EAAE,MAAM,EACjB,aAAa,EAAE,MAAM,EAAE,GACtB,OAAO,CAAC,MAAM,EAAE,CAAC,CAYnB"}
@@ -0,0 +1,34 @@
1
+ import { readdir, stat } from "node:fs/promises";
2
+ import { join, relative } from "node:path";
3
+ /** All file paths relative to `root` (POSIX-style separators for display). */
4
+ export async function listRelativeFiles(root) {
5
+ const out = [];
6
+ async function walk(dir) {
7
+ const entries = await readdir(dir, { withFileTypes: true });
8
+ for (const e of entries) {
9
+ const full = join(dir, e.name);
10
+ if (e.isDirectory())
11
+ await walk(full);
12
+ else if (e.isFile())
13
+ out.push(relative(root, full).split("\\").join("/"));
14
+ }
15
+ }
16
+ await walk(root);
17
+ return out;
18
+ }
19
+ /** Paths that already exist under `targetDir` (files or directories). */
20
+ export async function findConflictingPaths(targetDir, relativePaths) {
21
+ const conflicts = [];
22
+ for (const rel of relativePaths) {
23
+ const dest = join(targetDir, rel);
24
+ try {
25
+ await stat(dest);
26
+ conflicts.push(rel);
27
+ }
28
+ catch {
29
+ /* absent */
30
+ }
31
+ }
32
+ return conflicts;
33
+ }
34
+ //# sourceMappingURL=conflicts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conflicts.js","sourceRoot":"","sources":["../../src/utils/conflicts.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAE3C,8EAA8E;AAC9E,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,IAAY;IAClD,MAAM,GAAG,GAAa,EAAE,CAAC;IAEzB,KAAK,UAAU,IAAI,CAAC,GAAW;QAC7B,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;QAC5D,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;YACxB,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;YAC/B,IAAI,CAAC,CAAC,WAAW,EAAE;gBAAE,MAAM,IAAI,CAAC,IAAI,CAAC,CAAC;iBACjC,IAAI,CAAC,CAAC,MAAM,EAAE;gBAAE,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;QAC5E,CAAC;IACH,CAAC;IAED,MAAM,IAAI,CAAC,IAAI,CAAC,CAAC;IACjB,OAAO,GAAG,CAAC;AACb,CAAC;AAED,yEAAyE;AACzE,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,SAAiB,EACjB,aAAuB;IAEvB,MAAM,SAAS,GAAa,EAAE,CAAC;IAC/B,KAAK,MAAM,GAAG,IAAI,aAAa,EAAE,CAAC;QAChC,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;QAClC,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,IAAI,CAAC,CAAC;YACjB,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACtB,CAAC;QAAC,MAAM,CAAC;YACP,YAAY;QACd,CAAC;IACH,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC"}
@@ -0,0 +1,5 @@
1
+ import { CancelPromptError, ExitPromptError } from "@inquirer/core";
2
+ export declare function isPromptInterrupt(error: unknown): error is ExitPromptError | CancelPromptError;
3
+ /** Exit quietly when the user closes a prompt (Ctrl+C, etc.). */
4
+ export declare function exitOnPromptInterrupt(error: unknown): void;
5
+ //# sourceMappingURL=prompt-interrupt.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompt-interrupt.d.ts","sourceRoot":"","sources":["../../src/utils/prompt-interrupt.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEpE,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,eAAe,GAAG,iBAAiB,CAE9F;AAED,iEAAiE;AACjE,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAK1D"}
@@ -0,0 +1,12 @@
1
+ import { CancelPromptError, ExitPromptError } from "@inquirer/core";
2
+ export function isPromptInterrupt(error) {
3
+ return error instanceof ExitPromptError || error instanceof CancelPromptError;
4
+ }
5
+ /** Exit quietly when the user closes a prompt (Ctrl+C, etc.). */
6
+ export function exitOnPromptInterrupt(error) {
7
+ if (isPromptInterrupt(error)) {
8
+ console.error("\nCancelled.");
9
+ process.exit(0);
10
+ }
11
+ }
12
+ //# sourceMappingURL=prompt-interrupt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompt-interrupt.js","sourceRoot":"","sources":["../../src/utils/prompt-interrupt.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEpE,MAAM,UAAU,iBAAiB,CAAC,KAAc;IAC9C,OAAO,KAAK,YAAY,eAAe,IAAI,KAAK,YAAY,iBAAiB,CAAC;AAChF,CAAC;AAED,iEAAiE;AACjE,MAAM,UAAU,qBAAqB,CAAC,KAAc;IAClD,IAAI,iBAAiB,CAAC,KAAK,CAAC,EAAE,CAAC;QAC7B,OAAO,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;QAC9B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC"}
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "@foxsell/foxkit-cli",
3
+ "version": "0.0.1",
4
+ "description": "CLI tool to add prebuilt templates to themes and build new templates.",
5
+ "author": "FoxSellApp",
6
+ "license": "UNLICENSED",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/FoxSellApp/foxkit-cli.git"
10
+ },
11
+ "homepage": "https://github.com/FoxSellApp/foxkit-cli",
12
+ "bugs": {
13
+ "url": "https://github.com/FoxSellApp/foxkit-cli/issues"
14
+ },
15
+ "keywords": [
16
+ "cli",
17
+ "shopify",
18
+ "theme",
19
+ "templates",
20
+ "foxkit",
21
+ "foxsell"
22
+ ],
23
+ "type": "module",
24
+ "files": [
25
+ "dist"
26
+ ],
27
+ "publishConfig": {
28
+ "access": "public"
29
+ },
30
+ "bin": {
31
+ "foxkit": "./dist/cli.js"
32
+ },
33
+ "scripts": {
34
+ "build": "tsc",
35
+ "start": "node dist/cli.js",
36
+ "prepare": "npm run build"
37
+ },
38
+ "dependencies": {
39
+ "@inquirer/core": "^11.1.7",
40
+ "citty": "^0.2.1",
41
+ "giget": "^3.1.2",
42
+ "inquirer": "^13.3.2",
43
+ "nanospinner": "^1.2.2"
44
+ },
45
+ "devDependencies": {
46
+ "@types/node": "^22.13.10",
47
+ "typescript": "^5.8.2"
48
+ }
49
+ }