godot-cli 0.20.1 → 0.21.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 (36) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/README.md +20 -4
  3. package/dist/commands/login.js +54 -24
  4. package/dist/commands/login.js.map +1 -1
  5. package/dist/commands/open.js +2 -2
  6. package/dist/commands/open.js.map +1 -1
  7. package/dist/commands/run-tool-builder.js +1 -1
  8. package/dist/commands/run-tool-builder.js.map +1 -1
  9. package/dist/commands/status.js +1 -1
  10. package/dist/commands/status.js.map +1 -1
  11. package/dist/commands/wait-for-ready.js +1 -1
  12. package/dist/commands/wait-for-ready.js.map +1 -1
  13. package/dist/lib/enroll.js +29 -19
  14. package/dist/lib/enroll.js.map +1 -1
  15. package/dist/utils/addon-deps.js +1 -1
  16. package/dist/utils/cloud-login.d.ts +80 -14
  17. package/dist/utils/cloud-login.js +204 -51
  18. package/dist/utils/cloud-login.js.map +1 -1
  19. package/dist/utils/connection.d.ts +13 -8
  20. package/dist/utils/connection.js +116 -15
  21. package/dist/utils/connection.js.map +1 -1
  22. package/dist/utils/credentials.d.ts +13 -19
  23. package/dist/utils/credentials.js +13 -59
  24. package/dist/utils/credentials.js.map +1 -1
  25. package/dist/utils/machine-store.d.ts +76 -0
  26. package/dist/utils/machine-store.js +129 -0
  27. package/dist/utils/machine-store.js.map +1 -0
  28. package/dist/utils/server-source.d.ts +1 -1
  29. package/dist/utils/server-source.js +1 -1
  30. package/dist/utils/ui.d.ts +5 -0
  31. package/dist/utils/ui.js +15 -0
  32. package/dist/utils/ui.js.map +1 -1
  33. package/package.json +2 -2
  34. package/dist/utils/machine-credentials.d.ts +0 -74
  35. package/dist/utils/machine-credentials.js +0 -182
  36. package/dist/utils/machine-credentials.js.map +0 -1
