ai-cmg 0.0.2 → 0.0.3

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 (3) hide show
  1. package/README.md +57 -0
  2. package/dist/index.js +107 -6
  3. package/package.json +1 -1
package/README.md ADDED
@@ -0,0 +1,57 @@
1
+ # ai-cmg
2
+
3
+ An AI-powered CLI that analyzes staged changes and generates a commit message. You can commit immediately, edit in your editor, or copy the message.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install -g ai-cmg
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ```bash
14
+ ai-cmg
15
+ ```
16
+
17
+ Flow:
18
+ - If there are staged changes, it generates a message right away.
19
+ - If nothing is staged, it offers `git add .` or a file picker to stage selected files.
20
+ - You can choose to commit, edit, or copy the generated message.
21
+
22
+ ## Provide a Hint or Prompt
23
+
24
+ Use `-m` for a short hint (commit message guidance), and `-p` for a prompt (instruction).
25
+
26
+ ```bash
27
+ ai-cmg -m "Improve login error handling"
28
+ ai-cmg -p "Use a short title and 3 bullet points"
29
+ ```
30
+
31
+ ## Configuration
32
+
33
+ The Worker URL defaults to the built-in value but can be overridden.
34
+
35
+ ```bash
36
+ ai-cmg config --show
37
+ ai-cmg config --set https://your-worker.example.com
38
+ ai-cmg config --reset
39
+ ```
40
+
41
+ Interactive configuration is also available.
42
+
43
+ ```bash
44
+ ai-cmg config
45
+ ```
46
+
47
+ ## Version
48
+
49
+ ```bash
50
+ ai-cmg --version
51
+ ```
52
+
53
+ ## Notes
54
+
55
+ - The tool uses the **staged diff** to generate commit messages.
56
+ - Large diffs, binary/media files, and lockfiles are summarized to reduce token usage.
57
+
package/dist/index.js CHANGED
@@ -6,7 +6,7 @@ import { fileURLToPath } from 'url';
6
6
  import prompts from 'prompts';
7
7
  import clipboardy from 'clipboardy';
8
8
  import Conf from 'conf';
9
- const WORKER_URL = 'https://commit.d-code.workers.dev';
9
+ const DEFAULT_WORKER_URL = 'https://commit.d-code.workers.dev';
10
10
  const config = new Conf({ projectName: 'ai-cmg' });
