@orchid-labs/pluxx 0.1.8 → 0.1.10

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/dist/cli/index.js CHANGED
@@ -5195,11 +5195,27 @@ async function generateClaudeFamilyOutputs(args2) {
5195
5195
  function shellSingleQuote(value) {
5196
5196
  return `'${value.replace(/'/g, `'"'"'`)}'`;
5197
5197
  }
5198
+ function rewriteClaudePluginRootReference(value) {
5199
+ const normalized = value.replace(/\\/g, "/");
5200
+ if (normalized.startsWith("${CLAUDE_PLUGIN_ROOT}/")) return normalized;
5201
+ if (normalized.startsWith("${PLUGIN_ROOT}/")) {
5202
+ return normalized.replace("${PLUGIN_ROOT}", "${CLAUDE_PLUGIN_ROOT}");
5203
+ }
5204
+ if (normalized.startsWith("./")) {
5205
+ return `\${CLAUDE_PLUGIN_ROOT}/${normalized.slice(2)}`;
5206
+ }
5207
+ if (normalized.startsWith("../")) {
5208
+ return `\${CLAUDE_PLUGIN_ROOT}/${normalized}`;
5209
+ }
5210
+ return value;
5211
+ }
5198
5212
  function buildClaudeHookCommandWrapperScript(command2) {
5199
5213
  const serializedCommand = shellSingleQuote(command2);
5200
5214
  const exportLoader = [
5201
5215
  'import { readFileSync } from "node:fs"',
5202
5216
  "",
5217
+ "const shellSingleQuote = (input) => `'${String(input ?? \"\").replace(/'/g, `'\"'\"'`)}'`",
5218
+ "",
5203
5219
  "const filepath = process.argv[1]",
5204
5220
  "if (!filepath) process.exit(0)",
5205
5221
  'const payload = JSON.parse(readFileSync(filepath, "utf8"))',
@@ -5209,7 +5225,7 @@ function buildClaudeHookCommandWrapperScript(command2) {
5209
5225
  "",
5210
5226
  "for (const [key, value] of Object.entries(env)) {",
5211
5227
  " if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(key)) continue",
5212
- ' console.log(`export ${key}=${JSON.stringify(String(value ?? ""))}`)',
5228
+ " process.stdout.write(`export ${key}=${shellSingleQuote(value)}\\0`)",
5213
5229
  "}"
5214
5230
  ].join("\n");
5215
5231
  return [
@@ -5220,7 +5236,7 @@ function buildClaudeHookCommandWrapperScript(command2) {
5220
5236
  'PLUXX_USER_CONFIG_PATH="$PLUXX_PLUGIN_ROOT/.pluxx-user.json"',
5221
5237
  "",
5222
5238
  'if [ -f "$PLUXX_USER_CONFIG_PATH" ]; then',
5223
- " while IFS= read -r pluxx_export; do",
5239
+ " while IFS= read -r -d '' pluxx_export; do",
5224
5240
  ' if [ -n "$pluxx_export" ]; then',
5225
5241
  ' eval "$pluxx_export"',
5226
5242
  ' if [ -n "${CLAUDE_ENV_FILE:-}" ]; then',
@@ -5279,9 +5295,11 @@ async function writeMcpConfig(config, platform, writeJson) {
5279
5295
  const usesPlatformManagedAuth = platform === "claude-code" && config.platforms?.["claude-code"]?.mcpAuth === "platform";
5280
5296
  for (const [name, server] of Object.entries(config.mcp)) {
5281
5297
  if (server.transport === "stdio" && server.command) {
5298
+ const command2 = platform === "claude-code" ? rewriteClaudePluginRootReference(server.command) : server.command;
5299
+ const args2 = platform === "claude-code" ? (server.args ?? []).map(rewriteClaudePluginRootReference) : server.args ?? [];
5282
5300
  mcpServers[name] = {
5283
- command: server.command,
5284
- args: server.args ?? [],
5301
+ command: command2,
5302
+ args: args2,
5285
5303
  env: server.env ?? {}
5286
5304
  };
5287
5305
  } else {
@@ -8114,6 +8132,12 @@ var MAX_SKILL_NAME = AGENT_SKILLS_RULES.name.maxLength;
8114
8132
  var MAX_CODEX_DEFAULT_PROMPTS = CODEX_RULES.interface.maxDefaultPrompts;
8115
8133
  var MAX_CODEX_PROMPT_LENGTH = CODEX_RULES.interface.maxDefaultPromptLength;
8116
8134
  var HEX_COLOR_REGEX = CODEX_RULES.interface.brandColorPattern;
8135
+ var DIRECT_INSTALL_VALIDATION_HOOKS = /* @__PURE__ */ new Set([
8136
+ 'bash "${PLUGIN_ROOT}/scripts/check-env.sh"',
8137
+ 'bash "${CLAUDE_PLUGIN_ROOT}/scripts/check-env.sh"',
8138
+ 'bash "${CURSOR_PLUGIN_ROOT}/scripts/check-env.sh"',
8139
+ 'bash "./scripts/check-env.sh"'
8140
+ ]);
8117
8141
  function pushIssue(issues, issue) {
8118
8142
  issues.push(issue);
8119
8143
  }
@@ -8587,6 +8611,42 @@ function findLocalStdioRuntimePaths(rootDir, server) {
8587
8611
  function isLikelyLocalRuntimePath(value) {
8588
8612
  return value.startsWith("./") || value.startsWith("../") || value.startsWith(".\\") || value.startsWith("..\\");
8589
8613
  }
8614
+ function referencesInstallerOwnedCheckEnv(command2) {
8615
+ return command2.includes("check-env.sh");
8616
+ }
8617
+ function lintInstallerOwnedRuntimeScripts(config, issues) {
8618
+ if (config.mcp) {
8619
+ for (const [serverName, server] of Object.entries(config.mcp)) {
8620
+ if (server.transport !== "stdio") continue;
8621
+ const runtimeTokens = [server.command, ...server.args ?? []];
8622
+ if (!runtimeTokens.some((token) => referencesInstallerOwnedCheckEnv(token))) continue;
8623
+ pushIssue(issues, {
8624
+ level: "warning",
8625
+ code: "installer-owned-check-env-runtime",
8626
+ message: `MCP server "${serverName}" references scripts/check-env.sh 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. Use separate runtime scripts such as load-env.sh, bootstrap-runtime.sh, and start-mcp.sh instead.`,
8627
+ file: "pluxx.config.ts",
8628
+ platform: "Runtime"
8629
+ });
8630
+ }
8631
+ }
8632
+ if (!config.hooks) return;
8633
+ for (const [eventName, hookEntries] of Object.entries(config.hooks)) {
8634
+ if (!Array.isArray(hookEntries)) continue;
8635
+ for (const entry of hookEntries) {
8636
+ if (!entry || typeof entry !== "object") continue;
8637
+ const command2 = entry.command;
8638
+ if (typeof command2 !== "string" || !referencesInstallerOwnedCheckEnv(command2)) continue;
8639
+ if (DIRECT_INSTALL_VALIDATION_HOOKS.has(command2.trim())) continue;
8640
+ pushIssue(issues, {
8641
+ level: "warning",
8642
+ code: "installer-owned-check-env-hook",
8643
+ message: `Hook "${eventName}" references scripts/check-env.sh 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.`,
8644
+ file: "pluxx.config.ts",
8645
+ platform: "Runtime"
8646
+ });
8647
+ }
8648
+ }
8649
+ }
8590
8650
  function lintCodexHookCompatibility(config, issues) {
8591
8651
  if (!isCodexTargetEnabled(config) || !config.hooks) return;
8592
8652
  for (const hookEvent of Object.keys(config.hooks)) {
@@ -9276,6 +9336,7 @@ async function lintProject(dir = process.cwd(), options = {}) {
9276
9336
  lintOpenCodeAgentFrontmatter(dir, { ...lintConfig, agents: lintConfig.agents ?? "./agents/" }, issues);
9277
9337
  lintMcpUrls(lintConfig, issues);
9278
9338
  lintMcpRuntimeState(dir, lintConfig, issues);
9339
+ lintInstallerOwnedRuntimeScripts(lintConfig, issues);
9279
9340
  lintBrandMetadata(lintConfig, issues);
9280
9341
  lintCodexOverrides(lintConfig, issues);
9281
9342
  lintCodexHookCompatibility(lintConfig, issues);
@@ -1 +1 @@
1
- {"version":3,"file":"lint.d.ts","sourceRoot":"","sources":["../../src/cli/lint.ts"],"names":[],"mappings":"AAGA,OAAO,EAA6F,KAAK,cAAc,EAAE,MAAM,WAAW,CAAA;AAI1I,OAAO,EAAuE,KAAK,2BAA2B,EAAE,MAAM,qBAAqB,CAAA;AAsC3I,KAAK,SAAS,GAAG,OAAO,GAAG,SAAS,CAAA;AAEpC,UAAU,SAAS;IACjB,KAAK,EAAE,SAAS,CAAA;IAChB,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAaD,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,SAAS,EAAE,CAAA;IACnB,gBAAgB,CAAC,EAAE,2BAA2B,CAAA;CAC/C;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,CAAC,EAAE,cAAc,EAAE,CAAA;CAC3B;AAu1CD,wBAAsB,WAAW,CAC/B,GAAG,GAAE,MAAsB,EAC3B,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,UAAU,CAAC,CA6GrB;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,UAAU,EAAE,GAAG,GAAE,MAAsB,GAAG,IAAI,CA0BrF;AAED,wBAAsB,OAAO,CAAC,GAAG,GAAE,MAAsB,GAAG,OAAO,CAAC,MAAM,CAAC,CAI1E"}
1
+ {"version":3,"file":"lint.d.ts","sourceRoot":"","sources":["../../src/cli/lint.ts"],"names":[],"mappings":"AAGA,OAAO,EAA6F,KAAK,cAAc,EAAE,MAAM,WAAW,CAAA;AAI1I,OAAO,EAAuE,KAAK,2BAA2B,EAAE,MAAM,qBAAqB,CAAA;AAsC3I,KAAK,SAAS,GAAG,OAAO,GAAG,SAAS,CAAA;AAEpC,UAAU,SAAS;IACjB,KAAK,EAAE,SAAS,CAAA;IAChB,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAaD,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,SAAS,EAAE,CAAA;IACnB,gBAAgB,CAAC,EAAE,2BAA2B,CAAA;CAC/C;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,CAAC,EAAE,cAAc,EAAE,CAAA;CAC3B;AAy4CD,wBAAsB,WAAW,CAC/B,GAAG,GAAE,MAAsB,EAC3B,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,UAAU,CAAC,CA8GrB;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,UAAU,EAAE,GAAG,GAAE,MAAsB,GAAG,IAAI,CA0BrF;AAED,wBAAsB,OAAO,CAAC,GAAG,GAAE,MAAsB,GAAG,OAAO,CAAC,MAAM,CAAC,CAI1E"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@orchid-labs/pluxx",
3
- "version": "0.1.8",
3
+ "version": "0.1.10",
4
4
  "description": "Build AI agent plugins once. Prime-time on Claude Code, Cursor, Codex, and OpenCode, with beta generators for additional hosts.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",