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
62 changes: 62 additions & 0 deletions skills/opencode-live-smoke/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
---
name: opencode-live-smoke
description: Run live OpenCode smoke tests for opencode-dynamic-subagents against a real project by temporarily switching the local OpenCode plugin source to either the local dist build or the published npm package, executing a subagent-read prompt, and restoring config afterward.
---

# OpenCode Live Smoke

Use this skill when you need to verify the plugin in a real OpenCode run, not just unit tests.

## When To Use

- Before publishing a plugin change
- After publishing a new npm version
- When debugging real subagent behavior in OpenCode
- When checking whether a project path is treated as internal or external

## Workflow

1. Choose the target project root and a file inside that project.
2. Choose `local` before publish or `npm` after publish.
3. Run the helper script:

```bash
skills/opencode-live-smoke/scripts/run-live-smoke.sh \
--project /absolute/project/root \
--file /absolute/project/root/path/to/file.tsx \
--source local
```

For npm validation:

```bash
skills/opencode-live-smoke/scripts/run-live-smoke.sh \
--project /absolute/project/root \
--file /absolute/project/root/path/to/file.tsx \
--source npm
```

## What The Script Does

- Validates the project root and target file
- Uses the local built entrypoint for `local`, or `opencode-dynamic-subagents@<package.json version>` for `npm`
- Temporarily rewrites `~/.config/opencode/opencode.jsonc`
- Runs:

```bash
opencode run --print-logs --agent build "Use a subagent to read <file> and return only the first non-empty line."
```

- Restores the original OpenCode config on exit

## Expected Result

- OpenCode loads the plugin successfully
- A subagent task is launched
- The response returns the first non-empty line from the target file

## Notes

- Prefer a file inside the exact project root passed to `--project`
- `local` mode runs `npm run build` in this repo before testing
- If the run hangs or prompts unexpectedly, inspect the emitted logs before retrying
122 changes: 122 additions & 0 deletions skills/opencode-live-smoke/scripts/run-live-smoke.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
#!/bin/sh
set -eu

usage() {
cat <<'EOF'
Usage:
run-live-smoke.sh --project /abs/project/root --file /abs/file/in/project --source local|npm
EOF
}

PROJECT=""
TARGET_FILE=""
SOURCE=""

while [ "$#" -gt 0 ]; do
case "$1" in
--project)
PROJECT="${2:-}"
shift 2
;;
--file)
TARGET_FILE="${2:-}"
shift 2
;;
--source)
SOURCE="${2:-}"
shift 2
;;
-h|--help)
usage
exit 0
;;
*)
echo "Unknown argument: $1" >&2
usage >&2
exit 1
;;
esac
done

if [ -z "$PROJECT" ] || [ -z "$TARGET_FILE" ] || [ -z "$SOURCE" ]; then
usage >&2
exit 1
fi

case "$SOURCE" in
local|npm) ;;
*)
echo "--source must be 'local' or 'npm'" >&2
exit 1
;;
esac

if ! command -v opencode >/dev/null 2>&1; then
echo "opencode is not installed or not on PATH" >&2
exit 1
fi

SCRIPT_DIR="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)"
SKILL_DIR="$(CDPATH= cd -- "$SCRIPT_DIR/.." && pwd)"
REPO_ROOT="$(CDPATH= cd -- "$SKILL_DIR/../.." && pwd)"
CONFIG_PATH="$HOME/.config/opencode/opencode.jsonc"

if [ ! -d "$PROJECT" ]; then
echo "Project root not found: $PROJECT" >&2
exit 1
fi

if [ ! -f "$TARGET_FILE" ]; then
echo "Target file not found: $TARGET_FILE" >&2
exit 1
fi

case "$TARGET_FILE" in
"$PROJECT"/*) ;;
*)
echo "Target file must live under the provided project root" >&2
exit 1
;;
esac

if [ ! -f "$CONFIG_PATH" ]; then
echo "OpenCode config not found: $CONFIG_PATH" >&2
exit 1
fi

BACKUP_PATH="$(mktemp "${TMPDIR:-/tmp}/opencode.jsonc.XXXXXX")"
cp "$CONFIG_PATH" "$BACKUP_PATH"
cleanup() {
cp "$BACKUP_PATH" "$CONFIG_PATH"
rm -f "$BACKUP_PATH"
}
trap cleanup EXIT INT TERM

if [ "$SOURCE" = "local" ]; then
(cd "$REPO_ROOT" && npm run build >/dev/null)
PLUGIN_SPEC="$REPO_ROOT/dist/entrypoint.js"
else
VERSION="$(node -p "require('$REPO_ROOT/package.json').version")"
PLUGIN_SPEC="opencode-dynamic-subagents@$VERSION"
fi

node <<'EOF' "$CONFIG_PATH" "$PLUGIN_SPEC"
const fs = require("node:fs")

const [configPath, pluginSpec] = process.argv.slice(1)
const text = fs.readFileSync(configPath, "utf8")
const next = text.replace(
/"(opencode-dynamic-subagents@[^"]+|\/Users\/cgas\/Documents\/Projects\/OpenCodePlugins\/opencode-dynamic-subagents\/dist\/entrypoint\.js)"/g,
JSON.stringify(pluginSpec),
)

if (next === text) {
throw new Error("Could not find an opencode-dynamic-subagents plugin entry in opencode.jsonc")
}

fs.writeFileSync(configPath, next)
EOF

PROMPT="Use a subagent to read $TARGET_FILE and return only the first non-empty line."
cd "$PROJECT"
opencode run --print-logs --agent build "$PROMPT"