ccraft 1.0.3 → 1.0.4

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.
@@ -68,7 +68,7 @@ program
68
68
  .action(runCreate);
69
69
 
70
70
  program
71
- .command('install', { isDefault: true })
71
+ .command('install')
72
72
  .description('Generate Claude Code configuration files in the current project')
73
73
  .option('-y, --yes', 'Accept all defaults (non-interactive)')
74
74
  .option(`-p, --preset <preset>`, `Apply a framework preset (${Object.keys(PRESET_ALIASES).join(', ')})`)
@@ -82,4 +82,17 @@ program
82
82
  .option('-d, --dir <path>', 'Target directory (default: cwd)')
83
83
  .action(runUpdate);
84
84
 
85
+ // Warn on unknown commands
86
+ program.on('command:*', ([cmd]) => {
87
+ console.error(`\n ⚠ Unknown command: "${cmd}"\n`);
88
+ console.error(` Run "ccraft --help" to see available commands.\n`);
89
+ process.exit(1);
90
+ });
91
+
85
92
  program.parse();
93
+
94
+ // No command provided — show warning + help
95
+ if (!program.args.length) {
96
+ console.warn(`\n ⚠ No command specified.\n`);
97
+ program.help();
98
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ccraft",
3
- "version": "1.0.3",
3
+ "version": "1.0.4",
4
4
  "description": "Intelligent Claude Code project configurator — role-aware agents, skills, rules, MCPs, and workflows",
5
5
  "type": "module",
6
6
  "bin": {
@@ -22,12 +22,14 @@ export async function runAuth(key, options = {}) {
22
22
  const valid = await validateKey(key, serverUrl);
23
23
  if (!valid) {
24
24
  logger.error('API key is not valid. Check the key and try again.');
25
+ await new Promise((r) => setTimeout(r, 50));
25
26
  process.exit(1);
26
27
  }
27
28
  } catch (err) {
28
29
  if (err instanceof ApiError && err.code === 'NETWORK_ERROR') {
29
30
  logger.error('Could not reach server at ' + chalk.bold(serverUrl));
30
31
  console.log(chalk.dim(' Ensure the server is running, or specify a different URL with -s <url>'));
32
+ await new Promise((r) => setTimeout(r, 50));
31
33
  process.exit(1);
32
34
  }
33
35
  throw err;
@@ -231,7 +231,10 @@ export async function validateKey(apiKey, serverUrl) {
231
231
 
232
232
  res = await fetch(url, {
233
233
  method: 'POST',
234
- headers: { 'Content-Type': 'application/json' },
234
+ headers: {
235
+ 'Content-Type': 'application/json',
236
+ 'Connection': 'close',
237
+ },
235
238
  body: JSON.stringify({ apiKey }),
236
239
  signal: controller.signal,
237
240
  });
@@ -245,6 +248,8 @@ export async function validateKey(apiKey, serverUrl) {
245
248
  }
246
249
 
247
250
  if (!res.ok) {
251
+ // Consume body to fully release the TCP connection
252
+ await res.text().catch(() => {});
248
253
  return false;
249
254
  }
250
255
 
@@ -103,6 +103,10 @@ export async function runPreflight(options = {}) {
103
103
  for (const msg of envErrors) {
104
104
  logger.error(msg);
105
105
  }
106
+ // Allow libuv to close pending fetch handles before exiting.
107
+ // Calling process.exit() synchronously after fetch on Windows triggers
108
+ // "UV_HANDLE_CLOSING" assertion in libuv's async.c.
109
+ await new Promise((resolve) => setTimeout(resolve, 50));
106
110
  process.exit(1);
107
111
  }
108
112
 
@@ -37,6 +37,7 @@ export async function promptForApiKey() {
37
37
  const valid = await validateKey(trimmed);
38
38
  if (!valid) {
39
39
  spinner.fail('API key is not valid.');
40
+ await new Promise((r) => setTimeout(r, 50));
40
41
  process.exit(1);
41
42
  }
42
43
  spinner.succeed('API key validated.');
@@ -46,6 +47,7 @@ export async function promptForApiKey() {
46
47
  } else {
47
48
  spinner.fail('Validation failed: ' + err.message);
48
49
  }
50
+ await new Promise((r) => setTimeout(r, 50));
49
51
  process.exit(1);
50
52
  }
51
53