create-max-framework 1.0.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 +29 -0
- package/bin/create-max-framework.js +204 -0
- package/package.json +32 -0
package/README.md
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# create-max-framework
|
|
2
|
+
|
|
3
|
+
Scaffold a new [MAX/MSP Claude Code Framework](https://github.com/taylorbrook/MAX-MSP_CC_Framework) project with a single command.
|
|
4
|
+
|
|
5
|
+
## Usage
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npx create-max-framework my-project
|
|
9
|
+
cd my-project
|
|
10
|
+
claude
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## What it does
|
|
14
|
+
|
|
15
|
+
- Downloads the latest framework release from GitHub
|
|
16
|
+
- Sets up the project directory with all skills, commands, object database, and Python library
|
|
17
|
+
- Initializes a git repository and prints getting-started instructions
|
|
18
|
+
|
|
19
|
+
## Prerequisites
|
|
20
|
+
|
|
21
|
+
- [Node.js](https://nodejs.org/) 16+ (for running this installer)
|
|
22
|
+
- [Claude Code](https://docs.anthropic.com/en/docs/claude-code) (for using the framework)
|
|
23
|
+
- [MAX 9](https://cycling74.com/products/max) (for opening and testing generated patches)
|
|
24
|
+
- [Python 3.10+](https://www.python.org/) (for the validation and editing engine)
|
|
25
|
+
|
|
26
|
+
## Links
|
|
27
|
+
|
|
28
|
+
- [Main repository](https://github.com/taylorbrook/MAX-MSP_CC_Framework)
|
|
29
|
+
- [Technical documentation](https://github.com/taylorbrook/MAX-MSP_CC_Framework/blob/main/TECHNICAL.md)
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
'use strict';
|
|
4
|
+
|
|
5
|
+
const { spawn, execSync } = require('child_process');
|
|
6
|
+
const fs = require('fs');
|
|
7
|
+
const path = require('path');
|
|
8
|
+
const https = require('https');
|
|
9
|
+
|
|
10
|
+
const VERSION = '1.0.0';
|
|
11
|
+
const RELEASE_URL = 'https://github.com/taylorbrook/MAX-MSP_CC_Framework/releases/latest/download/framework.tar.gz';
|
|
12
|
+
const MAX_REDIRECTS = 5;
|
|
13
|
+
|
|
14
|
+
// ---------------------------------------------------------------------------
|
|
15
|
+
// Argument parsing
|
|
16
|
+
// ---------------------------------------------------------------------------
|
|
17
|
+
|
|
18
|
+
const args = process.argv.slice(2);
|
|
19
|
+
|
|
20
|
+
if (args.includes('--version') || args.includes('-v')) {
|
|
21
|
+
console.log(`create-max-framework v${VERSION}`);
|
|
22
|
+
process.exit(0);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (args.includes('--help') || args.includes('-h') || args.length === 0) {
|
|
26
|
+
printUsage();
|
|
27
|
+
process.exit(args.length === 0 ? 1 : 0);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const projectName = args[0];
|
|
31
|
+
|
|
32
|
+
if (projectName.startsWith('-')) {
|
|
33
|
+
console.error(`Error: Unknown flag "${projectName}".`);
|
|
34
|
+
printUsage();
|
|
35
|
+
process.exit(1);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// ---------------------------------------------------------------------------
|
|
39
|
+
// Main
|
|
40
|
+
// ---------------------------------------------------------------------------
|
|
41
|
+
|
|
42
|
+
const targetDir = path.resolve(projectName);
|
|
43
|
+
|
|
44
|
+
if (fs.existsSync(targetDir)) {
|
|
45
|
+
console.error(`Error: Directory '${projectName}' already exists.`);
|
|
46
|
+
process.exit(1);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
console.log(`\nCreating MAX/MSP Claude Code Framework in ${projectName}...\n`);
|
|
50
|
+
|
|
51
|
+
fs.mkdirSync(targetDir, { recursive: true });
|
|
52
|
+
|
|
53
|
+
downloadAndExtract(RELEASE_URL, targetDir)
|
|
54
|
+
.then(() => {
|
|
55
|
+
// Create patches directory and active-project config
|
|
56
|
+
const patchesDir = path.join(targetDir, 'patches');
|
|
57
|
+
if (!fs.existsSync(patchesDir)) {
|
|
58
|
+
fs.mkdirSync(patchesDir, { recursive: true });
|
|
59
|
+
}
|
|
60
|
+
fs.writeFileSync(
|
|
61
|
+
path.join(patchesDir, '.active-project.json'),
|
|
62
|
+
JSON.stringify({ active_project: null }, null, 2) + '\n'
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
// Initialize git repo
|
|
66
|
+
try {
|
|
67
|
+
execSync('git init', { cwd: targetDir, stdio: 'ignore' });
|
|
68
|
+
} catch (_) {
|
|
69
|
+
// git not available -- not critical
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Check Python version
|
|
73
|
+
checkPython();
|
|
74
|
+
|
|
75
|
+
// Success message
|
|
76
|
+
console.log(`Done! Your MAX/MSP Claude Code Framework project is ready.\n`);
|
|
77
|
+
console.log(`Next steps:`);
|
|
78
|
+
console.log(` cd ${projectName}`);
|
|
79
|
+
console.log(` claude`);
|
|
80
|
+
console.log(` /max-new my-first-patch\n`);
|
|
81
|
+
console.log(`Prerequisites:`);
|
|
82
|
+
console.log(` - Claude Code (https://docs.anthropic.com/en/docs/claude-code)`);
|
|
83
|
+
console.log(` - MAX 9 (https://cycling74.com/products/max)`);
|
|
84
|
+
console.log(` - Python 3.10+ (for the validation engine)\n`);
|
|
85
|
+
})
|
|
86
|
+
.catch((err) => {
|
|
87
|
+
console.error(`\nError: ${err.message || err}`);
|
|
88
|
+
// Clean up partial directory
|
|
89
|
+
try {
|
|
90
|
+
fs.rmSync(targetDir, { recursive: true, force: true });
|
|
91
|
+
} catch (_) {
|
|
92
|
+
// best effort cleanup
|
|
93
|
+
}
|
|
94
|
+
process.exit(1);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
// ---------------------------------------------------------------------------
|
|
98
|
+
// Helpers
|
|
99
|
+
// ---------------------------------------------------------------------------
|
|
100
|
+
|
|
101
|
+
function printUsage() {
|
|
102
|
+
console.log(`
|
|
103
|
+
Usage: npx create-max-framework <project-name>
|
|
104
|
+
|
|
105
|
+
Create a new MAX/MSP Claude Code Framework project.
|
|
106
|
+
|
|
107
|
+
Options:
|
|
108
|
+
-h, --help Show this help message
|
|
109
|
+
-v, --version Show version number
|
|
110
|
+
|
|
111
|
+
Examples:
|
|
112
|
+
npx create-max-framework my-synth
|
|
113
|
+
npx create-max-framework granular-sampler
|
|
114
|
+
`);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Download a URL, following up to MAX_REDIRECTS redirects,
|
|
119
|
+
* and pipe the response into tar to extract into targetDir.
|
|
120
|
+
*/
|
|
121
|
+
function downloadAndExtract(url, dir) {
|
|
122
|
+
return new Promise((resolve, reject) => {
|
|
123
|
+
followRedirects(url, 0, (err, response) => {
|
|
124
|
+
if (err) return reject(err);
|
|
125
|
+
|
|
126
|
+
if (response.statusCode !== 200) {
|
|
127
|
+
response.resume(); // consume response to free memory
|
|
128
|
+
return reject(new Error(`Download failed with status ${response.statusCode}`));
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const tar = spawn('tar', ['xz', '--strip-components=1', '-C', dir], {
|
|
132
|
+
stdio: ['pipe', 'inherit', 'pipe']
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
let tarStderr = '';
|
|
136
|
+
tar.stderr.on('data', (chunk) => { tarStderr += chunk.toString(); });
|
|
137
|
+
|
|
138
|
+
tar.on('close', (code) => {
|
|
139
|
+
if (code !== 0) {
|
|
140
|
+
return reject(new Error(`tar extraction failed (exit ${code}): ${tarStderr.trim()}`));
|
|
141
|
+
}
|
|
142
|
+
resolve();
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
tar.on('error', (spawnErr) => {
|
|
146
|
+
reject(new Error(`Failed to spawn tar: ${spawnErr.message}`));
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
response.pipe(tar.stdin);
|
|
150
|
+
|
|
151
|
+
response.on('error', (dlErr) => {
|
|
152
|
+
tar.kill();
|
|
153
|
+
reject(new Error(`Download error: ${dlErr.message}`));
|
|
154
|
+
});
|
|
155
|
+
});
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Follow HTTP(S) redirects up to maxRedirects.
|
|
161
|
+
*/
|
|
162
|
+
function followRedirects(url, count, callback) {
|
|
163
|
+
if (count >= MAX_REDIRECTS) {
|
|
164
|
+
return callback(new Error('Too many redirects'));
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const protocol = url.startsWith('https') ? https : require('http');
|
|
168
|
+
|
|
169
|
+
protocol.get(url, (response) => {
|
|
170
|
+
const status = response.statusCode;
|
|
171
|
+
|
|
172
|
+
if (status === 301 || status === 302 || status === 303 || status === 307 || status === 308) {
|
|
173
|
+
const location = response.headers.location;
|
|
174
|
+
if (!location) {
|
|
175
|
+
return callback(new Error('Redirect with no Location header'));
|
|
176
|
+
}
|
|
177
|
+
response.resume(); // discard body
|
|
178
|
+
return followRedirects(location, count + 1, callback);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
callback(null, response);
|
|
182
|
+
}).on('error', (err) => {
|
|
183
|
+
callback(err);
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Check for Python 3.10+ and warn if missing or too old.
|
|
189
|
+
*/
|
|
190
|
+
function checkPython() {
|
|
191
|
+
try {
|
|
192
|
+
const pyVersion = execSync('python3 --version', { encoding: 'utf8' }).trim();
|
|
193
|
+
const match = pyVersion.match(/Python\s+(\d+)\.(\d+)/);
|
|
194
|
+
if (match) {
|
|
195
|
+
const major = parseInt(match[1], 10);
|
|
196
|
+
const minor = parseInt(match[2], 10);
|
|
197
|
+
if (major < 3 || (major === 3 && minor < 10)) {
|
|
198
|
+
console.warn(`WARNING: Python 3.10+ required. Found: ${pyVersion}`);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
} catch (_) {
|
|
202
|
+
console.warn('WARNING: Python 3 not found. The framework requires Python 3.10+ for the validation engine.');
|
|
203
|
+
}
|
|
204
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "create-max-framework",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Create a MAX/MSP Claude Code Framework project",
|
|
5
|
+
"bin": {
|
|
6
|
+
"create-max-framework": "bin/create-max-framework.js"
|
|
7
|
+
},
|
|
8
|
+
"files": [
|
|
9
|
+
"bin/",
|
|
10
|
+
"README.md"
|
|
11
|
+
],
|
|
12
|
+
"keywords": [
|
|
13
|
+
"max",
|
|
14
|
+
"msp",
|
|
15
|
+
"maxmsp",
|
|
16
|
+
"claude",
|
|
17
|
+
"claude-code",
|
|
18
|
+
"audio",
|
|
19
|
+
"music",
|
|
20
|
+
"dsp"
|
|
21
|
+
],
|
|
22
|
+
"author": "Taylor Brook",
|
|
23
|
+
"license": "MIT",
|
|
24
|
+
"engines": {
|
|
25
|
+
"node": ">=16.0.0"
|
|
26
|
+
},
|
|
27
|
+
"repository": {
|
|
28
|
+
"type": "git",
|
|
29
|
+
"url": "git+https://github.com/taylorbrook/MAX-MSP_CC_Framework.git",
|
|
30
|
+
"directory": "installer"
|
|
31
|
+
}
|
|
32
|
+
}
|