Files
IdeaSDK/docs/packaging-distribution.md
Blomios b5a35563b6 docs(sdk): lancement des serveurs MCP JavaScript packagés — #294 (manifest: aucune substitution ${node}/${runtimeNode}/${hostNode} ni champ runtime, IdeA ne fournit pas de runtime Node plugin-scoped; command n'est pas du shell — démarrage direct avec args séparés, pas de fichiers de startup/alias/PATH du shell de login; command relatif résolu sous pluginRoot — command:"node" sans allowAbsoluteCommand devient ${pluginRoot}/node (cause ENOENT UnityPlugin #12); absolu littéral refusé sans allowAbsoluteCommand=true, command devenu absolu après substitution ${pluginRoot}/${appDataDir} passé tel quel; shebang #!/usr/bin/env node dépend du node visible du process app IdeA; recommandations: exécutable packagé incluant son runtime ou runtime géré sous stockage plugin/app pointé via ${pluginRoot}/${appDataDir}, sinon dépendance hôte explicite absolue /usr/bin/node avec allowAbsoluteCommand=true et scripts dans args; même règle pour command:"bash"; packaging-distribution: section Packaged Executables And Runtimes — bit exécutable et shebang valides dans le package installé, éviter le bare command:"node" en plugins distribués/multi-harness; services: distinction runCommand() (exécutable hôte de l'environnement task, aucune substitution) vs règles manifest mcpServers avec lien croisé; affirmations vérifiées par Git contre l'hôte crates/application/src/plugin/mod.rs:3199 substitution puis looks_absolute/allow_absolute_command sinon préfixage pluginRoot, et validation :3637 absolu littéral sans flag rejeté; QA verte reconfirmée par Git: npm run check — build, typecheck:examples, package:hello-plugin)
2026-09-09 16:24:16 +02:00

173 lines
5.2 KiB
Markdown

# Packaging And Distribution
A plugin archive is a ZIP file whose root contains `idea-plugin.json`.
```text
hello-plugin-0.1.0.zip
├── idea-plugin.json
├── README.md
└── dist/
├── index.js
├── constants.js
└── core/
├── layout.js
├── storage.js
└── workspace.js
```
The manifest `main` field must point to an emitted file inside the archive:
```json
{
"main": "dist/index.js"
}
```
## Module Resolution
IdeA loads `main` as ESM and serves package-relative imports from the plugin
package. This is supported:
```js
import { Dashboard } from "./core/layout.js";
```
For React, import bare host modules normally:
```js
import { useState } from "react";
import { jsx } from "react/jsx-runtime";
```
IdeA resolves React/ReactDOM bare imports to the host instance. Other bare
dependencies are not host-resolved. Bundle or vendor third-party dependencies
other than React/ReactDOM into package-relative files.
## Packaged Executables And Runtimes
Manifest-declared MCP servers are launched from `contributes.mcpServers` by
starting the declared `command` directly. IdeA does not inject a shell and does
not provide a plugin-scoped Node.js runtime.
For a packaged MCP server, prefer a package-relative executable such as
`scripts/my-plugin-mcp-server`. The installed file must keep the executable bit
and, when it is a script, a valid shebang. A JavaScript server with
`#!/usr/bin/env node` still requires `node` in the environment inherited by the
IdeA app process; this is not guaranteed to match the user's interactive shell,
especially when Node is provided by shell startup tooling.
For reproducible JavaScript MCP servers, either ship/install a runtime under the
plugin package or app-owned storage and point the manifest at that executable,
or declare an explicit absolute host dependency with `allowAbsoluteCommand:
true`. Avoid relying on a bare `command: "node"` in distributed or multi-harness
plugins.
## TypeScript Build
The hello plugin uses plain `tsc`:
```sh
npm run build
npm run build:hello-plugin
```
For React layouts, configure JSX:
```json
{
"compilerOptions": {
"jsx": "react-jsx",
"module": "NodeNext",
"moduleResolution": "NodeNext"
}
}
```
## Archive Build
The SDK example can be packaged with:
```sh
npm run package:hello-plugin
```
The resulting archive has no wrapping parent directory and is ready for IdeA's
plugin installer.
## Hot Reload During Development
Install the plugin from a directory when you want IdeA to hot-reload changes
without restarting the app.
In IdeA, open `Paramètres > Plugins`, choose `Installer depuis un dossier…`,
and select the plugin source directory. That directory must contain
`idea-plugin.json` at its root, and the manifest `main` field must point to the
built entrypoint that exists inside the same directory, for example
`dist/index.js`.
```text
hello-plugin/
├── idea-plugin.json
├── package.json
└── dist/
├── index.js
└── core/
└── layout.js
```
After editing plugin source files, rebuild the plugin output first:
```sh
npm run build
```
An IdeA agent can install a development plugin directory only when that agent has
the plugin administration MCP tool explicitly allowed. The public tool is
`idea_plugin_install_from_directory`:
```json
{
"path": "relative/path/to/hello-plugin",
"expectedPluginId": "com.example.hello-plugin"
}
```
The path must resolve under the requester's project root. This installs the
directory as the recorded development source for later reloads.
After source edits, rebuild the plugin output and ask an IdeA agent that has the
plugin administration tool available to run `idea_plugin_reload` with the
installed plugin id:
```json
{
"pluginId": "com.example.hello-plugin"
}
```
The reload uses the recorded directory source from the plugin registry. It
re-reads and validates the manifest, recalculates the package hash, updates the
installed package, emits `plugin_reloaded`, and reconciles plugin MCP servers.
It does not accept an arbitrary path at reload time; install from the intended
development directory first.
Do not install from the ZIP archive for a development loop that needs hot
reload. Archive installs are fixed package snapshots. They are appropriate for
distribution, but the reload command is only defined for plugins installed from
a directory source.
On reload, `plugin_reloaded` tells the UI to rebuild the plugin runtime registry.
When the package content hash changes, plugin ESM URLs change and React layout
components are loaded from the new package. Existing plugin layout instances may
remount and lose local React state; host-persisted layout state written through
`setState` remains the durable state channel.
JavaScript module instances cannot be forcibly removed from the browser ESM
cache. Register handlers, layouts, watches and subscriptions through the SDK
registries and push disposable side effects into `ctx.subscriptions`; global
module side effects can otherwise survive a reload. If the package hash did not
change, the reload is idempotent and may reuse the same module instance.
IdeA runtime plugin installation is separate from Codex plugin/skill discovery.
See [Codex Skills And IdeA Plugins](codex-skills-and-idea-plugins.md).