puppet-mcp 4.5.3 → 4.5.5
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/README.md +11 -5
- package/bin/puppet-mcp.js +40 -9
- package/engine-manifest.json +6 -6
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -7,12 +7,12 @@ manifest — it contains no server bytes.
|
|
|
7
7
|
## Run
|
|
8
8
|
|
|
9
9
|
```sh
|
|
10
|
-
npx puppet-mcp@
|
|
10
|
+
npx puppet-mcp@latest
|
|
11
11
|
```
|
|
12
12
|
|
|
13
13
|
Global installs are refused by design (`npm i -g` exits non-zero): a
|
|
14
|
-
global copy would shadow the
|
|
15
|
-
|
|
14
|
+
global copy would shadow the `npx` invocation and run a stale engine.
|
|
15
|
+
Always invoke it through `npx` as above.
|
|
16
16
|
|
|
17
17
|
Or pin it in an MCP client as a stdio server with command and args:
|
|
18
18
|
|
|
@@ -30,13 +30,14 @@ stdout belongs to the MCP channel.
|
|
|
30
30
|
## Diagnostics (no network)
|
|
31
31
|
|
|
32
32
|
```sh
|
|
33
|
-
npx puppet-mcp@
|
|
33
|
+
npx puppet-mcp@latest --doctor
|
|
34
34
|
```
|
|
35
35
|
|
|
36
36
|
Prints the launcher version, the pinned manifest, the resolved engine
|
|
37
37
|
path, the engine version parsed from the cache directory name, and
|
|
38
38
|
whether they match; exits 0, performs no fetch. `--print-manifest` is
|
|
39
|
-
an alias. `npx puppet-mcp@
|
|
39
|
+
an alias. `npx puppet-mcp@latest --version` prints the package name and
|
|
40
|
+
the version it is running.
|
|
40
41
|
|
|
41
42
|
## Requirements
|
|
42
43
|
|
|
@@ -56,6 +57,11 @@ There is no fully offline fresh install: the first serve run still downloads
|
|
|
56
57
|
the pinned binary, so treat these as pins and overrides, not as a no-network
|
|
57
58
|
setup.
|
|
58
59
|
|
|
60
|
+
## Full documentation
|
|
61
|
+
|
|
62
|
+
https://github.com/nathwn12/puppet/blob/main/README.md
|
|
63
|
+
https://www.npmjs.com/package/puppet-mcp
|
|
64
|
+
|
|
59
65
|
## License
|
|
60
66
|
|
|
61
67
|
MIT — see LICENSE.
|
package/bin/puppet-mcp.js
CHANGED
|
@@ -48,6 +48,12 @@ const MANIFEST_PATH = path.join(PKG_DIR, 'engine-manifest.json');
|
|
|
48
48
|
const PKG_PATH = path.join(PKG_DIR, 'package.json');
|
|
49
49
|
const PLATFORM_OVERRIDE_ENV = 'PUPPET_MCP_ALLOW_NON_WINDOWS';
|
|
50
50
|
const RUNTIME_CACHE_OVERRIDE_ENV = 'PUPPET_ENGINE_CACHE';
|
|
51
|
+
// Local-bundle override, diagnostics only. A normal run leaves it unset and
|
|
52
|
+
// downloads runtime.archive from the Release. The pre-publish cleanroom names
|
|
53
|
+
// the archive it just built, because the Release that would serve it does not
|
|
54
|
+
// exist until AFTER the build job passes. Every size/sha256 assertion still
|
|
55
|
+
// runs on the local bytes: an override can never smuggle in a bad artifact.
|
|
56
|
+
const RUNTIME_BUNDLE_OVERRIDE_ENV = 'PUPPET_ENGINE_BUNDLE';
|
|
51
57
|
const DOWNLOAD_TIMEOUT_MS = 15 * 60 * 1000;
|
|
52
58
|
// Staging/extraction guards: the real runtime bundle is ~2 MB. These caps
|
|
53
59
|
// reject zip bombs, never the real artifact.
|
|
@@ -177,6 +183,12 @@ function printDoctor(manifest, pkgVersion) {
|
|
|
177
183
|
runtimeCacheDir: runtime.dir,
|
|
178
184
|
runtimeCacheOverridden: runtime.overridden,
|
|
179
185
|
runtimeCacheNotes: runtime.notes,
|
|
186
|
+
runtimeBundleOverride: {
|
|
187
|
+
env: RUNTIME_BUNDLE_OVERRIDE_ENV,
|
|
188
|
+
set: Boolean(process.env[RUNTIME_BUNDLE_OVERRIDE_ENV]),
|
|
189
|
+
path: process.env[RUNTIME_BUNDLE_OVERRIDE_ENV] ?? null,
|
|
190
|
+
note: 'diagnostics only: the pre-publish cleanroom points this at the archive it just built; a normal run leaves it unset and downloads runtime.archive, whose size and sha256 are checked either way',
|
|
191
|
+
},
|
|
180
192
|
runtime: manifest.runtime,
|
|
181
193
|
network: 'none: this diagnostic performs no fetch and exits before any download code',
|
|
182
194
|
};
|
|
@@ -195,6 +207,8 @@ function usage(exitCode, stream) {
|
|
|
195
207
|
' --help, -h print this usage',
|
|
196
208
|
'',
|
|
197
209
|
'runtime cache: ' + path.join('%LOCALAPPDATA%', 'puppet', 'engine', '<serverVersion>-<bundleSha8>') + ` (override: ${RUNTIME_CACHE_OVERRIDE_ENV})`,
|
|
210
|
+
`local bundle: unset by default; ${RUNTIME_BUNDLE_OVERRIDE_ENV} names a zip file to verify and extract`,
|
|
211
|
+
' instead of downloading (pre-publish diagnostics only; size and sha256 are still checked)',
|
|
198
212
|
`platform: windows-x86_64 only (override: ${PLATFORM_OVERRIDE_ENV}=1, diagnostics only)`,
|
|
199
213
|
].join('\n') + '\n';
|
|
200
214
|
stream.write(text);
|
|
@@ -385,21 +399,38 @@ async function ensureRuntime(manifest, cacheDir) {
|
|
|
385
399
|
return cacheDir;
|
|
386
400
|
}
|
|
387
401
|
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
402
|
+
// Local bundle override: the pre-publish cleanroom builds the archive in
|
|
403
|
+
// this same job, before any GitHub Release exists, so it hands the zip over
|
|
404
|
+
// instead of fetching a URL that cannot exist yet. The size and sha256
|
|
405
|
+
// checks below stay unconditional: a local zip that disagrees with the
|
|
406
|
+
// manifest is refused exactly like a corrupt download would be.
|
|
407
|
+
const localBundle = process.env[RUNTIME_BUNDLE_OVERRIDE_ENV];
|
|
408
|
+
const origin = localBundle ? 'local bundle' : 'download';
|
|
391
409
|
let data;
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
410
|
+
if (localBundle) {
|
|
411
|
+
log(`provisioning runtime cache: ${cacheDir}`);
|
|
412
|
+
log(`reading ${localBundle} (${RUNTIME_BUNDLE_OVERRIDE_ENV} set; pre-publish diagnostics only)`);
|
|
413
|
+
try {
|
|
414
|
+
data = fs.readFileSync(localBundle);
|
|
415
|
+
} catch (err) {
|
|
416
|
+
fail(`cannot read local bundle ${localBundle}: ${err.message}`);
|
|
417
|
+
}
|
|
418
|
+
} else {
|
|
419
|
+
const url = `${rt.source}/${rt.archive.name}`;
|
|
420
|
+
log(`provisioning runtime cache: ${cacheDir}`);
|
|
421
|
+
log(`downloading ${url} (${rt.archive.size} bytes)`);
|
|
422
|
+
try {
|
|
423
|
+
data = await downloadToMemory(url);
|
|
424
|
+
} catch (err) {
|
|
425
|
+
fail(err.message);
|
|
426
|
+
}
|
|
396
427
|
}
|
|
397
428
|
if (data.length !== rt.archive.size) {
|
|
398
|
-
fail(
|
|
429
|
+
fail(`${origin} size ${data.length} != manifest ${rt.archive.size}; wrote nothing.`);
|
|
399
430
|
}
|
|
400
431
|
const digest = crypto.createHash('sha256').update(data).digest('hex');
|
|
401
432
|
if (digest !== rt.archive.sha256.toLowerCase()) {
|
|
402
|
-
fail(
|
|
433
|
+
fail(`${origin} sha256 mismatch; wrote nothing.`);
|
|
403
434
|
}
|
|
404
435
|
|
|
405
436
|
// Extract into a staging dir, verify, then rename: the target dir is
|
package/engine-manifest.json
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"_comment": "Pinned server manifest for the puppet-mcp launcher. The published package holds ONLY this launcher plus this manifest (no server bytes). On first run the launcher downloads ONLY runtime.archive from the tagged GitHub Release, verifying its sha256 before and after extraction. The release workflow fills the runtime.* hashes it computes from the real build artifacts; the committed manifest carries placeholders the launcher refuses to run with.",
|
|
3
3
|
"package": "puppet-mcp",
|
|
4
|
-
"serverVersion": "4.5.
|
|
4
|
+
"serverVersion": "4.5.5",
|
|
5
5
|
"runtime": {
|
|
6
|
-
"source": "https://github.com/nathwn12/puppet/releases/download/v4.5.
|
|
6
|
+
"source": "https://github.com/nathwn12/puppet/releases/download/v4.5.5",
|
|
7
7
|
"archive": {
|
|
8
|
-
"name": "puppet-v4.5.
|
|
9
|
-
"sha256": "
|
|
10
|
-
"size":
|
|
8
|
+
"name": "puppet-v4.5.5-windows-x86_64.zip",
|
|
9
|
+
"sha256": "2b37bd6b6eec0011b7208c9d821a641ff1c7257e20e8de19c99465c2edb5b4b4",
|
|
10
|
+
"size": 688301
|
|
11
11
|
},
|
|
12
12
|
"server": {
|
|
13
13
|
"name": "puppet.exe",
|
|
14
|
-
"sha256": "
|
|
14
|
+
"sha256": "1159d0ffda950a2f262abade2b2124af31427a15d426ddc100434307724d4f14",
|
|
15
15
|
"size": 1810944
|
|
16
16
|
}
|
|
17
17
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "puppet-mcp",
|
|
3
|
-
"version": "4.5.
|
|
3
|
+
"version": "4.5.5",
|
|
4
4
|
"description": "Windows desktop-control MCP server (npx launcher): provisions the pinned server binary from the GitHub Release on first run, then serves MCP over stdio",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -15,8 +15,8 @@
|
|
|
15
15
|
"puppet-mcp": "./bin/puppet-mcp.js"
|
|
16
16
|
},
|
|
17
17
|
"scripts": {
|
|
18
|
-
"preinstall": "node -e \"if(process.env.npm_config_global==='true'){console.error('puppet-mcp: global install refused — use npx puppet-mcp@4.5.
|
|
19
|
-
"postinstall": "node -e \"if(process.env.npm_config_global==='true'){console.error('puppet-mcp: global install refused — use npx puppet-mcp@4.5.
|
|
18
|
+
"preinstall": "node -e \"if(process.env.npm_config_global==='true'){console.error('puppet-mcp: global install refused — use npx puppet-mcp@4.5.4');process.exit(1)}\"",
|
|
19
|
+
"postinstall": "node -e \"if(process.env.npm_config_global==='true'){console.error('puppet-mcp: global install refused — use npx puppet-mcp@4.5.4');process.exit(1)}\""
|
|
20
20
|
},
|
|
21
21
|
"files": [
|
|
22
22
|
"bin/",
|