draftgo-cli 1.0.4

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 (99) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +249 -0
  3. package/bin/draftgo.js +9 -0
  4. package/package.json +70 -0
  5. package/resources/project-design/README.md +42 -0
  6. package/resources/skill/SKILL.md +62 -0
  7. package/resources/skill/init/SKILL.md +41 -0
  8. package/resources/skill/manifest.json +35 -0
  9. package/resources/skill/references/ai.md +41 -0
  10. package/resources/skill/references/app-api.md +97 -0
  11. package/resources/skill/references/architecture.md +13 -0
  12. package/resources/skill/references/chat-sdk.md +205 -0
  13. package/resources/skill/references/checkout.md +140 -0
  14. package/resources/skill/references/data.md +49 -0
  15. package/resources/skill/references/db-relations.md +29 -0
  16. package/resources/skill/references/delivery.md +33 -0
  17. package/resources/skill/references/development.md +41 -0
  18. package/resources/skill/references/diagnostics.md +50 -0
  19. package/resources/skill/references/frontend.md +158 -0
  20. package/resources/skill/references/mcp.md +110 -0
  21. package/resources/skill/references/methods.md +143 -0
  22. package/resources/skill/references/modules.md +75 -0
  23. package/resources/skill/references/runtime.md +109 -0
  24. package/resources/skill/references/services.md +32 -0
  25. package/src/apiContractCache.js +120 -0
  26. package/src/cli.js +100 -0
  27. package/src/commandRegistry.js +46 -0
  28. package/src/commands/api.js +244 -0
  29. package/src/commands/apiKey.js +30 -0
  30. package/src/commands/autoPush.js +36 -0
  31. package/src/commands/capabilities.js +100 -0
  32. package/src/commands/check.js +82 -0
  33. package/src/commands/checkout.js +18 -0
  34. package/src/commands/clean.js +72 -0
  35. package/src/commands/commit.js +47 -0
  36. package/src/commands/components.js +554 -0
  37. package/src/commands/conflict.js +30 -0
  38. package/src/commands/conflicts.js +16 -0
  39. package/src/commands/connect.js +91 -0
  40. package/src/commands/delete.js +95 -0
  41. package/src/commands/deploy.js +77 -0
  42. package/src/commands/diff.js +39 -0
  43. package/src/commands/group.js +37 -0
  44. package/src/commands/help.js +190 -0
  45. package/src/commands/init.js +126 -0
  46. package/src/commands/listTargets.js +13 -0
  47. package/src/commands/local.js +79 -0
  48. package/src/commands/map.js +395 -0
  49. package/src/commands/mcp.js +150 -0
  50. package/src/commands/reconcile.js +20 -0
  51. package/src/commands/role.js +31 -0
  52. package/src/commands/status.js +98 -0
  53. package/src/commands/uninstall.js +52 -0
  54. package/src/commands/update.js +79 -0
  55. package/src/commands/verify.js +188 -0
  56. package/src/commands/visualVerify.js +281 -0
  57. package/src/commands/worklog.js +117 -0
  58. package/src/consoleEncoding.js +34 -0
  59. package/src/contractCompatibility.js +65 -0
  60. package/src/detect.js +25 -0
  61. package/src/diffReport.js +106 -0
  62. package/src/fsx.js +67 -0
  63. package/src/index.js +46 -0
  64. package/src/localRuntime/compose.js +119 -0
  65. package/src/localRuntime/detect.js +77 -0
  66. package/src/localRuntime/index.js +211 -0
  67. package/src/localRuntime/mysqlClient.js +155 -0
  68. package/src/localRuntime/services.js +117 -0
  69. package/src/logger.js +37 -0
  70. package/src/mcp/client.js +558 -0
  71. package/src/mcp/hosts.js +520 -0
  72. package/src/mcp/parallel.js +54 -0
  73. package/src/mcp/protocol.js +223 -0
  74. package/src/mcp/stdio.js +300 -0
  75. package/src/mcp/tools.js +51 -0
  76. package/src/paths.js +32 -0
  77. package/src/platforms.js +110 -0
  78. package/src/projectConfig.js +139 -0
  79. package/src/projectDesign.js +19 -0
  80. package/src/projectHealth.js +33 -0
  81. package/src/projectMap.js +220 -0
  82. package/src/prompt.js +94 -0
  83. package/src/releaseInstall.js +105 -0
  84. package/src/runtimeFiles.js +45 -0
  85. package/src/skill.js +295 -0
  86. package/src/targets.js +43 -0
  87. package/src/timeout.js +18 -0
  88. package/src/updateCheck.js +100 -0
  89. package/src/worklog.js +276 -0
  90. package/src/worktree/backend.js +438 -0
  91. package/src/worktree/errors.js +28 -0
  92. package/src/worktree/index.js +751 -0
  93. package/src/worktree/inlineScripts.js +99 -0
  94. package/src/worktree/locks.js +52 -0
  95. package/src/worktree/manifest.js +89 -0
  96. package/src/worktree/status.js +124 -0
  97. package/src/worktree/streams.js +200 -0
  98. package/src/worktree/types.js +103 -0
  99. package/src/worktree/validate.js +37 -0