11
11
  const MEDIA_EXTENSIONS = new Set([
12
12
  '.png', '.jpg', '.jpeg', '.gif', '.webp', '.svg', '.ico', '.bmp', '.tiff',
@@ -36,6 +36,98 @@ function getPackageVersion() {
36
36
  return null;
37
37
  }
38
38
  }
39
+ function getWorkerUrl() {
40
+ return config.get('workerUrl') ?? DEFAULT_WORKER_URL;
41
+ }
42
+ function showConfig() {
43
+ const workerUrl = getWorkerUrl();
44
+ console.log('Current configuration:');
45
+ console.log(`- workerUrl: ${workerUrl}`);
46
+ }
47
+ function showConfigHelp() {
48
+ console.log('Usage: ai-cmg config [--show | --set <url> | --reset]');
49
+ console.log(' --show Show current configuration');
50
+ console.log(' --set <url> Set Worker URL');
51
+ console.log(' --reset Reset Worker URL to default');
52
+ }
53
+ function setWorkerUrl(url) {
54
+ config.set('workerUrl', url);
55
+ console.log('Updated workerUrl.');
56
+ }
57
+ function resetWorkerUrl() {
58
+ config.delete('workerUrl');
59
+ console.log('Reset workerUrl to default.');
60
+ }
61
+ async function runConfigCommand(args) {
62
+ if (args.includes('--help') || args.includes('-h')) {
63
+ showConfigHelp();
64
+ return;
65
+ }
66
+ if (args.includes('--show')) {
67
+ showConfig();
68
+ return;
69
+ }
70
+ const setIndex = args.indexOf('--set');
71
+ if (setIndex >= 0) {
72
+ const nextUrl = args[setIndex + 1]?.trim();
73
+ if (!nextUrl) {
74
+ console.log('Error: --set requires a URL.');
75
+ return;
76
+ }
77
+ setWorkerUrl(nextUrl);
78
+ return;
79
+ }
80
+ if (args.includes('--reset')) {
81
+ resetWorkerUrl();
82
+ return;
83
+ }
84
+ showConfig();
85
+ const response = await prompts({
86
+ type: 'text',
87
+ name: 'workerUrl',
88
+ message: 'Enter Worker URL (leave empty to keep current):'
89
+ });
90
+ const nextUrl = response.workerUrl?.trim();
91
+ if (nextUrl) {
92
+ setWorkerUrl(nextUrl);
93
+ }
94
+ else {
95
+ console.log('No changes made.');
96
+ }
97
+ }
98
+ function parseMessageArgs(rawArgs) {
99
+ const hintParts = [];
100
+ let hint;
101
+ let prompt;
102
+ for (let i = 0; i < rawArgs.length; i += 1) {
103
+ const arg = rawArgs[i];
104
+ if (arg === '-m') {
105
+ const value = rawArgs[i + 1];
106
+ if (!value) {
107
+ console.log('Error: -m requires a value.');
108
+ return null;
109
+ }
110
+ hint = value;
111
+ i += 1;
112
+ continue;
113
+ }
114
+ if (arg === '-p') {
115
+ const value = rawArgs[i + 1];
116
+ if (!value) {
117
+ console.log('Error: -p requires a value.');
118
+ return null;
119
+ }
120
+ prompt = value;
121
+ i += 1;
122
+ continue;
123
+ }
124
+ hintParts.push(arg);
125
+ }
126
+ if (!hint && hintParts.length > 0) {
127
+ hint = hintParts.join(' ');
128
+ }
129
+ return { hint, prompt };
130
+ }
39
131
  function getNameStatus() {
40
132
  const map = new Map();
41
133
  try {
@@ -103,6 +195,7 @@ async function promptStageFiles() {
103
195
  type: 'number',
104
196
  name: 'choice',
105
197
  message: 'Enter a number (1-3):',
198
+ initial: 1,
106
199
  min: 1,
107
200
  max: options.length
108
201
  });
@@ -200,9 +293,16 @@ async function main() {
200
293
  console.log(version ?? 'unknown');
201
294
  return;
202
295
  }
203
- const args = rawArgs.filter((arg) => arg !== '--version' && arg !== '-v').join(' ');
204
- if (args) {
205
- console.log(`Hint detected: "${args}"`);
296
+ if (rawArgs[0] === 'config') {
297
+ await runConfigCommand(rawArgs.slice(1));
298
+ return;
299
+ }
300
+ const parsed = parseMessageArgs(rawArgs.filter((arg) => arg !== '--version' && arg !== '-v'));
301
+ if (!parsed)
302
+ return;
303
+ const { hint, prompt } = parsed;
304
+ if (hint) {
305
+ console.log(`Hint detected: "${hint}"`);
206
306
  }
207
307
  // 2. 인증 토큰 확인 (없으면 물어봄)
208
308
  let authToken = config.get('authToken');
@@ -246,13 +346,13 @@ async function main() {
246
346
  }
247
347
  const filteredDiff = summarizeDiff(diff);
248
348
  // 4. API 요청 (Diff + Hint + Auth)
249
- const response = await fetch(WORKER_URL, {
349
+ const response = await fetch(getWorkerUrl(), {
250
350
  method: 'POST',
251
351
  headers: {
252
352
  'Content-Type': 'application/json',
253
353
  'X-AUTH-TOKEN': authToken
254
354
  },
255
- body: JSON.stringify({ diff: filteredDiff, hint: args }) // 힌트도 같이 전송
355
+ body: JSON.stringify({ diff: filteredDiff, hint, prompt }) // 힌트/프롬프트도 같이 전송
256
356
  });
257
357
  // 인증 실패 처리 (401)
258
358
  if (response.status === 401) {
@@ -283,6 +383,7 @@ async function main() {
283
383
  type: 'number',
284
384
  name: 'choice',
285
385
  message: 'Enter a number (1-4):',
386
+ initial: 1,
286
387
  min: 1,
287
388
  max: actions.length
288
389
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-cmg",
3
- "version": "0.0.2",
3
+ "version": "0.0.3",
4
4
  "description": "AI Commit Message Generator",
5
5
  "type": "module",
6
6
  "bin": {