codeep 1.1.35 → 1.2.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.
- package/README.md +90 -4
- package/dist/api/index.js +64 -2
- package/dist/renderer/App.d.ts +5 -10
- package/dist/renderer/App.js +165 -314
- package/dist/renderer/components/Export.d.ts +22 -0
- package/dist/renderer/components/Export.js +64 -0
- package/dist/renderer/components/Help.js +5 -1
- package/dist/renderer/components/Logout.d.ts +29 -0
- package/dist/renderer/components/Logout.js +91 -0
- package/dist/renderer/components/Search.d.ts +30 -0
- package/dist/renderer/components/Search.js +83 -0
- package/dist/renderer/components/Settings.js +20 -0
- package/dist/renderer/components/Status.d.ts +6 -0
- package/dist/renderer/components/Status.js +20 -1
- package/dist/renderer/main.js +296 -156
- package/dist/utils/agent.d.ts +5 -0
- package/dist/utils/agent.js +238 -3
- package/dist/utils/agent.test.d.ts +1 -0
- package/dist/utils/agent.test.js +250 -0
- package/dist/utils/diffPreview.js +104 -35
- package/dist/utils/gitignore.d.ts +24 -0
- package/dist/utils/gitignore.js +161 -0
- package/dist/utils/gitignore.test.d.ts +1 -0
- package/dist/utils/gitignore.test.js +167 -0
- package/dist/utils/skills.d.ts +21 -0
- package/dist/utils/skills.js +51 -0
- package/dist/utils/smartContext.js +8 -0
- package/dist/utils/smartContext.test.d.ts +1 -0
- package/dist/utils/smartContext.test.js +382 -0
- package/dist/utils/tokenTracker.d.ts +52 -0
- package/dist/utils/tokenTracker.js +86 -0
- package/dist/utils/tools.d.ts +16 -0
- package/dist/utils/tools.js +146 -19
- package/dist/utils/tools.test.d.ts +1 -0
- package/dist/utils/tools.test.js +664 -0
- package/package.json +1 -1
package/dist/renderer/main.js
CHANGED
|
@@ -15,12 +15,15 @@ import { config, loadApiKey, loadAllApiKeys, getCurrentProvider, getModelsForCur
|
|
|
15
15
|
import { isProjectDirectory, getProjectContext } from '../utils/project.js';
|
|
16
16
|
import { getCurrentVersion } from '../utils/update.js';
|
|
17
17
|
import { getProviderList } from '../config/providers.js';
|
|
18
|
+
import { getSessionStats } from '../utils/tokenTracker.js';
|
|
18
19
|
// State
|
|
19
20
|
let projectPath = process.cwd();
|
|
20
21
|
let projectContext = null;
|
|
21
22
|
let hasWriteAccess = false;
|
|
22
23
|
let sessionId = getCurrentSessionId();
|
|
23
24
|
let app;
|
|
25
|
+
// Added file context (/add, /drop)
|
|
26
|
+
const addedFiles = new Map();
|
|
24
27
|
/**
|
|
25
28
|
* Get current status
|
|
26
29
|
*/
|
|
@@ -28,6 +31,7 @@ function getStatus() {
|
|
|
28
31
|
const provider = getCurrentProvider();
|
|
29
32
|
const providers = getProviderList();
|
|
30
33
|
const providerInfo = providers.find(p => p.id === provider.id);
|
|
34
|
+
const stats = getSessionStats();
|
|
31
35
|
return {
|
|
32
36
|
version: getCurrentVersion(),
|
|
33
37
|
provider: providerInfo?.name || 'Unknown',
|
|
@@ -37,14 +41,29 @@ function getStatus() {
|
|
|
37
41
|
hasWriteAccess,
|
|
38
42
|
sessionId,
|
|
39
43
|
messageCount: 0, // Will be updated
|
|
44
|
+
tokenStats: {
|
|
45
|
+
totalTokens: stats.totalTokens,
|
|
46
|
+
promptTokens: stats.totalPromptTokens,
|
|
47
|
+
completionTokens: stats.totalCompletionTokens,
|
|
48
|
+
requestCount: stats.requestCount,
|
|
49
|
+
},
|
|
40
50
|
};
|
|
41
51
|
}
|
|
42
52
|
// Agent state
|
|
43
53
|
let isAgentRunning = false;
|
|
44
54
|
let agentAbortController = null;
|
|
45
55
|
/**
|
|
46
|
-
*
|
|
56
|
+
* Format added files as context to prepend to user messages
|
|
47
57
|
*/
|
|
58
|
+
function formatAddedFilesContext() {
|
|
59
|
+
if (addedFiles.size === 0)
|
|
60
|
+
return '';
|
|
61
|
+
const parts = ['[Attached files]'];
|
|
62
|
+
for (const [, file] of addedFiles) {
|
|
63
|
+
parts.push(`\nFile: ${file.relativePath}\n\`\`\`\n${file.content}\n\`\`\``);
|
|
64
|
+
}
|
|
65
|
+
return parts.join('\n') + '\n\n';
|
|
66
|
+
}
|
|
48
67
|
async function handleSubmit(message) {
|
|
49
68
|
// Check if we're waiting for interactive mode answers
|
|
50
69
|
if (pendingInteractiveContext) {
|
|
@@ -112,7 +131,10 @@ async function handleSubmit(message) {
|
|
|
112
131
|
app.startStreaming();
|
|
113
132
|
// Get conversation history for context
|
|
114
133
|
const history = app.getChatHistory();
|
|
115
|
-
|
|
134
|
+
// Prepend added file context if any
|
|
135
|
+
const fileContext = formatAddedFilesContext();
|
|
136
|
+
const enrichedMessage = fileContext ? fileContext + message : message;
|
|
137
|
+
const response = await chat(enrichedMessage, history, (chunk) => {
|
|
116
138
|
app.addStreamChunk(chunk);
|
|
117
139
|
}, undefined, projectContext, undefined);
|
|
118
140
|
app.endStreaming();
|
|
@@ -290,7 +312,10 @@ async function executeAgentTask(task, dryRun = false) {
|
|
|
290
312
|
// Store context in local variable for TypeScript narrowing
|
|
291
313
|
const context = projectContext;
|
|
292
314
|
try {
|
|
293
|
-
|
|
315
|
+
// Enrich task with added file context if any
|
|
316
|
+
const fileContext = formatAddedFilesContext();
|
|
317
|
+
const enrichedTask = fileContext ? fileContext + task : task;
|
|
318
|
+
const result = await runAgent(enrichedTask, context, {
|
|
294
319
|
dryRun,
|
|
295
320
|
onIteration: (iteration) => {
|
|
296
321
|
app.updateAgentProgress(iteration);
|
|
@@ -312,37 +337,64 @@ async function executeAgentTask(task, dryRun = false) {
|
|
|
312
337
|
// Update agent thinking
|
|
313
338
|
const shortTarget = target.length > 50 ? '...' + target.slice(-47) : target;
|
|
314
339
|
app.setAgentThinking(`${actionType}: ${shortTarget}`);
|
|
315
|
-
//
|
|
340
|
+
// Add chat message with diff preview for write/edit operations
|
|
316
341
|
if (actionType === 'write' && tool.parameters.content) {
|
|
317
342
|
const filePath = tool.parameters.path;
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
343
|
+
try {
|
|
344
|
+
const { createFileDiff, formatDiffForDisplay } = require('../utils/diffPreview');
|
|
345
|
+
const diff = createFileDiff(filePath, tool.parameters.content, context.root);
|
|
346
|
+
const diffText = formatDiffForDisplay(diff);
|
|
347
|
+
const additions = diff.hunks.reduce((sum, h) => sum + h.lines.filter((l) => l.type === 'add').length, 0);
|
|
348
|
+
const deletions = diff.hunks.reduce((sum, h) => sum + h.lines.filter((l) => l.type === 'remove').length, 0);
|
|
349
|
+
app.addMessage({
|
|
350
|
+
role: 'system',
|
|
351
|
+
content: `**${diff.type === 'create' ? 'Create' : 'Write'}** \`${filePath}\` (+${additions} -${deletions})\n\n\`\`\`diff\n${diffText}\n\`\`\``,
|
|
352
|
+
});
|
|
353
|
+
}
|
|
354
|
+
catch {
|
|
355
|
+
const ext = filePath.split('.').pop() || '';
|
|
356
|
+
app.addMessage({
|
|
357
|
+
role: 'system',
|
|
358
|
+
content: `**Write** \`${filePath}\`\n\n\`\`\`${ext}\n${tool.parameters.content}\n\`\`\``,
|
|
359
|
+
});
|
|
360
|
+
}
|
|
328
361
|
}
|
|
329
362
|
else if (actionType === 'edit' && tool.parameters.new_text) {
|
|
330
363
|
const filePath = tool.parameters.path;
|
|
331
|
-
|
|
364
|
+
try {
|
|
365
|
+
const { createEditDiff, formatDiffForDisplay } = require('../utils/diffPreview');
|
|
366
|
+
const diff = createEditDiff(filePath, tool.parameters.old_text, tool.parameters.new_text, context.root);
|
|
367
|
+
if (diff) {
|
|
368
|
+
const additions = diff.hunks.reduce((sum, h) => sum + h.lines.filter((l) => l.type === 'add').length, 0);
|
|
369
|
+
const deletions = diff.hunks.reduce((sum, h) => sum + h.lines.filter((l) => l.type === 'remove').length, 0);
|
|
370
|
+
app.addMessage({
|
|
371
|
+
role: 'system',
|
|
372
|
+
content: `**Edit** \`${filePath}\` (+${additions} -${deletions})\n\n\`\`\`diff\n${formatDiffForDisplay(diff)}\n\`\`\``,
|
|
373
|
+
});
|
|
374
|
+
}
|
|
375
|
+
else {
|
|
376
|
+
const ext = filePath.split('.').pop() || '';
|
|
377
|
+
app.addMessage({
|
|
378
|
+
role: 'system',
|
|
379
|
+
content: `**Edit** \`${filePath}\`\n\n\`\`\`${ext}\n${tool.parameters.new_text}\n\`\`\``,
|
|
380
|
+
});
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
catch {
|
|
384
|
+
const ext = filePath.split('.').pop() || '';
|
|
385
|
+
app.addMessage({
|
|
386
|
+
role: 'system',
|
|
387
|
+
content: `**Edit** \`${filePath}\`\n\n\`\`\`${ext}\n${tool.parameters.new_text}\n\`\`\``,
|
|
388
|
+
});
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
else if (actionType === 'delete') {
|
|
392
|
+
const filePath = tool.parameters.path;
|
|
332
393
|
app.addMessage({
|
|
333
394
|
role: 'system',
|
|
334
|
-
content: `**
|
|
335
|
-
});
|
|
336
|
-
app.setAgentCodePreview({
|
|
337
|
-
path: filePath,
|
|
338
|
-
actionType: 'edit',
|
|
339
|
-
content: tool.parameters.new_text,
|
|
340
|
-
oldContent: tool.parameters.old_text,
|
|
395
|
+
content: `**Delete** \`${filePath}\``,
|
|
341
396
|
});
|
|
342
397
|
}
|
|
343
|
-
else {
|
|
344
|
-
app.setAgentCodePreview(null);
|
|
345
|
-
}
|
|
346
398
|
},
|
|
347
399
|
onToolResult: (result, toolCall) => {
|
|
348
400
|
const toolName = toolCall.tool.toLowerCase();
|
|
@@ -374,6 +426,34 @@ async function executeAgentTask(task, dryRun = false) {
|
|
|
374
426
|
const summary = result.finalResponse || `Completed ${result.actions.length} actions in ${result.iterations} steps.`;
|
|
375
427
|
app.addMessage({ role: 'assistant', content: summary });
|
|
376
428
|
app.notify(`Agent completed: ${result.actions.length} actions`);
|
|
429
|
+
// Auto-commit if enabled and there were file changes
|
|
430
|
+
if (!dryRun && config.get('agentAutoCommit') && result.actions.length > 0) {
|
|
431
|
+
try {
|
|
432
|
+
const { autoCommitAgentChanges, createBranchAndCommit } = await import('../utils/git.js');
|
|
433
|
+
const useBranch = config.get('agentAutoCommitBranch');
|
|
434
|
+
if (useBranch) {
|
|
435
|
+
const commitResult = createBranchAndCommit(task, result.actions, context.root);
|
|
436
|
+
if (commitResult.success) {
|
|
437
|
+
app.addMessage({ role: 'system', content: `Auto-committed on branch \`${commitResult.branch}\` (${commitResult.hash?.slice(0, 7)})` });
|
|
438
|
+
}
|
|
439
|
+
else if (commitResult.error !== 'No changes detected by git') {
|
|
440
|
+
app.addMessage({ role: 'system', content: `Auto-commit failed: ${commitResult.error}` });
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
else {
|
|
444
|
+
const commitResult = autoCommitAgentChanges(task, result.actions, context.root);
|
|
445
|
+
if (commitResult.success) {
|
|
446
|
+
app.addMessage({ role: 'system', content: `Auto-committed: ${commitResult.hash?.slice(0, 7)}` });
|
|
447
|
+
}
|
|
448
|
+
else if (commitResult.error !== 'No changes detected by git') {
|
|
449
|
+
app.addMessage({ role: 'system', content: `Auto-commit failed: ${commitResult.error}` });
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
catch {
|
|
454
|
+
// Silently ignore commit errors
|
|
455
|
+
}
|
|
456
|
+
}
|
|
377
457
|
}
|
|
378
458
|
else if (result.aborted) {
|
|
379
459
|
app.addMessage({ role: 'assistant', content: 'Agent stopped by user.' });
|
|
@@ -397,6 +477,91 @@ async function executeAgentTask(task, dryRun = false) {
|
|
|
397
477
|
app.setAgentRunning(false);
|
|
398
478
|
}
|
|
399
479
|
}
|
|
480
|
+
/**
|
|
481
|
+
* Run a skill by name or shortcut with the given args.
|
|
482
|
+
* Wires the skill execution engine to App's UI.
|
|
483
|
+
*/
|
|
484
|
+
async function runSkill(nameOrShortcut, args) {
|
|
485
|
+
const { findSkill, parseSkillArgs, executeSkill, trackSkillUsage } = await import('../utils/skills.js');
|
|
486
|
+
const skill = findSkill(nameOrShortcut);
|
|
487
|
+
if (!skill)
|
|
488
|
+
return false;
|
|
489
|
+
// Pre-flight checks
|
|
490
|
+
if (skill.requiresGit) {
|
|
491
|
+
const { getGitStatus } = await import('../utils/git.js');
|
|
492
|
+
if (!projectPath || !getGitStatus(projectPath).isRepo) {
|
|
493
|
+
app.notify('This skill requires a git repository');
|
|
494
|
+
return true;
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
if (skill.requiresWriteAccess && !hasWriteAccess) {
|
|
498
|
+
app.notify('This skill requires write access. Use /grant first.');
|
|
499
|
+
return true;
|
|
500
|
+
}
|
|
501
|
+
const params = parseSkillArgs(args.join(' '), skill);
|
|
502
|
+
app.addMessage({ role: 'user', content: `/${skill.name}${args.length ? ' ' + args.join(' ') : ''}` });
|
|
503
|
+
trackSkillUsage(skill.name);
|
|
504
|
+
const { execSync } = await import('child_process');
|
|
505
|
+
try {
|
|
506
|
+
const result = await executeSkill(skill, params, {
|
|
507
|
+
onCommand: async (cmd) => {
|
|
508
|
+
try {
|
|
509
|
+
const output = execSync(cmd, {
|
|
510
|
+
cwd: projectPath || process.cwd(),
|
|
511
|
+
encoding: 'utf-8',
|
|
512
|
+
timeout: 60000,
|
|
513
|
+
});
|
|
514
|
+
return output.trim();
|
|
515
|
+
}
|
|
516
|
+
catch (err) {
|
|
517
|
+
const error = err;
|
|
518
|
+
throw new Error(error.stderr || error.message || 'Command failed');
|
|
519
|
+
}
|
|
520
|
+
},
|
|
521
|
+
onPrompt: (prompt) => {
|
|
522
|
+
return new Promise((resolve, reject) => {
|
|
523
|
+
handleSubmit(prompt).then(() => {
|
|
524
|
+
// The AI response will be displayed in chat.
|
|
525
|
+
// We resolve with an empty string since the response is already shown.
|
|
526
|
+
resolve('');
|
|
527
|
+
}).catch(reject);
|
|
528
|
+
});
|
|
529
|
+
},
|
|
530
|
+
onAgent: (task) => {
|
|
531
|
+
return new Promise((resolve, reject) => {
|
|
532
|
+
if (!projectContext) {
|
|
533
|
+
reject(new Error('Agent requires project context'));
|
|
534
|
+
return;
|
|
535
|
+
}
|
|
536
|
+
runAgentTask(task).then(() => resolve('Agent completed')).catch(reject);
|
|
537
|
+
});
|
|
538
|
+
},
|
|
539
|
+
onConfirm: (message) => {
|
|
540
|
+
return new Promise((resolve) => {
|
|
541
|
+
app.showConfirm({
|
|
542
|
+
title: 'Confirm',
|
|
543
|
+
message: [message],
|
|
544
|
+
confirmLabel: 'Yes',
|
|
545
|
+
cancelLabel: 'No',
|
|
546
|
+
onConfirm: () => resolve(true),
|
|
547
|
+
onCancel: () => resolve(false),
|
|
548
|
+
});
|
|
549
|
+
});
|
|
550
|
+
},
|
|
551
|
+
onNotify: (message) => {
|
|
552
|
+
app.notify(message);
|
|
553
|
+
},
|
|
554
|
+
});
|
|
555
|
+
if (!result.success && result.output !== 'Cancelled by user') {
|
|
556
|
+
app.notify(`Skill failed: ${result.output}`);
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
catch (err) {
|
|
560
|
+
app.notify(`Skill error: ${err.message}`);
|
|
561
|
+
trackSkillUsage(skill.name, false);
|
|
562
|
+
}
|
|
563
|
+
return true;
|
|
564
|
+
}
|
|
400
565
|
/**
|
|
401
566
|
* Run a chain of commands sequentially
|
|
402
567
|
*/
|
|
@@ -560,28 +725,6 @@ function handleCommand(command, args) {
|
|
|
560
725
|
});
|
|
561
726
|
break;
|
|
562
727
|
}
|
|
563
|
-
case 'commit': {
|
|
564
|
-
if (!projectContext) {
|
|
565
|
-
app.notify('No project context');
|
|
566
|
-
return;
|
|
567
|
-
}
|
|
568
|
-
import('../utils/git.js').then(({ getGitDiff, getGitStatus, suggestCommitMessage }) => {
|
|
569
|
-
const status = getGitStatus(projectPath);
|
|
570
|
-
if (!status.isRepo) {
|
|
571
|
-
app.notify('Not a git repository');
|
|
572
|
-
return;
|
|
573
|
-
}
|
|
574
|
-
const diff = getGitDiff(true, projectPath);
|
|
575
|
-
if (!diff.success || !diff.diff) {
|
|
576
|
-
app.notify('No staged changes. Use git add first.');
|
|
577
|
-
return;
|
|
578
|
-
}
|
|
579
|
-
const suggestion = suggestCommitMessage(diff.diff);
|
|
580
|
-
app.addMessage({ role: 'user', content: '/commit' });
|
|
581
|
-
handleSubmit(`Generate a commit message for these staged changes. Suggestion: "${suggestion}"\n\nDiff:\n\`\`\`diff\n${diff.diff.slice(0, 2000)}\n\`\`\``);
|
|
582
|
-
});
|
|
583
|
-
break;
|
|
584
|
-
}
|
|
585
728
|
case 'undo': {
|
|
586
729
|
import('../utils/agent.js').then(({ undoLastAction }) => {
|
|
587
730
|
const result = undoLastAction();
|
|
@@ -980,6 +1123,81 @@ function handleCommand(command, args) {
|
|
|
980
1123
|
});
|
|
981
1124
|
break;
|
|
982
1125
|
}
|
|
1126
|
+
// File context commands
|
|
1127
|
+
case 'add': {
|
|
1128
|
+
if (!args.length) {
|
|
1129
|
+
if (addedFiles.size === 0) {
|
|
1130
|
+
app.notify('Usage: /add <file-path> [file2] ... | No files added');
|
|
1131
|
+
}
|
|
1132
|
+
else {
|
|
1133
|
+
const fileList = Array.from(addedFiles.values()).map(f => f.relativePath).join(', ');
|
|
1134
|
+
app.notify(`Added files (${addedFiles.size}): ${fileList}`);
|
|
1135
|
+
}
|
|
1136
|
+
return;
|
|
1137
|
+
}
|
|
1138
|
+
const path = require('path');
|
|
1139
|
+
const fs = require('fs');
|
|
1140
|
+
const root = projectContext?.root || projectPath;
|
|
1141
|
+
let added = 0;
|
|
1142
|
+
const errors = [];
|
|
1143
|
+
for (const filePath of args) {
|
|
1144
|
+
const fullPath = path.isAbsolute(filePath) ? filePath : path.join(root, filePath);
|
|
1145
|
+
const relativePath = path.isAbsolute(filePath) ? path.relative(root, filePath) : filePath;
|
|
1146
|
+
try {
|
|
1147
|
+
const stat = fs.statSync(fullPath);
|
|
1148
|
+
if (!stat.isFile()) {
|
|
1149
|
+
errors.push(`${filePath}: not a file`);
|
|
1150
|
+
continue;
|
|
1151
|
+
}
|
|
1152
|
+
if (stat.size > 100000) {
|
|
1153
|
+
errors.push(`${filePath}: too large (${Math.round(stat.size / 1024)}KB, max 100KB)`);
|
|
1154
|
+
continue;
|
|
1155
|
+
}
|
|
1156
|
+
const content = fs.readFileSync(fullPath, 'utf-8');
|
|
1157
|
+
addedFiles.set(fullPath, { relativePath, content });
|
|
1158
|
+
added++;
|
|
1159
|
+
}
|
|
1160
|
+
catch {
|
|
1161
|
+
errors.push(`${filePath}: file not found`);
|
|
1162
|
+
}
|
|
1163
|
+
}
|
|
1164
|
+
if (added > 0) {
|
|
1165
|
+
app.notify(`Added ${added} file(s) to context (${addedFiles.size} total)`);
|
|
1166
|
+
}
|
|
1167
|
+
if (errors.length > 0) {
|
|
1168
|
+
app.notify(errors.join(', '));
|
|
1169
|
+
}
|
|
1170
|
+
break;
|
|
1171
|
+
}
|
|
1172
|
+
case 'drop': {
|
|
1173
|
+
if (!args.length) {
|
|
1174
|
+
if (addedFiles.size === 0) {
|
|
1175
|
+
app.notify('No files in context');
|
|
1176
|
+
}
|
|
1177
|
+
else {
|
|
1178
|
+
const count = addedFiles.size;
|
|
1179
|
+
addedFiles.clear();
|
|
1180
|
+
app.notify(`Dropped all ${count} file(s) from context`);
|
|
1181
|
+
}
|
|
1182
|
+
return;
|
|
1183
|
+
}
|
|
1184
|
+
const path = require('path');
|
|
1185
|
+
const root = projectContext?.root || projectPath;
|
|
1186
|
+
let dropped = 0;
|
|
1187
|
+
for (const filePath of args) {
|
|
1188
|
+
const fullPath = path.isAbsolute(filePath) ? filePath : path.join(root, filePath);
|
|
1189
|
+
if (addedFiles.delete(fullPath)) {
|
|
1190
|
+
dropped++;
|
|
1191
|
+
}
|
|
1192
|
+
}
|
|
1193
|
+
if (dropped > 0) {
|
|
1194
|
+
app.notify(`Dropped ${dropped} file(s) (${addedFiles.size} remaining)`);
|
|
1195
|
+
}
|
|
1196
|
+
else {
|
|
1197
|
+
app.notify('File not found in context. Use /add to see added files.');
|
|
1198
|
+
}
|
|
1199
|
+
break;
|
|
1200
|
+
}
|
|
983
1201
|
// Agent history and changes
|
|
984
1202
|
case 'history': {
|
|
985
1203
|
import('../utils/agent.js').then(({ getAgentHistory }) => {
|
|
@@ -1121,120 +1339,37 @@ function handleCommand(command, args) {
|
|
|
1121
1339
|
break;
|
|
1122
1340
|
}
|
|
1123
1341
|
// Skills shortcuts
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
case 't': {
|
|
1129
|
-
if (!projectContext) {
|
|
1130
|
-
app.notify('No project context');
|
|
1131
|
-
return;
|
|
1132
|
-
}
|
|
1133
|
-
app.addMessage({ role: 'user', content: '/test' });
|
|
1134
|
-
handleSubmit('Generate and run tests for the current project. Focus on untested code.');
|
|
1135
|
-
break;
|
|
1136
|
-
}
|
|
1137
|
-
case 'd': {
|
|
1138
|
-
if (!projectContext) {
|
|
1139
|
-
app.notify('No project context');
|
|
1140
|
-
return;
|
|
1141
|
-
}
|
|
1142
|
-
app.addMessage({ role: 'user', content: '/docs' });
|
|
1143
|
-
handleSubmit('Add documentation to the code. Focus on functions and classes that lack proper documentation.');
|
|
1144
|
-
break;
|
|
1145
|
-
}
|
|
1146
|
-
case 'r': {
|
|
1147
|
-
if (!projectContext) {
|
|
1148
|
-
app.notify('No project context');
|
|
1149
|
-
return;
|
|
1150
|
-
}
|
|
1151
|
-
app.addMessage({ role: 'user', content: '/refactor' });
|
|
1152
|
-
handleSubmit('Refactor the code to improve quality, readability, and maintainability.');
|
|
1153
|
-
break;
|
|
1154
|
-
}
|
|
1155
|
-
case 'f': {
|
|
1156
|
-
if (!projectContext) {
|
|
1157
|
-
app.notify('No project context');
|
|
1158
|
-
return;
|
|
1159
|
-
}
|
|
1160
|
-
app.addMessage({ role: 'user', content: '/fix' });
|
|
1161
|
-
handleSubmit('Debug and fix any issues in the current code. Look for bugs, errors, and potential problems.');
|
|
1162
|
-
break;
|
|
1163
|
-
}
|
|
1164
|
-
case 'e': {
|
|
1165
|
-
if (!args.length) {
|
|
1166
|
-
app.notify('Usage: /e <file or code to explain>');
|
|
1167
|
-
return;
|
|
1168
|
-
}
|
|
1169
|
-
app.addMessage({ role: 'user', content: `/explain ${args.join(' ')}` });
|
|
1170
|
-
handleSubmit(`Explain this code or concept: ${args.join(' ')}`);
|
|
1171
|
-
break;
|
|
1172
|
-
}
|
|
1173
|
-
case 'o': {
|
|
1174
|
-
if (!projectContext) {
|
|
1175
|
-
app.notify('No project context');
|
|
1176
|
-
return;
|
|
1177
|
-
}
|
|
1178
|
-
app.addMessage({ role: 'user', content: '/optimize' });
|
|
1179
|
-
handleSubmit('Optimize the code for better performance. Focus on efficiency and speed improvements.');
|
|
1180
|
-
break;
|
|
1181
|
-
}
|
|
1182
|
-
case 'b': {
|
|
1183
|
-
if (!projectContext) {
|
|
1184
|
-
app.notify('No project context');
|
|
1185
|
-
return;
|
|
1186
|
-
}
|
|
1187
|
-
app.addMessage({ role: 'user', content: '/debug' });
|
|
1188
|
-
handleSubmit('Help debug the current issue. Analyze the code and identify the root cause of problems.');
|
|
1189
|
-
break;
|
|
1190
|
-
}
|
|
1191
|
-
case 'p': {
|
|
1192
|
-
// Push shortcut
|
|
1193
|
-
import('child_process').then(({ execSync }) => {
|
|
1194
|
-
try {
|
|
1195
|
-
execSync('git push', { cwd: projectPath, encoding: 'utf-8' });
|
|
1196
|
-
app.notify('Pushed successfully');
|
|
1197
|
-
}
|
|
1198
|
-
catch (err) {
|
|
1199
|
-
app.notify(`Push failed: ${err.message}`);
|
|
1200
|
-
}
|
|
1201
|
-
});
|
|
1202
|
-
break;
|
|
1203
|
-
}
|
|
1204
|
-
// Full skill names
|
|
1342
|
+
// Skill shortcuts and full names — delegated to skill execution engine
|
|
1343
|
+
case 'c':
|
|
1344
|
+
case 'commit':
|
|
1345
|
+
case 't':
|
|
1205
1346
|
case 'test':
|
|
1347
|
+
case 'd':
|
|
1206
1348
|
case 'docs':
|
|
1349
|
+
case 'r':
|
|
1207
1350
|
case 'refactor':
|
|
1351
|
+
case 'f':
|
|
1208
1352
|
case 'fix':
|
|
1353
|
+
case 'e':
|
|
1209
1354
|
case 'explain':
|
|
1355
|
+
case 'o':
|
|
1210
1356
|
case 'optimize':
|
|
1211
|
-
case '
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
case '
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
}
|
|
1228
|
-
case 'pull': {
|
|
1229
|
-
import('child_process').then(({ execSync }) => {
|
|
1230
|
-
try {
|
|
1231
|
-
execSync('git pull', { cwd: projectPath, encoding: 'utf-8' });
|
|
1232
|
-
app.notify('Pulled successfully');
|
|
1233
|
-
}
|
|
1234
|
-
catch (err) {
|
|
1235
|
-
app.notify(`Pull failed: ${err.message}`);
|
|
1236
|
-
}
|
|
1237
|
-
});
|
|
1357
|
+
case 'b':
|
|
1358
|
+
case 'debug':
|
|
1359
|
+
case 'p':
|
|
1360
|
+
case 'push':
|
|
1361
|
+
case 'pull':
|
|
1362
|
+
case 'amend':
|
|
1363
|
+
case 'pr':
|
|
1364
|
+
case 'changelog':
|
|
1365
|
+
case 'branch':
|
|
1366
|
+
case 'stash':
|
|
1367
|
+
case 'unstash':
|
|
1368
|
+
case 'build':
|
|
1369
|
+
case 'deploy':
|
|
1370
|
+
case 'release':
|
|
1371
|
+
case 'publish': {
|
|
1372
|
+
runSkill(command, args);
|
|
1238
1373
|
break;
|
|
1239
1374
|
}
|
|
1240
1375
|
case 'skills': {
|
|
@@ -1336,7 +1471,12 @@ function handleCommand(command, args) {
|
|
|
1336
1471
|
break;
|
|
1337
1472
|
}
|
|
1338
1473
|
default:
|
|
1339
|
-
|
|
1474
|
+
// Try to run as a skill (handles custom skills and any built-in not in the switch)
|
|
1475
|
+
runSkill(command, args).then(handled => {
|
|
1476
|
+
if (!handled) {
|
|
1477
|
+
app.notify(`Unknown command: /${command}`);
|
|
1478
|
+
}
|
|
1479
|
+
});
|
|
1340
1480
|
}
|
|
1341
1481
|
}
|
|
1342
1482
|
/**
|
package/dist/utils/agent.d.ts
CHANGED
|
@@ -30,6 +30,11 @@ export interface AgentResult {
|
|
|
30
30
|
error?: string;
|
|
31
31
|
aborted?: boolean;
|
|
32
32
|
}
|
|
33
|
+
/**
|
|
34
|
+
* Load project rules from .codeep/rules.md or CODEEP.md
|
|
35
|
+
* Returns the rules content formatted for system prompt, or empty string if no rules found
|
|
36
|
+
*/
|
|
37
|
+
export declare function loadProjectRules(projectRoot: string): string;
|
|
33
38
|
/**
|
|
34
39
|
* Run the agent loop
|
|
35
40
|
*/
|