kustom-mc 0.1.2 → 0.1.4

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.
@@ -26,11 +26,9 @@ export const initCommand = new Command('init')
26
26
  process.exit(1);
27
27
  }
28
28
  }
29
- // Create directory structure
29
+ // Create directory structure (all scripts go in scripts/, type determined by __type)
30
30
  const dirs = [
31
31
  'scripts/lib',
32
- 'blocks',
33
- 'items',
34
32
  'textures',
35
33
  'gui',
36
34
  'models',
@@ -68,8 +66,6 @@ export const initCommand = new Command('init')
68
66
  },
69
67
  include: [
70
68
  "scripts/**/*.ts",
71
- "blocks/**/*.ts",
72
- "items/**/*.ts",
73
69
  "dist/types/**/*.d.ts",
74
70
  ".kustom/types/**/*.d.ts",
75
71
  "node_modules/kustom-mc/dist/types/globals.d.ts"
@@ -80,9 +76,7 @@ export const initCommand = new Command('init')
80
76
  // Write kustom.config.json with manifest
81
77
  const kustomConfig = {
82
78
  include: [
83
- "scripts/**/*.ts",
84
- "blocks/**/*.ts",
85
- "items/**/*.ts"
79
+ "scripts/**/*.ts"
86
80
  ],
87
81
  exclude: [
88
82
  "**/*.test.ts",
@@ -103,10 +97,6 @@ export const initCommand = new Command('init')
103
97
  server: {
104
98
  url: "http://localhost:8765"
105
99
  },
106
- deploy: {
107
- target: "../run/plugins/kustom-plugin/packs",
108
- reloadCommand: "/kustom pack reload"
109
- },
110
100
  bundle: {
111
101
  output: `dist/${packId}.zip`,
112
102
  include: [
@@ -127,12 +117,11 @@ export const initCommand = new Command('init')
127
117
  version: "1.0.0",
128
118
  type: "module",
129
119
  scripts: {
120
+ push: "kustom push",
121
+ dev: "kustom push --watch",
130
122
  build: "kustom build",
131
- watch: "kustom build --watch",
132
- deploy: "kustom build --deploy",
133
123
  bundle: "kustom bundle",
134
- validate: "kustom validate",
135
- push: "kustom push"
124
+ validate: "kustom validate"
136
125
  },
137
126
  devDependencies: {
138
127
  "kustom-mc": "^0.1.0",
@@ -194,11 +183,9 @@ dist/
194
183
  ├── kustom.config.json # Pack configuration & manifest
195
184
  ├── tsconfig.json # TypeScript configuration
196
185
  ├── package.json # npm configuration
197
- ├── scripts/ # General scripts
186
+ ├── scripts/ # All scripts (type determined by defineScript/defineBlock/defineItem)
198
187
  │ ├── example.ts # Example script
199
188
  │ └── lib/ # Shared utilities
200
- ├── blocks/ # Block definitions
201
- ├── items/ # Item definitions
202
189
  ├── textures/ # Texture files
203
190
  ├── models/ # Model files
204
191
  ├── sounds/ # Sound files
@@ -208,10 +195,10 @@ dist/
208
195
  console.log(chalk.cyan(` cd ${projectName}`));
209
196
  }
210
197
  console.log(chalk.cyan(' npm install'));
211
- console.log(chalk.cyan(' npm run build'));
198
+ console.log(chalk.cyan(' npm run push'));
212
199
  console.log('\n' + chalk.bold('Available commands:'));
213
- console.log(' npm run build - Compile TypeScript');
214
- console.log(' npm run watch - Watch mode');
215
- console.log(' npm run deploy - Build and deploy to server');
200
+ console.log(' npm run push - Build and push to server');
201
+ console.log(' npm run dev - Watch mode + auto-push');
202
+ console.log(' npm run build - Compile TypeScript only');
216
203
  console.log(' npm run bundle - Create distributable zip');
217
204
  });
@@ -1,6 +1,7 @@
1
1
  import { Command } from 'commander';
2
+ import * as readline from 'readline';
2
3
  import chalk from 'chalk';
3
- import { loadConfig } from '../config.js';
4
+ import { loadConfig, saveConfigServerUrl } from '../config.js';
4
5
  import { saveServerToken, getServerCredential, normalizeServerUrl, listStoredServers, removeServerCredential } from '../credentials.js';
5
6
  /**
6
7
  * Validate a token with the server.
@@ -60,6 +61,7 @@ export const loginCommand = new Command('login')
60
61
  // Determine server URL
61
62
  let serverUrl;
62
63
  let token;
64
+ let serverUrlExplicit = false; // true when user provided the URL as a CLI argument
63
65
  // If only one argument provided, it might be the token (use config for server)
64
66
  if (serverUrlArg && !tokenArg && !serverUrlArg.includes('://') && !serverUrlArg.includes(':')) {
65
67
  // Looks like a token, not a URL
@@ -76,6 +78,7 @@ export const loginCommand = new Command('login')
76
78
  else if (serverUrlArg) {
77
79
  serverUrl = serverUrlArg;
78
80
  token = tokenArg;
81
+ serverUrlExplicit = true;
79
82
  }
80
83
  else {
81
84
  // No arguments - use config
@@ -159,6 +162,29 @@ export const loginCommand = new Command('login')
159
162
  console.log(` Token expires: ${result.expiresAt}`);
160
163
  }
161
164
  console.log(`\nCredentials saved to ~/.kustom/credentials.json`);
165
+ // Offer to update kustom.config.json if the user explicitly provided a server URL
166
+ if (serverUrlExplicit) {
167
+ const config = loadConfig(process.cwd());
168
+ const configServerUrl = config.server?.url ? normalizeServerUrl(config.server.url) : undefined;
169
+ if (configServerUrl !== serverUrl) {
170
+ const rl = readline.createInterface({
171
+ input: process.stdin,
172
+ output: process.stdout
173
+ });
174
+ const answer = await new Promise((resolve) => {
175
+ rl.question(chalk.yellow(`Update server.url in kustom.config.json to ${serverUrl}? [y/N] `), resolve);
176
+ });
177
+ rl.close();
178
+ if (answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes') {
179
+ if (saveConfigServerUrl(process.cwd(), serverUrl)) {
180
+ console.log(chalk.green('Updated server.url in kustom.config.json'));
181
+ }
182
+ else {
183
+ console.log(chalk.yellow('Could not update kustom.config.json (file not found or not writable)'));
184
+ }
185
+ }
186
+ }
187
+ }
162
188
  }
163
189
  catch (error) {
164
190
  console.error(chalk.red(`Login failed: ${error instanceof Error ? error.message : error}`));
@@ -22,32 +22,37 @@ export default defineScript({
22
22
  }
23
23
  });
24
24
  `,
25
- block: `import { defineScript } from 'kustom-mc';
25
+ block: `import { defineBlock } from 'kustom-mc';
26
26
 
27
- export default defineScript({
28
- run({ shaper }) {
29
- shaper.create("{{name}}")
30
- .withModel("kustom:block/{{name}}")
31
- .fullBlockCollision()
32
- .onClick((event) => {
33
- const player = event.player;
34
- player.sendMessage("You clicked {{name}}!");
35
- })
36
- .register();
27
+ export default defineBlock({
28
+ id: "{{name}}",
29
+ model: "kustom:block/{{name}}",
30
+ collision: "full",
31
+ autoPlace: true,
32
+
33
+ onClick(event) {
34
+ event.player.sendMessage("You clicked {{name}}!");
35
+ },
36
+
37
+ onBreak(event) {
38
+ event.player.sendMessage("{{name}} broken!");
39
+ },
40
+
41
+ onPlace(event) {
42
+ event.player.sendMessage("{{name}} placed!");
37
43
  }
38
44
  });
39
45
  `,
40
- item: `import { defineScript } from 'kustom-mc';
46
+ item: `import { defineItem } from 'kustom-mc';
41
47
 
42
- export default defineScript({
43
- run({ items, definition }) {
44
- items.create("{{name}}")
45
- .withModel(definition.model("kustom:item/{{name}}"))
46
- .on("rightClick", (event) => {
47
- const player = event.player;
48
- player.sendMessage("You used {{name}}!");
49
- })
50
- .register();
48
+ export default defineItem({
49
+ id: "{{name}}",
50
+ material: "PAPER",
51
+ model: "kustom:item/{{name}}",
52
+ displayName: "{{name}}",
53
+
54
+ onRightClick(event) {
55
+ event.player.sendMessage("You used {{name}}!");
51
56
  }
52
57
  });
53
58
  `,
@@ -94,10 +99,11 @@ export const newCommand = new Command('new')
94
99
  process.exit(1);
95
100
  }
96
101
  // Determine output directory and file
102
+ // All script types go in scripts/ — type is determined by defineScript/defineBlock/defineItem
97
103
  const dirMap = {
98
104
  script: 'scripts',
99
- block: 'blocks',
100
- item: 'items',
105
+ block: 'scripts',
106
+ item: 'scripts',
101
107
  gui: 'scripts'
102
108
  };
103
109
  const dir = dirMap[type];
@@ -1,9 +1,16 @@
1
1
  import { Command } from 'commander';
2
2
  /**
3
- * Push command - bundle and upload pack to server.
3
+ * Push command build, bundle, and upload pack to server.
4
+ *
5
+ * This is the primary deployment command. It:
6
+ * 1. Builds all TypeScript files
7
+ * 2. Bundles compiled JS + assets into a zip
8
+ * 3. Uploads the zip to the server via HTTP
4
9
  *
5
10
  * Usage:
6
- * npx kustom-mc push # Push to configured server
7
- * npx kustom-mc push --server <url> # Push to specific server
11
+ * kustom push # One-shot build + push
12
+ * kustom push --watch # Watch + auto-push on changes
13
+ * kustom push --server <url> # Push to specific server
14
+ * kustom push --dry-run # Build + bundle, don't upload
8
15
  */
9
16
  export declare const pushCommand: Command;
@@ -2,113 +2,181 @@ import { Command } from 'commander';
2
2
  import * as fs from 'fs';
3
3
  import * as path from 'path';
4
4
  import chalk from 'chalk';
5
- import { glob } from 'glob';
6
- import archiver from 'archiver';
7
- import { loadConfig, generateManifest, validateManifest } from '../config.js';
5
+ import chokidar from 'chokidar';
6
+ import { loadConfig } from '../config.js';
8
7
  import { getServerToken, normalizeServerUrl, getServerCredential } from '../credentials.js';
8
+ import { bundleToBuffer } from '../bundler.js';
9
+ import { uploadPack } from '../upload.js';
10
+ import { buildAll, buildFile } from './build.js';
11
+ import { prepare } from './prepare.js';
12
+ /** Debounce delay in milliseconds before auto-pushing after a change */
13
+ const PUSH_DEBOUNCE_MS = 500;
9
14
  /**
10
- * Create a zip bundle in memory and return as Buffer.
15
+ * Build, bundle, and upload the pack to the server.
16
+ * Returns true on success, false on failure.
11
17
  */
12
- async function createBundle(projectDir) {
13
- const config = loadConfig(projectDir);
14
- // Validate manifest
15
- const errors = validateManifest(config);
16
- if (errors.length > 0) {
17
- throw new Error(`Manifest validation failed:\n ${errors.join('\n ')}`);
18
+ async function doPush(projectDir, serverUrl, token, options) {
19
+ try {
20
+ const { buffer, packId, version, fileCount } = await bundleToBuffer(projectDir);
21
+ const sizeKB = (buffer.length / 1024).toFixed(2);
22
+ if (options.verbose) {
23
+ console.log(` Bundle: ${fileCount} files, ${sizeKB} KB`);
24
+ }
25
+ const result = await uploadPack(serverUrl, token, buffer, packId);
26
+ if (result.success) {
27
+ console.log(chalk.green(` Pushed ${packId} v${version} (${sizeKB} KB)`));
28
+ return true;
29
+ }
30
+ else {
31
+ console.error(chalk.red(` Push failed: ${result.error || 'Unknown error'}`));
32
+ return false;
33
+ }
34
+ }
35
+ catch (error) {
36
+ console.error(chalk.red(` Push failed: ${error instanceof Error ? error.message : error}`));
37
+ return false;
18
38
  }
19
- const packId = config.manifest?.id || 'kustompack';
20
- const version = config.manifest?.version || '1.0.0';
21
- return new Promise((resolve, reject) => {
22
- const chunks = [];
23
- const archive = archiver('zip', { zlib: { level: 9 } });
24
- archive.on('data', (chunk) => chunks.push(chunk));
25
- archive.on('end', () => resolve({
26
- buffer: Buffer.concat(chunks),
27
- packId,
28
- version
29
- }));
30
- archive.on('error', reject);
31
- // Generate and add manifest
32
- const manifestContent = generateManifest(config);
33
- archive.append(manifestContent, { name: 'kustompack.json' });
34
- // Add files based on bundle config
35
- const includePatterns = config.bundle?.include || [
36
- '**/*.js',
37
- 'textures/**/*',
38
- 'gui/**/*',
39
- 'models/**/*',
40
- 'sounds/**/*'
41
- ];
42
- const addFiles = async () => {
43
- const addedFiles = new Set();
44
- for (const pattern of includePatterns) {
45
- const files = await glob(pattern, {
46
- cwd: projectDir,
47
- nodir: true,
48
- ignore: ['node_modules/**', 'dist/**', '*.ts', 'kustompack.json']
49
- });
50
- for (const file of files) {
51
- if (addedFiles.has(file))
52
- continue;
53
- const filePath = path.resolve(projectDir, file);
54
- if (fs.existsSync(filePath)) {
55
- archive.file(filePath, { name: file });
56
- addedFiles.add(file);
57
- }
58
- }
59
- }
60
- archive.finalize();
61
- };
62
- addFiles().catch(reject);
63
- });
64
39
  }
65
40
  /**
66
- * Upload a pack to the server.
67
- *
68
- * Currently sends raw zip bytes for simplicity and performance.
69
- *
70
- * TODO: If a web UI is added later, consider supporting multipart/form-data
71
- * uploads on the server side (Option 2). This would require:
72
- * - Adding multipart parsing to PackRegistryServer.java (Apache Commons FileUpload or manual)
73
- * - Keeping raw zip support for CLI (faster)
74
- * - Adding multipart support for browser uploads
41
+ * Watch mode: rebuild and auto-push on file changes with debounce.
75
42
  */
76
- async function uploadPack(serverUrl, token, buffer, packId) {
77
- const url = `${normalizeServerUrl(serverUrl)}/packs/upload`;
78
- // Send raw zip bytes (faster than multipart, server already supports this)
79
- const response = await fetch(url, {
80
- method: 'POST',
81
- headers: {
82
- 'Authorization': `Bearer ${token}`,
83
- 'Content-Type': 'application/zip',
84
- 'X-Pack-Id': packId // Optional hint for server
85
- },
86
- body: buffer
87
- });
88
- if (response.status === 401) {
89
- throw new Error('Authentication failed. Token may be invalid or expired. Run: npx kustom-mc login');
90
- }
91
- if (response.status === 403) {
92
- throw new Error('Permission denied. You may not have upload permissions.');
93
- }
94
- const result = await response.json();
95
- if (!response.ok) {
96
- throw new Error(result.error || result.message || `Server returned ${response.status}`);
43
+ async function pushWatchMode(config, projectDir, serverUrl, token, options) {
44
+ console.log(chalk.blue('Starting push watch mode...'));
45
+ console.log(` Server: ${serverUrl}`);
46
+ console.log();
47
+ // Initial build
48
+ await buildAll(config, options);
49
+ // Initial push
50
+ console.log('\nPushing initial build...');
51
+ await doPush(projectDir, serverUrl, token, options);
52
+ // Debounce timer
53
+ let pushTimer = null;
54
+ function schedulePush() {
55
+ if (pushTimer)
56
+ clearTimeout(pushTimer);
57
+ pushTimer = setTimeout(async () => {
58
+ pushTimer = null;
59
+ console.log(chalk.gray('\nPushing changes...'));
60
+ await doPush(projectDir, serverUrl, token, options);
61
+ }, PUSH_DEBOUNCE_MS);
97
62
  }
98
- return result;
63
+ // Watch script files
64
+ const patterns = config.include || ['scripts/**/*.ts'];
65
+ const libDirs = config.lib || ['scripts/lib'];
66
+ const scriptWatcher = chokidar.watch(patterns, {
67
+ cwd: projectDir,
68
+ ignoreInitial: true,
69
+ ignored: config.exclude
70
+ });
71
+ const rebuildAndPush = async (changedFile) => {
72
+ const isLibFile = libDirs.some(lib => changedFile.startsWith(lib + '/') || changedFile.startsWith(lib + '\\'));
73
+ if (isLibFile) {
74
+ console.log(`\nLib file changed: ${changedFile}`);
75
+ console.log('Rebuilding all scripts...');
76
+ await buildAll(config, options);
77
+ }
78
+ else {
79
+ console.log(`\nFile changed: ${changedFile}`);
80
+ try {
81
+ const outputPath = await buildFile(changedFile, config, options);
82
+ console.log(` [OK] ${changedFile} -> ${path.relative(projectDir, outputPath)}`);
83
+ }
84
+ catch (error) {
85
+ console.error(` [ERROR] ${changedFile}: ${error instanceof Error ? error.message : error}`);
86
+ return; // Don't push if build failed
87
+ }
88
+ }
89
+ schedulePush();
90
+ };
91
+ scriptWatcher.on('change', rebuildAndPush);
92
+ scriptWatcher.on('add', rebuildAndPush);
93
+ scriptWatcher.on('unlink', (file) => {
94
+ console.log(`\nFile deleted: ${file}`);
95
+ // Delete the compiled output
96
+ const outDir = config.outDir || 'dist';
97
+ const outputPath = path.resolve(projectDir, outDir, file.replace(/\.ts$/, '.js'));
98
+ if (fs.existsSync(outputPath)) {
99
+ fs.unlinkSync(outputPath);
100
+ }
101
+ schedulePush();
102
+ });
103
+ // Watch sounds folder for type regeneration + push
104
+ const soundsWatcher = chokidar.watch('sounds/**/*.ogg', {
105
+ cwd: projectDir,
106
+ ignoreInitial: true
107
+ });
108
+ soundsWatcher.on('add', async (file) => {
109
+ console.log(`\nSound added: ${file}`);
110
+ console.log('Regenerating types...');
111
+ await prepare(projectDir);
112
+ schedulePush();
113
+ });
114
+ soundsWatcher.on('change', () => {
115
+ schedulePush();
116
+ });
117
+ soundsWatcher.on('unlink', async (file) => {
118
+ console.log(`\nSound removed: ${file}`);
119
+ console.log('Regenerating types...');
120
+ await prepare(projectDir);
121
+ schedulePush();
122
+ });
123
+ // Watch asset folders (textures, models, gui, etc.) — push on change
124
+ const assetPatterns = [
125
+ 'textures/**/*',
126
+ 'models/**/*',
127
+ 'gui/**/*',
128
+ 'lang/**/*',
129
+ 'definitions/**/*'
130
+ ];
131
+ const assetsWatcher = chokidar.watch(assetPatterns, {
132
+ cwd: projectDir,
133
+ ignoreInitial: true
134
+ });
135
+ assetsWatcher.on('add', (file) => {
136
+ console.log(`\nAsset added: ${file}`);
137
+ schedulePush();
138
+ });
139
+ assetsWatcher.on('change', (file) => {
140
+ console.log(`\nAsset changed: ${file}`);
141
+ schedulePush();
142
+ });
143
+ assetsWatcher.on('unlink', (file) => {
144
+ console.log(`\nAsset removed: ${file}`);
145
+ schedulePush();
146
+ });
147
+ console.log('\nWatching for changes... (Ctrl+C to stop)');
148
+ // Keep process alive
149
+ process.on('SIGINT', () => {
150
+ console.log('\nStopping push watch mode...');
151
+ if (pushTimer)
152
+ clearTimeout(pushTimer);
153
+ scriptWatcher.close();
154
+ soundsWatcher.close();
155
+ assetsWatcher.close();
156
+ process.exit(0);
157
+ });
99
158
  }
100
159
  /**
101
- * Push command - bundle and upload pack to server.
160
+ * Push command build, bundle, and upload pack to server.
161
+ *
162
+ * This is the primary deployment command. It:
163
+ * 1. Builds all TypeScript files
164
+ * 2. Bundles compiled JS + assets into a zip
165
+ * 3. Uploads the zip to the server via HTTP
102
166
  *
103
167
  * Usage:
104
- * npx kustom-mc push # Push to configured server
105
- * npx kustom-mc push --server <url> # Push to specific server
168
+ * kustom push # One-shot build + push
169
+ * kustom push --watch # Watch + auto-push on changes
170
+ * kustom push --server <url> # Push to specific server
171
+ * kustom push --dry-run # Build + bundle, don't upload
106
172
  */
107
173
  export const pushCommand = new Command('push')
108
- .description('Bundle and upload pack to the connected server')
174
+ .description('Build, bundle, and upload pack to the server')
109
175
  .option('-s, --server <url>', 'Server URL (overrides config)')
110
- .option('--dry-run', 'Create bundle but do not upload')
176
+ .option('-w, --watch', 'Watch for changes and auto-push')
177
+ .option('--dry-run', 'Build and bundle but do not upload')
111
178
  .option('-y, --yes', 'Skip confirmation prompt')
179
+ .option('-v, --verbose', 'Verbose output')
112
180
  .action(async (options) => {
113
181
  const projectDir = process.cwd();
114
182
  const config = loadConfig(projectDir);
@@ -135,22 +203,35 @@ export const pushCommand = new Command('push')
135
203
  process.exit(1);
136
204
  }
137
205
  const cred = getServerCredential(serverUrl);
138
- console.log(chalk.blue('Preparing pack for upload...'));
206
+ // Watch mode
207
+ if (options?.watch) {
208
+ if (!token) {
209
+ console.error(chalk.red('Error: --watch requires authentication'));
210
+ process.exit(1);
211
+ }
212
+ await pushWatchMode(config, projectDir, serverUrl, token, { verbose: options.verbose });
213
+ return;
214
+ }
215
+ // One-shot mode: build → bundle → upload
216
+ console.log(chalk.blue('Building and pushing pack...'));
139
217
  console.log(` Server: ${serverUrl}`);
140
218
  if (cred?.playerName) {
141
219
  console.log(` As: ${cred.playerName}`);
142
220
  }
143
221
  console.log();
144
222
  try {
145
- // Create bundle
223
+ // Build
224
+ await buildAll(config, { verbose: options?.verbose });
225
+ console.log();
226
+ // Bundle
146
227
  console.log('Creating bundle...');
147
- const { buffer, packId, version } = await createBundle(projectDir);
228
+ const { buffer, packId, version, fileCount } = await bundleToBuffer(projectDir);
148
229
  const sizeKB = (buffer.length / 1024).toFixed(2);
149
230
  console.log(chalk.green(` Pack: ${packId} v${version}`));
150
- console.log(chalk.green(` Size: ${sizeKB} KB`));
231
+ console.log(chalk.green(` Size: ${sizeKB} KB (${fileCount} files)`));
232
+ // Dry run — save to disk instead of uploading
151
233
  if (options?.dryRun) {
152
234
  console.log(chalk.yellow('\n--dry-run: Bundle created but not uploaded.'));
153
- // Optionally save the bundle locally
154
235
  const outputPath = path.join(projectDir, 'dist', `${packId}.zip`);
155
236
  const outputDir = path.dirname(outputPath);
156
237
  if (!fs.existsSync(outputDir)) {
@@ -164,7 +245,6 @@ export const pushCommand = new Command('push')
164
245
  if (!options?.yes) {
165
246
  console.log(chalk.yellow(`\nThis will upload ${packId} v${version} to ${serverUrl}`));
166
247
  console.log(chalk.yellow('If a pack with this ID exists, it will be replaced.'));
167
- // Simple confirmation using readline
168
248
  const readline = await import('readline');
169
249
  const rl = readline.createInterface({
170
250
  input: process.stdin,
@@ -183,15 +263,14 @@ export const pushCommand = new Command('push')
183
263
  console.log('\nUploading...');
184
264
  const result = await uploadPack(serverUrl, token, buffer, packId);
185
265
  if (result.success) {
186
- console.log(chalk.green('\nUpload successful!'));
266
+ console.log(chalk.green('\nPush successful!'));
187
267
  if (result.message) {
188
268
  console.log(` ${result.message}`);
189
269
  }
190
- console.log(`\nPack ${packId} v${version} is now available on the server.`);
191
- console.log(chalk.gray('Run /kustom pack reload to apply changes in-game.'));
270
+ console.log(`\nPack ${packId} v${version} is now live on the server.`);
192
271
  }
193
272
  else {
194
- console.error(chalk.red('\nUpload failed'));
273
+ console.error(chalk.red('\nPush failed'));
195
274
  if (result.error) {
196
275
  console.error(chalk.red(` ${result.error}`));
197
276
  }
@@ -30,7 +30,7 @@ export const validateCommand = new Command('validate')
30
30
  }
31
31
  console.log('Validating scripts...');
32
32
  // Find all TypeScript files
33
- const patterns = config.include || ['scripts/**/*.ts', 'blocks/**/*.ts', 'items/**/*.ts'];
33
+ const patterns = config.include || ['scripts/**/*.ts'];
34
34
  const excludePatterns = config.exclude || [];
35
35
  const files = [];
36
36
  for (const pattern of patterns) {
package/dist/config.d.ts CHANGED
@@ -37,10 +37,6 @@ export interface KustomConfig {
37
37
  dependencies?: string[];
38
38
  /** Server connection settings */
39
39
  server?: ServerConfig;
40
- deploy?: {
41
- target?: string;
42
- reloadCommand?: string;
43
- };
44
40
  bundle?: {
45
41
  output?: string;
46
42
  include?: string[];
@@ -84,3 +80,9 @@ export declare function parseCrossPackImport(importPath: string): {
84
80
  * Create a fully qualified namespaced ID.
85
81
  */
86
82
  export declare function createNamespacedId(packId: string, type: string, name: string): string;
83
+ /**
84
+ * Update the server.url in kustom.config.json.
85
+ * Preserves all other config properties.
86
+ * Returns true if the file was updated, false if no config file exists.
87
+ */
88
+ export declare function saveConfigServerUrl(cwd: string, serverUrl: string): boolean;
package/dist/config.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as fs from 'fs';
2
2
  import * as path from 'path';
3
3
  const defaultConfig = {
4
- include: ['scripts/**/*.ts', 'blocks/**/*.ts', 'items/**/*.ts'],
4
+ include: ['scripts/**/*.ts'],
5
5
  exclude: ['**/*.test.ts', '**/*.spec.ts'],
6
6
  outDir: 'dist',
7
7
  lib: ['scripts/lib'],
@@ -15,10 +15,6 @@ const defaultConfig = {
15
15
  server: {
16
16
  url: 'http://localhost:8765'
17
17
  },
18
- deploy: {
19
- target: '../run/plugins/kustom-plugin/packs',
20
- reloadCommand: '/kustom pack reload'
21
- },
22
18
  bundle: {
23
19
  output: 'dist/kustompack.zip',
24
20
  include: ['**/*.js', 'textures/**/*', 'gui/**/*', 'models/**/*', 'sounds/**/*']
@@ -41,7 +37,6 @@ export function loadConfig(cwd) {
41
37
  id: userConfig.manifest?.id || defaultConfig.manifest?.id || 'my-pack'
42
38
  },
43
39
  server: { ...defaultConfig.server, ...userConfig.server },
44
- deploy: { ...defaultConfig.deploy, ...userConfig.deploy },
45
40
  bundle: { ...defaultConfig.bundle, ...userConfig.bundle }
46
41
  };
47
42
  return merged;
@@ -164,3 +159,27 @@ export function parseCrossPackImport(importPath) {
164
159
  export function createNamespacedId(packId, type, name) {
165
160
  return `${packId}:${type}/${name}`;
166
161
  }
162
+ /**
163
+ * Update the server.url in kustom.config.json.
164
+ * Preserves all other config properties.
165
+ * Returns true if the file was updated, false if no config file exists.
166
+ */
167
+ export function saveConfigServerUrl(cwd, serverUrl) {
168
+ const configPath = path.join(cwd, 'kustom.config.json');
169
+ if (!fs.existsSync(configPath)) {
170
+ return false;
171
+ }
172
+ try {
173
+ const content = fs.readFileSync(configPath, 'utf-8');
174
+ const config = JSON.parse(content);
175
+ if (!config.server || typeof config.server !== 'object') {
176
+ config.server = {};
177
+ }
178
+ config.server.url = serverUrl;
179
+ fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + '\n', 'utf-8');
180
+ return true;
181
+ }
182
+ catch {
183
+ return false;
184
+ }
185
+ }