draftgo-cli 2.0.9 → 3.0.1
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 +6 -0
- package/package.json +1 -1
- package/resources/skill/SKILL.md +74 -1378
- package/resources/skill/core/architecture.md +91 -0
- package/resources/skill/core/modules.md +54 -0
- package/resources/skill/practices/anti-patterns.md +70 -0
- package/resources/skill/practices/best-practices.md +41 -0
- package/resources/skill/practices/dev-declaration.md +94 -0
- package/resources/skill/push/SKILL.md +32 -1
- package/resources/skill/quickref/api-endpoints.md +130 -0
- package/resources/skill/quickref/api.json +17675 -0
- package/resources/skill/quickref/app-api.md +110 -0
- package/resources/skill/quickref/dg-components.md +198 -0
- package/resources/skill/rules/frontend.md +129 -596
- package/resources/skill/scripts/draftgo_delete.py +151 -0
- package/resources/skill/scripts/draftgo_push.py +80 -6
- package/resources/skill/specs/data.md +108 -0
- package/resources/skill/specs/runtime.md +98 -0
- package/resources/skill/specs/security.md +74 -0
- package/resources/skill/specs/ui-protocol.md +68 -0
- package/src/commands/delete.js +86 -0
- package/src/commands/help.js +7 -0
- package/src/commands/new.js +183 -0
- package/src/commands/sync.js +4 -1
- package/src/index.js +6 -0
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const { exists } = require('../fsx');
|
|
5
|
+
const log = require('../logger');
|
|
6
|
+
const { confirm } = require('../prompt');
|
|
7
|
+
const { findPython } = require('../python');
|
|
8
|
+
const { spawnSync } = require('child_process');
|
|
9
|
+
const { platforms } = require('../platforms');
|
|
10
|
+
|
|
11
|
+
function findDeleteScript(projectDir) {
|
|
12
|
+
for (const platform of platforms) {
|
|
13
|
+
const candidate = path.join(projectDir, platform.assetDir, 'scripts', 'draftgo_delete.py');
|
|
14
|
+
if (exists(candidate)) return candidate;
|
|
15
|
+
}
|
|
16
|
+
const bundled = path.resolve(__dirname, '..', '..', 'resources', 'skill', 'scripts', 'draftgo_delete.py');
|
|
17
|
+
return exists(bundled) ? bundled : null;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const TYPE_ALIASES = {
|
|
21
|
+
page: 'pages',
|
|
22
|
+
pages: 'pages',
|
|
23
|
+
nav: 'nav',
|
|
24
|
+
navigations: 'nav',
|
|
25
|
+
db_meta: 'db_meta',
|
|
26
|
+
script: 'custom_scripts',
|
|
27
|
+
scripts: 'custom_scripts',
|
|
28
|
+
custom_scripts: 'custom_scripts',
|
|
29
|
+
doc: 'docs',
|
|
30
|
+
docs: 'docs',
|
|
31
|
+
doc_category: 'doc_categories',
|
|
32
|
+
doc_categories: 'doc_categories',
|
|
33
|
+
external_api: 'external_apis',
|
|
34
|
+
external_apis: 'external_apis',
|
|
35
|
+
aihub: 'aihub',
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
async function deleteResource(projectDir, positional, flags) {
|
|
39
|
+
const [typeRaw, id] = positional;
|
|
40
|
+
|
|
41
|
+
if (!typeRaw || !id) {
|
|
42
|
+
log.err('用法:draftgo delete <type> <id>');
|
|
43
|
+
log.dim(' 支持类型:pages | nav | db_meta | custom_scripts | docs | doc_categories | external_apis | aihub');
|
|
44
|
+
return 1;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const type = TYPE_ALIASES[typeRaw];
|
|
48
|
+
if (!type) {
|
|
49
|
+
log.err(`未知类型:${typeRaw}`);
|
|
50
|
+
return 1;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (!exists(path.join(projectDir, '.draftgo', 'config.json'))) {
|
|
54
|
+
log.err('未找到 .draftgo/config.json,请先运行 /draftgo init');
|
|
55
|
+
return 1;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const py = findPython();
|
|
59
|
+
if (!py) {
|
|
60
|
+
log.err('未检测到 Python,无法运行删除脚本');
|
|
61
|
+
return 1;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const script = findDeleteScript(projectDir);
|
|
65
|
+
if (!script) {
|
|
66
|
+
log.err('未找到 draftgo_delete.py,请运行 draftgo update 更新');
|
|
67
|
+
return 1;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (!flags.yes && !flags.y) {
|
|
71
|
+
const ok = await confirm(`确认删除 ${type} id=${id}?此操作不可恢复`);
|
|
72
|
+
if (!ok) {
|
|
73
|
+
log.dim('已取消');
|
|
74
|
+
return 0;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const r = spawnSync(py.bin, [script, type, id], {
|
|
79
|
+
cwd: projectDir,
|
|
80
|
+
stdio: 'inherit',
|
|
81
|
+
shell: false,
|
|
82
|
+
});
|
|
83
|
+
return r.status || 0;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
module.exports = deleteResource;
|
package/src/commands/help.js
CHANGED
|
@@ -29,6 +29,13 @@ Usage:
|
|
|
29
29
|
entry binding, files, obvious mock risks.
|
|
30
30
|
draftgo dev Run this project's npm dev script.
|
|
31
31
|
draftgo build Run this project's npm build script.
|
|
32
|
+
draftgo new <type> <slug> Scaffold a new resource locally (no network).
|
|
33
|
+
Creates template file + index.json entry.
|
|
34
|
+
Types: page | nav | db_meta | script | doc
|
|
35
|
+
draftgo delete <type> <id> Delete resource from server + local index.
|
|
36
|
+
Types: pages | nav | db_meta | custom_scripts
|
|
37
|
+
| docs | doc_categories | external_apis
|
|
38
|
+
Alias: del, rm. Flags: --yes / -y skip confirm.
|
|
32
39
|
draftgo pull [type] [id...] Pull DraftGo resources via the bundled
|
|
33
40
|
sync script. Defaults to --all.
|
|
34
41
|
draftgo push <type> [id...] Push DraftGo resources via the bundled
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const log = require('../logger');
|
|
6
|
+
const { exists, ensureDir } = require('../fsx');
|
|
7
|
+
|
|
8
|
+
const TEMPLATES = {
|
|
9
|
+
page: (slug) => ({
|
|
10
|
+
indexEntry: {
|
|
11
|
+
title: slug,
|
|
12
|
+
route: `/${slug}`,
|
|
13
|
+
tag: null,
|
|
14
|
+
menu: null,
|
|
15
|
+
status: 'active',
|
|
16
|
+
permission: { default: 'public' },
|
|
17
|
+
html_file: `.draftgo/pages/page_new_${slug}.html`,
|
|
18
|
+
},
|
|
19
|
+
file: `.draftgo/pages/page_new_${slug}.html`,
|
|
20
|
+
content: `<!DOCTYPE html>
|
|
21
|
+
<html>
|
|
22
|
+
<head><meta charset="UTF-8"></head>
|
|
23
|
+
<body>
|
|
24
|
+
<script>
|
|
25
|
+
const App = window.parent?.App;
|
|
26
|
+
</script>
|
|
27
|
+
|
|
28
|
+
<div class="p-6">
|
|
29
|
+
<h1 class="text-2xl font-bold">${slug}</h1>
|
|
30
|
+
<p class="text-muted-foreground mt-2">页面内容</p>
|
|
31
|
+
</div>
|
|
32
|
+
</body>
|
|
33
|
+
</html>`,
|
|
34
|
+
}),
|
|
35
|
+
|
|
36
|
+
nav: (code) => ({
|
|
37
|
+
indexEntry: {
|
|
38
|
+
name: code,
|
|
39
|
+
code,
|
|
40
|
+
status: 'active',
|
|
41
|
+
order: 0,
|
|
42
|
+
html_file: `.draftgo/navigations/nav_new_${code}.html`,
|
|
43
|
+
},
|
|
44
|
+
file: `.draftgo/navigations/nav_new_${code}.html`,
|
|
45
|
+
content: `<nav class="flex items-center gap-4 px-4 h-14">
|
|
46
|
+
<a href="/" class="font-semibold">首页</a>
|
|
47
|
+
</nav>`,
|
|
48
|
+
}),
|
|
49
|
+
|
|
50
|
+
db_meta: (type) => ({
|
|
51
|
+
indexEntry: {
|
|
52
|
+
type,
|
|
53
|
+
label: type,
|
|
54
|
+
describe: '',
|
|
55
|
+
schema: {
|
|
56
|
+
type: 'object',
|
|
57
|
+
properties: {
|
|
58
|
+
title: { type: 'string', title: '标题', required: true, searchable: 'fuzzy' },
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
permission: {
|
|
62
|
+
public: { read: 'none', create: 'none', update: 'none', delete: 'none' },
|
|
63
|
+
login: { read: 'all', create: 'all', update: 'owner', delete: 'owner' },
|
|
64
|
+
admin: { read: 'all', create: 'all', update: 'all', delete: 'all' },
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
file: null,
|
|
68
|
+
content: null,
|
|
69
|
+
}),
|
|
70
|
+
|
|
71
|
+
script: (slug) => ({
|
|
72
|
+
indexEntry: {
|
|
73
|
+
name: slug,
|
|
74
|
+
slug,
|
|
75
|
+
mode: 'route',
|
|
76
|
+
status: 'active',
|
|
77
|
+
triggers: { path: `/${slug}`, methods: ['GET', 'POST'] },
|
|
78
|
+
config: {},
|
|
79
|
+
permission: { default: 'admin' },
|
|
80
|
+
code_file: `.draftgo/custom_scripts/script_new_${slug}.py`,
|
|
81
|
+
},
|
|
82
|
+
file: `.draftgo/custom_scripts/script_new_${slug}.py`,
|
|
83
|
+
content: `# ${slug}
|
|
84
|
+
# 路由脚本:/api/x/${slug}
|
|
85
|
+
|
|
86
|
+
def handle(request, context):
|
|
87
|
+
"""
|
|
88
|
+
request: { method, path, query, body, headers, user }
|
|
89
|
+
context: { db, config, logger }
|
|
90
|
+
"""
|
|
91
|
+
return {"message": "ok"}
|
|
92
|
+
`,
|
|
93
|
+
}),
|
|
94
|
+
|
|
95
|
+
doc: (slug) => ({
|
|
96
|
+
indexEntry: {
|
|
97
|
+
title: slug,
|
|
98
|
+
key: slug,
|
|
99
|
+
status: 'published',
|
|
100
|
+
category_id: null,
|
|
101
|
+
content_file: `.draftgo/docs/articles/doc_new_${slug}.md`,
|
|
102
|
+
},
|
|
103
|
+
file: `.draftgo/docs/articles/doc_new_${slug}.md`,
|
|
104
|
+
content: `# ${slug}\n\n文档内容\n`,
|
|
105
|
+
}),
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
const INDEX_MAP = {
|
|
109
|
+
page: 'pages/index.json',
|
|
110
|
+
nav: 'navigations/index.json',
|
|
111
|
+
db_meta: 'db_meta/index.json',
|
|
112
|
+
script: 'custom_scripts/index.json',
|
|
113
|
+
doc: 'docs/articles/index.json',
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
const PUSH_TYPE = {
|
|
117
|
+
page: 'pages',
|
|
118
|
+
nav: 'nav',
|
|
119
|
+
db_meta: 'db_meta',
|
|
120
|
+
script: 'custom_scripts',
|
|
121
|
+
doc: 'docs',
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
function newResource(projectDir, positional) {
|
|
125
|
+
const [type, slug] = positional;
|
|
126
|
+
|
|
127
|
+
if (!type || !TEMPLATES[type]) {
|
|
128
|
+
log.err(`用法:draftgo new <type> <slug>`);
|
|
129
|
+
log.dim(` 支持类型:${Object.keys(TEMPLATES).join(' | ')}`);
|
|
130
|
+
return 1;
|
|
131
|
+
}
|
|
132
|
+
if (!slug) {
|
|
133
|
+
log.err(`缺少 slug/name 参数,例如:draftgo new ${type} my-slug`);
|
|
134
|
+
return 1;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const draftgoDir = path.join(projectDir, '.draftgo');
|
|
138
|
+
if (!exists(draftgoDir)) {
|
|
139
|
+
log.err('未找到 .draftgo/,请先运行 draftgo connect 或 /draftgo init');
|
|
140
|
+
return 1;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const tpl = TEMPLATES[type](slug);
|
|
144
|
+
const indexRel = INDEX_MAP[type];
|
|
145
|
+
const indexPath = path.join(draftgoDir, indexRel);
|
|
146
|
+
|
|
147
|
+
if (!exists(indexPath)) {
|
|
148
|
+
log.err(`未找到 ${indexPath},请先运行 /draftgo pull`);
|
|
149
|
+
return 1;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// 追加 index 条目
|
|
153
|
+
const items = JSON.parse(fs.readFileSync(indexPath, 'utf8'));
|
|
154
|
+
|
|
155
|
+
// 检查重复
|
|
156
|
+
const dupKey = type === 'page' ? 'route' : type === 'nav' ? 'code' : type === 'db_meta' ? 'type' : type === 'script' ? 'slug' : 'key';
|
|
157
|
+
const dupVal = tpl.indexEntry[dupKey];
|
|
158
|
+
if (dupVal && items.some((it) => it[dupKey] === dupVal)) {
|
|
159
|
+
log.err(`已存在 ${dupKey}="${dupVal}",请换一个名称`);
|
|
160
|
+
return 1;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
items.push(tpl.indexEntry);
|
|
164
|
+
fs.writeFileSync(indexPath, JSON.stringify(items, null, 2), 'utf8');
|
|
165
|
+
|
|
166
|
+
// 创建模板文件
|
|
167
|
+
if (tpl.file && tpl.content !== null) {
|
|
168
|
+
const filePath = path.join(projectDir, tpl.file);
|
|
169
|
+
ensureDir(path.dirname(filePath));
|
|
170
|
+
if (exists(filePath)) {
|
|
171
|
+
log.warn(`文件已存在,跳过:${tpl.file}`);
|
|
172
|
+
} else {
|
|
173
|
+
fs.writeFileSync(filePath, tpl.content, 'utf8');
|
|
174
|
+
log.ok(`已创建:${tpl.file}`);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
log.ok(`已追加到 .draftgo/${indexRel}`);
|
|
179
|
+
log.dim(` 编辑完成后运行:draftgo push ${PUSH_TYPE[type]}`);
|
|
180
|
+
return 0;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
module.exports = newResource;
|
package/src/commands/sync.js
CHANGED
|
@@ -19,7 +19,7 @@ function findSyncScript(projectDir, command) {
|
|
|
19
19
|
return exists(bundled) ? bundled : null;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
function sync(projectDir, command, positional) {
|
|
22
|
+
function sync(projectDir, command, positional, flags = {}) {
|
|
23
23
|
const py = findPython();
|
|
24
24
|
if (!py) {
|
|
25
25
|
log.err('未检测到 Python,无法运行 DraftGo 同步脚本。');
|
|
@@ -40,6 +40,9 @@ function sync(projectDir, command, positional) {
|
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
const args = positional.length ? positional : ['--all'];
|
|
43
|
+
if (command === 'push' && flags.force) {
|
|
44
|
+
args.push('--force');
|
|
45
|
+
}
|
|
43
46
|
const r = spawnSync(py.bin, [script, ...args], {
|
|
44
47
|
cwd: projectDir,
|
|
45
48
|
stdio: 'inherit',
|
package/src/index.js
CHANGED
|
@@ -42,6 +42,12 @@ async function run(argv) {
|
|
|
42
42
|
case 'dev':
|
|
43
43
|
case 'build':
|
|
44
44
|
return require('./commands/projectScript')(projectDir, command, flags);
|
|
45
|
+
case 'new':
|
|
46
|
+
return require('./commands/new')(projectDir, positional, flags);
|
|
47
|
+
case 'delete':
|
|
48
|
+
case 'del':
|
|
49
|
+
case 'rm':
|
|
50
|
+
return await require('./commands/delete')(projectDir, positional, flags);
|
|
45
51
|
case 'pull':
|
|
46
52
|
case 'push':
|
|
47
53
|
return require('./commands/sync')(projectDir, command, positional, flags);
|