draftgo-cli 4.0.24 → 4.0.26

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 (88) hide show
  1. package/README.md +23 -37
  2. package/package.json +3 -5
  3. package/resources/skill/SKILL.md +9 -5
  4. package/resources/skill/manifest.json +2 -5
  5. package/resources/skill/references/ai.md +41 -0
  6. package/resources/skill/references/app-api.md +2 -50
  7. package/resources/skill/references/architecture.md +1 -1
  8. package/resources/skill/references/chat-sdk.md +29 -37
  9. package/resources/skill/references/checkout.md +4 -4
  10. package/resources/skill/references/data.md +0 -46
  11. package/resources/skill/references/delivery.md +3 -3
  12. package/resources/skill/references/diagnostics.md +10 -11
  13. package/resources/skill/references/frontend.md +23 -20
  14. package/resources/skill/references/mcp.md +4 -14
  15. package/resources/skill/references/methods.md +15 -68
  16. package/resources/skill/references/modules.md +23 -44
  17. package/resources/skill/references/runtime.md +3 -20
  18. package/resources/skill/story/SKILL.md +2 -2
  19. package/src/apiContractCache.js +14 -6
  20. package/src/cli.js +0 -7
  21. package/src/commandRegistry.js +0 -6
  22. package/src/commands/api.js +87 -17
  23. package/src/commands/apiKey.js +2 -6
  24. package/src/commands/autoPush.js +15 -51
  25. package/src/commands/capabilities.js +22 -15
  26. package/src/commands/check.js +19 -53
  27. package/src/commands/checkout.js +1 -4
  28. package/src/commands/clean.js +1 -1
  29. package/src/commands/commit.js +1 -4
  30. package/src/commands/components.js +12 -8
  31. package/src/commands/conflict.js +4 -6
  32. package/src/commands/conflicts.js +1 -2
  33. package/src/commands/connect.js +0 -8
  34. package/src/commands/delete.js +15 -11
  35. package/src/commands/deploy.js +64 -26
  36. package/src/commands/diff.js +1 -4
  37. package/src/commands/group.js +2 -3
  38. package/src/commands/help.js +22 -43
  39. package/src/commands/init.js +13 -6
  40. package/src/commands/local.js +4 -1
  41. package/src/commands/map.js +138 -23
  42. package/src/commands/reconcile.js +1 -15
  43. package/src/commands/role.js +1 -2
  44. package/src/commands/status.js +12 -40
  45. package/src/commands/update.js +18 -24
  46. package/src/commands/verify.js +8 -7
  47. package/src/commands/worklog.js +11 -5
  48. package/src/contractCompatibility.js +10 -2
  49. package/src/localRuntime/compose.js +41 -27
  50. package/src/localRuntime/detect.js +6 -6
  51. package/src/localRuntime/index.js +47 -47
  52. package/src/localRuntime/services.js +2 -39
  53. package/src/mcp/client.js +99 -134
  54. package/src/mcp/parallel.js +25 -2
  55. package/src/mcp/protocol.js +38 -9
  56. package/src/mcp/tools.js +10 -19
  57. package/src/projectConfig.js +1 -4
  58. package/src/{workspaceHealth.js → projectHealth.js} +5 -5
  59. package/src/projectMap.js +1 -1
  60. package/src/runtimeFiles.js +2 -1
  61. package/src/worklog.js +3 -2
  62. package/src/worktree/backend.js +127 -15
  63. package/src/worktree/index.js +64 -22
  64. package/src/worktree/locks.js +52 -0
  65. package/src/worktree/manifest.js +18 -4
  66. package/src/worktree/status.js +4 -2
  67. package/resources/custom-service-sdk/ai.go +0 -520
  68. package/resources/custom-service-sdk/ai_test.go +0 -156
  69. package/resources/custom-service-sdk/auth_test.go +0 -56
  70. package/resources/custom-service-sdk/billing.go +0 -596
  71. package/resources/custom-service-sdk/billing_test.go +0 -150
  72. package/resources/custom-service-sdk/go.mod +0 -3
  73. package/resources/custom-service-sdk/manifest.json +0 -77
  74. package/resources/custom-service-sdk/platform.go +0 -352
  75. package/resources/custom-service-sdk/platform_logger_test.go +0 -24
  76. package/resources/custom-service-sdk/registration_test.go +0 -39
  77. package/resources/custom-service-sdk/resources.go +0 -247
  78. package/resources/custom-service-sdk/resources_billing_test.go +0 -115
  79. package/resources/custom-service-sdk/resources_files_test.go +0 -57
  80. package/resources/custom-service-sdk/resources_scope_test.go +0 -92
  81. package/resources/custom-service-sdk/sdk.go +0 -209
  82. package/resources/skill/references/aihub.md +0 -116
  83. package/resources/skill/references/custom-services.md +0 -201
  84. package/src/commands/customService.js +0 -95
  85. package/src/commands/dataRange.js +0 -33
  86. package/src/commands/grant.js +0 -29
  87. package/src/commands/space.js +0 -41
  88. package/src/customServices.js +0 -484
