draftgo-cli 3.0.29 → 3.0.35
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/LICENSE +21 -0
- package/README.md +41 -139
- package/package.json +10 -2
- package/resources/skill/SKILL.md +61 -184
- package/resources/skill/init/SKILL.md +18 -66
- package/resources/skill/manifest.json +34 -0
- package/resources/skill/pull/SKILL.md +18 -52
- package/resources/skill/push/SKILL.md +30 -282
- package/resources/skill/references/aihub.md +86 -0
- package/resources/skill/{quickref → references}/api-endpoints.md +39 -13
- package/resources/skill/references/api.json +20248 -0
- package/resources/skill/{quickref → references}/app-api.md +40 -0
- package/resources/skill/{core → references}/architecture.md +2 -2
- package/resources/skill/references/chat-sdk.md +201 -0
- package/resources/skill/references/custom-services.md +308 -0
- package/resources/skill/{specs → references}/data.md +5 -5
- package/resources/skill/{rules → references}/frontend.md +138 -32
- package/resources/skill/{core → references}/modules.md +7 -5
- package/resources/skill/references/parallel.md +48 -0
- package/resources/skill/{specs → references}/runtime.md +1 -1
- package/resources/skill/scripts/draftgo_push.py +80 -12
- package/resources/skill/story/SKILL.md +11 -16
- package/src/cli.js +13 -7
- package/src/commandRegistry.js +34 -0
- package/src/commands/api.js +153 -8
- package/src/commands/help.js +24 -29
- package/src/commands/init.js +17 -18
- package/src/commands/local.js +9 -3
- package/src/commands/sync.js +1 -1
- package/src/commands/update.js +40 -12
- package/src/index.js +13 -57
- package/src/localdev/compose.js +44 -200
- package/src/localdev/index.js +116 -216
- package/src/localdev/mysqlClient.js +12 -9
- package/src/localdev/services.js +163 -0
- package/src/projectConfig.js +1 -1
- package/src/projectMap.js +17 -80
- package/src/skill.js +1 -1
- package/src/updateCheck.js +2 -12
- package/resources/skill/practices/anti-patterns.md +0 -80
- package/resources/skill/practices/best-practices.md +0 -60
- package/resources/skill/practices/dev-declaration.md +0 -114
- package/resources/skill/quickref/api.json +0 -17784
- package/resources/skill/rules/dev-workflow.md +0 -749
- package/resources/skill/rules/parallel.md +0 -263
- package/resources/skill/scripts/__pycache__/draftgo_pull.cpython-312.pyc +0 -0
- package/resources/skill/scripts/__pycache__/draftgo_push.cpython-312.pyc +0 -0
- package/resources/skill/specs/custom-services.md +0 -199
- package/src/commands/doctor.js +0 -54
- package/src/commands/new.js +0 -186
- package/src/commands/projectScript.js +0 -37
- package/src/commands/upgrade.js +0 -52
- /package/resources/skill/{specs → references}/db-relations.md +0 -0
- /package/resources/skill/{rules → references}/debugging-syntax.md +0 -0
- /package/resources/skill/{specs → references}/security.md +0 -0
- /package/resources/skill/{specs → references}/ui-protocol.md +0 -0
|
@@ -1,263 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: draftgo-parallel-execution
|
|
3
|
-
description: DraftGo 并行开发协议。仅在当前任务按 dev-workflow 分级后确实需要多任务/多代理协作,且存在无依赖关系的任务组时启用。
|
|
4
|
-
version: 1.0.0
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
# DraftGo 并行开发协议
|
|
8
|
-
|
|
9
|
-
> 本协议是 dev-workflow.md 的按需扩展,不是额外门禁。小修、轻功能和普通串行标准功能不启用;只有多任务、多资源或多代理协作确有收益,且存在 **2 个及以上无依赖任务** 时才启用。
|
|
10
|
-
|
|
11
|
-
---
|
|
12
|
-
|
|
13
|
-
## 核心模型
|
|
14
|
-
|
|
15
|
-
```
|
|
16
|
-
主代理(Orchestrator)
|
|
17
|
-
├── 按 dev-workflow 完成任务分级与必要范围确认
|
|
18
|
-
├── 分析任务依赖图
|
|
19
|
-
├── 分发无依赖任务组给子代理
|
|
20
|
-
├── 收集子代理结果
|
|
21
|
-
├── 统一推送(batch push)
|
|
22
|
-
└── 闭环门
|
|
23
|
-
|
|
24
|
-
子代理(Worker)
|
|
25
|
-
├── 接收:单个 Task + 上下文包
|
|
26
|
-
├── 执行:读 → 改 → 验(TDR 的 Tiny + Demo)
|
|
27
|
-
├── 产出:修改后的文件 + changelog 条目 + 验证证据
|
|
28
|
-
└── 不推送、不闭环(交回主代理)
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
---
|
|
32
|
-
|
|
33
|
-
## 依赖分析规则
|
|
34
|
-
|
|
35
|
-
当 dev-workflow 判定需要 Task、并行或多资源协作时,为相关任务标注 `depends` 字段:
|
|
36
|
-
|
|
37
|
-
```markdown
|
|
38
|
-
- [ ] T1. 用户列表页增加导出按钮 ⬜
|
|
39
|
-
- depends: []
|
|
40
|
-
- resource_lock: pages/admin-users.html
|
|
41
|
-
|
|
42
|
-
- [ ] T2. 用户详情页增加操作日志 ⬜
|
|
43
|
-
- depends: []
|
|
44
|
-
- resource_lock: pages/admin-user-detail.html
|
|
45
|
-
|
|
46
|
-
- [ ] T3. 导出 API 脚本编写 ⬜
|
|
47
|
-
- depends: []
|
|
48
|
-
- resource_lock: custom_scripts/user-export.py
|
|
49
|
-
|
|
50
|
-
- [ ] T4. 导出按钮对接 API ⬜
|
|
51
|
-
- depends: [T1, T3]
|
|
52
|
-
- resource_lock: pages/admin-users.html
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
### 依赖判定标准
|
|
56
|
-
|
|
57
|
-
| 关系 | 判定为依赖 | 判定为独立 |
|
|
58
|
-
|------|-----------|-----------|
|
|
59
|
-
| 同一文件 | T4 改 admin-users.html,T1 也改 → T4 depends T1 | - |
|
|
60
|
-
| 数据依赖 | T4 需要 T3 产出的 API slug → T4 depends T3 | - |
|
|
61
|
-
| 不同文件 | T1 改页面 A,T2 改页面 B | 无依赖,可并行 |
|
|
62
|
-
| 不同类型 | T1 改 page,T3 写 script | 无依赖,可并行 |
|
|
63
|
-
| 导航引用页面 | 导航加链接 → 目标页面必须先存在 | 页面和不相关导航 |
|
|
64
|
-
|
|
65
|
-
### resource_lock 规则
|
|
66
|
-
|
|
67
|
-
- 每个任务声明它要修改的文件路径(`resource_lock`)
|
|
68
|
-
- **同一 resource_lock 的任务不可并行**,必须串行或合并
|
|
69
|
-
- 一个任务可以锁多个资源:`resource_lock: [pages/a.html, pages/b.html]`
|
|
70
|
-
|
|
71
|
-
---
|
|
72
|
-
|
|
73
|
-
## 并行分发协议
|
|
74
|
-
|
|
75
|
-
### 主代理职责
|
|
76
|
-
|
|
77
|
-
1. **短计划或 Task 明确后**,按依赖图将任务分为并行批次(waves):
|
|
78
|
-
```
|
|
79
|
-
Wave 1: [T1, T2, T3] — 全部 depends: [],可并行
|
|
80
|
-
Wave 2: [T4] — depends T1+T3,等 Wave 1 结束
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
2. **为每个子代理打包上下文**(Context Pack):
|
|
84
|
-
```
|
|
85
|
-
- task_id: T1
|
|
86
|
-
- task_description: <从 Task 文档摘取该任务的完整定义>
|
|
87
|
-
- resource_files: <该任务涉及的当前文件内容>
|
|
88
|
-
- story_context: <story.yaml 的关键约束摘要>
|
|
89
|
-
- dev_rules: <frontend.md / debugging-syntax.md 的关键禁区摘要>
|
|
90
|
-
- project_config: <.draftgo/config.json 的 server 地址(不含 token)>
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
3. **分发时的指令模板**:
|
|
94
|
-
```
|
|
95
|
-
你是 DraftGo 子代理,负责执行单个开发任务。
|
|
96
|
-
|
|
97
|
-
## 你的任务
|
|
98
|
-
{task_description}
|
|
99
|
-
|
|
100
|
-
## 当前文件内容
|
|
101
|
-
{resource_files}
|
|
102
|
-
|
|
103
|
-
## 强制规则
|
|
104
|
-
- 只修改 resource_lock 声明的文件,禁止动其他文件
|
|
105
|
-
- 遵守 DraftGo 前端禁区(见下方摘要)
|
|
106
|
-
- 修改完成后输出:
|
|
107
|
-
1. 修改后的完整文件内容
|
|
108
|
-
2. changelog 条目(格式:- [HH:MM] [操作类型] 描述)
|
|
109
|
-
3. 验证证据(你做了什么验证、结果如何)
|
|
110
|
-
- 不要推送、不要更新 Task 文档、不要写 lessons
|
|
111
|
-
|
|
112
|
-
## 禁区摘要
|
|
113
|
-
{dev_rules_summary}
|
|
114
|
-
```
|
|
115
|
-
|
|
116
|
-
4. **收集结果后**:
|
|
117
|
-
- 将子代理产出的文件内容写入对应路径
|
|
118
|
-
- 汇总所有 changelog 条目,按时间排序写入 changelog.md
|
|
119
|
-
- 批量推送:`draftgo auto-push --batch pages 1,2,3 nav 4`(由 `auto_push` 开关决定是否真正推送)
|
|
120
|
-
- 统一更新 Task 文档标记
|
|
121
|
-
- 进入闭环门
|
|
122
|
-
|
|
123
|
-
### 子代理职责
|
|
124
|
-
|
|
125
|
-
1. 接收上下文包,理解任务边界
|
|
126
|
-
2. 执行 TDR 循环的 Tiny + Demo:
|
|
127
|
-
- 读取当前文件
|
|
128
|
-
- 做最小改动
|
|
129
|
-
- 在能力范围内验证(语法检查、逻辑自审)
|
|
130
|
-
3. **产出三件套**:修改后文件 + changelog 条目 + 验证报告
|
|
131
|
-
4. **不做**:推送、Task 标记、lessons 记录、闭环声明
|
|
132
|
-
|
|
133
|
-
### 子代理边界红线
|
|
134
|
-
|
|
135
|
-
```
|
|
136
|
-
禁止:
|
|
137
|
-
- 修改 resource_lock 之外的任何文件
|
|
138
|
-
- 调用推送 API 或推送脚本
|
|
139
|
-
- 修改 .draftgo/Task/ 文档
|
|
140
|
-
- 安装新依赖或引入新库
|
|
141
|
-
- 修改 .draftgo/config.json
|
|
142
|
-
- 做出超出 task_description 范围的"顺手"改动
|
|
143
|
-
|
|
144
|
-
允许:
|
|
145
|
-
- 读取其他文件以理解上下文(只读)
|
|
146
|
-
- 在验证阶段用 console.log 调试
|
|
147
|
-
- 发现阻塞时报告给主代理(而非自行绕过)
|
|
148
|
-
```
|
|
149
|
-
|
|
150
|
-
---
|
|
151
|
-
|
|
152
|
-
## 平台适配
|
|
153
|
-
|
|
154
|
-
不同 AI 平台实现并行的方式不同,主代理根据当前平台选择策略:
|
|
155
|
-
|
|
156
|
-
| 平台 | 并行实现方式 | 子代理能力 |
|
|
157
|
-
|------|-------------|-----------|
|
|
158
|
-
| Claude Code | `Agent` tool(subagent) | 完整文件读写 + Bash |
|
|
159
|
-
| Cursor | Background Agent / Composer | 文件读写 |
|
|
160
|
-
| Codex CLI | 多 sandbox 实例 | 完整隔离环境 |
|
|
161
|
-
| Windsurf | Cascade 多步 | 有限并行 |
|
|
162
|
-
| Kiro | Agent tool | 完整文件读写 |
|
|
163
|
-
| 其他 | 退化为串行 | - |
|
|
164
|
-
|
|
165
|
-
### 退化策略
|
|
166
|
-
|
|
167
|
-
当平台不支持子代理或任务数 ≤ 2 时,**静默退化为串行执行**,不需要告知用户。并行协议的 Task 依赖标注仍保留(对执行顺序有指导意义)。
|
|
168
|
-
|
|
169
|
-
---
|
|
170
|
-
|
|
171
|
-
## 批量推送
|
|
172
|
-
|
|
173
|
-
并行执行完毕后,主代理使用批量推送减少网络开销:
|
|
174
|
-
|
|
175
|
-
```bash
|
|
176
|
-
draftgo auto-push --batch pages 1,2,3 nav 4 custom_scripts 7
|
|
177
|
-
```
|
|
178
|
-
|
|
179
|
-
开关为 `true` 时,等价于依次推送 pages 1、2、3 + nav 4 + custom_scripts 7,但一次加载 config、一次建立连接;为 `false` 时仅执行本地检查并返回未推送信息。
|
|
180
|
-
|
|
181
|
-
---
|
|
182
|
-
|
|
183
|
-
## 错误处理
|
|
184
|
-
|
|
185
|
-
### 子代理失败
|
|
186
|
-
|
|
187
|
-
- 子代理报告阻塞 → 主代理判断:能否由自己接手修复?
|
|
188
|
-
- 能:主代理接手该 Task,其余子代理结果不受影响
|
|
189
|
-
- 不能:暂停该 Task(⏸),其余继续
|
|
190
|
-
- 子代理产出与禁区冲突 → 主代理拒收,自行修复或重新分发
|
|
191
|
-
|
|
192
|
-
### Wave 间传递
|
|
193
|
-
|
|
194
|
-
- Wave 1 中某个 Task 失败 → Wave 2 中依赖该 Task 的任务自动暂停
|
|
195
|
-
- Wave 1 中其他 Task 成功 → Wave 2 中不依赖失败任务的照常执行
|
|
196
|
-
|
|
197
|
-
### 资源冲突检测
|
|
198
|
-
|
|
199
|
-
主代理收集子代理结果时,如果发现两个子代理意外修改了同一文件(违规):
|
|
200
|
-
1. 比对两份输出,取变更不重叠的部分合并
|
|
201
|
-
2. 如果重叠 → 丢弃后执行的那份,由主代理手动合并
|
|
202
|
-
3. 记入 lessons:子代理 resource_lock 定义不够精确
|
|
203
|
-
|
|
204
|
-
---
|
|
205
|
-
|
|
206
|
-
## Task 文档并行标注格式
|
|
207
|
-
|
|
208
|
-
启用并行后,Task 文档的任务清单增加 `depends` 和 `resource_lock` 字段,进度总览增加 `wave` 列:
|
|
209
|
-
|
|
210
|
-
```markdown
|
|
211
|
-
## 任务清单
|
|
212
|
-
|
|
213
|
-
- [ ] T1. 用户列表页增加导出按钮 ⬜
|
|
214
|
-
- depends: []
|
|
215
|
-
- resource_lock: pages/admin-users.html
|
|
216
|
-
- wave: 1
|
|
217
|
-
|
|
218
|
-
- [ ] T2. 用户详情页增加操作日志 ⬜
|
|
219
|
-
- depends: []
|
|
220
|
-
- resource_lock: pages/admin-user-detail.html
|
|
221
|
-
- wave: 1
|
|
222
|
-
|
|
223
|
-
- [ ] T3. 导出 API 脚本编写 ⬜
|
|
224
|
-
- depends: []
|
|
225
|
-
- resource_lock: custom_scripts/user-export.py
|
|
226
|
-
- wave: 1
|
|
227
|
-
|
|
228
|
-
- [ ] T4. 导出按钮对接 API ⬜
|
|
229
|
-
- depends: [T1, T3]
|
|
230
|
-
- resource_lock: pages/admin-users.html
|
|
231
|
-
- wave: 2
|
|
232
|
-
|
|
233
|
-
## 进度总览
|
|
234
|
-
|
|
235
|
-
| 任务 | Wave | 状态 | 执行方式 | 完成时间 | 证据摘要 |
|
|
236
|
-
|-----|------|------|---------|---------|---------|
|
|
237
|
-
| T1 | 1 | ⬜ | 子代理 | | |
|
|
238
|
-
| T2 | 1 | ⬜ | 子代理 | | |
|
|
239
|
-
| T3 | 1 | ⬜ | 子代理 | | |
|
|
240
|
-
| T4 | 2 | ⬜ | 主代理 | | |
|
|
241
|
-
```
|
|
242
|
-
|
|
243
|
-
---
|
|
244
|
-
|
|
245
|
-
## 启用条件与判断
|
|
246
|
-
|
|
247
|
-
主代理在完成任务分级和必要范围确认后自动判断:
|
|
248
|
-
|
|
249
|
-
```
|
|
250
|
-
IF 无依赖任务数 >= 2
|
|
251
|
-
AND 平台支持子代理
|
|
252
|
-
AND 任务间无 resource_lock 冲突
|
|
253
|
-
THEN 启用并行分发
|
|
254
|
-
ELSE 串行执行(静默,不告知用户)
|
|
255
|
-
```
|
|
256
|
-
|
|
257
|
-
不需要用户显式启用。用户也可以明确说"串行做"来关闭并行。
|
|
258
|
-
|
|
259
|
-
---
|
|
260
|
-
|
|
261
|
-
## 一句话总结
|
|
262
|
-
|
|
263
|
-
> **主代理管脑子(计划 + 闭环),子代理管手脚(单 Task 执行),resource_lock 防冲突,batch push 收全场。**
|
|
Binary file
|
|
Binary file
|
|
@@ -1,199 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
read_when: 编写、修改、调试或评审自定义服务时;使用服务 SDK、路由、事件、定时任务或服务依赖时
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
# Go 自定义服务契约
|
|
6
|
-
|
|
7
|
-
DraftGo 的新自定义服务使用 Go。服务代码是完整的 `package main`,可以使用标准库和 `go.mod` 中声明的第三方库。平台在保存或发布时编译服务、运行 `Register` 并保存触发器清单;执行时在独立子进程中调用选定 handler。
|
|
8
|
-
|
|
9
|
-
平台 SDK 的固定导入路径是 `draftgo/sdk`。它是 DraftGo 构建器注入的本地 module,不从 GitHub 或其他网络仓库下载,也不要在服务的 `go.mod` 中自行添加或 `replace` 此依赖。
|
|
10
|
-
|
|
11
|
-
## 最小服务
|
|
12
|
-
|
|
13
|
-
```go
|
|
14
|
-
package main
|
|
15
|
-
|
|
16
|
-
import "draftgo/sdk"
|
|
17
|
-
|
|
18
|
-
func Register(app *sdk.App) {
|
|
19
|
-
app.Route("GET", "/health", health)
|
|
20
|
-
app.On("order.paid", afterPaid)
|
|
21
|
-
app.Schedule("0 9 * * 1-5", weekdayReport)
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
func health(ctx *sdk.Context) (any, error) {
|
|
25
|
-
return ctx.Respond(map[string]any{"ok": true}, 200, nil), nil
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
func afterPaid(ctx *sdk.Context) (any, error) {
|
|
29
|
-
ctx.Log.Info("order paid event received")
|
|
30
|
-
return nil, nil
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
func weekdayReport(ctx *sdk.Context) (any, error) { return nil, nil }
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
`Register` 必须没有业务副作用。它只注册 handler;网络请求、写数据库、发通知等操作放在 handler 内。
|
|
37
|
-
|
|
38
|
-
## 本地资源
|
|
39
|
-
|
|
40
|
-
```text
|
|
41
|
-
.draftgo/custom_scripts/
|
|
42
|
-
├── index.json
|
|
43
|
-
└── script_<id>_<slug>.go
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
`index.json` 的 Go 服务字段:
|
|
47
|
-
|
|
48
|
-
```json
|
|
49
|
-
{
|
|
50
|
-
"name": "order-service",
|
|
51
|
-
"slug": "order-service",
|
|
52
|
-
"mode": "mixed",
|
|
53
|
-
"code_file": ".draftgo/custom_scripts/script_new_order-service.go",
|
|
54
|
-
"go_mod": "module example.com/order-service\n\ngo 1.26.0\n\nrequire github.com/google/uuid v1.6.0\n",
|
|
55
|
-
"go_sum": ""
|
|
56
|
-
}
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
- 新服务使用 `mode=mixed`,允许同一个 `Register` 同时注册 route、event 和 scheduled。旧服务可继续使用单一 `route`、`event` 或 `scheduled` mode。
|
|
60
|
-
- `go_mod` 和可选的 `go_sum` 随服务版本保存并由 `draftgo push custom_scripts` 推送。
|
|
61
|
-
- 新依赖应锁定明确版本。构建错误会在保存/发布时返回,不会替换当前有效清单。
|
|
62
|
-
|
|
63
|
-
## 触发器
|
|
64
|
-
|
|
65
|
-
### Route
|
|
66
|
-
|
|
67
|
-
```go
|
|
68
|
-
func Register(app *sdk.App) {
|
|
69
|
-
app.Route("POST", "/orders", createOrder)
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
func createOrder(ctx *sdk.Context) (any, error) {
|
|
73
|
-
body, _ := ctx.Input["body"].(map[string]any)
|
|
74
|
-
return ctx.Respond(body, 201, nil), nil
|
|
75
|
-
}
|
|
76
|
-
```
|
|
77
|
-
|
|
78
|
-
`slug=commerce` 时地址为 `POST /api/x/commerce/orders`。Route 精确匹配,不支持 `/orders/{id}` 模板;ID 使用 query 或 body。
|
|
79
|
-
|
|
80
|
-
`ctx.Input` 的 Route 字段:`method`、`headers`、`body`、`query_params`、`path_params`。当前身份通过 `ctx.Auth.CurrentUser()` 获取,入站请求头通过 `ctx.Headers.Get("Authorization")` 等读取。
|
|
81
|
-
|
|
82
|
-
Route 默认以请求调用者身份访问 `draftgo.DB`、`draftgo.Users` 和其他平台能力。服务由管理员创建、拥有 `scripts:*` 管理权限,或在请求中收到 SAT,都不会让普通 SDK 调用自动提升;`draftgo.Auth.RequireAdmin()` 也只检查当前调用者。
|
|
83
|
-
|
|
84
|
-
可信服务需要管理员权限时,逐次显式使用 `draftgo.Admin.*`。这不是服务配置项,也不需要 `admin_access` 开关:调用 `Admin` 就是管理员调用声明。运行时为**这一次**平台 SDK 调用注入管理员身份,并把服务、版本、真实调用者、操作、资源和结果写进该次执行的审计日志;SAT、数据库连接和管理员凭据不会暴露给服务代码。
|
|
85
|
-
|
|
86
|
-
```go
|
|
87
|
-
func catalog(draftgo *sdk.Context) (any, error) {
|
|
88
|
-
// 继承调用者权限
|
|
89
|
-
owned, err := draftgo.DB.Query("order", sdk.QueryOptions{})
|
|
90
|
-
if err != nil { return nil, err }
|
|
91
|
-
|
|
92
|
-
// 显式管理员权限;仅此调用提升
|
|
93
|
-
internal, err := draftgo.Admin.DB.Query("internal_catalog", sdk.QueryOptions{})
|
|
94
|
-
if err != nil { return nil, err }
|
|
95
|
-
|
|
96
|
-
return draftgo.Respond(map[string]any{
|
|
97
|
-
"orders": owned.Items,
|
|
98
|
-
"catalog": internal.Items, // 生产代码应再按客户端可见字段组装
|
|
99
|
-
}, 200, nil)
|
|
100
|
-
}
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
`draftgo.Admin` 提供与普通 SDK 对齐的 `DB`、`Users`、`Auth`、`Notify`、`HTTP`、`Cache`、`Config`、`AIHub` 能力。它等价于管理员在平台拥有的权限,不做资源级白名单;因此只能授予可信服务编辑者,并且 Route 返回值仍必须由代码负责脱敏。
|
|
104
|
-
|
|
105
|
-
### Event
|
|
106
|
-
|
|
107
|
-
```go
|
|
108
|
-
app.On("user.registered", welcome)
|
|
109
|
-
|
|
110
|
-
func welcome(ctx *sdk.Context) (any, error) {
|
|
111
|
-
payload, _ := ctx.Input["payload"].(map[string]any)
|
|
112
|
-
ctx.Log.Info("registered user: " + fmt.Sprint(payload["user_id"]))
|
|
113
|
-
return nil, nil
|
|
114
|
-
}
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
事件异步且不阻塞原请求。事件输入含 `event`、`timestamp`、`payload`。
|
|
118
|
-
|
|
119
|
-
事件 `payload` 含 `user_id` 或 `actor_user_id` 且该用户仍存在时,handler 继承该用户身份;无法解析用户时才以系统身份执行。事件服务应把事件数据视为业务输入,而不是把它当成绕过资源权限的通道。
|
|
120
|
-
|
|
121
|
-
### Scheduled
|
|
122
|
-
|
|
123
|
-
```go
|
|
124
|
-
app.Schedule("0 2 * * *", cleanup)
|
|
125
|
-
```
|
|
126
|
-
|
|
127
|
-
cron 使用五字段表达式,也支持 `interval:5m`。定时 handler 的 `ctx.Input` 为空对象。
|
|
128
|
-
|
|
129
|
-
定时任务没有调用者,会以系统身份执行。因此它只能由可信编辑者维护,写入范围应限制在明确的数据类型,并在 handler 中记录可审计的业务日志。
|
|
130
|
-
|
|
131
|
-
## 平台 SDK
|
|
132
|
-
|
|
133
|
-
所有资源访问经受控 RPC 返回 Go 主服务。不要自行读取数据库连接、服务 token 或宿主机环境变量。
|
|
134
|
-
|
|
135
|
-
```go
|
|
136
|
-
record, err := ctx.DB.Create("order", map[string]any{"title": "DraftGo"})
|
|
137
|
-
records, err := ctx.DB.Query("order", sdk.QueryOptions{
|
|
138
|
-
Filters: map[string]any{"status": "paid"},
|
|
139
|
-
Page: 1, PageSize: 20, OrderBy: "id", Order: "desc",
|
|
140
|
-
})
|
|
141
|
-
|
|
142
|
-
user, err := ctx.Users.Get(12)
|
|
143
|
-
err = ctx.Auth.RequireLogin()
|
|
144
|
-
err = ctx.Notify.Send(12, "完成", "订单已创建", "info")
|
|
145
|
-
|
|
146
|
-
cached, err := ctx.Cache.Get("daily-report")
|
|
147
|
-
err = ctx.Cache.Set("daily-report", map[string]any{"ok": true}, time.Hour)
|
|
148
|
-
|
|
149
|
-
value, err := ctx.Config.Get("feature_flag", false)
|
|
150
|
-
response, err := ctx.HTTP.Get(ctx.Context(), "https://api.example.com/health", nil, 10*time.Second)
|
|
151
|
-
|
|
152
|
-
reply, err := ctx.AIHub.Chat(ctx.Context(), sdk.AIChatRequest{AgentID: 12, Message: "总结订单"})
|
|
153
|
-
ctx.Log.Info("service completed")
|
|
154
|
-
```
|
|
155
|
-
|
|
156
|
-
`ctx.DB` 支持 `Create`、`CreateMany`、`Get`、`Update`、`UpdateMany`、`Delete`、`Query`。`Query` 返回 `sdk.QueryResult{Items, Total, Page, PageSize}`。
|
|
157
|
-
|
|
158
|
-
`ctx.Users` 支持 `Get`、`List`、`Update`。`ctx.Auth` 支持 `RequireLogin`、`RequireAdmin`、`RequireRole`、`CurrentUser`。
|
|
159
|
-
|
|
160
|
-
`ctx.HTTP` 支持 `Get`、`Post`、`Put`、`Patch`、`Delete`;响应为 `sdk.HTTPResponse{StatusCode, Headers, Data}`。服务可使用 `config.http_allowed_hosts` 限制出站目标;HTTP timeout 最终限制为 1-30 秒,响应体最大 5 MB。
|
|
161
|
-
|
|
162
|
-
`ctx.AIHub.Chat` 与 `ctx.AIHub.GenerateImage` 使用已配置的 Agent。AIHub 权限仍受服务配置与调用身份控制。
|
|
163
|
-
|
|
164
|
-
日志每次执行最多 500 条、单条最多 4096 字符。不要记录 token、Cookie、密码或完整个人信息。
|
|
165
|
-
|
|
166
|
-
## 权限与运行限制
|
|
167
|
-
|
|
168
|
-
- `scripts:read/create/update/delete/execute` 控制可信人员管理服务。
|
|
169
|
-
- Route 调用者仍由服务 `permission` 与 `config.route_security` 控制;管理权限不绕过 Route 调用权限。
|
|
170
|
-
- Route 的普通 SDK 数据访问继承调用者权限;不要把“管理员创建服务”误写成自动提升。只有显式 `draftgo.Admin.*` 调用才以管理员执行并记录审计;定时任务和无可解析用户的事件是系统身份例外。
|
|
171
|
-
- `config.timeout`、`max_concurrency`、`queue_timeout_ms` 适用于服务执行。Route 饱和时返回 HTTP 429。
|
|
172
|
-
- Go 服务以独立进程运行,超时会终止该进程;它不是为不可信多租户代码准备的安全沙箱。只向可信编辑者授予服务编辑权限。
|
|
173
|
-
- 每个保存版本按源码、依赖、SDK 和 Runner 协议生成不可变构建键。代码或依赖变更会生成新构建产物;旧版本可通过现有版本恢复接口重新激活。
|
|
174
|
-
|
|
175
|
-
## 管理 API
|
|
176
|
-
|
|
177
|
-
管理 API 使用 `{code, data, message}` 信封并受 `scripts:*` 权限控制:
|
|
178
|
-
|
|
179
|
-
| 方法 | 路径 |
|
|
180
|
-
|---|---|
|
|
181
|
-
| `POST` / `GET` | `/api/scripts` |
|
|
182
|
-
| `GET` | `/api/scripts/options/roles` |
|
|
183
|
-
| `GET` / `PUT` / `DELETE` | `/api/scripts/{id}` |
|
|
184
|
-
| `GET` | `/api/scripts/{id}/routes` |
|
|
185
|
-
| `POST` | `/api/scripts/{id}/enable`、`/api/scripts/{id}/disable`、`/api/scripts/{id}/execute` |
|
|
186
|
-
| `GET` | `/api/scripts/{id}/versions`、`/api/scripts/{id}/executions` |
|
|
187
|
-
| `POST` | `/api/scripts/{id}/versions/{version_id}/restore` |
|
|
188
|
-
| `GET` | `/api/scripts/{id}/executions/{execution_id}` |
|
|
189
|
-
|
|
190
|
-
运行时 route 为 `ANY /api/x/{slug}/{path}`,不使用管理 API 信封。
|
|
191
|
-
|
|
192
|
-
## 验收清单
|
|
193
|
-
|
|
194
|
-
- [ ] `package main` 且实现 `Register(app *sdk.App)`。
|
|
195
|
-
- [ ] 服务使用 `mode=mixed`,第三方库写入 `go_mod`。
|
|
196
|
-
- [ ] 路由使用 `app.Route`,事件使用 `app.On`,定时任务使用 `app.Schedule`。
|
|
197
|
-
- [ ] handler 返回 `(any, error)`,需要状态码时使用 `ctx.Respond`。
|
|
198
|
-
- [ ] Route 显式设置 `permission` 与 `route_security`。
|
|
199
|
-
- [ ] 推送后请求无副作用 GET Route,必要时运行 `draftgo push custom_scripts --probe-routes`。
|
package/src/commands/doctor.js
DELETED
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const log = require('../logger');
|
|
4
|
-
const { all } = require('../installers');
|
|
5
|
-
const { detectTargets } = require('../detect');
|
|
6
|
-
const { findPython } = require('../python');
|
|
7
|
-
const { readInstalledVersion, getPackageVersion } = require('../skill');
|
|
8
|
-
const { fetchLatestVersion, cmpSemver } = require('../updateCheck');
|
|
9
|
-
|
|
10
|
-
async function doctor(projectDir, flags = {}) {
|
|
11
|
-
log.title('draftgo doctor');
|
|
12
|
-
|
|
13
|
-
log.info(`Node 版本:${process.version}`);
|
|
14
|
-
log.info(`平台:${process.platform}`);
|
|
15
|
-
log.info(`CLI 版本:${getPackageVersion()}`);
|
|
16
|
-
log.info(`项目目录:${projectDir}`);
|
|
17
|
-
|
|
18
|
-
console.log('');
|
|
19
|
-
const py = findPython();
|
|
20
|
-
if (py) log.ok(`Python:${py.bin} (${py.version})`);
|
|
21
|
-
else log.err('Python 未检测到(DraftGo init/sync 脚本需要 Python 3.9+)。');
|
|
22
|
-
|
|
23
|
-
console.log('');
|
|
24
|
-
if (!flags['skip-update-check'] && process.env.DRAFTGO_NO_UPDATE_CHECK !== '1') {
|
|
25
|
-
const current = getPackageVersion();
|
|
26
|
-
const latest = await fetchLatestVersion();
|
|
27
|
-
if (!latest) {
|
|
28
|
-
log.dim('CLI 最新版查询失败(可能离线或 registry 不可达)');
|
|
29
|
-
} else if (cmpSemver(latest, current) > 0) {
|
|
30
|
-
log.warn(`CLI 有新版:${current} → ${latest}`);
|
|
31
|
-
log.dim(' 运行 `draftgo upgrade` 可显式升级。');
|
|
32
|
-
} else {
|
|
33
|
-
log.ok(`CLI 已是最新:${current}`);
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
console.log('');
|
|
38
|
-
log.info('项目中检测到的 AI 工具信号:');
|
|
39
|
-
const hits = detectTargets(projectDir);
|
|
40
|
-
if (hits.length === 0) log.dim(' (无)');
|
|
41
|
-
else hits.forEach((n) => log.dim(` • ${n}`));
|
|
42
|
-
|
|
43
|
-
console.log('');
|
|
44
|
-
log.info(`已装 skill 版本:${readInstalledVersion(projectDir) || '未安装'}`);
|
|
45
|
-
log.info('各 AI 工具入口状态:');
|
|
46
|
-
for (const t of all) {
|
|
47
|
-
const st = t.status(projectDir);
|
|
48
|
-
const mark = st.installed ? log.c.green('✓') : log.c.gray('·');
|
|
49
|
-
console.log(` ${mark} ${t.name.padEnd(12)} ${t.displayName}`);
|
|
50
|
-
}
|
|
51
|
-
return 0;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
module.exports = doctor;
|