Skip to content

Commit d9647e0

Browse files
committed
Move bin/ scripts to scripts/ so the plugin installs on claude.ai
claude.ai-hosted plugins may not ship a top-level bin/ directory: its contents are added to PATH on the CLI but are not shown on the admin approval surface, so the platform rejects the plugin at install time (both repository-add and file upload). This blocked all claude.ai web and Cowork users from installing fusion-skills (issue #17); foundry-skills installs fine because it has no bin/. These are not executable entry points. They are internal helpers (the Python venv-bootstrap chain: python.sh, python-detect.sh, setup-python-venv.sh) and repo dev tooling (cleanup_workflows.py, convert_catalog_to_yaml.py, export-trigger-yaml.sh), invoked by the skills and test harness rather than run as commands. bin/ is the only trigger, so the fix is relocation, not declaring them as commands or hooks. They move to a top-level scripts/ directory (shared across all four sub-skills, so not owned by any one skill's scripts/ dir), and every reference is updated: the four SKILL.md allowed-tools declarations and example commands, _bootstrap.py's wrapper path, hooks/bootstrap.sh, run-ab-test.sh, verify-workflows.sh, the test suite and conftest sys.path, and the CI shellcheck/pylint/pytest-cov globs. Git detects all six as renames. Full local CI passes: 541 tests at 93.65% coverage, pylint 10.00/10, shellcheck clean, hook and scorecard suites green.
1 parent c354974 commit d9647e0

20 files changed

Lines changed: 86 additions & 86 deletions

.github/workflows/main.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ jobs:
1818
run: command -v shellcheck || { sudo apt-get update -qq && sudo apt-get install -y -qq shellcheck; }
1919
- name: Run ShellCheck
2020
run: |
21-
shellcheck hooks/*.sh bin/*.sh
21+
shellcheck hooks/*.sh scripts/*.sh
2222
shellcheck --severity=error *.sh
2323
2424
test-hooks:
@@ -69,7 +69,7 @@ jobs:
6969
--cov=skills/deployment/scripts \
7070
--cov=skills/execution/scripts \
7171
--cov=skills/lookup-files/scripts \
72-
--cov=bin \
72+
--cov=scripts \
7373
--cov-report=term-missing \
7474
--cov-fail-under=90
7575
@@ -95,7 +95,7 @@ jobs:
9595
skills/deployment/scripts/*.py \
9696
skills/execution/scripts/*.py \
9797
skills/lookup-files/scripts/*.py \
98-
bin/*.py
98+
scripts/*.py
9999
100100
validate:
101101
runs-on: ubuntu-latest

common/scripts/_bootstrap.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@
22
33
The skill's Python scripts depend on `crowdstrike-falconpy` (and `pyyaml`). Those
44
live in a managed virtualenv at ``~/.cache/claude-code-fusion/venv``, created by
5-
the plugin's SessionStart hook and used by ``bin/python.sh``. But a script may be
5+
the plugin's SessionStart hook and used by ``scripts/python.sh``. But a script may be
66
launched with a bare ``python script.py`` — for example from a cloned repo in dev
77
mode, where the plugin hook never fired — using an interpreter that has no
88
falconpy installed. That produces a ``ModuleNotFoundError`` at the first API call.
99
1010
``ensure_deps()`` makes the scripts resilient to how they are launched: if the
1111
marker dependency (``falconpy``) is missing from the current interpreter, it
12-
re-executes the script through ``bin/python.sh``, which runs (and, on demand,
12+
re-executes the script through ``scripts/python.sh``, which runs (and, on demand,
1313
builds) the managed venv. If falconpy is already importable — the normal case,
1414
including when already running inside the venv — it does nothing.
1515
@@ -33,13 +33,13 @@
3333

3434

3535
def _python_sh_path():
36-
"""Absolute path to bin/python.sh, resolved relative to this file.
36+
"""Absolute path to scripts/python.sh, resolved relative to this file.
3737
3838
This module lives at ``<repo>/common/scripts/_bootstrap.py``; the wrapper is
39-
at ``<repo>/bin/python.sh``.
39+
at ``<repo>/scripts/python.sh``.
4040
"""
4141
here = os.path.dirname(os.path.abspath(__file__))
42-
return os.path.join(here, "..", "..", "bin", "python.sh")
42+
return os.path.join(here, "..", "..", "scripts", "python.sh")
4343

4444

4545
def ensure_deps(script_path):

hooks/bootstrap.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55

66
PLUGIN_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
77

8-
"$PLUGIN_ROOT/bin/setup-python-venv.sh" >&2 || {
9-
echo "fusion-skills: venv bootstrap did not complete; scripts may need a manual venv setup (bin/setup-python-venv.sh)." >&2
8+
"$PLUGIN_ROOT/scripts/setup-python-venv.sh" >&2 || {
9+
echo "fusion-skills: venv bootstrap did not complete; scripts may need a manual venv setup (scripts/setup-python-venv.sh)." >&2
1010
}
1111

1212
exit 0

run-ab-test.sh

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ find_workflow_file() {
9393

9494
# Clean up deployed Fusion workflows from a phase directory.
9595
#
96-
# Deletes via the Workflows delete API (bin/cleanup_workflows.py, FalconPy
96+
# Deletes via the Workflows delete API (scripts/cleanup_workflows.py, FalconPy
9797
# delete_definitions) — no browser. Collects the workflow names deployed by each
9898
# run in the phase, then deletes them by name. Skipped entirely in --skip-deploy
9999
# mode, where nothing was imported.
@@ -117,9 +117,9 @@ cleanup_phase_workflows() {
117117
return 0
118118
fi
119119

120-
local cleanup_py="$REPO_ROOT/bin/cleanup_workflows.py"
120+
local cleanup_py="$REPO_ROOT/scripts/cleanup_workflows.py"
121121
if [ ! -f "$cleanup_py" ]; then
122-
echo " NOTE: bin/cleanup_workflows.py not found — skipping cleanup."
122+
echo " NOTE: scripts/cleanup_workflows.py not found — skipping cleanup."
123123
echo " Remove these manually in Falcon console → Fusion → Workflows:"
124124
printf ' - %s\n' "${names[@]}"
125125
return 0
File renamed without changes.

0 commit comments

Comments
 (0)