@orchid-labs/pluxx 0.1.13 → 0.1.15

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 (51) hide show
  1. package/dist/agent-translation-registry.d.ts +6 -0
  2. package/dist/agent-translation-registry.d.ts.map +1 -0
  3. package/dist/agents.d.ts +22 -0
  4. package/dist/agents.d.ts.map +1 -1
  5. package/dist/cli/agent.d.ts.map +1 -1
  6. package/dist/cli/behavioral.d.ts +2 -0
  7. package/dist/cli/behavioral.d.ts.map +1 -1
  8. package/dist/cli/discover-installed-mcp.d.ts +2 -1
  9. package/dist/cli/discover-installed-mcp.d.ts.map +1 -1
  10. package/dist/cli/doctor.d.ts.map +1 -1
  11. package/dist/cli/index.js +3592 -1385
  12. package/dist/cli/init-from-mcp.d.ts +2 -0
  13. package/dist/cli/init-from-mcp.d.ts.map +1 -1
  14. package/dist/cli/install.d.ts.map +1 -1
  15. package/dist/cli/lint.d.ts.map +1 -1
  16. package/dist/cli/migrate.d.ts.map +1 -1
  17. package/dist/cli/publish.d.ts.map +1 -1
  18. package/dist/cli/verify-install.d.ts.map +1 -1
  19. package/dist/command-translation-registry.d.ts +9 -0
  20. package/dist/command-translation-registry.d.ts.map +1 -0
  21. package/dist/commands.d.ts +31 -0
  22. package/dist/commands.d.ts.map +1 -1
  23. package/dist/compiler-intent.d.ts +8 -0
  24. package/dist/compiler-intent.d.ts.map +1 -1
  25. package/dist/distribution-lifecycle.d.ts +6 -0
  26. package/dist/distribution-lifecycle.d.ts.map +1 -0
  27. package/dist/generators/base.d.ts.map +1 -1
  28. package/dist/generators/claude-code/index.d.ts.map +1 -1
  29. package/dist/generators/codex/index.d.ts +1 -0
  30. package/dist/generators/codex/index.d.ts.map +1 -1
  31. package/dist/generators/cursor/index.d.ts.map +1 -1
  32. package/dist/generators/opencode/index.d.ts +1 -0
  33. package/dist/generators/opencode/index.d.ts.map +1 -1
  34. package/dist/generators/shared/claude-family.d.ts.map +1 -1
  35. package/dist/hook-command-env.d.ts +2 -0
  36. package/dist/hook-command-env.d.ts.map +1 -0
  37. package/dist/hook-translation-registry.d.ts +10 -0
  38. package/dist/hook-translation-registry.d.ts.map +1 -1
  39. package/dist/index.js +248 -31
  40. package/dist/instructions.d.ts +6 -0
  41. package/dist/instructions.d.ts.map +1 -0
  42. package/dist/mcp-native-overrides.d.ts +14 -0
  43. package/dist/mcp-native-overrides.d.ts.map +1 -0
  44. package/dist/schema.d.ts +10109 -1659
  45. package/dist/schema.d.ts.map +1 -1
  46. package/dist/skill-translation-registry.d.ts +8 -0
  47. package/dist/skill-translation-registry.d.ts.map +1 -0
  48. package/dist/skills.d.ts +36 -0
  49. package/dist/skills.d.ts.map +1 -1
  50. package/dist/validation/platform-rules.d.ts.map +1 -1
  51. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -7415,10 +7415,20 @@ var McpServerSchema = external_exports.preprocess(
7415
7415
  external_exports.discriminatedUnion("transport", [McpServerHttpSchema, McpServerSseSchema, McpServerStdioSchema])
7416
7416
  );
7417
7417
  var HookEntrySchema = external_exports.object({
7418
- type: external_exports.enum(["command", "prompt"]).default("command"),
7418
+ type: external_exports.enum(["command", "http", "mcp_tool", "prompt", "agent"]).default("command"),
7419
7419
  command: external_exports.string().optional(),
7420
7420
  prompt: external_exports.string().optional(),
7421
7421
  model: external_exports.string().optional(),
7422
+ url: external_exports.string().url().optional(),
7423
+ headers: external_exports.record(external_exports.string(), external_exports.string()).optional(),
7424
+ allowedEnvVars: external_exports.array(external_exports.string()).optional(),
7425
+ server: external_exports.string().optional(),
7426
+ tool: external_exports.string().optional(),
7427
+ input: external_exports.record(external_exports.string(), external_exports.unknown()).optional(),
7428
+ if: external_exports.string().optional(),
7429
+ async: external_exports.boolean().optional(),
7430
+ asyncRewake: external_exports.boolean().optional(),
7431
+ shell: external_exports.enum(["bash"]).optional(),
7422
7432
  timeout: external_exports.number().optional(),
7423
7433
  matcher: external_exports.union([external_exports.string(), external_exports.record(external_exports.string(), external_exports.unknown())]).optional(),
7424
7434
  failClosed: external_exports.boolean().optional(),
@@ -7431,11 +7441,34 @@ var HookEntrySchema = external_exports.object({
7431
7441
  message: "Command hooks require a command."
7432
7442
  });
7433
7443
  }
7434
- if (entry.type === "prompt" && !entry.prompt) {
7444
+ if (entry.type === "http" && !entry.url) {
7445
+ ctx.addIssue({
7446
+ code: external_exports.ZodIssueCode.custom,
7447
+ path: ["url"],
7448
+ message: "HTTP hooks require a url."
7449
+ });
7450
+ }
7451
+ if (entry.type === "mcp_tool") {
7452
+ if (!entry.server) {
7453
+ ctx.addIssue({
7454
+ code: external_exports.ZodIssueCode.custom,
7455
+ path: ["server"],
7456
+ message: "MCP tool hooks require a server."
7457
+ });
7458
+ }
7459
+ if (!entry.tool) {
7460
+ ctx.addIssue({
7461
+ code: external_exports.ZodIssueCode.custom,
7462
+ path: ["tool"],
7463
+ message: "MCP tool hooks require a tool."
7464
+ });
7465
+ }
7466
+ }
7467
+ if ((entry.type === "prompt" || entry.type === "agent") && !entry.prompt) {
7435
7468
  ctx.addIssue({
7436
7469
  code: external_exports.ZodIssueCode.custom,
7437
7470
  path: ["prompt"],
7438
- message: "Prompt hooks require a prompt."
7471
+ message: `${entry.type === "agent" ? "Agent" : "Prompt"} hooks require a prompt.`
7439
7472
  });
7440
7473
  }
7441
7474
  });
