@insforge/cli 0.1.48 → 0.1.50

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
@@ -5,7 +5,166 @@ import { readFileSync as readFileSync7 } from "fs";
5
5
  import { join as join9, dirname } from "path";
6
6
  import { fileURLToPath } from "url";
7
7
  import { Command } from "commander";
8
- import * as clack15 from "@clack/prompts";
8
+ import * as clack11 from "@clack/prompts";
9
+
10
+ // src/lib/prompts.ts
11
+ import * as readline from "readline";
12
+ import * as clack from "@clack/prompts";
13
+ var isInteractive = !!(process.stdin.isTTY && process.stdout.isTTY);
14
+ var LineReader = class {
15
+ constructor(input, output) {
16
+ this.output = output;
17
+ this.rl = readline.createInterface({ input });
18
+ this.rl.on("line", (line) => {
19
+ if (this.waiter) {
20
+ const w = this.waiter;
21
+ this.waiter = null;
22
+ w(line);
23
+ } else {
24
+ this.queue.push(line);
25
+ }
26
+ });
27
+ this.rl.on("close", () => {
28
+ this.closed = true;
29
+ if (this.waiter) {
30
+ const w = this.waiter;
31
+ this.waiter = null;
32
+ w(null);
33
+ }
34
+ });
35
+ }
36
+ queue = [];
37
+ waiter = null;
38
+ closed = false;
39
+ rl;
40
+ async readLine(prompt) {
41
+ this.output.write(prompt);
42
+ if (this.queue.length > 0) return this.queue.shift();
43
+ if (this.closed) return null;
44
+ return new Promise((resolve4) => {
45
+ this.waiter = resolve4;
46
+ });
47
+ }
48
+ close() {
49
+ this.rl.close();
50
+ }
51
+ };
52
+ var sharedReader = null;
53
+ function getReader() {
54
+ if (!sharedReader) {
55
+ sharedReader = new LineReader(process.stdin, process.stdout);
56
+ }
57
+ return sharedReader;
58
+ }
59
+ var CANCEL = /* @__PURE__ */ Symbol("prompt.cancel");
60
+ function isCancel2(v) {
61
+ return v === CANCEL || clack.isCancel(v);
62
+ }
63
+ async function text2(opts) {
64
+ if (isInteractive) {
65
+ const result = await clack.text({
66
+ message: opts.message,
67
+ initialValue: opts.initialValue,
68
+ placeholder: opts.placeholder,
69
+ validate: opts.validate
70
+ });
71
+ if (clack.isCancel(result)) return CANCEL;
72
+ return result;
73
+ }
74
+ return nonTtyText(opts);
75
+ }
76
+ async function select2(opts) {
77
+ if (isInteractive) {
78
+ const result = await clack.select({
79
+ message: opts.message,
80
+ options: opts.options,
81
+ initialValue: opts.initialValue
82
+ });
83
+ if (clack.isCancel(result)) return CANCEL;
84
+ return result;
85
+ }
86
+ return nonTtySelect(opts);
87
+ }
88
+ async function confirm2(opts) {
89
+ if (isInteractive) {
90
+ const result = await clack.confirm({
91
+ message: opts.message,
92
+ initialValue: opts.initialValue
93
+ });
94
+ if (clack.isCancel(result)) return CANCEL;
95
+ return result;
96
+ }
97
+ return nonTtyConfirm(opts);
98
+ }
99
+ async function password2(opts) {
100
+ if (isInteractive) {
101
+ const result = await clack.password({ message: opts.message });
102
+ if (clack.isCancel(result)) return CANCEL;
103
+ return result;
104
+ }
105
+ return nonTtyText({ message: opts.message, trim: false });
106
+ }
107
+ async function nonTtyText(opts, io = {}) {
108
+ const reader = io.reader ?? getReader();
109
+ const stderr = io.stderr ?? process.stderr;
110
+ const shouldTrim = opts.trim ?? true;
111
+ const defaultHint = opts.initialValue ? ` [${opts.initialValue}]` : "";
112
+ for (; ; ) {
113
+ const raw = await reader.readLine(`? ${opts.message}${defaultHint} `);
114
+ if (raw === null) return CANCEL;
115
+ const normalized = shouldTrim ? raw.trim() : raw;
116
+ const value = normalized === "" ? opts.initialValue ?? "" : normalized;
117
+ if (opts.validate) {
118
+ const err = opts.validate(value);
119
+ if (err) {
120
+ stderr.write(` ${err}
121
+ `);
122
+ continue;
123
+ }
124
+ }
125
+ return value;
126
+ }
127
+ }
128
+ async function nonTtySelect(opts, io = {}) {
129
+ if (opts.options.length === 0) {
130
+ throw new Error(`No options available for prompt "${opts.message}".`);
131
+ }
132
+ const reader = io.reader ?? getReader();
133
+ const stdout = io.stdout ?? process.stdout;
134
+ const stderr = io.stderr ?? process.stderr;
135
+ stdout.write(`? ${opts.message}
136
+ `);
137
+ opts.options.forEach((o, i) => {
138
+ const hint = o.hint ? ` \u2014 ${o.hint}` : "";
139
+ stdout.write(` ${i + 1}) ${o.label}${hint}
140
+ `);
141
+ });
142
+ for (; ; ) {
143
+ const raw = await reader.readLine(`Enter number [1-${opts.options.length}]: `);
144
+ if (raw === null) return CANCEL;
145
+ const n = Number.parseInt(raw.trim(), 10);
146
+ if (Number.isInteger(n) && n >= 1 && n <= opts.options.length) {
147
+ return opts.options[n - 1].value;
148
+ }
149
+ stderr.write(` Please enter a number between 1 and ${opts.options.length}.
150
+ `);
151
+ }
152
+ }
153
+ async function nonTtyConfirm(opts, io = {}) {
154
+ const reader = io.reader ?? getReader();
155
+ const stderr = io.stderr ?? process.stderr;
156
+ const defaultHint = opts.initialValue === true ? " [Y/n]" : opts.initialValue === false ? " [y/N]" : " [y/n]";
157
+ for (; ; ) {
158
+ const raw = await reader.readLine(`? ${opts.message}${defaultHint} `);
159
+ if (raw === null) return CANCEL;
160
+ const answer = raw.trim().toLowerCase();
161
+ if (answer === "" && opts.initialValue !== void 0) return opts.initialValue;
162
+ if (answer === "y" || answer === "yes") return true;
163
+ if (answer === "n" || answer === "no") return false;
164
+ stderr.write(` Please answer y or n.
165
+ `);
166
+ }
167
+ }
9
168
 
