openxiangda 1.0.139 → 1.0.140

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 CHANGED
@@ -82,7 +82,7 @@ Domestic npm mirrors may lag and return an older OpenXiangda version. `openxiang
82
82
 
83
83
  Architecture-class requests are plan-gated by default. For new apps, complex pages, login/register, public/no-login access, role/data-scope design, workflow/automation, App Function, connector, notification, and external integration work, AI agents must plan first and implement only after the user confirms the design.
84
84
 
85
- High-risk implementation is also SDD-gated. New workspaces include `openspec/` by default. Before changing forms, pages, resources, functions, automations, workflows, JS_CODE nodes, runtime code, or `app-workspace.config.ts`, run `openxiangda sdd context --json`, create or continue a change with `openxiangda sdd propose <change>`, and wait for `openxiangda sdd approve <change>`. Release checks fail when high-risk targets are not covered by an approved active change; emergency releases can use `--sdd-bypass --reason "..."`, which writes `openspec/changes/bypass-log.md`.
85
+ High-risk implementation is also SDD-gated. New workspaces include OpenXiangda SDD v2 records under `openspec/` by default. Before changing forms, pages, resources, functions, automations, workflows, JS_CODE nodes, runtime code, or `app-workspace.config.ts`, run `openxiangda sdd context --json`, create or continue a change with `openxiangda sdd propose <change>`, and wait for `openxiangda sdd approve <change>`. `approve` only opens the implementation gate; release checks also require `coverage.json`, `release.json`, `evidence.md`, `tasks.md`, and delta specs to pass `openxiangda sdd verify <change> --changed`. Emergency releases can use `--sdd-bypass --reason "..."`, which writes `openspec/changes/bypass-log.md` and appends bypass evidence to the active approved change when one exists.
86
86
 
87
87
  Before confirmation, agents may read, inspect, snapshot, dry-run, ask questions, and output/write the architecture document. They must not edit source files, mutate platform resources, publish, deploy, send notifications, or call live write/delete endpoints.
88
88
 
package/lib/cli.js CHANGED
@@ -127,7 +127,7 @@ Usage:
127
127
  openxiangda doctor [--profile name] [--app-type APP_XXX] [--release] [--json]
128
128
  openxiangda contract list|explain <contract-name> [--json]
129
129
  openxiangda design gates|template|review [--topic code] [--json]
130
- openxiangda sdd init|propose|approve|status|context|verify|sync|archive [change] [--json]
130
+ openxiangda sdd init|migrate|propose|approve|status|context|verify|sync|archive [change] [--json]
131
131
  openxiangda env [--profile name]
132
132
  openxiangda workspace init [dir] [--name package-name] [--runtime legacy|react-spa] [--install] [--profile name --app-type APP_XXX]
133
133
  openxiangda workspace init [dir] --profile <name> --app-name <app-name> [--runtime legacy|react-spa] [--install]
@@ -531,26 +531,28 @@ async function sdd(args) {
531
531
  const { flags, positional } = parseArgs(rest);
532
532
  if (wantsSubcommandHelp(subcommand, flags)) {
533
533
  print([
534
- '用法: openxiangda sdd init|propose|approve|status|context|verify|sync|archive [change] [--json]',
534
+ '用法: openxiangda sdd init|migrate|propose|approve|status|context|verify|sync|archive [change] [--json]',
535
535
  '常用流程:',
536
- ' openxiangda sdd init',
537
- ' openxiangda sdd propose add-customer-list --title "客户列表" --forms customer --pages customer_list',
536
+ ' openxiangda sdd init --upgrade',
537
+ ' openxiangda sdd propose add-customer-list --title "客户列表" --forms customer --pages customer_list --resources',
538
538
  ' openxiangda sdd approve add-customer-list --summary "用户确认设计"',
539
539
  ' openxiangda sdd context --json',
540
540
  ' openxiangda sdd verify add-customer-list --changed --json',
541
541
  ' openxiangda sdd archive add-customer-list',
542
542
  '说明:',
543
543
  ' - SDD 记录保存在 openspec/,不依赖官方 OpenSpec CLI。',
544
- ' - 高风险发布需要 approved change 覆盖本次 forms/pages/resources/runtime 目标。',
544
+ ' - 新工作区使用 openxiangda-sdd-v2:proposal/specs/design/tasks/evidence 给人读,coverage.json/release.json 给 CLI 校验。',
545
+ ' - 高风险发布需要 approved change 的 coverage 覆盖本次 forms/pages/resources/runtime 目标和高风险文件。',
545
546
  ].join('\n'));
546
547
  return;
547
548
  }
548
549
 
549
- if (subcommand === 'init') {
550
+ if (subcommand === 'init' || subcommand === 'migrate' || subcommand === 'upgrade') {
550
551
  const result = initSddWorkspace({
551
552
  cwd: process.cwd(),
552
553
  path: flags.path,
553
554
  force: Boolean(flags.force),
555
+ upgrade: Boolean(flags.upgrade || subcommand === 'migrate' || subcommand === 'upgrade'),
554
556
  });
555
557
  if (flags.json) return writeJson(result);
556
558
  printSddInitReport(result);
@@ -586,13 +588,17 @@ async function sdd(args) {
586
588
  }
587
589
 
588
590
  if (subcommand === 'status' || subcommand === 'context') {
589
- const status = buildSddStatus({ cwd: process.cwd(), configText: readWorkspaceConfigText() });
590
591
  const releasePlan = buildWorkspaceReleasePlan({
591
592
  changed: Boolean(flags.changed || flags['changed-only']),
592
593
  since: flags.since,
593
594
  profile: flags.profile || '<profile>',
594
595
  skipSdd: true,
595
596
  });
597
+ const status = buildSddStatus({
598
+ cwd: process.cwd(),
599
+ configText: readWorkspaceConfigText(),
600
+ releasePlan,
601
+ });
596
602
  const result = {
597
603
  ...status,
598
604
  releasePlan,
@@ -667,7 +673,7 @@ async function sdd(args) {
667
673
  return;
668
674
  }
669
675
 
670
- fail('用法: openxiangda sdd init|propose|approve|status|context|verify|sync|archive [change] [--json]');
676
+ fail('用法: openxiangda sdd init|migrate|propose|approve|status|context|verify|sync|archive [change] [--json]');
671
677
  }
672
678
 
673
679
  function parseSddAffectedFlags(flags) {
@@ -681,6 +687,11 @@ function parseSddAffectedFlags(flags) {
681
687
  return {
682
688
  forms: split(flags.forms || flags.form),
683
689
  pages: split(flags.pages || flags.page),
690
+ functions: split(flags.functions || flags.function),
691
+ automations: split(flags.automations || flags.automation),
692
+ workflows: split(flags.workflows || flags.workflow),
693
+ jsCodeNodes: split(flags['js-code-nodes'] || flags.jsCodeNodes || flags['js-code']),
694
+ files: split(flags.files || flags.file),
684
695
  resources: Boolean(flags.resources),
685
696
  runtime: Boolean(flags.runtime),
686
697
  backend: Boolean(flags.backend),
@@ -689,7 +700,7 @@ function parseSddAffectedFlags(flags) {
689
700
  }
690
701
 
691
702
  function printSddInitReport(result) {
692
- const lines = [`OpenXiangda SDD initialized: ${result.path}`];
703
+ const lines = [`OpenXiangda SDD initialized: ${result.path}`, `schemaVersion: ${result.schemaVersion || 'unknown'}`];
693
704
  for (const op of result.operations) {
694
705
  lines.push(`- ${op.action}: ${op.path}`);
695
706
  }
@@ -700,12 +711,18 @@ function printSddStatusReport(result) {
700
711
  const lines = [
701
712
  `OpenXiangda SDD status: ${result.governance.initialized ? 'initialized' : 'not initialized'}`,
702
713
  `path: ${result.governance.path}`,
714
+ `schemaVersion: ${result.schemaVersion || result.governance.schemaVersion || 'unknown'}`,
703
715
  `strictHighRisk: ${result.governance.strictHighRisk ? 'true' : 'false'}`,
704
716
  `active changes: ${result.activeChanges.length}`,
705
717
  ];
706
718
  for (const change of result.activeChanges) {
707
719
  lines.push(`- ${change.id}: ${change.status}${change.approvedAt ? ` approvedAt=${change.approvedAt}` : ''}`);
708
720
  }
721
+ if (result.activeChange) lines.push(`activeChange: ${result.activeChange.id}`);
722
+ if (result.blockingErrors?.length) {
723
+ lines.push('blockingErrors:');
724
+ for (const error of result.blockingErrors) lines.push(`- ${error.name}: ${error.message}`);
725
+ }
709
726
  if (result.bypassLog) lines.push(`bypass log: ${result.bypassLog}`);
710
727
  print(lines.join('\n'));
711
728
  }
@@ -714,6 +731,7 @@ function printSddVerifyReport(result) {
714
731
  const lines = [
715
732
  `OpenXiangda SDD verify: ${result.passed ? 'passed' : 'failed'}`,
716
733
  `change: ${result.change.id}`,
734
+ `schemaVersion: ${result.schemaVersion || result.change.schemaVersion || 'unknown'}`,
717
735
  ];
718
736
  if (result.errors.length > 0) {
719
737
  lines.push('Errors:');
@@ -4629,7 +4647,10 @@ async function resource(args) {
4629
4647
  assertSddReleaseGate(
4630
4648
  buildExplicitSddReleasePlan(
4631
4649
  { forms: [], pages: [], resources: true, runtime: false, other: [] },
4632
- { files: getWorkspaceChangedFiles() }
4650
+ {
4651
+ files: getWorkspaceChangedFiles(),
4652
+ commands: [`openxiangda resource publish --profile ${profileName}`],
4653
+ }
4633
4654
  ),
4634
4655
  flags,
4635
4656
  'openxiangda resource publish'
@@ -4696,7 +4717,10 @@ async function runtime(args) {
4696
4717
  assertSddReleaseGate(
4697
4718
  buildExplicitSddReleasePlan(
4698
4719
  { forms: [], pages: [], resources: false, runtime: true, other: [] },
4699
- { files: getWorkspaceChangedFiles() }
4720
+ {
4721
+ files: getWorkspaceChangedFiles(),
4722
+ commands: [`openxiangda runtime deploy --profile ${target.profileName}`],
4723
+ }
4700
4724
  ),
4701
4725
  flags,
4702
4726
  'openxiangda runtime deploy'
@@ -5313,7 +5337,7 @@ async function commands(args) {
5313
5337
  'doctor [--profile name] [--app-type APP_XXX] [--release]',
5314
5338
  'contract list|explain <contract-name>',
5315
5339
  'design gates|template|review [--topic code]',
5316
- 'sdd init|propose|approve|status|context|verify|sync|archive',
5340
+ 'sdd init|migrate|propose|approve|status|context|verify|sync|archive',
5317
5341
  'env',
5318
5342
  'workspace init|bind|plan|check|publish [--app-name] [--changed|--since|--form|--page|--only|--dry-run|--force|--resources|--skip-resources|--prune]',
5319
5343
  'app list|create|snapshot',
@@ -5347,7 +5371,7 @@ async function commands(args) {
5347
5371
  'public-access is the new React SPA public policy resource for /view/:appType/public/* routes; page code should use PublicAccessGate, and Page SDK hooks must stay inside OpenXiangdaProvider + OpenXiangdaPageProvider.',
5348
5372
  'settings public-access is legacy form public-access compatibility/repair and should not be used for new React SPA apps.',
5349
5373
  'Direct live mutation commands should use --dry-run first and --write-manifest when the repository should remain source of truth.',
5350
- 'OpenXiangda native SDD uses openspec/ records; high-risk publishes require an approved change unless --sdd-bypass --reason is used.',
5374
+ 'OpenXiangda native SDD uses openspec/ records; high-risk publishes require an approved change with coverage.json/release.json verification unless --sdd-bypass --reason is used.',
5351
5375
  ],
5352
5376
  };
5353
5377
  if (flags.json) return writeJson(manifest);
@@ -12367,6 +12391,7 @@ function buildWorkspaceReleasePlan(options = {}) {
12367
12391
  ? getWorkspaceChangedFiles({ since: options.since })
12368
12392
  : getAllWorkspaceSourceFiles();
12369
12393
  const targets = classifyWorkspaceFiles(files, runtimeMode);
12394
+ if (options.includeResources) targets.resources = true;
12370
12395
  const issues = scanWorkspaceReliabilityIssues(files);
12371
12396
  const errors = issues
12372
12397
  .filter(issue => issue.severity === 'error')
@@ -12382,6 +12407,7 @@ function buildWorkspaceReleasePlan(options = {}) {
12382
12407
  configText,
12383
12408
  targets,
12384
12409
  files,
12410
+ commands,
12385
12411
  });
12386
12412
  const sddErrors = sdd ? sdd.errors.map(error => ({ name: error.name, message: error.message })) : [];
12387
12413
  const checks = [
@@ -12471,14 +12497,17 @@ function printWorkspaceReleasePlan(plan) {
12471
12497
 
12472
12498
  function buildExplicitSddReleasePlan(targets, options = {}) {
12473
12499
  const configText = readWorkspaceConfigText();
12500
+ const commands = options.commands || [];
12474
12501
  const sdd = buildSddGovernanceReport({
12475
12502
  cwd: process.cwd(),
12476
12503
  configText,
12477
12504
  targets,
12478
12505
  files: options.files || [],
12506
+ commands,
12479
12507
  });
12480
12508
  return {
12481
12509
  targets,
12510
+ commands,
12482
12511
  sdd,
12483
12512
  errors: sdd.errors.map(error => ({ name: error.name, message: error.message })),
12484
12513
  };
@@ -12503,15 +12532,12 @@ function assertSddReleaseGate(plan, flags, command) {
12503
12532
 
12504
12533
  function buildWorkspacePublishSddPlan(publishOptions, runtimeMode, profile) {
12505
12534
  if (publishOptions.changed || (!publishOptions.targetForm && !publishOptions.targetPage && !publishOptions.only)) {
12506
- const plan = buildWorkspaceReleasePlan({
12535
+ return buildWorkspaceReleasePlan({
12507
12536
  changed: publishOptions.changed,
12508
12537
  since: publishOptions.since,
12509
12538
  profile,
12539
+ includeResources: publishOptions.includeResources,
12510
12540
  });
12511
- if (publishOptions.includeResources) {
12512
- plan.targets.resources = true;
12513
- }
12514
- return plan;
12515
12541
  }
12516
12542
  const targets = {
12517
12543
  forms: [],
@@ -12536,7 +12562,7 @@ function buildWorkspacePublishSddPlan(publishOptions, runtimeMode, profile) {
12536
12562
  targets.forms = unique(targets.forms).sort();
12537
12563
  targets.pages = unique(targets.pages).sort();
12538
12564
  const commands = buildWorkspaceReleaseCommands(targets, runtimeMode, profile);
12539
- const sddPlan = buildExplicitSddReleasePlan(targets, { files: [] });
12565
+ const sddPlan = buildExplicitSddReleasePlan(targets, { files: [], commands });
12540
12566
  return {
12541
12567
  workspace: {
12542
12568
  cwd: process.cwd(),