ai-cmg 0.0.8 → 0.0.9
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/index.js +59 -14
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { execSync, spawnSync } from 'child_process';
|
|
2
|
+
import { execFileSync, execSync, spawnSync } from 'child_process';
|
|
3
3
|
import { readFileSync, existsSync } from 'fs';
|
|
4
4
|
import { dirname, join, resolve } from 'path';
|
|
5
5
|
import { fileURLToPath } from 'url';
|
|
@@ -105,13 +105,62 @@ function getGitEnv() {
|
|
|
105
105
|
}
|
|
106
106
|
function isGitAvailable() {
|
|
107
107
|
try {
|
|
108
|
-
|
|
108
|
+
execFileSync('git', ['--version'], { env: getGitEnv(), stdio: 'ignore' });
|
|
109
109
|
return true;
|
|
110
110
|
}
|
|
111
111
|
catch {
|
|
112
112
|
return false;
|
|
113
113
|
}
|
|
114
114
|
}
|
|
115
|
+
function resolveGitDir(repoRoot) {
|
|
116
|
+
const gitPath = join(repoRoot, '.git');
|
|
117
|
+
if (!existsSync(gitPath))
|
|
118
|
+
return null;
|
|
119
|
+
try {
|
|
120
|
+
const stat = execSync(`test -d "${gitPath}" && echo "dir" || echo "file"`).toString().trim();
|
|
121
|
+
if (stat === 'dir')
|
|
122
|
+
return gitPath;
|
|
123
|
+
}
|
|
124
|
+
catch {
|
|
125
|
+
// fallthrough to file parsing
|
|
126
|
+
}
|
|
127
|
+
try {
|
|
128
|
+
const content = readFileSync(gitPath, 'utf8').trim();
|
|
129
|
+
const match = content.match(/^gitdir:\s*(.+)$/i);
|
|
130
|
+
if (!match)
|
|
131
|
+
return null;
|
|
132
|
+
const gitDirPath = match[1].trim();
|
|
133
|
+
return gitDirPath.startsWith('/')
|
|
134
|
+
? gitDirPath
|
|
135
|
+
: resolve(repoRoot, gitDirPath);
|
|
136
|
+
}
|
|
137
|
+
catch {
|
|
138
|
+
return null;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
function runGit(args, repoRoot) {
|
|
142
|
+
try {
|
|
143
|
+
return execFileSync('git', ['-C', repoRoot, ...args], { env: getGitEnv() }).toString();
|
|
144
|
+
}
|
|
145
|
+
catch {
|
|
146
|
+
const gitDir = resolveGitDir(repoRoot);
|
|
147
|
+
if (!gitDir)
|
|
148
|
+
throw new Error('git failed');
|
|
149
|
+
return execFileSync('git', ['--git-dir', gitDir, '--work-tree', repoRoot, ...args], {
|
|
150
|
+
env: getGitEnv()
|
|
151
|
+
}).toString();
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
function spawnGit(args, repoRoot) {
|
|
155
|
+
const first = spawnSync('git', ['-C', repoRoot, ...args], { stdio: 'inherit', env: getGitEnv() });
|
|
156
|
+
if (first.status === 0)
|
|
157
|
+
return 0;
|
|
158
|
+
const gitDir = resolveGitDir(repoRoot);
|
|
159
|
+
if (!gitDir)
|
|
160
|
+
return first.status ?? 1;
|
|
161
|
+
const second = spawnSync('git', ['--git-dir', gitDir, '--work-tree', repoRoot, ...args], { stdio: 'inherit', env: getGitEnv() });
|
|
162
|
+
return second.status ?? 1;
|
|
163
|
+
}
|
|
115
164
|
function findRepoRootByFs(startDir) {
|
|
116
165
|
let current = resolve(startDir);
|
|
117
166
|
while (true) {
|
|
@@ -174,9 +223,7 @@ function parseMessageArgs(rawArgs) {
|
|
|
174
223
|
function getNameStatus(repoRoot) {
|
|
175
224
|
const map = new Map();
|
|
176
225
|
try {
|
|
177
|
-
const output =
|
|
178
|
-
env: getGitEnv()
|
|
179
|
-
}).toString();
|
|
226
|
+
const output = runGit(['diff', '--cached', '--name-status'], repoRoot);
|
|
180
227
|
output.split('\n').forEach((line) => {
|
|
181
228
|
if (!line.trim())
|
|
182
229
|
return;
|
|
@@ -193,9 +240,7 @@ function getNameStatus(repoRoot) {
|
|
|
193
240
|
}
|
|
194
241
|
function getChangedFiles(repoRoot) {
|
|
195
242
|
try {
|
|
196
|
-
const output =
|
|
197
|
-
env: getGitEnv()
|
|
198
|
-
}).toString();
|
|
243
|
+
const output = runGit(['status', '--porcelain', '-z'], repoRoot);
|
|
199
244
|
if (!output)
|
|
200
245
|
return [];
|
|
201
246
|
const parts = output.split('\0').filter(Boolean);
|
|
@@ -253,7 +298,7 @@ async function promptStageFiles(repoRoot) {
|
|
|
253
298
|
if (action === 'cancel')
|
|
254
299
|
return false;
|
|
255
300
|
if (action === 'all') {
|
|
256
|
-
|
|
301
|
+
spawnGit(['add', '.'], repoRoot);
|
|
257
302
|
return true;
|
|
258
303
|
}
|
|
259
304
|
const fileChoices = candidates.map((entry) => ({
|
|
@@ -270,7 +315,7 @@ async function promptStageFiles(repoRoot) {
|
|
|
270
315
|
const files = picked.files;
|
|
271
316
|
if (!files || files.length === 0)
|
|
272
317
|
return false;
|
|
273
|
-
|
|
318
|
+
spawnGit(['add', '--', ...files], repoRoot);
|
|
274
319
|
return true;
|
|
275
320
|
}
|
|
276
321
|
function getExtension(filePath) {
|
|
@@ -397,7 +442,7 @@ async function main() {
|
|
|
397
442
|
// 3. Git Diff 가져오기
|
|
398
443
|
let diff;
|
|
399
444
|
try {
|
|
400
|
-
diff =
|
|
445
|
+
diff = runGit(['diff', '--cached'], repoRoot);
|
|
401
446
|
}
|
|
402
447
|
catch (e) {
|
|
403
448
|
console.log('Error: not a git repository or git is unavailable.');
|
|
@@ -407,7 +452,7 @@ async function main() {
|
|
|
407
452
|
const staged = await promptStageFiles(repoRoot);
|
|
408
453
|
if (!staged)
|
|
409
454
|
return;
|
|
410
|
-
diff =
|
|
455
|
+
diff = runGit(['diff', '--cached'], repoRoot);
|
|
411
456
|
if (!diff.trim()) {
|
|
412
457
|
console.log('No staged changes. Nothing to commit.');
|
|
413
458
|
return;
|
|
@@ -466,11 +511,11 @@ async function main() {
|
|
|
466
511
|
const action = actions[choice - 1].value;
|
|
467
512
|
switch (action) {
|
|
468
513
|
case 'commit':
|
|
469
|
-
|
|
514
|
+
spawnGit(['commit', '-m', message], repoRoot);
|
|
470
515
|
console.log('Commit complete.');
|
|
471
516
|
break;
|
|
472
517
|
case 'edit':
|
|
473
|
-
|
|
518
|
+
spawnGit(['commit', '-e', '-m', message], repoRoot);
|
|
474
519
|
console.log('Commit complete.');
|
|
475
520
|
break;
|
|
476
521
|
case 'copy':
|