Jelajahi Sumber

Merge pull request #1805 from obra/fix/render-graphs-no-shell

fix(writing-skills): make render-graphs ESM-compatible and shell-free
Drew Ritter 1 bulan lalu
induk
melakukan
1245282b05

+ 7 - 6
skills/writing-skills/render-graphs.js

@@ -13,9 +13,9 @@
  * Requires: graphviz (dot) installed on system
  */
 
-const fs = require('fs');
-const path = require('path');
-const { execSync } = require('child_process');
+import * as fs from 'fs';
+import * as path from 'path';
+import { execFileSync } from 'child_process';
 
 function extractDotBlocks(markdown) {
   const blocks = [];
@@ -69,7 +69,7 @@ ${bodies.join('\n\n')}
 
 function renderToSvg(dotContent) {
   try {
-    return execSync('dot -Tsvg', {
+    return execFileSync('dot', ['-Tsvg'], {
       input: dotContent,
       encoding: 'utf-8',
       maxBuffer: 10 * 1024 * 1024
@@ -107,9 +107,10 @@ function main() {
     process.exit(1);
   }
 
-  // Check if dot is available
+  // Check if dot is available. Run the binary directly rather than probing
+  // with `which`, which is not a command on Windows.
   try {
-    execSync('which dot', { encoding: 'utf-8' });
+    execFileSync('dot', ['-V'], { stdio: 'ignore' });
   } catch {
     console.error('Error: graphviz (dot) not found. Install with:');
     console.error('  brew install graphviz    # macOS');

+ 113 - 0
tests/writing-skills/test-render-graphs.sh

@@ -0,0 +1,113 @@
+#!/usr/bin/env bash
+set -u
+
+SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
+REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
+SCRIPT_UNDER_TEST="$REPO_ROOT/skills/writing-skills/render-graphs.js"
+NODE_BIN="$(command -v node)"
+
+PASSES=0
+FAILURES=0
+TEST_ROOT="$(mktemp -d)"
+
+cleanup() {
+  rm -rf "$TEST_ROOT"
+}
+trap cleanup EXIT
+
+pass() {
+  echo "  [PASS] $1"
+  PASSES=$((PASSES + 1))
+}
+
+fail() {
+  echo "  [FAIL] $1"
+  FAILURES=$((FAILURES + 1))
+}
+
+assert_contains() {
+  local haystack="$1"
+  local needle="$2"
+  local description="$3"
+
+  if printf '%s' "$haystack" | grep -Fq -- "$needle"; then
+    pass "$description"
+  else
+    fail "$description"
+    echo "    expected to find: $needle"
+  fi
+}
+
+assert_not_contains() {
+  local haystack="$1"
+  local needle="$2"
+  local description="$3"
+
+  if printf '%s' "$haystack" | grep -Fq -- "$needle"; then
+    fail "$description"
+    echo "    did not expect to find: $needle"
+  else
+    pass "$description"
+  fi
+}
+
+fixture="$TEST_ROOT/fixture-skill"
+mkdir -p "$fixture" "$TEST_ROOT/empty-path"
+cat >"$fixture/SKILL.md" <<'EOF'
+---
+name: fixture-skill
+---
+
+# Fixture Skill
+
+```dot
+digraph fixture_graph {
+  start -> end;
+}
+```
+EOF
+
+echo "Writing-skills render-graphs tests"
+
+missing_dot_output="$(PATH="$TEST_ROOT/empty-path" "$NODE_BIN" "$SCRIPT_UNDER_TEST" "$fixture" 2>&1)"
+missing_dot_status=$?
+
+if [[ "$missing_dot_status" -ne 0 ]]; then
+  pass "missing Graphviz exits non-zero"
+else
+  fail "missing Graphviz exits non-zero"
+fi
+assert_contains "$missing_dot_output" "Error: graphviz (dot) not found." "missing Graphviz reports install guidance"
+assert_not_contains "$missing_dot_output" "ReferenceError: require is not defined" "script runs as an ES module"
+
+render_output="$("$NODE_BIN" "$SCRIPT_UNDER_TEST" "$fixture" 2>&1)"
+render_status=$?
+
+if [[ "$render_status" -eq 0 ]]; then
+  pass "fixture diagram renders"
+else
+  fail "fixture diagram renders"
+  printf '%s\n' "$render_output"
+fi
+
+assert_contains "$render_output" "Found 1 diagram(s)" "reports discovered diagram"
+assert_contains "$render_output" "Rendered: fixture_graph.svg" "reports rendered SVG"
+
+if [[ -f "$fixture/diagrams/fixture_graph.svg" ]]; then
+  pass "writes SVG output"
+else
+  fail "writes SVG output"
+fi
+
+if [[ -f "$fixture/diagrams/fixture_graph.svg" ]] && grep -Fq "<svg" "$fixture/diagrams/fixture_graph.svg"; then
+  pass "SVG output has SVG markup"
+else
+  fail "SVG output has SVG markup"
+fi
+
+echo
+echo "Results: $PASSES passed, $FAILURES failed"
+
+if [[ "$FAILURES" -gt 0 ]]; then
+  exit 1
+fi