codeep 1.2.0 → 1.2.2
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/renderer/main.js +41 -19
- package/dist/utils/skills.js +23 -3
- package/package.json +1 -1
package/dist/renderer/main.js
CHANGED
|
@@ -501,32 +501,52 @@ async function runSkill(nameOrShortcut, args) {
|
|
|
501
501
|
const params = parseSkillArgs(args.join(' '), skill);
|
|
502
502
|
app.addMessage({ role: 'user', content: `/${skill.name}${args.length ? ' ' + args.join(' ') : ''}` });
|
|
503
503
|
trackSkillUsage(skill.name);
|
|
504
|
-
const {
|
|
504
|
+
const { spawnSync } = await import('child_process');
|
|
505
505
|
try {
|
|
506
506
|
const result = await executeSkill(skill, params, {
|
|
507
507
|
onCommand: async (cmd) => {
|
|
508
|
+
// Use spawnSync via shell for reliable stdout+stderr capture
|
|
509
|
+
const proc = spawnSync(cmd, {
|
|
510
|
+
cwd: projectPath || process.cwd(),
|
|
511
|
+
encoding: 'utf-8',
|
|
512
|
+
timeout: 60000,
|
|
513
|
+
shell: true,
|
|
514
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
515
|
+
});
|
|
516
|
+
const stdout = (proc.stdout || '').trim();
|
|
517
|
+
const stderr = (proc.stderr || '').trim();
|
|
518
|
+
const output = stdout || stderr || '';
|
|
519
|
+
if (proc.status === 0) {
|
|
520
|
+
if (output) {
|
|
521
|
+
app.addMessage({ role: 'system', content: `\`${cmd}\`\n\`\`\`\n${output}\n\`\`\`` });
|
|
522
|
+
}
|
|
523
|
+
return output;
|
|
524
|
+
}
|
|
525
|
+
// Non-zero exit
|
|
526
|
+
if (output) {
|
|
527
|
+
app.addMessage({ role: 'system', content: `\`${cmd}\` failed:\n\`\`\`\n${output}\n\`\`\`` });
|
|
528
|
+
}
|
|
529
|
+
throw new Error(output || `Command exited with code ${proc.status}`);
|
|
530
|
+
},
|
|
531
|
+
onPrompt: async (prompt) => {
|
|
508
532
|
try {
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
533
|
+
app.addMessage({ role: 'user', content: prompt });
|
|
534
|
+
app.startStreaming();
|
|
535
|
+
const history = app.getChatHistory();
|
|
536
|
+
const response = await chat(prompt, history, (chunk) => {
|
|
537
|
+
app.addStreamChunk(chunk);
|
|
538
|
+
}, undefined, projectContext, undefined);
|
|
539
|
+
app.endStreaming();
|
|
540
|
+
// Return the AI response text for use in subsequent steps
|
|
541
|
+
const lastMsg = app.getMessages();
|
|
542
|
+
const assistantMsg = lastMsg[lastMsg.length - 1];
|
|
543
|
+
return (assistantMsg?.role === 'assistant' ? assistantMsg.content : response || '').trim();
|
|
515
544
|
}
|
|
516
545
|
catch (err) {
|
|
517
|
-
|
|
518
|
-
throw
|
|
546
|
+
app.endStreaming();
|
|
547
|
+
throw err;
|
|
519
548
|
}
|
|
520
549
|
},
|
|
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
550
|
onAgent: (task) => {
|
|
531
551
|
return new Promise((resolve, reject) => {
|
|
532
552
|
if (!projectContext) {
|
|
@@ -1369,7 +1389,9 @@ function handleCommand(command, args) {
|
|
|
1369
1389
|
case 'deploy':
|
|
1370
1390
|
case 'release':
|
|
1371
1391
|
case 'publish': {
|
|
1372
|
-
runSkill(command, args)
|
|
1392
|
+
runSkill(command, args).catch((err) => {
|
|
1393
|
+
app.notify(`Skill error: ${err.message}`);
|
|
1394
|
+
});
|
|
1373
1395
|
break;
|
|
1374
1396
|
}
|
|
1375
1397
|
case 'skills': {
|
package/dist/utils/skills.js
CHANGED
|
@@ -20,9 +20,10 @@ const BUILT_IN_SKILLS = [
|
|
|
20
20
|
{ name: 'message', description: 'Optional commit message (skips AI generation)', required: false },
|
|
21
21
|
],
|
|
22
22
|
steps: [
|
|
23
|
-
{ type: '
|
|
23
|
+
{ type: 'command', content: 'git diff --cached --stat || git diff --stat' },
|
|
24
|
+
{ type: 'prompt', content: 'Based on this git diff, generate ONLY a conventional commit message (no explanation, no markdown). Format: type(scope): description. Types: feat, fix, docs, style, refactor, test, chore. Be concise. One line only.\n\n${_prev}' },
|
|
24
25
|
{ type: 'confirm', content: 'Commit with this message?' },
|
|
25
|
-
{ type: 'command', content: 'git add -A && git commit -m "${
|
|
26
|
+
{ type: 'command', content: 'git add -A && git commit -m "${_prev}"' },
|
|
26
27
|
{ type: 'notify', content: 'Changes committed successfully!' },
|
|
27
28
|
],
|
|
28
29
|
},
|
|
@@ -707,6 +708,23 @@ export function parseSkillArgs(args, skill) {
|
|
|
707
708
|
}
|
|
708
709
|
return result;
|
|
709
710
|
}
|
|
711
|
+
/**
|
|
712
|
+
* Sanitize text for safe use inside shell commands.
|
|
713
|
+
* Strips markdown formatting and escapes double quotes.
|
|
714
|
+
*/
|
|
715
|
+
function sanitizeForShell(text) {
|
|
716
|
+
return text
|
|
717
|
+
// Strip markdown code blocks
|
|
718
|
+
.replace(/```[\s\S]*?```/g, '')
|
|
719
|
+
// Strip inline backticks
|
|
720
|
+
.replace(/`([^`]*)`/g, '$1')
|
|
721
|
+
// Strip bold/italic markers
|
|
722
|
+
.replace(/\*{1,3}([^*]+)\*{1,3}/g, '$1')
|
|
723
|
+
// Take only the first non-empty line (commit messages should be one line)
|
|
724
|
+
.split('\n').map(l => l.trim()).filter(Boolean)[0] || text.trim()
|
|
725
|
+
// Escape double quotes for shell safety
|
|
726
|
+
.replace(/"/g, '\\"');
|
|
727
|
+
}
|
|
710
728
|
/**
|
|
711
729
|
* Interpolate parameters into skill step content
|
|
712
730
|
*/
|
|
@@ -778,7 +796,9 @@ export async function executeSkill(skill, params, callbacks) {
|
|
|
778
796
|
let lastOutput = '';
|
|
779
797
|
for (const step of skill.steps) {
|
|
780
798
|
// Interpolate params and ${_prev} into step content
|
|
781
|
-
|
|
799
|
+
// For command steps, sanitize _prev for safe shell usage
|
|
800
|
+
const sanitizedPrev = step.type === 'command' ? sanitizeForShell(lastOutput) : lastOutput;
|
|
801
|
+
const allParams = { ...params, _prev: sanitizedPrev };
|
|
782
802
|
const content = interpolateParams(step.content, allParams);
|
|
783
803
|
try {
|
|
784
804
|
let result = '';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codeep",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.2",
|
|
4
4
|
"description": "AI-powered coding assistant built for the terminal. Multiple LLM providers, project-aware context, and a seamless development workflow.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|