tenko-api 0.1.0__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.
tenko_api/__init__.py ADDED
@@ -0,0 +1,16 @@
1
+ """Tenko 第三方插件的稳定宿主接口。
2
+
3
+ 本包没有运行时依赖,只是一层薄转发:各子模块在导入时才转发到正在运行的
4
+ Tenko 宿主(``tenko.*``),所以 ``import tenko_api`` 本身不要求宿主已安装。
5
+ 插件只应从 ``tenko_api.*`` 导入宿主能力,不要导入 ``tenko.*`` 内部模块。
6
+
7
+ 版本遵循语义化版本,且 1.0 之前(预览期)接口可能调整:
8
+
9
+ - 新增能力:次版本号 +1;
10
+ - 删除或改变语义:主版本号 +1,废弃的接口至少保留一个次版本并给出
11
+ ``DeprecationWarning``。
12
+ """
13
+
14
+ __version__ = "0.1.0"
15
+
16
+ __all__ = ["__version__"]
tenko_api/accounts.py ADDED
@@ -0,0 +1,23 @@
1
+ """稳定插件 API:只读账号信息。"""
2
+
3
+ from satori.client import Account
4
+
5
+ from tenko.host.accounts import account_registry
6
+
7
+ __all__ = ["Account", "accounts_for_group", "online_accounts"]
8
+
9
+
10
+ def online_accounts() -> tuple[Account, ...]:
11
+ """返回当前在线(已连接且未被停用)的全部账号。"""
12
+
13
+ return tuple(
14
+ account
15
+ for account in account_registry.accounts.values()
16
+ if account_registry.is_available(account)
17
+ )
18
+
19
+
20
+ def accounts_for_group(group_id: str | int) -> tuple[Account, ...]:
21
+ """返回在该群可响应的账号:在线、未停用、未被该群禁言。"""
22
+
23
+ return account_registry.accounts_for_group(group_id)
tenko_api/actions.py ADDED
@@ -0,0 +1,48 @@
1
+ """稳定插件 API:宿主平台动作。
2
+
3
+ 动作经过宿主的权限检查、账号可用性判断和能力探测;失败时抛出
4
+ :class:`ActionServiceError` 的子类。首个参数 ``account_or_id`` 接受 Satori
5
+ 账号对象或账号 ID,``ctx`` 为触发动作的消息上下文。
6
+ """
7
+
8
+ from tenko.host.actions import (
9
+ ActionAccountUnavailable,
10
+ ActionCapabilityUnavailable,
11
+ ActionExecutionError,
12
+ ActionFailure,
13
+ ActionPermissionDenied,
14
+ ActionReceipt,
15
+ ActionServiceError,
16
+ ActionTargetUnavailable,
17
+ action_service,
18
+ )
19
+
20
+ send_group_message = action_service.send_group_message
21
+ send_private_message = action_service.send_private_message
22
+ mute_member = action_service.mute_member
23
+ unmute_member = action_service.unmute_member
24
+ kick_member = action_service.kick_member
25
+ delete_message = action_service.delete_message
26
+ get_group_member = action_service.get_group_member
27
+ list_group_members = action_service.list_group_members
28
+ list_groups = action_service.list_groups
29
+
30
+ __all__ = [
31
+ "ActionAccountUnavailable",
32
+ "ActionCapabilityUnavailable",
33
+ "ActionExecutionError",
34
+ "ActionFailure",
35
+ "ActionPermissionDenied",
36
+ "ActionReceipt",
37
+ "ActionServiceError",
38
+ "ActionTargetUnavailable",
39
+ "delete_message",
40
+ "get_group_member",
41
+ "kick_member",
42
+ "list_group_members",
43
+ "list_groups",
44
+ "mute_member",
45
+ "send_group_message",
46
+ "send_private_message",
47
+ "unmute_member",
48
+ ]
tenko_api/context.py ADDED
@@ -0,0 +1,6 @@
1
+ """稳定插件 API:消息上下文。"""
2
+
3
+ from tenko.context import MessageContext
4
+ from tenko.plugins._common import context_from_session
5
+
6
+ __all__ = ["MessageContext", "context_from_session"]
tenko_api/features.py ADDED
@@ -0,0 +1,41 @@
1
+ """稳定插件 API:功能开关查询与 Tenko 专有元数据声明。"""
2
+
3
+ from typing import Literal
4
+
5
+ from tenko.host import features as _features
6
+ from tenko.host.guards import feature_required
7
+ from tenko.host.perm import Permission
8
+
9
+ __all__ = ["declare", "feature_enabled", "feature_required"]
10
+
11
+
12
+ def feature_enabled(plugin_id: str, group_id: str | int | None = None) -> bool:
13
+ """只读查询插件在某群是否开启(全局开关、维护状态和默认值已合并)。"""
14
+
15
+ return _features.feature_service.is_enabled(plugin_id, group_id)
16
+
17
+
18
+ def declare(
19
+ *,
20
+ scope: Literal["group", "global"] = "group",
21
+ default_enabled: bool = True,
22
+ rate_weight: int = 1,
23
+ level: Permission = Permission.ActiveGroup,
24
+ ) -> None:
25
+ """在插件模块导入期间声明 Tenko 元数据,须与 ``plugin.metadata(...)`` 一起调用。
26
+
27
+ - ``scope``:``"group"`` 按群开关;``"global"`` 只有一个全局开关。
28
+ - ``default_enabled``:为 ``False`` 时,没有显式设置的群默认关闭该插件。
29
+ - ``rate_weight``:每次调用该插件命令计入限流窗口的权重(正整数)。
30
+ - ``level``:插件要求的群等级(``Permission.InactiveGroup`` 到 ``TestGroup``),
31
+ 默认 ``ActiveGroup``。群等级低于它时,该插件的命令在群里被静默忽略。
32
+
33
+ 插件不能借此声明自己是受保护的宿主插件。
34
+ """
35
+
36
+ _features.declare_feature(
37
+ scope=scope,
38
+ default_enabled=default_enabled,
39
+ rate_weight=rate_weight,
40
+ level=level,
41
+ )
tenko_api/messages.py ADDED
@@ -0,0 +1,12 @@
1
+ """稳定插件 API:消息构造与错误上报。"""
2
+
3
+ from tenko.plugins._common import (
4
+ action_error_message,
5
+ report_action_error,
6
+ text_message,
7
+ )
8
+
9
+ # 把异常连同消息来源报告给 Master;投递失败只记日志,不会再抛出。
10
+ report_error = report_action_error
11
+
12
+ __all__ = ["action_error_message", "report_error", "text_message"]
tenko_api/perm.py ADDED
@@ -0,0 +1,51 @@
1
+ """稳定插件 API:权限等级、权限检查和声明式权限装饰器。
2
+
3
+ 装饰器(``require`` / ``require_group`` / ``private_only`` / ``group_only``)
4
+ 是限定命令权限的默认写法,放在 ``@command.on(...)`` 之上或之下均可;要求会登记
5
+ 在处理函数上,``/帮助 <编号>`` 据此显示命令所需权限。只有权限取决于运行时数据
6
+ (例如按参数区分的权限)时才在函数体里用 :func:`require_perm`。
7
+ """
8
+
9
+ from tenko.context import MessageContext
10
+ from tenko.host import perm as _perm
11
+ from tenko.host.guards import group_only, private_only, require_group
12
+ from tenko.host.guards import require as _require
13
+ from tenko.host.perm import Permission
14
+
15
+ __all__ = [
16
+ "Permission",
17
+ "get_group_perm",
18
+ "get_user_perm",
19
+ "group_only",
20
+ "private_only",
21
+ "require",
22
+ "require_group",
23
+ "require_perm",
24
+ ]
25
+
26
+
27
+ async def get_user_perm(ctx: MessageContext) -> int:
28
+ """返回消息发送者在当前群(私聊为全局)的权限数值。"""
29
+
30
+ return await _perm.get_user_perm(ctx)
31
+
32
+
33
+ async def get_group_perm(ctx: MessageContext) -> int:
34
+ """返回当前群的群等级数值。"""
35
+
36
+ return await _perm.get_group_perm(ctx)
37
+
38
+
39
+ async def require_perm(ctx: MessageContext, level: int) -> bool:
40
+ """发送者权限不低于 ``level``(可用 :class:`Permission`)时返回 ``True``。"""
41
+
42
+ return await _perm.require_perm(ctx, level)
43
+
44
+
45
+ def require(level: Permission):
46
+ """要求发送者的成员权限不低于 ``level``,否则回复权限不足并停止处理。
47
+
48
+ 用法见模块说明;权限数值沿用 :class:`Permission`(含 DB 里的 BotAdmin 和黑名单)。
49
+ """
50
+
51
+ return _require(level)
tenko_api/py.typed ADDED
File without changes
tenko_api/render.py ADDED
@@ -0,0 +1,9 @@
1
+ """稳定插件 API:离线渲染。
2
+
3
+ ``RenderService`` 由 Entari 按类型注入到命令处理函数;调用
4
+ :func:`render_or_none` 渲染,浏览器不可用时得到 ``None``,请回退到文本。
5
+ """
6
+
7
+ from tenko.render import RenderService, render_or_none
8
+
9
+ __all__ = ["RenderService", "render_or_none"]
tenko_api/storage.py ADDED
@@ -0,0 +1,17 @@
1
+ """稳定插件 API:插件独立存储。
2
+
3
+ 两种存储都以调用方插件的 ID 为键,且只能在插件自己的模块里使用(包必须在
4
+ ``pyproject.toml`` 的 ``tenko.plugins`` 入口中声明,子模块同样适用):
5
+
6
+ - :func:`data_dir`:数据目录 ``.tenko/plugin-data/<id>/``;
7
+ - :class:`Store`:带版本号的 JSON 文件,旧版本迁移前自动备份。
8
+ """
9
+
10
+ from tenko.host.plugin_storage import (
11
+ PluginStorageError,
12
+ Store,
13
+ StoreVersionError,
14
+ data_dir,
15
+ )
16
+
17
+ __all__ = ["PluginStorageError", "Store", "StoreVersionError", "data_dir"]
@@ -0,0 +1,127 @@
1
+ Metadata-Version: 2.5
2
+ Name: tenko-api
3
+ Version: 0.1.0
4
+ Summary: Tenko 第三方插件的稳定宿主接口(运行时转发到 Tenko 宿主)
5
+ Project-URL: Homepage, https://github.com/g1331/tenko
6
+ Project-URL: Issues, https://github.com/g1331/tenko/issues
7
+ License-Expression: GPL-3.0-only
8
+ Classifier: Development Status :: 4 - Beta
9
+ Classifier: Framework :: AsyncIO
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Programming Language :: Python :: 3.11
12
+ Classifier: Programming Language :: Python :: 3.12
13
+ Classifier: Programming Language :: Python :: 3.13
14
+ Classifier: Typing :: Typed
15
+ Requires-Python: <3.14,>=3.11
16
+ Description-Content-Type: text/markdown
17
+
18
+ # tenko-api
19
+
20
+ [Tenko](https://github.com/g1331/tenko) 第三方插件使用的稳定宿主接口。
21
+
22
+ 插件依赖它,而不是依赖 `tenko` 本体:`tenko-api` 没有任何运行时依赖,
23
+ 只是转发到正在运行的 Tenko 宿主,因此不会影响插件自己的依赖解析。插件声明
24
+ `tenko-api>=0.1,<0.2` 这样的范围,安装时由 pip / uv 的解析器拒绝不兼容的宿主,
25
+ 不需要另写兼容检查。
26
+
27
+ > 当前为预览版(0.x)。1.0 之前接口可能调整,请把上限写到次版本。
28
+
29
+ ## 最小示例
30
+
31
+ 插件是标准 Python 包,写法与 Entari 原生插件相同,宿主能力一律从
32
+ `tenko_api` 导入:
33
+
34
+ ```toml
35
+ # pyproject.toml
36
+ [project]
37
+ name = "tenko-plugin-hello"
38
+ version = "0.1.0"
39
+ dependencies = ["tenko-api>=0.1,<0.2"]
40
+
41
+ [project.entry-points."tenko.plugins"]
42
+ hello = "tenko_plugin_hello" # 入口名 = 插件 ID
43
+ ```
44
+
45
+ ```python
46
+ # src/tenko_plugin_hello/__init__.py
47
+ from arclet.alconna import Alconna
48
+ from arclet.entari import Session, command, plugin
49
+
50
+ from tenko_api.features import declare
51
+ from tenko_api.messages import text_message
52
+ from tenko_api.perm import Permission, require
53
+
54
+ plugin.metadata("你好", author=["you"], version="0.1.0", description="打招呼")
55
+ declare(
56
+ scope="group", default_enabled=True, rate_weight=1, level=Permission.ActiveGroup
57
+ )
58
+
59
+
60
+ @command.on(Alconna("你好"))
61
+ @require(Permission.User)
62
+ async def hello(session: Session):
63
+ return text_message("你好!")
64
+ ```
65
+
66
+ ## 权限与功能开关
67
+
68
+ 限制命令的默认写法是装饰器,不要在函数体里重复写检查(漏写就等于没有权限控制):
69
+
70
+ | 装饰器 | 作用 |
71
+ |---|---|
72
+ | `@require(Permission.X)` | 发送者的成员权限不低于 X(含 Master、BotAdmin 和数据库里的黑名单);不足时回复“权限不足(当前权限:… / 需要权限:…)” |
73
+ | `@require_group(Permission.X)` | 当前群等级不低于 X,不足时**静默忽略**;私聊不受限 |
74
+ | `@group_only()` / `@private_only()` | 只允许群聊 / 私聊,否则回复“该指令只能在群聊/私聊中使用” |
75
+
76
+ - 装饰器放在 `@command.on(...)` 之下,放在之上也同样生效;同一种装饰器在一个函数上只能用一次。
77
+ 它们在命令匹配之后执行,所以只有命中命令的消息才会收到拒绝回复。
78
+ - 声明的要求登记在处理函数上,`/帮助 <编号>` 会显示每条命令的“权限”。
79
+ - 只有权限取决于运行时数据时(例如按参数区分的权限)才在函数体里调用 `require_perm`。
80
+ - `declare(level=Permission.X)` 声明整个插件要求的群等级,默认 `ActiveGroup`:群等级更低的群里,
81
+ 该插件的所有命令都被宿主静默忽略。
82
+ - 不走命令的监听器(例如响应 @bot 的消息监听)没有宿主的命令策略保护,用
83
+ `@feature_required()` 检查所属插件的功能开关和维护模式(只在群聊生效,默认静默,
84
+ `notify=True` 时回复提示)。所属插件按被装饰函数的模块确定,规则与 `data_dir()` 相同。
85
+
86
+ ```python
87
+ from arclet.entari import MessageCreatedEvent, plugin
88
+
89
+ from tenko_api.features import feature_required
90
+
91
+
92
+ @plugin.listen(MessageCreatedEvent)
93
+ @feature_required()
94
+ async def on_message(event: MessageCreatedEvent): ...
95
+ ```
96
+
97
+ ## 接口一览
98
+
99
+ | 模块 | 内容 |
100
+ |---|---|
101
+ | `tenko_api.context` | `MessageContext`、`context_from_session` |
102
+ | `tenko_api.perm` | `Permission`;装饰器 `require`、`require_group`、`group_only`、`private_only`;函数体内的 `require_perm`、`get_user_perm`、`get_group_perm` |
103
+ | `tenko_api.actions` | 发消息、禁言、踢人、撤回、查询群成员等宿主动作,以及 `ActionServiceError` 系列异常 |
104
+ | `tenko_api.accounts` | 只读账号信息:在线账号、某群可响应的账号 |
105
+ | `tenko_api.features` | `feature_enabled` 只读查询;`declare` 声明范围、默认开关、限流权重和群等级;`feature_required` 装饰非命令监听器 |
106
+ | `tenko_api.render` | `render_or_none`(浏览器不可用时回退文本) |
107
+ | `tenko_api.messages` | `text_message`、`report_error` |
108
+ | `tenko_api.storage` | 插件独立数据目录 `data_dir()`、带版本号并自动备份迁移的 JSON `Store` |
109
+
110
+ 完整的开发、测试和发布流程见仓库中的示例插件
111
+ [`examples/tenko-plugin-example`](https://github.com/g1331/tenko/tree/main/examples/tenko-plugin-example)。
112
+
113
+ ## 版本承诺
114
+
115
+ 版本号独立于 Tenko 本体,遵循语义化版本(1.0 起生效):
116
+
117
+ | 变更 | 版本号 |
118
+ |---|---|
119
+ | 新增能力 | 次版本号 +1 |
120
+ | 删除或改变语义 | 主版本号 +1 |
121
+
122
+ 被废弃的接口至少保留一个次版本,并抛出 `DeprecationWarning`。
123
+
124
+ ## 运行环境
125
+
126
+ 需要在 Tenko 宿主进程中使用:开发和测试时把 `tenko` 作为开发依赖安装即可。
127
+ Python `>=3.11,<3.14`。
@@ -0,0 +1,13 @@
1
+ tenko_api/__init__.py,sha256=ZqG-QHnUjrZTCVRyE8Tx1cqJ881c-VuY_rUvwHojY9Y,641
2
+ tenko_api/accounts.py,sha256=02RL-nlzVhW6RVDpvemfaV7O_z7gO9UHodhXzeMKeLI,687
3
+ tenko_api/actions.py,sha256=ETJu-pF2sVFr9nTRq1-8mlguIAYrzCEr0sBJi-6iVag,1440
4
+ tenko_api/context.py,sha256=buVuQuLmv8CAs7FrQXRCc_2wZ0ggj-l9gFFwd7j1O5w,195
5
+ tenko_api/features.py,sha256=WRyECyDeZtkIqI7GXKeJ9VxH1JMBoNgcGyRr1zNPxI4,1564
6
+ tenko_api/messages.py,sha256=qLJEOxb0D3jROkwZWU9f3hwXdeMs-1Dtac9W8_I-cqg,362
7
+ tenko_api/perm.py,sha256=JIde31FDPn4G-hU9vZqJ9Dxs8E_yrkVUaZuQHqTkQBQ,1706
8
+ tenko_api/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
+ tenko_api/render.py,sha256=kcwQwLyzEOhAZ1OgcBAcelSrqiwCiZiqzC3Y58fp0gM,314
10
+ tenko_api/storage.py,sha256=ZOXxlhENzSirC7GUBunxuHSy9mSLrNMKfm4omVjh-5E,584
11
+ tenko_api-0.1.0.dist-info/METADATA,sha256=SyMP2wC9bnxqXCiAEvizVKaiUNL9ovTyFcxrTDIRdfY,5505
12
+ tenko_api-0.1.0.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
13
+ tenko_api-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.32.4
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any