@su-record/vibe 2.0.0 → 2.0.1
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/.claude/agents/explorer.md +48 -48
- package/.claude/agents/implementer.md +53 -53
- package/.claude/agents/searcher.md +54 -54
- package/.claude/agents/simplifier.md +119 -119
- package/.claude/agents/tester.md +49 -49
- package/.claude/commands/vibe.analyze.md +239 -239
- package/.claude/commands/vibe.continue.md +88 -88
- package/.claude/commands/vibe.diagram.md +178 -178
- package/.claude/commands/vibe.reason.md +306 -306
- package/.claude/commands/vibe.run.md +760 -760
- package/.claude/commands/vibe.spec.md +339 -339
- package/.claude/commands/vibe.tool.md +153 -153
- package/.claude/commands/vibe.ui.md +137 -137
- package/.claude/commands/vibe.verify.md +238 -238
- package/.claude/settings.json +152 -152
- package/.claude/settings.local.json +4 -57
- package/.vibe/config.json +9 -0
- package/.vibe/constitution.md +184 -184
- package/.vibe/rules/core/communication-guide.md +104 -104
- package/.vibe/rules/core/development-philosophy.md +52 -52
- package/.vibe/rules/core/quick-start.md +120 -120
- package/.vibe/rules/quality/bdd-contract-testing.md +388 -388
- package/.vibe/rules/quality/checklist.md +276 -276
- package/.vibe/rules/quality/testing-strategy.md +437 -437
- package/.vibe/rules/standards/anti-patterns.md +369 -369
- package/.vibe/rules/standards/code-structure.md +291 -291
- package/.vibe/rules/standards/complexity-metrics.md +312 -312
- package/.vibe/rules/standards/naming-conventions.md +198 -198
- package/.vibe/rules/tools/mcp-hi-ai-guide.md +665 -665
- package/.vibe/rules/tools/mcp-workflow.md +51 -51
- package/.vibe/setup.sh +31 -31
- package/CLAUDE.md +122 -122
- package/LICENSE +21 -21
- package/README.md +568 -568
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +391 -406
- package/dist/cli/index.js.map +1 -1
- package/dist/lib/MemoryManager.js +92 -92
- package/dist/lib/PythonParser.js +108 -108
- package/dist/lib/gemini-mcp.js +15 -15
- package/dist/lib/gemini-oauth.js +35 -35
- package/dist/lib/gpt-mcp.js +17 -17
- package/dist/lib/gpt-oauth.js +44 -44
- package/dist/tools/analytics/getUsageAnalytics.js +12 -12
- package/dist/tools/memory/createMemoryTimeline.js +10 -10
- package/dist/tools/memory/getMemoryGraph.js +12 -12
- package/dist/tools/memory/getSessionContext.js +9 -9
- package/dist/tools/memory/linkMemories.js +14 -14
- package/dist/tools/memory/listMemories.js +4 -4
- package/dist/tools/memory/recallMemory.js +4 -4
- package/dist/tools/memory/saveMemory.js +4 -4
- package/dist/tools/memory/searchMemoriesAdvanced.js +22 -22
- package/dist/tools/planning/generatePrd.js +46 -46
- package/dist/tools/prompt/enhancePromptGemini.js +160 -160
- package/dist/tools/reasoning/applyReasoningFramework.js +56 -56
- package/dist/tools/semantic/analyzeDependencyGraph.js +12 -12
- package/package.json +67 -67
- package/templates/constitution-template.md +184 -184
- package/templates/contract-backend-template.md +517 -517
- package/templates/contract-frontend-template.md +594 -594
- package/templates/feature-template.md +96 -96
- package/templates/hooks-template.json +103 -103
- package/templates/spec-template.md +199 -199
- package/dist/lib/vibe-mcp.d.ts.map +0 -1
- package/dist/lib/vibe-mcp.js.map +0 -1
package/dist/lib/PythonParser.js
CHANGED
|
@@ -35,114 +35,114 @@ function getPythonCommand() {
|
|
|
35
35
|
const PYTHON_CMD = getPythonCommand();
|
|
36
36
|
export class PythonParser {
|
|
37
37
|
static cleanupRegistered = false;
|
|
38
|
-
static pythonScript = `
|
|
39
|
-
import ast
|
|
40
|
-
import sys
|
|
41
|
-
import json
|
|
42
|
-
|
|
43
|
-
def analyze_code(code):
|
|
44
|
-
try:
|
|
45
|
-
tree = ast.parse(code)
|
|
46
|
-
symbols = []
|
|
47
|
-
|
|
48
|
-
for node in ast.walk(tree):
|
|
49
|
-
if isinstance(node, ast.FunctionDef):
|
|
50
|
-
symbols.append({
|
|
51
|
-
'name': node.name,
|
|
52
|
-
'kind': 'function',
|
|
53
|
-
'line': node.lineno,
|
|
54
|
-
'column': node.col_offset,
|
|
55
|
-
'endLine': node.end_lineno,
|
|
56
|
-
'docstring': ast.get_docstring(node)
|
|
57
|
-
})
|
|
58
|
-
elif isinstance(node, ast.ClassDef):
|
|
59
|
-
symbols.append({
|
|
60
|
-
'name': node.name,
|
|
61
|
-
'kind': 'class',
|
|
62
|
-
'line': node.lineno,
|
|
63
|
-
'column': node.col_offset,
|
|
64
|
-
'endLine': node.end_lineno,
|
|
65
|
-
'docstring': ast.get_docstring(node)
|
|
66
|
-
})
|
|
67
|
-
elif isinstance(node, ast.Assign):
|
|
68
|
-
for target in node.targets:
|
|
69
|
-
if isinstance(target, ast.Name):
|
|
70
|
-
symbols.append({
|
|
71
|
-
'name': target.id,
|
|
72
|
-
'kind': 'variable',
|
|
73
|
-
'line': node.lineno,
|
|
74
|
-
'column': node.col_offset
|
|
75
|
-
})
|
|
76
|
-
elif isinstance(node, ast.Import) or isinstance(node, ast.ImportFrom):
|
|
77
|
-
for alias in node.names:
|
|
78
|
-
symbols.append({
|
|
79
|
-
'name': alias.name,
|
|
80
|
-
'kind': 'import',
|
|
81
|
-
'line': node.lineno,
|
|
82
|
-
'column': node.col_offset
|
|
83
|
-
})
|
|
84
|
-
|
|
85
|
-
return {'success': True, 'symbols': symbols}
|
|
86
|
-
except SyntaxError as e:
|
|
87
|
-
return {'success': False, 'error': str(e)}
|
|
88
|
-
except Exception as e:
|
|
89
|
-
return {'success': False, 'error': str(e)}
|
|
90
|
-
|
|
91
|
-
def calculate_complexity(code):
|
|
92
|
-
try:
|
|
93
|
-
tree = ast.parse(code)
|
|
94
|
-
|
|
95
|
-
def cyclomatic_complexity(node):
|
|
96
|
-
complexity = 1
|
|
97
|
-
for child in ast.walk(node):
|
|
98
|
-
if isinstance(child, (ast.If, ast.For, ast.While, ast.And, ast.Or, ast.ExceptHandler)):
|
|
99
|
-
complexity += 1
|
|
100
|
-
elif isinstance(child, ast.BoolOp):
|
|
101
|
-
complexity += len(child.values) - 1
|
|
102
|
-
return complexity
|
|
103
|
-
|
|
104
|
-
functions = []
|
|
105
|
-
classes = []
|
|
106
|
-
total_complexity = 1
|
|
107
|
-
|
|
108
|
-
for node in ast.walk(tree):
|
|
109
|
-
if isinstance(node, ast.FunctionDef):
|
|
110
|
-
func_complexity = cyclomatic_complexity(node)
|
|
111
|
-
functions.append({
|
|
112
|
-
'name': node.name,
|
|
113
|
-
'complexity': func_complexity,
|
|
114
|
-
'line': node.lineno
|
|
115
|
-
})
|
|
116
|
-
total_complexity += func_complexity
|
|
117
|
-
elif isinstance(node, ast.ClassDef):
|
|
118
|
-
method_count = sum(1 for n in node.body if isinstance(n, ast.FunctionDef))
|
|
119
|
-
classes.append({
|
|
120
|
-
'name': node.name,
|
|
121
|
-
'methods': method_count,
|
|
122
|
-
'line': node.lineno
|
|
123
|
-
})
|
|
124
|
-
|
|
125
|
-
return {
|
|
126
|
-
'success': True,
|
|
127
|
-
'cyclomaticComplexity': total_complexity,
|
|
128
|
-
'functions': functions,
|
|
129
|
-
'classes': classes
|
|
130
|
-
}
|
|
131
|
-
except Exception as e:
|
|
132
|
-
return {'success': False, 'error': str(e)}
|
|
133
|
-
|
|
134
|
-
if __name__ == '__main__':
|
|
135
|
-
code = sys.stdin.read()
|
|
136
|
-
action = sys.argv[1] if len(sys.argv) > 1 else 'symbols'
|
|
137
|
-
|
|
138
|
-
if action == 'symbols':
|
|
139
|
-
result = analyze_code(code)
|
|
140
|
-
elif action == 'complexity':
|
|
141
|
-
result = calculate_complexity(code)
|
|
142
|
-
else:
|
|
143
|
-
result = {'success': False, 'error': 'Unknown action'}
|
|
144
|
-
|
|
145
|
-
print(json.dumps(result))
|
|
38
|
+
static pythonScript = `
|
|
39
|
+
import ast
|
|
40
|
+
import sys
|
|
41
|
+
import json
|
|
42
|
+
|
|
43
|
+
def analyze_code(code):
|
|
44
|
+
try:
|
|
45
|
+
tree = ast.parse(code)
|
|
46
|
+
symbols = []
|
|
47
|
+
|
|
48
|
+
for node in ast.walk(tree):
|
|
49
|
+
if isinstance(node, ast.FunctionDef):
|
|
50
|
+
symbols.append({
|
|
51
|
+
'name': node.name,
|
|
52
|
+
'kind': 'function',
|
|
53
|
+
'line': node.lineno,
|
|
54
|
+
'column': node.col_offset,
|
|
55
|
+
'endLine': node.end_lineno,
|
|
56
|
+
'docstring': ast.get_docstring(node)
|
|
57
|
+
})
|
|
58
|
+
elif isinstance(node, ast.ClassDef):
|
|
59
|
+
symbols.append({
|
|
60
|
+
'name': node.name,
|
|
61
|
+
'kind': 'class',
|
|
62
|
+
'line': node.lineno,
|
|
63
|
+
'column': node.col_offset,
|
|
64
|
+
'endLine': node.end_lineno,
|
|
65
|
+
'docstring': ast.get_docstring(node)
|
|
66
|
+
})
|
|
67
|
+
elif isinstance(node, ast.Assign):
|
|
68
|
+
for target in node.targets:
|
|
69
|
+
if isinstance(target, ast.Name):
|
|
70
|
+
symbols.append({
|
|
71
|
+
'name': target.id,
|
|
72
|
+
'kind': 'variable',
|
|
73
|
+
'line': node.lineno,
|
|
74
|
+
'column': node.col_offset
|
|
75
|
+
})
|
|
76
|
+
elif isinstance(node, ast.Import) or isinstance(node, ast.ImportFrom):
|
|
77
|
+
for alias in node.names:
|
|
78
|
+
symbols.append({
|
|
79
|
+
'name': alias.name,
|
|
80
|
+
'kind': 'import',
|
|
81
|
+
'line': node.lineno,
|
|
82
|
+
'column': node.col_offset
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
return {'success': True, 'symbols': symbols}
|
|
86
|
+
except SyntaxError as e:
|
|
87
|
+
return {'success': False, 'error': str(e)}
|
|
88
|
+
except Exception as e:
|
|
89
|
+
return {'success': False, 'error': str(e)}
|
|
90
|
+
|
|
91
|
+
def calculate_complexity(code):
|
|
92
|
+
try:
|
|
93
|
+
tree = ast.parse(code)
|
|
94
|
+
|
|
95
|
+
def cyclomatic_complexity(node):
|
|
96
|
+
complexity = 1
|
|
97
|
+
for child in ast.walk(node):
|
|
98
|
+
if isinstance(child, (ast.If, ast.For, ast.While, ast.And, ast.Or, ast.ExceptHandler)):
|
|
99
|
+
complexity += 1
|
|
100
|
+
elif isinstance(child, ast.BoolOp):
|
|
101
|
+
complexity += len(child.values) - 1
|
|
102
|
+
return complexity
|
|
103
|
+
|
|
104
|
+
functions = []
|
|
105
|
+
classes = []
|
|
106
|
+
total_complexity = 1
|
|
107
|
+
|
|
108
|
+
for node in ast.walk(tree):
|
|
109
|
+
if isinstance(node, ast.FunctionDef):
|
|
110
|
+
func_complexity = cyclomatic_complexity(node)
|
|
111
|
+
functions.append({
|
|
112
|
+
'name': node.name,
|
|
113
|
+
'complexity': func_complexity,
|
|
114
|
+
'line': node.lineno
|
|
115
|
+
})
|
|
116
|
+
total_complexity += func_complexity
|
|
117
|
+
elif isinstance(node, ast.ClassDef):
|
|
118
|
+
method_count = sum(1 for n in node.body if isinstance(n, ast.FunctionDef))
|
|
119
|
+
classes.append({
|
|
120
|
+
'name': node.name,
|
|
121
|
+
'methods': method_count,
|
|
122
|
+
'line': node.lineno
|
|
123
|
+
})
|
|
124
|
+
|
|
125
|
+
return {
|
|
126
|
+
'success': True,
|
|
127
|
+
'cyclomaticComplexity': total_complexity,
|
|
128
|
+
'functions': functions,
|
|
129
|
+
'classes': classes
|
|
130
|
+
}
|
|
131
|
+
except Exception as e:
|
|
132
|
+
return {'success': False, 'error': str(e)}
|
|
133
|
+
|
|
134
|
+
if __name__ == '__main__':
|
|
135
|
+
code = sys.stdin.read()
|
|
136
|
+
action = sys.argv[1] if len(sys.argv) > 1 else 'symbols'
|
|
137
|
+
|
|
138
|
+
if action == 'symbols':
|
|
139
|
+
result = analyze_code(code)
|
|
140
|
+
elif action == 'complexity':
|
|
141
|
+
result = calculate_complexity(code)
|
|
142
|
+
else:
|
|
143
|
+
result = {'success': False, 'error': 'Unknown action'}
|
|
144
|
+
|
|
145
|
+
print(json.dumps(result))
|
|
146
146
|
`;
|
|
147
147
|
// Singleton Python script path to avoid recreating it
|
|
148
148
|
static scriptPath = null;
|
package/dist/lib/gemini-mcp.js
CHANGED
|
@@ -161,12 +161,12 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
161
161
|
}
|
|
162
162
|
case 'gemini_analyze_code': {
|
|
163
163
|
const { code, language, focus } = args;
|
|
164
|
-
const sysPrompt = `You are an expert code reviewer. Analyze the given ${language || 'code'} and provide detailed feedback focusing on: ${focus || 'all aspects including performance, security, readability, and best practices'}.
|
|
165
|
-
|
|
166
|
-
Respond in Korean and provide:
|
|
167
|
-
1. 코드 요약
|
|
168
|
-
2. 주요 이슈 (있다면)
|
|
169
|
-
3. 개선 제안
|
|
164
|
+
const sysPrompt = `You are an expert code reviewer. Analyze the given ${language || 'code'} and provide detailed feedback focusing on: ${focus || 'all aspects including performance, security, readability, and best practices'}.
|
|
165
|
+
|
|
166
|
+
Respond in Korean and provide:
|
|
167
|
+
1. 코드 요약
|
|
168
|
+
2. 주요 이슈 (있다면)
|
|
169
|
+
3. 개선 제안
|
|
170
170
|
4. 전체 품질 점수 (1-10)`;
|
|
171
171
|
const result = await geminiApi.chat({
|
|
172
172
|
model: 'gemini-2.5-flash',
|
|
@@ -186,15 +186,15 @@ Respond in Korean and provide:
|
|
|
186
186
|
}
|
|
187
187
|
case 'gemini_review_ui': {
|
|
188
188
|
const { description, context } = args;
|
|
189
|
-
const sysPrompt = `You are a UI/UX expert. Review the given UI description and provide detailed feedback.
|
|
190
|
-
|
|
191
|
-
${context ? `Project context: ${context}` : ''}
|
|
192
|
-
|
|
193
|
-
Respond in Korean and provide:
|
|
194
|
-
1. UI 구조 평가
|
|
195
|
-
2. UX 개선점
|
|
196
|
-
3. 접근성 체크
|
|
197
|
-
4. 모범 사례 비교
|
|
189
|
+
const sysPrompt = `You are a UI/UX expert. Review the given UI description and provide detailed feedback.
|
|
190
|
+
|
|
191
|
+
${context ? `Project context: ${context}` : ''}
|
|
192
|
+
|
|
193
|
+
Respond in Korean and provide:
|
|
194
|
+
1. UI 구조 평가
|
|
195
|
+
2. UX 개선점
|
|
196
|
+
3. 접근성 체크
|
|
197
|
+
4. 모범 사례 비교
|
|
198
198
|
5. 구체적인 개선 제안`;
|
|
199
199
|
const result = await geminiApi.chat({
|
|
200
200
|
model: 'gemini-2.5-flash',
|
package/dist/lib/gemini-oauth.js
CHANGED
|
@@ -209,15 +209,15 @@ export function startOAuthFlow() {
|
|
|
209
209
|
const error = url.searchParams.get('error');
|
|
210
210
|
if (error) {
|
|
211
211
|
res.writeHead(400, { 'Content-Type': 'text/html; charset=utf-8' });
|
|
212
|
-
res.end(`
|
|
213
|
-
<html>
|
|
214
|
-
<head><title>인증 실패</title></head>
|
|
215
|
-
<body style="font-family: sans-serif; text-align: center; padding-top: 50px;">
|
|
216
|
-
<h1>인증 실패</h1>
|
|
217
|
-
<p>오류: ${error}</p>
|
|
218
|
-
<p>이 창을 닫고 다시 시도해주세요.</p>
|
|
219
|
-
</body>
|
|
220
|
-
</html>
|
|
212
|
+
res.end(`
|
|
213
|
+
<html>
|
|
214
|
+
<head><title>인증 실패</title></head>
|
|
215
|
+
<body style="font-family: sans-serif; text-align: center; padding-top: 50px;">
|
|
216
|
+
<h1>인증 실패</h1>
|
|
217
|
+
<p>오류: ${error}</p>
|
|
218
|
+
<p>이 창을 닫고 다시 시도해주세요.</p>
|
|
219
|
+
</body>
|
|
220
|
+
</html>
|
|
221
221
|
`);
|
|
222
222
|
if (!isResolved) {
|
|
223
223
|
isResolved = true;
|
|
@@ -228,14 +228,14 @@ export function startOAuthFlow() {
|
|
|
228
228
|
}
|
|
229
229
|
if (!code || !state) {
|
|
230
230
|
res.writeHead(400, { 'Content-Type': 'text/html; charset=utf-8' });
|
|
231
|
-
res.end(`
|
|
232
|
-
<html>
|
|
233
|
-
<head><title>인증 실패</title></head>
|
|
234
|
-
<body style="font-family: sans-serif; text-align: center; padding-top: 50px;">
|
|
235
|
-
<h1>인증 실패</h1>
|
|
236
|
-
<p>필수 파라미터가 없습니다.</p>
|
|
237
|
-
</body>
|
|
238
|
-
</html>
|
|
231
|
+
res.end(`
|
|
232
|
+
<html>
|
|
233
|
+
<head><title>인증 실패</title></head>
|
|
234
|
+
<body style="font-family: sans-serif; text-align: center; padding-top: 50px;">
|
|
235
|
+
<h1>인증 실패</h1>
|
|
236
|
+
<p>필수 파라미터가 없습니다.</p>
|
|
237
|
+
</body>
|
|
238
|
+
</html>
|
|
239
239
|
`);
|
|
240
240
|
if (!isResolved) {
|
|
241
241
|
isResolved = true;
|
|
@@ -247,16 +247,16 @@ export function startOAuthFlow() {
|
|
|
247
247
|
try {
|
|
248
248
|
const tokens = await exchangeCodeForTokens(code, state);
|
|
249
249
|
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
|
|
250
|
-
res.end(`
|
|
251
|
-
<html>
|
|
252
|
-
<head><title>인증 성공</title></head>
|
|
253
|
-
<body style="font-family: sans-serif; text-align: center; padding-top: 50px;">
|
|
254
|
-
<h1>인증 성공!</h1>
|
|
255
|
-
<p>${tokens.email}로 로그인되었습니다.</p>
|
|
256
|
-
<p>이 창을 닫아도 됩니다.</p>
|
|
257
|
-
<script>setTimeout(() => window.close(), 2000);</script>
|
|
258
|
-
</body>
|
|
259
|
-
</html>
|
|
250
|
+
res.end(`
|
|
251
|
+
<html>
|
|
252
|
+
<head><title>인증 성공</title></head>
|
|
253
|
+
<body style="font-family: sans-serif; text-align: center; padding-top: 50px;">
|
|
254
|
+
<h1>인증 성공!</h1>
|
|
255
|
+
<p>${tokens.email}로 로그인되었습니다.</p>
|
|
256
|
+
<p>이 창을 닫아도 됩니다.</p>
|
|
257
|
+
<script>setTimeout(() => window.close(), 2000);</script>
|
|
258
|
+
</body>
|
|
259
|
+
</html>
|
|
260
260
|
`);
|
|
261
261
|
if (!isResolved) {
|
|
262
262
|
isResolved = true;
|
|
@@ -266,14 +266,14 @@ export function startOAuthFlow() {
|
|
|
266
266
|
}
|
|
267
267
|
catch (err) {
|
|
268
268
|
res.writeHead(500, { 'Content-Type': 'text/html; charset=utf-8' });
|
|
269
|
-
res.end(`
|
|
270
|
-
<html>
|
|
271
|
-
<head><title>인증 실패</title></head>
|
|
272
|
-
<body style="font-family: sans-serif; text-align: center; padding-top: 50px;">
|
|
273
|
-
<h1>인증 실패</h1>
|
|
274
|
-
<p>${err.message}</p>
|
|
275
|
-
</body>
|
|
276
|
-
</html>
|
|
269
|
+
res.end(`
|
|
270
|
+
<html>
|
|
271
|
+
<head><title>인증 실패</title></head>
|
|
272
|
+
<body style="font-family: sans-serif; text-align: center; padding-top: 50px;">
|
|
273
|
+
<h1>인증 실패</h1>
|
|
274
|
+
<p>${err.message}</p>
|
|
275
|
+
</body>
|
|
276
|
+
</html>
|
|
277
277
|
`);
|
|
278
278
|
if (!isResolved) {
|
|
279
279
|
isResolved = true;
|
package/dist/lib/gpt-mcp.js
CHANGED
|
@@ -159,15 +159,15 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
159
159
|
}
|
|
160
160
|
case 'gpt_analyze_architecture': {
|
|
161
161
|
const { code, context } = args;
|
|
162
|
-
const sysPrompt = `You are a senior software architect. Analyze the given code or architecture and provide detailed insights.
|
|
163
|
-
|
|
164
|
-
${context ? `Project context: ${context}` : ''}
|
|
165
|
-
|
|
166
|
-
Respond in Korean and provide:
|
|
167
|
-
1. 아키텍처 요약
|
|
168
|
-
2. 강점
|
|
169
|
-
3. 잠재적 문제점
|
|
170
|
-
4. 개선 제안
|
|
162
|
+
const sysPrompt = `You are a senior software architect. Analyze the given code or architecture and provide detailed insights.
|
|
163
|
+
|
|
164
|
+
${context ? `Project context: ${context}` : ''}
|
|
165
|
+
|
|
166
|
+
Respond in Korean and provide:
|
|
167
|
+
1. 아키텍처 요약
|
|
168
|
+
2. 강점
|
|
169
|
+
3. 잠재적 문제점
|
|
170
|
+
4. 개선 제안
|
|
171
171
|
5. 확장성 평가`;
|
|
172
172
|
const result = await gptApi.chat({
|
|
173
173
|
model: 'gpt-5.2',
|
|
@@ -187,14 +187,14 @@ Respond in Korean and provide:
|
|
|
187
187
|
}
|
|
188
188
|
case 'gpt_debug': {
|
|
189
189
|
const { code, error, language } = args;
|
|
190
|
-
const sysPrompt = `You are an expert debugger. Analyze the given ${language || 'code'} and identify bugs.
|
|
191
|
-
|
|
192
|
-
${error ? `Error/Symptom: ${error}` : ''}
|
|
193
|
-
|
|
194
|
-
Respond in Korean and provide:
|
|
195
|
-
1. 버그 식별
|
|
196
|
-
2. 원인 분석
|
|
197
|
-
3. 수정된 코드
|
|
190
|
+
const sysPrompt = `You are an expert debugger. Analyze the given ${language || 'code'} and identify bugs.
|
|
191
|
+
|
|
192
|
+
${error ? `Error/Symptom: ${error}` : ''}
|
|
193
|
+
|
|
194
|
+
Respond in Korean and provide:
|
|
195
|
+
1. 버그 식별
|
|
196
|
+
2. 원인 분석
|
|
197
|
+
3. 수정된 코드
|
|
198
198
|
4. 예방 방법`;
|
|
199
199
|
const result = await gptApi.chat({
|
|
200
200
|
model: 'gpt-5.2-codex',
|
package/dist/lib/gpt-oauth.js
CHANGED
|
@@ -196,16 +196,16 @@ export function startOAuthFlow() {
|
|
|
196
196
|
const errorDescription = url.searchParams.get('error_description');
|
|
197
197
|
if (error) {
|
|
198
198
|
res.writeHead(400, { 'Content-Type': 'text/html; charset=utf-8' });
|
|
199
|
-
res.end(`
|
|
200
|
-
<html>
|
|
201
|
-
<head><title>인증 실패</title></head>
|
|
202
|
-
<body style="font-family: sans-serif; text-align: center; padding-top: 50px;">
|
|
203
|
-
<h1>인증 실패</h1>
|
|
204
|
-
<p>오류: ${error}</p>
|
|
205
|
-
<p>${errorDescription || ''}</p>
|
|
206
|
-
<p>이 창을 닫고 다시 시도해주세요.</p>
|
|
207
|
-
</body>
|
|
208
|
-
</html>
|
|
199
|
+
res.end(`
|
|
200
|
+
<html>
|
|
201
|
+
<head><title>인증 실패</title></head>
|
|
202
|
+
<body style="font-family: sans-serif; text-align: center; padding-top: 50px;">
|
|
203
|
+
<h1>인증 실패</h1>
|
|
204
|
+
<p>오류: ${error}</p>
|
|
205
|
+
<p>${errorDescription || ''}</p>
|
|
206
|
+
<p>이 창을 닫고 다시 시도해주세요.</p>
|
|
207
|
+
</body>
|
|
208
|
+
</html>
|
|
209
209
|
`);
|
|
210
210
|
if (!isResolved) {
|
|
211
211
|
isResolved = true;
|
|
@@ -217,14 +217,14 @@ export function startOAuthFlow() {
|
|
|
217
217
|
// state 검증
|
|
218
218
|
if (state !== auth.state) {
|
|
219
219
|
res.writeHead(400, { 'Content-Type': 'text/html; charset=utf-8' });
|
|
220
|
-
res.end(`
|
|
221
|
-
<html>
|
|
222
|
-
<head><title>인증 실패</title></head>
|
|
223
|
-
<body style="font-family: sans-serif; text-align: center; padding-top: 50px;">
|
|
224
|
-
<h1>인증 실패</h1>
|
|
225
|
-
<p>State 불일치 - CSRF 공격 가능성</p>
|
|
226
|
-
</body>
|
|
227
|
-
</html>
|
|
220
|
+
res.end(`
|
|
221
|
+
<html>
|
|
222
|
+
<head><title>인증 실패</title></head>
|
|
223
|
+
<body style="font-family: sans-serif; text-align: center; padding-top: 50px;">
|
|
224
|
+
<h1>인증 실패</h1>
|
|
225
|
+
<p>State 불일치 - CSRF 공격 가능성</p>
|
|
226
|
+
</body>
|
|
227
|
+
</html>
|
|
228
228
|
`);
|
|
229
229
|
if (!isResolved) {
|
|
230
230
|
isResolved = true;
|
|
@@ -235,14 +235,14 @@ export function startOAuthFlow() {
|
|
|
235
235
|
}
|
|
236
236
|
if (!code) {
|
|
237
237
|
res.writeHead(400, { 'Content-Type': 'text/html; charset=utf-8' });
|
|
238
|
-
res.end(`
|
|
239
|
-
<html>
|
|
240
|
-
<head><title>인증 실패</title></head>
|
|
241
|
-
<body style="font-family: sans-serif; text-align: center; padding-top: 50px;">
|
|
242
|
-
<h1>인증 실패</h1>
|
|
243
|
-
<p>Authorization code가 없습니다.</p>
|
|
244
|
-
</body>
|
|
245
|
-
</html>
|
|
238
|
+
res.end(`
|
|
239
|
+
<html>
|
|
240
|
+
<head><title>인증 실패</title></head>
|
|
241
|
+
<body style="font-family: sans-serif; text-align: center; padding-top: 50px;">
|
|
242
|
+
<h1>인증 실패</h1>
|
|
243
|
+
<p>Authorization code가 없습니다.</p>
|
|
244
|
+
</body>
|
|
245
|
+
</html>
|
|
246
246
|
`);
|
|
247
247
|
if (!isResolved) {
|
|
248
248
|
isResolved = true;
|
|
@@ -254,16 +254,16 @@ export function startOAuthFlow() {
|
|
|
254
254
|
try {
|
|
255
255
|
const tokens = await exchangeCodeForTokens(code, auth.verifier);
|
|
256
256
|
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
|
|
257
|
-
res.end(`
|
|
258
|
-
<html>
|
|
259
|
-
<head><title>인증 성공</title></head>
|
|
260
|
-
<body style="font-family: sans-serif; text-align: center; padding-top: 50px;">
|
|
261
|
-
<h1>인증 성공!</h1>
|
|
262
|
-
<p>${tokens.email}로 로그인되었습니다.</p>
|
|
263
|
-
<p>이 창을 닫아도 됩니다.</p>
|
|
264
|
-
<script>setTimeout(() => window.close(), 2000);</script>
|
|
265
|
-
</body>
|
|
266
|
-
</html>
|
|
257
|
+
res.end(`
|
|
258
|
+
<html>
|
|
259
|
+
<head><title>인증 성공</title></head>
|
|
260
|
+
<body style="font-family: sans-serif; text-align: center; padding-top: 50px;">
|
|
261
|
+
<h1>인증 성공!</h1>
|
|
262
|
+
<p>${tokens.email}로 로그인되었습니다.</p>
|
|
263
|
+
<p>이 창을 닫아도 됩니다.</p>
|
|
264
|
+
<script>setTimeout(() => window.close(), 2000);</script>
|
|
265
|
+
</body>
|
|
266
|
+
</html>
|
|
267
267
|
`);
|
|
268
268
|
if (!isResolved) {
|
|
269
269
|
isResolved = true;
|
|
@@ -273,14 +273,14 @@ export function startOAuthFlow() {
|
|
|
273
273
|
}
|
|
274
274
|
catch (err) {
|
|
275
275
|
res.writeHead(500, { 'Content-Type': 'text/html; charset=utf-8' });
|
|
276
|
-
res.end(`
|
|
277
|
-
<html>
|
|
278
|
-
<head><title>인증 실패</title></head>
|
|
279
|
-
<body style="font-family: sans-serif; text-align: center; padding-top: 50px;">
|
|
280
|
-
<h1>인증 실패</h1>
|
|
281
|
-
<p>${err.message}</p>
|
|
282
|
-
</body>
|
|
283
|
-
</html>
|
|
276
|
+
res.end(`
|
|
277
|
+
<html>
|
|
278
|
+
<head><title>인증 실패</title></head>
|
|
279
|
+
<body style="font-family: sans-serif; text-align: center; padding-top: 50px;">
|
|
280
|
+
<h1>인증 실패</h1>
|
|
281
|
+
<p>${err.message}</p>
|
|
282
|
+
</body>
|
|
283
|
+
</html>
|
|
284
284
|
`);
|
|
285
285
|
if (!isResolved) {
|
|
286
286
|
isResolved = true;
|
|
@@ -2,18 +2,18 @@
|
|
|
2
2
|
import { MemoryManager } from '../../lib/MemoryManager.js';
|
|
3
3
|
export const getUsageAnalyticsDefinition = {
|
|
4
4
|
name: 'get_usage_analytics',
|
|
5
|
-
description: `도구 사용 분석 및 통계를 조회합니다.
|
|
6
|
-
|
|
7
|
-
키워드: 분석, 통계, 사용량, analytics, statistics, usage
|
|
8
|
-
|
|
9
|
-
**제공 정보:**
|
|
10
|
-
- 메모리 사용 통계
|
|
11
|
-
- 카테고리별 분포
|
|
12
|
-
- 시간별 사용 패턴
|
|
13
|
-
- 그래프 관계 통계
|
|
14
|
-
|
|
15
|
-
사용 예시:
|
|
16
|
-
- "사용 통계 보여줘"
|
|
5
|
+
description: `도구 사용 분석 및 통계를 조회합니다.
|
|
6
|
+
|
|
7
|
+
키워드: 분석, 통계, 사용량, analytics, statistics, usage
|
|
8
|
+
|
|
9
|
+
**제공 정보:**
|
|
10
|
+
- 메모리 사용 통계
|
|
11
|
+
- 카테고리별 분포
|
|
12
|
+
- 시간별 사용 패턴
|
|
13
|
+
- 그래프 관계 통계
|
|
14
|
+
|
|
15
|
+
사용 예시:
|
|
16
|
+
- "사용 통계 보여줘"
|
|
17
17
|
- "메모리 분석"`,
|
|
18
18
|
inputSchema: {
|
|
19
19
|
type: 'object',
|
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
import { MemoryManager } from '../../lib/MemoryManager.js';
|
|
3
3
|
export const createMemoryTimelineDefinition = {
|
|
4
4
|
name: 'create_memory_timeline',
|
|
5
|
-
description: `메모리 타임라인을 생성합니다.
|
|
6
|
-
|
|
7
|
-
키워드: 타임라인, 시간순, 히스토리, timeline, history, chronological
|
|
8
|
-
|
|
9
|
-
사용 예시:
|
|
10
|
-
- "최근 메모리 타임라인 보여줘"
|
|
5
|
+
description: `메모리 타임라인을 생성합니다.
|
|
6
|
+
|
|
7
|
+
키워드: 타임라인, 시간순, 히스토리, timeline, history, chronological
|
|
8
|
+
|
|
9
|
+
사용 예시:
|
|
10
|
+
- "최근 메모리 타임라인 보여줘"
|
|
11
11
|
- "지난 7일간 메모리 히스토리"`,
|
|
12
12
|
inputSchema: {
|
|
13
13
|
type: 'object',
|
|
@@ -61,10 +61,10 @@ export async function createMemoryTimeline(args) {
|
|
|
61
61
|
return {
|
|
62
62
|
content: [{
|
|
63
63
|
type: 'text',
|
|
64
|
-
text: `✗ 지정된 기간에 메모리가 없습니다.
|
|
65
|
-
|
|
66
|
-
${startDate ? `**시작일**: ${startDate}` : ''}
|
|
67
|
-
${endDate ? `**종료일**: ${endDate}` : ''}
|
|
64
|
+
text: `✗ 지정된 기간에 메모리가 없습니다.
|
|
65
|
+
|
|
66
|
+
${startDate ? `**시작일**: ${startDate}` : ''}
|
|
67
|
+
${endDate ? `**종료일**: ${endDate}` : ''}
|
|
68
68
|
${category ? `**카테고리**: ${category}` : ''}`
|
|
69
69
|
}]
|
|
70
70
|
};
|
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
import { MemoryManager } from '../../lib/MemoryManager.js';
|
|
3
3
|
export const getMemoryGraphDefinition = {
|
|
4
4
|
name: 'get_memory_graph',
|
|
5
|
-
description: `메모리 지식 그래프를 조회합니다.
|
|
6
|
-
|
|
7
|
-
키워드: 그래프, 관계도, 연결 보기, memory graph, relations, connections
|
|
8
|
-
|
|
9
|
-
사용 예시:
|
|
10
|
-
- "project-architecture의 관계 그래프 보여줘"
|
|
5
|
+
description: `메모리 지식 그래프를 조회합니다.
|
|
6
|
+
|
|
7
|
+
키워드: 그래프, 관계도, 연결 보기, memory graph, relations, connections
|
|
8
|
+
|
|
9
|
+
사용 예시:
|
|
10
|
+
- "project-architecture의 관계 그래프 보여줘"
|
|
11
11
|
- "전체 메모리 그래프 조회"`,
|
|
12
12
|
inputSchema: {
|
|
13
13
|
type: 'object',
|
|
@@ -79,12 +79,12 @@ export async function getMemoryGraph(args) {
|
|
|
79
79
|
output = generateTreeFormat(key, graph.nodes, filteredEdges);
|
|
80
80
|
}
|
|
81
81
|
// Add statistics
|
|
82
|
-
const stats = `
|
|
83
|
-
---
|
|
84
|
-
**통계**
|
|
85
|
-
- 노드 수: ${graph.nodes.length}
|
|
86
|
-
- 관계 수: ${filteredEdges.length}
|
|
87
|
-
- 클러스터 수: ${graph.clusters.length}
|
|
82
|
+
const stats = `
|
|
83
|
+
---
|
|
84
|
+
**통계**
|
|
85
|
+
- 노드 수: ${graph.nodes.length}
|
|
86
|
+
- 관계 수: ${filteredEdges.length}
|
|
87
|
+
- 클러스터 수: ${graph.clusters.length}
|
|
88
88
|
${graph.clusters.length > 0 ? `- 클러스터: ${graph.clusters.map(c => `[${c.join(', ')}]`).join(', ')}` : ''}`;
|
|
89
89
|
return {
|
|
90
90
|
content: [{
|