@insforge/cli 0.1.49 → 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 +257 -88
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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
|
|
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
|
|
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
|
|
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
|
-
|
|
319
|
-
|
|
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
|
-
|
|
494
|
+
if (isInteractive) clack2.log.warn("Could not open browser. Please visit the URL above.");
|
|
326
495
|
}
|
|
327
|
-
const s =
|
|
328
|
-
s
|
|
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
|
|
503
|
+
s?.stop("Authentication failed");
|
|
334
504
|
throw new Error("State mismatch. Possible CSRF attack.");
|
|
335
505
|
}
|
|
336
|
-
s
|
|
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
|
|
524
|
+
s?.stop(`Authenticated as ${profile.email}`);
|
|
525
|
+
if (!isInteractive) process.stderr.write(`Authenticated as ${profile.email}
|
|
526
|
+
`);
|
|
355
527
|
} catch {
|
|
356
|
-
s
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
393
|
-
const retry = await
|
|
394
|
-
if (
|
|
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
|
-
|
|
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,
|
|
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:
|
|
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
|
-
|
|
795
|
+
clack4.intro("InsForge CLI");
|
|
622
796
|
}
|
|
623
|
-
const email = json ? process.env.INSFORGE_EMAIL : await
|
|
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 (
|
|
628
|
-
|
|
801
|
+
if (isCancel2(email)) {
|
|
802
|
+
clack4.cancel("Login cancelled.");
|
|
629
803
|
throw new Error("cancelled");
|
|
630
804
|
}
|
|
631
|
-
const
|
|
805
|
+
const password3 = json ? process.env.INSFORGE_PASSWORD : await password2({
|
|
632
806
|
message: "Password:"
|
|
633
807
|
});
|
|
634
|
-
if (
|
|
635
|
-
|
|
808
|
+
if (isCancel2(password3)) {
|
|
809
|
+
clack4.cancel("Login cancelled.");
|
|
636
810
|
throw new Error("cancelled");
|
|
637
811
|
}
|
|
638
|
-
if (!email || !
|
|
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 =
|
|
816
|
+
const s = clack4.spinner();
|
|
643
817
|
s.start("Authenticating...");
|
|
644
|
-
const result = await login(email,
|
|
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
|
-
|
|
826
|
+
clack4.outro("Done");
|
|
653
827
|
} else {
|
|
654
|
-
const result = await login(email,
|
|
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
|
-
|
|
840
|
+
clack4.intro("InsForge CLI");
|
|
667
841
|
}
|
|
668
842
|
const creds = await performOAuthLogin(apiUrl);
|
|
669
843
|
if (!json) {
|
|
670
|
-
|
|
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
|
|
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 (
|
|
960
|
+
if (isCancel2(selected)) {
|
|
788
961
|
process.exit(0);
|
|
789
962
|
}
|
|
790
963
|
orgId = selected;
|
|
@@ -817,7 +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";
|
|
820
|
-
import
|
|
993
|
+
import pc2 from "picocolors";
|
|
821
994
|
|
|
822
995
|
// src/lib/skills.ts
|
|
823
996
|
import { exec } from "child_process";
|
|
@@ -1383,14 +1556,14 @@ function registerCreateCommand(program2) {
|
|
|
1383
1556
|
if (json) {
|
|
1384
1557
|
throw new CLIError("Multiple organizations found. Specify --org-id.");
|
|
1385
1558
|
}
|
|
1386
|
-
const selected = await
|
|
1559
|
+
const selected = await select2({
|
|
1387
1560
|
message: "Select an organization:",
|
|
1388
1561
|
options: orgs.map((o) => ({
|
|
1389
1562
|
value: o.id,
|
|
1390
1563
|
label: o.name
|
|
1391
1564
|
}))
|
|
1392
1565
|
});
|
|
1393
|
-
if (
|
|
1566
|
+
if (isCancel2(selected)) process.exit(0);
|
|
1394
1567
|
orgId = selected;
|
|
1395
1568
|
}
|
|
1396
1569
|
}
|
|
@@ -1401,12 +1574,12 @@ function registerCreateCommand(program2) {
|
|
|
1401
1574
|
if (!projectName) {
|
|
1402
1575
|
if (json) throw new CLIError("--name is required in JSON mode.");
|
|
1403
1576
|
const defaultName = getDefaultProjectName();
|
|
1404
|
-
const name = await
|
|
1577
|
+
const name = await text2({
|
|
1405
1578
|
message: "Project name:",
|
|
1406
1579
|
...defaultName ? { initialValue: defaultName } : {},
|
|
1407
1580
|
validate: (v) => v.length >= 2 ? void 0 : "Name must be at least 2 characters"
|
|
1408
1581
|
});
|
|
1409
|
-
if (
|
|
1582
|
+
if (isCancel2(name)) process.exit(0);
|
|
1410
1583
|
projectName = name;
|
|
1411
1584
|
}
|
|
1412
1585
|
projectName = path3.basename(projectName).replace(/[^a-zA-Z0-9._-]/g, "-").replace(/\.+/g, ".");
|
|
@@ -1422,21 +1595,21 @@ function registerCreateCommand(program2) {
|
|
|
1422
1595
|
if (json) {
|
|
1423
1596
|
template = "empty";
|
|
1424
1597
|
} else {
|
|
1425
|
-
const approach = await
|
|
1598
|
+
const approach = await select2({
|
|
1426
1599
|
message: "How would you like to start?",
|
|
1427
1600
|
options: [
|
|
1428
1601
|
{ value: "blank", label: "Blank project", hint: "Start from scratch with .env.local ready" },
|
|
1429
1602
|
{ value: "template", label: "Start from a template", hint: "Pre-built starter apps" }
|
|
1430
1603
|
]
|
|
1431
1604
|
});
|
|
1432
|
-
if (
|
|
1605
|
+
if (isCancel2(approach)) process.exit(0);
|
|
1433
1606
|
captureEvent(orgId, "create_approach_selected", {
|
|
1434
1607
|
approach
|
|
1435
1608
|
});
|
|
1436
1609
|
if (approach === "blank") {
|
|
1437
1610
|
template = "empty";
|
|
1438
1611
|
} else {
|
|
1439
|
-
const selected = await
|
|
1612
|
+
const selected = await select2({
|
|
1440
1613
|
message: "Choose a starter template:",
|
|
1441
1614
|
options: [
|
|
1442
1615
|
{ value: "react", label: "Web app template with React" },
|
|
@@ -1447,7 +1620,7 @@ function registerCreateCommand(program2) {
|
|
|
1447
1620
|
{ value: "todo", label: "Todo app with Next.js" }
|
|
1448
1621
|
]
|
|
1449
1622
|
});
|
|
1450
|
-
if (
|
|
1623
|
+
if (isCancel2(selected)) process.exit(0);
|
|
1451
1624
|
template = selected;
|
|
1452
1625
|
}
|
|
1453
1626
|
}
|
|
@@ -1463,7 +1636,7 @@ function registerCreateCommand(program2) {
|
|
|
1463
1636
|
if (hasTemplate) {
|
|
1464
1637
|
dirName = projectName;
|
|
1465
1638
|
if (!json) {
|
|
1466
|
-
const inputDir = await
|
|
1639
|
+
const inputDir = await text2({
|
|
1467
1640
|
message: "Directory name:",
|
|
1468
1641
|
initialValue: projectName,
|
|
1469
1642
|
validate: (v) => {
|
|
@@ -1473,7 +1646,7 @@ function registerCreateCommand(program2) {
|
|
|
1473
1646
|
return void 0;
|
|
1474
1647
|
}
|
|
1475
1648
|
});
|
|
1476
|
-
if (
|
|
1649
|
+
if (isCancel2(inputDir)) process.exit(0);
|
|
1477
1650
|
dirName = path3.basename(inputDir).replace(/[^a-zA-Z0-9._-]/g, "-");
|
|
1478
1651
|
}
|
|
1479
1652
|
if (!dirName || dirName === "." || dirName === "..") {
|
|
@@ -1561,10 +1734,10 @@ function registerCreateCommand(program2) {
|
|
|
1561
1734
|
}
|
|
1562
1735
|
let liveUrl = null;
|
|
1563
1736
|
if (templateDownloaded && !json) {
|
|
1564
|
-
const shouldDeploy = await
|
|
1737
|
+
const shouldDeploy = await confirm2({
|
|
1565
1738
|
message: "Would you like to deploy now?"
|
|
1566
1739
|
});
|
|
1567
|
-
if (!
|
|
1740
|
+
if (!isCancel2(shouldDeploy) && shouldDeploy) {
|
|
1568
1741
|
try {
|
|
1569
1742
|
const envVars = await readEnvFile(process.cwd());
|
|
1570
1743
|
const startBody = {};
|
|
@@ -1826,14 +1999,14 @@ function registerProjectLinkCommand(program2) {
|
|
|
1826
1999
|
if (json) {
|
|
1827
2000
|
throw new CLIError("Multiple organizations found. Specify --org-id.");
|
|
1828
2001
|
}
|
|
1829
|
-
const selected = await
|
|
2002
|
+
const selected = await select2({
|
|
1830
2003
|
message: "Select an organization:",
|
|
1831
2004
|
options: orgs.map((o) => ({
|
|
1832
2005
|
value: o.id,
|
|
1833
2006
|
label: o.name
|
|
1834
2007
|
}))
|
|
1835
2008
|
});
|
|
1836
|
-
if (
|
|
2009
|
+
if (isCancel2(selected)) process.exit(0);
|
|
1837
2010
|
orgId = selected;
|
|
1838
2011
|
}
|
|
1839
2012
|
}
|
|
@@ -1848,14 +2021,14 @@ function registerProjectLinkCommand(program2) {
|
|
|
1848
2021
|
if (json) {
|
|
1849
2022
|
throw new CLIError("Specify --project-id in JSON mode.");
|
|
1850
2023
|
}
|
|
1851
|
-
const selected = await
|
|
2024
|
+
const selected = await select2({
|
|
1852
2025
|
message: "Select a project to link:",
|
|
1853
2026
|
options: projects.map((p) => ({
|
|
1854
2027
|
value: p.id,
|
|
1855
2028
|
label: `${p.name} (${p.region}, ${p.status})`
|
|
1856
2029
|
}))
|
|
1857
2030
|
});
|
|
1858
|
-
if (
|
|
2031
|
+
if (isCancel2(selected)) process.exit(0);
|
|
1859
2032
|
projectId = selected;
|
|
1860
2033
|
}
|
|
1861
2034
|
let project;
|
|
@@ -1906,7 +2079,7 @@ function registerProjectLinkCommand(program2) {
|
|
|
1906
2079
|
}
|
|
1907
2080
|
let dirName = project.name;
|
|
1908
2081
|
if (!json) {
|
|
1909
|
-
const inputDir = await
|
|
2082
|
+
const inputDir = await text2({
|
|
1910
2083
|
message: "Directory name:",
|
|
1911
2084
|
initialValue: project.name,
|
|
1912
2085
|
validate: (v) => {
|
|
@@ -1916,7 +2089,7 @@ function registerProjectLinkCommand(program2) {
|
|
|
1916
2089
|
return void 0;
|
|
1917
2090
|
}
|
|
1918
2091
|
});
|
|
1919
|
-
if (
|
|
2092
|
+
if (isCancel2(inputDir)) process.exit(0);
|
|
1920
2093
|
dirName = path4.basename(inputDir).replace(/[^a-zA-Z0-9._-]/g, "-");
|
|
1921
2094
|
}
|
|
1922
2095
|
if (!dirName || dirName === "." || dirName === "..") {
|
|
@@ -1954,12 +2127,12 @@ function registerProjectLinkCommand(program2) {
|
|
|
1954
2127
|
await reportCliUsage("cli.link", true, 6, projectConfig);
|
|
1955
2128
|
if (!json) {
|
|
1956
2129
|
const dashboardUrl = `${getFrontendUrl()}/dashboard/project/${project.id}`;
|
|
1957
|
-
clack8.log.step(`Dashboard: ${
|
|
2130
|
+
clack8.log.step(`Dashboard: ${pc2.underline(dashboardUrl)}`);
|
|
1958
2131
|
if (templateDownloaded) {
|
|
1959
|
-
const runCommand = `${
|
|
2132
|
+
const runCommand = `${pc2.cyan("cd")} ${pc2.green(dirName)} ${pc2.dim("&&")} ${pc2.cyan("npm run dev")}`;
|
|
1960
2133
|
const steps = [
|
|
1961
|
-
`${
|
|
1962
|
-
`${
|
|
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`
|
|
1963
2136
|
];
|
|
1964
2137
|
clack8.note(steps.join("\n"), "What's next");
|
|
1965
2138
|
} else {
|
|
@@ -2590,8 +2763,8 @@ function registerFunctionsInvokeCommand(functionsCmd2) {
|
|
|
2590
2763
|
console.log(JSON.stringify(data, null, 2));
|
|
2591
2764
|
}
|
|
2592
2765
|
} else {
|
|
2593
|
-
const
|
|
2594
|
-
console.log(
|
|
2766
|
+
const text3 = await res.text();
|
|
2767
|
+
console.log(text3);
|
|
2595
2768
|
}
|
|
2596
2769
|
if (status >= 400) {
|
|
2597
2770
|
throw new CLIError(`HTTP ${status}`, 1, "HTTP_ERROR");
|
|
@@ -2634,10 +2807,10 @@ function registerFunctionsDeleteCommand(functionsCmd2) {
|
|
|
2634
2807
|
try {
|
|
2635
2808
|
await requireAuth();
|
|
2636
2809
|
if (!yes && !json) {
|
|
2637
|
-
const confirmed = await
|
|
2810
|
+
const confirmed = await confirm2({
|
|
2638
2811
|
message: `Delete function "${slug}"? This cannot be undone.`
|
|
2639
2812
|
});
|
|
2640
|
-
if (
|
|
2813
|
+
if (isCancel2(confirmed) || !confirmed) {
|
|
2641
2814
|
clack9.log.info("Cancelled.");
|
|
2642
2815
|
return;
|
|
2643
2816
|
}
|
|
@@ -2796,17 +2969,16 @@ function registerStorageCreateBucketCommand(storageCmd2) {
|
|
|
2796
2969
|
}
|
|
2797
2970
|
|
|
2798
2971
|
// src/commands/storage/delete-bucket.ts
|
|
2799
|
-
import * as clack10 from "@clack/prompts";
|
|
2800
2972
|
function registerStorageDeleteBucketCommand(storageCmd2) {
|
|
2801
2973
|
storageCmd2.command("delete-bucket <name>").description("Delete a storage bucket and all its objects").action(async (name, _opts, cmd) => {
|
|
2802
2974
|
const { json, yes } = getRootOpts(cmd);
|
|
2803
2975
|
try {
|
|
2804
2976
|
await requireAuth();
|
|
2805
2977
|
if (!yes && !json) {
|
|
2806
|
-
const
|
|
2978
|
+
const confirm3 = await confirm2({
|
|
2807
2979
|
message: `Delete bucket "${name}" and all its objects? This cannot be undone.`
|
|
2808
2980
|
});
|
|
2809
|
-
if (
|
|
2981
|
+
if (isCancel2(confirm3) || !confirm3) {
|
|
2810
2982
|
process.exit(0);
|
|
2811
2983
|
}
|
|
2812
2984
|
}
|
|
@@ -3061,7 +3233,6 @@ function registerDeploymentsStatusCommand(deploymentsCmd2) {
|
|
|
3061
3233
|
}
|
|
3062
3234
|
|
|
3063
3235
|
// src/commands/deployments/cancel.ts
|
|
3064
|
-
import * as clack11 from "@clack/prompts";
|
|
3065
3236
|
function registerDeploymentsCancelCommand(deploymentsCmd2) {
|
|
3066
3237
|
deploymentsCmd2.command("cancel <id>").description("Cancel a deployment").action(async (id, _opts, cmd) => {
|
|
3067
3238
|
const { json, yes } = getRootOpts(cmd);
|
|
@@ -3069,10 +3240,10 @@ function registerDeploymentsCancelCommand(deploymentsCmd2) {
|
|
|
3069
3240
|
await requireAuth();
|
|
3070
3241
|
if (!getProjectConfig()) throw new ProjectNotLinkedError();
|
|
3071
3242
|
if (!yes && !json) {
|
|
3072
|
-
const confirmed = await
|
|
3243
|
+
const confirmed = await confirm2({
|
|
3073
3244
|
message: `Cancel deployment ${id}?`
|
|
3074
3245
|
});
|
|
3075
|
-
if (
|
|
3246
|
+
if (isCancel2(confirmed) || !confirmed) process.exit(0);
|
|
3076
3247
|
}
|
|
3077
3248
|
const res = await ossFetch(`/api/deployments/${id}/cancel`, { method: "POST" });
|
|
3078
3249
|
const result = await res.json();
|
|
@@ -3352,17 +3523,16 @@ function registerSecretsUpdateCommand(secretsCmd2) {
|
|
|
3352
3523
|
}
|
|
3353
3524
|
|
|
3354
3525
|
// src/commands/secrets/delete.ts
|
|
3355
|
-
import * as clack12 from "@clack/prompts";
|
|
3356
3526
|
function registerSecretsDeleteCommand(secretsCmd2) {
|
|
3357
3527
|
secretsCmd2.command("delete <key>").description("Delete a secret").action(async (key, _opts, cmd) => {
|
|
3358
3528
|
const { json, yes } = getRootOpts(cmd);
|
|
3359
3529
|
try {
|
|
3360
3530
|
await requireAuth();
|
|
3361
3531
|
if (!yes && !json) {
|
|
3362
|
-
const
|
|
3532
|
+
const confirm3 = await confirm2({
|
|
3363
3533
|
message: `Delete secret "${key}"? This cannot be undone.`
|
|
3364
3534
|
});
|
|
3365
|
-
if (
|
|
3535
|
+
if (isCancel2(confirm3) || !confirm3) {
|
|
3366
3536
|
process.exit(0);
|
|
3367
3537
|
}
|
|
3368
3538
|
}
|
|
@@ -3538,17 +3708,16 @@ function registerSchedulesUpdateCommand(schedulesCmd2) {
|
|
|
3538
3708
|
}
|
|
3539
3709
|
|
|
3540
3710
|
// src/commands/schedules/delete.ts
|
|
3541
|
-
import * as clack13 from "@clack/prompts";
|
|
3542
3711
|
function registerSchedulesDeleteCommand(schedulesCmd2) {
|
|
3543
3712
|
schedulesCmd2.command("delete <id>").description("Delete a schedule").action(async (id, _opts, cmd) => {
|
|
3544
3713
|
const { json, yes } = getRootOpts(cmd);
|
|
3545
3714
|
try {
|
|
3546
3715
|
await requireAuth();
|
|
3547
3716
|
if (!yes && !json) {
|
|
3548
|
-
const
|
|
3717
|
+
const confirm3 = await confirm2({
|
|
3549
3718
|
message: `Delete schedule "${id}"? This cannot be undone.`
|
|
3550
3719
|
});
|
|
3551
|
-
if (
|
|
3720
|
+
if (isCancel2(confirm3) || !confirm3) {
|
|
3552
3721
|
process.exit(0);
|
|
3553
3722
|
}
|
|
3554
3723
|
}
|
|
@@ -4179,7 +4348,7 @@ function formatSize2(gb) {
|
|
|
4179
4348
|
|
|
4180
4349
|
// src/commands/diagnose/index.ts
|
|
4181
4350
|
import * as os from "os";
|
|
4182
|
-
import * as
|
|
4351
|
+
import * as clack10 from "@clack/prompts";
|
|
4183
4352
|
|
|
4184
4353
|
// src/commands/diagnose/metrics.ts
|
|
4185
4354
|
var METRIC_LABELS = {
|
|
@@ -4716,10 +4885,10 @@ function registerDiagnoseCommands(diagnoseCmd2) {
|
|
|
4716
4885
|
if (question.length === 0 || question.length > 2e3) {
|
|
4717
4886
|
throw new CLIError("Question must be between 1 and 2000 characters.");
|
|
4718
4887
|
}
|
|
4719
|
-
const s = !json ?
|
|
4888
|
+
const s = !json ? clack10.spinner() : null;
|
|
4720
4889
|
s?.start("Collecting diagnostic data...");
|
|
4721
4890
|
const data2 = await collectDiagnosticData(projectId, ossMode, apiUrl);
|
|
4722
|
-
const cliVersion = "0.1.
|
|
4891
|
+
const cliVersion = "0.1.50";
|
|
4723
4892
|
s?.stop("Data collected");
|
|
4724
4893
|
if (!json) {
|
|
4725
4894
|
console.log(`
|
|
@@ -4835,7 +5004,7 @@ function registerDiagnoseCommands(diagnoseCmd2) {
|
|
|
4835
5004
|
outputJson({ sessionId, events: jsonEvents });
|
|
4836
5005
|
}
|
|
4837
5006
|
if (!json && sessionId) {
|
|
4838
|
-
const ratingChoice = await
|
|
5007
|
+
const ratingChoice = await select2({
|
|
4839
5008
|
message: "Was this analysis helpful?",
|
|
4840
5009
|
options: [
|
|
4841
5010
|
{ value: "skip", label: "Skip", hint: "no rating" },
|
|
@@ -4844,7 +5013,7 @@ function registerDiagnoseCommands(diagnoseCmd2) {
|
|
|
4844
5013
|
{ value: "incorrect", label: "Incorrect", hint: "diagnosis was wrong or misleading" }
|
|
4845
5014
|
]
|
|
4846
5015
|
});
|
|
4847
|
-
if (!
|
|
5016
|
+
if (!isCancel2(ratingChoice) && ratingChoice !== "skip") {
|
|
4848
5017
|
try {
|
|
4849
5018
|
await rateDiagnosticSession(
|
|
4850
5019
|
sessionId,
|
|
@@ -4852,9 +5021,9 @@ function registerDiagnoseCommands(diagnoseCmd2) {
|
|
|
4852
5021
|
void 0,
|
|
4853
5022
|
apiUrl
|
|
4854
5023
|
);
|
|
4855
|
-
|
|
5024
|
+
clack10.log.success("Thanks for your feedback!");
|
|
4856
5025
|
} catch {
|
|
4857
|
-
|
|
5026
|
+
clack10.log.warn("Failed to submit rating.");
|
|
4858
5027
|
}
|
|
4859
5028
|
}
|
|
4860
5029
|
}
|
|
@@ -5049,7 +5218,7 @@ async function showInteractiveMenu() {
|
|
|
5049
5218
|
} catch {
|
|
5050
5219
|
}
|
|
5051
5220
|
console.log(INSFORGE_LOGO);
|
|
5052
|
-
|
|
5221
|
+
clack11.intro(`InsForge CLI v${pkg.version}`);
|
|
5053
5222
|
const options = [];
|
|
5054
5223
|
if (!isLoggedIn) {
|
|
5055
5224
|
options.push({ value: "login", label: "Log in to InsForge" });
|
|
@@ -5065,12 +5234,12 @@ async function showInteractiveMenu() {
|
|
|
5065
5234
|
{ value: "docs", label: "View documentation" },
|
|
5066
5235
|
{ value: "help", label: "Show all commands" }
|
|
5067
5236
|
);
|
|
5068
|
-
const action = await
|
|
5237
|
+
const action = await select2({
|
|
5069
5238
|
message: "What would you like to do?",
|
|
5070
5239
|
options
|
|
5071
5240
|
});
|
|
5072
|
-
if (
|
|
5073
|
-
|
|
5241
|
+
if (isCancel2(action)) {
|
|
5242
|
+
clack11.cancel("Bye!");
|
|
5074
5243
|
process.exit(0);
|
|
5075
5244
|
}
|
|
5076
5245
|
switch (action) {
|