godot-cli 0.1.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.
Files changed (110) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/README.md +101 -0
  3. package/bin/godot-cli.js +2 -0
  4. package/dist/cli.d.ts +11 -0
  5. package/dist/cli.js +17 -0
  6. package/dist/cli.js.map +1 -0
  7. package/dist/commands/close.d.ts +18 -0
  8. package/dist/commands/close.js +112 -0
  9. package/dist/commands/close.js.map +1 -0
  10. package/dist/commands/configure.d.ts +2 -0
  11. package/dist/commands/configure.js +92 -0
  12. package/dist/commands/configure.js.map +1 -0
  13. package/dist/commands/install-plugin.d.ts +2 -0
  14. package/dist/commands/install-plugin.js +35 -0
  15. package/dist/commands/install-plugin.js.map +1 -0
  16. package/dist/commands/open.d.ts +16 -0
  17. package/dist/commands/open.js +124 -0
  18. package/dist/commands/open.js.map +1 -0
  19. package/dist/commands/remove-plugin.d.ts +2 -0
  20. package/dist/commands/remove-plugin.js +31 -0
  21. package/dist/commands/remove-plugin.js.map +1 -0
  22. package/dist/commands/run-system-tool.d.ts +1 -0
  23. package/dist/commands/run-system-tool.js +13 -0
  24. package/dist/commands/run-system-tool.js.map +1 -0
  25. package/dist/commands/run-tool-builder.d.ts +25 -0
  26. package/dist/commands/run-tool-builder.js +119 -0
  27. package/dist/commands/run-tool-builder.js.map +1 -0
  28. package/dist/commands/run-tool.d.ts +1 -0
  29. package/dist/commands/run-tool.js +13 -0
  30. package/dist/commands/run-tool.js.map +1 -0
  31. package/dist/commands/setup-mcp.d.ts +2 -0
  32. package/dist/commands/setup-mcp.js +58 -0
  33. package/dist/commands/setup-mcp.js.map +1 -0
  34. package/dist/commands/status.d.ts +2 -0
  35. package/dist/commands/status.js +64 -0
  36. package/dist/commands/status.js.map +1 -0
  37. package/dist/commands/update.d.ts +2 -0
  38. package/dist/commands/update.js +75 -0
  39. package/dist/commands/update.js.map +1 -0
  40. package/dist/commands/wait-for-ready.d.ts +2 -0
  41. package/dist/commands/wait-for-ready.js +57 -0
  42. package/dist/commands/wait-for-ready.js.map +1 -0
  43. package/dist/index.d.ts +1 -0
  44. package/dist/index.js +69 -0
  45. package/dist/index.js.map +1 -0
  46. package/dist/lib/install-plugin.d.ts +22 -0
  47. package/dist/lib/install-plugin.js +118 -0
  48. package/dist/lib/install-plugin.js.map +1 -0
  49. package/dist/lib/open.d.ts +34 -0
  50. package/dist/lib/open.js +198 -0
  51. package/dist/lib/open.js.map +1 -0
  52. package/dist/lib/progress.d.ts +7 -0
  53. package/dist/lib/progress.js +16 -0
  54. package/dist/lib/progress.js.map +1 -0
  55. package/dist/lib/run-tool.d.ts +12 -0
  56. package/dist/lib/run-tool.js +192 -0
  57. package/dist/lib/run-tool.js.map +1 -0
  58. package/dist/lib/setup-mcp.d.ts +16 -0
  59. package/dist/lib/setup-mcp.js +118 -0
  60. package/dist/lib/setup-mcp.js.map +1 -0
  61. package/dist/lib/types.d.ts +210 -0
  62. package/dist/lib/types.js +8 -0
  63. package/dist/lib/types.js.map +1 -0
  64. package/dist/lib/validation.d.ts +30 -0
  65. package/dist/lib/validation.js +44 -0
  66. package/dist/lib/validation.js.map +1 -0
  67. package/dist/lib.d.ts +5 -0
  68. package/dist/lib.js +19 -0
  69. package/dist/lib.js.map +1 -0
  70. package/dist/utils/agents.d.ts +31 -0
  71. package/dist/utils/agents.js +188 -0
  72. package/dist/utils/agents.js.map +1 -0
  73. package/dist/utils/config.d.ts +40 -0
  74. package/dist/utils/config.js +97 -0
  75. package/dist/utils/config.js.map +1 -0
  76. package/dist/utils/connection.d.ts +57 -0
  77. package/dist/utils/connection.js +129 -0
  78. package/dist/utils/connection.js.map +1 -0
  79. package/dist/utils/godot-editor.d.ts +42 -0
  80. package/dist/utils/godot-editor.js +184 -0
  81. package/dist/utils/godot-editor.js.map +1 -0
  82. package/dist/utils/godot-process.d.ts +10 -0
  83. package/dist/utils/godot-process.js +93 -0
  84. package/dist/utils/godot-process.js.map +1 -0
  85. package/dist/utils/godot-shutdown.d.ts +16 -0
  86. package/dist/utils/godot-shutdown.js +67 -0
  87. package/dist/utils/godot-shutdown.js.map +1 -0
  88. package/dist/utils/input.d.ts +13 -0
  89. package/dist/utils/input.js +72 -0
  90. package/dist/utils/input.js.map +1 -0
  91. package/dist/utils/json-parse.d.ts +25 -0
  92. package/dist/utils/json-parse.js +83 -0
  93. package/dist/utils/json-parse.js.map +1 -0
  94. package/dist/utils/probe.d.ts +18 -0
  95. package/dist/utils/probe.js +61 -0
  96. package/dist/utils/probe.js.map +1 -0
  97. package/dist/utils/project-godot.d.ts +41 -0
  98. package/dist/utils/project-godot.js +126 -0
  99. package/dist/utils/project-godot.js.map +1 -0
  100. package/dist/utils/semver.d.ts +4 -0
  101. package/dist/utils/semver.js +25 -0
  102. package/dist/utils/semver.js.map +1 -0
  103. package/dist/utils/ui.d.ts +61 -0
  104. package/dist/utils/ui.js +238 -0
  105. package/dist/utils/ui.js.map +1 -0
  106. package/dist/utils/update-check.d.ts +19 -0
  107. package/dist/utils/update-check.js +92 -0
  108. package/dist/utils/update-check.js.map +1 -0
  109. package/docs/README.md +7 -0
  110. package/package.json +73 -0
