openxiangda 1.0.231 → 1.0.232

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.
@@ -183,32 +183,16 @@ function buildNextSteps(targetDir, installedDependencies, bound, runtime) {
183
183
  }
184
184
  const profileArg = bound ? bound.profile : '<name>';
185
185
  steps.push(`openxiangda env --profile ${profileArg}`);
186
- steps.push('初始化并 push 权威 <main-branch>;此 canonical 检出以后只用于集成和发布');
187
186
  steps.push(
188
- `git worktree add ../${path.basename(targetDir)}-<change> -b codex/<change> origin/<main-branch>`
187
+ '完成应用开发后运行 openxiangda check --environment preproduction'
189
188
  );
190
- steps.push(`cd ../${path.basename(targetDir)}-<change>`);
191
- steps.push('openxiangda sdd propose <change>');
192
- steps.push('完成开发、测试、approve 并提交 codex/<change>,不要从 feature worktree 发布');
189
+ steps.push('openxiangda deploy preproduction --json');
193
190
  steps.push(
194
- `cd ${targetDir} && git merge --no-ff codex/<change> && git push origin <main-branch>`
191
+ '从预发结果复制 packageDigest,然后运行 openxiangda deploy production --package <packageDigest>'
195
192
  );
196
193
  steps.push(
197
- 'openxiangda sdd bundle <release-change> --changes <change-a,change-b>'
194
+ '失败时运行 openxiangda status <runId>,修复外部原因后运行 openxiangda retry <runId>'
198
195
  );
199
- steps.push(
200
- 'git add openspec/changes/<release-change> && git commit -m "chore: prepare <release-change>" && git push origin <main-branch>'
201
- );
202
- steps.push(
203
- runtime === 'react-spa'
204
- ? `openxiangda runtime deploy --no-activate --change <release-change> --profile ${profileArg}`
205
- : `openxiangda workspace publish --dry-run --only <exact-codes> --change <release-change> --profile ${profileArg}`
206
- );
207
- steps.push(
208
- `原子激活后运行 openxiangda release integration-status --change <release-change> --profile ${profileArg} --check,再运行 openxiangda release end --change <release-change> --profile ${profileArg}`
209
- );
210
- steps.push('openxiangda workspace cleanup');
211
- steps.push('确认所有目标均为 SAFE 后运行 openxiangda workspace cleanup --apply');
212
196
  return steps;
213
197
  }
214
198
 
@@ -3,13 +3,33 @@ name: openxiangda
3
3
  description: "Use OpenXiangda for private low-code platform work: app workspaces, forms, pages, resources, functions, automations, workflows, permissions, publishing, deployment, diagnosis, profiles, and the openxiangda CLI."
4
4
  ---
5
5
 
6
- <!-- OpenXiangda-Policy-Version: 4 -->
6
+ <!-- OpenXiangda-Policy-Version: 5 -->
7
7
  # OpenXiangda
8
8
 
9
9
  OpenXiangda connects an AI coding workspace to the private low-code platform through a normal-user profile and `/openxiangda-api/v1`. External backends using AK/SK are a separate `openxiangda-open-api` flow.
10
10
 
11
11
  This file is a router and safety card. Read only the one or two subskills selected below; do not load every OpenXiangda reference into the same turn.
12
12
 
13
+ ## Delivery V2 is the normal release path
14
+
15
+ When `app-workspace.config.ts` declares `deliveryVersion: 2`, all later V1 SDD,
16
+ Git-mainline, candidate/ship, `--change`, and `--only` release rules are
17
+ compatibility notes only. Do not assemble a V2 release from low-level commands.
18
+
19
+ ```bash
20
+ openxiangda check --environment preproduction
21
+ openxiangda deploy preproduction --json
22
+ openxiangda deploy production --package <packageDigest> --json
23
+ openxiangda status <runId> --json
24
+ openxiangda retry <runId> --json
25
+ openxiangda rollback production --to <appReleaseId> --json
26
+ ```
27
+
28
+ The V2 compiler derives the exact desired-state delta, excludes secrets, builds
29
+ Runtime once, uploads content-addressed layers, and creates a server-persisted
30
+ ReleaseRun. Production consumes the sealed preproduction package without a
31
+ rebuild. Keep the `runId`; failures preserve successful checkpoints.
32
+
13
33
  ## Keep the agent loop small
14
34
 
15
35
  - Start with one broad CodeGraph exploration that names the complete flow or feature. Use at most one focused follow-up when the first result explicitly omits a required symbol; do not repeat overlapping surveys.
@@ -7,6 +7,23 @@ description: Core OpenXiangda CLI workflow for profiles, login, workspace state,
7
7
 
8
8
  Use this skill for login/profile/state questions and any plan, publish, deploy, or release operation. It intentionally contains only release-critical rules; load domain skills for forms, pages, permissions, Functions, Automation, or Workflow behavior.
9
9
 
10
+ ## Delivery V2
11
+
12
+ If `app-workspace.config.ts` declares `deliveryVersion: 2`, this section
13
+ overrides the V1 release material below. The normal flow has no SDD, Git clean,
14
+ mainline ancestry, explicit change id, `--only`, candidate, or ship gate:
15
+
16
+ ```bash
17
+ openxiangda check --environment preproduction
18
+ openxiangda deploy preproduction --json
19
+ openxiangda deploy production --package <packageDigest> --json
20
+ ```
21
+
22
+ Use `openxiangda status <runId>` and `openxiangda retry <runId>` for a failed or
23
+ interrupted run. Use `openxiangda rollback <environment> --to <appReleaseId>`
24
+ for rollback. Never ask the AI to choose or sequence low-level
25
+ `workspace/resource/runtime/app-finalize` commands for a V2 release.
26
+
10
27
  ## Resolve the boundary
11
28
 
12
29
  Before a write or release, establish all four values:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openxiangda",
3
- "version": "1.0.231",
3
+ "version": "1.0.232",
4
4
  "description": "OpenXiangda CLI, workspace build tools, runtime SDK, and form components.",
5
5
  "private": false,
