draftgo-cli 4.0.24 → 4.0.26

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.
Files changed (88) hide show
  1. package/README.md +23 -37
  2. package/package.json +3 -5
  3. package/resources/skill/SKILL.md +9 -5
  4. package/resources/skill/manifest.json +2 -5
  5. package/resources/skill/references/ai.md +41 -0
  6. package/resources/skill/references/app-api.md +2 -50
  7. package/resources/skill/references/architecture.md +1 -1
  8. package/resources/skill/references/chat-sdk.md +29 -37
  9. package/resources/skill/references/checkout.md +4 -4
  10. package/resources/skill/references/data.md +0 -46
  11. package/resources/skill/references/delivery.md +3 -3
  12. package/resources/skill/references/diagnostics.md +10 -11
  13. package/resources/skill/references/frontend.md +23 -20
  14. package/resources/skill/references/mcp.md +4 -14
  15. package/resources/skill/references/methods.md +15 -68
  16. package/resources/skill/references/modules.md +23 -44
  17. package/resources/skill/references/runtime.md +3 -20
  18. package/resources/skill/story/SKILL.md +2 -2
  19. package/src/apiContractCache.js +14 -6
  20. package/src/cli.js +0 -7
  21. package/src/commandRegistry.js +0 -6
  22. package/src/commands/api.js +87 -17
  23. package/src/commands/apiKey.js +2 -6
  24. package/src/commands/autoPush.js +15 -51
  25. package/src/commands/capabilities.js +22 -15
  26. package/src/commands/check.js +19 -53
  27. package/src/commands/checkout.js +1 -4
  28. package/src/commands/clean.js +1 -1
  29. package/src/commands/commit.js +1 -4
  30. package/src/commands/components.js +12 -8
  31. package/src/commands/conflict.js +4 -6
  32. package/src/commands/conflicts.js +1 -2
  33. package/src/commands/connect.js +0 -8
  34. package/src/commands/delete.js +15 -11
  35. package/src/commands/deploy.js +64 -26
  36. package/src/commands/diff.js +1 -4
  37. package/src/commands/group.js +2 -3
  38. package/src/commands/help.js +22 -43
  39. package/src/commands/init.js +13 -6
  40. package/src/commands/local.js +4 -1
  41. package/src/commands/map.js +138 -23
  42. package/src/commands/reconcile.js +1 -15
  43. package/src/commands/role.js +1 -2
  44. package/src/commands/status.js +12 -40
  45. package/src/commands/update.js +18 -24
  46. package/src/commands/verify.js +8 -7
  47. package/src/commands/worklog.js +11 -5
  48. package/src/contractCompatibility.js +10 -2
  49. package/src/localRuntime/compose.js +41 -27
  50. package/src/localRuntime/detect.js +6 -6
  51. package/src/localRuntime/index.js +47 -47
  52. package/src/localRuntime/services.js +2 -39
  53. package/src/mcp/client.js +99 -134
  54. package/src/mcp/parallel.js +25 -2
  55. package/src/mcp/protocol.js +38 -9
  56. package/src/mcp/tools.js +10 -19
  57. package/src/projectConfig.js +1 -4
  58. package/src/{workspaceHealth.js → projectHealth.js} +5 -5
  59. package/src/projectMap.js +1 -1
  60. package/src/runtimeFiles.js +2 -1
  61. package/src/worklog.js +3 -2
  62. package/src/worktree/backend.js +127 -15
  63. package/src/worktree/index.js +64 -22
  64. package/src/worktree/locks.js +52 -0
  65. package/src/worktree/manifest.js +18 -4
  66. package/src/worktree/status.js +4 -2
  67. package/resources/custom-service-sdk/ai.go +0 -520
  68. package/resources/custom-service-sdk/ai_test.go +0 -156
  69. package/resources/custom-service-sdk/auth_test.go +0 -56
  70. package/resources/custom-service-sdk/billing.go +0 -596
  71. package/resources/custom-service-sdk/billing_test.go +0 -150
  72. package/resources/custom-service-sdk/go.mod +0 -3
  73. package/resources/custom-service-sdk/manifest.json +0 -77
  74. package/resources/custom-service-sdk/platform.go +0 -352
  75. package/resources/custom-service-sdk/platform_logger_test.go +0 -24
  76. package/resources/custom-service-sdk/registration_test.go +0 -39
  77. package/resources/custom-service-sdk/resources.go +0 -247
  78. package/resources/custom-service-sdk/resources_billing_test.go +0 -115
  79. package/resources/custom-service-sdk/resources_files_test.go +0 -57
  80. package/resources/custom-service-sdk/resources_scope_test.go +0 -92
  81. package/resources/custom-service-sdk/sdk.go +0 -209
  82. package/resources/skill/references/aihub.md +0 -116
  83. package/resources/skill/references/custom-services.md +0 -201
  84. package/src/commands/customService.js +0 -95
  85. package/src/commands/dataRange.js +0 -33
  86. package/src/commands/grant.js +0 -29
  87. package/src/commands/space.js +0 -41
  88. package/src/customServices.js +0 -484
@@ -17,9 +17,9 @@ draftgo check --remote --output json
17
17
 
18
18
  `nav`、`docs` 同理。先用 `--stat` 或 `--summary` 确认变更范围,只有需要审查正文时才展开完整 diff。`commit` 返回新版本与哈希后,再用远端检查确认基线一致。409/412、未解决冲突或远端状态不明时停止。
19
19
 
20
- ## 结构化资源与自定义服务
20
+ ## 结构化资源
21
21
 
22
- 结构化资源按最新 describe 调用写 operation,再用 get/list operation 回读。自定义服务执行 `diff -> commit`,其中 commit 自动完成 validate 和 publish;需要运行行为证据时再执行 test。
22
+ 结构化资源按最新 describe 调用写 operation,再用 get/list operation 回读。
23
23
 
24
24
  ## 统一收尾
25
25
 
@@ -28,6 +28,6 @@ draftgo verify
28
28
  draftgo work complete <ref> --note "<结果与证据>"
29
29
  ```
30
30
 
31
- 默认 `verify` 不启动浏览器。只有用户明确要求视觉验收时,才增加 `--url <url> --screenshot always`;需要 DOM 或交互验证时再用 `--ui always`。所有 commit、MCP 写入、必要 test/publish 和回读都成功后才能 complete;失败项保持 active,并在 note 外记录可脱敏的 request ID。
31
+ 默认 `verify` 不启动浏览器。只有用户明确要求视觉验收时,才增加 `--url <url> --screenshot always`;需要 DOM 或交互验证时再用 `--ui always`。所有 commit、MCP 写入和回读都成功后才能 complete;失败项保持 active,并在 note 外记录可脱敏的 request ID。
32
32
 
33
33
  完成条件:本地检查通过,目标远端资源可回读,版本/哈希或结构化状态与预期一致,任务要求的运行或视觉证据齐全,且证据不含凭据。
@@ -14,7 +14,7 @@ draftgo map --type pages --summary --output json
14
14
  draftgo check --remote --output json
15
15
  ```
16
16
 
