@orchid-labs/pluxx 0.1.18 → 0.1.20
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 +328 -8
- package/dist/cli/publish.d.ts.map +1 -1
- package/dist/index.js +328 -8
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -24455,17 +24455,18 @@ function renderInstallerUserConfigSnippet(config, platform, installDirVariable)
|
|
|
24455
24455
|
if (entries.length === 0) return "";
|
|
24456
24456
|
const promptLines = entries.map((entry) => {
|
|
24457
24457
|
const functionName = entry.type === "secret" ? "pluxx_prompt_secret_config" : "pluxx_prompt_text_config";
|
|
24458
|
-
return `${functionName} ${JSON.stringify(entry.envVar)} ${JSON.stringify(entry.title)} ${entry.required ? "1" : "0"}`;
|
|
24458
|
+
return `${functionName} ${JSON.stringify(entry.key)} ${JSON.stringify(entry.envVar)} ${JSON.stringify(entry.title)} ${entry.required ? "1" : "0"}`;
|
|
24459
24459
|
});
|
|
24460
24460
|
return `
|
|
24461
24461
|
PLUXX_USER_CONFIG_SPEC="$(cat <<'PLUXX_USER_CONFIG_JSON'
|
|
24462
24462
|
${JSON.stringify(entries)}
|
|
24463
24463
|
PLUXX_USER_CONFIG_JSON
|
|
24464
24464
|
)"
|
|
24465
|
+
PLUXX_REUSED_USER_CONFIG=0
|
|
24465
24466
|
|
|
24466
24467
|
pluxx_is_placeholder_secret() {
|
|
24467
24468
|
case "$1" in
|
|
24468
|
-
*dummy*|*Dummy*|*DUMMY*|*placeholder*|*Placeholder*|*PLACEHOLDER*|*changeme*|*CHANGE_ME*|*replace*me*|*Replace*Me*|*your*key*|*YOUR*KEY*|*api*key*here*|*API*KEY*HERE*|*token*here*|*TOKEN*HERE*)
|
|
24469
|
+
*dummy*|*Dummy*|*DUMMY*|*placeholder*|*Placeholder*|*PLACEHOLDER*|*example*|*Example*|*EXAMPLE*|*changeme*|*CHANGE_ME*|*replace*me*|*Replace*Me*|*your*key*|*YOUR*KEY*|*api*key*here*|*API*KEY*HERE*|*token*here*|*TOKEN*HERE*)
|
|
24469
24470
|
return 0
|
|
24470
24471
|
;;
|
|
24471
24472
|
*)
|
|
@@ -24474,12 +24475,61 @@ pluxx_is_placeholder_secret() {
|
|
|
24474
24475
|
esac
|
|
24475
24476
|
}
|
|
24476
24477
|
|
|
24478
|
+
pluxx_saved_config_value() {
|
|
24479
|
+
local key="$1"
|
|
24480
|
+
local env_var="$2"
|
|
24481
|
+
|
|
24482
|
+
if [[ -z "\${PLUXX_SAVED_USER_CONFIG_PATH:-}" || ! -f "$PLUXX_SAVED_USER_CONFIG_PATH" ]]; then
|
|
24483
|
+
return 1
|
|
24484
|
+
fi
|
|
24485
|
+
|
|
24486
|
+
PLUXX_SAVED_CONFIG_KEY="$key" PLUXX_SAVED_CONFIG_ENV_VAR="$env_var" node <<'NODE'
|
|
24487
|
+
const fs = require('fs')
|
|
24488
|
+
|
|
24489
|
+
const filepath = process.env.PLUXX_SAVED_USER_CONFIG_PATH
|
|
24490
|
+
const key = process.env.PLUXX_SAVED_CONFIG_KEY
|
|
24491
|
+
const envVar = process.env.PLUXX_SAVED_CONFIG_ENV_VAR
|
|
24492
|
+
|
|
24493
|
+
try {
|
|
24494
|
+
const payload = JSON.parse(fs.readFileSync(filepath, 'utf8'))
|
|
24495
|
+
const candidates = [
|
|
24496
|
+
payload && payload.env && envVar ? payload.env[envVar] : undefined,
|
|
24497
|
+
payload && payload.values && key ? payload.values[key] : undefined,
|
|
24498
|
+
]
|
|
24499
|
+
|
|
24500
|
+
for (const candidate of candidates) {
|
|
24501
|
+
if (candidate === undefined || candidate === null) continue
|
|
24502
|
+
if (!['string', 'number', 'boolean'].includes(typeof candidate)) continue
|
|
24503
|
+
const value = String(candidate)
|
|
24504
|
+
if (value === '') continue
|
|
24505
|
+
process.stdout.write(value)
|
|
24506
|
+
process.exit(0)
|
|
24507
|
+
}
|
|
24508
|
+
} catch {}
|
|
24509
|
+
|
|
24510
|
+
process.exit(1)
|
|
24511
|
+
NODE
|
|
24512
|
+
}
|
|
24513
|
+
|
|
24477
24514
|
pluxx_prompt_secret_config() {
|
|
24478
|
-
local
|
|
24479
|
-
local
|
|
24480
|
-
local
|
|
24515
|
+
local key="$1"
|
|
24516
|
+
local env_var="$2"
|
|
24517
|
+
local label="$3"
|
|
24518
|
+
local required="$4"
|
|
24481
24519
|
local current_value="\${!env_var:-}"
|
|
24482
24520
|
|
|
24521
|
+
if [[ -z "$current_value" && "\${PLUXX_RECONFIGURE:-0}" != "1" ]]; then
|
|
24522
|
+
local saved_value=""
|
|
24523
|
+
if saved_value="$(pluxx_saved_config_value "$key" "$env_var")"; then
|
|
24524
|
+
if pluxx_is_placeholder_secret "$saved_value"; then
|
|
24525
|
+
echo "Ignoring placeholder-looking saved config for $env_var." >&2
|
|
24526
|
+
else
|
|
24527
|
+
current_value="$saved_value"
|
|
24528
|
+
PLUXX_REUSED_USER_CONFIG=1
|
|
24529
|
+
fi
|
|
24530
|
+
fi
|
|
24531
|
+
fi
|
|
24532
|
+
|
|
24483
24533
|
if [[ -z "$current_value" && "$required" == "1" ]]; then
|
|
24484
24534
|
if [[ -t 0 || -r /dev/tty ]]; then
|
|
24485
24535
|
read -r -s -p "$label [$env_var]: " current_value </dev/tty
|
|
@@ -24499,11 +24549,20 @@ pluxx_prompt_secret_config() {
|
|
|
24499
24549
|
}
|
|
24500
24550
|
|
|
24501
24551
|
pluxx_prompt_text_config() {
|
|
24502
|
-
local
|
|
24503
|
-
local
|
|
24504
|
-
local
|
|
24552
|
+
local key="$1"
|
|
24553
|
+
local env_var="$2"
|
|
24554
|
+
local label="$3"
|
|
24555
|
+
local required="$4"
|
|
24505
24556
|
local current_value="\${!env_var:-}"
|
|
24506
24557
|
|
|
24558
|
+
if [[ -z "$current_value" && "\${PLUXX_RECONFIGURE:-0}" != "1" ]]; then
|
|
24559
|
+
local saved_value=""
|
|
24560
|
+
if saved_value="$(pluxx_saved_config_value "$key" "$env_var")"; then
|
|
24561
|
+
current_value="$saved_value"
|
|
24562
|
+
PLUXX_REUSED_USER_CONFIG=1
|
|
24563
|
+
fi
|
|
24564
|
+
fi
|
|
24565
|
+
|
|
24507
24566
|
if [[ -z "$current_value" && "$required" == "1" ]]; then
|
|
24508
24567
|
if [[ -t 0 || -r /dev/tty ]]; then
|
|
24509
24568
|
read -r -p "$label [$env_var]: " current_value </dev/tty
|
|
@@ -24518,6 +24577,10 @@ pluxx_prompt_text_config() {
|
|
|
24518
24577
|
|
|
24519
24578
|
${promptLines.join("\n")}
|
|
24520
24579
|
|
|
24580
|
+
if [[ "$PLUXX_REUSED_USER_CONFIG" == "1" ]]; then
|
|
24581
|
+
echo "Found existing plugin config; reusing saved install values."
|
|
24582
|
+
fi
|
|
24583
|
+
|
|
24521
24584
|
export PLUXX_USER_CONFIG_SPEC
|
|
24522
24585
|
export PLUXX_INSTALL_DIR="${installDirVariable}"
|
|
24523
24586
|
|
|
@@ -24613,6 +24676,17 @@ NODE
|
|
|
24613
24676
|
function hasInstallerUserConfig(config, platform) {
|
|
24614
24677
|
return collectUserConfigEntries(config, [platform]).length > 0;
|
|
24615
24678
|
}
|
|
24679
|
+
function renderInstallerSavedUserConfigCaptureSnippet(config, platform, installDirVariable) {
|
|
24680
|
+
if (!hasInstallerUserConfig(config, platform)) return "";
|
|
24681
|
+
return `
|
|
24682
|
+
PLUXX_SAVED_USER_CONFIG_PATH=""
|
|
24683
|
+
if [[ "\${PLUXX_RECONFIGURE:-0}" != "1" && -f "${installDirVariable}/.pluxx-user.json" ]]; then
|
|
24684
|
+
PLUXX_SAVED_USER_CONFIG_PATH="$TMP_DIR/pluxx-saved-user-config.json"
|
|
24685
|
+
cp "${installDirVariable}/.pluxx-user.json" "$PLUXX_SAVED_USER_CONFIG_PATH"
|
|
24686
|
+
fi
|
|
24687
|
+
export PLUXX_SAVED_USER_CONFIG_PATH
|
|
24688
|
+
`;
|
|
24689
|
+
}
|
|
24616
24690
|
function renderInstallerMcpPathMaterializationSnippet(platform, installDirVariable) {
|
|
24617
24691
|
if (platform !== "codex") return "";
|
|
24618
24692
|
return `
|
|
@@ -24681,6 +24755,247 @@ if [[ -f "${installDirVariable}/scripts/bootstrap-runtime.sh" ]]; then
|
|
|
24681
24755
|
fi
|
|
24682
24756
|
`;
|
|
24683
24757
|
}
|
|
24758
|
+
function renderInstallerCodexPluginHooksSnippet(installDirVariable) {
|
|
24759
|
+
return `
|
|
24760
|
+
export PLUXX_INSTALL_DIR="${installDirVariable}"
|
|
24761
|
+
|
|
24762
|
+
set +e
|
|
24763
|
+
node <<'NODE'
|
|
24764
|
+
const fs = require('fs')
|
|
24765
|
+
const path = require('path')
|
|
24766
|
+
|
|
24767
|
+
const installDir = process.env.PLUXX_INSTALL_DIR
|
|
24768
|
+
if (!installDir) process.exit(0)
|
|
24769
|
+
|
|
24770
|
+
const manifestPath = path.join(installDir, '.codex-plugin/plugin.json')
|
|
24771
|
+
const standardHooksPath = path.join(installDir, 'hooks/hooks.json')
|
|
24772
|
+
let hasPluginHooks = fs.existsSync(standardHooksPath)
|
|
24773
|
+
|
|
24774
|
+
if (fs.existsSync(manifestPath)) {
|
|
24775
|
+
try {
|
|
24776
|
+
const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8'))
|
|
24777
|
+
const manifestHooks = manifest.hooks
|
|
24778
|
+
hasPluginHooks ||= typeof manifestHooks === 'string' && manifestHooks.trim().length > 0
|
|
24779
|
+
hasPluginHooks ||= Array.isArray(manifestHooks) && manifestHooks.length > 0
|
|
24780
|
+
hasPluginHooks ||= manifestHooks && typeof manifestHooks === 'object' && Object.keys(manifestHooks).length > 0
|
|
24781
|
+
hasPluginHooks ||= manifestHooks === true
|
|
24782
|
+
} catch {}
|
|
24783
|
+
}
|
|
24784
|
+
|
|
24785
|
+
process.exit(hasPluginHooks ? 0 : 2)
|
|
24786
|
+
NODE
|
|
24787
|
+
PLUXX_CODEX_BUNDLE_HAS_HOOKS="$?"
|
|
24788
|
+
set -e
|
|
24789
|
+
|
|
24790
|
+
if [[ "$PLUXX_CODEX_BUNDLE_HAS_HOOKS" == "0" ]]; then
|
|
24791
|
+
CODEX_HOME_DIR="\${CODEX_HOME:-$HOME/.codex}"
|
|
24792
|
+
CODEX_CONFIG_PATH="\${PLUXX_CODEX_CONFIG_PATH:-$CODEX_HOME_DIR/config.toml}"
|
|
24793
|
+
PLUXX_CODEX_HOOKS_MODE="\${PLUXX_CODEX_ENABLE_PLUGIN_HOOKS:-prompt}"
|
|
24794
|
+
|
|
24795
|
+
export CODEX_CONFIG_PATH
|
|
24796
|
+
if node <<'NODE'
|
|
24797
|
+
const fs = require('fs')
|
|
24798
|
+
const filepath = process.env.CODEX_CONFIG_PATH
|
|
24799
|
+
|
|
24800
|
+
function stripTomlComment(line) {
|
|
24801
|
+
let quote = null
|
|
24802
|
+
let escaped = false
|
|
24803
|
+
for (let index = 0; index < line.length; index += 1) {
|
|
24804
|
+
const char = line[index]
|
|
24805
|
+
if (escaped) {
|
|
24806
|
+
escaped = false
|
|
24807
|
+
continue
|
|
24808
|
+
}
|
|
24809
|
+
if (quote && char === '\\\\') {
|
|
24810
|
+
escaped = true
|
|
24811
|
+
continue
|
|
24812
|
+
}
|
|
24813
|
+
if (char === '"' || char === "'") {
|
|
24814
|
+
quote = quote === char ? null : quote || char
|
|
24815
|
+
continue
|
|
24816
|
+
}
|
|
24817
|
+
if (!quote && char === '#') return line.slice(0, index)
|
|
24818
|
+
}
|
|
24819
|
+
return line
|
|
24820
|
+
}
|
|
24821
|
+
|
|
24822
|
+
function isTomlTrue(rawValue) {
|
|
24823
|
+
return /^true\\b/i.test(rawValue.trim())
|
|
24824
|
+
}
|
|
24825
|
+
|
|
24826
|
+
let text = ''
|
|
24827
|
+
try {
|
|
24828
|
+
text = fs.readFileSync(filepath, 'utf8')
|
|
24829
|
+
} catch {
|
|
24830
|
+
process.exit(1)
|
|
24831
|
+
}
|
|
24832
|
+
const lines = text.split(/\\r?\\n/)
|
|
24833
|
+
let tableName = ''
|
|
24834
|
+
for (const line of lines) {
|
|
24835
|
+
const trimmed = stripTomlComment(line).trim()
|
|
24836
|
+
if (!trimmed) continue
|
|
24837
|
+
const tableMatch = trimmed.match(/^\\[([^\\]]+)\\]$/)
|
|
24838
|
+
if (tableMatch) {
|
|
24839
|
+
tableName = tableMatch[1].trim()
|
|
24840
|
+
continue
|
|
24841
|
+
}
|
|
24842
|
+
if (tableName === '') {
|
|
24843
|
+
const dottedMatch = trimmed.match(/^features\\.plugin_hooks\\s*=\\s*(.+)$/)
|
|
24844
|
+
if (dottedMatch && isTomlTrue(dottedMatch[1])) process.exit(0)
|
|
24845
|
+
const inlineMatch = trimmed.match(/^features\\s*=\\s*(.+)$/)
|
|
24846
|
+
if (inlineMatch && /\\bplugin_hooks\\s*=\\s*true\\b/i.test(inlineMatch[1])) process.exit(0)
|
|
24847
|
+
}
|
|
24848
|
+
if (tableName !== 'features') continue
|
|
24849
|
+
const match = trimmed.match(/^plugin_hooks\\s*=\\s*(.+)$/)
|
|
24850
|
+
if (match && isTomlTrue(match[1])) process.exit(0)
|
|
24851
|
+
}
|
|
24852
|
+
process.exit(1)
|
|
24853
|
+
NODE
|
|
24854
|
+
then
|
|
24855
|
+
echo "Codex plugin-bundled hooks already enabled in $CODEX_CONFIG_PATH."
|
|
24856
|
+
else
|
|
24857
|
+
PLUXX_ENABLE_CODEX_HOOKS="0"
|
|
24858
|
+
case "$PLUXX_CODEX_HOOKS_MODE" in
|
|
24859
|
+
1|true|TRUE|yes|YES|always|ALWAYS)
|
|
24860
|
+
PLUXX_ENABLE_CODEX_HOOKS="1"
|
|
24861
|
+
;;
|
|
24862
|
+
0|false|FALSE|no|NO|never|NEVER|skip|SKIP)
|
|
24863
|
+
PLUXX_ENABLE_CODEX_HOOKS="0"
|
|
24864
|
+
;;
|
|
24865
|
+
*)
|
|
24866
|
+
if [[ -r /dev/tty ]]; then
|
|
24867
|
+
echo "This Codex plugin bundle includes startup hooks." >/dev/tty
|
|
24868
|
+
echo "Codex requires [features].plugin_hooks = true before plugin-bundled hooks can run." >/dev/tty
|
|
24869
|
+
read -r -p "Enable Codex plugin-bundled hooks in $CODEX_CONFIG_PATH now? [Y/n] " PLUXX_CODEX_HOOKS_REPLY </dev/tty
|
|
24870
|
+
case "$PLUXX_CODEX_HOOKS_REPLY" in
|
|
24871
|
+
n|N|no|NO)
|
|
24872
|
+
PLUXX_ENABLE_CODEX_HOOKS="0"
|
|
24873
|
+
;;
|
|
24874
|
+
*)
|
|
24875
|
+
PLUXX_ENABLE_CODEX_HOOKS="1"
|
|
24876
|
+
;;
|
|
24877
|
+
esac
|
|
24878
|
+
fi
|
|
24879
|
+
;;
|
|
24880
|
+
esac
|
|
24881
|
+
|
|
24882
|
+
if [[ "$PLUXX_ENABLE_CODEX_HOOKS" == "1" ]]; then
|
|
24883
|
+
mkdir -p "$(dirname "$CODEX_CONFIG_PATH")"
|
|
24884
|
+
node <<'NODE'
|
|
24885
|
+
const fs = require('fs')
|
|
24886
|
+
const path = require('path')
|
|
24887
|
+
|
|
24888
|
+
const filepath = process.env.CODEX_CONFIG_PATH
|
|
24889
|
+
|
|
24890
|
+
function stripTomlComment(line) {
|
|
24891
|
+
let quote = null
|
|
24892
|
+
let escaped = false
|
|
24893
|
+
for (let index = 0; index < line.length; index += 1) {
|
|
24894
|
+
const char = line[index]
|
|
24895
|
+
if (escaped) {
|
|
24896
|
+
escaped = false
|
|
24897
|
+
continue
|
|
24898
|
+
}
|
|
24899
|
+
if (quote && char === '\\\\') {
|
|
24900
|
+
escaped = true
|
|
24901
|
+
continue
|
|
24902
|
+
}
|
|
24903
|
+
if (char === '"' || char === "'") {
|
|
24904
|
+
quote = quote === char ? null : quote || char
|
|
24905
|
+
continue
|
|
24906
|
+
}
|
|
24907
|
+
if (!quote && char === '#') return line.slice(0, index)
|
|
24908
|
+
}
|
|
24909
|
+
return line
|
|
24910
|
+
}
|
|
24911
|
+
|
|
24912
|
+
let text = ''
|
|
24913
|
+
try {
|
|
24914
|
+
text = fs.readFileSync(filepath, 'utf8')
|
|
24915
|
+
} catch {}
|
|
24916
|
+
|
|
24917
|
+
const lines = text.split(/\\r?\\n/)
|
|
24918
|
+
if (lines.length === 1 && lines[0] === '') lines.pop()
|
|
24919
|
+
|
|
24920
|
+
let start = -1
|
|
24921
|
+
let end = lines.length
|
|
24922
|
+
let firstTopLevelFeaturesDotted = -1
|
|
24923
|
+
let topLevelPluginHooksDotted = -1
|
|
24924
|
+
let topLevelInlineFeatures = -1
|
|
24925
|
+
let tableName = ''
|
|
24926
|
+
for (let index = 0; index < lines.length; index += 1) {
|
|
24927
|
+
const trimmed = stripTomlComment(lines[index]).trim()
|
|
24928
|
+
const tableMatch = trimmed.match(/^\\[([^\\]]+)\\]$/)
|
|
24929
|
+
if (tableMatch) tableName = tableMatch[1].trim()
|
|
24930
|
+
|
|
24931
|
+
if (trimmed === '[features]') {
|
|
24932
|
+
start = index
|
|
24933
|
+
break
|
|
24934
|
+
}
|
|
24935
|
+
|
|
24936
|
+
if (tableName === '') {
|
|
24937
|
+
if (/^features\\.[A-Za-z0-9_-]+\\s*=/.test(trimmed) && firstTopLevelFeaturesDotted < 0) {
|
|
24938
|
+
firstTopLevelFeaturesDotted = index
|
|
24939
|
+
}
|
|
24940
|
+
if (/^features\\.plugin_hooks\\s*=/.test(trimmed)) {
|
|
24941
|
+
topLevelPluginHooksDotted = index
|
|
24942
|
+
}
|
|
24943
|
+
if (/^features\\s*=\\s*\\{/.test(trimmed)) {
|
|
24944
|
+
topLevelInlineFeatures = index
|
|
24945
|
+
}
|
|
24946
|
+
}
|
|
24947
|
+
}
|
|
24948
|
+
|
|
24949
|
+
if (start >= 0) {
|
|
24950
|
+
for (let index = start + 1; index < lines.length; index += 1) {
|
|
24951
|
+
if (/^\\s*\\[[^\\]]+\\]/.test(stripTomlComment(lines[index]))) {
|
|
24952
|
+
end = index
|
|
24953
|
+
break
|
|
24954
|
+
}
|
|
24955
|
+
}
|
|
24956
|
+
|
|
24957
|
+
let updated = false
|
|
24958
|
+
for (let index = start + 1; index < end; index += 1) {
|
|
24959
|
+
if (/^plugin_hooks\\s*=/.test(stripTomlComment(lines[index]).trim())) {
|
|
24960
|
+
lines[index] = 'plugin_hooks = true'
|
|
24961
|
+
updated = true
|
|
24962
|
+
}
|
|
24963
|
+
}
|
|
24964
|
+
if (!updated) lines.splice(start + 1, 0, 'plugin_hooks = true')
|
|
24965
|
+
} else if (topLevelPluginHooksDotted >= 0) {
|
|
24966
|
+
lines[topLevelPluginHooksDotted] = 'features.plugin_hooks = true'
|
|
24967
|
+
} else if (firstTopLevelFeaturesDotted >= 0) {
|
|
24968
|
+
lines.splice(firstTopLevelFeaturesDotted + 1, 0, 'features.plugin_hooks = true')
|
|
24969
|
+
} else if (topLevelInlineFeatures >= 0 && lines[topLevelInlineFeatures].includes('}')) {
|
|
24970
|
+
if (/\\bplugin_hooks\\s*=/.test(lines[topLevelInlineFeatures])) {
|
|
24971
|
+
lines[topLevelInlineFeatures] = lines[topLevelInlineFeatures].replace(
|
|
24972
|
+
/\\bplugin_hooks\\s*=\\s*(true|false)\\b/i,
|
|
24973
|
+
'plugin_hooks = true',
|
|
24974
|
+
)
|
|
24975
|
+
} else {
|
|
24976
|
+
lines[topLevelInlineFeatures] = lines[topLevelInlineFeatures].replace(/}/, ', plugin_hooks = true }')
|
|
24977
|
+
}
|
|
24978
|
+
} else {
|
|
24979
|
+
if (lines.length > 0 && lines[lines.length - 1] !== '') lines.push('')
|
|
24980
|
+
lines.push('[features]', 'plugin_hooks = true')
|
|
24981
|
+
}
|
|
24982
|
+
|
|
24983
|
+
fs.mkdirSync(path.dirname(filepath), { recursive: true })
|
|
24984
|
+
fs.writeFileSync(filepath, lines.join('\\n') + '\\n')
|
|
24985
|
+
NODE
|
|
24986
|
+
echo "Enabled Codex plugin-bundled hooks in $CODEX_CONFIG_PATH."
|
|
24987
|
+
echo "Restart or refresh Codex before relying on plugin startup hooks."
|
|
24988
|
+
else
|
|
24989
|
+
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
|
|
24990
|
+
echo "[features]" >&2
|
|
24991
|
+
echo "plugin_hooks = true" >&2
|
|
24992
|
+
echo "Then restart or refresh Codex before relying on plugin startup hooks." >&2
|
|
24993
|
+
echo "Set PLUXX_CODEX_ENABLE_PLUGIN_HOOKS=1 before running this installer to enable it noninteractively." >&2
|
|
24994
|
+
fi
|
|
24995
|
+
fi
|
|
24996
|
+
fi
|
|
24997
|
+
`;
|
|
24998
|
+
}
|
|
24684
24999
|
function renderInstallClaudeCodeScript(config) {
|
|
24685
25000
|
return `#!/usr/bin/env bash
|
|
24686
25001
|
set -euo pipefail
|
|
@@ -24742,6 +25057,7 @@ VERSION="$(grep -E '"version"' "$PLUGIN_MANIFEST" | head -n1 | sed -E 's/.*"vers
|
|
|
24742
25057
|
DESCRIPTION="$(grep -E '"description"' "$PLUGIN_MANIFEST" | head -n1 | sed -E 's/.*"description"[[:space:]]*:[[:space:]]*"([^"]+)".*/\\1/')"
|
|
24743
25058
|
|
|
24744
25059
|
mkdir -p "$INSTALL_ROOT/.claude-plugin" "$INSTALL_ROOT/plugins"
|
|
25060
|
+
${renderInstallerSavedUserConfigCaptureSnippet(config, "claude-code", "$INSTALL_ROOT/plugins/$PLUGIN_NAME")}
|
|
24745
25061
|
rm -rf "$INSTALL_ROOT/plugins/$PLUGIN_NAME"
|
|
24746
25062
|
cp -R "$BUNDLE_DIR" "$INSTALL_ROOT/plugins/$PLUGIN_NAME"
|
|
24747
25063
|
${renderInstallerUserConfigSnippet(config, "claude-code", "$INSTALL_ROOT/plugins/$PLUGIN_NAME")}
|
|
@@ -24837,6 +25153,7 @@ if [[ ! -f "$PLUGIN_MANIFEST" ]]; then
|
|
|
24837
25153
|
fi
|
|
24838
25154
|
|
|
24839
25155
|
mkdir -p "$(dirname "$INSTALL_DIR")"
|
|
25156
|
+
${renderInstallerSavedUserConfigCaptureSnippet(config, "cursor", "$INSTALL_DIR")}
|
|
24840
25157
|
rm -rf "$INSTALL_DIR"
|
|
24841
25158
|
cp -R "$BUNDLE_DIR" "$INSTALL_DIR"
|
|
24842
25159
|
${renderInstallerUserConfigSnippet(config, "cursor", "$INSTALL_DIR")}
|
|
@@ -24897,11 +25214,13 @@ if [[ ! -f "$PLUGIN_MANIFEST" ]]; then
|
|
|
24897
25214
|
fi
|
|
24898
25215
|
|
|
24899
25216
|
mkdir -p "$(dirname "$INSTALL_DIR")"
|
|
25217
|
+
${renderInstallerSavedUserConfigCaptureSnippet(config, "codex", "$INSTALL_DIR")}
|
|
24900
25218
|
rm -rf "$INSTALL_DIR"
|
|
24901
25219
|
cp -R "$BUNDLE_DIR" "$INSTALL_DIR"
|
|
24902
25220
|
${renderInstallerUserConfigSnippet(config, "codex", "$INSTALL_DIR")}
|
|
24903
25221
|
${renderInstallerMcpPathMaterializationSnippet("codex", "$INSTALL_DIR")}
|
|
24904
25222
|
${renderInstallerRuntimeBootstrapSnippet("$INSTALL_DIR")}
|
|
25223
|
+
${renderInstallerCodexPluginHooksSnippet("$INSTALL_DIR")}
|
|
24905
25224
|
|
|
24906
25225
|
mkdir -p "$(dirname "$MARKETPLACE_PATH")"
|
|
24907
25226
|
|
|
@@ -25014,6 +25333,7 @@ if [[ ! -f "$PLUGIN_PACKAGE" ]]; then
|
|
|
25014
25333
|
fi
|
|
25015
25334
|
|
|
25016
25335
|
mkdir -p "$(dirname "$INSTALL_DIR")" "$SKILLS_ROOT"
|
|
25336
|
+
${renderInstallerSavedUserConfigCaptureSnippet(config, "opencode", "$INSTALL_DIR")}
|
|
25017
25337
|
rm -rf "$INSTALL_DIR"
|
|
25018
25338
|
cp -R "$BUNDLE_DIR" "$INSTALL_DIR"
|
|
25019
25339
|
${renderInstallerUserConfigSnippet(config, "opencode", "$INSTALL_DIR")}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"publish.d.ts","sourceRoot":"","sources":["../../src/cli/publish.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,WAAW,CAAA;AAI7D,KAAK,cAAc,GAAG,KAAK,GAAG,gBAAgB,CAAA;AAC9C,KAAK,gBAAgB,GAAG,SAAS,GAAG,WAAW,GAAG,UAAU,GAAG,UAAU,CAAA;AACzE,KAAK,qBAAqB,GAAG,WAAW,GAAG,QAAQ,CAAA;AAEnD,UAAU,aAAa;IACrB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;IACrB,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;CACf;AAED,KAAK,aAAa,GAAG,CACnB,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EAAE,EACd,OAAO,CAAC,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,KACvB,aAAa,CAAA;AAElB,MAAM,WAAW,kBAAkB;IACjC,iBAAiB,CAAC,EAAE,cAAc,EAAE,CAAA;IACpC,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,UAAU,CAAC,EAAE,aAAa,CAAA;CAC3B;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,gBAAgB,CAAA;IACtB,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,CAAC,EAAE,cAAc,CAAA;IACzB,OAAO,CAAC,EAAE,qBAAqB,CAAA;CAChC;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAA;IACZ,EAAE,EAAE,OAAO,CAAA;IACX,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,SAAS,CAAA;IAClB,MAAM,EAAE,OAAO,CAAA;IACf,OAAO,EAAE,MAAM,CAAA;IACf,GAAG,EAAE,MAAM,CAAA;IACX,QAAQ,EAAE;QACR,GAAG,EAAE;YACH,OAAO,EAAE,OAAO,CAAA;YAChB,QAAQ,EAAE,OAAO,CAAA;YACjB,WAAW,CAAC,EAAE,MAAM,CAAA;YACpB,UAAU,CAAC,EAAE,MAAM,CAAA;YACnB,YAAY,EAAE,OAAO,CAAA;SACtB,CAAA;QACD,aAAa,EAAE;YACb,OAAO,EAAE,OAAO,CAAA;YAChB,QAAQ,EAAE,OAAO,CAAA;YACjB,IAAI,CAAC,EAAE,MAAM,CAAA;YACb,UAAU,CAAC,EAAE,MAAM,CAAA;YACnB,kBAAkB,EAAE,OAAO,CAAA;YAC3B,MAAM,EAAE,gBAAgB,EAAE,CAAA;SAC3B,CAAA;KACF,CAAA;IACD,MAAM,EAAE,YAAY,EAAE,CAAA;CACvB;AAED,MAAM,WAAW,gBAAiB,SAAQ,WAAW;IACnD,EAAE,EAAE,OAAO,CAAA;IACX,SAAS,CAAC,EAAE;QACV,GAAG,CAAC,EAAE;YAAE,EAAE,EAAE,OAAO,CAAC;YAAC,MAAM,CAAC,EAAE,MAAM,CAAA;SAAE,CAAA;QACtC,aAAa,CAAC,EAAE;YAAE,EAAE,EAAE,OAAO,CAAC;YAAC,MAAM,CAAC,EAAE,MAAM,CAAA;SAAE,CAAA;KACjD,CAAA;CACF;AAwPD,wBAAgB,WAAW,CAAC,MAAM,EAAE,YAAY,EAAE,OAAO,GAAE,kBAAuB,GAAG,WAAW,CAmD/F;
|
|
1
|
+
{"version":3,"file":"publish.d.ts","sourceRoot":"","sources":["../../src/cli/publish.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -9449,17 +9449,18 @@ function renderInstallerUserConfigSnippet(config, platform, installDirVariable)
|
|
|
9449
9449
|
if (entries.length === 0) return "";
|
|
9450
9450
|
const promptLines = entries.map((entry) => {
|
|
9451
9451
|
const functionName = entry.type === "secret" ? "pluxx_prompt_secret_config" : "pluxx_prompt_text_config";
|
|
9452
|
-
return `${functionName} ${JSON.stringify(entry.envVar)} ${JSON.stringify(entry.title)} ${entry.required ? "1" : "0"}`;
|
|
9452
|
+
return `${functionName} ${JSON.stringify(entry.key)} ${JSON.stringify(entry.envVar)} ${JSON.stringify(entry.title)} ${entry.required ? "1" : "0"}`;
|
|
9453
9453
|
});
|
|
9454
9454
|
return `
|
|
9455
9455
|
PLUXX_USER_CONFIG_SPEC="$(cat <<'PLUXX_USER_CONFIG_JSON'
|
|
9456
9456
|
${JSON.stringify(entries)}
|
|
9457
9457
|
PLUXX_USER_CONFIG_JSON
|
|
9458
9458
|
)"
|
|
9459
|
+
PLUXX_REUSED_USER_CONFIG=0
|
|
9459
9460
|
|
|
9460
9461
|
pluxx_is_placeholder_secret() {
|
|
9461
9462
|
case "$1" in
|
|
9462
|
-
*dummy*|*Dummy*|*DUMMY*|*placeholder*|*Placeholder*|*PLACEHOLDER*|*changeme*|*CHANGE_ME*|*replace*me*|*Replace*Me*|*your*key*|*YOUR*KEY*|*api*key*here*|*API*KEY*HERE*|*token*here*|*TOKEN*HERE*)
|
|
9463
|
+
*dummy*|*Dummy*|*DUMMY*|*placeholder*|*Placeholder*|*PLACEHOLDER*|*example*|*Example*|*EXAMPLE*|*changeme*|*CHANGE_ME*|*replace*me*|*Replace*Me*|*your*key*|*YOUR*KEY*|*api*key*here*|*API*KEY*HERE*|*token*here*|*TOKEN*HERE*)
|
|
9463
9464
|
return 0
|
|
9464
9465
|
;;
|
|
9465
9466
|
*)
|
|
@@ -9468,12 +9469,61 @@ pluxx_is_placeholder_secret() {
|
|
|
9468
9469
|
esac
|
|
9469
9470
|
}
|
|
9470
9471
|
|
|
9472
|
+
pluxx_saved_config_value() {
|
|
9473
|
+
local key="$1"
|
|
9474
|
+
local env_var="$2"
|
|
9475
|
+
|
|
9476
|
+
if [[ -z "\${PLUXX_SAVED_USER_CONFIG_PATH:-}" || ! -f "$PLUXX_SAVED_USER_CONFIG_PATH" ]]; then
|
|
9477
|
+
return 1
|
|
9478
|
+
fi
|
|
9479
|
+
|
|
9480
|
+
PLUXX_SAVED_CONFIG_KEY="$key" PLUXX_SAVED_CONFIG_ENV_VAR="$env_var" node <<'NODE'
|
|
9481
|
+
const fs = require('fs')
|
|
9482
|
+
|
|
9483
|
+
const filepath = process.env.PLUXX_SAVED_USER_CONFIG_PATH
|
|
9484
|
+
const key = process.env.PLUXX_SAVED_CONFIG_KEY
|
|
9485
|
+
const envVar = process.env.PLUXX_SAVED_CONFIG_ENV_VAR
|
|
9486
|
+
|
|
9487
|
+
try {
|
|
9488
|
+
const payload = JSON.parse(fs.readFileSync(filepath, 'utf8'))
|
|
9489
|
+
const candidates = [
|
|
9490
|
+
payload && payload.env && envVar ? payload.env[envVar] : undefined,
|
|
9491
|
+
payload && payload.values && key ? payload.values[key] : undefined,
|
|
9492
|
+
]
|
|
9493
|
+
|
|
9494
|
+
for (const candidate of candidates) {
|
|
9495
|
+
if (candidate === undefined || candidate === null) continue
|
|
9496
|
+
if (!['string', 'number', 'boolean'].includes(typeof candidate)) continue
|
|
9497
|
+
const value = String(candidate)
|
|
9498
|
+
if (value === '') continue
|
|
9499
|
+
process.stdout.write(value)
|
|
9500
|
+
process.exit(0)
|
|
9501
|
+
}
|
|
9502
|
+
} catch {}
|
|
9503
|
+
|
|
9504
|
+
process.exit(1)
|
|
9505
|
+
NODE
|
|
9506
|
+
}
|
|
9507
|
+
|
|
9471
9508
|
pluxx_prompt_secret_config() {
|
|
9472
|
-
local
|
|
9473
|
-
local
|
|
9474
|
-
local
|
|
9509
|
+
local key="$1"
|
|
9510
|
+
local env_var="$2"
|
|
9511
|
+
local label="$3"
|
|
9512
|
+
local required="$4"
|
|
9475
9513
|
local current_value="\${!env_var:-}"
|
|
9476
9514
|
|
|
9515
|
+
if [[ -z "$current_value" && "\${PLUXX_RECONFIGURE:-0}" != "1" ]]; then
|
|
9516
|
+
local saved_value=""
|
|
9517
|
+
if saved_value="$(pluxx_saved_config_value "$key" "$env_var")"; then
|
|
9518
|
+
if pluxx_is_placeholder_secret "$saved_value"; then
|
|
9519
|
+
echo "Ignoring placeholder-looking saved config for $env_var." >&2
|
|
9520
|
+
else
|
|
9521
|
+
current_value="$saved_value"
|
|
9522
|
+
PLUXX_REUSED_USER_CONFIG=1
|
|
9523
|
+
fi
|
|
9524
|
+
fi
|
|
9525
|
+
fi
|
|
9526
|
+
|
|
9477
9527
|
if [[ -z "$current_value" && "$required" == "1" ]]; then
|
|
9478
9528
|
if [[ -t 0 || -r /dev/tty ]]; then
|
|
9479
9529
|
read -r -s -p "$label [$env_var]: " current_value </dev/tty
|
|
@@ -9493,11 +9543,20 @@ pluxx_prompt_secret_config() {
|
|
|
9493
9543
|
}
|
|
9494
9544
|
|
|
9495
9545
|
pluxx_prompt_text_config() {
|
|
9496
|
-
local
|
|
9497
|
-
local
|
|
9498
|
-
local
|
|
9546
|
+
local key="$1"
|
|
9547
|
+
local env_var="$2"
|
|
9548
|
+
local label="$3"
|
|
9549
|
+
local required="$4"
|
|
9499
9550
|
local current_value="\${!env_var:-}"
|
|
9500
9551
|
|
|
9552
|
+
if [[ -z "$current_value" && "\${PLUXX_RECONFIGURE:-0}" != "1" ]]; then
|
|
9553
|
+
local saved_value=""
|
|
9554
|
+
if saved_value="$(pluxx_saved_config_value "$key" "$env_var")"; then
|
|
9555
|
+
current_value="$saved_value"
|
|
9556
|
+
PLUXX_REUSED_USER_CONFIG=1
|
|
9557
|
+
fi
|
|
9558
|
+
fi
|
|
9559
|
+
|
|
9501
9560
|
if [[ -z "$current_value" && "$required" == "1" ]]; then
|
|
9502
9561
|
if [[ -t 0 || -r /dev/tty ]]; then
|
|
9503
9562
|
read -r -p "$label [$env_var]: " current_value </dev/tty
|
|
@@ -9512,6 +9571,10 @@ pluxx_prompt_text_config() {
|
|
|
9512
9571
|
|
|
9513
9572
|
${promptLines.join("\n")}
|
|
9514
9573
|
|
|
9574
|
+
if [[ "$PLUXX_REUSED_USER_CONFIG" == "1" ]]; then
|
|
9575
|
+
echo "Found existing plugin config; reusing saved install values."
|
|
9576
|
+
fi
|
|
9577
|
+
|
|
9515
9578
|
export PLUXX_USER_CONFIG_SPEC
|
|
9516
9579
|
export PLUXX_INSTALL_DIR="${installDirVariable}"
|
|
9517
9580
|
|
|
@@ -9607,6 +9670,17 @@ NODE
|
|
|
9607
9670
|
function hasInstallerUserConfig(config, platform) {
|
|
9608
9671
|
return collectUserConfigEntries(config, [platform]).length > 0;
|
|
9609
9672
|
}
|
|
9673
|
+
function renderInstallerSavedUserConfigCaptureSnippet(config, platform, installDirVariable) {
|
|
9674
|
+
if (!hasInstallerUserConfig(config, platform)) return "";
|
|
9675
|
+
return `
|
|
9676
|
+
PLUXX_SAVED_USER_CONFIG_PATH=""
|
|
9677
|
+
if [[ "\${PLUXX_RECONFIGURE:-0}" != "1" && -f "${installDirVariable}/.pluxx-user.json" ]]; then
|
|
9678
|
+
PLUXX_SAVED_USER_CONFIG_PATH="$TMP_DIR/pluxx-saved-user-config.json"
|
|
9679
|
+
cp "${installDirVariable}/.pluxx-user.json" "$PLUXX_SAVED_USER_CONFIG_PATH"
|
|
9680
|
+
fi
|
|
9681
|
+
export PLUXX_SAVED_USER_CONFIG_PATH
|
|
9682
|
+
`;
|
|
9683
|
+
}
|
|
9610
9684
|
function renderInstallerMcpPathMaterializationSnippet(platform, installDirVariable) {
|
|
9611
9685
|
if (platform !== "codex") return "";
|
|
9612
9686
|
return `
|
|
@@ -9675,6 +9749,247 @@ if [[ -f "${installDirVariable}/scripts/bootstrap-runtime.sh" ]]; then
|
|
|
9675
9749
|
fi
|
|
9676
9750
|
`;
|
|
9677
9751
|
}
|
|
9752
|
+
function renderInstallerCodexPluginHooksSnippet(installDirVariable) {
|
|
9753
|
+
return `
|
|
9754
|
+
export PLUXX_INSTALL_DIR="${installDirVariable}"
|
|
9755
|
+
|
|
9756
|
+
set +e
|
|
9757
|
+
node <<'NODE'
|
|
9758
|
+
const fs = require('fs')
|
|
9759
|
+
const path = require('path')
|
|
9760
|
+
|
|
9761
|
+
const installDir = process.env.PLUXX_INSTALL_DIR
|
|
9762
|
+
if (!installDir) process.exit(0)
|
|
9763
|
+
|
|
9764
|
+
const manifestPath = path.join(installDir, '.codex-plugin/plugin.json')
|
|
9765
|
+
const standardHooksPath = path.join(installDir, 'hooks/hooks.json')
|
|
9766
|
+
let hasPluginHooks = fs.existsSync(standardHooksPath)
|
|
9767
|
+
|
|
9768
|
+
if (fs.existsSync(manifestPath)) {
|
|
9769
|
+
try {
|
|
9770
|
+
const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8'))
|
|
9771
|
+
const manifestHooks = manifest.hooks
|
|
9772
|
+
hasPluginHooks ||= typeof manifestHooks === 'string' && manifestHooks.trim().length > 0
|
|
9773
|
+
hasPluginHooks ||= Array.isArray(manifestHooks) && manifestHooks.length > 0
|
|
9774
|
+
hasPluginHooks ||= manifestHooks && typeof manifestHooks === 'object' && Object.keys(manifestHooks).length > 0
|
|
9775
|
+
hasPluginHooks ||= manifestHooks === true
|
|
9776
|
+
} catch {}
|
|
9777
|
+
}
|
|
9778
|
+
|
|
9779
|
+
process.exit(hasPluginHooks ? 0 : 2)
|
|
9780
|
+
NODE
|
|
9781
|
+
PLUXX_CODEX_BUNDLE_HAS_HOOKS="$?"
|
|
9782
|
+
set -e
|
|
9783
|
+
|
|
9784
|
+
if [[ "$PLUXX_CODEX_BUNDLE_HAS_HOOKS" == "0" ]]; then
|
|
9785
|
+
CODEX_HOME_DIR="\${CODEX_HOME:-$HOME/.codex}"
|
|
9786
|
+
CODEX_CONFIG_PATH="\${PLUXX_CODEX_CONFIG_PATH:-$CODEX_HOME_DIR/config.toml}"
|
|
9787
|
+
PLUXX_CODEX_HOOKS_MODE="\${PLUXX_CODEX_ENABLE_PLUGIN_HOOKS:-prompt}"
|
|
9788
|
+
|
|
9789
|
+
export CODEX_CONFIG_PATH
|
|
9790
|
+
if node <<'NODE'
|
|
9791
|
+
const fs = require('fs')
|
|
9792
|
+
const filepath = process.env.CODEX_CONFIG_PATH
|
|
9793
|
+
|
|
9794
|
+
function stripTomlComment(line) {
|
|
9795
|
+
let quote = null
|
|
9796
|
+
let escaped = false
|
|
9797
|
+
for (let index = 0; index < line.length; index += 1) {
|
|
9798
|
+
const char = line[index]
|
|
9799
|
+
if (escaped) {
|
|
9800
|
+
escaped = false
|
|
9801
|
+
continue
|
|
9802
|
+
}
|
|
9803
|
+
if (quote && char === '\\\\') {
|
|
9804
|
+
escaped = true
|
|
9805
|
+
continue
|
|
9806
|
+
}
|
|
9807
|
+
if (char === '"' || char === "'") {
|
|
9808
|
+
quote = quote === char ? null : quote || char
|
|
9809
|
+
continue
|
|
9810
|
+
}
|
|
9811
|
+
if (!quote && char === '#') return line.slice(0, index)
|
|
9812
|
+
}
|
|
9813
|
+
return line
|
|
9814
|
+
}
|
|
9815
|
+
|
|
9816
|
+
function isTomlTrue(rawValue) {
|
|
9817
|
+
return /^true\\b/i.test(rawValue.trim())
|
|
9818
|
+
}
|
|
9819
|
+
|
|
9820
|
+
let text = ''
|
|
9821
|
+
try {
|
|
9822
|
+
text = fs.readFileSync(filepath, 'utf8')
|
|
9823
|
+
} catch {
|
|
9824
|
+
process.exit(1)
|
|
9825
|
+
}
|
|
9826
|
+
const lines = text.split(/\\r?\\n/)
|
|
9827
|
+
let tableName = ''
|
|
9828
|
+
for (const line of lines) {
|
|
9829
|
+
const trimmed = stripTomlComment(line).trim()
|
|
9830
|
+
if (!trimmed) continue
|
|
9831
|
+
const tableMatch = trimmed.match(/^\\[([^\\]]+)\\]$/)
|
|
9832
|
+
if (tableMatch) {
|
|
9833
|
+
tableName = tableMatch[1].trim()
|
|
9834
|
+
continue
|
|
9835
|
+
}
|
|
9836
|
+
if (tableName === '') {
|
|
9837
|
+
const dottedMatch = trimmed.match(/^features\\.plugin_hooks\\s*=\\s*(.+)$/)
|
|
9838
|
+
if (dottedMatch && isTomlTrue(dottedMatch[1])) process.exit(0)
|
|
9839
|
+
const inlineMatch = trimmed.match(/^features\\s*=\\s*(.+)$/)
|
|
9840
|
+
if (inlineMatch && /\\bplugin_hooks\\s*=\\s*true\\b/i.test(inlineMatch[1])) process.exit(0)
|
|
9841
|
+
}
|
|
9842
|
+
if (tableName !== 'features') continue
|
|
9843
|
+
const match = trimmed.match(/^plugin_hooks\\s*=\\s*(.+)$/)
|
|
9844
|
+
if (match && isTomlTrue(match[1])) process.exit(0)
|
|
9845
|
+
}
|
|
9846
|
+
process.exit(1)
|
|
9847
|
+
NODE
|
|
9848
|
+
then
|
|
9849
|
+
echo "Codex plugin-bundled hooks already enabled in $CODEX_CONFIG_PATH."
|
|
9850
|
+
else
|
|
9851
|
+
PLUXX_ENABLE_CODEX_HOOKS="0"
|
|
9852
|
+
case "$PLUXX_CODEX_HOOKS_MODE" in
|
|
9853
|
+
1|true|TRUE|yes|YES|always|ALWAYS)
|
|
9854
|
+
PLUXX_ENABLE_CODEX_HOOKS="1"
|
|
9855
|
+
;;
|
|
9856
|
+
0|false|FALSE|no|NO|never|NEVER|skip|SKIP)
|
|
9857
|
+
PLUXX_ENABLE_CODEX_HOOKS="0"
|
|
9858
|
+
;;
|
|
9859
|
+
*)
|
|
9860
|
+
if [[ -r /dev/tty ]]; then
|
|
9861
|
+
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
|
|
9863
|
+
read -r -p "Enable Codex plugin-bundled hooks in $CODEX_CONFIG_PATH now? [Y/n] " PLUXX_CODEX_HOOKS_REPLY </dev/tty
|
|
9864
|
+
case "$PLUXX_CODEX_HOOKS_REPLY" in
|
|
9865
|
+
n|N|no|NO)
|
|
9866
|
+
PLUXX_ENABLE_CODEX_HOOKS="0"
|
|
9867
|
+
;;
|
|
9868
|
+
*)
|
|
9869
|
+
PLUXX_ENABLE_CODEX_HOOKS="1"
|
|
9870
|
+
;;
|
|
9871
|
+
esac
|
|
9872
|
+
fi
|
|
9873
|
+
;;
|
|
9874
|
+
esac
|
|
9875
|
+
|
|
9876
|
+
if [[ "$PLUXX_ENABLE_CODEX_HOOKS" == "1" ]]; then
|
|
9877
|
+
mkdir -p "$(dirname "$CODEX_CONFIG_PATH")"
|
|
9878
|
+
node <<'NODE'
|
|
9879
|
+
const fs = require('fs')
|
|
9880
|
+
const path = require('path')
|
|
9881
|
+
|
|
9882
|
+
const filepath = process.env.CODEX_CONFIG_PATH
|
|
9883
|
+
|
|
9884
|
+
function stripTomlComment(line) {
|
|
9885
|
+
let quote = null
|
|
9886
|
+
let escaped = false
|
|
9887
|
+
for (let index = 0; index < line.length; index += 1) {
|
|
9888
|
+
const char = line[index]
|
|
9889
|
+
if (escaped) {
|
|
9890
|
+
escaped = false
|
|
9891
|
+
continue
|
|
9892
|
+
}
|
|
9893
|
+
if (quote && char === '\\\\') {
|
|
9894
|
+
escaped = true
|
|
9895
|
+
continue
|
|
9896
|
+
}
|
|
9897
|
+
if (char === '"' || char === "'") {
|
|
9898
|
+
quote = quote === char ? null : quote || char
|
|
9899
|
+
continue
|
|
9900
|
+
}
|
|
9901
|
+
if (!quote && char === '#') return line.slice(0, index)
|
|
9902
|
+
}
|
|
9903
|
+
return line
|
|
9904
|
+
}
|
|
9905
|
+
|
|
9906
|
+
let text = ''
|
|
9907
|
+
try {
|
|
9908
|
+
text = fs.readFileSync(filepath, 'utf8')
|
|
9909
|
+
} catch {}
|
|
9910
|
+
|
|
9911
|
+
const lines = text.split(/\\r?\\n/)
|
|
9912
|
+
if (lines.length === 1 && lines[0] === '') lines.pop()
|
|
9913
|
+
|
|
9914
|
+
let start = -1
|
|
9915
|
+
let end = lines.length
|
|
9916
|
+
let firstTopLevelFeaturesDotted = -1
|
|
9917
|
+
let topLevelPluginHooksDotted = -1
|
|
9918
|
+
let topLevelInlineFeatures = -1
|
|
9919
|
+
let tableName = ''
|
|
9920
|
+
for (let index = 0; index < lines.length; index += 1) {
|
|
9921
|
+
const trimmed = stripTomlComment(lines[index]).trim()
|
|
9922
|
+
const tableMatch = trimmed.match(/^\\[([^\\]]+)\\]$/)
|
|
9923
|
+
if (tableMatch) tableName = tableMatch[1].trim()
|
|
9924
|
+
|
|
9925
|
+
if (trimmed === '[features]') {
|
|
9926
|
+
start = index
|
|
9927
|
+
break
|
|
9928
|
+
}
|
|
9929
|
+
|
|
9930
|
+
if (tableName === '') {
|
|
9931
|
+
if (/^features\\.[A-Za-z0-9_-]+\\s*=/.test(trimmed) && firstTopLevelFeaturesDotted < 0) {
|
|
9932
|
+
firstTopLevelFeaturesDotted = index
|
|
9933
|
+
}
|
|
9934
|
+
if (/^features\\.plugin_hooks\\s*=/.test(trimmed)) {
|
|
9935
|
+
topLevelPluginHooksDotted = index
|
|
9936
|
+
}
|
|
9937
|
+
if (/^features\\s*=\\s*\\{/.test(trimmed)) {
|
|
9938
|
+
topLevelInlineFeatures = index
|
|
9939
|
+
}
|
|
9940
|
+
}
|
|
9941
|
+
}
|
|
9942
|
+
|
|
9943
|
+
if (start >= 0) {
|
|
9944
|
+
for (let index = start + 1; index < lines.length; index += 1) {
|
|
9945
|
+
if (/^\\s*\\[[^\\]]+\\]/.test(stripTomlComment(lines[index]))) {
|
|
9946
|
+
end = index
|
|
9947
|
+
break
|
|
9948
|
+
}
|
|
9949
|
+
}
|
|
9950
|
+
|
|
9951
|
+
let updated = false
|
|
9952
|
+
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'
|
|
9955
|
+
updated = true
|
|
9956
|
+
}
|
|
9957
|
+
}
|
|
9958
|
+
if (!updated) lines.splice(start + 1, 0, 'plugin_hooks = true')
|
|
9959
|
+
} else if (topLevelPluginHooksDotted >= 0) {
|
|
9960
|
+
lines[topLevelPluginHooksDotted] = 'features.plugin_hooks = true'
|
|
9961
|
+
} else if (firstTopLevelFeaturesDotted >= 0) {
|
|
9962
|
+
lines.splice(firstTopLevelFeaturesDotted + 1, 0, 'features.plugin_hooks = true')
|
|
9963
|
+
} else if (topLevelInlineFeatures >= 0 && lines[topLevelInlineFeatures].includes('}')) {
|
|
9964
|
+
if (/\\bplugin_hooks\\s*=/.test(lines[topLevelInlineFeatures])) {
|
|
9965
|
+
lines[topLevelInlineFeatures] = lines[topLevelInlineFeatures].replace(
|
|
9966
|
+
/\\bplugin_hooks\\s*=\\s*(true|false)\\b/i,
|
|
9967
|
+
'plugin_hooks = true',
|
|
9968
|
+
)
|
|
9969
|
+
} else {
|
|
9970
|
+
lines[topLevelInlineFeatures] = lines[topLevelInlineFeatures].replace(/}/, ', plugin_hooks = true }')
|
|
9971
|
+
}
|
|
9972
|
+
} else {
|
|
9973
|
+
if (lines.length > 0 && lines[lines.length - 1] !== '') lines.push('')
|
|
9974
|
+
lines.push('[features]', 'plugin_hooks = true')
|
|
9975
|
+
}
|
|
9976
|
+
|
|
9977
|
+
fs.mkdirSync(path.dirname(filepath), { recursive: true })
|
|
9978
|
+
fs.writeFileSync(filepath, lines.join('\\n') + '\\n')
|
|
9979
|
+
NODE
|
|
9980
|
+
echo "Enabled Codex plugin-bundled hooks in $CODEX_CONFIG_PATH."
|
|
9981
|
+
echo "Restart or refresh Codex before relying on plugin startup hooks."
|
|
9982
|
+
else
|
|
9983
|
+
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
|
+
echo "[features]" >&2
|
|
9985
|
+
echo "plugin_hooks = true" >&2
|
|
9986
|
+
echo "Then restart or refresh Codex before relying on plugin startup hooks." >&2
|
|
9987
|
+
echo "Set PLUXX_CODEX_ENABLE_PLUGIN_HOOKS=1 before running this installer to enable it noninteractively." >&2
|
|
9988
|
+
fi
|
|
9989
|
+
fi
|
|
9990
|
+
fi
|
|
9991
|
+
`;
|
|
9992
|
+
}
|
|
9678
9993
|
function renderInstallClaudeCodeScript(config) {
|
|
9679
9994
|
return `#!/usr/bin/env bash
|
|
9680
9995
|
set -euo pipefail
|
|
@@ -9736,6 +10051,7 @@ VERSION="$(grep -E '"version"' "$PLUGIN_MANIFEST" | head -n1 | sed -E 's/.*"vers
|
|
|
9736
10051
|
DESCRIPTION="$(grep -E '"description"' "$PLUGIN_MANIFEST" | head -n1 | sed -E 's/.*"description"[[:space:]]*:[[:space:]]*"([^"]+)".*/\\1/')"
|
|
9737
10052
|
|
|
9738
10053
|
mkdir -p "$INSTALL_ROOT/.claude-plugin" "$INSTALL_ROOT/plugins"
|
|
10054
|
+
${renderInstallerSavedUserConfigCaptureSnippet(config, "claude-code", "$INSTALL_ROOT/plugins/$PLUGIN_NAME")}
|
|
9739
10055
|
rm -rf "$INSTALL_ROOT/plugins/$PLUGIN_NAME"
|
|
9740
10056
|
cp -R "$BUNDLE_DIR" "$INSTALL_ROOT/plugins/$PLUGIN_NAME"
|
|
9741
10057
|
${renderInstallerUserConfigSnippet(config, "claude-code", "$INSTALL_ROOT/plugins/$PLUGIN_NAME")}
|
|
@@ -9831,6 +10147,7 @@ if [[ ! -f "$PLUGIN_MANIFEST" ]]; then
|
|
|
9831
10147
|
fi
|
|
9832
10148
|
|
|
9833
10149
|
mkdir -p "$(dirname "$INSTALL_DIR")"
|
|
10150
|
+
${renderInstallerSavedUserConfigCaptureSnippet(config, "cursor", "$INSTALL_DIR")}
|
|
9834
10151
|
rm -rf "$INSTALL_DIR"
|
|
9835
10152
|
cp -R "$BUNDLE_DIR" "$INSTALL_DIR"
|
|
9836
10153
|
${renderInstallerUserConfigSnippet(config, "cursor", "$INSTALL_DIR")}
|
|
@@ -9891,11 +10208,13 @@ if [[ ! -f "$PLUGIN_MANIFEST" ]]; then
|
|
|
9891
10208
|
fi
|
|
9892
10209
|
|
|
9893
10210
|
mkdir -p "$(dirname "$INSTALL_DIR")"
|
|
10211
|
+
${renderInstallerSavedUserConfigCaptureSnippet(config, "codex", "$INSTALL_DIR")}
|
|
9894
10212
|
rm -rf "$INSTALL_DIR"
|
|
9895
10213
|
cp -R "$BUNDLE_DIR" "$INSTALL_DIR"
|
|
9896
10214
|
${renderInstallerUserConfigSnippet(config, "codex", "$INSTALL_DIR")}
|
|
9897
10215
|
${renderInstallerMcpPathMaterializationSnippet("codex", "$INSTALL_DIR")}
|
|
9898
10216
|
${renderInstallerRuntimeBootstrapSnippet("$INSTALL_DIR")}
|
|
10217
|
+
${renderInstallerCodexPluginHooksSnippet("$INSTALL_DIR")}
|
|
9899
10218
|
|
|
9900
10219
|
mkdir -p "$(dirname "$MARKETPLACE_PATH")"
|
|
9901
10220
|
|
|
@@ -10008,6 +10327,7 @@ if [[ ! -f "$PLUGIN_PACKAGE" ]]; then
|
|
|
10008
10327
|
fi
|
|
10009
10328
|
|
|
10010
10329
|
mkdir -p "$(dirname "$INSTALL_DIR")" "$SKILLS_ROOT"
|
|
10330
|
+
${renderInstallerSavedUserConfigCaptureSnippet(config, "opencode", "$INSTALL_DIR")}
|
|
10011
10331
|
rm -rf "$INSTALL_DIR"
|
|
10012
10332
|
cp -R "$BUNDLE_DIR" "$INSTALL_DIR"
|
|
10013
10333
|
${renderInstallerUserConfigSnippet(config, "opencode", "$INSTALL_DIR")}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@orchid-labs/pluxx",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.20",
|
|
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",
|