@@ -0,0 +1,184 @@
1
+ import * as fs from 'fs';
2
+ import * as path from 'path';
3
+ import { spawn } from 'child_process';
4
+ import { homedir, platform } from 'os';
5
+ /**
6
+ * Environment variables that, when set, point directly at a Godot editor
7
+ * binary. Checked before PATH and common install dirs. `GODOT_BIN` is the
8
+ * conventional name; `GODOT4_BIN` is honored for setups that pin a Godot 4
9
+ * binary alongside a legacy Godot 3 one.
10
+ */
11
+ export const GODOT_BIN_ENV_VARS = ['GODOT_BIN', 'GODOT4_BIN'];
12
+ /**
13
+ * Candidate executable base-names searched on `PATH`. The Windows mono build
14
+ * uses a `_console.exe` companion that surfaces stdout; the mono editor binary
15
+ * itself ships under several historical names, so we probe a small set.
16
+ */
17
+ function pathCandidateNames(os) {
18
+ if (os === 'win32') {
19
+ // Prefer the mono build; the `_console` variant surfaces GD.Print/stdout.
20
+ return [
21
+ 'godot_mono.exe',
22
+ 'godot.exe',
23
+ 'Godot_mono.exe',
24
+ 'Godot.exe',
25
+ ];
26
+ }
27
+ if (os === 'darwin') {
28
+ return ['godot', 'godot_mono', 'Godot'];
29
+ }
30
+ return ['godot', 'godot_mono', 'Godot'];
31
+ }
32
+ /**
33
+ * Per-OS common install directories to scan for a Godot editor binary when
34
+ * neither an env override nor a PATH hit resolves one.
35
+ * - Windows: prefer the mono build under Program Files / common download dirs.
36
+ * - macOS: the `.app` bundle's inner `Contents/MacOS/Godot` binary.
37
+ * - Linux: extracted binaries under common app dirs.
38
+ */
39
+ function commonInstallCandidates(os) {
40
+ const home = homedir();
41
+ const candidates = [];
42
+ if (os === 'win32') {
43
+ const programFiles = process.env['PROGRAMFILES'] ?? 'C:\\Program Files';
44
+ const localAppData = process.env['LOCALAPPDATA'] ?? path.join(home, 'AppData', 'Local');
45
+ for (const root of [
46
+ path.join(programFiles, 'Godot'),
47
+ path.join(localAppData, 'Programs', 'Godot'),
48
+ path.join(home, 'Downloads'),
49
+ ]) {
50
+ // Prefer the mono console build (surfaces stdout), then the plain mono build.
51
+ candidates.push(path.join(root, 'Godot_mono.exe'));
52
+ candidates.push(path.join(root, 'Godot.exe'));
53
+ }
54
+ return candidates;
55
+ }
56
+ if (os === 'darwin') {
57
+ for (const app of [
58
+ '/Applications/Godot_mono.app',
59
+ '/Applications/Godot.app',
60
+ path.join(home, 'Applications', 'Godot_mono.app'),
61
+ path.join(home, 'Applications', 'Godot.app'),
62
+ ]) {
63
+ candidates.push(path.join(app, 'Contents', 'MacOS', 'Godot'));
64
+ }
65
+ return candidates;
66
+ }
67
+ // linux + others
68
+ for (const dir of [
69
+ '/usr/local/bin',
70
+ '/usr/bin',
71
+ path.join(home, '.local', 'bin'),
72
+ path.join(home, 'Applications'),
73
+ path.join(home, 'bin'),
74
+ ]) {
75
+ candidates.push(path.join(dir, 'godot'));
76
+ candidates.push(path.join(dir, 'godot_mono'));
77
+ candidates.push(path.join(dir, 'Godot'));
78
+ }
79
+ return candidates;
80
+ }
81
+ /**
82
+ * Search the directories on `PATH` for the first matching Godot binary name.
83
+ * Pure filesystem lookup — never spawns anything.
84
+ */
85
+ function findOnPath(os) {
86
+ const pathEnv = process.env['PATH'] ?? '';
87
+ if (!pathEnv)
88
+ return null;
89
+ const sep = os === 'win32' ? ';' : ':';
90
+ const dirs = pathEnv.split(sep).filter((d) => d.length > 0);
91
+ const names = pathCandidateNames(os);
92
+ for (const dir of dirs) {
93
+ for (const name of names) {
94
+ const candidate = path.join(dir, name);
95
+ if (existsAsFile(candidate)) {
96
+ return candidate;
97
+ }
98
+ }
99
+ }
100
+ return null;
101
+ }
102
+ function existsAsFile(p) {
103
+ try {
104
+ return fs.statSync(p).isFile();
105
+ }
106
+ catch {
107
+ return false;
108
+ }
109
+ }
110
+ /**
111
+ * Resolve the Godot editor binary path.
112
+ *
113
+ * Resolution order (first hit wins):
114
+ * 1. An explicit `editorPath` argument (validated to be an existing file).
115
+ * 2. `GODOT_BIN` / `GODOT4_BIN` environment variables.
116
+ * 3. The first matching Godot binary on `PATH`.
117
+ * 4. Per-OS common install directories (Windows prefers the mono build;
118
+ * macOS resolves the `.app/Contents/MacOS` binary; Linux scans common
119
+ * extracted-binary locations).
120
+ *
121
+ * Returns the absolute path, or `null` when no Godot binary can be located.
122
+ * Pure / no spawn — exported for unit tests (the `os`/env are injectable via
123
+ * the running process; tests stub `fs` + env).
124
+ */
125
+ export function findGodotBinary(editorPath, os = platform()) {
126
+ // 1. Explicit path
127
+ if (editorPath !== undefined) {
128
+ const trimmed = editorPath.trim();
129
+ if (trimmed.length === 0)
130
+ return null;
131
+ const resolved = path.resolve(trimmed);
132
+ return existsAsFile(resolved) ? resolved : null;
133
+ }
134
+ // 2. Env overrides
135
+ for (const envVar of GODOT_BIN_ENV_VARS) {
136
+ const raw = process.env[envVar];
137
+ if (raw && raw.trim().length > 0) {
138
+ const resolved = path.resolve(raw.trim());
139
+ if (existsAsFile(resolved)) {
140
+ return resolved;
141
+ }
142
+ }
143
+ }
144
+ // 3. PATH
145
+ const onPath = findOnPath(os);
146
+ if (onPath)
147
+ return onPath;
148
+ // 4. Common install dirs
149
+ for (const candidate of commonInstallCandidates(os)) {
150
+ if (existsAsFile(candidate)) {
151
+ return candidate;
152
+ }
153
+ }
154
+ return null;
155
+ }
156
+ /**
157
+ * Spawn the Godot editor binary opening the given project, optionally with
158
+ * `GODOT_MCP_*` connection environment variables. Mirrors the Unity CLI's
159
+ * `launchEditor`: spawns detached, with `stdio: 'ignore'`, and `unref()`s so
160
+ * the parent process can exit without waiting on the editor.
161
+ *
162
+ * Godot's editor-open invocation is `--editor --path <project>` (the
163
+ * `--editor` flag forces the project to open in the editor rather than run).
164
+ *
165
+ * Library-safe (no process.exit, no stdout/stderr writes — observability is
166
+ * the caller's responsibility via the optional callbacks).
167
+ */
168
+ export function launchEditor(editorPath, projectPath, env, callbacks) {
169
+ const args = ['--editor', '--path', path.resolve(projectPath)];
170
+ const child = spawn(editorPath, args, {
171
+ detached: true,
172
+ stdio: 'ignore',
173
+ env: { ...process.env, ...env },
174
+ });
175
+ child.on('spawn', () => {
176
+ callbacks?.onSpawn?.(child.pid);
177
+ });
178
+ child.on('error', (err) => {
179
+ callbacks?.onError?.(err);
180
+ });
181
+ child.unref();
182
+ return child;
183
+ }
184
+ //# sourceMappingURL=godot-editor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"godot-editor.js","sourceRoot":"","sources":["../../src/utils/godot-editor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ export interface GodotProcess {
2
+ pid: number;
3
+ projectPath: string;
4
+ commandLine: string;
5
+ }
6
+ /**
7
+ * Check if a Godot editor process is running with the given project path.
8
+ * Returns process info if found, null otherwise.
9
+ */
10
+ export declare function findGodotProcess(projectPath: string): GodotProcess | null;
@@ -0,0 +1,93 @@
1
+ import { execFileSync, execSync } from 'child_process';
2
+ import { platform } from 'os';
3
+ import * as path from 'path';
4
+ import { verbose } from './ui.js';
5
+ /**
6
+ * Extract the `--path <project>` value from a Godot editor command line.
7
+ * Quote-aware: a double-quoted path (Windows CIM `CommandLine` shape for paths
8
+ * with spaces) is consumed whole, otherwise the first whitespace-delimited
9
+ * token is used. Returns the resolved absolute path, or null when absent.
10
+ */
11
+ function extractProjectPath(commandLine) {
12
+ const quoted = commandLine.match(/--path\s+"([^"]+)"/i);
13
+ if (quoted)
14
+ return path.resolve(quoted[1].trim());
15
+ const unquoted = commandLine.match(/--path\s+(\S+)/i);
16
+ if (unquoted)
17
+ return path.resolve(unquoted[1].trim());
18
+ return null;
19
+ }
20
+ /**
21
+ * Check if a Godot editor process is running with the given project path.
22
+ * Returns process info if found, null otherwise.
23
+ */
24
+ export function findGodotProcess(projectPath) {
25
+ const isWindows = platform() === 'win32';
26
+ const resolvedTarget = path.resolve(projectPath);
27
+ const normalizedTarget = isWindows ? resolvedTarget.toLowerCase() : resolvedTarget;
28
+ const processes = listGodotProcesses();
29
+ for (const proc of processes) {
30
+ const normalizedProc = isWindows ? proc.projectPath.toLowerCase() : proc.projectPath;
31
+ if (normalizedProc === normalizedTarget) {
32
+ verbose(`Found Godot process PID ${proc.pid} with project: ${proc.projectPath}`);
33
+ return proc;
34
+ }
35
+ }
36
+ verbose(`No Godot process found for project: ${projectPath}`);
37
+ return null;
38
+ }
39
+ /**
40
+ * List all running Godot editor processes with their project paths. Matches
41
+ * any process whose name contains "godot" (covers `Godot.exe`, `Godot_mono.exe`,
42
+ * `godot_mono_console.exe`, the macOS `Godot` binary, and Linux extracted
43
+ * binaries) and that carries a `--path` argument.
44
+ */
45
+ function listGodotProcesses() {
46
+ const os = platform();
47
+ const results = [];
48
+ try {
49
+ if (os === 'win32') {
50
+ const psCommand = "Get-CimInstance Win32_Process -Filter \"Name LIKE '%godot%'\" | Select-Object ProcessId,CommandLine | ForEach-Object { $_.ProcessId.ToString() + '|||' + $_.CommandLine }";
51
+ const output = execFileSync('powershell.exe', ['-NoProfile', '-Command', psCommand], { encoding: 'utf-8', timeout: 10000, stdio: ['pipe', 'pipe', 'pipe'] });
52
+ const lines = output.split('\n').filter((l) => l.trim().length > 0);
53
+ for (const line of lines) {
54
+ const sepIdx = line.indexOf('|||');
55
+ if (sepIdx === -1)
56
+ continue;
57
+ const pid = parseInt(line.substring(0, sepIdx).trim(), 10);
58
+ const commandLine = line.substring(sepIdx + 3).trim();
59
+ if (!Number.isFinite(pid) || pid === 0)
60
+ continue;
61
+ if (!/--path/i.test(commandLine))
62
+ continue;
63
+ const projectPath = extractProjectPath(commandLine);
64
+ if (projectPath) {
65
+ results.push({ pid, projectPath, commandLine });
66
+ }
67
+ }
68
+ }
69
+ else {
70
+ const output = execSync("ps -eo pid,args | grep -i '[g]odot' || true", { encoding: 'utf-8', timeout: 5000, stdio: ['pipe', 'pipe', 'pipe'] });
71
+ const lines = output.split('\n').filter((l) => l.trim().length > 0);
72
+ for (const line of lines) {
73
+ const match = line.trim().match(/^(\d+)\s+(.*)$/);
74
+ if (!match)
75
+ continue;
76
+ const pid = parseInt(match[1], 10);
77
+ const commandLine = match[2];
78
+ if (!/--path/i.test(commandLine))
79
+ continue;
80
+ const projectPath = extractProjectPath(commandLine);
81
+ if (projectPath) {
82
+ results.push({ pid, projectPath, commandLine });
83
+ }
84
+ }
85
+ }
86
+ }
87
+ catch (err) {
88
+ verbose(`Failed to list Godot processes: ${err instanceof Error ? err.message : String(err)}`);
89
+ }
90
+ verbose(`Found ${results.length} Godot process(es)`);
91
+ return results;
92
+ }
93
+ //# sourceMappingURL=godot-process.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"godot-process.js","sourceRoot":"","sources":["../../src/utils/godot-process.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ export type SupportedPlatform = 'win32' | 'darwin' | 'linux';
2
+ /** True when the process with the given PID is currently alive. */
3
+ export declare function isProcessAlive(pid: number, os?: SupportedPlatform): boolean;
4
+ /**
5
+ * Send a graceful-shutdown request. On POSIX this is SIGTERM; on Windows we use
6
+ * `taskkill` WITHOUT `/F` (a polite close request the OS routes to the process).
7
+ * Returns true when the signal was delivered without error.
8
+ */
9
+ export declare function sendGracefulShutdown(pid: number, os?: SupportedPlatform): boolean;
10
+ /** Hard-kill the process. SIGKILL on POSIX; `taskkill /F` on Windows. */
11
+ export declare function sendForceKill(pid: number, os?: SupportedPlatform): boolean;
12
+ /**
13
+ * Poll for the process to exit, up to `timeoutMs`. Resolves true when the
14
+ * process is gone, false on timeout.
15
+ */
16
+ export declare function waitForExit(pid: number, timeoutMs: number, os?: SupportedPlatform): Promise<boolean>;
@@ -0,0 +1,67 @@
1
+ import { execFileSync } from 'child_process';
2
+ import { platform } from 'os';
3
+ /** True when the process with the given PID is currently alive. */
4
+ export function isProcessAlive(pid, os = platform()) {
5
+ try {
6
+ if (os === 'win32') {
7
+ const out = execFileSync('tasklist', ['/FI', `PID eq ${pid}`, '/NH'], {
8
+ encoding: 'utf-8',
9
+ timeout: 5000,
10
+ });
11
+ return out.includes(String(pid));
12
+ }
13
+ // POSIX: signal 0 probes existence without delivering a signal.
14
+ process.kill(pid, 0);
15
+ return true;
16
+ }
17
+ catch {
18
+ return false;
19
+ }
20
+ }
21
+ /**
22
+ * Send a graceful-shutdown request. On POSIX this is SIGTERM; on Windows we use
23
+ * `taskkill` WITHOUT `/F` (a polite close request the OS routes to the process).
24
+ * Returns true when the signal was delivered without error.
25
+ */
26
+ export function sendGracefulShutdown(pid, os = platform()) {
27
+ try {
28
+ if (os === 'win32') {
29
+ execFileSync('taskkill', ['/PID', String(pid)], { encoding: 'utf-8', timeout: 5000, stdio: 'pipe' });
30
+ return true;
31
+ }
32
+ process.kill(pid, 'SIGTERM');
33
+ return true;
34
+ }
35
+ catch {
36
+ return false;
37
+ }
38
+ }
39
+ /** Hard-kill the process. SIGKILL on POSIX; `taskkill /F` on Windows. */
40
+ export function sendForceKill(pid, os = platform()) {
41
+ try {
42
+ if (os === 'win32') {
43
+ execFileSync('taskkill', ['/PID', String(pid), '/F'], { encoding: 'utf-8', timeout: 5000, stdio: 'pipe' });
44
+ return true;
45
+ }
46
+ process.kill(pid, 'SIGKILL');
47
+ return true;
48
+ }
49
+ catch {
50
+ return false;
51
+ }
52
+ }
53
+ /**
54
+ * Poll for the process to exit, up to `timeoutMs`. Resolves true when the
55
+ * process is gone, false on timeout.
56
+ */
57
+ export async function waitForExit(pid, timeoutMs, os = platform()) {
58
+ const start = Date.now();
59
+ const interval = 250;
60
+ while (Date.now() - start < timeoutMs) {
61
+ if (!isProcessAlive(pid, os))
62
+ return true;
63
+ await new Promise((resolve) => setTimeout(resolve, interval));
64
+ }
65
+ return !isProcessAlive(pid, os);
66
+ }
67
+ //# sourceMappingURL=godot-shutdown.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"godot-shutdown.js","sourceRoot":"","sources":["../../src/utils/godot-shutdown.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAE,MAAM,IAAI,CAAC;AAI9B,mEAAmE;AACnE,MAAM,UAAU,cAAc,CAAC,GAAW,EAAE,KAAwB,QAAQ,EAAuB;IACjG,IAAI,CAAC;QACH,IAAI,EAAE,KAAK,OAAO,EAAE,CAAC;YACnB,MAAM,GAAG,GAAG,YAAY,CAAC,UAAU,EAAE,CAAC,KAAK,EAAE,UAAU,GAAG,EAAE,EAAE,KAAK,CAAC,EAAE;gBACpE,QAAQ,EAAE,OAAO;gBACjB,OAAO,EAAE,IAAI;aACd,CAAC,CAAC;YACH,OAAO,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;QACnC,CAAC;QACD,gEAAgE;QAChE,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QACrB,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,oBAAoB,CAClC,GAAW,EACX,KAAwB,QAAQ,EAAuB;IAEvD,IAAI,CAAC;QACH,IAAI,EAAE,KAAK,OAAO,EAAE,CAAC;YACnB,YAAY,CAAC,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;YACrG,OAAO,IAAI,CAAC;QACd,CAAC;QACD,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;QAC7B,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,yEAAyE;AACzE,MAAM,UAAU,aAAa,CAC3B,GAAW,EACX,KAAwB,QAAQ,EAAuB;IAEvD,IAAI,CAAC;QACH,IAAI,EAAE,KAAK,OAAO,EAAE,CAAC;YACnB,YAAY,CAAC,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;YAC3G,OAAO,IAAI,CAAC;QACd,CAAC;QACD,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;QAC7B,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,GAAW,EACX,SAAiB,EACjB,KAAwB,QAAQ,EAAuB;IAEvD,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACzB,MAAM,QAAQ,GAAG,GAAG,CAAC;IACrB,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,GAAG,SAAS,EAAE,CAAC;QACtC,IAAI,CAAC,cAAc,CAAC,GAAG,EAAE,EAAE,CAAC;YAAE,OAAO,IAAI,CAAC;QAC1C,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC;IAChE,CAAC;IACD,OAAO,CAAC,cAAc,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;AAClC,CAAC"}
@@ -0,0 +1,13 @@
1
+ export interface InputOptions {
2
+ input?: string;
3
+ inputFile?: string;
4
+ }
5
+ /**
6
+ * Parse tool input from --input, --input-file, or stdin.
7
+ *
8
+ * - `--input-file -` or `--input-file /dev/stdin` reads from stdin (cross-platform).
9
+ * - `--input-file <path>` reads from a file.
10
+ * - `--input <json>` parses inline JSON.
11
+ * - Falls back to `{}` if nothing provided.
12
+ */
13
+ export declare function parseInput(options: InputOptions): string;
@@ -0,0 +1,72 @@
1
+ import * as fs from 'fs';
2
+ import * as path from 'path';
3
+ import * as ui from './ui.js';
4
+ import { verbose } from './ui.js';
5
+ import { parseJsonStrict, JsonParseError } from './json-parse.js';
6
+ /**
7
+ * Parse tool input from --input, --input-file, or stdin.
8
+ *
9
+ * - `--input-file -` or `--input-file /dev/stdin` reads from stdin (cross-platform).
10
+ * - `--input-file <path>` reads from a file.
11
+ * - `--input <json>` parses inline JSON.
12
+ * - Falls back to `{}` if nothing provided.
13
+ */
14
+ export function parseInput(options) {
15
+ if (options.inputFile) {
16
+ const isStdin = options.inputFile === '-' || options.inputFile === '/dev/stdin';
17
+ let content;
18
+ if (isStdin) {
19
+ verbose('Reading input from stdin...');
20
+ try {
21
+ content = fs.readFileSync(0, 'utf-8');
22
+ }
23
+ catch {
24
+ ui.error('Failed to read from stdin.');
25
+ process.exit(1);
26
+ }
27
+ if (!content.trim()) {
28
+ ui.error('No input received from stdin.');
29
+ process.exit(1);
30
+ }
31
+ }
32
+ else {
33
+ const filePath = path.resolve(options.inputFile);
34
+ if (!fs.existsSync(filePath)) {
35
+ ui.error(`Input file does not exist: ${filePath}`);
36
+ process.exit(1);
37
+ }
38
+ content = fs.readFileSync(filePath, 'utf-8');
39
+ }
40
+ try {
41
+ parseJsonStrict(content);
42
+ }
43
+ catch (err) {
44
+ const source = isStdin ? 'stdin' : options.inputFile;
45
+ if (err instanceof JsonParseError) {
46
+ ui.error(`--input-file content from '${source}' must be valid JSON\n${err.message}`);
47
+ }
48
+ else {
49
+ ui.error(`--input-file content from '${source}' must be valid JSON`);
50
+ }
51
+ process.exit(1);
52
+ }
53
+ return content;
54
+ }
55
+ if (options.input) {
56
+ try {
57
+ const result = parseJsonStrict(options.input);
58
+ return result.raw;
59
+ }
60
+ catch (err) {
61
+ if (err instanceof JsonParseError) {
62
+ ui.error(`--input must be valid JSON\n${err.message}`);
63
+ }
64
+ else {
65
+ ui.error('--input must be valid JSON');
66
+ }
67
+ process.exit(1);
68
+ }
69
+ }
70
+ return '{}';
71
+ }
72
+ //# sourceMappingURL=input.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"input.js","sourceRoot":"","sources":["../../src/utils/input.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAOlE;;;;;;;GAOG;AACH,MAAM,UAAU,UAAU,CAAC,OAAqB;IAC9C,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;QACtB,MAAM,OAAO,GAAG,OAAO,CAAC,SAAS,KAAK,GAAG,IAAI,OAAO,CAAC,SAAS,KAAK,YAAY,CAAC;QAChF,IAAI,OAAe,CAAC;QAEpB,IAAI,OAAO,EAAE,CAAC;YACZ,OAAO,CAAC,6BAA6B,CAAC,CAAC;YACvC,IAAI,CAAC;gBACH,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;YACxC,CAAC;YAAC,MAAM,CAAC;gBACP,EAAE,CAAC,KAAK,CAAC,4BAA4B,CAAC,CAAC;gBACvC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC;YACD,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC;gBACpB,EAAE,CAAC,KAAK,CAAC,+BAA+B,CAAC,CAAC;gBAC1C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC;QACH,CAAC;aAAM,CAAC;YACN,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;YACjD,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;gBAC7B,EAAE,CAAC,KAAK,CAAC,8BAA8B,QAAQ,EAAE,CAAC,CAAC;gBACnD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC;YACD,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QAC/C,CAAC;QAED,IAAI,CAAC;YACH,eAAe,CAAC,OAAO,CAAC,CAAC;QAC3B,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC;YACrD,IAAI,GAAG,YAAY,cAAc,EAAE,CAAC;gBAClC,EAAE,CAAC,KAAK,CAAC,8BAA8B,MAAM,yBAAyB,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;YACvF,CAAC;iBAAM,CAAC;gBACN,EAAE,CAAC,KAAK,CAAC,8BAA8B,MAAM,sBAAsB,CAAC,CAAC;YACvE,CAAC;YACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAED,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;QAClB,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,eAAe,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;YAC9C,OAAO,MAAM,CAAC,GAAG,CAAC;QACpB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,GAAG,YAAY,cAAc,EAAE,CAAC;gBAClC,EAAE,CAAC,KAAK,CAAC,+BAA+B,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;YACzD,CAAC;iBAAM,CAAC;gBACN,EAAE,CAAC,KAAK,CAAC,4BAA4B,CAAC,CAAC;YACzC,CAAC;YACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Robust JSON parsing with detailed error reporting.
3
+ *
4
+ * 1. Try to parse the raw string as JSON.
5
+ * 2. If invalid, report the exact position where parsing fails.
6
+ */
7
+ export interface JsonParseResult {
8
+ readonly value: unknown;
9
+ readonly raw: string;
10
+ readonly wasStringified: boolean;
11
+ }
12
+ export declare class JsonParseError extends Error {
13
+ readonly position: number;
14
+ readonly snippet: string;
15
+ constructor(message: string, position: number, snippet: string);
16
+ }
17
+ /**
18
+ * Parse a string as strict JSON. Throws {@link JsonParseError} with
19
+ * position and snippet on failure.
20
+ *
21
+ * @param input The raw string to parse as JSON.
22
+ * @returns A result containing the parsed value.
23
+ * @throws {@link JsonParseError} with position and snippet on failure.
24
+ */
25
+ export declare function parseJsonStrict(input: string): JsonParseResult;
@@ -0,0 +1,83 @@
1
+ export class JsonParseError extends Error {
2
+ constructor(message, position, snippet) {
3
+ super(message);
4
+ this.name = 'JsonParseError';
5
+ this.position = position;
6
+ this.snippet = snippet;
7
+ }
8
+ }
9
+ /**
10
+ * Extract the error position from a JSON.parse SyntaxError message.
11
+ * Common formats:
12
+ * - "... at position 42" (V8 / Node)
13
+ * - "... at line 3 column 5" (some engines)
14
+ * - "Unexpected token X in JSON at position 42"
15
+ */
16
+ function extractErrorPosition(error, input) {
17
+ const msg = error.message;
18
+ const posMatch = msg.match(/position\s+(\d+)/i);
19
+ if (posMatch) {
20
+ return parseInt(posMatch[1], 10);
21
+ }
22
+ const lineColMatch = msg.match(/line\s+(\d+)\s+column\s+(\d+)/i);
23
+ if (lineColMatch) {
24
+ const targetLine = parseInt(lineColMatch[1], 10);
25
+ const targetCol = parseInt(lineColMatch[2], 10);
26
+ const lines = input.split('\n');
27
+ let offset = 0;
28
+ for (let i = 0; i < targetLine - 1 && i < lines.length; i++) {
29
+ offset += lines[i].length + 1; // +1 for newline
30
+ }
31
+ return offset + targetCol - 1;
32
+ }
33
+ return -1;
34
+ }
35
+ /**
36
+ * Build a human-readable snippet around the error position.
37
+ */
38
+ function buildSnippet(input, position) {
39
+ if (position < 0 || position > input.length) {
40
+ return input.length <= 80 ? input : input.slice(0, 80) + '...';
41
+ }
42
+ const contextBefore = 20;
43
+ const contextAfter = 20;
44
+ const start = Math.max(0, position - contextBefore);
45
+ const end = Math.min(input.length, position + contextAfter);
46
+ const before = (start > 0 ? '...' : '') + input.slice(start, position);
47
+ const errorChar = position < input.length ? input[position] : '<end>';
48
+ const after = input.slice(position + 1, end) + (end < input.length ? '...' : '');
49
+ const pointer = ' '.repeat(before.length) + '^';
50
+ return `${before}${errorChar}${after}\n${pointer}`;
51
+ }
52
+ /**
53
+ * Build a detailed error message for a JSON parse failure.
54
+ */
55
+ function buildDetailedError(input, error) {
56
+ const position = extractErrorPosition(error, input);
57
+ const snippet = buildSnippet(input, position);
58
+ const posInfo = position >= 0 ? ` at position ${position}` : '';
59
+ const message = `Invalid JSON${posInfo}: ${error.message}\n\n` +
60
+ ` ${snippet.split('\n').join('\n ')}\n`;
61
+ return new JsonParseError(message, position, snippet);
62
+ }
63
+ /**
64
+ * Parse a string as strict JSON. Throws {@link JsonParseError} with
65
+ * position and snippet on failure.
66
+ *
67
+ * @param input The raw string to parse as JSON.
68
+ * @returns A result containing the parsed value.
69
+ * @throws {@link JsonParseError} with position and snippet on failure.
70
+ */
71
+ export function parseJsonStrict(input) {
72
+ try {
73
+ const value = JSON.parse(input);
74
+ return { value, raw: input, wasStringified: false };
75
+ }
76
+ catch (error) {
77
+ if (error instanceof SyntaxError) {
78
+ throw buildDetailedError(input, error);
79
+ }
80
+ throw error;
81
+ }
82
+ }
83
+ //# sourceMappingURL=json-parse.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json-parse.js","sourceRoot":"","sources":["../../src/utils/json-parse.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ export declare const PING_ENDPOINT = "/api/tools/ping";
2
+ export interface ProbeSuccess {
3
+ ok: true;
4
+ baseUrl: string;
5
+ data: unknown;
6
+ }
7
+ export interface ProbeFailure {
8
+ ok: false;
9
+ reason: string;
10
+ }
11
+ export type ProbeResult = ProbeSuccess | ProbeFailure;
12
+ /**
13
+ * Probe a Godot-MCP server's ping endpoint (`<base>/api/tools/ping`).
14
+ * Returns a structured result. The `ping` tool is registered by the
15
+ * `Tool_Ping` family (pure-managed, no editor required), so a connected
16
+ * plugin responds `{ "structured": { "result": "pong" } }`.
17
+ */
18
+ export declare function probe(baseUrl: string, headers: Record<string, string>, timeoutMs: number): Promise<ProbeResult>;