17
- `draftgo status` 的 `connection.health` 报告 `healthy`、`unhealthy` 或 `not_configured`,并输出当前 `platform`/`space` TokenScope;space 上下文同时带 `workspace_id` 与 `space_id`。只执行与故障层级有关的命令:连接失败看 `mcp test`;已知页面可用 `map --type pages --route <path>` 或 `--title <title>` 精确检查,未知资源先看 `map --summary`;checkout、哈希或版本异常看 `check --remote`。需要浏览时用 `--limit <1-100>`(默认 20)和单一类型的 `--cursor`,不运行默认全量 map。命令失败仍保留其非零退出码和脱敏输出。
17
+ `draftgo status` 的 `connection.health` 报告 `healthy`、`unhealthy` 或 `not_configured`。只执行与故障层级有关的命令:连接失败看 `mcp test`;已知页面可用 `map --type pages --route <path>` 或 `--title <title>` 精确检查,未知资源先看 `map --summary`;checkout、哈希或版本异常看 `check --remote`。需要浏览时用 `--limit <1-100>`(默认 20)和单一类型的 `--cursor`,不运行默认全量 map。命令失败仍保留其非零退出码和脱敏输出。
18
18
 
19
19
  API 运行失败时,用原 operation 生成结构化诊断:
20
20
 
@@ -24,28 +24,27 @@ draftgo api call <operation_id> --input request.json --output json
24
24
  draftgo api search "AI run logs"
25
25
  ```
26
26
 
27
- 记录 `operation_id`、`status_code`、`server_code`、`request_id`,再通过实时日志 operation 查询对应 run。AI 调用按入口 Agent/模型和 request ID 定位;子 Agent 链路从 span 查,不把一次入口请求误算成多条主 run。自定义服务再按 `custom-services.md` 执行 validate/test,页面运行时再读 `runtime.md`。
27
+ 记录 `operation_id`、`status_code`、`server_code`、`request_id`,再通过实时日志 operation 查询对应 run。AI 调用按入口 Agent/模型和 request ID 定位;子 Agent 链路从 span 查,不把一次入口请求误算成多条主 run。页面运行时问题再读 `runtime.md`。
28
28
 
29
- ## 权限与范围诊断
29
+ ## 权限诊断
30
30
 
31
31
  | 结果 | 最短定位 |
32
32
  |---|---|
33
- | 400 | 重新 `draftgo api describe <operation_id>`,核对当前 registry revision、`path/query/body/multipart` 容器、必填字段和 `scope_type/space_id` 组合。不要靠修改字段名试探契约。 |
33
+ | 400 | 重新 `draftgo api describe <operation_id>`,核对当前 registry revision、`path/query/body/multipart` 容器和必填字段。不要靠修改字段名试探契约。 |
34
34
  | 401 | 运行 `draftgo status`;检查项目是否连接、当前用户 API Key 是否缺失、过期或已撤销。重新连接或轮换后再试一次,不把密钥放进输入、宿主配置或日志。 |
35
- | 403 | 从结构化错误读取 `error_code`、`permission` 和 `scope_type`;核对 operation 所需 permission、API Key TokenScope、持久化 ResourceOwnership、有效 AccessGrant 和 DataRange。管理员身份与工作区成员关系都不是授权来源。 |
36
- | space 跨根拒绝 | 这是预期边界。确认目标资源保存的 workspace root 与 Grant 所属 root;改用同根 self/subtree Grant 或合法迁移流程。只有实时契约支持且明确需要跨空间管理时,才检查显式 permission 的 platform Grant。不要篡改 workspace/space ID 或 header 重试。 |
35
+ | 403 | 从结构化错误读取 `error_code` 和 `permission`;核对 operation 所需权限、当前用户有效角色及 API Key 是否仍有效。页面显隐不是服务端授权证据。 |
37
36
 
38
- 解释 Grant 来源时先用实时契约,不从角色名或 UI 状态推测:
37
+ 解释权限来源时先用实时契约,不从 UI 状态推测:
39
38
 
40
39
  ```bash
41
- draftgo grant list --input request.json
42
- draftgo api search "access grant explain"
40
+ draftgo role list
41
+ draftgo api search "effective permissions"
43
42
  draftgo api describe <explain_operation_id>
44
43
  draftgo api call <explain_operation_id> --input request.json --output json
