openxiangda-devkit-core 2.0.0-alpha.118 → 2.0.0-alpha.120
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/dist/app-spec.d.ts +13 -7
- package/dist/app-spec.d.ts.map +1 -1
- package/dist/app-spec.js +80 -18
- package/dist/app-spec.js.map +1 -1
- package/dist/application-services.d.ts +117 -25
- package/dist/application-services.d.ts.map +1 -1
- package/dist/application-services.js +4 -2
- package/dist/application-services.js.map +1 -1
- package/dist/compiler/bundle.d.ts.map +1 -1
- package/dist/compiler/bundle.js +6 -0
- package/dist/compiler/bundle.js.map +1 -1
- package/dist/compiler/config.d.ts.map +1 -1
- package/dist/compiler/config.js +11 -3
- package/dist/compiler/config.js.map +1 -1
- package/dist/compiler/package-compiler.d.ts.map +1 -1
- package/dist/compiler/package-compiler.js +11 -0
- package/dist/compiler/package-compiler.js.map +1 -1
- package/dist/compiler/permission-review.d.ts.map +1 -1
- package/dist/deployment.js +8 -8
- package/dist/deployment.js.map +1 -1
- package/dist/design-readiness.d.ts +24 -0
- package/dist/design-readiness.d.ts.map +1 -0
- package/dist/design-readiness.js +102 -0
- package/dist/design-readiness.js.map +1 -0
- package/dist/developer-operations.d.ts +24 -4
- package/dist/developer-operations.d.ts.map +1 -1
- package/dist/development-lifecycle.d.ts +34 -7
- package/dist/development-lifecycle.d.ts.map +1 -1
- package/dist/development-lifecycle.js +19 -10
- package/dist/development-lifecycle.js.map +1 -1
- package/dist/documentation.d.ts +11 -3
- package/dist/documentation.d.ts.map +1 -1
- package/dist/documentation.js +2 -0
- package/dist/documentation.js.map +1 -1
- package/dist/workspace.d.ts.map +1 -1
- package/dist/workspace.js +1 -0
- package/dist/workspace.js.map +1 -1
- package/package.json +2 -3
- package/templates/backend/package.json +1 -1
- package/templates/backend/test/smoke.test.ts +0 -17
package/dist/app-spec.d.ts
CHANGED
|
@@ -4,7 +4,8 @@ export declare const APP_SPEC_SCHEMAS: {
|
|
|
4
4
|
readonly capability: "openxiangda.appspec/capability/v1";
|
|
5
5
|
readonly change: "openxiangda.appspec/change/v1";
|
|
6
6
|
readonly decision: "openxiangda.appspec/decision/v1";
|
|
7
|
-
readonly
|
|
7
|
+
readonly design: "openxiangda.appspec/design/v1";
|
|
8
|
+
readonly context: "openxiangda.appspec/context/v4";
|
|
8
9
|
};
|
|
9
10
|
export declare const APP_SPEC_LIMITS: {
|
|
10
11
|
readonly maximumFiles: 128;
|
|
@@ -16,7 +17,7 @@ export declare const APP_SPEC_LIMITS: {
|
|
|
16
17
|
};
|
|
17
18
|
export type AppSpecRisk = "L1" | "L2" | "L3";
|
|
18
19
|
export type AppSpecCurrentSpecStatus = "pending" | "merged" | "not-applicable";
|
|
19
|
-
export type AppSpecDocumentKind = "app" | "capability" | "change" | "decision";
|
|
20
|
+
export type AppSpecDocumentKind = "app" | "capability" | "change" | "decision" | "design";
|
|
20
21
|
type MetadataValue = string | string[] | boolean;
|
|
21
22
|
export interface AppSpecContractIndex {
|
|
22
23
|
appCode: string;
|
|
@@ -41,6 +42,7 @@ export interface AppSpecDocument {
|
|
|
41
42
|
resources: string[];
|
|
42
43
|
actions: string[];
|
|
43
44
|
decisions: string[];
|
|
45
|
+
documents: string[];
|
|
44
46
|
};
|
|
45
47
|
content: string;
|
|
46
48
|
}
|
|
@@ -67,6 +69,7 @@ export interface AppSpecContext {
|
|
|
67
69
|
capabilities: AppSpecDocumentSummary[];
|
|
68
70
|
activeChanges: AppSpecDocumentSummary[];
|
|
69
71
|
decisions: AppSpecDocumentSummary[];
|
|
72
|
+
designs: AppSpecDocumentSummary[];
|
|
70
73
|
history: AppSpecDocumentSummary[];
|
|
71
74
|
};
|
|
72
75
|
application: AppSpecDocument | null;
|
|
@@ -74,6 +77,7 @@ export interface AppSpecContext {
|
|
|
74
77
|
activeChanges: AppSpecDocument[];
|
|
75
78
|
archivedChanges: AppSpecDocument[];
|
|
76
79
|
decisions: AppSpecDocument[];
|
|
80
|
+
designs: AppSpecDocument[];
|
|
77
81
|
historyPage: {
|
|
78
82
|
offset: number;
|
|
79
83
|
limit: number;
|
|
@@ -93,6 +97,7 @@ export interface AppSpecContext {
|
|
|
93
97
|
activeChanges: number;
|
|
94
98
|
historyChanges: number;
|
|
95
99
|
decisions: number;
|
|
100
|
+
designs: number;
|
|
96
101
|
requirements: number;
|
|
97
102
|
acceptanceScenarios: number;
|
|
98
103
|
};
|
|
@@ -129,7 +134,7 @@ export interface CloseAppSpecChangeInput {
|
|
|
129
134
|
contract: AppSpecContractIndex;
|
|
130
135
|
}
|
|
131
136
|
export declare function initializeAppSpec(input: InitializeAppSpecInput): {
|
|
132
|
-
schemaVersion: "openxiangda.appspec/context/
|
|
137
|
+
schemaVersion: "openxiangda.appspec/context/v4";
|
|
133
138
|
enabled: boolean;
|
|
134
139
|
advisory: boolean;
|
|
135
140
|
releaseGate: boolean;
|
|
@@ -137,14 +142,14 @@ export declare function initializeAppSpec(input: InitializeAppSpecInput): {
|
|
|
137
142
|
existing: string[];
|
|
138
143
|
};
|
|
139
144
|
export declare function createAppSpecCapability(input: CreateAppSpecCapabilityInput): {
|
|
140
|
-
schemaVersion: "openxiangda.appspec/context/
|
|
145
|
+
schemaVersion: "openxiangda.appspec/context/v4";
|
|
141
146
|
enabled: boolean;
|
|
142
147
|
advisory: boolean;
|
|
143
148
|
releaseGate: boolean;
|
|
144
149
|
created: string;
|
|
145
150
|
};
|
|
146
151
|
export declare function createAppSpecChange(input: CreateAppSpecChangeInput): {
|
|
147
|
-
schemaVersion: "openxiangda.appspec/context/
|
|
152
|
+
schemaVersion: "openxiangda.appspec/context/v4";
|
|
148
153
|
enabled: boolean;
|
|
149
154
|
advisory: boolean;
|
|
150
155
|
releaseGate: boolean;
|
|
@@ -153,7 +158,7 @@ export declare function createAppSpecChange(input: CreateAppSpecChangeInput): {
|
|
|
153
158
|
status: string;
|
|
154
159
|
};
|
|
155
160
|
export declare function closeAppSpecChange(input: CloseAppSpecChangeInput): {
|
|
156
|
-
schemaVersion: "openxiangda.appspec/context/
|
|
161
|
+
schemaVersion: "openxiangda.appspec/context/v4";
|
|
157
162
|
enabled: boolean;
|
|
158
163
|
advisory: boolean;
|
|
159
164
|
releaseGate: boolean;
|
|
@@ -162,7 +167,7 @@ export declare function closeAppSpecChange(input: CloseAppSpecChangeInput): {
|
|
|
162
167
|
converged: boolean;
|
|
163
168
|
diagnostics: Diagnostic[];
|
|
164
169
|
} | {
|
|
165
|
-
schemaVersion: "openxiangda.appspec/context/
|
|
170
|
+
schemaVersion: "openxiangda.appspec/context/v4";
|
|
166
171
|
enabled: boolean;
|
|
167
172
|
advisory: boolean;
|
|
168
173
|
releaseGate: boolean;
|
|
@@ -208,6 +213,7 @@ export declare function summarizeAppSpecContext(context: AppSpecContext): {
|
|
|
208
213
|
activeChanges: number;
|
|
209
214
|
historyChanges: number;
|
|
210
215
|
decisions: number;
|
|
216
|
+
designs: number;
|
|
211
217
|
requirements: number;
|
|
212
218
|
acceptanceScenarios: number;
|
|
213
219
|
};
|
package/dist/app-spec.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app-spec.d.ts","sourceRoot":"","sources":["../src/app-spec.ts"],"names":[],"mappings":"AAcA,OAAO,EACL,eAAe,EACf,KAAK,UAAU,EAChB,MAAM,uBAAuB,CAAC;AAE/B,eAAO,MAAM,gBAAgB
|
|
1
|
+
{"version":3,"file":"app-spec.d.ts","sourceRoot":"","sources":["../src/app-spec.ts"],"names":[],"mappings":"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"}
|
package/dist/app-spec.js
CHANGED
|
@@ -7,7 +7,8 @@ export const APP_SPEC_SCHEMAS = {
|
|
|
7
7
|
capability: "openxiangda.appspec/capability/v1",
|
|
8
8
|
change: "openxiangda.appspec/change/v1",
|
|
9
9
|
decision: "openxiangda.appspec/decision/v1",
|
|
10
|
-
|
|
10
|
+
design: "openxiangda.appspec/design/v1",
|
|
11
|
+
context: "openxiangda.appspec/context/v4",
|
|
11
12
|
};
|
|
12
13
|
export const APP_SPEC_LIMITS = {
|
|
13
14
|
maximumFiles: 128,
|
|
@@ -216,6 +217,7 @@ export function inspectAppSpec(root, contract, selector, historyOffset = 0) {
|
|
|
216
217
|
...collection.activeChanges,
|
|
217
218
|
...collection.history,
|
|
218
219
|
...collection.decisions,
|
|
220
|
+
...collection.designs,
|
|
219
221
|
];
|
|
220
222
|
const index = summarizeCollection(collection);
|
|
221
223
|
const workspaceDigest = digestDocuments(allDocuments.filter(document => !document.path.startsWith("appspec/changes/history/")), contract);
|
|
@@ -241,6 +243,7 @@ export function inspectAppSpec(root, contract, selector, historyOffset = 0) {
|
|
|
241
243
|
activeChanges: budgeted.activeChanges,
|
|
242
244
|
archivedChanges: budgeted.archivedChanges,
|
|
243
245
|
decisions: budgeted.decisions,
|
|
246
|
+
designs: budgeted.designs,
|
|
244
247
|
historyPage: collection.historyPage,
|
|
245
248
|
contextBudget: budgeted.contextBudget,
|
|
246
249
|
stats: {
|
|
@@ -250,8 +253,9 @@ export function inspectAppSpec(root, contract, selector, historyOffset = 0) {
|
|
|
250
253
|
activeChanges: collection.activeChanges.length,
|
|
251
254
|
historyChanges: collection.historyPage.total,
|
|
252
255
|
decisions: collection.decisions.length,
|
|
253
|
-
|
|
254
|
-
|
|
256
|
+
designs: collection.designs.length,
|
|
257
|
+
requirements: unique([...collection.app, ...collection.capabilities, ...collection.designs].flatMap(document => document.requirementIds)).length,
|
|
258
|
+
acceptanceScenarios: unique([...collection.app, ...collection.capabilities, ...collection.designs].flatMap(document => document.acceptanceIds)).length,
|
|
255
259
|
},
|
|
256
260
|
workspaceDigest,
|
|
257
261
|
selectionDigest,
|
|
@@ -300,6 +304,7 @@ function emptyContext(contract, selector, diagnostics = [], enabled = false) {
|
|
|
300
304
|
capabilities: [],
|
|
301
305
|
activeChanges: [],
|
|
302
306
|
decisions: [],
|
|
307
|
+
designs: [],
|
|
303
308
|
history: [],
|
|
304
309
|
},
|
|
305
310
|
application: null,
|
|
@@ -307,6 +312,7 @@ function emptyContext(contract, selector, diagnostics = [], enabled = false) {
|
|
|
307
312
|
activeChanges: [],
|
|
308
313
|
archivedChanges: [],
|
|
309
314
|
decisions: [],
|
|
315
|
+
designs: [],
|
|
310
316
|
historyPage: { offset: 0, limit: 50, total: 0, nextOffset: null },
|
|
311
317
|
contextBudget: {
|
|
312
318
|
maximumBytes: APP_SPEC_LIMITS.maximumContextBytes,
|
|
@@ -321,6 +327,7 @@ function emptyContext(contract, selector, diagnostics = [], enabled = false) {
|
|
|
321
327
|
activeChanges: 0,
|
|
322
328
|
historyChanges: 0,
|
|
323
329
|
decisions: 0,
|
|
330
|
+
designs: 0,
|
|
324
331
|
requirements: 0,
|
|
325
332
|
acceptanceScenarios: 0,
|
|
326
333
|
},
|
|
@@ -385,6 +392,7 @@ function collectDocuments(root, diagnostics, selector, historyOffset = 0) {
|
|
|
385
392
|
activeChanges: [],
|
|
386
393
|
history: [],
|
|
387
394
|
decisions: [],
|
|
395
|
+
designs: [],
|
|
388
396
|
bytes: 0,
|
|
389
397
|
historyPage: { offset: historyOffset, limit: 50, total: 0, nextOffset: null },
|
|
390
398
|
};
|
|
@@ -401,6 +409,9 @@ function collectDocuments(root, diagnostics, selector, historyOffset = 0) {
|
|
|
401
409
|
path,
|
|
402
410
|
kind: "decision",
|
|
403
411
|
})));
|
|
412
|
+
for (const directory of ['product', 'experience', 'design', 'reviews']) {
|
|
413
|
+
candidates.push(...markdownFiles(join(paths.root, directory), false, diagnostics, root).map(path => ({ path, kind: 'design' })));
|
|
414
|
+
}
|
|
404
415
|
if (candidates.length > APP_SPEC_LIMITS.maximumFiles) {
|
|
405
416
|
diagnostics.push(issue("error", "APPSPEC_FILE_LIMIT_EXCEEDED", `AppSpec 文件数 ${candidates.length} 超过上限 ${APP_SPEC_LIMITS.maximumFiles}`, "appspec"));
|
|
406
417
|
candidates.splice(APP_SPEC_LIMITS.maximumFiles);
|
|
@@ -457,6 +468,8 @@ function collectDocuments(root, diagnostics, selector, historyOffset = 0) {
|
|
|
457
468
|
result.app.push(document);
|
|
458
469
|
else if (candidate.kind === "capability")
|
|
459
470
|
result.capabilities.push(document);
|
|
471
|
+
else if (candidate.kind === "design")
|
|
472
|
+
result.designs.push(document);
|
|
460
473
|
else if (candidate.kind === "decision")
|
|
461
474
|
result.decisions.push(document);
|
|
462
475
|
else if (candidate.history)
|
|
@@ -484,12 +497,12 @@ function validateDocuments(collection, contract, diagnostics) {
|
|
|
484
497
|
diagnostics.push(issue("error", "APPSPEC_HISTORY_CHANGE_STATUS_INVALID", `历史目录中的 ChangeSpec 必须是 archived 或 cancelled,当前为 ${document.status}`, document.path));
|
|
485
498
|
}
|
|
486
499
|
}
|
|
487
|
-
duplicateDiagnostics([...collection.capabilities, ...collection.activeChanges, ...collection.history, ...collection.decisions], document => document.id, "APPSPEC_DOCUMENT_ID_DUPLICATED", diagnostics);
|
|
488
|
-
duplicateDiagnostics([...collection.app, ...collection.capabilities].flatMap(document => document.requirementIds.map(id => ({ ...document, id }))), document => document.id, "APPSPEC_REQUIREMENT_ID_DUPLICATED", diagnostics);
|
|
489
|
-
duplicateDiagnostics([...collection.app, ...collection.capabilities].flatMap(document => document.acceptanceIds.map(id => ({ ...document, id }))), document => document.id, "APPSPEC_ACCEPTANCE_ID_DUPLICATED", diagnostics);
|
|
500
|
+
duplicateDiagnostics([...collection.capabilities, ...collection.activeChanges, ...collection.history, ...collection.decisions, ...collection.designs], document => document.id, "APPSPEC_DOCUMENT_ID_DUPLICATED", diagnostics);
|
|
501
|
+
duplicateDiagnostics([...collection.app, ...collection.capabilities, ...collection.designs].flatMap(document => document.requirementIds.map(id => ({ ...document, id }))), document => document.id, "APPSPEC_REQUIREMENT_ID_DUPLICATED", diagnostics);
|
|
502
|
+
duplicateDiagnostics([...collection.app, ...collection.capabilities, ...collection.designs].flatMap(document => document.acceptanceIds.map(id => ({ ...document, id }))), document => document.id, "APPSPEC_ACCEPTANCE_ID_DUPLICATED", diagnostics);
|
|
490
503
|
const capabilityIds = new Set(collection.capabilities.map(document => document.id));
|
|
491
|
-
const requirementIds = new Set([...collection.app, ...collection.capabilities].flatMap(document => document.requirementIds));
|
|
492
|
-
const acceptanceIds = new Set([...collection.app, ...collection.capabilities].flatMap(document => document.acceptanceIds));
|
|
504
|
+
const requirementIds = new Set([...collection.app, ...collection.capabilities, ...collection.designs].flatMap(document => document.requirementIds));
|
|
505
|
+
const acceptanceIds = new Set([...collection.app, ...collection.capabilities, ...collection.designs].flatMap(document => document.acceptanceIds));
|
|
493
506
|
const resourceCodes = new Set(contract.resourceCodes);
|
|
494
507
|
const actionCodes = new Set(contract.actionCodes);
|
|
495
508
|
const decisionIds = new Set(collection.decisions.map(document => document.id));
|
|
@@ -542,8 +555,8 @@ function validateCloseConvergence(document, collection, contract, diagnostics) {
|
|
|
542
555
|
diagnostics.push(issue("error", "APPSPEC_CURRENT_SPEC_NOT_CONVERGED", "关闭前必须确认 currentSpec=merged 或 not-applicable;该检查只约束 spec close", document.path));
|
|
543
556
|
}
|
|
544
557
|
const capabilityIds = new Set(collection.capabilities.map(item => item.id));
|
|
545
|
-
const requirementIds = new Set([...collection.app, ...collection.capabilities].flatMap(item => item.requirementIds));
|
|
546
|
-
const acceptanceIds = new Set([...collection.app, ...collection.capabilities].flatMap(item => item.acceptanceIds));
|
|
558
|
+
const requirementIds = new Set([...collection.app, ...collection.capabilities, ...collection.designs].flatMap(item => item.requirementIds));
|
|
559
|
+
const acceptanceIds = new Set([...collection.app, ...collection.capabilities, ...collection.designs].flatMap(item => item.acceptanceIds));
|
|
547
560
|
const decisionIds = new Set(collection.decisions.map(item => item.id));
|
|
548
561
|
for (const id of document.references.capabilities) {
|
|
549
562
|
const matches = collection.capabilities.filter(item => item.id === id);
|
|
@@ -555,7 +568,7 @@ function validateCloseConvergence(document, collection, contract, diagnostics) {
|
|
|
555
568
|
}
|
|
556
569
|
}
|
|
557
570
|
for (const id of document.references.requirements) {
|
|
558
|
-
const matches = [...collection.app, ...collection.capabilities].filter(item => item.requirementIds.includes(id));
|
|
571
|
+
const matches = [...collection.app, ...collection.capabilities, ...collection.designs].filter(item => item.requirementIds.includes(id));
|
|
559
572
|
if (!requirementIds.has(id)) {
|
|
560
573
|
diagnostics.push(issue("error", "APPSPEC_CHANGE_REQUIREMENT_UNKNOWN", `关闭前必须把需求 ${id} 合入当前总纲或能力规格`, document.path));
|
|
561
574
|
}
|
|
@@ -573,13 +586,13 @@ function validateCloseConvergence(document, collection, contract, diagnostics) {
|
|
|
573
586
|
}
|
|
574
587
|
}
|
|
575
588
|
for (const id of document.requirementIds) {
|
|
576
|
-
const matches = [...collection.app, ...collection.capabilities].filter(item => item.requirementIds.includes(id));
|
|
589
|
+
const matches = [...collection.app, ...collection.capabilities, ...collection.designs].filter(item => item.requirementIds.includes(id));
|
|
577
590
|
if (matches.length > 1) {
|
|
578
591
|
diagnostics.push(issue("error", "APPSPEC_REQUIREMENT_ID_DUPLICATED", `关闭前必须消除需求 ${id} 的重复定义`, document.path));
|
|
579
592
|
}
|
|
580
593
|
}
|
|
581
594
|
for (const id of document.acceptanceIds) {
|
|
582
|
-
const matches = [...collection.app, ...collection.capabilities].filter(item => item.acceptanceIds.includes(id));
|
|
595
|
+
const matches = [...collection.app, ...collection.capabilities, ...collection.designs].filter(item => item.acceptanceIds.includes(id));
|
|
583
596
|
if (matches.length > 1) {
|
|
584
597
|
diagnostics.push(issue("error", "APPSPEC_ACCEPTANCE_ID_DUPLICATED", `关闭前必须消除验收场景 ${id} 的重复定义`, document.path));
|
|
585
598
|
}
|
|
@@ -652,7 +665,7 @@ function validateRiskSections(document, diagnostics) {
|
|
|
652
665
|
}
|
|
653
666
|
}
|
|
654
667
|
}
|
|
655
|
-
function
|
|
668
|
+
function selectBaseContext(collection, selector, diagnostics) {
|
|
656
669
|
if (!selector) {
|
|
657
670
|
return {
|
|
658
671
|
primary: collection.app[0] || null,
|
|
@@ -662,6 +675,9 @@ function selectContext(collection, selector, diagnostics) {
|
|
|
662
675
|
decisions: [],
|
|
663
676
|
};
|
|
664
677
|
}
|
|
678
|
+
const design = collection.designs.find(document => document.id === selector);
|
|
679
|
+
if (design)
|
|
680
|
+
return { primary: design, capabilities: [], activeChanges: [], archivedChanges: [], decisions: [] };
|
|
665
681
|
const change = collection.activeChanges.find(document => document.id === selector);
|
|
666
682
|
if (change) {
|
|
667
683
|
const capabilityIds = new Set(change.references.capabilities);
|
|
@@ -717,12 +733,43 @@ function selectContext(collection, selector, diagnostics) {
|
|
|
717
733
|
decisions: [],
|
|
718
734
|
};
|
|
719
735
|
}
|
|
736
|
+
function selectContext(collection, selector, diagnostics) {
|
|
737
|
+
const base = selectBaseContext(collection, selector, diagnostics);
|
|
738
|
+
const designs = [];
|
|
739
|
+
const selected = { ...base, capabilities: [...base.capabilities], decisions: [...base.decisions], designs };
|
|
740
|
+
if (!selector)
|
|
741
|
+
return selected;
|
|
742
|
+
const available = [...collection.app, ...collection.capabilities, ...collection.decisions, ...collection.designs];
|
|
743
|
+
const queue = [base.primary, ...base.capabilities, ...base.decisions].filter((item) => !!item);
|
|
744
|
+
const seen = new Set();
|
|
745
|
+
for (let index = 0; index < queue.length; index++) {
|
|
746
|
+
const document = queue[index];
|
|
747
|
+
if (seen.has(document.id))
|
|
748
|
+
continue;
|
|
749
|
+
seen.add(document.id);
|
|
750
|
+
if (document.kind === 'design')
|
|
751
|
+
designs.push(document);
|
|
752
|
+
if (document.kind === 'capability' && !selected.capabilities.includes(document))
|
|
753
|
+
selected.capabilities.push(document);
|
|
754
|
+
if (document.kind === 'decision' && !selected.decisions.includes(document))
|
|
755
|
+
selected.decisions.push(document);
|
|
756
|
+
for (const id of document.references.documents) {
|
|
757
|
+
const target = available.find(item => item.id === id);
|
|
758
|
+
if (!target)
|
|
759
|
+
diagnostics.push(issue('error', 'APPSPEC_DESIGN_REFERENCE_UNKNOWN', `设计引用 ${id} 不存在;先恢复资料或修正引用`, document.path));
|
|
760
|
+
else if (!seen.has(id))
|
|
761
|
+
queue.push(target);
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
return selected;
|
|
765
|
+
}
|
|
720
766
|
function summarizeCollection(collection) {
|
|
721
767
|
return {
|
|
722
768
|
application: collection.app[0] ? summarize(collection.app[0]) : null,
|
|
723
769
|
capabilities: collection.capabilities.map(summarize),
|
|
724
770
|
activeChanges: collection.activeChanges.map(summarize),
|
|
725
771
|
decisions: collection.decisions.map(summarize),
|
|
772
|
+
designs: collection.designs.map(summarize),
|
|
726
773
|
history: collection.history.map(summarize),
|
|
727
774
|
};
|
|
728
775
|
}
|
|
@@ -734,6 +781,7 @@ function selectedDocuments(application, selected) {
|
|
|
734
781
|
...selected.activeChanges,
|
|
735
782
|
...selected.archivedChanges,
|
|
736
783
|
...selected.decisions,
|
|
784
|
+
...selected.designs,
|
|
737
785
|
]);
|
|
738
786
|
}
|
|
739
787
|
function applyContextBudget(application, selected) {
|
|
@@ -757,6 +805,7 @@ function applyContextBudget(application, selected) {
|
|
|
757
805
|
activeChanges: keep(selected.activeChanges),
|
|
758
806
|
archivedChanges: keep(selected.archivedChanges),
|
|
759
807
|
decisions: keep(selected.decisions),
|
|
808
|
+
designs: keep(selected.designs),
|
|
760
809
|
contextBudget: {
|
|
761
810
|
maximumBytes: APP_SPEC_LIMITS.maximumContextBytes,
|
|
762
811
|
contentBytes,
|
|
@@ -812,20 +861,24 @@ function parseAppSpecDocument(root, path, kind, content, diagnostics) {
|
|
|
812
861
|
? CAPABILITY_ID
|
|
813
862
|
: kind === "decision"
|
|
814
863
|
? DECISION_ID
|
|
815
|
-
: CHANGE_ID;
|
|
864
|
+
: kind === "design" ? /^DES-[A-Z0-9]+(?:-[A-Z0-9]+)*$/ : CHANGE_ID;
|
|
816
865
|
if (!pattern.test(id)) {
|
|
817
|
-
diagnostics.push(issue("error", "APPSPEC_DOCUMENT_ID_INVALID", `无效 ${kind} id: ${id}`, pointer));
|
|
866
|
+
diagnostics.push(issue("error", "APPSPEC_DOCUMENT_ID_INVALID", `无效 ${kind} id: ${id}${kind === 'decision' ? ';请使用 ADR- 加四位数字,可选大写字母/数字后缀,例如 ADR-0001 或 ADR-0001-DATA-OWNER,参见 docs appspec' : ''}`, pointer));
|
|
818
867
|
}
|
|
819
868
|
const status = String(frontMatter.metadata.status || "draft");
|
|
820
869
|
const validStatuses = {
|
|
821
870
|
app: ["active", "retired"],
|
|
822
871
|
capability: ["draft", "active", "retired"],
|
|
823
872
|
change: ["draft", "confirmed", "implementing", "verified", "released", "archived", "cancelled"],
|
|
873
|
+
design: ["draft", "confirmed", "superseded", "rejected"],
|
|
824
874
|
decision: ["proposed", "accepted", "superseded", "rejected"],
|
|
825
875
|
};
|
|
826
876
|
if (!validStatuses[kind].includes(status)) {
|
|
827
877
|
diagnostics.push(issue("error", "APPSPEC_STATUS_INVALID", `${kind} status=${status} 不受支持`, pointer));
|
|
828
878
|
}
|
|
879
|
+
if (kind === 'design' && !['sources', 'product', 'journey', 'page', 'visual', 'permissions', 'architecture', 'review'].includes(String(frontMatter.metadata.type))) {
|
|
880
|
+
diagnostics.push(issue('error', 'APPSPEC_DESIGN_TYPE_INVALID', '设计资料需要明确 type,参见 docs product-design', pointer));
|
|
881
|
+
}
|
|
829
882
|
if (kind === "change") {
|
|
830
883
|
const currentSpec = String(frontMatter.metadata.currentSpec || "pending");
|
|
831
884
|
if (!["pending", "merged", "not-applicable"].includes(currentSpec)) {
|
|
@@ -851,6 +904,7 @@ function parseAppSpecDocument(root, path, kind, content, diagnostics) {
|
|
|
851
904
|
resources: metadataStrings(frontMatter.metadata, "resources"),
|
|
852
905
|
actions: metadataStrings(frontMatter.metadata, "actions"),
|
|
853
906
|
decisions: metadataStrings(frontMatter.metadata, "decisions"),
|
|
907
|
+
documents: metadataStrings(frontMatter.metadata, "documents"),
|
|
854
908
|
},
|
|
855
909
|
content,
|
|
856
910
|
};
|
|
@@ -1061,7 +1115,7 @@ status: active
|
|
|
1061
1115
|
---
|
|
1062
1116
|
# ${appName}
|
|
1063
1117
|
|
|
1064
|
-
|
|
1118
|
+
本文件是当前有效设计的总纲与目录。新应用先完成产品发现、详细设计与实际确认,形成评审基线后再制定实施计划;按 docs product-design 在 AppSpec 中建立相关材料。正式变更关联 ChangeSpec;测试发布前核对设计与验收计划,生产晋级前核对实际验收。资源、字段、权限和动作的实现以
|
|
1065
1119
|
\`openxiangda.config.ts\` 与实时编译合同为准。
|
|
1066
1120
|
|
|
1067
1121
|
## 业务目标
|
|
@@ -1078,6 +1132,10 @@ status: active
|
|
|
1078
1132
|
|
|
1079
1133
|
### 不包含
|
|
1080
1134
|
|
|
1135
|
+
## 设计资料目录
|
|
1136
|
+
|
|
1137
|
+
<!-- 引用产品、旅程、页面、视觉、权限、架构与评审的稳定 ID;详细规则各有唯一归属。 -->
|
|
1138
|
+
|
|
1081
1139
|
## 能力目录
|
|
1082
1140
|
|
|
1083
1141
|
<!-- 复杂业务再在 capabilities/ 下增加 CAP-*;简单应用的稳定规则直接写在本文件。 -->
|
|
@@ -1317,9 +1375,11 @@ function withoutHtmlComments(content) {
|
|
|
1317
1375
|
}
|
|
1318
1376
|
function validateMetadata(kind, metadata, pointer, diagnostics) {
|
|
1319
1377
|
const allowed = {
|
|
1320
|
-
app: new Set(["schema", "app", "title", "status"]),
|
|
1378
|
+
app: new Set(["schema", "app", "title", "status", "documents"]),
|
|
1379
|
+
design: new Set(["schema", "id", "title", "status", "type", "documents", "scope", "baselineDigest", "confirmedBy", "confirmedAt", "confirmationSource", "capabilities", "requirements", "resources", "actions", "decisions"]),
|
|
1321
1380
|
capability: new Set([
|
|
1322
1381
|
"schema",
|
|
1382
|
+
"documents",
|
|
1323
1383
|
"id",
|
|
1324
1384
|
"title",
|
|
1325
1385
|
"status",
|
|
@@ -1328,6 +1388,7 @@ function validateMetadata(kind, metadata, pointer, diagnostics) {
|
|
|
1328
1388
|
]),
|
|
1329
1389
|
change: new Set([
|
|
1330
1390
|
"schema",
|
|
1391
|
+
"documents",
|
|
1331
1392
|
"id",
|
|
1332
1393
|
"title",
|
|
1333
1394
|
"status",
|
|
@@ -1343,6 +1404,7 @@ function validateMetadata(kind, metadata, pointer, diagnostics) {
|
|
|
1343
1404
|
]),
|
|
1344
1405
|
decision: new Set([
|
|
1345
1406
|
"schema",
|
|
1407
|
+
"documents",
|
|
1346
1408
|
"id",
|
|
1347
1409
|
"title",
|
|
1348
1410
|
"status",
|