@pulse-editor/cli 0.0.1 → 0.1.0-beta.0

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/app.d.ts ADDED
@@ -0,0 +1,6 @@
1
+ import React from 'react';
2
+ import { Result } from 'meow';
3
+ import { Flags } from './lib/cli-flags.js';
4
+ export default function App({ cli }: {
5
+ cli: Result<Flags>;
6
+ }): React.JSX.Element;
package/dist/app.js ADDED
@@ -0,0 +1,21 @@
1
+ import React, { useEffect, useState } from 'react';
2
+ import Login from './components/commands/login.js';
3
+ import Publish from './components/commands/publish.js';
4
+ import Help from './components/commands/help.js';
5
+ import Chat from './components/commands/chat.js';
6
+ import Logout from './components/commands/logout.js';
7
+ import Create from './components/commands/create.js';
8
+ export default function App({ cli }) {
9
+ const [command, setCommand] = useState(undefined);
10
+ useEffect(() => {
11
+ const cmd = cli.input[0] ?? 'help';
12
+ setCommand(cmd);
13
+ }, [cli.input]);
14
+ return (React.createElement(React.Fragment, null,
15
+ command === 'help' && React.createElement(Help, { cli: cli }),
16
+ command === 'chat' && React.createElement(Chat, { cli: cli }),
17
+ command === 'login' && React.createElement(Login, { cli: cli }),
18
+ command === 'logout' && React.createElement(Logout, { cli: cli }),
19
+ command === 'publish' && React.createElement(Publish, { cli: cli }),
20
+ command === 'create' && React.createElement(Create, { cli: cli })));
21
+ }
package/dist/cli.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/cli.js ADDED
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/env node
2
+ import React from 'react';
3
+ import { render } from 'ink';
4
+ import meow from 'meow';
5
+ import App from './app.js';
6
+ import { commandsManual } from './lib/manual.js';
7
+ import { flags } from './lib/cli-flags.js';
8
+ const cli = meow(`\
9
+ Usage
10
+ pulse [command] [flags]
11
+
12
+ Commands
13
+ ${Object.entries(commandsManual)
14
+ .map(([_, description]) => `${description}`)
15
+ .join('')}
16
+ Examples
17
+ pulse help publish
18
+ `, {
19
+ importMeta: import.meta,
20
+ flags: flags,
21
+ });
22
+ render(React.createElement(App, { cli: cli }));
@@ -0,0 +1,6 @@
1
+ import { Result } from 'meow';
2
+ import { Flags } from '../../lib/cli-flags.js';
3
+ import React from 'react';
4
+ export default function Chat({ cli }: {
5
+ cli: Result<Flags>;
6
+ }): React.JSX.Element;
@@ -0,0 +1,9 @@
1
+ import React from 'react';
2
+ import { Text } from 'ink';
3
+ export default function Chat({ cli }) {
4
+ const message = cli.input[1];
5
+ return (React.createElement(React.Fragment, null,
6
+ React.createElement(Text, null,
7
+ "Hello, ",
8
+ React.createElement(Text, { color: "green" }, message))));
9
+ }
@@ -0,0 +1,6 @@
1
+ import { Result } from 'meow';
2
+ import React from 'react';
3
+ import { Flags } from '../../lib/cli-flags.js';
4
+ export default function Create({ cli }: {
5
+ cli: Result<Flags>;
6
+ }): React.JSX.Element;
@@ -0,0 +1,93 @@
1
+ import React, { useEffect, useState } from 'react';
2
+ import { Box, Text } from 'ink';
3
+ import Spinner from 'ink-spinner';
4
+ import { $ } from 'execa';
5
+ import SelectInput from 'ink-select-input';
6
+ import { UncontrolledTextInput } from 'ink-text-input';
7
+ import fs from 'fs';
8
+ import path from 'path';
9
+ export default function Create({ cli }) {
10
+ const [framework, setFramework] = useState(undefined);
11
+ const [projectName, setProjectName] = useState(undefined);
12
+ const [isCreated, setIsCreated] = useState(false);
13
+ const [isFrameworkSelected, setIsFrameworkSelected] = useState(false);
14
+ const [isPathValid, setIsPathValid] = useState(true);
15
+ const [isCloneFailed, setIsCloneFailed] = useState(false);
16
+ const frameworkItems = [
17
+ {
18
+ label: 'React',
19
+ value: 'react',
20
+ },
21
+ {
22
+ label: 'Modern.js (WIP)',
23
+ value: 'modernjs',
24
+ },
25
+ {
26
+ label: 'Vue (WIP)',
27
+ value: 'vue',
28
+ },
29
+ {
30
+ label: 'Angular (WIP)',
31
+ value: 'angular',
32
+ },
33
+ ];
34
+ useEffect(() => {
35
+ const framework = cli.flags.framework;
36
+ setFramework(framework);
37
+ }, [cli]);
38
+ useEffect(() => {
39
+ async function createFromTemplate(name) {
40
+ if (framework === 'react') {
41
+ // Clone the template repository
42
+ try {
43
+ await $ `git clone https://github.com/ClayPulse/pulse-editor-extension-template.git ${name}`;
44
+ setIsCreated(true);
45
+ }
46
+ catch (error) {
47
+ setIsCloneFailed(true);
48
+ return;
49
+ }
50
+ // Modify the package.json file to update the name
51
+ const packageJsonPath = path.join(process.cwd(), name, 'package.json');
52
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
53
+ packageJson.name = name;
54
+ // Write the modified package.json back to the file
55
+ fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2));
56
+ }
57
+ }
58
+ if (projectName) {
59
+ // Check if the project already exists
60
+ const projectPath = path.join(process.cwd(), projectName);
61
+ if (fs.existsSync(projectPath)) {
62
+ setIsPathValid(false);
63
+ return;
64
+ }
65
+ createFromTemplate(projectName);
66
+ }
67
+ }, [projectName]);
68
+ useEffect(() => {
69
+ setTimeout(() => {
70
+ setIsFrameworkSelected(framework !== undefined);
71
+ }, 0);
72
+ }, [framework]);
73
+ return (React.createElement(React.Fragment, null,
74
+ !cli.flags.framework && (React.createElement(React.Fragment, null,
75
+ React.createElement(Text, null, "\uD83D\uDEA9Create a new Pulse Editor app using your favorite web framework!"),
76
+ React.createElement(SelectInput, { items: frameworkItems, onSelect: item => {
77
+ setFramework(item.value);
78
+ }, isFocused: framework === undefined }),
79
+ React.createElement(Text, null, " "))),
80
+ isFrameworkSelected && (React.createElement(React.Fragment, null,
81
+ React.createElement(Box, null,
82
+ React.createElement(Text, null, "Enter your project name: "),
83
+ React.createElement(UncontrolledTextInput, { onSubmit: value => setProjectName(value), focus: projectName === undefined })),
84
+ projectName && (React.createElement(React.Fragment, null,
85
+ framework === 'react' &&
86
+ (!isPathValid ? (React.createElement(Text, { color: "redBright" }, "\u274C A project with same name already exists in current path.")) : isCloneFailed ? (React.createElement(Text, { color: "redBright" }, "\u274C Failed to clone the template. Please check your internet connection and try again.")) : isCreated ? (React.createElement(Text, null, "\uD83D\uDE80 Pulse Editor React app project created successfully!")) : (React.createElement(React.Fragment, null,
87
+ React.createElement(Box, null,
88
+ React.createElement(Spinner, { type: "dots" }),
89
+ React.createElement(Text, null,
90
+ ' ',
91
+ "Creating a new Pulse Editor app using React template..."))))),
92
+ framework !== 'react' && (React.createElement(Text, null, "\uD83D\uDEA7 Currently not available. We'd like to invite you to work on these frameworks if you are interested in! Check out our tutorial to integrate your favorite web framework with Pulse Editor using Module Federation."))))))));
93
+ }
@@ -0,0 +1,6 @@
1
+ import { Result } from 'meow';
2
+ import React from 'react';
3
+ import { Flags } from '../../lib/cli-flags.js';
4
+ export default function Help({ cli }: {
5
+ cli: Result<Flags>;
6
+ }): React.JSX.Element;
@@ -0,0 +1,10 @@
1
+ import React from 'react';
2
+ import { Text } from 'ink';
3
+ import { commandsManual } from '../../lib/manual.js';
4
+ import Header from '../header.js';
5
+ export default function Help({ cli }) {
6
+ const subCommand = cli.input[1];
7
+ return (React.createElement(React.Fragment, null, subCommand ? (React.createElement(Text, null, commandsManual[subCommand])) : (React.createElement(React.Fragment, null,
8
+ React.createElement(Header, null),
9
+ React.createElement(Text, null, cli.help)))));
10
+ }
@@ -0,0 +1,6 @@
1
+ import React from 'react';
2
+ import { Flags } from '../../lib/cli-flags.js';
3
+ import { Result } from 'meow';
4
+ export default function Login({ cli }: {
5
+ cli: Result<Flags>;
6
+ }): React.JSX.Element;
@@ -0,0 +1,108 @@
1
+ import React, { useEffect, useState } from 'react';
2
+ import { Box, Text, useApp } from 'ink';
3
+ import SelectInput from 'ink-select-input';
4
+ import TextInput from 'ink-text-input';
5
+ import Spinner from 'ink-spinner';
6
+ import os from 'os';
7
+ import path from 'path';
8
+ import { checkToken, getToken, isTokenInEnv, saveToken, } from '../../lib/token.js';
9
+ export default function Login({ cli }) {
10
+ const [loginMethod, setLoginMethod] = useState(undefined);
11
+ const [isShowLoginMethod, setIsShowLoginMethod] = useState(false);
12
+ const [isMethodSelected, setIsMethodSelected] = useState(false);
13
+ const [isCheckingAuth, setIsCheckingAuth] = useState(true);
14
+ const [isAuthenticated, setIsAuthenticated] = useState(false);
15
+ const [token, setToken] = useState('');
16
+ const [isTokenSaved, setIsTokenSaved] = useState(false);
17
+ const [tokenInput, setTokenInput] = useState('');
18
+ const [saveTokenInput, setSaveTokenInput] = useState('');
19
+ const loginMethodItems = [
20
+ {
21
+ label: 'Login using access token',
22
+ value: 'token',
23
+ },
24
+ {
25
+ label: '(WIP) Login in browser',
26
+ value: 'flow',
27
+ },
28
+ ];
29
+ const { exit } = useApp();
30
+ // Check login method
31
+ useEffect(() => {
32
+ const savedToken = getToken();
33
+ setIsShowLoginMethod(!savedToken && !cli.flags.token && !cli.flags.flow);
34
+ if (savedToken) {
35
+ setLoginMethod('token');
36
+ setToken(savedToken);
37
+ return;
38
+ }
39
+ else if (cli.flags.token) {
40
+ setLoginMethod('token');
41
+ }
42
+ else if (cli.flags.flow) {
43
+ setLoginMethod('flow');
44
+ }
45
+ }, [cli]);
46
+ // Check token validity
47
+ useEffect(() => {
48
+ // Only check token validity when it is set
49
+ if (loginMethod === 'token' && token.length > 0) {
50
+ checkToken(token, cli.flags.dev).then(isValid => {
51
+ setIsAuthenticated(isValid);
52
+ setIsCheckingAuth(false);
53
+ });
54
+ }
55
+ }, [token, loginMethod]);
56
+ useEffect(() => {
57
+ setTimeout(() => {
58
+ setIsMethodSelected(loginMethod !== undefined);
59
+ }, 0);
60
+ }, [loginMethod]);
61
+ return (React.createElement(React.Fragment, null,
62
+ isShowLoginMethod && (React.createElement(React.Fragment, null,
63
+ React.createElement(Text, null, "Login to the Pulse Editor Platform"),
64
+ React.createElement(SelectInput, { items: loginMethodItems, onSelect: item => {
65
+ setLoginMethod(item.value);
66
+ }, isFocused: loginMethod === undefined }),
67
+ React.createElement(Text, null, " "))),
68
+ isMethodSelected &&
69
+ loginMethod === 'token' &&
70
+ (token.length === 0 ? (React.createElement(React.Fragment, null,
71
+ React.createElement(Text, null, "Enter your Pulse Editor access token:"),
72
+ React.createElement(TextInput, { mask: "*", value: tokenInput, onChange: setTokenInput, onSubmit: value => {
73
+ if (value.length === 0) {
74
+ return;
75
+ }
76
+ setToken(value);
77
+ } }))) : isCheckingAuth ? (React.createElement(Box, null,
78
+ React.createElement(Spinner, { type: "dots" }),
79
+ React.createElement(Text, null, " Checking authentication..."))) : isAuthenticated ? (React.createElement(React.Fragment, null,
80
+ React.createElement(Text, null, "\u2705 You are signed in successfully."),
81
+ !isTokenInEnv() && getToken() !== token && (React.createElement(React.Fragment, null,
82
+ React.createElement(Text, null, "\uD83D\uDFE2 It is recommended to save your access token as an environment variable PE_ACCESS_TOKEN."),
83
+ React.createElement(Box, null,
84
+ React.createElement(Text, null,
85
+ "\u26A0\uFE0F (NOT recommended) Or, do you want to save access token to user home directory? (y/n)",
86
+ ' '),
87
+ React.createElement(TextInput, { value: saveTokenInput, onChange: setSaveTokenInput, onSubmit: value => {
88
+ if (value.length === 0) {
89
+ return;
90
+ }
91
+ if (value === 'y') {
92
+ saveToken(token);
93
+ setIsTokenSaved(true);
94
+ setTimeout(() => {
95
+ exit();
96
+ }, 0);
97
+ }
98
+ else {
99
+ exit();
100
+ }
101
+ } })))),
102
+ isTokenSaved && (React.createElement(Text, null,
103
+ "Token saved to ",
104
+ path.join(os.homedir(), '.pulse-editor'))))) : (React.createElement(Text, null, "Authentication error: please enter valid credentials."))),
105
+ isMethodSelected && loginMethod === 'flow' && (React.createElement(React.Fragment, null,
106
+ React.createElement(Text, null, "(WIP) Open the following URL in your browser:"),
107
+ React.createElement(Text, null, "https://pulse-editor.com/login")))));
108
+ }
@@ -0,0 +1,6 @@
1
+ import { Result } from 'meow';
2
+ import { Flags } from '../../lib/cli-flags.js';
3
+ import React from 'react';
4
+ export default function Logout({ cli }: {
5
+ cli: Result<Flags>;
6
+ }): React.JSX.Element;
@@ -0,0 +1,14 @@
1
+ import React, { useEffect, useState } from 'react';
2
+ import { Box, Text } from 'ink';
3
+ import { saveToken } from '../../lib/token.js';
4
+ import Spinner from 'ink-spinner';
5
+ export default function Logout({ cli }) {
6
+ const [isLoggedOut, setIsLoggedOut] = useState(false);
7
+ useEffect(() => {
8
+ saveToken(undefined);
9
+ setIsLoggedOut(true);
10
+ }, []);
11
+ return (React.createElement(React.Fragment, null, isLoggedOut ? (React.createElement(Text, null, "\uD83D\uDE80 Successfully logged out!")) : (React.createElement(Box, null,
12
+ React.createElement(Spinner, { type: "dots" }),
13
+ React.createElement(Text, null, " Logging out...")))));
14
+ }
@@ -0,0 +1,6 @@
1
+ import React from 'react';
2
+ import { Result } from 'meow';
3
+ import { Flags } from '../../lib/cli-flags.js';
4
+ export default function Publish({ cli }: {
5
+ cli: Result<Flags>;
6
+ }): React.JSX.Element;
@@ -0,0 +1,125 @@
1
+ import React, { useEffect, useState } from 'react';
2
+ import { Box, Text } from 'ink';
3
+ import { checkToken, getToken } from '../../lib/token.js';
4
+ import Spinner from 'ink-spinner';
5
+ import fs from 'fs';
6
+ import { $ } from 'execa';
7
+ export default function Publish({ cli }) {
8
+ const [isInProjectDir, setIsInProjectDir] = useState(false);
9
+ const [isCheckingAuth, setIsCheckingAuth] = useState(true);
10
+ const [isAuthenticated, setIsAuthenticated] = useState(false);
11
+ const [isBuilding, setIsBuilding] = useState(false);
12
+ const [isBuildingError, setIsBuildingError] = useState(false);
13
+ const [isPublishing, setIsPublishing] = useState(false);
14
+ const [isPublishingError, setIsPublishingError] = useState(false);
15
+ const [isPublished, setIsPublished] = useState(false);
16
+ const [failureMessage, setFailureMessage] = useState(undefined);
17
+ useEffect(() => {
18
+ // Check if the current dir contains pulse.config.ts
19
+ const currentDir = process.cwd();
20
+ const pulseConfigPath = `${currentDir}/pulse.config.ts`;
21
+ if (fs.existsSync(pulseConfigPath)) {
22
+ setIsInProjectDir(true);
23
+ }
24
+ }, []);
25
+ // Check if the user is authenticated
26
+ useEffect(() => {
27
+ async function checkAuth() {
28
+ const token = getToken();
29
+ if (token) {
30
+ const isValid = await checkToken(token, cli.flags.dev);
31
+ if (isValid) {
32
+ setIsAuthenticated(true);
33
+ }
34
+ }
35
+ setIsCheckingAuth(false);
36
+ }
37
+ if (isInProjectDir) {
38
+ checkAuth();
39
+ }
40
+ }, [isInProjectDir]);
41
+ // Build the extension
42
+ useEffect(() => {
43
+ async function buildExtension() {
44
+ try {
45
+ setIsBuilding(true);
46
+ await $ `npm run build`;
47
+ // Zip the dist folder
48
+ await $({ cwd: 'dist' }) `zip -r ../node_modules/@pulse-editor/dist.zip *`;
49
+ }
50
+ catch (error) {
51
+ setIsBuildingError(true);
52
+ return;
53
+ }
54
+ finally {
55
+ setIsBuilding(false);
56
+ }
57
+ await publishExtension();
58
+ }
59
+ async function publishExtension() {
60
+ setIsPublishing(true);
61
+ // Upload the zip file to the server
62
+ try {
63
+ const formData = new FormData();
64
+ const buffer = fs.readFileSync('./node_modules/@pulse-editor/dist.zip');
65
+ const blob = new Blob([buffer], {
66
+ type: 'application/zip',
67
+ });
68
+ formData.append('file', blob, 'dist.zip');
69
+ // Send the file to the server
70
+ const res = await fetch(cli.flags.dev
71
+ ? 'http://localhost:3000/api/extension/publish'
72
+ : 'https://pulse-editor.com/api/extension/publish', {
73
+ method: 'POST',
74
+ headers: {
75
+ Authorization: `Bearer ${getToken()}`,
76
+ },
77
+ body: formData,
78
+ });
79
+ if (res.status === 200) {
80
+ setIsPublished(true);
81
+ }
82
+ else {
83
+ setIsPublishingError(true);
84
+ const msg = await res.json();
85
+ if (msg.error) {
86
+ setFailureMessage(msg.error);
87
+ }
88
+ else {
89
+ setFailureMessage('Unknown error occurred while publishing.');
90
+ }
91
+ }
92
+ }
93
+ catch (error) {
94
+ console.error('Error uploading the file:', error);
95
+ setIsPublishingError(true);
96
+ return;
97
+ }
98
+ finally {
99
+ setIsPublishing(false);
100
+ }
101
+ }
102
+ if (isAuthenticated) {
103
+ buildExtension();
104
+ }
105
+ }, [isAuthenticated]);
106
+ return (React.createElement(React.Fragment, null, !isInProjectDir ? (React.createElement(Text, { color: 'redBright' }, "\u26D4 The current directory does not contain a Pulse Editor project.")) : isCheckingAuth ? (React.createElement(Box, null,
107
+ React.createElement(Spinner, { type: "dots" }),
108
+ React.createElement(Text, null, " Checking authentication..."))) : isAuthenticated ? (React.createElement(React.Fragment, null,
109
+ isBuilding && (React.createElement(Box, null,
110
+ React.createElement(Spinner, { type: "dots" }),
111
+ React.createElement(Text, null, " Building..."))),
112
+ isBuildingError && (React.createElement(Text, { color: 'redBright' }, "\u274C Error building the extension. Please run `npm run build` to see the error.")),
113
+ isPublishing && (React.createElement(Box, null,
114
+ React.createElement(Spinner, { type: "dots" }),
115
+ React.createElement(Text, null, " Publishing..."))),
116
+ isPublishingError && (React.createElement(React.Fragment, null,
117
+ React.createElement(Text, { color: 'redBright' }, "\u274C Failed to publish extension."),
118
+ failureMessage && (React.createElement(Text, { color: 'redBright' },
119
+ "Error: ",
120
+ failureMessage)))),
121
+ isPublished && (React.createElement(Text, { color: 'greenBright' }, "\u2705 Extension published successfully.")))) : (React.createElement(Text, null,
122
+ "You are not authenticated or your access token is invalid. Publishing to Extension Marketplace is in Beta access. Please visit",
123
+ React.createElement(Text, { color: 'blueBright' }, " https://pulse-editor.com/beta "),
124
+ "to apply for Beta access."))));
125
+ }
@@ -0,0 +1,2 @@
1
+ import React from 'react';
2
+ export default function Header(): React.JSX.Element;
@@ -0,0 +1,8 @@
1
+ import { Box, Text } from 'ink';
2
+ import React from 'react';
3
+ export default function Header() {
4
+ return (React.createElement(Box, { flexDirection: "column", alignItems: "center" },
5
+ React.createElement(Text, { color: 'whiteBright' }, "Pulse Editor CLI"),
6
+ React.createElement(Text, null, "Version: 0.0.1"),
7
+ React.createElement(Text, { color: 'blueBright' }, "https://pulse-editor.com")));
8
+ }
@@ -0,0 +1,17 @@
1
+ export declare const flags: {
2
+ token: {
3
+ type: "boolean";
4
+ };
5
+ flow: {
6
+ type: "boolean";
7
+ };
8
+ framework: {
9
+ type: "string";
10
+ shortFlag: string;
11
+ };
12
+ dev: {
13
+ type: "boolean";
14
+ default: false;
15
+ };
16
+ };
17
+ export type Flags = typeof flags;
@@ -0,0 +1,20 @@
1
+ // Helper to preserve literal types *and* validate against AnyFlags
2
+ function defineFlags(flags) {
3
+ return flags;
4
+ }
5
+ export const flags = defineFlags({
6
+ token: {
7
+ type: 'boolean',
8
+ },
9
+ flow: {
10
+ type: 'boolean',
11
+ },
12
+ framework: {
13
+ type: 'string',
14
+ shortFlag: 'f',
15
+ },
16
+ dev: {
17
+ type: 'boolean',
18
+ default: false,
19
+ },
20
+ });
@@ -0,0 +1 @@
1
+ export declare const commandsManual: Record<string, string>;
@@ -0,0 +1,44 @@
1
+ const help = `\
2
+ help [command] Show help for a command.
3
+ `;
4
+ const chat = `\
5
+ chat [message] (WIP) Chat with the Pulse Editor AI assistant.
6
+
7
+ Flags:
8
+ --interactive, -i
9
+ Start an interactive chat session
10
+
11
+ `;
12
+ const login = `\
13
+ login Login to the Pulse Editor Platform.
14
+
15
+ Flags:
16
+ --token [token]
17
+ Login using an access token. This is the default if the
18
+ token is set in the environment variable PE_ACCESS_TOKEN.
19
+ --flow
20
+ Login using a browser flow.
21
+
22
+ `;
23
+ const logout = `\
24
+ logout Logout from the Pulse Editor Platform.
25
+ `;
26
+ const publish = `\
27
+ publish Publish Pulse Editor Extension in current directory to the Pulse Editor Platform.
28
+ `;
29
+ const create = `\
30
+ create Create a new Pulse App using the starter template.
31
+ Flags:
32
+ --framework, -f [framework]
33
+ The framework to use for the new app.
34
+ Currently available options: react.
35
+ Future options: vue, angular, etc.
36
+ `;
37
+ export const commandsManual = {
38
+ help,
39
+ chat,
40
+ login,
41
+ logout,
42
+ publish,
43
+ create,
44
+ };
@@ -0,0 +1,4 @@
1
+ export declare function saveToken(token: string | undefined): void;
2
+ export declare function getToken(): string | undefined;
3
+ export declare function isTokenInEnv(): boolean;
4
+ export declare function checkToken(token: string, devMode: boolean): Promise<boolean>;
@@ -0,0 +1,65 @@
1
+ import os from 'os';
2
+ import path from 'path';
3
+ import fs from 'fs';
4
+ export function saveToken(token) {
5
+ // Save the token to .pulse-editor/config.json in user home directory
6
+ const configDir = path.join(os.homedir(), '.pulse-editor');
7
+ const configFile = path.join(configDir, 'config.json');
8
+ const config = {
9
+ accessToken: token,
10
+ };
11
+ if (!fs.existsSync(configDir)) {
12
+ fs.mkdirSync(configDir, { recursive: true });
13
+ }
14
+ fs.writeFileSync(configFile, JSON.stringify(config, null, 2));
15
+ }
16
+ export function getToken() {
17
+ // First try to get the token from the environment variable
18
+ const tokenEnv = process.env['PE_ACCESS_TOKEN'];
19
+ if (tokenEnv) {
20
+ return tokenEnv;
21
+ }
22
+ // If not found, try to get the token from the config file
23
+ const configDir = path.join(os.homedir(), '.pulse-editor');
24
+ const configFile = path.join(configDir, 'config.json');
25
+ if (fs.existsSync(configFile)) {
26
+ try {
27
+ const config = JSON.parse(fs.readFileSync(configFile, 'utf8'));
28
+ if (config.accessToken) {
29
+ return config.accessToken;
30
+ }
31
+ }
32
+ catch (error) {
33
+ console.error('Failed to parse config.json:', error);
34
+ // Return undefined if JSON parsing fails
35
+ return undefined;
36
+ }
37
+ }
38
+ // If not found, return undefined
39
+ return undefined;
40
+ }
41
+ export function isTokenInEnv() {
42
+ // Check if the token is set in the environment variable
43
+ const tokenEnv = process.env['PE_ACCESS_TOKEN'];
44
+ if (tokenEnv) {
45
+ return true;
46
+ }
47
+ return false;
48
+ }
49
+ export async function checkToken(token, devMode) {
50
+ const res = await fetch(devMode
51
+ ? 'http://localhost:3000/api/api-keys/check'
52
+ : 'https://pulse-editor.com/api/api-keys/check', {
53
+ body: JSON.stringify({ token }),
54
+ headers: {
55
+ 'Content-Type': 'application/json',
56
+ },
57
+ method: 'POST',
58
+ });
59
+ if (res.status === 200) {
60
+ return true;
61
+ }
62
+ else {
63
+ return false;
64
+ }
65
+ }
@@ -0,0 +1,5 @@
1
+ export type Item<V> = {
2
+ key?: string;
3
+ label: string;
4
+ value: V;
5
+ };
@@ -0,0 +1 @@
1
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pulse-editor/cli",
3
- "version": "0.0.1",
3
+ "version": "0.1.0-beta.0",
4
4
  "license": "MIT",
