claude-code-templates 1.26.4 ā 1.28.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/bin/create-claude-config.js +1 -0
- package/components/sandbox/docker/Dockerfile +38 -0
- package/components/sandbox/docker/README.md +453 -0
- package/components/sandbox/docker/docker-launcher.js +184 -0
- package/components/sandbox/docker/execute.js +251 -0
- package/components/sandbox/docker/package.json +26 -0
- package/package.json +2 -1
- package/src/index.js +294 -24
- package/src/skill-dashboard-web/index.html +326 -0
- package/src/skill-dashboard-web/script.js +445 -0
- package/src/skill-dashboard-web/styles.css +3469 -0
- package/src/skill-dashboard.js +441 -0
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Docker Sandbox Executor
|
|
5
|
+
* Runs inside Docker container using Claude Agent SDK
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { query } from '@anthropic-ai/claude-agent-sdk';
|
|
9
|
+
import fs from 'fs/promises';
|
|
10
|
+
import path from 'path';
|
|
11
|
+
import { spawn } from 'child_process';
|
|
12
|
+
|
|
13
|
+
// Parse command line arguments
|
|
14
|
+
const args = process.argv.slice(2);
|
|
15
|
+
const prompt = args[0] || 'Hello, Claude!';
|
|
16
|
+
const componentsToInstall = args[1] || '';
|
|
17
|
+
const anthropicApiKey = process.env.ANTHROPIC_API_KEY;
|
|
18
|
+
|
|
19
|
+
// Validate API key
|
|
20
|
+
if (!anthropicApiKey) {
|
|
21
|
+
console.error('ā Error: ANTHROPIC_API_KEY environment variable is required');
|
|
22
|
+
process.exit(1);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
console.log('š³ Docker Sandbox Executor');
|
|
26
|
+
console.log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n');
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Install Claude Code components if specified
|
|
30
|
+
*/
|
|
31
|
+
async function installComponents() {
|
|
32
|
+
if (!componentsToInstall || componentsToInstall.trim() === '') {
|
|
33
|
+
return true;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
console.log('š¦ Installing components...');
|
|
37
|
+
console.log(` Components: ${componentsToInstall}\n`);
|
|
38
|
+
|
|
39
|
+
return new Promise((resolve) => {
|
|
40
|
+
const installCmd = `npx claude-code-templates@latest ${componentsToInstall} --yes`;
|
|
41
|
+
|
|
42
|
+
const child = spawn('sh', ['-c', installCmd], {
|
|
43
|
+
stdio: 'inherit',
|
|
44
|
+
env: process.env
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
child.on('close', (code) => {
|
|
48
|
+
if (code === 0) {
|
|
49
|
+
console.log('\nā
Components installed successfully\n');
|
|
50
|
+
resolve(true);
|
|
51
|
+
} else {
|
|
52
|
+
console.log('\nā ļø Component installation had warnings (continuing...)\n');
|
|
53
|
+
resolve(true); // Continue even if installation has warnings
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
child.on('error', (error) => {
|
|
58
|
+
console.error(`ā Installation error: ${error.message}`);
|
|
59
|
+
resolve(false);
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Execute Claude Code query using Agent SDK
|
|
66
|
+
*/
|
|
67
|
+
async function executeQuery() {
|
|
68
|
+
try {
|
|
69
|
+
console.log('š¤ Executing Claude Code...');
|
|
70
|
+
console.log(` Prompt: "${prompt.substring(0, 80)}${prompt.length > 80 ? '...' : ''}"\n`);
|
|
71
|
+
console.log('ā'.repeat(60));
|
|
72
|
+
console.log('š CLAUDE OUTPUT:');
|
|
73
|
+
console.log('ā'.repeat(60) + '\n');
|
|
74
|
+
|
|
75
|
+
// Enhance prompt with working directory context
|
|
76
|
+
const enhancedPrompt = `${prompt}\n\nNote: Your current working directory is /app. When creating files, save them in the current directory (/app) so they can be captured in the output.`;
|
|
77
|
+
|
|
78
|
+
// query() returns an async generator - we need to iterate it
|
|
79
|
+
const generator = query({
|
|
80
|
+
prompt: enhancedPrompt,
|
|
81
|
+
options: {
|
|
82
|
+
apiKey: anthropicApiKey,
|
|
83
|
+
model: 'claude-sonnet-4-5',
|
|
84
|
+
permissionMode: 'bypassPermissions', // Auto-allow all tool uses
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
let assistantResponses = [];
|
|
89
|
+
let messageCount = 0;
|
|
90
|
+
|
|
91
|
+
// Iterate through the async generator
|
|
92
|
+
for await (const message of generator) {
|
|
93
|
+
messageCount++;
|
|
94
|
+
|
|
95
|
+
if (message.type === 'assistant') {
|
|
96
|
+
// Extract text from assistant message content
|
|
97
|
+
if (message.message && message.message.content) {
|
|
98
|
+
const content = Array.isArray(message.message.content)
|
|
99
|
+
? message.message.content
|
|
100
|
+
: [message.message.content];
|
|
101
|
+
|
|
102
|
+
content.forEach(block => {
|
|
103
|
+
if (block.type === 'text') {
|
|
104
|
+
console.log(block.text);
|
|
105
|
+
assistantResponses.push(block.text);
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
} else if (message.type === 'result') {
|
|
110
|
+
// Show final result metadata
|
|
111
|
+
console.log('\n' + 'ā'.repeat(60));
|
|
112
|
+
console.log(`ā
Execution completed (${message.num_turns} turn${message.num_turns > 1 ? 's' : ''})`);
|
|
113
|
+
console.log(` Duration: ${message.duration_ms}ms`);
|
|
114
|
+
console.log(` Cost: $${message.total_cost_usd.toFixed(5)}`);
|
|
115
|
+
console.log('ā'.repeat(60) + '\n');
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Show response summary
|
|
120
|
+
const responseText = assistantResponses.join('\n');
|
|
121
|
+
if (responseText) {
|
|
122
|
+
console.log('š Response Summary:');
|
|
123
|
+
console.log(` ${messageCount} message(s) received`);
|
|
124
|
+
console.log(` ${assistantResponses.length} assistant response(s)`);
|
|
125
|
+
console.log(` ${responseText.length} characters generated`);
|
|
126
|
+
console.log('');
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return true;
|
|
130
|
+
} catch (error) {
|
|
131
|
+
console.error('\nā Execution error:', error.message);
|
|
132
|
+
if (error.stack) {
|
|
133
|
+
console.error('\nStack trace:');
|
|
134
|
+
console.error(error.stack);
|
|
135
|
+
}
|
|
136
|
+
return false;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Find and copy generated files to output directory
|
|
142
|
+
*/
|
|
143
|
+
async function copyGeneratedFiles() {
|
|
144
|
+
try {
|
|
145
|
+
console.log('š Searching for generated files...\n');
|
|
146
|
+
|
|
147
|
+
// Common file extensions to look for
|
|
148
|
+
const extensions = [
|
|
149
|
+
'js', 'jsx', 'ts', 'tsx',
|
|
150
|
+
'py', 'html', 'css', 'scss',
|
|
151
|
+
'json', 'md', 'yaml', 'yml',
|
|
152
|
+
'txt', 'sh', 'bash'
|
|
153
|
+
];
|
|
154
|
+
|
|
155
|
+
// Search for files in multiple directories
|
|
156
|
+
const { execSync } = await import('child_process');
|
|
157
|
+
|
|
158
|
+
const findPattern = extensions.map(ext => `-name "*.${ext}"`).join(' -o ');
|
|
159
|
+
|
|
160
|
+
// Search in /app and /tmp for generated files
|
|
161
|
+
const searchPaths = ['/app', '/tmp'];
|
|
162
|
+
let allFiles = [];
|
|
163
|
+
|
|
164
|
+
for (const searchPath of searchPaths) {
|
|
165
|
+
const findCmd = `find ${searchPath} -type f \\( ${findPattern} \\) ! -path "*/node_modules/*" ! -path "*/.npm/*" ! -path "/app/execute.js" ! -path "/app/package*.json" -newer /app/execute.js 2>/dev/null | head -50`;
|
|
166
|
+
|
|
167
|
+
try {
|
|
168
|
+
const output = execSync(findCmd, { encoding: 'utf8' });
|
|
169
|
+
const files = output.trim().split('\n').filter(f => f.trim());
|
|
170
|
+
allFiles = allFiles.concat(files);
|
|
171
|
+
} catch (error) {
|
|
172
|
+
// Continue to next search path
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
if (allFiles.length === 0) {
|
|
177
|
+
console.log('ā¹ļø No generated files found\n');
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
console.log(`š¦ Found ${allFiles.length} file(s):\n`);
|
|
182
|
+
|
|
183
|
+
// Copy files to output directory preserving structure
|
|
184
|
+
let copiedCount = 0;
|
|
185
|
+
for (const file of allFiles) {
|
|
186
|
+
try {
|
|
187
|
+
// Determine relative path based on source directory
|
|
188
|
+
let relativePath;
|
|
189
|
+
if (file.startsWith('/app/')) {
|
|
190
|
+
relativePath = file.replace('/app/', '');
|
|
191
|
+
} else if (file.startsWith('/tmp/')) {
|
|
192
|
+
relativePath = file.replace('/tmp/', '');
|
|
193
|
+
} else {
|
|
194
|
+
relativePath = path.basename(file);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
const outputPath = path.join('/output', relativePath);
|
|
198
|
+
|
|
199
|
+
// Create directory structure
|
|
200
|
+
await fs.mkdir(path.dirname(outputPath), { recursive: true });
|
|
201
|
+
|
|
202
|
+
// Copy file
|
|
203
|
+
await fs.copyFile(file, outputPath);
|
|
204
|
+
|
|
205
|
+
console.log(` ā
${relativePath}`);
|
|
206
|
+
copiedCount++;
|
|
207
|
+
} catch (error) {
|
|
208
|
+
console.log(` ā ļø Failed to copy: ${file}`);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
if (copiedCount > 0) {
|
|
213
|
+
console.log(`\nā
Copied ${copiedCount} file(s) to output directory\n`);
|
|
214
|
+
}
|
|
215
|
+
} catch (error) {
|
|
216
|
+
console.error('ā Error copying files:', error.message);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Main execution flow
|
|
222
|
+
*/
|
|
223
|
+
async function main() {
|
|
224
|
+
try {
|
|
225
|
+
// Step 1: Install components
|
|
226
|
+
const installSuccess = await installComponents();
|
|
227
|
+
if (!installSuccess) {
|
|
228
|
+
console.error('ā Component installation failed');
|
|
229
|
+
process.exit(1);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// Step 2: Execute Claude query
|
|
233
|
+
const executeSuccess = await executeQuery();
|
|
234
|
+
if (!executeSuccess) {
|
|
235
|
+
console.error('ā Query execution failed');
|
|
236
|
+
process.exit(1);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// Step 3: Copy generated files
|
|
240
|
+
await copyGeneratedFiles();
|
|
241
|
+
|
|
242
|
+
console.log('š Docker sandbox execution completed successfully!');
|
|
243
|
+
process.exit(0);
|
|
244
|
+
} catch (error) {
|
|
245
|
+
console.error('ā Fatal error:', error.message);
|
|
246
|
+
process.exit(1);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// Run main function
|
|
251
|
+
main();
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "claude-code-docker-sandbox",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Docker sandbox for Claude Code execution with Claude Agent SDK",
|
|
5
|
+
"main": "docker-launcher.js",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"build": "docker build -t claude-sandbox .",
|
|
9
|
+
"clean": "docker rmi claude-sandbox || true"
|
|
10
|
+
},
|
|
11
|
+
"dependencies": {
|
|
12
|
+
"@anthropic-ai/claude-agent-sdk": "^0.1.30"
|
|
13
|
+
},
|
|
14
|
+
"engines": {
|
|
15
|
+
"node": ">=18.0.0"
|
|
16
|
+
},
|
|
17
|
+
"keywords": [
|
|
18
|
+
"claude",
|
|
19
|
+
"docker",
|
|
20
|
+
"sandbox",
|
|
21
|
+
"ai",
|
|
22
|
+
"agent"
|
|
23
|
+
],
|
|
24
|
+
"author": "Claude Code Templates",
|
|
25
|
+
"license": "MIT"
|
|
26
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-code-templates",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.28.0",
|
|
4
4
|
"description": "CLI tool to setup Claude Code configurations with framework-specific commands, automation hooks and MCP Servers for your projects",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -94,6 +94,7 @@
|
|
|
94
94
|
"src/",
|
|
95
95
|
"components/sandbox/e2b/",
|
|
96
96
|
"components/sandbox/cloudflare/",
|
|
97
|
+
"components/sandbox/docker/",
|
|
97
98
|
"README.md"
|
|
98
99
|
],
|
|
99
100
|
"devDependencies": {
|