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
21 changes: 21 additions & 0 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"name": "StorageOps",
"image": "mcr.microsoft.com/devcontainers/python:1-3.12-bookworm",
"features": {
"ghcr.io/devcontainers/features/node:1": {
"version": "22"
},
"ghcr.io/devcontainers/features/common-utils:2": {}
},
"postCreateCommand": "bash scripts/dev_setup.sh --persist-path",
"customizations": {
"vscode": {
"settings": {
"python.defaultInterpreterPath": "${workspaceFolder}/.venv/bin/python"
}
}
},
"remoteEnv": {
"PATH": "${containerEnv:PATH}:${workspaceFolder}/.venv/bin:${containerEnv:HOME}/.local/bin"
}
}
22 changes: 5 additions & 17 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -132,22 +132,10 @@ jobs:
python -m build --wheel
pip install dist/*.whl
storageops install
- name: Run a diagnosis and evaluate it
- name: Run live diagnosis smoke (3 golden cases)
if: steps.gate.outputs.present == 'true'
env:
MODEL_KEY: ${{ secrets.STORAGEOPS_MODEL_KEY }}
PROVIDER: ${{ vars.STORAGEOPS_PROVIDER }}
MODEL: ${{ vars.STORAGEOPS_MODEL }}
run: |
set -e
CASE=skills/storageops-eval-golden-cases/cases/throttling-hot-prefix
INPUT=$(ls "$CASE"/input/* | head -1)
storageops --provider "${PROVIDER:-deepseek}" --model "${MODEL:-deepseek-v4-pro}" \
--api-key "$MODEL_KEY" --print @"$INPUT" \
'Diagnose the root cause and safe next steps' > /tmp/diag.md
echo "----- diagnosis output (head) -----"; head -40 /tmp/diag.md
test -s /tmp/diag.md
# eval_runner exits non-zero on HARD_FAIL (wrong category, low confidence,
# missing required evidence, or forbidden/unsafe output).
python skills/storageops-eval-golden-cases/scripts/eval_runner.py \
--case "$CASE" --output /tmp/diag.md
STORAGEOPS_MODEL_KEY: ${{ secrets.STORAGEOPS_MODEL_KEY }}
STORAGEOPS_PROVIDER: ${{ vars.STORAGEOPS_PROVIDER }}
STORAGEOPS_MODEL: ${{ vars.STORAGEOPS_MODEL }}
run: bash scripts/live_smoke.sh
14 changes: 8 additions & 6 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ make test # alias for ci-local
make test-fast # pytest + extension tests + fast validate
make ci-full # ci-local + package-check (pre-release)
make dev # one-shot dev setup (venv, Node, storageops install)
make live-smoke # live model smoke + 3 golden-case diagnoses (needs API key)
```

`make validate` does not exercise the TypeScript extension — the routing,
Expand Down Expand Up @@ -79,9 +80,10 @@ commands live in the `## Validation Commands` section above, `Makefile`, and
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`).
run fully offline and need no key. **Live diagnosis** needs install + Node/Pi + API key;
check `storageops doctor --json` field `live_diagnosis_available`, then run
`make live-smoke` (3 golden cases + model smoke).
- **Devcontainer.** Open in VS Code / Codespaces with `.devcontainer/devcontainer.json`
(Python 3.12 + Node 22; postCreate runs `dev_setup.sh --persist-path`).
- **PR gate.** Run `make ci-local` before opening a PR. Use `make dev` for first-time
setup (`scripts/dev_setup.sh`; optional `DEV_SETUP_FLAGS="--persist-path --verify"`).
15 changes: 15 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,20 @@
# Changelog

## 2026-06-29 — v0.7.2: Live diagnosis smoke & devcontainer

- **`make live-smoke` / `scripts/live_smoke.sh`** — model round-trip plus live
diagnosis + eval for three golden cases (`throttling-hot-prefix`,
`access-denied-cross-account`, `signature-clock-skew`). Requires a configured
API key; reads `STORAGEOPS_MODEL_KEY` or provider env vars when set.
- **`storageops doctor`** — adds `Live diagnosis` row and `live_diagnosis_available`
in `--json` output when install, Node, Pi, and API key are ready.
- **CI `diagnosis-smoke`** — calls `scripts/live_smoke.sh` (3 cases) when
`STORAGEOPS_MODEL_KEY` is configured.
- **`.devcontainer/devcontainer.json`** — Python 3.12 + Node 22; postCreate runs
`dev_setup.sh --persist-path`.
- **`dev_setup.sh`** — new `--persist-path` (idempotent `~/.bashrc` PATH hints) and
`--verify` (runs `make ci-local` after setup).

## 2026-06-29 — v0.7.1: Dev ergonomics & CI alignment

- **`make ci-local`** mirrors the offline PR gate (provider/contract/coverage checks,
Expand Down
17 changes: 14 additions & 3 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,14 @@ make dev
ensures Node.js >= 22.19 (prefers nvm when the default `node` is too old), runs
`storageops install --force`, and prints `storageops doctor`.

Optional flags via `DEV_SETUP_FLAGS`:

```bash
make dev DEV_SETUP_FLAGS="--persist-path --verify"
```

VS Code / Codespaces: use `.devcontainer/devcontainer.json` (runs `dev_setup.sh --persist-path`).

Manual setup (equivalent):

```bash
Expand Down Expand Up @@ -111,14 +119,17 @@ python3 skills/storageops-eval-golden-cases/scripts/eval_all.py \
.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):
Optional live diagnosis smoke (needs a model provider API key):

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

CI runs the same script when the repo secret **`STORAGEOPS_MODEL_KEY`** is set
(optional vars: **`STORAGEOPS_PROVIDER`**, **`STORAGEOPS_MODEL`**) — see
`.github/workflows/ci.yml` `diagnosis-smoke` job and `docs/release.md`.

## Pull Request Checklist

- The change is scoped and documented.
Expand Down
14 changes: 9 additions & 5 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.PHONY: help validate validate-full ci-local ci-full extension-tests test-fast test install dev package-check
.PHONY: help validate validate-full ci-local ci-full extension-tests test-fast test install dev live-smoke package-check

help:
@echo "StorageOps — Pi Coding Agent extension + skill pack"
Expand All @@ -12,11 +12,12 @@ help:
@echo " make test-fast pytest + extension tests + fast validate only"
@echo " make extension-tests Run the TypeScript extension behavioral tests"
@echo " make install Install thin CLI shim (pip install -e .)"
@echo " make dev One-shot dev setup (venv, Node, storageops install)"
@echo " make dev One-shot dev setup (scripts/dev_setup.sh; DEV_SETUP_FLAGS=...)"
@echo " make live-smoke Model smoke + 3 golden-case live diagnoses (needs API key)"
@echo " make package-check Build wheel and run package_check.py (needs network once)"
@echo ""
@echo " Note: install-smoke and diagnosis-smoke run in CI only"
@echo " (wheel install / model key) — see docs/release.md."
@echo " Note: install-smoke and diagnosis-smoke run in CI when configured"
@echo " (wheel install / STORAGEOPS_MODEL_KEY) — see docs/release.md."

validate:
@echo "=== Validating skills ==="
Expand Down Expand Up @@ -67,7 +68,10 @@ install:
pip install -e .

dev:
@bash scripts/dev_setup.sh
@bash scripts/dev_setup.sh $(DEV_SETUP_FLAGS)

live-smoke:
@bash scripts/live_smoke.sh

package-check:
python3 -m pip install --upgrade pip build
Expand Down
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@ make test # alias for ci-local
make test-fast # faster loop while editing
make ci-full # pre-release: ci-local + package-check
make dev # one-shot dev setup (venv, Node, storageops install)
make live-smoke # live model smoke + 3 golden-case diagnoses (needs API key)
```

`make validate` only *greps* the TypeScript extension; the routing, provider, and
Expand All @@ -198,6 +199,9 @@ trace behavior is covered by the extension tests, so run `make ci-local`
`make ci-full`, `install-smoke`, and `diagnosis-smoke` need a wheel build
or network/model key — see [Release](docs/release.md).

Reproducible dev environment: open `.devcontainer/devcontainer.json` in VS Code
or Codespaces (`make dev` with `--persist-path` on postCreate).

## Documentation Map

- [Getting Started](docs/getting-started.md)
Expand Down
2 changes: 1 addition & 1 deletion docs/ARCHITECTURE.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Architecture

StorageOps v0.7.1 is a Pi Coding Agent extension and skill pack.
StorageOps v0.7.2 is a Pi Coding Agent extension and skill pack.

## Components

Expand Down
2 changes: 1 addition & 1 deletion docs/cli-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ from the older local package. Deployment provenance is written to
## `storageops --version`

```text
StorageOps v0.7.1 (pi: 0.78.0)
StorageOps v0.7.2 (pi: 0.78.0)
httpmon : /root/.storageops/bin/httpmon
api key : api-key file
independent install : yes (~/.storageops/agent)
Expand Down
21 changes: 21 additions & 0 deletions docs/release.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,3 +75,24 @@ source repository.
Use the workflow's manual `workflow_dispatch` preflight before the first real
release, or whenever release plumbing changes. Manual runs build and validate
the package but never publish to PyPI.

## Live diagnosis smoke (optional CI)

The `diagnosis-smoke` job in `.github/workflows/ci.yml` runs `scripts/live_smoke.sh`
when a model key is configured. Without the secret it skips cleanly (job still passes).

| GitHub setting | Purpose |
| --- | --- |
| Secret `STORAGEOPS_MODEL_KEY` | Model provider API key (required to enable live smoke) |
| Var `STORAGEOPS_PROVIDER` | Optional; default `deepseek` |
| Var `STORAGEOPS_MODEL` | Optional; default `deepseek-v4-pro` |

Locally (after `storageops configure --api-key` or exporting a provider env var):

```bash
make live-smoke
```

The script runs `storageops smoke` plus live `--print` diagnosis + eval for three
golden cases: `throttling-hot-prefix`, `access-denied-cross-account`,
`signature-clock-skew`.
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"

[project]
name = "storageops"
version = "0.7.1"
version = "0.7.2"
description = "StorageOps — S3-compatible object storage diagnostic toolkit. A Pi Coding Agent extension + skill pack."
requires-python = ">=3.11"
readme = "README.md"
Expand Down
53 changes: 49 additions & 4 deletions scripts/dev_setup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ cd "$(dirname "$0")/.."

USE_VENV=1
SKIP_INSTALL=0
PERSIST_PATH=0
VERIFY=0
NVM_BIN=""
PYTHON_BIN_PREFIX=""

while [[ $# -gt 0 ]]; do
case "$1" in
--user)
Expand All @@ -16,10 +21,20 @@ while [[ $# -gt 0 ]]; do
SKIP_INSTALL=1
shift
;;
--persist-path)
PERSIST_PATH=1
shift
;;
--verify)
VERIFY=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 "Usage: bash scripts/dev_setup.sh [OPTIONS]"
echo " --user pip install -e '.[dev]' to user site (~/.local/bin)"
echo " --skip-storageops-install skip storageops install --force (offline only)"
echo " --persist-path append PATH hints to ~/.bashrc (idempotent)"
echo " --verify run make ci-local after setup"
exit 0
;;
*)
Expand All @@ -31,6 +46,16 @@ done

min_node_major=22
min_node_minor=19
STORAGEOPS_PATH_MARKER="# storageops-dev-setup"

persist_path_line() {
local line="$1"
touch "$HOME/.bashrc"
if ! grep -Fq "$line" "$HOME/.bashrc" 2>/dev/null; then
echo "$line $STORAGEOPS_PATH_MARKER" >> "$HOME/.bashrc"
echo "[ok] persisted: $line"
fi
}

node_triple() {
node --version 2>/dev/null | sed -n 's/^v\?\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\).*/\1 \2 \3/p'
Expand Down Expand Up @@ -63,6 +88,7 @@ prepend_nvm_node() {
fi
done
if [[ -n "$best" ]]; then
NVM_BIN="$best"
export PATH="$best:$PATH"
return 0
fi
Expand All @@ -81,11 +107,13 @@ if [[ "$USE_VENV" == 1 ]]; then
source .venv/bin/activate
python -m pip install -U pip
python -m pip install -e '.[dev]'
export PATH="$(pwd)/.venv/bin:$PATH"
PYTHON_BIN_PREFIX="$(pwd)/.venv/bin"
export PATH="${PYTHON_BIN_PREFIX}:$PATH"
else
python3 -m pip install -U pip
python3 -m pip install -e '.[dev]'
export PATH="$HOME/.local/bin:$PATH"
PYTHON_BIN_PREFIX="$HOME/.local/bin"
export PATH="${PYTHON_BIN_PREFIX}:$PATH"
fi

echo "=== Node.js (need >= ${min_node_major}.${min_node_minor}) ==="
Expand All @@ -101,6 +129,16 @@ else
echo "[ok] Node $(node --version)"
fi

if [[ "$PERSIST_PATH" == 1 ]]; then
echo "=== Persist PATH hints ==="
if [[ -n "$PYTHON_BIN_PREFIX" ]]; then
persist_path_line "export PATH=\"${PYTHON_BIN_PREFIX}:\$PATH\""
fi
if [[ -n "$NVM_BIN" ]]; then
persist_path_line "export PATH=\"${NVM_BIN}:\$PATH\""
fi
fi

if [[ "$SKIP_INSTALL" != 1 ]]; then
echo "=== storageops install --force ==="
storageops install --force
Expand All @@ -111,6 +149,13 @@ fi
echo "=== storageops doctor ==="
storageops doctor || true

if [[ "$VERIFY" == 1 ]]; then
echo "=== make ci-local (--verify) ==="
make ci-local
fi

echo
echo "Dev setup complete. Before opening a PR, run:"
echo " make ci-local"
echo "With a model key configured, also run:"
echo " make live-smoke"
Loading
Loading