pragmatiks-cli 0.5.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pragma_cli/__init__.py +32 -0
- pragma_cli/commands/__init__.py +1 -0
- pragma_cli/commands/auth.py +247 -0
- pragma_cli/commands/completions.py +54 -0
- pragma_cli/commands/config.py +79 -0
- pragma_cli/commands/dead_letter.py +233 -0
- pragma_cli/commands/ops.py +14 -0
- pragma_cli/commands/provider.py +1165 -0
- pragma_cli/commands/resources.py +199 -0
- pragma_cli/config.py +86 -0
- pragma_cli/helpers.py +21 -0
- pragma_cli/main.py +67 -0
- pragma_cli/py.typed +0 -0
- pragmatiks_cli-0.5.1.dist-info/METADATA +199 -0
- pragmatiks_cli-0.5.1.dist-info/RECORD +17 -0
- pragmatiks_cli-0.5.1.dist-info/WHEEL +4 -0
- pragmatiks_cli-0.5.1.dist-info/entry_points.txt +3 -0
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
"""CLI commands for resource management with lifecycle operations."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from typing import Annotated
|
|
8
|
+
|
|
9
|
+
import typer
|
|
10
|
+
import yaml
|
|
11
|
+
from rich import print
|
|
12
|
+
from rich.console import Console
|
|
13
|
+
from rich.markup import escape
|
|
14
|
+
|
|
15
|
+
from pragma_cli import get_client
|
|
16
|
+
from pragma_cli.commands.completions import (
|
|
17
|
+
completion_resource_ids,
|
|
18
|
+
completion_resource_names,
|
|
19
|
+
)
|
|
20
|
+
from pragma_cli.helpers import parse_resource_id
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
console = Console()
|
|
24
|
+
app = typer.Typer()
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def resolve_file_references(resource: dict, base_dir: Path) -> dict:
|
|
28
|
+
"""Resolve file references in secret resource config.
|
|
29
|
+
|
|
30
|
+
For pragma/secret resources, scans config.data values for '@' prefix
|
|
31
|
+
and replaces them with the file contents.
|
|
32
|
+
|
|
33
|
+
Args:
|
|
34
|
+
resource: Resource dictionary from YAML.
|
|
35
|
+
base_dir: Base directory for resolving relative paths.
|
|
36
|
+
|
|
37
|
+
Returns:
|
|
38
|
+
Resource dictionary with file references resolved.
|
|
39
|
+
|
|
40
|
+
Raises:
|
|
41
|
+
typer.Exit: If a referenced file is not found.
|
|
42
|
+
"""
|
|
43
|
+
is_secret = resource.get("provider") == "pragma" and resource.get("resource") == "secret"
|
|
44
|
+
if not is_secret:
|
|
45
|
+
return resource
|
|
46
|
+
|
|
47
|
+
config = resource.get("config")
|
|
48
|
+
if not config or not isinstance(config, dict):
|
|
49
|
+
return resource
|
|
50
|
+
|
|
51
|
+
data = config.get("data")
|
|
52
|
+
if not data or not isinstance(data, dict):
|
|
53
|
+
return resource
|
|
54
|
+
|
|
55
|
+
resolved_data = {}
|
|
56
|
+
for key, value in data.items():
|
|
57
|
+
if isinstance(value, str) and value.startswith("@"):
|
|
58
|
+
file_path = Path(value[1:])
|
|
59
|
+
if not file_path.is_absolute():
|
|
60
|
+
file_path = base_dir / file_path
|
|
61
|
+
|
|
62
|
+
if not file_path.exists():
|
|
63
|
+
console.print(f"[red]Error:[/red] File not found: {file_path}")
|
|
64
|
+
raise typer.Exit(1)
|
|
65
|
+
|
|
66
|
+
try:
|
|
67
|
+
resolved_data[key] = file_path.read_text()
|
|
68
|
+
except OSError as e:
|
|
69
|
+
console.print(f"[red]Error:[/red] Cannot read file {file_path}: {e}")
|
|
70
|
+
raise typer.Exit(1)
|
|
71
|
+
else:
|
|
72
|
+
resolved_data[key] = value
|
|
73
|
+
|
|
74
|
+
resolved_resource = resource.copy()
|
|
75
|
+
resolved_resource["config"] = {**config, "data": resolved_data}
|
|
76
|
+
return resolved_resource
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def format_state(state: str) -> str:
|
|
80
|
+
"""Format lifecycle state for display, escaping Rich markup.
|
|
81
|
+
|
|
82
|
+
Returns:
|
|
83
|
+
State string wrapped in brackets and escaped for Rich console.
|
|
84
|
+
"""
|
|
85
|
+
return escape(f"[{state}]")
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
@app.command("list")
|
|
89
|
+
def list_resources(
|
|
90
|
+
provider: Annotated[str | None, typer.Option("--provider", "-p", help="Filter by provider")] = None,
|
|
91
|
+
resource: Annotated[str | None, typer.Option("--resource", "-r", help="Filter by resource type")] = None,
|
|
92
|
+
tags: Annotated[list[str] | None, typer.Option("--tag", "-t", help="Filter by tags")] = None,
|
|
93
|
+
):
|
|
94
|
+
"""List resources, optionally filtered by provider, resource type, or tags."""
|
|
95
|
+
client = get_client()
|
|
96
|
+
for res in client.list_resources(provider=provider, resource=resource, tags=tags):
|
|
97
|
+
print(f"{res['provider']}/{res['resource']}/{res['name']} {format_state(res['lifecycle_state'])}")
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
@app.command()
|
|
101
|
+
def get(
|
|
102
|
+
resource_id: Annotated[str, typer.Argument(autocompletion=completion_resource_ids)],
|
|
103
|
+
name: Annotated[str | None, typer.Argument(autocompletion=completion_resource_names)] = None,
|
|
104
|
+
):
|
|
105
|
+
"""Get resources by provider/resource type, optionally filtered by name."""
|
|
106
|
+
client = get_client()
|
|
107
|
+
provider, resource = parse_resource_id(resource_id)
|
|
108
|
+
if name:
|
|
109
|
+
res = client.get_resource(provider=provider, resource=resource, name=name)
|
|
110
|
+
print(f"{resource_id}/{res['name']} {format_state(res['lifecycle_state'])}")
|
|
111
|
+
else:
|
|
112
|
+
for res in client.list_resources(provider=provider, resource=resource):
|
|
113
|
+
print(f"{resource_id}/{res['name']} {format_state(res['lifecycle_state'])}")
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
@app.command()
|
|
117
|
+
def apply(
|
|
118
|
+
file: list[typer.FileText],
|
|
119
|
+
pending: Annotated[
|
|
120
|
+
bool, typer.Option("--pending", "-p", help="Queue for processing (set lifecycle_state to PENDING)")
|
|
121
|
+
] = False,
|
|
122
|
+
):
|
|
123
|
+
"""Apply resources from YAML files (multi-document supported).
|
|
124
|
+
|
|
125
|
+
By default, resources are created in DRAFT state (not processed).
|
|
126
|
+
Use --pending to queue for immediate processing.
|
|
127
|
+
|
|
128
|
+
For pragma/secret resources, file references in config.data values
|
|
129
|
+
are resolved before submission. Use '@path/to/file' syntax to inline
|
|
130
|
+
file contents.
|
|
131
|
+
"""
|
|
132
|
+
client = get_client()
|
|
133
|
+
for f in file:
|
|
134
|
+
base_dir = Path(f.name).parent
|
|
135
|
+
resources = yaml.safe_load_all(f.read())
|
|
136
|
+
|
|
137
|
+
for resource in resources:
|
|
138
|
+
resource = resolve_file_references(resource, base_dir)
|
|
139
|
+
if pending:
|
|
140
|
+
resource["lifecycle_state"] = "pending"
|
|
141
|
+
result = client.apply_resource(resource=resource)
|
|
142
|
+
res_id = f"{result['provider']}/{result['resource']}/{result['name']}"
|
|
143
|
+
print(f"Applied {res_id} {format_state(result['lifecycle_state'])}")
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
@app.command()
|
|
147
|
+
def delete(
|
|
148
|
+
resource_id: Annotated[str, typer.Argument(autocompletion=completion_resource_ids)],
|
|
149
|
+
name: Annotated[str, typer.Argument(autocompletion=completion_resource_names)],
|
|
150
|
+
):
|
|
151
|
+
"""Delete a resource."""
|
|
152
|
+
client = get_client()
|
|
153
|
+
provider, resource = parse_resource_id(resource_id)
|
|
154
|
+
client.delete_resource(provider=provider, resource=resource, name=name)
|
|
155
|
+
print(f"Deleted {resource_id}/{name}")
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
@app.command()
|
|
159
|
+
def register(
|
|
160
|
+
resource_id: Annotated[str, typer.Argument(help="Resource type in provider/resource format")],
|
|
161
|
+
description: Annotated[str | None, typer.Option("--description", "-d", help="Resource type description")] = None,
|
|
162
|
+
schema_file: Annotated[typer.FileText | None, typer.Option("--schema", "-s", help="JSON schema file")] = None,
|
|
163
|
+
tags: Annotated[list[str] | None, typer.Option("--tag", "-t", help="Tags for categorization")] = None,
|
|
164
|
+
):
|
|
165
|
+
"""Register a new resource type.
|
|
166
|
+
|
|
167
|
+
Registers a resource type so that resources of this type can be created.
|
|
168
|
+
Providers use this to declare what resources they can manage.
|
|
169
|
+
"""
|
|
170
|
+
client = get_client()
|
|
171
|
+
provider, resource = parse_resource_id(resource_id)
|
|
172
|
+
|
|
173
|
+
schema = None
|
|
174
|
+
if schema_file:
|
|
175
|
+
schema = json.load(schema_file)
|
|
176
|
+
|
|
177
|
+
client.register_resource(
|
|
178
|
+
provider=provider,
|
|
179
|
+
resource=resource,
|
|
180
|
+
schema=schema,
|
|
181
|
+
description=description,
|
|
182
|
+
tags=tags,
|
|
183
|
+
)
|
|
184
|
+
print(f"Registered {resource_id}")
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
@app.command()
|
|
188
|
+
def unregister(
|
|
189
|
+
resource_id: Annotated[str, typer.Argument(autocompletion=completion_resource_ids)],
|
|
190
|
+
):
|
|
191
|
+
"""Unregister a resource type.
|
|
192
|
+
|
|
193
|
+
Removes a resource type registration. Existing resources of this type
|
|
194
|
+
will no longer be manageable.
|
|
195
|
+
"""
|
|
196
|
+
client = get_client()
|
|
197
|
+
provider, resource = parse_resource_id(resource_id)
|
|
198
|
+
client.unregister_resource(provider=provider, resource=resource)
|
|
199
|
+
print(f"Unregistered {resource_id}")
|
pragma_cli/config.py
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"""CLI configuration management for contexts and credentials."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
import yaml
|
|
9
|
+
from pydantic import BaseModel
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def _get_config_dir() -> Path:
|
|
13
|
+
"""Get the configuration directory following XDG Base Directory specification.
|
|
14
|
+
|
|
15
|
+
Returns:
|
|
16
|
+
Path to configuration directory (~/.config/pragma by default).
|
|
17
|
+
"""
|
|
18
|
+
xdg_config_home = os.getenv("XDG_CONFIG_HOME")
|
|
19
|
+
if xdg_config_home:
|
|
20
|
+
return Path(xdg_config_home) / "pragma"
|
|
21
|
+
return Path.home() / ".config" / "pragma"
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
CONFIG_DIR = _get_config_dir()
|
|
25
|
+
CONFIG_PATH = CONFIG_DIR / "config"
|
|
26
|
+
CREDENTIALS_FILE = CONFIG_DIR / "credentials"
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class ContextConfig(BaseModel):
|
|
30
|
+
"""Configuration for a single CLI context."""
|
|
31
|
+
|
|
32
|
+
api_url: str
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class PragmaConfig(BaseModel):
|
|
36
|
+
"""CLI configuration with multiple named contexts."""
|
|
37
|
+
|
|
38
|
+
current_context: str
|
|
39
|
+
contexts: dict[str, ContextConfig]
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def load_config() -> PragmaConfig:
|
|
43
|
+
"""Load config from ~/.config/pragma/config.
|
|
44
|
+
|
|
45
|
+
Returns:
|
|
46
|
+
PragmaConfig with contexts loaded from file, or default if not found.
|
|
47
|
+
"""
|
|
48
|
+
if not CONFIG_PATH.exists():
|
|
49
|
+
return PragmaConfig(
|
|
50
|
+
current_context="default", contexts={"default": ContextConfig(api_url="https://api.pragmatiks.io")}
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
with open(CONFIG_PATH) as f:
|
|
54
|
+
data = yaml.safe_load(f)
|
|
55
|
+
return PragmaConfig.model_validate(data)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def save_config(config: PragmaConfig):
|
|
59
|
+
"""Save config to ~/.config/pragma/config."""
|
|
60
|
+
CONFIG_PATH.parent.mkdir(parents=True, exist_ok=True)
|
|
61
|
+
with open(CONFIG_PATH, "w") as f:
|
|
62
|
+
yaml.safe_dump(config.model_dump(), f)
|
|
63
|
+
CONFIG_PATH.chmod(0o644)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def get_current_context(context_name: str | None = None) -> tuple[str, ContextConfig]:
|
|
67
|
+
"""Get context name and configuration.
|
|
68
|
+
|
|
69
|
+
Args:
|
|
70
|
+
context_name: Explicit context name. If None, uses current context from config.
|
|
71
|
+
|
|
72
|
+
Returns:
|
|
73
|
+
Tuple of (context_name, context_config).
|
|
74
|
+
|
|
75
|
+
Raises:
|
|
76
|
+
ValueError: If context not found in configuration.
|
|
77
|
+
"""
|
|
78
|
+
config = load_config()
|
|
79
|
+
|
|
80
|
+
if context_name is None:
|
|
81
|
+
context_name = config.current_context
|
|
82
|
+
|
|
83
|
+
if context_name not in config.contexts:
|
|
84
|
+
raise ValueError(f"Context '{context_name}' not found in configuration")
|
|
85
|
+
|
|
86
|
+
return context_name, config.contexts[context_name]
|
pragma_cli/helpers.py
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"""CLI helper functions for parsing resource identifiers."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def parse_resource_id(resource_id: str) -> tuple[str, str]:
|
|
7
|
+
"""Parse resource identifier into provider and resource type.
|
|
8
|
+
|
|
9
|
+
Args:
|
|
10
|
+
resource_id: Resource identifier in format 'provider/resource'.
|
|
11
|
+
|
|
12
|
+
Returns:
|
|
13
|
+
Tuple of (provider, resource).
|
|
14
|
+
|
|
15
|
+
Raises:
|
|
16
|
+
ValueError: If resource_id format is invalid.
|
|
17
|
+
"""
|
|
18
|
+
if "/" not in resource_id:
|
|
19
|
+
raise ValueError(f"Invalid resource ID format: {resource_id}. Expected 'provider/resource'.")
|
|
20
|
+
provider, resource = resource_id.split("/", 1)
|
|
21
|
+
return provider, resource
|
pragma_cli/main.py
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"""CLI entry point with Typer application setup and command routing."""
|
|
2
|
+
|
|
3
|
+
from typing import Annotated
|
|
4
|
+
|
|
5
|
+
import typer
|
|
6
|
+
from pragma_sdk import PragmaClient
|
|
7
|
+
|
|
8
|
+
from pragma_cli import set_client
|
|
9
|
+
from pragma_cli.commands import auth, config, ops, provider, resources
|
|
10
|
+
from pragma_cli.config import get_current_context
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
app = typer.Typer()
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@app.callback()
|
|
17
|
+
def main(
|
|
18
|
+
ctx: typer.Context,
|
|
19
|
+
context: Annotated[
|
|
20
|
+
str | None,
|
|
21
|
+
typer.Option(
|
|
22
|
+
"--context",
|
|
23
|
+
"-c",
|
|
24
|
+
help="Configuration context to use",
|
|
25
|
+
envvar="PRAGMA_CONTEXT",
|
|
26
|
+
),
|
|
27
|
+
] = None,
|
|
28
|
+
token: Annotated[
|
|
29
|
+
str | None,
|
|
30
|
+
typer.Option(
|
|
31
|
+
"--token",
|
|
32
|
+
"-t",
|
|
33
|
+
help="Override authentication token (not recommended, use environment variable instead)",
|
|
34
|
+
),
|
|
35
|
+
] = None,
|
|
36
|
+
):
|
|
37
|
+
"""Pragma CLI - Declarative resource management.
|
|
38
|
+
|
|
39
|
+
Authentication (industry-standard pattern):
|
|
40
|
+
- CLI writes credentials: 'pragma login' stores tokens in ~/.config/pragma/credentials
|
|
41
|
+
- SDK reads credentials: Automatic token discovery via precedence chain
|
|
42
|
+
|
|
43
|
+
Token Discovery Precedence:
|
|
44
|
+
1. --token flag (explicit override)
|
|
45
|
+
2. PRAGMA_AUTH_TOKEN_<CONTEXT> context-specific environment variable
|
|
46
|
+
3. PRAGMA_AUTH_TOKEN environment variable
|
|
47
|
+
4. ~/.config/pragma/credentials file (from pragma login)
|
|
48
|
+
5. No authentication
|
|
49
|
+
"""
|
|
50
|
+
context_name, context_config = get_current_context(context)
|
|
51
|
+
|
|
52
|
+
if token:
|
|
53
|
+
client = PragmaClient(base_url=context_config.api_url, auth_token=token)
|
|
54
|
+
else:
|
|
55
|
+
client = PragmaClient(base_url=context_config.api_url, context=context_name, require_auth=False)
|
|
56
|
+
|
|
57
|
+
set_client(client)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
app.add_typer(resources.app, name="resources")
|
|
61
|
+
app.add_typer(auth.app, name="auth")
|
|
62
|
+
app.add_typer(config.app, name="config")
|
|
63
|
+
app.add_typer(ops.app, name="ops")
|
|
64
|
+
app.add_typer(provider.app, name="provider")
|
|
65
|
+
|
|
66
|
+
if __name__ == "__main__": # pragma: no cover
|
|
67
|
+
app()
|
pragma_cli/py.typed
ADDED
|
File without changes
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: pragmatiks-cli
|
|
3
|
+
Version: 0.5.1
|
|
4
|
+
Summary: Command-line interface for Pragmatiks
|
|
5
|
+
Requires-Dist: typer>=0.15.3
|
|
6
|
+
Requires-Dist: pragmatiks-sdk>=0.6.0
|
|
7
|
+
Requires-Dist: pyyaml>=6.0.3
|
|
8
|
+
Requires-Dist: copier>=9.0.0
|
|
9
|
+
Requires-Dist: rich>=13.9.0
|
|
10
|
+
Requires-Python: >=3.13
|
|
11
|
+
Description-Content-Type: text/markdown
|
|
12
|
+
|
|
13
|
+
# Pragmatiks CLI
|
|
14
|
+
|
|
15
|
+
[](https://deepwiki.com/pragmatiks/cli)
|
|
16
|
+
[](https://pypi.org/project/pragmatiks-cli/)
|
|
17
|
+
[](https://www.python.org/downloads/)
|
|
18
|
+
[](https://opensource.org/licenses/MIT)
|
|
19
|
+
[](https://github.com/astral-sh/ruff)
|
|
20
|
+
|
|
21
|
+
**[Documentation](https://docs.pragmatiks.io/cli/overview)** | **[SDK](https://github.com/pragmatiks/sdk)** | **[Providers](https://github.com/pragmatiks/providers)**
|
|
22
|
+
|
|
23
|
+
Command-line interface for managing Pragmatiks resources.
|
|
24
|
+
|
|
25
|
+
<!-- TODO: Add logo and demo GIF -->
|
|
26
|
+
|
|
27
|
+
## Quick Start
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
# Authenticate
|
|
31
|
+
pragma auth login
|
|
32
|
+
|
|
33
|
+
# Apply a resource
|
|
34
|
+
pragma resources apply bucket.yaml
|
|
35
|
+
|
|
36
|
+
# Check status
|
|
37
|
+
pragma resources get gcp/storage my-bucket
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Installation
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
pip install pragmatiks-cli
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Or with uv:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
uv add pragmatiks-cli
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Enable shell completion for intelligent command-line assistance:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
pragma --install-completion
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Features
|
|
59
|
+
|
|
60
|
+
- **Declarative Resources** - Apply, get, and delete resources with YAML manifests
|
|
61
|
+
- **Smart Completion** - Tab completion for providers, resources, and names
|
|
62
|
+
- **Provider Development** - Initialize, sync, and deploy custom providers
|
|
63
|
+
- **Multi-document Support** - Apply multiple resources from a single YAML file
|
|
64
|
+
|
|
65
|
+
## Resource Management
|
|
66
|
+
|
|
67
|
+
### Apply Resources
|
|
68
|
+
|
|
69
|
+
```yaml
|
|
70
|
+
# bucket.yaml
|
|
71
|
+
provider: gcp
|
|
72
|
+
resource: storage
|
|
73
|
+
name: my-bucket
|
|
74
|
+
config:
|
|
75
|
+
location: US
|
|
76
|
+
storage_class: STANDARD
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
# Apply from file
|
|
81
|
+
pragma resources apply bucket.yaml
|
|
82
|
+
|
|
83
|
+
# Apply multiple files
|
|
84
|
+
pragma resources apply *.yaml
|
|
85
|
+
|
|
86
|
+
# Apply with pending flag to execute immediately
|
|
87
|
+
pragma resources apply --pending bucket.yaml
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### List and Get Resources
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
# List all resources
|
|
94
|
+
pragma resources list
|
|
95
|
+
|
|
96
|
+
# Filter by provider
|
|
97
|
+
pragma resources list --provider gcp
|
|
98
|
+
|
|
99
|
+
# Filter by resource type
|
|
100
|
+
pragma resources list --resource storage
|
|
101
|
+
|
|
102
|
+
# Get specific resource
|
|
103
|
+
pragma resources get gcp/storage my-bucket
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### Delete Resources
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
pragma resources delete gcp/storage my-bucket
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## Provider Development
|
|
113
|
+
|
|
114
|
+
Build and deploy custom providers:
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
# Initialize a new provider project
|
|
118
|
+
pragma provider init mycompany
|
|
119
|
+
|
|
120
|
+
# Sync resource schemas with the platform
|
|
121
|
+
pragma provider sync
|
|
122
|
+
|
|
123
|
+
# Build and deploy
|
|
124
|
+
pragma provider push --deploy
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## Authentication
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
# Login (opens browser)
|
|
131
|
+
pragma auth login
|
|
132
|
+
|
|
133
|
+
# Check current user
|
|
134
|
+
pragma auth whoami
|
|
135
|
+
|
|
136
|
+
# Logout
|
|
137
|
+
pragma auth logout
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## Configuration
|
|
141
|
+
|
|
142
|
+
Set environment variables to configure the CLI:
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
export PRAGMA_API_URL=https://api.pragmatiks.io
|
|
146
|
+
export PRAGMA_AUTH_TOKEN=sk_...
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
## Command Reference
|
|
150
|
+
|
|
151
|
+
### Resources
|
|
152
|
+
|
|
153
|
+
| Command | Description |
|
|
154
|
+
|---------|-------------|
|
|
155
|
+
| `pragma resources list` | List resources with optional filters |
|
|
156
|
+
| `pragma resources get <provider/resource> <name>` | Get a specific resource |
|
|
157
|
+
| `pragma resources apply <file>` | Apply resources from YAML |
|
|
158
|
+
| `pragma resources delete <provider/resource> <name>` | Delete a resource |
|
|
159
|
+
|
|
160
|
+
### Providers
|
|
161
|
+
|
|
162
|
+
| Command | Description |
|
|
163
|
+
|---------|-------------|
|
|
164
|
+
| `pragma provider init <name>` | Initialize a new provider project |
|
|
165
|
+
| `pragma provider sync` | Sync resource schemas with platform |
|
|
166
|
+
| `pragma provider push` | Build and push provider image |
|
|
167
|
+
| `pragma provider push --deploy` | Build, push, and deploy |
|
|
168
|
+
|
|
169
|
+
### Authentication
|
|
170
|
+
|
|
171
|
+
| Command | Description |
|
|
172
|
+
|---------|-------------|
|
|
173
|
+
| `pragma auth login` | Authenticate with the platform |
|
|
174
|
+
| `pragma auth whoami` | Show current user |
|
|
175
|
+
| `pragma auth logout` | Clear credentials |
|
|
176
|
+
|
|
177
|
+
### Operations
|
|
178
|
+
|
|
179
|
+
| Command | Description |
|
|
180
|
+
|---------|-------------|
|
|
181
|
+
| `pragma ops dead-letter list` | List failed events |
|
|
182
|
+
| `pragma ops dead-letter retry <id>` | Retry a failed event |
|
|
183
|
+
|
|
184
|
+
## Development
|
|
185
|
+
|
|
186
|
+
```bash
|
|
187
|
+
# Run tests
|
|
188
|
+
task cli:test
|
|
189
|
+
|
|
190
|
+
# Format code
|
|
191
|
+
task cli:format
|
|
192
|
+
|
|
193
|
+
# Type check and lint
|
|
194
|
+
task cli:check
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
## License
|
|
198
|
+
|
|
199
|
+
MIT
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
pragma_cli/__init__.py,sha256=9REbOdKs9CeuOd-rxeFs17gWtou1dUdCogYU8G5Cz6c,682
|
|
2
|
+
pragma_cli/commands/__init__.py,sha256=zltFPaCZgkeTdOH1YWrUEqqBF9Dg6tokgAFcmqP4_n4,24
|
|
3
|
+
pragma_cli/commands/auth.py,sha256=6VqLTD8sZ7LRmI8RXEkSze1Ctnq5oM_1Zv0Br-HuFIA,8198
|
|
4
|
+
pragma_cli/commands/completions.py,sha256=ZCW38A1-6l_IcGC7Gj2CP5VL6PzaY4zKdcxylDuCoWM,1609
|
|
5
|
+
pragma_cli/commands/config.py,sha256=Bow71Tg_zeprHlbn_6y8g2YsV_k9nRobA6ooYfaxtWE,2281
|
|
6
|
+
pragma_cli/commands/dead_letter.py,sha256=8Mh_QVZiwkbOA1fYkw1O9BeHgPdqepis6tSJOAY3vhA,6754
|
|
7
|
+
pragma_cli/commands/ops.py,sha256=ztx0Gx2L2mEqJQpbgDHgfOUZ4uaD132NxgKohaPOWv8,361
|
|
8
|
+
pragma_cli/commands/provider.py,sha256=BX1NqGbH9XOrYFrWb92UpZhjTJA5qJ_U6cppMB1_lq0,36271
|
|
9
|
+
pragma_cli/commands/resources.py,sha256=BzwFKK5vqDo37wUPwRkulKdC4TFEJEoSXLlzsxQFD6w,6904
|
|
10
|
+
pragma_cli/config.py,sha256=kcU4tJUV1DfnXC_ydQbgQoJzjdGB1s-6-7g4cwA1nZw,2340
|
|
11
|
+
pragma_cli/helpers.py,sha256=dVxokT-sqF08oY0O35QZ64QyNC0PHZEBJYTvZ726UtI,650
|
|
12
|
+
pragma_cli/main.py,sha256=3UAKMsgc5u2v55ykWy-o_XC5W2CwyDNGfTSFhSvsLfU,1970
|
|
13
|
+
pragma_cli/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
14
|
+
pragmatiks_cli-0.5.1.dist-info/WHEEL,sha256=XjEbIc5-wIORjWaafhI6vBtlxDBp7S9KiujWF1EM7Ak,79
|
|
15
|
+
pragmatiks_cli-0.5.1.dist-info/entry_points.txt,sha256=9xeQQlnHxq94dks6mlJ2I9LuMUKmqxuJzyKSZCb9iJM,48
|
|
16
|
+
pragmatiks_cli-0.5.1.dist-info/METADATA,sha256=N3AEoBl0p7bLIpxYtZtI7mltnY4xdKVHnO9iSIg4njs,4400
|
|
17
|
+
pragmatiks_cli-0.5.1.dist-info/RECORD,,
|