use serde_json::json;
pub fn run() -> crate::error::Result<()> {
let schema = json!({
"clispec": "0.2",
"name": "sharepoint",
"version": env!("CARGO_PKG_VERSION"),
"description": "Agent-friendly SharePoint Online CLI with JSON output, structured exit codes, and schema introspection",
"global_args": [
{
"name": "--output",
"type": "string",
"enum": ["auto", "text", "json"],
"default": "auto",
"description": "Output format. auto emits JSON when stdout is not a TTY; text always emits human-friendly output; json always emits JSON."
},
{
"name": "-o",
"type": "string",
"enum": ["auto", "text", "json"],
"default": "auto",
"description": "Short alias for --output."
},
{
"name": "--quiet",
"type": "boolean",
"default": false,
"description": "Suppress informational messages on stderr."
},
{
"name": "--profile",
"type": "string",
"required": false,
"description": "Active config profile. Env: SHAREPOINT_PROFILE."
},
{
"name": "--tenant",
"type": "string",
"required": false,
"description": "Tenant ID or domain override. Env: SHAREPOINT_TENANT_ID."
},
{
"name": "--client-id",
"type": "string",
"required": false,
"description": "Azure app client ID override. Env: SHAREPOINT_CLIENT_ID."
}
],
"commands": [
{
"name": "auth",
"description": "Manage authentication tokens. Subcommands: login, logout, status.",
"mutating": true,
"subcommands": [
{
"name": "login",
"description": "Run the device-code flow and cache the resulting tokens.",
"mutating": true,
"args": [],
"output_fields": [
{"name": "username", "type": "string"},
{"name": "name", "type": "string"},
{"name": "tenant_id", "type": "string"}
]
},
{
"name": "logout",
"description": "Delete cached tokens for the active profile.",
"mutating": true,
"args": [],
"output_fields": [
{"name": "removed", "type": "integer"}
]
},
{
"name": "status",
"description": "Show cached account info, token expiry, and scopes. Works without network access.",
"mutating": false,
"args": [
{"name": "--limit", "type": "integer", "required": false, "default": 50, "description": "Maximum number of accounts to show."},
{"name": "--page", "type": "string", "required": false, "description": "Opaque pagination cursor from a previous response's `next` field."},
{"name": "--fields", "type": "string[]", "required": false, "description": "Comma-separated fields to include (e.g. username,expires_at)."}
],
"output_fields": [
{"name": "total", "type": "integer"},
{"name": "next", "type": "string | null"},
{"name": "items", "type": "object[]"}
]
}
]
},
{
"name": "config",
"description": "Inspect the resolved configuration. Subcommands: show, path.",
"mutating": true,
"subcommands": [
{
"name": "show",
"description": "Print the resolved config with secrets masked.",
"mutating": false,
"args": [],
"output_fields": [
{"name": "profile", "type": "string", "description": "Active profile name."},
{"name": "tenant_id", "type": "string | null", "description": "Azure AD tenant ID or domain."},
{"name": "client_id", "type": "string | null", "description": "Entra public-client app client ID."},
{"name": "default_site", "type": "string | null", "description": "Default SharePoint site name or URL for this profile."},
{"name": "read_only", "type": "boolean", "description": "Whether write operations are blocked for this profile."},
{"name": "site_aliases", "type": "object", "description": "Map of alias names to site URLs or names."},
{"name": "graph_endpoint", "type": "string", "description": "Microsoft Graph API base URL."},
{"name": "login_endpoint", "type": "string", "description": "Azure AD login base URL."},
{"name": "config_path", "type": "string", "description": "Absolute path to the resolved config file."},
{"name": "cache_path", "type": "string", "description": "Absolute path to the token cache directory."}
]
},
{
"name": "path",
"description": "Print the absolute path to the config file.",
"mutating": false,
"args": []
}
]
},
{
"name": "init",
"description": "Interactive setup: write a config profile and run the first device-code login.",
"mutating": true,
"args": [],
"output_fields": [
{"name": "username", "type": "string", "description": "UPN of the signed-in account (e.g. user@contoso.com)."},
{"name": "name", "type": "string", "description": "Display name of the signed-in account."},
{"name": "tenant_id", "type": "string", "description": "Azure AD tenant GUID for the signed-in account."}
]
},
{
"name": "sites use",
"description": "Set the default site for the active profile. Writes the config file; idempotent and safe to re-run.",
"mutating": true,
"args": [
{"name": "site", "type": "string", "required": true, "description": "Site name or URL."}
],
"output_fields": [
{"name": "profile", "type": "string"},
{"name": "default_site", "type": "string"}
]
},
{
"name": "sites",
"description": "Discover and select SharePoint sites. Subcommands: list, use.",
"mutating": true,
"subcommands": [
{
"name": "list",
"description": "List followed sites (default) or search by query.",
"mutating": false,
"args": [
{"name": "--query", "type": "string", "required": false, "description": "Search query; omit to list followed sites."},
{"name": "--limit", "type": "integer", "required": false, "default": 50, "description": "Maximum number of items to return."},
{"name": "--offset", "type": "integer", "required": false, "default": 0, "description": "Number of items to skip (applied client-side)."},
{"name": "--all", "type": "boolean", "required": false, "default": false, "description": "Fetch all pages (ignores --limit)."},
{"name": "--page", "type": "string", "required": false, "description": "Opaque pagination cursor from a previous response's `next` field."},
{"name": "--fields", "type": "string[]", "required": false, "description": "Comma-separated list of fields to include in each item (e.g. id,name,url)."}
],
"output_fields": [
{"name": "items", "type": "object[]"},
{"name": "total", "type": "integer"},
{"name": "next", "type": "string | null"},
{"name": "source", "type": "string"}
]
},
{
"name": "use",
"description": "Set the default site for the active profile.",
"mutating": true,
"args": [
{"name": "site", "type": "string", "required": true, "description": "Site name or URL."},
{"name": "--yes", "type": "boolean", "required": false, "default": false, "description": "Skip confirmation prompt (required when stdin is not a TTY)."}
],
"output_fields": [
{"name": "profile", "type": "string"},
{"name": "default_site", "type": "string"}
]
}
]
},
{
"name": "drives",
"description": "List document libraries (drives) for a site. Subcommands: list.",
"mutating": true,
"subcommands": [
{
"name": "list",
"description": "List drives (document libraries) for a site.",
"mutating": false,
"args": [
{"name": "site", "type": "string", "required": true, "description": "Site reference: URL, spo://SiteName, or 'default'."},
{"name": "--limit", "type": "integer", "required": false, "default": 50, "description": "Maximum number of items to return."},
{"name": "--all", "type": "boolean", "required": false, "default": false, "description": "Return all drives (ignores --limit)."},
{"name": "--fields", "type": "string[]", "required": false, "description": "Comma-separated fields to include in each item (e.g. id,name,drive_type)."}
],
"output_fields": [
{"name": "items", "type": "object[]"},
{"name": "total", "type": "integer"},
{"name": "next", "type": "string | null"}
]
}
]
},
{
"name": "files",
"description": "Browse, search, and download files from SharePoint drives. Subcommands: ls, stat, download, find.",
"mutating": true,
"subcommands": [
{
"name": "ls",
"description": "List items in a folder.",
"mutating": false,
"args": [
{"name": "REF", "type": "string", "required": true, "description": "Reference in the form Site:Library/path or spo://Site/Library/path."},
{"name": "--recursive", "type": "boolean", "required": false, "default": false, "description": "List all items recursively. Cannot be combined with --limit/--all/--page."},
{"name": "--limit", "type": "integer", "required": false, "default": 200, "description": "Maximum number of items per response."},
{"name": "--all", "type": "boolean", "required": false, "default": false, "description": "Fetch all pages."},
{"name": "--page", "type": "string", "required": false, "description": "Opaque pagination cursor from a previous response's `next` field."},
{"name": "--fields", "type": "string[]", "required": false, "description": "Comma-separated fields to include in each item (e.g. name,size,kind)."}
],
"output_fields": [
{"name": "items", "type": "object[]"},
{"name": "total", "type": "integer"},
{"name": "next", "type": "string | null"}
]
},
{
"name": "stat",
"description": "Show metadata for a single file or folder.",
"mutating": false,
"args": [
{"name": "REF", "type": "string", "required": true, "description": "Reference to the item."}
],
"output_fields": [
{"name": "id", "type": "string"},
{"name": "name", "type": "string"},
{"name": "kind", "type": "string"},
{"name": "size", "type": "integer"},
{"name": "modified", "type": "string | null"},
{"name": "download_url", "type": "string | null"},
{"name": "site", "type": "object"},
{"name": "drive", "type": "object"}
]
},
{
"name": "download",
"description": "Download a file to a local path or stdout.",
"mutating": false,
"args": [
{"name": "REF", "type": "string", "required": true, "description": "Reference to the file."},
{"name": "--path", "type": "path", "required": false, "description": "Destination path. Use `-` to write to stdout."},
{"name": "--overwrite", "type": "boolean", "required": false, "default": false, "description": "Overwrite the file if it already exists."}
],
"output_fields": [
{"name": "path", "type": "string"},
{"name": "bytes", "type": "integer"}
]
},
{
"name": "find",
"description": "Search for files by query and/or name glob.",
"mutating": false,
"args": [
{"name": "REF", "type": "string", "required": true, "description": "Drive root reference (Site:Library or spo://Site/Library)."},
{"name": "--query", "type": "string", "required": false, "description": "Full-text search query."},
{"name": "--name", "type": "string", "required": false, "description": "Shell glob to filter results by file name."},
{"name": "--limit", "type": "integer", "required": false, "default": 200, "description": "Maximum number of results."},
{"name": "--all", "type": "boolean", "required": false, "default": false, "description": "Fetch all pages."},
{"name": "--page", "type": "string", "required": false, "description": "Opaque pagination cursor from a previous response's `next` field."},
{"name": "--fields", "type": "string[]", "required": false, "description": "Comma-separated fields to include in each item."}
],
"output_fields": [
{"name": "items", "type": "object[]"},
{"name": "total", "type": "integer"},
{"name": "next", "type": "string | null"}
]
}
]
}
],
"errors": [
{
"kind": "input",
"exit_code": 2,
"retryable": false,
"description": "Bad user input, missing required argument, or invalid configuration."
},
{
"kind": "auth",
"exit_code": 3,
"retryable": false,
"description": "Authentication or token failure. Run `sharepoint auth login` to refresh."
},
{
"kind": "read_only",
"exit_code": 2,
"retryable": false,
"description": "Write operation blocked because SHAREPOINT_READ_ONLY=true or read_only=true in config."
},
{
"kind": "conflict",
"exit_code": 7,
"retryable": false,
"description": "Resource already exists with an incompatible configuration."
},
{
"kind": "not_found",
"exit_code": 4,
"retryable": false,
"description": "Site, drive, or item not found."
},
{
"kind": "api",
"exit_code": 5,
"retryable": false,
"description": "Microsoft Graph API returned a non-2xx response."
},
{
"kind": "rate_limit",
"exit_code": 6,
"retryable": true,
"description": "Too many requests; Microsoft Graph is rate-limiting this client."
},
{
"kind": "http",
"exit_code": 1,
"retryable": true,
"description": "Underlying HTTP transport error (network failure, TLS, timeout)."
},
{
"kind": "other",
"exit_code": 1,
"retryable": false,
"description": "Unexpected internal error."
}
]
});
println!(
"{}",
serde_json::to_string_pretty(&schema).expect("serialize schema")
);
Ok(())
}