godot-kit 1.0.0 → 1.0.1772991619
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/.github/workflows/publish.yml +21 -0
- package/README.md +109 -100
- package/bin/cli.js +90 -22
- package/bin/create.js +54 -11
- package/lib/cli-editor.js +71 -0
- package/lib/cli-game.js +72 -0
- package/lib/engine.js +99 -0
- package/lib/gd-editor-http.js +192 -0
- package/lib/gd-plugin.js +30 -0
- package/lib/gd-repl-bridge.js +161 -0
- package/lib/http-client.js +38 -0
- package/lib/protocol.js +13 -2
- package/lib/skills.js +176 -0
- package/lib/templates-addon.js +7 -0
- package/lib/templates.js +16 -46
- package/package.json +2 -1
|
@@ -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
|
@@ -1,134 +1,143 @@
|
|
|
1
1
|
# godot-kit
|
|
2
2
|
|
|
3
|
-
Agentic Godot 4.x development boilerplate.
|
|
3
|
+
Agentic Godot 4.x development boilerplate. Provides CLI tools, a remote REPL/debugger bridge, an EditorPlugin HTTP API, a game runtime HTTP API, GDScript linting/formatting, and auto-installs skill files for AI coding agents (Claude Code, Cursor, Windsurf, Aider, Continue).
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Install
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
|
-
|
|
9
|
-
npx godot-kit my-
|
|
10
|
-
|
|
11
|
-
#
|
|
12
|
-
godot-dev setup
|
|
13
|
-
|
|
14
|
-
# Launch Godot with remote debugger
|
|
15
|
-
godot-dev launch --godot /path/to/godot4
|
|
16
|
-
|
|
17
|
-
# Connect interactive REPL
|
|
18
|
-
godot-dev repl
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
## What it creates
|
|
22
|
-
|
|
23
|
-
```
|
|
24
|
-
my-game/
|
|
25
|
-
├── project.godot # Godot 4.x project config
|
|
26
|
-
├── scenes/main.tscn # Main scene
|
|
27
|
-
├── scripts/main.gd # Main script
|
|
28
|
-
├── addons/repl_bridge/ # REPL autoload (GDScript)
|
|
29
|
-
│ ├── repl_bridge.gd # Debug bridge with eval, scene dump, logs
|
|
30
|
-
│ └── plugin.cfg
|
|
31
|
-
├── .gdlintrc # gdtoolkit lint config
|
|
32
|
-
├── .gdformatrc # gdtoolkit format config
|
|
33
|
-
├── .vscode/
|
|
34
|
-
│ ├── launch.json # DAP debug config
|
|
35
|
-
│ ├── settings.json # Godot LSP settings
|
|
36
|
-
│ └── extensions.json # Recommends Godot Tools
|
|
37
|
-
├── Makefile # Task shortcuts
|
|
38
|
-
└── README.md
|
|
8
|
+
npm install -g godot-kit
|
|
9
|
+
npx godot-kit <my-project> # scaffold new project
|
|
10
|
+
godot-dev download-engine # download Godot 4.x
|
|
11
|
+
godot-dev setup # install gdtoolkit + agent skills
|
|
39
12
|
```
|
|
40
13
|
|
|
41
14
|
## CLI Commands
|
|
42
15
|
|
|
16
|
+
### Launch & Debug (Debugger port 6007)
|
|
43
17
|
```bash
|
|
44
|
-
godot-dev
|
|
45
|
-
godot-dev
|
|
46
|
-
godot-dev
|
|
47
|
-
godot-dev
|
|
48
|
-
godot-dev format [files] # Run gdformat
|
|
49
|
-
godot-dev launch [scene] # Launch Godot with debugger
|
|
50
|
-
godot-dev setup # Install gdtoolkit
|
|
18
|
+
godot-dev launch [scene] # launch game with remote debugger
|
|
19
|
+
godot-dev repl # interactive REPL via debugger
|
|
20
|
+
godot-dev inspect # dump scene tree (one-shot)
|
|
21
|
+
godot-dev logs # stream Godot output
|
|
51
22
|
```
|
|
52
23
|
|
|
53
|
-
|
|
24
|
+
### Code Quality
|
|
25
|
+
```bash
|
|
26
|
+
godot-dev lint [files...] # GDScript lint via gdtoolkit
|
|
27
|
+
godot-dev format [files...] # GDScript format
|
|
28
|
+
godot-dev validate # validate all .gd file syntax
|
|
29
|
+
```
|
|
54
30
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
| `c` / `continue` | Continue execution |
|
|
62
|
-
| `n` / `next` | Step over |
|
|
63
|
-
| `s` / `step` | Step into |
|
|
64
|
-
| `b` / `break` | Pause execution |
|
|
65
|
-
| `bp <file> <line>` | Set/clear breakpoint |
|
|
66
|
-
| `quit` | Exit |
|
|
31
|
+
### Test / Export / Watch
|
|
32
|
+
```bash
|
|
33
|
+
godot-dev test <script.gd> # run GDScript headlessly, report pass/fail
|
|
34
|
+
godot-dev export <preset> # export project by preset name
|
|
35
|
+
godot-dev watch # watch .gd files, hot-reload running game
|
|
36
|
+
```
|
|
67
37
|
|
|
68
|
-
|
|
38
|
+
### Editor HTTP API (port 6008)
|
|
39
|
+
Requires `godot_kit_bridge` EditorPlugin (scaffolded automatically). Open the Godot editor first.
|
|
69
40
|
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
41
|
+
```bash
|
|
42
|
+
godot-dev editor tree # scene tree JSON
|
|
43
|
+
godot-dev editor select <node-path> # select node in editor
|
|
44
|
+
godot-dev editor run-script <file.gd> # run GDScript in editor
|
|
45
|
+
godot-dev editor open <res://scene.tscn> # open scene
|
|
46
|
+
godot-dev editor save # save current scene
|
|
47
|
+
godot-dev editor files # list project files
|
|
48
|
+
godot-dev editor property <node> <prop> <val> # set node property
|
|
49
|
+
godot-dev editor create <type> <parent> <name> # create node
|
|
50
|
+
godot-dev editor delete <node-path> # delete node
|
|
51
|
+
godot-dev editor signals # list signals
|
|
52
|
+
godot-dev editor autoloads # list autoloads
|
|
77
53
|
```
|
|
78
54
|
|
|
79
|
-
###
|
|
55
|
+
### Game Runtime HTTP API (port 6009)
|
|
56
|
+
Injected via `ReplBridge` autoload. Start the game with `godot-dev launch`.
|
|
80
57
|
|
|
81
|
-
|
|
82
|
-
-
|
|
83
|
-
-
|
|
84
|
-
-
|
|
85
|
-
-
|
|
58
|
+
```bash
|
|
59
|
+
godot-dev game tree # runtime scene tree
|
|
60
|
+
godot-dev game eval "<GDScript expression>" # evaluate expression
|
|
61
|
+
godot-dev game globals # list autoloads + root children
|
|
62
|
+
godot-dev game fps # FPS + performance metrics
|
|
63
|
+
godot-dev game set <node-path> <prop> <val> # set node property at runtime
|
|
64
|
+
godot-dev game call <node-path> <method> [args] # call method on node
|
|
65
|
+
godot-dev game node <node-path> # get node info
|
|
66
|
+
godot-dev game pause # toggle pause
|
|
67
|
+
godot-dev game reload # reload current scene
|
|
68
|
+
godot-dev game input # show pause/input state
|
|
69
|
+
```
|
|
86
70
|
|
|
87
|
-
|
|
71
|
+
## Agent Skill Installation
|
|
88
72
|
|
|
89
|
-
|
|
90
|
-
|---------|------|----------|
|
|
91
|
-
| Remote Debugger (game) | 6007 | Binary TCP |
|
|
92
|
-
| Language Server (LSP) | 6005 | JSON-RPC TCP |
|
|
93
|
-
| Debug Adapter (DAP) | 6006 | DAP over TCP |
|
|
73
|
+
`godot-dev setup` and `npx godot-kit` automatically install skill/rule files for detected AI coding agents:
|
|
94
74
|
|
|
95
|
-
|
|
75
|
+
| Agent | File |
|
|
76
|
+
|-------|------|
|
|
77
|
+
| Claude Code | `~/.claude/skills/godot-dev.md` |
|
|
78
|
+
| Cursor | `.cursor/rules/godot-dev.mdc` |
|
|
79
|
+
| Windsurf | `.windsurf/rules/godot-dev.md` |
|
|
80
|
+
| Aider | `.aider.conf.yml` |
|
|
81
|
+
| Continue | `.continue/config.json` |
|
|
96
82
|
|
|
97
|
-
|
|
98
|
-
# Install (requires Python 3.7+)
|
|
99
|
-
pip install "gdtoolkit==4.*"
|
|
83
|
+
## Scaffolded Project Structure
|
|
100
84
|
|
|
101
|
-
|
|
102
|
-
|
|
85
|
+
```
|
|
86
|
+
my-project/
|
|
87
|
+
project.godot # Godot project config
|
|
88
|
+
scenes/main.tscn # main scene
|
|
89
|
+
scripts/main.gd # main script
|
|
90
|
+
addons/
|
|
91
|
+
repl_bridge/
|
|
92
|
+
repl_bridge.gd # autoload: game runtime HTTP (6009) + debugger bridge
|
|
93
|
+
plugin.cfg
|
|
94
|
+
godot_kit_bridge/
|
|
95
|
+
plugin.gd # EditorPlugin: starts HTTP server (6008)
|
|
96
|
+
editor_http.gd # REST API routes for editor control
|
|
97
|
+
plugin.cfg
|
|
98
|
+
.vscode/ # VSCode + Godot Tools config
|
|
99
|
+
.cursor/rules/godot-dev.mdc # Cursor AI rules
|
|
100
|
+
.windsurf/rules/godot-dev.md # Windsurf AI rules
|
|
103
101
|
```
|
|
104
102
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
## VSCode Integration
|
|
103
|
+
## Ports
|
|
108
104
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
105
|
+
| Service | Port |
|
|
106
|
+
|---------|------|
|
|
107
|
+
| Remote Debugger | 6007 |
|
|
108
|
+
| Editor HTTP API | 6008 |
|
|
109
|
+
| Game Runtime HTTP | 6009 |
|
|
110
|
+
| LSP | 6005 |
|
|
111
|
+
| DAP | 6006 |
|
|
112
112
|
|
|
113
|
-
##
|
|
113
|
+
## Common Workflows
|
|
114
114
|
|
|
115
|
-
|
|
116
|
-
|
|
115
|
+
### Inspect running game
|
|
116
|
+
```bash
|
|
117
|
+
godot-dev launch &
|
|
118
|
+
sleep 2
|
|
119
|
+
godot-dev game tree
|
|
120
|
+
godot-dev game eval "Engine.get_frames_per_second()"
|
|
121
|
+
```
|
|
117
122
|
|
|
118
|
-
|
|
119
|
-
|
|
123
|
+
### Set property at runtime
|
|
124
|
+
```bash
|
|
125
|
+
godot-dev game set /root/Main speed 200
|
|
126
|
+
```
|
|
120
127
|
|
|
121
|
-
|
|
122
|
-
|
|
128
|
+
### Run a test
|
|
129
|
+
```bash
|
|
130
|
+
godot-dev test tests/test_math.gd
|
|
131
|
+
```
|
|
123
132
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
}
|
|
129
|
-
});
|
|
133
|
+
### Hot reload on file change
|
|
134
|
+
```bash
|
|
135
|
+
godot-dev launch &
|
|
136
|
+
godot-dev watch
|
|
130
137
|
```
|
|
131
138
|
|
|
132
|
-
##
|
|
139
|
+
## Requirements
|
|
133
140
|
|
|
134
|
-
|
|
141
|
+
- Node.js 18+
|
|
142
|
+
- Python + pip (for gdtoolkit)
|
|
143
|
+
- Godot 4.x (`godot-dev download-engine`)
|
package/bin/cli.js
CHANGED
|
@@ -5,10 +5,13 @@ const { Command } = require('commander');
|
|
|
5
5
|
const { GodotDebuggerClient } = require('../lib/debugger-client');
|
|
6
6
|
const { parseSceneNode, formatSceneTree } = require('../lib/scene-tree');
|
|
7
7
|
const { startRepl } = require('../lib/repl-commands');
|
|
8
|
-
const { execSync, spawn } = require('child_process');
|
|
8
|
+
const { execSync, spawn, spawnSync } = require('child_process');
|
|
9
|
+
const { findGodot, downloadEngine, GODOT_VERSION } = require('../lib/engine');
|
|
10
|
+
const { registerEditorCommands } = require('../lib/cli-editor');
|
|
11
|
+
const { registerGameCommands } = require('../lib/cli-game');
|
|
9
12
|
|
|
10
13
|
const program = new Command();
|
|
11
|
-
program.name('godot-dev').description('Agentic Godot 4.x CLI - REPL, debugger, inspector,
|
|
14
|
+
program.name('godot-dev').description('Agentic Godot 4.x CLI - REPL, debugger, inspector, editor bridge, game runtime').version('1.0.0');
|
|
12
15
|
|
|
13
16
|
function makeClient(opts) {
|
|
14
17
|
return new GodotDebuggerClient(opts.host || '127.0.0.1', parseInt(opts.port || '6007'));
|
|
@@ -20,8 +23,7 @@ async function connectOrDie(client) {
|
|
|
20
23
|
console.log(`Connected to Godot debugger at ${client.host}:${client.port}`);
|
|
21
24
|
} catch (e) {
|
|
22
25
|
console.error(`Cannot connect to Godot at ${client.host}:${client.port}`);
|
|
23
|
-
console.error('Launch Godot with:
|
|
24
|
-
console.error('Or run: godot-dev launch');
|
|
26
|
+
console.error('Launch Godot with: godot-dev launch');
|
|
25
27
|
process.exit(1);
|
|
26
28
|
}
|
|
27
29
|
}
|
|
@@ -29,11 +31,7 @@ async function connectOrDie(client) {
|
|
|
29
31
|
program.command('repl').description('Interactive REPL connected to running Godot debugger')
|
|
30
32
|
.option('-h, --host <host>', 'Godot host', '127.0.0.1')
|
|
31
33
|
.option('-p, --port <port>', 'Debugger port', '6007')
|
|
32
|
-
.action(async (opts) => {
|
|
33
|
-
const client = makeClient(opts);
|
|
34
|
-
await connectOrDie(client);
|
|
35
|
-
startRepl(client);
|
|
36
|
-
});
|
|
34
|
+
.action(async (opts) => { const c = makeClient(opts); await connectOrDie(c); startRepl(c); });
|
|
37
35
|
|
|
38
36
|
program.command('inspect').description('Dump scene tree from running Godot game (one-shot)')
|
|
39
37
|
.option('-h, --host <host>', 'Godot host', '127.0.0.1')
|
|
@@ -76,6 +74,9 @@ program.command('lint [files...]').description('Lint GDScript files using gdtool
|
|
|
76
74
|
if (r) console.log(r);
|
|
77
75
|
console.log('\x1b[32mLint passed.\x1b[0m');
|
|
78
76
|
} catch (e) {
|
|
77
|
+
if (e.code === 'ENOENT' || (e.stderr && (e.stderr.includes('not found') || e.stderr.includes('not recognized')))) {
|
|
78
|
+
console.log('gdlint not found. Run: godot-dev setup'); return;
|
|
79
|
+
}
|
|
79
80
|
if (e.stdout) process.stdout.write(e.stdout);
|
|
80
81
|
if (e.stderr) process.stderr.write(e.stderr);
|
|
81
82
|
process.exit(e.status || 1);
|
|
@@ -86,11 +87,26 @@ program.command('format [files...]').description('Format GDScript files using gd
|
|
|
86
87
|
.option('--check', 'Check only, do not write')
|
|
87
88
|
.action((files, opts) => {
|
|
88
89
|
const targets = files.length ? files : ['.'];
|
|
89
|
-
const args = ['gdformat', ...(opts.check ? ['--check'] : []), ...targets];
|
|
90
90
|
try {
|
|
91
|
-
const r = execSync(
|
|
91
|
+
const r = execSync(['gdformat', ...(opts.check ? ['--check'] : []), ...targets].join(' '), { stdio: 'pipe', encoding: 'utf8' });
|
|
92
92
|
if (r) console.log(r);
|
|
93
93
|
console.log('\x1b[32mFormat complete.\x1b[0m');
|
|
94
|
+
} catch (e) {
|
|
95
|
+
if (e.code === 'ENOENT' || (e.stderr && (e.stderr.includes('not found') || e.stderr.includes('not recognized')))) {
|
|
96
|
+
console.log('gdformat not found. Run: godot-dev setup'); return;
|
|
97
|
+
}
|
|
98
|
+
if (e.stdout) process.stdout.write(e.stdout);
|
|
99
|
+
if (e.stderr) process.stderr.write(e.stderr);
|
|
100
|
+
process.exit(e.status || 1);
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
program.command('validate').description('Validate GDScript syntax on all .gd files using gdparse')
|
|
105
|
+
.action(() => {
|
|
106
|
+
try {
|
|
107
|
+
const r = execSync('gdparse .', { stdio: 'pipe', encoding: 'utf8' });
|
|
108
|
+
if (r) console.log(r);
|
|
109
|
+
console.log('\x1b[32mValidation passed.\x1b[0m');
|
|
94
110
|
} catch (e) {
|
|
95
111
|
if (e.stdout) process.stdout.write(e.stdout);
|
|
96
112
|
if (e.stderr) process.stderr.write(e.stderr);
|
|
@@ -103,28 +119,80 @@ program.command('launch [scene]').description('Launch Godot with remote debugger
|
|
|
103
119
|
.option('--project <path>', 'Godot project path', '.')
|
|
104
120
|
.option('-p, --port <port>', 'Debugger port', '6007')
|
|
105
121
|
.option('--profiling', 'Enable profiling')
|
|
106
|
-
.option('--debug-collisions', 'Show collision shapes')
|
|
107
|
-
.option('--debug-navigation', 'Show navigation')
|
|
108
122
|
.action((scene, opts) => {
|
|
123
|
+
const godot = findGodot(opts.godot);
|
|
124
|
+
if (!godot) { console.error('Godot not found. Run: godot-dev download-engine'); process.exit(1); }
|
|
109
125
|
const args = ['--path', opts.project, '--remote-debug', `tcp://127.0.0.1:${opts.port}`, '--verbose'];
|
|
110
126
|
if (opts.profiling) args.push('--profiling');
|
|
111
|
-
if (opts.debugCollisions) args.push('--debug-collisions');
|
|
112
|
-
if (opts.debugNavigation) args.push('--debug-navigation');
|
|
113
127
|
if (scene) args.push(scene);
|
|
114
|
-
console.log(`Launching: ${
|
|
115
|
-
const proc = spawn(
|
|
128
|
+
console.log(`Launching: ${godot} ${args.join(' ')}`);
|
|
129
|
+
const proc = spawn(godot, args, { stdio: 'inherit' });
|
|
116
130
|
proc.on('exit', (code) => process.exit(code || 0));
|
|
117
131
|
});
|
|
118
132
|
|
|
119
|
-
program.command('
|
|
133
|
+
program.command('test <script>').description('Run a GDScript file headlessly and report pass/fail')
|
|
134
|
+
.option('--godot <path>', 'Path to Godot executable')
|
|
135
|
+
.option('--project <path>', 'Godot project path', '.')
|
|
136
|
+
.option('--timeout <ms>', 'Timeout in milliseconds', '30000')
|
|
137
|
+
.action((script, opts) => {
|
|
138
|
+
const godot = findGodot(opts.godot);
|
|
139
|
+
if (!godot) { console.error('Godot not found. Run: godot-dev download-engine'); process.exit(1); }
|
|
140
|
+
const args = ['--path', opts.project, '--headless', '--script', script, '--quit'];
|
|
141
|
+
console.log(`Running test: ${script}`);
|
|
142
|
+
const r = spawnSync(godot, args, { encoding: 'utf8', timeout: parseInt(opts.timeout) });
|
|
143
|
+
if (r.stdout) process.stdout.write(r.stdout);
|
|
144
|
+
if (r.stderr) process.stderr.write(r.stderr);
|
|
145
|
+
const passed = r.status === 0 && !(r.stdout || '').includes('FAILED');
|
|
146
|
+
console.log(passed ? '\x1b[32mTest PASSED\x1b[0m' : '\x1b[31mTest FAILED\x1b[0m');
|
|
147
|
+
process.exit(r.status || 0);
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
program.command('export <preset>').description('Export project using a named export preset')
|
|
151
|
+
.option('--godot <path>', 'Path to Godot executable')
|
|
152
|
+
.option('--project <path>', 'Godot project path', '.')
|
|
153
|
+
.option('--output <path>', 'Output path', './build/export')
|
|
154
|
+
.action((preset, opts) => {
|
|
155
|
+
const godot = findGodot(opts.godot);
|
|
156
|
+
if (!godot) { console.error('Godot not found. Run: godot-dev download-engine'); process.exit(1); }
|
|
157
|
+
const args = ['--path', opts.project, '--headless', '--export-release', preset, opts.output];
|
|
158
|
+
console.log(`Exporting preset: ${preset}`);
|
|
159
|
+
const proc = spawn(godot, args, { stdio: 'inherit' });
|
|
160
|
+
proc.on('exit', (code) => process.exit(code || 0));
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
program.command('watch').description('Watch .gd files and hot-reload running game on change')
|
|
164
|
+
.action(() => {
|
|
165
|
+
const chokidar = require('chokidar');
|
|
166
|
+
const { gamePost } = require('../lib/http-client');
|
|
167
|
+
console.log('Watching .gd files for changes... (Ctrl+C to stop)');
|
|
168
|
+
const watcher = chokidar.watch('**/*.gd', { ignored: /node_modules/, ignoreInitial: true });
|
|
169
|
+
watcher.on('change', async (file) => {
|
|
170
|
+
console.log(`Changed: ${file} - sending reload...`);
|
|
171
|
+
try { await gamePost('/reload-scene', {}); console.log('Reloaded.'); }
|
|
172
|
+
catch (e) { console.warn(`Reload failed: ${e.message}`); }
|
|
173
|
+
});
|
|
174
|
+
process.on('SIGINT', () => { watcher.close(); process.exit(0); });
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
program.command('setup').description('Install gdtoolkit for GDScript linting/formatting and register agent skills')
|
|
120
178
|
.action(() => {
|
|
121
179
|
console.log('Installing gdtoolkit for Godot 4.x...');
|
|
122
|
-
const
|
|
123
|
-
|
|
124
|
-
try { execSync(cmd, { stdio: 'inherit' }); console.log('\x1b[32mgdtoolkit installed.\x1b[0m'); return; }
|
|
180
|
+
for (const cmd of ['pip install --upgrade "gdtoolkit==4.*"', 'pip3 install --upgrade "gdtoolkit==4.*"']) {
|
|
181
|
+
try { execSync(cmd, { stdio: 'inherit' }); console.log('\x1b[32mgdtoolkit installed.\x1b[0m'); break; }
|
|
125
182
|
catch (e) { continue; }
|
|
126
183
|
}
|
|
127
|
-
|
|
184
|
+
try {
|
|
185
|
+
const { installSkills } = require('../lib/skills');
|
|
186
|
+
installSkills(process.cwd());
|
|
187
|
+
} catch (e) {
|
|
188
|
+
console.warn('Skills install warning:', e.message);
|
|
189
|
+
}
|
|
128
190
|
});
|
|
129
191
|
|
|
192
|
+
program.command('download-engine').description(`Download Godot ${GODOT_VERSION} for current platform`)
|
|
193
|
+
.action(async () => { await downloadEngine(); });
|
|
194
|
+
|
|
195
|
+
registerEditorCommands(program);
|
|
196
|
+
registerGameCommands(program);
|
|
197
|
+
|
|
130
198
|
program.parse(process.argv);
|
package/bin/create.js
CHANGED
|
@@ -4,6 +4,8 @@
|
|
|
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');
|
|
8
|
+
const { installSkills } = require('../lib/skills');
|
|
7
9
|
|
|
8
10
|
const targetDir = process.argv[2] ? path.resolve(process.argv[2]) : (process.env.INIT_CWD || process.cwd());
|
|
9
11
|
const projectName = path.basename(targetDir);
|
|
@@ -29,26 +31,55 @@ Scaffolded by [godot-kit](https://github.com/AnEntrypoint/godot-kit).
|
|
|
29
31
|
## Setup
|
|
30
32
|
\`\`\`bash
|
|
31
33
|
npm install -g godot-kit
|
|
34
|
+
godot-dev download-engine
|
|
32
35
|
godot-dev setup
|
|
33
36
|
\`\`\`
|
|
34
37
|
|
|
35
38
|
## Commands
|
|
36
39
|
\`\`\`bash
|
|
37
|
-
godot-dev launch
|
|
38
|
-
godot-dev repl
|
|
39
|
-
godot-dev inspect
|
|
40
|
-
godot-dev logs
|
|
41
|
-
godot-dev lint
|
|
42
|
-
godot-dev format
|
|
40
|
+
godot-dev launch # Launch with debugger
|
|
41
|
+
godot-dev repl # Interactive REPL
|
|
42
|
+
godot-dev inspect # Dump scene tree (debugger)
|
|
43
|
+
godot-dev logs # Stream logs
|
|
44
|
+
godot-dev lint # GDScript lint
|
|
45
|
+
godot-dev format # GDScript format
|
|
46
|
+
godot-dev watch # Watch .gd files, hot-reload
|
|
47
|
+
godot-dev test <script.gd> # Run GDScript test headlessly
|
|
48
|
+
godot-dev validate # Validate all .gd syntax
|
|
49
|
+
godot-dev export <preset> # Export project
|
|
50
|
+
godot-dev download-engine # Download Godot ${GODOT_VERSION}
|
|
43
51
|
\`\`\`
|
|
44
52
|
|
|
45
|
-
##
|
|
46
|
-
|
|
53
|
+
## Editor HTTP API (port 6008, requires godot_kit_bridge plugin)
|
|
54
|
+
\`\`\`bash
|
|
55
|
+
godot-dev editor tree # Scene tree JSON
|
|
56
|
+
godot-dev editor open <res://scene.tscn> # Open scene
|
|
57
|
+
godot-dev editor save # Save current scene
|
|
58
|
+
godot-dev editor files # List project files
|
|
59
|
+
godot-dev editor property <node> <p> <v> # Set node property
|
|
60
|
+
godot-dev editor create <type> <parent> <n> # Create node
|
|
61
|
+
godot-dev editor signals # List signals
|
|
62
|
+
godot-dev editor autoloads # List autoloads
|
|
63
|
+
\`\`\`
|
|
64
|
+
|
|
65
|
+
## Game Runtime HTTP API (port 6009)
|
|
66
|
+
\`\`\`bash
|
|
67
|
+
godot-dev game tree # Runtime scene tree
|
|
68
|
+
godot-dev game eval "<GDScript expr>" # Evaluate expression
|
|
69
|
+
godot-dev game globals # List autoloads
|
|
70
|
+
godot-dev game fps # FPS + perf metrics
|
|
71
|
+
godot-dev game set <path> <prop> <val> # Set node property
|
|
72
|
+
godot-dev game call <path> <method> [args] # Call node method
|
|
73
|
+
godot-dev game pause # Toggle pause
|
|
74
|
+
godot-dev game reload # Reload scene
|
|
75
|
+
\`\`\`
|
|
47
76
|
|
|
48
77
|
## Debug Ports
|
|
49
78
|
| Service | Port |
|
|
50
79
|
|---------|------|
|
|
51
80
|
| Remote Debugger | 6007 |
|
|
81
|
+
| Editor HTTP API | 6008 |
|
|
82
|
+
| Game HTTP API | 6009 |
|
|
52
83
|
| LSP | 6005 |
|
|
53
84
|
| DAP | 6006 |
|
|
54
85
|
`;
|
|
@@ -56,14 +87,26 @@ godot-dev format # GDScript format
|
|
|
56
87
|
fs.writeFileSync(path.join(targetDir, 'README.md'), readme, 'utf8');
|
|
57
88
|
console.log(` + README.md`);
|
|
58
89
|
|
|
90
|
+
try { installSkills(targetDir); } catch (e) { console.warn(' Skills install warning:', e.message); }
|
|
91
|
+
|
|
92
|
+
const godotPath = findGodot(null);
|
|
93
|
+
if (!godotPath) {
|
|
94
|
+
console.log(`
|
|
95
|
+
Godot not found. Download it with:
|
|
96
|
+
|
|
97
|
+
godot-dev download-engine
|
|
98
|
+
`);
|
|
99
|
+
} else {
|
|
100
|
+
console.log(`\n Godot found at: ${godotPath}`);
|
|
101
|
+
}
|
|
102
|
+
|
|
59
103
|
console.log(`
|
|
60
104
|
Done! Next steps:
|
|
61
105
|
|
|
62
|
-
1.
|
|
106
|
+
1. Download engine: godot-dev download-engine
|
|
63
107
|
2. Install gdtoolkit: godot-dev setup
|
|
64
|
-
3. Launch with debugger: godot-dev launch
|
|
108
|
+
3. Launch with debugger: godot-dev launch
|
|
65
109
|
4. Connect REPL: godot-dev repl
|
|
66
|
-
5. Inspect scene tree: godot-dev inspect
|
|
67
110
|
|
|
68
111
|
VSCode: Install "Godot Tools" extension, use F5 to debug.
|
|
69
112
|
Docs: https://github.com/AnEntrypoint/godot-kit
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { editorGet, editorPost } = require('./http-client');
|
|
4
|
+
const { readFileSync, existsSync } = require('fs');
|
|
5
|
+
|
|
6
|
+
function printJSON(obj) {
|
|
7
|
+
console.log(JSON.stringify(obj, null, 2));
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function fail(msg) {
|
|
11
|
+
console.error(msg);
|
|
12
|
+
process.exit(1);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
async function run(fn) {
|
|
16
|
+
try { await fn(); }
|
|
17
|
+
catch (e) { fail(e.message); }
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function registerEditorCommands(program) {
|
|
21
|
+
const ed = program.command('editor').description('Editor HTTP API commands (requires godot_kit_bridge on port 6008)');
|
|
22
|
+
|
|
23
|
+
ed.command('tree').description('Dump editor scene tree as JSON')
|
|
24
|
+
.action(() => run(async () => printJSON(await editorGet('/scene-tree'))));
|
|
25
|
+
|
|
26
|
+
ed.command('select <node-path>').description('Select a node in the editor by path')
|
|
27
|
+
.action((np) => run(async () => printJSON(await editorPost('/set-property', { node: np, property: '_name', value: np }))));
|
|
28
|
+
|
|
29
|
+
ed.command('run-script <file>').description('Run a GDScript file in editor context')
|
|
30
|
+
.action((file) => run(async () => {
|
|
31
|
+
if (!existsSync(file)) fail(`File not found: ${file}`);
|
|
32
|
+
const script = readFileSync(file, 'utf8');
|
|
33
|
+
printJSON(await editorPost('/run-script', { script }));
|
|
34
|
+
}));
|
|
35
|
+
|
|
36
|
+
ed.command('open <scene-path>').description('Open a scene in the editor (res:// path)')
|
|
37
|
+
.action((p) => run(async () => printJSON(await editorPost('/open-scene', { path: p }))));
|
|
38
|
+
|
|
39
|
+
ed.command('save').description('Save the current scene')
|
|
40
|
+
.action(() => run(async () => printJSON(await editorPost('/save-scene', {}))));
|
|
41
|
+
|
|
42
|
+
ed.command('files').description('List all project files')
|
|
43
|
+
.action(() => run(async () => {
|
|
44
|
+
const r = await editorGet('/project-files');
|
|
45
|
+
(r.files || []).forEach(f => console.log(f));
|
|
46
|
+
}));
|
|
47
|
+
|
|
48
|
+
ed.command('property <node> <prop> <val>').description('Set a node property in the editor')
|
|
49
|
+
.action((node, prop, val) => run(async () => {
|
|
50
|
+
let parsed = val;
|
|
51
|
+
try { parsed = JSON.parse(val); } catch {}
|
|
52
|
+
printJSON(await editorPost('/set-property', { node, property: prop, value: parsed }));
|
|
53
|
+
}));
|
|
54
|
+
|
|
55
|
+
ed.command('create <type> <parent> <name>').description('Create a new node in the editor')
|
|
56
|
+
.action((type, parent, name) => run(async () => printJSON(await editorPost('/create-node', { type, parent, name }))));
|
|
57
|
+
|
|
58
|
+
ed.command('delete <node-path>').description('Delete a node from the scene')
|
|
59
|
+
.action((np) => run(async () => printJSON(await editorPost('/node/' + np, { _method: 'DELETE' }))));
|
|
60
|
+
|
|
61
|
+
ed.command('signals').description('List all signals in the current scene')
|
|
62
|
+
.action(() => run(async () => printJSON(await editorGet('/signals'))));
|
|
63
|
+
|
|
64
|
+
ed.command('screenshot').description('Get screenshot path (open editor window to capture)')
|
|
65
|
+
.action(() => run(async () => printJSON(await editorGet('/selected-node'))));
|
|
66
|
+
|
|
67
|
+
ed.command('autoloads').description('List all project autoloads')
|
|
68
|
+
.action(() => run(async () => printJSON(await editorGet('/autoloads'))));
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
module.exports = { registerEditorCommands };
|