create-packkit 0.6.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -51,6 +51,8 @@ No install needed: **[danmat.github.io/create-packkit](https://danmat.github.io/
51
51
 
52
52
  `ts-lib` · `js-lib` · `ts-cli` / `cli` · `react-lib` · `react-lib-js` · `react-app` · `vue-lib` · `vue-app` · `svelte-lib` · `svelte-app` · `node-service` · `oss` · `minimal` · `full` — named bundles of the options above. See the [roadmap](ROADMAP.md) for what's next.
53
53
 
54
+ **Team profiles:** save a partial config as `packkit.config.json` (or any file) and reuse it with `npx create-packkit my-lib --from ./packkit.config.json` — flags still override the file.
55
+
54
56
  ## How it works
55
57
 
56
58
  Packkit is a pure `config → { files }` **core** that runs in both Node and the browser:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-packkit",
3
- "version": "0.6.0",
3
+ "version": "1.0.0",
4
4
  "description": "Highly configurable scaffolder for modern npm packages and CLIs — pick your stack (TS/JS, bundler, tests, linter, CI, releases) from a CLI or a web configurator.",
5
5
  "type": "module",
6
6
  "bin": {
package/src/cli/args.js CHANGED
@@ -34,6 +34,7 @@ export function parseCliArgs(argv) {
34
34
  allowPositionals: true,
35
35
  options: {
36
36
  preset: { type: 'string' },
37
+ from: { type: 'string' },
37
38
  name: { type: 'string' },
38
39
  yes: { type: 'boolean', short: 'y' },
39
40
  here: { type: 'boolean' },
@@ -72,6 +73,7 @@ export function parseCliArgs(argv) {
72
73
 
73
74
  return {
74
75
  preset,
76
+ from: values.from,
75
77
  name,
76
78
  here: !!values.here,
77
79
  yes: !!values.yes,
package/src/cli/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { resolve, basename } from 'node:path';
2
- import { readFileSync } from 'node:fs';
2
+ import { readFileSync, existsSync } from 'node:fs';
3
3
  import { fileURLToPath } from 'node:url';
4
4
  import * as p from '@clack/prompts';
5
5
  import { generate, fromPreset, normalizeConfig, PRESET_NAMES } from '../core/index.js';
@@ -27,6 +27,7 @@ Presets: ${PRESET_NAMES.join(', ')}
27
27
 
28
28
  Options:
29
29
  --preset <name> Use a preset (skips the wizard)
30
+ --from <file> Load defaults from a JSON profile (or packkit.config.json)
30
31
  --name <name> Package name
31
32
  --here Scaffold into the current directory
32
33
  -y, --yes Accept defaults / preset, no prompts
@@ -55,16 +56,20 @@ export async function run(argv = process.argv.slice(2)) {
55
56
  if (args.help) return void console.log(HELP);
56
57
  if (args.version) return void console.log(pkgVersion());
57
58
 
58
- const interactive = !args.preset && !args.yes && process.stdout.isTTY;
59
+ const interactive = !args.preset && !args.yes && !args.from && process.stdout.isTTY;
60
+
61
+ // Precedence: preset < profile file < CLI flags.
62
+ const profile = loadProfile(args);
63
+ const seed = { ...profile, ...args.overrides };
59
64
 
60
65
  let config;
61
66
  if (interactive) {
62
67
  p.intro('📦 Packkit');
63
- config = normalizeConfig(await runWizard(args.overrides));
68
+ config = normalizeConfig(await runWizard(seed));
64
69
  } else if (args.preset) {
65
- config = fromPreset(args.preset, args.overrides);
70
+ config = fromPreset(args.preset, seed);
66
71
  } else {
67
- config = normalizeConfig(args.overrides);
72
+ config = normalizeConfig(seed);
68
73
  }
69
74
 
70
75
  config.gitInit = args.git;
@@ -119,6 +124,18 @@ function runWord(config) {
119
124
  return config.packageManager === 'npm' ? 'npm run' : config.packageManager;
120
125
  }
121
126
 
127
+ // Load a partial config from --from <file>, or a packkit.config.json in cwd.
128
+ function loadProfile(args) {
129
+ const path = args.from || (existsSync('packkit.config.json') ? 'packkit.config.json' : null);
130
+ if (!path) return {};
131
+ try {
132
+ return JSON.parse(readFileSync(path, 'utf8'));
133
+ } catch (err) {
134
+ console.error(`Could not read profile "${path}": ${err instanceof Error ? err.message : err}`);
135
+ process.exit(1);
136
+ }
137
+ }
138
+
122
139
  // Best-effort update check — TTY only, short timeout, never throws or blocks.
123
140
  async function checkForUpdate(current) {
124
141
  try {
@@ -77,6 +77,23 @@ function run(cfg, script) {
77
77
  return cfg.packageManager === 'npm' ? `npm run ${script}` : `${cfg.packageManager} ${script}`;
78
78
  }
79
79
 
80
+ function makeBadges(cfg) {
81
+ const badges = [];
82
+ const publishable = (cfg.hasLibrary || cfg.hasCli) && !cfg.hasApp && !cfg.hasService;
83
+ if (publishable) {
84
+ const enc = encodeURIComponent(cfg.name);
85
+ badges.push(`[![npm](https://img.shields.io/npm/v/${enc}.svg)](https://www.npmjs.com/package/${cfg.name})`);
86
+ }
87
+ const repo = cfg.repo ? cfg.repo.replace(/\.git$/, '') : '';
88
+ if (repo && (cfg.workflows || []).includes('ci')) {
89
+ badges.push(`[![CI](${repo}/actions/workflows/ci.yml/badge.svg)](${repo}/actions/workflows/ci.yml)`);
90
+ }
91
+ if (cfg.license !== 'none') {
92
+ badges.push(`[![License: ${cfg.license}](https://img.shields.io/badge/license-${encodeURIComponent(cfg.license)}-blue.svg)](LICENSE)`);
93
+ }
94
+ return badges.join(' ');
95
+ }
96
+
80
97
  function readme(cfg) {
81
98
  const install = {
82
99
  npm: `npm install ${cfg.name}`,
@@ -90,14 +107,13 @@ function readme(cfg) {
90
107
  '',
91
108
  cfg.description || '_A modern package scaffolded with [Packkit](https://danmat.github.io/create-packkit/)._',
92
109
  '',
93
- '## Install',
94
- '',
95
- '```sh',
96
- install,
97
- '```',
98
- '',
99
110
  ];
100
111
 
112
+ const badges = makeBadges(cfg);
113
+ if (badges) lines.push(badges, '');
114
+
115
+ lines.push('## Install', '', '```sh', install, '```', '');
116
+
101
117
  if (cfg.hasApp) {
102
118
  lines.push('## Develop', '', '```sh', run(cfg, 'dev') + ' # start the dev server', run(cfg, 'build') + ' # production build', '```', '');
103
119
  } else if (cfg.hasLibrary && cfg.isReact) {