{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "title": "Service Launcher manifest v1",
  "type": "object",
  "additionalProperties": false,
  "required": ["schemaVersion", "id", "name", "launchd"],
  "properties": {
    "$schema": {"type": "string"},
    "schemaVersion": {"const": 1},
    "id": {"$ref": "#/$defs/identifier"},
    "name": {"type": "string", "minLength": 1, "pattern": "\\S"},
    "launchd": {
      "type": "object",
      "additionalProperties": false,
      "required": ["mode", "label"],
      "properties": {
        "mode": {"enum": ["managed", "existing"]},
        "label": {"allOf": [{"$ref": "#/$defs/identifier"}, {"not": {"pattern": "^com\\.apple\\."}}]},
        "plistPath": {"$ref": "#/$defs/path"},
        "startAtLogin": {"type": "boolean", "default": false},
        "restartPolicy": {"enum": ["never", "on-failure", "always"], "default": "never"}
      }
    },
    "process": {"$ref": "#/$defs/command"},
    "shutdown": {"$ref": "#/$defs/command", "description": "Optional graceful shutdown hook; launchd cleanup follows even if it fails."},
    "shutdownTimeoutSeconds": {"type": "number", "minimum": 1, "maximum": 300, "default": 15},
    "healthCheck": {
      "type": "object", "additionalProperties": false, "required": ["url"],
      "properties": {
        "url": {"$ref": "#/$defs/httpURL"},
        "timeoutSeconds": {"type": "number", "minimum": 0.1, "maximum": 60, "default": 3}
      }
    },
    "links": {
      "type": "object", "additionalProperties": false,
      "properties": {"open": {"$ref": "#/$defs/httpURL"}}
    },
    "actions": {
      "type": "array",
      "description": "Action ids must be unique (also checked by the importer).",
      "items": {
        "type": "object", "additionalProperties": false,
        "required": ["id", "title", "command"],
        "properties": {
          "id": {"$ref": "#/$defs/identifier"},
          "title": {"type": "string", "minLength": 1},
          "command": {"$ref": "#/$defs/command"},
          "availableWhen": {"enum": ["always", "running", "stopped"], "default": "always"},
          "timeoutSeconds": {"type": "number", "minimum": 1, "maximum": 300, "default": 30},
          "confirmation": {"type": "boolean", "default": false}
        }
      }
    }
  },
  "allOf": [
    {
      "if": {"properties": {"launchd": {"properties": {"mode": {"const": "managed"}}}}},
      "then": {
        "required": ["process"],
        "properties": {"launchd": {"not": {"required": ["plistPath"]}}}
      },
      "else": {
        "not": {"required": ["process"]},
        "properties": {
          "launchd": {
            "required": ["plistPath"],
            "not": {"anyOf": [{"required": ["startAtLogin"]}, {"required": ["restartPolicy"]}]}
          }
        }
      }
    }
  ],
  "$defs": {
    "identifier": {"type": "string", "pattern": "^[a-zA-Z0-9][a-zA-Z0-9._-]{0,127}$"},
    "path": {"type": "string", "pattern": "^(?:/|\\$\\{projectDir\\}(?:/|$)|\\$\\{home\\}(?:/|$))", "description": "Absolute path, or ${projectDir}/… or ${home}/…. No ~ or shell expansion."},
    "httpURL": {"type": "string", "format": "uri", "pattern": "^https?://[^/\\s]+"},
    "command": {
      "type": "object", "additionalProperties": false, "required": ["executable"],
      "properties": {
        "executable": {"$ref": "#/$defs/path"},
        "arguments": {"type": "array", "items": {"type": "string"}, "default": []},
        "workingDirectory": {"$ref": "#/$defs/path"},
        "environment": {"type": "object", "propertyNames": {"minLength": 1, "pattern": "^[^=\\u0000]+$"}, "additionalProperties": {"type": "string"}}
      }
    }
  }
}
