ChatCoolify 0.2.0__tar.gz → 0.2.1__tar.gz
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.
- {chatcoolify-0.2.0/src/ChatCoolify.egg-info → chatcoolify-0.2.1}/PKG-INFO +8 -2
- {chatcoolify-0.2.0 → chatcoolify-0.2.1}/README.md +2 -0
- {chatcoolify-0.2.0 → chatcoolify-0.2.1}/pyproject.toml +5 -2
- {chatcoolify-0.2.0 → chatcoolify-0.2.1/src/ChatCoolify.egg-info}/PKG-INFO +8 -2
- {chatcoolify-0.2.0 → chatcoolify-0.2.1}/src/ChatCoolify.egg-info/SOURCES.txt +9 -0
- {chatcoolify-0.2.0 → chatcoolify-0.2.1}/src/ChatCoolify.egg-info/requires.txt +6 -1
- {chatcoolify-0.2.0 → chatcoolify-0.2.1}/src/chatcoolify/__init__.py +10 -1
- {chatcoolify-0.2.0 → chatcoolify-0.2.1}/src/chatcoolify/cli.py +6 -27
- {chatcoolify-0.2.0 → chatcoolify-0.2.1}/src/chatcoolify/client.py +4 -1
- chatcoolify-0.2.1/src/chatcoolify/config.py +81 -0
- chatcoolify-0.2.1/src/chatcoolify/platform.py +670 -0
- chatcoolify-0.2.1/src/chatcoolify/platform_artifact.py +113 -0
- chatcoolify-0.2.1/src/chatcoolify/platform_backend.py +103 -0
- chatcoolify-0.2.1/src/chatcoolify/platform_cli.py +258 -0
- chatcoolify-0.2.1/src/chatcoolify/platform_client.py +105 -0
- chatcoolify-0.2.1/src/chatcoolify/platform_runtime.py +207 -0
- chatcoolify-0.2.1/src/chatcoolify/platform_source.py +86 -0
- chatcoolify-0.2.1/src/chatcoolify/platform_web.py +214 -0
- {chatcoolify-0.2.0 → chatcoolify-0.2.1}/tests/test_cli.py +4 -2
- chatcoolify-0.2.1/tests/test_platform.py +293 -0
- chatcoolify-0.2.0/src/chatcoolify/config.py +0 -48
- {chatcoolify-0.2.0 → chatcoolify-0.2.1}/LICENSE +0 -0
- {chatcoolify-0.2.0 → chatcoolify-0.2.1}/setup.cfg +0 -0
- {chatcoolify-0.2.0 → chatcoolify-0.2.1}/src/ChatCoolify.egg-info/dependency_links.txt +0 -0
- {chatcoolify-0.2.0 → chatcoolify-0.2.1}/src/ChatCoolify.egg-info/entry_points.txt +0 -0
- {chatcoolify-0.2.0 → chatcoolify-0.2.1}/src/ChatCoolify.egg-info/top_level.txt +0 -0
- {chatcoolify-0.2.0 → chatcoolify-0.2.1}/tests/test_client.py +0 -0
- {chatcoolify-0.2.0 → chatcoolify-0.2.1}/tests/test_release_contract.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ChatCoolify
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.1
|
|
4
4
|
Summary: AI-safe Python client and CLI for the official Coolify API
|
|
5
5
|
Author-email: ChatArch <1073853456@qq.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -19,8 +19,12 @@ Classifier: Programming Language :: Python :: 3.12
|
|
|
19
19
|
Requires-Python: >=3.10
|
|
20
20
|
Description-Content-Type: text/markdown
|
|
21
21
|
License-File: LICENSE
|
|
22
|
-
Requires-Dist: chatenv<0.3.0,>=0.2.
|
|
22
|
+
Requires-Dist: chatenv<0.3.0,>=0.2.10
|
|
23
|
+
Requires-Dist: chatstyle<0.3.0,>=0.2.0
|
|
24
|
+
Requires-Dist: chatlogin<0.3.0,>=0.2.1
|
|
23
25
|
Requires-Dist: click<9.0,>=8.1
|
|
26
|
+
Provides-Extra: comments
|
|
27
|
+
Requires-Dist: ChatComment<0.3.0,>=0.2.0; extra == "comments"
|
|
24
28
|
Provides-Extra: dev
|
|
25
29
|
Requires-Dist: build<2.0,>=1.2; extra == "dev"
|
|
26
30
|
Requires-Dist: pytest<10.0,>=8.0; extra == "dev"
|
|
@@ -64,6 +68,8 @@ coolify --tree
|
|
|
64
68
|
|
|
65
69
|
## 最快开始
|
|
66
70
|
|
|
71
|
+
已有平台账号可通过 `coolify platform` 完成本地目录上传、原生预览、显式发布及回退;平台按项目授权,普通用户不持有原生 Team token。见[本地项目平台](docs/platform.md)。以下保留原生 Coolify 客户端用法,其写操作仍需 `--allow-write`。
|
|
72
|
+
|
|
67
73
|
```bash
|
|
68
74
|
coolify --base-url https://<coolify-url> health
|
|
69
75
|
```
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "ChatCoolify"
|
|
7
|
-
version = "0.2.
|
|
7
|
+
version = "0.2.1"
|
|
8
8
|
description = "AI-safe Python client and CLI for the official Coolify API"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.10"
|
|
@@ -21,7 +21,9 @@ classifiers = [
|
|
|
21
21
|
"Programming Language :: Python :: 3.12",
|
|
22
22
|
]
|
|
23
23
|
dependencies = [
|
|
24
|
-
"chatenv>=0.2.
|
|
24
|
+
"chatenv>=0.2.10,<0.3.0",
|
|
25
|
+
"chatstyle>=0.2.0,<0.3.0",
|
|
26
|
+
"chatlogin>=0.2.1,<0.3.0",
|
|
25
27
|
"click>=8.1,<9.0",
|
|
26
28
|
]
|
|
27
29
|
|
|
@@ -38,6 +40,7 @@ coolify = "chatcoolify.cli:main"
|
|
|
38
40
|
chatcoolify = "chatcoolify.config"
|
|
39
41
|
|
|
40
42
|
[project.optional-dependencies]
|
|
43
|
+
comments = ["ChatComment>=0.2.0,<0.3.0"]
|
|
41
44
|
dev = [
|
|
42
45
|
"build>=1.2,<2.0",
|
|
43
46
|
"pytest>=8.0,<10.0",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ChatCoolify
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.1
|
|
4
4
|
Summary: AI-safe Python client and CLI for the official Coolify API
|
|
5
5
|
Author-email: ChatArch <1073853456@qq.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -19,8 +19,12 @@ Classifier: Programming Language :: Python :: 3.12
|
|
|
19
19
|
Requires-Python: >=3.10
|
|
20
20
|
Description-Content-Type: text/markdown
|
|
21
21
|
License-File: LICENSE
|
|
22
|
-
Requires-Dist: chatenv<0.3.0,>=0.2.
|
|
22
|
+
Requires-Dist: chatenv<0.3.0,>=0.2.10
|
|
23
|
+
Requires-Dist: chatstyle<0.3.0,>=0.2.0
|
|
24
|
+
Requires-Dist: chatlogin<0.3.0,>=0.2.1
|
|
23
25
|
Requires-Dist: click<9.0,>=8.1
|
|
26
|
+
Provides-Extra: comments
|
|
27
|
+
Requires-Dist: ChatComment<0.3.0,>=0.2.0; extra == "comments"
|
|
24
28
|
Provides-Extra: dev
|
|
25
29
|
Requires-Dist: build<2.0,>=1.2; extra == "dev"
|
|
26
30
|
Requires-Dist: pytest<10.0,>=8.0; extra == "dev"
|
|
@@ -64,6 +68,8 @@ coolify --tree
|
|
|
64
68
|
|
|
65
69
|
## 最快开始
|
|
66
70
|
|
|
71
|
+
已有平台账号可通过 `coolify platform` 完成本地目录上传、原生预览、显式发布及回退;平台按项目授权,普通用户不持有原生 Team token。见[本地项目平台](docs/platform.md)。以下保留原生 Coolify 客户端用法,其写操作仍需 `--allow-write`。
|
|
72
|
+
|
|
67
73
|
```bash
|
|
68
74
|
coolify --base-url https://<coolify-url> health
|
|
69
75
|
```
|
|
@@ -11,6 +11,15 @@ src/chatcoolify/__init__.py
|
|
|
11
11
|
src/chatcoolify/cli.py
|
|
12
12
|
src/chatcoolify/client.py
|
|
13
13
|
src/chatcoolify/config.py
|
|
14
|
+
src/chatcoolify/platform.py
|
|
15
|
+
src/chatcoolify/platform_artifact.py
|
|
16
|
+
src/chatcoolify/platform_backend.py
|
|
17
|
+
src/chatcoolify/platform_cli.py
|
|
18
|
+
src/chatcoolify/platform_client.py
|
|
19
|
+
src/chatcoolify/platform_runtime.py
|
|
20
|
+
src/chatcoolify/platform_source.py
|
|
21
|
+
src/chatcoolify/platform_web.py
|
|
14
22
|
tests/test_cli.py
|
|
15
23
|
tests/test_client.py
|
|
24
|
+
tests/test_platform.py
|
|
16
25
|
tests/test_release_contract.py
|
|
@@ -10,7 +10,12 @@ from .client import (
|
|
|
10
10
|
PublicApplicationSpec,
|
|
11
11
|
)
|
|
12
12
|
|
|
13
|
-
__version__ = "0.2.
|
|
13
|
+
__version__ = "0.2.1"
|
|
14
|
+
|
|
15
|
+
from .platform import PlatformService
|
|
16
|
+
from .platform_client import PlatformClient
|
|
17
|
+
from .platform_artifact import PlatformError
|
|
18
|
+
from .platform_backend import CoolifyBackend
|
|
14
19
|
|
|
15
20
|
__all__ = [
|
|
16
21
|
"DEFAULT_BASE_URL",
|
|
@@ -20,5 +25,9 @@ __all__ = [
|
|
|
20
25
|
"CoolifyError",
|
|
21
26
|
"CoolifyPermissionError",
|
|
22
27
|
"PublicApplicationSpec",
|
|
28
|
+
"PlatformService",
|
|
29
|
+
"PlatformClient",
|
|
30
|
+
"PlatformError",
|
|
31
|
+
"CoolifyBackend",
|
|
23
32
|
"__version__",
|
|
24
33
|
]
|
|
@@ -6,6 +6,7 @@ import json
|
|
|
6
6
|
from typing import Any
|
|
7
7
|
|
|
8
8
|
import click
|
|
9
|
+
from chatstyle import add_tree_option
|
|
9
10
|
|
|
10
11
|
from . import __version__
|
|
11
12
|
from .client import DEFAULT_BASE_URL, CoolifyClient, CoolifyError, PublicApplicationSpec
|
|
@@ -26,35 +27,9 @@ def _handle_error(error: CoolifyError) -> None:
|
|
|
26
27
|
raise click.ClickException(str(error)) from error
|
|
27
28
|
|
|
28
29
|
|
|
29
|
-
def _render_tree(command: click.Group, *, brief: bool) -> str:
|
|
30
|
-
"""Render the registered CLI surface instead of maintaining docs by hand."""
|
|
31
|
-
|
|
32
|
-
options = ["--help", "--version", "--tree", "--tree-brief", "--base-url", "--allow-write"]
|
|
33
|
-
lines = [command.name or "coolify"]
|
|
34
|
-
for option in options:
|
|
35
|
-
lines.append(f"|- {option}")
|
|
36
|
-
commands = sorted(command.commands.values(), key=lambda item: item.name)
|
|
37
|
-
for index, subcommand in enumerate(commands):
|
|
38
|
-
connector = "`-" if index == len(commands) - 1 else "|-"
|
|
39
|
-
suffix = "" if brief else f" # {subcommand.help or subcommand.short_help or ''}".rstrip()
|
|
40
|
-
lines.append(f"{connector} {subcommand.name}{suffix}")
|
|
41
|
-
return "\n".join(lines)
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
def _tree_callback(brief: bool):
|
|
45
|
-
def callback(ctx: click.Context, _param: click.Parameter, value: bool) -> None:
|
|
46
|
-
if not value or ctx.resilient_parsing:
|
|
47
|
-
return
|
|
48
|
-
click.echo(_render_tree(ctx.command, brief=brief))
|
|
49
|
-
ctx.exit()
|
|
50
|
-
|
|
51
|
-
return callback
|
|
52
|
-
|
|
53
|
-
|
|
54
30
|
@click.group(name="coolify", context_settings=CONTEXT_SETTINGS)
|
|
55
31
|
@click.version_option(__version__, prog_name="coolify")
|
|
56
|
-
@
|
|
57
|
-
@click.option("--tree-brief", is_flag=True, is_eager=True, expose_value=False, callback=_tree_callback(True), help="Print the registered command tree without descriptions.")
|
|
32
|
+
@add_tree_option()
|
|
58
33
|
@click.option(
|
|
59
34
|
"--base-url",
|
|
60
35
|
envvar="COOLIFY_BASE_URL",
|
|
@@ -311,5 +286,9 @@ def deploy(ctx: click.Context, application_uuid: str, force: bool) -> None:
|
|
|
311
286
|
_handle_error(error)
|
|
312
287
|
|
|
313
288
|
|
|
289
|
+
from .platform_cli import platform
|
|
290
|
+
main.add_command(platform)
|
|
291
|
+
|
|
292
|
+
|
|
314
293
|
if __name__ == "__main__": # pragma: no cover
|
|
315
294
|
main()
|
|
@@ -371,7 +371,10 @@ def _error_message(error: HTTPError, token: str | None) -> str:
|
|
|
371
371
|
raw = error.read().decode("utf-8", errors="replace")
|
|
372
372
|
parsed = json.loads(raw)
|
|
373
373
|
if isinstance(parsed, Mapping) and isinstance(parsed.get("message"), str):
|
|
374
|
-
|
|
374
|
+
fields = parsed.get('errors', {})
|
|
375
|
+
safe_fields = [key for key in fields if isinstance(key,str) and re.fullmatch(r'[A-Za-z0-9_.]{1,80}',key)] if isinstance(fields,Mapping) else []
|
|
376
|
+
suffix = ' (fields: ' + ', '.join(safe_fields[:20]) + ')' if safe_fields else ''
|
|
377
|
+
return _redact_sensitive_text(parsed["message"], token)[:500] + suffix
|
|
375
378
|
except (OSError, UnicodeDecodeError, json.JSONDecodeError):
|
|
376
379
|
pass
|
|
377
380
|
return _redact_sensitive_text(str(error.reason or "request failed"), token)
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"""ChatEnv schema for ChatCoolify credentials and API endpoint."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
|
|
7
|
+
from chatenv import BaseEnvConfig, EnvField, EnvStore, get_paths
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class CoolifyConfig(BaseEnvConfig):
|
|
11
|
+
"""Typed configuration for the existing Coolify control plane."""
|
|
12
|
+
|
|
13
|
+
_title = "Coolify Configuration"
|
|
14
|
+
_aliases = ["coolify", "chatcoolify"]
|
|
15
|
+
_storage_dir = "Coolify"
|
|
16
|
+
|
|
17
|
+
COOLIFY_BASE_URL = EnvField(
|
|
18
|
+
"COOLIFY_BASE_URL",
|
|
19
|
+
default="https://coolify.example.com",
|
|
20
|
+
desc="Public HTTPS URL of the Coolify control plane",
|
|
21
|
+
)
|
|
22
|
+
COOLIFY_API_TOKEN = EnvField(
|
|
23
|
+
"COOLIFY_API_TOKEN",
|
|
24
|
+
desc="Team-scoped Coolify API token; use the minimum required permissions and expiration",
|
|
25
|
+
is_sensitive=True,
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
@classmethod
|
|
29
|
+
def test(cls) -> None:
|
|
30
|
+
"""Validate a configured endpoint, while keeping unconfigured schemas offline."""
|
|
31
|
+
|
|
32
|
+
from .client import DEFAULT_BASE_URL, CoolifyClient, CoolifyError
|
|
33
|
+
|
|
34
|
+
profile_values = EnvStore(get_paths().envs_dir).load_active(cls)
|
|
35
|
+
base_url = os.getenv("COOLIFY_BASE_URL") or profile_values.get("COOLIFY_BASE_URL") or DEFAULT_BASE_URL
|
|
36
|
+
if base_url == DEFAULT_BASE_URL:
|
|
37
|
+
print("ChatCoolify schema loaded; configure COOLIFY_BASE_URL to run a health check.")
|
|
38
|
+
return
|
|
39
|
+
try:
|
|
40
|
+
result = CoolifyClient(base_url).health()
|
|
41
|
+
except CoolifyError as error:
|
|
42
|
+
raise RuntimeError(f"Coolify health check failed: {error}") from error
|
|
43
|
+
if not result.get("ok"):
|
|
44
|
+
raise RuntimeError("Coolify health check did not report OK")
|
|
45
|
+
print(f"Coolify health check passed for {base_url}.")
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class PlatformConfig(BaseEnvConfig):
|
|
49
|
+
"""A user's platform endpoint; opaque sessions live in TokenStore."""
|
|
50
|
+
_title = 'ChatCoolify Platform'
|
|
51
|
+
_aliases = ['coolify-platform']
|
|
52
|
+
_storage_dir = 'CoolifyPlatform'
|
|
53
|
+
CHATCOOLIFY_PLATFORM_URL = EnvField('CHATCOOLIFY_PLATFORM_URL',desc='HTTPS origin of the project platform')
|
|
54
|
+
|
|
55
|
+
@classmethod
|
|
56
|
+
def test(cls):
|
|
57
|
+
print('Platform endpoint schema loaded; login sessions use the private TokenStore.')
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class PlatformServerConfig(BaseEnvConfig):
|
|
61
|
+
"""Operator-only configuration, never returned by the public platform API."""
|
|
62
|
+
_title = 'ChatCoolify Platform Server'
|
|
63
|
+
_aliases = ['coolify-platform-server']
|
|
64
|
+
_storage_dir = 'CoolifyPlatformServer'
|
|
65
|
+
COOLIFY_BASE_URL = EnvField('COOLIFY_BASE_URL',desc='Existing native control origin')
|
|
66
|
+
COOLIFY_API_TOKEN = EnvField('COOLIFY_API_TOKEN',is_sensitive=True,desc='Server-only native Team service token')
|
|
67
|
+
CHATCOOLIFY_PLATFORM_DATA = EnvField('CHATCOOLIFY_PLATFORM_DATA',default='/data',desc='Persistent platform root')
|
|
68
|
+
CHATCOOLIFY_CONTROL_URL = EnvField('CHATCOOLIFY_CONTROL_URL',desc='Public platform HTTPS origin')
|
|
69
|
+
CHATCOOLIFY_INTERNAL_URL = EnvField('CHATCOOLIFY_INTERNAL_URL',desc='Private platform origin for frontend authorization')
|
|
70
|
+
CHATCOOLIFY_SERVER_UUID = EnvField('CHATCOOLIFY_SERVER_UUID',desc='Operator-approved native server')
|
|
71
|
+
CHATCOOLIFY_TEAM_ID = EnvField('CHATCOOLIFY_TEAM_ID',desc='Native service Team ID')
|
|
72
|
+
CHATCOOLIFY_SOURCE_URL = EnvField('CHATCOOLIFY_SOURCE_URL',desc='Private read-only Git source base URL')
|
|
73
|
+
CHATCOOLIFY_SOURCE_KEY_UUID = EnvField('CHATCOOLIFY_SOURCE_KEY_UUID',desc='Native key resource for restricted source clone')
|
|
74
|
+
CHATCOOLIFY_EXTERNAL_TLS = EnvField('CHATCOOLIFY_EXTERNAL_TLS',default='false',desc='Existing external edge terminates HTTPS; native routing remains HTTP')
|
|
75
|
+
|
|
76
|
+
@classmethod
|
|
77
|
+
def test(cls):
|
|
78
|
+
print('Platform server schema loaded; credentials stay server-side.')
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
__all__ = ["CoolifyConfig", "PlatformConfig", "PlatformServerConfig"]
|