@orchid-labs/pluxx 0.1.21 → 0.1.22

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/index.js CHANGED
@@ -7841,6 +7841,20 @@ function definePlugin(config) {
7841
7841
  return PluginConfigSchema.parse(config);
7842
7842
  }
7843
7843
 
7844
+ // src/hook-events.ts
7845
+ var CODEX_SUPPORTED_HOOK_EVENTS = [
7846
+ "SessionStart",
7847
+ "SubagentStart",
7848
+ "PreToolUse",
7849
+ "PermissionRequest",
7850
+ "PostToolUse",
7851
+ "PreCompact",
7852
+ "PostCompact",
7853
+ "UserPromptSubmit",
7854
+ "SubagentStop",
7855
+ "Stop"
7856
+ ];
7857
+
7844
7858
  // src/runtime-readiness-registry.ts
7845
7859
  function getEnabledRuntimeReadinessBindings(capability, plan) {
7846
7860
  return capability.bindings.filter((binding) => {
@@ -7855,7 +7869,7 @@ function getEnabledRuntimeReadinessBindings(capability, plan) {
7855
7869
  });
7856
7870
  }
7857
7871
  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.";
7858
- var CODEX_EXTERNAL_NOTE = "Codex readiness now bundles translated hooks in the plugin, and Pluxx still emits `.codex/readiness.generated.json` plus `.codex/hooks.generated.json` as debugging companions because plugin-bundled hook activation still depends on `[features].plugin_hooks = true`. The general `hooks = true` flag covers non-plugin hook config and defaults on, while `codex_hooks` is deprecated and should not be treated as a plugin-bundled hook fallback.";
7872
+ var CODEX_EXTERNAL_NOTE = "Codex readiness now bundles translated hooks in the plugin, and Pluxx still emits `.codex/readiness.generated.json` plus `.codex/hooks.generated.json` as debugging companions because hook activation still depends on `[features].hooks = true`, enabled plugin state, review, trust, and runtime support. `codex_hooks` is deprecated and should not be treated as the current hook feature key.";
7859
7873
  function getRuntimeReadinessNamedPromptTargetNote() {
7860
7874
  return NAMED_PROMPT_TARGET_NOTE;
7861
7875
  }
@@ -8103,7 +8117,7 @@ var PLATFORM_LIMIT_POLICIES = {
8103
8117
  },
8104
8118
  hooksFeatureFlag: {
8105
8119
  kind: "hard",
8106
- notes: "Hook support depends on the Codex hooks feature flag/runtime support."
8120
+ notes: "Codex hook support depends on the canonical hooks feature flag plus enabled-plugin, trust/review, and runtime support."
8107
8121
  }
8108
8122
  },
