draftgo-cli 3.0.35 → 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 -272
- 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 +5 -4
- 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 +1 -1
- 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/check.js
CHANGED
|
@@ -1,62 +1,32 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
3
5
|
const log = require('../logger');
|
|
4
6
|
const { analyzeProject } = require('../projectMap');
|
|
5
7
|
|
|
8
|
+
function legacyCacheDetected(projectDir) {
|
|
9
|
+
return ['pages', 'navigations', 'docs', 'db_meta', 'custom_scripts', 'aihub', 'roles', 'users', 'system_config']
|
|
10
|
+
.some((name) => fs.existsSync(path.join(projectDir, '.draftgo', name, 'index.json')));
|
|
11
|
+
}
|
|
12
|
+
|
|
6
13
|
function check(projectDir, flags = {}) {
|
|
7
14
|
const result = analyzeProject(projectDir);
|
|
8
|
-
|
|
9
15
|
if (flags.output === 'json') {
|
|
10
|
-
console.log(JSON.stringify(result, null, 2));
|
|
16
|
+
console.log(JSON.stringify({ ...result, legacy_cache_ignored: legacyCacheDetected(projectDir) }, null, 2));
|
|
11
17
|
return result.errors.length || (flags.strict && result.warnings.length) ? 1 : 0;
|
|
12
18
|
}
|
|
13
19
|
|
|
14
20
|
log.title('draftgo check');
|
|
15
|
-
log.info(
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
['aihub', m.aihub.length],
|
|
25
|
-
['docs', m.docs.length],
|
|
26
|
-
];
|
|
27
|
-
console.log(' ' + overview.map(([k, v]) => `${log.c.cyan(k)} ${v}`).join(' '));
|
|
28
|
-
const pageAreas = [
|
|
29
|
-
['home', m.pageGroups.home.length],
|
|
30
|
-
['admin', m.pageGroups.admin.length],
|
|
31
|
-
['business', m.pageGroups.business.length],
|
|
32
|
-
['system', m.pageGroups.system.length],
|
|
33
|
-
];
|
|
34
|
-
console.log(' ' + pageAreas.map(([k, v]) => `${log.c.cyan(k)} ${v}`).join(' '));
|
|
35
|
-
|
|
36
|
-
if (result.errors.length) {
|
|
37
|
-
console.log('');
|
|
38
|
-
result.errors.forEach((msg) => console.log(` ${log.c.red('x')} ${msg}`));
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
if (result.warnings.length) {
|
|
42
|
-
console.log('');
|
|
43
|
-
result.warnings.forEach((msg) => {
|
|
44
|
-
const detail = (result.warningDetails || []).find((item) => item.message === msg);
|
|
45
|
-
const prefix = detail ? `[${detail.code}/${detail.confidence}] ` : '';
|
|
46
|
-
console.log(` ${log.c.yellow('!')} ${prefix}${msg}`);
|
|
47
|
-
});
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
console.log('');
|
|
51
|
-
if (result.errors.length) {
|
|
52
|
-
log.err('检查未通过:请先修复错误。');
|
|
53
|
-
return 1;
|
|
54
|
-
}
|
|
55
|
-
if (flags.strict && result.warnings.length) {
|
|
56
|
-
log.err('strict 模式:存在提醒项,检查未通过。');
|
|
57
|
-
return 1;
|
|
58
|
-
}
|
|
59
|
-
log.ok(result.warnings.length ? '检查完成(有提醒项)。' : '检查通过。');
|
|
21
|
+
log.info(`Checked-out pages: ${result.map.pages.length}`);
|
|
22
|
+
log.info(`Checked-out navigations: ${result.map.navigations.length}`);
|
|
23
|
+
log.info(`Checked-out docs: ${result.map.docs.length}`);
|
|
24
|
+
for (const message of result.errors) log.err(message);
|
|
25
|
+
for (const detail of result.warningDetails) log.warn(`[${detail.code}/${detail.confidence}] ${detail.message}`);
|
|
26
|
+
if (legacyCacheDetected(projectDir)) log.dim(' Legacy .draftgo index caches were detected and ignored.');
|
|
27
|
+
|
|
28
|
+
if (result.errors.length || (flags.strict && result.warnings.length)) return 1;
|
|
29
|
+
log.ok(result.warnings.length ? 'Local checkout validation completed with warnings.' : 'Local checkout validation passed.');
|
|
60
30
|
return 0;
|
|
61
31
|
}
|
|
62
32
|
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const log = require('../logger');
|
|
4
|
+
const { checkoutResources } = require('../worktree');
|
|
5
|
+
|
|
6
|
+
async function checkout(projectDir, positional, flags = {}) {
|
|
7
|
+
const [resourceType, ...ids] = positional;
|
|
8
|
+
if (!resourceType || !ids.length) {
|
|
9
|
+
log.err('Usage: draftgo checkout <pages|nav|docs> <id...>');
|
|
10
|
+
return 1;
|
|
11
|
+
}
|
|
12
|
+
const results = await checkoutResources(projectDir, resourceType, ids, { force: Boolean(flags.force) });
|
|
13
|
+
if (flags.output === 'json') console.log(JSON.stringify(results, null, 2));
|
|
14
|
+
else for (const entry of results) log.ok(`Checked out ${entry.resource_type} ${entry.resource_id} -> ${entry.local_path}`);
|
|
15
|
+
return 0;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
module.exports = checkout;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const log = require('../logger');
|
|
4
|
+
const { commitResources } = require('../worktree');
|
|
5
|
+
|
|
6
|
+
async function commit(projectDir, positional, flags = {}) {
|
|
7
|
+
const [resourceType, ...ids] = positional;
|
|
8
|
+
if (!resourceType || !ids.length) {
|
|
9
|
+
log.err('Usage: draftgo commit <pages|nav|docs> <id...>');
|
|
10
|
+
return 1;
|
|
11
|
+
}
|
|
12
|
+
const results = await commitResources(projectDir, resourceType, ids);
|
|
13
|
+
if (flags.output === 'json') console.log(JSON.stringify(results, null, 2));
|
|
14
|
+
else for (const result of results) {
|
|
15
|
+
if (result.status === 'unchanged') log.dim(`${result.resource_type} ${result.resource_id}: unchanged`);
|
|
16
|
+
else log.ok(`Committed ${result.resource_type} ${result.resource_id}`);
|
|
17
|
+
}
|
|
18
|
+
return 0;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
module.exports = commit;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const log = require('../logger');
|
|
4
|
+
const { showConflict, resolveConflict } = require('../worktree');
|
|
5
|
+
|
|
6
|
+
function printRecord(record) {
|
|
7
|
+
log.info(`${record.resource_type} ${record.resource_id}: ${record.status}`);
|
|
8
|
+
log.plain(` base: ${record.base_path}`);
|
|
9
|
+
log.plain(` local: ${record.local_path}`);
|
|
10
|
+
log.plain(` remote: ${record.remote_path}`);
|
|
11
|
+
log.plain(` worktree local: ${record.worktree_local_path}`);
|
|
12
|
+
log.plain(` manifest: ${record.manifest_path}`);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
async function conflict(projectDir, positional, flags = {}) {
|
|
16
|
+
const [action, resourceType, resourceId] = positional;
|
|
17
|
+
if (!['show', 'resolve'].includes(action) || !resourceType || !resourceId) {
|
|
18
|
+
log.err('Usage: draftgo conflict <show|resolve> <pages|nav|docs> <id>');
|
|
19
|
+
return 1;
|
|
20
|
+
}
|
|
21
|
+
const record = action === 'show'
|
|
22
|
+
? showConflict(projectDir, resourceType, resourceId)
|
|
23
|
+
: await resolveConflict(projectDir, resourceType, resourceId);
|
|
24
|
+
if (flags.output === 'json') console.log(JSON.stringify(record, null, 2));
|
|
25
|
+
else printRecord(record);
|
|
26
|
+
if (action === 'resolve') log.info('The remote revision is now the base; run check, diff, and commit the merged worktree file.');
|
|
27
|
+
return 0;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
module.exports = conflict;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const log = require('../logger');
|
|
4
|
+
const { listConflicts } = require('../worktree');
|
|
5
|
+
|
|
6
|
+
function conflicts(projectDir, _positional, flags = {}) {
|
|
7
|
+
const records = listConflicts(projectDir, { all: Boolean(flags.all) });
|
|
8
|
+
if (flags.output === 'json') console.log(JSON.stringify(records, null, 2));
|
|
9
|
+
else if (!records.length) log.ok('No unresolved DraftGo conflicts.');
|
|
10
|
+
else for (const record of records) {
|
|
11
|
+
log.warn(`${record.resource_type} ${record.resource_id}: ${record.status} (${record.manifest_path})`);
|
|
12
|
+
}
|
|
13
|
+
return records.some((record) => record.status === 'unresolved') ? 1 : 0;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
module.exports = conflicts;
|
package/src/commands/connect.js
CHANGED
|
@@ -1,61 +1,73 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
// `draftgo connect` — wire this project to an already-deployed DraftGo base.
|
|
4
|
-
// Prompts for server URL + access token, writes .draftgo/config.json, and
|
|
5
|
-
// (if Python is available) runs draftgo_init.py to pull initial context.
|
|
6
|
-
|
|
7
3
|
const log = require('../logger');
|
|
8
|
-
const { ask,
|
|
9
|
-
const {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
let v = String(raw || '').trim();
|
|
13
|
-
if (!v) return '';
|
|
14
|
-
if (!/^https?:\/\//i.test(v)) v = 'http://' + v;
|
|
15
|
-
return v.replace(/\/+$/, '');
|
|
16
|
-
}
|
|
4
|
+
const { ask, askPassword } = require('../prompt');
|
|
5
|
+
const { normalizeServer, writeProjectConfig } = require('../projectConfig');
|
|
6
|
+
const { testConnection } = require('../mcp/client');
|
|
7
|
+
const { redactText } = require('../mcp/protocol');
|
|
17
8
|
|
|
18
|
-
async function promptServer(
|
|
9
|
+
async function promptServer(defaultValue) {
|
|
19
10
|
while (true) {
|
|
20
|
-
const
|
|
21
|
-
const norm = normalizeServer(v);
|
|
22
|
-
if (!norm) { log.dim(' 不能为空'); continue; }
|
|
11
|
+
const raw = await ask('DraftGo server (Base URL)', { default: defaultValue });
|
|
23
12
|
try {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
log.dim(` 不是合法 URL:${norm}`);
|
|
29
|
-
continue;
|
|
13
|
+
const value = normalizeServer(raw);
|
|
14
|
+
if (value) return value;
|
|
15
|
+
} catch (error) {
|
|
16
|
+
log.dim(` ${error.message}`);
|
|
30
17
|
}
|
|
31
|
-
return norm;
|
|
32
18
|
}
|
|
33
19
|
}
|
|
34
20
|
|
|
35
|
-
async function
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
log.
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
21
|
+
async function promptToken() {
|
|
22
|
+
while (true) {
|
|
23
|
+
const value = String(await askPassword('DraftGo system access token (SAT)') || '').trim();
|
|
24
|
+
if (value) return value;
|
|
25
|
+
log.dim(' A SAT is required.');
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async function connect(projectDir, positional, flags = {}) {
|
|
30
|
+
log.title('draftgo connect');
|
|
31
|
+
const server = flags.server ? normalizeServer(flags.server) : await promptServer('https://');
|
|
32
|
+
const token = flags.token ? String(flags.token).trim() : await promptToken();
|
|
33
|
+
if (!token) {
|
|
34
|
+
log.err('A non-empty SAT is required.');
|
|
35
|
+
return 1;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
log.step('Validating SAT and DraftGo MCP capabilities...');
|
|
39
|
+
try {
|
|
40
|
+
const diagnostic = await testConnection({ server, token }, {
|
|
41
|
+
timeoutMs: flags.timeout ? Number(flags.timeout) : undefined,
|
|
42
|
+
});
|
|
43
|
+
log.ok(`MCP ready (${diagnostic.tools.length} tools; tested ${diagnostic.testedTool}).`);
|
|
44
|
+
} catch (error) {
|
|
45
|
+
const message = redactText(error && error.message ? error.message : error, [token]);
|
|
46
|
+
if (!flags['allow-offline']) {
|
|
47
|
+
log.err(message);
|
|
48
|
+
log.dim(' The project config was not changed. Run `draftgo mcp test` after checking the server and SAT.');
|
|
49
|
+
return 1;
|
|
50
|
+
}
|
|
51
|
+
log.warn(`MCP validation unavailable: ${message}`);
|
|
52
|
+
log.warn('Continuing only because --allow-offline was explicitly supplied.');
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const configFile = writeProjectConfig(projectDir, server, token);
|
|
56
|
+
log.ok(`Project configuration written: ${configFile}`);
|
|
57
|
+
|
|
58
|
+
if (!flags['no-mcp-setup']) {
|
|
59
|
+
try {
|
|
60
|
+
const setupCode = require('./mcp').setup(projectDir, positional, flags);
|
|
61
|
+
if (setupCode !== 0) log.dim(' Run `draftgo mcp setup <target>` when the AI host is known.');
|
|
62
|
+
} catch (error) {
|
|
63
|
+
log.warn(`MCP host setup was not completed: ${redactText(error.message || error, [token])}`);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
log.title('Connected');
|
|
68
|
+
log.plain(` server: ${server}`);
|
|
69
|
+
log.plain(` config: ${configFile}`);
|
|
70
|
+
log.dim(' No DraftGo business resources were downloaded. Use MCP discovery or checkout long content explicitly.');
|
|
59
71
|
return 0;
|
|
60
72
|
}
|
|
61
73
|
|
package/src/commands/delete.js
CHANGED
|
@@ -1,88 +1,103 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
const fs = require('fs');
|
|
3
4
|
const path = require('path');
|
|
4
|
-
const { exists } = require('../fsx');
|
|
5
5
|
const log = require('../logger');
|
|
6
6
|
const { confirm } = require('../prompt');
|
|
7
|
-
const {
|
|
8
|
-
const {
|
|
9
|
-
const { platforms } = require('../platforms');
|
|
7
|
+
const { loadProjectConfig } = require('../projectConfig');
|
|
8
|
+
const { TOOL_NAMES, openToolSession, callStructured } = require('../mcp/tools');
|
|
10
9
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
}
|
|
16
|
-
const bundled = path.resolve(__dirname, '..', '..', 'resources', 'skill', 'scripts', 'draftgo_delete.py');
|
|
17
|
-
return exists(bundled) ? bundled : null;
|
|
18
|
-
}
|
|
10
|
+
const LEGACY_TYPES = new Set([
|
|
11
|
+
'page', 'pages', 'nav', 'navigation', 'navigations', 'doc', 'docs', 'article',
|
|
12
|
+
'db_meta', 'custom_scripts', 'doc_categories', 'aihub', 'roles', 'users', 'system_config',
|
|
13
|
+
]);
|
|
19
14
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
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
|
-
aihub: 'aihub',
|
|
34
|
-
};
|
|
15
|
+
function resultItems(value) {
|
|
16
|
+
if (Array.isArray(value)) return value;
|
|
17
|
+
if (!value || typeof value !== 'object') return [];
|
|
18
|
+
if (Array.isArray(value.items)) return value.items;
|
|
19
|
+
if (Array.isArray(value.operations)) return value.operations;
|
|
20
|
+
return value.data ? resultItems(value.data) : [];
|
|
21
|
+
}
|
|
35
22
|
|
|
36
|
-
|
|
37
|
-
|
|
23
|
+
function operationId(value) {
|
|
24
|
+
return value && (value.operation_id || value.operationId || value.id);
|
|
25
|
+
}
|
|
38
26
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
27
|
+
function readParams(projectDir, flags) {
|
|
28
|
+
const raw = flags.params ? String(flags.params)
|
|
29
|
+
: flags.input ? fs.readFileSync(path.resolve(projectDir, String(flags.input)), 'utf8') : '';
|
|
30
|
+
if (!raw) return {};
|
|
31
|
+
const parsed = JSON.parse(raw);
|
|
32
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
33
|
+
throw new Error('Delete MCP parameters must be a JSON object.');
|
|
43
34
|
}
|
|
35
|
+
return parsed;
|
|
36
|
+
}
|
|
44
37
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
38
|
+
function pathParameterName(description) {
|
|
39
|
+
const source = description && (description.parameters || description.params
|
|
40
|
+
|| description.operation && description.operation.parameters) || [];
|
|
41
|
+
const pathParameters = source.filter((parameter) => parameter && parameter.in === 'path');
|
|
42
|
+
return pathParameters.length === 1 ? pathParameters[0].name : null;
|
|
43
|
+
}
|
|
50
44
|
|
|
51
|
-
|
|
52
|
-
|
|
45
|
+
async function deleteResource(projectDir, positional, flags = {}) {
|
|
46
|
+
if (!positional.length && !flags['operation-id']) {
|
|
47
|
+
log.err('Usage: draftgo delete <operation_id> [id] [--params JSON]');
|
|
48
|
+
log.dim(' Legacy form is supported when discovery is unambiguous: draftgo delete <type> <id>.');
|
|
53
49
|
return 1;
|
|
54
50
|
}
|
|
51
|
+
const config = loadProjectConfig(projectDir);
|
|
52
|
+
const session = await openToolSession(config, [
|
|
53
|
+
TOOL_NAMES.apiSearch, TOOL_NAMES.apiDescribe, TOOL_NAMES.apiCall,
|
|
54
|
+
]);
|
|
55
55
|
|
|
56
|
-
const
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
56
|
+
const first = String(positional[0] || '');
|
|
57
|
+
const legacy = LEGACY_TYPES.has(first.toLowerCase()) && !flags['operation-id'];
|
|
58
|
+
let selectedOperation = flags['operation-id'] ? String(flags['operation-id']) : (legacy ? null : first);
|
|
59
|
+
const resourceId = legacy ? positional[1] : positional[1];
|
|
60
|
+
if (legacy) {
|
|
61
|
+
if (!resourceId) {
|
|
62
|
+
log.err('Legacy delete form requires a resource id.');
|
|
63
|
+
return 1;
|
|
64
|
+
}
|
|
65
|
+
const search = await callStructured(session, TOOL_NAMES.apiSearch, { query: `delete ${first}` });
|
|
66
|
+
const candidates = resultItems(search).filter((item) => operationId(item)
|
|
67
|
+
&& (!item.method || String(item.method).toUpperCase() === 'DELETE'));
|
|
68
|
+
if (candidates.length !== 1) {
|
|
69
|
+
log.err(`Delete operation discovery was ambiguous (${candidates.length} matches).`);
|
|
70
|
+
log.dim(` Run \`draftgo api delete ${first}\`, then pass --operation-id explicitly.`);
|
|
71
|
+
return 1;
|
|
72
|
+
}
|
|
73
|
+
selectedOperation = operationId(candidates[0]);
|
|
60
74
|
}
|
|
61
75
|
|
|
62
|
-
const
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
76
|
+
const description = await callStructured(session, TOOL_NAMES.apiDescribe, {
|
|
77
|
+
operation_id: selectedOperation,
|
|
78
|
+
});
|
|
79
|
+
const params = readParams(projectDir, flags);
|
|
80
|
+
if (resourceId && Object.keys(params).length === 0) {
|
|
81
|
+
const parameterName = pathParameterName(description);
|
|
82
|
+
if (!parameterName) {
|
|
83
|
+
log.err('The operation does not expose exactly one path parameter; provide --params JSON explicitly.');
|
|
84
|
+
return 1;
|
|
85
|
+
}
|
|
86
|
+
params.path_params = { [parameterName]: resourceId };
|
|
66
87
|
}
|
|
67
|
-
|
|
68
88
|
if (!flags.yes && !flags.y) {
|
|
69
|
-
const
|
|
70
|
-
if (!
|
|
71
|
-
log.dim('已取消');
|
|
72
|
-
return 0;
|
|
73
|
-
}
|
|
89
|
+
const approved = await confirm(`Call destructive DraftGo operation ${selectedOperation}?`, { default: false });
|
|
90
|
+
if (!approved) return 0;
|
|
74
91
|
}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
shell: false,
|
|
92
|
+
const result = await callStructured(session, TOOL_NAMES.apiCall, {
|
|
93
|
+
...params,
|
|
94
|
+
operation_id: selectedOperation,
|
|
95
|
+
confirm: true,
|
|
80
96
|
});
|
|
81
|
-
if (
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
}
|
|
85
|
-
return Number.isInteger(r.status) ? r.status : 1;
|
|
97
|
+
if (flags.output === 'json') console.log(JSON.stringify(result, null, 2));
|
|
98
|
+
else log.ok(`DraftGo operation completed: ${selectedOperation}`);
|
|
99
|
+
return 0;
|
|
86
100
|
}
|
|
87
101
|
|
|
88
102
|
module.exports = deleteResource;
|
|
103
|
+
module.exports.pathParameterName = pathParameterName;
|
package/src/commands/deploy.js
CHANGED
|
@@ -2,30 +2,38 @@
|
|
|
2
2
|
|
|
3
3
|
const log = require('../logger');
|
|
4
4
|
const check = require('./check');
|
|
5
|
-
const sync = require('./sync');
|
|
6
5
|
|
|
7
|
-
function deploy(projectDir, positional, flags = {}) {
|
|
6
|
+
async function deploy(projectDir, positional, flags = {}) {
|
|
8
7
|
const delivery = String(flags.delivery || 'deploy').toLowerCase();
|
|
9
8
|
if (!['local', 'preview', 'deploy'].includes(delivery)) {
|
|
10
|
-
log.err('--delivery
|
|
9
|
+
log.err('--delivery accepts local, preview, or deploy.');
|
|
11
10
|
return 1;
|
|
12
11
|
}
|
|
13
|
-
|
|
12
|
+
|
|
13
|
+
log.step('deploy: validating checked-out content...');
|
|
14
14
|
const checkCode = check(projectDir, { strict: flags.strict });
|
|
15
15
|
if (checkCode !== 0) {
|
|
16
|
-
log.err('
|
|
16
|
+
log.err('Deploy stopped because local validation failed.');
|
|
17
17
|
return checkCode;
|
|
18
18
|
}
|
|
19
19
|
if (delivery === 'local') {
|
|
20
|
-
log.ok('
|
|
20
|
+
log.ok('Local validation passed; no remote content was changed.');
|
|
21
21
|
return 0;
|
|
22
22
|
}
|
|
23
|
+
|
|
24
|
+
const [resourceType, ...ids] = positional;
|
|
25
|
+
if (!resourceType || !ids.length) {
|
|
26
|
+
log.err('Deploy no longer commits every legacy index. Specify <pages|nav|docs> <id...>.');
|
|
27
|
+
return 1;
|
|
28
|
+
}
|
|
23
29
|
if (delivery === 'preview') {
|
|
24
|
-
|
|
25
|
-
|
|
30
|
+
for (const id of ids) {
|
|
31
|
+
const code = require('./diff')(projectDir, [resourceType, id], flags);
|
|
32
|
+
if (code !== 0) return code;
|
|
33
|
+
}
|
|
34
|
+
return 0;
|
|
26
35
|
}
|
|
27
|
-
|
|
28
|
-
return sync(projectDir, 'push', positional, flags);
|
|
36
|
+
return require('./commit')(projectDir, [resourceType, ...ids], flags);
|
|
29
37
|
}
|
|
30
38
|
|
|
31
39
|
module.exports = deploy;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const log = require('../logger');
|
|
4
|
+
const { diffResource } = require('../worktree');
|
|
5
|
+
|
|
6
|
+
function diff(projectDir, positional, flags = {}) {
|
|
7
|
+
const [resourceType, resourceId] = positional;
|
|
8
|
+
if (!resourceType || !resourceId) {
|
|
9
|
+
log.err('Usage: draftgo diff <pages|nav|docs> <id>');
|
|
10
|
+
return 1;
|
|
11
|
+
}
|
|
12
|
+
const result = diffResource(projectDir, resourceType, resourceId);
|
|
13
|
+
if (flags.output === 'json') {
|
|
14
|
+
console.log(JSON.stringify({ changed: result.changed, entry: result.entry, diff: result.output }, null, 2));
|
|
15
|
+
} else if (result.changed) {
|
|
16
|
+
process.stdout.write(result.output);
|
|
17
|
+
} else {
|
|
18
|
+
log.dim(`${result.entry.resource_type} ${result.entry.resource_id}: no local changes`);
|
|
19
|
+
}
|
|
20
|
+
return 0;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
module.exports = diff;
|