10
169
  // src/lib/config.ts
11
170
  import { existsSync, mkdirSync, readFileSync, writeFileSync, unlinkSync } from "fs";
@@ -87,7 +246,7 @@ function getAccessToken() {
87
246
  }
88
247
 
89
248
  // src/commands/login.ts
90
- import * as clack3 from "@clack/prompts";
249
+ import * as clack4 from "@clack/prompts";
91
250
 
92
251
  // src/lib/errors.ts
93
252
  var CLIError = class extends Error {
@@ -179,7 +338,8 @@ function getRootOpts(cmd) {
179
338
  import { createServer } from "http";
180
339
  import { randomBytes, createHash } from "crypto";
181
340
  import { URL as URL2 } from "url";
182
- import * as clack from "@clack/prompts";
341
+ import * as clack2 from "@clack/prompts";
342
+ import pc from "picocolors";
183
343
  var DEFAULT_CLIENT_ID = "clf_NK8cMUs41gm8ZcfdtSguVw";
184
344
  var OAUTH_SCOPES = "user:read organizations:read projects:read projects:write";
185
345
  function generatePKCE() {
@@ -315,25 +475,35 @@ async function performOAuthLogin(apiUrl) {
315
475
  state,
316
476
  scopes: OAUTH_SCOPES
317
477
  });
318
- clack.log.info("Opening browser for authentication...");
319
- clack.log.info(`If browser doesn't open, visit:
478
+ if (isInteractive) {
479
+ clack2.log.info("Opening browser for authentication...");
480
+ clack2.log.info(`If browser doesn't open, visit:
320
481
  ${authUrl}`);
482
+ } else {
483
+ process.stderr.write(`
484
+ To sign in, open this URL in your browser:
485
+
486
+ ${pc.cyan(pc.underline(authUrl))}
487
+
488
+ `);
489
+ }
321
490
  try {
322
491
  const open = (await import("open")).default;
323
492
  await open(authUrl);
324
493
  } catch {
325
- clack.log.warn("Could not open browser. Please visit the URL above.");
494
+ if (isInteractive) clack2.log.warn("Could not open browser. Please visit the URL above.");
326
495
  }
327
- const s = clack.spinner();
328
- s.start("Waiting for authentication...");
496
+ const s = isInteractive ? clack2.spinner() : null;
497
+ s?.start("Waiting for authentication...");
498
+ if (!isInteractive) process.stderr.write("Waiting for authentication...\n");
329
499
  try {
330
500
  const callbackResult = await result;
331
501
  close();
332
502
  if (callbackResult.state !== state) {
333
- s.stop("Authentication failed");
503
+ s?.stop("Authentication failed");
334
504
  throw new Error("State mismatch. Possible CSRF attack.");
335
505
  }
336
- s.message("Exchanging authorization code...");
506
+ s?.message("Exchanging authorization code...");
337
507
  const tokens = await exchangeCodeForTokens({
338
508
  platformUrl,
339
509
  code: callbackResult.code,
@@ -351,20 +521,24 @@ ${authUrl}`);
351
521
  const profile = await getProfile(apiUrl);
352
522
  creds.user = profile;
353
523
  saveCredentials(creds);
354
- s.stop(`Authenticated as ${profile.email}`);
524
+ s?.stop(`Authenticated as ${profile.email}`);
525
+ if (!isInteractive) process.stderr.write(`Authenticated as ${profile.email}
526
+ `);
355
527
  } catch {
356
- s.stop("Authenticated successfully");
528
+ s?.stop("Authenticated successfully");
529
+ if (!isInteractive) process.stderr.write("Authenticated successfully\n");
357
530
  }
358
531
  return creds;
359
532
  } catch (err) {
360
533
  close();
361
- s.stop("Authentication failed");
534
+ s?.stop("Authentication failed");
535
+ if (!isInteractive) process.stderr.write("Authentication failed\n");
362
536
  throw err;
363
537
  }
