cf-yoyo 1.0.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 (141) hide show
  1. package/.eslintrc.json +28 -0
  2. package/.github/workflows/ci.yml +96 -0
  3. package/.prettierrc.json +10 -0
  4. package/CHANGELOG.md +55 -0
  5. package/README.md +138 -0
  6. package/__tests__/cli-e2e.test.ts +145 -0
  7. package/__tests__/config.test.ts +268 -0
  8. package/__tests__/filesystem.test.ts +453 -0
  9. package/__tests__/logger.test.ts +274 -0
  10. package/__tests__/template-engine.test.ts +450 -0
  11. package/__tests__/types.test.ts +25 -0
  12. package/deep_todos.md +766 -0
  13. package/dist/cli/commands/create.d.ts +26 -0
  14. package/dist/cli/commands/create.d.ts.map +1 -0
  15. package/dist/cli/commands/create.js +308 -0
  16. package/dist/cli/commands/create.js.map +1 -0
  17. package/dist/cli/commands/git.d.ts +10 -0
  18. package/dist/cli/commands/git.d.ts.map +1 -0
  19. package/dist/cli/commands/git.js +887 -0
  20. package/dist/cli/commands/git.js.map +1 -0
  21. package/dist/cli/commands/list.d.ts +10 -0
  22. package/dist/cli/commands/list.d.ts.map +1 -0
  23. package/dist/cli/commands/list.js +90 -0
  24. package/dist/cli/commands/list.js.map +1 -0
  25. package/dist/cli/index.d.ts +15 -0
  26. package/dist/cli/index.d.ts.map +1 -0
  27. package/dist/cli/index.js +62 -0
  28. package/dist/cli/index.js.map +1 -0
  29. package/dist/core/config.d.ts +35 -0
  30. package/dist/core/config.d.ts.map +1 -0
  31. package/dist/core/config.js +260 -0
  32. package/dist/core/config.js.map +1 -0
  33. package/dist/core/filesystem.d.ts +84 -0
  34. package/dist/core/filesystem.d.ts.map +1 -0
  35. package/dist/core/filesystem.js +417 -0
  36. package/dist/core/filesystem.js.map +1 -0
  37. package/dist/core/git-token.d.ts +81 -0
  38. package/dist/core/git-token.d.ts.map +1 -0
  39. package/dist/core/git-token.js +244 -0
  40. package/dist/core/git-token.js.map +1 -0
  41. package/dist/core/git.d.ts +70 -0
  42. package/dist/core/git.d.ts.map +1 -0
  43. package/dist/core/git.js +367 -0
  44. package/dist/core/git.js.map +1 -0
  45. package/dist/core/prompt.d.ts +28 -0
  46. package/dist/core/prompt.d.ts.map +1 -0
  47. package/dist/core/prompt.js +253 -0
  48. package/dist/core/prompt.js.map +1 -0
  49. package/dist/core/template-engine.d.ts +52 -0
  50. package/dist/core/template-engine.d.ts.map +1 -0
  51. package/dist/core/template-engine.js +308 -0
  52. package/dist/core/template-engine.js.map +1 -0
  53. package/dist/core/template-manager.d.ts +54 -0
  54. package/dist/core/template-manager.d.ts.map +1 -0
  55. package/dist/core/template-manager.js +330 -0
  56. package/dist/core/template-manager.js.map +1 -0
  57. package/dist/index.d.ts +12 -0
  58. package/dist/index.d.ts.map +1 -0
  59. package/dist/index.js +19 -0
  60. package/dist/index.js.map +1 -0
  61. package/dist/types/index.d.ts +244 -0
  62. package/dist/types/index.d.ts.map +1 -0
  63. package/dist/types/index.js +51 -0
  64. package/dist/types/index.js.map +1 -0
  65. package/dist/utils/logger.d.ts +68 -0
  66. package/dist/utils/logger.d.ts.map +1 -0
  67. package/dist/utils/logger.js +140 -0
  68. package/dist/utils/logger.js.map +1 -0
  69. package/memory.md +241 -0
  70. package/need-debug.md +395 -0
  71. package/package.json +42 -0
  72. package/src/cli/commands/create.ts +326 -0
  73. package/src/cli/commands/git.ts +1001 -0
  74. package/src/cli/commands/list.ts +97 -0
  75. package/src/cli/index.ts +71 -0
  76. package/src/core/config.ts +262 -0
  77. package/src/core/filesystem.ts +408 -0
  78. package/src/core/git-token.ts +248 -0
  79. package/src/core/git.ts +384 -0
  80. package/src/core/prompt.ts +345 -0
  81. package/src/core/template-engine.ts +324 -0
  82. package/src/core/template-manager.ts +338 -0
  83. package/src/index.ts +19 -0
  84. package/src/types/index.ts +259 -0
  85. package/src/utils/logger.ts +150 -0
  86. package/templates/pages/basic/README.md.mustache +63 -0
  87. package/templates/pages/basic/package.json.mustache +23 -0
  88. package/templates/pages/basic/public/css/style.css +199 -0
  89. package/templates/pages/basic/public/index.html.mustache +72 -0
  90. package/templates/pages/basic/public/js/main.js +103 -0
  91. package/templates/pages/basic/template.json +38 -0
  92. package/templates/pages/basic/tsconfig.json +21 -0
  93. package/templates/pages/basic/wrangler.toml.mustache +14 -0
  94. package/templates/pages/basic-js/README.md.mustache +62 -0
  95. package/templates/pages/basic-js/package.json.mustache +25 -0
  96. package/templates/pages/basic-js/public/css/style.css +212 -0
  97. package/templates/pages/basic-js/public/index.html.mustache +53 -0
  98. package/templates/pages/basic-js/public/js/main.js +134 -0
  99. package/templates/pages/basic-js/template.json +35 -0
  100. package/templates/pages/basic-js/wrangler.toml.mustache +14 -0
  101. package/templates/pages/react/README.md.mustache +97 -0
  102. package/templates/pages/react/index.html.mustache +14 -0
  103. package/templates/pages/react/package.json.mustache +34 -0
  104. package/templates/pages/react/src/App.css +168 -0
  105. package/templates/pages/react/src/App.tsx.mustache +62 -0
  106. package/templates/pages/react/src/index.css +53 -0
  107. package/templates/pages/react/src/main.tsx.mustache +10 -0
  108. package/templates/pages/react/src/vite-env.d.ts +1 -0
  109. package/templates/pages/react/template.json +54 -0
  110. package/templates/pages/react/tsconfig.json +21 -0
  111. package/templates/pages/react/tsconfig.node.json +10 -0
  112. package/templates/pages/react/vite.config.ts +16 -0
  113. package/templates/worker/basic/README.md.mustache +56 -0
  114. package/templates/worker/basic/package.json.mustache +29 -0
  115. package/templates/worker/basic/src/index.ts.mustache +125 -0
  116. package/templates/worker/basic/template.json +30 -0
  117. package/templates/worker/basic/tsconfig.json +24 -0
  118. package/templates/worker/basic/wrangler.toml.mustache +33 -0
  119. package/templates/worker/basic-js/README.md.mustache +55 -0
  120. package/templates/worker/basic-js/package.json.mustache +25 -0
  121. package/templates/worker/basic-js/src/index.js.mustache +146 -0
  122. package/templates/worker/basic-js/template.json +27 -0
  123. package/templates/worker/basic-js/wrangler.toml.mustache +33 -0
  124. package/templates/worker/hono/README.md.mustache +79 -0
  125. package/templates/worker/hono/package.json.mustache +33 -0
  126. package/templates/worker/hono/src/index.ts.mustache +64 -0
  127. package/templates/worker/hono/src/routes/index.ts.mustache +165 -0
  128. package/templates/worker/hono/template.json +34 -0
  129. package/templates/worker/hono/tsconfig.json +24 -0
  130. package/templates/worker/hono/wrangler.toml.mustache +36 -0
  131. package/templates/worker/hono-js/README.md.mustache +67 -0
  132. package/templates/worker/hono-js/package.json.mustache +29 -0
  133. package/templates/worker/hono-js/src/index.js.mustache +55 -0
  134. package/templates/worker/hono-js/src/routes/index.js.mustache +127 -0
  135. package/templates/worker/hono-js/template.json +31 -0
  136. package/templates/worker/hono-js/wrangler.toml.mustache +36 -0
  137. package/thoughts/ledgers/CONTINUITY_ses_287e.md +74 -0
  138. package/thoughts/ledgers/CONTINUITY_ses_28b5.md +85 -0
  139. package/tsconfig.json +30 -0
  140. package/vitest.config.ts +20 -0
  141. package//351/240/205/347/233/256/350/241/250.md +140 -0
