@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.
Files changed (55) hide show
  1. package/GITHUB_OAUTH_SETUP.md +247 -0
  2. package/dist/commands/create.d.ts +9 -0
  3. package/dist/commands/create.d.ts.map +1 -0
  4. package/dist/commands/create.js +130 -0
  5. package/dist/commands/create.js.map +1 -0
  6. package/dist/commands/delete.d.ts +2 -0
  7. package/dist/commands/delete.d.ts.map +1 -0
  8. package/dist/commands/delete.js +59 -0
  9. package/dist/commands/delete.js.map +1 -0
  10. package/dist/commands/github-disconnect.d.ts +2 -0
  11. package/dist/commands/github-disconnect.d.ts.map +1 -0
  12. package/dist/commands/github-disconnect.js +73 -0
  13. package/dist/commands/github-disconnect.js.map +1 -0
  14. package/dist/commands/github-login.d.ts +2 -0
  15. package/dist/commands/github-login.d.ts.map +1 -0
  16. package/dist/commands/github-login.js +100 -0
  17. package/dist/commands/github-login.js.map +1 -0
  18. package/dist/commands/login.d.ts +2 -0
  19. package/dist/commands/login.d.ts.map +1 -0
  20. package/dist/commands/login.js +90 -0
  21. package/dist/commands/login.js.map +1 -0
  22. package/dist/commands/publish.d.ts +6 -0
  23. package/dist/commands/publish.d.ts.map +1 -0
  24. package/dist/commands/publish.js +176 -0
  25. package/dist/commands/publish.js.map +1 -0
  26. package/dist/commands/save.d.ts +2 -0
  27. package/dist/commands/save.d.ts.map +1 -0
  28. package/dist/commands/save.js +162 -0
  29. package/dist/commands/save.js.map +1 -0
  30. package/dist/commands/update-git-url.d.ts +2 -0
  31. package/dist/commands/update-git-url.d.ts.map +1 -0
  32. package/dist/commands/update-git-url.js +153 -0
  33. package/dist/commands/update-git-url.js.map +1 -0
  34. package/dist/index.d.ts +3 -0
  35. package/dist/index.d.ts.map +1 -0
  36. package/dist/index.js +119 -0
  37. package/dist/index.js.map +1 -0
  38. package/dist/utils/api.d.ts +117 -0
  39. package/dist/utils/api.d.ts.map +1 -0
  40. package/dist/utils/api.js +202 -0
  41. package/dist/utils/api.js.map +1 -0
  42. package/dist/utils/auth.d.ts +4 -0
  43. package/dist/utils/auth.d.ts.map +1 -0
  44. package/dist/utils/auth.js +27 -0
  45. package/dist/utils/auth.js.map +1 -0
  46. package/dist/utils/git.d.ts +47 -0
  47. package/dist/utils/git.d.ts.map +1 -0
  48. package/dist/utils/git.js +224 -0
  49. package/dist/utils/git.js.map +1 -0
  50. package/package.json +2 -1
  51. package/src/commands/github-disconnect.ts +80 -0
  52. package/src/commands/github-login.ts +107 -0
  53. package/src/index.ts +37 -0
  54. package/src/utils/api.ts +21 -0
  55. 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":";;;;;;AAAA,4DAAkD;AAElD,4CAAoB;AACpB,kDAA0B;AAC1B,+BAAkC;AAElC,+DAA+D;AAC/D,MAAM,aAAa;IAMjB,YAAY,OAAe;QAJnB,aAAQ,GAA0B,IAAI,CAAC;QACvC,WAAM,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;QAC5D,iBAAY,GAAG,CAAC,CAAC;QAGvB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACzB,CAAC;IAED,8BAA8B;IAC9B,IAAI,IAAI,CAAC,UAAkB;QACzB,IAAI,CAAC,OAAO,GAAG,UAAU,CAAC;IAC5B,CAAC;IAED,KAAK;QACH,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACnC,IAAI,CAAC,QAAQ,GAAG,WAAW,CAAC,GAAG,EAAE;YAC/B,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,KAAK,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,IAAI,CAAC,OAAO,EAAE,CACtD,CAAC;YACF,IAAI,CAAC,YAAY,GAAG,CAAC,IAAI,CAAC,YAAY,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC;QACnE,CAAC,EAAE,EAAE,CAAC,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,CAAC,OAAe;QACrB,IAAI,CAAC,IAAI,EAAE,CAAC;QACZ,OAAO,CAAC,GAAG,CAAC,OAAO,OAAO,EAAE,CAAC,CAAC;IAChC,CAAC;IAED,IAAI,CAAC,OAAe;QAClB,IAAI,CAAC,IAAI,EAAE,CAAC;QACZ,OAAO,CAAC,GAAG,CAAC,OAAO,OAAO,EAAE,CAAC,CAAC;IAChC,CAAC;IAEO,IAAI;QACV,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAClB,aAAa,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YAC7B,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;QACvB,CAAC;QACD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC7B,CAAC;CACF;AAED,SAAS,GAAG,CAAC,OAAe;IAC1B,OAAO,IAAI,aAAa,CAAC,OAAO,CAAC,CAAC;AACpC,CAAC;AAED,MAAa,UAAU;IAGrB,YAAY,GAAY;QACtB,IAAI,CAAC,GAAG,GAAG,IAAA,oBAAS,EAAC,GAAG,CAAC,CAAC;IAC5B,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,eAAe,CAAC,OAAe,EAAE,SAAiB;QACtD,MAAM,OAAO,GAAG,GAAG,CAAC,2BAA2B,OAAO,KAAK,CAAC,CAAC,KAAK,EAAE,CAAC;QAErE,IAAI,CAAC;YACH,wCAAwC;YACxC,IAAI,YAAE,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;gBAC7B,OAAO,CAAC,IAAI,CAAC,eAAK,CAAC,GAAG,CAAC,aAAa,SAAS,iBAAiB,CAAC,CAAC,CAAC;gBACjE,MAAM,IAAI,KAAK,CAAC,aAAa,SAAS,iBAAiB,CAAC,CAAC;YAC3D,CAAC;YAED,+DAA+D;YAC/D,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;YAChD,IAAI,gBAAgB,GAAG,OAAO,CAAC;YAE/B,IAAI,QAAQ,EAAE,CAAC;gBACb,IAAI,CAAC;oBACH,kDAAkD;oBAClD,MAAM,SAAS,GAAG,MAAM,eAAS,CAAC,cAAc,EAAE,CAAC;oBAEnD,IAAI,SAAS,CAAC,OAAO,IAAI,SAAS,CAAC,KAAK,EAAE,CAAC;wBACzC,kDAAkD;wBAClD,gBAAgB,GAAG,IAAI,CAAC,kBAAkB,CAAC,OAAO,EAAE,SAAS,CAAC,KAAK,CAAC,CAAC;wBACrE,OAAO,CAAC,IAAI,GAAG,uCAAuC,CAAC;oBACzD,CAAC;gBACH,CAAC;gBAAC,OAAO,KAAU,EAAE,CAAC;oBACpB,mEAAmE;oBACnE,uCAAuC;oBACvC,IAAI,KAAK,CAAC,QAAQ,EAAE,MAAM,KAAK,GAAG,EAAE,CAAC;wBACnC,OAAO,CAAC,IAAI,GAAG,gCAAgC,CAAC;oBAClD,CAAC;gBACH,CAAC;YACH,CAAC;YAED,uBAAuB;YACvB,MAAM,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,gBAAgB,EAAE,SAAS,CAAC,CAAC;YAElD,OAAO,CAAC,OAAO,CAAC,eAAK,CAAC,KAAK,CAAC,wBAAwB,SAAS,EAAE,CAAC,CAAC,CAAC;QACpE,CAAC;QAAC,OAAO,KAAU,EAAE,CAAC;YACpB,0CAA0C;YAC1C,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,uBAAuB,CAAC;gBAC/C,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,yBAAyB,CAAC;gBACjD,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAAC,EAAE,CAAC;gBACnD,OAAO,CAAC,IAAI,CAAC,eAAK,CAAC,GAAG,CAAC,qDAAqD,CAAC,CAAC,CAAC;gBAC/E,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,MAAM,CAAC,0CAA0C,CAAC,CAAC,CAAC;gBACtE,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,IAAI,CAAC,sDAAsD,CAAC,CAAC,CAAC;YAClF,CAAC;iBAAM,CAAC;gBACN,OAAO,CAAC,IAAI,CAAC,eAAK,CAAC,GAAG,CAAC,+BAA+B,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;YAC1E,CAAC;YACD,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;IAED;;OAEG;IACK,kBAAkB,CAAC,OAAe,EAAE,KAAa;QACvD,oBAAoB;QACpB,IAAI,OAAO,CAAC,UAAU,CAAC,qBAAqB,CAAC,EAAE,CAAC;YAC9C,OAAO,OAAO,CAAC,OAAO,CAAC,qBAAqB,EAAE,WAAW,KAAK,cAAc,CAAC,CAAC;QAChF,CAAC;QAED,gDAAgD;QAChD,IAAI,OAAO,CAAC,UAAU,CAAC,iBAAiB,CAAC,EAAE,CAAC;YAC1C,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,iBAAiB,EAAE,EAAE,CAAC,CAAC;YACpD,OAAO,WAAW,KAAK,eAAe,IAAI,EAAE,CAAC;QAC/C,CAAC;QAED,+CAA+C;QAC/C,OAAO,OAAO,CAAC;IACjB,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,eAAe,CAAC,GAAY;QAChC,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC,IAAA,oBAAS,EAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;YAC5C,MAAM,GAAG,CAAC,MAAM,EAAE,CAAC;YACnB,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,YAAY,CAAC,GAAY;QAC7B,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC,IAAA,oBAAS,EAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;YAC5C,MAAM,OAAO,GAAG,MAAM,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;YAC3C,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC;YAClE,OAAO,MAAM,EAAE,IAAI,EAAE,KAAK,IAAI,IAAI,CAAC;QACrC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,qBAAqB,CAAC,GAAY;QACtC,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC,IAAA,oBAAS,EAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;YAC5C,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,MAAM,EAAE,CAAC;YAClC,OAAO,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QAC3B,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,YAAY,CAAC,GAAY;QAC7B,MAAM,OAAO,GAAG,GAAG,CAAC,yCAAyC,CAAC,CAAC,KAAK,EAAE,CAAC;QAEvE,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC,IAAA,oBAAS,EAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;YAE5C,qBAAqB;YACrB,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,MAAM,EAAE,CAAC;YAClC,MAAM,aAAa,GAAG,MAAM,CAAC,OAAO,CAAC;YAErC,IAAI,CAAC,aAAa,EAAE,CAAC;gBACnB,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;YAC7C,CAAC;YAED,iBAAiB;YACjB,MAAM,GAAG,CAAC,IAAI,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC;YAExC,OAAO,CAAC,OAAO,CAAC,eAAK,CAAC,KAAK,CAAC,qCAAqC,CAAC,CAAC,CAAC;QACtE,CAAC;QAAC,OAAO,KAAU,EAAE,CAAC;YACpB,OAAO,CAAC,IAAI,CAAC,eAAK,CAAC,GAAG,CAAC,2BAA2B,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;YACpE,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,iBAAiB,CAAC,GAAY;QAKlC,MAAM,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC,IAAA,oBAAS,EAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;QAE5C,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,MAAM,EAAE,CAAC;QAClC,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC;QAE/C,OAAO;YACL,MAAM,EAAE,MAAM,CAAC,OAAO,IAAI,SAAS;YACnC,SAAS;YACT,UAAU,EAAE,CAAC,MAAM,CAAC,OAAO,EAAE;SAC9B,CAAC;IACJ,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,eAAe,CAAC,MAAc;QACnC,iCAAiC;QACjC,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,wBAAwB,CAAC,CAAC;QACrD,IAAI,KAAK,EAAE,CAAC;YACV,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAED,yCAAyC;QACzC,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAChC,OAAO,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IACrD,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,aAAa,CAAC,GAAW;QAC9B,MAAM,QAAQ,GAAG;YACf,yDAAyD;YACzD,kDAAkD;YAClD,yDAAyD;YACzD,kDAAkD;SACnD,CAAC;QAEF,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IACvD,CAAC;CACF;AArMD,gCAqMC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mexty/cli",
3
- "version": "1.6.0",
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;