superkit-mcp-server 1.2.5 → 1.2.6
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/build/__tests__/test_apply_prompt_args.js +104 -0
- package/build/index.js +18 -0
- package/package.json +1 -1
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { apply_prompt_args } from '../index.js';
|
|
3
|
+
describe('apply_prompt_args', () => {
|
|
4
|
+
describe('{{args}} substitution', () => {
|
|
5
|
+
it('should replace {{args}} with the provided user args', () => {
|
|
6
|
+
const result = apply_prompt_args('Task: {{args}}', 'Add user authentication');
|
|
7
|
+
expect(result).toBe('Task: Add user authentication');
|
|
8
|
+
});
|
|
9
|
+
it('should replace all occurrences of {{args}}', () => {
|
|
10
|
+
const result = apply_prompt_args('{{args}} and also {{args}}', 'hello');
|
|
11
|
+
expect(result).toBe('hello and also hello');
|
|
12
|
+
});
|
|
13
|
+
it('should replace {{args}} with an empty string when no args are provided', () => {
|
|
14
|
+
const result = apply_prompt_args('Task: {{args}}', '');
|
|
15
|
+
expect(result).toBe('Task: ');
|
|
16
|
+
});
|
|
17
|
+
it('should replace {{args}} with an empty string when args is only whitespace', () => {
|
|
18
|
+
const result = apply_prompt_args('Task: {{args}}', ' ');
|
|
19
|
+
expect(result).toBe('Task: ');
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
describe('{{#if args}} ... {{/if}} block (no else branch)', () => {
|
|
23
|
+
it('should include the block content when args is provided', () => {
|
|
24
|
+
const template = '{{#if args}}Task: {{args}}{{/if}}';
|
|
25
|
+
const result = apply_prompt_args(template, 'Fix bug');
|
|
26
|
+
expect(result).toBe('Task: Fix bug');
|
|
27
|
+
});
|
|
28
|
+
it('should remove the block entirely when args is empty', () => {
|
|
29
|
+
const template = 'Before\n{{#if args}}Task: {{args}}{{/if}}\nAfter';
|
|
30
|
+
const result = apply_prompt_args(template, '');
|
|
31
|
+
expect(result).toBe('Before\n\nAfter');
|
|
32
|
+
});
|
|
33
|
+
it('should remove the block entirely when args is only whitespace', () => {
|
|
34
|
+
const template = '{{#if args}}Task: {{args}}{{/if}}';
|
|
35
|
+
const result = apply_prompt_args(template, ' ');
|
|
36
|
+
expect(result).toBe('');
|
|
37
|
+
});
|
|
38
|
+
it('should handle multiline block content', () => {
|
|
39
|
+
const template = '{{#if args}}\n# Task\n**Input:** {{args}}\n{{/if}}';
|
|
40
|
+
const result = apply_prompt_args(template, 'Do something');
|
|
41
|
+
expect(result).toBe('\n# Task\n**Input:** Do something\n');
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
describe('{{#if args}} ... {{else}} ... {{/if}} block', () => {
|
|
45
|
+
it('should render the if-block when args is provided', () => {
|
|
46
|
+
const template = '{{#if args}}Task: {{args}}{{else}}No task provided.{{/if}}';
|
|
47
|
+
const result = apply_prompt_args(template, 'Add login');
|
|
48
|
+
expect(result).toBe('Task: Add login');
|
|
49
|
+
});
|
|
50
|
+
it('should render the else-block when args is empty', () => {
|
|
51
|
+
const template = '{{#if args}}Task: {{args}}{{else}}No task provided.{{/if}}';
|
|
52
|
+
const result = apply_prompt_args(template, '');
|
|
53
|
+
expect(result).toBe('No task provided.');
|
|
54
|
+
});
|
|
55
|
+
it('should render the else-block when args is only whitespace', () => {
|
|
56
|
+
const template = '{{#if args}}Task: {{args}}{{else}}No task provided.{{/if}}';
|
|
57
|
+
const result = apply_prompt_args(template, ' ');
|
|
58
|
+
expect(result).toBe('No task provided.');
|
|
59
|
+
});
|
|
60
|
+
it('should handle multiline if and else blocks', () => {
|
|
61
|
+
const template = [
|
|
62
|
+
'{{#if args}}',
|
|
63
|
+
'# Running: {{args}}',
|
|
64
|
+
'Execute the task above.',
|
|
65
|
+
'{{else}}',
|
|
66
|
+
'# Usage',
|
|
67
|
+
'Provide a task to run.',
|
|
68
|
+
'{{/if}}',
|
|
69
|
+
].join('\n');
|
|
70
|
+
const with_args = apply_prompt_args(template, 'Build the feature');
|
|
71
|
+
expect(with_args).toContain('# Running: Build the feature');
|
|
72
|
+
expect(with_args).not.toContain('# Usage');
|
|
73
|
+
const without_args = apply_prompt_args(template, '');
|
|
74
|
+
expect(without_args).toContain('# Usage');
|
|
75
|
+
expect(without_args).not.toContain('# Running:');
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
describe('edge cases', () => {
|
|
79
|
+
it('should return the template unchanged when it has no placeholders', () => {
|
|
80
|
+
const template = '# Plan\nThis is a static template.';
|
|
81
|
+
const result = apply_prompt_args(template, 'some args');
|
|
82
|
+
expect(result).toBe(template);
|
|
83
|
+
});
|
|
84
|
+
it('should handle a template with both {{args}} and {{#if args}} blocks', () => {
|
|
85
|
+
const template = [
|
|
86
|
+
'{{#if args}}',
|
|
87
|
+
'**Task:** {{args}}',
|
|
88
|
+
'{{else}}',
|
|
89
|
+
'**Task:** (none)',
|
|
90
|
+
'{{/if}}',
|
|
91
|
+
'',
|
|
92
|
+
'Details: {{args}}',
|
|
93
|
+
].join('\n');
|
|
94
|
+
const result = apply_prompt_args(template, 'Refactor auth');
|
|
95
|
+
expect(result).toContain('**Task:** Refactor auth');
|
|
96
|
+
expect(result).toContain('Details: Refactor auth');
|
|
97
|
+
expect(result).not.toContain('(none)');
|
|
98
|
+
});
|
|
99
|
+
it('should handle empty template string', () => {
|
|
100
|
+
const result = apply_prompt_args('', 'some args');
|
|
101
|
+
expect(result).toBe('');
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
});
|
package/build/index.js
CHANGED
|
@@ -302,6 +302,13 @@ server.setRequestHandler(ListPromptsRequestSchema, async () => {
|
|
|
302
302
|
prompts.push({
|
|
303
303
|
name: file.replace(".toml", ""),
|
|
304
304
|
description: description,
|
|
305
|
+
arguments: [
|
|
306
|
+
{
|
|
307
|
+
name: "args",
|
|
308
|
+
description: "Arguments to pass to the command",
|
|
309
|
+
required: false,
|
|
310
|
+
},
|
|
311
|
+
],
|
|
305
312
|
});
|
|
306
313
|
}
|
|
307
314
|
catch (e) {
|
|
@@ -316,8 +323,18 @@ server.setRequestHandler(ListPromptsRequestSchema, async () => {
|
|
|
316
323
|
return { prompts: [] };
|
|
317
324
|
}
|
|
318
325
|
});
|
|
326
|
+
export function apply_prompt_args(promptText, userArgs) {
|
|
327
|
+
// Substitute {{#if args}} ... {{else}} ... {{/if}} Handlebars blocks
|
|
328
|
+
promptText = promptText.replace(/\{\{#if args\}\}([\s\S]*?)\{\{else\}\}([\s\S]*?)\{\{\/if\}\}/g, (_, ifBlock, elseBlock) => userArgs.trim() ? ifBlock : elseBlock);
|
|
329
|
+
// Substitute {{#if args}} ... {{/if}} blocks (no else branch)
|
|
330
|
+
promptText = promptText.replace(/\{\{#if args\}\}([\s\S]*?)\{\{\/if\}\}/g, (_, ifBlock) => (userArgs.trim() ? ifBlock : ""));
|
|
331
|
+
// Substitute all {{args}} occurrences with the actual user-provided args
|
|
332
|
+
promptText = promptText.replace(/\{\{args\}\}/g, userArgs);
|
|
333
|
+
return promptText;
|
|
334
|
+
}
|
|
319
335
|
server.setRequestHandler(GetPromptRequestSchema, async (request) => {
|
|
320
336
|
const promptName = request.params.name;
|
|
337
|
+
const userArgs = request.params.arguments?.args ?? "";
|
|
321
338
|
const commandFile = `${promptName}.toml`;
|
|
322
339
|
const basePath = path.join(superKitRoot, "commands");
|
|
323
340
|
const safePath = getSafePath(basePath, commandFile);
|
|
@@ -328,6 +345,7 @@ server.setRequestHandler(GetPromptRequestSchema, async (request) => {
|
|
|
328
345
|
const content = await fs.readFile(safePath, "utf-8");
|
|
329
346
|
const parsed = toml.parse(content);
|
|
330
347
|
let promptText = parsed?.prompt || `Execute the ${promptName} command.`;
|
|
348
|
+
promptText = apply_prompt_args(promptText, userArgs);
|
|
331
349
|
// Resolve @{path} includes from super-kit package root
|
|
332
350
|
const includePattern = /@\{([^}]+)\}/g;
|
|
333
351
|
let match;
|