@@ -0,0 +1,244 @@
1
+ "use strict";
2
+ /**
3
+ * Git Token 管理模組
4
+ * 負責管理私人倉庫推送所需的 Git Token
5
+ */
6
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
7
+ if (k2 === undefined) k2 = k;
8
+ var desc = Object.getOwnPropertyDescriptor(m, k);
9
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
10
+ desc = { enumerable: true, get: function() { return m[k]; } };
11
+ }
12
+ Object.defineProperty(o, k2, desc);
13
+ }) : (function(o, m, k, k2) {
14
+ if (k2 === undefined) k2 = k;
15
+ o[k2] = m[k];
16
+ }));
17
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
18
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
19
+ }) : function(o, v) {
20
+ o["default"] = v;
21
+ });
22
+ var __importStar = (this && this.__importStar) || (function () {
23
+ var ownKeys = function(o) {
24
+ ownKeys = Object.getOwnPropertyNames || function (o) {
25
+ var ar = [];
26
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
27
+ return ar;
28
+ };
29
+ return ownKeys(o);
30
+ };
31
+ return function (mod) {
32
+ if (mod && mod.__esModule) return mod;
33
+ var result = {};
34
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
35
+ __setModuleDefault(result, mod);
36
+ return result;
37
+ };
38
+ })();
39
+ Object.defineProperty(exports, "__esModule", { value: true });
40
+ exports.getTokenConfigPath = getTokenConfigPath;
41
+ exports.loadTokens = loadTokens;
42
+ exports.saveTokens = saveTokens;
43
+ exports.addToken = addToken;
44
+ exports.deleteToken = deleteToken;
45
+ exports.updateToken = updateToken;
46
+ exports.updateTokenName = updateTokenName;
47
+ exports.selectToken = selectToken;
48
+ exports.getTokenList = getTokenList;
49
+ const fs_1 = require("fs");
50
+ const path_1 = require("path");
51
+ const os_1 = require("os");
52
+ const uuid_1 = require("uuid");
53
+ const logger_1 = require("../utils/logger");
54
+ /**
55
+ * 獲取配置檔路徑
56
+ * 路徑:~/.config/cf-yoyo/git-token.json(跨平台)
57
+ * 使用 os.homedir() 確保在 Windows、macOS、Linux 上都能正確獲取用戶目錄
58
+ */
59
+ function getTokenConfigPath() {
60
+ const userHome = (0, os_1.homedir)();
61
+ if (!userHome) {
62
+ throw new Error('無法獲取用戶目錄路徑');
63
+ }
64
+ const configDir = (0, path_1.join)(userHome, '.config', 'cf-yoyo');
65
+ const configPath = (0, path_1.join)(configDir, 'git-token.json');
66
+ return configPath;
67
+ }
68
+ /**
69
+ * 確保配置目錄存在
70
+ */
71
+ function ensureConfigDir() {
72
+ const configPath = getTokenConfigPath();
73
+ const configDir = (0, path_1.join)(configPath, '..');
74
+ if (!(0, fs_1.existsSync)(configDir)) {
75
+ (0, fs_1.mkdirSync)(configDir, { recursive: true });
76
+ }
77
+ }
78
+ /**
79
+ * 載入已存 Token
80
+ * @returns GitTokenConfig 配置對象
81
+ */
82
+ function loadTokens() {
83
+ const configPath = getTokenConfigPath();
84
+ if (!(0, fs_1.existsSync)(configPath)) {
85
+ return { tokens: [] };
86
+ }
87
+ try {
88
+ const content = (0, fs_1.readFileSync)(configPath, 'utf-8');
89
+ const config = JSON.parse(content);
90
+ return config;
91
+ }
92
+ catch (error) {
93
+ logger_1.logger.warn('讀取 Token 配置失敗,返回空配置');
94
+ return { tokens: [] };
95
+ }
96
+ }
97
+ /**
98
+ * 保存 Token 配置
99
+ * @param tokens Token 配置對象
100
+ */
101
+ function saveTokens(tokens) {
102
+ ensureConfigDir();
103
+ const configPath = getTokenConfigPath();
104
+ (0, fs_1.writeFileSync)(configPath, JSON.stringify(tokens, null, 2), 'utf-8');
105
+ }
106
+ /**
107
+ * 新增 Token
108
+ * @param name Token 名稱
109
+ * @param token Token 值
110
+ * @returns 新增的 GitToken 對象
111
+ */
112
+ function addToken(name, token) {
113
+ const config = loadTokens();
114
+ const newToken = {
115
+ id: (0, uuid_1.v4)(),
116
+ name,
117
+ token,
118
+ createdAt: new Date().toISOString(),
119
+ };
120
+ config.tokens.push(newToken);
121
+ saveTokens(config);
122
+ return newToken;
123
+ }
124
+ /**
125
+ * 刪除 Token
126
+ * @param id Token ID
127
+ * @returns 是否刪除成功
128
+ */
129
+ function deleteToken(id) {
130
+ const config = loadTokens();
131
+ const initialLength = config.tokens.length;
132
+ config.tokens = config.tokens.filter((tokenItem) => tokenItem.id !== id);
133
+ if (config.tokens.length < initialLength) {
134
+ saveTokens(config);
135
+ return true;
136
+ }
137
+ return false;
138
+ }
139
+ /**
140
+ * 更新 Token
141
+ * @param id Token ID
142
+ * @param name Token 名稱
143
+ * @param token Token 值
144
+ * @returns 是否更新成功
145
+ */
146
+ function updateToken(id, name, token) {
147
+ const config = loadTokens();
148
+ const tokenIndex = config.tokens.findIndex((tokenItem) => tokenItem.id === id);
149
+ if (tokenIndex === -1) {
150
+ return false;
151
+ }
152
+ const existingToken = config.tokens[tokenIndex];
153
+ if (!existingToken) {
154
+ return false;
155
+ }
156
+ config.tokens[tokenIndex] = {
157
+ ...existingToken,
158
+ name,
159
+ token,
160
+ };
161
+ saveTokens(config);
162
+ return true;
163
+ }
164
+ /**
165
+ * 更新 Token 名稱
166
+ * @param id Token ID
167
+ * @param name 新名稱
168
+ * @returns 是否更新成功
169
+ */
170
+ function updateTokenName(id, name) {
171
+ const config = loadTokens();
172
+ const tokenIndex = config.tokens.findIndex((tokenItem) => tokenItem.id === id);
173
+ if (tokenIndex === -1) {
174
+ return false;
175
+ }
176
+ const existingToken = config.tokens[tokenIndex];
177
+ if (!existingToken) {
178
+ return false;
179
+ }
180
+ existingToken.name = name;
181
+ saveTokens(config);
182
+ return true;
183
+ }
184
+ /**
185
+ * 選擇 Token(互動式)
186
+ * 根據不同情況返回對應的 Token
187
+ * - 若無 Token:返回 null
188
+ * - 若有 1 個 Token:返回該 Token
189
+ * - 若有 2+ 個 Token:讓用戶選擇
190
+ * @returns 選擇的 GitToken 或 null
191
+ */
192
+ async function selectToken() {
193
+ const config = loadTokens();
194
+ // 若無 Token
195
+ if (config.tokens.length === 0) {
196
+ return null;
197
+ }
198
+ // 若只有 1 個 Token
199
+ if (config.tokens.length === 1) {
200
+ const firstToken = config.tokens[0];
201
+ if (!firstToken) {
202
+ return null;
203
+ }
204
+ return firstToken;
205
+ }
206
+ // 若有多個 Token,讓用戶選擇
207
+ const { selectedToken } = await Promise.resolve().then(() => __importStar(require('inquirer'))).then((mod) => mod.default.prompt([
208
+ {
209
+ type: 'list',
210
+ name: 'selectedToken',
211
+ message: '選擇要使用的 Git Token:',
212
+ choices: [
213
+ ...config.tokens.map((tokenItem) => ({
214
+ name: tokenItem.name,
215
+ value: tokenItem.id,
216
+ })),
217
+ {
218
+ name: '❌ 退出',
219
+ value: 'exit',
220
+ },
221
+ ],
222
+ },
223
+ ]));
224
+ if (selectedToken === 'exit') {
225
+ return null;
226
+ }
227
+ const selectedTokenItem = config.tokens.find((tokenItem) => tokenItem.id === selectedToken);
228
+ if (!selectedTokenItem) {
229
+ return null;
230
+ }
231
+ return selectedTokenItem;
232
+ }
233
+ /**
234
+ * 獲取所有 Token 名稱列表(用於顯示,不顯示 Token 值)
235
+ */
236
+ function getTokenList() {
237
+ const config = loadTokens();
238
+ return config.tokens.map((tokenItem) => ({
239
+ id: tokenItem.id,
240
+ name: tokenItem.name,
241
+ createdAt: tokenItem.createdAt,
242
+ }));
243
+ }
244
+ //# sourceMappingURL=git-token.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git-token.js","sourceRoot":"","sources":["../../src/core/git-token.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Git 操作核心功能模組
3
+ * 負責執行 Git 相關操作(init、push、clone 等)
4
+ */
5
+ import { GitResult } from '../types';
6
+ /**
7
+ * 檢查是否為 Git 倉庫
8
+ * @param cwd 工作目錄
9
+ */
10
+ export declare function isGitRepository(cwd?: string): Promise<boolean>;
11
+ /**
12
+ * 初始化 Git 倉庫
13
+ * @param cwd 工作目錄
14
+ */
15
+ export declare function gitInit(cwd?: string): Promise<GitResult>;
16
+ /**
17
+ * 建立 .gitignore 檔案(若不存在)
18
+ * @param cwd 工作目錄
19
+ */
20
+ export declare function createGitignore(cwd?: string): boolean;
21
+ /**
22
+ * Git 提交
23
+ * @param message 提交信息
24
+ * @param cwd 工作目錄
25
+ */
26
+ export declare function gitCommit(message: string, cwd?: string): Promise<GitResult>;
27
+ /**
28
+ * 添加 Git remote
29
+ * @param remoteName remote 名稱
30
+ * @param url remote URL
31
+ * @param cwd 工作目錄
32
+ */
33
+ export declare function gitAddRemote(remoteName: string, url: string, cwd?: string): Promise<GitResult>;
34
+ /**
35
+ * Git push
36
+ * @param remote remote 名稱
37
+ * @param branch 分支名稱
38
+ * @param cwd 工作目錄
39
+ * @param token Git Token(可選,若提供則使用 Token 認證)
40
+ */
41
+ export declare function gitPush(remote: string, branch: string, cwd?: string, token?: string): Promise<GitResult>;
42
+ /**
43
+ * Git clone
44
+ * @param url 倉庫 URL
45
+ * @param directory 目標目錄
46
+ * @param token Git Token(可選,若提供則使用 Token 認證)
47
+ */
48
+ export declare function gitClone(url: string, directory?: string, token?: string): Promise<GitResult>;
49
+ /**
50
+ * 獲取當前分支名稱
51
+ * @param cwd 工作目錄
52
+ */
53
+ export declare function getCurrentBranch(cwd?: string): Promise<string | null>;
54
+ /**
55
+ * 獲取 remote 列表
56
+ * @param cwd 工作目錄
57
+ */
58
+ export declare function getRemotes(cwd?: string): Promise<string[]>;
59
+ /**
60
+ * 設置 default branch
61
+ * @param branch 分支名稱
62
+ * @param cwd 工作目錄
63
+ */
64
+ export declare function gitBranchM1(branch: string, cwd?: string): Promise<GitResult>;
65
+ /**
66
+ * 取消 Git 倉庫(刪除 .git 目錄)
67
+ * @param cwd 工作目錄
68
+ */
69
+ export declare function removeGitRepo(cwd?: string): Promise<GitResult>;
70
+ //# sourceMappingURL=git.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git.d.ts","sourceRoot":"","sources":["../../src/core/git.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AA8FrC;;;GAGG;AACH,wBAAsB,eAAe,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAGpE;AAED;;;GAGG;AACH,wBAAsB,OAAO,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,CAa9D;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CA+CrD;AAED;;;;GAIG;AACH,wBAAsB,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,CAQjF;AAED;;;;;GAKG;AACH,wBAAsB,YAAY,CAChC,UAAU,EAAE,MAAM,EAClB,GAAG,EAAE,MAAM,EACX,GAAG,CAAC,EAAE,MAAM,GACX,OAAO,CAAC,SAAS,CAAC,CAEpB;AAED;;;;;;GAMG;AACH,wBAAsB,OAAO,CAC3B,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,GAAG,CAAC,EAAE,MAAM,EACZ,KAAK,CAAC,EAAE,MAAM,GACb,OAAO,CAAC,SAAS,CAAC,CAoEpB;AAED;;;;;GAKG;AACH,wBAAsB,QAAQ,CAC5B,GAAG,EAAE,MAAM,EACX,SAAS,CAAC,EAAE,MAAM,EAClB,KAAK,CAAC,EAAE,MAAM,GACb,OAAO,CAAC,SAAS,CAAC,CAUpB;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAQ3E;AAED;;;GAGG;AACH,wBAAsB,UAAU,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAShE;AAED;;;;GAIG;AACH,wBAAsB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,CAElF;AAED;;;GAGG;AACH,wBAAsB,aAAa,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,CAyBpE"}
@@ -0,0 +1,367 @@
1
+ "use strict";
2
+ /**
3
+ * Git 操作核心功能模組
4
+ * 負責執行 Git 相關操作(init、push、clone 等)
5
+ */
6
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
7
+ if (k2 === undefined) k2 = k;
8
+ var desc = Object.getOwnPropertyDescriptor(m, k);
9
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
10
+ desc = { enumerable: true, get: function() { return m[k]; } };
11
+ }
12
+ Object.defineProperty(o, k2, desc);
13
+ }) : (function(o, m, k, k2) {
14
+ if (k2 === undefined) k2 = k;
15
+ o[k2] = m[k];
16
+ }));
17
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
18
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
19
+ }) : function(o, v) {
20
+ o["default"] = v;
21
+ });
22
+ var __importStar = (this && this.__importStar) || (function () {
23
+ var ownKeys = function(o) {
24
+ ownKeys = Object.getOwnPropertyNames || function (o) {
25
+ var ar = [];
26
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
27
+ return ar;
28
+ };
29
+ return ownKeys(o);
30
+ };
31
+ return function (mod) {
32
+ if (mod && mod.__esModule) return mod;
33
+ var result = {};
34
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
35
+ __setModuleDefault(result, mod);
36
+ return result;
37
+ };
38
+ })();
39
+ Object.defineProperty(exports, "__esModule", { value: true });
40
+ exports.isGitRepository = isGitRepository;
41
+ exports.gitInit = gitInit;
42
+ exports.createGitignore = createGitignore;
43
+ exports.gitCommit = gitCommit;
44
+ exports.gitAddRemote = gitAddRemote;
45
+ exports.gitPush = gitPush;
46
+ exports.gitClone = gitClone;
47
+ exports.getCurrentBranch = getCurrentBranch;
48
+ exports.getRemotes = getRemotes;
49
+ exports.gitBranchM1 = gitBranchM1;
50
+ exports.removeGitRepo = removeGitRepo;
51
+ const execa_1 = require("execa");
52
+ const fs_1 = require("fs");
53
+ const path_1 = require("path");
54
+ const git_token_1 = require("./git-token");
55
+ /**
56
+ * 檢查錯誤是否為 ExecaError
57
+ */
58
+ function isExecaError(error) {
59
+ return error instanceof Error && 'stderr' in error;
60
+ }
61
+ /**
62
+ * 將 HTTPS URL 轉換為包含 Token 的格式
63
+ * 例如:https://github.com/user/repo.git -> https://<token>@github.com/user/repo.git
64
+ * @param url Git 倉庫 URL
65
+ * @param token Git Token
66
+ * @returns 包含 Token 的 URL
67
+ */
68
+ function injectTokenToUrl(url, token) {
69
+ // 只處理 HTTPS URL
70
+ if (!url.startsWith('https://')) {
71
+ return url;
72
+ }
73
+ // 移除 https:// 前綴
74
+ const urlWithoutProtocol = url.slice(8);
75
+ // 插入 token@
76
+ return `https://${token}@${urlWithoutProtocol}`;
77
+ }
78
+ /**
79
+ * 獲取要使用的 Git Token(若有)
80
+ * @returns GitToken 或 null
81
+ */
82
+ function getGitToken() {
83
+ const config = (0, git_token_1.loadTokens)();
84
+ if (config.tokens.length === 0) {
85
+ return null;
86
+ }
87
+ // 返回第一個 token(預設使用最新或第一個)
88
+ return config.tokens[0] || null;
89
+ }
90
+ /**
91
+ * 執行 Git 命令
92
+ * @param args Git 命令參數
93
+ * @param options 執行選項
94
+ */
95
+ async function executeGitCommand(args, options = {}) {
96
+ try {
97
+ const execOptions = {
98
+ cwd: options.cwd ?? process.cwd(),
99
+ timeout: options.timeout ?? 60000, // 預設 60 秒超時
100
+ };
101
+ const { stdout, stderr } = await (0, execa_1.execa)('git', args, execOptions);
102
+ return {
103
+ success: true,
104
+ message: '命令執行成功',
105
+ output: stdout || stderr,
106
+ };
107
+ }
108
+ catch (error) {
109
+ const errorMessage = error instanceof Error ? error.message : String(error);
110
+ const stderr = isExecaError(error) ? error.stderr : undefined;
111
+ const result = {
112
+ success: false,
113
+ message: `Git 命令執行失敗:${errorMessage}`,
114
+ };
115
+ // 只有在有 stderr 時才添加 output 屬性
116
+ if (stderr !== undefined) {
117
+ result.output = stderr;
118
+ }
119
+ return result;
120
+ }
121
+ }
122
+ /**
123
+ * 檢查是否為 Git 倉庫
124
+ * @param cwd 工作目錄
125
+ */
126
+ async function isGitRepository(cwd) {
127
+ const result = await executeGitCommand(['rev-parse', '--git-dir'], { cwd: cwd ?? process.cwd() });
128
+ return result.success;
129
+ }
130
+ /**
131
+ * 初始化 Git 倉庫
132
+ * @param cwd 工作目錄
133
+ */
134
+ async function gitInit(cwd) {
135
+ const targetDir = cwd || process.cwd();
136
+ // 檢查是否已為 Git 倉庫
137
+ const alreadyGit = await isGitRepository(targetDir);
138
+ if (alreadyGit) {
139
+ return {
140
+ success: false,
141
+ message: '此目錄已經是 Git 倉庫',
142
+ };
143
+ }
144
+ return await executeGitCommand(['init'], { cwd: targetDir });
145
+ }
146
+ /**
147
+ * 建立 .gitignore 檔案(若不存在)
148
+ * @param cwd 工作目錄
149
+ */
150
+ function createGitignore(cwd) {
151
+ const targetDir = cwd || process.cwd();
152
+ const gitignorePath = (0, path_1.join)(targetDir, '.gitignore');
153
+ if ((0, fs_1.existsSync)(gitignorePath)) {
154
+ return false; // 已存在
155
+ }
156
+ const defaultGitignore = `# 依賴
157
+ node_modules/
158
+ .pnpm-store/
159
+
160
+ # 構建輸出
161
+ dist/
162
+ build/
163
+ .next/
164
+ out/
165
+
166
+ # 環境變量
167
+ .env
168
+ .env.local
169
+ .env.*.local
170
+
171
+ # 日誌
172
+ *.log
173
+ npm-debug.log*
174
+ yarn-debug.log*
175
+ yarn-error.log*
176
+
177
+ # 編輯器
178
+ .vscode/
179
+ .idea/
180
+ *.swp
181
+ *.swo
182
+ *~
183
+
184
+ # 操作系統
185
+ .DS_Store
186
+ Thumbs.db
187
+
188
+ # Cloudflare
189
+ .wrangler/
190
+ .dev.vars
191
+ `;
192
+ (0, fs_1.writeFileSync)(gitignorePath, defaultGitignore, 'utf-8');
193
+ return true;
194
+ }
195
+ /**
196
+ * Git 提交
197
+ * @param message 提交信息
198
+ * @param cwd 工作目錄
199
+ */
200
+ async function gitCommit(message, cwd) {
201
+ const targetCwd = cwd ?? process.cwd();
202
+ const result = await executeGitCommand(['add', '-A'], { cwd: targetCwd });
203
+ if (!result.success) {
204
+ return result;
205
+ }
206
+ return await executeGitCommand(['commit', '-m', message], { cwd: targetCwd });
207
+ }
208
+ /**
209
+ * 添加 Git remote
210
+ * @param remoteName remote 名稱
211
+ * @param url remote URL
212
+ * @param cwd 工作目錄
213
+ */
214
+ async function gitAddRemote(remoteName, url, cwd) {
215
+ return await executeGitCommand(['remote', 'add', remoteName, url], { cwd: cwd ?? process.cwd() });
216
+ }
217
+ /**
218
+ * Git push
219
+ * @param remote remote 名稱
220
+ * @param branch 分支名稱
221
+ * @param cwd 工作目錄
222
+ * @param token Git Token(可選,若提供則使用 Token 認證)
223
+ */
224
+ async function gitPush(remote, branch, cwd, token) {
225
+ const targetCwd = cwd ?? process.cwd();
226
+ // 若有提供 token,先修改 remote URL 以包含 token
227
+ if (token) {
228
+ try {
229
+ // 獲取 remote URL
230
+ const { stdout: remoteUrl } = await (0, execa_1.execa)('git', ['remote', 'get-url', remote], {
231
+ cwd: targetCwd,
232
+ });
233
+ if (!remoteUrl) {
234
+ return {
235
+ success: false,
236
+ message: '無法獲取 remote URL',
237
+ };
238
+ }
239
+ if (remoteUrl.startsWith('https://')) {
240
+ // 將 token 注入 URL
241
+ const tokenUrl = injectTokenToUrl(remoteUrl, token);
242
+ // 設置臨時 remote URL
243
+ await (0, execa_1.execa)('git', ['remote', 'set-url', remote, tokenUrl], {
244
+ cwd: targetCwd,
245
+ });
246
+ try {
247
+ // 執行 push
248
+ const result = await executeGitCommand(['push', '-u', remote, branch], {
249
+ cwd: targetCwd,
250
+ });
251
+ // 還原 remote URL(移除 token)
252
+ await (0, execa_1.execa)('git', ['remote', 'set-url', remote, remoteUrl], {
253
+ cwd: targetCwd,
254
+ });
255
+ return result;
256
+ }
257
+ catch (error) {
258
+ // 如果失敗,還是要嘗試還原 URL
259
+ try {
260
+ await (0, execa_1.execa)('git', ['remote', 'set-url', remote, remoteUrl], {
261
+ cwd: targetCwd,
262
+ });
263
+ }
264
+ catch {
265
+ // 忽略還原失敗
266
+ }
267
+ throw error;
268
+ }
269
+ }
270
+ else {
271
+ // 非 HTTPS URL(例如 SSH),無法使用 Token
272
+ return {
273
+ success: false,
274
+ message: `Token 認證僅支援 HTTPS URL,目前為:${remoteUrl},請改用 HTTPS 格式的 remote URL`,
275
+ };
276
+ }
277
+ }
278
+ catch (error) {
279
+ // 如果 token 認證失敗,返回錯誤
280
+ const errorMessage = error instanceof Error ? error.message : String(error);
281
+ return {
282
+ success: false,
283
+ message: `Token 認證推送失敗:${errorMessage}`,
284
+ };
285
+ }
286
+ }
287
+ return await executeGitCommand(['push', '-u', remote, branch], { cwd: targetCwd });
288
+ }
289
+ /**
290
+ * Git clone
291
+ * @param url 倉庫 URL
292
+ * @param directory 目標目錄
293
+ * @param token Git Token(可選,若提供則使用 Token 認證)
294
+ */
295
+ async function gitClone(url, directory, token) {
296
+ // 若有 token 且為 HTTPS URL,注入 token
297
+ const cloneUrl = token && url.startsWith('https://') ? injectTokenToUrl(url, token) : url;
298
+ const args = ['clone', cloneUrl];
299
+ if (directory) {
300
+ args.push(directory);
301
+ }
302
+ return await executeGitCommand(args);
303
+ }
304
+ /**
305
+ * 獲取當前分支名稱
306
+ * @param cwd 工作目錄
307
+ */
308
+ async function getCurrentBranch(cwd) {
309
+ const result = await executeGitCommand(['branch', '--show-current'], {
310
+ cwd: cwd ?? process.cwd(),
311
+ });
312
+ if (result.success && result.output) {
313
+ return result.output.trim();
314
+ }
315
+ return null;
316
+ }
317
+ /**
318
+ * 獲取 remote 列表
319
+ * @param cwd 工作目錄
320
+ */
321
+ async function getRemotes(cwd) {
322
+ const result = await executeGitCommand(['remote'], { cwd: cwd ?? process.cwd() });
323
+ if (result.success && result.output) {
324
+ return result.output
325
+ .trim()
326
+ .split('\n')
327
+ .filter((remoteName) => remoteName.trim() !== '');
328
+ }
329
+ return [];
330
+ }
331
+ /**
332
+ * 設置 default branch
333
+ * @param branch 分支名稱
334
+ * @param cwd 工作目錄
335
+ */
336
+ async function gitBranchM1(branch, cwd) {
337
+ return await executeGitCommand(['branch', '-M', branch], { cwd: cwd ?? process.cwd() });
338
+ }
339
+ /**
340
+ * 取消 Git 倉庫(刪除 .git 目錄)
341
+ * @param cwd 工作目錄
342
+ */
343
+ async function removeGitRepo(cwd) {
344
+ const gitDir = (0, path_1.join)(cwd ?? process.cwd(), '.git');
345
+ if (!(0, fs_1.existsSync)(gitDir)) {
346
+ return {
347
+ success: false,
348
+ message: '此目錄不是 Git 倉庫',
349
+ };
350
+ }
351
+ try {
352
+ const { rmSync } = await Promise.resolve().then(() => __importStar(require('fs')));
353
+ rmSync(gitDir, { recursive: true, force: true });
354
+ return {
355
+ success: true,
356
+ message: '已成功取消 Git 倉庫',
357
+ };
358
+ }
359
+ catch (error) {
360
+ const errorMessage = error instanceof Error ? error.message : String(error);
361
+ return {
362
+ success: false,
363
+ message: `取消 Git 倉庫失敗:${errorMessage}`,
364
+ };
365
+ }
366
+ }
367
+ //# sourceMappingURL=git.js.map