godot-kit 1.0.0 → 1.0.1772990785

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.
@@ -10,6 +10,8 @@ jobs:
10
10
  runs-on: ubuntu-latest
11
11
  steps:
12
12
  - uses: actions/checkout@v4
13
+ with:
14
+ token: ${{ secrets.GITHUB_TOKEN }}
13
15
 
14
16
  - uses: actions/setup-node@v4
15
17
  with:
@@ -18,6 +20,25 @@ jobs:
18
20
 
19
21
  - run: npm ci --ignore-scripts
20
22
 
23
+ - name: Bump version to 1.0.<timestamp>
24
+ run: |
25
+ TS=$(date +%s)
26
+ node -e "
27
+ const fs = require('fs');
28
+ const p = JSON.parse(fs.readFileSync('package.json', 'utf8'));
29
+ p.version = '1.0.' + process.argv[1];
30
+ fs.writeFileSync('package.json', JSON.stringify(p, null, 2) + '\n');
31
+ console.log('Version bumped to', p.version);
32
+ " $TS
33
+
34
+ - name: Commit version bump
35
+ run: |
36
+ git config user.name "github-actions[bot]"
37
+ git config user.email "github-actions[bot]@users.noreply.github.com"
38
+ git add package.json
39
+ git commit -m "chore: bump version [skip ci]" || echo "nothing to commit"
40
+ git push || echo "push skipped"
41
+
21
42
  - run: npm publish --access public
22
43
  env:
23
44
  NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
package/README.md CHANGED
@@ -8,11 +8,14 @@ Agentic Godot 4.x development boilerplate. Single command setup, REPL/CLI debugg
8
8
  # Create a new Godot project
9
9
  npx godot-kit my-game
10
10
 
11
+ # Download Godot 4.6 automatically
12
+ godot-dev download-engine
13
+
11
14
  # Install gdtoolkit
12
15
  godot-dev setup
13
16
 
14
17
  # Launch Godot with remote debugger
15
- godot-dev launch --godot /path/to/godot4
18
+ godot-dev launch
16
19
 
17
20
  # Connect interactive REPL
18
21
  godot-dev repl
@@ -41,15 +44,36 @@ my-game/
41
44
  ## CLI Commands
42
45
 
43
46
  ```bash
44
- godot-dev repl # Interactive debugger REPL
45
- godot-dev inspect # Dump scene tree (one-shot)
46
- godot-dev logs # Stream Godot output logs
47
- godot-dev lint [files] # Run gdlint
48
- godot-dev format [files] # Run gdformat
49
- godot-dev launch [scene] # Launch Godot with debugger
50
- godot-dev setup # Install gdtoolkit
47
+ godot-dev repl # Interactive debugger REPL
48
+ godot-dev inspect # Dump scene tree (one-shot)
49
+ godot-dev logs # Stream Godot output logs
50
+ godot-dev lint [files] # Run gdlint
51
+ godot-dev format [files] # Run gdformat
52
+ godot-dev launch [scene] # Launch Godot with debugger
53
+ godot-dev setup # Install gdtoolkit (requires Python)
54
+ godot-dev download-engine # Download Godot 4.6 for current platform
55
+ ```
56
+
57
+ ## Godot Engine Auto-Download
58
+
59
+ `godot-dev download-engine` downloads Godot 4.6-stable from the official GitHub releases:
60
+
61
+ - **Windows**: downloads `Godot_v4.6-stable_win64.exe.zip`, extracts `.exe`
62
+ - **Linux**: downloads `Godot_v4.6-stable_linux.x86_64.zip`, extracts binary, `chmod +x`
63
+ - **macOS**: downloads `Godot_v4.6-stable_macos.universal.zip`
64
+
65
+ The engine is saved to `~/.godot-kit/godot[.exe]` and the path is stored in `~/.godot-kit/config.json`. The `launch` command reads this config automatically — no `--godot` flag needed after downloading.
66
+
67
+ ```bash
68
+ # Download once
69
+ godot-dev download-engine
70
+
71
+ # Launch uses ~/.godot-kit/config.json automatically
72
+ godot-dev launch
51
73
  ```
52
74
 
75
+ When scaffolding a new project with `npx godot-kit`, it will detect whether Godot is installed and prompt you to run `godot-dev download-engine` if not found.
76
+
53
77
  ## REPL Commands
