@suronai/cli 0.1.34 → 0.1.35

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@suronai/cli",
3
- "version": "0.1.34",
3
+ "version": "0.1.35",
4
4
  "description": "CLI for Suron — suron login, init, whoami, recover",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,6 +1,6 @@
1
1
  import { Command } from "commander";
2
2
  import { existsSync, writeFileSync, readFileSync } from "fs";
3
- import { join, basename } from "path";
3
+ import { join, basename, relative } from "path";
4
4
  import { execSync } from "child_process";
5
5
  import { requireApiUrl, prompt } from "../utils/config.js";
6
6
  import { encryptDotenv, readPrivateKey } from "../utils/dotenvx.js";
@@ -30,7 +30,8 @@ export const initCommand = new Command("init")
30
30
  }
31
31
 
32
32
  // ── App name ──────────────────────────────────────────────────────────────
33
- const suggested = sanitiseName(basename(cwd) || "my-project");
33
+ // Preserve the folder's original casing as the default suggestion.
34
+ const suggested = sanitiseName(basename(cwd) || "myapp");
34
35
  let appName;
35
36
 
36
37
  if (opts.name) {
@@ -40,6 +41,12 @@ export const initCommand = new Command("init")
40
41
  appName = sanitiseName(raw || suggested);
41
42
  }
42
43
 
44
+ if (!appName) {
45
+ console.error(" " + c.red("✗") + " App name is required and must contain at least one letter or digit.");
46
+ console.error(" Example: suron init --name MyApp\n");
47
+ process.exit(1);
48
+ }
49
+
43
50
  console.log(" App name " + c.dim("·") + " " + c.cyan(appName));
44
51
  console.log(HR);
45
52
 
@@ -118,8 +125,9 @@ export const initCommand = new Command("init")
118
125
  printSteps();
119
126
  console.log(HR);
120
127
  if (res.status === 409) {
121
- console.error("\n " + c.red("✗") + ` An app named "${c.cyan(appName)}" is already registered.`);
122
- console.error(" If you lost .suron.json, run: " + c.bold("suron recover") + "\n");
128
+ const canonical = body?.existing_name ?? appName;
129
+ console.error("\n " + c.red("") + ` An app named "${c.cyan(String(canonical))}" is already registered (case-insensitive match).`);
130
+ console.error(" If you lost .suron.json, run: " + c.bold("suron recover --name " + String(canonical)) + "\n");
123
131
  } else {
124
132
  console.error("\n " + c.red("✗") + ` ${body?.error ?? `register-app failed (${res.status})`}\n`);
125
133
  }
@@ -225,11 +233,14 @@ function pmAddCmd(pm) {
225
233
  }
226
234
 
227
235
  /**
236
+ * Strips everything except letters and digits while preserving the original case.
237
+ * The backend stores names case-sensitively for display but compares lowercase
238
+ * for uniqueness, so "DataHaven" and "datahaven" are the same app.
228
239
  * @param {string} name
229
240
  * @returns {string}
230
241
  */
231
242
  function sanitiseName(name) {
232
- return name.toLowerCase().replace(/[^a-z0-9]/g, "");
243
+ return name.replace(/[^a-zA-Z0-9]/g, "");
233
244
  }
234
245
 
235
246
  /**
@@ -309,7 +320,7 @@ async function patchEntryPoint(cwd, isEsm) {
309
320
  return;
310
321
  }
311
322
 
312
- const relEntry = entryPath.replace(cwd + "\\", "").replace(cwd + "/", "");
323
+ const relEntry = relative(cwd, entryPath);
313
324
 
314
325
  // ── Diff preview ───────────────────────────────────────────────────────────
315
326
  console.log(" " + c.dim("▎"));
@@ -23,18 +23,21 @@ export const recoverCommand = new Command("recover")
23
23
  }
24
24
 
25
25
  // ── App name ──────────────────────────────────────────────────────────────
26
+ // Names are case-insensitive for lookup — "datahaven" finds "DataHaven".
27
+ // We preserve the input casing here; the backend returns the canonical name.
26
28
  let appName;
27
29
  if (opts.name) {
28
- appName = opts.name.toLowerCase().replace(/[^a-z0-9]/g, "");
30
+ // Strip non-alphanumeric but preserve case — backend does case-insensitive match.
31
+ appName = opts.name.replace(/[^a-zA-Z0-9]/g, "");
29
32
  console.log(" App name " + c.cyan(appName));
30
33
  } else {
31
- const suggested = basename(cwd) || "my-project";
34
+ const suggested = sanitiseName(basename(cwd) || "myapp");
32
35
  const raw = await prompt(` App name [${c.dim(suggested)}] › `);
33
- appName = (raw || suggested).toLowerCase().replace(/[^a-z0-9]/g, "");
36
+ appName = sanitiseName(raw || suggested);
34
37
  }
35
38
 
36
39
  if (!appName) {
37
- console.error(" " + c.red("✗") + " App name is required.\n");
40
+ console.error(" " + c.red("✗") + " App name is required and must contain at least one letter or digit.\n");
38
41
  process.exit(1);
39
42
  }
40
43
 
@@ -58,7 +61,7 @@ export const recoverCommand = new Command("recover")
58
61
  try { body = await res.json(); } catch { /* ignore */ }
59
62
  if (res.status === 404) {
60
63
  console.error("\n " + c.red("✗") + ` No app named "${c.cyan(appName)}" found.`);
61
- console.error(" Check the name carefully names are lowercase and alphanumeric only.\n");
64
+ console.error(" Lookup is case-insensitivecheck spelling (letters and numbers only).\n");
62
65
  } else {
63
66
  console.error("\n " + c.red("✗") + ` ${body?.error ?? `recover-app failed (${res.status})`}\n`);
64
67
  }
@@ -68,6 +71,7 @@ export const recoverCommand = new Command("recover")
68
71
  const { app_id, name } = await res.json();
69
72
 
70
73
  // ── Write .suron.json ─────────────────────────────────────────────────────
74
+ // Use the canonical name returned by the server (original registration casing).
71
75
  writeFileSync(
72
76
  join(cwd, ".suron.json"),
73
77
  JSON.stringify({ app: name, id: app_id, api_url: apiUrl }, null, 2) + "\n",
@@ -80,3 +84,12 @@ export const recoverCommand = new Command("recover")
80
84
  console.log(" " + c.dim(" id: ") + c.cyan(app_id));
81
85
  console.log();
82
86
  });
87
+
88
+ /**
89
+ * Strips non-alphanumeric characters while preserving case.
90
+ * @param {string} name
91
+ * @returns {string}
92
+ */
93
+ function sanitiseName(name) {
94
+ return name.replace(/[^a-zA-Z0-9]/g, "");
95
+ }