6
6
  "bin": {
@@ -68,7 +68,7 @@
68
68
  "source:admin-list": "node scripts/sync-admin-list-source.mjs",
69
69
  "check": "node --check bin/openxiangda.js && node --check lib/*.js && node --check packages/sdk/src/build-source/src/cli.mjs && node --check packages/sdk/src/build-source/scripts/*.mjs && node --check packages/sdk/src/build-source/scripts/utils/*.mjs",
70
70
  "test": "npm run test:fast",
71
- "test:fast": "npm run check && node scripts/http-proxy-smoke.mjs && node scripts/form-export-cli-smoke.mjs && node scripts/open-api-cli-smoke.mjs && node scripts/release-plan-smoke.mjs && node scripts/typed-resource-plan-smoke.mjs && node scripts/integration-bundle-smoke.mjs && node scripts/content-cache-smoke.mjs && node scripts/dependency-capsule-smoke.mjs && node scripts/sdd-stages-smoke.mjs && node scripts/environment-swap-cli-smoke.mjs && node scripts/environment-policy-cli-smoke.mjs",
71
+ "test:fast": "npm run check && node scripts/delivery-v2-package-smoke.mjs && node scripts/delivery-v2-executor-smoke.mjs && node scripts/http-proxy-smoke.mjs && node scripts/form-export-cli-smoke.mjs && node scripts/open-api-cli-smoke.mjs && node scripts/release-plan-smoke.mjs && node scripts/typed-resource-plan-smoke.mjs && node scripts/integration-bundle-smoke.mjs && node scripts/content-cache-smoke.mjs && node scripts/dependency-capsule-smoke.mjs && node scripts/sdd-stages-smoke.mjs && node scripts/environment-swap-cli-smoke.mjs && node scripts/environment-policy-cli-smoke.mjs",
72
72
  "test:changed": "npm run check && node scripts/run-test-suite.mjs --changed --evidence",
73
73
  "test:contract": "npm run check && node scripts/run-test-suite.mjs --contract --evidence",
74
74
  "test:release": "npm run check && node scripts/run-test-suite.mjs --release --evidence",
@@ -108,6 +108,8 @@
108
108
  "test:release-telemetry": "node scripts/release-telemetry-smoke.mjs",
109
109
  "test:release-explain": "node scripts/release-explain-smoke.mjs",
110
110
  "test:release-error-classification": "node scripts/release-error-classification-smoke.mjs",
111
+ "test:delivery-v2-package": "node scripts/delivery-v2-package-smoke.mjs",
112
+ "test:delivery-v2-executor": "node scripts/delivery-v2-executor-smoke.mjs",
111
113
  "test:task-status": "node scripts/task-status-smoke.mjs",
112
114
  "test:policy": "node scripts/policy-smoke.mjs",
113
115
  "test:release-plan": "node scripts/release-plan-smoke.mjs",
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/build/index.ts"],"sourcesContent":["export type CssIsolation = 'namespace' | 'shadow' | 'none';\nexport type WorkspaceRuntimeMode = 'legacy' | 'react-spa';\n\nexport interface AppWorkspaceConfig {\n appType?: string;\n appName?: string;\n runtimeMode?: WorkspaceRuntimeMode;\n platformUrl?: string;\n servicePrefix?: string;\n appKey?: string;\n appSecret?: string;\n userId?: string;\n version?: string;\n buildId?: string;\n oss?: {\n region?: string;\n bucket?: string;\n accessKeyId?: string;\n accessKeySecret?: string;\n pathPrefix?: string;\n corsOrigins?: string[];\n skipCors?: boolean;\n };\n defaults?: {\n protocolVersion?: string;\n frameworkVersion?: string;\n cssIsolation?: CssIsolation;\n formMenuParentId?: string;\n formMenuIcon?: string;\n pageMenuParentId?: string;\n pageMenuIcon?: string;\n formBuilderVersion?: string;\n };\n forms?: { dir?: string; publishLegacyBundle?: boolean };\n pages?: { dir?: string };\n governance?: {\n sdd?: {\n enabled?: boolean;\n strictHighRisk?: boolean;\n strictDocumentation?: boolean;\n path?: string;\n };\n };\n}\n\nexport function defineAppWorkspaceConfig<T extends AppWorkspaceConfig>(config: T): T {\n return config;\n}\n\nconst DEFAULT_NAMESPACE_PREFIX = '.sy-app-workspace';\n\nfunction splitCssSelectors(selector: string) {\n const selectors: string[] = [];\n let depth = 0;\n let quote = '';\n let current = '';\n for (const char of selector) {\n if (quote) {\n current += char;\n if (char === quote) quote = '';\n continue;\n }\n if (char === '\"' || char === \"'\") {\n quote = char;\n current += char;\n continue;\n }\n if (char === '(' || char === '[') depth += 1;\n if (char === ')' || char === ']') depth -= 1;\n if (char === ',' && depth === 0) {\n selectors.push(current.trim());\n current = '';\n continue;\n }\n current += char;\n }\n if (current.trim()) selectors.push(current.trim());\n return selectors;\n}\n\nfunction shouldSkipNamespace(selector: string, prefix: string) {\n if (!selector || selector.includes(prefix)) return true;\n if (/^(html|body|:root)(\\b|:|\\[|$)/.test(selector)) return true;\n if (/^(@|from\\b|to\\b|\\d+%)/.test(selector)) return true;\n if (/^\\.(ant|sy-ant|anticon|adm)-/.test(selector)) return true;\n return false;\n}\n\nfunction createAntdSelectorAlias(selector: string) {\n const aliased = selector\n .replace(/(^|[^A-Za-z0-9_-])\\.ant-/g, '$1.sy-ant-')\n .replace(/(^|[^A-Za-z0-9_-])\\.anticon-/g, '$1.sy-anticon-')\n .replace(/(^|[^A-Za-z0-9_-])\\.anticon(?=$|[^A-Za-z0-9_-])/g, '$1.sy-anticon');\n return aliased === selector ? null : aliased;\n}\n\nexport function createOpenXiangdaNamespaceCssPlugin(\n prefix = DEFAULT_NAMESPACE_PREFIX,\n) {\n return {\n postcssPlugin: 'openxiangda-namespace-css',\n Rule(rule: { selector?: string; parent?: any }) {\n if (!rule.selector) return;\n let parent = rule.parent;\n while (parent) {\n if (parent.type === 'atrule' && /keyframes$/i.test(parent.name)) {\n return;\n }\n parent = parent.parent;\n }\n rule.selector = Array.from(\n new Set(\n splitCssSelectors(rule.selector).flatMap((selector) => {\n const scopedSelector = shouldSkipNamespace(selector, prefix)\n ? selector\n : `${prefix} ${selector}`;\n const antdAlias = createAntdSelectorAlias(scopedSelector);\n return antdAlias ? [scopedSelector, antdAlias] : [scopedSelector];\n }),\n ),\n ).join(', ');\n },\n };\n}\n\n(createOpenXiangdaNamespaceCssPlugin as any).postcss = true;\n\nexport const createNamespaceCssPlugin = createOpenXiangdaNamespaceCssPlugin;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA6CO,SAAS,yBAAuD,QAAc;AACnF,SAAO;AACT;AAEA,IAAM,2BAA2B;AAEjC,SAAS,kBAAkB,UAAkB;AAC3C,QAAM,YAAsB,CAAC;AAC7B,MAAI,QAAQ;AACZ,MAAI,QAAQ;AACZ,MAAI,UAAU;AACd,aAAW,QAAQ,UAAU;AAC3B,QAAI,OAAO;AACT,iBAAW;AACX,UAAI,SAAS,MAAO,SAAQ;AAC5B;AAAA,IACF;AACA,QAAI,SAAS,OAAO,SAAS,KAAK;AAChC,cAAQ;AACR,iBAAW;AACX;AAAA,IACF;AACA,QAAI,SAAS,OAAO,SAAS,IAAK,UAAS;AAC3C,QAAI,SAAS,OAAO,SAAS,IAAK,UAAS;AAC3C,QAAI,SAAS,OAAO,UAAU,GAAG;AAC/B,gBAAU,KAAK,QAAQ,KAAK,CAAC;AAC7B,gBAAU;AACV;AAAA,IACF;AACA,eAAW;AAAA,EACb;AACA,MAAI,QAAQ,KAAK,EAAG,WAAU,KAAK,QAAQ,KAAK,CAAC;AACjD,SAAO;AACT;AAEA,SAAS,oBAAoB,UAAkB,QAAgB;AAC7D,MAAI,CAAC,YAAY,SAAS,SAAS,MAAM,EAAG,QAAO;AACnD,MAAI,gCAAgC,KAAK,QAAQ,EAAG,QAAO;AAC3D,MAAI,wBAAwB,KAAK,QAAQ,EAAG,QAAO;AACnD,MAAI,+BAA+B,KAAK,QAAQ,EAAG,QAAO;AAC1D,SAAO;AACT;AAEA,SAAS,wBAAwB,UAAkB;AACjD,QAAM,UAAU,SACb,QAAQ,6BAA6B,YAAY,EACjD,QAAQ,iCAAiC,gBAAgB,EACzD,QAAQ,oDAAoD,eAAe;AAC9E,SAAO,YAAY,WAAW,OAAO;AACvC;AAEO,SAAS,oCACd,SAAS,0BACT;AACA,SAAO;AAAA,IACL,eAAe;AAAA,IACf,KAAK,MAA2C;AAC9C,UAAI,CAAC,KAAK,SAAU;AACpB,UAAI,SAAS,KAAK;AAClB,aAAO,QAAQ;AACb,YAAI,OAAO,SAAS,YAAY,cAAc,KAAK,OAAO,IAAI,GAAG;AAC/D;AAAA,QACF;AACA,iBAAS,OAAO;AAAA,MAClB;AACA,WAAK,WAAW,MAAM;AAAA,QACpB,IAAI;AAAA,UACF,kBAAkB,KAAK,QAAQ,EAAE,QAAQ,CAAC,aAAa;AACrD,kBAAM,iBAAiB,oBAAoB,UAAU,MAAM,IACvD,WACA,GAAG,MAAM,IAAI,QAAQ;AACzB,kBAAM,YAAY,wBAAwB,cAAc;AACxD,mBAAO,YAAY,CAAC,gBAAgB,SAAS,IAAI,CAAC,cAAc;AAAA,UAClE,CAAC;AAAA,QACH;AAAA,MACF,EAAE,KAAK,IAAI;AAAA,IACb;AAAA,EACF;AACF;AAEC,oCAA4C,UAAU;AAEhD,IAAM,2BAA2B;","names":[]}
1
+ {"version":3,"sources":["../../src/build/index.ts"],"sourcesContent":["export type CssIsolation = 'namespace' | 'shadow' | 'none';\nexport type WorkspaceRuntimeMode = 'legacy' | 'react-spa';\n\nexport interface AppWorkspaceConfig {\n deliveryVersion?: 2;\n appType?: string;\n appName?: string;\n runtimeMode?: WorkspaceRuntimeMode;\n platformUrl?: string;\n servicePrefix?: string;\n appKey?: string;\n appSecret?: string;\n userId?: string;\n version?: string;\n buildId?: string;\n oss?: {\n region?: string;\n bucket?: string;\n accessKeyId?: string;\n accessKeySecret?: string;\n pathPrefix?: string;\n corsOrigins?: string[];\n skipCors?: boolean;\n };\n defaults?: {\n protocolVersion?: string;\n frameworkVersion?: string;\n cssIsolation?: CssIsolation;\n formMenuParentId?: string;\n formMenuIcon?: string;\n pageMenuParentId?: string;\n pageMenuIcon?: string;\n formBuilderVersion?: string;\n };\n forms?: { dir?: string; publishLegacyBundle?: boolean };\n pages?: { dir?: string };\n governance?: {\n sdd?: {\n enabled?: boolean;\n strictHighRisk?: boolean;\n strictDocumentation?: boolean;\n path?: string;\n };\n };\n}\n\nexport function defineAppWorkspaceConfig<T extends AppWorkspaceConfig>(config: T): T {\n return config;\n}\n\nconst DEFAULT_NAMESPACE_PREFIX = '.sy-app-workspace';\n\nfunction splitCssSelectors(selector: string) {\n const selectors: string[] = [];\n let depth = 0;\n let quote = '';\n let current = '';\n for (const char of selector) {\n if (quote) {\n current += char;\n if (char === quote) quote = '';\n continue;\n }\n if (char === '\"' || char === \"'\") {\n quote = char;\n current += char;\n continue;\n }\n if (char === '(' || char === '[') depth += 1;\n if (char === ')' || char === ']') depth -= 1;\n if (char === ',' && depth === 0) {\n selectors.push(current.trim());\n current = '';\n continue;\n }\n current += char;\n }\n if (current.trim()) selectors.push(current.trim());\n return selectors;\n}\n\nfunction shouldSkipNamespace(selector: string, prefix: string) {\n if (!selector || selector.includes(prefix)) return true;\n if (/^(html|body|:root)(\\b|:|\\[|$)/.test(selector)) return true;\n if (/^(@|from\\b|to\\b|\\d+%)/.test(selector)) return true;\n if (/^\\.(ant|sy-ant|anticon|adm)-/.test(selector)) return true;\n return false;\n}\n\nfunction createAntdSelectorAlias(selector: string) {\n const aliased = selector\n .replace(/(^|[^A-Za-z0-9_-])\\.ant-/g, '$1.sy-ant-')\n .replace(/(^|[^A-Za-z0-9_-])\\.anticon-/g, '$1.sy-anticon-')\n .replace(/(^|[^A-Za-z0-9_-])\\.anticon(?=$|[^A-Za-z0-9_-])/g, '$1.sy-anticon');\n return aliased === selector ? null : aliased;\n}\n\nexport function createOpenXiangdaNamespaceCssPlugin(\n prefix = DEFAULT_NAMESPACE_PREFIX,\n) {\n return {\n postcssPlugin: 'openxiangda-namespace-css',\n Rule(rule: { selector?: string; parent?: any }) {\n if (!rule.selector) return;\n let parent = rule.parent;\n while (parent) {\n if (parent.type === 'atrule' && /keyframes$/i.test(parent.name)) {\n return;\n }\n parent = parent.parent;\n }\n rule.selector = Array.from(\n new Set(\n splitCssSelectors(rule.selector).flatMap((selector) => {\n const scopedSelector = shouldSkipNamespace(selector, prefix)\n ? selector\n : `${prefix} ${selector}`;\n const antdAlias = createAntdSelectorAlias(scopedSelector);\n return antdAlias ? [scopedSelector, antdAlias] : [scopedSelector];\n }),\n ),\n ).join(', ');\n },\n };\n}\n\n(createOpenXiangdaNamespaceCssPlugin as any).postcss = true;\n\nexport const createNamespaceCssPlugin = createOpenXiangdaNamespaceCssPlugin;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA8CO,SAAS,yBAAuD,QAAc;AACnF,SAAO;AACT;AAEA,IAAM,2BAA2B;AAEjC,SAAS,kBAAkB,UAAkB;AAC3C,QAAM,YAAsB,CAAC;AAC7B,MAAI,QAAQ;AACZ,MAAI,QAAQ;AACZ,MAAI,UAAU;AACd,aAAW,QAAQ,UAAU;AAC3B,QAAI,OAAO;AACT,iBAAW;AACX,UAAI,SAAS,MAAO,SAAQ;AAC5B;AAAA,IACF;AACA,QAAI,SAAS,OAAO,SAAS,KAAK;AAChC,cAAQ;AACR,iBAAW;AACX;AAAA,IACF;AACA,QAAI,SAAS,OAAO,SAAS,IAAK,UAAS;AAC3C,QAAI,SAAS,OAAO,SAAS,IAAK,UAAS;AAC3C,QAAI,SAAS,OAAO,UAAU,GAAG;AAC/B,gBAAU,KAAK,QAAQ,KAAK,CAAC;AAC7B,gBAAU;AACV;AAAA,IACF;AACA,eAAW;AAAA,EACb;AACA,MAAI,QAAQ,KAAK,EAAG,WAAU,KAAK,QAAQ,KAAK,CAAC;AACjD,SAAO;AACT;AAEA,SAAS,oBAAoB,UAAkB,QAAgB;AAC7D,MAAI,CAAC,YAAY,SAAS,SAAS,MAAM,EAAG,QAAO;AACnD,MAAI,gCAAgC,KAAK,QAAQ,EAAG,QAAO;AAC3D,MAAI,wBAAwB,KAAK,QAAQ,EAAG,QAAO;AACnD,MAAI,+BAA+B,KAAK,QAAQ,EAAG,QAAO;AAC1D,SAAO;AACT;AAEA,SAAS,wBAAwB,UAAkB;AACjD,QAAM,UAAU,SACb,QAAQ,6BAA6B,YAAY,EACjD,QAAQ,iCAAiC,gBAAgB,EACzD,QAAQ,oDAAoD,eAAe;AAC9E,SAAO,YAAY,WAAW,OAAO;AACvC;AAEO,SAAS,oCACd,SAAS,0BACT;AACA,SAAO;AAAA,IACL,eAAe;AAAA,IACf,KAAK,MAA2C;AAC9C,UAAI,CAAC,KAAK,SAAU;AACpB,UAAI,SAAS,KAAK;AAClB,aAAO,QAAQ;AACb,YAAI,OAAO,SAAS,YAAY,cAAc,KAAK,OAAO,IAAI,GAAG;AAC/D;AAAA,QACF;AACA,iBAAS,OAAO;AAAA,MAClB;AACA,WAAK,WAAW,MAAM;AAAA,QACpB,IAAI;AAAA,UACF,kBAAkB,KAAK,QAAQ,EAAE,QAAQ,CAAC,aAAa;AACrD,kBAAM,iBAAiB,oBAAoB,UAAU,MAAM,IACvD,WACA,GAAG,MAAM,IAAI,QAAQ;AACzB,kBAAM,YAAY,wBAAwB,cAAc;AACxD,mBAAO,YAAY,CAAC,gBAAgB,SAAS,IAAI,CAAC,cAAc;AAAA,UAClE,CAAC;AAAA,QACH;AAAA,MACF,EAAE,KAAK,IAAI;AAAA,IACb;AAAA,EACF;AACF;AAEC,oCAA4C,UAAU;AAEhD,IAAM,2BAA2B;","names":[]}
@@ -1,6 +1,7 @@
1
1
  type CssIsolation = 'namespace' | 'shadow' | 'none';
2
2
  type WorkspaceRuntimeMode = 'legacy' | 'react-spa';
3
3
  interface AppWorkspaceConfig {
4
+ deliveryVersion?: 2;
4
5
  appType?: string;
5
6
  appName?: string;
6
7
  runtimeMode?: WorkspaceRuntimeMode;
@@ -1,6 +1,7 @@
1
1
  type CssIsolation = 'namespace' | 'shadow' | 'none';
2
2
  type WorkspaceRuntimeMode = 'legacy' | 'react-spa';
3
3
  interface AppWorkspaceConfig {
4
+ deliveryVersion?: 2;
4
5
  appType?: string;
5
6
  appName?: string;
6
7
  runtimeMode?: WorkspaceRuntimeMode;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/build/index.ts"],"sourcesContent":["export type CssIsolation = 'namespace' | 'shadow' | 'none';\nexport type WorkspaceRuntimeMode = 'legacy' | 'react-spa';\n\nexport interface AppWorkspaceConfig {\n appType?: string;\n appName?: string;\n runtimeMode?: WorkspaceRuntimeMode;\n platformUrl?: string;\n servicePrefix?: string;\n appKey?: string;\n appSecret?: string;\n userId?: string;\n version?: string;\n buildId?: string;\n oss?: {\n region?: string;\n bucket?: string;\n accessKeyId?: string;\n accessKeySecret?: string;\n pathPrefix?: string;\n corsOrigins?: string[];\n skipCors?: boolean;\n };\n defaults?: {\n protocolVersion?: string;\n frameworkVersion?: string;\n cssIsolation?: CssIsolation;\n formMenuParentId?: string;\n formMenuIcon?: string;\n pageMenuParentId?: string;\n pageMenuIcon?: string;\n formBuilderVersion?: string;\n };\n forms?: { dir?: string; publishLegacyBundle?: boolean };\n pages?: { dir?: string };\n governance?: {\n sdd?: {\n enabled?: boolean;\n strictHighRisk?: boolean;\n strictDocumentation?: boolean;\n path?: string;\n };\n };\n}\n\nexport function defineAppWorkspaceConfig<T extends AppWorkspaceConfig>(config: T): T {\n return config;\n}\n\nconst DEFAULT_NAMESPACE_PREFIX = '.sy-app-workspace';\n\nfunction splitCssSelectors(selector: string) {\n const selectors: string[] = [];\n let depth = 0;\n let quote = '';\n let current = '';\n for (const char of selector) {\n if (quote) {\n current += char;\n if (char === quote) quote = '';\n continue;\n }\n if (char === '\"' || char === \"'\") {\n quote = char;\n current += char;\n continue;\n }\n if (char === '(' || char === '[') depth += 1;\n if (char === ')' || char === ']') depth -= 1;\n if (char === ',' && depth === 0) {\n selectors.push(current.trim());\n current = '';\n continue;\n }\n current += char;\n }\n if (current.trim()) selectors.push(current.trim());\n return selectors;\n}\n\nfunction shouldSkipNamespace(selector: string, prefix: string) {\n if (!selector || selector.includes(prefix)) return true;\n if (/^(html|body|:root)(\\b|:|\\[|$)/.test(selector)) return true;\n if (/^(@|from\\b|to\\b|\\d+%)/.test(selector)) return true;\n if (/^\\.(ant|sy-ant|anticon|adm)-/.test(selector)) return true;\n return false;\n}\n\nfunction createAntdSelectorAlias(selector: string) {\n const aliased = selector\n .replace(/(^|[^A-Za-z0-9_-])\\.ant-/g, '$1.sy-ant-')\n .replace(/(^|[^A-Za-z0-9_-])\\.anticon-/g, '$1.sy-anticon-')\n .replace(/(^|[^A-Za-z0-9_-])\\.anticon(?=$|[^A-Za-z0-9_-])/g, '$1.sy-anticon');\n return aliased === selector ? null : aliased;\n}\n\nexport function createOpenXiangdaNamespaceCssPlugin(\n prefix = DEFAULT_NAMESPACE_PREFIX,\n) {\n return {\n postcssPlugin: 'openxiangda-namespace-css',\n Rule(rule: { selector?: string; parent?: any }) {\n if (!rule.selector) return;\n let parent = rule.parent;\n while (parent) {\n if (parent.type === 'atrule' && /keyframes$/i.test(parent.name)) {\n return;\n }\n parent = parent.parent;\n }\n rule.selector = Array.from(\n new Set(\n splitCssSelectors(rule.selector).flatMap((selector) => {\n const scopedSelector = shouldSkipNamespace(selector, prefix)\n ? selector\n : `${prefix} ${selector}`;\n const antdAlias = createAntdSelectorAlias(scopedSelector);\n return antdAlias ? [scopedSelector, antdAlias] : [scopedSelector];\n }),\n ),\n ).join(', ');\n },\n };\n}\n\n(createOpenXiangdaNamespaceCssPlugin as any).postcss = true;\n\nexport const createNamespaceCssPlugin = createOpenXiangdaNamespaceCssPlugin;\n"],"mappings":";AA6CO,SAAS,yBAAuD,QAAc;AACnF,SAAO;AACT;AAEA,IAAM,2BAA2B;AAEjC,SAAS,kBAAkB,UAAkB;AAC3C,QAAM,YAAsB,CAAC;AAC7B,MAAI,QAAQ;AACZ,MAAI,QAAQ;AACZ,MAAI,UAAU;AACd,aAAW,QAAQ,UAAU;AAC3B,QAAI,OAAO;AACT,iBAAW;AACX,UAAI,SAAS,MAAO,SAAQ;AAC5B;AAAA,IACF;AACA,QAAI,SAAS,OAAO,SAAS,KAAK;AAChC,cAAQ;AACR,iBAAW;AACX;AAAA,IACF;AACA,QAAI,SAAS,OAAO,SAAS,IAAK,UAAS;AAC3C,QAAI,SAAS,OAAO,SAAS,IAAK,UAAS;AAC3C,QAAI,SAAS,OAAO,UAAU,GAAG;AAC/B,gBAAU,KAAK,QAAQ,KAAK,CAAC;AAC7B,gBAAU;AACV;AAAA,IACF;AACA,eAAW;AAAA,EACb;AACA,MAAI,QAAQ,KAAK,EAAG,WAAU,KAAK,QAAQ,KAAK,CAAC;AACjD,SAAO;AACT;AAEA,SAAS,oBAAoB,UAAkB,QAAgB;AAC7D,MAAI,CAAC,YAAY,SAAS,SAAS,MAAM,EAAG,QAAO;AACnD,MAAI,gCAAgC,KAAK,QAAQ,EAAG,QAAO;AAC3D,MAAI,wBAAwB,KAAK,QAAQ,EAAG,QAAO;AACnD,MAAI,+BAA+B,KAAK,QAAQ,EAAG,QAAO;AAC1D,SAAO;AACT;AAEA,SAAS,wBAAwB,UAAkB;AACjD,QAAM,UAAU,SACb,QAAQ,6BAA6B,YAAY,EACjD,QAAQ,iCAAiC,gBAAgB,EACzD,QAAQ,oDAAoD,eAAe;AAC9E,SAAO,YAAY,WAAW,OAAO;AACvC;AAEO,SAAS,oCACd,SAAS,0BACT;AACA,SAAO;AAAA,IACL,eAAe;AAAA,IACf,KAAK,MAA2C;AAC9C,UAAI,CAAC,KAAK,SAAU;AACpB,UAAI,SAAS,KAAK;AAClB,aAAO,QAAQ;AACb,YAAI,OAAO,SAAS,YAAY,cAAc,KAAK,OAAO,IAAI,GAAG;AAC/D;AAAA,QACF;AACA,iBAAS,OAAO;AAAA,MAClB;AACA,WAAK,WAAW,MAAM;AAAA,QACpB,IAAI;AAAA,UACF,kBAAkB,KAAK,QAAQ,EAAE,QAAQ,CAAC,aAAa;AACrD,kBAAM,iBAAiB,oBAAoB,UAAU,MAAM,IACvD,WACA,GAAG,MAAM,IAAI,QAAQ;AACzB,kBAAM,YAAY,wBAAwB,cAAc;AACxD,mBAAO,YAAY,CAAC,gBAAgB,SAAS,IAAI,CAAC,cAAc;AAAA,UAClE,CAAC;AAAA,QACH;AAAA,MACF,EAAE,KAAK,IAAI;AAAA,IACb;AAAA,EACF;AACF;AAEC,oCAA4C,UAAU;AAEhD,IAAM,2BAA2B;","names":[]}
1
+ {"version":3,"sources":["../../src/build/index.ts"],"sourcesContent":["export type CssIsolation = 'namespace' | 'shadow' | 'none';\nexport type WorkspaceRuntimeMode = 'legacy' | 'react-spa';\n\nexport interface AppWorkspaceConfig {\n deliveryVersion?: 2;\n appType?: string;\n appName?: string;\n runtimeMode?: WorkspaceRuntimeMode;\n platformUrl?: string;\n servicePrefix?: string;\n appKey?: string;\n appSecret?: string;\n userId?: string;\n version?: string;\n buildId?: string;\n oss?: {\n region?: string;\n bucket?: string;\n accessKeyId?: string;\n accessKeySecret?: string;\n pathPrefix?: string;\n corsOrigins?: string[];\n skipCors?: boolean;\n };\n defaults?: {\n protocolVersion?: string;\n frameworkVersion?: string;\n cssIsolation?: CssIsolation;\n formMenuParentId?: string;\n formMenuIcon?: string;\n pageMenuParentId?: string;\n pageMenuIcon?: string;\n formBuilderVersion?: string;\n };\n forms?: { dir?: string; publishLegacyBundle?: boolean };\n pages?: { dir?: string };\n governance?: {\n sdd?: {\n enabled?: boolean;\n strictHighRisk?: boolean;\n strictDocumentation?: boolean;\n path?: string;\n };\n };\n}\n\nexport function defineAppWorkspaceConfig<T extends AppWorkspaceConfig>(config: T): T {\n return config;\n}\n\nconst DEFAULT_NAMESPACE_PREFIX = '.sy-app-workspace';\n\nfunction splitCssSelectors(selector: string) {\n const selectors: string[] = [];\n let depth = 0;\n let quote = '';\n let current = '';\n for (const char of selector) {\n if (quote) {\n current += char;\n if (char === quote) quote = '';\n continue;\n }\n if (char === '\"' || char === \"'\") {\n quote = char;\n current += char;\n continue;\n }\n if (char === '(' || char === '[') depth += 1;\n if (char === ')' || char === ']') depth -= 1;\n if (char === ',' && depth === 0) {\n selectors.push(current.trim());\n current = '';\n continue;\n }\n current += char;\n }\n if (current.trim()) selectors.push(current.trim());\n return selectors;\n}\n\nfunction shouldSkipNamespace(selector: string, prefix: string) {\n if (!selector || selector.includes(prefix)) return true;\n if (/^(html|body|:root)(\\b|:|\\[|$)/.test(selector)) return true;\n if (/^(@|from\\b|to\\b|\\d+%)/.test(selector)) return true;\n if (/^\\.(ant|sy-ant|anticon|adm)-/.test(selector)) return true;\n return false;\n}\n\nfunction createAntdSelectorAlias(selector: string) {\n const aliased = selector\n .replace(/(^|[^A-Za-z0-9_-])\\.ant-/g, '$1.sy-ant-')\n .replace(/(^|[^A-Za-z0-9_-])\\.anticon-/g, '$1.sy-anticon-')\n .replace(/(^|[^A-Za-z0-9_-])\\.anticon(?=$|[^A-Za-z0-9_-])/g, '$1.sy-anticon');\n return aliased === selector ? null : aliased;\n}\n\nexport function createOpenXiangdaNamespaceCssPlugin(\n prefix = DEFAULT_NAMESPACE_PREFIX,\n) {\n return {\n postcssPlugin: 'openxiangda-namespace-css',\n Rule(rule: { selector?: string; parent?: any }) {\n if (!rule.selector) return;\n let parent = rule.parent;\n while (parent) {\n if (parent.type === 'atrule' && /keyframes$/i.test(parent.name)) {\n return;\n }\n parent = parent.parent;\n }\n rule.selector = Array.from(\n new Set(\n splitCssSelectors(rule.selector).flatMap((selector) => {\n const scopedSelector = shouldSkipNamespace(selector, prefix)\n ? selector\n : `${prefix} ${selector}`;\n const antdAlias = createAntdSelectorAlias(scopedSelector);\n return antdAlias ? [scopedSelector, antdAlias] : [scopedSelector];\n }),\n ),\n ).join(', ');\n },\n };\n}\n\n(createOpenXiangdaNamespaceCssPlugin as any).postcss = true;\n\nexport const createNamespaceCssPlugin = createOpenXiangdaNamespaceCssPlugin;\n"],"mappings":";AA8CO,SAAS,yBAAuD,QAAc;AACnF,SAAO;AACT;AAEA,IAAM,2BAA2B;AAEjC,SAAS,kBAAkB,UAAkB;AAC3C,QAAM,YAAsB,CAAC;AAC7B,MAAI,QAAQ;AACZ,MAAI,QAAQ;AACZ,MAAI,UAAU;AACd,aAAW,QAAQ,UAAU;AAC3B,QAAI,OAAO;AACT,iBAAW;AACX,UAAI,SAAS,MAAO,SAAQ;AAC5B;AAAA,IACF;AACA,QAAI,SAAS,OAAO,SAAS,KAAK;AAChC,cAAQ;AACR,iBAAW;AACX;AAAA,IACF;AACA,QAAI,SAAS,OAAO,SAAS,IAAK,UAAS;AAC3C,QAAI,SAAS,OAAO,SAAS,IAAK,UAAS;AAC3C,QAAI,SAAS,OAAO,UAAU,GAAG;AAC/B,gBAAU,KAAK,QAAQ,KAAK,CAAC;AAC7B,gBAAU;AACV;AAAA,IACF;AACA,eAAW;AAAA,EACb;AACA,MAAI,QAAQ,KAAK,EAAG,WAAU,KAAK,QAAQ,KAAK,CAAC;AACjD,SAAO;AACT;AAEA,SAAS,oBAAoB,UAAkB,QAAgB;AAC7D,MAAI,CAAC,YAAY,SAAS,SAAS,MAAM,EAAG,QAAO;AACnD,MAAI,gCAAgC,KAAK,QAAQ,EAAG,QAAO;AAC3D,MAAI,wBAAwB,KAAK,QAAQ,EAAG,QAAO;AACnD,MAAI,+BAA+B,KAAK,QAAQ,EAAG,QAAO;AAC1D,SAAO;AACT;AAEA,SAAS,wBAAwB,UAAkB;AACjD,QAAM,UAAU,SACb,QAAQ,6BAA6B,YAAY,EACjD,QAAQ,iCAAiC,gBAAgB,EACzD,QAAQ,oDAAoD,eAAe;AAC9E,SAAO,YAAY,WAAW,OAAO;AACvC;AAEO,SAAS,oCACd,SAAS,0BACT;AACA,SAAO;AAAA,IACL,eAAe;AAAA,IACf,KAAK,MAA2C;AAC9C,UAAI,CAAC,KAAK,SAAU;AACpB,UAAI,SAAS,KAAK;AAClB,aAAO,QAAQ;AACb,YAAI,OAAO,SAAS,YAAY,cAAc,KAAK,OAAO,IAAI,GAAG;AAC/D;AAAA,QACF;AACA,iBAAS,OAAO;AAAA,MAClB;AACA,WAAK,WAAW,MAAM;AAAA,QACpB,IAAI;AAAA,UACF,kBAAkB,KAAK,QAAQ,EAAE,QAAQ,CAAC,aAAa;AACrD,kBAAM,iBAAiB,oBAAoB,UAAU,MAAM,IACvD,WACA,GAAG,MAAM,IAAI,QAAQ;AACzB,kBAAM,YAAY,wBAAwB,cAAc;AACxD,mBAAO,YAAY,CAAC,gBAAgB,SAAS,IAAI,CAAC,cAAc;AAAA,UAClE,CAAC;AAAA,QACH;AAAA,MACF,EAAE,KAAK,IAAI;AAAA,IACb;AAAA,EACF;AACF;AAEC,oCAA4C,UAAU;AAEhD,IAAM,2BAA2B;","names":[]}
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "schemaVersion": "openxiangda_engineering_policy_v1",
3
- "policyVersion": 4,
3
+ "policyVersion": 5,
4
4
  "risk": {
5
5
  "levels": ["L0", "L1", "L2", "L3"],
6
6
  "quickMaxLevel": "L1",
@@ -28,6 +28,13 @@
28
28
  "requireRemoteMainlineContainment": true
29
29
  },
30
30
  "release": {
31
+ "normalDeliveryVersion": 2,
32
+ "trustedDeveloperMode": true,
33
+ "normalCommands": ["check", "deploy", "status", "retry", "rollback"],
34
+ "productionConsumesSealedPackage": true,
35
+ "serverPersistedReleaseRun": true,
36
+ "v2RequiresSdd": false,
37
+ "v2RequiresGitMainline": false,
31
38
  "planAndVerifyAreReadOnly": true,
32
39
  "applicationEnvironmentMode": "candidate-preproduction-evidence-production",
33
40
  "candidateImmutable": true,
@@ -5,21 +5,22 @@ alwaysApply: true
5
5
 
6
6
  # OpenXiangda React SPA Rule
7
7
 
8
- This is an OpenXiangda React SPA workspace. See [AGENTS.md](mdc:AGENTS.md) for full guidance.
8
+ This is an OpenXiangda React SPA workspace using Delivery V2. See [DELIVERY.md](mdc:DELIVERY.md) and [AGENTS.md](mdc:AGENTS.md). Low-level V1 resource/runtime commands are compatibility tools.
9
9
 
10
10
  ## Hard route
11
11
 
12
12
  | User says | Command |
13
13
  |---|---|
14
- | publish resources | `openxiangda resource publish <type> --only <codes> --profile <name> --change <change>` |
15
- | deploy frontend | `openxiangda runtime deploy --profile <name> --no-activate` |
16
- | formal promotion | managed app: `release candidate` → preproduction deploy/test → same-candidate `release promote --confirm-production` |
17
- | diff / plan | `openxiangda resource plan <type> --only <codes> --profile <name>` |
14
+ | publish / deploy | `openxiangda check --environment preproduction` → `openxiangda deploy preproduction` |
15
+ | formal promotion | `openxiangda deploy production --package <packageDigest>` |
16
+ | status / retry | `openxiangda status <runId>` → `openxiangda retry <runId>` |
17
+ | rollback | `openxiangda rollback production --to <appReleaseId>` |
18
18
  | diagnose | `openxiangda doctor --profile <name> --json` |
19
19
  | external backend Open API | `openxiangda-open-api` + `openxiangda open-api spec describe ...` |
20
20
 
21
21
  ## Always
22
22
 
23
+ - Delivery V2 derives exact scope and does not require SDD, Git clean, `--change`, `--only`, candidate, or ship.
23
24
  - Writes and deploys must pass `--profile <name>` explicitly.
24
25
  - Architecture-class work is plan-gated: run `openxiangda design gates --topic <code> --json` and wait for confirmation.
25
26
  - Give every task an isolated worktree/branch and one explicit development change; feature worktrees never publish. Merge approved commits to the remote default branch, create one `sdd bundle <release-change> --changes ...`, commit/push it, then publish once from the synchronized clean main/master checkout.
@@ -5,22 +5,22 @@ alwaysApply: true
5
5
 
6
6
  # OpenXiangda React SPA Rule
7
7
 
8
- This is an OpenXiangda React SPA workspace. Read [AGENTS.md](AGENTS.md) for full guidance. New apps use `resource publish` plus `runtime deploy`; do not use classic workspace publish flows for frontend deployment.
8
+ This is an OpenXiangda React SPA workspace using Delivery V2. Read [DELIVERY.md](DELIVERY.md) and [AGENTS.md](AGENTS.md). Low-level V1 resource/runtime commands are compatibility tools, not the normal release entrypoint.
9
9
 
10
10
  ## Hard route
11
11
 
12
12
  | 用户说 | 必用命令 |
13
13
  |---|---|
14
- | 发布资源 / publish resources | `openxiangda resource publish <type> --only <codes> --change <change> --profile <name>` |
15
- | 发布前端预览 / deploy preview | `openxiangda runtime deploy --profile <name> --no-activate --json` |
16
- | 正式 promotion | 环境托管应用:`release candidate` → 预发 deploy/test → 同 candidate `release promote --confirm-production` |
17
- | 完整部署 / deploy | 使用同一 change + 精确 `--only` 的显式命令;无范围 `pnpm deploy` 已停用 |
18
- | 资源计划 / diff | `openxiangda resource plan <type> --only <codes> --profile <name>` |
14
+ | 发布 / 完整部署 | `openxiangda check --environment preproduction` → `openxiangda deploy preproduction` |
15
+ | 正式 promotion | `openxiangda deploy production --package <packageDigest>` |
16
+ | 状态 / 失败重试 | `openxiangda status <runId>` → `openxiangda retry <runId>` |
17
+ | 回滚 | `openxiangda rollback production --to <appReleaseId>` |
19
18
  | 诊断 / 环境 | `openxiangda doctor --profile <name> --json` / `openxiangda env --profile <name>` |
20
19
  | 外部后端 / 三方系统开放接口 | `openxiangda-open-api` + `openxiangda open-api spec describe ...` |
21
20
 
22
21
  ## Always
23
22
 
23
+ - Delivery V2 自动计算精确范围,不要求 SDD、Git clean、`--change`、`--only` 或 candidate/ship。
24
24
  - 发布和写平台资源必须显式传 `--profile <name>`。
25
25
  - 架构类需求先跑 `openxiangda design gates --topic <code> --json` 并等用户确认。
26
26
  - 每个任务使用独立 worktree/branch 和一个开发 change,但 feature worktree 不发布。批准提交先合并并 push 到远端默认主分支,再创建一个 `sdd bundle <release-change> --changes ...`,从同步且干净的 main/master 一次发布。
@@ -1,8 +1,12 @@
1
- <!-- OpenXiangda-Policy-Version: 4 -->
1
+ <!-- OpenXiangda-Policy-Version: 5 -->
2
2
  # AGENTS.md — OpenXiangda React SPA 应用工作区
3
3
 
4
4
  本工作区是标准 React 18 + Vite + React Router 应用。默认模板只提供应用壳、账号菜单和一个首页,不是开发验证控制台。
5
5
 
6
+ ## Delivery V2(发布唯一入口)
7
+
8
+ 本工作区声明 `deliveryVersion: 2`,正常发布只使用 `openxiangda check`、`openxiangda deploy`、`openxiangda status`、`openxiangda retry`、`openxiangda rollback`,完整约定见 [DELIVERY.md](DELIVERY.md)。V2 自动计算资源范围并在服务端持久化 ReleaseRun,不要求 SDD、Git clean、主线 ancestry、`--change`、`--only` 或生产确认参数。本文后续出现的 `resource publish`、`runtime deploy`、`release publish/ship`、candidate、SDD/mainline 发布门禁均为 V1 底层兼容说明,不得用于 V2 正常发布。
9
+
6
10
  ## 开发原则
7
11
 
8
12
  - 架构类需求先运行 `openxiangda doctor --json` 和 `openxiangda design gates --topic <code> --json`。只有仍存在会改变实现方向的业务、安全或数据选择时才输出设计并等待确认;用户已经给出具体需求与验收标准时,直接记录结构化 SDD 范围并实现,不再写长篇设计或重复确认。
@@ -0,0 +1,33 @@
1
+ # OpenXiangda Delivery V2
2
+
3
+ This workspace uses `deliveryVersion: 2`. Delivery V2 is desired-state based,
4
+ content-addressed, resumable, and independent from Git/SDD cleanliness.
5
+
6
+ Normal release commands are deliberately limited to:
7
+
8
+ ```bash
9
+ openxiangda check --environment preproduction
10
+ openxiangda deploy preproduction --json
11
+ openxiangda deploy production --package <packageDigest> --json
12
+ openxiangda status <runId> --json
13
+ openxiangda retry <runId> --json
14
+ openxiangda rollback production --to <appReleaseId> --json
15
+ ```
16
+
17
+ Rules:
18
+
19
+ - Do not assemble a release by choosing low-level `workspace publish`,
20
+ `resource publish`, `runtime deploy`, `release publish`, `release ship`, or
21
+ `app-finalize` commands. Delivery V2 owns that orchestration.
22
+ - Do not add `--only`, `--change`, SDD bypass flags, Git-clean workarounds, or
23
+ production-confirmation flags. The package compiler derives the exact delta.
24
+ - Preproduction compiles and uploads one immutable App Package. Production
25
+ deploys that exact `packageDigest` without rebuilding.
26
+ - On failure, keep the `runId`. Read its compact structured status and use
27
+ `retry`; successful checkpoints are preserved.
28
+ - Project `.env`, credentials, private keys, `.git`, `node_modules`, `dist`,
29
+ and generated `.openxiangda` state are never included in the authored source
30
+ layer. Runtime output is a separate immutable layer.
31
+
32
+ Low-level V1 commands remain installed only for diagnostics and compatibility
33
+ with old workspaces that do not declare `deliveryVersion: 2`.
@@ -1,6 +1,7 @@
1
1
  import { defineAppWorkspaceConfig } from "openxiangda/build";
2
2
 
3
3
  export default defineAppWorkspaceConfig({
4
+ deliveryVersion: 2,
4
5
  appType: process.env.APP_TYPE || process.env.OPENXIANGDA_APP_TYPE || "APP_XXXXXXXXXXXXXXXX",
5
6
  appName: process.env.APP_NAME || "OpenXiangda React SPA",
6
7
  runtimeMode: "react-spa",
@@ -38,9 +39,8 @@ export default defineAppWorkspaceConfig({
38
39
  },
39
40
  governance: {
40
41
  sdd: {
41
- enabled: process.env.OPENXIANGDA_SDD_ENABLED === "false" ? false : true,
42
- strictHighRisk:
43
- process.env.OPENXIANGDA_SDD_STRICT_HIGH_RISK === "false" ? false : true,
42
+ enabled: false,
43
+ strictHighRisk: false,
44
44
  strictDocumentation: false,
45
45
  documentationMode: 'structured',
46
46
  path: process.env.OPENXIANGDA_SDD_PATH || "openspec",
@@ -11,7 +11,9 @@ This is a `sy-lowcode-app-workspace` managed by the `openxiangda` CLI. See [AGEN
11
11
 
12
12
  | User says | Skill | Command |
13
13
  |---|---|---|
14
- | publish / deploy / 发布 / 上线 / 部署 | `openxiangda-core` | `openxiangda workspace publish --profile <name>` (+ `--changed` / `--page` / `--form` / `--only`) |
14
+ | publish / deploy / 发布 / 上线 / 部署 | `openxiangda-core` | `openxiangda check --environment preproduction` → `openxiangda deploy preproduction` |
15
+ | production promotion | `openxiangda-core` | `openxiangda deploy production --package <packageDigest>` |
16
+ | failed delivery / retry | `openxiangda-core` | `openxiangda status <runId>` → `openxiangda retry <runId>` |
15
17
  | create / scaffold app / 创建应用 / 初始化 | `openxiangda-app` | `openxiangda workspace init <dir> --profile <name> --app-name "..."` |
16
18
  | bind existing app / 绑定已有应用 | `openxiangda-app` | `openxiangda workspace bind --profile <name> --app-type APP_XXX` |
17
19
  | edit form / schema / 表单字段 / 表单页 | `openxiangda-form` | edit `src/forms/<code>/` → `workspace publish --form <code>` |
@@ -25,6 +27,7 @@ This is a `sy-lowcode-app-workspace` managed by the `openxiangda` CLI. See [AGEN
25
27
 
26
28
  ## Always
27
29
 
30
+ - For `deliveryVersion: 2`, use only Delivery V2 commands. Later V1 SDD/mainline/`--only`/candidate/ship text is compatibility guidance and must not be mixed into V2.
28
31
  - Give every task an isolated worktree/branch and one development change; feature worktrees never publish. Merge approved commits to the remote default branch, create one `sdd bundle`, commit/push it, and publish once from synchronized clean main/master.
29
32
  - Close tasks from canonical main only. Review `openxiangda workspace cleanup`, then run `openxiangda workspace cleanup --apply` for that exact hashed `SAFE` plan; it revalidates managed worktrees under the owner lock, never picks up newly-safe entries, and never runs global `git worktree prune`. Review stale records separately.
30
33
  - L0 read-only/docs/tests need no SDD; L1 narrow reversible fixes record exact scope without a redundant second confirmation; schema, business Functions, Automation/Workflow, permissions, auth/public access, data writes, and runtime/config are L2/L3 full-SDD work. Live evidence/archive are post-release stages.
@@ -11,7 +11,9 @@ This is a `sy-lowcode-app-workspace` managed by the `openxiangda` CLI. Read [AGE
11
11
 
12
12
  | 用户说 | 必用 skill | 必用命令 |
13
13
  |---|---|---|
14
- | 发布 / 上线 / 部署 / publish / deploy | `openxiangda-core` | `openxiangda workspace publish --profile <name>` (+`--changed` / `--page` / `--form` / `--only`) |
14
+ | 发布 / 上线 / 部署 / publish / deploy | `openxiangda-core` | `openxiangda check --environment preproduction` → `openxiangda deploy preproduction` |
15
+ | 晋级生产 | `openxiangda-core` | `openxiangda deploy production --package <packageDigest>` |
16
+ | 发布失败 / 重试 | `openxiangda-core` | `openxiangda status <runId>` → `openxiangda retry <runId>` |
15
17
  | 创建 / 初始化应用 | `openxiangda-app` | `openxiangda workspace init <dir> --profile <name> --app-name "..."` |
16
18
  | 绑定已有应用 | `openxiangda-app` | `openxiangda workspace bind --profile <name> --app-type APP_XXX` |
17
19
  | 改表单字段 / schema / 表单页 | `openxiangda-form` | 编辑 `src/forms/<code>/` → `workspace publish --form <code>` |
@@ -25,6 +27,7 @@ This is a `sy-lowcode-app-workspace` managed by the `openxiangda` CLI. Read [AGE
25
27
 
26
28
  ## Always
27
29
 
30
+ - `deliveryVersion: 2` 的正常发布只允许 Delivery V2 命令;后续 V1 SDD/mainline/`--only`/candidate/ship 内容仅作兼容说明,不得混入 V2。
28
31
  - 每个任务使用独立 worktree/branch 和一个开发 change,但 feature worktree 不发布。批准提交先合并并 push 到远端默认主分支,再创建一个 `sdd bundle`,从同步且干净的 main/master 一次发布。
29
32
  - 合并、push、发布和 `release end` 后,回到 canonical 主工作区先审阅 `openxiangda workspace cleanup`,再执行 `openxiangda workspace cleanup --apply` 应用精确哈希计划。CLI 在 owner lock 内复核,只删除已审阅的 managed `SAFE` 项,不顺带处理后来才安全的项,也不执行全局 `git worktree prune`;stale 记录单独人工审阅。
30
33
  - L0 只读/文档/测试无需 SDD;L1 窄小可逆改动记录精确范围且不重复确认;表单结构、业务函数、自动化/流程、权限、登录/公开访问、数据写入、runtime/config 等 L2/L3 走完整 SDD,live evidence/archive 放到发布后。
@@ -1,4 +1,4 @@
1
- <!-- OpenXiangda-Policy-Version: 4 -->
1
+ <!-- OpenXiangda-Policy-Version: 5 -->
2
2
  # AGENTS.md — OpenXiangda 工作区 AI 强约束
3
3
 
4
4
  > 任何 AI(Qoder / Claude / Codex / Cursor / Copilot 等)在本工作区操作前 **必须先读完本文件**。
@@ -6,7 +6,9 @@
6
6
 
7
7
  ## 一句话原则
8
8
 
9
- **所有"发布 / 上线 / 部署 / publish / deploy / ship / release"请求,唯一正确入口是 `openxiangda workspace publish --profile <name>`,不要直接 `pnpm publish:all`。**
9
+ **本工作区声明 `deliveryVersion: 2`。所有“发布 / 上线 / 部署 / publish / deploy / ship / release”请求只使用 `openxiangda check`、`openxiangda deploy`、`openxiangda status`、`openxiangda retry`、`openxiangda rollback`,完整约定见 [DELIVERY.md](DELIVERY.md)。**
10
+
11
+ Delivery V2 自动从期望状态计算精确资源范围,封存内容寻址 App Package,并在服务端持久化 ReleaseRun 和检查点。它不要求 SDD、Git clean、主线 ancestry、`--change`、`--only` 或生产确认参数。本文后续出现的 `workspace publish`、`resource publish`、`runtime deploy`、`release publish/ship`、candidate、SDD/mainline 发布门禁均属于 V1 底层兼容说明,不得用于 V2 正常发布。
10
12
 
11
13
  **架构类需求先过设计门。** 新应用、复杂页面、登录注册、公开访问、权限数据范围、流程自动化、连接器/通知等需求,先 `openxiangda doctor --json` + `openxiangda design gates --topic <code> --json`。只有仍存在会改变实现方向的业务、安全或数据选择时才输出设计并等待确认;用户已经给出具体需求与验收标准时,直接记录结构化 SDD 范围并实现,不再写长篇设计或重复确认。
12
14
 
@@ -24,8 +26,9 @@
24
26
 
25
27
  | 用户说(中 / 英) | 用 skill | 第一条命令 |
26
28
  |---|---|---|
27
- | 发布 / 上线 / 部署 / publish / deploy | `openxiangda-core` | `openxiangda workspace publish --profile <name> --changed --dry-run` |
28
- | 只发布改动 / 增量 / 单页 / 单表 | `openxiangda-core` | `... --changed` / `--page <code>` / `--form <code>` / `--only pages/a,forms/b` |
29
+ | 发布 / 上线 / 部署 / publish / deploy | `openxiangda-core` | `openxiangda check --environment preproduction` → `openxiangda deploy preproduction` |
30
+ | 晋级生产 | `openxiangda-core` | `openxiangda deploy production --package <packageDigest>` |
31
+ | 发布失败 / 断点续跑 | `openxiangda-core` | `openxiangda status <runId>` → `openxiangda retry <runId>` |
29
32
  | 创建应用 / 新建 app / 初始化工作区 | `openxiangda-app` | `openxiangda workspace init <dir> --profile <name> --app-name "..."` |
30
33
  | 绑定已有应用 | `openxiangda-app` | `openxiangda workspace bind --profile <name> --app-type APP_XXX` |
31
34
  | 创建 / 改表单字段、schema、表单页 | `openxiangda-form` | 编辑表单并声明 form-setting bundle → `resource publish form-setting --only <code>` 暂存;整应用由 `app-finalize` 激活 |
@@ -0,0 +1,33 @@
1
+ # OpenXiangda Delivery V2
2
+
3
+ This workspace uses `deliveryVersion: 2`. Delivery V2 is desired-state based,
4
+ content-addressed, resumable, and independent from Git/SDD cleanliness.
5
+
6
+ Normal release commands are deliberately limited to:
7
+
8
+ ```bash
9
+ openxiangda check --environment preproduction
10
+ openxiangda deploy preproduction --json
11
+ openxiangda deploy production --package <packageDigest> --json
12
+ openxiangda status <runId> --json
13
+ openxiangda retry <runId> --json
14
+ openxiangda rollback production --to <appReleaseId> --json
15
+ ```
16
+
17
+ Rules:
18
+
19
+ - Do not assemble a release by choosing low-level `workspace publish`,
20
+ `resource publish`, `runtime deploy`, `release publish`, `release ship`, or
21
+ `app-finalize` commands. Delivery V2 owns that orchestration.
22
+ - Do not add `--only`, `--change`, SDD bypass flags, Git-clean workarounds, or
23
+ production-confirmation flags. The package compiler derives the exact delta.
24
+ - Preproduction compiles and uploads one immutable App Package. Production
25
+ deploys that exact `packageDigest` without rebuilding.
26
+ - On failure, keep the `runId`. Read its compact structured status and use
27
+ `retry`; successful checkpoints are preserved.
28
+ - Project `.env`, credentials, private keys, `.git`, `node_modules`, `dist`,
29
+ and generated `.openxiangda` state are never included in the authored source
30
+ layer. Runtime output is a separate immutable layer.
31
+
32
+ Low-level V1 commands remain installed only for diagnostics and compatibility
33
+ with old workspaces that do not declare `deliveryVersion: 2`.
@@ -1,6 +1,7 @@
1
1
  import { defineAppWorkspaceConfig } from "openxiangda/build";
2
2
 
3
3
  export default defineAppWorkspaceConfig({
4
+ deliveryVersion: 2,
4
5
  appType: process.env.APP_TYPE || process.env.OPENXIANGDA_APP_TYPE || "APP_XXXXXXXXXXXXXXXX",
5
6
  appName: process.env.APP_NAME || "低代码应用",
6
7
  platformUrl: process.env.APP_PLATFORM_URL || process.env.OPENXIANGDA_BASE_URL || "http://yida.wisejob.cn/service",
@@ -39,9 +40,8 @@ export default defineAppWorkspaceConfig({
39
40
  },
40
41
  governance: {
41
42
  sdd: {
42
- enabled: process.env.OPENXIANGDA_SDD_ENABLED === "false" ? false : true,
43
- strictHighRisk:
44
- process.env.OPENXIANGDA_SDD_STRICT_HIGH_RISK === "false" ? false : true,
43
+ enabled: false,
44
+ strictHighRisk: false,
45
45
  strictDocumentation: false,
46
46
  documentationMode: 'structured',
47
47
  path: process.env.OPENXIANGDA_SDD_PATH || "openspec",
@@ -1,4 +1,5 @@
1
1
  export interface AppWorkspaceConfig {
2
+ deliveryVersion: 2;
2
3
  appType: string;
3
4
  appName: string;
4
5
  runtimeMode?: "legacy" | "react-spa";