pulumi-package-docs 0.8.0 → 0.9.1
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 +98 -4
- package/bin/args.js +62 -3
- package/bin/args.test.js +60 -0
- package/bin/cli-bun.js +55 -23
- package/bin/cli.js +74 -28
- package/bin/cli.test.js +18 -0
- package/bin/static.js +196 -0
- package/bin/static.test.js +176 -0
- package/dist/client/assets/MemberDetail-Du4HYTda.js +1 -0
- package/dist/client/assets/{token-oQmZfAP3.js → examples-zkHFEaMt.js} +1 -1
- package/dist/client/assets/index-g58gbZKl.js +12 -0
- package/dist/client/assets/matchContext-BfDTxnb0.js +2 -0
- package/dist/client/assets/providers._name-DztqmroK.js +1 -0
- package/dist/client/assets/providers._name.functions._token-Dds2hD5R.js +1 -0
- package/dist/client/assets/providers._name.functions._token-DkZe4R_v.js +1 -0
- package/dist/client/assets/providers._name.index-B6cK3ZCZ.js +1 -0
- package/dist/client/assets/providers._name.index-CvFTUtAs.js +1 -0
- package/dist/client/assets/providers._name.resources._token-Bf7TPYcB.js +1 -0
- package/dist/client/assets/providers._name.resources._token-CIjv9yb8.js +1 -0
- package/dist/client/assets/routes-Dz3Kksbm.js +1 -0
- package/dist/mcp/stdio.js +449 -0
- package/dist/server/assets/{MemberDetail-C5sAHNZW.js → MemberDetail-CdHUSmQD.js} +2 -1
- package/dist/server/assets/{_tanstack-start-manifest_v-B0J-S-em.js → _tanstack-start-manifest_v-Drm3Ru6D.js} +15 -15
- package/dist/server/assets/api-D49ZDhMh.js +27 -0
- package/dist/server/assets/{providers._name.functions._token-Gkw4zt3M.js → providers._name.functions._token-BvkwmQ-L.js} +3 -2
- package/dist/server/assets/{providers._name.index-CEXkl-76.js → providers._name.index-DBkfEjsy.js} +3 -2
- package/dist/server/assets/{providers._name.resources._token-R_i2MmRl.js → providers._name.resources._token-Sl31Qlvd.js} +3 -2
- package/dist/server/assets/{schema.server-B-VvU1qb.js → providers.server-B1ZHZ5jE.js} +48 -1
- package/dist/server/assets/{router-1INob9fh.js → router-_zs8P-B2.js} +24 -87
- package/dist/server/assets/{routes-4jiXnS1p.js → routes-BUxagg9r.js} +1 -1
- package/dist/server/assets/token-DBEFeZIN.js +92 -0
- package/dist/server/server.js +987 -375
- package/examples/github-pages.yml +56 -0
- package/examples/gitlab-ci.yml +22 -0
- package/package.json +7 -3
- package/src/components/ThemeToggle.tsx +37 -0
- package/src/lib/pulumi/api.ts +18 -69
- package/src/lib/pulumi/mcp.server.test.ts +112 -0
- package/src/lib/pulumi/mcp.server.ts +11 -6
- package/src/lib/pulumi/providers.server.ts +80 -0
- package/src/lib/pulumi/stdio.server.ts +16 -0
- package/src/lib/pulumi/token.test.ts +44 -1
- package/src/lib/pulumi/token.ts +28 -0
- package/src/lib/static-docs.ts +15 -0
- package/src/router.tsx +3 -0
- package/src/routes/__root.tsx +6 -3
- package/src/routes/providers.$name.functions.$token.tsx +7 -4
- package/src/routes/providers.$name.index.tsx +2 -2
- package/src/routes/providers.$name.resources.$token.tsx +7 -4
- package/vite.config.ts +41 -1
- package/dist/client/assets/MemberDetail-BS9DbqEt.js +0 -1
- package/dist/client/assets/index-2FzxAhzN.js +0 -13
- package/dist/client/assets/providers._name-FmJEVkdV.js +0 -1
- package/dist/client/assets/providers._name.functions._token-BzjmNHea.js +0 -1
- package/dist/client/assets/providers._name.functions._token-D768U6I-.js +0 -1
- package/dist/client/assets/providers._name.index-C42yQ95z.js +0 -1
- package/dist/client/assets/providers._name.index-Dm0YiZWP.js +0 -1
- package/dist/client/assets/providers._name.resources._token-CIYPoqyA.js +0 -1
- package/dist/client/assets/providers._name.resources._token-D0OLvgo_.js +0 -1
- package/dist/client/assets/routes-DKNWlgPZ.js +0 -1
- package/dist/client/assets/useSelector-BIt42tGI.js +0 -1
- package/dist/server/assets/api-C55bS4R6.js +0 -64
package/README.md
CHANGED
|
@@ -11,13 +11,27 @@ npx pulumi-package-docs
|
|
|
11
11
|
This serves docs for the Pulumi project in your current directory. Options:
|
|
12
12
|
|
|
13
13
|
```bash
|
|
14
|
-
pulumi-package-docs [options]
|
|
14
|
+
pulumi-package-docs [command] [options]
|
|
15
15
|
|
|
16
|
+
Commands:
|
|
17
|
+
serve Serve the docs (default)
|
|
18
|
+
static Generate a static site to publish (GitHub/GitLab Pages)
|
|
19
|
+
|
|
20
|
+
Options:
|
|
16
21
|
-d, --dir <path> Pulumi project directory to inspect (default: current directory)
|
|
22
|
+
-h, --help Show this help message
|
|
23
|
+
|
|
24
|
+
serve options:
|
|
17
25
|
-p, --port <port> Port to serve on (default: 3000)
|
|
18
26
|
--host Expose the server on your network
|
|
19
27
|
--open Open the docs in your default browser once ready
|
|
20
|
-
|
|
28
|
+
--stdio Run as an MCP server over stdio instead of serving the docs site
|
|
29
|
+
|
|
30
|
+
static options:
|
|
31
|
+
-o, --out <path> Directory to write the site to (default: <dir>/pulumi-package-docs-site)
|
|
32
|
+
-b, --base <path> Base URL path the site is served from, e.g. /my-repo/ for a
|
|
33
|
+
GitHub/GitLab Pages project site (default: /)
|
|
34
|
+
-f, --force Overwrite --out even if it holds files we didn't generate
|
|
21
35
|
```
|
|
22
36
|
|
|
23
37
|
Requires the `pulumi` CLI to be installed and on `PATH`; it's used to fetch each provider's schema (`pulumi package get-schema`). If a schema was fetched successfully before, it's cached and reused if a later CLI call fails.
|
|
@@ -37,9 +51,81 @@ On macOS or Linux, it's also available via Homebrew:
|
|
|
37
51
|
brew install pierskarsenbarg/tap/pulumi-package-docs
|
|
38
52
|
```
|
|
39
53
|
|
|
54
|
+
## Static site (GitHub Pages / GitLab Pages)
|
|
55
|
+
|
|
56
|
+
`pulumi-package-docs static` renders the same docs to a folder of plain HTML,
|
|
57
|
+
so a project's provider docs can live on GitHub Pages, GitLab Pages, or any
|
|
58
|
+
other static host instead of only on a developer's machine:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
npx pulumi-package-docs static # -> ./pulumi-package-docs-site
|
|
62
|
+
npx pulumi-package-docs static --out ./site \
|
|
63
|
+
--base /my-repo/ # for https://<owner>.github.io/my-repo/
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Every provider, resource and function gets its own prerendered page, with the
|
|
67
|
+
project's `Pulumi.yaml` deciding what's in the site — the generator crawls its
|
|
68
|
+
own output, so nothing needs listing up front. The pages ship without the
|
|
69
|
+
client bundle: links are ordinary links and each page stands on its own, which
|
|
70
|
+
keeps a large provider's schema out of the pages that don't need it. The
|
|
71
|
+
`pulumi` CLI is needed to generate the site (same as serving it), but not to
|
|
72
|
+
host it.
|
|
73
|
+
|
|
74
|
+
`--base` is the path the site is served from, and it has to match: a
|
|
75
|
+
GitHub/GitLab Pages _project_ site lives under `/<repo>/`, while a user/org
|
|
76
|
+
site (or a custom domain) lives at `/`, where `--base` can be left off. The
|
|
77
|
+
output directory is rebuilt on each run, and a non-empty directory that wasn't
|
|
78
|
+
generated by this tool is left alone unless you pass `--force`.
|
|
79
|
+
|
|
80
|
+
Preview the result with any static file server:
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
npx serve ./site
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Ready-to-copy CI config lives in [`examples/`](examples): [GitHub
|
|
87
|
+
Actions](examples/github-pages.yml) and [GitLab
|
|
88
|
+
CI](examples/gitlab-ci.yml). Both install the `pulumi` CLI (the schemas come
|
|
89
|
+
from it), run the generator, and publish the output — note that GitLab Pages
|
|
90
|
+
only publishes a directory called `public`.
|
|
91
|
+
|
|
92
|
+
The standalone binaries can't generate a static site (they carry no build
|
|
93
|
+
toolchain); use `npx pulumi-package-docs static` for that.
|
|
94
|
+
|
|
40
95
|
## MCP
|
|
41
96
|
|
|
42
|
-
The
|
|
97
|
+
The same local provider docs are available to coding agents over [MCP](https://modelcontextprotocol.io), via either transport.
|
|
98
|
+
|
|
99
|
+
**Streamable HTTP**, while the docs site is running: the server exposes an MCP endpoint at `/mcp`, so point an MCP client at `http://localhost:3000/mcp` (e.g. in Claude Code, `claude mcp add --transport http pulumi-package-docs http://localhost:3000/mcp`).
|
|
100
|
+
|
|
101
|
+
**stdio**, for clients that spawn a server process instead of connecting to a URL: run with `--stdio` and no docs site is started at all — the process speaks MCP on stdin/stdout and exits with the client.
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
claude mcp add pulumi-package-docs -- npx -y pulumi-package-docs --stdio --dir /path/to/pulumi/project
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Or, in an MCP client's JSON config:
|
|
108
|
+
|
|
109
|
+
```json
|
|
110
|
+
{
|
|
111
|
+
"mcpServers": {
|
|
112
|
+
"pulumi-package-docs": {
|
|
113
|
+
"command": "npx",
|
|
114
|
+
"args": [
|
|
115
|
+
"-y",
|
|
116
|
+
"pulumi-package-docs",
|
|
117
|
+
"--stdio",
|
|
118
|
+
"--dir",
|
|
119
|
+
"/path/to/pulumi/project"
|
|
120
|
+
]
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
`--dir` defaults to the process's working directory, so it can be omitted when the client launches the server from the Pulumi project itself. The standalone binary works the same way — use its path in place of `npx -y pulumi-package-docs`.
|
|
127
|
+
|
|
128
|
+
Both transports serve the same tools:
|
|
43
129
|
|
|
44
130
|
- `list_providers` — the local providers declared in `Pulumi.yaml`, with resource/function counts and schema load status.
|
|
45
131
|
- `list_resources` / `list_functions` — a provider's resource or function tokens, with a one-line summary and deprecation status for each.
|
|
@@ -73,7 +159,15 @@ Build the production app with:
|
|
|
73
159
|
npm run build
|
|
74
160
|
```
|
|
75
161
|
|
|
76
|
-
|
|
162
|
+
Build a static site from the same sources (`VITE_STATIC_DOCS=true` switches the
|
|
163
|
+
app into its no-hydration, prerendered mode, and `PULUMI_DOCS_BASE` sets the
|
|
164
|
+
path it's served from):
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
node bin/cli.js static --dir /path/to/pulumi/project --out ./site
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
`bin/cli.js` is the `npx` entry point: it serves the production build with `vite preview` if one exists (`npm run build` first), otherwise falls back to `vite dev`. With `--stdio` it skips Vite entirely and runs `dist/mcp/stdio.js` in-process, which `npm run build` produces from `vite.mcp.config.ts` (so `--stdio` needs a build — there's no dev-server fallback for it). `bin/cli-bun.js` is a separate entry point used to build the standalone Bun executables (see above); it serves the built SSR handler directly with `Bun.serve` instead of shelling out to Vite. Build one locally with:
|
|
77
171
|
|
|
78
172
|
```bash
|
|
79
173
|
npm run build
|
package/bin/args.js
CHANGED
|
@@ -1,35 +1,94 @@
|
|
|
1
1
|
import { resolve } from 'node:path'
|
|
2
2
|
|
|
3
|
+
export const COMMANDS = ['serve', 'static']
|
|
4
|
+
|
|
5
|
+
const DEFAULT_OUT_DIR = 'pulumi-package-docs-site'
|
|
6
|
+
|
|
3
7
|
export function parseArgs(argv) {
|
|
4
|
-
const options = {
|
|
8
|
+
const options = {
|
|
9
|
+
command: 'serve',
|
|
10
|
+
dir: process.cwd(),
|
|
11
|
+
port: '3000',
|
|
12
|
+
host: false,
|
|
13
|
+
open: false,
|
|
14
|
+
stdio: false,
|
|
15
|
+
out: null,
|
|
16
|
+
base: '/',
|
|
17
|
+
force: false,
|
|
18
|
+
}
|
|
19
|
+
let commandSeen = false
|
|
20
|
+
|
|
5
21
|
for (let i = 0; i < argv.length; i++) {
|
|
6
22
|
const arg = argv[i]
|
|
7
23
|
if (arg === '--dir' || arg === '-d') {
|
|
8
24
|
options.dir = resolve(argv[++i])
|
|
9
25
|
} else if (arg === '--port' || arg === '-p') {
|
|
10
26
|
options.port = argv[++i]
|
|
27
|
+
} else if (arg === '--stdio') {
|
|
28
|
+
options.stdio = true
|
|
29
|
+
} else if (arg === '--out' || arg === '-o') {
|
|
30
|
+
options.out = resolve(argv[++i])
|
|
31
|
+
} else if (arg === '--base' || arg === '-b') {
|
|
32
|
+
options.base = argv[++i]
|
|
33
|
+
} else if (arg === '--force' || arg === '-f') {
|
|
34
|
+
options.force = true
|
|
11
35
|
} else if (arg === '--host') {
|
|
12
36
|
options.host = true
|
|
13
37
|
} else if (arg === '--open') {
|
|
14
38
|
options.open = true
|
|
15
39
|
} else if (arg === '--help' || arg === '-h') {
|
|
16
40
|
options.help = true
|
|
41
|
+
} else if (!commandSeen && !arg.startsWith('-')) {
|
|
42
|
+
commandSeen = true
|
|
43
|
+
if (!COMMANDS.includes(arg)) {
|
|
44
|
+
options.unknownCommand = arg
|
|
45
|
+
} else {
|
|
46
|
+
options.command = arg
|
|
47
|
+
}
|
|
17
48
|
}
|
|
18
49
|
}
|
|
50
|
+
|
|
51
|
+
// Deliberately resolved after the loop: the default depends on --dir, which
|
|
52
|
+
// may be given after the command.
|
|
53
|
+
if (options.out === null) options.out = resolve(options.dir, DEFAULT_OUT_DIR)
|
|
54
|
+
|
|
19
55
|
return options
|
|
20
56
|
}
|
|
21
57
|
|
|
58
|
+
/**
|
|
59
|
+
* The address the standalone binary's `Bun.serve` listens on. Bun treats a
|
|
60
|
+
* missing hostname as every interface, so loopback has to be explicit.
|
|
61
|
+
*/
|
|
62
|
+
export function serveHostname(options) {
|
|
63
|
+
return options.host ? '0.0.0.0' : '127.0.0.1'
|
|
64
|
+
}
|
|
65
|
+
|
|
22
66
|
export function printHelp() {
|
|
23
|
-
console.log(`pulumi-package-docs [options]
|
|
67
|
+
console.log(`pulumi-package-docs [command] [options]
|
|
24
68
|
|
|
25
69
|
Serves local documentation for the parameterized/local Pulumi providers used
|
|
26
70
|
by a Pulumi project.
|
|
27
71
|
|
|
72
|
+
Commands:
|
|
73
|
+
serve Serve the docs (default)
|
|
74
|
+
static Generate a static site to publish (GitHub/GitLab Pages)
|
|
75
|
+
|
|
28
76
|
Options:
|
|
29
77
|
-d, --dir <path> Pulumi project directory to inspect (default: current directory)
|
|
78
|
+
-h, --help Show this help message
|
|
79
|
+
|
|
80
|
+
serve options:
|
|
30
81
|
-p, --port <port> Port to serve on (default: 3000)
|
|
31
82
|
--host Expose the server on your network
|
|
32
83
|
--open Open the docs in your default browser once ready
|
|
33
|
-
|
|
84
|
+
--stdio Run as an MCP server over stdio instead of serving the docs
|
|
85
|
+
site (for MCP clients that spawn a server process). The
|
|
86
|
+
same tools are served over HTTP at /mcp when serving the site.
|
|
87
|
+
|
|
88
|
+
static options:
|
|
89
|
+
-o, --out <path> Directory to write the site to (default: <dir>/${DEFAULT_OUT_DIR})
|
|
90
|
+
-b, --base <path> Base URL path the site is served from, e.g. /my-repo/ for a
|
|
91
|
+
GitHub/GitLab Pages project site (default: /)
|
|
92
|
+
-f, --force Overwrite --out even if it holds files we didn't generate
|
|
34
93
|
`)
|
|
35
94
|
}
|
package/bin/args.test.js
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { resolve } from 'node:path'
|
|
2
|
+
import { describe, expect, it } from 'vitest'
|
|
3
|
+
|
|
4
|
+
import { parseArgs, serveHostname } from './args.js'
|
|
5
|
+
|
|
6
|
+
describe('serveHostname', () => {
|
|
7
|
+
it('listens on loopback only unless --host is passed', () => {
|
|
8
|
+
expect(serveHostname(parseArgs([]))).toBe('127.0.0.1')
|
|
9
|
+
})
|
|
10
|
+
|
|
11
|
+
it('listens on every interface with --host', () => {
|
|
12
|
+
expect(serveHostname(parseArgs(['--host']))).toBe('0.0.0.0')
|
|
13
|
+
})
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
describe('parseArgs', () => {
|
|
17
|
+
it('defaults to serving the current directory', () => {
|
|
18
|
+
const options = parseArgs([])
|
|
19
|
+
expect(options.command).toBe('serve')
|
|
20
|
+
expect(options.dir).toBe(process.cwd())
|
|
21
|
+
expect(options.port).toBe('3000')
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
it('reads the static command and its options', () => {
|
|
25
|
+
const options = parseArgs([
|
|
26
|
+
'static',
|
|
27
|
+
'--dir',
|
|
28
|
+
'/tmp/project',
|
|
29
|
+
'--out',
|
|
30
|
+
'/tmp/site',
|
|
31
|
+
'--base',
|
|
32
|
+
'/my-repo/',
|
|
33
|
+
'--force',
|
|
34
|
+
])
|
|
35
|
+
expect(options.command).toBe('static')
|
|
36
|
+
expect(options.dir).toBe(resolve('/tmp/project'))
|
|
37
|
+
expect(options.out).toBe(resolve('/tmp/site'))
|
|
38
|
+
expect(options.base).toBe('/my-repo/')
|
|
39
|
+
expect(options.force).toBe(true)
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
it('defaults the output directory to one inside the project directory', () => {
|
|
43
|
+
const options = parseArgs(['static', '--dir', '/tmp/project'])
|
|
44
|
+
expect(options.out).toBe(
|
|
45
|
+
resolve('/tmp/project', 'pulumi-package-docs-site'),
|
|
46
|
+
)
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
it('reports an unknown command rather than treating it as a flag value', () => {
|
|
50
|
+
const options = parseArgs(['publish'])
|
|
51
|
+
expect(options.unknownCommand).toBe('publish')
|
|
52
|
+
expect(options.command).toBe('serve')
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
it("doesn't mistake an option value for the command", () => {
|
|
56
|
+
const options = parseArgs(['--port', '8080', 'static'])
|
|
57
|
+
expect(options.command).toBe('static')
|
|
58
|
+
expect(options.port).toBe('8080')
|
|
59
|
+
})
|
|
60
|
+
})
|
package/bin/cli-bun.js
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
import { spawn } from 'node:child_process'
|
|
3
|
-
import { parseArgs, printHelp } from './args.js'
|
|
4
|
-
import server from '../dist/server/server.js'
|
|
5
|
-
import embeddedAssets from './embedded-assets.generated.js'
|
|
3
|
+
import { parseArgs, printHelp, serveHostname } from './args.js'
|
|
6
4
|
|
|
7
5
|
const options = parseArgs(process.argv.slice(2))
|
|
8
6
|
|
|
@@ -11,8 +9,36 @@ if (options.help) {
|
|
|
11
9
|
process.exit(0)
|
|
12
10
|
}
|
|
13
11
|
|
|
12
|
+
if (options.unknownCommand) {
|
|
13
|
+
console.error(`Unknown command: ${options.unknownCommand}\n`)
|
|
14
|
+
printHelp()
|
|
15
|
+
process.exit(1)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
if (options.command === 'static') {
|
|
19
|
+
// Generating a site runs a Vite build, which isn't part of this standalone
|
|
20
|
+
// executable (it only carries the prebuilt server and its assets).
|
|
21
|
+
console.error(
|
|
22
|
+
'The standalone binary cannot generate a static site: it has no build toolchain.\n' +
|
|
23
|
+
'Run `npx pulumi-package-docs static` instead.',
|
|
24
|
+
)
|
|
25
|
+
process.exit(1)
|
|
26
|
+
}
|
|
27
|
+
|
|
14
28
|
process.env.PULUMI_LOCAL_DOCS_DIR = options.dir
|
|
15
29
|
|
|
30
|
+
if (options.stdio) {
|
|
31
|
+
// stdout is the MCP protocol channel here, so the banner goes to stderr and the
|
|
32
|
+
// docs site (and its embedded client assets) is never loaded — these imports stay
|
|
33
|
+
// dynamic so that stays true, and so `bun build --compile` still bundles both paths.
|
|
34
|
+
const { runStdioMcpServer } =
|
|
35
|
+
await import('../src/lib/pulumi/stdio.server.ts')
|
|
36
|
+
console.error(`Serving provider docs over stdio for: ${options.dir}`)
|
|
37
|
+
await runStdioMcpServer()
|
|
38
|
+
} else {
|
|
39
|
+
await serveDocsSite()
|
|
40
|
+
}
|
|
41
|
+
|
|
16
42
|
function openBrowser(url) {
|
|
17
43
|
const command =
|
|
18
44
|
process.platform === 'darwin'
|
|
@@ -30,23 +56,29 @@ function openBrowser(url) {
|
|
|
30
56
|
child.unref()
|
|
31
57
|
}
|
|
32
58
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
59
|
+
async function serveDocsSite() {
|
|
60
|
+
const { default: server } = await import('../dist/server/server.js')
|
|
61
|
+
const { default: embeddedAssets } =
|
|
62
|
+
await import('./embedded-assets.generated.js')
|
|
63
|
+
|
|
64
|
+
console.log(`Serving provider docs for: ${options.dir}`)
|
|
65
|
+
|
|
66
|
+
const bunServer = Bun.serve({
|
|
67
|
+
port: Number(options.port),
|
|
68
|
+
hostname: serveHostname(options),
|
|
69
|
+
async fetch(request) {
|
|
70
|
+
const url = new URL(request.url)
|
|
71
|
+
const embeddedPath = embeddedAssets[url.pathname]
|
|
72
|
+
if (embeddedPath) {
|
|
73
|
+
return new Response(Bun.file(embeddedPath))
|
|
74
|
+
}
|
|
75
|
+
return server.fetch(request)
|
|
76
|
+
},
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
const localUrl = `http://localhost:${bunServer.port}/`
|
|
80
|
+
console.log(` ➜ Local: ${localUrl}`)
|
|
81
|
+
console.log(` ➜ MCP: ${new URL('mcp', localUrl)}`)
|
|
82
|
+
|
|
83
|
+
if (options.open) openBrowser(localUrl)
|
|
84
|
+
}
|
package/bin/cli.js
CHANGED
|
@@ -5,6 +5,7 @@ import { dirname, join, resolve } from 'node:path'
|
|
|
5
5
|
import { fileURLToPath } from 'node:url'
|
|
6
6
|
import { spawn } from 'node:child_process'
|
|
7
7
|
import { parseArgs, printHelp } from './args.js'
|
|
8
|
+
import { buildStaticSite } from './static.js'
|
|
8
9
|
|
|
9
10
|
const packageRoot = resolve(dirname(fileURLToPath(import.meta.url)), '..')
|
|
10
11
|
const require = createRequire(import.meta.url)
|
|
@@ -16,35 +17,80 @@ if (options.help) {
|
|
|
16
17
|
process.exit(0)
|
|
17
18
|
}
|
|
18
19
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
join(packageRoot, 'dist', 'server', 'server.js'),
|
|
24
|
-
)
|
|
25
|
-
const viteArgs = [
|
|
26
|
-
hasProductionBuild ? 'preview' : 'dev',
|
|
27
|
-
'--port',
|
|
28
|
-
options.port,
|
|
29
|
-
]
|
|
30
|
-
if (options.host) viteArgs.push('--host')
|
|
31
|
-
if (options.open) viteArgs.push('--open')
|
|
32
|
-
|
|
33
|
-
if (!hasProductionBuild) {
|
|
34
|
-
console.log(
|
|
35
|
-
'No production build found, starting the dev server instead (this is slower).',
|
|
36
|
-
)
|
|
20
|
+
if (options.unknownCommand) {
|
|
21
|
+
console.error(`Unknown command: ${options.unknownCommand}\n`)
|
|
22
|
+
printHelp()
|
|
23
|
+
process.exit(1)
|
|
37
24
|
}
|
|
38
|
-
console.log(`Serving provider docs for: ${options.dir}`)
|
|
39
25
|
|
|
40
|
-
|
|
41
|
-
cwd: packageRoot,
|
|
42
|
-
stdio: 'inherit',
|
|
43
|
-
env: { ...process.env, PULUMI_LOCAL_DOCS_DIR: options.dir },
|
|
44
|
-
})
|
|
26
|
+
process.env.PULUMI_LOCAL_DOCS_DIR = options.dir
|
|
45
27
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
console.error('Failed to start pulumi-package-docs:', err)
|
|
28
|
+
if (options.command === 'static' && options.stdio) {
|
|
29
|
+
console.error('`--stdio` is a serve option; it has no effect on `static`.')
|
|
49
30
|
process.exit(1)
|
|
50
|
-
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (options.stdio) {
|
|
34
|
+
// stdout is the MCP protocol channel here, so the usual startup banner goes to
|
|
35
|
+
// stderr and the server runs in-process (no vite, no HTTP server).
|
|
36
|
+
const stdioEntry = join(packageRoot, 'dist', 'mcp', 'stdio.js')
|
|
37
|
+
if (!existsSync(stdioEntry)) {
|
|
38
|
+
console.error(
|
|
39
|
+
'No production build found. Run `npm run build` before using --stdio.',
|
|
40
|
+
)
|
|
41
|
+
process.exit(1)
|
|
42
|
+
}
|
|
43
|
+
console.error(`Serving provider docs over stdio for: ${options.dir}`)
|
|
44
|
+
const { runStdioMcpServer } = await import(stdioEntry)
|
|
45
|
+
await runStdioMcpServer()
|
|
46
|
+
} else {
|
|
47
|
+
const vitePkgJson = require.resolve('vite/package.json')
|
|
48
|
+
const viteBin = join(dirname(vitePkgJson), 'bin', 'vite.js')
|
|
49
|
+
|
|
50
|
+
if (options.command === 'static') {
|
|
51
|
+
try {
|
|
52
|
+
await buildStaticSite({
|
|
53
|
+
packageRoot,
|
|
54
|
+
viteBin,
|
|
55
|
+
dir: options.dir,
|
|
56
|
+
out: options.out,
|
|
57
|
+
base: options.base,
|
|
58
|
+
force: options.force,
|
|
59
|
+
})
|
|
60
|
+
} catch (err) {
|
|
61
|
+
console.error(err instanceof Error ? err.message : err)
|
|
62
|
+
process.exit(1)
|
|
63
|
+
}
|
|
64
|
+
process.exit(0)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const hasProductionBuild = existsSync(
|
|
68
|
+
join(packageRoot, 'dist', 'server', 'server.js'),
|
|
69
|
+
)
|
|
70
|
+
const viteArgs = [
|
|
71
|
+
hasProductionBuild ? 'preview' : 'dev',
|
|
72
|
+
'--port',
|
|
73
|
+
options.port,
|
|
74
|
+
]
|
|
75
|
+
if (options.host) viteArgs.push('--host')
|
|
76
|
+
if (options.open) viteArgs.push('--open')
|
|
77
|
+
|
|
78
|
+
if (!hasProductionBuild) {
|
|
79
|
+
console.log(
|
|
80
|
+
'No production build found, starting the dev server instead (this is slower).',
|
|
81
|
+
)
|
|
82
|
+
}
|
|
83
|
+
console.log(`Serving provider docs for: ${options.dir}`)
|
|
84
|
+
|
|
85
|
+
const child = spawn(process.execPath, [viteBin, ...viteArgs], {
|
|
86
|
+
cwd: packageRoot,
|
|
87
|
+
stdio: 'inherit',
|
|
88
|
+
env: { ...process.env, PULUMI_LOCAL_DOCS_DIR: options.dir },
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
child.on('exit', (code) => process.exit(code ?? 0))
|
|
92
|
+
child.on('error', (err) => {
|
|
93
|
+
console.error('Failed to start pulumi-package-docs:', err)
|
|
94
|
+
process.exit(1)
|
|
95
|
+
})
|
|
96
|
+
}
|
package/bin/cli.test.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { spawnSync } from 'node:child_process'
|
|
2
|
+
import { dirname, join } from 'node:path'
|
|
3
|
+
import { fileURLToPath } from 'node:url'
|
|
4
|
+
import { describe, expect, it } from 'vitest'
|
|
5
|
+
|
|
6
|
+
const cliPath = join(dirname(fileURLToPath(import.meta.url)), 'cli.js')
|
|
7
|
+
|
|
8
|
+
describe('cli.js', () => {
|
|
9
|
+
it('rejects `static --stdio` instead of silently serving MCP over stdio', () => {
|
|
10
|
+
const result = spawnSync(process.execPath, [cliPath, 'static', '--stdio'], {
|
|
11
|
+
encoding: 'utf8',
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
expect(result.status).toBe(1)
|
|
15
|
+
expect(result.stderr).toContain('--stdio')
|
|
16
|
+
expect(result.stderr).toContain('static')
|
|
17
|
+
})
|
|
18
|
+
})
|