@suronai/cli 0.1.31 → 0.1.32

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.31",
3
+ "version": "0.1.32",
4
4
  "description": "CLI for Suron — suron login, init, whoami, recover",
5
5
  "type": "module",
6
6
  "bin": {
@@ -15,6 +15,12 @@ export const initCommand = new Command("init")
15
15
 
16
16
  console.log("\n" + c.bold(" suron init") + " — " + c.dim(cwd) + "\n");
17
17
 
18
+ if (existsSync(join(cwd, ".suron.json"))) {
19
+ console.error(" " + c.red("✗") + " .suron.json already exists — this app is already initialised.");
20
+ console.error(" To restore a lost config, run: " + c.bold("suron recover") + "\n");
21
+ process.exit(1);
22
+ }
23
+
18
24
  if (!existsSync(join(cwd, ".env"))) {
19
25
  console.error(" " + c.red("✗") + " .env not found in current directory");
20
26
  console.error(" Create a .env file with your secrets, then run: suron init\n");
@@ -213,15 +219,53 @@ async function patchEntryPoint(cwd, isEsm) {
213
219
 
214
220
  const lines = src.split("\n");
215
221
 
216
- // Find every line that references dotenv (import or require, any style)
217
- const dotenvLines = [];
222
+ // Two-pass scan:
223
+ // Pass 1 lines containing "dotenv" (import or require)
224
+ // Pass 2 — bare config() / config({...}) call lines that don't contain "dotenv"
225
+ // (these appear after the import was already on a separate line)
226
+ const toReplace = [];
227
+ const seenIndices = new Set();
228
+
218
229
  for (let i = 0; i < lines.length; i++) {
230
+ const trimmed = lines[i].trim();
231
+ const indent = lines[i].match(/^(\s*)/)[1];
232
+
219
233
  if (lines[i].includes("dotenv")) {
220
- dotenvLines.push({ index: i, content: lines[i] });
234
+ seenIndices.add(i);
235
+ let replacement = null;
236
+ if (isEsm) {
237
+ if (trimmed.startsWith("import")) {
238
+ replacement = indent + trimmed.replace(/(from\s+)['"]dotenv(?:\/config)?['"]/, '$1"@suronai/sdk"');
239
+ }
240
+ } else {
241
+ if (trimmed.includes("require")) {
242
+ replacement = indent + "const { config } = require(\"@suronai/sdk\");\n" + indent + "await config();";
243
+ }
244
+ }
245
+ toReplace.push({ index: i, content: lines[i], replacement });
221
246
  }
222
247
  }
223
248
 
224
- if (dotenvLines.length === 0) {
249
+ // Pass 2: bare config() call — only in ESM where the import and call are separate lines
250
+ if (isEsm) {
251
+ for (let i = 0; i < lines.length; i++) {
252
+ if (seenIndices.has(i)) continue;
253
+ const trimmed = lines[i].trim();
254
+ const indent = lines[i].match(/^(\s*)/)[1];
255
+ // Matches: config() / config({}) / config({ ... }) — with or without semicolon
256
+ if (/^config\s*\(.*\);?$/.test(trimmed) && !trimmed.startsWith("//")) {
257
+ toReplace.push({
258
+ index: i,
259
+ content: lines[i],
260
+ replacement: indent + trimmed.replace(/^config\s*\(/, "await config("),
261
+ });
262
+ }
263
+ }
264
+ // Sort by line number so the diff preview is in file order
265
+ toReplace.sort((a, b) => a.index - b.index);
266
+ }
267
+
268
+ if (toReplace.length === 0) {
225
269
  console.log("\n Add to your app entry point:\n");
226
270
  printSnippet(isEsm);
227
271
  return;
@@ -232,36 +276,7 @@ async function patchEntryPoint(cwd, isEsm) {
232
276
  console.log(" " + c.yellow("▶") + " Found dotenv in " + c.dim(relEntry) + ":");
233
277
  console.log();
234
278
 
235
- // For each dotenv line, compute its replacement.
236
- // We preserve the original line's leading whitespace (indent) and only
237
- // swap out the dotenv-specific part — nothing else on the line is touched.
238
- const replacements = dotenvLines.map(({ index, content }) => {
239
- const trimmed = content.trim();
240
- const indent = content.match(/^(\s*)/)[1];
241
- let replacement = null;
242
-
243
- if (isEsm) {
244
- // import { config } from "dotenv" → import { config } from "@suronai/sdk"
245
- // Preserves the quote style and anything else on the line.
246
- if (trimmed.startsWith("import") && trimmed.includes("dotenv")) {
247
- replacement = indent + trimmed.replace(/(from\s+)['"]dotenv['"]/, '$1"@suronai/sdk"');
248
- }
249
- // config(); → await config();
250
- // Only matches lines that are purely a config() call, nothing else.
251
- else if (/^config\s*\(\s*\);?$/.test(trimmed)) {
252
- replacement = indent + trimmed.replace(/^config\s*\(/, "await config(");
253
- }
254
- } else {
255
- // require("dotenv").config() → const { config } = require("@suronai/sdk"); await config();
256
- if (trimmed.includes("require") && trimmed.includes("dotenv")) {
257
- replacement = indent + "const { config } = require(\"@suronai/sdk\");\n" + indent + "await config();";
258
- }
259
- }
260
-
261
- // If we found a dotenv line but don't know how to replace it, show it
262
- // with a warning so the user knows to handle it manually.
263
- return { index, content, replacement };
264
- });
279
+ const replacements = toReplace;
265
280
 
266
281
  // Show the diff preview
267
282
  for (const { content, replacement } of replacements) {