364
538
  }
365
539
 
366
540
  // src/lib/credentials.ts
367
- import * as clack2 from "@clack/prompts";
541
+ import * as clack3 from "@clack/prompts";
368
542
  async function requireAuth(apiUrl, allowOssBypass = true) {
369
543
  const projConfig = getProjectConfig();
370
544
  if (allowOssBypass && projConfig?.project_id === FAKE_PROJECT_ID) {
@@ -382,16 +556,16 @@ async function requireAuth(apiUrl, allowOssBypass = true) {
382
556
  }
383
557
  const creds = getCredentials();
384
558
  if (creds && creds.access_token) return creds;
385
- clack2.log.info("You need to log in to continue.");
559
+ clack3.log.info("You need to log in to continue.");
386
560
  for (; ; ) {
387
561
  try {
388
562
  return await performOAuthLogin(apiUrl);
389
563
  } catch (err) {
390
564
  if (!process.stdout.isTTY) throw err;
391
565
  const msg = err instanceof Error ? err.message : "Unknown error";
392
- clack2.log.error(`Login failed: ${msg}`);
393
- const retry = await clack2.confirm({ message: "Would you like to try again?" });
394
- if (clack2.isCancel(retry) || !retry) {
566
+ clack3.log.error(`Login failed: ${msg}`);
567
+ const retry = await confirm2({ message: "Would you like to try again?" });
568
+ if (isCancel2(retry) || !retry) {
395
569
  throw new AuthError("Authentication required. Run `npx @insforge/cli login` to authenticate.");
396
570
  }
397
571
  }
@@ -421,7 +595,7 @@ async function refreshAccessToken(apiUrl) {
421
595
  return data.access_token;
422
596
  } catch {
423
597
  if (process.stdout.isTTY) {
424
- clack2.log.warn("Session expired. Please log in again.");
598
+ clack3.log.warn("Session expired. Please log in again.");
425
599
  const newCreds = await performOAuthLogin(apiUrl);
426
600
  return newCreds.access_token;
427
601
  }
@@ -477,12 +651,12 @@ async function platformFetch(path5, options = {}, apiUrl) {
477
651
  }
478
652
  return res;
479
653
  }
480
- async function login(email, password2, apiUrl) {
654
+ async function login(email, password3, apiUrl) {
481
655
  const baseUrl = getPlatformApiUrl(apiUrl);
482
656
  const res = await fetch(`${baseUrl}/auth/v1/login`, {
483
657
  method: "POST",
484
658
  headers: { "Content-Type": "application/json" },
485
- body: JSON.stringify({ email, password: password2 })
659
+ body: JSON.stringify({ email, password: password3 })
486
660
  });
487
661
  if (!res.ok) {
488
662
  const err = await res.json().catch(() => ({}));
@@ -618,30 +792,30 @@ function registerLoginCommand(program2) {
618
792
  }
619
793
  async function loginWithEmail(json, apiUrl) {
620
794
  if (!json) {
621
- clack3.intro("InsForge CLI");
795
+ clack4.intro("InsForge CLI");
622
796
  }
623
- const email = json ? process.env.INSFORGE_EMAIL : await clack3.text({
797
+ const email = json ? process.env.INSFORGE_EMAIL : await text2({
624
798
  message: "Email:",
625
799
  validate: (v) => v.includes("@") ? void 0 : "Please enter a valid email"
626
800
  });
627
- if (clack3.isCancel(email)) {
628
- clack3.cancel("Login cancelled.");
801
+ if (isCancel2(email)) {
802
+ clack4.cancel("Login cancelled.");
629
803
  throw new Error("cancelled");
630
804
  }
631
- const password2 = json ? process.env.INSFORGE_PASSWORD : await clack3.password({
805
+ const password3 = json ? process.env.INSFORGE_PASSWORD : await password2({
632
806
  message: "Password:"
633
807
  });
634
- if (clack3.isCancel(password2)) {
635
- clack3.cancel("Login cancelled.");
808
+ if (isCancel2(password3)) {
809
+ clack4.cancel("Login cancelled.");
636
810
  throw new Error("cancelled");
637
811
  }
638
- if (!email || !password2) {
812
+ if (!email || !password3) {
639
813
  throw new Error("Email and password are required. Set INSFORGE_EMAIL and INSFORGE_PASSWORD environment variables for non-interactive mode.");
640
814
  }
641
815
  if (!json) {
642
- const s = clack3.spinner();
816
+ const s = clack4.spinner();
643
817
  s.start("Authenticating...");
644
- const result = await login(email, password2, apiUrl);
818
+ const result = await login(email, password3, apiUrl);
645
819
  const creds = {
646
820
  access_token: result.token,
647
821
  refresh_token: result._refreshToken ?? "",
@@ -649,9 +823,9 @@ async function loginWithEmail(json, apiUrl) {
649
823
  };
650
824
  saveCredentials(creds);
651
825
  s.stop(`Authenticated as ${result.user.email}`);
652
- clack3.outro("Done");
826
+ clack4.outro("Done");
653
827
  } else {
654
- const result = await login(email, password2, apiUrl);
828
+ const result = await login(email, password3, apiUrl);
655
829
  const creds = {
656
830
  access_token: result.token,
657
831
  refresh_token: result._refreshToken ?? "",
@@ -663,11 +837,11 @@ async function loginWithEmail(json, apiUrl) {
663
837
  }
664
838
  async function loginWithOAuth(json, apiUrl) {
665
839
  if (!json) {
666
- clack3.intro("InsForge CLI");
840
+ clack4.intro("InsForge CLI");
667
841
  }
668
842
  const creds = await performOAuthLogin(apiUrl);
669
843
  if (!json) {
670
- clack3.outro("Done");
844
+ clack4.outro("Done");
671
845
  } else {
672
846
  console.log(JSON.stringify({ success: true, user: creds.user }));
673
847
  }
@@ -762,7 +936,6 @@ function registerOrgsCommands(orgsCmd2) {
762
936
  }
763
937
 
764
938
  // src/commands/projects/list.ts
765
- import * as clack4 from "@clack/prompts";
766
939
  function registerProjectsCommands(projectsCmd2) {
767
940
  projectsCmd2.command("list").description("List all projects in an organization").option("--org-id <id>", "Organization ID (uses default if not specified)").action(async (opts, cmd) => {
768
941
  const { json, apiUrl } = getRootOpts(cmd);
@@ -777,14 +950,14 @@ function registerProjectsCommands(projectsCmd2) {
777
950
  if (orgs.length === 1) {
778
951
  orgId = orgs[0].id;
779
952
  } else if (!json) {
780
- const selected = await clack4.select({
953
+ const selected = await select2({
781
954
  message: "Select an organization:",
782
955
  options: orgs.map((o) => ({
783
956
  value: o.id,
784
957
  label: o.name
785
958
  }))
786
959
  });
787
- if (clack4.isCancel(selected)) {
960
+ if (isCancel2(selected)) {
788
961
  process.exit(0);
789
962
  }
790
963
  orgId = selected;
@@ -817,6 +990,7 @@ import { promisify as promisify3 } from "util";
817
990
  import * as fs4 from "fs/promises";
818
991
  import * as path4 from "path";
819
992
  import * as clack8 from "@clack/prompts";
993
+ import pc2 from "picocolors";
820
994
 
821
995
  // src/lib/skills.ts
822
996
  import { exec } from "child_process";
@@ -1382,14 +1556,14 @@ function registerCreateCommand(program2) {
1382
1556
  if (json) {
1383
1557
  throw new CLIError("Multiple organizations found. Specify --org-id.");
1384
1558
  }
1385
- const selected = await clack7.select({
1559
+ const selected = await select2({
1386
1560
  message: "Select an organization:",
1387
1561
  options: orgs.map((o) => ({
1388
1562
  value: o.id,
1389
1563
  label: o.name
1390
1564
  }))
1391
1565
  });
1392
- if (clack7.isCancel(selected)) process.exit(0);
1566
+ if (isCancel2(selected)) process.exit(0);
1393
1567
  orgId = selected;
1394
1568
  }
1395
1569
  }
@@ -1400,12 +1574,12 @@ function registerCreateCommand(program2) {
1400
1574
  if (!projectName) {
1401
1575
  if (json) throw new CLIError("--name is required in JSON mode.");
1402
1576
  const defaultName = getDefaultProjectName();
1403
- const name = await clack7.text({
1577
+ const name = await text2({
1404
1578
  message: "Project name:",
1405
1579
  ...defaultName ? { initialValue: defaultName } : {},
1406
1580
  validate: (v) => v.length >= 2 ? void 0 : "Name must be at least 2 characters"
1407
1581
  });
1408
- if (clack7.isCancel(name)) process.exit(0);
1582
+ if (isCancel2(name)) process.exit(0);
1409
1583
  projectName = name;
1410
1584
  }
1411
1585
  projectName = path3.basename(projectName).replace(/[^a-zA-Z0-9._-]/g, "-").replace(/\.+/g, ".");
@@ -1421,21 +1595,21 @@ function registerCreateCommand(program2) {
1421
1595
  if (json) {
1422
1596
  template = "empty";
1423
1597
  } else {
1424
- const approach = await clack7.select({
1598
+ const approach = await select2({
1425
1599
  message: "How would you like to start?",
1426
1600
  options: [
1427
1601
  { value: "blank", label: "Blank project", hint: "Start from scratch with .env.local ready" },
1428
1602
  { value: "template", label: "Start from a template", hint: "Pre-built starter apps" }
1429
1603
  ]
1430
1604
  });
1431
- if (clack7.isCancel(approach)) process.exit(0);
1605
+ if (isCancel2(approach)) process.exit(0);
1432
1606
  captureEvent(orgId, "create_approach_selected", {
1433
1607
  approach
1434
1608
  });
1435
1609
  if (approach === "blank") {
1436
1610
  template = "empty";
1437
1611
  } else {
1438
- const selected = await clack7.select({
1612
+ const selected = await select2({
1439
1613
  message: "Choose a starter template:",
1440
1614
  options: [
1441
1615
  { value: "react", label: "Web app template with React" },
@@ -1446,7 +1620,7 @@ function registerCreateCommand(program2) {
1446
1620
  { value: "todo", label: "Todo app with Next.js" }
1447
1621
  ]
1448
1622
  });
1449
- if (clack7.isCancel(selected)) process.exit(0);
1623
+ if (isCancel2(selected)) process.exit(0);
1450
1624
  template = selected;
1451
1625
  }
1452
1626
  }
@@ -1462,7 +1636,7 @@ function registerCreateCommand(program2) {
1462
1636
  if (hasTemplate) {
1463
1637
  dirName = projectName;
1464
1638
  if (!json) {
1465
- const inputDir = await clack7.text({
1639
+ const inputDir = await text2({
1466
1640
  message: "Directory name:",
1467
1641
  initialValue: projectName,
1468
1642
  validate: (v) => {
@@ -1472,7 +1646,7 @@ function registerCreateCommand(program2) {
1472
1646
  return void 0;
1473
1647
  }
1474
1648
  });
1475
- if (clack7.isCancel(inputDir)) process.exit(0);
1649
+ if (isCancel2(inputDir)) process.exit(0);
1476
1650
  dirName = path3.basename(inputDir).replace(/[^a-zA-Z0-9._-]/g, "-");
1477
1651
  }
1478
1652
  if (!dirName || dirName === "." || dirName === "..") {
@@ -1560,10 +1734,10 @@ function registerCreateCommand(program2) {
1560
1734
  }
1561
1735
  let liveUrl = null;
1562
1736
  if (templateDownloaded && !json) {
1563
- const shouldDeploy = await clack7.confirm({
1737
+ const shouldDeploy = await confirm2({
1564
1738
  message: "Would you like to deploy now?"
1565
1739
  });
1566
- if (!clack7.isCancel(shouldDeploy) && shouldDeploy) {
1740
+ if (!isCancel2(shouldDeploy) && shouldDeploy) {
1567
1741
  try {
1568
1742
  const envVars = await readEnvFile(process.cwd());
1569
1743
  const startBody = {};
@@ -1825,14 +1999,14 @@ function registerProjectLinkCommand(program2) {
1825
1999
  if (json) {
1826
2000
  throw new CLIError("Multiple organizations found. Specify --org-id.");
1827
2001
  }
1828
- const selected = await clack8.select({
2002
+ const selected = await select2({
1829
2003
  message: "Select an organization:",
1830
2004
  options: orgs.map((o) => ({
1831
2005
  value: o.id,
1832
2006
  label: o.name
1833
2007
  }))
1834
2008
  });
1835
- if (clack8.isCancel(selected)) process.exit(0);
2009
+ if (isCancel2(selected)) process.exit(0);
1836
2010
  orgId = selected;
1837
2011
  }
1838
2012
  }
@@ -1847,14 +2021,14 @@ function registerProjectLinkCommand(program2) {
1847
2021
  if (json) {
1848
2022
  throw new CLIError("Specify --project-id in JSON mode.");
1849
2023
  }
1850
- const selected = await clack8.select({
2024
+ const selected = await select2({
1851
2025
  message: "Select a project to link:",
1852
2026
  options: projects.map((p) => ({
1853
2027
  value: p.id,
1854
2028
  label: `${p.name} (${p.region}, ${p.status})`
1855
2029
  }))
1856
2030
  });
1857
- if (clack8.isCancel(selected)) process.exit(0);
2031
+ if (isCancel2(selected)) process.exit(0);
1858
2032
  projectId = selected;
1859
2033
  }
1860
2034
  let project;
@@ -1905,7 +2079,7 @@ function registerProjectLinkCommand(program2) {
1905
2079
  }
1906
2080
  let dirName = project.name;
1907
2081
  if (!json) {
1908
- const inputDir = await clack8.text({
2082
+ const inputDir = await text2({
1909
2083
  message: "Directory name:",
1910
2084
  initialValue: project.name,
1911
2085
  validate: (v) => {
@@ -1915,7 +2089,7 @@ function registerProjectLinkCommand(program2) {
1915
2089
  return void 0;
1916
2090
  }
1917
2091
  });
1918
- if (clack8.isCancel(inputDir)) process.exit(0);
2092
+ if (isCancel2(inputDir)) process.exit(0);
1919
2093
  dirName = path4.basename(inputDir).replace(/[^a-zA-Z0-9._-]/g, "-");
1920
2094
  }
1921
2095
  if (!dirName || dirName === "." || dirName === "..") {
@@ -1953,11 +2127,14 @@ function registerProjectLinkCommand(program2) {
1953
2127
  await reportCliUsage("cli.link", true, 6, projectConfig);
1954
2128
  if (!json) {
1955
2129
  const dashboardUrl = `${getFrontendUrl()}/dashboard/project/${project.id}`;
1956
- clack8.log.step(`Dashboard: ${dashboardUrl}`);
2130
+ clack8.log.step(`Dashboard: ${pc2.underline(dashboardUrl)}`);
1957
2131
  if (templateDownloaded) {
1958
- const steps = [`cd ${dirName}`, "npm run dev"];
1959
- clack8.note(steps.join("\n"), "Next steps");
1960
- clack8.note("Open your coding agent (Claude Code, Codex, Cursor, etc.) to add new features.", "Keep building");
2132
+ const runCommand = `${pc2.cyan("cd")} ${pc2.green(dirName)} ${pc2.dim("&&")} ${pc2.cyan("npm run dev")}`;
2133
+ const steps = [
2134
+ `${pc2.bold("1.")} ${runCommand}`,
2135
+ `${pc2.bold("2.")} Open ${pc2.cyan("Claude Code")} or ${pc2.cyan("Cursor")} and prompt your agent to add more features`
2136
+ ];
2137
+ clack8.note(steps.join("\n"), "What's next");
1961
2138
  } else {
1962
2139
  clack8.log.warn("Template download failed. You can retry or set up manually.");
1963
2140
  }
@@ -2586,8 +2763,8 @@ function registerFunctionsInvokeCommand(functionsCmd2) {
2586
2763
  console.log(JSON.stringify(data, null, 2));
2587
2764
  }
2588
2765
  } else {
2589
- const text4 = await res.text();
2590
- console.log(text4);
2766
+ const text3 = await res.text();
2767
+ console.log(text3);
2591
2768
  }
2592
2769
  if (status >= 400) {
2593
2770
  throw new CLIError(`HTTP ${status}`, 1, "HTTP_ERROR");
@@ -2630,10 +2807,10 @@ function registerFunctionsDeleteCommand(functionsCmd2) {
2630
2807
  try {
2631
2808
  await requireAuth();
2632
2809
  if (!yes && !json) {
2633
- const confirmed = await clack9.confirm({
2810
+ const confirmed = await confirm2({
2634
2811
  message: `Delete function "${slug}"? This cannot be undone.`
2635
2812
  });
2636
- if (clack9.isCancel(confirmed) || !confirmed) {
2813
+ if (isCancel2(confirmed) || !confirmed) {
2637
2814
  clack9.log.info("Cancelled.");
2638
2815
  return;
2639
2816
  }
@@ -2792,17 +2969,16 @@ function registerStorageCreateBucketCommand(storageCmd2) {
2792
2969
  }
2793
2970
 
2794
2971
  // src/commands/storage/delete-bucket.ts
2795
- import * as clack10 from "@clack/prompts";
2796
2972
  function registerStorageDeleteBucketCommand(storageCmd2) {
2797
2973
  storageCmd2.command("delete-bucket <name>").description("Delete a storage bucket and all its objects").action(async (name, _opts, cmd) => {
2798
2974
  const { json, yes } = getRootOpts(cmd);
2799
2975
  try {
2800
2976
  await requireAuth();
2801
2977
  if (!yes && !json) {
2802
- const confirm8 = await clack10.confirm({
2978
+ const confirm3 = await confirm2({
2803
2979
  message: `Delete bucket "${name}" and all its objects? This cannot be undone.`
2804
2980
  });
2805
- if (!confirm8 || clack10.isCancel(confirm8)) {
2981
+ if (isCancel2(confirm3) || !confirm3) {
2806
2982
  process.exit(0);
2807
2983
  }
2808
2984
  }
@@ -3057,7 +3233,6 @@ function registerDeploymentsStatusCommand(deploymentsCmd2) {
3057
3233
  }
3058
3234
 
3059
3235
  // src/commands/deployments/cancel.ts
3060
- import * as clack11 from "@clack/prompts";
3061
3236
  function registerDeploymentsCancelCommand(deploymentsCmd2) {
3062
3237
  deploymentsCmd2.command("cancel <id>").description("Cancel a deployment").action(async (id, _opts, cmd) => {
3063
3238
  const { json, yes } = getRootOpts(cmd);
@@ -3065,10 +3240,10 @@ function registerDeploymentsCancelCommand(deploymentsCmd2) {
3065
3240
  await requireAuth();
3066
3241
  if (!getProjectConfig()) throw new ProjectNotLinkedError();
3067
3242
  if (!yes && !json) {
3068
- const confirmed = await clack11.confirm({
3243
+ const confirmed = await confirm2({
3069
3244
  message: `Cancel deployment ${id}?`
3070
3245
  });
3071
- if (clack11.isCancel(confirmed) || !confirmed) process.exit(0);
3246
+ if (isCancel2(confirmed) || !confirmed) process.exit(0);
3072
3247
  }
3073
3248
  const res = await ossFetch(`/api/deployments/${id}/cancel`, { method: "POST" });
3074
3249
  const result = await res.json();
@@ -3348,17 +3523,16 @@ function registerSecretsUpdateCommand(secretsCmd2) {
3348
3523
  }
3349
3524
 
3350
3525
  // src/commands/secrets/delete.ts
3351
- import * as clack12 from "@clack/prompts";
3352
3526
  function registerSecretsDeleteCommand(secretsCmd2) {
3353
3527
  secretsCmd2.command("delete <key>").description("Delete a secret").action(async (key, _opts, cmd) => {
3354
3528
  const { json, yes } = getRootOpts(cmd);
3355
3529
  try {
3356
3530
  await requireAuth();
3357
3531
  if (!yes && !json) {
3358
- const confirm8 = await clack12.confirm({
3532
+ const confirm3 = await confirm2({
3359
3533
  message: `Delete secret "${key}"? This cannot be undone.`
3360
3534
  });
3361
- if (!confirm8 || clack12.isCancel(confirm8)) {
3535
+ if (isCancel2(confirm3) || !confirm3) {
3362
3536
  process.exit(0);
3363
3537
  }
3364
3538
  }
@@ -3534,17 +3708,16 @@ function registerSchedulesUpdateCommand(schedulesCmd2) {
3534
3708
  }
3535
3709
 
3536
3710
  // src/commands/schedules/delete.ts
3537
- import * as clack13 from "@clack/prompts";
3538
3711
  function registerSchedulesDeleteCommand(schedulesCmd2) {
3539
3712
  schedulesCmd2.command("delete <id>").description("Delete a schedule").action(async (id, _opts, cmd) => {
3540
3713
  const { json, yes } = getRootOpts(cmd);
3541
3714
  try {
3542
3715
  await requireAuth();
3543
3716
  if (!yes && !json) {
3544
- const confirm8 = await clack13.confirm({
3717
+ const confirm3 = await confirm2({
3545
3718
  message: `Delete schedule "${id}"? This cannot be undone.`
3546
3719
  });
3547
- if (!confirm8 || clack13.isCancel(confirm8)) {
3720
+ if (isCancel2(confirm3) || !confirm3) {
3548
3721
  process.exit(0);
3549
3722
  }
3550
3723
  }
@@ -4175,7 +4348,7 @@ function formatSize2(gb) {
4175
4348
 
4176
4349
  // src/commands/diagnose/index.ts
4177
4350
  import * as os from "os";
4178
- import * as clack14 from "@clack/prompts";
4351
+ import * as clack10 from "@clack/prompts";
4179
4352
 
4180
4353
  // src/commands/diagnose/metrics.ts
4181
4354
  var METRIC_LABELS = {
@@ -4712,10 +4885,10 @@ function registerDiagnoseCommands(diagnoseCmd2) {
4712
4885
  if (question.length === 0 || question.length > 2e3) {
4713
4886
  throw new CLIError("Question must be between 1 and 2000 characters.");
4714
4887
  }
4715
- const s = !json ? clack14.spinner() : null;
4888
+ const s = !json ? clack10.spinner() : null;
4716
4889
  s?.start("Collecting diagnostic data...");
4717
4890
  const data2 = await collectDiagnosticData(projectId, ossMode, apiUrl);
4718
- const cliVersion = "0.1.48";
4891
+ const cliVersion = "0.1.50";
4719
4892
  s?.stop("Data collected");
4720
4893
  if (!json) {
4721
4894
  console.log(`
@@ -4831,7 +5004,7 @@ function registerDiagnoseCommands(diagnoseCmd2) {
4831
5004
  outputJson({ sessionId, events: jsonEvents });
4832
5005
  }
4833
5006
  if (!json && sessionId) {
4834
- const ratingChoice = await clack14.select({
5007
+ const ratingChoice = await select2({
4835
5008
  message: "Was this analysis helpful?",
4836
5009
  options: [
4837
5010
  { value: "skip", label: "Skip", hint: "no rating" },
@@ -4840,7 +5013,7 @@ function registerDiagnoseCommands(diagnoseCmd2) {
4840
5013
  { value: "incorrect", label: "Incorrect", hint: "diagnosis was wrong or misleading" }
4841
5014
  ]
4842
5015
  });
4843
- if (!clack14.isCancel(ratingChoice) && ratingChoice !== "skip") {
5016
+ if (!isCancel2(ratingChoice) && ratingChoice !== "skip") {
4844
5017
  try {
4845
5018
  await rateDiagnosticSession(
4846
5019
  sessionId,
@@ -4848,9 +5021,9 @@ function registerDiagnoseCommands(diagnoseCmd2) {
4848
5021
  void 0,
4849
5022
  apiUrl
4850
5023
  );
4851
- clack14.log.success("Thanks for your feedback!");
5024
+ clack10.log.success("Thanks for your feedback!");
4852
5025
  } catch {
4853
- clack14.log.warn("Failed to submit rating.");
5026
+ clack10.log.warn("Failed to submit rating.");
4854
5027
  }
4855
5028
  }
4856
5029
  }
@@ -5045,7 +5218,7 @@ async function showInteractiveMenu() {
5045
5218
  } catch {
5046
5219
  }
5047
5220
  console.log(INSFORGE_LOGO);
5048
- clack15.intro(`InsForge CLI v${pkg.version}`);
5221
+ clack11.intro(`InsForge CLI v${pkg.version}`);
5049
5222
  const options = [];
5050
5223
  if (!isLoggedIn) {
5051
5224
  options.push({ value: "login", label: "Log in to InsForge" });
@@ -5061,12 +5234,12 @@ async function showInteractiveMenu() {
5061
5234
  { value: "docs", label: "View documentation" },
5062
5235
  { value: "help", label: "Show all commands" }
5063
5236
  );
5064
- const action = await clack15.select({
5237
+ const action = await select2({
5065
5238
  message: "What would you like to do?",
5066
5239
  options
5067
5240
  });
5068
- if (clack15.isCancel(action)) {
5069
- clack15.cancel("Bye!");
5241
+ if (isCancel2(action)) {
5242
+ clack11.cancel("Bye!");
5070
5243
  process.exit(0);
5071
5244
  }
5072
5245
  switch (action) {