@@ -1,182 +0,0 @@
1
- import * as fs from 'fs';
2
- import * as os from 'os';
3
- import * as path from 'path';
4
- import { execFileSync } from 'child_process';
5
- /**
6
- * The shared **machine credential store** at `~/.ai-game-dev/` — a single per-machine home for the
7
- * ai-game.dev account credential (`credentials.json`). Engines, CLIs, and the local server all read
8
- * this store, so **sign-in happens once per machine** (design `06-engine-plugins.md` / D12).
9
- *
10
- * This is the TypeScript peer of the shared C# `MachineCredentialStore`
11
- * (`MCP-Plugin-dotnet/McpPlugin/src/AgentConfig/MachineCredentialStore.cs`). The on-disk contract is
12
- * matched byte-for-byte so a credential written by `godot-cli login` is read by the engine plugin
13
- * (which auto-adopts it on editor boot) and vice-versa:
14
- *
15
- * - **POSIX** — `credentials.json` is written plaintext with `0600` permissions inside a `0700`
16
- * directory.
17
- * - **Windows** — the file content is **DPAPI-encrypted** with the current user's key
18
- * (`CryptProtectData`, `CurrentUser` scope, no entropy) so the on-disk bytes are never plaintext.
19
- * Node has no built-in DPAPI, so we interop via PowerShell's `System.Security.Cryptography.
20
- * ProtectedData`, which is a managed wrapper over the very same `CryptProtectData`/
21
- * `CryptUnprotectData` calls the C# store uses — the blobs are cross-readable.
22
- *
23
- * Credentials are NEVER written to a project file / VCS. The optional `--project` per-project override
24
- * (project-local `.godot-mcp/credentials.json`, gitignored) is handled by `credentials.ts`, not here.
25
- */
26
- /** Directory name under the user home that holds the store (matches C# `MachineCredentialStore.DirectoryName`). */
27
- export const MACHINE_STORE_DIR_NAME = '.ai-game-dev';
28
- /** File name of the secret credential document. */
29
- export const MACHINE_CREDENTIALS_FILE_NAME = 'credentials.json';
30
- /**
31
- * Optional env override for the store directory (advanced use / tests). When set, this exact
32
- * directory is used verbatim; otherwise the store lives at `~/.ai-game-dev`. The DEFAULT matches the
33
- * C# store so cross-tool interop holds — the override never changes the production path.
34
- */
35
- export const MACHINE_STORE_DIR_ENV = 'AI_GAME_DEV_CREDENTIALS_DIR';
36
- // Schema version of the persisted document (matches C# `MachineCredentials.Version`).
37
- const SCHEMA_VERSION = 1;
38
- /** Absolute path of the store directory (honoring the env override). */
39
- export function getMachineStoreDir(baseDirOverride) {
40
- if (baseDirOverride)
41
- return baseDirOverride;
42
- const envDir = process.env[MACHINE_STORE_DIR_ENV];
43
- if (envDir && envDir.trim().length > 0)
44
- return envDir;
45
- return path.join(os.homedir(), MACHINE_STORE_DIR_NAME);
46
- }
47
- /** Absolute path of the secret credential file. */
48
- export function getMachineCredentialsPath(baseDirOverride) {
49
- return path.join(getMachineStoreDir(baseDirOverride), MACHINE_CREDENTIALS_FILE_NAME);
50
- }
51
- /** True when a credential file exists in the store. */
52
- export function machineCredentialsExist(baseDirOverride) {
53
- return fs.existsSync(getMachineCredentialsPath(baseDirOverride));
54
- }
55
- /**
56
- * Read and (on Windows) decrypt the stored credentials, or `null` when none are present / empty.
57
- * Throws on a decryption failure or malformed JSON (a corrupt or foreign-user credential); callers on
58
- * a hot path should use {@link readMachineAccessToken}, which swallows those.
59
- */
60
- export function readMachineCredentials(baseDirOverride) {
61
- const credentialsPath = getMachineCredentialsPath(baseDirOverride);
62
- if (!fs.existsSync(credentialsPath)) {
63
- return null;
64
- }
65
- const raw = fs.readFileSync(credentialsPath);
66
- if (raw.length === 0) {
67
- return null;
68
- }
69
- const plaintext = isWindows() ? unprotectDpapi(raw) : raw;
70
- const json = plaintext.toString('utf8');
71
- if (json.trim().length === 0) {
72
- return null;
73
- }
74
- const parsed = JSON.parse(json);
75
- return parsed;
76
- }
77
- /**
78
- * Encrypt (Windows) / restrict (POSIX) and write `credentials` to the store, creating the store
79
- * directory with owner-only permissions if needed.
80
- */
81
- export function writeMachineCredentials(credentials, baseDirOverride) {
82
- const dir = getMachineStoreDir(baseDirOverride);
83
- const credentialsPath = path.join(dir, MACHINE_CREDENTIALS_FILE_NAME);
84
- ensureStoreDirectory(dir);
85
- const json = serialize(credentials);
86
- const plaintext = Buffer.from(json, 'utf8');
87
- const bytes = isWindows() ? protectDpapi(plaintext) : plaintext;
88
- fs.writeFileSync(credentialsPath, bytes, { mode: 0o600 });
89
- setPosixPermissions(credentialsPath, 0o600);
90
- }
91
- /**
92
- * Convenience reader for the persisted access token. Swallows a missing / malformed / undecryptable
93
- * file (returns undefined) so a broken store can never crash a command; `login` re-authenticates and
94
- * overwrites it.
95
- */
96
- export function readMachineAccessToken(baseDirOverride) {
97
- let credentials;
98
- try {
99
- credentials = readMachineCredentials(baseDirOverride);
100
- }
101
- catch {
102
- return undefined;
103
- }
104
- const token = credentials?.accessToken;
105
- return typeof token === 'string' && token.trim().length > 0 ? token : undefined;
106
- }
107
- /** Delete the stored credentials (sign-out). No-op when none exist. */
108
- export function deleteMachineCredentials(baseDirOverride) {
109
- const credentialsPath = getMachineCredentialsPath(baseDirOverride);
110
- if (fs.existsSync(credentialsPath)) {
111
- fs.rmSync(credentialsPath, { force: true });
112
- }
113
- }
114
- // ── Serialization ────────────────────────────────────────────────────────────────────────────────
115
- function serialize(credentials) {
116
- // Mirror the C# store's camelCase + WhenWritingNull: always emit `version`, omit null/undefined
117
- // optional fields. Indentation is cosmetic (the reader is whitespace-insensitive).
118
- const doc = { version: credentials.version ?? SCHEMA_VERSION };
119
- if (credentials.accessToken != null)
120
- doc.accessToken = credentials.accessToken;
121
- if (credentials.refreshToken != null)
122
- doc.refreshToken = credentials.refreshToken;
123
- if (credentials.expiresAt != null)
124
- doc.expiresAt = credentials.expiresAt;
125
- if (credentials.serverTarget != null)
126
- doc.serverTarget = credentials.serverTarget;
127
- if (credentials.subject != null)
128
- doc.subject = credentials.subject;
129
- return JSON.stringify(doc, null, 2) + '\n';
130
- }
131
- // ── Filesystem permissions ───────────────────────────────────────────────────────────────────────
132
- function ensureStoreDirectory(dir) {
133
- fs.mkdirSync(dir, { recursive: true, mode: 0o700 });
134
- setPosixPermissions(dir, 0o700);
135
- }
136
- function setPosixPermissions(target, mode) {
137
- if (isWindows())
138
- return; // chmod is a no-op on Windows; DPAPI provides at-rest protection there.
139
- try {
140
- fs.chmodSync(target, mode);
141
- }
142
- catch {
143
- // Best-effort only — never fail persistence over a chmod (e.g. exotic filesystems).
144
- }
145
- }
146
- // ── Windows DPAPI via PowerShell (System.Security.Cryptography.ProtectedData) ───────────────────────
147
- // ProtectedData.Protect/Unprotect wrap CryptProtectData/CryptUnprotectData with the SAME CurrentUser
148
- // scope + null entropy the C# MachineCredentialStore uses, so the on-disk blobs are cross-readable.
149
- function isWindows() {
150
- return process.platform === 'win32';
151
- }
152
- const DPAPI_PROTECT_SCRIPT = "Add-Type -AssemblyName System.Security; " +
153
- "$in = [Console]::In.ReadToEnd().Trim(); " +
154
- "$bytes = [Convert]::FromBase64String($in); " +
155
- "$prot = [System.Security.Cryptography.ProtectedData]::Protect($bytes, $null, 'CurrentUser'); " +
156
- "[Console]::Out.Write([Convert]::ToBase64String($prot))";
157
- const DPAPI_UNPROTECT_SCRIPT = "Add-Type -AssemblyName System.Security; " +
158
- "$in = [Console]::In.ReadToEnd().Trim(); " +
159
- "$bytes = [Convert]::FromBase64String($in); " +
160
- "$plain = [System.Security.Cryptography.ProtectedData]::Unprotect($bytes, $null, 'CurrentUser'); " +
161
- "[Console]::Out.Write([Convert]::ToBase64String($plain))";
162
- function protectDpapi(plaintext) {
163
- return runDpapi(DPAPI_PROTECT_SCRIPT, plaintext, 'encrypt');
164
- }
165
- function unprotectDpapi(cipher) {
166
- return runDpapi(DPAPI_UNPROTECT_SCRIPT, cipher, 'decrypt');
167
- }
168
- function runDpapi(script, input, op) {
169
- try {
170
- const out = execFileSync('powershell', ['-NoProfile', '-NonInteractive', '-Command', script], {
171
- input: input.toString('base64'),
172
- encoding: 'utf8',
173
- windowsHide: true,
174
- });
175
- return Buffer.from(out.trim(), 'base64');
176
- }
177
- catch (err) {
178
- const message = err instanceof Error ? err.message : String(err);
179
- throw new Error(`Failed to ${op} the machine credential store via DPAPI: ${message}`);
180
- }
181
- }
182
- //# sourceMappingURL=machine-credentials.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"machine-credentials.js","sourceRoot":"","sources":["../../src/utils/machine-credentials.ts"],"names":[],"mappings":"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"}