draftgo-cli 3.0.1 → 3.0.33
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 +73 -124
- package/package.json +21 -8
- package/resources/skill/SKILL.md +62 -89
- package/resources/skill/init/SKILL.md +18 -67
- package/resources/skill/manifest.json +27 -0
- package/resources/skill/pull/SKILL.md +18 -44
- package/resources/skill/push/SKILL.md +30 -247
- package/resources/skill/references/aihub.md +86 -0
- package/resources/skill/references/api-endpoints.md +178 -0
- package/resources/skill/references/api.json +20248 -0
- package/resources/skill/{quickref → references}/app-api.md +44 -14
- package/resources/skill/{core → references}/architecture.md +6 -26
- package/resources/skill/references/chat-sdk.md +201 -0
- package/resources/skill/references/custom-services.md +308 -0
- package/resources/skill/references/data.md +298 -0
- package/resources/skill/references/db-relations.md +227 -0
- package/resources/skill/references/frontend.md +788 -0
- package/resources/skill/references/modules.md +66 -0
- package/resources/skill/references/parallel.md +48 -0
- package/resources/skill/{specs → references}/runtime.md +31 -1
- package/resources/skill/{specs → references}/security.md +3 -3
- package/resources/skill/references/ui-protocol.md +99 -0
- package/resources/skill/scripts/draftgo_delete.py +0 -2
- package/resources/skill/scripts/draftgo_init.py +15 -3
- package/resources/skill/scripts/draftgo_pull.py +154 -87
- package/resources/skill/scripts/draftgo_push.py +440 -183
- package/resources/skill/story/SKILL.md +13 -23
- package/src/cli.js +22 -7
- package/src/commandRegistry.js +34 -0
- package/src/commands/api.js +204 -0
- package/src/commands/autoPush.js +41 -0
- package/src/commands/check.js +27 -17
- package/src/commands/delete.js +6 -4
- package/src/commands/deploy.js +31 -0
- package/src/commands/help.js +41 -28
- package/src/commands/init.js +34 -20
- package/src/commands/local.js +9 -3
- package/src/commands/map.js +18 -7
- package/src/commands/sync.js +11 -4
- package/src/commands/update.js +39 -52
- package/src/commands/verifyUi.js +199 -0
- package/src/index.js +13 -46
- package/src/localdev/compose.js +48 -197
- package/src/localdev/index.js +116 -216
- package/src/localdev/mysqlClient.js +12 -9
- package/src/localdev/services.js +163 -0
- package/src/platforms.js +3 -3
- package/src/projectConfig.js +12 -2
- package/src/projectMap.js +240 -68
- package/src/skill.js +113 -29
- package/src/updateCheck.js +37 -15
- package/resources/skill/core/modules.md +0 -54
- package/resources/skill/practices/anti-patterns.md +0 -70
- package/resources/skill/practices/best-practices.md +0 -41
- package/resources/skill/practices/dev-declaration.md +0 -94
- package/resources/skill/quickref/api-endpoints.md +0 -130
- package/resources/skill/quickref/api.json +0 -17675
- package/resources/skill/quickref/dg-components.md +0 -198
- package/resources/skill/rules/dev-workflow.md +0 -652
- package/resources/skill/rules/frontend.md +0 -210
- package/resources/skill/rules/parallel.md +0 -263
- package/resources/skill/specs/data.md +0 -108
- package/resources/skill/specs/ui-protocol.md +0 -68
- package/src/commands/doctor.js +0 -54
- package/src/commands/new.js +0 -183
- package/src/commands/projectScript.js +0 -37
- /package/resources/skill/{rules → references}/debugging-syntax.md +0 -0
package/src/commands/help.js
CHANGED
|
@@ -7,57 +7,63 @@ function help() {
|
|
|
7
7
|
const targets = all.map((i) => ` ${i.name.padEnd(12)} ${i.displayName}`).join('\n');
|
|
8
8
|
console.log(`draftgo v${getPackageVersion()} — DraftGo Next workbench CLI for AI coding agents
|
|
9
9
|
|
|
10
|
-
DraftGo Next frontend baseline: React + Vite
|
|
11
|
-
Database pages use
|
|
10
|
+
DraftGo Next frontend baseline: React + Vite.
|
|
11
|
+
Database pages use standard HTML + Tailwind CSS.
|
|
12
12
|
The CLI is the workbench layer for local runtime, resource sync, checks, and push/pull flows.
|
|
13
13
|
|
|
14
14
|
Usage:
|
|
15
15
|
draftgo init [<target>...] Install skill. No target = auto-detect.
|
|
16
16
|
Use "all" to install every target.
|
|
17
|
-
draftgo update [<target>...]
|
|
18
|
-
|
|
19
|
-
automatically then reruns itself.
|
|
17
|
+
draftgo update [<target>...] Fully update the global CLI, then atomically
|
|
18
|
+
refresh skill + entry files.
|
|
20
19
|
draftgo uninstall <target|all> Remove entry files for target(s).
|
|
21
20
|
Use explicit "all" to remove every target.
|
|
22
21
|
--purge also removes .draftgo/ (runtime data).
|
|
23
22
|
draftgo status Show installed targets and skill version.
|
|
24
|
-
draftgo doctor Diagnose environment (python, targets,
|
|
25
|
-
CLI freshness).
|
|
26
23
|
draftgo map Print a local DraftGo project resource map
|
|
27
24
|
for fast AI orientation.
|
|
28
|
-
draftgo check Check
|
|
29
|
-
|
|
30
|
-
draftgo
|
|
31
|
-
|
|
32
|
-
draftgo
|
|
33
|
-
|
|
34
|
-
|
|
25
|
+
draftgo check Check page entry binding, page/navigation
|
|
26
|
+
HTML parsing, and unregistered local files.
|
|
27
|
+
draftgo verify-ui <url> Run a deterministic browser smoke check.
|
|
28
|
+
Uses one viewport and screenshots on failure.
|
|
29
|
+
draftgo api <keyword> Search DraftGo base APIs and show request/
|
|
30
|
+
response/authentication contracts.
|
|
31
|
+
Custom service routes come from app.Route;
|
|
32
|
+
they are not part of the bundled OpenAPI.
|
|
35
33
|
draftgo delete <type> <id> Delete resource from server + local index.
|
|
36
34
|
Types: pages | nav | db_meta | custom_scripts
|
|
37
|
-
| docs | doc_categories |
|
|
35
|
+
| docs | doc_categories | aihub
|
|
38
36
|
Alias: del, rm. Flags: --yes / -y skip confirm.
|
|
39
37
|
draftgo pull [type] [id...] Pull DraftGo resources via the bundled
|
|
40
38
|
sync script. Defaults to --all.
|
|
41
39
|
draftgo push <type> [id...] Push DraftGo resources via the bundled
|
|
42
40
|
sync script.
|
|
43
|
-
draftgo
|
|
41
|
+
draftgo deploy [type] [id...] Run check, then push explicitly.
|
|
42
|
+
--delivery local|preview|deploy
|
|
43
|
+
draftgo auto-push [type] [id...] Run check, then push only when
|
|
44
|
+
config.auto_push is true.
|
|
45
|
+
Supports --batch <type> <ids> ... too.
|
|
46
|
+
draftgo local setup|start|stop|logs|status
|
|
44
47
|
Manage .draftgo/docker/docker-compose.yaml
|
|
45
|
-
generated by
|
|
48
|
+
generated by local setup. up/down remain
|
|
49
|
+
compatible aliases for start/stop.
|
|
46
50
|
draftgo list-targets List supported AI tools.
|
|
47
51
|
draftgo connect Bind this project to an existing DraftGo
|
|
48
52
|
server. Prompts for BaseURL + access
|
|
49
53
|
token (or pass --server / --token).
|
|
50
|
-
draftgo local
|
|
51
|
-
(MySQL
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
finish setup and paste
|
|
54
|
+
draftgo local setup One-click local DraftGo stack via Docker
|
|
55
|
+
(shared MySQL, Redis, Milvus + app). It
|
|
56
|
+
generates an app-only project compose,
|
|
57
|
+
<project>/.draftgo/docker/docker-compose.yaml,
|
|
58
|
+
then guides you to finish setup and paste
|
|
59
|
+
an access token.
|
|
60
|
+
draftgo local-dev Compatibility alias for \`draftgo local setup\`.
|
|
55
61
|
draftgo -v | --version Print CLI version.
|
|
56
62
|
draftgo -h | --help Show this help.
|
|
57
63
|
|
|
58
64
|
v3 Workbench:
|
|
59
|
-
draftgo local
|
|
60
|
-
draftgo
|
|
65
|
+
draftgo local start|stop|logs Local stack lifecycle commands.
|
|
66
|
+
draftgo check Local resource closure gate.
|
|
61
67
|
draftgo pull|push First-class resource sync wrappers.
|
|
62
68
|
|
|
63
69
|
Flags:
|
|
@@ -67,15 +73,21 @@ Flags:
|
|
|
67
73
|
--skip-update-check Do not contact npm to check for a newer CLI.
|
|
68
74
|
--yes Assume "yes" for interactive prompts.
|
|
69
75
|
--connect (init) Skip the prompt and run \`draftgo connect\`.
|
|
70
|
-
--local-dev (init) Skip the prompt and run \`draftgo local
|
|
76
|
+
--local-dev (init) Skip the prompt and run \`draftgo local setup\`.
|
|
71
77
|
--no-setup (init) Don't offer either flow after installing.
|
|
72
78
|
--server <url> (connect) Provide the DraftGo BaseURL non-interactively.
|
|
73
79
|
--token <sat> (connect) Provide the access token non-interactively.
|
|
74
80
|
--output <json> (map/check) Print machine-readable JSON.
|
|
75
81
|
--strict (check) Treat warnings as failures.
|
|
82
|
+
--mobile-check <mode> (verify-ui) auto | always | never. Default: auto.
|
|
83
|
+
--screenshot <mode> (verify-ui) on-failure | always | never.
|
|
84
|
+
--browser <name> (verify-ui) chromium | chrome | msedge.
|
|
85
|
+
--selector <css> (verify-ui) Require a key element to be visible.
|
|
86
|
+
--width/--height <px> (verify-ui) Override the default 390x844 viewport.
|
|
87
|
+
--delivery <mode> (deploy) local | preview | deploy.
|
|
76
88
|
|
|
77
89
|
Environment:
|
|
78
|
-
DRAFTGO_NO_UPDATE_CHECK=1 Disable the
|
|
90
|
+
DRAFTGO_NO_UPDATE_CHECK=1 Disable the cached CLI version check.
|
|
79
91
|
|
|
80
92
|
Targets:
|
|
81
93
|
${targets}
|
|
@@ -85,9 +97,10 @@ Examples:
|
|
|
85
97
|
draftgo init claudecode # install for Claude Code only
|
|
86
98
|
draftgo init claudecode kiro # install for both
|
|
87
99
|
draftgo init all # install for every supported target
|
|
88
|
-
draftgo update #
|
|
100
|
+
draftgo update # fully update CLI and installed skills
|
|
89
101
|
draftgo map # inspect pages/nav/db/scripts before development
|
|
90
|
-
draftgo check --strict # fail on
|
|
102
|
+
draftgo check --strict # fail on any resource-check warning before push
|
|
103
|
+
draftgo verify-ui http://localhost:5173 --mobile-check auto
|
|
91
104
|
draftgo uninstall all --purge # full removal incl. runtime data
|
|
92
105
|
`);
|
|
93
106
|
}
|
package/src/commands/init.js
CHANGED
|
@@ -12,8 +12,8 @@ const { ask } = require('../prompt');
|
|
|
12
12
|
function warnIfNoPython() {
|
|
13
13
|
const py = findPython();
|
|
14
14
|
if (!py) {
|
|
15
|
-
log.warn('Python 未检测到。DraftGo
|
|
16
|
-
log.dim('
|
|
15
|
+
log.warn('Python 未检测到。DraftGo 资源同步需要 Python 3.9+。');
|
|
16
|
+
log.dim(' 安装 Python 3.9+ 后运行 `draftgo pull` 获取项目资源。');
|
|
17
17
|
} else {
|
|
18
18
|
log.dim(` detected ${py.bin} (${py.version})`);
|
|
19
19
|
}
|
|
@@ -47,17 +47,32 @@ async function init(projectDir, positional, flags) {
|
|
|
47
47
|
|
|
48
48
|
// 2) Render skill body into each target's own directory (no shared
|
|
49
49
|
// .draftgo/skill/ indirection anymore — each AI tool gets a real copy).
|
|
50
|
-
log.step('写入各 AI 工具 skill 目录(含 SKILL.md / 子技能 /
|
|
50
|
+
log.step('写入各 AI 工具 skill 目录(含 SKILL.md / 子技能 / references / scripts)');
|
|
51
51
|
ensureRuntime(projectDir);
|
|
52
|
+
const failures = [];
|
|
53
|
+
let installedCount = 0;
|
|
54
|
+
let skippedCount = 0;
|
|
52
55
|
for (const t of resolved) {
|
|
53
56
|
try {
|
|
54
57
|
const r = t.install(projectDir, { force: !!flags.force });
|
|
55
|
-
|
|
58
|
+
if (r.skipped) {
|
|
59
|
+
skippedCount += 1;
|
|
60
|
+
log.warn(`${t.displayName.padEnd(16)} 已存在,未覆盖;使用 draftgo update 或 --force 更新。`);
|
|
61
|
+
} else {
|
|
62
|
+
installedCount += 1;
|
|
63
|
+
log.ok(`${t.displayName.padEnd(16)} → ${r.path}`);
|
|
64
|
+
}
|
|
56
65
|
} catch (e) {
|
|
57
66
|
log.err(`${t.displayName} 安装失败:${e.message}`);
|
|
67
|
+
failures.push(t.displayName);
|
|
58
68
|
}
|
|
59
69
|
}
|
|
60
|
-
|
|
70
|
+
if (failures.length) {
|
|
71
|
+
log.err(`安装未完成,失败目标:${failures.join(', ')}`);
|
|
72
|
+
return 1;
|
|
73
|
+
}
|
|
74
|
+
if (installedCount > 0 && skippedCount === 0) writeInstalledVersion(projectDir);
|
|
75
|
+
if (skippedCount > 0) log.dim(' 存在未覆盖目标,未更新全局 skill 版本标记;运行 draftgo update 可统一刷新。');
|
|
61
76
|
log.dim(` CLI 版本:${getPackageVersion()}`);
|
|
62
77
|
|
|
63
78
|
// 3) Environment check (advisory).
|
|
@@ -86,29 +101,28 @@ async function init(projectDir, positional, flags) {
|
|
|
86
101
|
return await require('./localDev')(projectDir, [], flags);
|
|
87
102
|
}
|
|
88
103
|
if (interactive) {
|
|
89
|
-
log.title('
|
|
90
|
-
log.plain('
|
|
91
|
-
log.
|
|
92
|
-
log.plain(` ${log.c.cyan('[
|
|
93
|
-
log.
|
|
94
|
-
|
|
95
|
-
|
|
104
|
+
log.title('选择 DraftGo 基座处理方式');
|
|
105
|
+
log.plain(` ${log.c.cyan('[A]')} 连接基座服务`);
|
|
106
|
+
log.dim(' 使用已有 DraftGo 服务,接下来输入 BaseURL 和系统访问令牌。');
|
|
107
|
+
log.plain(` ${log.c.cyan('[B]')} 本地启动基座`);
|
|
108
|
+
log.dim(' 使用 Docker 启动 DraftGo;按需准备共享的 MySQL、Redis 和 Milvus。');
|
|
109
|
+
log.plain(` ${log.c.cyan('[C]')} 稍后自行处理`);
|
|
110
|
+
log.dim(' 仅安装 Skill,不写入服务配置,也不创建容器。');
|
|
111
|
+
const choice = (await ask('请选择 [A/B/C]', { default: 'C' })).trim().toUpperCase();
|
|
112
|
+
if (choice === 'A') {
|
|
96
113
|
return await require('./connect')(projectDir, [], flags);
|
|
97
114
|
}
|
|
98
|
-
if (choice === '
|
|
99
|
-
return await require('./localDev')(projectDir, [], flags);
|
|
115
|
+
if (choice === 'B') {
|
|
116
|
+
return await require('./localDev')(projectDir, [], { ...flags, yes: true });
|
|
100
117
|
}
|
|
101
|
-
if (choice !== '
|
|
102
|
-
log.warn('
|
|
118
|
+
if (choice !== 'C') {
|
|
119
|
+
log.warn('无效选择,已跳过基座处理。');
|
|
103
120
|
}
|
|
104
121
|
}
|
|
105
122
|
}
|
|
106
123
|
|
|
107
124
|
log.title('完成');
|
|
108
|
-
log.plain('
|
|
109
|
-
log.dim('或直接运行:');
|
|
110
|
-
log.dim(' draftgo connect # 连接已有 DraftGo 服务器');
|
|
111
|
-
log.dim(' draftgo local-dev # 本地一键部署 DraftGo');
|
|
125
|
+
log.plain(hasConfig ? 'Skill 已安装,项目已连接 DraftGo。' : 'Skill 已安装。');
|
|
112
126
|
return 0;
|
|
113
127
|
}
|
|
114
128
|
|
package/src/commands/local.js
CHANGED
|
@@ -5,6 +5,7 @@ const { spawnSync } = require('child_process');
|
|
|
5
5
|
const log = require('../logger');
|
|
6
6
|
const { exists } = require('../fsx');
|
|
7
7
|
const { detectDocker } = require('../localdev/detect');
|
|
8
|
+
const { runWizard } = require('../localdev');
|
|
8
9
|
|
|
9
10
|
function composeFile(projectDir) {
|
|
10
11
|
return path.join(projectDir, '.draftgo', 'docker', 'docker-compose.yaml');
|
|
@@ -22,7 +23,7 @@ function runCompose(projectDir, args, stdio = 'inherit') {
|
|
|
22
23
|
const file = composeFile(projectDir);
|
|
23
24
|
if (!exists(file)) {
|
|
24
25
|
log.err('未找到 .draftgo/docker/docker-compose.yaml。');
|
|
25
|
-
log.dim(' 请先运行 `draftgo local
|
|
26
|
+
log.dim(' 请先运行 `draftgo local setup` 生成本地 DraftGo stack。');
|
|
26
27
|
return 1;
|
|
27
28
|
}
|
|
28
29
|
|
|
@@ -34,13 +35,17 @@ function runCompose(projectDir, args, stdio = 'inherit') {
|
|
|
34
35
|
return r.status || 0;
|
|
35
36
|
}
|
|
36
37
|
|
|
37
|
-
function local(projectDir, positional) {
|
|
38
|
+
function local(projectDir, positional, flags = {}) {
|
|
38
39
|
const action = positional[0] || 'status';
|
|
39
40
|
|
|
40
41
|
switch (action) {
|
|
42
|
+
case 'setup':
|
|
43
|
+
return runWizard(projectDir, { yes: !!(flags.yes || flags.y) });
|
|
41
44
|
case 'up':
|
|
45
|
+
case 'start':
|
|
42
46
|
return runCompose(projectDir, ['up', '-d']);
|
|
43
47
|
case 'down':
|
|
48
|
+
case 'stop':
|
|
44
49
|
return runCompose(projectDir, ['down']);
|
|
45
50
|
case 'logs':
|
|
46
51
|
return runCompose(projectDir, ['logs', ...(positional.slice(1).length ? positional.slice(1) : ['-f', 'app'])]);
|
|
@@ -49,7 +54,8 @@ function local(projectDir, positional) {
|
|
|
49
54
|
return runCompose(projectDir, ['ps']);
|
|
50
55
|
default:
|
|
51
56
|
log.err(`未知 local 子命令:${action}`);
|
|
52
|
-
log.dim(' 可用:draftgo local
|
|
57
|
+
log.dim(' 可用:draftgo local setup | start | stop | logs | status');
|
|
58
|
+
log.dim(' 兼容别名:up | down');
|
|
53
59
|
return 1;
|
|
54
60
|
}
|
|
55
61
|
}
|
package/src/commands/map.js
CHANGED
|
@@ -40,13 +40,13 @@ function mapCommand(projectDir, flags = {}) {
|
|
|
40
40
|
});
|
|
41
41
|
|
|
42
42
|
printList('自定义脚本', map.custom_scripts, (s) => {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
const
|
|
49
|
-
return `${
|
|
43
|
+
const bindings = [
|
|
44
|
+
...(s.routes || []),
|
|
45
|
+
...(s.events || []).map((event) => `EVENT ${event}`),
|
|
46
|
+
...(s.schedules || []).map((cron) => `CRON ${cron}`),
|
|
47
|
+
];
|
|
48
|
+
const summary = bindings.length ? ` [${bindings.join(' | ')}]` : '';
|
|
49
|
+
return `${s.slug || '(无 slug)'} ${s.mode || 'mode?'} ${s.name || ''}${summary}${s.code_file ? ` ${s.code_file}` : ''}`;
|
|
50
50
|
});
|
|
51
51
|
|
|
52
52
|
printList('文档', map.docs, (d) => {
|
|
@@ -82,6 +82,17 @@ function mapCommand(projectDir, flags = {}) {
|
|
|
82
82
|
});
|
|
83
83
|
printList('角色', map.roles, (r) => `${r.code || r.id || 'new'} ${r.name || ''}`);
|
|
84
84
|
|
|
85
|
+
console.log('');
|
|
86
|
+
log.info('页面分区:');
|
|
87
|
+
const areaRows = [
|
|
88
|
+
['home', map.pageGroups.home.length],
|
|
89
|
+
['admin', map.pageGroups.admin.length],
|
|
90
|
+
['business', map.pageGroups.business.length],
|
|
91
|
+
['system', map.pageGroups.system.length],
|
|
92
|
+
['unknown', map.pageGroups.unknown.length],
|
|
93
|
+
];
|
|
94
|
+
log.dim(' ' + areaRows.map(([k, v]) => `${k} ${v}`).join(' '));
|
|
95
|
+
|
|
85
96
|
console.log('');
|
|
86
97
|
log.info('入口引用:');
|
|
87
98
|
const routes = Object.keys(map.routeRefs).sort();
|
package/src/commands/sync.js
CHANGED
|
@@ -35,20 +35,27 @@ function sync(projectDir, command, positional, flags = {}) {
|
|
|
35
35
|
|
|
36
36
|
if (!exists(path.join(projectDir, '.draftgo', 'config.json'))) {
|
|
37
37
|
log.err('未找到 .draftgo/config.json。');
|
|
38
|
-
log.dim(' 请先运行 `draftgo connect
|
|
38
|
+
log.dim(' 请先运行 `draftgo connect`。');
|
|
39
39
|
return 1;
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
const args = positional.length ? positional : ['--all'];
|
|
43
|
-
if (command === 'push' && flags
|
|
44
|
-
args.push('--
|
|
43
|
+
if (command === 'push' && flags['dry-run']) {
|
|
44
|
+
args.push('--dry-run');
|
|
45
|
+
}
|
|
46
|
+
if (command === 'push' && flags['probe-routes']) {
|
|
47
|
+
args.push('--probe-routes');
|
|
45
48
|
}
|
|
46
49
|
const r = spawnSync(py.bin, [script, ...args], {
|
|
47
50
|
cwd: projectDir,
|
|
48
51
|
stdio: 'inherit',
|
|
49
52
|
shell: false,
|
|
50
53
|
});
|
|
51
|
-
|
|
54
|
+
if (r.error) {
|
|
55
|
+
log.err(`${command} 启动失败:${r.error.message}`);
|
|
56
|
+
return 1;
|
|
57
|
+
}
|
|
58
|
+
return Number.isInteger(r.status) ? r.status : 1;
|
|
52
59
|
}
|
|
53
60
|
|
|
54
61
|
module.exports = sync;
|
package/src/commands/update.js
CHANGED
|
@@ -7,77 +7,57 @@ const { ensureRuntime, writeInstalledVersion, readInstalledVersion, getPackageVe
|
|
|
7
7
|
const { fetchLatestVersion, cmpSemver } = require('../updateCheck');
|
|
8
8
|
const { detectTargets } = require('../detect');
|
|
9
9
|
|
|
10
|
-
// Env flag we set before re-exec to avoid infinite upgrade loops.
|
|
11
10
|
const REENTRY_FLAG = 'DRAFTGO_UPDATE_REENTERED';
|
|
12
11
|
|
|
13
|
-
function
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
const r = spawnSync(npm, ['install', '-g', 'draftgo-cli@latest'], { stdio: 'inherit' });
|
|
17
|
-
if (r.error) { log.err(`升级失败:${r.error.message}`); return false; }
|
|
18
|
-
if (r.status !== 0) {
|
|
19
|
-
log.err(`npm install 返回码 ${r.status}`);
|
|
20
|
-
log.dim(' 常见原因:权限不足(macOS/Linux 用 sudo,或用 nvm 管理 Node)');
|
|
21
|
-
return false;
|
|
22
|
-
}
|
|
23
|
-
return true;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
function reExecSameCommand(projectDir) {
|
|
27
|
-
// Re-run `draftgo update` from the freshly installed global CLI, so the user
|
|
28
|
-
// gets the newest skill content written into .draftgo/skill in the same call.
|
|
29
|
-
const cmd = process.platform === 'win32' ? 'draftgo.cmd' : 'draftgo';
|
|
30
|
-
const args = ['update', '--project', projectDir, '--skip-update-check'];
|
|
31
|
-
log.step('以新版 CLI 重新执行:draftgo update');
|
|
32
|
-
const r = spawnSync(cmd, args, {
|
|
33
|
-
stdio: 'inherit',
|
|
34
|
-
env: { ...process.env, [REENTRY_FLAG]: '1' },
|
|
35
|
-
});
|
|
36
|
-
if (r.error) {
|
|
37
|
-
log.err(`重新执行失败:${r.error.message}`);
|
|
38
|
-
log.dim(' 请手动在项目目录再跑一次:draftgo update');
|
|
39
|
-
return 1;
|
|
12
|
+
async function updateCliIfNeeded(projectDir, positional, flags) {
|
|
13
|
+
if (process.env[REENTRY_FLAG] === '1' || flags['skip-update-check'] || process.env.DRAFTGO_NO_UPDATE_CHECK === '1') {
|
|
14
|
+
return null;
|
|
40
15
|
}
|
|
41
|
-
return r.status || 0;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
async function maybeAutoUpgrade(projectDir, flags) {
|
|
45
|
-
if (flags['skip-update-check']) return { upgraded: false };
|
|
46
|
-
if (process.env[REENTRY_FLAG] === '1') return { upgraded: false };
|
|
47
|
-
if (process.env.DRAFTGO_NO_UPDATE_CHECK === '1') return { upgraded: false };
|
|
48
|
-
|
|
49
16
|
const current = getPackageVersion();
|
|
50
|
-
const latest = await fetchLatestVersion();
|
|
17
|
+
const latest = await fetchLatestVersion(5000, { force: true });
|
|
51
18
|
if (!latest) {
|
|
52
|
-
log.
|
|
53
|
-
return
|
|
19
|
+
log.warn('无法查询 npm 最新版本;将用当前 CLI 刷新 skill。');
|
|
20
|
+
return null;
|
|
54
21
|
}
|
|
55
22
|
if (cmpSemver(latest, current) <= 0) {
|
|
56
23
|
log.dim(` CLI 已是最新(${current})`);
|
|
57
|
-
return
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const npm = process.platform === 'win32' ? 'npm.cmd' : 'npm';
|
|
28
|
+
log.step(`更新 draftgo-cli:${current} → ${latest}`);
|
|
29
|
+
const install = spawnSync(npm, ['install', '-g', `draftgo-cli@${latest}`], { stdio: 'inherit', shell: false });
|
|
30
|
+
if (install.error) {
|
|
31
|
+
log.err(`CLI 更新启动失败:${install.error.message}`);
|
|
32
|
+
return 1;
|
|
33
|
+
}
|
|
34
|
+
if (install.status !== 0) {
|
|
35
|
+
log.err(`npm install 返回码 ${install.status}`);
|
|
36
|
+
return Number.isInteger(install.status) ? install.status : 1;
|
|
58
37
|
}
|
|
59
38
|
|
|
60
|
-
|
|
61
|
-
const
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
39
|
+
const command = process.platform === 'win32' ? 'draftgo.cmd' : 'draftgo';
|
|
40
|
+
const rerun = spawnSync(command, ['update', ...positional, '--project', projectDir, '--skip-update-check'], {
|
|
41
|
+
stdio: 'inherit',
|
|
42
|
+
shell: false,
|
|
43
|
+
env: { ...process.env, [REENTRY_FLAG]: '1' },
|
|
44
|
+
});
|
|
45
|
+
if (rerun.error) {
|
|
46
|
+
log.err(`新版 CLI 刷新 skill 失败:${rerun.error.message}`);
|
|
47
|
+
return 1;
|
|
65
48
|
}
|
|
66
|
-
|
|
67
|
-
const code = reExecSameCommand(projectDir);
|
|
68
|
-
return { upgraded: true, exitCode: code };
|
|
49
|
+
return Number.isInteger(rerun.status) ? rerun.status : 1;
|
|
69
50
|
}
|
|
70
51
|
|
|
71
52
|
async function update(projectDir, positional, flags) {
|
|
72
53
|
log.title('draftgo update');
|
|
73
54
|
|
|
55
|
+
const reentryCode = await updateCliIfNeeded(projectDir, positional, flags);
|
|
56
|
+
if (reentryCode !== null) return reentryCode;
|
|
57
|
+
|
|
74
58
|
const prev = readInstalledVersion(projectDir);
|
|
75
59
|
log.info(`当前已装 skill:${prev || '未安装'},CLI 版本:${getPackageVersion()}`);
|
|
76
60
|
|
|
77
|
-
// Auto-upgrade-and-rerun path.
|
|
78
|
-
const { upgraded, exitCode } = await maybeAutoUpgrade(projectDir, flags);
|
|
79
|
-
if (upgraded) return exitCode;
|
|
80
|
-
|
|
81
61
|
// Determine which entry files to refresh:
|
|
82
62
|
// - no positional → refresh installed targets plus project-level tool signals
|
|
83
63
|
// - "all" → refresh every known target
|
|
@@ -111,14 +91,20 @@ async function update(projectDir, positional, flags) {
|
|
|
111
91
|
|
|
112
92
|
ensureRuntime(projectDir);
|
|
113
93
|
log.step('用 CLI 内置版本覆盖各 AI 工具 skill 目录');
|
|
94
|
+
const failures = [];
|
|
114
95
|
for (const t of resolved) {
|
|
115
96
|
try {
|
|
116
97
|
const r = t.install(projectDir, { force: true });
|
|
117
98
|
log.ok(`${t.displayName.padEnd(16)} → ${r.path}`);
|
|
118
99
|
} catch (e) {
|
|
119
100
|
log.err(`${t.displayName} 更新失败:${e.message}`);
|
|
101
|
+
failures.push(t.displayName);
|
|
120
102
|
}
|
|
121
103
|
}
|
|
104
|
+
if (failures.length) {
|
|
105
|
+
log.err(`更新未完成,失败目标:${failures.join(', ')}`);
|
|
106
|
+
return 1;
|
|
107
|
+
}
|
|
122
108
|
writeInstalledVersion(projectDir);
|
|
123
109
|
|
|
124
110
|
log.title('完成');
|
|
@@ -126,3 +112,4 @@ async function update(projectDir, positional, flags) {
|
|
|
126
112
|
}
|
|
127
113
|
|
|
128
114
|
module.exports = update;
|
|
115
|
+
module.exports.updateCliIfNeeded = updateCliIfNeeded;
|