draftgo-cli 3.0.33 → 3.0.38
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 +220 -269
- package/package.json +6 -2
- package/resources/skill/SKILL.md +114 -55
- package/resources/skill/init/SKILL.md +29 -15
- package/resources/skill/manifest.json +13 -5
- package/resources/skill/push/SKILL.md +41 -29
- package/resources/skill/references/aihub.md +8 -5
- package/resources/skill/references/api-endpoints.md +5 -3
- package/resources/skill/references/architecture.md +1 -1
- package/resources/skill/references/checkout.md +116 -0
- package/resources/skill/references/custom-services.md +9 -10
- package/resources/skill/references/data.md +4 -2
- package/resources/skill/references/frontend.md +99 -23
- package/resources/skill/references/mcp.md +101 -0
- package/resources/skill/references/modules.md +8 -8
- package/resources/skill/references/parallel.md +6 -3
- package/resources/skill/references/runtime.md +7 -10
- package/resources/skill/scripts/README.md +8 -0
- package/resources/skill/story/SKILL.md +8 -8
- package/src/cli.js +5 -0
- package/src/commandRegistry.js +7 -1
- package/src/commands/api.js +24 -187
- package/src/commands/autoPush.js +48 -17
- package/src/commands/check.js +17 -47
- package/src/commands/checkout.js +18 -0
- package/src/commands/commit.js +21 -0
- package/src/commands/conflict.js +30 -0
- package/src/commands/conflicts.js +16 -0
- package/src/commands/connect.js +60 -48
- package/src/commands/delete.js +79 -64
- package/src/commands/deploy.js +18 -10
- package/src/commands/diff.js +23 -0
- package/src/commands/help.js +99 -75
- package/src/commands/init.js +4 -10
- package/src/commands/local.js +23 -6
- package/src/commands/map.js +89 -89
- package/src/commands/mcp.js +126 -0
- package/src/commands/sync.js +28 -43
- package/src/commands/verifyUi.js +3 -2
- package/src/localdev/index.js +37 -7
- package/src/localdev/mysqlClient.js +1 -1
- package/src/mcp/client.js +275 -0
- package/src/mcp/hosts.js +520 -0
- package/src/mcp/protocol.js +173 -0
- package/src/mcp/stdio.js +300 -0
- package/src/mcp/tools.js +37 -0
- package/src/platforms.js +3 -4
- package/src/projectConfig.js +91 -49
- package/src/projectMap.js +123 -460
- package/src/skill.js +6 -28
- package/src/worktree/backend.js +250 -0
- package/src/worktree/errors.js +28 -0
- package/src/worktree/index.js +461 -0
- package/src/worktree/manifest.js +75 -0
- package/src/worktree/streams.js +200 -0
- package/src/worktree/types.js +103 -0
- package/src/worktree/validate.js +37 -0
- package/resources/skill/pull/SKILL.md +0 -33
- package/resources/skill/references/api.json +0 -20248
- package/resources/skill/scripts/draftgo_delete.py +0 -149
- package/resources/skill/scripts/draftgo_init.py +0 -80
- package/resources/skill/scripts/draftgo_pull.py +0 -427
- package/resources/skill/scripts/draftgo_push.py +0 -1022
- package/src/python.js +0 -27
package/src/commands/map.js
CHANGED
|
@@ -1,105 +1,105 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
3
5
|
const log = require('../logger');
|
|
4
|
-
const {
|
|
6
|
+
const { loadProjectConfig } = require('../projectConfig');
|
|
7
|
+
const { loadManifest, absolutePath } = require('../worktree/manifest');
|
|
8
|
+
const { hashFile } = require('../worktree/streams');
|
|
9
|
+
const { TOOL_NAMES, openToolSession, callStructured } = require('../mcp/tools');
|
|
10
|
+
|
|
11
|
+
function itemsFrom(value) {
|
|
12
|
+
if (Array.isArray(value)) return value;
|
|
13
|
+
if (!value || typeof value !== 'object') return [];
|
|
14
|
+
if (Array.isArray(value.items)) return value.items;
|
|
15
|
+
if (Array.isArray(value.resources)) return value.resources;
|
|
16
|
+
if (value.data) return itemsFrom(value.data);
|
|
17
|
+
return [];
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function nextCursor(value) {
|
|
21
|
+
return value && (value.next_cursor || value.nextCursor || value.cursor && value.has_more && value.cursor);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
async function listRemoteResources(session, flags) {
|
|
25
|
+
const resources = [];
|
|
26
|
+
const seen = new Set();
|
|
27
|
+
let cursor = null;
|
|
28
|
+
for (let page = 0; page < 100; page += 1) {
|
|
29
|
+
const args = {};
|
|
30
|
+
if (cursor) args.cursor = cursor;
|
|
31
|
+
if (flags.type) args.resource_type = String(flags.type);
|
|
32
|
+
const payload = await callStructured(session, TOOL_NAMES.resourceList, args);
|
|
33
|
+
resources.push(...itemsFrom(payload));
|
|
34
|
+
cursor = nextCursor(payload);
|
|
35
|
+
if (!cursor) break;
|
|
36
|
+
if (seen.has(cursor)) throw new Error('DraftGo resource_list repeated a cursor.');
|
|
37
|
+
seen.add(cursor);
|
|
38
|
+
}
|
|
39
|
+
if (cursor) throw new Error('DraftGo resource_list exceeded 100 pages.');
|
|
40
|
+
return resources;
|
|
41
|
+
}
|
|
5
42
|
|
|
6
|
-
function
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
43
|
+
async function localCheckouts(projectDir) {
|
|
44
|
+
const manifest = loadManifest(projectDir);
|
|
45
|
+
const entries = [];
|
|
46
|
+
for (const entry of Object.values(manifest.entries)) {
|
|
47
|
+
const local = absolutePath(projectDir, entry.local_path);
|
|
48
|
+
let currentHash = null;
|
|
49
|
+
if (fs.existsSync(local)) currentHash = (await hashFile(local)).hash;
|
|
50
|
+
entries.push({
|
|
51
|
+
...entry,
|
|
52
|
+
exists: currentHash !== null,
|
|
53
|
+
current_hash: currentHash,
|
|
54
|
+
changed: currentHash !== null && currentHash !== entry.base_hash,
|
|
55
|
+
});
|
|
12
56
|
}
|
|
13
|
-
|
|
57
|
+
return entries;
|
|
14
58
|
}
|
|
15
59
|
|
|
16
|
-
function
|
|
17
|
-
|
|
60
|
+
function legacyCaches(projectDir) {
|
|
61
|
+
return ['pages', 'navigations', 'docs', 'db_meta', 'custom_scripts', 'aihub', 'roles', 'users', 'system_config']
|
|
62
|
+
.filter((name) => fs.existsSync(path.join(projectDir, '.draftgo', name, 'index.json')));
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
async function mapCommand(projectDir, flags = {}) {
|
|
66
|
+
const config = loadProjectConfig(projectDir);
|
|
67
|
+
const session = await openToolSession(config, [TOOL_NAMES.projectOverview, TOOL_NAMES.resourceList]);
|
|
68
|
+
const [overview, resources, checkouts] = await Promise.all([
|
|
69
|
+
callStructured(session, TOOL_NAMES.projectOverview, {}),
|
|
70
|
+
listRemoteResources(session, flags),
|
|
71
|
+
localCheckouts(projectDir),
|
|
72
|
+
]);
|
|
73
|
+
const result = {
|
|
74
|
+
server: config.server,
|
|
75
|
+
overview,
|
|
76
|
+
resources,
|
|
77
|
+
checkouts,
|
|
78
|
+
legacy_cache: { ignored: true, detected: legacyCaches(projectDir) },
|
|
79
|
+
};
|
|
18
80
|
|
|
19
81
|
if (flags.output === 'json') {
|
|
20
|
-
console.log(JSON.stringify(
|
|
82
|
+
console.log(JSON.stringify(result, null, 2));
|
|
21
83
|
return 0;
|
|
22
84
|
}
|
|
23
|
-
|
|
24
85
|
log.title('draftgo map');
|
|
25
|
-
log.info(
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
printList('自定义脚本', map.custom_scripts, (s) => {
|
|
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
|
-
});
|
|
51
|
-
|
|
52
|
-
printList('文档', map.docs, (d) => {
|
|
53
|
-
return `${d.id || 'new'} ${d.slug || '(无 slug)'} ${d.title || '未命名'}${d.content_file ? ` ${d.content_file}` : ''}`;
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
printList('文档分类', map.doc_categories, (c) => {
|
|
57
|
-
const parent = c.parent_id == null ? 'root' : `parent:${c.parent_id}`;
|
|
58
|
-
return `${c.id || 'new'} ${c.slug || '(无 slug)'} ${c.name || '未命名'} ${parent}`;
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
printList('系统配置', map.system_config, (c) => {
|
|
62
|
-
const sensitive = c.is_sensitive ? ' sensitive' : '';
|
|
63
|
-
return `${c.config_key || '(无 key)'} ${c.category || 'default'} ${c.value_type || 'value'}${sensitive}`;
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
printList('AIHub', map.aihub, (a) => {
|
|
67
|
-
const extra = [];
|
|
68
|
-
if (a.type === 'agent') {
|
|
69
|
-
if (a.mode) extra.push(a.mode);
|
|
70
|
-
if (a.output_format && a.output_format.mode === 'json') extra.push(`json:${a.output_format.json_strategy || 'auto'}`);
|
|
71
|
-
if (a.model_selection && a.model_selection.user_selectable) extra.push('user-model');
|
|
72
|
-
if (a.tools && a.tools.sources.length) extra.push(`tools:${a.tools.sources.length}`);
|
|
73
|
-
} else if (a.type === 'model') {
|
|
74
|
-
extra.push(`models:${a.models_count || 0}`);
|
|
75
|
-
if (a.supports_response_format === true) extra.push('response_format');
|
|
76
|
-
if (a.supports_json_schema === true) extra.push('json_schema');
|
|
77
|
-
} else if (a.type === 'mcp') {
|
|
78
|
-
extra.push(a.transport || 'transport?');
|
|
79
|
-
extra.push(`tools:${a.tools_count || 0}`);
|
|
80
|
-
}
|
|
81
|
-
return `${a.id || 'new'} ${a.type || ''} ${a.name || ''}${extra.length ? ` [${extra.join(', ')}]` : ''}`;
|
|
82
|
-
});
|
|
83
|
-
printList('角色', map.roles, (r) => `${r.code || r.id || 'new'} ${r.name || ''}`);
|
|
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
|
-
|
|
96
|
-
console.log('');
|
|
97
|
-
log.info('入口引用:');
|
|
98
|
-
const routes = Object.keys(map.routeRefs).sort();
|
|
99
|
-
if (routes.length === 0) log.dim(' (未发现 data-page-route / href 引用)');
|
|
100
|
-
else routes.forEach((route) => log.dim(` • ${route} ← ${map.routeRefs[route].join(', ')}`));
|
|
101
|
-
|
|
86
|
+
log.info(`Remote resources: ${resources.length}`);
|
|
87
|
+
const counts = new Map();
|
|
88
|
+
for (const resource of resources) {
|
|
89
|
+
const type = resource.resource_type || resource.type || 'unknown';
|
|
90
|
+
counts.set(type, (counts.get(type) || 0) + 1);
|
|
91
|
+
}
|
|
92
|
+
for (const [type, count] of [...counts.entries()].sort()) log.plain(` ${type}: ${count}`);
|
|
93
|
+
log.info(`Local checkouts: ${checkouts.length}`);
|
|
94
|
+
for (const entry of checkouts) {
|
|
95
|
+
const state = !entry.exists ? 'missing' : entry.changed ? 'modified' : 'clean';
|
|
96
|
+
log.plain(` ${entry.resource_type} ${entry.resource_id}: ${state} (${entry.local_path})`);
|
|
97
|
+
}
|
|
98
|
+
if (result.legacy_cache.detected.length) {
|
|
99
|
+
log.warn(`Ignored legacy cache indexes: ${result.legacy_cache.detected.join(', ')}`);
|
|
100
|
+
}
|
|
102
101
|
return 0;
|
|
103
102
|
}
|
|
104
103
|
|
|
105
104
|
module.exports = mapCommand;
|
|
105
|
+
module.exports.itemsFrom = itemsFrom;
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const log = require('../logger');
|
|
4
|
+
const { loadProjectConfig } = require('../projectConfig');
|
|
5
|
+
const { testConnection } = require('../mcp/client');
|
|
6
|
+
const { redactText } = require('../mcp/protocol');
|
|
7
|
+
const {
|
|
8
|
+
HOSTS,
|
|
9
|
+
detectHostTargets,
|
|
10
|
+
setupHosts,
|
|
11
|
+
statusHosts,
|
|
12
|
+
} = require('../mcp/hosts');
|
|
13
|
+
const { serveStdio } = require('../mcp/stdio');
|
|
14
|
+
|
|
15
|
+
function targetArgs(positional, flags) {
|
|
16
|
+
const values = positional.slice();
|
|
17
|
+
if (flags.target) values.push(...String(flags.target).split(','));
|
|
18
|
+
return values.map((value) => String(value).trim()).filter(Boolean);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function printUsage() {
|
|
22
|
+
log.plain('Usage:');
|
|
23
|
+
log.plain(' draftgo mcp setup [target...]');
|
|
24
|
+
log.plain(' draftgo mcp status [target...]');
|
|
25
|
+
log.plain(' draftgo mcp test');
|
|
26
|
+
log.plain(' draftgo mcp serve');
|
|
27
|
+
log.dim(` targets: ${HOSTS.map((host) => host.name).join(', ')}`);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function setup(projectDir, positional = [], flags = {}) {
|
|
31
|
+
const targets = targetArgs(positional, flags);
|
|
32
|
+
const detected = targets.length ? null : detectHostTargets(projectDir);
|
|
33
|
+
if (!targets.length && detected.length === 0) {
|
|
34
|
+
log.err('No supported AI host was detected in this project.');
|
|
35
|
+
log.dim(' Run `draftgo mcp setup <target>` to select one explicitly.');
|
|
36
|
+
return 1;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const results = setupHosts(projectDir, targets.length ? targets : detected.map((host) => host.name));
|
|
40
|
+
let configured = 0;
|
|
41
|
+
let unsupported = 0;
|
|
42
|
+
for (const result of results) {
|
|
43
|
+
if (!result.supported) {
|
|
44
|
+
unsupported += 1;
|
|
45
|
+
log.warn(`${result.host.displayName}: ${result.reason}`);
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
configured += 1;
|
|
49
|
+
if (result.changed) log.ok(`${result.host.displayName}: ${result.host.path}`);
|
|
50
|
+
else log.info(`${result.host.displayName}: already configured`);
|
|
51
|
+
}
|
|
52
|
+
if (!configured && unsupported) return 1;
|
|
53
|
+
if (!configured) {
|
|
54
|
+
log.err('No MCP host configuration was written.');
|
|
55
|
+
return 1;
|
|
56
|
+
}
|
|
57
|
+
return 0;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function status(projectDir, positional = [], flags = {}) {
|
|
61
|
+
const targets = targetArgs(positional, flags);
|
|
62
|
+
const results = statusHosts(projectDir, targets);
|
|
63
|
+
log.title('draftgo mcp status');
|
|
64
|
+
let exitCode = 0;
|
|
65
|
+
try {
|
|
66
|
+
const config = loadProjectConfig(projectDir);
|
|
67
|
+
log.plain(` project configured (${config.server}; SAT present)`);
|
|
68
|
+
} catch (error) {
|
|
69
|
+
log.plain(` project not ready (${error.message})`);
|
|
70
|
+
exitCode = 1;
|
|
71
|
+
}
|
|
72
|
+
for (const result of results) {
|
|
73
|
+
if (!result.supported) {
|
|
74
|
+
log.plain(` - ${result.host.name.padEnd(12)} unsupported`);
|
|
75
|
+
} else if (result.configured && result.secure) {
|
|
76
|
+
log.plain(` OK ${result.host.name.padEnd(12)} ${result.host.path}`);
|
|
77
|
+
} else if (result.error) {
|
|
78
|
+
log.plain(` x ${result.host.name.padEnd(12)} invalid config`);
|
|
79
|
+
exitCode = 1;
|
|
80
|
+
} else {
|
|
81
|
+
log.plain(` - ${result.host.name.padEnd(12)} not configured`);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return exitCode;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
async function test(projectDir, _positional = [], flags = {}) {
|
|
88
|
+
let config;
|
|
89
|
+
try {
|
|
90
|
+
config = loadProjectConfig(projectDir);
|
|
91
|
+
const result = await testConnection(config, {
|
|
92
|
+
timeoutMs: flags.timeout ? Number(flags.timeout) : undefined,
|
|
93
|
+
});
|
|
94
|
+
log.ok('DraftGo MCP initialize succeeded.');
|
|
95
|
+
log.ok(`tools/list returned ${result.tools.length} tools.`);
|
|
96
|
+
log.ok(`tools/call succeeded: ${result.testedTool}`);
|
|
97
|
+
log.dim(` protocol: ${result.protocolVersion}`);
|
|
98
|
+
return 0;
|
|
99
|
+
} catch (error) {
|
|
100
|
+
const token = config && String(config.token || config.sat || '');
|
|
101
|
+
log.err(redactText(error && error.message ? error.message : error, [token]));
|
|
102
|
+
return 1;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
async function serve(projectDir, _positional = [], _flags = {}) {
|
|
107
|
+
return serveStdio(projectDir);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
async function mcp(projectDir, positional = [], flags = {}) {
|
|
111
|
+
const [action, ...rest] = positional;
|
|
112
|
+
if (action === 'setup') return setup(projectDir, rest, flags);
|
|
113
|
+
if (action === 'status') return status(projectDir, rest, flags);
|
|
114
|
+
if (action === 'test') return test(projectDir, rest, flags);
|
|
115
|
+
if (action === 'serve') return serve(projectDir, rest, flags);
|
|
116
|
+
printUsage();
|
|
117
|
+
return 1;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
mcp.setup = setup;
|
|
121
|
+
mcp.status = status;
|
|
122
|
+
mcp.test = test;
|
|
123
|
+
mcp.serve = serve;
|
|
124
|
+
mcp.printUsage = printUsage;
|
|
125
|
+
|
|
126
|
+
module.exports = mcp;
|
package/src/commands/sync.js
CHANGED
|
@@ -1,61 +1,46 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const path = require('path');
|
|
4
|
-
const { spawnSync } = require('child_process');
|
|
5
3
|
const log = require('../logger');
|
|
6
|
-
const {
|
|
7
|
-
const { findPython } = require('../python');
|
|
8
|
-
const { platforms } = require('../platforms');
|
|
4
|
+
const { canonicalResourceType } = require('../worktree/types');
|
|
9
5
|
|
|
10
|
-
function
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
6
|
+
async function sync(projectDir, command, positional, flags = {}) {
|
|
7
|
+
if (command === 'pull') {
|
|
8
|
+
log.err('`draftgo pull` no longer downloads DraftGo resources.');
|
|
9
|
+
log.dim(' Use MCP project/resource discovery. For complete pages, navigation, or docs, use `draftgo checkout <type> <id...>`.');
|
|
10
|
+
log.dim(' Existing legacy .draftgo indexes are left untouched and ignored.');
|
|
11
|
+
return 1;
|
|
16
12
|
}
|
|
17
13
|
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
const py = findPython();
|
|
24
|
-
if (!py) {
|
|
25
|
-
log.err('未检测到 Python,无法运行 DraftGo 同步脚本。');
|
|
14
|
+
const [rawType, ...ids] = positional;
|
|
15
|
+
if (!rawType) {
|
|
16
|
+
log.err('The legacy push-all workflow has been removed.');
|
|
17
|
+
log.dim(' Use `draftgo commit <pages|nav|docs> <id...>` for checked-out long content.');
|
|
18
|
+
log.dim(' Use DraftGo MCP for structured resources.');
|
|
26
19
|
return 1;
|
|
27
20
|
}
|
|
28
21
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
22
|
+
let resourceType;
|
|
23
|
+
try {
|
|
24
|
+
resourceType = canonicalResourceType(rawType);
|
|
25
|
+
} catch {
|
|
26
|
+
log.err(`Legacy push for ${rawType} is no longer supported.`);
|
|
27
|
+
log.dim(' Discover the live API with `draftgo api <query>` and use MCP api_call for structured resources.');
|
|
33
28
|
return 1;
|
|
34
29
|
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
log.err('未找到 .draftgo/config.json。');
|
|
38
|
-
log.dim(' 请先运行 `draftgo connect`。');
|
|
30
|
+
if (!ids.length) {
|
|
31
|
+
log.err('Refusing legacy push-all behavior; specify checked-out resource ids explicitly.');
|
|
39
32
|
return 1;
|
|
40
33
|
}
|
|
41
34
|
|
|
42
|
-
|
|
43
|
-
if (
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
const r = spawnSync(py.bin, [script, ...args], {
|
|
50
|
-
cwd: projectDir,
|
|
51
|
-
stdio: 'inherit',
|
|
52
|
-
shell: false,
|
|
53
|
-
});
|
|
54
|
-
if (r.error) {
|
|
55
|
-
log.err(`${command} 启动失败:${r.error.message}`);
|
|
56
|
-
return 1;
|
|
35
|
+
log.warn('`draftgo push` is deprecated; forwarding checked-out long content to `draftgo commit`.');
|
|
36
|
+
if (flags['dry-run']) {
|
|
37
|
+
for (const id of ids) {
|
|
38
|
+
const code = require('./diff')(projectDir, [resourceType, id], flags);
|
|
39
|
+
if (code !== 0) return code;
|
|
40
|
+
}
|
|
41
|
+
return 0;
|
|
57
42
|
}
|
|
58
|
-
return
|
|
43
|
+
return require('./commit')(projectDir, [resourceType, ...ids], flags);
|
|
59
44
|
}
|
|
60
45
|
|
|
61
46
|
module.exports = sync;
|
package/src/commands/verifyUi.js
CHANGED
|
@@ -14,8 +14,9 @@ function isUiFile(file) {
|
|
|
14
14
|
if (!['.js', '.ts'].includes(ext)) return false;
|
|
15
15
|
return /(^|\/)(frontend|web|ui|components|pages|views|client)(\/|$)/.test(normalized)
|
|
16
16
|
|| /(^|\/)(app|main|client)\.(js|ts)$/.test(normalized)
|
|
17
|
-
|| normalized.startsWith('.draftgo/pages/')
|
|
18
|
-
|| normalized.startsWith('.draftgo/navigations/')
|
|
17
|
+
|| normalized.startsWith('.draftgo/worktree/pages/')
|
|
18
|
+
|| normalized.startsWith('.draftgo/worktree/navigations/')
|
|
19
|
+
|| normalized.startsWith('.draftgo/worktree/docs/');
|
|
19
20
|
}
|
|
20
21
|
|
|
21
22
|
function gitChangedFiles(projectDir) {
|
package/src/localdev/index.js
CHANGED
|
@@ -7,7 +7,7 @@ const { probePort, probeHttp, detectDocker } = require('./detect');
|
|
|
7
7
|
const compose = require('./compose');
|
|
8
8
|
const { ensureDatabase, testConnection, describeClient } = require('./mysqlClient');
|
|
9
9
|
const { defaults, portOpen, probeRedis, probeMilvus, startService } = require('./services');
|
|
10
|
-
const { writeProjectConfig
|
|
10
|
+
const { writeProjectConfig } = require('../projectConfig');
|
|
11
11
|
const { appendGitignoreLine } = require('../fsx');
|
|
12
12
|
|
|
13
13
|
const DEFAULT_APP_PORT = 3000;
|
|
@@ -147,7 +147,35 @@ async function waitForApp(appPort) {
|
|
|
147
147
|
return ok;
|
|
148
148
|
}
|
|
149
149
|
|
|
150
|
-
async function
|
|
150
|
+
async function finishMcpSetup(projectDir, mcpCommands) {
|
|
151
|
+
const commands = mcpCommands || require('../commands/mcp');
|
|
152
|
+
const setupMcp = commands.setupMcp || commands.setup;
|
|
153
|
+
const testMcp = commands.testMcp || commands.test;
|
|
154
|
+
if (typeof setupMcp !== 'function' || typeof testMcp !== 'function') {
|
|
155
|
+
log.warn(' MCP setup helpers are unavailable. Run `draftgo mcp setup` after updating the CLI.');
|
|
156
|
+
return false;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
let setupOk = false;
|
|
160
|
+
try {
|
|
161
|
+
setupOk = await setupMcp(projectDir, [], { yes: true }) === 0;
|
|
162
|
+
} catch {
|
|
163
|
+
log.warn(' MCP host setup failed. Retry with `draftgo mcp setup`.');
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
let testOk = false;
|
|
167
|
+
try {
|
|
168
|
+
testOk = await testMcp(projectDir, {}) === 0;
|
|
169
|
+
} catch {
|
|
170
|
+
log.warn(' MCP validation failed. Run `draftgo mcp test` for diagnostics.');
|
|
171
|
+
}
|
|
172
|
+
if (!testOk) {
|
|
173
|
+
log.dim(' The local stack and project config are ready; MCP may still be starting.');
|
|
174
|
+
}
|
|
175
|
+
return setupOk && testOk;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
async function runWizard(projectDir, { yes = false, mcpCommands } = {}) {
|
|
151
179
|
log.title('draftgo local setup');
|
|
152
180
|
if (!yes && !await confirm('Continue with local DraftGo setup?', { default: true })) return 0;
|
|
153
181
|
|
|
@@ -169,14 +197,16 @@ async function runWizard(projectDir, { yes = false } = {}) {
|
|
|
169
197
|
if (!composeUp(docker, out.dir) || !await waitForApp(appPort)) return 1;
|
|
170
198
|
|
|
171
199
|
const url = `http://localhost:${appPort}`;
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
200
|
+
let token = '';
|
|
201
|
+
while (token.length < 10) {
|
|
202
|
+
token = String(await askPassword('Paste a DraftGo system access token (SAT)')).trim();
|
|
203
|
+
if (token.length < 10) log.err(' Token appears too short. Please try again.');
|
|
204
|
+
}
|
|
175
205
|
const cfgPath = writeProjectConfig(projectDir, url, token);
|
|
176
|
-
|
|
206
|
+
await finishMcpSetup(projectDir, mcpCommands);
|
|
177
207
|
log.ok(`DraftGo is ready at ${url}`);
|
|
178
208
|
log.dim(`Project config: ${cfgPath}`);
|
|
179
209
|
return 0;
|
|
180
210
|
}
|
|
181
211
|
|
|
182
|
-
module.exports = { runWizard };
|
|
212
|
+
module.exports = { finishMcpSetup, runWizard };
|