@orchid-labs/pluxx 0.1.10 → 0.1.12

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 (41) hide show
  1. package/dist/branding-completeness.d.ts +10 -0
  2. package/dist/branding-completeness.d.ts.map +1 -0
  3. package/dist/cli/agent.d.ts.map +1 -1
  4. package/dist/cli/doctor.d.ts.map +1 -1
  5. package/dist/cli/index.js +2153 -952
  6. package/dist/cli/install.d.ts +1 -0
  7. package/dist/cli/install.d.ts.map +1 -1
  8. package/dist/cli/lint.d.ts.map +1 -1
  9. package/dist/cli/migrate.d.ts.map +1 -1
  10. package/dist/cli/publish.d.ts.map +1 -1
  11. package/dist/commands.d.ts +1 -0
  12. package/dist/commands.d.ts.map +1 -1
  13. package/dist/compiler-intent.d.ts +28 -28
  14. package/dist/generators/base.d.ts.map +1 -1
  15. package/dist/generators/claude-code/index.d.ts.map +1 -1
  16. package/dist/generators/codex/index.d.ts +1 -0
  17. package/dist/generators/codex/index.d.ts.map +1 -1
  18. package/dist/generators/cursor/index.d.ts.map +1 -1
  19. package/dist/generators/hooks-warning.d.ts.map +1 -1
  20. package/dist/generators/opencode/index.d.ts +1 -0
  21. package/dist/generators/opencode/index.d.ts.map +1 -1
  22. package/dist/generators/shared/claude-family.d.ts.map +1 -1
  23. package/dist/hook-translation-registry.d.ts +15 -0
  24. package/dist/hook-translation-registry.d.ts.map +1 -0
  25. package/dist/index.d.ts +4 -2
  26. package/dist/index.d.ts.map +1 -1
  27. package/dist/index.js +599 -35
  28. package/dist/mcp-stdio-paths.d.ts +9 -0
  29. package/dist/mcp-stdio-paths.d.ts.map +1 -0
  30. package/dist/readiness.d.ts +13 -0
  31. package/dist/readiness.d.ts.map +1 -0
  32. package/dist/runtime-readiness-registry.d.ts +26 -0
  33. package/dist/runtime-readiness-registry.d.ts.map +1 -0
  34. package/dist/runtime-script-contract.d.ts +20 -0
  35. package/dist/runtime-script-contract.d.ts.map +1 -0
  36. package/dist/schema.d.ts +1444 -706
  37. package/dist/schema.d.ts.map +1 -1
  38. package/dist/skills.d.ts +27 -0
  39. package/dist/skills.d.ts.map +1 -0
  40. package/dist/validation/platform-rules.d.ts.map +1 -1
  41. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -7461,6 +7461,99 @@ var HooksSchema = external_exports.object({
7461
7461
  beforeTabFileRead: external_exports.array(HookEntrySchema).optional(),
7462
7462
  afterTabFileEdit: external_exports.array(HookEntrySchema).optional()
7463
7463
  }).catchall(external_exports.array(HookEntrySchema));
