91 lines
5.2 KiB
Bash
Executable file
91 lines
5.2 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
# Stufe 0 (→ KONZEPT.md 20): Verhalten von OpenCode prüfen, ohne Modellaufruf.
|
|
# Nutzt nur `opencode debug …` und kostet keine Tokens. Ergebnisse → STUFE0.md.
|
|
#
|
|
# scripts/stage0.sh # mit dem installierten opencode
|
|
# OPENCODE=opencode2 scripts/stage0.sh
|
|
set -euo pipefail
|
|
|
|
OC="${OPENCODE:-opencode}"
|
|
T="$(mktemp -d)"
|
|
trap 'rm -rf "$T"' EXIT
|
|
cd "$T" && git init -q
|
|
|
|
mkdir -p .claude/skills/s0-unbekannt .claude/skills/s0-doppelt .opencode/skills/s0-doppelt \
|
|
.claude/skills/s0-slash-ohne .claude/skills/s0-slash-false \
|
|
.claude/commands .claude/agents .opencode/commands .opencode/agents .hugin/rules
|
|
printf -- '---\nname: s0-unbekannt\ndescription: Claude-Felder\nallowed-tools: [Read]\npaths: ["**/*.go"]\neffort: high\n---\nx\n' \
|
|
> .claude/skills/s0-unbekannt/SKILL.md
|
|
printf -- '---\nname: s0-doppelt\ndescription: aus .claude/skills\n---\nA\n' > .claude/skills/s0-doppelt/SKILL.md
|
|
printf -- '---\nname: s0-doppelt\ndescription: aus .opencode/skills\n---\nB\n' > .opencode/skills/s0-doppelt/SKILL.md
|
|
printf -- '---\nname: s0-slash-ohne\ndescription: ohne metadata\n---\nx\n' > .claude/skills/s0-slash-ohne/SKILL.md
|
|
printf -- '---\nname: s0-slash-false\ndescription: slash false\nmetadata:\n opencode/slash: "false"\n---\nx\n' \
|
|
> .claude/skills/s0-slash-false/SKILL.md
|
|
printf -- '---\ndescription: aus .claude/commands\n---\nx\n' > .claude/commands/s0-claude-befehl.md
|
|
printf -- '---\nname: s0-claude-agent\ndescription: aus .claude/agents\n---\nx\n' > .claude/agents/s0-claude-agent.md
|
|
printf -- '---\ndescription: aus .opencode/commands\n---\nTu $1\n' > .opencode/commands/s0-befehl.md
|
|
printf -- '---\ndescription: aus .opencode/agents\nmode: subagent\npermission:\n edit: deny\n bash: deny\n webfetch: deny\n---\nx\n' \
|
|
> .opencode/agents/s0-agent.md
|
|
printf '# Regel\n' > .hugin/rules/s0.md
|
|
cat > opencode.json <<'EOF'
|
|
{
|
|
// JSONC: Kommentar und Komma am Ende
|
|
"instructions": [".hugin/rules/*.md"],
|
|
"mcp": {
|
|
"s0": { "type": "remote", "url": "http://127.0.0.1:9/mcp", "enabled": true,
|
|
"headers": { "Authorization": "Bearer {env:S0_KEY}" } }
|
|
},
|
|
}
|
|
EOF
|
|
|
|
# Über eine Pipe schneidet opencode lange Ausgaben ab; deshalb erst in Dateien
|
|
json() { python3 -c 'import json,sys; r=open(sys.argv[1]).read(); print(json.dumps(json.loads(r[min(i for i in (r.find("{"), r.find("[")) if i >= 0):])))' "$1"; }
|
|
|
|
echo "OpenCode: $($OC --version)"
|
|
$OC debug skill --pure >"$T/.skills" 2>/dev/null
|
|
S0_KEY=geheim $OC debug config --pure >"$T/.config" 2>/dev/null
|
|
SKILLS=$(json "$T/.skills")
|
|
CONFIG=$(json "$T/.config")
|
|
python3 - "$SKILLS" "$CONFIG" <<'EOF'
|
|
import json, sys
|
|
skills = [s for s in json.loads(sys.argv[1]) if s["name"].startswith("s0-")]
|
|
config = json.loads(sys.argv[2])
|
|
names = [s["name"] for s in skills]
|
|
def report(question, ok, text): print(f"{'✓' if ok else '✗'} {question}: {text}")
|
|
report("1 unbekannte Felder", "s0-unbekannt" in names, "Skill geladen" if "s0-unbekannt" in names else "Skill fehlt")
|
|
duplicates = [s for s in skills if s["name"] == "s0-doppelt"]
|
|
report("2 gleicher Name in .claude und .opencode", len(duplicates) == 1,
|
|
f"{len(duplicates)} Fassung(en): " + ", ".join(s["description"] for s in duplicates))
|
|
commands = list((config.get("command") or {}))
|
|
agents = list((config.get("agent") or {}))
|
|
report("3 liest .claude/commands nicht", "s0-claude-befehl" not in commands, f"Befehle: {commands}")
|
|
report("3 liest .claude/agents nicht", "s0-claude-agent" not in agents, f"Agenten: {[a for a in agents if a.startswith('s0')]}")
|
|
report("6 JSONC erlaubt", config.get("instructions") == [".hugin/rules/*.md"], f"instructions: {config.get('instructions')}")
|
|
mcp = (config.get("mcp") or {}).get("s0") or (config.get("mcp") or {}).get("servers", {}).get("s0")
|
|
# Ab 1.19 zeigt debug config Header nur maskiert; dann belegt der Rauchtest {env:VAR}
|
|
masked = bool(mcp) and "***" in json.dumps(mcp)
|
|
report("10 MCP alte Form, {env:VAR}", bool(mcp) and ("geheim" in json.dumps(mcp) or masked),
|
|
json.dumps(mcp) + (" (Header maskiert, {env:VAR} prüft tool-smoke-test.sh)" if masked else ""))
|
|
EOF
|
|
|
|
# Slash-Befehle: dieselbe Liste, die das TUI bei „/“ anbietet, liefert der Server unter /command
|
|
PORT="${PORT:-47123}"
|
|
$OC serve --pure --port "$PORT" >"$T/.serve" 2>&1 &
|
|
SERVE=$!
|
|
trap 'kill $SERVE 2>/dev/null; wait $SERVE 2>/dev/null; rm -rf "$T"' EXIT
|
|
for _ in $(seq 60); do curl -fsS "http://127.0.0.1:$PORT/command" >"$T/.commands" 2>/dev/null && break; sleep 0.25; done
|
|
python3 - "$T/.commands" <<'EOF2'
|
|
import json, sys
|
|
try:
|
|
commands = {c["name"]: c.get("source") for c in json.load(open(sys.argv[1]))}
|
|
except Exception as e:
|
|
sys.exit(f"✗ 8 Slash-Befehle: /command nicht lesbar ({e})")
|
|
def report(question, ok, text): print(f"{'✓' if ok else '✗'} {question}: {text}")
|
|
report("8 Skill ohne metadata ist Slash-Befehl", "s0-slash-ohne" in commands, commands.get("s0-slash-ohne", "fehlt"))
|
|
# Erwartet (1.19.3): opencode/slash wirkt nicht, auch „false“ blendet nicht aus
|
|
report("8 opencode/slash: \"false\" wirkt nicht", "s0-slash-false" in commands,
|
|
"weiter in der Liste" if "s0-slash-false" in commands else "ausgeblendet: opencode/slash wirkt")
|
|
EOF2
|
|
|
|
echo
|
|
echo "Mit Modellaufruf in scripts/tool-smoke-test.sh: 4, 5, 8 (benannte Argumente), opencode/autoinvoke"
|