Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 36 additions & 4 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,16 @@ Packaging is the most fragile part of this repo. `storageops_cli.__init__._packa

```bash
make validate # fast skill/extension/doc gates (greps the extension only)
make validate-full # + pytest, extension behavioral tests, size/routing gates
make ci-local # mirror CI validate job (offline; run before PR)
make validate-full # alias for ci-local
make dev # one-shot dev setup (venv, Node, storageops install)
```

`make validate` does not exercise the TypeScript extension — the routing,
provider, and trace logic is only covered by the extension behavioral tests, so
run `make validate-full` (or `make extension-tests`) when touching
`storageops_cli/extensions/storageops.ts`. `package_check.py`, `install-smoke`,
and `diagnosis-smoke` run in CI (wheel build / network) — see `docs/release.md`.
run `make ci-local` (or `make extension-tests`) when touching
`storageops_cli/extensions/storageops.ts`. `make package-check`, `install-smoke`,
and `diagnosis-smoke` need a wheel build or network/model key — see `docs/release.md`.

## Editing Skills

Expand All @@ -50,3 +52,33 @@ Every skill should keep:
- references with `Read when:` guidance.

Use `docs/skill-quality-guide.md` and `docs/skill-taxonomy.md` as the source of truth for quality expectations.

## Cursor Cloud specific instructions

This is a CLI/skill-pack product — there is no long-running server or GUI. "Running
the app" means the `storageops` CLI plus the offline quality gates. Standard
commands live in the `## Validation Commands` section above, `Makefile`, and
`README.md`; the notes below are only the non-obvious cloud gotchas.

- **Console scripts are in `~/.local/bin`.** The update script installs with
`pip install -e '.[dev]'`, which puts `storageops` and `pytest` in
`~/.local/bin`. That dir is added to `PATH` via `~/.bashrc`; if a command says
`storageops: not found`, run `export PATH="$HOME/.local/bin:$PATH"`.
- **Two Node versions exist; the default is too old for Pi.** `node` resolves to
`/exec-daemon/node` (v22.14.0), which is **below** Pi's required 22.19+. To run
`storageops install` or launch Pi, put the nvm Node first:
`export PATH="$HOME/.nvm/versions/node/v22.22.2/bin:$PATH"` (or `nvm use 22`).
The extension tests (`make extension-tests`) use `node --experimental-strip-types`
and work on either Node, so plain `make validate-full` is fine without switching.
- **Pi, httpmon, and skills are already deployed** to `~/.storageops/` (via
`storageops install`, persisted in the snapshot). `storageops doctor` should
report everything `ok` except the API key. If `~/.storageops` is ever missing,
re-run `storageops install` with the nvm Node on `PATH` (needs network for the
npm Pi install).
- **Offline vs. live.** All gates and `make ci-local` / `storageops eval --baselines`
run fully offline and need no key. A **live diagnosis**
(`storageops --print '...'`) and `storageops smoke` require a model provider key
(`ANTHROPIC_API_KEY` / `DEEPSEEK_API_KEY` / `OPENAI_API_KEY`, etc.), which is not
configured in this environment.
- **PR gate.** Run `make ci-local` before opening a PR; it mirrors the CI `validate`
job. Use `make dev` for first-time setup (`scripts/dev_setup.sh`).
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
# Changelog

## Unreleased — Dev ergonomics (ci-local, dev_setup, doctor Node hints)

- **`make ci-local`** mirrors the CI `validate` job offline (provider/contract/coverage
gates, golden-case validation, pytest, extension tests, baseline eval). `make validate-full`
is now an alias.
- **`make dev` / `scripts/dev_setup.sh`** one-shot setup: venv, editable install, Node
>= 22.19 (nvm fallback), `storageops install --force`, and `storageops doctor`.
- **`make package-check`** builds a wheel and runs `package_check.py` locally.
- **`storageops doctor`** suggests an nvm Node `PATH` prefix when the active Node is
< 22.19 (`node_path_hint` in `--json` output).

## 2026-06-21 — v0.7.0: Unify & Complete (major iteration)

A major iteration that closes the last structural gaps rather than adding features.
Expand Down
33 changes: 29 additions & 4 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,19 @@ StorageOps is mostly a skill pack plus a thin installer. Good contributions keep
```bash
git clone https://github.com/hxddh/storageops.git
cd storageops
make dev
```

`make dev` runs `scripts/dev_setup.sh`: creates `.venv`, installs `pip install -e '.[dev]'`,
ensures Node.js >= 22.19 (prefers nvm when the default `node` is too old), runs
`storageops install --force`, and prints `storageops doctor`.

Manual setup (equivalent):

```bash
python3 -m venv .venv
.venv/bin/python -m pip install -e '.[dev]'
storageops install --force
storageops install --force # needs Node >= 22.19 and network for Pi/npm
```