8109
8123
  "cursor": {
@@ -8303,8 +8317,8 @@ var PLATFORM_VALIDATION_RULES = {
8303
8317
  hooks: {
8304
8318
  supported: true,
8305
8319
  files: ["hooks/hooks.json", ".codex/hooks.json", "~/.codex/hooks.json"],
8306
- eventNames: ["SessionStart", "PreToolUse", "PermissionRequest", "PostToolUse", "UserPromptSubmit", "Stop"],
8307
- notes: "Codex documents both project or user hook config and plugin-bundled hooks. Plugin-bundled hooks live at `hooks/hooks.json` in the plugin and require `[features].plugin_hooks = true`; the general `[features].hooks = true` flag covers non-plugin hook config and defaults on. `codex_hooks` is deprecated and should not be treated as a plugin-bundled hook fallback."
8320
+ eventNames: [...CODEX_SUPPORTED_HOOK_EVENTS],
8321
+ notes: "Codex documents both project/user hook config and plugin-bundled hooks. Plugin-bundled hooks live at `hooks/hooks.json` in the plugin and require the canonical `[features].hooks = true` flag, enabled plugin state, user review, trust, and runtime support. `codex_hooks` is deprecated and should not be treated as the current hook feature key."
8308
8322
  },
8309
8323
  instructions: {
8310
8324
  files: ["AGENTS.md", "AGENTS.override.md"],
@@ -8743,7 +8757,7 @@ var CORE_FOUR_PRIMITIVE_CAPABILITIES = {
8743
8757
  hooks: {
8744
8758
  mode: "translate",
8745
8759
  nativeSurfaces: ["hooks/hooks.json", ".codex/hooks.json", "~/.codex/hooks.json"],
8746
- notes: "Hooks are native. Pluxx bundles translated Codex hooks in the plugin with the documented `[features].plugin_hooks = true` plugin gate, and still tracks the broader project/user hook config paths where `[features].hooks` is the general flag and `codex_hooks` is deprecated."
8760
+ notes: "Hooks are native. Pluxx bundles translated Codex hooks in the plugin with the documented `[features].hooks = true` feature key, and still tracks broader project/user hook config paths where `codex_hooks` is deprecated. Plugin-bundled execution still also depends on enabled plugin state, review, trust, and runtime support."
8747
8761
  },
8748
8762
  permissions: {
8749
8763
  mode: "translate",
@@ -9139,6 +9153,78 @@ function getPublishReloadInstruction(target) {
9139
9153
  return PUBLISH_RELOAD_INSTRUCTIONS[target];
9140
9154
  }
9141
9155
 
9156
+ // src/mcp-native-overrides.ts
9157
+ function asRecord(value) {
9158
+ if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
9159
+ return value;
9160
+ }
9161
+ function firstString(...values) {
9162
+ for (const value of values) {
9163
+ if (typeof value === "string" && value.trim()) return value.trim();
9164
+ }
9165
+ return void 0;
9166
+ }
9167
+ function readStringRecord(value) {
9168
+ const record = asRecord(value);
9169
+ if (!record) return void 0;
9170
+ const stringRecord = Object.fromEntries(
9171
+ Object.entries(record).filter(([, entryValue]) => typeof entryValue === "string")
9172
+ );
9173
+ return Object.keys(stringRecord).length > 0 ? stringRecord : void 0;
9174
+ }
9175
+ function extractEnvVar(value) {
9176
+ const match = value.match(/\$\{(?:env:)?([A-Za-z_][A-Za-z0-9_]*)\}|\$([A-Za-z_][A-Za-z0-9_]*)/);
9177
+ return match?.[1] ?? match?.[2];
9178
+ }
9179
+ function envVarToKey(envVar) {
9180
+ return envVar.toLowerCase().replace(/_/g, "-");
9181
+ }
9182
+ function collectNativeMcpAuthUserConfigEntries(config, platforms, existingFields) {
9183
+ const next = [];
9184
+ const seenKeys = new Set(existingFields.map((field) => field.key));
9185
+ const seenEnvVars = new Set(
9186
+ existingFields.map((field) => field.envVar ?? defaultUserConfigEnvVar(field.key))
9187
+ );
9188
+ const pushDerived = (envVar, platform, serverName) => {
9189
+ if (!envVar || seenEnvVars.has(envVar)) return;
9190
+ const key = envVarToKey(envVar);
9191
+ if (seenKeys.has(key)) return;
9192
+ seenEnvVars.add(envVar);
9193
+ seenKeys.add(key);
9194
+ next.push({
9195
+ key,
9196
+ title: envVar,
9197
+ description: `Derived from native ${platform} MCP auth for ${serverName}.`,
9198
+ type: "secret",
9199
+ required: true,
9200
+ envVar,
9201
+ targets: [platform]
9202
+ });
9203
+ };
9204
+ for (const platform of platforms) {
9205
+ const platformConfig = asRecord(config.platforms?.[platform]);
9206
+ const mcpServers = asRecord(platformConfig?.mcpServers);
9207
+ if (!mcpServers) continue;
9208
+ for (const [serverName, rawOverride] of Object.entries(mcpServers)) {
9209
+ const override = asRecord(rawOverride);
9210
+ if (!override) continue;
9211
+ const bearerTokenEnv = firstString(override.bearer_token_env_var, override.bearerTokenEnvVar);
9212
+ if (bearerTokenEnv) pushDerived(bearerTokenEnv, platform, serverName);
9213
+ for (const record of [
9214
+ readStringRecord(override.env_http_headers ?? override.envHttpHeaders),
9215
+ readStringRecord(override.headers),
9216
+ readStringRecord(override.http_headers ?? override.httpHeaders)
9217
+ ]) {
9218
+ for (const value of Object.values(record ?? {})) {
9219
+ const envVar = extractEnvVar(value) ?? value;
9220
+ pushDerived(envVar, platform, serverName);
9221
+ }
9222
+ }
9223
+ }
9224
+ }
9225
+ return next;
9226
+ }
9227
+
9142
9228
  // src/cli/publish.ts
9143
9229
  var INSTALLER_TARGETS = ["claude-code", "cursor", "codex", "opencode"];
9144
9230
  function runCommandDefault(command, args, options) {
@@ -9438,8 +9524,15 @@ echo
9438
9524
  echo "Installed __DISPLAY_NAME__ across ${installerTargets.join(", ")}."
9439
9525
  `.replaceAll("__REPO__", "REPO_PLACEHOLDER").replaceAll("__DISPLAY_NAME__", "DISPLAY_PLACEHOLDER");
9440
9526
  }
9527
+ function collectInstallerUserConfigEntries(config, platforms) {
9528
+ const baseEntries = collectUserConfigEntries(config, platforms);
9529
+ return [
9530
+ ...baseEntries,
9531
+ ...collectNativeMcpAuthUserConfigEntries(config, platforms, baseEntries)
9532
+ ];
9533
+ }
9441
9534
  function renderInstallerUserConfigSnippet(config, platform, installDirVariable) {
9442
- const entries = collectUserConfigEntries(config, [platform]).map((entry) => ({
9535
+ const entries = collectInstallerUserConfigEntries(config, [platform]).map((entry) => ({
9443
9536
  key: entry.key,
9444
9537
  title: entry.title,
9445
9538
  type: entry.type ?? "string",
@@ -9447,6 +9540,7 @@ function renderInstallerUserConfigSnippet(config, platform, installDirVariable)
9447
9540
  envVar: entry.envVar ?? defaultUserConfigEnvVar(entry.key)
9448
9541
  }));
9449
9542
  if (entries.length === 0) return "";
9543
+ const preserveSecretReferences = platform === "codex";
9450
9544
  const promptLines = entries.map((entry) => {
9451
9545
  const functionName = entry.type === "secret" ? "pluxx_prompt_secret_config" : "pluxx_prompt_text_config";
9452
9546
  return `${functionName} ${JSON.stringify(entry.key)} ${JSON.stringify(entry.envVar)} ${JSON.stringify(entry.title)} ${entry.required ? "1" : "0"}`;
@@ -9457,6 +9551,8 @@ ${JSON.stringify(entries)}
9457
9551
  PLUXX_USER_CONFIG_JSON
9458
9552
  )"
9459
9553
  PLUXX_REUSED_USER_CONFIG=0
9554
+ PLUXX_PRESERVE_SECRET_REFS="${preserveSecretReferences ? "1" : "0"}"
9555
+ export PLUXX_PRESERVE_SECRET_REFS
9460
9556
 
9461
9557
  pluxx_is_placeholder_secret() {
9462
9558
  case "$1" in
@@ -9483,12 +9579,14 @@ const fs = require('fs')
9483
9579
  const filepath = process.env.PLUXX_SAVED_USER_CONFIG_PATH
9484
9580
  const key = process.env.PLUXX_SAVED_CONFIG_KEY
9485
9581
  const envVar = process.env.PLUXX_SAVED_CONFIG_ENV_VAR
9582
+ const preserveSecretRefs = process.env.PLUXX_PRESERVE_SECRET_REFS === '1'
9486
9583
 
9487
9584
  try {
9488
9585
  const payload = JSON.parse(fs.readFileSync(filepath, 'utf8'))
9489
9586
  const candidates = [
9490
9587
  payload && payload.env && envVar ? payload.env[envVar] : undefined,
9491
9588
  payload && payload.values && key ? payload.values[key] : undefined,
9589
+ preserveSecretRefs && payload && payload.envRefs && envVar && payload.envRefs[envVar] === envVar ? envVar : undefined,
9492
9590
  ]
9493
9591
 
9494
9592
  for (const candidate of candidates) {
@@ -9584,21 +9682,53 @@ const path = require('path')
9584
9682
 
9585
9683
  const installDir = process.env.PLUXX_INSTALL_DIR
9586
9684
  const spec = JSON.parse(process.env.PLUXX_USER_CONFIG_SPEC || '[]')
9685
+ const preserveSecretReferences = ${preserveSecretReferences ? "true" : "false"}
9587
9686
 
9588
9687
  if (installDir && spec.length > 0) {
9589
9688
  const env = {}
9590
9689
  const values = {}
9690
+ const envRefs = {}
9691
+ const secretKeys = []
9692
+ const secretEnv = []
9693
+ let hasSecret = false
9694
+ const secretEnvVars = new Set(
9695
+ spec
9696
+ .filter((entry) => entry && entry.type === 'secret' && typeof entry.envVar === 'string' && entry.envVar !== '')
9697
+ .map((entry) => entry.envVar),
9698
+ )
9591
9699
 
9592
9700
  for (const entry of spec) {
9701
+ if (entry.type === 'secret') {
9702
+ hasSecret = true
9703
+ if (preserveSecretReferences) {
9704
+ if (entry.key) secretKeys.push(entry.key)
9705
+ if (entry.envVar) secretEnv.push(entry.envVar)
9706
+ }
9707
+ }
9593
9708
  const value = process.env[entry.envVar]
9594
9709
  if (value === undefined || value === '') continue
9710
+ if (preserveSecretReferences && entry.type === 'secret') {
9711
+ envRefs[entry.envVar] = entry.envVar
9712
+ continue
9713
+ }
9595
9714
  values[entry.key] = value
9596
9715
  env[entry.envVar] = value
9597
9716
  }
9598
9717
 
9599
9718
  fs.writeFileSync(
9600
9719
  path.join(installDir, '.pluxx-user.json'),
9601
- JSON.stringify({ values, env }, null, 2) + '\\n',
9720
+ JSON.stringify(
9721
+ {
9722
+ ...(Object.keys(values).length > 0 ? { values } : {}),
9723
+ ...(Object.keys(env).length > 0 ? { env } : {}),
9724
+ ...(Object.keys(envRefs).length > 0 ? { envRefs } : {}),
9725
+ ...(hasSecret ? { secretStorage: preserveSecretReferences ? 'env-ref' : 'materialized' } : {}),
9726
+ ...(preserveSecretReferences && secretKeys.length > 0 ? { secretKeys: [...new Set(secretKeys)].sort() } : {}),
9727
+ ...(preserveSecretReferences && secretEnv.length > 0 ? { secretEnv: [...new Set(secretEnv)].sort() } : {}),
9728
+ },
9729
+ null,
9730
+ 2,
9731
+ ) + '\\n',
9602
9732
  )
9603
9733
 
9604
9734
  const envScriptPath = path.join(installDir, 'scripts/check-env.sh')
@@ -9611,7 +9741,10 @@ if (installDir && spec.length > 0) {
9611
9741
 
9612
9742
  const materialize = (value) =>
9613
9743
  typeof value === 'string'
9614
- ? value.replace(/\\$\\{([A-Za-z_][A-Za-z0-9_]*)\\}/g, (_match, name) => env[name] || '${" + name + "}')
9744
+ ? value.replace(
9745
+ /\\$\\{([A-Za-z_][A-Za-z0-9_]*)\\}/g,
9746
+ (_match, name) => (preserveSecretReferences && secretEnvVars.has(name) ? '${" + name + "}' : (env[name] || '${" + name + "}')),
9747
+ )
9615
9748
  : value
9616
9749
 
9617
9750
  const materializeRecord = (record) => {
@@ -9635,7 +9768,7 @@ if (installDir && spec.length > 0) {
9635
9768
  server.env = materializeRecord(server.env)
9636
9769
  }
9637
9770
 
9638
- if (server.bearer_token_env_var && env[server.bearer_token_env_var]) {
9771
+ if (!preserveSecretReferences && server.bearer_token_env_var && env[server.bearer_token_env_var]) {
9639
9772
  server.http_headers = {
9640
9773
  ...(server.http_headers || {}),
9641
9774
  Authorization: 'Bearer ' + env[server.bearer_token_env_var],
@@ -9643,7 +9776,7 @@ if (installDir && spec.length > 0) {
9643
9776
  delete server.bearer_token_env_var
9644
9777
  }
9645
9778
 
9646
- if (server.env_http_headers && typeof server.env_http_headers === 'object') {
9779
+ if (!preserveSecretReferences && server.env_http_headers && typeof server.env_http_headers === 'object') {
9647
9780
  server.http_headers = {
9648
9781
  ...(server.http_headers || {}),
9649
9782
  }
@@ -9668,7 +9801,7 @@ NODE
9668
9801
  `;
9669
9802
  }
9670
9803
  function hasInstallerUserConfig(config, platform) {
9671
- return collectUserConfigEntries(config, [platform]).length > 0;
9804
+ return collectInstallerUserConfigEntries(config, [platform]).length > 0;
9672
9805
  }
9673
9806
  function renderInstallerSavedUserConfigCaptureSnippet(config, platform, installDirVariable) {
9674
9807
  if (!hasInstallerUserConfig(config, platform)) return "";
@@ -9834,13 +9967,13 @@ for (const line of lines) {
9834
9967
  continue
9835
9968
  }
9836
9969
  if (tableName === '') {
9837
- const dottedMatch = trimmed.match(/^features\\.plugin_hooks\\s*=\\s*(.+)$/)
9970
+ const dottedMatch = trimmed.match(/^features\\.hooks\\s*=\\s*(.+)$/)
9838
9971
  if (dottedMatch && isTomlTrue(dottedMatch[1])) process.exit(0)
9839
9972
  const inlineMatch = trimmed.match(/^features\\s*=\\s*(.+)$/)
9840
- if (inlineMatch && /\\bplugin_hooks\\s*=\\s*true\\b/i.test(inlineMatch[1])) process.exit(0)
9973
+ if (inlineMatch && /\\bhooks\\s*=\\s*true\\b/i.test(inlineMatch[1])) process.exit(0)
9841
9974
  }
9842
9975
  if (tableName !== 'features') continue
9843
- const match = trimmed.match(/^plugin_hooks\\s*=\\s*(.+)$/)
9976
+ const match = trimmed.match(/^hooks\\s*=\\s*(.+)$/)
9844
9977
  if (match && isTomlTrue(match[1])) process.exit(0)
9845
9978
  }
9846
9979
  process.exit(1)
@@ -9859,7 +9992,7 @@ NODE
9859
9992
  *)
9860
9993
  if [[ -r /dev/tty ]]; then
9861
9994
  echo "This Codex plugin bundle includes startup hooks." >/dev/tty
9862
- echo "Codex requires [features].plugin_hooks = true before plugin-bundled hooks can run." >/dev/tty
9995
+ echo "Codex requires [features].hooks = true before plugin-bundled hooks can run." >/dev/tty
9863
9996
  read -r -p "Enable Codex plugin-bundled hooks in $CODEX_CONFIG_PATH now? [Y/n] " PLUXX_CODEX_HOOKS_REPLY </dev/tty
9864
9997
  case "$PLUXX_CODEX_HOOKS_REPLY" in
9865
9998
  n|N|no|NO)
@@ -9931,7 +10064,7 @@ for (let index = 0; index < lines.length; index += 1) {
9931
10064
  if (/^features\\.[A-Za-z0-9_-]+\\s*=/.test(trimmed) && firstTopLevelFeaturesDotted < 0) {
9932
10065
  firstTopLevelFeaturesDotted = index
9933
10066
  }
9934
- if (/^features\\.plugin_hooks\\s*=/.test(trimmed)) {
10067
+ if (/^features\\.hooks\\s*=/.test(trimmed)) {
9935
10068
  topLevelPluginHooksDotted = index
9936
10069
  }
9937
10070
  if (/^features\\s*=\\s*\\{/.test(trimmed)) {
@@ -9950,28 +10083,28 @@ if (start >= 0) {
9950
10083
 
9951
10084
  let updated = false
9952
10085
  for (let index = start + 1; index < end; index += 1) {
9953
- if (/^plugin_hooks\\s*=/.test(stripTomlComment(lines[index]).trim())) {
9954
- lines[index] = 'plugin_hooks = true'
10086
+ if (/^hooks\\s*=/.test(stripTomlComment(lines[index]).trim())) {
10087
+ lines[index] = 'hooks = true'
9955
10088
  updated = true
9956
10089
  }
9957
10090
  }
9958
- if (!updated) lines.splice(start + 1, 0, 'plugin_hooks = true')
10091
+ if (!updated) lines.splice(start + 1, 0, 'hooks = true')
9959
10092
  } else if (topLevelPluginHooksDotted >= 0) {
9960
- lines[topLevelPluginHooksDotted] = 'features.plugin_hooks = true'
10093
+ lines[topLevelPluginHooksDotted] = 'features.hooks = true'
9961
10094
  } else if (firstTopLevelFeaturesDotted >= 0) {
9962
- lines.splice(firstTopLevelFeaturesDotted + 1, 0, 'features.plugin_hooks = true')
10095
+ lines.splice(firstTopLevelFeaturesDotted + 1, 0, 'features.hooks = true')
9963
10096
  } else if (topLevelInlineFeatures >= 0 && lines[topLevelInlineFeatures].includes('}')) {
9964
- if (/\\bplugin_hooks\\s*=/.test(lines[topLevelInlineFeatures])) {
10097
+ if (/\\bhooks\\s*=/.test(lines[topLevelInlineFeatures])) {
9965
10098
  lines[topLevelInlineFeatures] = lines[topLevelInlineFeatures].replace(
9966
- /\\bplugin_hooks\\s*=\\s*(true|false)\\b/i,
9967
- 'plugin_hooks = true',
10099
+ /\\bhooks\\s*=\\s*(true|false)\\b/i,
10100
+ 'hooks = true',
9968
10101
  )
9969
10102
  } else {
9970
- lines[topLevelInlineFeatures] = lines[topLevelInlineFeatures].replace(/}/, ', plugin_hooks = true }')
10103
+ lines[topLevelInlineFeatures] = lines[topLevelInlineFeatures].replace(/}/, ', hooks = true }')
9971
10104
  }
9972
10105
  } else {
9973
10106
  if (lines.length > 0 && lines[lines.length - 1] !== '') lines.push('')
9974
- lines.push('[features]', 'plugin_hooks = true')
10107
+ lines.push('[features]', 'hooks = true')
9975
10108
  }
9976
10109
 
9977
10110
  fs.mkdirSync(path.dirname(filepath), { recursive: true })
@@ -9982,7 +10115,7 @@ NODE
9982
10115
  else
9983
10116
  echo "Codex plugin-bundled hooks are not enabled. Startup hooks from this plugin will not run until you add this to $CODEX_CONFIG_PATH:" >&2
9984
10117
  echo "[features]" >&2
9985
- echo "plugin_hooks = true" >&2
10118
+ echo "hooks = true" >&2
9986
10119
  echo "Then restart or refresh Codex before relying on plugin startup hooks." >&2
9987
10120
  echo "Set PLUXX_CODEX_ENABLE_PLUGIN_HOOKS=1 before running this installer to enable it noninteractively." >&2
9988
10121
  fi
@@ -10621,7 +10754,7 @@ import { resolve as resolve5 } from "path";
10621
10754
  import { spawn, spawnSync as spawnSync2 } from "child_process";
10622
10755
  import { accessSync, constants, existsSync as existsSync4, lstatSync, readFileSync as readFileSync4, readdirSync as readdirSync2, realpathSync } from "fs";
10623
10756
  import { homedir } from "os";
10624
- import { basename as basename2, dirname as dirname2, resolve as resolve4 } from "path";
10757
+ import { basename as basename2, dirname as dirname2, relative as relative2, resolve as resolve4 } from "path";
10625
10758
 
10626
10759
  // node_modules/jiti/lib/jiti.mjs
10627
10760
  var import_jiti = __toESM(require_jiti(), 1);
@@ -11156,7 +11289,7 @@ var MUTATING_PREFIX_PATTERN = new RegExp(`^(${MUTATING_PREFIXES.join("|")})\\b`,
11156
11289
  // src/codex-hooks-feature.ts
11157
11290
  var RECOMMENDED_CODEX_HOOKS_FEATURE_FLAG = "hooks";
11158
11291
  var ALTERNATE_CODEX_HOOKS_FEATURE_FLAG = "codex_hooks";
11159
- var PLUGIN_BUNDLED_CODEX_HOOKS_FEATURE_FLAG = "plugin_hooks";
11292
+ var PLUGIN_BUNDLED_CODEX_HOOKS_FEATURE_FLAG = "hooks";
11160
11293
  function getCodexHooksFeatureState(features) {
11161
11294
  if (!features) {
11162
11295
  return {
@@ -11334,12 +11467,119 @@ function splitTomlDottedPath(value) {
11334
11467
  var MATERIALIZED_ENV_MARKER = "materialized required config";
11335
11468
  var MIN_NODE_MAJOR = 18;
11336
11469
  var STDIO_LAUNCH_SMOKE_TIMEOUT_MS = 1200;
11470
+ var MAX_SECRET_SCAN_FILE_BYTES = 512 * 1024;
11471
+ var LEGACY_SECRET_IDENTIFIER_PATTERN = /(^|[-_])(api[-_]?key|secret|token|password|credential)([-_]|$)/i;
11472
+ var TEST_SECRET_SENTINELS = [
11473
+ { pattern: /\bshh-secret\b/i, label: "test secret sentinel" },
11474
+ { pattern: /\bsecret-key\b/i, label: "test secret sentinel" },
11475
+ { pattern: /\bliteral-secret-value-that-should-not-copy\b/i, label: "test secret sentinel" }
11476
+ ];
11337
11477
  function renderInstalledPluginRoot(value, rootDir) {
11338
11478
  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);
11339
11479
  }
11340
11480
  function addCheck(checks, check) {
11341
11481
  checks.push(check);
11342
11482
  }
11483
+ function looksLegacySecretIdentifier(value) {
11484
+ return LEGACY_SECRET_IDENTIFIER_PATTERN.test(
11485
+ value.replace(/([a-z0-9])([A-Z])/g, "$1-$2").replace(/[._/\s]+/g, "-")
11486
+ );
11487
+ }
11488
+ function walkInstalledBundleFiles(rootDir, currentDir = rootDir) {
11489
+ const files = [];
11490
+ for (const entry of readdirSync2(currentDir, { withFileTypes: true })) {
11491
+ const absolutePath = resolve4(currentDir, entry.name);
11492
+ if (entry.isDirectory()) {
11493
+ files.push(...walkInstalledBundleFiles(rootDir, absolutePath));
11494
+ continue;
11495
+ }
11496
+ if (!entry.isFile()) continue;
11497
+ files.push(relative2(rootDir, absolutePath).replace(/\\/g, "/"));
11498
+ }
11499
+ return files.sort();
11500
+ }
11501
+ function readInstalledTextFile(rootDir, relativePath) {
11502
+ const absolutePath = resolve4(rootDir, relativePath);
11503
+ const content = readFileSync4(absolutePath);
11504
+ if (content.length > MAX_SECRET_SCAN_FILE_BYTES) return null;
11505
+ if (content.includes(0)) return null;
11506
+ return content.toString("utf-8");
11507
+ }
11508
+ function collectInstalledPlaintextSecretCandidates(rootDir) {
11509
+ const userConfigPath = resolve4(rootDir, ".pluxx-user.json");
11510
+ if (!existsSync4(userConfigPath)) return [];
11511
+ try {
11512
+ const payload = JSON.parse(readFileSync4(userConfigPath, "utf-8"));
11513
+ if (payload.secretStorage === "materialized") return [];
11514
+ const secretKeys = new Set(Array.isArray(payload.secretKeys) ? payload.secretKeys.filter((value) => typeof value === "string") : []);
11515
+ const secretEnv = new Set(Array.isArray(payload.secretEnv) ? payload.secretEnv.filter((value) => typeof value === "string") : []);
11516
+ const hasSecretMetadata = secretKeys.size > 0 || secretEnv.size > 0;
11517
+ const candidateLabels = /* @__PURE__ */ new Map();
11518
+ const recordCandidate = (rawValue, label) => {
11519
+ if (typeof rawValue !== "string") return;
11520
+ const value = rawValue.trim();
11521
+ if (!value) return;
11522
+ if (extractEnvReference(value)) return;
11523
+ if (isPlaceholderSecretValue(value)) return;
11524
+ const labels = candidateLabels.get(value) ?? /* @__PURE__ */ new Set();
11525
+ labels.add(label);
11526
+ candidateLabels.set(value, labels);
11527
+ };
11528
+ for (const [key, value] of Object.entries(payload.values ?? {})) {
11529
+ if (hasSecretMetadata ? !secretKeys.has(key) : !looksLegacySecretIdentifier(key)) continue;
11530
+ recordCandidate(value, `userConfig "${key}"`);
11531
+ }
11532
+ for (const [key, value] of Object.entries(payload.env ?? {})) {
11533
+ if (hasSecretMetadata ? !secretEnv.has(key) : !looksLegacySecretIdentifier(key)) continue;
11534
+ recordCandidate(value, `env "${key}"`);
11535
+ }
11536
+ return [...candidateLabels.entries()].map(([value, labels]) => ({
11537
+ value,
11538
+ labels: [...labels].sort()
11539
+ }));
11540
+ } catch {
11541
+ return [];
11542
+ }
11543
+ }
11544
+ function checkInstalledPlaintextSecrets(checks, rootDir) {
11545
+ const literalCandidates = collectInstalledPlaintextSecretCandidates(rootDir);
11546
+ const findings = /* @__PURE__ */ new Map();
11547
+ for (const relativePath of walkInstalledBundleFiles(rootDir)) {
11548
+ const content = readInstalledTextFile(rootDir, relativePath);
11549
+ if (!content) continue;
11550
+ const labels = /* @__PURE__ */ new Set();
11551
+ for (const candidate of literalCandidates) {
11552
+ if (!content.includes(candidate.value)) continue;
11553
+ for (const label of candidate.labels) labels.add(label);
11554
+ }
11555
+ for (const sentinel of TEST_SECRET_SENTINELS) {
11556
+ if (sentinel.pattern.test(content)) {
11557
+ labels.add(sentinel.label);
11558
+ }
11559
+ }
11560
+ if (labels.size > 0) {
11561
+ findings.set(relativePath, labels);
11562
+ }
11563
+ }
11564
+ if (findings.size === 0) {
11565
+ addCheck(checks, {
11566
+ level: "success",
11567
+ code: "consumer-plaintext-secret-absent",
11568
+ title: "Installed bundle does not expose known plaintext secret material",
11569
+ detail: "No known prompted secret values or maintained test-secret sentinels were detected in scanned installed text files.",
11570
+ fix: "No action needed."
11571
+ });
11572
+ return;
11573
+ }
11574
+ const detail = [...findings.entries()].map(([path, labels]) => `${path} (${[...labels].sort().join(", ")})`).join("; ");
11575
+ addCheck(checks, {
11576
+ level: "error",
11577
+ code: "consumer-plaintext-secret-leak",
11578
+ title: "Installed bundle contains plaintext secret material",
11579
+ detail: `Detected plaintext secret material in installed files: ${detail}.`,
11580
+ fix: "Rotate the affected credential, remove the leaking install, reinstall after the Pluxx secret-reference fix, and rerun pluxx doctor --consumer."
11581
+ });
11582
+ }
11343
11583
  function summarizeChecks(checks) {
11344
11584
  const visibleChecks = checks.filter((check) => !check.code.startsWith("primitive-"));
11345
11585
  const errors = visibleChecks.filter((check) => check.level === "error").length;
@@ -11474,7 +11714,7 @@ function readCodexHooksFeatureFlag(filePath) {
11474
11714
  inFeaturesTable = sectionMatch[1].trim() === "features";
11475
11715
  continue;
11476
11716
  }
11477
- const dottedFeatureMatch = line.match(/^features\.(plugin_hooks|hooks|codex_hooks)\s*=\s*(.+)$/);
11717
+ const dottedFeatureMatch = line.match(/^features\.(hooks|codex_hooks)\s*=\s*(.+)$/);
11478
11718
  if (dottedFeatureMatch) {
11479
11719
  assignFeatureFlag(dottedFeatureMatch[1], dottedFeatureMatch[2]);
11480
11720
  continue;
@@ -11491,7 +11731,7 @@ function readCodexHooksFeatureFlag(filePath) {
11491
11731
  continue;
11492
11732
  }
11493
11733
  if (!inFeaturesTable) continue;
11494
- const featureMatch = line.match(/^(plugin_hooks|hooks|codex_hooks)\s*=\s*(.+)$/);
11734
+ const featureMatch = line.match(/^(hooks|codex_hooks)\s*=\s*(.+)$/);
11495
11735
  if (!featureMatch) continue;
11496
11736
  assignFeatureFlag(featureMatch[1], featureMatch[2]);
11497
11737
  }
@@ -12110,20 +12350,20 @@ function checkInstalledCodexHooksFeatureFlag(checks, rootDir, layout, options) {
12110
12350
  const enabledProbes = probes.filter((probe) => probe.enabled);
12111
12351
  const checkedPaths = probes.map((probe) => `${probe.scope} ${probe.exists ? "config" : "path"}: ${probe.path}${probe.exists ? "" : " (missing)"}`).join("; ");
12112
12352
  const describeEnabledFlags = (probe) => {
12113
- const enabledFlags = [];
12114
- if (probe.pluginBundledEnabled) enabledFlags.push(PLUGIN_BUNDLED_CODEX_HOOKS_FEATURE_FLAG);
12115
- if (probe.recommendedEnabled) enabledFlags.push(RECOMMENDED_CODEX_HOOKS_FEATURE_FLAG);
12116
- if (probe.alternateEnabled) enabledFlags.push(ALTERNATE_CODEX_HOOKS_FEATURE_FLAG);
12117
- return enabledFlags.join(" + ");
12353
+ const enabledFlags = /* @__PURE__ */ new Set();
12354
+ if (probe.pluginBundledEnabled) enabledFlags.add(PLUGIN_BUNDLED_CODEX_HOOKS_FEATURE_FLAG);
12355
+ if (probe.recommendedEnabled) enabledFlags.add(RECOMMENDED_CODEX_HOOKS_FEATURE_FLAG);
12356
+ if (probe.alternateEnabled) enabledFlags.add(ALTERNATE_CODEX_HOOKS_FEATURE_FLAG);
12357
+ return [...enabledFlags].join(" + ");
12118
12358
  };
12119
12359
  const generalOnlyProbes = probes.filter((probe) => !probe.pluginBundledEnabled && (probe.recommendedEnabled || probe.alternateEnabled));
12120
12360
  if (generalOnlyProbes.length > 0) {
12121
12361
  addCheck(checks, {
12122
12362
  level: "warning",
12123
12363
  code: "consumer-codex-plugin-hooks-feature-flag-general-only",
12124
- title: "Codex config enables only general hook flags, not the plugin-bundled hook gate",
12125
- detail: `This installed Codex bundle declares plugin-bundled hooks at ${hooksReference}, but ${generalOnlyProbes.map((probe) => `${probe.scope} config ${probe.path}`).join(" and ")} enables only general hook flags (${generalOnlyProbes.map((probe) => describeEnabledFlags(probe)).join(" and ")}). Those general flags do not activate plugin-bundled hooks by themselves.`,
12126
- fix: `Enable \`${PLUGIN_BUNDLED_CODEX_HOOKS_FEATURE_FLAG} = true\` under \`[features]\` in the active Codex config, reload Codex, and rerun pluxx verify-install.`,
12364
+ title: "Codex config enables only deprecated hook flags",
12365
+ detail: `This installed Codex bundle declares plugin-bundled hooks at ${hooksReference}, but ${generalOnlyProbes.map((probe) => `${probe.scope} config ${probe.path}`).join(" and ")} enables only deprecated hook flags (${generalOnlyProbes.map((probe) => describeEnabledFlags(probe)).join(" and ")}). Current Codex docs use \`${RECOMMENDED_CODEX_HOOKS_FEATURE_FLAG}\` as the canonical feature key.`,
12366
+ fix: `Enable \`${RECOMMENDED_CODEX_HOOKS_FEATURE_FLAG} = true\` under \`[features]\` in the active Codex config, reload Codex, and rerun pluxx verify-install.`,
12127
12367
  path: generalOnlyProbes[0].path
12128
12368
  });
12129
12369
  }
@@ -12133,8 +12373,8 @@ function checkInstalledCodexHooksFeatureFlag(checks, rootDir, layout, options) {
12133
12373
  level: "warning",
12134
12374
  code: "consumer-codex-hooks-feature-flag-legacy-only",
12135
12375
  title: "Codex config still uses the deprecated general hook compatibility flag",
12136
- detail: `This installed Codex bundle declares plugin-bundled hooks at ${hooksReference}, and the checked Codex config enables only the deprecated general hook flag \`${ALTERNATE_CODEX_HOOKS_FEATURE_FLAG} = true\` in ${legacyOnlyProbes.map((probe) => `${probe.scope} config ${probe.path}`).join(" and ")}. That flag is not the plugin-bundled hook gate.`,
12137
- fix: `Prefer \`${RECOMMENDED_CODEX_HOOKS_FEATURE_FLAG} = true\` only for non-plugin hook config if needed, and use \`${PLUGIN_BUNDLED_CODEX_HOOKS_FEATURE_FLAG} = true\` under \`[features]\` for plugin-bundled hooks. Reload Codex and rerun pluxx verify-install after updating the active config.`,
12376
+ detail: `This installed Codex bundle declares plugin-bundled hooks at ${hooksReference}, and the checked Codex config enables only the deprecated hook flag \`${ALTERNATE_CODEX_HOOKS_FEATURE_FLAG} = true\` in ${legacyOnlyProbes.map((probe) => `${probe.scope} config ${probe.path}`).join(" and ")}. Current Codex docs use \`${RECOMMENDED_CODEX_HOOKS_FEATURE_FLAG}\` as the canonical feature key.`,
12377
+ fix: `Use \`${RECOMMENDED_CODEX_HOOKS_FEATURE_FLAG} = true\` under \`[features]\`, reload Codex, and rerun pluxx verify-install after updating the active config.`,
12138
12378
  path: legacyOnlyProbes[0].path
12139
12379
  });
12140
12380
  }
@@ -12142,8 +12382,8 @@ function checkInstalledCodexHooksFeatureFlag(checks, rootDir, layout, options) {
12142
12382
  addCheck(checks, {
12143
12383
  level: "success",
12144
12384
  code: "consumer-codex-hooks-feature-flag-enabled",
12145
- title: "Codex plugin-bundled hook feature flag found for this install",
12146
- detail: `This installed Codex bundle declares plugin-bundled hooks at ${hooksReference}, and the plugin hook gate was found in ${enabledProbes.map((probe) => `${probe.scope} config ${probe.path} (${describeEnabledFlags(probe)})`).join(" and ")}. Treat that as a prerequisite, not proof of live hook execution.`,
12385
+ title: "Codex hook feature flag found for this install",
12386
+ detail: `This installed Codex bundle declares plugin-bundled hooks at ${hooksReference}, and the canonical hook feature key was found in ${enabledProbes.map((probe) => `${probe.scope} config ${probe.path} (${describeEnabledFlags(probe)})`).join(" and ")}. Treat that as a prerequisite, not proof of live hook execution.`,
12147
12387
  fix: "No action needed.",
12148
12388
  path: enabledProbes[0].path
12149
12389
  });
@@ -12154,8 +12394,8 @@ function checkInstalledCodexHooksFeatureFlag(checks, rootDir, layout, options) {
12154
12394
  level: "warning",
12155
12395
  code: "consumer-codex-hooks-feature-flag-missing",
12156
12396
  title: "Codex plugin-bundled hook activation is missing its known feature-gate prerequisite",
12157
- detail: `This installed Codex bundle declares plugin-bundled hooks at ${hooksReference}, but \`${PLUGIN_BUNDLED_CODEX_HOOKS_FEATURE_FLAG} = true\` was not found in the checked Codex config layers. The general \`${RECOMMENDED_CODEX_HOOKS_FEATURE_FLAG}\` flag covers non-plugin hook config and defaults on, while \`${ALTERNATE_CODEX_HOOKS_FEATURE_FLAG}\` is deprecated and should not be treated as a plugin-bundled hook fallback. Checked ${checkedPaths}.${parseErrors.length > 0 ? ` Unparseable config: ${parseErrors.join("; ")}.` : ""}`,
12158
- fix: `Enable \`${PLUGIN_BUNDLED_CODEX_HOOKS_FEATURE_FLAG} = true\` under \`[features]\` in the relevant project or user Codex config, reload Codex, and rerun pluxx verify-install.`,
12397
+ detail: `This installed Codex bundle declares plugin-bundled hooks at ${hooksReference}, but \`${RECOMMENDED_CODEX_HOOKS_FEATURE_FLAG} = true\` was not found in the checked Codex config layers. \`${ALTERNATE_CODEX_HOOKS_FEATURE_FLAG}\` is deprecated and should not be treated as the current hook feature key. Checked ${checkedPaths}.${parseErrors.length > 0 ? ` Unparseable config: ${parseErrors.join("; ")}.` : ""}`,
12398
+ fix: `Enable \`${RECOMMENDED_CODEX_HOOKS_FEATURE_FLAG} = true\` under \`[features]\` in the relevant project or user Codex config, reload Codex, and rerun pluxx verify-install.`,
12159
12399
  path: probes.find((probe) => probe.exists)?.path ?? hooksReference
12160
12400
  });
12161
12401
  }
@@ -12689,6 +12929,7 @@ async function doctorConsumer(rootDir = process.cwd(), options = {}) {
12689
12929
  checkInstalledCodexPermissionCompanion(checks, rootDir, layout, options);
12690
12930
  checkInstalledPermissionHook(checks, rootDir, layout);
12691
12931
  checkInstalledUserConfig(checks, rootDir);
12932
+ checkInstalledPlaintextSecrets(checks, rootDir);
12692
12933
  checkInstalledEnvValidation(checks, rootDir);
12693
12934
  checkInstalledRuntimeScriptRoles(checks, rootDir);
12694
12935
  await checkInstalledMcpConfig(checks, rootDir, layout);
@@ -1 +1 @@
1
- {"version":3,"file":"readiness.d.ts","sourceRoot":"","sources":["../src/readiness.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAA;AAEhD,MAAM,WAAW,oBAAoB;IACnC,YAAY,EAAE,OAAO,CAAA;IACrB,aAAa,EAAE,MAAM,EAAE,CAAA;IACvB,iBAAiB,EAAE,OAAO,CAAA;IAC1B,YAAY,EAAE,OAAO,CAAA;IACrB,eAAe,EAAE,OAAO,CAAA;IACxB,gBAAgB,EAAE,OAAO,CAAA;IACzB,qBAAqB,EAAE,OAAO,CAAA;CAC/B;AAED,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,gBAAgB,GAAG,SAAS,GAAG,oBAAoB,CAsBrG;AAED,wBAAgB,6BAA6B,CAAC,SAAS,EAAE,gBAAgB,GAAG,MAAM,CAyRjF"}
1
+ {"version":3,"file":"readiness.d.ts","sourceRoot":"","sources":["../src/readiness.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAA;AAEhD,MAAM,WAAW,oBAAoB;IACnC,YAAY,EAAE,OAAO,CAAA;IACrB,aAAa,EAAE,MAAM,EAAE,CAAA;IACvB,iBAAiB,EAAE,OAAO,CAAA;IAC1B,YAAY,EAAE,OAAO,CAAA;IACrB,eAAe,EAAE,OAAO,CAAA;IACxB,gBAAgB,EAAE,OAAO,CAAA;IACzB,qBAAqB,EAAE,OAAO,CAAA;CAC/B;AAED,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,gBAAgB,GAAG,SAAS,GAAG,oBAAoB,CAsBrG;AAED,wBAAgB,6BAA6B,CAAC,SAAS,EAAE,gBAAgB,GAAG,MAAM,CAiSjF"}
@@ -4,6 +4,14 @@ export interface ResolvedUserConfigEntry {
4
4
  value: string | number | boolean;
5
5
  envVar?: string;
6
6
  }
7
+ export interface InstalledUserConfigPayload {
8
+ values?: Record<string, string | number | boolean>;
9
+ env?: Record<string, string>;
10
+ envRefs?: Record<string, string>;
11
+ secretStorage?: 'env-ref' | 'materialized';
12
+ secretKeys?: string[];
13
+ secretEnv?: string[];
14
+ }
7
15
  interface DerivedUserConfigEntry extends UserConfigEntry {
8
16
  source: 'explicit' | 'mcp-auth' | 'mcp-env';
9
17
  }
@@ -16,5 +24,8 @@ export declare function collectUserConfigEntries(config: PluginConfig, platforms
16
24
  export declare function resolveUserConfigEntriesForTarget(entries: ResolvedUserConfigEntry[], target: TargetPlatform): ResolvedUserConfigEntry[];
17
25
  export declare function buildUserConfigEnvMap(entries: ResolvedUserConfigEntry[]): Record<string, string>;
18
26
  export declare function buildUserConfigValueMap(entries: ResolvedUserConfigEntry[]): Record<string, string | number | boolean>;
27
+ export declare function buildInstalledUserConfigPayload(entries: ResolvedUserConfigEntry[], options?: {
28
+ preserveSecretReferences?: boolean;
29
+ }): InstalledUserConfigPayload;
19
30
  export {};
20
31
  //# sourceMappingURL=user-config.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"user-config.d.ts","sourceRoot":"","sources":["../src/user-config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAa,YAAY,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAExF,MAAM,WAAW,uBAAuB;IACtC,KAAK,EAAE,eAAe,CAAA;IACtB,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAA;IAChC,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED,UAAU,sBAAuB,SAAQ,eAAe;IACtD,MAAM,EAAE,UAAU,GAAG,UAAU,GAAG,SAAS,CAAA;CAC5C;AAcD,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAS5D;AAED,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAU7D;AAED,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAM3D;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAIjF;AAED,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAKhE;AA2CD,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,YAAY,EACpB,SAAS,GAAE,cAAc,EAAmB,GAC3C,sBAAsB,EAAE,CAyD1B;AAED,wBAAgB,iCAAiC,CAC/C,OAAO,EAAE,uBAAuB,EAAE,EAClC,MAAM,EAAE,cAAc,GACrB,uBAAuB,EAAE,CAE3B;AAED,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,uBAAuB,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAOhG;AAED,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,uBAAuB,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,CAMrH"}
1
+ {"version":3,"file":"user-config.d.ts","sourceRoot":"","sources":["../src/user-config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAa,YAAY,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAExF,MAAM,WAAW,uBAAuB;IACtC,KAAK,EAAE,eAAe,CAAA;IACtB,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAA;IAChC,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,0BAA0B;IACzC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,CAAA;IAClD,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC5B,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAChC,aAAa,CAAC,EAAE,SAAS,GAAG,cAAc,CAAA;IAC1C,UAAU,CAAC,EAAE,MAAM,EAAE,CAAA;IACrB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAA;CACrB;AAED,UAAU,sBAAuB,SAAQ,eAAe;IACtD,MAAM,EAAE,UAAU,GAAG,UAAU,GAAG,SAAS,CAAA;CAC5C;AAcD,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAS5D;AAED,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAU7D;AAED,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAM3D;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAIjF;AAED,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAKhE;AA2CD,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,YAAY,EACpB,SAAS,GAAE,cAAc,EAAmB,GAC3C,sBAAsB,EAAE,CAyD1B;AAED,wBAAgB,iCAAiC,CAC/C,OAAO,EAAE,uBAAuB,EAAE,EAClC,MAAM,EAAE,cAAc,GACrB,uBAAuB,EAAE,CAE3B;AAED,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,uBAAuB,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAOhG;AAED,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,uBAAuB,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,CAMrH;AAED,wBAAgB,+BAA+B,CAC7C,OAAO,EAAE,uBAAuB,EAAE,EAClC,OAAO,GAAE;IAAE,wBAAwB,CAAC,EAAE,OAAO,CAAA;CAAO,GACnD,0BAA0B,CAqC5B"}
@@ -77,6 +77,7 @@ export interface PlatformRules {
77
77
  }
78
78
  export type PrimitiveTranslationMode = 'preserve' | 'translate' | 'degrade' | 'drop';
79
79
  export type CoreFourPlatform = Extract<TargetPlatform, 'claude-code' | 'cursor' | 'codex' | 'opencode'>;
80
+ export declare const CORE_FOUR_PLATFORMS: readonly ["claude-code", "cursor", "codex", "opencode"];
80
81
  export interface PlatformPrimitiveCapability {
81
82
  mode: PrimitiveTranslationMode;
82
83
  nativeSurfaces: string[];
@@ -1 +1 @@
1
- {"version":3,"file":"platform-rules.d.ts","sourceRoot":"","sources":["../../src/validation/platform-rules.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"platform-rules.d.ts","sourceRoot":"","sources":["../../src/validation/platform-rules.ts"],"names":[],"mappings":"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"}