@insforge/cli 0.1.7 → 0.1.9

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/index.js CHANGED
@@ -1,13 +1,11 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/index.ts
4
- import { existsSync as existsSync4, mkdirSync as mkdirSync2, readFileSync as readFileSync5 } from "fs";
5
- import { join as join5, dirname } from "path";
4
+ import { readFileSync as readFileSync6 } from "fs";
5
+ import { join as join6, dirname } from "path";
6
6
  import { fileURLToPath } from "url";
7
7
  import { Command } from "commander";
8
-
9
- // src/commands/login.ts
10
- import * as clack3 from "@clack/prompts";
8
+ import * as clack13 from "@clack/prompts";
11
9
 
12
10
  // src/lib/config.ts
13
11
  import { existsSync, mkdirSync, readFileSync, writeFileSync, unlinkSync } from "fs";
@@ -86,6 +84,9 @@ function getAccessToken() {
86
84
  return process.env.INSFORGE_ACCESS_TOKEN ?? getCredentials()?.access_token ?? null;
87
85
  }
88
86
 
87
+ // src/commands/login.ts
88
+ import * as clack3 from "@clack/prompts";
89
+
89
90
  // src/lib/errors.ts
90
91
  var CLIError = class extends Error {
91
92
  constructor(message, exitCode = 1, code) {
@@ -102,7 +103,7 @@ var AuthError = class extends CLIError {
102
103
  };
103
104
  var ProjectNotLinkedError = class extends CLIError {
104
105
  constructor() {
105
- super("No project linked. Run `insforge projects link` first.", 3, "PROJECT_NOT_LINKED");
106
+ super("No project linked. Run `insforge link` first.", 3, "PROJECT_NOT_LINKED");
106
107
  }
107
108
  };
108
109
  function handleError(err, json) {
@@ -317,7 +318,19 @@ async function requireAuth(apiUrl) {
317
318
  const creds = getCredentials();
318
319
  if (creds && creds.access_token) return creds;
319
320
  clack2.log.info("You need to log in to continue.");
320
- return await performOAuthLogin(apiUrl);
321
+ for (; ; ) {
322
+ try {
323
+ return await performOAuthLogin(apiUrl);
324
+ } catch (err) {
325
+ if (!process.stdout.isTTY) throw err;
326
+ const msg = err instanceof Error ? err.message : "Unknown error";
327
+ clack2.log.error(`Login failed: ${msg}`);
328
+ const retry = await clack2.confirm({ message: "Would you like to try again?" });
329
+ if (clack2.isCancel(retry) || !retry) {
330
+ throw new AuthError("Authentication required. Run `insforge login` to authenticate.");
331
+ }
332
+ }
333
+ }
321
334
  }
322
335
  async function refreshAccessToken(apiUrl) {
323
336
  const creds = getCredentials();
@@ -649,9 +662,38 @@ import * as clack6 from "@clack/prompts";
649
662
 
650
663
  // src/lib/skills.ts
651
664
  import { exec } from "child_process";
665
+ import { existsSync as existsSync2, readFileSync as readFileSync2, appendFileSync } from "fs";
666
+ import { join as join2 } from "path";
652
667
  import { promisify } from "util";
653
668
  import * as clack5 from "@clack/prompts";
654
669
  var execAsync = promisify(exec);
670
+ var GITIGNORE_ENTRIES = [
671
+ ".insforge",
672
+ ".agent",
673
+ ".agents",
674
+ ".augment",
675
+ ".claude",
676
+ ".cline",
677
+ ".github/copilot*",
678
+ ".kilocode",
679
+ ".qoder",
680
+ ".qwen",
681
+ ".roo",
682
+ ".trae",
683
+ ".windsurf"
684
+ ];
685
+ function updateGitignore() {
686
+ const gitignorePath = join2(process.cwd(), ".gitignore");
687
+ const existing = existsSync2(gitignorePath) ? readFileSync2(gitignorePath, "utf-8") : "";
688
+ const lines = new Set(existing.split("\n").map((l) => l.trim()));
689
+ const missing = GITIGNORE_ENTRIES.filter((entry) => !lines.has(entry));
690
+ if (!missing.length) return;
691
+ const block = `
692
+ # InsForge & AI agent skills
693
+ ${missing.join("\n")}
694
+ `;
695
+ appendFileSync(gitignorePath, block);
696
+ }
655
697
  async function installSkills(json) {
656
698
  try {
657
699
  if (!json) clack5.log.info("Installing InsForge agent skills...");
@@ -663,6 +705,10 @@ async function installSkills(json) {
663
705
  } catch {
664
706
  if (!json) clack5.log.warn("Failed to install agent skills. You can run manually: npx skills add insforge/agent-skills");
665
707
  }
708
+ try {
709
+ updateGitignore();
710
+ } catch {
711
+ }
666
712
  }
667
713
 
668
714
  // src/commands/projects/link.ts
@@ -1089,7 +1135,7 @@ function registerDbExportCommand(dbCmd2) {
1089
1135
  }
1090
1136
 
1091
1137
  // src/commands/db/import.ts
1092
- import { readFileSync as readFileSync2 } from "fs";
1138
+ import { readFileSync as readFileSync3 } from "fs";
1093
1139
  import { basename } from "path";
1094
1140
  function registerDbImportCommand(dbCmd2) {
1095
1141
  dbCmd2.command("import <file>").description("Import database from a local SQL file").option("--truncate", "Truncate existing tables before import").action(async (file, opts, cmd) => {
@@ -1098,7 +1144,7 @@ function registerDbImportCommand(dbCmd2) {
1098
1144
  await requireAuth();
1099
1145
  const config = getProjectConfig();
1100
1146
  if (!config) throw new ProjectNotLinkedError();
1101
- const fileContent = readFileSync2(file);
1147
+ const fileContent = readFileSync3(file);
1102
1148
  const fileName = basename(file);
1103
1149
  const formData = new FormData();
1104
1150
  formData.append("file", new Blob([fileContent]), fileName);
@@ -1309,21 +1355,21 @@ function registerFunctionsCommands(functionsCmd2) {
1309
1355
  }
1310
1356
 
1311
1357
  // src/commands/functions/deploy.ts
1312
- import { readFileSync as readFileSync3, existsSync as existsSync2 } from "fs";
1313
- import { join as join2 } from "path";
1358
+ import { readFileSync as readFileSync4, existsSync as existsSync3 } from "fs";
1359
+ import { join as join3 } from "path";
1314
1360
  function registerFunctionsDeployCommand(functionsCmd2) {
1315
1361
  functionsCmd2.command("deploy <slug>").description("Deploy an edge function (create or update)").option("--file <path>", "Path to the function source file").option("--name <name>", "Function display name").option("--description <desc>", "Function description").action(async (slug, opts, cmd) => {
1316
1362
  const { json } = getRootOpts(cmd);
1317
1363
  try {
1318
1364
  await requireAuth();
1319
- const filePath = opts.file ?? join2(process.cwd(), "insforge", "functions", slug, "index.ts");
1320
- if (!existsSync2(filePath)) {
1365
+ const filePath = opts.file ?? join3(process.cwd(), "insforge", "functions", slug, "index.ts");
1366
+ if (!existsSync3(filePath)) {
1321
1367
  throw new CLIError(
1322
1368
  `Source file not found: ${filePath}
1323
- Specify --file <path> or create ${join2("insforge", "functions", slug, "index.ts")}`
1369
+ Specify --file <path> or create ${join3("insforge", "functions", slug, "index.ts")}`
1324
1370
  );
1325
1371
  }
1326
- const code = readFileSync3(filePath, "utf-8");
1372
+ const code = readFileSync4(filePath, "utf-8");
1327
1373
  const name = opts.name ?? slug;
1328
1374
  const description = opts.description ?? "";
1329
1375
  let exists = false;
@@ -1464,7 +1510,7 @@ function registerStorageBucketsCommand(storageCmd2) {
1464
1510
  }
1465
1511
 
1466
1512
  // src/commands/storage/upload.ts
1467
- import { readFileSync as readFileSync4, existsSync as existsSync3 } from "fs";
1513
+ import { readFileSync as readFileSync5, existsSync as existsSync4 } from "fs";
1468
1514
  import { basename as basename2 } from "path";
1469
1515
  function registerStorageUploadCommand(storageCmd2) {
1470
1516
  storageCmd2.command("upload <file>").description("Upload a file to a storage bucket").requiredOption("--bucket <name>", "Target bucket name").option("--key <objectKey>", "Object key (defaults to filename)").action(async (file, opts, cmd) => {
@@ -1473,10 +1519,10 @@ function registerStorageUploadCommand(storageCmd2) {
1473
1519
  await requireAuth();
1474
1520
  const config = getProjectConfig();
1475
1521
  if (!config) throw new ProjectNotLinkedError();
1476
- if (!existsSync3(file)) {
1522
+ if (!existsSync4(file)) {
1477
1523
  throw new CLIError(`File not found: ${file}`);
1478
1524
  }
1479
- const fileContent = readFileSync4(file);
1525
+ const fileContent = readFileSync5(file);
1480
1526
  const objectKey = opts.key ?? basename2(file);
1481
1527
  const bucketName = opts.bucket;
1482
1528
  const formData = new FormData();
@@ -1508,7 +1554,7 @@ function registerStorageUploadCommand(storageCmd2) {
1508
1554
 
1509
1555
  // src/commands/storage/download.ts
1510
1556
  import { writeFileSync as writeFileSync3 } from "fs";
1511
- import { join as join3, basename as basename3 } from "path";
1557
+ import { join as join4, basename as basename3 } from "path";
1512
1558
  function registerStorageDownloadCommand(storageCmd2) {
1513
1559
  storageCmd2.command("download <objectKey>").description("Download a file from a storage bucket").requiredOption("--bucket <name>", "Source bucket name").option("--output <path>", "Output file path (defaults to current directory)").action(async (objectKey, opts, cmd) => {
1514
1560
  const { json } = getRootOpts(cmd);
@@ -1528,7 +1574,7 @@ function registerStorageDownloadCommand(storageCmd2) {
1528
1574
  throw new CLIError(err.error ?? `Download failed: ${res.status}`);
1529
1575
  }
1530
1576
  const buffer = Buffer.from(await res.arrayBuffer());
1531
- const outputPath = opts.output ?? join3(process.cwd(), basename3(objectKey));
1577
+ const outputPath = opts.output ?? join4(process.cwd(), basename3(objectKey));
1532
1578
  writeFileSync3(outputPath, buffer);
1533
1579
  if (json) {
1534
1580
  outputJson({ success: true, path: outputPath, size: buffer.length });
@@ -1572,10 +1618,10 @@ function registerStorageDeleteBucketCommand(storageCmd2) {
1572
1618
  try {
1573
1619
  await requireAuth();
1574
1620
  if (!yes && !json) {
1575
- const confirm6 = await clack7.confirm({
1621
+ const confirm7 = await clack7.confirm({
1576
1622
  message: `Delete bucket "${name}" and all its objects? This cannot be undone.`
1577
1623
  });
1578
- if (!confirm6 || clack7.isCancel(confirm6)) {
1624
+ if (!confirm7 || clack7.isCancel(confirm7)) {
1579
1625
  process.exit(0);
1580
1626
  }
1581
1627
  }
@@ -2416,10 +2462,10 @@ function registerSecretsDeleteCommand(secretsCmd2) {
2416
2462
  try {
2417
2463
  await requireAuth();
2418
2464
  if (!yes && !json) {
2419
- const confirm6 = await clack11.confirm({
2465
+ const confirm7 = await clack11.confirm({
2420
2466
  message: `Delete secret "${key}"? This cannot be undone.`
2421
2467
  });
2422
- if (!confirm6 || clack11.isCancel(confirm6)) {
2468
+ if (!confirm7 || clack11.isCancel(confirm7)) {
2423
2469
  process.exit(0);
2424
2470
  }
2425
2471
  }
@@ -2598,10 +2644,10 @@ function registerSchedulesDeleteCommand(schedulesCmd2) {
2598
2644
  try {
2599
2645
  await requireAuth();
2600
2646
  if (!yes && !json) {
2601
- const confirm6 = await clack12.confirm({
2647
+ const confirm7 = await clack12.confirm({
2602
2648
  message: `Delete schedule "${id}"? This cannot be undone.`
2603
2649
  });
2604
- if (!confirm6 || clack12.isCancel(confirm6)) {
2650
+ if (!confirm7 || clack12.isCancel(confirm7)) {
2605
2651
  process.exit(0);
2606
2652
  }
2607
2653
  }
@@ -2701,7 +2747,7 @@ function registerLogsCommand(program2) {
2701
2747
 
2702
2748
  // src/index.ts
2703
2749
  var __dirname = dirname(fileURLToPath(import.meta.url));
2704
- var pkg = JSON.parse(readFileSync5(join5(__dirname, "../package.json"), "utf-8"));
2750
+ var pkg = JSON.parse(readFileSync6(join6(__dirname, "../package.json"), "utf-8"));
2705
2751
  var INSFORGE_LOGO = `
2706
2752
  \u2588\u2588\u2557\u2588\u2588\u2588\u2557 \u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557
2707
2753
  \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2554\u2550\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D \u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D
@@ -2710,15 +2756,6 @@ var INSFORGE_LOGO = `
2710
2756
  \u2588\u2588\u2551\u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2551 \u2588\u2588\u2551\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557
2711
2757
  \u255A\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u2550\u2550\u255D\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D
2712
2758
  `;
2713
- function showLogoOnFirstRun() {
2714
- if (process.argv.includes("--json")) return;
2715
- const localDir = join5(process.cwd(), ".insforge");
2716
- if (existsSync4(localDir)) return;
2717
- console.log(INSFORGE_LOGO);
2718
- console.log(" Welcome to InsForge CLI! Run `insforge login` to get started.\n");
2719
- mkdirSync2(localDir, { recursive: true });
2720
- }
2721
- showLogoOnFirstRun();
2722
2759
  var program = new Command();
2723
2760
  program.name("insforge").description("InsForge CLI - Command line tool for InsForge platform").version(pkg.version);
2724
2761
  program.option("--json", "Output in JSON format").option("--api-url <url>", "Override Platform API URL").option("-y, --yes", "Skip confirmation prompts");
@@ -2780,5 +2817,66 @@ registerSchedulesCreateCommand(schedulesCmd);
2780
2817
  registerSchedulesUpdateCommand(schedulesCmd);
2781
2818
  registerSchedulesDeleteCommand(schedulesCmd);
2782
2819
  registerSchedulesLogsCommand(schedulesCmd);
2783
- program.parse();
2820
+ if (process.argv.length <= 2 && process.stdout.isTTY) {
2821
+ await showInteractiveMenu();
2822
+ } else {
2823
+ program.parse();
2824
+ }
2825
+ async function showInteractiveMenu() {
2826
+ let isLoggedIn = false;
2827
+ let isLinked = false;
2828
+ try {
2829
+ isLoggedIn = !!getCredentials()?.access_token;
2830
+ } catch {
2831
+ }
2832
+ try {
2833
+ isLinked = !!getProjectConfig()?.project_id;
2834
+ } catch {
2835
+ }
2836
+ console.log(INSFORGE_LOGO);
2837
+ clack13.intro(`InsForge CLI v${pkg.version}`);
2838
+ const options = [];
2839
+ if (!isLoggedIn) {
2840
+ options.push({ value: "login", label: "Log in to InsForge" });
2841
+ }
2842
+ options.push(
2843
+ { value: "create", label: "Create a new project", hint: isLoggedIn ? void 0 : "requires login" },
2844
+ { value: "link", label: "Link an existing project", hint: isLoggedIn ? void 0 : "requires login" }
2845
+ );
2846
+ if (isLinked) {
2847
+ options.push({ value: "deploy", label: "Deploy your project" });
2848
+ }
2849
+ options.push(
2850
+ { value: "docs", label: "View documentation" },
2851
+ { value: "help", label: "Show all commands" }
2852
+ );
2853
+ const action = await clack13.select({
2854
+ message: "What would you like to do?",
2855
+ options
2856
+ });
2857
+ if (clack13.isCancel(action)) {
2858
+ clack13.cancel("Bye!");
2859
+ process.exit(0);
2860
+ }
2861
+ switch (action) {
2862
+ case "login":
2863
+ await program.parseAsync(["node", "insforge", "login"]);
2864
+ break;
2865
+ case "create":
2866
+ await program.parseAsync(["node", "insforge", "create"]);
2867
+ break;
2868
+ case "link":
2869
+ await program.parseAsync(["node", "insforge", "link"]);
2870
+ break;
2871
+ case "deploy":
2872
+ await program.parseAsync(["node", "insforge", "deployments", "deploy"]);
2873
+ break;
2874
+ case "docs":
2875
+ await program.parseAsync(["node", "insforge", "docs"]);
2876
+ break;
2877
+ case "help":
2878
+ program.help();
2879
+ break;
2880
+ }
2881
+ }
2784
2882
  //# sourceMappingURL=index.js.map