## Common Changes
Expand Down Expand Up @@ -76,7 +86,16 @@ Edit `storageops_cli/__init__.py`. Be careful with:

## Validation

Run these from the repository root:
Run these from the repository root before opening a PR:

```bash
make ci-local # mirrors CI validate job (offline)
make package-check # wheel build + package_check.py (needs network once)
```

`make ci-local` runs skill gates, provider/contract/coverage checks, golden-case
validation, pytest, extension tests, size/routing gates, and baseline eval.
Individual scripts (for targeted debugging):

```bash
python3 scripts/skill_integrity_check.py
Expand All @@ -88,11 +107,17 @@ python3 skills/storageops-eval-golden-cases/scripts/eval_all.py \
--cases skills/storageops-eval-golden-cases/cases \
--outputs skills/storageops-eval-golden-cases/baseline-outputs \
--only-with-outputs
python3 scripts/package_check.py
make validate
.venv/bin/python -m pytest
```

Optional live diagnosis smoke (needs a model provider API key; CI uses
`STORAGEOPS_MODEL_KEY` — see `.github/workflows/ci.yml` `diagnosis-smoke` job):

```bash
storageops configure --provider deepseek --model deepseek-v4-pro --api-key
storageops smoke --provider deepseek --model deepseek-v4-pro
```

## Pull Request Checklist

- The change is scoped and documented.
Expand Down
39 changes: 30 additions & 9 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
.PHONY: help validate validate-full extension-tests test install
.PHONY: help validate validate-full ci-local extension-tests test install dev package-check

help:
@echo "StorageOps — Pi Coding Agent extension + skill pack"
@echo ""
@echo "Usage:"
@echo " make validate Fast skill/extension/doc gates (no tests run)"
@echo " make ci-local Mirror CI validate job (offline; run before PR)"
@echo " make validate-full Alias for ci-local"
@echo " make extension-tests Run the TypeScript extension behavioral tests"
@echo " make validate-full Everything runnable offline: validate + pytest + extension tests + size/routing gates"
@echo " make test Run pytest, extension tests, and validation"
@echo " make install Install thin CLI shim"
@echo " make install Install thin CLI shim (pip install -e .)"
@echo " make dev One-shot dev setup (venv, Node, storageops install)"
@echo " make package-check Build wheel and run package_check.py (needs network once)"
@echo ""
@echo " Note: package_check.py, install-smoke, and diagnosis-smoke run in CI"
@echo " (they need a wheel build / network) — see docs/release.md."
@echo " Note: install-smoke and diagnosis-smoke run in CI only"
@echo " (wheel install / model key) — see docs/release.md."

validate:
@echo "=== Validating skills ==="
Expand All @@ -30,14 +33,23 @@ validate:
extension-tests:
@bash scripts/run_extension_tests.sh

# Everything that can run offline, mirroring the deterministic CI gates. Grepping
# the extension is not enough — the routing/provider/trace logic lives in
# TypeScript and is only covered by extension-tests.
validate-full: validate
# Mirrors .github/workflows/ci.yml validate job (everything offline).
ci-local: validate
python3 scripts/provider_scope_check.py
python3 scripts/contract_check.py
python3 scripts/coverage_check.py
python3 skills/storageops-eval-golden-cases/scripts/golden_case_validator.py \
skills/storageops-eval-golden-cases/cases
python3 -m pytest
$(MAKE) extension-tests
python3 scripts/repo_size_gate.py
python3 scripts/routing_contract_check.py
python3 skills/storageops-eval-golden-cases/scripts/eval_all.py \
--cases skills/storageops-eval-golden-cases/cases \
--outputs skills/storageops-eval-golden-cases/baseline-outputs \
--only-with-outputs

validate-full: ci-local

test:
python3 -m pytest
Expand All @@ -46,3 +58,12 @@ test:

install:
pip install -e .

dev:
@bash scripts/dev_setup.sh

package-check:
python3 -m pip install --upgrade pip build
python3 scripts/prepare_httpmon_vendor.py
python3 -m build --wheel
python3 scripts/package_check.py
10 changes: 6 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -184,14 +184,16 @@ Run quality gates from a checkout:

```bash
make validate # fast skill/extension/doc gates (greps the extension)
make validate-full # + pytest, extension behavioral tests, size/routing gates
make ci-local # mirror CI validate job (offline; run before PR)
make validate-full # alias for ci-local
make dev # one-shot dev setup (venv, Node, storageops install)
```

