{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://quickrun.org/quickrun.schema.json",
  "title": "quickrun.yml",
  "description": "How to start this repository. Every block is optional; the file only has to describe something to execute.",
  "type": "object",
  "additionalProperties": false,
  "properties": {
    "version": { "type": "integer", "const": 1, "default": 1 },
    "name": { "type": "string", "description": "Shown in the UI. Defaults to the repository name." },
    "description": { "type": "string" },
    "icon": { "type": "string", "description": "Repository-relative path or URL." },
    "docs": { "type": "string", "description": "Link shown in the UI." },
    "requires": {
      "type": "array",
      "description": "Prerequisites checked before anything runs.",
      "items": { "$ref": "#/$defs/requirement" }
    },
    "inputs": {
      "type": "array",
      "description": "Values QuickRun asks for, rendered as a form.",
      "items": { "$ref": "#/$defs/input" }
    },
    "env": { "$ref": "#/$defs/stringMap", "description": "Environment for every command." },
    "setup": {
      "type": "array",
      "description": "Sequential commands, run before the tasks.",
      "items": { "$ref": "#/$defs/step" }
    },
    "run": {
      "$ref": "#/$defs/command",
      "description": "Shorthand for a single task. Use either run or tasks, not both."
    },
    "tasks": {
      "type": "array",
      "description": "Long-running processes, started in parallel unless dependsOn says otherwise.",
      "items": { "$ref": "#/$defs/task" }
    },
    "stop": {
      "type": "array",
      "description": "Commands run when the user stops the app.",
      "items": { "$ref": "#/$defs/step" }
    }
  },
  "not": { "required": ["run", "tasks"] },
  "$defs": {
    "platform": { "enum": ["windows", "linux", "macos"] },
    "stringMap": {
      "type": "object",
      "additionalProperties": { "type": ["string", "number", "boolean"] }
    },
    "command": {
      "description": "A command line, or one per platform.",
      "oneOf": [
        { "type": "string" },
        {
          "type": "object",
          "additionalProperties": false,
          "minProperties": 1,
          "properties": {
            "windows": { "type": "string" },
            "linux": { "type": "string" },
            "macos": { "type": "string" }
          }
        }
      ]
    },
    "when": {
      "description": "Platforms this step applies to. Omit for all of them.",
      "oneOf": [
        { "$ref": "#/$defs/platform" },
        { "type": "array", "items": { "$ref": "#/$defs/platform" } }
      ]
    },
    "step": {
      "oneOf": [
        { "type": "string" },
        {
          "type": "object",
          "additionalProperties": false,
          "required": ["run"],
          "properties": {
            "run": { "$ref": "#/$defs/command" },
            "cwd": { "type": "string", "description": "Relative to the repository root." },
            "when": { "$ref": "#/$defs/when" },
            "continueOnError": { "type": "boolean", "default": false }
          }
        }
      ]
    },
    "readyWhen": {
      "type": "object",
      "description": "Exactly one condition. Omit the block to mean ready as soon as the process started.",
      "additionalProperties": false,
      "minProperties": 1,
      "maxProperties": 1,
      "properties": {
        "port": { "type": "integer", "minimum": 1, "maximum": 65535 },
        "http": { "type": "string" },
        "log": { "type": "string", "description": "Regular expression matched against the task's output." },
        "window": {
          "type": "boolean",
          "description": "Ready when the process, or something it started, has a window. For desktop applications; Windows only."
        },
        "delay": {
          "description": "500ms, 5s, 2m, or a number of seconds.",
          "oneOf": [
            { "type": "string", "pattern": "^\\d+(\\.\\d+)?(ms|s|m)?$" },
            { "type": "number" }
          ]
        }
      }
    },
    "task": {
      "oneOf": [
        { "type": "string" },
        {
          "type": "object",
          "additionalProperties": false,
          "required": ["run"],
          "properties": {
            "name": { "type": "string" },
            "run": { "$ref": "#/$defs/command" },
            "cwd": { "type": "string", "description": "Relative to the repository root." },
            "env": { "$ref": "#/$defs/stringMap" },
            "dependsOn": {
              "description": "Task names to wait for. Cycles are rejected at validation time.",
              "oneOf": [
                { "type": "string" },
                { "type": "array", "items": { "type": "string" } }
              ]
            },
            "readyWhen": { "$ref": "#/$defs/readyWhen" },
            "open": {
              "description": "true opens the readyWhen URL; a string opens that URL.",
              "oneOf": [{ "type": "boolean" }, { "type": "string" }]
            },
            "restart": { "enum": ["never", "onFailure"], "default": "never" }
          }
        }
      ]
    },
    "requirement": {
      "oneOf": [
        { "type": "string", "description": "Just the tool name." },
        {
          "type": "object",
          "additionalProperties": false,
          "required": ["tool"],
          "properties": {
            "tool": { "type": "string" },
            "version": {
              "type": "string",
              "description": "A single comparison: >=9.0, >20, <=3.12, =1.2.3, or a bare version.",
              "pattern": "^(>=|<=|>|<|=)?\\s*\\d+(\\.\\d+)*$"
            },
            "install": { "type": "string", "description": "Shown when the tool is missing." },
            "optional": { "type": "boolean", "default": false }
          }
        }
      ]
    },
    "input": {
      "type": "object",
      "additionalProperties": false,
      "required": ["id"],
      "properties": {
        "id": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_]*$" },
        "label": { "type": "string" },
        "type": {
          "enum": ["text", "password", "number", "bool", "select", "path", "dir", "file"],
          "default": "text"
        },
        "description": { "type": "string" },
        "default": { "type": ["string", "number", "boolean", "null"] },
        "required": { "type": "boolean", "default": false },
        "pattern": { "type": "string", "description": "Regular expression, for text-like types." },
        "min": { "type": "number" },
        "max": { "type": "number" },
        "options": {
          "type": "array",
          "items": {
            "oneOf": [
              { "type": ["string", "number"] },
              {
                "type": "object",
                "additionalProperties": false,
                "required": ["value"],
                "properties": {
                  "value": { "type": ["string", "number"] },
                  "label": { "type": "string" }
                }
              }
            ]
          }
        },
        "env": { "type": "string", "description": "Environment variable this value is exported as." },
        "persist": { "type": "boolean", "default": false }
      }
    }
  }
}