@@ -0,0 +1,91 @@
1
+ 'use strict';
2
+
3
+ const log = require('../logger');
4
+ const { ask, askPassword } = require('../prompt');
5
+ const { normalizeConnection, normalizeServer, writeProjectConfig } = require('../projectConfig');
6
+ const { testConnection } = require('../mcp/client');
7
+ const { redactText } = require('../mcp/protocol');
8
+ const { parseTimeout } = require('../timeout');
9
+
10
+ async function promptServer(defaultValue) {
11
+ while (true) {
12
+ const raw = await ask('DraftGo server (Base URL)', { default: defaultValue });
13
+ try {
14
+ const value = normalizeServer(raw);
15
+ if (value) return value;
16
+ } catch (error) {
17
+ log.dim(` ${error.message}`);
18
+ }
19
+ }
20
+ }
21
+
22
+ async function promptAPIKey() {
23
+ while (true) {
24
+ const value = String(await askPassword('DraftGo user API Key') || '').trim();
25
+ if (value) return value;
26
+ log.dim(' A DraftGo API Key is required.');
27
+ }
28
+ }
29
+
30
+ async function connect(projectDir, positional, flags = {}) {
31
+ log.title('draftgo connect');
32
+ const endpointConnection = flags['mcp-url']
33
+ ? normalizeConnection(flags['mcp-url'])
34
+ : null;
35
+ if (endpointConnection && !endpointConnection.server && !flags.server) {
36
+ throw new Error('--server is required when --mcp-url does not use the standard /mcp path.');
37
+ }
38
+ const connection = {
39
+ server: flags.server
40
+ ? normalizeServer(flags.server)
41
+ : endpointConnection && endpointConnection.server || await promptServer('https://'),
42
+ mcp_url: endpointConnection && endpointConnection.mcp_url || '',
43
+ };
44
+ const server = connection.server;
45
+ const suppliedAPIKey = flags['api-key'] || flags.token;
46
+ const token = suppliedAPIKey ? String(suppliedAPIKey).trim() : await promptAPIKey();
47
+ if (!token) {
48
+ log.err('A non-empty DraftGo API Key is required.');
49
+ return 1;
50
+ }
51
+ const timeoutMs = parseTimeout(flags.timeout);
52
+ log.step('Validating DraftGo API Key and MCP capabilities...');
53
+ try {
54
+ const diagnostic = await testConnection({ ...connection, server, token }, {
55
+ timeoutMs,
56
+ });
57
+ log.ok(`MCP ready (${diagnostic.tools.length} tools; tested ${diagnostic.testedCalls.join(', ')}).`);
58
+ } catch (error) {
59
+ const message = redactText(error && error.message ? error.message : error, [token]);
60
+ if (!flags['allow-offline']) {
61
+ log.err(message);
62
+ log.dim(' The project config was not changed. Run `draftgo mcp test` after checking the server and API Key.');
63
+ return 1;
64
+ }
65
+ log.warn(`MCP validation unavailable: ${message}`);
66
+ log.warn('Continuing only because --allow-offline was explicitly supplied.');
67
+ }
68
+
69
+ const configFile = writeProjectConfig(projectDir, server, token, {
70
+ mcp_url: connection.mcp_url,
71
+ });
72
+ log.ok(`Project configuration written: ${configFile}`);
73
+
74
+ if (!flags['no-mcp-setup']) {
75
+ try {
76
+ const setupCode = require('./mcp').setup(projectDir, positional, flags);
77
+ if (setupCode !== 0) log.dim(' Run `draftgo mcp setup <target>` when the AI host is known.');
78
+ } catch (error) {
79
+ log.warn(`MCP host setup was not completed: ${redactText(error.message || error, [token])}`);
80
+ }
81
+ }
82
+
83
+ log.title('Connected');
84
+ log.plain(` server: ${server}`);
85
+ if (connection.mcp_url) log.plain(` mcp endpoint: ${connection.mcp_url}`);
86
+ log.plain(` config: ${configFile}`);
87
+ log.dim(' No DraftGo business resources were downloaded. Use MCP discovery or checkout long content explicitly.');
88
+ return 0;
89
+ }
90
+
91
+ module.exports = connect;
@@ -0,0 +1,95 @@
1
+ 'use strict';
2
+
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+ const log = require('../logger');
6
+ const { confirm } = require('../prompt');
7
+ const { loadProjectConfig } = require('../projectConfig');
8
+ const { TOOL_NAMES, openToolSession, callStructured } = require('../mcp/tools');
9
+ const { cachedDescription } = require('../apiContractCache');
10
+ const { registryRevision, describeOperation } = require('./api');
11
+ const {
12
+ isContractCompatibilityError,
13
+ isHardContractIncompatibility,
14
+ sameOperationContract,
15
+ incompatibleOperationError,
16
+ } = require('../contractCompatibility');
17
+
18
+ function readParams(projectDir, flags) {
19
+ const raw = flags.params ? String(flags.params)
20
+ : flags.input ? fs.readFileSync(path.resolve(projectDir, String(flags.input)), 'utf8') : '';
21
+ if (!raw) return {};
22
+ const parsed = JSON.parse(raw);
23
+ if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
24
+ throw new Error('Delete MCP parameters must be a JSON object.');
25
+ }
26
+ return parsed;
27
+ }
28
+
29
+ function pathParameterName(description) {
30
+ const operation = description && (description.operation || description) || {};
31
+ const properties = operation.input_schema && operation.input_schema.properties || {};
32
+ const pathProperties = properties.path && properties.path.properties || {};
33
+ const names = Object.keys(pathProperties);
34
+ if (names.length === 1) return names[0];
35
+ const parameters = operation.parameters || operation.params || [];
36
+ const legacy = parameters.filter((parameter) => parameter && parameter.in === 'path');
37
+ return legacy.length === 1 ? legacy[0].name : null;
38
+ }
39
+
40
+ async function deleteResource(projectDir, positional, flags = {}) {
41
+ if (!positional.length && !flags['operation-id']) {
42
+ log.err('Usage: draftgo delete <operation_id> [id] [--params JSON]');
43
+ return 1;
44
+ }
45
+ const config = loadProjectConfig(projectDir);
46
+ const session = await openToolSession(config, [
47
+ TOOL_NAMES.apiSearch, TOOL_NAMES.apiDescribe, TOOL_NAMES.apiCall,
48
+ ]);
49
+
50
+ const selectedOperation = flags['operation-id'] ? String(flags['operation-id']) : String(positional[0]);
51
+ const resourceId = positional[1];
52
+
53
+ let contract = cachedDescription(projectDir, config.server, selectedOperation);
54
+ if (!contract) {
55
+ contract = await describeOperation(projectDir, config, session, selectedOperation);
56
+ }
57
+ if (!contract) throw new Error('DraftGo API description is missing contract revision metadata.');
58
+ const params = readParams(projectDir, flags);
59
+ if (resourceId && Object.keys(params).length === 0) {
60
+ const parameterName = pathParameterName(contract.operation);
61
+ if (!parameterName) {
62
+ log.err('The operation does not expose exactly one path parameter; provide --params JSON explicitly.');
63
+ return 1;
64
+ }
65
+ params.path = { [parameterName]: resourceId };
66
+ }
67
+ if (!flags.yes && !flags.y) {
68
+ const approved = await confirm(`Call destructive DraftGo operation ${selectedOperation}?`, { default: false });
69
+ if (!approved) return 0;
70
+ }
71
+ const invoke = () => callStructured(session, TOOL_NAMES.apiCall, {
72
+ ...params, operation_id: selectedOperation, registry_revision: contract.registry_revision, confirm: true,
73
+ });
74
+ let result;
75
+ try {
76
+ result = await invoke();
77
+ } catch (error) {
78
+ if (!isContractCompatibilityError(error)) throw error;
79
+ if (isHardContractIncompatibility(error)) throw incompatibleOperationError(selectedOperation, error);
80
+ const previousContract = contract;
81
+ const revision = await registryRevision(session, selectedOperation);
82
+ contract = await describeOperation(projectDir, config, session, selectedOperation, revision);
83
+ if (!contract) throw new Error('DraftGo API description is missing contract revision metadata.');
84
+ if (!sameOperationContract(previousContract, contract)) {
85
+ throw incompatibleOperationError(selectedOperation, error);
86
+ }
87
+ result = await invoke();
88
+ }
89
+ if (flags.output === 'json') console.log(JSON.stringify(result, null, 2));
90
+ else log.ok(`DraftGo operation completed: ${selectedOperation}`);
91
+ return 0;
92
+ }
93
+
94
+ module.exports = deleteResource;
95
+ module.exports.pathParameterName = pathParameterName;
@@ -0,0 +1,77 @@
1
+ 'use strict';
2
+
3
+ const log = require('../logger');
4
+ const check = require('./check');
5
+ const { canonicalResourceType, entryKey } = require('../worktree/types');
6
+ const { commitBatch, diffResource } = require('../worktree');
7
+ const { report, formatSummary, formatStat } = require('../diffReport');
8
+ const { absolutePath } = require('../worktree/manifest');
9
+
10
+ function targetsFrom(positional) {
11
+ const [type, ...ids] = positional;
12
+ if (!type || !ids.length) throw new Error('Specify <pages|nav|docs> <id...>.');
13
+ const resource_type = canonicalResourceType(type);
14
+ return [...new Set(ids.map(String))].map((resource_id) => ({ resource_type, resource_id }));
15
+ }
16
+
17
+ function outputResult(value, flags) {
18
+ if (flags.output === 'json') console.log(JSON.stringify(value, null, 2));
19
+ else if (value.error) {
20
+ log.err(value.error.message);
21
+ for (const message of value.validation?.content_validation?.errors || []) log.err(message);
22
+ if (value.completed?.length) log.warn('Completed resources already changed remotely; use draftgo check --remote before retrying.');
23
+ } else if (value.skipped) log.dim(value.skipped);
24
+ else log.ok(`${value.delivery}: ${value.completed?.length || 0} resource(s) completed.`);
25
+ return value.error ? 1 : 0;
26
+ }
27
+
28
+ async function deliverTargets(projectDir, targets, flags = {}, options = {}) {
29
+ const delivery = flags.delivery || 'deploy';
30
+ const validation = await check(projectDir, { strict: flags.strict, quiet: true, returnResult: true,
31
+ resourceKeys: targets?.map((item) => entryKey(item.resource_type, item.resource_id)) });
32
+ if (validation.code) return { delivery, validation, error: { code: 'VALIDATION_FAILED', message: 'Delivery stopped because local validation failed.' },
33
+ completed: [], failed: [], not_started: targets || [] };
34
+ if (delivery === 'local') return { delivery, validation, completed: [], failed: [], not_started: [] };
35
+ if (delivery === 'preview') {
36
+ const previews = targets.map((item) => {
37
+ const result = diffResource(projectDir, item.resource_type, item.resource_id);
38
+ if (!flags.stat && !flags.summary) return { changed: result.changed, entry: result.entry, diff: result.output };
39
+ return report(result.entry, [{ path: result.entry.local_path, changed: result.changed, output: result.output,
40
+ base_path: absolutePath(projectDir, result.entry.base_path), local_path: absolutePath(projectDir, result.entry.local_path) }]);
41
+ });
42
+ return { delivery, validation, previews, completed: [], failed: [], not_started: [] };
43
+ }
44
+ const statuses = [];
45
+ try {
46
+ const completed = await commitBatch(projectDir, targets, { ...options, onStatus: (item) => statuses.push(item) });
47
+ return { delivery, validation, completed, failed: [], not_started: [] };
48
+ } catch (error) {
49
+ const batch = error.details?.batch || error.details;
50
+ return { delivery, validation, error: { code: error.code || 'COMMIT_FAILED', message: error.message },
51
+ ...(Array.isArray(batch?.completed) ? batch : {
52
+ completed: statuses.filter((item) => ['committed', 'unchanged'].includes(item.status)),
53
+ failed: statuses.filter((item) => item.status === 'failed'),
54
+ not_started: statuses.length ? statuses.filter((item) => item.status === 'not_started') : targets,
55
+ }) };
56
+ }
57
+ }
58
+
59
+ async function deploy(projectDir, positional, flags = {}) {
60
+ try {
61
+ const delivery = String(flags.delivery || 'deploy').toLowerCase();
62
+ if (!['local', 'preview', 'deploy'].includes(delivery)) throw new Error('--delivery accepts local, preview, or deploy.');
63
+ const targets = positional.length || delivery !== 'local' ? targetsFrom(positional) : null;
64
+ const value = await deliverTargets(projectDir, targets, { ...flags, delivery });
65
+ if (flags.output !== 'json' && value.previews) {
66
+ for (const preview of value.previews) process.stdout.write(flags.stat ? formatStat(preview)
67
+ : flags.summary ? formatSummary(preview) : preview.diff);
68
+ return 0;
69
+ }
70
+ return outputResult(value, flags);
71
+ } catch (error) { return outputResult({ error: { code: error.code || 'DEPLOY_FAILED', message: error.message } }, flags); }
72
+ }
73
+
74
+ module.exports = deploy;
75
+ module.exports.targetsFrom = targetsFrom;
76
+ module.exports.deliverTargets = deliverTargets;
77
+ module.exports.outputResult = outputResult;
@@ -0,0 +1,39 @@
1
+ 'use strict';
2
+
3
+ const log = require('../logger');
4
+ const { diffResource } = require('../worktree');
5
+ const { report, formatSummary, formatStat } = require('../diffReport');
6
+ const { absolutePath } = require('../worktree/manifest');
7
+
8
+ function diff(projectDir, positional, flags = {}) {
9
+ const [resourceType, resourceId] = positional;
10
+ if (!resourceType || !resourceId) {
11
+ log.err('Usage: draftgo diff <pages|nav|docs> <id>');
12
+ return 1;
13
+ }
14
+ const result = diffResource(projectDir, resourceType, resourceId);
15
+ const concise = Boolean(flags.stat || flags.summary);
16
+ const value = concise ? report(result.entry, [{
17
+ path: result.entry.local_path,
18
+ changed: result.changed,
19
+ output: result.output,
20
+ base_path: absolutePath(projectDir, result.entry.base_path),
21
+ local_path: absolutePath(projectDir, result.entry.local_path),
22
+ }]) : null;
23
+ if (flags.output === 'json' && concise) {
24
+ console.log(JSON.stringify(value, null, 2));
25
+ } else if (flags.output === 'json') {
26
+ console.log(JSON.stringify({ changed: result.changed, entry: result.entry, diff: result.output }, null, 2));
27
+ } else if (flags.stat) {
28
+ process.stdout.write(formatStat(value));
29
+ } else if (flags.summary) {
30
+ process.stdout.write(formatSummary(value));
31
+ } else if (result.changed) {
32
+ process.stdout.write(result.output);
33
+ } else {
34
+ log.dim(`${result.entry.resource_type} ${result.entry.resource_id}: no local changes`);
35
+ }
36
+ return 0;
37
+ }
38
+
39
+ module.exports = diff;
@@ -0,0 +1,37 @@
1
+ 'use strict';
2
+
3
+ const log = require('../logger');
4
+ const { callOperation } = require('./api');
5
+
6
+ const OPERATIONS = Object.freeze({
7
+ list: 'listUserGroups',
8
+ create: 'createUserGroup',
9
+ get: 'getUserGroup',
10
+ update: 'updateUserGroup',
11
+ remove: 'deleteUserGroup',
12
+ 'members.list': 'listUserGroupMembers',
13
+ 'members.add': 'addUserGroupMember',
14
+ 'members.remove': 'removeUserGroupMember',
15
+ });
16
+
17
+ function operationKey(parts) {
18
+ const values = parts.map((part) => String(part || '').trim().toLowerCase()).filter(Boolean);
19
+ if (values.length === 1) return values[0] === 'delete' ? 'remove' : values[0];
20
+ if (values.length === 2 && ['member', 'members'].includes(values[0])) {
21
+ return `members.${values[1] === 'delete' ? 'remove' : values[1]}`;
22
+ }
23
+ return '';
24
+ }
25
+
26
+ async function groupCommand(projectDir, positional, flags = {}) {
27
+ const key = operationKey(positional);
28
+ if (!OPERATIONS[key]) {
29
+ log.err('Usage: draftgo group list|create|get|update|remove | members list|add|remove [--input <json-file>]');
30
+ return 1;
31
+ }
32
+ return callOperation(projectDir, OPERATIONS[key], flags);
33
+ }
34
+
35
+ module.exports = groupCommand;
36
+ module.exports.OPERATIONS = OPERATIONS;
37
+ module.exports.operationKey = operationKey;
@@ -0,0 +1,190 @@
1
+ 'use strict';
2
+
3
+ const { all } = require('../targets');
4
+ const { HOSTS } = require('../mcp/hosts');
5
+ const { getPackageVersion } = require('../skill');
6
+
7
+ function help() {
8
+ const targets = all.map((i) => ` ${i.name.padEnd(12)} ${i.displayName}`).join('\n');
9
+ const mcpTargets = HOSTS.map((host) => {
10
+ const status = host.supported === false ? 'unsupported' : host.path;
11
+ return ` ${host.name.padEnd(12)} ${status}`;
12
+ }).join('\n');
13
+
14
+ console.log(`draftgo v${getPackageVersion()} - DraftGo workbench CLI for AI coding agents
15
+
16
+ DraftGo shell baseline: React + Vite. Database Pages default to native HTML,
17
+ Tailwind CSS 4, and the DraftGo built-in component library (draftgo/*).
18
+ Provider brands and shared icons are served from the local /assets/providers and
19
+ /assets/icons directories; the Page runtime does not require third-party CDNs.
20
+ System MCP handles live discovery and structured resources; complete page,
21
+ navigation, and document bodies use checkout/commit outside MCP context.
22
+ The installed Skill routes agents to task-specific References and MCP tools.
23
+
24
+ Usage:
25
+ draftgo init [<target>...] Install the DraftGo Skill. Omit the target
26
+ to detect host-owned directories such as
27
+ .cursor or .codex, not shared files like
28
+ AGENTS.md. Use "all" for every Skill target.
29
+ draftgo update [<target>...] Refresh already installed Skills. Does not
30
+ upgrade the global CLI. An explicit target
31
+ may also install that target when missing.
32
+ draftgo uninstall <target|all> Remove Skill files. --purge also removes
33
+ the entire .draftgo/ runtime directory.
34
+ draftgo status Show connection health, Registry revision, targets, and Skill version.
35
+
36
+ draftgo connect [<target>...] Verify and save server/API Key, then configure
37
+ a detected or explicit MCP host. This never
38
+ downloads DraftGo business resources.
39
+ draftgo mcp setup [<target>...] Merge project-level stdio MCP configuration.
40
+ draftgo mcp status [<target>...] Check host configuration and secret safety.
41
+ draftgo mcp test Test project, resource, and API MCP calls.
42
+ draftgo mcp serve Bridge local stdio to the remote /mcp endpoint.
43
+
44
+ draftgo map [--type <type>] Locate bounded remote resource metadata and
45
+ overlay matching local checkout state.
46
+ Use --route/--title for exact selection.
47
+ draftgo checkout <type> <id...> Download a long-form body + verified base,
48
+ --force explicitly replaces local changes.
49
+ draftgo check Validate all checked-out content.
50
+ --remote also compares remote hash/version.
51
+ draftgo verify [<type> <id...>] Run the default delivery verification.
52
+ Browser options are explicit and optional.
53
+ draftgo diff <type> <id> Show checkout base versus local body/files.
54
+ --stat/--summary omit the full patch.
55
+ draftgo commit <type> <id...> Validate and upload complete checked-out bodies/files.
56
+ draftgo components search <query> Search the live component catalog.
57
+ draftgo components show <library/component>
58
+ Show HTML, props, slots, CSS variables and revision.
59
+ draftgo components expand --page <id> --instance <data-dg-instance>
60
+ Expand one component in a checked-out Page worktree.
61
+ draftgo components libraries list|show|create|update|delete
62
+ Manage component libraries.
63
+ draftgo components list|create|copy|delete
64
+ Manage component catalog entries.
65
+ draftgo components checkout|diff|verify|commit|publish <library/component>
66
+ Develop a component draft locally, then publish explicitly.
67
+ draftgo components import <zip> [--dry-run]
68
+ draftgo components export <library> [--file <zip>]
69
+ Transfer standard DraftGo component archives.
70
+ draftgo refresh <type> <id...> Safely refresh a clean checkout from the cloud.
71
+ draftgo reconcile <type> <id...> Repair stale metadata only when local equals remote.
72
+ draftgo conflicts List unresolved conflicts; --all includes resolved.
73
+ draftgo conflict show <type> <id>
74
+ Show preserved base/local/remote paths.
75
+ draftgo conflict resolve <type> <id>
76
+ Mark a merged worktree file ready against the
77
+ preserved remote base; then check/diff/commit.
78
+ draftgo clean [--dry-run|--yes] Plan or remove all tmp and registered artifacts.
79
+ draftgo work start <item> Add an active item to .draftgo/worklog.md.
80
+ draftgo work add <item> Add an item awaiting a decision.
81
+ draftgo work wait <ref> Mark an item waiting; --note records the reason.
82
+ draftgo work start-item <ref> Mark an item active; ref is number or date#number.
83
+ draftgo work complete <ref> Mark an item complete; --note appends evidence.
84
+ draftgo work show [<ref>] Show all history or one item with notes.
85
+ draftgo work list Latest first; --status active|waiting|completed,
86
+ --date YYYY-MM-DD, --limit 1-100 (20), --offset N.
87
+
88
+ draftgo api <query> Search the live API contract through MCP.
89
+ draftgo api search <query> Search the live operation registry explicitly.
90
+ draftgo api describe <operation_id>
91
+ Describe one live API operation through MCP.
92
+ draftgo api call <operation_id> --input <json-file>
93
+ Call one described operation with UTF-8 JSON.
94
+ draftgo capabilities list|search|show|audit
95
+ Discover and audit the current server's live operation catalog.
96
+ draftgo group <action> Manage RBAC groups and group members.
97
+ draftgo api-key status|create|update|delete|rotate
98
+ Manage the current user's API key through MCP.
99
+ draftgo role permissions|list|create|get|update|delete
100
+ Manage structured permission templates.
101
+ draftgo delete <operation_id> [id]
102
+ Confirm and call a live delete operation.
103
+ draftgo deploy [<type> <id...>] Check, then diff or commit checked-out content.
104
+ --delivery local needs no IDs; preview/deploy
105
+ require an explicit type and IDs.
106
+ draftgo auto-push [<type> <id...>]
107
+ With config.auto_push=true, check and commit
108
+ changed checkouts. Any conflict stops the run.
109
+ draftgo local setup|start|stop|logs|status
110
+ Manage the project-local Docker stack.
111
+ draftgo list-targets List Skill installation targets.
112
+ draftgo -v | --version Print CLI version.
113
+ draftgo -h | --help Show this help.
114
+
115
+ Resource types:
116
+ pages | nav/navigations | docs/articles
117
+
118
+ Important flags:
119
+ --project <dir> Operate on <dir> instead of the current directory.
120
+ --target <name,...> Select one or more MCP setup/status targets.
121
+ --server <url> (connect) DraftGo base URL.
122
+ --mcp-url <url> (connect) Explicit endpoint; standard /mcp derives the
123
+ base URL; custom paths also need --server.
124
+ --api-key <key> (connect) DraftGo user API Key for non-interactive use.
125
+ --timeout <ms> (connect/mcp test) Network timeout.
126
+ --allow-offline (connect) Save only after explicitly accepting a
127
+ failed MCP validation.
128
+ --no-mcp-setup (connect) Do not write host MCP configuration.
129
+ --force (init/checkout) Overwrite Skill or local changes.
130
+ --purge (uninstall) Also remove the .draftgo/ directory.
131
+ --skip-update-check (update) Compatibility flag; update never upgrades CLI.
132
+ --connect (init) Continue into DraftGo server connection.
133
+ --no-setup (init) Install the Skill without either setup flow.
134
+ --output json Print machine-readable output where supported.
135
+ --type <type> (map) pages | nav/navigations | docs/articles;
136
+ (capabilities) alias for a Registry module filter.
137
+ --route <path> (map) Select resources with this exact route.
138
+ --title <title> (map) Select resources with this exact title.
139
+ --limit <1-100> (map) Maximum resources returned per type/page;
140
+ defaults to 20.
141
+ --cursor <cursor> (map) Continue one typed map result page.
142
+ --summary (map/diff) Print bounded resource or change summary.
143
+ --stat (diff) Print per-file and total change statistics.
144
+ --strict Treat check warnings as failures.
145
+ --remote (check) Compare checkout hashes/versions with remote.
146
+ --yes Skip supported confirmation prompts.
147
+ --operation-id <id> (delete) Select an operation explicitly.
148
+ --params <json> (api call/delete) Pass an API parameter object.
149
+ --input <file> (api call/delete) Read a UTF-8 JSON object.
150
+ --delivery <mode> (deploy) local | preview | deploy.
151
+ --dry-run Preview supported cleanup or delivery operations.
152
+ --ui <mode> (verify) always | never; default never.
153
+ --remote (check/verify) Compare checkout hashes with remote.
154
+ --viewport <mode> (verify) mobile | desktop | both.
155
+ --frame <mode> (verify) auto | top | all | <iframe-selector>.
156
+ --token <mode> (verify) auto | never; auto appends the configured
157
+ API Key to same-origin URLs as the token query parameter.
158
+ --screenshot <mode> (verify) always | never; always alone captures a screenshot.
159
+ --browser <name> (verify) chromium | chrome | msedge.
160
+ --browser-path <file> (verify) Explicit browser executable; environment
161
+ fallback: DRAFTGO_BROWSER_PATH.
162
+ --selector <css> (verify) Require a visible element in top or iframe DOM.
163
+ --width/--height <px> (verify) Override the default 1440x900 desktop viewport.
164
+
165
+ Security:
166
+ .draftgo/config.json stores the server and API Key and is gitignored. Host MCP
167
+ files contain only "draftgo mcp serve"; they never contain the API Key.
168
+
169
+ MCP targets (project config or status):
170
+ ${mcpTargets}
171
+
172
+ Skill targets:
173
+ ${targets}
174
+
175
+ Examples:
176
+ draftgo init codex
177
+ draftgo connect codex --server https://draftgo.example --api-key <key>
178
+ draftgo mcp test
179
+ draftgo map --type pages --route /admin/channel-ops --summary --output json
180
+ draftgo checkout pages 42
181
+ draftgo verify pages 42
182
+ draftgo diff pages 42 --stat
183
+ draftgo commit pages 42
184
+ draftgo work start "Build document management and role permissions"
185
+ draftgo work complete 1 --note "Verification and delivery passed"
186
+ draftgo deploy docs 7 --delivery preview
187
+ `);
188
+ }
189
+
190
+ module.exports = help;
@@ -0,0 +1,126 @@
1
+ 'use strict';
2
+
3
+ const path = require('path');
4
+ const log = require('../logger');
5
+ const { detectTargets } = require('../detect');
6
+ const { resolveTargets, all } = require('../targets');
7
+ const { ensureRuntime, getPackageVersion } = require('../skill');
8
+ const { exists } = require('../fsx');
9
+ const { ask } = require('../prompt');
10
+
11
+ function showEnvironment() {
12
+ log.dim(` Node.js ${process.versions.node}`);
13
+ log.dim(' DraftGo resources use MCP discovery; long content uses checkout/commit.');
14
+ }
15
+
16
+ async function init(projectDir, positional, flags) {
17
+ log.title('draftgo init');
18
+ const interactive = Boolean(process.stdin.isTTY && process.stdout.isTTY) && !(flags.yes || flags.y);
19
+
20
+ // 1) Figure out which targets to install.
21
+ let resolved = [];
22
+ let unknown = [];
23
+
24
+ if (positional.length === 0) {
25
+ let hits = detectTargets(projectDir);
26
+ if (hits.length === 0) {
27
+ log.warn('未在当前项目检测到任何支持的 AI 工具目录。');
28
+ log.dim(` 支持列表:${all.map((i) => i.name).join(', ')}`);
29
+ if (!interactive) {
30
+ log.dim(' 使用 `draftgo init <target>` 手动指定,例如 `draftgo init codex`。');
31
+ return 1;
32
+ }
33
+ hits = String(await ask('请选择你的 AI 工具,例如 codex')).trim().split(/[\s,]+/);
34
+ }
35
+ ({ resolved, unknown } = resolveTargets(hits));
36
+ if (unknown.length || !resolved.length) {
37
+ log.err(`未知 target:${hits.join(', ')}`);
38
+ return 1;
39
+ }
40
+ log.info(`自动识别到:${resolved.map((r) => r.displayName).join(', ')}`);
41
+ } else {
42
+ ({ resolved, unknown } = resolveTargets(positional));
43
+ if (unknown.length) {
44
+ log.err(`未知 target:${unknown.join(', ')}`);
45
+ log.dim(` 支持列表:${all.map((i) => i.name).join(', ')}`);
46
+ return 1;
47
+ }
48
+ }
49
+
50
+ // 2) Render skill body into each target's own directory (no shared
51
+ // .draftgo/skill/ indirection anymore — each AI tool gets a real copy).
52
+ log.step('写入各 AI 工具 skill 目录(含 SKILL.md / 子技能 / references)');
53
+ ensureRuntime(projectDir);
54
+ const failures = [];
55
+ let installedCount = 0;
56
+ let skippedCount = 0;
57
+ for (const t of resolved) {
58
+ try {
59
+ const r = t.install(projectDir, { force: !!flags.force });
60
+ if (r.skipped) {
61
+ skippedCount += 1;
62
+ log.warn(`${t.displayName.padEnd(16)} 已存在,未覆盖;使用 draftgo update 或 --force 更新。`);
63
+ } else {
64
+ installedCount += 1;
65
+ log.ok(`${t.displayName.padEnd(16)} → ${r.path}`);
66
+ }
67
+ } catch (e) {
68
+ log.err(`${t.displayName} 安装失败:${e.message}`);
69
+ failures.push(t.displayName);
70
+ }
71
+ }
72
+ if (failures.length) {
73
+ log.err(`安装未完成,失败目标:${failures.join(', ')}`);
74
+ return 1;
75
+ }
76
+ if (skippedCount > 0) log.dim(' 存在未覆盖目标;运行 draftgo update 可统一刷新。');
77
+ const design = require('../projectDesign').ensureProjectDesign(projectDir);
78
+ log.info(design.created ? '已创建 Design/README.md;业务设计按需建立。' : '已保留现有 Design/README.md。');
79
+ log.dim(' 在 AI 工具中打开当前目录,描述产品需求;Agent 按 Design 和 worklog 开发。');
80
+ log.dim(` CLI 版本:${getPackageVersion()}`);
81
+
82
+ // 3) Environment check (advisory).
83
+ log.step('环境检查');
84
+ showEnvironment();
85
+
86
+ // 4) Optional server binding flow.
87
+ const cfgPath = path.join(projectDir, '.draftgo', 'config.json');
88
+ const hasConfig = exists(cfgPath);
89
+ const flagConnect = flags.connect === true;
90
+ const flagSkip = flags['no-setup'] === true;
91
+
92
+ if (!hasConfig && !flagSkip) {
93
+ // Non-interactive setup can connect immediately with a server and API Key.
94
+ if (flags.server && (flags['api-key'] || flags.token) && !flagConnect) {
95
+ return await require('./connect')(projectDir, [], flags);
96
+ }
97
+ if (flagConnect) {
98
+ return await require('./connect')(projectDir, [], flags);
99
+ }
100
+ if (interactive) {
101
+ log.title('选择 DraftGo 基座处理方式');
102
+ log.plain(` ${log.c.cyan('[A]')} 连接基座服务`);
103
+ log.dim(' 使用已有 DraftGo 服务,接下来输入 BaseURL 和系统访问令牌。');
104
+ log.plain(` ${log.c.cyan('[B]')} 本地启动基座`);
105
+ log.dim(' 使用 Docker 启动 DraftGo 和独立 Redis;按需准备 MySQL 和 Qdrant。');
106
+ log.plain(` ${log.c.cyan('[C]')} 稍后自行处理`);
107
+ log.dim(' 仅安装 Skill,不写入服务配置,也不创建容器。');
108
+ const choice = (await ask('请选择 [A/B/C]', { default: 'C' })).trim().toUpperCase();
109
+ if (choice === 'A') {
110
+ return await require('./connect')(projectDir, [], flags);
111
+ }
112
+ if (choice === 'B') {
113
+ return await require('../localRuntime').runWizard(projectDir, { yes: true, interactive: true });
114
+ }
115
+ if (choice !== 'C') {
116
+ log.warn('无效选择,已跳过基座处理。');
117
+ }
118
+ }
119
+ }
120
+
121
+ log.title('完成');
122
+ log.plain(hasConfig ? 'Skill 已安装,项目已连接 DraftGo。' : 'Skill 已安装。');
123
+ return 0;
124
+ }
125
+
126
+ module.exports = init;
@@ -0,0 +1,13 @@
1
+ 'use strict';
2
+
3
+ const { all } = require('../targets');
4
+
5
+ function listTargets() {
6
+ console.log('draftgo 支持的 AI 工具(target):');
7
+ for (const t of all) {
8
+ console.log(` ${t.name.padEnd(12)} ${t.displayName}`);
9
+ }
10
+ return 0;
11
+ }
12
+
13
+ module.exports = listTargets;