`make validate` only *greps* the TypeScript extension; the routing, provider, and
trace behavior is covered by the extension tests, so run `make validate-full`
trace behavior is covered by the extension tests, so run `make ci-local`
(or `make test`) before changing `storageops_cli/extensions/storageops.ts`.
`package_check.py`, `install-smoke`, and `diagnosis-smoke` run in CI (they need a
wheel build or network) — see [Release](docs/release.md).
`make package-check`, `install-smoke`, and `diagnosis-smoke` need a wheel build
or network/model key — see [Release](docs/release.md).

## Documentation Map

Expand Down
11 changes: 2 additions & 9 deletions docs/release.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,8 @@ Trusted Publisher.
2. Run the local quality gates:

```bash
.venv/bin/python -m pytest
make validate
.venv/bin/python scripts/package_check.py
python3 scripts/repo_size_gate.py
python3 scripts/routing_contract_check.py
python3 skills/storageops-eval-golden-cases/scripts/eval_all.py \
--cases skills/storageops-eval-golden-cases/cases \
--outputs skills/storageops-eval-golden-cases/baseline-outputs \
--only-with-outputs
make ci-local
make package-check # optional; wheel build + package_check.py
```

3. Merge the release PR to `main`.
Expand Down
116 changes: 116 additions & 0 deletions scripts/dev_setup.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
#!/usr/bin/env bash
# One-shot developer setup: Python editable install, Node >= 22.19 on PATH,
# storageops install, and a doctor readiness check.
set -euo pipefail
cd "$(dirname "$0")/.."

USE_VENV=1
SKIP_INSTALL=0
while [[ $# -gt 0 ]]; do
case "$1" in
--user)
USE_VENV=0
shift
;;
--skip-storageops-install)
SKIP_INSTALL=1
shift
;;
-h|--help)
echo "Usage: bash scripts/dev_setup.sh [--user] [--skip-storageops-install]"
echo " --user pip install -e '.[dev]' to user site (~/.local/bin)"
echo " --skip-storageops-install skip storageops install --force (offline only)"
exit 0
;;
*)
echo "unknown argument: $1" >&2
exit 2
;;
esac
done

min_node_major=22
min_node_minor=19

node_triple() {
node --version 2>/dev/null | sed -n 's/^v\?\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\).*/\1 \2 \3/p'
}

node_ok() {
read -r major minor patch <<< "$(node_triple)" || return 1
[[ -n "${major:-}" ]] || return 1
if (( major > min_node_major )); then return 0; fi
if (( major == min_node_major && minor >= min_node_minor )); then return 0; fi
return 1
}

prepend_nvm_node() {
local nvm_root="${NVM_DIR:-$HOME/.nvm}/versions/node"
[[ -d "$nvm_root" ]] || return 1
local best=""
local best_ver=""
for dir in "$nvm_root"/*; do
[[ -d "$dir/bin" && -x "$dir/bin/node" ]] || continue
local ver="${dir##*/}"
ver="${ver#v}"
IFS=. read -r major minor patch <<< "$ver"
[[ -n "${major:-}" ]] || continue
if (( major > min_node_major || (major == min_node_major && minor >= min_node_minor) )); then
if [[ -z "$best_ver" || "$ver" > "$best_ver" ]]; then
best="$dir/bin"
best_ver="$ver"
fi
fi
done
if [[ -n "$best" ]]; then
export PATH="$best:$PATH"
return 0
fi
return 1
}

echo "=== Python dev install ==="
if [[ "$USE_VENV" == 1 ]]; then
if ! python3 -m venv .venv 2>/dev/null; then
echo "[warn] python3 -m venv failed (install python3-venv); falling back to --user install"
USE_VENV=0
fi
fi
if [[ "$USE_VENV" == 1 ]]; then
# shellcheck disable=SC1091
source .venv/bin/activate
python -m pip install -U pip
python -m pip install -e '.[dev]'
export PATH="$(pwd)/.venv/bin:$PATH"
else
python3 -m pip install -U pip
python3 -m pip install -e '.[dev]'
export PATH="$HOME/.local/bin:$PATH"
fi

echo "=== Node.js (need >= ${min_node_major}.${min_node_minor}) ==="
if ! node_ok; then
if prepend_nvm_node && node_ok; then
echo "[ok] using nvm Node $(node --version) on PATH"
else
echo "[error] Node $(node --version 2>/dev/null || echo 'not found') is too old for Pi Coding Agent." >&2
echo " Install Node >= ${min_node_major}.${min_node_minor} (e.g. nvm install 22) and re-run." >&2
exit 1
fi
else
echo "[ok] Node $(node --version)"
fi

if [[ "$SKIP_INSTALL" != 1 ]]; then
echo "=== storageops install --force ==="
storageops install --force
else
echo "=== skipping storageops install (--skip-storageops-install) ==="
fi

echo "=== storageops doctor ==="
storageops doctor || true

echo
echo "Dev setup complete. Before opening a PR, run:"
echo " make ci-local"
Loading
Loading