draftgo-cli 4.0.1 → 4.0.23
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.
- package/README.md +87 -11
- package/package.json +9 -4
- package/resources/custom-service-sdk/ai.go +520 -0
- package/resources/custom-service-sdk/ai_test.go +156 -0
- package/resources/custom-service-sdk/auth_test.go +56 -0
- package/resources/custom-service-sdk/billing.go +596 -0
- package/resources/custom-service-sdk/billing_test.go +150 -0
- package/resources/custom-service-sdk/go.mod +3 -0
- package/resources/custom-service-sdk/manifest.json +77 -0
- package/resources/custom-service-sdk/platform.go +345 -0
- package/resources/custom-service-sdk/platform_logger_test.go +24 -0
- package/resources/custom-service-sdk/registration_test.go +39 -0
- package/resources/custom-service-sdk/resources.go +246 -0
- package/resources/custom-service-sdk/resources_billing_test.go +115 -0
- package/resources/custom-service-sdk/resources_files_test.go +57 -0
- package/resources/custom-service-sdk/resources_scope_test.go +87 -0
- package/resources/custom-service-sdk/sdk.go +208 -0
- package/resources/skill/SKILL.md +36 -88
- package/resources/skill/init/SKILL.md +4 -4
- package/resources/skill/manifest.json +5 -1
- package/resources/skill/references/aihub.md +25 -2
- package/resources/skill/references/app-api.md +56 -6
- package/resources/skill/references/architecture.md +2 -2
- package/resources/skill/references/chat-sdk.md +4 -2
- package/resources/skill/references/checkout.md +17 -3
- package/resources/skill/references/custom-services.md +112 -47
- package/resources/skill/references/data.md +19 -4
- package/resources/skill/references/delivery.md +33 -0
- package/resources/skill/references/diagnostics.md +51 -0
- package/resources/skill/references/frontend.md +34 -46
- package/resources/skill/references/mcp.md +33 -5
- package/resources/skill/references/methods.md +189 -0
- package/resources/skill/references/modules.md +37 -9
- package/resources/skill/references/runtime.md +23 -1
- package/src/cli.js +24 -0
- package/src/commandRegistry.js +9 -1
- package/src/commands/api.js +21 -10
- package/src/commands/apiKey.js +34 -0
- package/src/commands/capabilities.js +93 -0
- package/src/commands/checkout.js +1 -1
- package/src/commands/commit.js +1 -1
- package/src/commands/components.js +550 -0
- package/src/commands/conflict.js +1 -1
- package/src/commands/connect.js +18 -8
- package/src/commands/customService.js +20 -4
- package/src/commands/dataRange.js +33 -0
- package/src/commands/delete.js +12 -1
- package/src/commands/diff.js +18 -2
- package/src/commands/grant.js +29 -0
- package/src/commands/group.js +38 -0
- package/src/commands/help.js +64 -20
- package/src/commands/init.js +3 -3
- package/src/commands/map.js +145 -17
- package/src/commands/mcp.js +2 -2
- package/src/commands/reconcile.js +1 -1
- package/src/commands/role.js +32 -0
- package/src/commands/space.js +41 -0
- package/src/commands/status.js +110 -7
- package/src/commands/update.js +23 -11
- package/src/commands/verify.js +75 -0
- package/src/commands/worklog.js +6 -2
- package/src/consoleEncoding.js +34 -0
- package/src/contractCompatibility.js +57 -0
- package/src/customServices.js +138 -18
- package/src/diffReport.js +106 -0
- package/src/index.js +2 -0
- package/src/localRuntime/compose.js +14 -17
- package/src/localRuntime/index.js +22 -23
- package/src/localRuntime/services.js +27 -36
- package/src/mcp/client.js +11 -2
- package/src/mcp/protocol.js +22 -2
- package/src/mcp/tools.js +14 -1
- package/src/platforms.js +9 -0
- package/src/projectConfig.js +6 -4
- package/src/releaseInstall.js +105 -0
- package/src/updateCheck.js +48 -28
- package/src/worklog.js +2 -1
- package/src/worktree/backend.js +1 -1
- package/src/worktree/index.js +7 -2
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
---
|
|
2
|
+
read_when: 不确定 DraftGo 任务应使用 API/MCP 还是 checkout;需要 AIHub、数据、内容、自定义服务、诊断或交付的最短正确命令链时
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# 极简方法指南
|
|
6
|
+
|
|
7
|
+
只使用本页列出的真实 CLI 命令。动态 operation、字段、权限和响应以当前服务器为准;不知道精确契约时统一执行:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
draftgo api search "<能力或资源>"
|
|
11
|
+
draftgo api describe <operation_id>
|
|
12
|
+
draftgo api call <operation_id> --input request.json --output json
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
已有准确 `operation_id` 且缓存 revision 未变化时可跳过 search;describe 不完整时停止,不猜字段、operation ID 或 URL。`request.json` 必须是 UTF-8 JSON object,并按 describe 使用 `path`、`query`、`body` 或 `multipart` 容器。
|
|
16
|
+
|
|
17
|
+
所有 `--output json` 命令都将单一 UTF-8 JSON 写到 stdout,诊断写入 stderr。先选择摘要、精确筛选或分页,避免用终端截断处理大结果。
|
|
18
|
+
|
|
19
|
+
## AIHub
|
|
20
|
+
|
|
21
|
+
适用场景:查询或管理 Agent、模型、供应商、路由、Skill、Prompt,或验证一次 AI 调用。
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
draftgo api search "AIHub <agent|model|provider|route>"
|
|
25
|
+
draftgo api describe <operation_id>
|
|
26
|
+
draftgo api call <operation_id> --input request.json --output json
|
|
27
|
+
draftgo api search "AI run logs"
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
关键约束与失败定位:AIHub 是结构化远端资源,不 checkout;只传 describe 允许的字段。不得把 API Key、Authorization、供应商 header 或上游地址写入文件和日志。401/403 查登录、`aihub:*` 权限和资源调用策略;503 查模型路由、适配器与凭据是否就绪。
|
|
31
|
+
|
|
32
|
+
完成条件:写入后的目标 ID 可由 get/list operation 回读;任务涉及调用时,调用成功且 run 能按入口 Agent/模型或 request ID 定位。完整字段和编排规则再读 `aihub.md`。
|
|
33
|
+
|
|
34
|
+
## 知识库与记忆
|
|
35
|
+
|
|
36
|
+
适用场景:知识库、文档、Chunk、检索/重建,以及 Agent 长期记忆和作用域配置。
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
draftgo api search "knowledge base"
|
|
40
|
+
draftgo api search "agent memory"
|
|
41
|
+
draftgo api describe <operation_id>
|
|
42
|
+
draftgo api call <operation_id> --input request.json --output json
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
关键约束与失败定位:知识库保存可检索资料,记忆保存运行时提炼结果,不能互相替代。知识库操作使用独立的 `knowledge:*`,不会继承 `aihub:*`。上传、检索、重建和记忆字段均以 describe 为准;没有专用 CLI 子命令。检索为空时依次核对文档状态、索引/重建结果、作用域和调用权限。
|
|
46
|
+
|
|
47
|
+
完成条件:目标资源可回读;任务涉及检索或记忆召回时,最小验证调用能返回预期范围的数据,且运行日志可关联。
|
|
48
|
+
|
|
49
|
+
## 统一权限与数据范围
|
|
50
|
+
|
|
51
|
+
适用场景:设计角色、组织授权、动态 DB CRUD、知识库或自定义服务的资源归属。
|
|
52
|
+
|
|
53
|
+
```text
|
|
54
|
+
Role = 无作用域的权限模板
|
|
55
|
+
AccessGrant = 主体在哪个 platform/space 范围获得 Role
|
|
56
|
+
WorkspaceMember = 加入根工作区的关系,本身不授权
|
|
57
|
+
ResourceOwnership = 资源持久化归属,服务端最终判定边界
|
|
58
|
+
DataRange = 作用域内记录策略:none / own / all
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
platform AccessGrant 可跨空间,但只覆盖角色中显式列出的权限;space Grant 只能覆盖同根的 self/subtree。请求 header 只是候选上下文。
|
|
62
|
+
创建、读取、更新、删除都必须由服务端同时校验动作权限、持久化 ResourceOwnership 和 DataRange。
|
|
63
|
+
|
|
64
|
+
### 空间化最短流程
|
|
65
|
+
|
|
66
|
+
开始前只运行一次 `draftgo status` 确认连接健康和 API Key 当前范围;需要选择空间时再运行 `draftgo space list`。目标 operation 仍须以实时 `describe` 的 `permission`、`supported_scopes` 和 `ownership_mode` 为准。
|
|
67
|
+
|
|
68
|
+
| 场景 | 最短正确做法 |
|
|
69
|
+
|---|---|
|
|
70
|
+
| 单空间 | 固定使用该业务空间;调用输入传 `scope_type=space` 和目标 `space_id`。不为“方便”创建 platform Grant、子空间或用户组。 |
|
|
71
|
+
| 多空间 | 每次先确定目标空间,再以该 `space_id` 调用;切换空间后重新读取目标资源。不要缓存一个空间的资源 ID 后在另一个空间复用。 |
|
|
72
|
+
| 平台跨空间 | 仅当 operation 的实时契约支持 `platform`,且当前用户的 platform AccessGrant 明确包含所需 permission 时传 `scope_type=platform`。普通空间写入仍选择具体空间。 |
|
|
73
|
+
| 超级管理员普通使用 | 与普通用户相同,选择当前业务空间并传 `scope_type=space`。管理员身份不把资源改成 platform 归属,也不绕过 Authorizer、DataRange 或持久化 ownership。 |
|
|
74
|
+
|
|
75
|
+
空间调用输入只增加实时 MCP 支持的范围字段,其余容器仍按 `describe` 填写:
|
|
76
|
+
|
|
77
|
+
```json
|
|
78
|
+
{"scope_type":"space","space_id":120,"path":{},"query":{},"body":{}}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
平台调用使用 `{"scope_type":"platform", ...}` 且不传 `space_id`。对已有资源的按 ID 操作,客户端选择的范围不能覆盖服务端已保存的 ResourceOwnership;403 时进入 `diagnostics.md`,不要改 ID 或扩大范围反复试探。
|
|
82
|
+
|
|
83
|
+
## 页面、导航与内容
|
|
84
|
+
|
|
85
|
+
适用场景:修改已有 page/navigation/article 完整正文,或创建后继续编辑正文。
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
draftgo map --type pages --route /admin/channel-ops --output json
|
|
89
|
+
draftgo checkout pages <id>
|
|
90
|
+
draftgo diff pages <id> --stat
|
|
91
|
+
draftgo verify pages <id>
|
|
92
|
+
draftgo commit pages <id>
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
导航将 `pages` 换为 `nav`,文档文章换为 `docs`。`--route` 与 `--title` 均为精确匹配,同时给出时取交集;CLI 会先用资源搜索缩小候选,再在本地判定精确结果。只需确认范围、数量和 checkout 状态时使用 `map --summary`;必须浏览时使用 `--limit <1-100>`(默认 20),并仅在单一 `--type` 下用返回的 `--cursor <opaque>` 请求下一页。`map --summary` 不含 project overview、资源列表或 hash。`diff --stat` 显示文件与增删行数,`diff --summary` 显示资源、版本和变化概览;只有需要审查正文时才运行不带这两个参数的 `diff`。新资源先发现创建契约并取得 ID:
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
draftgo api search "create <page|navigation|article>"
|
|
99
|
+
draftgo api describe <operation_id>
|
|
100
|
+
draftgo api call <operation_id> --input request.json --output json
|
|
101
|
+
draftgo checkout <pages|nav|docs> <id>
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
关键约束与失败定位:checkout 只处理已存在资源的完整正文,不负责创建。409/412 时停止提交,使用 `draftgo conflicts` 和 `draftgo conflict show <type> <id>` 检查保留的 base/local/remote;不要 force、覆盖或自动合并。
|
|
105
|
+
|
|
106
|
+
完成条件:commit 返回新版本/哈希,随后 `draftgo check --remote --output json` 显示本地基线与远端一致。正文和冲突细节再读 `checkout.md`,页面运行规则再读 `frontend.md`。
|
|
107
|
+
|
|
108
|
+
## 动态数据
|
|
109
|
+
|
|
110
|
+
适用场景:管理 `db_meta` schema、权限、关系,或查询/写入动态 DB 记录。
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
draftgo api search "db meta"
|
|
114
|
+
draftgo api describe <operation_id>
|
|
115
|
+
draftgo api call <operation_id> --input request.json --output json
|
|
116
|
+
draftgo api search "dynamic db record"
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
关键约束与失败定位:schema 和记录都是结构化远端资源,不 checkout。创建或更新 schema 后先回读目标 `type`,再按实时记录 operation 做最小 CRUD。400 优先核对 searchable、filter 操作符和字段容器;403 核对 `db_meta` permission 与记录 owner;列表不完整先核对分页,不用超大 page size 假装全量。
|
|
120
|
+
|
|
121
|
+
完成条件:schema 可按 `type` 回读,目标角色的最小 CRUD/筛选符合预期;批量写入还需验证失败时整批回滚。字段和关系规则再读 `data.md`。
|
|
122
|
+
|
|
123
|
+
## 自定义服务
|
|
124
|
+
|
|
125
|
+
适用场景:编写、保存、验证、试运行或发布 Go 自定义服务。
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
draftgo api search "custom service create"
|
|
129
|
+
draftgo api describe <operation_id>
|
|
130
|
+
draftgo api call <operation_id> --input request.json --output json
|
|
131
|
+
draftgo checkout custom-services <id>
|
|
132
|
+
draftgo diff custom-services <id>
|
|
133
|
+
draftgo commit custom-services <id>
|
|
134
|
+
draftgo validate custom-services <id>
|
|
135
|
+
draftgo test custom-services <id> --source draft --handler route:POST:/path --input request.json
|
|
136
|
+
draftgo publish custom-services <id>
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
关键约束与失败定位:自定义服务只有一种 Go `Register` 形态;后端从 `Register` 自动发现 Route/Event/Scheduled handler,不需要配置服务模式或 `triggers` 字段。worktree 只含 `service.go` 和 `service.json`,`go.mod/go.sum` 由 Runner 管理。`commit custom-services` 自动完成提交、验证和发布。余额、权益、支付和订阅使用 `ctx.Billing` / `ctx.Admin.Billing`,精确签名读 checkout 后的 `.draftgo-sdk/billing.go`,不要用动态 DB 自建账本。试运行默认拒绝副作用;真实写入必须显式使用 `--side-effect-policy live --test-write`。validate 失败查编译/Register/依赖;test 失败按 execution/request ID 查运行日志;revision 冲突停止重试。
|
|
140
|
+
|
|
141
|
+
完成条件:`commit custom-services` 返回 published 且 validate passed;需要运行行为证据时再要求 test success。完整 SDK、handler selector 和依赖规则再读 `custom-services.md`。
|
|
142
|
+
|
|
143
|
+
## MCP 与实时契约
|
|
144
|
+
|
|
145
|
+
适用场景:首次连接、宿主配置变化、工具不可用,或不知道 operation/schema。
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
draftgo mcp status
|
|
149
|
+
draftgo mcp test
|
|
150
|
+
draftgo api search "<业务能力>"
|
|
151
|
+
draftgo api describe <operation_id>
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
关键约束与失败定位:已配置且健康时不必每个任务重复 setup/status/test。宿主配置只运行 `draftgo mcp serve`,不得保存 API Key。401/403 查用户 API Key 和 grant;session/uninitialized 重新建立连接;operation 不唯一时继续缩小 search;describe 缺字段、风险或响应契约时停止。
|
|
155
|
+
|
|
156
|
+
完成条件:initialize、tools/list、关键 tools/call 可用,目标 operation schema 已确认且可回读一次无副作用结果。完整缓存、风险和 multipart 规则再读 `mcp.md`。
|
|
157
|
+
|
|
158
|
+
## 运行诊断
|
|
159
|
+
|
|
160
|
+
适用场景:连接失败、API 调用失败、checkout 状态异常,或需要定位 AI/custom-service run。
|
|
161
|
+
|
|
162
|
+
```bash
|
|
163
|
+
draftgo mcp status
|
|
164
|
+
draftgo mcp test
|
|
165
|
+
draftgo map --type pages --summary --output json
|
|
166
|
+
draftgo check --remote --output json
|
|
167
|
+
draftgo api describe <operation_id>
|
|
168
|
+
draftgo api call <operation_id> --input request.json --output json
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
关键约束与失败定位:只运行与故障层级相关的命令。保留脱敏的 `operation_id`、`status_code`、`server_code`、`request_id`;非幂等写失败后先回读状态,不自动重试。连接问题看 mcp test,正文版本看 check/conflicts,AI 与服务运行问题再 search 对应日志 operation。
|
|
172
|
+
|
|
173
|
+
完成条件:故障被定位到连接、契约、权限、资源版本、Runner 或业务运行中的一层,并有 request ID/run 等可关联证据。完整分流再读 `diagnostics.md`。
|
|
174
|
+
|
|
175
|
+
## 交付验收
|
|
176
|
+
|
|
177
|
+
适用场景:准备提交、发布、交付或关闭 worklog 项目。
|
|
178
|
+
|
|
179
|
+
```bash
|
|
180
|
+
draftgo verify
|
|
181
|
+
draftgo check --remote --output json
|
|
182
|
+
draftgo work complete <ref> --note "<结果与证据>"
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
正文资源在 complete 前还必须成功执行 `diff -> commit`;结构化资源必须 call 后回读;自定义服务按任务要求追加 validate/test/publish。默认不启动浏览器,只有用户明确要求视觉验收时才使用 `draftgo verify --url <url> --screenshot always`,需要 DOM/交互时再加 `--ui always`。
|
|
186
|
+
|
|
187
|
+
关键约束与失败定位:本地验证通过不等于已提交或已发布。任何 verify、commit、MCP 写入、必要 test/publish、回读或视觉验收失败时,工作项保持 active。
|
|
188
|
+
|
|
189
|
+
完成条件:全部目标远端状态可回读,正文版本/哈希或结构化状态符合预期,任务要求的运行/视觉证据齐全且不含凭据,然后才 complete。
|
|
@@ -11,22 +11,43 @@ read_when: 评估功能可行性时 · 选择开发路径时 · 进入新项目
|
|
|
11
11
|
| 页面 | 数据库 HTML(`page.value.html`) | 已有页面由 MCP 定位后 `checkout pages` / `commit pages`;新页面先按实时 API 契约创建并取得 ID |
|
|
12
12
|
| 导航栏 | 数据库 HTML(`navigation.html`) | MCP 定位,`checkout nav` / `commit nav` 编辑正文 |
|
|
13
13
|
| 动态 DB | db_meta 定义 schema 并操作结构化记录 | MCP `api_search` / `api_describe` / `api_call` |
|
|
14
|
-
|
|
|
14
|
+
| 文件资产 | 文件夹、文件元数据、绑定、下载、回收站和对象存储 | MCP 实时 API;文件字节不进入普通 tool result |
|
|
15
|
+
| 自定义服务 | 单一 Go `Register` 服务;后端从注册代码自动发现 Route/Event/Scheduled handler | MCP 定位/创建;正文用 `checkout custom-services` / `commit custom-services` |
|
|
15
16
|
| AIHub | 配置 AI Agent(模型/编排/能力/子智能体/记忆);页面对话使用 `<dg-chat>`,图片模式使用 `DraftGoAI.images`;见 `references/chat-sdk.md` 与 `references/aihub.md` | MCP 实时 API;不创建本地镜像 |
|
|
16
17
|
| 文档中心 | Markdown/HTML 文章 + 分类树 | 正文用 `checkout docs` / `commit docs`;分类用 MCP |
|
|
17
18
|
| 系统配置 | KV 存储,含全局前端层槽位 | MCP 实时 API;不创建本地镜像 |
|
|
19
|
+
| 商业与计费 | 账本、余额、权益、支付订单、退款、套餐、订阅和 AI 计费 | 管理任务用 MCP 实时 API;自定义服务用 `ctx.Billing` / `ctx.Admin.Billing`;不要用动态 DB 重建金钱状态 |
|
|
18
20
|
|
|
19
21
|
## 平台内置模块(开箱即用,不需实现)
|
|
20
22
|
|
|
21
23
|
| 模块 | 能力 | 调用方式 |
|
|
22
24
|
|---|---|---|
|
|
23
25
|
| 认证 | 注册/登录/刷新/找回密码/微信登录/手机邮箱验证 | 页面使用 `App`;服务端操作通过 MCP 实时描述接口 |
|
|
24
|
-
| 角色权限 |
|
|
26
|
+
| 角色权限 | 无作用域 Role 模板 + 带 `platform` / `space` 范围的 AccessGrant | 页面可用 `App.permissions` 辅助显隐;服务端按资源授权 |
|
|
27
|
+
| 工作区与空间 | 根工作区成员、用户组和递归 Space;成员关系本身不授权 | `App.scopeContext` + MCP space/group/grant operations;资源保存直接归属 |
|
|
28
|
+
| 动态数据范围 | `DataRange=none|own|all`,限制空间内的记录级访问 | db_meta 的记录策略;不替代 ResourceOwnership 或 AccessGrant |
|
|
25
29
|
| 通知公告 | 发布公告,支持类型/状态/分页 | MCP 实时 API |
|
|
26
30
|
| 工单反馈 | 用户提交问题,支持类型/状态跟踪 | MCP 实时 API |
|
|
27
31
|
| 备份恢复 | 完整/选择性备份,JSON/.dgbak 格式,支持 dry-run | MCP 实时 API |
|
|
28
32
|
| 系统管理 | 系统配置 KV、存储健康、全局前端层、通知测试 | MCP 实时 API |
|
|
29
33
|
|
|
34
|
+
`App.currentUser.role_code` 是展示投影,不是用户表中的可写字段。真正的资源/API 授权由服务端根据 ResourceOwnership 与有效 AccessGrant 决定;platform Grant 也只能使用角色中显式声明的权限。
|
|
35
|
+
|
|
36
|
+
用户 API Key 只是一种用户认证方式;它不改变 AccessGrant、ResourceOwnership、DataRange 或管理员边界。服务身份是平台运行时主体。
|
|
37
|
+
|
|
38
|
+
## 新模块权限接入检查表
|
|
39
|
+
|
|
40
|
+
AI 新建或扩展受保护模块时,按以下最小闭环逐项确认;缺少任一项都不能用页面显隐、角色名或调用来源补洞:
|
|
41
|
+
|
|
42
|
+
- [ ] 在统一 Permission Catalog 注册每个 `resource:action`,声明支持的 `platform` / `space` 范围以及是否使用 DataRange;不在模块内另建权限字符串或角色分支。
|
|
43
|
+
- [ ] 顶层资源持久化 canonical ResourceOwnership:platform,或完整的 `ownership_type=space + workspace_id + space_id`;需要 own/all 时同时保存 `owner_user_id`。子资源只能通过不可变父键继承归属。
|
|
44
|
+
- [ ] 创建和列表只接受服务端验证后的范围上下文;读取、更新、删除及其他按 ID 操作先加载持久化 ownership,忽略客户端提交的 workspace、space、owner 或调用者替代值。
|
|
45
|
+
- [ ] 使用统一 Authorizer 校验真实 Principal、Catalog permission 和持久化 ResourceOwnership;执行记录级操作时继续应用返回的 DataRange,不能把 `all` 解释为跨工作区。
|
|
46
|
+
- [ ] HTTP、MCP、SDK、Route、Event、Schedule 和 worker 等所有实际入口复用同一授权路径;TokenScope 只能对最终权限取交集并收窄。
|
|
47
|
+
- [ ] 保留最小拒绝证据:无 Grant、space Grant 跨根、伪造归属;支持 own/all 时再覆盖他人记录拒绝。不要为同一规则复制一套测试框架。
|
|
48
|
+
|
|
49
|
+
实现位置和具体 API 以目标 DraftGo 服务端仓库的现有 Catalog、ResourceOwnership 与 WorkspaceAuthorizer 模式为准;本 Skill 不复制服务端动态 schema。
|
|
50
|
+
|
|
30
51
|
## 模块选型决策
|
|
31
52
|
|
|
32
53
|
```
|
|
@@ -34,20 +55,27 @@ read_when: 评估功能可行性时 · 选择开发路径时 · 进入新项目
|
|
|
34
55
|
→ 有固定结构 → 动态 DB(db_meta 定义 schema)
|
|
35
56
|
→ 仅需 KV → sys_config(category 自定义)
|
|
36
57
|
|
|
58
|
+
要保存文件?
|
|
59
|
+
→ 文件夹、上传、下载、回收站或业务绑定 → 文件资产模块;不要把文件字节塞进动态 DB
|
|
60
|
+
|
|
61
|
+
要做余额、支付、会员或订阅?
|
|
62
|
+
→ 管理操作走 money/payment/subscription/billing 的 MCP 实时契约;自定义服务读 `.draftgo-sdk/billing.go` 并使用 Billing SDK,不自行实现账本或扣费一致性
|
|
63
|
+
|
|
37
64
|
要调用 AI?
|
|
38
65
|
→ 聊天/问答 UI → AIHub + `<dg-chat>`(自动隔离 thread/session)
|
|
39
66
|
→ 无 UI 的旧代码文本调用 → AIHub + DraftGoAI.chat()(兼容门面)
|
|
40
67
|
→ 图片生成 → AIHub + DraftGoAI.images()
|
|
68
|
+
→ Responses、Embedding、Rerank、TTS、ASR 或 Video → AIHub capability 与 provider readiness;先确认模型的 canonical capability 和 transport
|
|
41
69
|
→ 需要工具/子智能体/记忆/结构化输出/多模态 → 都是 Agent spec 开关,见 references/aihub.md
|
|
42
70
|
|
|
43
71
|
要调用第三方服务?
|
|
44
|
-
→ 自定义服务(用 `
|
|
72
|
+
→ 自定义服务(用 `ctx.HTTP` 请求;在同一 Go 服务中按需注册 Route/Event/Scheduled handler)
|
|
45
73
|
|
|
46
74
|
要展示内容文档?
|
|
47
75
|
→ 文档中心(Markdown + 分类树)
|
|
48
76
|
|
|
49
77
|
要做定时任务或事件响应?
|
|
50
|
-
→
|
|
78
|
+
→ 自定义服务(用 `app.Schedule` / `app.On` 注册;后端自动识别定时任务和事件 handler)
|
|
51
79
|
|
|
52
80
|
要做后台管理页?
|
|
53
81
|
→ 业务页面 + 动态 DB + 角色权限
|
|
@@ -56,11 +84,11 @@ read_when: 评估功能可行性时 · 选择开发路径时 · 进入新项目
|
|
|
56
84
|
## 自定义服务边界
|
|
57
85
|
|
|
58
86
|
- 新服务使用 Go `Register(app *sdk.App)` 自动注册路由、事件和定时任务;完整语言、`draftgo` 和 SDK 契约见 `references/custom-services.md`。
|
|
59
|
-
- `
|
|
60
|
-
- `
|
|
61
|
-
- `
|
|
87
|
+
- `Route`:对外暴露 HTTP 端点;同一 Go 服务可用多个 `app.Route(method, path, handler)` 注册多个端点,实际路径通过 MCP 实时发现,草稿行为先用 `draftgo test custom-services` 验证。
|
|
88
|
+
- `Event`:响应平台事件,如 `db.created` / `db.updated` / `user.registered`;用 `app.On(event, handler)` 注册,可为同一事件注册多个 handler。
|
|
89
|
+
- `Scheduled`:用 `app.Schedule("分 时 日 月 周", handler)` 注册 cron;同一服务可声明多个定时 handler。
|
|
62
90
|
- 新 Go 服务的 `Register` 是唯一触发器事实来源;旧 `triggers` 字段不参与注册。
|
|
63
|
-
- 管理面由角色 RBAC 的 `scripts:*` 动作控制;Route
|
|
91
|
+
- 管理面由角色 RBAC 的 `scripts:*` 动作控制;Route 不再读取服务级 `permission`,由宿主认证、持久化 ownership 和 `scripts:execute` AccessGrant 统一控制。
|
|
64
92
|
- Go 服务在独立子进程中构建/运行;只有可信角色才能获得 `scripts:create` / `scripts:update`。
|
|
65
93
|
- 自定义服务适合服务端加工、鉴权后聚合、第三方回调、定时任务和事件响应;普通 CRUD 管理界面优先用“页面 + 动态 DB”,不要把所有业务后台都塞进 route 脚本。
|
|
66
|
-
- 脚本内读动态 DB 用 `
|
|
94
|
+
- 脚本内读动态 DB 用 `ctx.DB.Query(type, sdk.QueryOptions{...})`;返回 `sdk.QueryResult`,分页和筛选见 `references/custom-services.md`。
|
|
@@ -35,7 +35,7 @@ read_when: 需要理解运行时机制时 · 处理 token/路由/事件相关问
|
|
|
35
35
|
|
|
36
36
|
壳层将 `app` 对象赋值给 `window.App`,页面通过 `window.parent.App` 访问。
|
|
37
37
|
|
|
38
|
-
`app` 组成:`api.js`(请求)+ `feedback.js`(弹窗/Toast)+ `runtime.js
|
|
38
|
+
`app` 组成:`api.js`(请求)+ `feedback.js`(弹窗/Toast)+ `runtime.js`(路由/主题/作用域)+ `i18n.js`(国际化)+ state(currentUser/isAdmin/config/theme/scopeContext)
|
|
39
39
|
|
|
40
40
|
完整 API 见 `references/app-api.md`
|
|
41
41
|
|
|
@@ -103,3 +103,25 @@ registry revision 变化时 `draftgo_api_describe`,再用 `draftgo_api_call`
|
|
|
103
103
|
|
|
104
104
|
页面管理中 Toast 时长以秒输入,`sys_config` 中仍以毫秒存储。例如 UI 中
|
|
105
105
|
`错误 Toast 时长(s) = 4.5` 对应 `frontend_global_toast_duration_error.config_value = 4500`。
|
|
106
|
+
|
|
107
|
+
## 统一作用域
|
|
108
|
+
|
|
109
|
+
DraftGo 的资源归属和授权范围只有 `platform`、`space`。`Role` 是无作用域权限模板;`AccessGrant`
|
|
110
|
+
定义 user/group/service 主体在哪个范围拥有该角色。工作区成员与用户组成员关系本身不授予权限。
|
|
111
|
+
|
|
112
|
+
`platform` Grant 可跨全部空间,但只能使用 Role 中显式列出的权限。`space` Grant 仅覆盖同一根工作区内的
|
|
113
|
+
目标空间或 subtree;所有授权为 allow-only 并集,DataRange 使用 `all > own > none`。
|
|
114
|
+
|
|
115
|
+
页面需要切换工作范围时使用 `App.getScopeContext()`、`App.setScopeContext(context)`,不要把
|
|
116
|
+
space id 当作自定义权限判断。上下文只是请求意图,服务端仍以持久化 `ResourceOwnership` 和有效 AccessGrant 为准。
|
|
117
|
+
API 请求只使用 `X-DraftGo-Scope-Type` 与 `X-DraftGo-Space-Id`;workspace_id 由服务端推导。
|
|
118
|
+
|
|
119
|
+
动态 DB 的 `DataRange`(数据库元数据中的记录策略)是另一层:`none` 拒绝动作,`owner` 仅允许当前
|
|
120
|
+
所有者记录,`all` 允许当前 ResourceOwnership 内全部记录。它不能扩大 `platform` / `space` 范围;
|
|
121
|
+
不要把 `all` 解释成跨工作区。记录的 `userid` 是当前兼容实现的所有者字段,`created_by` / 独立
|
|
122
|
+
`owner_user_id` 只有在服务端契约明确提供后才能使用。
|
|
123
|
+
|
|
124
|
+
认证边界:交互式 CLI、MCP 和普通 HTTP API 使用当前用户的 API Key;该凭据始终代表该用户,权限来自
|
|
125
|
+
用户及用户组的 AccessGrant,TokenScope 只能收窄,不能变成管理员或服务身份。CI、定时任务和共享服务等
|
|
126
|
+
无人值守自动化使用平台的独立服务凭据通道;service principal 由平台内部注入,CLI 不生成、导出或伪造
|
|
127
|
+
服务身份凭据。
|
package/src/cli.js
CHANGED
|
@@ -8,6 +8,7 @@ const VALUE_FLAGS = new Set([
|
|
|
8
8
|
'target',
|
|
9
9
|
'server',
|
|
10
10
|
'mcp-url',
|
|
11
|
+
'api-key',
|
|
11
12
|
'token',
|
|
12
13
|
'output',
|
|
13
14
|
'url',
|
|
@@ -29,12 +30,35 @@ const VALUE_FLAGS = new Set([
|
|
|
29
30
|
'params',
|
|
30
31
|
'input',
|
|
31
32
|
'type',
|
|
33
|
+
'route',
|
|
34
|
+
'title',
|
|
35
|
+
'limit',
|
|
36
|
+
'cursor',
|
|
32
37
|
'date',
|
|
33
38
|
'handler',
|
|
39
|
+
'source',
|
|
34
40
|
'headers',
|
|
35
41
|
'user',
|
|
36
42
|
'side-effect-policy',
|
|
43
|
+
'page',
|
|
44
|
+
'instance',
|
|
37
45
|
'note',
|
|
46
|
+
'file',
|
|
47
|
+
'library',
|
|
48
|
+
'name',
|
|
49
|
+
'slug',
|
|
50
|
+
'category',
|
|
51
|
+
'description',
|
|
52
|
+
'tags',
|
|
53
|
+
'source-type',
|
|
54
|
+
'status',
|
|
55
|
+
'scope-type',
|
|
56
|
+
'space-id',
|
|
57
|
+
'module',
|
|
58
|
+
'resource-type',
|
|
59
|
+
'method',
|
|
60
|
+
'risk',
|
|
61
|
+
'permission',
|
|
38
62
|
]);
|
|
39
63
|
|
|
40
64
|
function parse(argv) {
|
package/src/commandRegistry.js
CHANGED
|
@@ -6,7 +6,7 @@ const commands = [
|
|
|
6
6
|
{ name: 'init', run: (dir, args, flags) => require('./commands/init')(dir, args, flags) },
|
|
7
7
|
{ name: 'update', run: (dir, args, flags) => require('./commands/update')(dir, args, flags) },
|
|
8
8
|
{ name: 'uninstall', run: (dir, args, flags) => require('./commands/uninstall')(dir, args, flags) },
|
|
9
|
-
{ name: 'status', run: (dir) => require('./commands/status')(dir) },
|
|
9
|
+
{ name: 'status', run: (dir, args, flags) => require('./commands/status')(dir, args, flags) },
|
|
10
10
|
{ name: 'work', run: (dir, args, flags) => require('./commands/worklog')(dir, args, flags) },
|
|
11
11
|
{ name: 'clean', run: (dir, args, flags) => require('./commands/clean')(dir, args, flags) },
|
|
12
12
|
{ name: 'map', run: (dir, _args, flags) => require('./commands/map')(dir, flags) },
|
|
@@ -24,12 +24,20 @@ const commands = [
|
|
|
24
24
|
{ name: 'conflicts', run: (dir, args, flags) => require('./commands/conflicts')(dir, args, flags) },
|
|
25
25
|
{ name: 'conflict', run: (dir, args, flags) => require('./commands/conflict')(dir, args, flags) },
|
|
26
26
|
{ name: 'api', run: (dir, args, flags) => require('./commands/api')(dir, args, flags) },
|
|
27
|
+
{ name: 'space', run: (dir, args, flags) => require('./commands/space')(dir, args, flags) },
|
|
28
|
+
{ name: 'group', run: (dir, args, flags) => require('./commands/group')(dir, args, flags) },
|
|
29
|
+
{ name: 'grant', run: (dir, args, flags) => require('./commands/grant')(dir, args, flags) },
|
|
30
|
+
{ name: 'api-key', run: (dir, args, flags) => require('./commands/apiKey')(dir, args, flags) },
|
|
31
|
+
{ name: 'role', run: (dir, args, flags) => require('./commands/role')(dir, args, flags) },
|
|
32
|
+
{ name: 'data-range', run: (dir, args, flags) => require('./commands/dataRange')(dir, args, flags) },
|
|
27
33
|
{ name: 'delete', run: (dir, args, flags) => require('./commands/delete')(dir, args, flags) },
|
|
28
34
|
{ name: 'deploy', run: (dir, args, flags) => require('./commands/deploy')(dir, args, flags) },
|
|
29
35
|
{ name: 'auto-push', run: (dir, args, flags) => require('./commands/autoPush')(dir, args, flags) },
|
|
30
36
|
{ name: 'local', run: (dir, args, flags) => require('./commands/local')(dir, args, flags) },
|
|
31
37
|
{ name: 'list-targets', run: () => require('./commands/listTargets')() },
|
|
32
38
|
{ name: 'connect', run: (dir, args, flags) => require('./commands/connect')(dir, args, flags) },
|
|
39
|
+
{ name: 'components', run: (dir, args, flags) => require('./commands/components')(dir, args, flags) },
|
|
40
|
+
{ name: 'capabilities', run: (dir, args, flags) => require('./commands/capabilities')(dir, args, flags) },
|
|
33
41
|
];
|
|
34
42
|
|
|
35
43
|
const aliases = new Map();
|
package/src/commands/api.js
CHANGED
|
@@ -5,8 +5,15 @@ const path = require('path');
|
|
|
5
5
|
const log = require('../logger');
|
|
6
6
|
const { confirm } = require('../prompt');
|
|
7
7
|
const { loadProjectConfig } = require('../projectConfig');
|
|
8
|
-
const { TOOL_NAMES, openToolSession, callStructured } = require('../mcp/tools');
|
|
8
|
+
const { TOOL_NAMES, openToolSession, callStructured, configuredScope } = require('../mcp/tools');
|
|
9
9
|
const { cachedDescription, normalizeDescription, storeDescription } = require('../apiContractCache');
|
|
10
|
+
const {
|
|
11
|
+
isContractCompatibilityError,
|
|
12
|
+
isHardContractIncompatibility,
|
|
13
|
+
isDangerousOperation,
|
|
14
|
+
sameOperationContract,
|
|
15
|
+
incompatibleOperationError,
|
|
16
|
+
} = require('../contractCompatibility');
|
|
10
17
|
|
|
11
18
|
function readCallInput(projectDir, flags) {
|
|
12
19
|
const raw = flags.input
|
|
@@ -81,8 +88,8 @@ async function callOperation(projectDir, operationId, flags = {}) {
|
|
|
81
88
|
} catch (error) {
|
|
82
89
|
return printCallError(operationId, error, flags);
|
|
83
90
|
}
|
|
84
|
-
const
|
|
85
|
-
if (
|
|
91
|
+
const dangerous = isDangerousOperation(description);
|
|
92
|
+
if (dangerous && !flags.yes && !flags.y) {
|
|
86
93
|
const approved = await confirm(`Call destructive DraftGo operation ${operationId}?`, { default: false });
|
|
87
94
|
if (!approved) return 0;
|
|
88
95
|
}
|
|
@@ -90,21 +97,25 @@ async function callOperation(projectDir, operationId, flags = {}) {
|
|
|
90
97
|
try {
|
|
91
98
|
const invoke = (contract, confirmed) => callStructured(session, TOOL_NAMES.apiCall, {
|
|
92
99
|
...input, operation_id: operationId, registry_revision: contract.registry_revision,
|
|
100
|
+
...configuredScope(config, contract),
|
|
93
101
|
...(confirmed ? { confirm: true } : {}),
|
|
94
102
|
});
|
|
95
103
|
try {
|
|
96
|
-
result = await invoke(description,
|
|
104
|
+
result = await invoke(description, dangerous);
|
|
97
105
|
} catch (error) {
|
|
98
|
-
if (error
|
|
106
|
+
if (!isContractCompatibilityError(error)) throw error;
|
|
107
|
+
if (isHardContractIncompatibility(error)) {
|
|
108
|
+
throw incompatibleOperationError(operationId, error);
|
|
109
|
+
}
|
|
110
|
+
const previousDescription = description;
|
|
99
111
|
const described = await callStructured(session, TOOL_NAMES.apiDescribe, { operation_id: operationId });
|
|
100
112
|
description = storeDescription(projectDir, config.server, described) || normalizeDescription(described);
|
|
101
113
|
if (!description) throw new Error('DraftGo API description is missing contract revision metadata.');
|
|
102
|
-
const
|
|
103
|
-
if (
|
|
104
|
-
|
|
105
|
-
if (!approved) return 0;
|
|
114
|
+
const changedDangerous = isDangerousOperation(description);
|
|
115
|
+
if ((dangerous || changedDangerous) && !sameOperationContract(previousDescription, description)) {
|
|
116
|
+
throw incompatibleOperationError(operationId, error);
|
|
106
117
|
}
|
|
107
|
-
result = await invoke(description,
|
|
118
|
+
result = await invoke(description, changedDangerous);
|
|
108
119
|
}
|
|
109
120
|
} catch (error) {
|
|
110
121
|
return printCallError(operationId, error, flags);
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const log = require('../logger');
|
|
4
|
+
const { callOperation } = require('./api');
|
|
5
|
+
|
|
6
|
+
const OPERATIONS = Object.freeze({
|
|
7
|
+
status: 'getCurrentUserAPIKey',
|
|
8
|
+
create: 'createCurrentUserAPIKey',
|
|
9
|
+
update: 'updateCurrentUserAPIKey',
|
|
10
|
+
delete: 'deleteCurrentUserAPIKey',
|
|
11
|
+
rotate: 'rotateCurrentUserAPIKey',
|
|
12
|
+
reset: 'resetCurrentUserAPIKey',
|
|
13
|
+
enable: 'enableCurrentUserAPIKey',
|
|
14
|
+
disable: 'disableCurrentUserAPIKey',
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
function operationKey(value) {
|
|
18
|
+
const action = String(value || 'status').trim().toLowerCase();
|
|
19
|
+
return OPERATIONS[action] ? action : '';
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
async function apiKeyCommand(projectDir, positional, flags = {}) {
|
|
23
|
+
const action = operationKey(positional[0]);
|
|
24
|
+
if (!action) {
|
|
25
|
+
log.err('Usage: draftgo api-key status|create|update|delete|rotate|reset|enable|disable [--input <json-file>]');
|
|
26
|
+
return 1;
|
|
27
|
+
}
|
|
28
|
+
if (action === 'reset') log.warn('api-key reset is deprecated; prefer rotate.');
|
|
29
|
+
return callOperation(projectDir, OPERATIONS[action], flags);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
module.exports = apiKeyCommand;
|
|
33
|
+
module.exports.OPERATIONS = OPERATIONS;
|
|
34
|
+
module.exports.operationKey = operationKey;
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const log = require('../logger');
|
|
4
|
+
const { loadProjectConfig } = require('../projectConfig');
|
|
5
|
+
const { TOOL_NAMES, openToolSession, callStructured } = require('../mcp/tools');
|
|
6
|
+
|
|
7
|
+
function itemsOf(value) {
|
|
8
|
+
if (Array.isArray(value)) return value;
|
|
9
|
+
return value && Array.isArray(value.items) ? value.items : [];
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function nextCursorOf(value) {
|
|
13
|
+
return value && (value.next_cursor ?? value.nextCursor) || null;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function print(value, flags, title) {
|
|
17
|
+
if (flags.output === 'json') console.log(JSON.stringify(value, null, 2));
|
|
18
|
+
else {
|
|
19
|
+
log.title(title);
|
|
20
|
+
if (Array.isArray(value)) value.forEach(item => log.plain(` ${item.operation_id || item.name || JSON.stringify(item)}`));
|
|
21
|
+
else console.log(JSON.stringify(value, null, 2));
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function searchArguments(query, flags, cursor) {
|
|
26
|
+
const input = { limit: Math.min(100, Math.max(1, Number(flags.limit) || 100)) };
|
|
27
|
+
if (query) input.query = query;
|
|
28
|
+
if (flags.module) input.module = String(flags.module);
|
|
29
|
+
if (flags['resource-type'] || flags.type) input.resource_type = String(flags['resource-type'] || flags.type);
|
|
30
|
+
if (flags.method) input.method = String(flags.method).toUpperCase();
|
|
31
|
+
if (flags.risk) input.risk = String(flags.risk);
|
|
32
|
+
if (flags.permission) input.permission = String(flags.permission);
|
|
33
|
+
if (cursor) input.cursor = cursor;
|
|
34
|
+
return input;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
async function collect(session, query, flags, allPages) {
|
|
38
|
+
const result = [];
|
|
39
|
+
let cursor = flags.cursor || null;
|
|
40
|
+
const seen = new Set();
|
|
41
|
+
do {
|
|
42
|
+
const page = await callStructured(session, TOOL_NAMES.apiSearch, searchArguments(query, flags, cursor));
|
|
43
|
+
result.push(...itemsOf(page));
|
|
44
|
+
cursor = nextCursorOf(page);
|
|
45
|
+
if (!allPages || !cursor) break;
|
|
46
|
+
if (seen.has(cursor)) throw new Error('DraftGo capability search repeated a cursor.');
|
|
47
|
+
seen.add(cursor);
|
|
48
|
+
} while (true);
|
|
49
|
+
return { items: result, next_cursor: cursor };
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
async function capabilities(projectDir, positional = [], flags = {}) {
|
|
53
|
+
const action = String(positional[0] || 'list').toLowerCase();
|
|
54
|
+
const config = loadProjectConfig(projectDir);
|
|
55
|
+
if (action === 'show') {
|
|
56
|
+
const operationID = String(positional[1] || '').trim();
|
|
57
|
+
if (!operationID) throw new Error('Usage: draftgo capabilities show <operation_id>');
|
|
58
|
+
const session = await openToolSession(config, [TOOL_NAMES.apiDescribe]);
|
|
59
|
+
const result = await callStructured(session, TOOL_NAMES.apiDescribe, { operation_id: operationID });
|
|
60
|
+
print(result, flags, `DraftGo capability ${operationID}`);
|
|
61
|
+
return 0;
|
|
62
|
+
}
|
|
63
|
+
if (action === 'audit') {
|
|
64
|
+
const session = await openToolSession(config, [TOOL_NAMES.projectOverview, TOOL_NAMES.apiSearch]);
|
|
65
|
+
const overview = await callStructured(session, TOOL_NAMES.projectOverview, {});
|
|
66
|
+
const catalog = await collect(session, '', flags, true);
|
|
67
|
+
const registry = overview && (overview.operation_registry || overview.registry) || {};
|
|
68
|
+
const result = {
|
|
69
|
+
server: config.server,
|
|
70
|
+
registry_revision: registry.registry_revision || overview.registry_revision || null,
|
|
71
|
+
mapped_operations: registry.mapped_operations ?? registry.mapped ?? catalog.items.length,
|
|
72
|
+
excluded_operations: registry.excluded_operations ?? registry.excluded ?? null,
|
|
73
|
+
total_operations: registry.total_operations ?? registry.total ?? null,
|
|
74
|
+
discovered_operations: catalog.items.length,
|
|
75
|
+
complete: (registry.mapped_operations ?? registry.mapped ?? catalog.items.length) === catalog.items.length,
|
|
76
|
+
};
|
|
77
|
+
print(result, flags, 'DraftGo capability audit');
|
|
78
|
+
return result.complete ? 0 : 1;
|
|
79
|
+
}
|
|
80
|
+
if (action !== 'list' && action !== 'search') throw new Error('Usage: draftgo capabilities list|search|show|audit');
|
|
81
|
+
const query = action === 'search' ? positional.slice(1).join(' ').trim() : '';
|
|
82
|
+
if (action === 'search' && !query && !flags.module && !flags.type && !flags.method && !flags.risk && !flags.permission) {
|
|
83
|
+
throw new Error('Capability search needs a query or filter.');
|
|
84
|
+
}
|
|
85
|
+
const session = await openToolSession(config, [TOOL_NAMES.apiSearch]);
|
|
86
|
+
const result = await collect(session, query, flags, action === 'list' && !flags.cursor);
|
|
87
|
+
print(flags.output === 'json' ? result : result.items, flags, action === 'search' ? `DraftGo capabilities: ${query || 'filtered'}` : 'DraftGo capabilities');
|
|
88
|
+
return 0;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
module.exports = capabilities;
|
|
92
|
+
module.exports.searchArguments = searchArguments;
|
|
93
|
+
module.exports.itemsOf = itemsOf;
|
package/src/commands/checkout.js
CHANGED
|
@@ -6,7 +6,7 @@ const { checkoutResources } = require('../worktree');
|
|
|
6
6
|
async function checkout(projectDir, positional, flags = {}) {
|
|
7
7
|
const [resourceType, ...ids] = positional;
|
|
8
8
|
if (!resourceType || !ids.length) {
|
|
9
|
-
log.err('Usage: draftgo checkout <pages|nav|docs> <id...>');
|
|
9
|
+
log.err('Usage: draftgo checkout <pages|nav|docs|custom-services> <id...>');
|
|
10
10
|
return 1;
|
|
11
11
|
}
|
|
12
12
|
if (require('./customService').isServiceType(resourceType)) {
|
package/src/commands/commit.js
CHANGED
|
@@ -6,7 +6,7 @@ const { commitResources } = require('../worktree');
|
|
|
6
6
|
async function commit(projectDir, positional, flags = {}) {
|
|
7
7
|
const [resourceType, ...ids] = positional;
|
|
8
8
|
if (!resourceType || !ids.length) {
|
|
9
|
-
log.err('Usage: draftgo commit <pages|nav|docs> <id...>');
|
|
9
|
+
log.err('Usage: draftgo commit <pages|nav|docs|custom-services> <id...>');
|
|
10
10
|
return 1;
|
|
11
11
|
}
|
|
12
12
|
if (require('./customService').isServiceType(resourceType)) {
|