5
5
  "bin": {
6
6
  "pulse": "./dist/cli.js"
package/readme.md CHANGED
@@ -1,25 +1,43 @@
1
- # cli
2
-
3
- > This readme is automatically generated by [create-ink-app](https://github.com/vadimdemedes/create-ink-app)
4
-
1
+ # Pulse CLI
5
2
  ## Install
6
3
 
7
4
  ```bash
8
- $ npm install --global cli
5
+ $ npm install --global @pulse-editor/cli
9
6
  ```
10
7
 
11
- ## CLI
8
+ ## CLI Manual
12
9
 
13
10
  ```
14
- $ cli --help
15
-
16
11
  Usage
17
- $ cli
18
-
19
- Options
20
- --name Your name
12
+ pulse [command] [flags]
13
+
14
+ Commands
15
+ help [command] Show help for a command.
16
+ chat [message] (WIP) Chat with the Pulse Editor AI assistant.
17
+
18
+ Flags:
19
+ --interactive, -i
20
+ Start an interactive chat session
21
+
22
+ login Login to the Pulse Editor Platform.
23
+
24
+ Flags:
25
+ --token [token]
26
+ Login using an access token. This is the default if the
27
+ token is set in the environment variable PE_ACCESS_TOKEN.
28
+ --flow
29
+ Login using a browser flow.
30
+
31
+ logout Logout from the Pulse Editor Platform.
32
+ publish Publish Pulse Editor Extension in current directory to the Pulse Editor Platform.
33
+ create Create a new Pulse App using the starter template.
34
+ Flags:
35
+ --framework, -f [framework]
36
+ The framework to use for the new app.
37
+ Currently available options: react.
38
+ Future options: vue, angular, etc.
21
39
 
22
40
  Examples
23
- $ cli --name=Jane
24
- Hello, Jane
41
+ pulse help publish
42
+
25
43
  ```