openxiangda 1.0.93 → 1.0.95

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/lib/cli.js CHANGED
@@ -237,6 +237,10 @@ async function update(args) {
237
237
  const requestedSubcommand = args[0] && !args[0].startsWith('--') ? args[0] : 'check';
238
238
  const parsedArgs = requestedSubcommand === args[0] ? args.slice(1) : args;
239
239
  const { flags } = parseArgs(parsedArgs);
240
+ if (wantsSubcommandHelp(requestedSubcommand, flags)) {
241
+ print('用法: openxiangda update check|install [--json] [--registry https://registry.npmjs.org] [--no-skills]');
242
+ return;
243
+ }
240
244
  const registry = normalizeNpmRegistry(flags.registry || OFFICIAL_NPM_REGISTRY);
241
245
 
242
246
  if (requestedSubcommand === 'check') {
@@ -457,8 +461,12 @@ async function design(args) {
457
461
 
458
462
  async function doctor(args) {
459
463
  const { flags } = parseArgs(args);
464
+ if (flags.help || flags.h) {
465
+ print('用法: openxiangda doctor [--profile name] [--app-type APP_XXX] [--agent codex] [--json]');
466
+ return;
467
+ }
460
468
  const config = loadConfig();
461
- const profileName = flags.profile || config.currentProfile;
469
+ const profileName = resolveDoctorProfileName(config, flags);
462
470
  const result = {
463
471
  cli: {
464
472
  version: CURRENT_VERSION,
@@ -553,6 +561,24 @@ async function doctor(args) {
553
561
  printDoctorReport(result);
554
562
  }
555
563
 
564
+ function resolveDoctorProfileName(config, flags) {
565
+ if (flags.profile) return flags.profile;
566
+ const state = loadProjectState();
567
+ const boundEntries = Object.entries(state.profiles || {}).filter(([, bound]) => bound?.appType);
568
+ const requestedAppType = flags['app-type'];
569
+ if (requestedAppType) {
570
+ const matched = boundEntries.find(([, bound]) => bound.appType === requestedAppType);
571
+ if (matched) return matched[0];
572
+ }
573
+ if (config.currentProfile && state.profiles?.[config.currentProfile]?.appType) {
574
+ return config.currentProfile;
575
+ }
576
+ if (boundEntries.length === 1) {
577
+ return boundEntries[0][0];
578
+ }
579
+ return config.currentProfile;
580
+ }
581
+
556
582
  function printDoctorReport(result) {
557
583
  const lines = [
558
584
  `OpenXiangda doctor v${result.cli.version}`,
@@ -577,6 +603,10 @@ function printDoctorReport(result) {
577
603
  async function platform(args) {
578
604
  const [subcommand, ...rest] = args;
579
605
  const { flags, positional } = parseArgs(rest);
606
+ if (wantsSubcommandHelp(subcommand, flags)) {
607
+ print('用法: openxiangda platform add|list|use|remove');
608
+ return;
609
+ }
580
610
  const config = loadConfig();
581
611
 
582
612
  if (subcommand === 'add') {
@@ -652,6 +682,16 @@ async function platform(args) {
652
682
 
653
683
  async function login(args) {
654
684
  const { flags, positional } = parseArgs(args);
685
+ if (
686
+ flags.help ||
687
+ flags.h ||
688
+ positional[0] === 'help' ||
689
+ positional[0] === '--help' ||
690
+ positional[0] === '-h'
691
+ ) {
692
+ print('用法: openxiangda login <platform-url> [--profile name] [--no-open] [--json]');
693
+ return;
694
+ }
655
695
  const config = loadConfig();
656
696
  const rawUrl = positional[0];
657
697
  const profileName = flags.profile || config.currentProfile || 'default';
@@ -765,6 +805,10 @@ function normalizePlatformSessionUrl(value, baseUrl) {
765
805
  async function auth(args) {
766
806
  const [subcommand, ...rest] = args;
767
807
  const { flags } = parseArgs(rest);
808
+ if (wantsSubcommandHelp(subcommand, flags)) {
809
+ print('用法: openxiangda auth status|refresh|logout [--profile name] [--json]');
810
+ return;
811
+ }
768
812
 
769
813
  if (subcommand === 'status') {
770
814
  const config = loadConfig();
@@ -819,6 +863,10 @@ async function auth(args) {
819
863
 
820
864
  async function env(args) {
821
865
  const { flags } = parseArgs(args);
866
+ if (flags.help || flags.h) {
867
+ print('用法: openxiangda env [--profile name] [--json]');
868
+ return;
869
+ }
822
870
  const config = loadConfig();
823
871
  const globalEnv = loadGlobalEnv();
824
872
  const profileName = flags.profile || config.currentProfile;
@@ -856,6 +904,12 @@ async function env(args) {
856
904
  async function feedback(args) {
857
905
  const [subcommand, ...rest] = args;
858
906
  const { flags, positional } = parseArgs(rest);
907
+ if (wantsSubcommandHelp(subcommand, flags)) {
908
+ print(
909
+ '用法: openxiangda feedback preview|submit --summary <text> [--type bug] [--severity medium] [--profile name] [--yes] [--json]'
910
+ );
911
+ return;
912
+ }
859
913
 
860
914
  if (subcommand !== 'preview' && subcommand !== 'submit') {
861
915
  fail(
@@ -1279,6 +1333,10 @@ function summarizeOssEnv(globalEnv) {
1279
1333
  async function workspace(args) {
1280
1334
  const [subcommand, ...rest] = args;
1281
1335
  const { flags, positional } = parseArgs(rest);
1336
+ if (wantsSubcommandHelp(subcommand, flags)) {
1337
+ print('用法: openxiangda workspace init|bind|publish [--changed [--since ref]|--form code|--page code|--only list] [--dry-run] [--force] [--resources|--skip-resources]');
1338
+ return;
1339
+ }
1282
1340
  const config = loadConfig();
1283
1341
 
1284
1342
  if (subcommand === 'init') {
@@ -1411,6 +1469,10 @@ async function workspace(args) {
1411
1469
  async function app(args) {
1412
1470
  const [subcommand, ...rest] = args;
1413
1471
  const { flags, positional } = parseArgs(rest);
1472
+ if (wantsSubcommandHelp(subcommand, flags)) {
1473
+ print('用法: openxiangda app list|create|snapshot [--profile name] [--json]');
1474
+ return;
1475
+ }
1414
1476
  const config = loadConfig();
1415
1477
  const profileName = flags.profile || config.currentProfile;
1416
1478
 
@@ -1481,6 +1543,10 @@ function extractCreatedAppType(data) {
1481
1543
  async function form(args) {
1482
1544
  const [subcommand, ...rest] = args;
1483
1545
  const { flags, positional } = parseArgs(rest);
1546
+ if (wantsSubcommandHelp(subcommand, flags)) {
1547
+ print('用法: openxiangda form list|create|bind|pull|publish [--profile name] [--json]');
1548
+ return;
1549
+ }
1484
1550
  const config = loadConfig();
1485
1551
  const profileName = flags.profile || config.currentProfile;
1486
1552
 
@@ -1589,6 +1655,10 @@ async function form(args) {
1589
1655
  async function page(args) {
1590
1656
  const [subcommand, ...rest] = args;
1591
1657
  const { flags, positional } = parseArgs(rest);
1658
+ if (wantsSubcommandHelp(subcommand, flags)) {
1659
+ print('用法: openxiangda page list|publish|bind|releases|activate [--profile name] [--json]');
1660
+ return;
1661
+ }
1592
1662
  const config = loadConfig();
1593
1663
  const profileName = flags.profile || config.currentProfile;
1594
1664
 
@@ -1709,6 +1779,10 @@ async function page(args) {
1709
1779
  async function menu(args) {
1710
1780
  const [subcommand, ...rest] = args;
1711
1781
  const { flags, positional } = parseArgs(rest);
1782
+ if (wantsSubcommandHelp(subcommand, flags)) {
1783
+ print('用法: openxiangda menu list|create|update|sort|bind|delete [--profile name] [--json]');
1784
+ return;
1785
+ }
1712
1786
  const config = loadConfig();
1713
1787
  const profileName = flags.profile || config.currentProfile;
1714
1788
 
@@ -2794,6 +2868,12 @@ async function notification(args) {
2794
2868
  async function permission(args) {
2795
2869
  const [subcommand, ...rest] = args;
2796
2870
  const { flags, positional } = parseArgs(rest);
2871
+ if (wantsSubcommandHelp(subcommand, flags)) {
2872
+ print(
2873
+ '用法: openxiangda permission role-list|role-create|role-update|role-delete|role-bind|role-users|role-add-users|page-group-list|page-group-create|page-group-update|page-group-delete|page-group-bind|form-group-list|form-group-create|form-group-update|form-group-delete|form-group-bind|form-summary|menu-permissions|audit'
2874
+ );
2875
+ return;
2876
+ }
2797
2877
  const config = loadConfig();
2798
2878
  const profileName = flags.profile || config.currentProfile;
2799
2879
 
@@ -3246,6 +3326,12 @@ async function permission(args) {
3246
3326
  async function settings(args) {
3247
3327
  const [subcommand, ...rest] = args;
3248
3328
  const { flags, positional } = parseArgs(rest);
3329
+ if (wantsSubcommandHelp(subcommand, flags)) {
3330
+ print(
3331
+ '用法: openxiangda settings get|save|indexes|indexes-save|data-management|data-management-save|public-access|public-access-save|public-access-delete'
3332
+ );
3333
+ return;
3334
+ }
3249
3335
  const config = loadConfig();
3250
3336
  const profileName = flags.profile || config.currentProfile;
3251
3337
 
@@ -3841,6 +3927,16 @@ function formatBytes(value) {
3841
3927
  async function inspect(args) {
3842
3928
  const [subcommand, ...rest] = args;
3843
3929
  const { flags, positional } = parseArgs(rest);
3930
+ if (
3931
+ subcommand === 'help' ||
3932
+ subcommand === '--help' ||
3933
+ subcommand === '-h' ||
3934
+ flags.help ||
3935
+ flags.h
3936
+ ) {
3937
+ print('用法: openxiangda inspect app|form|workflow|automation|permissions [--profile name] [--json]');
3938
+ return;
3939
+ }
3844
3940
  const config = loadConfig();
3845
3941
  const profileName = flags.profile || config.currentProfile;
3846
3942
 
@@ -3947,6 +4043,7 @@ async function commands(args) {
3947
4043
  'permission form-group-list|form-group-create|form-group-update|form-group-delete|form-group-bind|form-summary|menu-permissions',
3948
4044
  'settings get|save|indexes|indexes-save|data-management|data-management-save|public-access|public-access-save|public-access-delete',
3949
4045
  'resource validate|plan|publish|pull|typegen|explain',
4046
+ 'runtime deploy|releases|activate',
3950
4047
  'inspect app|form|workflow|automation|permissions',
3951
4048
  'feedback preview|submit',
3952
4049
  'skill install|status|bootstrap',
@@ -3980,6 +4077,10 @@ function printWorkspaceInitReport(result) {
3980
4077
  async function skill(args) {
3981
4078
  const [subcommand, ...rest] = args;
3982
4079
  const { flags, positional } = parseArgs(rest);
4080
+ if (wantsSubcommandHelp(subcommand, flags)) {
4081
+ print('用法: openxiangda skill install|status [--agent codex|claude|qoder|dual] [--dest <skills-dir>] [--force] [--dry-run] [--json]\n openxiangda skill bootstrap [<dir>] [--force] [--dry-run] [--json]');
4082
+ return;
4083
+ }
3983
4084
  const options = {
3984
4085
  agent: flags.agent || 'codex',
3985
4086
  dest: flags.dest,
@@ -4965,6 +5066,9 @@ function validateWorkspaceResources(manifest) {
4965
5066
  const errors = [];
4966
5067
  const warnings = [];
4967
5068
  const counts = {};
5069
+ if (!fs.existsSync(manifest.baseDir)) {
5070
+ warnings.push('未发现 src/resources;多资源正式开发请在该目录声明资源,或使用一等 CLI 子命令进行只读诊断/小步维护');
5071
+ }
4968
5072
  for (const spec of RESOURCE_SPECS) {
4969
5073
  const items = manifest[spec.key] || [];
4970
5074
  counts[spec.key] = items.length;
@@ -219,15 +219,77 @@ const DESIGN_GATE_TOPICS = [
219
219
  },
220
220
  ];
221
221
 
222
+ const DESIGN_GATE_TOPIC_ALIASES = {
223
+ app: 'new-app',
224
+ application: 'new-app',
225
+ dashboard: 'complex-page',
226
+ page: 'complex-page',
227
+ pages: 'complex-page',
228
+ login: 'auth',
229
+ register: 'auth',
230
+ registration: 'auth',
231
+ sso: 'auth',
232
+ public: 'public-access',
233
+ guest: 'public-access',
234
+ visitor: 'public-access',
235
+ visitors: 'public-access',
236
+ permission: 'permissions',
237
+ role: 'permissions',
238
+ roles: 'permissions',
239
+ workflow: 'workflow-automation',
240
+ automation: 'workflow-automation',
241
+ function: 'workflow-automation',
242
+ functions: 'workflow-automation',
243
+ 'app-function': 'workflow-automation',
244
+ js_code: 'workflow-automation',
245
+ jscode: 'workflow-automation',
246
+ connector: 'connector-notification',
247
+ connectors: 'connector-notification',
248
+ notification: 'connector-notification',
249
+ notifications: 'connector-notification',
250
+ integration: 'connector-notification',
251
+ integrations: 'connector-notification',
252
+ webhook: 'connector-notification',
253
+ resource: 'resource-maintenance',
254
+ resources: 'resource-maintenance',
255
+ maintenance: 'resource-maintenance',
256
+ };
257
+
258
+ function resolveTopicSelection(topicCode) {
259
+ if (!topicCode || topicCode === 'all') {
260
+ return { requested: ['all'], wanted: null, unknown: [] };
261
+ }
262
+ const knownCodes = new Set(DESIGN_GATE_TOPICS.map(topic => topic.code));
263
+ const requested = String(topicCode)
264
+ .split(/[,/|+\s]+/)
265
+ .map(item => item.trim())
266
+ .filter(Boolean);
267
+ const wanted = new Set();
268
+ const unknown = [];
269
+ for (const item of requested) {
270
+ const normalized = item.toLowerCase();
271
+ const code = DESIGN_GATE_TOPIC_ALIASES[normalized] || normalized;
272
+ if (knownCodes.has(code)) {
273
+ wanted.add(code);
274
+ } else {
275
+ unknown.push(item);
276
+ }
277
+ }
278
+ return { requested, wanted, unknown };
279
+ }
280
+
222
281
  function selectTopics(topicCode) {
223
- if (!topicCode || topicCode === 'all') return DESIGN_GATE_TOPICS;
224
- const wanted = new Set(String(topicCode).split(',').map(item => item.trim()).filter(Boolean));
225
- return DESIGN_GATE_TOPICS.filter(topic => wanted.has(topic.code));
282
+ const selection = resolveTopicSelection(topicCode);
283
+ if (!selection.wanted) return DESIGN_GATE_TOPICS;
284
+ return DESIGN_GATE_TOPICS.filter(topic => selection.wanted.has(topic.code));
226
285
  }
227
286
 
228
287
  function getDesignGates(topicCode) {
288
+ const selection = resolveTopicSelection(topicCode);
229
289
  return {
230
290
  hardRule: DESIGN_GATE_HARD_RULE,
291
+ requestedTopics: selection.requested,
292
+ unknownTopics: selection.unknown,
231
293
  topics: selectTopics(topicCode),
232
294
  };
233
295
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openxiangda",
3
- "version": "1.0.93",
3
+ "version": "1.0.95",
4
4
  "description": "OpenXiangda CLI, workspace build tools, runtime SDK, and form components.",
5
5
  "private": false,
6
6
  "bin": {
@@ -67,6 +67,7 @@
67
67
  "test:resource-plan": "node scripts/resource-plan-smoke.mjs",
68
68
  "test:design-gates": "node scripts/design-gates-smoke.mjs",
69
69
  "test:resource-cli": "node scripts/resource-cli-smoke.mjs",
70
+ "test:help-no-side-effects": "node scripts/help-no-side-effects-smoke.mjs",
70
71
  "test:app-function-fallback": "node scripts/app-function-source-fallback-smoke.mjs",
71
72
  "test:runtime-deploy": "node scripts/runtime-deploy-smoke.mjs",
72
73
  "test:skill-install": "bash scripts/skill-install-smoke.sh",