         self.enableSandbox = enableSandbox
     }
 
-    /// Public protocol function that compiles and runs the plugin as a subprocess.  The tools version controls the availability of APIs in PackagePlugin, and should be
+    /// Public protocol function that compiles and runs the plugin as a subprocess.  The tools version controls the availability of APIs in PackagePlugin, and should be set to the tools version of the package that defines the plugin (not of the target to which it is being applied).
     public func runPluginScript(sources: Sources, inputJSON: Data, toolsVersion: ToolsVersion, writableDirectories: [AbsolutePath], diagnostics: DiagnosticsEngine, fileSystem: FileSystem) throws -> (outputJSON: Data, stdoutText: Data) {
         let compiledExec = try self.compile(sources: sources, toolsVersion: toolsVersion, cacheDir: self.cacheDir)
         return try self.invoke(compiledExec: compiledExec, toolsVersion: toolsVersion, writableDirectories: writableDirectories, input: inputJSON)

    }

}
public typealias DefaultExtensionRunner = DefaultPluginScriptRunner

/// An error in the default plugin runner.
public enum DefaultPluginScriptRunnerError: Swift.Error {
    case didNotReceiveJSONFromPlugin(_ message: String)
    case pluginSubprocessFailed(_ message: String)
}

        #endif

        // Invoke the plugin script as a subprocess.
        let result: ProcessResult
        do {
            result = try Process.popen(arguments: command)
        } catch {
            throw DefaultPluginScriptRunnerError.subprocessDidNotStart("\(error)", command: command)
        }

        // Collect the output. The `PackagePlugin` runtime library writes the output as a zero byte followed by
        // the JSON-serialized PluginEvaluationResult. Since this appears after any free-form output from the
        // script, it can be safely split out while maintaining the ability to see debug output without resorting
        // to side-channel communication that might be not be very cross-platform (e.g. pipes, file handles, etc).
        // We end up with an optional Data for the JSON, and two Datas for stdout and stderr respectively.
        var stdoutPieces = (try? result.output.get().split(separator: 0, omittingEmptySubsequences: false)) ?? []
        let jsonData = (stdoutPieces.count > 1) ? Data(stdoutPieces.removeLast()) : nil
        let stdoutData = Data(stdoutPieces.joined())
        let stderrData = (try? Data(result.stderrOutput.get())) ?? Data()
                
        // Throw an error if we the subprocess ended badly.
        if result.exitStatus != .terminated(code: 0) {
            let output = String(decoding: stdoutData + stderrData, as: UTF8.self)
            throw DefaultPluginScriptRunnerError.subprocessFailed("\(result.exitStatus)", command: command, output: output)
        }
        
        // Throw an error if we didn't get the JSON data.
        guard let json = jsonData else {
            let output = String(decoding: stdoutData + stderrData, as: UTF8.self)
            throw DefaultPluginScriptRunnerError.missingPluginJSON("didn't receive JSON output data", command: command, output: output)
        }

        // Otherwise return the JSON data and any output text.
        return (outputJSON: json, stdoutText: stdoutData + stderrData)
    }

    /// Constructs the sandbox profile to use for plugin scripts on macOS.  The tools version can affect what's allowed.
