@mexty/cli 1.6.0 → 1.7.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/GITHUB_OAUTH_SETUP.md +247 -0
- package/dist/commands/create.d.ts +9 -0
- package/dist/commands/create.d.ts.map +1 -0
- package/dist/commands/create.js +130 -0
- package/dist/commands/create.js.map +1 -0
- package/dist/commands/delete.d.ts +2 -0
- package/dist/commands/delete.d.ts.map +1 -0
- package/dist/commands/delete.js +59 -0
- package/dist/commands/delete.js.map +1 -0
- package/dist/commands/github-disconnect.d.ts +2 -0
- package/dist/commands/github-disconnect.d.ts.map +1 -0
- package/dist/commands/github-disconnect.js +73 -0
- package/dist/commands/github-disconnect.js.map +1 -0
- package/dist/commands/github-login.d.ts +2 -0
- package/dist/commands/github-login.d.ts.map +1 -0
- package/dist/commands/github-login.js +100 -0
- package/dist/commands/github-login.js.map +1 -0
- package/dist/commands/login.d.ts +2 -0
- package/dist/commands/login.d.ts.map +1 -0
- package/dist/commands/login.js +90 -0
- package/dist/commands/login.js.map +1 -0
- package/dist/commands/publish.d.ts +6 -0
- package/dist/commands/publish.d.ts.map +1 -0
- package/dist/commands/publish.js +176 -0
- package/dist/commands/publish.js.map +1 -0
- package/dist/commands/save.d.ts +2 -0
- package/dist/commands/save.d.ts.map +1 -0
- package/dist/commands/save.js +162 -0
- package/dist/commands/save.js.map +1 -0
- package/dist/commands/update-git-url.d.ts +2 -0
- package/dist/commands/update-git-url.d.ts.map +1 -0
- package/dist/commands/update-git-url.js +153 -0
- package/dist/commands/update-git-url.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +119 -0
- package/dist/index.js.map +1 -0
- package/dist/utils/api.d.ts +117 -0
- package/dist/utils/api.d.ts.map +1 -0
- package/dist/utils/api.js +202 -0
- package/dist/utils/api.js.map +1 -0
- package/dist/utils/auth.d.ts +4 -0
- package/dist/utils/auth.d.ts.map +1 -0
- package/dist/utils/auth.js +27 -0
- package/dist/utils/auth.js.map +1 -0
- package/dist/utils/git.d.ts +47 -0
- package/dist/utils/git.d.ts.map +1 -0
- package/dist/utils/git.js +224 -0
- package/dist/utils/git.js.map +1 -0
- package/package.json +2 -1
- package/src/commands/github-disconnect.ts +80 -0
- package/src/commands/github-login.ts +107 -0
- package/src/index.ts +37 -0
- package/src/utils/api.ts +21 -0
- package/src/utils/git.ts +60 -2
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.checkAuthentication = checkAuthentication;
|
|
7
|
+
exports.getAuthenticatedUser = getAuthenticatedUser;
|
|
8
|
+
exports.requireAuthentication = requireAuthentication;
|
|
9
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
10
|
+
const api_1 = require("./api");
|
|
11
|
+
function checkAuthentication() {
|
|
12
|
+
if (!api_1.apiClient.isAuthenticated()) {
|
|
13
|
+
console.error(chalk_1.default.red('❌ Authentication required'));
|
|
14
|
+
console.log(chalk_1.default.yellow(' Please login first: mexty login'));
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
return true;
|
|
18
|
+
}
|
|
19
|
+
function getAuthenticatedUser() {
|
|
20
|
+
return api_1.apiClient.getStoredUser();
|
|
21
|
+
}
|
|
22
|
+
function requireAuthentication() {
|
|
23
|
+
if (!checkAuthentication()) {
|
|
24
|
+
process.exit(1);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=auth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/utils/auth.ts"],"names":[],"mappings":";;;;;AAGA,kDAOC;AAED,oDAEC;AAED,sDAIC;AApBD,kDAA0B;AAC1B,+BAAkC;AAElC,SAAgB,mBAAmB;IACjC,IAAI,CAAC,eAAS,CAAC,eAAe,EAAE,EAAE,CAAC;QACjC,OAAO,CAAC,KAAK,CAAC,eAAK,CAAC,GAAG,CAAC,2BAA2B,CAAC,CAAC,CAAC;QACtD,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,MAAM,CAAC,oCAAoC,CAAC,CAAC,CAAC;QAChE,OAAO,KAAK,CAAC;IACf,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAgB,oBAAoB;IAClC,OAAO,eAAS,CAAC,aAAa,EAAE,CAAC;AACnC,CAAC;AAED,SAAgB,qBAAqB;IACnC,IAAI,CAAC,mBAAmB,EAAE,EAAE,CAAC;QAC3B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { SimpleGit } from "simple-git";
|
|
2
|
+
export declare class GitManager {
|
|
3
|
+
git: SimpleGit;
|
|
4
|
+
constructor(cwd?: string);
|
|
5
|
+
/**
|
|
6
|
+
* Clone a repository to a local directory
|
|
7
|
+
* Supports private repositories if GitHub is connected
|
|
8
|
+
*/
|
|
9
|
+
cloneRepository(repoUrl: string, targetDir: string): Promise<void>;
|
|
10
|
+
/**
|
|
11
|
+
* Inject GitHub token into repository URL for authenticated access
|
|
12
|
+
*/
|
|
13
|
+
private injectTokenIntoUrl;
|
|
14
|
+
/**
|
|
15
|
+
* Check if current directory is a Git repository
|
|
16
|
+
*/
|
|
17
|
+
isGitRepository(dir?: string): Promise<boolean>;
|
|
18
|
+
/**
|
|
19
|
+
* Get the current repository's remote URL
|
|
20
|
+
*/
|
|
21
|
+
getRemoteUrl(dir?: string): Promise<string | null>;
|
|
22
|
+
/**
|
|
23
|
+
* Check if there are uncommitted changes
|
|
24
|
+
*/
|
|
25
|
+
hasUncommittedChanges(dir?: string): Promise<boolean>;
|
|
26
|
+
/**
|
|
27
|
+
* Push current branch to remote
|
|
28
|
+
*/
|
|
29
|
+
pushToRemote(dir?: string): Promise<void>;
|
|
30
|
+
/**
|
|
31
|
+
* Get repository information
|
|
32
|
+
*/
|
|
33
|
+
getRepositoryInfo(dir?: string): Promise<{
|
|
34
|
+
branch: string;
|
|
35
|
+
remoteUrl: string | null;
|
|
36
|
+
hasChanges: boolean;
|
|
37
|
+
}>;
|
|
38
|
+
/**
|
|
39
|
+
* Extract repository name from URL
|
|
40
|
+
*/
|
|
41
|
+
static extractRepoName(gitUrl: string): string;
|
|
42
|
+
/**
|
|
43
|
+
* Validate Git URL format
|
|
44
|
+
*/
|
|
45
|
+
static isValidGitUrl(url: string): boolean;
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=git.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git.d.ts","sourceRoot":"","sources":["../../src/utils/git.ts"],"names":[],"mappings":"AAAA,OAAkB,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAwDlD,qBAAa,UAAU;IACd,GAAG,EAAE,SAAS,CAAC;gBAEV,GAAG,CAAC,EAAE,MAAM;IAIxB;;;OAGG;IACG,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAoDxE;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAgB1B;;OAEG;IACG,eAAe,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAUrD;;OAEG;IACG,YAAY,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAWxD;;OAEG;IACG,qBAAqB,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAU3D;;OAEG;IACG,YAAY,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAwB/C;;OAEG;IACG,iBAAiB,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;QAC7C,MAAM,EAAE,MAAM,CAAC;QACf,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;QACzB,UAAU,EAAE,OAAO,CAAC;KACrB,CAAC;IAaF;;OAEG;IACH,MAAM,CAAC,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;IAY9C;;OAEG;IACH,MAAM,CAAC,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;CAU3C"}
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.GitManager = void 0;
|
|
7
|
+
const simple_git_1 = __importDefault(require("simple-git"));
|
|
8
|
+
const fs_1 = __importDefault(require("fs"));
|
|
9
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
10
|
+
const api_1 = require("./api");
|
|
11
|
+
// Simple spinner implementation since ora v5 has import issues
|
|
12
|
+
class SimpleSpinner {
|
|
13
|
+
constructor(message) {
|
|
14
|
+
this.interval = null;
|
|
15
|
+
this.frames = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
|
|
16
|
+
this.currentFrame = 0;
|
|
17
|
+
this.message = message;
|
|
18
|
+
}
|
|
19
|
+
// Add setter for message text
|
|
20
|
+
set text(newMessage) {
|
|
21
|
+
this.message = newMessage;
|
|
22
|
+
}
|
|
23
|
+
start() {
|
|
24
|
+
process.stdout.write(this.message);
|
|
25
|
+
this.interval = setInterval(() => {
|
|
26
|
+
process.stdout.write(`\r${this.frames[this.currentFrame]} ${this.message}`);
|
|
27
|
+
this.currentFrame = (this.currentFrame + 1) % this.frames.length;
|
|
28
|
+
}, 80);
|
|
29
|
+
return this;
|
|
30
|
+
}
|
|
31
|
+
succeed(message) {
|
|
32
|
+
this.stop();
|
|
33
|
+
console.log(`\r✅ ${message}`);
|
|
34
|
+
}
|
|
35
|
+
fail(message) {
|
|
36
|
+
this.stop();
|
|
37
|
+
console.log(`\r❌ ${message}`);
|
|
38
|
+
}
|
|
39
|
+
stop() {
|
|
40
|
+
if (this.interval) {
|
|
41
|
+
clearInterval(this.interval);
|
|
42
|
+
this.interval = null;
|
|
43
|
+
}
|
|
44
|
+
process.stdout.write("\r");
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
function ora(message) {
|
|
48
|
+
return new SimpleSpinner(message);
|
|
49
|
+
}
|
|
50
|
+
class GitManager {
|
|
51
|
+
constructor(cwd) {
|
|
52
|
+
this.git = (0, simple_git_1.default)(cwd);
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Clone a repository to a local directory
|
|
56
|
+
* Supports private repositories if GitHub is connected
|
|
57
|
+
*/
|
|
58
|
+
async cloneRepository(repoUrl, targetDir) {
|
|
59
|
+
const spinner = ora(`Cloning repository from ${repoUrl}...`).start();
|
|
60
|
+
try {
|
|
61
|
+
// Ensure target directory doesn't exist
|
|
62
|
+
if (fs_1.default.existsSync(targetDir)) {
|
|
63
|
+
spinner.fail(chalk_1.default.red(`Directory ${targetDir} already exists`));
|
|
64
|
+
throw new Error(`Directory ${targetDir} already exists`);
|
|
65
|
+
}
|
|
66
|
+
// Check if this is a GitHub URL that might need authentication
|
|
67
|
+
const isGitHub = repoUrl.includes('github.com');
|
|
68
|
+
let authenticatedUrl = repoUrl;
|
|
69
|
+
if (isGitHub) {
|
|
70
|
+
try {
|
|
71
|
+
// Try to get GitHub token for private repo access
|
|
72
|
+
const tokenData = await api_1.apiClient.getGitHubToken();
|
|
73
|
+
if (tokenData.success && tokenData.token) {
|
|
74
|
+
// Inject token into URL for authenticated cloning
|
|
75
|
+
authenticatedUrl = this.injectTokenIntoUrl(repoUrl, tokenData.token);
|
|
76
|
+
spinner.text = `Cloning repository (authenticated)...`;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
catch (error) {
|
|
80
|
+
// If token retrieval fails (e.g., not connected), try without auth
|
|
81
|
+
// This is fine for public repositories
|
|
82
|
+
if (error.response?.status === 404) {
|
|
83
|
+
spinner.text = `Cloning repository (public)...`;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
// Clone the repository
|
|
88
|
+
await this.git.clone(authenticatedUrl, targetDir);
|
|
89
|
+
spinner.succeed(chalk_1.default.green(`Repository cloned to ${targetDir}`));
|
|
90
|
+
}
|
|
91
|
+
catch (error) {
|
|
92
|
+
// Check if error is due to authentication
|
|
93
|
+
if (error.message.includes('Authentication failed') ||
|
|
94
|
+
error.message.includes('could not read Username') ||
|
|
95
|
+
error.message.includes('Repository not found')) {
|
|
96
|
+
spinner.fail(chalk_1.default.red(`Failed to clone repository: Authentication required`));
|
|
97
|
+
console.log(chalk_1.default.yellow('\n💡 This might be a private repository.'));
|
|
98
|
+
console.log(chalk_1.default.blue(' Connect your GitHub account: mexty github-login\n'));
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
spinner.fail(chalk_1.default.red(`Failed to clone repository: ${error.message}`));
|
|
102
|
+
}
|
|
103
|
+
throw error;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Inject GitHub token into repository URL for authenticated access
|
|
108
|
+
*/
|
|
109
|
+
injectTokenIntoUrl(repoUrl, token) {
|
|
110
|
+
// Handle HTTPS URLs
|
|
111
|
+
if (repoUrl.startsWith('https://github.com/')) {
|
|
112
|
+
return repoUrl.replace('https://github.com/', `https://${token}@github.com/`);
|
|
113
|
+
}
|
|
114
|
+
// Handle SSH URLs (convert to HTTPS with token)
|
|
115
|
+
if (repoUrl.startsWith('git@github.com:')) {
|
|
116
|
+
const path = repoUrl.replace('git@github.com:', '');
|
|
117
|
+
return `https://${token}@github.com/${path}`;
|
|
118
|
+
}
|
|
119
|
+
// Return original URL if format not recognized
|
|
120
|
+
return repoUrl;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Check if current directory is a Git repository
|
|
124
|
+
*/
|
|
125
|
+
async isGitRepository(dir) {
|
|
126
|
+
try {
|
|
127
|
+
const git = dir ? (0, simple_git_1.default)(dir) : this.git;
|
|
128
|
+
await git.status();
|
|
129
|
+
return true;
|
|
130
|
+
}
|
|
131
|
+
catch (error) {
|
|
132
|
+
return false;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Get the current repository's remote URL
|
|
137
|
+
*/
|
|
138
|
+
async getRemoteUrl(dir) {
|
|
139
|
+
try {
|
|
140
|
+
const git = dir ? (0, simple_git_1.default)(dir) : this.git;
|
|
141
|
+
const remotes = await git.getRemotes(true);
|
|
142
|
+
const origin = remotes.find((remote) => remote.name === "origin");
|
|
143
|
+
return origin?.refs?.fetch || null;
|
|
144
|
+
}
|
|
145
|
+
catch (error) {
|
|
146
|
+
return null;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Check if there are uncommitted changes
|
|
151
|
+
*/
|
|
152
|
+
async hasUncommittedChanges(dir) {
|
|
153
|
+
try {
|
|
154
|
+
const git = dir ? (0, simple_git_1.default)(dir) : this.git;
|
|
155
|
+
const status = await git.status();
|
|
156
|
+
return !status.isClean();
|
|
157
|
+
}
|
|
158
|
+
catch (error) {
|
|
159
|
+
return false;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Push current branch to remote
|
|
164
|
+
*/
|
|
165
|
+
async pushToRemote(dir) {
|
|
166
|
+
const spinner = ora("Pushing changes to remote repository...").start();
|
|
167
|
+
try {
|
|
168
|
+
const git = dir ? (0, simple_git_1.default)(dir) : this.git;
|
|
169
|
+
// Get current branch
|
|
170
|
+
const status = await git.status();
|
|
171
|
+
const currentBranch = status.current;
|
|
172
|
+
if (!currentBranch) {
|
|
173
|
+
throw new Error("No current branch found");
|
|
174
|
+
}
|
|
175
|
+
// Push to remote
|
|
176
|
+
await git.push("origin", currentBranch);
|
|
177
|
+
spinner.succeed(chalk_1.default.green("Changes pushed to remote repository"));
|
|
178
|
+
}
|
|
179
|
+
catch (error) {
|
|
180
|
+
spinner.fail(chalk_1.default.red(`Failed to push changes: ${error.message}`));
|
|
181
|
+
throw error;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Get repository information
|
|
186
|
+
*/
|
|
187
|
+
async getRepositoryInfo(dir) {
|
|
188
|
+
const git = dir ? (0, simple_git_1.default)(dir) : this.git;
|
|
189
|
+
const status = await git.status();
|
|
190
|
+
const remoteUrl = await this.getRemoteUrl(dir);
|
|
191
|
+
return {
|
|
192
|
+
branch: status.current || "unknown",
|
|
193
|
+
remoteUrl,
|
|
194
|
+
hasChanges: !status.isClean(),
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Extract repository name from URL
|
|
199
|
+
*/
|
|
200
|
+
static extractRepoName(gitUrl) {
|
|
201
|
+
// Handle both SSH and HTTPS URLs
|
|
202
|
+
const match = gitUrl.match(/\/([^\/]+?)(?:\.git)?$/);
|
|
203
|
+
if (match) {
|
|
204
|
+
return match[1];
|
|
205
|
+
}
|
|
206
|
+
// Fallback: use the last part of the URL
|
|
207
|
+
const parts = gitUrl.split("/");
|
|
208
|
+
return parts[parts.length - 1].replace(".git", "");
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Validate Git URL format
|
|
212
|
+
*/
|
|
213
|
+
static isValidGitUrl(url) {
|
|
214
|
+
const patterns = [
|
|
215
|
+
/^https:\/\/github\.com\/[\w\-\.]+\/[\w\-\.]+(?:\.git)?$/,
|
|
216
|
+
/^git@github\.com:[\w\-\.]+\/[\w\-\.]+(?:\.git)?$/,
|
|
217
|
+
/^https:\/\/gitlab\.com\/[\w\-\.]+\/[\w\-\.]+(?:\.git)?$/,
|
|
218
|
+
/^git@gitlab\.com:[\w\-\.]+\/[\w\-\.]+(?:\.git)?$/,
|
|
219
|
+
];
|
|
220
|
+
return patterns.some((pattern) => pattern.test(url));
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
exports.GitManager = GitManager;
|
|
224
|
+
//# sourceMappingURL=git.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git.js","sourceRoot":"","sources":["../../src/utils/git.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mexty/cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.7.0",
|
|
4
4
|
"description": "MEXT CLI for managing blocks and repositories",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
"chalk": "^4.1.2",
|
|
18
18
|
"commander": "^11.1.0",
|
|
19
19
|
"inquirer": "^12.6.3",
|
|
20
|
+
"open": "^8.4.2",
|
|
20
21
|
"simple-git": "^3.20.0"
|
|
21
22
|
},
|
|
22
23
|
"devDependencies": {
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import { createInterface } from 'readline';
|
|
3
|
+
import { apiClient } from '../utils/api';
|
|
4
|
+
import { requireAuthentication } from '../utils/auth';
|
|
5
|
+
|
|
6
|
+
// Simple prompt function
|
|
7
|
+
async function prompt(question: string): Promise<string> {
|
|
8
|
+
return new Promise((resolve) => {
|
|
9
|
+
const rl = createInterface({
|
|
10
|
+
input: process.stdin,
|
|
11
|
+
output: process.stdout
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
rl.question(question, (answer) => {
|
|
15
|
+
rl.close();
|
|
16
|
+
resolve(answer.trim());
|
|
17
|
+
});
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export async function githubDisconnectCommand(): Promise<void> {
|
|
22
|
+
try {
|
|
23
|
+
// Check authentication first
|
|
24
|
+
requireAuthentication();
|
|
25
|
+
|
|
26
|
+
console.log(chalk.blue('🔓 Disconnect GitHub Account'));
|
|
27
|
+
console.log(chalk.gray(' Remove GitHub access from your MEXTY account\n'));
|
|
28
|
+
|
|
29
|
+
// Check if connected
|
|
30
|
+
try {
|
|
31
|
+
const status = await apiClient.getGitHubStatus();
|
|
32
|
+
|
|
33
|
+
if (!status.connected) {
|
|
34
|
+
console.log(chalk.yellow('ℹ️ GitHub is not connected'));
|
|
35
|
+
console.log(chalk.gray(' Nothing to disconnect\n'));
|
|
36
|
+
console.log(chalk.blue('To connect GitHub, run: mexty github-login'));
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
console.log(chalk.yellow('⚠️ Current GitHub connection:'));
|
|
41
|
+
console.log(chalk.gray(` Username: ${status.githubUsername}\n`));
|
|
42
|
+
|
|
43
|
+
// Confirm disconnection
|
|
44
|
+
const confirm = await prompt('Are you sure you want to disconnect GitHub? (y/N): ');
|
|
45
|
+
|
|
46
|
+
if (confirm.toLowerCase() !== 'y' && confirm.toLowerCase() !== 'yes') {
|
|
47
|
+
console.log(chalk.gray('Cancelled'));
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
console.log(chalk.yellow('\n🔄 Disconnecting GitHub...'));
|
|
52
|
+
|
|
53
|
+
// Disconnect
|
|
54
|
+
const result = await apiClient.disconnectGitHub();
|
|
55
|
+
|
|
56
|
+
if (result.success) {
|
|
57
|
+
console.log(chalk.green(`\n✅ ${result.message}`));
|
|
58
|
+
console.log(chalk.gray(' You will no longer be able to clone private repositories'));
|
|
59
|
+
console.log(chalk.blue('\nTo reconnect, run: mexty github-login'));
|
|
60
|
+
} else {
|
|
61
|
+
console.error(chalk.red(`\n❌ ${result.message}`));
|
|
62
|
+
process.exit(1);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
} catch (error: any) {
|
|
66
|
+
console.error(chalk.red(`❌ Failed to disconnect GitHub: ${error.message}`));
|
|
67
|
+
process.exit(1);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
} catch (error: any) {
|
|
71
|
+
console.error(chalk.red(`❌ GitHub disconnect failed: ${error.message}`));
|
|
72
|
+
|
|
73
|
+
if (error.response?.status === 401) {
|
|
74
|
+
console.log(chalk.yellow(' Please login first: mexty login'));
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
process.exit(1);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import open from 'open';
|
|
3
|
+
import { apiClient } from '../utils/api';
|
|
4
|
+
import { requireAuthentication } from '../utils/auth';
|
|
5
|
+
|
|
6
|
+
async function wait(seconds: number): Promise<void> {
|
|
7
|
+
return new Promise(resolve => setTimeout(resolve, seconds * 1000));
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export async function githubLoginCommand(): Promise<void> {
|
|
11
|
+
try {
|
|
12
|
+
// Check authentication first
|
|
13
|
+
requireAuthentication();
|
|
14
|
+
|
|
15
|
+
console.log(chalk.blue('🔐 GitHub Authentication'));
|
|
16
|
+
console.log(chalk.gray(' Connecting your GitHub account for private repository access\n'));
|
|
17
|
+
|
|
18
|
+
// Check if already connected
|
|
19
|
+
try {
|
|
20
|
+
const status = await apiClient.getGitHubStatus();
|
|
21
|
+
if (status.connected) {
|
|
22
|
+
console.log(chalk.green('✅ GitHub already connected!'));
|
|
23
|
+
console.log(chalk.gray(` Username: ${status.githubUsername}`));
|
|
24
|
+
console.log(chalk.gray(` Status: ${status.message}\n`));
|
|
25
|
+
|
|
26
|
+
console.log(chalk.yellow('To disconnect and reconnect, run: mexty github-disconnect'));
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
} catch (error: any) {
|
|
30
|
+
// If status check fails, continue with login
|
|
31
|
+
console.log(chalk.yellow('⚠️ Could not check GitHub status, proceeding with login...'));
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Get GitHub OAuth URL
|
|
35
|
+
console.log(chalk.yellow('📡 Requesting GitHub OAuth URL...'));
|
|
36
|
+
const authData = await apiClient.getGitHubAuthUrl();
|
|
37
|
+
|
|
38
|
+
if (!authData.success || !authData.url) {
|
|
39
|
+
console.error(chalk.red(`❌ ${authData.message}`));
|
|
40
|
+
process.exit(1);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
console.log(chalk.green('✅ OAuth URL generated'));
|
|
44
|
+
console.log(chalk.blue('\n🌐 Opening browser for GitHub authentication...'));
|
|
45
|
+
console.log(chalk.gray(` URL: ${authData.url}\n`));
|
|
46
|
+
|
|
47
|
+
// Open browser
|
|
48
|
+
try {
|
|
49
|
+
await open(authData.url);
|
|
50
|
+
console.log(chalk.yellow('👆 Please authorize MEXTY in your browser'));
|
|
51
|
+
} catch (error) {
|
|
52
|
+
console.warn(chalk.yellow('⚠️ Could not open browser automatically'));
|
|
53
|
+
console.log(chalk.blue('\nPlease open this URL in your browser:'));
|
|
54
|
+
console.log(chalk.cyan(authData.url));
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
console.log(chalk.gray('\n⏳ Waiting for you to authorize...'));
|
|
58
|
+
console.log(chalk.gray(' This may take a moment\n'));
|
|
59
|
+
|
|
60
|
+
// Poll for connection status
|
|
61
|
+
let connected = false;
|
|
62
|
+
let attempts = 0;
|
|
63
|
+
const maxAttempts = 60; // 2 minutes (2 second intervals)
|
|
64
|
+
|
|
65
|
+
while (!connected && attempts < maxAttempts) {
|
|
66
|
+
await wait(2);
|
|
67
|
+
attempts++;
|
|
68
|
+
|
|
69
|
+
try {
|
|
70
|
+
const status = await apiClient.getGitHubStatus();
|
|
71
|
+
if (status.connected) {
|
|
72
|
+
connected = true;
|
|
73
|
+
console.log(chalk.green('\n🎉 GitHub connected successfully!'));
|
|
74
|
+
console.log(chalk.gray(` Username: ${status.githubUsername}`));
|
|
75
|
+
console.log(chalk.gray(` Status: ${status.message}\n`));
|
|
76
|
+
console.log(chalk.blue('You can now clone private block repositories!'));
|
|
77
|
+
break;
|
|
78
|
+
}
|
|
79
|
+
} catch (error) {
|
|
80
|
+
// Continue polling
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Show progress indicator every 10 attempts
|
|
84
|
+
if (attempts % 10 === 0) {
|
|
85
|
+
console.log(chalk.gray(` Still waiting... (${attempts * 2}s)`));
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (!connected) {
|
|
90
|
+
console.error(chalk.red('\n❌ Authentication timeout'));
|
|
91
|
+
console.log(chalk.yellow(' Please try again: mexty github-login'));
|
|
92
|
+
process.exit(1);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
} catch (error: any) {
|
|
96
|
+
console.error(chalk.red(`❌ GitHub login failed: ${error.message}`));
|
|
97
|
+
|
|
98
|
+
if (error.response?.status === 401) {
|
|
99
|
+
console.log(chalk.yellow(' Please login first: mexty login'));
|
|
100
|
+
} else if (error.response?.status === 500) {
|
|
101
|
+
console.log(chalk.yellow(' GitHub OAuth may not be configured on the server'));
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
process.exit(1);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
package/src/index.ts
CHANGED
|
@@ -8,6 +8,8 @@ import { deleteCommand } from "./commands/delete";
|
|
|
8
8
|
import { publishCommand } from "./commands/publish";
|
|
9
9
|
import { saveCommand } from "./commands/save";
|
|
10
10
|
import { updateGitUrlCommand } from "./commands/update-git-url";
|
|
11
|
+
import { githubLoginCommand } from "./commands/github-login";
|
|
12
|
+
import { githubDisconnectCommand } from "./commands/github-disconnect";
|
|
11
13
|
import { apiClient } from "./utils/api";
|
|
12
14
|
|
|
13
15
|
const program = new Command();
|
|
@@ -81,6 +83,41 @@ program
|
|
|
81
83
|
updateGitUrlCommand(blockId, options.url, options.reset);
|
|
82
84
|
});
|
|
83
85
|
|
|
86
|
+
program
|
|
87
|
+
.command("github-login")
|
|
88
|
+
.description("Connect your GitHub account for private repository access")
|
|
89
|
+
.action(githubLoginCommand);
|
|
90
|
+
|
|
91
|
+
program
|
|
92
|
+
.command("github-disconnect")
|
|
93
|
+
.description("Disconnect your GitHub account")
|
|
94
|
+
.action(githubDisconnectCommand);
|
|
95
|
+
|
|
96
|
+
program
|
|
97
|
+
.command("github-status")
|
|
98
|
+
.description("Check GitHub connection status")
|
|
99
|
+
.action(async () => {
|
|
100
|
+
try {
|
|
101
|
+
if (!apiClient.isAuthenticated()) {
|
|
102
|
+
console.log(chalk.yellow("⚠️ Please login first: mexty login"));
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const status = await apiClient.getGitHubStatus();
|
|
107
|
+
|
|
108
|
+
if (status.connected) {
|
|
109
|
+
console.log(chalk.green("✅ GitHub connected"));
|
|
110
|
+
console.log(chalk.gray(` Username: ${status.githubUsername}`));
|
|
111
|
+
console.log(chalk.gray(` Status: ${status.message}`));
|
|
112
|
+
} else {
|
|
113
|
+
console.log(chalk.yellow("❌ GitHub not connected"));
|
|
114
|
+
console.log(chalk.blue(" Connect with: mexty github-login"));
|
|
115
|
+
}
|
|
116
|
+
} catch (error: any) {
|
|
117
|
+
console.error(chalk.red(`❌ Failed to check status: ${error.message}`));
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
|
|
84
121
|
// Error handling
|
|
85
122
|
program.on("command:*", () => {
|
|
86
123
|
console.error(chalk.red(`Invalid command: ${program.args.join(" ")}`));
|
package/src/utils/api.ts
CHANGED
|
@@ -312,6 +312,27 @@ class ApiClient {
|
|
|
312
312
|
return response.data;
|
|
313
313
|
}
|
|
314
314
|
|
|
315
|
+
// GitHub OAuth methods
|
|
316
|
+
async getGitHubAuthUrl(): Promise<{ success: boolean; url?: string; message: string }> {
|
|
317
|
+
const response = await this.client.get("/api/auth/github/url");
|
|
318
|
+
return response.data;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
async getGitHubStatus(): Promise<{ success: boolean; connected: boolean; githubUsername?: string; message: string }> {
|
|
322
|
+
const response = await this.client.get("/api/auth/github/status");
|
|
323
|
+
return response.data;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
async getGitHubToken(): Promise<{ success: boolean; token?: string; username?: string; expiresAt?: Date; message?: string; expired?: boolean }> {
|
|
327
|
+
const response = await this.client.get("/api/auth/github/token");
|
|
328
|
+
return response.data;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
async disconnectGitHub(): Promise<{ success: boolean; message: string }> {
|
|
332
|
+
const response = await this.client.post("/api/auth/github/disconnect");
|
|
333
|
+
return response.data;
|
|
334
|
+
}
|
|
335
|
+
|
|
315
336
|
setBaseUrl(url: string): void {
|
|
316
337
|
this.baseUrl = url;
|
|
317
338
|
this.client.defaults.baseURL = url;
|