54
78
 
55
79
  | Command | Description |
package/bin/cli.js CHANGED
@@ -6,6 +6,7 @@ const { GodotDebuggerClient } = require('../lib/debugger-client');
6
6
  const { parseSceneNode, formatSceneTree } = require('../lib/scene-tree');
7
7
  const { startRepl } = require('../lib/repl-commands');
8
8
  const { execSync, spawn } = require('child_process');
9
+ const { findGodot, downloadEngine, GODOT_VERSION } = require('../lib/engine');
9
10
 
10
11
  const program = new Command();
11
12
  program.name('godot-dev').description('Agentic Godot 4.x CLI - REPL, debugger, inspector, profiler').version('1.0.0');
@@ -29,11 +30,7 @@ async function connectOrDie(client) {
29
30
  program.command('repl').description('Interactive REPL connected to running Godot debugger')
30
31
  .option('-h, --host <host>', 'Godot host', '127.0.0.1')
31
32
  .option('-p, --port <port>', 'Debugger port', '6007')
32
- .action(async (opts) => {
33
- const client = makeClient(opts);
34
- await connectOrDie(client);
35
- startRepl(client);
36
- });
33
+ .action(async (opts) => { const c = makeClient(opts); await connectOrDie(c); startRepl(c); });
37
34
 
38
35
  program.command('inspect').description('Dump scene tree from running Godot game (one-shot)')
39
36
  .option('-h, --host <host>', 'Godot host', '127.0.0.1')
@@ -76,6 +73,9 @@ program.command('lint [files...]').description('Lint GDScript files using gdtool
76
73
  if (r) console.log(r);
77
74
  console.log('\x1b[32mLint passed.\x1b[0m');
78
75
  } catch (e) {
76
+ if (e.code === 'ENOENT' || (e.stderr && (e.stderr.includes('not found') || e.stderr.includes('not recognized')))) {
77
+ console.log('gdlint not found. Run: godot-dev setup'); return;
78
+ }
79
79
  if (e.stdout) process.stdout.write(e.stdout);
80
80
  if (e.stderr) process.stderr.write(e.stderr);
81
81
  process.exit(e.status || 1);
@@ -86,12 +86,14 @@ program.command('format [files...]').description('Format GDScript files using gd
86
86
  .option('--check', 'Check only, do not write')
87
87
  .action((files, opts) => {
88
88
  const targets = files.length ? files : ['.'];
89
- const args = ['gdformat', ...(opts.check ? ['--check'] : []), ...targets];
90
89
  try {
91
- const r = execSync(args.join(' '), { stdio: 'pipe', encoding: 'utf8' });
90
+ const r = execSync(['gdformat', ...(opts.check ? ['--check'] : []), ...targets].join(' '), { stdio: 'pipe', encoding: 'utf8' });
92
91
  if (r) console.log(r);
93
92
  console.log('\x1b[32mFormat complete.\x1b[0m');
94
93
  } catch (e) {
94
+ if (e.code === 'ENOENT' || (e.stderr && (e.stderr.includes('not found') || e.stderr.includes('not recognized')))) {
95
+ console.log('gdformat not found. Run: godot-dev setup'); return;
96
+ }
95
97
  if (e.stdout) process.stdout.write(e.stdout);
96
98
  if (e.stderr) process.stderr.write(e.stderr);
97
99
  process.exit(e.status || 1);
@@ -106,25 +108,32 @@ program.command('launch [scene]').description('Launch Godot with remote debugger
106
108
  .option('--debug-collisions', 'Show collision shapes')
107
109
  .option('--debug-navigation', 'Show navigation')
108
110
  .action((scene, opts) => {
111
+ const godot = findGodot(opts.godot);
112
+ if (!godot) {
113
+ console.error('Godot executable not found. Run: godot-dev download-engine');
114
+ process.exit(1);
115
+ }
109
116
  const args = ['--path', opts.project, '--remote-debug', `tcp://127.0.0.1:${opts.port}`, '--verbose'];
110
117
  if (opts.profiling) args.push('--profiling');
111
118
  if (opts.debugCollisions) args.push('--debug-collisions');
112
119
  if (opts.debugNavigation) args.push('--debug-navigation');
113
120
  if (scene) args.push(scene);
114
- console.log(`Launching: ${opts.godot} ${args.join(' ')}`);
115
- const proc = spawn(opts.godot, args, { stdio: 'inherit' });
121
+ console.log(`Launching: ${godot} ${args.join(' ')}`);
122
+ const proc = spawn(godot, args, { stdio: 'inherit' });
116
123
  proc.on('exit', (code) => process.exit(code || 0));
117
124
  });
118
125
 
119
126
  program.command('setup').description('Install gdtoolkit for GDScript linting/formatting')
120
127
  .action(() => {
121
128
  console.log('Installing gdtoolkit for Godot 4.x...');
122
- const cmds = ['pip install --upgrade "gdtoolkit==4.*"', 'pip3 install --upgrade "gdtoolkit==4.*"'];
123
- for (const cmd of cmds) {
129
+ for (const cmd of ['pip install --upgrade "gdtoolkit==4.*"', 'pip3 install --upgrade "gdtoolkit==4.*"']) {
124
130
  try { execSync(cmd, { stdio: 'inherit' }); console.log('\x1b[32mgdtoolkit installed.\x1b[0m'); return; }
125
131
  catch (e) { continue; }
126
132
  }
127
133
  console.error('Failed. Install Python and pip first.'); process.exit(1);
128
134
  });
129
135
 
136
+ program.command('download-engine').description(`Download Godot ${GODOT_VERSION} for current platform`)
137
+ .action(async () => { await downloadEngine(); });
138
+
130
139
  program.parse(process.argv);
package/bin/create.js CHANGED
@@ -4,6 +4,7 @@
4
4
  const fs = require('fs');
5
5
  const path = require('path');
6
6
  const getTemplates = require('../lib/templates');
7
+ const { findGodot, GODOT_VERSION } = require('../lib/engine');
7
8
 
8
9
  const targetDir = process.argv[2] ? path.resolve(process.argv[2]) : (process.env.INIT_CWD || process.cwd());
9
10
  const projectName = path.basename(targetDir);
@@ -29,17 +30,19 @@ Scaffolded by [godot-kit](https://github.com/AnEntrypoint/godot-kit).
29
30
  ## Setup
30
31
  \`\`\`bash
31
32
  npm install -g godot-kit
33
+ godot-dev download-engine
32
34
  godot-dev setup
33
35
  \`\`\`
34
36
 
35
37
  ## Commands
36
38
  \`\`\`bash
37
- godot-dev launch --godot /path/to/godot4 # Launch with debugger
39
+ godot-dev launch # Launch with debugger
38
40
  godot-dev repl # Interactive REPL
39
41
  godot-dev inspect # Dump scene tree
40
42
  godot-dev logs # Stream logs
41
43
  godot-dev lint # GDScript lint
42
44
  godot-dev format # GDScript format
45
+ godot-dev download-engine # Download Godot ${GODOT_VERSION}
43
46
  \`\`\`
44
47
 
45
48
  ## REPL Commands
@@ -56,14 +59,24 @@ godot-dev format # GDScript format
56
59
  fs.writeFileSync(path.join(targetDir, 'README.md'), readme, 'utf8');
57
60
  console.log(` + README.md`);
58
61
 
62
+ const godotPath = findGodot(null);
63
+ if (!godotPath) {
64
+ console.log(`
65
+ Godot not found. Download it with:
66
+
67
+ godot-dev download-engine
68
+ `);
69
+ } else {
70
+ console.log(`\n Godot found at: ${godotPath}`);
71
+ }
72
+
59
73
  console.log(`
60
74
  Done! Next steps:
61
75
 
62
- 1. Open project in Godot 4.x editor
76
+ 1. Download engine: godot-dev download-engine
63
77
  2. Install gdtoolkit: godot-dev setup
64
- 3. Launch with debugger: godot-dev launch --godot /path/to/godot4
78
+ 3. Launch with debugger: godot-dev launch
65
79
  4. Connect REPL: godot-dev repl
66
- 5. Inspect scene tree: godot-dev inspect
67
80
 
68
81
  VSCode: Install "Godot Tools" extension, use F5 to debug.
69
82
  Docs: https://github.com/AnEntrypoint/godot-kit
package/lib/engine.js ADDED
@@ -0,0 +1,99 @@
1
+ 'use strict';
2
+
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+ const https = require('https');
6
+ const os = require('os');
7
+ const { execSync } = require('child_process');
8
+
9
+ const GODOT_VERSION = '4.6-stable';
10
+ const CFG_DIR = path.join(os.homedir(), '.godot-kit');
11
+ const CFG_PATH = path.join(CFG_DIR, 'config.json');
12
+ const PLATFORM_ASSETS = {
13
+ win32: `Godot_v${GODOT_VERSION}_win64.exe.zip`,
14
+ linux: `Godot_v${GODOT_VERSION}_linux.x86_64.zip`,
15
+ darwin: `Godot_v${GODOT_VERSION}_macos.universal.zip`
16
+ };
17
+
18
+ function readConfig() {
19
+ try { return JSON.parse(fs.readFileSync(CFG_PATH, 'utf8')); } catch { return {}; }
20
+ }
21
+
22
+ function writeConfig(cfg) {
23
+ fs.mkdirSync(CFG_DIR, { recursive: true });
24
+ fs.writeFileSync(CFG_PATH, JSON.stringify(cfg, null, 2), 'utf8');
25
+ }
26
+
27
+ function findGodot(explicitPath) {
28
+ if (explicitPath && explicitPath !== 'godot') return explicitPath;
29
+ const cfg = readConfig();
30
+ if (cfg.godotPath && fs.existsSync(cfg.godotPath)) return cfg.godotPath;
31
+ const exeName = process.platform === 'win32' ? 'godot.exe' : 'godot';
32
+ const p = path.join(CFG_DIR, exeName);
33
+ if (fs.existsSync(p)) return p;
34
+ try { execSync('godot --version', { stdio: 'pipe' }); return 'godot'; } catch {}
35
+ try { execSync('godot4 --version', { stdio: 'pipe' }); return 'godot4'; } catch {}
36
+ return null;
37
+ }
38
+
39
+ function followRedirect(url, cb, depth = 0) {
40
+ if (depth > 10) return cb(new Error('Too many redirects'), null);
41
+ const u = new URL(url);
42
+ https.get({ hostname: u.hostname, path: u.pathname + (u.search || ''), headers: { 'User-Agent': 'godot-kit/1.0' } }, (res) => {
43
+ if ([301, 302, 303, 307, 308].includes(res.statusCode) && res.headers.location) {
44
+ res.destroy();
45
+ const loc = res.headers.location.startsWith('http') ? res.headers.location : `https://${u.hostname}${res.headers.location}`;
46
+ followRedirect(loc, cb, depth + 1);
47
+ } else cb(null, res);
48
+ }).on('error', e => cb(e, null));
49
+ }
50
+
51
+ async function downloadEngine() {
52
+ const assetFile = PLATFORM_ASSETS[process.platform];
53
+ if (!assetFile) throw new Error(`Unsupported platform: ${process.platform}`);
54
+ const url = `https://github.com/godotengine/godot/releases/download/${GODOT_VERSION}/${assetFile}`;
55
+ const zipPath = path.join(CFG_DIR, assetFile);
56
+ fs.mkdirSync(CFG_DIR, { recursive: true });
57
+ console.log(`Downloading Godot ${GODOT_VERSION}...`);
58
+ console.log(`From: ${url}`);
59
+ await new Promise((resolve, reject) => {
60
+ followRedirect(url, (err, res) => {
61
+ if (err || !res) return reject(err || new Error('No response'));
62
+ const total = parseInt(res.headers['content-length'] || '0');
63
+ let received = 0;
64
+ const out = fs.createWriteStream(zipPath);
65
+ res.on('data', (chunk) => {
66
+ received += chunk.length;
67
+ out.write(chunk);
68
+ if (total > 0) {
69
+ const pct = Math.round(received / total * 100);
70
+ process.stdout.write(`\rProgress: ${pct}% (${Math.round(received/1024/1024)}/${Math.round(total/1024/1024)} MB) `);
71
+ }
72
+ });
73
+ res.on('end', () => { out.end(); console.log('\nDownload complete.'); resolve(); });
74
+ res.on('error', reject);
75
+ });
76
+ });
77
+ console.log('Extracting...');
78
+ if (process.platform === 'win32') {
79
+ execSync(`powershell -Command "Expand-Archive -Path '${zipPath}' -DestinationPath '${CFG_DIR}' -Force"`, { stdio: 'inherit' });
80
+ } else {
81
+ execSync(`unzip -o "${zipPath}" -d "${CFG_DIR}"`, { stdio: 'inherit' });
82
+ }
83
+ fs.unlinkSync(zipPath);
84
+ const files = fs.readdirSync(CFG_DIR).filter(f => {
85
+ const p = path.join(CFG_DIR, f);
86
+ return fs.statSync(p).isFile() && (f.startsWith('Godot') || f === 'godot.exe' || f === 'godot');
87
+ });
88
+ const godotPath = files.length ? path.join(CFG_DIR, files[0]) : null;
89
+ if (!godotPath) throw new Error('Could not find extracted Godot executable.');
90
+ if (process.platform !== 'win32') execSync(`chmod +x "${godotPath}"`);
91
+ const cfg = readConfig();
92
+ cfg.godotPath = godotPath;
93
+ writeConfig(cfg);
94
+ console.log(`Godot installed to: ${godotPath}`);
95
+ console.log(`Config: ${CFG_PATH}`);
96
+ return godotPath;
97
+ }
98
+
99
+ module.exports = { GODOT_VERSION, CFG_DIR, CFG_PATH, readConfig, writeConfig, findGodot, downloadEngine };
package/lib/protocol.js CHANGED
@@ -73,6 +73,17 @@ function encodeVariant(value) {
73
73
  for (const p of parts) { p.copy(b, off); off += p.length; }
74
74
  return b;
75
75
  }
76
+ if (typeof value === 'object') {
77
+ const keys = Object.keys(value);
78
+ const pairs = keys.map(k => [encodeVariant(k), encodeVariant(value[k])]);
79
+ const dataLen = 4 + pairs.reduce((a, [k, v]) => a + k.length + v.length, 0);
80
+ const b = Buffer.alloc(4 + dataLen);
81
+ b.writeUInt32LE(TYPES.DICTIONARY, 0);
82
+ b.writeUInt32LE(keys.length, 4);
83
+ let off = 8;
84
+ for (const [k, v] of pairs) { k.copy(b, off); off += k.length; v.copy(b, off); off += v.length; }
85
+ return b;
86
+ }
76
87
  return Buffer.from([0, 0, 0, 0]);
77
88
  }
78
89
 
@@ -136,7 +147,7 @@ function decodeVariant(buf, offset) {
136
147
  items.push(r.value);
137
148
  off += r.size;
138
149
  }
139
- return { value: items, size: 4 + (off - offset - 4) };
150
+ return { value: items, size: 4 + (off - offset) };
140
151
  }
141
152
  case TYPES.DICTIONARY: {
142
153
  const count = buf.readUInt32LE(offset) & 0x7fffffff;
@@ -147,7 +158,7 @@ function decodeVariant(buf, offset) {
147
158
  const vr = decodeVariant(buf, off); off += vr.size;
148
159
  dict[String(kr.value)] = vr.value;
149
160
  }
150
- return { value: dict, size: 4 + (off - offset - 4) };
161
+ return { value: dict, size: 4 + (off - offset) };
151
162
  }
152
163
  default: return { value: `<type:${type}>`, size: 4 };
153
164
  }
package/lib/templates.js CHANGED
@@ -34,7 +34,9 @@ script = ExtResource("1_main")
34
34
 
35
35
  func _ready() -> void:
36
36
  \tprint("[%s] Ready" % name)
37
- \tReplBridge.log_info("Game started: " + name)
37
+ \tvar bridge = get_node_or_null("/root/ReplBridge")
38
+ \tif bridge:
39
+ \t\tbridge.log_info("Game started: " + name)
38
40
 
39
41
  func _process(_delta: float) -> void:
40
42
  \tpass
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "godot-kit",
3
- "version": "1.0.0",
3
+ "version": "1.0.1772990785",
4
4
  "description": "Agentic Godot 4.x development boilerplate - REPL/CLI debugging, gdtoolkit, DAP, scene inspector, profiler",
5
5
  "bin": {
6
6
  "godot-kit": "bin/create.js",