@@ -46,7 +46,7 @@ function csv(value) {
46
46
 
47
47
  function normalizeDefinition(definition = {}) {
48
48
  return {
49
- html: definition.html || '', css: definition.css || '', js: definition.js || '',
49
+ html: definition.html || '', css: definition.css || '', js: definition.js || '', assets: definition.assets || [],
50
50
  props: definition.props || [], slots: definition.slots || [], css_variables: definition.css_variables || [],
51
51
  events: definition.events || [], dependencies: definition.dependencies || [], examples: definition.examples || [],
52
52
  usage: definition.usage || '', root_tag: definition.root_tag || '', meta: definition.meta || {},
@@ -66,12 +66,12 @@ function componentDir(projectDir, name) {
66
66
  }
67
67
 
68
68
  function contractFrom(definition = {}) {
69
- const { props, slots, css_variables, events, dependencies, examples, usage, root_tag, meta } = normalizeDefinition(definition);
70
- return { props, slots, css_variables, events, dependencies, examples, usage, root_tag, meta };
69
+ const { assets, props, slots, css_variables, events, dependencies, examples, usage, root_tag, meta } = normalizeDefinition(definition);
70
+ return { assets, props, slots, css_variables, events, dependencies, examples, usage, root_tag, meta };
71
71
  }
72
72
 
73
73
  function localDefinition(directory) {
74
- const contract = JSON.parse(fs.readFileSync(path.join(directory, 'contract.json'), 'utf8'));
74
+ const contract = JSON.parse(fs.readFileSync(path.join(directory, 'component.json'), 'utf8'));
75
75
  return normalizeDefinition({
76
76
  html: fs.readFileSync(path.join(directory, 'component.html'), 'utf8'),
77
77
  css: fs.readFileSync(path.join(directory, 'component.css'), 'utf8'),
@@ -85,12 +85,12 @@ function writeComponentFiles(directory, item) {
85
85
  fs.writeFileSync(path.join(directory, 'component.html'), item.draft.html || '', 'utf8');
86
86
  fs.writeFileSync(path.join(directory, 'component.css'), item.draft.css || '', 'utf8');
87
87
  fs.writeFileSync(path.join(directory, 'component.js'), item.draft.js || '', 'utf8');
88
- fs.writeFileSync(path.join(directory, 'contract.json'), `${JSON.stringify(contractFrom(item.draft), null, 2)}\n`, 'utf8');
89
88
  const metadata = {
90
89
  id: item.id, library_id: item.library_id, library_slug: item.library_slug,
91
90
  name: item.name, slug: item.slug, category: item.category || '', description: item.description || '',
92
91
  tags: item.tags || [], status: item.status || 'active', published_revision: item.published_revision || 0,
93
92
  remote_draft_hash: definitionHash(item.draft), updated_at: item.updated_at,
93
+ ...contractFrom(item.draft),
94
94
  };
95
95
  fs.writeFileSync(path.join(directory, 'component.json'), `${JSON.stringify(metadata, null, 2)}\n`, 'utf8');
96
96
  fs.writeFileSync(path.join(directory, '.base.json'), `${JSON.stringify(item, null, 2)}\n`, 'utf8');
@@ -231,7 +231,7 @@ async function diff(projectDir, name, flags) {
231
231
  const config = loadProjectConfig(projectDir);
232
232
  const state = localState(projectDir, name);
233
233
  const remote = await findComponent(config, name);
234
- const sections = ['html', 'css', 'js', 'props', 'slots', 'css_variables', 'events', 'dependencies', 'examples', 'usage', 'root_tag', 'meta'];
234
+ const sections = ['html', 'css', 'js', 'assets', 'props', 'slots', 'css_variables', 'events', 'dependencies', 'examples', 'usage', 'root_tag', 'meta'];
235
235
  const changed = (left, right) => {
236
236
  const normalizedLeft = normalizeDefinition(left);
237
237
  const normalizedRight = normalizeDefinition(right);
@@ -364,9 +364,13 @@ async function exportZIP(projectDir, librarySlug, flags) {
364
364
  }
365
365
  for (const summary of components) {
366
366
  const item = await request(config, 'GET', `components/${summary.id}`);
367
- const definition = `components/${item.slug}.json`;
367
+ const directory = `components/${item.slug}`;
368
+ const definition = `${directory}/component.json`;
368
369
  manifest.components.push({ name: item.name, slug: item.slug, category: item.category, description: item.description, tags: item.tags, definition });
369
- zip.addFile(definition, Buffer.from(`${JSON.stringify(item.draft, null, 2)}\n`, 'utf8'));
370
+ zip.addFile(definition, Buffer.from(`${JSON.stringify(contractFrom(item.draft), null, 2)}\n`, 'utf8'));
371
+ zip.addFile(`${directory}/component.html`, Buffer.from(item.draft.html || '', 'utf8'));
372
+ zip.addFile(`${directory}/component.css`, Buffer.from(item.draft.css || '', 'utf8'));
373
+ zip.addFile(`${directory}/component.js`, Buffer.from(item.draft.js || '', 'utf8'));
370
374
  }
371
375
  zip.addFile('draftgo-components.json', Buffer.from(`${JSON.stringify(manifest, null, 2)}\n`, 'utf8'));
372
376
  const destination = path.resolve(projectDir, flags.file || `${library.slug}-components.zip`);
@@ -15,14 +15,12 @@ function printRecord(record) {
15
15
  async function conflict(projectDir, positional, flags = {}) {
16
16
  const [action, resourceType, resourceId] = positional;
17
17
  if (!['show', 'resolve'].includes(action) || !resourceType || !resourceId) {
18
- log.err('Usage: draftgo conflict <show|resolve> <pages|nav|docs|custom-services> <id>');
18
+ log.err('Usage: draftgo conflict <show|resolve> <pages|nav|docs> <id>');
19
19
  return 1;
20
20
  }
21
- const custom = require('./customService').isServiceType(resourceType);
22
- const services = custom ? require('../customServices') : null;
23
- const record = custom
24
- ? (action === 'show' ? services.showConflict(projectDir, resourceId) : services.resolveConflict(projectDir, resourceId))
25
- : (action === 'show' ? showConflict(projectDir, resourceType, resourceId) : await resolveConflict(projectDir, resourceType, resourceId));
21
+ const record = action === 'show'
22
+ ? showConflict(projectDir, resourceType, resourceId)
23
+ : await resolveConflict(projectDir, resourceType, resourceId);
26
24
  if (flags.output === 'json') console.log(JSON.stringify(record, null, 2));
27
25
  else printRecord(record);
28
26
  if (action === 'resolve') log.info('The remote revision is now the base; run check, diff, and commit the merged worktree file.');
@@ -2,10 +2,9 @@
2
2
 
3
3
  const log = require('../logger');
4
4
  const { listConflicts } = require('../worktree');
5
- const { serviceConflicts } = require('../customServices');
6
5
 
7
6
  function conflicts(projectDir, _positional, flags = {}) {
8
- const records = [...listConflicts(projectDir, { all: Boolean(flags.all) }), ...serviceConflicts(projectDir, { all: Boolean(flags.all) })];
7
+ const records = listConflicts(projectDir, { all: Boolean(flags.all) });
9
8
  if (flags.output === 'json') console.log(JSON.stringify(records, null, 2));
10
9
  else if (!records.length) log.ok('No unresolved DraftGo conflicts.');
11
10
  else for (const record of records) {
@@ -49,16 +49,10 @@ async function connect(projectDir, positional, flags = {}) {
49
49
  return 1;
50
50
  }
51
51
  const timeoutMs = parseTimeout(flags.timeout);
52
- if ((flags['scope-type'] === 'space') !== Boolean(flags['space-id'])) {
53
- throw new Error('--scope-type space and --space-id must be provided together.');
54
- }
55
-
56
52
  log.step('Validating DraftGo API Key and MCP capabilities...');
57
53
  try {
58
54
  const diagnostic = await testConnection({ ...connection, server, token }, {
59
55
  timeoutMs,
60
- scopeType: flags['scope-type'],
61
- spaceId: flags['space-id'] && Number(flags['space-id']),
62
56
  });
63
57
  log.ok(`MCP ready (${diagnostic.tools.length} tools; tested ${diagnostic.testedCalls.join(', ')}).`);
64
58
  } catch (error) {
@@ -74,8 +68,6 @@ async function connect(projectDir, positional, flags = {}) {
74
68
 
75
69
  const configFile = writeProjectConfig(projectDir, server, token, {
76
70
  mcp_url: connection.mcp_url,
77
- scope_type: flags['scope-type'],
78
- space_id: flags['space-id'],
79
71
  });
80
72
  log.ok(`Project configuration written: ${configFile}`);
81
73
 
@@ -6,7 +6,8 @@ const log = require('../logger');
6
6
  const { confirm } = require('../prompt');
7
7
  const { loadProjectConfig } = require('../projectConfig');
8
8
  const { TOOL_NAMES, openToolSession, callStructured } = require('../mcp/tools');
9
- const { cachedDescription, normalizeDescription, storeDescription } = require('../apiContractCache');
9
+ const { cachedDescription } = require('../apiContractCache');
10
+ const { registryRevision, describeOperation } = require('./api');
10
11
  const {
11
12
  isContractCompatibilityError,
12
13
  isHardContractIncompatibility,
@@ -26,10 +27,14 @@ function readParams(projectDir, flags) {
26
27
  }
27
28
 
28
29
  function pathParameterName(description) {
29
- const source = description && (description.parameters || description.params
30
- || description.operation && description.operation.parameters) || [];
31
- const pathParameters = source.filter((parameter) => parameter && parameter.in === 'path');
32
- return pathParameters.length === 1 ? pathParameters[0].name : null;
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;
33
38
  }
34
39
 
35
40
  async function deleteResource(projectDir, positional, flags = {}) {
@@ -39,7 +44,7 @@ async function deleteResource(projectDir, positional, flags = {}) {
39
44
  }
40
45
  const config = loadProjectConfig(projectDir);
41
46
  const session = await openToolSession(config, [
42
- TOOL_NAMES.apiDescribe, TOOL_NAMES.apiCall,
47
+ TOOL_NAMES.apiSearch, TOOL_NAMES.apiDescribe, TOOL_NAMES.apiCall,
43
48
  ]);
44
49
 
45
50
  const selectedOperation = flags['operation-id'] ? String(flags['operation-id']) : String(positional[0]);
@@ -47,8 +52,7 @@ async function deleteResource(projectDir, positional, flags = {}) {
47
52
 
48
53
  let contract = cachedDescription(projectDir, config.server, selectedOperation);
49
54
  if (!contract) {
50
- const described = await callStructured(session, TOOL_NAMES.apiDescribe, { operation_id: selectedOperation });
51
- contract = storeDescription(projectDir, config.server, described) || normalizeDescription(described);
55
+ contract = await describeOperation(projectDir, config, session, selectedOperation);
52
56
  }
53
57
  if (!contract) throw new Error('DraftGo API description is missing contract revision metadata.');
54
58
  const params = readParams(projectDir, flags);
@@ -58,7 +62,7 @@ async function deleteResource(projectDir, positional, flags = {}) {
58
62
  log.err('The operation does not expose exactly one path parameter; provide --params JSON explicitly.');
59
63
  return 1;
60
64
  }
61
- params.path_params = { [parameterName]: resourceId };
65
+ params.path = { [parameterName]: resourceId };
62
66
  }
63
67
  if (!flags.yes && !flags.y) {
64
68
  const approved = await confirm(`Call destructive DraftGo operation ${selectedOperation}?`, { default: false });
@@ -74,8 +78,8 @@ async function deleteResource(projectDir, positional, flags = {}) {
74
78
  if (!isContractCompatibilityError(error)) throw error;
75
79
  if (isHardContractIncompatibility(error)) throw incompatibleOperationError(selectedOperation, error);
76
80
  const previousContract = contract;
77
- const described = await callStructured(session, TOOL_NAMES.apiDescribe, { operation_id: selectedOperation });
78
- contract = storeDescription(projectDir, config.server, described) || normalizeDescription(described);
81
+ const revision = await registryRevision(session, selectedOperation);
82
+ contract = await describeOperation(projectDir, config, session, selectedOperation, revision);
79
83
  if (!contract) throw new Error('DraftGo API description is missing contract revision metadata.');
80
84
  if (!sameOperationContract(previousContract, contract)) {
81
85
  throw incompatibleOperationError(selectedOperation, error);
@@ -2,38 +2,76 @@
2
2
 
3
3
  const log = require('../logger');
4
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');
5
9
 
6
- async function deploy(projectDir, positional, flags = {}) {
7
- const delivery = String(flags.delivery || 'deploy').toLowerCase();
8
- if (!['local', 'preview', 'deploy'].includes(delivery)) {
9
- log.err('--delivery accepts local, preview, or deploy.');
10
- return 1;
11
- }
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
+ }
12
16
 
13
- log.step('deploy: validating checked-out content...');
14
- const checkCode = await check(projectDir, { strict: flags.strict });
15
- if (checkCode !== 0) {
16
- log.err('Deploy stopped because local validation failed.');
17
- return checkCode;
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: [] };
18
43
  }
19
- if (delivery === 'local') {
20
- log.ok('Local validation passed; no remote content was changed.');
21
- return 0;
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
+ }) };
22
56
  }
57
+ }
23
58
 
24
- const [resourceType, ...ids] = positional;
25
- if (!resourceType || !ids.length) {
26
- log.err('Usage: draftgo deploy <pages|nav|docs> <id...> --delivery preview|deploy');
27
- return 1;
28
- }
29
- if (delivery === 'preview') {
30
- for (const id of ids) {
31
- const code = require('./diff')(projectDir, [resourceType, id], flags);
32
- if (code !== 0) return code;
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;
33
69
  }
34
- return 0;
35
- }
36
- return require('./commit')(projectDir, [resourceType, ...ids], flags);
70
+ return outputResult(value, flags);
71
+ } catch (error) { return outputResult({ error: { code: error.code || 'DEPLOY_FAILED', message: error.message } }, flags); }
37
72
  }
38
73
 
39
74
  module.exports = deploy;
75
+ module.exports.targetsFrom = targetsFrom;
76
+ module.exports.deliverTargets = deliverTargets;
77
+ module.exports.outputResult = outputResult;
@@ -8,12 +8,9 @@ const { absolutePath } = require('../worktree/manifest');
8
8
  function diff(projectDir, positional, flags = {}) {
9
9
  const [resourceType, resourceId] = positional;
10
10
  if (!resourceType || !resourceId) {
11
- log.err('Usage: draftgo diff <pages|nav|docs|custom-services> <id>');
11
+ log.err('Usage: draftgo diff <pages|nav|docs> <id>');
12
12
  return 1;
13
13
  }
14
- if (require('./customService').isServiceType(resourceType)) {
15
- return require('./customService').diff(projectDir, [resourceId], flags);
16
- }
17
14
  const result = diffResource(projectDir, resourceType, resourceId);
18
15
  const concise = Boolean(flags.stat || flags.summary);
19
16
  const value = concise ? report(result.entry, [{
@@ -8,8 +8,7 @@ const OPERATIONS = Object.freeze({
8
8
  create: 'createUserGroup',
9
9
  get: 'getUserGroup',
10
10
  update: 'updateUserGroup',
11
- replace: 'replaceUserGroup',
12
- remove: 'removeUserGroup',
11
+ remove: 'deleteUserGroup',
13
12
  'members.list': 'listUserGroupMembers',
14
13
  'members.add': 'addUserGroupMember',
15
14
  'members.remove': 'removeUserGroupMember',
@@ -27,7 +26,7 @@ function operationKey(parts) {
27
26
  async function groupCommand(projectDir, positional, flags = {}) {
28
27
  const key = operationKey(positional);
29
28
  if (!OPERATIONS[key]) {
30
- log.err('Usage: draftgo group list|create|get|update|replace|remove | members list|add|remove [--input <json-file>]');
29
+ log.err('Usage: draftgo group list|create|get|update|remove | members list|add|remove [--input <json-file>]');
31
30
  return 1;
32
31
  }
33
32
  return callOperation(projectDir, OPERATIONS[key], flags);
@@ -14,19 +14,22 @@ function help() {
14
14
  console.log(`draftgo v${getPackageVersion()} - DraftGo workbench CLI for AI coding agents
15
15
 
16
16
  DraftGo shell baseline: React + Vite. Database Pages default to native HTML,
17
- Tailwind CSS 4, and Basecoat UI; Oat UI remains an optional Web Components layer.
18
- MCP handles live discovery and structured resources; complete page, navigation,
19
- document, and custom-service bodies use checkout/commit outside MCP context.
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.
20
22
  The installed Skill routes agents to task-specific References and MCP tools.
21
23
 
22
24
  Usage:
23
25
  draftgo init [<target>...] Install the DraftGo Skill. No target = detect.
24
26
  Use "all" to install every Skill target.
25
- draftgo update [<target>...] Fully update the global CLI, then atomically
26
- refresh installed or detected Skills.
27
+ draftgo update [<target>...] Fully update the global CLI, then atomically
28
+ refresh installed Skills. An explicit target
29
+ may also install that target when missing.
27
30
  draftgo uninstall <target|all> Remove Skill files. --purge also removes
28
31
  the entire .draftgo/ runtime directory.
29
- draftgo status Show connection health, current scope, targets, and Skill version.
32
+ draftgo status Show connection health, Registry revision, targets, and Skill version.
30
33
 
31
34
  draftgo connect [<target>...] Verify and save server/API Key, then configure
32
35
  a detected or explicit MCP host. This never
@@ -40,10 +43,8 @@ Usage:
40
43
  overlay matching local checkout state.
41
44
  Use --route/--title for exact selection.
42
45
  draftgo checkout <type> <id...> Download a long-form body + verified base,
43
- including custom-service worktrees.
44
- --force explicitly replaces local changes.
45
- draftgo check [custom-services <id...>]
46
- Validate all checkouts or selected custom services.
46
+ --force explicitly replaces local changes.
47
+ draftgo check Validate all checked-out content.
47
48
  --remote also compares remote hash/version.
48
49
  draftgo verify [<type> <id...>] Run the default delivery verification.
49
50
  Browser options are explicit and optional.
@@ -65,13 +66,6 @@ Usage:
65
66
  draftgo components export <library> [--file <zip>]
66
67
  Transfer standard DraftGo component archives.
67
68
  draftgo refresh <type> <id...> Safely refresh a clean checkout from the cloud.
68
- draftgo validate custom-services <id>
69
- Build and inspect the current cloud draft.
70
- draftgo test custom-services <id> [--source <source>] [--input <file>] [--handler <selector>]
71
- Run the cloud draft in the DraftGo Runner.
72
- draftgo publish custom-services <id...>
73
- Publish current validated drafts; batch errors
74
- report services already completed.
75
69
  draftgo reconcile <type> <id...> Repair stale metadata only when local equals remote.
76
70
  draftgo conflicts List unresolved conflicts; --all includes resolved.
77
71
  draftgo conflict show <type> <id>
@@ -81,28 +75,25 @@ Usage:
81
75
  preserved remote base; then check/diff/commit.
82
76
  draftgo clean [--dry-run|--yes] Plan or remove all tmp and registered artifacts.
83
77
  draftgo work start <item> Add an active item to .draftgo/worklog.md.
84
- draftgo work add <item> Add a pending item.
78
+ draftgo work add <item> Add an item awaiting a decision.
79
+ draftgo work wait <ref> Mark an item waiting; --note records the reason.
85
80
  draftgo work start-item <ref> Mark an item active; ref is number or date#number.
86
81
  draftgo work complete <ref> Mark an item complete; --note appends evidence.
87
82
  draftgo work show|list Show the worklog or its structured item list.
88
83
 
89
- draftgo api <query> Search the live API contract through MCP.
84
+ draftgo api <query> Search the live API contract through MCP.
85
+ draftgo api search <query> Search the live operation registry explicitly.
90
86
  draftgo api describe <operation_id>
91
87
  Describe one live API operation through MCP.
92
88
  draftgo api call <operation_id> --input <json-file>
93
89
  Call one described operation with UTF-8 JSON.
94
90
  draftgo capabilities list|search|show|audit
95
91
  Discover and audit the current server's live operation catalog.
96
- draftgo space <action> Manage spaces and workspace members.
97
- draftgo group <action> Manage workspace groups and group members.
98
- draftgo grant list|create|get|revoke
99
- Manage platform/space AccessGrants.
100
- draftgo api-key status|create|update|delete|rotate|reset|enable|disable
92
+ draftgo group <action> Manage RBAC groups and group members.
93
+ draftgo api-key status|create|update|delete|rotate
101
94
  Manage the current user's API key through MCP.
102
95
  draftgo role permissions|list|create|get|update|delete
103
96
  Manage structured permission templates.
104
- draftgo data-range list|create|get|update|batch|delete
105
- Manage db_meta record policies (none|owner|all).
106
97
  draftgo delete <operation_id> [id]
107
98
  Confirm and call a live delete operation.
108
99
  draftgo deploy [<type> <id...>] Check, then diff or commit checked-out content.
@@ -117,8 +108,8 @@ Usage:
117
108
  draftgo -v | --version Print CLI version.
118
109
  draftgo -h | --help Show this help.
119
110
 
120
- Resource types:
121
- pages | nav/navigations | docs/articles | custom-services
111
+ Resource types:
112
+ pages | nav/navigations | docs/articles
122
113
 
123
114
  Important flags:
124
115
  --project <dir> Operate on <dir> instead of the current directory.
@@ -127,8 +118,6 @@ Important flags:
127
118
  --mcp-url <url> (connect) Explicit endpoint; standard /mcp derives the
128
119
  base URL; custom paths also need --server.
129
120
  --api-key <key> (connect) DraftGo user API Key for non-interactive use.
130
- --scope-type space --space-id <id>
131
- (connect) Save a target space for workspace resources.
132
121
  --timeout <ms> (connect/mcp test) Network timeout.
133
122
  --allow-offline (connect) Save only after explicitly accepting a
134
123
  failed MCP validation.
@@ -139,8 +128,8 @@ Important flags:
139
128
  --connect (init) Continue into DraftGo server connection.
140
129
  --no-setup (init) Install the Skill without either setup flow.
141
130
  --output json Print machine-readable output where supported.
142
- --type <type> (map) pages | nav/navigations | docs/articles |
143
- custom-services.
131
+ --type <type> (map) pages | nav/navigations | docs/articles;
132
+ (capabilities) alias for a Registry module filter.
144
133
  --route <path> (map) Select resources with this exact route.
145
134
  --title <title> (map) Select resources with this exact title.
146
135
  --limit <1-100> (map) Maximum resources returned per type/page;
@@ -153,15 +142,7 @@ Important flags:
153
142
  --yes Skip supported confirmation prompts.
154
143
  --operation-id <id> (delete) Select an operation explicitly.
155
144
  --params <json> (api call/delete) Pass an API parameter object.
156
- --input <file> (api call/delete/custom-service test) Read a UTF-8
157
- JSON object.
158
- --handler <selector> (custom-service test) route:METHOD:/path, event:name,
159
- scheduled:name, or a handler name.
160
- --source <source> (custom-service test) draft (default), auto, or published.
161
- --headers/--user <file> (custom-service test) Read JSON test identity data.
162
- --test-write (custom-service test) Permit declared write testing.
163
- --side-effect-policy <mode>
164
- (custom-service test) deny | mock | live; default deny.
145
+ --input <file> (api call/delete) Read a UTF-8 JSON object.
165
146
  --delivery <mode> (deploy) local | preview | deploy.
166
147
  --dry-run Preview supported cleanup or delivery operations.
167
148
  --ui <mode> (verify) always | never; default never.
@@ -196,8 +177,6 @@ Examples:
196
177
  draftgo verify pages 42
197
178
  draftgo diff pages 42 --stat
198
179
  draftgo commit pages 42
199
- draftgo checkout custom-services 12
200
- draftgo test custom-services 12 --handler route:POST:/health --input request.json
201
180
  draftgo work start "Build document management and role permissions"
202
181
  draftgo work complete 1 --note "Verification and delivery passed"
203
182
  draftgo deploy docs 7 --delivery preview
@@ -15,20 +15,28 @@ function showEnvironment() {
15
15
 
16
16
  async function init(projectDir, positional, flags) {
17
17
  log.title('draftgo init');
18
+ const interactive = Boolean(process.stdin.isTTY && process.stdout.isTTY) && !(flags.yes || flags.y);
18
19
 
19
20
  // 1) Figure out which targets to install.
20
21
  let resolved = [];
21
22
  let unknown = [];
22
23
 
23
24
  if (positional.length === 0) {
24
- const hits = detectTargets(projectDir);
25
+ let hits = detectTargets(projectDir);
25
26
  if (hits.length === 0) {
26
27
  log.warn('未在当前项目检测到任何支持的 AI 工具目录。');
27
- log.dim(' 使用 `draftgo init all` 或 `draftgo init <target>` 手动指定。');
28
28
  log.dim(` 支持列表:${all.map((i) => i.name).join(', ')}`);
29
- return 1;
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,]+/);
30
34
  }
31
35
  ({ resolved, unknown } = resolveTargets(hits));
36
+ if (unknown.length || !resolved.length) {
37
+ log.err(`未知 target:${hits.join(', ')}`);
38
+ return 1;
39
+ }
32
40
  log.info(`自动识别到:${resolved.map((r) => r.displayName).join(', ')}`);
33
41
  } else {
34
42
  ({ resolved, unknown } = resolveTargets(positional));
@@ -77,7 +85,6 @@ async function init(projectDir, positional, flags) {
77
85
  const hasConfig = exists(cfgPath);
78
86
  const flagConnect = flags.connect === true;
79
87
  const flagSkip = flags['no-setup'] === true;
80
- const interactive = process.stdin.isTTY && process.stdout.isTTY;
81
88
 
82
89
  if (!hasConfig && !flagSkip) {
83
90
  // Non-interactive setup can connect immediately with a server and API Key.
@@ -92,7 +99,7 @@ async function init(projectDir, positional, flags) {
92
99
  log.plain(` ${log.c.cyan('[A]')} 连接基座服务`);
93
100
  log.dim(' 使用已有 DraftGo 服务,接下来输入 BaseURL 和系统访问令牌。');
94
101
  log.plain(` ${log.c.cyan('[B]')} 本地启动基座`);
95
- log.dim(' 使用 Docker 启动 DraftGo;按需准备共享的 MySQL、Redis 和 Qdrant。');
102
+ log.dim(' 使用 Docker 启动 DraftGo 和独立 Redis;按需准备 MySQL 和 Qdrant。');
96
103
  log.plain(` ${log.c.cyan('[C]')} 稍后自行处理`);
97
104
  log.dim(' 仅安装 Skill,不写入服务配置,也不创建容器。');
98
105
  const choice = (await ask('请选择 [A/B/C]', { default: 'C' })).trim().toUpperCase();
@@ -100,7 +107,7 @@ async function init(projectDir, positional, flags) {
100
107
  return await require('./connect')(projectDir, [], flags);
101
108
  }
102
109
  if (choice === 'B') {
103
- return await require('../localRuntime').runWizard(projectDir, { yes: true });
110
+ return await require('../localRuntime').runWizard(projectDir, { yes: true, interactive: true });
104
111
  }
105
112
  if (choice !== 'C') {
106
113
  log.warn('无效选择,已跳过基座处理。');
@@ -57,7 +57,10 @@ function local(projectDir, positional, flags = {}) {
57
57
 
58
58
  switch (action) {
59
59
  case 'setup':
60
- return runWizard(projectDir, { yes: !!(flags.yes || flags.y) });
60
+ return runWizard(projectDir, {
61
+ yes: !!(flags.yes || flags.y),
62
+ ...(flags.params ? { params: flags.params } : {}),
63
+ });
61
64
  case 'start':
62
65
  return runCompose(projectDir, ['up', '-d']);
63
66
  case 'stop':