salesprompter-cli 0.1.33 → 0.1.34
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/cli.js +224 -19
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -42,6 +42,32 @@ const runtimeOutputOptions = {
|
|
|
42
42
|
quiet: false
|
|
43
43
|
};
|
|
44
44
|
const nullableOptionalString = z.string().min(1).nullish().transform((value) => value ?? undefined);
|
|
45
|
+
const CliWorkspaceSchema = z.object({
|
|
46
|
+
id: z.string().min(1),
|
|
47
|
+
name: nullableOptionalString,
|
|
48
|
+
slug: nullableOptionalString,
|
|
49
|
+
workspaceClientId: nullableOptionalString,
|
|
50
|
+
workspaceClientName: nullableOptionalString
|
|
51
|
+
});
|
|
52
|
+
const CliWorkspaceListResponseSchema = z.object({
|
|
53
|
+
workspaces: z.array(CliWorkspaceSchema),
|
|
54
|
+
currentOrgId: nullableOptionalString
|
|
55
|
+
});
|
|
56
|
+
const CliAuthUserSchema = z.object({
|
|
57
|
+
id: z.string().min(1),
|
|
58
|
+
email: z.string().email(),
|
|
59
|
+
name: nullableOptionalString,
|
|
60
|
+
orgId: nullableOptionalString,
|
|
61
|
+
orgName: nullableOptionalString,
|
|
62
|
+
orgSlug: nullableOptionalString,
|
|
63
|
+
workspaceClientId: nullableOptionalString,
|
|
64
|
+
workspaceClientName: nullableOptionalString
|
|
65
|
+
});
|
|
66
|
+
const CliWorkspaceSwitchResponseSchema = z.object({
|
|
67
|
+
token: z.string().min(1),
|
|
68
|
+
expiresAt: z.string().datetime().optional(),
|
|
69
|
+
user: CliAuthUserSchema
|
|
70
|
+
});
|
|
45
71
|
const LinkedInCompanyBackfillClientIdStateSchema = z
|
|
46
72
|
.object({
|
|
47
73
|
clientId: z.number().int().positive(),
|
|
@@ -2564,6 +2590,37 @@ function resolveSessionOrgId(session) {
|
|
|
2564
2590
|
const orgId = session.user.orgId?.trim();
|
|
2565
2591
|
return orgId && orgId.length > 0 ? orgId : null;
|
|
2566
2592
|
}
|
|
2593
|
+
function normalizeCliApiBaseUrl(value) {
|
|
2594
|
+
return value.trim().replace(/\/+$/, "");
|
|
2595
|
+
}
|
|
2596
|
+
function getWorkspaceDisplayName(workspace) {
|
|
2597
|
+
return (compactOptionalText(workspace.name) ??
|
|
2598
|
+
compactOptionalText(workspace.workspaceClientName) ??
|
|
2599
|
+
compactOptionalText(workspace.slug) ??
|
|
2600
|
+
workspace.id);
|
|
2601
|
+
}
|
|
2602
|
+
function formatCliWorkspaceLabel(workspace) {
|
|
2603
|
+
const name = getWorkspaceDisplayName(workspace);
|
|
2604
|
+
const details = [
|
|
2605
|
+
compactOptionalText(workspace.slug),
|
|
2606
|
+
compactOptionalText(workspace.workspaceClientId),
|
|
2607
|
+
workspace.id
|
|
2608
|
+
].filter((value) => Boolean(value));
|
|
2609
|
+
return details.length > 0 ? `${name} (${details.join(", ")})` : name;
|
|
2610
|
+
}
|
|
2611
|
+
function workspaceMatchesInput(workspace, value) {
|
|
2612
|
+
const normalized = normalizeChoiceText(value);
|
|
2613
|
+
return [
|
|
2614
|
+
workspace.id,
|
|
2615
|
+
workspace.name,
|
|
2616
|
+
workspace.slug,
|
|
2617
|
+
workspace.workspaceClientId,
|
|
2618
|
+
workspace.workspaceClientName
|
|
2619
|
+
].some((candidate) => {
|
|
2620
|
+
const compacted = compactOptionalText(candidate);
|
|
2621
|
+
return compacted ? normalizeChoiceText(compacted) === normalized : false;
|
|
2622
|
+
});
|
|
2623
|
+
}
|
|
2567
2624
|
function writeSessionSummary(session) {
|
|
2568
2625
|
const identity = session.user.name?.trim()
|
|
2569
2626
|
? `${session.user.name} (${session.user.email})`
|
|
@@ -2748,6 +2805,21 @@ async function promptChoice(rl, prompt, options, defaultValue) {
|
|
|
2748
2805
|
writeWizardLine();
|
|
2749
2806
|
}
|
|
2750
2807
|
}
|
|
2808
|
+
async function withPromptReader(existingReader, run) {
|
|
2809
|
+
if (existingReader) {
|
|
2810
|
+
return await run(existingReader);
|
|
2811
|
+
}
|
|
2812
|
+
const rl = createInterface({
|
|
2813
|
+
input: process.stdin,
|
|
2814
|
+
output: process.stdout
|
|
2815
|
+
});
|
|
2816
|
+
try {
|
|
2817
|
+
return await run(rl);
|
|
2818
|
+
}
|
|
2819
|
+
finally {
|
|
2820
|
+
rl.close();
|
|
2821
|
+
}
|
|
2822
|
+
}
|
|
2751
2823
|
async function promptText(rl, prompt, options = {}) {
|
|
2752
2824
|
while (true) {
|
|
2753
2825
|
const suffix = options.defaultValue !== undefined ? ` [${options.defaultValue}]` : "";
|
|
@@ -2828,7 +2900,7 @@ async function confirmWizardWorkspace(rl, session, options) {
|
|
|
2828
2900
|
? hasNamedOrg
|
|
2829
2901
|
? "Current cached CLI workspace"
|
|
2830
2902
|
: "Workspace name is not available in this cached token"
|
|
2831
|
-
: "
|
|
2903
|
+
: "Select from your Salesprompter organizations in this terminal";
|
|
2832
2904
|
const workspaceChoice = await promptChoice(rl, "Which workspace should I use?", [
|
|
2833
2905
|
{
|
|
2834
2906
|
value: "current",
|
|
@@ -2838,8 +2910,8 @@ async function confirmWizardWorkspace(rl, session, options) {
|
|
|
2838
2910
|
},
|
|
2839
2911
|
{
|
|
2840
2912
|
value: "browser",
|
|
2841
|
-
label: "Choose another workspace
|
|
2842
|
-
description: "
|
|
2913
|
+
label: "Choose another workspace",
|
|
2914
|
+
description: "Select from your Salesprompter organizations in this terminal",
|
|
2843
2915
|
aliases: ["browser", "choose another", "switch workspace", "select organization"]
|
|
2844
2916
|
}
|
|
2845
2917
|
], "current");
|
|
@@ -2848,12 +2920,10 @@ async function confirmWizardWorkspace(rl, session, options) {
|
|
|
2848
2920
|
return session;
|
|
2849
2921
|
}
|
|
2850
2922
|
writeWizardLine();
|
|
2851
|
-
|
|
2852
|
-
writeWizardLine();
|
|
2853
|
-
await clearAuthSession();
|
|
2854
|
-
const result = await performLogin({
|
|
2923
|
+
const result = await switchWorkspaceInCli({
|
|
2855
2924
|
apiUrl: options?.apiUrl ?? session.apiBaseUrl,
|
|
2856
|
-
timeoutSeconds: options?.timeoutSeconds
|
|
2925
|
+
timeoutSeconds: options?.timeoutSeconds,
|
|
2926
|
+
rl
|
|
2857
2927
|
});
|
|
2858
2928
|
writeSessionSummary(result.session);
|
|
2859
2929
|
writeWizardLine();
|
|
@@ -2866,6 +2936,134 @@ async function switchWorkspaceWithBrowser(options) {
|
|
|
2866
2936
|
timeoutSeconds: options?.timeoutSeconds ?? 180
|
|
2867
2937
|
})).session;
|
|
2868
2938
|
}
|
|
2939
|
+
async function listCliWorkspaces(session) {
|
|
2940
|
+
const { session: refreshedSession, value } = await fetchCliJson(session, async (currentSession) => await fetch(`${normalizeCliApiBaseUrl(currentSession.apiBaseUrl)}/api/cli/auth/workspaces`, {
|
|
2941
|
+
method: "GET",
|
|
2942
|
+
headers: {
|
|
2943
|
+
Authorization: `Bearer ${currentSession.accessToken}`,
|
|
2944
|
+
"X-Salesprompter-Client": "salesprompter-cli/0.2"
|
|
2945
|
+
}
|
|
2946
|
+
}), CliWorkspaceListResponseSchema);
|
|
2947
|
+
return {
|
|
2948
|
+
session: refreshedSession,
|
|
2949
|
+
workspaces: value.workspaces,
|
|
2950
|
+
currentOrgId: value.currentOrgId ?? null
|
|
2951
|
+
};
|
|
2952
|
+
}
|
|
2953
|
+
async function selectCliWorkspace(session, orgId) {
|
|
2954
|
+
const { value } = await fetchCliJson(session, async (currentSession) => await fetch(`${normalizeCliApiBaseUrl(currentSession.apiBaseUrl)}/api/cli/auth/workspaces`, {
|
|
2955
|
+
method: "POST",
|
|
2956
|
+
headers: {
|
|
2957
|
+
Authorization: `Bearer ${currentSession.accessToken}`,
|
|
2958
|
+
"Content-Type": "application/json",
|
|
2959
|
+
"X-Salesprompter-Client": "salesprompter-cli/0.2"
|
|
2960
|
+
},
|
|
2961
|
+
body: JSON.stringify({ orgId })
|
|
2962
|
+
}), CliWorkspaceSwitchResponseSchema);
|
|
2963
|
+
const nextSession = {
|
|
2964
|
+
accessToken: value.token,
|
|
2965
|
+
refreshToken: session.refreshToken,
|
|
2966
|
+
apiBaseUrl: session.apiBaseUrl,
|
|
2967
|
+
user: value.user,
|
|
2968
|
+
expiresAt: value.expiresAt,
|
|
2969
|
+
createdAt: new Date().toISOString()
|
|
2970
|
+
};
|
|
2971
|
+
await writeAuthSession(nextSession);
|
|
2972
|
+
return nextSession;
|
|
2973
|
+
}
|
|
2974
|
+
async function promptForCliWorkspace(rl, workspaces, currentOrgId, requestedWorkspace) {
|
|
2975
|
+
const requested = compactOptionalText(requestedWorkspace);
|
|
2976
|
+
if (requested) {
|
|
2977
|
+
const matched = workspaces.find((workspace) => workspaceMatchesInput(workspace, requested));
|
|
2978
|
+
if (!matched) {
|
|
2979
|
+
throw new Error(`workspace not found for this account: ${requested}`);
|
|
2980
|
+
}
|
|
2981
|
+
return matched.id;
|
|
2982
|
+
}
|
|
2983
|
+
const current = currentOrgId ? workspaces.find((workspace) => workspace.id === currentOrgId) : undefined;
|
|
2984
|
+
const options = workspaces.map((workspace) => ({
|
|
2985
|
+
value: workspace.id,
|
|
2986
|
+
label: formatCliWorkspaceLabel(workspace),
|
|
2987
|
+
description: workspace.id === currentOrgId ? "Current cached CLI workspace" : undefined,
|
|
2988
|
+
aliases: [workspace.name, workspace.slug, workspace.workspaceClientId, workspace.workspaceClientName].filter((value) => Boolean(compactOptionalText(value)))
|
|
2989
|
+
}));
|
|
2990
|
+
options.push({
|
|
2991
|
+
value: "browser",
|
|
2992
|
+
label: "Use browser chooser",
|
|
2993
|
+
description: "Fallback if this terminal list is missing a workspace",
|
|
2994
|
+
aliases: ["browser", "open browser", "web"]
|
|
2995
|
+
});
|
|
2996
|
+
return await promptChoice(rl, "Which workspace should I use?", options, current?.id ?? options[0]?.value ?? "browser");
|
|
2997
|
+
}
|
|
2998
|
+
async function switchWorkspaceInCli(options = {}) {
|
|
2999
|
+
if (options.browser) {
|
|
3000
|
+
return {
|
|
3001
|
+
session: await switchWorkspaceWithBrowser(options),
|
|
3002
|
+
method: "browser"
|
|
3003
|
+
};
|
|
3004
|
+
}
|
|
3005
|
+
let session = null;
|
|
3006
|
+
try {
|
|
3007
|
+
session = await requireAuthSession();
|
|
3008
|
+
if (options.apiUrl) {
|
|
3009
|
+
session = {
|
|
3010
|
+
...session,
|
|
3011
|
+
apiBaseUrl: normalizeCliApiBaseUrl(options.apiUrl)
|
|
3012
|
+
};
|
|
3013
|
+
}
|
|
3014
|
+
}
|
|
3015
|
+
catch {
|
|
3016
|
+
if (!runtimeOutputOptions.quiet) {
|
|
3017
|
+
writeWizardLine("No cached CLI session found. Starting browser login flow.");
|
|
3018
|
+
writeWizardLine();
|
|
3019
|
+
}
|
|
3020
|
+
return {
|
|
3021
|
+
session: await switchWorkspaceWithBrowser(options),
|
|
3022
|
+
method: "browser"
|
|
3023
|
+
};
|
|
3024
|
+
}
|
|
3025
|
+
let workspaces;
|
|
3026
|
+
let currentOrgId;
|
|
3027
|
+
try {
|
|
3028
|
+
const listed = await listCliWorkspaces(session);
|
|
3029
|
+
session = listed.session;
|
|
3030
|
+
workspaces = listed.workspaces;
|
|
3031
|
+
currentOrgId = listed.currentOrgId;
|
|
3032
|
+
}
|
|
3033
|
+
catch (error) {
|
|
3034
|
+
if (!runtimeOutputOptions.quiet) {
|
|
3035
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
3036
|
+
writeWizardLine(`Terminal workspace selection is unavailable (${message}). Starting browser chooser.`);
|
|
3037
|
+
writeWizardLine();
|
|
3038
|
+
}
|
|
3039
|
+
return {
|
|
3040
|
+
session: await switchWorkspaceWithBrowser(options),
|
|
3041
|
+
method: "browser"
|
|
3042
|
+
};
|
|
3043
|
+
}
|
|
3044
|
+
if (workspaces.length === 0) {
|
|
3045
|
+
if (!runtimeOutputOptions.quiet) {
|
|
3046
|
+
writeWizardLine("No Salesprompter workspaces were returned for this account. Starting browser chooser.");
|
|
3047
|
+
writeWizardLine();
|
|
3048
|
+
}
|
|
3049
|
+
return {
|
|
3050
|
+
session: await switchWorkspaceWithBrowser(options),
|
|
3051
|
+
method: "browser"
|
|
3052
|
+
};
|
|
3053
|
+
}
|
|
3054
|
+
const selectedOrgId = options.orgId ?? (await withPromptReader(options.rl, async (rl) => await promptForCliWorkspace(rl, workspaces, currentOrgId, options.workspace)));
|
|
3055
|
+
if (selectedOrgId === "browser") {
|
|
3056
|
+
return {
|
|
3057
|
+
session: await switchWorkspaceWithBrowser(options),
|
|
3058
|
+
method: "browser"
|
|
3059
|
+
};
|
|
3060
|
+
}
|
|
3061
|
+
const nextSession = await selectCliWorkspace(session, selectedOrgId);
|
|
3062
|
+
return {
|
|
3063
|
+
session: nextSession,
|
|
3064
|
+
method: "terminal"
|
|
3065
|
+
};
|
|
3066
|
+
}
|
|
2869
3067
|
async function resolveLlmAuthReadiness() {
|
|
2870
3068
|
const apiBaseUrl = process.env.SALESPROMPTER_API_BASE_URL?.trim() || "https://salesprompter.ai";
|
|
2871
3069
|
const envToken = resolveNonInteractiveAuthToken(process.env);
|
|
@@ -5485,10 +5683,11 @@ async function runWizard(options) {
|
|
|
5485
5683
|
], "product-market");
|
|
5486
5684
|
writeWizardLine();
|
|
5487
5685
|
if (flow === "switch-workspace") {
|
|
5488
|
-
|
|
5489
|
-
|
|
5490
|
-
|
|
5491
|
-
|
|
5686
|
+
const result = await switchWorkspaceInCli({
|
|
5687
|
+
...options,
|
|
5688
|
+
rl
|
|
5689
|
+
});
|
|
5690
|
+
writeSessionSummary(result.session);
|
|
5492
5691
|
writeWizardLine();
|
|
5493
5692
|
continue;
|
|
5494
5693
|
}
|
|
@@ -5829,19 +6028,25 @@ program
|
|
|
5829
6028
|
.alias("auth:switch")
|
|
5830
6029
|
.description("Switch the active Salesprompter workspace for this CLI session.")
|
|
5831
6030
|
.option("--api-url <url>", "Salesprompter API base URL, defaults to SALESPROMPTER_API_BASE_URL or salesprompter.ai")
|
|
5832
|
-
.option("--timeout-seconds <number>", "Browser login timeout in seconds", "180")
|
|
6031
|
+
.option("--timeout-seconds <number>", "Browser fallback login timeout in seconds", "180")
|
|
6032
|
+
.option("--org-id <id>", "Switch directly to a Clerk organization id")
|
|
6033
|
+
.option("--workspace <nameOrSlug>", "Switch directly to a workspace by name, slug, client id, or org id")
|
|
6034
|
+
.option("--browser", "Use the browser chooser instead of terminal workspace selection")
|
|
5833
6035
|
.action(async (options) => {
|
|
5834
6036
|
const timeoutSeconds = z.coerce.number().int().min(30).max(1800).parse(options.timeoutSeconds);
|
|
5835
|
-
const
|
|
6037
|
+
const result = await switchWorkspaceInCli({
|
|
5836
6038
|
apiUrl: options.apiUrl,
|
|
5837
|
-
timeoutSeconds
|
|
6039
|
+
timeoutSeconds,
|
|
6040
|
+
orgId: options.orgId,
|
|
6041
|
+
workspace: options.workspace,
|
|
6042
|
+
browser: Boolean(options.browser)
|
|
5838
6043
|
});
|
|
5839
6044
|
printOutput({
|
|
5840
6045
|
status: "ok",
|
|
5841
|
-
method:
|
|
5842
|
-
apiBaseUrl: session.apiBaseUrl,
|
|
5843
|
-
user: session.user,
|
|
5844
|
-
expiresAt: session.expiresAt ?? null
|
|
6046
|
+
method: result.method,
|
|
6047
|
+
apiBaseUrl: result.session.apiBaseUrl,
|
|
6048
|
+
user: result.session.user,
|
|
6049
|
+
expiresAt: result.session.expiresAt ?? null
|
|
5845
6050
|
});
|
|
5846
6051
|
});
|
|
5847
6052
|
program
|
package/package.json
CHANGED