45
44
  ```
46
45
 
47
- 按解释结果核对直接用户 Grant 与用户组 Grant 的并集、Role 中的精确 permission、space 的 self/subtree 覆盖、Grant/Role/成员/组的启用状态和有效期,以及最终 `matched_grant_ids` / DataRange。没有匹配来源时保持拒绝,不临时授予更大的 platform 权限来验证。
46
+ 按解释结果核对用户直接角色与用户组角色的并集、Role 中的精确 permission,以及用户、Role 和用户组状态。没有匹配来源时保持拒绝,不临时扩大权限来验证。
48
47
 
49
48
  不要在 issue、工作日志、命令参数或诊断文件中写 API Key、服务凭据、Authorization、完整请求头或上游服务地址。非幂等写入失败后先回读状态,不自动重试。
50
49
 
51
- 完成条件:故障已定位到连接、契约、权限、资源版本、Runner 或业务运行中的一层,并保留可关联的 request ID/run 证据;无法定位时明确缺少哪项服务端证据。
50
+ 完成条件:故障已定位到连接、契约、权限、资源版本或业务运行中的一层,并保留可关联的 request ID/run 证据;无法定位时明确缺少哪项服务端证据。
@@ -21,7 +21,7 @@ draftgo components show <library/component> --output json
21
21
 
22
22
  有合适组件时优先使用 `data-dg-use="library/component"`、`data-dg-instance`、`data-dg-prop-*` 和 `data-dg-slot`。个性化优先改 props、slots、CSS 变量和 Page 局部 class;高度个性化时使用 `draftgo components expand --page <id> --instance <name>`,展开后就是普通 HTML/CSS/JavaScript,不再跟随组件库升级。展开后的 Page 仍必须经过 `draftgo diff`、`draftgo verify`、`draftgo commit`。
23
23
 
24
- 开发组件库组件使用 `draftgo components checkout <library/component>`,直接编辑生成的 `component.html/css/js`、`contract.json` 和 `component.json`,然后依次执行 `components diff`、`components verify`、`components commit`。`commit` 只保存草稿;只有用户明确要求上线时才执行 `components publish`。库管理和组件创建、复制、删除、ZIP 导入导出均使用 `components libraries|create|copy|delete|import|export`,不要绕过 CLI 直接修改 DraftGo 数据库。
24
+ 开发组件库组件使用 `draftgo components checkout <library/component>`,直接编辑统一目录中的 `component.html`、`component.css`、`component.js` 和 `component.json`,然后依次执行 `components diff`、`components verify`、`components commit`。`component.json` 同时保存组件元数据和 Props、Slots、Events 等契约,不另设 `contract.json`。`commit` 只保存草稿;只有用户明确要求上线时才执行 `components publish`。库管理和组件创建、复制、删除、ZIP 导入导出均使用 `components libraries|create|copy|delete|import|export`,不要绕过 CLI 直接修改 DraftGo 数据库。
25
25
 
26
26
  ### 页面身份与创建
27
27
 
@@ -66,7 +66,7 @@ draftgo components show <library/component> --output json
66
66
  - 按钮、标签、导航项、徽章等视觉整体内部使用 `white-space: nowrap`;整组可换行,但图标与文字不能被拆散。
67
67
  - 空态需有明确文案和下一步操作;已有固定主操作入口时使用紧凑说明和就近操作,自定义空态用 flex 对齐图标与文字。
68
68
  - 弹窗和抽屉把滚动放在内容区,避免双滚动条;flex 内容区使用 `min-height: 0` 保持滚动可用。
69
- - 官方内置页的复杂选择器优先使用 Basecoat 或可访问的自定义弹层;普通 Page 可按场景使用原生 `<select>`,并补齐主题、焦点、禁用、空值和错误状态。
69
+ - 官方页面和交付页面的选择器统一使用 DraftGo 内置 `draftgo/select`(多选使用 `draftgo/multi-select`);不要使用原生 `<select>` 作为可见控件。组件运行时会把选项 slot 渲染为可访问的自绘面板,并处理键盘、焦点、禁用、空值和错误状态。
70
70
  - 运营表格可把排序和筛选放在对应表头的弹层中,保持数据列、条件和结果之间的直接关系;具体交互由数据规模与操作频率决定。
71
71
 
72
72
  ### 响应式
@@ -79,24 +79,23 @@ draftgo components show <library/component> --output json
79
79
 
80
80
  动效仅用于解释层级、状态、空间关系或操作结果。可用 CSS、Web Animations、组件库或内置 GSAP,并为 `prefers-reduced-motion` 降级;不得阻塞操作、掩盖等待、引发布局跳动或成为唯一状态表达。
81
81
 
82
- GSAP 从 `/assets/vendor/gsap/gsap.min.js` 先加载核心,再按需加载插件并 `gsap.registerPlugin(...)`。可用插件:`ScrollTrigger`、`ScrollToPlugin`、`Draggable`、`Flip`、`SplitText`、`MorphSVGPlugin`、`MotionPathPlugin`、`DrawSVGPlugin`、`Observer`、`EasePack`、`CustomEase`、`TextPlugin`。页面卸载时 kill timeline/trigger;同一属性不要同时由 CSS transition 与 GSAP 控制。
82
+ GSAP 从 `/assets/vendor/gsap/gsap.min.js` 加载核心;最终版本地额外提供 `/assets/vendor/gsap/Draggable.min.js`,使用时显式 `gsap.registerPlugin(Draggable)`。不要假设存在其他 GSAP 插件。页面卸载时清理 timeline 和 Draggable 实例;同一属性不要同时由 CSS transition 与 GSAP 控制。
83
83
 
84
84
  ## 运行形态
85
85
 
86
86
  - DraftGo 壳层位于 `frontend/`,使用 React 19 + Vite 8 + Tailwind CSS 4。只有用户明确要求修改壳层时才编辑该源码。
87
87
  - 业务页面与导航存储为数据库中的完整 HTML 文档,由壳层在 iframe 中运行。不得写入 TSX、ESM import、npm 依赖或 Vite 构建产物。
88
- - 数据库 Page 使用普通 HTML + Tailwind CSS 4 + 原生 JavaScript;官方内置 Page 默认搭配 Basecoat UI,按需使用下方列出的本地资源。
88
+ - 数据库 Page 使用普通 HTML + Tailwind CSS 4 + 原生 JavaScript;官方内置 Page 默认搭配 DraftGo 内置组件库,按需使用下方列出的本地资源。
89
89
  - 页面使用 `const App = window.parent?.App`。参数读取 `window.__DG_ROUTE_CONTEXT__.query`;页面跳转使用父窗口;登出调用 `await App.logout()`。
90
90
 
91
91
  ## 实践建议
92
92
 
93
93
  - 提交完整 `<html><head><body>` 文档,静态资源使用下方本地路径。
94
- - Basecoat 是默认 Page 组件库;Oat Web Components 场景的可选组件库,版本处于 pre-1.0。每个 Page 按场景选择其中一套组件库。
94
+ - DraftGo 是唯一官方 Page 组件库,使用 `draftgo/*` 组件名和 `data-dg-use` 引用。组件定义、props、slots、CSS 变量和 revision 以服务端实时组件目录为准;不要在 Skill 或页面中复制静态组件契约。第三方页面可以自带局部 HTML/CSS/JavaScript,但仍应遵守本地资源和无障碍规则。
95
95
  - 默认使用 `var(--dg-*)` 主题 token,并支持浅色/深色;用户输入或不可信 HTML 经 DOMPurify 净化。
96
96
  - 使用 `App.confirm()`、`App.toast()` 或对应反馈 API;关键状态不能只靠颜色或动画。
97
97
  - 建议调用全局 `App.formatDateTime(value, options)` 来适配系统时间显示;API 时间按 UTC 解析,页面不要直接按浏览器本地时区展示。
98
98
  - 初始渲染立即显示稳定的加载状态。
99
- - 空间业务页先读取有效的 `{ scope_type: 'space', space_id }` 再发送业务请求;上下文就绪期间保持稳定加载状态,没有可用工作空间时呈现紧凑的工作空间状态和重试入口。完整写法见 `app-api.md`。
100
99
  - 页面文案使用页面级 `page_i18n`:静态 HTML 可用 `data-i18n-key` / `data-i18n-placeholder`,JavaScript 使用 `App.t(key, fallback, values)`;不要创建公共词条表或自定义 namespace。翻译输入必须保持原 messages key 集合和 ICU 占位符不变。
101
100
  - 选择器、Toast 等交互控件优先采用项目已有组件或统一封装,使视觉、状态和反馈与页面设计系统保持一致;提示就近呈现并说明下一步操作。
102
101
  - 外部资源优先使用项目内置文件;品牌图标的明确例外见资源章节。
@@ -109,10 +108,9 @@ GSAP 从 `/assets/vendor/gsap/gsap.min.js` 先加载核心,再按需加载插
109
108
 
110
109
  | 名称 | 版本与形态 | 本地资源 |
111
110
  |---|---|---|
112
- | Basecoat UI | 1.0.2,HTML/CSS/JS,`window.basecoat` | `/assets/vendor/basecoat/basecoat.min.css`、`basecoat.min.js` |
113
- | Oat UI | 0.7.0,Web Components,`window.ot` | `/assets/vendor/oat/oat.min.css`、`oat.min.js` |
111
+ | DraftGo 内置组件库 | 服务端实时目录;浏览器原生 Custom Elements/HTML 运行时 | `/assets/adapters/draftgo-components.js`、`/assets/adapters/draftgo-theme.css` |
114
112
 
115
- `/assets/adapters/draftgo-ui.js` 提供 `window.DraftGoUI` 与 `DraftGoUI.load('basecoat'|'oat')`。壳层自动注入 `/assets/adapters/draftgo-theme.css` 与组件运行时,Page 可直接使用;第三方 Page 按产品需求自主选择技术与视觉方案。使用组件库时通过公开类名/API 和 DraftGo 语义 token 适配。
113
+ `/assets/adapters/draftgo-ui.js` 仅提供 `DraftGoUI.load('draftgo')` 的轻量入口和主题快照,不再加载第三方组件库。壳层会自动注入主题与组件运行时;页面通常直接声明 `data-dg-use="draftgo/<component>"`,复杂交互优先复用当前目录中的组件。
116
114
 
117
115
  确认、信息弹层和反馈优先使用 `App.confirm()`、`App.showModal()`、`App.showSuccess/showError/showInfo/showWarning()`,避免页面各自复制 Toast 或浏览器原生对话框。
118
116
 
@@ -122,14 +120,15 @@ GSAP 从 `/assets/vendor/gsap/gsap.min.js` 先加载核心,再按需加载插
122
120
  |---|---|
123
121
  | Tailwind CSS 4.3.1 Browser Runtime | `/assets/tailwindcss.js` |
124
122
  | UI adapters | `/assets/adapters/draftgo-ui.js`、`/assets/adapters/draftgo-theme.css` |
125
- | Basecoat/Oat | `/assets/vendor/basecoat/*`、`/assets/vendor/oat/*` |
123
+ | DraftGo 内置组件 | `/assets/adapters/draftgo-components.js`、`/assets/adapters/draftgo-theme.css` |
126
124
  | Icons | `/assets/fontawesome/css/all.min.css`、`/assets/icons/{name}.svg`、`/assets/icons/manifest.json` |
125
+ | Provider brands | `/assets/providers/{provider}.svg`、`/assets/providers/provider-icons.js` |
127
126
  | Markdown/code | `/assets/vendor/marked/marked.min.js`、`/assets/vendor/highlightjs/highlight.min.js`、`/assets/vendor/highlightjs/styles/github.min.css` |
128
127
  | HTML security | `/assets/vendor/dompurify/purify.min.js` |
129
- | Chat | `/assets/draftgo-chat.js` |
130
- | Motion | `/assets/vendor/gsap/*.js` |
128
+ | Chat runtime | 完整实现位于 `draftgo/chat` 的 `Definition.JS`,随组件按需解析与发布 |
129
+ | Motion | `/assets/vendor/gsap/gsap.min.js`、`/assets/vendor/gsap/Draggable.min.js` |
131
130
 
132
- 正文使用系统无衬线字体栈,代码使用系统等宽字体栈。通用图标优先使用项目内置 SVG,其他通用图标可使用 Font Awesome。模型/Provider 品牌标识可用固定版本的 LobeHub `@lobehub/icons-static-svg` npmmirror URL
131
+ 正文使用系统无衬线字体栈,代码使用系统等宽字体栈。通用图标优先使用项目内置 SVG,其他通用图标可使用 Font Awesome。模型/Provider 品牌标识使用本地 `/assets/providers/`;通过 `DraftGoProviderIcons.get(provider.kind)` 查找,未知或加载失败时回退通用图标,不访问 CDN
133
132
 
134
133
  ## 主题
135
134
 
@@ -142,16 +141,20 @@ GSAP 从 `/assets/vendor/gsap/gsap.min.js` 先加载核心,再按需加载插
142
141
 
143
142
  壳层已把变量注入 `<head>`,直接使用即可。默认继承 `App.theme` 与 `App.colorScheme`。品牌或图表需要自主配色时,先定义页面局部变量并提供 light/dark 两套值;正文和交互文字保持 WCAG AA。不要把 hex/rgb 散落在组件样式中。
144
143
 
145
- ## AIHub 页面 SDK
144
+ ## AI 页面 SDK
146
145
 
147
- AI 对话 UI 使用:
146
+ DraftGo Page 的 AI 对话 UI 使用组件目录中的 `draftgo/chat`,不要手工加载 SDK 或自行实现流式状态:
148
147
 
149
148
  ```html
150
- <script src="/assets/draftgo-chat.js"></script>
151
- <dg-chat protocol="draftgo-agent" agent-id="AGENT_ID"></dg-chat>
149
+ <dg-chat
150
+ data-dg-use="draftgo/chat"
151
+ data-dg-instance="page-assistant"
152
+ data-dg-prop-agent-id="AGENT_ID"
153
+ data-dg-prop-view="conversation"
154
+ data-dg-prop-surface="inline">
155
+ </dg-chat>
152
156
  ```
153
157
 
154
- 动态创建使用 `DraftGoChat.create()`;无 UI 文本或图片调用可用同一脚本的 `DraftGoAI` 兼容门面。完整事件、会话和安全契约见 `chat-sdk.md`,Agent `spec` `aihub.md`。
158
+ 完整 Chat 实现保存在 `draftgo/chat` 组件的 `Definition.JS`,与其他组件统一按需解析;同一 Page iframe 内相同 revision 与 hash 只编译一次。Page 使用 `<dg-chat data-dg-use="draftgo/chat">`,不手工加载第二套脚本。无 UI 的文本、图片或其他模型能力调用统一走服务端 AI Registry。完整组件边界见 `chat-sdk.md`,服务端 AI 能力见 `ai.md`。
155
159
 
156
- 平台请求与反馈见 `app-api.md`;iframe 路由、认证与全局层见 `runtime.md`;动态 DB、`scope=mine`、筛选和关系见 `data.md`。
157
- Chat JSON 配置按 DraftGo 当前 `contracts/chat-sdk.schema.json` 校验,函数型扩展只在 JavaScript 注册。
160
+ 平台请求与反馈见 `app-api.md`;iframe 路由、认证与全局层见 `runtime.md`;动态 DB、筛选和关系见 `data.md`。DraftGo Page 的可序列化 Chat 配置以 `draftgo components show draftgo/chat` 返回的实时契约为准;函数型扩展只用于外部应用的直接 SDK 接入。
@@ -18,17 +18,9 @@ draftgo capabilities search <query> --output json
18
18
  draftgo capabilities show <operation_id> --output json
19
19
  draftgo capabilities audit --output json
20
20
 
21
- # 领域快捷命令(仍使用实时 operation describe/cache)
22
- draftgo role list
23
- draftgo space list
24
- draftgo grant create --input request.json
25
- draftgo data-range list
26
- draftgo api-key status
27
-
28
21
  # 领域快捷命令(仍使用实时 operation describe/cache)
29
22
  draftgo role list
30
23
  draftgo group list --input request.json
31
- draftgo grant list --input request.json
32
24
  draftgo api-key status
33
25
  ```
34
26
 
@@ -36,7 +28,7 @@ draftgo api-key status
36
28
 
37
29
  ## 边界
38
30
 
39
- MCP 用于实时发现、结构化查询和普通 API 操作。pages、navigations、docs/articles、custom_services 的完整正文走 `draftgo checkout` / `draftgo commit`;工具返回 `artifact` 或 `omitted` 时保留该语义,不要求模型展开长内容。
31
+ MCP 用于实时发现、结构化查询和普通 API 操作。pages、navigations、docs/articles 的完整正文走 `draftgo checkout` / `draftgo commit`;工具返回 `artifact` 或 `omitted` 时保留该语义,不要求模型展开长内容。
40
32
 
41
33
  不要增加聚合上下文工具或静态 API 路径表。按任务读取最少必要的 Reference,再调用精确工具:
42
34
 
@@ -45,9 +37,9 @@ MCP 用于实时发现、结构化查询和普通 API 操作。pages、navigatio
45
37
  | 项目能力、registry 覆盖和 checkout 类型 | `draftgo_project_overview` |
46
38
  | 定位资源 | `draftgo_resource_search` / `draftgo_resource_list` |
47
39
  | 元数据或短片段 | `draftgo_resource_get_metadata` / `draftgo_resource_read_fragment` |
48
- | 定位 API operation | `draftgo_api_search` |
49
- | 读取 operation schema | `draftgo_api_describe` |
50
- | 结构化读写 | `draftgo_api_call` |
40
+ | 定位 API operation | Registry `search`(兼容 `draftgo_api_search`) |
41
+ | 读取 operation schema | Registry `describe`(兼容 `draftgo_api_describe`) |
42
+ | 结构化读写 | Registry `invoke`(兼容 `draftgo_api_call`) |
51
43
 
52
44
  只在需要对应信息时调用工具,不把 `project_overview` 作为每个任务的固定前置步骤。独立资源或 operation 可并发调用;同一资源的依赖步骤保持顺序。非幂等写入失败后先读状态,不自动重试。
53
45
 
@@ -62,8 +54,6 @@ MCP 用于实时发现、结构化查询和普通 API 操作。pages、navigatio
62
54
 
63
55
  describe 缺少本次调用需要的 schema、权限、风险或响应契约时停止并报告,不猜字段、不拼路径、不绕过 MCP。多个 operation 仍可能匹配时继续缩小 search,而不是任选一个。
64
56
 
65
- 动态 Go 自定义服务 Route 也在 registry 中:module 为 `scripts_dynamic`,resource type 为 `custom_scripts`。Route 的 SDK、身份和运行限制见 `custom-services.md`。
66
-
67
57
  ## 调用形状
68
58
 
69
59
  ```json
@@ -1,5 +1,5 @@
1
1
  ---
2
- read_when: 不确定 DraftGo 任务应使用 API/MCP 还是 checkout;需要 AIHub、数据、内容、自定义服务、诊断或交付的最短正确命令链时
2
+ read_when: 不确定 DraftGo 任务应使用 API/MCP 还是 checkout;需要 AI、数据、内容、诊断或交付的最短正确命令链时
3
3
  ---
4
4
 
5
5
  # 极简方法指南
@@ -16,24 +16,24 @@ draftgo api call <operation_id> --input request.json --output json
16
16
 
17
17
  所有 `--output json` 命令都将单一 UTF-8 JSON 写到 stdout,诊断写入 stderr。先选择摘要、精确筛选或分页,避免用终端截断处理大结果。
18
18
 
19
- ## AIHub
19
+ ## AI 能力
20
20
 
21
21
  适用场景:查询或管理 Agent、模型、供应商、路由、Skill、Prompt,或验证一次 AI 调用。
22
22
 
23
23
  ```bash
24
- draftgo api search "AIHub <agent|model|provider|route>"
24
+ draftgo api search "<agent|model|provider|route>"
25
25
  draftgo api describe <operation_id>
26
26
  draftgo api call <operation_id> --input request.json --output json
27
27
  draftgo api search "AI run logs"
28
28
  ```
29
29
 
30
- 关键约束与失败定位:AIHub 是结构化远端资源,不 checkout;只传 describe 允许的字段。不得把 API Key、Authorization、供应商 header 或上游地址写入文件和日志。401/403 查登录、`aihub:*` 权限和资源调用策略;503 查模型路由、适配器与凭据是否就绪。
30
+ 关键约束与失败定位:AI 配置是结构化远端资源,不 checkout;只传 describe 允许的字段。不得把 API Key、Authorization、供应商 header 或上游地址写入文件和日志。401/403 查登录、实时 permission 和资源调用策略;503 查模型路由、适配器与凭据是否就绪。
31
31
 
32
- 完成条件:写入后的目标 ID 可由 get/list operation 回读;任务涉及调用时,调用成功且 run 能按入口 Agent/模型或 request ID 定位。完整字段和编排规则再读 `aihub.md`。
32
+ 完成条件:写入后的目标 ID 可由 get/list operation 回读;任务涉及调用时,调用成功且 run 能按入口 Agent/模型或 request ID 定位。模块边界和验证规则再读 `ai.md`。
33
33
 
34
34
  ## 知识库与记忆
35
35
 
36
- 适用场景:知识库、文档、Chunk、检索/重建,以及 Agent 长期记忆和作用域配置。
36
+ 适用场景:知识库、文档、Chunk、检索/重建,以及 Agent 长期记忆配置。
37
37
 
38
38
  ```bash
39
39
  draftgo api search "knowledge base"
@@ -42,51 +42,18 @@ draftgo api describe <operation_id>
42
42
  draftgo api call <operation_id> --input request.json --output json
43
43
  ```
44
44
 
45
- 关键约束与失败定位:知识库保存可检索资料,记忆保存运行时提炼结果,不能互相替代。知识库操作使用独立的 `knowledge:*`,不会继承 `aihub:*`。上传、检索、重建和记忆字段均以 describe 为准;没有专用 CLI 子命令。检索为空时依次核对文档状态、索引/重建结果、作用域和调用权限。
45
+ 关键约束与失败定位:知识库保存可检索资料,记忆保存运行时提炼结果,不能互相替代。上传、检索、重建、权限和记忆字段均以 describe 为准;没有专用 CLI 子命令。检索为空时依次核对文档状态、索引/重建结果和调用权限。
46
46
 
47
47
  完成条件:目标资源可回读;任务涉及检索或记忆召回时,最小验证调用能返回预期范围的数据,且运行日志可关联。
48
48
 
49
- ## 统一权限与数据范围
49
+ ## 身份与权限
50
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
- 用户注册成功时,服务端会授予所有启用的注册默认平台 Role,并将用户加入系统默认工作区及其 `default_members` 用户组;前者创建 AccessGrant,后者创建成员关系,两者互不替代。
64
-
65
- ### 空间化最短流程
66
-
67
- 开始前只运行一次 `draftgo status` 确认连接健康和 API Key 当前范围;需要选择空间时再运行 `draftgo space list`。目标 operation 仍须以实时 `describe` 的 `permission`、`supported_scopes` 和 `ownership_mode` 为准。
68
-
69
- | 场景 | 最短正确做法 |
70
- |---|---|
71
- | 单空间 | 固定使用该业务空间;调用输入传 `scope_type=space` 和目标 `space_id`。不为“方便”创建 platform Grant、子空间或用户组。 |
72
- | 多空间 | 每次先确定目标空间,再以该 `space_id` 调用;切换空间后重新读取目标资源。不要缓存一个空间的资源 ID 后在另一个空间复用。 |
73
- | 平台跨空间 | 仅当 operation 的实时契约支持 `platform`,且当前用户的 platform AccessGrant 明确包含所需 permission 时传 `scope_type=platform`。普通空间写入仍选择具体空间。 |
74
- | 超级管理员普通使用 | 与普通用户相同,选择当前业务空间并传 `scope_type=space`。管理员身份不把资源改成 platform 归属,也不绕过 Authorizer、DataRange 或持久化 ownership。 |
75
-
76
- 空间调用输入只增加实时 MCP 支持的范围字段,其余容器仍按 `describe` 填写:
77
-
78
- ```json
79
- {"scope_type":"space","space_id":120,"path":{},"query":{},"body":{}}
80
- ```
81
-
82
- 平台调用使用 `{"scope_type":"platform", ...}` 且不传 `space_id`。对已有资源的按 ID 操作,客户端选择的范围不能覆盖服务端已保存的 ResourceOwnership;403 时进入 `diagnostics.md`,不要改 ID 或扩大范围反复试探。
51
+ CLI、MCP 与直接 HTTP API 使用同一个用户 API Key,并进入相同的基础 RBAC 和业务守卫。CLI 不创建服务主体或隐式管理员上下文,也不向 `invoke` 注入契约之外的授权字段。403 时检查目标 operation 的实时 `permission`、当前用户角色和资源所有者规则,不通过修改 ID 或请求字段反复试探。
83
52
 
84
53
  ## 页面、导航与内容
85
54
 
86
55
  适用场景:修改已有 page/navigation/article 完整正文,或创建后继续编辑正文。
87
56
 
88
- `docs/articles` 是系统说明使用的平台资源,只接受 platform scope;不要为文档传 `scope_type=space` 或 `space_id`。
89
-
90
57
  ```bash
91
58
  draftgo map --type pages --route /admin/channel-ops --output json
92
59
  draftgo checkout pages <id>
@@ -123,26 +90,6 @@ draftgo api search "dynamic db record"
123
90
 
124
91
  完成条件:schema 可按 `type` 回读,目标角色的最小 CRUD/筛选符合预期;批量写入还需验证失败时整批回滚。字段和关系规则再读 `data.md`。
125
92
 
126
- ## 自定义服务
127
-
128
- 适用场景:编写、保存、验证、试运行或发布 Go 自定义服务。
129
-
130
- ```bash
131
- draftgo api search "custom service create"
132
- draftgo api describe <operation_id>
133
- draftgo api call <operation_id> --input request.json --output json
134
- draftgo checkout custom-services <id>
135
- draftgo diff custom-services <id>
136
- draftgo commit custom-services <id>
137
- draftgo validate custom-services <id>
138
- draftgo test custom-services <id> --source draft --handler route:POST:/path --input request.json
139
- draftgo publish custom-services <id>
140
- ```
141
-
142
- 关键约束与失败定位:自定义服务只有一种 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 冲突停止重试。
143
-
144
- 完成条件:`commit custom-services` 返回 published 且 validate passed;需要运行行为证据时再要求 test success。完整 SDK、handler selector 和依赖规则再读 `custom-services.md`。
145
-
146
93
  ## MCP 与实时契约
147
94
 
148
95
  适用场景:首次连接、宿主配置变化、工具不可用,或不知道 operation/schema。
@@ -154,13 +101,13 @@ draftgo api search "<业务能力>"
154
101
  draftgo api describe <operation_id>
155
102
  ```
156
103
 
157
- 关键约束与失败定位:已配置且健康时不必每个任务重复 setup/status/test。宿主配置只运行 `draftgo mcp serve`,不得保存 API Key。401/403 查用户 API Key 和 grant;session/uninitialized 重新建立连接;operation 不唯一时继续缩小 search;describe 缺字段、风险或响应契约时停止。
104
+ 关键约束与失败定位:已配置且健康时不必每个任务重复 setup/status/test。宿主配置只运行 `draftgo mcp serve`,不得保存 API Key。401/403 查用户 API Key、角色和目标权限;session/uninitialized 重新建立连接;operation 不唯一时继续缩小 search;describe 缺字段、风险或响应契约时停止。
158
105
 
159
106
  完成条件:initialize、tools/list、关键 tools/call 可用,目标 operation schema 已确认且可回读一次无副作用结果。完整缓存、风险和 multipart 规则再读 `mcp.md`。
160
107
 
161
108
  ## 运行诊断
162
109
 
163
- 适用场景:连接失败、API 调用失败、checkout 状态异常,或需要定位 AI/custom-service run。
110
+ 适用场景:连接失败、API 调用失败、checkout 状态异常,或需要定位 AI run。
164
111
 
165
112
  ```bash
166
113
  draftgo mcp status
@@ -171,9 +118,9 @@ draftgo api describe <operation_id>
171
118
  draftgo api call <operation_id> --input request.json --output json
172
119
  ```
173
120
 
174
- 关键约束与失败定位:只运行与故障层级相关的命令。保留脱敏的 `operation_id`、`status_code`、`server_code`、`request_id`;非幂等写失败后先回读状态,不自动重试。连接问题看 mcp test,正文版本看 check/conflicts,AI 与服务运行问题再 search 对应日志 operation。
121
+ 关键约束与失败定位:只运行与故障层级相关的命令。保留脱敏的 `operation_id`、`status_code`、`server_code`、`request_id`;非幂等写失败后先回读状态,不自动重试。连接问题看 mcp test,正文版本看 check/conflicts,AI 运行问题再 search 对应日志 operation。
175
122
 
176
- 完成条件:故障被定位到连接、契约、权限、资源版本、Runner 或业务运行中的一层,并有 request ID/run 等可关联证据。完整分流再读 `diagnostics.md`。
123
+ 完成条件:故障被定位到连接、契约、权限、资源版本或业务运行中的一层,并有 request ID/run 等可关联证据。完整分流再读 `diagnostics.md`。
177
124
 
178
125
  ## 交付验收
179
126
 
@@ -185,8 +132,8 @@ draftgo check --remote --output json
185
132
  draftgo work complete <ref> --note "<结果与证据>"
186
133
  ```
187
134
 
188
- 正文资源在 complete 前还必须成功执行 `diff -> commit`;结构化资源必须 call 后回读;自定义服务按任务要求追加 validate/test/publish。默认不启动浏览器,只有用户明确要求视觉验收时才使用 `draftgo verify --url <url> --screenshot always`,需要 DOM/交互时再加 `--ui always`。
135
+ 正文资源在 complete 前还必须成功执行 `diff -> commit`;结构化资源必须 call 后回读。默认不启动浏览器,只有用户明确要求视觉验收时才使用 `draftgo verify --url <url> --screenshot always`,需要 DOM/交互时再加 `--ui always`。
189
136
 
190
- 关键约束与失败定位:本地验证通过不等于已提交或已发布。任何 verify、commit、MCP 写入、必要 test/publish、回读或视觉验收失败时,工作项保持 active。
137
+ 关键约束与失败定位:本地验证通过不等于已提交或已发布。任何 verify、commit、MCP 写入、回读或视觉验收失败时,工作项保持 active。
191
138
 
192
139
  完成条件:全部目标远端状态可回读,正文版本/哈希或结构化状态符合预期,任务要求的运行/视觉证据齐全且不含凭据,然后才 complete。
@@ -12,41 +12,38 @@ read_when: 评估功能可行性时 · 选择开发路径时 · 进入新项目
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` |
16
- | AIHub | 配置 AI Agent(模型/编排/能力/子智能体/记忆);页面对话使用 `<dg-chat>`,图片模式使用 `DraftGoAI.images`;见 `references/chat-sdk.md` `references/aihub.md` | MCP 实时 API;不创建本地镜像 |
17
- | 文档中心 | 平台级 Markdown/HTML 系统文章 + 分类树 | 正文用 `checkout docs` / `commit docs`;分类用 MCP;不传 space scope |
15
+ | AI 能力 | 配置模型、提示词、插件、知识库、记忆和智能体;DraftGo Page 对话使用 `draftgo/chat`;图片、Embedding、Rerank、TTS、ASR Video 通过服务端 AI Registry 调用;见 `references/chat-sdk.md` `references/ai.md` | MCP 实时 API;不创建本地镜像 |
16
+ | 文档中心 | Markdown/HTML 系统文章 + 分类树 | 正文用 `checkout docs` / `commit docs`;分类用 MCP |
18
17
  | 系统配置 | KV 存储,含全局前端层槽位 | MCP 实时 API;不创建本地镜像 |
19
- | 商业与计费 | 账本、余额、权益、支付订单、退款、套餐、订阅和 AI 计费 | 管理任务用 MCP 实时 API;自定义服务用 `ctx.Billing` / `ctx.Admin.Billing`;不要用动态 DB 重建金钱状态 |
18
+ | 支付与余额 | 账单、支付、退款、余额和资金流水 | 管理任务用 MCP 实时 API;不要用动态 DB 重建金钱状态 |
20
19
 
21
20
  ## 平台内置模块(开箱即用,不需实现)
22
21
 
23
22
  | 模块 | 能力 | 调用方式 |
24
23
  |---|---|---|
25
24
  | 认证 | 注册/登录/刷新/找回密码/微信登录/手机邮箱验证 | 页面使用 `App`;服务端操作通过 MCP 实时描述接口 |
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
+ | 角色权限 | Role 权限模板、用户直接角色与用户组角色 | 页面可用 `App.permissions` 辅助显隐;服务端执行最终授权 |
26
+ | 用户组 | 用户组成员与角色分配 | MCP 实时 API;CLI 提供 `group` 快捷命令 |
27
+ | API Key | 当前用户的 System MCP 凭据 | CLI 提供 `api-key` 快捷命令;不把凭据写入请求文件或宿主配置 |
29
28
  | 通知公告 | 发布公告,支持类型/状态/分页 | MCP 实时 API |
30
29
  | 工单反馈 | 用户提交问题,支持类型/状态跟踪 | MCP 实时 API |
31
30
  | 备份恢复 | 完整/选择性备份,JSON/.dgbak 格式,支持 dry-run | MCP 实时 API |
32
31
  | 系统管理 | 系统配置 KV、存储健康、全局前端层、通知测试 | MCP 实时 API |
33
32
 
34
- `App.currentUser.role_code` 是展示投影,不是用户表中的可写字段。真正的资源/API 授权由服务端根据 ResourceOwnership 与有效 AccessGrant 决定;platform Grant 也只能使用角色中显式声明的权限。
33
+ `App.currentUser.role_code` 是展示投影,不是用户表中的可写字段。真正的资源/API 授权由服务端根据有效 Role、用户组角色、资源所有者规则和业务守卫决定。
35
34
 
36
- 用户 API Key 只是一种用户认证方式;它不改变 AccessGrant、ResourceOwnership、DataRange 或管理员边界。无人值守任务由平台运行时以 system 身份执行。
35
+ 用户 API Key 只是一种用户认证方式;它始终代表当前用户,不能创建服务身份或绕过管理员边界。
37
36
 
38
37
  ## 新模块权限接入检查表
39
38
 
40
39
  AI 新建或扩展受保护模块时,按以下最小闭环逐项确认;缺少任一项都不能用页面显隐、角色名或调用来源补洞:
41
40
 
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 时再覆盖他人记录拒绝。不要为同一规则复制一套测试框架。
41
+ - [ ] 在统一 Permission Catalog 注册每个 `resource:action`,不在模块内另建权限字符串或角色分支。
42
+ - [ ] HTTP、MCP 和后台任务等所有实际入口复用同一授权路径。
43
+ - [ ] ID 操作先加载服务端真实资源;忽略客户端提交的 owner 或调用者替代值。
44
+ - [ ] 保留最小拒绝证据:缺少权限、伪造 owner、越权访问他人资源。不要为同一规则复制一套测试框架。
48
45
 
49
- 实现位置和具体 API 以目标 DraftGo 服务端仓库的现有 Catalog、ResourceOwnershipWorkspaceAuthorizer 模式为准;本 Skill 不复制服务端动态 schema。
46
+ 实现位置和具体 API 以目标 DraftGo 服务端仓库的现有 Permission Catalog 与 Authorizer 模式为准;本 Skill 不复制服务端动态 schema。
50
47
 
51
48
  ## 模块选型决策
52
49
 
@@ -58,37 +55,19 @@ AI 新建或扩展受保护模块时,按以下最小闭环逐项确认;缺
58
55
  要保存文件?
59
56
  → 文件夹、上传、下载、回收站或业务绑定 → 文件资产模块;不要把文件字节塞进动态 DB
60
57
 
61
- 要做余额、支付、会员或订阅?
62
- 管理操作走 money/payment/subscription/billing 的 MCP 实时契约;自定义服务读 `.draftgo-sdk/billing.go` 并使用 Billing SDK,不自行实现账本或扣费一致性
58
+ 要做余额、支付或退款?
59
+ payment/wallet 的 MCP 实时契约,不自行实现账本或扣费一致性
63
60
 
64
61
  要调用 AI?
65
- → 聊天/问答 UI → AIHub + `<dg-chat>`(自动隔离 thread/session)
66
- → 无 UI 的旧代码文本调用AIHub + DraftGoAI.chat()(兼容门面)
67
- → 图片生成 → AIHub + DraftGoAI.images()
68
- → Responses、Embedding、Rerank、TTS、ASR 或 Video → AIHub capability 与 provider readiness;先确认模型的 canonical capability 和 transport
69
- 需要工具/子智能体/记忆/结构化输出/多模态都是 Agent spec 开关,见 references/aihub.md
70
-
71
- 要调用第三方服务?
72
- → 自定义服务(用 `ctx.HTTP` 请求;在同一 Go 服务中按需注册 Route/Event/Scheduled handler)
62
+ DraftGo Page 聊天/问答 UI → AI 能力 + `draftgo/chat`(组件定义按需解析,自动隔离 thread/session)
63
+ → 无 UI 的文本或媒体调用AI 能力 + MCP Registry operation(先 search/describe,再 call)
64
+ → 图片生成 → AI 能力的 image capability 与当前 Provider readiness
65
+ → Responses、Embedding、Rerank、TTS、ASR 或 Video → 模型 capability 与 provider readiness;先确认模型的 canonical capability 和 transport
66
+ 需要工具、知识、记忆、结构化输出或多模态先读 references/ai.md,再通过实时 Registry 确认当前契约
73
67
 
74
68
  要展示内容文档?
75
69
  → 文档中心(Markdown + 分类树)
76
70
 
77
- 要做定时任务或事件响应?
78
- 自定义服务(用 `app.Schedule` / `app.On` 注册;后端自动识别定时任务和事件 handler)
79
-
80
- 要做后台管理页?
81
- → 业务页面 + 动态 DB + 角色权限
82
- ```
83
-
84
- ## 自定义服务边界
85
-
86
- - 新服务使用 Go `Register(app *sdk.App)` 自动注册路由、事件和定时任务;完整语言、`draftgo` 和 SDK 契约见 `references/custom-services.md`。
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。
90
- - 新 Go 服务的 `Register` 是唯一触发器事实来源;旧 `triggers` 字段不参与注册。
91
- - 管理面由角色 RBAC 的 `scripts:*` 动作控制;Route 不再读取服务级 `permission`,由宿主认证、持久化 ownership 和 `scripts:execute` AccessGrant 统一控制。
92
- - Go 服务在独立子进程中构建/运行;只有可信角色才能获得 `scripts:create` / `scripts:update`。
93
- - 自定义服务适合服务端加工、鉴权后聚合、第三方回调、定时任务和事件响应;普通 CRUD 管理界面优先用“页面 + 动态 DB”,不要把所有业务后台都塞进 route 脚本。
94
- - 脚本内读动态 DB 用 `ctx.DB.Query(type, sdk.QueryOptions{...})`;返回 `sdk.QueryResult`,分页和筛选见 `references/custom-services.md`。
71
+ 要做后台管理页?
72
+ 业务页面 + 动态 DB + 角色权限
73
+ ```
@@ -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`(路由/主题/作用域)+ `i18n.js`(国际化)+ state(currentUser/isAdmin/config/theme/scopeContext
38
+ `app` 组成:`api.js`(请求)+ `feedback.js`(弹窗/Toast)+ `runtime.js`(路由/主题)+ `i18n.js`(国际化)+ state(currentUser/isAdmin/config/theme)
39
39
 
40
40
  完整 API 见 `references/app-api.md`
41
41
 
@@ -104,23 +104,6 @@ registry revision 变化时 `draftgo_api_describe`,再用 `draftgo_api_call`
104
104
  页面管理中 Toast 时长以秒输入,`sys_config` 中仍以毫秒存储。例如 UI 中
105
105
  `错误 Toast 时长(s) = 4.5` 对应 `frontend_global_toast_duration_error.config_value = 4500`。
106
106
 
107
- ## 统一作用域
107
+ ## 认证与权限边界
108
108
 
109
- DraftGo 的资源归属和授权范围只有 `platform`、`space`。`Role` 是无作用域权限模板;`AccessGrant`
110
- 定义 user/group 主体在哪个范围拥有该角色。运行时 `system/0` 调用不是 AccessGrant 主体;工作区成员与用户组成员关系本身不授予权限。
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 只能收窄,不能变成管理员或 system 身份。CI、定时任务和共享服务等
126
- 无人值守自动化由平台运行时使用 system 身份;CLI 不生成、导出或伪造服务主体凭据。Event/Scheduled 代码必须显式使用 `ctx.Admin.*`。
109
+ 页面会话使用访问 token;CLI 与 System MCP 使用当前用户的 API Key。两者都按服务端 Role、用户组角色、资源所有者规则和业务守卫授权。页面中的 `App.permissions` 只适合辅助显隐,不能替代服务端检查;未知权限要求始终读取实时 operation describe。CLI 不创建、导出或伪造服务身份,也不附加契约之外的授权字段。
@@ -95,7 +95,7 @@ now:
95
95
  ```
96
96
  通过 MCP 实时摘要和项目内可保留的决策记录判断走哪条路径:
97
97
 
98
- ├─ MCP 显示存在用户自建内容(非 tag="系统" 的页面、db_meta、custom_scripts)→ 路径 A
98
+ ├─ MCP 显示存在用户自建内容(非 tag="系统" 的页面、导航、文档或 db_meta)→ 路径 A
99
99
  ├─ 用户提供了设计文档(PRD、原型图描述、需求文档等)→ 路径 A(以文档为分析素材)
100
100
  └─ 只有内置系统页面,无用户自建内容,无设计文档 → 路径 B(对话采集)
101
101
  ```
@@ -108,7 +108,7 @@ now:
108
108
  1. 查询项目结构(以及读取用户提供的设计文档,如有):
109
109
  - MCP project_overview/resource_list → 资源总览
110
110
  - MCP resource_search/get_metadata → 页面与导航元数据(跳过 tag="系统" 的内置页)
111
- - MCP api_search/api_describe/api_call → db_meta 与自定义服务结构
111
+ - MCP api_search/api_describe/api_call → db_meta 与其他结构化资源
112
112
  - 只有必须分析完整 pages/nav/docs 正文时才 checkout;不要要求 MCP 返回全文
113
113
  - .draftgo/worklog.md → 工作进度与完成记录
114
114
  - .draftgo/lessons/ → 开发经验记录
@@ -28,17 +28,25 @@ function readCache(projectDir, server) {
28
28
  }
29
29
  }
30
30
 
31
- function normalizeDescription(value) {
31
+ function normalizeDescription(value, fallbackRevision = '') {
32
32
  if (!value || typeof value !== 'object' || Array.isArray(value)) return null;
33
33
  const operation = value.operation && typeof value.operation === 'object' ? value.operation : value;
34
- const registryRevision = String(value.registry_revision || operation.registry_revision || '').trim();
34
+ const registryRevision = String(value.registry_revision || operation.registry_revision || fallbackRevision).trim();
35
35
  const contractHash = String(value.contract_hash || operation.contract_hash || '').trim();
36
36
  const operationId = String(operation.operation_id || '').trim();
37
- if (!operationId || !registryRevision || !contractHash) return null;
37
+ if (!operationId || !registryRevision) return null;
38
38
  const normalized = { ...operation };
39
39
  delete normalized.registry_revision;
40
40
  delete normalized.contract_hash;
41
- return { operation: normalized, registry_revision: registryRevision, contract_hash: contractHash };
41
+ const resolvedHash = contractHash || crypto.createHash('sha256')
42
+ .update(JSON.stringify(canonicalValue(normalized))).digest('hex');
43
+ return { operation: normalized, registry_revision: registryRevision, contract_hash: resolvedHash };
44
+ }
45
+
46
+ function canonicalValue(value) {
47
+ if (Array.isArray(value)) return value.map(canonicalValue);
48
+ if (!value || typeof value !== 'object') return value;
49
+ return Object.fromEntries(Object.keys(value).sort().map((key) => [key, canonicalValue(value[key])]));
42
50
  }
43
51
 
44
52
  function cachedDescription(projectDir, server, operationId) {
@@ -82,8 +90,8 @@ function writeAtomic(file, value) {
82
90
  }
83
91
  }
84
92
 
85
- function storeDescription(projectDir, server, value) {
86
- const normalized = normalizeDescription(value);
93
+ function storeDescription(projectDir, server, value, fallbackRevision = '') {
94
+ const normalized = normalizeDescription(value, fallbackRevision);
87
95
  if (!normalized) return null;
88
96
  const file = cachePath(projectDir);
89
97
  const lock = acquire(file);