@@ -7822,7 +7855,7 @@ function getEnabledRuntimeReadinessBindings(capability, plan) {
7822
7855
  });
7823
7856
  }
7824
7857
  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.";
7858
+ var CODEX_EXTERNAL_NOTE = "Codex readiness now bundles translated hooks in the plugin, but Pluxx still emits `.codex/readiness.generated.json` and `.codex/hooks.generated.json` companion guidance because some Codex runtimes still gate hook activation behind `codex_hooks`.";
7826
7859
  function getRuntimeReadinessNamedPromptTargetNote() {
7827
7860
  return NAMED_PROMPT_TARGET_NOTE;
7828
7861
  }
@@ -7891,7 +7924,7 @@ function getRuntimeReadinessCapability(platform, pluginRootVar = "PLUGIN_ROOT")
7891
7924
  bundleEnforced: false,
7892
7925
  namedPromptTargetScope: "best-effort",
7893
7926
  scriptPath: ".codex/pluxx-readiness.mjs",
7894
- companionArtifacts: [".codex/readiness.generated.json", ".codex/hooks.generated.json"],
7927
+ companionArtifacts: [".codex/readiness.generated.json", "hooks/hooks.json", ".codex/hooks.generated.json"],
7895
7928
  bindings: [
7896
7929
  {
7897
7930
  gate: "session-start",
@@ -8115,7 +8148,7 @@ var PLATFORM_LIMIT_POLICIES = {
8115
8148
  var PLATFORM_VALIDATION_RULES = {
8116
8149
  "claude-code": {
8117
8150
  platform: "claude-code",
8118
- summary: "Claude Code plugins use an optional manifest at .claude-plugin/plugin.json with auto-discovery for skills, commands, agents, hooks, MCP, marketplaces, and output styles.",
8151
+ summary: "Claude Code plugins use an optional manifest at .claude-plugin/plugin.json with auto-discovery for skills, commands, agents, hooks, MCP, marketplaces, output styles, and adjacent plugin assets like LSP, monitors, and themes.",
8119
8152
  limits: PLATFORM_LIMITS["claude-code"],
8120
8153
  limitPolicies: PLATFORM_LIMIT_POLICIES["claude-code"],
8121
8154
  skillDiscoveryDirs: [
@@ -8154,13 +8187,13 @@ var PLATFORM_VALIDATION_RULES = {
8154
8187
  hooks: {
8155
8188
  supported: true,
8156
8189
  files: ["hooks/hooks.json", ".claude-plugin/plugin.json", "~/.claude/settings.json", ".claude/settings.json", ".claude/settings.local.json"],
8157
- eventNames: ["SessionStart", "PreToolUse", "PostToolUse", "PermissionRequest", "TaskCreated", "TaskCompleted", "Stop", "Notification", "ConfigChange"],
8158
- notes: "Hook configs can be stored in hooks/hooks.json, inlined in plugin.json, added in settings files, or scoped through skill and agent frontmatter."
8190
+ eventNames: ["SessionStart", "Setup", "UserPromptSubmit", "UserPromptExpansion", "PreToolUse", "PermissionRequest", "PermissionDenied", "PostToolUse", "PostToolUseFailure", "PostToolBatch", "Notification", "SubagentStart", "SubagentStop", "TaskCreated", "TaskCompleted", "Stop", "StopFailure", "TeammateIdle", "InstructionsLoaded", "ConfigChange", "CwdChanged", "FileChanged", "WorktreeCreate", "WorktreeRemove", "PreCompact", "PostCompact", "Elicitation", "ElicitationResult", "SessionEnd"],
8191
+ notes: "Hook configs can be stored in hooks/hooks.json, inlined in plugin.json, added in settings files, or scoped through skill and agent frontmatter. Claude also documents a broader lifecycle event set than the older simplified Pluxx model."
8159
8192
  },
8160
8193
  instructions: {
8161
8194
  files: ["CLAUDE.md"],
8162
8195
  format: "markdown",
8163
- notes: "Claude keeps persistent instructions in CLAUDE.md and pushes longer procedures into skills."
8196
+ notes: "Claude keeps persistent instructions in CLAUDE.md and pushes longer procedures into skills. Related enforcement and distribution config also depends on managed, user, project, and local settings scopes."
8164
8197
  },
8165
8198
  sources: [
8166
8199
  { label: "Claude Code MCP docs", url: "https://code.claude.com/docs/en/mcp" },
@@ -8174,6 +8207,9 @@ var PLATFORM_VALIDATION_RULES = {
8174
8207
  { label: "Claude Code plugins reference", url: "https://code.claude.com/docs/en/plugins-reference" },
8175
8208
  { label: "Claude Code hooks guide", url: "https://code.claude.com/docs/en/hooks-guide" },
8176
8209
  { label: "Claude Code hooks docs", url: "https://code.claude.com/docs/en/hooks" },
8210
+ { label: "Claude Code settings docs", url: "https://code.claude.com/docs/en/settings" },
8211
+ { label: "Claude Code permissions docs", url: "https://code.claude.com/docs/en/permissions" },
8212
+ { label: "Claude Code memory docs", url: "https://code.claude.com/docs/en/memory" },
8177
8213
  { label: "Claude Code skills docs", url: "https://code.claude.com/docs/en/skills" },
8178
8214
  { label: "Claude Code sub-agents docs", url: "https://code.claude.com/docs/en/sub-agents" },
8179
8215
  { label: "Claude Code env vars docs", url: "https://code.claude.com/docs/en/env-vars" }
@@ -8212,13 +8248,13 @@ var PLATFORM_VALIDATION_RULES = {
8212
8248
  hooks: {
8213
8249
  supported: true,
8214
8250
  files: ["hooks/hooks.json", ".cursor/hooks.json", "~/.cursor/hooks.json"],
8215
- eventNames: ["sessionStart", "preToolUse", "postToolUse", "subagentStart", "subagentStop", "beforeShellExecution", "afterShellExecution"],
8216
- notes: "Cursor plugin hooks live under hooks/hooks.json; project and user hooks also exist separately and reload on save."
8251
+ eventNames: ["sessionStart", "sessionEnd", "preToolUse", "postToolUse", "postToolUseFailure", "subagentStart", "subagentStop", "beforeShellExecution", "afterShellExecution", "beforeMCPExecution", "afterMCPExecution", "beforeReadFile", "afterFileEdit", "beforeSubmitPrompt", "preCompact", "stop", "afterAgentResponse", "afterAgentThought", "beforeTabFileRead", "afterTabFileEdit"],
8252
+ notes: "Cursor plugin hooks live under hooks/hooks.json; project and user hooks also exist separately and reload on save. The official event surface spans both Agent and Tab flows."
8217
8253
  },
8218
8254
  instructions: {
8219
8255
  files: ["rules/", "AGENTS.md"],
8220
8256
  format: "mdc + markdown",
8221
- notes: "rules/ is the plugin-native instruction surface. AGENTS.md remains useful as shared repo guidance. Cursor subagents use markdown files under .cursor/agents or ~/.cursor/agents (with .claude/.codex compatibility paths)."
8257
+ notes: "rules/ is the plugin-native instruction surface. AGENTS.md remains useful as shared repo guidance. Cursor subagents use markdown files under .cursor/agents or ~/.cursor/agents (with .claude/.codex compatibility paths). Cursor rules do not apply to Tab."
8222
8258
  },
8223
8259
  sources: [
8224
8260
  { label: "Cursor plugins overview", url: "https://cursor.com/docs/plugins" },
@@ -8238,7 +8274,7 @@ var PLATFORM_VALIDATION_RULES = {
8238
8274
  },
8239
8275
  "codex": {
8240
8276
  platform: "codex",
8241
- summary: "Codex plugins use .codex-plugin/plugin.json with skills, optional .mcp.json and .app.json, marketplace catalogs, cache installs, AGENTS.md instructions, and separate hook configuration.",
8277
+ summary: "Codex plugins use .codex-plugin/plugin.json with skills, optional .mcp.json and .app.json, marketplace catalogs, cache installs, AGENTS.md instructions, and native bundled hook support plus broader project or user hook config.",
8242
8278
  limits: PLATFORM_LIMITS["codex"],
8243
8279
  limitPolicies: PLATFORM_LIMIT_POLICIES["codex"],
8244
8280
  skillDiscoveryDirs: [
@@ -8266,9 +8302,9 @@ var PLATFORM_VALIDATION_RULES = {
8266
8302
  },
8267
8303
  hooks: {
8268
8304
  supported: true,
8269
- files: [".codex/hooks.json", "~/.codex/hooks.json"],
8305
+ files: ["hooks/hooks.json", ".codex/hooks.json", "~/.codex/hooks.json"],
8270
8306
  eventNames: ["SessionStart", "PreToolUse", "PermissionRequest", "PostToolUse", "UserPromptSubmit", "Stop"],
8271
- notes: "Codex documents hooks in project/user config, guarded by the codex_hooks feature flag; the current plugin build guide does not document plugin-packaged hooks."
8307
+ notes: "Codex documents hooks in project and user config, and the hooks docs still mention the codex_hooks feature flag/runtime caveat. The official hooks docs also cover plugin-bundled hooks, which Pluxx now emits at hooks/hooks.json."
8272
8308
  },
8273
8309
  instructions: {
8274
8310
  files: ["AGENTS.md", "AGENTS.override.md"],
@@ -8286,6 +8322,9 @@ var PLATFORM_VALIDATION_RULES = {
8286
8322
  { label: "Codex hooks docs", url: "https://developers.openai.com/codex/hooks" },
8287
8323
  { label: "Codex skills docs", url: "https://developers.openai.com/codex/skills" },
8288
8324
  { label: "Codex MCP docs", url: "https://developers.openai.com/codex/mcp" },
8325
+ { label: "Codex basic config docs", url: "https://developers.openai.com/codex/config-basic" },
8326
+ { label: "Codex agent approvals and security docs", url: "https://developers.openai.com/codex/agent-approvals-security" },
8327
+ { label: "Codex app commands docs", url: "https://developers.openai.com/codex/app/commands" },
8289
8328
  { label: "Codex AGENTS.md guide", url: "https://developers.openai.com/codex/guides/agents-md" },
8290
8329
  { label: "Codex subagents docs", url: "https://developers.openai.com/codex/subagents" },
8291
8330
  { label: "Codex subagents concept docs", url: "https://developers.openai.com/codex/concepts/subagents" },
@@ -8296,7 +8335,7 @@ var PLATFORM_VALIDATION_RULES = {
8296
8335
  },
8297
8336
  "opencode": {
8298
8337
  platform: "opencode",
8299
- summary: "OpenCode plugins are code-first JS or TS modules loaded from local plugin dirs or npm references in config, with native skills, commands, agents, MCP, and permission surfaces.",
8338
+ summary: "OpenCode plugins are code-first JS or TS modules loaded from local plugin dirs or npm references in config, with native skills, commands, agents, MCP, permission, custom-tool, and plugin-event surfaces.",
8300
8339
  limits: PLATFORM_LIMITS["opencode"],
8301
8340
  limitPolicies: PLATFORM_LIMIT_POLICIES["opencode"],
8302
8341
  skillDiscoveryDirs: [
@@ -8326,13 +8365,13 @@ var PLATFORM_VALIDATION_RULES = {
8326
8365
  hooks: {
8327
8366
  supported: true,
8328
8367
  files: ["plugin module (index.ts/index.js)"],
8329
- eventNames: [],
8330
- notes: "OpenCode hooks are plugin event handlers implemented in code, not a separate hooks.json file."
8368
+ eventNames: ["command.executed", "file.edited", "file.watcher.updated", "installation.updated", "lsp.client.diagnostics", "lsp.updated", "message.part.removed", "message.part.updated", "message.removed", "message.updated", "permission.asked", "permission.replied", "server.connected", "session.created", "session.compacted", "session.deleted", "session.diff", "session.error", "session.idle", "session.status", "session.updated", "todo.updated", "shell.env", "tool.execute.before", "tool.execute.after", "tui.prompt.append", "tui.command.execute", "tui.toast.show", "experimental.session.compacting"],
8369
+ notes: "OpenCode hooks are plugin event handlers implemented in code, not a separate hooks.json file. The official surface is an event bus rather than a small lifecycle-hook JSON schema."
8331
8370
  },
8332
8371
  instructions: {
8333
8372
  files: ["AGENTS.md", "CLAUDE.md", "opencode.json"],
8334
8373
  format: "markdown + json + code",
8335
- notes: "OpenCode supports AGENTS.md, CLAUDE.md fallback, config instructions, and plugin runtime instruction injection."
8374
+ notes: "OpenCode supports AGENTS.md, CLAUDE.md fallback, config instructions, and plugin runtime instruction injection. Config layering also includes remote config, managed config files, and macOS managed preferences."
8336
8375
  },
8337
8376
  sources: [
8338
8377
  { label: "OpenCode SDK docs", url: "https://opencode.ai/docs/sdk/" },
@@ -8693,8 +8732,8 @@ var CORE_FOUR_PRIMITIVE_CAPABILITIES = {
8693
8732
  },
8694
8733
  commands: {
8695
8734
  mode: "degrade",
8696
- nativeSurfaces: ["skills/", "AGENTS.md"],
8697
- notes: "Current Codex docs do not document plugin-packaged slash-command parity."
8735
+ nativeSurfaces: ["skills/", "AGENTS.md", ".codex/commands.generated.json"],
8736
+ notes: "Current Codex docs do not document plugin-packaged slash-command parity, so Pluxx keeps canonical command intent through routing guidance plus a generated companion mirror."
8698
8737
  },
8699
8738
  agents: {
8700
8739
  mode: "translate",
@@ -8703,8 +8742,8 @@ var CORE_FOUR_PRIMITIVE_CAPABILITIES = {
8703
8742
  },
8704
8743
  hooks: {
8705
8744
  mode: "translate",
8706
- nativeSurfaces: [".codex/hooks.json", "~/.codex/hooks.json"],
8707
- notes: "Hooks are native, but they currently live next to config layers rather than inside the documented plugin bundle structure."
8745
+ nativeSurfaces: ["hooks/hooks.json", ".codex/hooks.json", "~/.codex/hooks.json"],
8746
+ notes: "Hooks are native. Pluxx bundles translated Codex hooks in the plugin and still tracks the project/user config paths plus the codex_hooks feature-gate caveat."
8708
8747
  },
8709
8748
  permissions: {
8710
8749
  mode: "translate",
@@ -8947,6 +8986,7 @@ var CompilerIntentSkillPolicySchema = external_exports.object({
8947
8986
  skillDir: external_exports.string(),
8948
8987
  title: external_exports.string(),
8949
8988
  description: external_exports.string().optional(),
8989
+ sourceFrontmatter: external_exports.record(external_exports.unknown()).optional(),
8950
8990
  source: external_exports.object({
8951
8991
  kind: external_exports.literal("claude-allowed-tools"),
8952
8992
  platform: external_exports.literal("claude-code").default("claude-code")
@@ -9082,6 +9122,23 @@ function collectUserConfigEntries(config, platforms = config.targets) {
9082
9122
  ]);
9083
9123
  }
9084
9124
 
9125
+ // src/distribution-lifecycle.ts
9126
+ var VERIFY_STALE_ACTIONS = {
9127
+ codex: "in Codex, use Plugins > Refresh if available, or restart Codex so the plugin cache reloads"
9128
+ };
9129
+ var PUBLISH_RELOAD_INSTRUCTIONS = {
9130
+ "claude-code": "If Claude is already open, run /reload-plugins in the active session.",
9131
+ cursor: "If Cursor is already open, use Developer: Reload Window or restart Cursor so the plugin is picked up.",
9132
+ codex: "If Codex is already open, use Plugins > Refresh if that action is available in your current UI, or restart Codex so the plugin is picked up.",
9133
+ opencode: "If OpenCode is already open, restart or reload it so the plugin is picked up."
9134
+ };
9135
+ function getVerifyInstallStaleAction(target) {
9136
+ return VERIFY_STALE_ACTIONS[target];
9137
+ }
9138
+ function getPublishReloadInstruction(target) {
9139
+ return PUBLISH_RELOAD_INSTRUCTIONS[target];
9140
+ }
9141
+
9085
9142
  // src/cli/publish.ts
9086
9143
  var INSTALLER_TARGETS = ["claude-code", "cursor", "codex", "opencode"];
9087
9144
  function runCommandDefault(command, args, options) {
@@ -9724,7 +9781,7 @@ claude plugin install "\${PLUGIN_NAME}@\${MARKETPLACE_NAME}" --scope user
9724
9781
 
9725
9782
  echo
9726
9783
  echo "Installed \${PLUGIN_NAME}@\${MARKETPLACE_NAME} into Claude Code user scope."
9727
- echo "If Claude is already open, run /reload-plugins in the active session."
9784
+ echo "${getPublishReloadInstruction("claude-code")}"
9728
9785
  `;
9729
9786
  }
9730
9787
  function renderInstallCursorScript(config) {
@@ -9781,7 +9838,7 @@ ${renderInstallerMcpPathMaterializationSnippet("cursor", "$INSTALL_DIR")}
9781
9838
  ${renderInstallerRuntimeBootstrapSnippet("$INSTALL_DIR")}
9782
9839
 
9783
9840
  echo "Installed $PLUGIN_NAME to $INSTALL_DIR"
9784
- echo "If Cursor is already open, use Developer: Reload Window or restart Cursor so the plugin is picked up."
9841
+ echo "${getPublishReloadInstruction("cursor")}"
9785
9842
  `;
9786
9843
  }
9787
9844
  function renderInstallCodexScript(config) {
@@ -9898,7 +9955,7 @@ NODE
9898
9955
 
9899
9956
  echo "Installed $PLUGIN_NAME to $INSTALL_DIR"
9900
9957
  echo "Updated Codex marketplace catalog at $MARKETPLACE_PATH"
9901
- echo "If Codex is already open, use Plugins > Refresh if that action is available in your current UI, or restart Codex so the plugin is picked up."
9958
+ echo "${getPublishReloadInstruction("codex")}"
9902
9959
  `;
9903
9960
  }
9904
9961
  function renderInstallOpenCodeScript(config) {
@@ -10045,7 +10102,7 @@ fi
10045
10102
  echo "Installed $PLUGIN_NAME plugin code to $INSTALL_DIR"
10046
10103
  echo "Installed OpenCode wrapper at $ENTRY_PATH"
10047
10104
  echo "Synced namespaced skills into $SKILLS_ROOT"
10048
- echo "If OpenCode is already open, restart or reload it so the plugin is picked up."
10105
+ echo "${getPublishReloadInstruction("opencode")}"
10049
10106
  `;
10050
10107
  }
10051
10108
  function replaceInstallerPlaceholders(script, config, context) {
@@ -10241,7 +10298,7 @@ import { existsSync as existsSync5, lstatSync as lstatSync2, readdirSync as read
10241
10298
  import { resolve as resolve5 } from "path";
10242
10299
 
10243
10300
  // src/cli/doctor.ts
10244
- import { spawn } from "child_process";
10301
+ import { spawn, spawnSync as spawnSync2 } from "child_process";
10245
10302
  import { accessSync, constants, existsSync as existsSync4, lstatSync, readFileSync as readFileSync4, readdirSync as readdirSync2 } from "fs";
10246
10303
  import { basename, dirname as dirname2, resolve as resolve4 } from "path";
10247
10304
 
@@ -11131,6 +11188,166 @@ function checkInstalledBundleIntegrity(checks, rootDir, layout) {
11131
11188
  path: layout.manifestPath
11132
11189
  });
11133
11190
  }
11191
+ function parseInstalledPermissionRules(scriptSource) {
11192
+ const match = scriptSource.match(/const RULES = (\[[\s\S]*?\]);\nconst ACTION_PRIORITY/);
11193
+ if (!match?.[1]) {
11194
+ throw new Error("Could not locate embedded RULES payload in hooks/pluxx-permissions.mjs.");
11195
+ }
11196
+ const parsed = JSON.parse(match[1]);
11197
+ if (!Array.isArray(parsed)) {
11198
+ throw new Error("Embedded RULES payload is not an array.");
11199
+ }
11200
+ return parsed;
11201
+ }
11202
+ function materializePermissionPattern(pattern) {
11203
+ return pattern.replace(/\*\*/g, "probe/path").replace(/\*/g, "probe");
11204
+ }
11205
+ function buildInstalledPermissionProbe(platform, rule) {
11206
+ const value = materializePermissionPattern(rule.pattern);
11207
+ if (rule.kind === "Bash") {
11208
+ return {
11209
+ action: rule.action,
11210
+ raw: rule.raw,
11211
+ mode: platform === "cursor" ? "cursor-shell" : "claude-pretool",
11212
+ event: platform === "cursor" ? { command: value } : { tool_name: "Bash", tool_input: { command: value } }
11213
+ };
11214
+ }
11215
+ if (rule.kind === "Read") {
11216
+ return {
11217
+ action: rule.action,
11218
+ raw: rule.raw,
11219
+ mode: platform === "cursor" ? "cursor-read" : "claude-pretool",
11220
+ event: platform === "cursor" ? { file_path: value } : { tool_name: "Read", tool_input: { file_path: value } }
11221
+ };
11222
+ }
11223
+ if (rule.kind === "Edit") {
11224
+ return {
11225
+ action: rule.action,
11226
+ raw: rule.raw,
11227
+ mode: platform === "cursor" ? "cursor" : "claude-pretool",
11228
+ event: { tool_name: "Edit", tool_input: { file_path: value } }
11229
+ };
11230
+ }
11231
+ if (rule.kind === "Skill") {
11232
+ return {
11233
+ action: rule.action,
11234
+ raw: rule.raw,
11235
+ mode: platform === "cursor" ? "cursor" : "claude-pretool",
11236
+ event: { tool_name: "Skill", tool_input: { name: value } }
11237
+ };
11238
+ }
11239
+ if (rule.kind === "MCP") {
11240
+ const canonical = value.includes(".") ? value : `${value}.probe`;
11241
+ const dotIndex = canonical.indexOf(".");
11242
+ const server = canonical.slice(0, dotIndex).trim();
11243
+ const tool = canonical.slice(dotIndex + 1).trim();
11244
+ if (!server || !tool) return null;
11245
+ return {
11246
+ action: rule.action,
11247
+ raw: rule.raw,
11248
+ mode: platform === "cursor" ? "cursor-mcp" : "claude-pretool",
11249
+ event: platform === "cursor" ? { tool_name: `mcp__${server}__${tool.replace(/\./g, "__")}` } : { tool_name: `mcp__${server}__${tool.replace(/\./g, "__")}` }
11250
+ };
11251
+ }
11252
+ return null;
11253
+ }
11254
+ function extractPermissionDecision(platform, payload) {
11255
+ if (platform === "claude-code") {
11256
+ const hookSpecificOutput = payload.hookSpecificOutput;
11257
+ if (!hookSpecificOutput || typeof hookSpecificOutput !== "object") return void 0;
11258
+ const decision2 = hookSpecificOutput.permissionDecision;
11259
+ return typeof decision2 === "string" ? decision2 : void 0;
11260
+ }
11261
+ const decision = payload.permission;
11262
+ return typeof decision === "string" ? decision : void 0;
11263
+ }
11264
+ function smokeCheckInstalledPermissionHook(rootDir, layout) {
11265
+ if (layout.platform !== "claude-code" && layout.platform !== "cursor") {
11266
+ return null;
11267
+ }
11268
+ const scriptPath = resolve4(rootDir, "hooks/pluxx-permissions.mjs");
11269
+ if (!existsSync4(scriptPath)) {
11270
+ return null;
11271
+ }
11272
+ const rules = parseInstalledPermissionRules(readFileSync4(scriptPath, "utf-8"));
11273
+ const selected = /* @__PURE__ */ new Map();
11274
+ for (const rule of rules) {
11275
+ if (selected.has(rule.action)) continue;
11276
+ const probe = buildInstalledPermissionProbe(layout.platform, rule);
11277
+ if (!probe) continue;
11278
+ selected.set(rule.action, probe);
11279
+ }
11280
+ if (selected.size === 0) {
11281
+ return {
11282
+ ok: false,
11283
+ detail: "Permission hook script is present, but no supported canonical probe cases could be derived from its embedded rules."
11284
+ };
11285
+ }
11286
+ const failures = [];
11287
+ const successes = [];
11288
+ for (const probe of selected.values()) {
11289
+ const result = spawnSync2("node", [scriptPath, probe.mode], {
11290
+ cwd: rootDir,
11291
+ input: JSON.stringify(probe.event),
11292
+ encoding: "utf-8",
11293
+ env: process.env
11294
+ });
11295
+ if (result.status !== 0) {
11296
+ failures.push(`${probe.raw} exited ${result.status ?? "null"}${result.stderr ? `: ${result.stderr.trim()}` : ""}`);
11297
+ continue;
11298
+ }
11299
+ let payload;
11300
+ try {
11301
+ payload = JSON.parse(result.stdout || "{}");
11302
+ } catch (error) {
11303
+ failures.push(`${probe.raw} returned non-JSON output: ${error instanceof Error ? error.message : String(error)}`);
11304
+ continue;
11305
+ }
11306
+ const decision = extractPermissionDecision(layout.platform, payload);
11307
+ if (decision !== probe.action) {
11308
+ failures.push(`${probe.raw} returned ${decision ?? "no decision"} instead of ${probe.action}`);
11309
+ continue;
11310
+ }
11311
+ successes.push(`${probe.raw} -> ${decision}`);
11312
+ }
11313
+ return failures.length > 0 ? { ok: false, detail: failures.join("; ") } : { ok: true, detail: `Validated ${successes.join(", ")}` };
11314
+ }
11315
+ function checkInstalledPermissionHook(checks, rootDir, layout) {
11316
+ const permissionScriptPath = "hooks/pluxx-permissions.mjs";
11317
+ let scriptResult;
11318
+ try {
11319
+ scriptResult = smokeCheckInstalledPermissionHook(rootDir, layout);
11320
+ } catch (error) {
11321
+ addCheck(checks, {
11322
+ level: "error",
11323
+ code: "consumer-permission-hook-invalid",
11324
+ title: "Installed bundled permission hook behavior is broken",
11325
+ detail: error instanceof Error ? error.message : String(error),
11326
+ fix: "Rebuild or reinstall the plugin so the bundled permission hook script and hook wiring stay aligned with the declared permission rules.",
11327
+ path: permissionScriptPath
11328
+ });
11329
+ return;
11330
+ }
11331
+ if (!scriptResult) {
11332
+ addCheck(checks, {
11333
+ level: "info",
11334
+ code: "consumer-permission-hook-not-applicable",
11335
+ title: "No bundled permission hook smoke check for this install",
11336
+ detail: layout.platform === "claude-code" || layout.platform === "cursor" ? "This installed bundle does not include hooks/pluxx-permissions.mjs." : "This platform does not currently use a bundled pluxx-permissions.mjs hook script for permission enforcement.",
11337
+ fix: "No action needed unless you expected bundled permission-hook enforcement in this installed bundle.",
11338
+ path: permissionScriptPath
11339
+ });
11340
+ return;
11341
+ }
11342
+ addCheck(checks, {
11343
+ level: scriptResult.ok ? "success" : "error",
11344
+ code: scriptResult.ok ? "consumer-permission-hook-valid" : "consumer-permission-hook-invalid",
11345
+ title: scriptResult.ok ? "Installed bundled permission hook returns expected decisions" : "Installed bundled permission hook behavior is broken",
11346
+ detail: scriptResult.detail,
11347
+ fix: scriptResult.ok ? "No action needed." : "Rebuild or reinstall the plugin so the bundled permission hook script and hook wiring stay aligned with the declared permission rules.",
11348
+ path: permissionScriptPath
11349
+ });
11350
+ }
11134
11351
  function findMissingInstalledStdioRuntimePaths(rootDir, stdioEntries) {
11135
11352
  const missing = /* @__PURE__ */ new Set();
11136
11353
  for (const server of stdioEntries) {
@@ -11398,6 +11615,7 @@ async function doctorConsumer(rootDir = process.cwd()) {
11398
11615
  });
11399
11616
  checkConsumerManifest(checks, rootDir, layout);
11400
11617
  checkInstalledBundleIntegrity(checks, rootDir, layout);
11618
+ checkInstalledPermissionHook(checks, rootDir, layout);
11401
11619
  checkInstalledUserConfig(checks, rootDir);
11402
11620
  checkInstalledEnvValidation(checks, rootDir);
11403
11621
  checkInstalledRuntimeScriptRoles(checks, rootDir);
@@ -11557,9 +11775,8 @@ function getVerifyInstallRecoveryActions(check) {
11557
11775
  }
11558
11776
  if (check.stale) {
11559
11777
  actions.push(`rerun pluxx install --target ${check.platform} to replace the stale local install`);
11560
- if (check.platform === "codex") {
11561
- actions.push("in Codex, use Plugins > Refresh if available, or restart Codex so the plugin cache reloads");
11562
- }
11778
+ const staleAction = getVerifyInstallStaleAction(check.platform);
11779
+ if (staleAction) actions.push(staleAction);
11563
11780
  }
11564
11781
  if (check.errors > 0 && actions.length === 0) {
11565
11782
  actions.push(`run pluxx doctor --consumer "${check.consumerPath}" for the detailed host-specific failure`);
@@ -0,0 +1,6 @@
1
+ import type { PluginConfig } from './schema';
2
+ export declare function resolveInstructionsPath(rootDir: string, config: Pick<PluginConfig, 'instructions'>): string | null;
3
+ export declare function readInstructionsContent(rootDir: string, config: Pick<PluginConfig, 'instructions'>): Promise<string | null>;
4
+ export declare function readInstructionsContentSync(rootDir: string, config: Pick<PluginConfig, 'instructions'>): string | null;
5
+ export declare function renderTitledInstructionsDocument(config: Pick<PluginConfig, 'name' | 'description' | 'brand'>, content: string, titleSuffix?: string): string;
6
+ //# sourceMappingURL=instructions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"instructions.d.ts","sourceRoot":"","sources":["../src/instructions.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AAG5C,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,IAAI,CAAC,YAAY,EAAE,cAAc,CAAC,GACzC,MAAM,GAAG,IAAI,CAIf;AAED,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,IAAI,CAAC,YAAY,EAAE,cAAc,CAAC,GACzC,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAIxB;AAED,wBAAgB,2BAA2B,CACzC,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,IAAI,CAAC,YAAY,EAAE,cAAc,CAAC,GACzC,MAAM,GAAG,IAAI,CAIf;AAED,wBAAgB,gCAAgC,CAAC,MAAM,EAAE,IAAI,CAAC,YAAY,EAAE,MAAM,GAAG,aAAa,GAAG,OAAO,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,WAAW,SAAW,GAAG,MAAM,CAQ9J"}
@@ -0,0 +1,14 @@
1
+ import type { PluginConfig, TargetPlatform, UserConfigEntry } from './schema';
2
+ type JsonRecord = Record<string, unknown>;
3
+ type NativeMcpServerOverrides = Record<string, Record<string, unknown>>;
4
+ type NativeMcpPlatformOverrides = Partial<Record<TargetPlatform, {
5
+ mcpServers: NativeMcpServerOverrides;
6
+ }>>;
7
+ export declare function extractNativeMcpAuthConfig(cfg: Record<string, unknown>): Record<string, unknown> | undefined;
8
+ export declare function buildNativeMcpPlatformOverrides(platform: TargetPlatform, servers: Record<string, unknown>): NativeMcpPlatformOverrides | undefined;
9
+ export declare function getNativeMcpServerOverride(config: PluginConfig, platform: TargetPlatform, serverName: string): JsonRecord | undefined;
10
+ export declare function getNativeJsonHeadersOverride(config: PluginConfig, platform: TargetPlatform, serverName: string): Record<string, string> | undefined;
11
+ export declare function getNativeCodexMcpEntryOverride(config: PluginConfig, serverName: string): JsonRecord | undefined;
12
+ export declare function collectNativeMcpAuthUserConfigEntries(config: PluginConfig, platforms: TargetPlatform[], existingFields: UserConfigEntry[]): UserConfigEntry[];
13
+ export {};
14
+ //# sourceMappingURL=mcp-native-overrides.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-native-overrides.d.ts","sourceRoot":"","sources":["../src/mcp-native-overrides.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAG7E,KAAK,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;AACzC,KAAK,wBAAwB,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;AACvE,KAAK,0BAA0B,GAAG,OAAO,CAAC,MAAM,CAAC,cAAc,EAAE;IAAE,UAAU,EAAE,wBAAwB,CAAA;CAAE,CAAC,CAAC,CAAA;AA6B3G,wBAAgB,0BAA0B,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAqB5G;AAED,wBAAgB,+BAA+B,CAC7C,QAAQ,EAAE,cAAc,EACxB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC/B,0BAA0B,GAAG,SAAS,CAkBxC;AAWD,wBAAgB,0BAA0B,CACxC,MAAM,EAAE,YAAY,EACpB,QAAQ,EAAE,cAAc,EACxB,UAAU,EAAE,MAAM,GACjB,UAAU,GAAG,SAAS,CAKxB;AAED,wBAAgB,4BAA4B,CAC1C,MAAM,EAAE,YAAY,EACpB,QAAQ,EAAE,cAAc,EACxB,UAAU,EAAE,MAAM,GACjB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAGpC;AAED,wBAAgB,8BAA8B,CAC5C,MAAM,EAAE,YAAY,EACpB,UAAU,EAAE,MAAM,GACjB,UAAU,GAAG,SAAS,CAkBxB;AAED,wBAAgB,qCAAqC,CACnD,MAAM,EAAE,YAAY,EACpB,SAAS,EAAE,cAAc,EAAE,EAC3B,cAAc,EAAE,eAAe,EAAE,GAChC,eAAe,EAAE,CAoDnB"}