7464
+ var RuntimeReadinessRefreshSchema = external_exports.object({
7465
+ command: external_exports.string(),
7466
+ timeoutMs: external_exports.number().int().positive().default(1e4),
7467
+ detached: external_exports.boolean().default(true)
7468
+ });
7469
+ var RuntimeReadinessDependencySchema = external_exports.object({
7470
+ id: external_exports.string().regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/, "Use lowercase kebab-case for readiness dependency ids"),
7471
+ kind: external_exports.enum(["status-file"]).default("status-file"),
7472
+ path: external_exports.string(),
7473
+ format: external_exports.enum(["json"]).default("json"),
7474
+ statusField: external_exports.string().default("status"),
7475
+ readyValues: external_exports.array(external_exports.string()).default(["succeeded"]),
7476
+ pendingValues: external_exports.array(external_exports.string()).default(["running"]),
7477
+ failedValues: external_exports.array(external_exports.string()).default(["failed"]),
7478
+ refresh: RuntimeReadinessRefreshSchema,
7479
+ description: external_exports.string().optional()
7480
+ }).superRefine((dependency, ctx) => {
7481
+ const ready = new Set(dependency.readyValues);
7482
+ const pending = new Set(dependency.pendingValues);
7483
+ const failed = new Set(dependency.failedValues);
7484
+ const overlap = [
7485
+ ...ready,
7486
+ ...pending
7487
+ ].filter(
7488
+ (value, index, values) => values.indexOf(value) === index && (ready.has(value) ? 1 : 0) + (pending.has(value) ? 1 : 0) + (failed.has(value) ? 1 : 0) > 1
7489
+ );
7490
+ if (overlap.length > 0) {
7491
+ ctx.addIssue({
7492
+ code: external_exports.ZodIssueCode.custom,
7493
+ path: ["readyValues"],
7494
+ message: `Readiness dependency values must not overlap across ready/pending/failed buckets: ${overlap.join(", ")}`
7495
+ });
7496
+ }
7497
+ });
7498
+ var RuntimeReadinessGateSchema = external_exports.object({
7499
+ dependency: external_exports.string(),
7500
+ applyTo: external_exports.array(external_exports.enum(["mcp-tools", "skills", "commands"])).nonempty().default(["mcp-tools"]),
7501
+ tools: external_exports.array(external_exports.string()).nonempty().optional(),
7502
+ skills: external_exports.array(external_exports.string()).nonempty().optional(),
7503
+ commands: external_exports.array(external_exports.string()).nonempty().optional(),
7504
+ timeoutMs: external_exports.number().int().positive().default(15e3),
7505
+ pollMs: external_exports.number().int().positive().default(500),
7506
+ onTimeout: external_exports.enum(["continue", "warn", "fail"]).default("warn"),
7507
+ message: external_exports.string().optional()
7508
+ }).superRefine((gate, ctx) => {
7509
+ if (gate.tools && !gate.applyTo.includes("mcp-tools")) {
7510
+ ctx.addIssue({
7511
+ code: external_exports.ZodIssueCode.custom,
7512
+ path: ["tools"],
7513
+ message: 'Runtime readiness gate.tools requires applyTo to include "mcp-tools".'
7514
+ });
7515
+ }
7516
+ if (gate.skills && !gate.applyTo.includes("skills")) {
7517
+ ctx.addIssue({
7518
+ code: external_exports.ZodIssueCode.custom,
7519
+ path: ["skills"],
7520
+ message: 'Runtime readiness gate.skills requires applyTo to include "skills".'
7521
+ });
7522
+ }
7523
+ if (gate.commands && !gate.applyTo.includes("commands")) {
7524
+ ctx.addIssue({
7525
+ code: external_exports.ZodIssueCode.custom,
7526
+ path: ["commands"],
7527
+ message: 'Runtime readiness gate.commands requires applyTo to include "commands".'
7528
+ });
7529
+ }
7530
+ });
7531
+ var RuntimeReadinessSchema = external_exports.object({
7532
+ dependencies: external_exports.array(RuntimeReadinessDependencySchema).default([]),
7533
+ gates: external_exports.array(RuntimeReadinessGateSchema).default([])
7534
+ }).superRefine((config, ctx) => {
7535
+ const seenDependencyIds = /* @__PURE__ */ new Set();
7536
+ for (const [index, dependency] of config.dependencies.entries()) {
7537
+ if (seenDependencyIds.has(dependency.id)) {
7538
+ ctx.addIssue({
7539
+ code: external_exports.ZodIssueCode.custom,
7540
+ path: ["dependencies", index, "id"],
7541
+ message: `Runtime readiness dependency id "${dependency.id}" is duplicated.`
7542
+ });
7543
+ }
7544
+ seenDependencyIds.add(dependency.id);
7545
+ }
7546
+ const dependencyIds = new Set(config.dependencies.map((dependency) => dependency.id));
7547
+ for (const [index, gate] of config.gates.entries()) {
7548
+ if (!dependencyIds.has(gate.dependency)) {
7549
+ ctx.addIssue({
7550
+ code: external_exports.ZodIssueCode.custom,
7551
+ path: ["gates", index, "dependency"],
7552
+ message: `Runtime readiness gate references unknown dependency "${gate.dependency}".`
7553
+ });
7554
+ }
7555
+ }
7556
+ });
7464
7557
  var BrandSchema = external_exports.object({
7465
7558
  displayName: external_exports.string(),
7466
7559
  shortDescription: external_exports.string().optional(),
@@ -7590,6 +7683,8 @@ var PluginConfigSchema = external_exports.object({
7590
7683
  instructions: external_exports.string().optional(),
7591
7684
  // MCP servers
7592
7685
  mcp: external_exports.record(external_exports.string(), McpServerSchema).optional(),
7686
+ // Runtime readiness gates
7687
+ readiness: RuntimeReadinessSchema.optional(),
7593
7688
  // Hooks
7594
7689
  hooks: HooksSchema.optional(),
7595
7690
  // Scripts (copied to all targets)
@@ -7616,6 +7711,37 @@ var PLUXX_COMPILER_BUCKETS = [
7616
7711
  "distribution"
7617
7712
  ];
7618
7713
  function getPluginCompilerBuckets(config) {
7714
+ const runtimeMcpSurface = {
7715
+ servers: config.mcp,
7716
+ hasRuntimeAuth: Object.values(config.mcp ?? {}).some((server) => server.auth?.type !== "none" && server.auth !== void 0)
7717
+ };
7718
+ const runtimeReadinessSurface = {
7719
+ config: config.readiness
7720
+ };
7721
+ const runtimePayloadSurface = {
7722
+ scriptsPath: config.scripts,
7723
+ assetsPath: config.assets,
7724
+ passthroughPaths: config.passthrough ?? []
7725
+ };
7726
+ const distributionBrandingSurface = {
7727
+ identity: {
7728
+ name: config.name,
7729
+ version: config.version,
7730
+ description: config.description,
7731
+ author: config.author,
7732
+ repository: config.repository,
7733
+ license: config.license,
7734
+ keywords: config.keywords
7735
+ },
7736
+ brand: config.brand
7737
+ };
7738
+ const distributionInstallSurface = {
7739
+ userConfig: config.userConfig ?? []
7740
+ };
7741
+ const distributionOutputSurface = {
7742
+ targets: config.targets,
7743
+ outDir: config.outDir
7744
+ };
7619
7745
  return {
7620
7746
  instructions: {
7621
7747
  path: config.instructions
@@ -7636,25 +7762,24 @@ function getPluginCompilerBuckets(config) {
7636
7762
  rules: config.permissions
7637
7763
  },
7638
7764
  runtime: {
7639
- mcp: config.mcp,
7640
- scriptsPath: config.scripts,
7641
- assetsPath: config.assets,
7642
- passthroughPaths: config.passthrough ?? []
7765
+ mcp: runtimeMcpSurface.servers,
7766
+ readiness: runtimeReadinessSurface.config,
7767
+ scriptsPath: runtimePayloadSurface.scriptsPath,
7768
+ assetsPath: runtimePayloadSurface.assetsPath,
7769
+ passthroughPaths: runtimePayloadSurface.passthroughPaths,
7770
+ mcpSurface: runtimeMcpSurface,
7771
+ readinessSurface: runtimeReadinessSurface,
7772
+ payloadSurface: runtimePayloadSurface
7643
7773
  },
7644
7774
  distribution: {
7645
- identity: {
7646
- name: config.name,
7647
- version: config.version,
7648
- description: config.description,
7649
- author: config.author,
7650
- repository: config.repository,
7651
- license: config.license,
7652
- keywords: config.keywords
7653
- },
7654
- brand: config.brand,
7655
- userConfig: config.userConfig ?? [],
7656
- targets: config.targets,
7657
- outDir: config.outDir
7775
+ identity: distributionBrandingSurface.identity,
7776
+ brand: distributionBrandingSurface.brand,
7777
+ userConfig: distributionInstallSurface.userConfig,
7778
+ targets: distributionOutputSurface.targets,
7779
+ outDir: distributionOutputSurface.outDir,
7780
+ brandingSurface: distributionBrandingSurface,
7781
+ installSurface: distributionInstallSurface,
7782
+ outputSurface: distributionOutputSurface
7658
7783
  }
7659
7784
  };
7660
7785
  }
@@ -7671,7 +7796,7 @@ function getConfiguredCompilerBuckets(config) {
7671
7796
  );
7672
7797
  if (hasPermissions) configured.push("permissions");
7673
7798
  const hasRuntime = Boolean(
7674
- buckets.runtime.mcp && Object.keys(buckets.runtime.mcp).length > 0 || buckets.runtime.scriptsPath || buckets.runtime.assetsPath || buckets.runtime.passthroughPaths.length > 0
7799
+ buckets.runtime.mcp && Object.keys(buckets.runtime.mcp).length > 0 || buckets.runtime.readiness && (buckets.runtime.readiness.dependencies.length > 0 || buckets.runtime.readiness.gates.length > 0) || buckets.runtime.scriptsPath || buckets.runtime.assetsPath || buckets.runtime.passthroughPaths.length > 0
7675
7800
  );
7676
7801
  if (hasRuntime) configured.push("runtime");
7677
7802
  configured.push("distribution");
@@ -7683,6 +7808,139 @@ function definePlugin(config) {
7683
7808
  return PluginConfigSchema.parse(config);
7684
7809
  }
7685
7810
 
7811
+ // src/runtime-readiness-registry.ts
7812
+ function getEnabledRuntimeReadinessBindings(capability, plan) {
7813
+ return capability.bindings.filter((binding) => {
7814
+ switch (binding.gate) {
7815
+ case "session-start":
7816
+ return plan.needsSessionStart;
7817
+ case "mcp-gate":
7818
+ return plan.needsMcpGate;
7819
+ case "prompt-gate":
7820
+ return plan.needsPromptGate;
7821
+ }
7822
+ });
7823
+ }
7824
+ var NAMED_PROMPT_TARGET_NOTE = "Named `skills` / `commands` readiness targets currently translate through prompt-entry gating with best-effort matching because the core four do not share one exact per-skill or per-command runtime interception surface.";
7825
+ var CODEX_EXTERNAL_NOTE = "Codex readiness currently translates into generated hook/config guidance rather than an enforced plugin-bundled runtime surface.";
7826
+ function getRuntimeReadinessNamedPromptTargetNote() {
7827
+ return NAMED_PROMPT_TARGET_NOTE;
7828
+ }
7829
+ function getRuntimeReadinessExternalConfigNote() {
7830
+ return CODEX_EXTERNAL_NOTE;
7831
+ }
7832
+ function getRuntimeReadinessCapability(platform, pluginRootVar = "PLUGIN_ROOT") {
7833
+ switch (platform) {
7834
+ case "claude-code":
7835
+ return {
7836
+ platform,
7837
+ delivery: "bundled-hooks",
7838
+ bundleEnforced: true,
7839
+ namedPromptTargetScope: "best-effort",
7840
+ scriptPath: "hooks/pluxx-readiness.mjs",
7841
+ companionArtifacts: [],
7842
+ bindings: [
7843
+ {
7844
+ gate: "session-start",
7845
+ event: "SessionStart",
7846
+ command: `node \${${pluginRootVar}}/hooks/pluxx-readiness.mjs session-start`
7847
+ },
7848
+ {
7849
+ gate: "mcp-gate",
7850
+ event: "PreToolUse",
7851
+ matcher: "MCP",
7852
+ command: `node \${${pluginRootVar}}/hooks/pluxx-readiness.mjs mcp-gate`
7853
+ },
7854
+ {
7855
+ gate: "prompt-gate",
7856
+ event: "UserPromptSubmit",
7857
+ command: `node \${${pluginRootVar}}/hooks/pluxx-readiness.mjs prompt-gate`
7858
+ }
7859
+ ]
7860
+ };
7861
+ case "cursor":
7862
+ return {
7863
+ platform,
7864
+ delivery: "bundled-hooks",
7865
+ bundleEnforced: true,
7866
+ namedPromptTargetScope: "best-effort",
7867
+ scriptPath: "hooks/pluxx-readiness.mjs",
7868
+ companionArtifacts: [],
7869
+ bindings: [
7870
+ {
7871
+ gate: "session-start",
7872
+ event: "sessionStart",
7873
+ command: "node ./hooks/pluxx-readiness.mjs session-start"
7874
+ },
7875
+ {
7876
+ gate: "mcp-gate",
7877
+ event: "beforeMCPExecution",
7878
+ command: "node ./hooks/pluxx-readiness.mjs mcp-gate"
7879
+ },
7880
+ {
7881
+ gate: "prompt-gate",
7882
+ event: "beforeSubmitPrompt",
7883
+ command: "node ./hooks/pluxx-readiness.mjs prompt-gate"
7884
+ }
7885
+ ]
7886
+ };
7887
+ case "codex":
7888
+ return {
7889
+ platform,
7890
+ delivery: "generated-guidance",
7891
+ bundleEnforced: false,
7892
+ namedPromptTargetScope: "best-effort",
7893
+ scriptPath: ".codex/pluxx-readiness.mjs",
7894
+ companionArtifacts: [".codex/readiness.generated.json", ".codex/hooks.generated.json"],
7895
+ bindings: [
7896
+ {
7897
+ gate: "session-start",
7898
+ event: "SessionStart",
7899
+ command: "node ./.codex/pluxx-readiness.mjs session-start"
7900
+ },
7901
+ {
7902
+ gate: "mcp-gate",
7903
+ event: "PreToolUse",
7904
+ matcher: "MCP",
7905
+ command: "node ./.codex/pluxx-readiness.mjs mcp-gate"
7906
+ },
7907
+ {
7908
+ gate: "prompt-gate",
7909
+ event: "UserPromptSubmit",
7910
+ command: "node ./.codex/pluxx-readiness.mjs prompt-gate"
7911
+ }
7912
+ ],
7913
+ notes: CODEX_EXTERNAL_NOTE
7914
+ };
7915
+ case "opencode":
7916
+ return {
7917
+ platform,
7918
+ delivery: "runtime-callbacks",
7919
+ bundleEnforced: true,
7920
+ namedPromptTargetScope: "best-effort",
7921
+ scriptPath: "runtime/pluxx-readiness.mjs",
7922
+ companionArtifacts: [],
7923
+ bindings: [
7924
+ {
7925
+ gate: "session-start",
7926
+ event: "session.created",
7927
+ command: "node ./runtime/pluxx-readiness.mjs session-start"
7928
+ },
7929
+ {
7930
+ gate: "mcp-gate",
7931
+ event: "tool.execute.before",
7932
+ command: "node ./runtime/pluxx-readiness.mjs mcp-gate"
7933
+ },
7934
+ {
7935
+ gate: "prompt-gate",
7936
+ event: "chat.message",
7937
+ command: "node ./runtime/pluxx-readiness.mjs prompt-gate"
7938
+ }
7939
+ ]
7940
+ };
7941
+ }
7942
+ }
7943
+
7686
7944
  // src/validation/platform-rules.ts
7687
7945
  var STANDARD_SKILL_FRONTMATTER = [
7688
7946
  "name",
@@ -8456,7 +8714,7 @@ var CORE_FOUR_PRIMITIVE_CAPABILITIES = {
8456
8714
  runtime: {
8457
8715
  mode: "preserve",
8458
8716
  nativeSurfaces: [".mcp.json", ".app.json", ".codex/config.toml", "scripts/", "assets/"],
8459
- notes: "Bundle-local MCP config exists, but active MCP state also lives in config.toml."
8717
+ notes: `Bundle-local MCP config exists, but active MCP state also lives in config.toml. ${getRuntimeReadinessExternalConfigNote()}`
8460
8718
  },
8461
8719
  distribution: {
8462
8720
  mode: "preserve",
@@ -8630,6 +8888,57 @@ function renderCompatibilityMatrixMarkdown() {
8630
8888
  `;
8631
8889
  }
8632
8890
 
8891
+ // src/runtime-script-contract.ts
8892
+ var INSTALLER_OWNED_CHECK_ENV_PATH = "scripts/check-env.sh";
8893
+ var RUNTIME_SCRIPT_ROLE_PATHS = {
8894
+ "install-validation": INSTALLER_OWNED_CHECK_ENV_PATH,
8895
+ "runtime-env": "scripts/load-env.sh",
8896
+ "runtime-bootstrap": "scripts/bootstrap-runtime.sh",
8897
+ "runtime-entrypoint": "scripts/start-mcp.sh"
8898
+ };
8899
+ var PORTABLE_RUNTIME_SCRIPT_ROLES = [
8900
+ RUNTIME_SCRIPT_ROLE_PATHS["runtime-env"],
8901
+ RUNTIME_SCRIPT_ROLE_PATHS["runtime-bootstrap"],
8902
+ RUNTIME_SCRIPT_ROLE_PATHS["runtime-entrypoint"]
8903
+ ];
8904
+ function getPortableRuntimeScriptRoleGuidance() {
8905
+ return `Use separate runtime scripts such as ${PORTABLE_RUNTIME_SCRIPT_ROLES.join(", ")} instead.`;
8906
+ }
8907
+ function getRuntimeScriptRoleForPath(path) {
8908
+ const normalized = path.replace(/\\/g, "/").replace(/^\.\//, "");
8909
+ for (const [role, rolePath] of Object.entries(RUNTIME_SCRIPT_ROLE_PATHS)) {
8910
+ if (normalized === rolePath) return role;
8911
+ }
8912
+ return null;
8913
+ }
8914
+ function getRuntimeScriptPathsForRoles(roles) {
8915
+ return roles.map((role) => RUNTIME_SCRIPT_ROLE_PATHS[role]);
8916
+ }
8917
+ function formatRuntimeScriptRoles(roles) {
8918
+ return getRuntimeScriptPathsForRoles(roles).join(", ");
8919
+ }
8920
+ function referencesInstallerOwnedCheckEnv(command) {
8921
+ return command.includes("check-env.sh");
8922
+ }
8923
+ function getInstallerOwnedCheckEnvRuntimeMessage(serverName) {
8924
+ return `MCP server "${serverName}" references ${INSTALLER_OWNED_CHECK_ENV_PATH} in its runtime command or args. Pluxx install rewrites that file into a no-op after userConfig materialization, so runtime startup must not depend on it. ${getPortableRuntimeScriptRoleGuidance()}`;
8925
+ }
8926
+ function getInstallerOwnedCheckEnvHookMessage(eventName) {
8927
+ return `Hook "${eventName}" references ${INSTALLER_OWNED_CHECK_ENV_PATH} as part of a broader runtime command. Treat that script as installer-owned and install-time only, because local installs may rewrite it into a no-op after required config is materialized.`;
8928
+ }
8929
+ function getConsumerEnvScriptMissingDetail() {
8930
+ return `This bundle does not ship a ${INSTALLER_OWNED_CHECK_ENV_PATH} file.`;
8931
+ }
8932
+ function getConsumerEnvScriptActiveDetail() {
8933
+ return `This bundle still runs ${INSTALLER_OWNED_CHECK_ENV_PATH}, which usually means required config was not materialized into the installed plugin.`;
8934
+ }
8935
+ function getConsumerRuntimeScriptRolesDetail(roles) {
8936
+ if (roles.length === 0) {
8937
+ return "This bundle does not include any of the known portable runtime script-role files.";
8938
+ }
8939
+ return `This bundle includes the following known runtime script-role files: ${formatRuntimeScriptRoles(roles)}.`;
8940
+ }
8941
+
8633
8942
  // src/compiler-intent.ts
8634
8943
  import { existsSync, readFileSync } from "fs";
8635
8944
  import { resolve } from "path";
@@ -9241,6 +9550,14 @@ NODE
9241
9550
  function hasInstallerUserConfig(config, platform) {
9242
9551
  return collectUserConfigEntries(config, [platform]).length > 0;
9243
9552
  }
9553
+ function renderInstallerRuntimeBootstrapSnippet(installDirVariable) {
9554
+ return `
9555
+ if [[ -f "${installDirVariable}/scripts/bootstrap-runtime.sh" ]]; then
9556
+ echo "Preparing local plugin runtime dependencies..."
9557
+ bash "${installDirVariable}/scripts/bootstrap-runtime.sh"
9558
+ fi
9559
+ `;
9560
+ }
9244
9561
  function renderInstallClaudeCodeScript(config) {
9245
9562
  return `#!/usr/bin/env bash
9246
9563
  set -euo pipefail
@@ -9305,6 +9622,7 @@ mkdir -p "$INSTALL_ROOT/.claude-plugin" "$INSTALL_ROOT/plugins"
9305
9622
  rm -rf "$INSTALL_ROOT/plugins/$PLUGIN_NAME"
9306
9623
  cp -R "$BUNDLE_DIR" "$INSTALL_ROOT/plugins/$PLUGIN_NAME"
9307
9624
  ${renderInstallerUserConfigSnippet(config, "claude-code", "$INSTALL_ROOT/plugins/$PLUGIN_NAME")}
9625
+ ${renderInstallerRuntimeBootstrapSnippet("$INSTALL_ROOT/plugins/$PLUGIN_NAME")}
9308
9626
 
9309
9627
  cat > "$INSTALL_ROOT/.claude-plugin/marketplace.json" <<JSON
9310
9628
  {
@@ -9398,6 +9716,7 @@ mkdir -p "$(dirname "$INSTALL_DIR")"
9398
9716
  rm -rf "$INSTALL_DIR"
9399
9717
  cp -R "$BUNDLE_DIR" "$INSTALL_DIR"
9400
9718
  ${renderInstallerUserConfigSnippet(config, "cursor", "$INSTALL_DIR")}
9719
+ ${renderInstallerRuntimeBootstrapSnippet("$INSTALL_DIR")}
9401
9720
 
9402
9721
  echo "Installed $PLUGIN_NAME to $INSTALL_DIR"
9403
9722
  echo "If Cursor is already open, use Developer: Reload Window or restart Cursor so the plugin is picked up."
@@ -9456,6 +9775,7 @@ mkdir -p "$(dirname "$INSTALL_DIR")"
9456
9775
  rm -rf "$INSTALL_DIR"
9457
9776
  cp -R "$BUNDLE_DIR" "$INSTALL_DIR"
9458
9777
  ${renderInstallerUserConfigSnippet(config, "codex", "$INSTALL_DIR")}
9778
+ ${renderInstallerRuntimeBootstrapSnippet("$INSTALL_DIR")}
9459
9779
 
9460
9780
  mkdir -p "$(dirname "$MARKETPLACE_PATH")"
9461
9781
 
@@ -9571,6 +9891,7 @@ mkdir -p "$(dirname "$INSTALL_DIR")" "$SKILLS_ROOT"
9571
9891
  rm -rf "$INSTALL_DIR"
9572
9892
  cp -R "$BUNDLE_DIR" "$INSTALL_DIR"
9573
9893
  ${renderInstallerUserConfigSnippet(config, "opencode", "$INSTALL_DIR")}
9894
+ ${renderInstallerRuntimeBootstrapSnippet("$INSTALL_DIR")}
9574
9895
 
9575
9896
  export ENTRY_PATH
9576
9897
  export PLUGIN_NAME
@@ -9856,6 +10177,7 @@ import { existsSync as existsSync5, lstatSync as lstatSync2, readdirSync as read
9856
10177
  import { resolve as resolve5 } from "path";
9857
10178
 
9858
10179
  // src/cli/doctor.ts
10180
+ import { spawn } from "child_process";
9859
10181
  import { accessSync, constants, existsSync as existsSync4, lstatSync, readFileSync as readFileSync4, readdirSync as readdirSync2 } from "fs";
9860
10182
  import { basename, dirname as dirname2, resolve as resolve4 } from "path";
9861
10183
 
@@ -9872,6 +10194,29 @@ var CONFIG_FILES = [
9872
10194
  // src/cli/install.ts
9873
10195
  import { resolve as resolve3, dirname } from "path";
9874
10196
  import { existsSync as existsSync3, symlinkSync, mkdirSync as mkdirSync2, rmSync as rmSync2, readFileSync as readFileSync3, writeFileSync as writeFileSync2, cpSync, readdirSync } from "fs";
10197
+
10198
+ // src/mcp-stdio-paths.ts
10199
+ function findHostPluginRootVars(value) {
10200
+ const matches = value.match(/\$\{(?:CLAUDE_PLUGIN_ROOT|CURSOR_PLUGIN_ROOT|PLUGIN_ROOT)\}/g) ?? [];
10201
+ return [...new Set(matches.map((match) => match.slice(2, -1)))];
10202
+ }
10203
+ function findLeakedPluginRootVars(platform, values) {
10204
+ const leaks = /* @__PURE__ */ new Set();
10205
+ for (const value of values) {
10206
+ for (const pluginRootVar of findHostPluginRootVars(value)) {
10207
+ if (platform === "claude-code") {
10208
+ if (pluginRootVar !== "CLAUDE_PLUGIN_ROOT") {
10209
+ leaks.add(pluginRootVar);
10210
+ }
10211
+ continue;
10212
+ }
10213
+ leaks.add(pluginRootVar);
10214
+ }
10215
+ }
10216
+ return [...leaks];
10217
+ }
10218
+
10219
+ // src/cli/install.ts
9875
10220
  function getInstallTargets(pluginName) {
9876
10221
  const home = process.env.HOME ?? "~";
9877
10222
  return [
@@ -9935,9 +10280,39 @@ function getInstallTargets(pluginName) {
9935
10280
  function getClaudeMarketplaceName(pluginName) {
9936
10281
  return `pluxx-local-${pluginName}`;
9937
10282
  }
10283
+ function readBundleManifestVersion(rootDir, platform) {
10284
+ const manifestPath = manifestPathForPlatform(platform);
10285
+ if (!manifestPath) return void 0;
10286
+ const filepath = resolve3(rootDir, manifestPath);
10287
+ if (!existsSync3(filepath)) return void 0;
10288
+ try {
10289
+ const manifest = JSON.parse(readFileSync3(filepath, "utf-8"));
10290
+ return typeof manifest.version === "string" ? manifest.version : void 0;
10291
+ } catch {
10292
+ return void 0;
10293
+ }
10294
+ }
10295
+ function resolveClaudeInstalledCachePath(pluginName, version) {
10296
+ if (!version) return void 0;
10297
+ const home = process.env.HOME ?? "~";
10298
+ return resolve3(home, ".claude/plugins/cache", getClaudeMarketplaceName(pluginName), pluginName, version);
10299
+ }
10300
+ function resolveExpectedInstalledConsumerPath(target, pluginName) {
10301
+ if (target.platform === "claude-code" && pluginName !== "") {
10302
+ const cachePath = resolveClaudeInstalledCachePath(
10303
+ pluginName,
10304
+ readBundleManifestVersion(target.sourceDir, "claude-code")
10305
+ );
10306
+ if (cachePath) return cachePath;
10307
+ }
10308
+ return target.pluginDir;
10309
+ }
9938
10310
  function resolveInstalledConsumerPath(target, pluginName) {
9939
10311
  if (target.platform === "claude-code" && pluginName !== "") {
9940
- return target.pluginDir;
10312
+ const expectedPath = resolveExpectedInstalledConsumerPath(target, pluginName);
10313
+ if (existsSync3(expectedPath)) return expectedPath;
10314
+ if (existsSync3(target.pluginDir)) return target.pluginDir;
10315
+ return expectedPath;
9941
10316
  }
9942
10317
  return target.pluginDir;
9943
10318
  }
@@ -10013,7 +10388,8 @@ function findInstalledBundleIntegrityIssues(rootDir, platform) {
10013
10388
  if (!manifestPath) {
10014
10389
  return {
10015
10390
  missingManifestPaths: [],
10016
- missingHookTargets: []
10391
+ missingHookTargets: [],
10392
+ invalidRuntimeScripts: []
10017
10393
  };
10018
10394
  }
10019
10395
  const manifestFile = resolve3(rootDir, manifestPath);
@@ -10021,7 +10397,8 @@ function findInstalledBundleIntegrityIssues(rootDir, platform) {
10021
10397
  return {
10022
10398
  manifestIssue: `missing plugin manifest at ${manifestPath}`,
10023
10399
  missingManifestPaths: [],
10024
- missingHookTargets: []
10400
+ missingHookTargets: [],
10401
+ invalidRuntimeScripts: []
10025
10402
  };
10026
10403
  }
10027
10404
  let manifest;
@@ -10031,7 +10408,8 @@ function findInstalledBundleIntegrityIssues(rootDir, platform) {
10031
10408
  return {
10032
10409
  manifestIssue: `plugin manifest at ${manifestPath} is not parseable: ${error instanceof Error ? error.message : String(error)}`,
10033
10410
  missingManifestPaths: [],
10034
- missingHookTargets: []
10411
+ missingHookTargets: [],
10412
+ invalidRuntimeScripts: []
10035
10413
  };
10036
10414
  }
10037
10415
  const missingManifestPaths = readBundleManifestReferences(manifest).filter((value) => {
@@ -10042,14 +10420,16 @@ function findInstalledBundleIntegrityIssues(rootDir, platform) {
10042
10420
  if (!hooksReference) {
10043
10421
  return {
10044
10422
  missingManifestPaths,
10045
- missingHookTargets: []
10423
+ missingHookTargets: [],
10424
+ invalidRuntimeScripts: findInstalledRuntimeScriptIssues(rootDir, manifest)
10046
10425
  };
10047
10426
  }
10048
10427
  const hooksPath = resolveBundleReference(rootDir, hooksReference);
10049
10428
  if (!hooksPath || !existsSync3(hooksPath)) {
10050
10429
  return {
10051
10430
  missingManifestPaths,
10052
- missingHookTargets: []
10431
+ missingHookTargets: [],
10432
+ invalidRuntimeScripts: findInstalledRuntimeScriptIssues(rootDir, manifest)
10053
10433
  };
10054
10434
  }
10055
10435
  try {
@@ -10064,15 +10444,47 @@ function findInstalledBundleIntegrityIssues(rootDir, platform) {
10064
10444
  )].sort();
10065
10445
  return {
10066
10446
  missingManifestPaths,
10067
- missingHookTargets
10447
+ missingHookTargets,
10448
+ invalidRuntimeScripts: findInstalledRuntimeScriptIssues(rootDir, manifest)
10068
10449
  };
10069
10450
  } catch {
10070
10451
  return {
10071
10452
  missingManifestPaths,
10072
- missingHookTargets: []
10453
+ missingHookTargets: [],
10454
+ invalidRuntimeScripts: findInstalledRuntimeScriptIssues(rootDir, manifest)
10073
10455
  };
10074
10456
  }
10075
10457
  }
10458
+ function findInstalledRuntimeScriptIssues(rootDir, manifest) {
10459
+ const mcpReference = typeof manifest.mcpServers === "string" ? manifest.mcpServers : void 0;
10460
+ if (!mcpReference) return [];
10461
+ const mcpPath = resolveBundleReference(rootDir, mcpReference);
10462
+ if (!mcpPath || !existsSync3(mcpPath)) return [];
10463
+ try {
10464
+ const parsed = JSON.parse(readFileSync3(mcpPath, "utf-8"));
10465
+ const issues = /* @__PURE__ */ new Set();
10466
+ for (const [serverName, server] of Object.entries(parsed.mcpServers ?? {})) {
10467
+ if (!server || typeof server !== "object") continue;
10468
+ const serverRecord = server;
10469
+ const args = Array.isArray(serverRecord.args) ? serverRecord.args.filter((value) => typeof value === "string") : [];
10470
+ const commandTargets = [
10471
+ typeof serverRecord.command === "string" ? serverRecord.command : "",
10472
+ ...args
10473
+ ].flatMap(extractBundleCommandTargets);
10474
+ for (const target of commandTargets) {
10475
+ const resolved = resolveBundleReference(rootDir, target);
10476
+ if (!resolved || !existsSync3(resolved) || !resolved.endsWith(".sh")) continue;
10477
+ const content = readFileSync3(resolved, "utf-8");
10478
+ if (!content.includes("check-env.sh")) continue;
10479
+ const relativePath = resolved.startsWith(`${rootDir}/`) ? resolved.slice(rootDir.length + 1) : resolved;
10480
+ issues.add(`runtime script ${relativePath} for MCP server "${serverName}" still references installer-owned scripts/check-env.sh`);
10481
+ }
10482
+ }
10483
+ return [...issues].sort();
10484
+ } catch {
10485
+ return [];
10486
+ }
10487
+ }
10076
10488
  function planInstallPlugin(distDir, pluginName, platforms) {
10077
10489
  const targets = getInstallTargets(pluginName);
10078
10490
  const filtered = platforms ? targets.filter((t) => platforms.includes(t.platform)) : targets;
@@ -10224,6 +10636,10 @@ var MUTATING_PREFIX_PATTERN = new RegExp(`^(${MUTATING_PREFIXES.join("|")})\\b`,
10224
10636
  // src/cli/doctor.ts
10225
10637
  var MATERIALIZED_ENV_MARKER = "materialized required config";
10226
10638
  var MIN_NODE_MAJOR = 18;
10639
+ var STDIO_LAUNCH_SMOKE_TIMEOUT_MS = 1200;
10640
+ function renderInstalledPluginRoot(value, rootDir) {
10641
+ return value.replaceAll("${PLUGIN_ROOT}", rootDir).replaceAll("${CLAUDE_PLUGIN_ROOT}", rootDir).replaceAll("${CURSOR_PLUGIN_ROOT}", rootDir).replaceAll("${CODEX_PLUGIN_ROOT}", rootDir).replaceAll("${OPENCODE_PLUGIN_ROOT}", rootDir);
10642
+ }
10227
10643
  function addCheck(checks, check) {
10228
10644
  checks.push(check);
10229
10645
  }
@@ -10422,14 +10838,14 @@ function checkInstalledUserConfig(checks, rootDir) {
10422
10838
  }
10423
10839
  }
10424
10840
  function checkInstalledEnvValidation(checks, rootDir) {
10425
- const envScriptPath = "scripts/check-env.sh";
10841
+ const envScriptPath = INSTALLER_OWNED_CHECK_ENV_PATH;
10426
10842
  const resolvedPath = resolve4(rootDir, envScriptPath);
10427
10843
  if (!existsSync4(resolvedPath)) {
10428
10844
  addCheck(checks, {
10429
10845
  level: "info",
10430
10846
  code: "consumer-env-script-missing",
10431
10847
  title: "No install-time env validation script found",
10432
- detail: "This bundle does not ship a scripts/check-env.sh file.",
10848
+ detail: getConsumerEnvScriptMissingDetail(),
10433
10849
  fix: "No action needed unless this plugin is expected to validate runtime secrets on install.",
10434
10850
  path: envScriptPath
10435
10851
  });
@@ -10451,12 +10867,30 @@ function checkInstalledEnvValidation(checks, rootDir) {
10451
10867
  level: "warning",
10452
10868
  code: "consumer-env-script-active",
10453
10869
  title: "Install-time env validation is still active",
10454
- detail: "This bundle still runs scripts/check-env.sh, which usually means required config was not materialized into the installed plugin.",
10870
+ detail: getConsumerEnvScriptActiveDetail(),
10455
10871
  fix: "If authenticated tools fail, reinstall the plugin and provide the requested userConfig values or required env vars.",
10456
10872
  path: envScriptPath
10457
10873
  });
10458
10874
  }
10459
- function checkInstalledMcpConfig(checks, rootDir, layout) {
10875
+ function checkInstalledRuntimeScriptRoles(checks, rootDir) {
10876
+ const roleFiles = [
10877
+ "scripts/check-env.sh",
10878
+ "scripts/load-env.sh",
10879
+ "scripts/bootstrap-runtime.sh",
10880
+ "scripts/start-mcp.sh"
10881
+ ];
10882
+ const presentRoles = roleFiles.filter((relativePath) => existsSync4(resolve4(rootDir, relativePath))).map((relativePath) => getRuntimeScriptRoleForPath(relativePath)).filter((role) => role !== null);
10883
+ if (presentRoles.length === 0) return;
10884
+ addCheck(checks, {
10885
+ level: "info",
10886
+ code: "consumer-runtime-script-roles",
10887
+ title: "Known runtime script-role files detected",
10888
+ detail: getConsumerRuntimeScriptRolesDetail(presentRoles),
10889
+ fix: "No action needed unless the runtime startup chain is unexpectedly missing a script you rely on.",
10890
+ path: "scripts/"
10891
+ });
10892
+ }
10893
+ async function checkInstalledMcpConfig(checks, rootDir, layout) {
10460
10894
  if (!layout.mcpConfigPath) {
10461
10895
  addCheck(checks, {
10462
10896
  level: "info",
@@ -10504,8 +10938,9 @@ function checkInstalledMcpConfig(checks, rootDir, layout) {
10504
10938
  path: layout.mcpConfigPath
10505
10939
  });
10506
10940
  }
10507
- const remoteEntries = servers.filter((server) => "url" in server);
10508
- const stdioEntries = servers.filter((server) => "command" in server);
10941
+ const namedServers = Object.entries(payload.mcpServers ?? {}).map(([name, server]) => ({ name, ...server }));
10942
+ const remoteEntries = namedServers.filter((server) => "url" in server);
10943
+ const stdioEntries = namedServers.filter((server) => "command" in server);
10509
10944
  const inlineHeaderEntries = servers.filter((server) => {
10510
10945
  if ("headers" in server && server.headers && typeof server.headers === "object") return true;
10511
10946
  if ("http_headers" in server && server.http_headers && typeof server.http_headers === "object") return true;
@@ -10531,6 +10966,38 @@ function checkInstalledMcpConfig(checks, rootDir, layout) {
10531
10966
  path: layout.mcpConfigPath
10532
10967
  });
10533
10968
  }
10969
+ const leakedPluginRootVars = [...new Set(
10970
+ stdioEntries.flatMap((server) => {
10971
+ const serverRecord = server;
10972
+ const serverArgs = Array.isArray(serverRecord.args) ? serverRecord.args.filter((value) => typeof value === "string") : [];
10973
+ const values = [
10974
+ typeof server.command === "string" ? server.command : "",
10975
+ ...serverArgs
10976
+ ];
10977
+ return findLeakedPluginRootVars(layout.platform, values);
10978
+ })
10979
+ )].sort();
10980
+ if (leakedPluginRootVars.length > 0) {
10981
+ addCheck(checks, {
10982
+ level: "warning",
10983
+ code: "consumer-mcp-stdio-host-root-leak",
10984
+ title: "Installed stdio MCP config contains the wrong host root contract",
10985
+ detail: `This installed ${layout.platform} MCP config still contains plugin root variable${leakedPluginRootVars.length === 1 ? "" : "s"} that do not belong in this host bundle: ${leakedPluginRootVars.map((pluginRootVar) => `\${${pluginRootVar}}`).join(", ")}.`,
10986
+ fix: "Author global stdio MCP paths as `./...` or `${PLUGIN_ROOT}/...`, then rebuild and reinstall so Pluxx can normalize the correct host-specific path.",
10987
+ path: layout.mcpConfigPath
10988
+ });
10989
+ }
10990
+ const launchResults = await smokeCheckInstalledStdioServers(rootDir, stdioEntries);
10991
+ for (const result of launchResults) {
10992
+ addCheck(checks, {
10993
+ level: result.ok ? "success" : "error",
10994
+ code: result.ok ? "consumer-mcp-stdio-launch-valid" : "consumer-mcp-stdio-launch-failed",
10995
+ title: result.ok ? `Installed stdio MCP server launches for ${result.serverName}` : `Installed stdio MCP server failed to stay up for ${result.serverName}`,
10996
+ detail: `${result.command || "(empty command)"} \u2014 ${result.detail}`,
10997
+ fix: result.ok ? "No action needed." : "Launch the installed command directly from the plugin directory, fix any missing runtime files/dependencies, then reinstall and rerun pluxx verify-install.",
10998
+ path: layout.mcpConfigPath
10999
+ });
11000
+ }
10534
11001
  }
10535
11002
  if (remoteEntries.length > 0 && inlineHeaderEntries.length > 0) {
10536
11003
  addCheck(checks, {
@@ -10577,6 +11044,9 @@ function checkInstalledBundleIntegrity(checks, rootDir, layout) {
10577
11044
  if (issues.missingHookTargets.length > 0) {
10578
11045
  details.push(`hook commands reference missing bundle target${issues.missingHookTargets.length === 1 ? "" : "s"}: ${issues.missingHookTargets.join(", ")}`);
10579
11046
  }
11047
+ if (issues.invalidRuntimeScripts.length > 0) {
11048
+ details.push(`runtime startup still depends on installer-owned validation: ${issues.invalidRuntimeScripts.join(", ")}`);
11049
+ }
10580
11050
  if (details.length === 0) {
10581
11051
  addCheck(checks, {
10582
11052
  level: "success",
@@ -10612,6 +11082,87 @@ function findMissingInstalledStdioRuntimePaths(rootDir, stdioEntries) {
10612
11082
  }
10613
11083
  return [...missing].sort();
10614
11084
  }
11085
+ async function smokeCheckInstalledStdioServers(rootDir, stdioEntries) {
11086
+ const results = [];
11087
+ for (const server of stdioEntries) {
11088
+ const serverName = typeof server.name === "string" ? server.name : "unknown";
11089
+ const command = typeof server.command === "string" ? renderInstalledPluginRoot(server.command, rootDir) : "";
11090
+ const args = Array.isArray(server.args) ? server.args.filter((value) => typeof value === "string").map((value) => renderInstalledPluginRoot(value, rootDir)) : [];
11091
+ const envRecord = server.env && typeof server.env === "object" ? Object.fromEntries(
11092
+ Object.entries(server.env).filter((entry) => typeof entry[1] === "string").map(([key, value]) => [key, renderInstalledPluginRoot(value, rootDir)])
11093
+ ) : {};
11094
+ if (command.trim().length === 0) {
11095
+ results.push({
11096
+ serverName,
11097
+ command: "",
11098
+ ok: false,
11099
+ detail: "stdio command is empty"
11100
+ });
11101
+ continue;
11102
+ }
11103
+ const renderedCommand = [command, ...args].join(" ");
11104
+ const stdoutChunks = [];
11105
+ const stderrChunks = [];
11106
+ const child = spawn(command, args, {
11107
+ cwd: rootDir,
11108
+ env: {
11109
+ ...process.env,
11110
+ ...envRecord
11111
+ },
11112
+ stdio: ["pipe", "pipe", "pipe"]
11113
+ });
11114
+ child.stdout?.on("data", (chunk) => {
11115
+ if (stdoutChunks.reduce((sum, entry) => sum + entry.length, 0) < 4096) {
11116
+ stdoutChunks.push(Buffer.from(chunk));
11117
+ }
11118
+ });
11119
+ child.stderr?.on("data", (chunk) => {
11120
+ if (stderrChunks.reduce((sum, entry) => sum + entry.length, 0) < 4096) {
11121
+ stderrChunks.push(Buffer.from(chunk));
11122
+ }
11123
+ });
11124
+ const exitResult = await new Promise((resolveResult) => {
11125
+ let settled = false;
11126
+ const settle = (result) => {
11127
+ if (settled) return;
11128
+ settled = true;
11129
+ clearTimeout(timeout);
11130
+ resolveResult(result);
11131
+ };
11132
+ const timeout = setTimeout(() => {
11133
+ child.stdin?.end();
11134
+ child.kill("SIGTERM");
11135
+ settle({
11136
+ serverName,
11137
+ command: renderedCommand,
11138
+ ok: true,
11139
+ detail: `process stayed alive for ${STDIO_LAUNCH_SMOKE_TIMEOUT_MS}ms before teardown`
11140
+ });
11141
+ }, STDIO_LAUNCH_SMOKE_TIMEOUT_MS);
11142
+ child.once("error", (error) => {
11143
+ settle({
11144
+ serverName,
11145
+ command: renderedCommand,
11146
+ ok: false,
11147
+ detail: `failed to spawn: ${error.message}`
11148
+ });
11149
+ });
11150
+ child.once("exit", (code, signal) => {
11151
+ const stdout = Buffer.concat(stdoutChunks).toString("utf-8").trim();
11152
+ const stderr = Buffer.concat(stderrChunks).toString("utf-8").trim();
11153
+ const output = [stderr, stdout].filter(Boolean).join(" | ");
11154
+ settle({
11155
+ serverName,
11156
+ command: renderedCommand,
11157
+ ok: false,
11158
+ detail: `process exited before ready window (code=${code ?? "null"}, signal=${signal ?? "null"})${output ? `: ${output}` : ""}`
11159
+ });
11160
+ });
11161
+ });
11162
+ results.push(exitResult);
11163
+ }
11164
+ return results;
11165
+ }
10615
11166
  function isLikelyLocalRuntimePath(value) {
10616
11167
  return value.startsWith("./") || value.startsWith("../") || value.startsWith(".\\") || value.startsWith("..\\");
10617
11168
  }
@@ -10785,7 +11336,8 @@ async function doctorConsumer(rootDir = process.cwd()) {
10785
11336
  checkInstalledBundleIntegrity(checks, rootDir, layout);
10786
11337
  checkInstalledUserConfig(checks, rootDir);
10787
11338
  checkInstalledEnvValidation(checks, rootDir);
10788
- checkInstalledMcpConfig(checks, rootDir, layout);
11339
+ checkInstalledRuntimeScriptRoles(checks, rootDir);
11340
+ await checkInstalledMcpConfig(checks, rootDir, layout);
10789
11341
  if (layout.platform === "opencode") {
10790
11342
  checkInstalledOpenCodeHostBridge(checks, rootDir);
10791
11343
  checkInstalledOpenCodeSkills(checks, rootDir);
@@ -10800,7 +11352,7 @@ function buildCheckFromReport(target, pluginName, report) {
10800
11352
  const stale = staleReason !== void 0;
10801
11353
  return {
10802
11354
  platform: target.platform,
10803
- installPath: target.pluginDir,
11355
+ installPath: consumerPath,
10804
11356
  consumerPath,
10805
11357
  built: target.built,
10806
11358
  installed: existsSync5(consumerPath),
@@ -10952,11 +11504,13 @@ function getVerifyInstallRecoveryActions(check) {
10952
11504
  }
10953
11505
  export {
10954
11506
  CORE_FOUR_PRIMITIVE_CAPABILITIES,
11507
+ INSTALLER_OWNED_CHECK_ENV_PATH,
10955
11508
  PLATFORM_LIMITS,
10956
11509
  PLATFORM_LIMIT_POLICIES,
10957
11510
  PLATFORM_VALIDATION_RULES,
10958
11511
  PLUXX_COMPILER_BUCKETS,
10959
11512
  PLUXX_COMPILER_INTENT_PATH,
11513
+ PORTABLE_RUNTIME_SCRIPT_ROLES,
10960
11514
  PluginConfigSchema,
10961
11515
  buildGeneratedPermissionHookScript,
10962
11516
  buildOpenCodePermissionMap,
@@ -10964,15 +11518,25 @@ export {
10964
11518
  definePlugin,
10965
11519
  formatPublishPlan,
10966
11520
  getConfiguredCompilerBuckets,
11521
+ getConsumerEnvScriptActiveDetail,
11522
+ getConsumerEnvScriptMissingDetail,
10967
11523
  getCoreFourPrimitiveCapabilities,
11524
+ getEnabledRuntimeReadinessBindings,
11525
+ getInstallerOwnedCheckEnvHookMessage,
11526
+ getInstallerOwnedCheckEnvRuntimeMessage,
10968
11527
  getPlatformCompatibilityMatrix,
10969
11528
  getPlatformRules,
10970
11529
  getPluginCompilerBuckets,
11530
+ getPortableRuntimeScriptRoleGuidance,
11531
+ getRuntimeReadinessCapability,
11532
+ getRuntimeReadinessExternalConfigNote,
11533
+ getRuntimeReadinessNamedPromptTargetNote,
10971
11534
  parsePermissionRule,
10972
11535
  permissionRulesNeedToolLevelDowngrade,
10973
11536
  planPublish,
10974
11537
  printVerifyInstallResult,
10975
11538
  readCompilerIntent,
11539
+ referencesInstallerOwnedCheckEnv,
10976
11540
  renderCompatibilityMatrixMarkdown,
10977
11541
  runPublish,
10978
11542
  verifyInstall