spec-manager 0.1.1 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (101) hide show
  1. package/README.md +58 -7
  2. package/dist/cli/change.d.ts.map +1 -1
  3. package/dist/cli/change.js +93 -4
  4. package/dist/cli/change.js.map +1 -1
  5. package/dist/cli/index.js +4 -1
  6. package/dist/cli/index.js.map +1 -1
  7. package/dist/cli/project.d.ts.map +1 -1
  8. package/dist/cli/project.js +50 -0
  9. package/dist/cli/project.js.map +1 -1
  10. package/dist/cli/task.d.ts.map +1 -1
  11. package/dist/cli/task.js +146 -41
  12. package/dist/cli/task.js.map +1 -1
  13. package/dist/core/agents.d.ts +17 -0
  14. package/dist/core/agents.d.ts.map +1 -1
  15. package/dist/core/agents.js +43 -1
  16. package/dist/core/agents.js.map +1 -1
  17. package/dist/core/archive.d.ts.map +1 -1
  18. package/dist/core/archive.js +74 -2
  19. package/dist/core/archive.js.map +1 -1
  20. package/dist/core/audit.d.ts +1 -0
  21. package/dist/core/audit.d.ts.map +1 -1
  22. package/dist/core/audit.js +60 -40
  23. package/dist/core/audit.js.map +1 -1
  24. package/dist/core/completion.js +1 -1
  25. package/dist/core/completion.js.map +1 -1
  26. package/dist/core/delta.d.ts +30 -1
  27. package/dist/core/delta.d.ts.map +1 -1
  28. package/dist/core/delta.js +141 -4
  29. package/dist/core/delta.js.map +1 -1
  30. package/dist/core/harness.d.ts +69 -0
  31. package/dist/core/harness.d.ts.map +1 -0
  32. package/dist/core/harness.js +278 -0
  33. package/dist/core/harness.js.map +1 -0
  34. package/dist/core/integrity-exemptions.d.ts +29 -0
  35. package/dist/core/integrity-exemptions.d.ts.map +1 -0
  36. package/dist/core/integrity-exemptions.js +100 -0
  37. package/dist/core/integrity-exemptions.js.map +1 -0
  38. package/dist/core/integrity.d.ts +12 -0
  39. package/dist/core/integrity.d.ts.map +1 -0
  40. package/dist/core/integrity.js +163 -0
  41. package/dist/core/integrity.js.map +1 -0
  42. package/dist/core/invariants.d.ts +5 -0
  43. package/dist/core/invariants.d.ts.map +1 -0
  44. package/dist/core/invariants.js +19 -0
  45. package/dist/core/invariants.js.map +1 -0
  46. package/dist/core/lifecycle.d.ts +37 -0
  47. package/dist/core/lifecycle.d.ts.map +1 -0
  48. package/dist/core/lifecycle.js +70 -0
  49. package/dist/core/lifecycle.js.map +1 -0
  50. package/dist/core/paths.d.ts +3 -0
  51. package/dist/core/paths.d.ts.map +1 -1
  52. package/dist/core/paths.js +19 -1
  53. package/dist/core/paths.js.map +1 -1
  54. package/dist/core/reconciliation.d.ts +25 -0
  55. package/dist/core/reconciliation.d.ts.map +1 -0
  56. package/dist/core/reconciliation.js +122 -0
  57. package/dist/core/reconciliation.js.map +1 -0
  58. package/dist/core/remediation.d.ts +41 -0
  59. package/dist/core/remediation.d.ts.map +1 -0
  60. package/dist/core/remediation.js +169 -0
  61. package/dist/core/remediation.js.map +1 -0
  62. package/dist/core/spec-io.d.ts +2 -0
  63. package/dist/core/spec-io.d.ts.map +1 -1
  64. package/dist/core/spec-io.js +23 -2
  65. package/dist/core/spec-io.js.map +1 -1
  66. package/dist/core/status.d.ts +2 -0
  67. package/dist/core/status.d.ts.map +1 -1
  68. package/dist/core/status.js +7 -0
  69. package/dist/core/status.js.map +1 -1
  70. package/dist/core/task.d.ts +24 -0
  71. package/dist/core/task.d.ts.map +1 -1
  72. package/dist/core/task.js +62 -43
  73. package/dist/core/task.js.map +1 -1
  74. package/dist/core/transaction.d.ts +10 -0
  75. package/dist/core/transaction.d.ts.map +1 -0
  76. package/dist/core/transaction.js +65 -0
  77. package/dist/core/transaction.js.map +1 -0
  78. package/dist/core/usability.d.ts.map +1 -1
  79. package/dist/core/usability.js +50 -13
  80. package/dist/core/usability.js.map +1 -1
  81. package/dist/index.d.ts +7 -0
  82. package/dist/index.d.ts.map +1 -1
  83. package/dist/index.js +7 -0
  84. package/dist/index.js.map +1 -1
  85. package/dist/schemas/change.d.ts +20 -20
  86. package/dist/schemas/spec.d.ts +12 -12
  87. package/package.json +1 -1
  88. package/rules/doc-governance.md +2 -2
  89. package/skill/SKILL.md +12 -9
  90. package/skill/subskills/adr.md +2 -2
  91. package/skill/subskills/change.md +4 -4
  92. package/skill/subskills/design.md +4 -4
  93. package/skill/subskills/impl.md +9 -9
  94. package/skill/subskills/plan.md +1 -1
  95. package/skill/subskills/postmortem.md +1 -1
  96. package/skill/subskills/prd.md +9 -9
  97. package/skill/subskills/release.md +2 -2
  98. package/skill/subskills/runbook.md +1 -1
  99. package/skill/subskills/testplan.md +2 -2
  100. package/templates/L2-design.md +2 -2
  101. package/templates/L3-impl.md +1 -1
@@ -0,0 +1,19 @@
1
+ const MUTABLE_TASK_STATUSES = new Set(['running']);
2
+ const ACTIVE_TASK_STATUSES = new Set(['draft', 'running', 'waiting']);
3
+ export function assertTaskMutable(task, operation) {
4
+ if (!MUTABLE_TASK_STATUSES.has(task.status)) {
5
+ throw new Error(`TASK_IMMUTABLE: cannot ${operation} task ${task.id} with status=${task.status}`);
6
+ }
7
+ }
8
+ export function assertNoActiveTaskForSpec(tasks, specCode) {
9
+ const active = tasks.find(task => task.specCode === specCode && ACTIVE_TASK_STATUSES.has(task.status));
10
+ if (active) {
11
+ throw new Error(`TASK_ALREADY_ACTIVE: ${specCode} already has ${active.id} status=${active.status}`);
12
+ }
13
+ }
14
+ export function assertTaskHasSuccessfulVerification(task) {
15
+ if (!(task.verifications ?? []).some(verification => verification.exitCode === 0)) {
16
+ throw new Error(`VERIFICATION_REQUIRED: task ${task.id} requires at least one successful verification`);
17
+ }
18
+ }
19
+ //# sourceMappingURL=invariants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"invariants.js","sourceRoot":"","sources":["../../src/core/invariants.ts"],"names":[],"mappings":"AAEA,MAAM,qBAAqB,GAAG,IAAI,GAAG,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;AACnD,MAAM,oBAAoB,GAAG,IAAI,GAAG,CAAC,CAAC,OAAO,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC;AAEtE,MAAM,UAAU,iBAAiB,CAAC,IAAgB,EAAE,SAAiB;IACnE,IAAI,CAAC,qBAAqB,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;QAC5C,MAAM,IAAI,KAAK,CAAC,0BAA0B,SAAS,SAAS,IAAI,CAAC,EAAE,gBAAgB,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;IACpG,CAAC;AACH,CAAC;AAED,MAAM,UAAU,yBAAyB,CAAC,KAAmB,EAAE,QAAgB;IAC7E,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,KAAK,QAAQ,IAAI,oBAAoB,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;IACvG,IAAI,MAAM,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CAAC,wBAAwB,QAAQ,gBAAgB,MAAM,CAAC,EAAE,WAAW,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;IACvG,CAAC;AACH,CAAC;AAED,MAAM,UAAU,mCAAmC,CAAC,IAAgB;IAClE,IAAI,CAAC,CAAC,IAAI,CAAC,aAAa,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC,YAAY,CAAC,QAAQ,KAAK,CAAC,CAAC,EAAE,CAAC;QAClF,MAAM,IAAI,KAAK,CAAC,+BAA+B,IAAI,CAAC,EAAE,gDAAgD,CAAC,CAAC;IAC1G,CAAC;AACH,CAAC"}
@@ -0,0 +1,37 @@
1
+ import type { AuditSink } from './audit-events.js';
2
+ import type { ProjectPaths } from './paths.js';
3
+ import type { ImplementationAuthority, SpecStatus } from './status.js';
4
+ import type { SpecLevel } from './validate.js';
5
+ export type { ImplementationAuthority } from './status.js';
6
+ export type ImplementationBlocker = 'missing-spec' | 'wrong-status' | 'no-children' | 'children-incomplete' | 'authority-not-allowed';
7
+ export interface ImplementationReadiness {
8
+ specCode: string;
9
+ level?: SpecLevel;
10
+ currentStatus?: SpecStatus;
11
+ expectedStatus: 'confirmed' | 'frozen';
12
+ ready: boolean;
13
+ alreadyImplemented: boolean;
14
+ blockers: ImplementationBlocker[];
15
+ }
16
+ export interface LifecycleCascadeResult {
17
+ cascadedSpecs: Array<{
18
+ code: string;
19
+ oldStatus: string;
20
+ newStatus: 'implemented';
21
+ level: SpecLevel;
22
+ }>;
23
+ skippedSpecs: Array<{
24
+ code: string;
25
+ status: string;
26
+ reason: string;
27
+ }>;
28
+ }
29
+ export interface CascadeImplementedHierarchyOptions {
30
+ paths: ProjectPaths;
31
+ startSpecCode: string;
32
+ authority: ImplementationAuthority;
33
+ auditSink?: AuditSink;
34
+ }
35
+ export declare function assessImplementationReadiness(paths: ProjectPaths, specCode: string, authority: ImplementationAuthority): ImplementationReadiness;
36
+ export declare function cascadeImplementedHierarchy(options: CascadeImplementedHierarchyOptions): LifecycleCascadeResult;
37
+ //# sourceMappingURL=lifecycle.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lifecycle.d.ts","sourceRoot":"","sources":["../../src/core/lifecycle.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C,OAAO,KAAK,EAAE,uBAAuB,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACvE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAE/C,YAAY,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AAE3D,MAAM,MAAM,qBAAqB,GAC7B,cAAc,GACd,cAAc,GACd,aAAa,GACb,qBAAqB,GACrB,uBAAuB,CAAC;AAE5B,MAAM,WAAW,uBAAuB;IACtC,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,aAAa,CAAC,EAAE,UAAU,CAAC;IAC3B,cAAc,EAAE,WAAW,GAAG,QAAQ,CAAC;IACvC,KAAK,EAAE,OAAO,CAAC;IACf,kBAAkB,EAAE,OAAO,CAAC;IAC5B,QAAQ,EAAE,qBAAqB,EAAE,CAAC;CACnC;AAED,MAAM,WAAW,sBAAsB;IACrC,aAAa,EAAE,KAAK,CAAC;QACnB,IAAI,EAAE,MAAM,CAAC;QACb,SAAS,EAAE,MAAM,CAAC;QAClB,SAAS,EAAE,aAAa,CAAC;QACzB,KAAK,EAAE,SAAS,CAAC;KAClB,CAAC,CAAC;IACH,YAAY,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACvE;AAED,MAAM,WAAW,kCAAkC;IACjD,KAAK,EAAE,YAAY,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,uBAAuB,CAAC;IACnC,SAAS,CAAC,EAAE,SAAS,CAAC;CACvB;AAED,wBAAgB,6BAA6B,CAC3C,KAAK,EAAE,YAAY,EACnB,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,uBAAuB,GACjC,uBAAuB,CAwCzB;AAED,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,kCAAkC,GAAG,sBAAsB,CAI/G"}
@@ -0,0 +1,70 @@
1
+ import { findSpecByCode, listAllSpecs, updateSpec } from './spec-io.js';
2
+ export function assessImplementationReadiness(paths, specCode, authority) {
3
+ const spec = findSpecByCode(paths, specCode);
4
+ const expectedStatus = spec?.fm.level === 'L3' ? 'frozen' : 'confirmed';
5
+ if (!spec) {
6
+ return { specCode, expectedStatus: 'confirmed', ready: false, alreadyImplemented: false, blockers: ['missing-spec'] };
7
+ }
8
+ if (spec.fm.status === 'implemented') {
9
+ return {
10
+ specCode,
11
+ level: spec.fm.level,
12
+ currentStatus: spec.fm.status,
13
+ expectedStatus,
14
+ ready: false,
15
+ alreadyImplemented: true,
16
+ blockers: [],
17
+ };
18
+ }
19
+ const blockers = [];
20
+ if (spec.fm.level === 'L3') {
21
+ if (authority !== 'task-complete')
22
+ blockers.push('authority-not-allowed');
23
+ if (spec.fm.status !== 'frozen')
24
+ blockers.push('wrong-status');
25
+ }
26
+ else if (spec.fm.level === 'L1' || spec.fm.level === 'L2') {
27
+ if (spec.fm.status !== 'confirmed')
28
+ blockers.push('wrong-status');
29
+ const children = listAllSpecs(paths).filter(child => child.fm.parentCode === specCode);
30
+ if (children.length === 0)
31
+ blockers.push('no-children');
32
+ else if (children.some(child => child.fm.status !== 'implemented'))
33
+ blockers.push('children-incomplete');
34
+ }
35
+ else {
36
+ blockers.push('authority-not-allowed');
37
+ }
38
+ return {
39
+ specCode,
40
+ level: spec.fm.level,
41
+ currentStatus: spec.fm.status,
42
+ expectedStatus,
43
+ ready: blockers.length === 0,
44
+ alreadyImplemented: false,
45
+ blockers,
46
+ };
47
+ }
48
+ export function cascadeImplementedHierarchy(options) {
49
+ const result = { cascadedSpecs: [], skippedSpecs: [] };
50
+ cascadeOne(options, options.startSpecCode, result);
51
+ return result;
52
+ }
53
+ function cascadeOne(options, specCode, result) {
54
+ const spec = findSpecByCode(options.paths, specCode);
55
+ const readiness = assessImplementationReadiness(options.paths, specCode, options.authority);
56
+ if (!spec || !readiness.ready) {
57
+ result.skippedSpecs.push({
58
+ code: specCode,
59
+ status: readiness.currentStatus ?? 'missing',
60
+ reason: readiness.alreadyImplemented ? 'already implemented' : readiness.blockers.join(', '),
61
+ });
62
+ return;
63
+ }
64
+ const oldStatus = spec.fm.status;
65
+ updateSpec(options.paths, specCode, { status: 'implemented', changeSummary: `cascade: ${options.authority}` }, { auditSink: options.auditSink, transitionAuthority: options.authority });
66
+ result.cascadedSpecs.push({ code: specCode, oldStatus, newStatus: 'implemented', level: spec.fm.level });
67
+ if (spec.fm.parentCode)
68
+ cascadeOne(options, spec.fm.parentCode, result);
69
+ }
70
+ //# sourceMappingURL=lifecycle.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lifecycle.js","sourceRoot":"","sources":["../../src/core/lifecycle.ts"],"names":[],"mappings":"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"}
@@ -9,6 +9,7 @@ export interface ProjectPaths {
9
9
  configDir: string;
10
10
  configFile: string;
11
11
  auditFile: string;
12
+ integrityExemptionsFile: string;
12
13
  incidentsDir: string;
13
14
  dictFile: string;
14
15
  specsDir: string;
@@ -31,6 +32,8 @@ export declare function getPaths(root?: string): ProjectPaths;
31
32
  export declare function specFilePath(paths: ProjectPaths, _parentFilePath: string | null, code: string, topic?: string, _date?: string): string;
32
33
  export declare function assertSafeTopic(topic: string): void;
33
34
  export declare function assertSafeSpecCode(code: string): void;
35
+ export declare function assertSafeChangeName(name: string): void;
36
+ export declare function resolveWithin(baseDir: string, ...segments: string[]): string;
34
37
  /**
35
38
  * 平铺布局下,元数据目录在 topic 级别:
36
39
  * specs/<topic>/decisions/、specs/<topic>/tasks/
@@ -1 +1 @@
1
- {"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../src/core/paths.ts"],"names":[],"mappings":"AAIA;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,GAAE,MAAsB,GAAG,MAAM,CAYtE;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,OAAO,CAAC;CACxB;AAED,wBAAgB,QAAQ,CAAC,IAAI,GAAE,MAA6B,GAAG,YAAY,CAe1E;AAUD;;;;;;;;;;GAUG;AACH,wBAAgB,YAAY,CAC1B,KAAK,EAAE,YAAY,EACnB,eAAe,EAAE,MAAM,GAAG,IAAI,EAC9B,IAAI,EAAE,MAAM,EACZ,KAAK,CAAC,EAAE,MAAM,EACd,KAAK,CAAC,EAAE,MAAM,GACb,MAAM,CAKR;AASD,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAInD;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAIrD;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,YAAY,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,GAAG,OAAO,GAAG,MAAM,CAExF;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,WAAW,GAAG,aAAa,CAAC;IACpC,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,YAAY,GAAG,aAAa,EAAE,CAqBlE;AAED,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,YAAY,GAAG,iBAAiB,EAAE,CAoB/E;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,kBAAkB,GAAG,IAAI,CAU7E"}
1
+ {"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../src/core/paths.ts"],"names":[],"mappings":"AAIA;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,GAAE,MAAsB,GAAG,MAAM,CAYtE;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,uBAAuB,EAAE,MAAM,CAAC;IAChC,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,OAAO,CAAC;CACxB;AAED,wBAAgB,QAAQ,CAAC,IAAI,GAAE,MAA6B,GAAG,YAAY,CAgB1E;AAUD;;;;;;;;;;GAUG;AACH,wBAAgB,YAAY,CAC1B,KAAK,EAAE,YAAY,EACnB,eAAe,EAAE,MAAM,GAAG,IAAI,EAC9B,IAAI,EAAE,MAAM,EACZ,KAAK,CAAC,EAAE,MAAM,EACd,KAAK,CAAC,EAAE,MAAM,GACb,MAAM,CAKR;AASD,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAInD;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAIrD;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAIvD;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,QAAQ,EAAE,MAAM,EAAE,GAAG,MAAM,CAW5E;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,YAAY,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,GAAG,OAAO,GAAG,MAAM,CAExF;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,WAAW,GAAG,aAAa,CAAC;IACpC,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,YAAY,GAAG,aAAa,EAAE,CAqBlE;AAED,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,YAAY,GAAG,iBAAiB,EAAE,CAoB/E;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,kBAAkB,GAAG,IAAI,CAU7E"}
@@ -1,5 +1,5 @@
1
1
  import { existsSync, readdirSync, statSync } from 'node:fs';
2
- import { dirname, join, resolve } from 'node:path';
2
+ import { dirname, isAbsolute, join, relative, resolve } from 'node:path';
3
3
  import { SPEC_CODE_RE, TOPIC_RE } from './constants.js';
4
4
  /**
5
5
  * 解析项目根目录。
@@ -29,6 +29,7 @@ export function getPaths(root = resolveProjectRoot()) {
29
29
  configDir,
30
30
  configFile: join(configDir, 'config.yaml'),
31
31
  auditFile: join(configDir, 'audit.json'),
32
+ integrityExemptionsFile: join(configDir, 'integrity-exemptions.json'),
32
33
  incidentsDir: join(configDir, 'incidents'),
33
34
  dictFile: join(configDir, 'dict.yaml'),
34
35
  specsDir: join(root, 'specs'),
@@ -79,6 +80,23 @@ export function assertSafeSpecCode(code) {
79
80
  throw new Error(`spec code 非法: ${code}(必须匹配 ${SPEC_CODE_RE.source},且不能包含路径分隔符)`);
80
81
  }
81
82
  }
83
+ export function assertSafeChangeName(name) {
84
+ if (!/^[a-z0-9-]+$/.test(name)) {
85
+ throw new Error(`PATH_OUTSIDE_PROJECT: change name 非法: ${name}`);
86
+ }
87
+ }
88
+ export function resolveWithin(baseDir, ...segments) {
89
+ if (segments.some(segment => isAbsolute(segment))) {
90
+ throw new Error(`PATH_OUTSIDE_PROJECT: absolute path is not allowed`);
91
+ }
92
+ const base = resolve(baseDir);
93
+ const target = resolve(base, ...segments);
94
+ const rel = relative(base, target);
95
+ if (rel === '..' || rel.startsWith(`..${process.platform === 'win32' ? '\\' : '/'}`) || isAbsolute(rel)) {
96
+ throw new Error(`PATH_OUTSIDE_PROJECT: ${target} is outside ${base}`);
97
+ }
98
+ return target;
99
+ }
82
100
  /**
83
101
  * 平铺布局下,元数据目录在 topic 级别:
84
102
  * specs/<topic>/decisions/、specs/<topic>/tasks/
@@ -1 +1 @@
1
- {"version":3,"file":"paths.js","sourceRoot":"","sources":["../../src/core/paths.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"paths.js","sourceRoot":"","sources":["../../src/core/paths.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC5D,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzE,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAExD;;;;GAIG;AACH,MAAM,UAAU,kBAAkB,CAAC,MAAc,OAAO,CAAC,GAAG,EAAE;IAC5D,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC;IAC9C,IAAI,OAAO;QAAE,OAAO,OAAO,CAAC,OAAO,CAAC,CAAC;IAErC,IAAI,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;IACvB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QAC3B,IAAI,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,eAAe,CAAC,CAAC;YAAE,OAAO,GAAG,CAAC;QACvD,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;QAC5B,IAAI,MAAM,KAAK,GAAG;YAAE,MAAM;QAC1B,GAAG,GAAG,MAAM,CAAC;IACf,CAAC;IACD,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC;AACtB,CAAC;AAgBD,MAAM,UAAU,QAAQ,CAAC,OAAe,kBAAkB,EAAE;IAC1D,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,EAAE,eAAe,CAAC,CAAC;IAC9C,MAAM,aAAa,GAAG,QAAQ,CAAC,SAAS,CAAC,EAAE,WAAW,EAAE,IAAI,KAAK,CAAC;IAClE,OAAO;QACL,IAAI;QACJ,SAAS;QACT,UAAU,EAAE,IAAI,CAAC,SAAS,EAAE,aAAa,CAAC;QAC1C,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,YAAY,CAAC;QACxC,uBAAuB,EAAE,IAAI,CAAC,SAAS,EAAE,2BAA2B,CAAC;QACrE,YAAY,EAAE,IAAI,CAAC,SAAS,EAAE,WAAW,CAAC;QAC1C,QAAQ,EAAE,IAAI,CAAC,SAAS,EAAE,WAAW,CAAC;QACtC,QAAQ,EAAE,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC;QAC7B,UAAU,EAAE,IAAI,CAAC,IAAI,EAAE,SAAS,CAAC;QACjC,UAAU,EAAE,IAAI,CAAC,IAAI,EAAE,SAAS,CAAC;QACjC,aAAa;KACd,CAAC;AACJ,CAAC;AAED,SAAS,QAAQ,CAAC,CAAS;IACzB,IAAI,CAAC;QACH,OAAO,QAAQ,CAAC,CAAC,CAAC,CAAC;IACrB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,YAAY,CAC1B,KAAmB,EACnB,eAA8B,EAC9B,IAAY,EACZ,KAAc,EACd,KAAc;IAEd,kBAAkB,CAAC,IAAI,CAAC,CAAC;IACzB,MAAM,CAAC,GAAG,KAAK,IAAI,oBAAoB,CAAC,IAAI,CAAC,CAAC;IAC9C,eAAe,CAAC,CAAC,CAAC,CAAC;IACnB,OAAO,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,EAAE,GAAG,IAAI,KAAK,CAAC,CAAC;AAC/C,CAAC;AAED,SAAS,oBAAoB,CAAC,IAAY;IACxC,6CAA6C;IAC7C,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;IACtC,IAAI,KAAK;QAAE,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC;IAC3B,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;AACjE,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,KAAa;IAC3C,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QAC1B,MAAM,IAAI,KAAK,CAAC,aAAa,KAAK,SAAS,QAAQ,CAAC,MAAM,cAAc,CAAC,CAAC;IAC5E,CAAC;AACH,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,IAAY;IAC7C,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QAC7B,MAAM,IAAI,KAAK,CAAC,iBAAiB,IAAI,SAAS,YAAY,CAAC,MAAM,cAAc,CAAC,CAAC;IACnF,CAAC;AACH,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,IAAY;IAC/C,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QAC/B,MAAM,IAAI,KAAK,CAAC,yCAAyC,IAAI,EAAE,CAAC,CAAC;IACnE,CAAC;AACH,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,OAAe,EAAE,GAAG,QAAkB;IAClE,IAAI,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC;QAClD,MAAM,IAAI,KAAK,CAAC,oDAAoD,CAAC,CAAC;IACxE,CAAC;IACD,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC9B,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,EAAE,GAAG,QAAQ,CAAC,CAAC;IAC1C,MAAM,GAAG,GAAG,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACnC,IAAI,GAAG,KAAK,IAAI,IAAI,GAAG,CAAC,UAAU,CAAC,KAAK,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,IAAI,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACxG,MAAM,IAAI,KAAK,CAAC,yBAAyB,MAAM,eAAe,IAAI,EAAE,CAAC,CAAC;IACxE,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,YAAoB,EAAE,IAA2B;IAC9E,OAAO,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,IAAI,CAAC,CAAC;AAC3C,CAAC;AAsBD;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,KAAmB;IAC/C,MAAM,GAAG,GAAoB,EAAE,CAAC;IAChC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,QAAQ,CAAC;QAAE,OAAO,GAAG,CAAC;IAC5C,KAAK,MAAM,UAAU,IAAI,WAAW,CAAC,KAAK,CAAC,QAAQ,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;QAC9E,IAAI,CAAC,UAAU,CAAC,WAAW,EAAE,IAAI,UAAU,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,SAAS;QAC3E,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,UAAU,CAAC,IAAI,CAAC,CAAC;QACvD,KAAK,MAAM,IAAI,IAAI,WAAW,CAAC,QAAQ,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;YAClE,IAAI,IAAI,CAAC,WAAW,EAAE;gBAAE,SAAS;YACjC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC;gBAAE,SAAS;YACzC,IAAI,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;gBAAE,SAAS;YACxC,MAAM,MAAM,GAAG,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC5C,IAAI,CAAC,MAAM;gBAAE,SAAS;YACtB,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;YAC3C,MAAM,GAAG,GAAG,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,UAAU,CAAC,IAAI,IAAI,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC;YACjF,IAAI,GAAG,EAAE,CAAC;gBACR,MAAM,IAAI,KAAK,CAAC,iBAAiB,MAAM,CAAC,IAAI,KAAK,GAAG,CAAC,QAAQ,KAAK,QAAQ,GAAG,CAAC,CAAC;YACjF,CAAC;YACD,GAAG,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,UAAU,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC;QACpE,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AAC1D,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,KAAmB;IACxD,MAAM,GAAG,GAAwB,EAAE,CAAC;IACpC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,QAAQ,CAAC;QAAE,OAAO,GAAG,CAAC;IAC5C,KAAK,MAAM,UAAU,IAAI,WAAW,CAAC,KAAK,CAAC,QAAQ,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;QAC9E,IAAI,CAAC,UAAU,CAAC,WAAW,EAAE,IAAI,UAAU,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,SAAS;QAC3E,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,UAAU,CAAC,IAAI,CAAC,CAAC;QACvD,KAAK,MAAM,IAAI,IAAI,WAAW,CAAC,QAAQ,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;YAClE,IAAI,IAAI,CAAC,WAAW,EAAE,IAAI,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC;gBAAE,SAAS;YAC5F,MAAM,MAAM,GAAG,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC5C,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,KAAK,aAAa,IAAI,CAAC,MAAM,CAAC,UAAU;gBAAE,SAAS;YAC/E,GAAG,CAAC,IAAI,CAAC;gBACP,KAAK,EAAE,UAAU,CAAC,IAAI;gBACtB,IAAI,EAAE,MAAM,CAAC,IAAI;gBACjB,IAAI,EAAE,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC;gBAC/B,EAAE,EAAE,IAAI,CAAC,QAAQ,EAAE,GAAG,MAAM,CAAC,IAAI,KAAK,CAAC;gBACvC,UAAU,EAAE,MAAM,CAAC,UAAU;aAC9B,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AAC1D,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAAC,QAAgB;IAChD,MAAM,MAAM,GAAG,QAAQ,CAAC,KAAK,CAAC,oBAAoB,CAAC,CAAC;IACpD,IAAI,MAAM,IAAI,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAC3C,OAAO,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;IAC3E,CAAC;IACD,MAAM,GAAG,GAAG,QAAQ,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;IACzC,IAAI,GAAG,IAAI,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACrC,OAAO,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC;IAC/C,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,25 @@
1
+ import type { ProjectPaths } from './paths.js';
2
+ import { type CreateDecisionInput } from './decision.js';
3
+ export interface ReconciliationAction {
4
+ action: 'implement' | 'create' | 'skip';
5
+ target: string;
6
+ detail: string;
7
+ }
8
+ export interface ReconciliationConflict {
9
+ target: string;
10
+ message: string;
11
+ }
12
+ export interface LifecycleReconciliationPlan {
13
+ implementationActions: ReconciliationAction[];
14
+ decisionActions: ReconciliationAction[];
15
+ conflicts: ReconciliationConflict[];
16
+ }
17
+ export interface LifecycleReconciliationReport extends LifecycleReconciliationPlan {
18
+ applied: boolean;
19
+ }
20
+ export declare const LIFECYCLE_RECONCILIATION_TARGETS: readonly ["architecture-hardening-L2.1", "architecture-hardening-L1", "harness-coding-L2.1", "harness-coding-L1", "repository-remediation-L2.1", "repository-remediation-L1"];
21
+ export declare const LIFECYCLE_RECONCILIATION_STARTS: readonly ["architecture-hardening-L2.1", "harness-coding-L2.1", "repository-remediation-L2.1"];
22
+ export declare const LIFECYCLE_RECONCILIATION_DECISIONS: Omit<CreateDecisionInput, 'paths'>[];
23
+ export declare function planLifecycleReconciliation(paths: ProjectPaths): LifecycleReconciliationPlan;
24
+ export declare function applyLifecycleReconciliation(paths: ProjectPaths): LifecycleReconciliationReport;
25
+ //# sourceMappingURL=reconciliation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reconciliation.d.ts","sourceRoot":"","sources":["../../src/core/reconciliation.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C,OAAO,EAAiD,KAAK,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAKxG,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,WAAW,GAAG,QAAQ,GAAG,MAAM,CAAC;IACxC,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,2BAA2B;IAC1C,qBAAqB,EAAE,oBAAoB,EAAE,CAAC;IAC9C,eAAe,EAAE,oBAAoB,EAAE,CAAC;IACxC,SAAS,EAAE,sBAAsB,EAAE,CAAC;CACrC;AAED,MAAM,WAAW,6BAA8B,SAAQ,2BAA2B;IAChF,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,eAAO,MAAM,gCAAgC,+KAOnC,CAAC;AAEX,eAAO,MAAM,+BAA+B,gGAIlC,CAAC;AAEX,eAAO,MAAM,kCAAkC,EAAE,IAAI,CAAC,mBAAmB,EAAE,OAAO,CAAC,EAmBlF,CAAC;AAEF,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,YAAY,GAAG,2BAA2B,CAkD5F;AAED,wBAAgB,4BAA4B,CAAC,KAAK,EAAE,YAAY,GAAG,6BAA6B,CA4B/F"}
@@ -0,0 +1,122 @@
1
+ import { join } from 'node:path';
2
+ import { siblingMetaDir } from './paths.js';
3
+ import { createDecision, listDecisions, nextDecisionId } from './decision.js';
4
+ import { cascadeImplementedHierarchy } from './lifecycle.js';
5
+ import { findSpecByCode, listAllSpecs } from './spec-io.js';
6
+ import { withProjectTransaction } from './transaction.js';
7
+ export const LIFECYCLE_RECONCILIATION_TARGETS = [
8
+ 'architecture-hardening-L2.1',
9
+ 'architecture-hardening-L1',
10
+ 'harness-coding-L2.1',
11
+ 'harness-coding-L1',
12
+ 'repository-remediation-L2.1',
13
+ 'repository-remediation-L1',
14
+ ];
15
+ export const LIFECYCLE_RECONCILIATION_STARTS = [
16
+ 'architecture-hardening-L2.1',
17
+ 'harness-coding-L2.1',
18
+ 'repository-remediation-L2.1',
19
+ ];
20
+ export const LIFECYCLE_RECONCILIATION_DECISIONS = [
21
+ {
22
+ docCode: 'architecture-hardening-L1',
23
+ topic: 'architecture-hardening',
24
+ what: '以领域不变量、完整性扫描和项目事务强化跨文件一致性与审计可信度。',
25
+ why: '集中修复任务绕过、路径安全、引用完整性、并发写入与验证门禁问题。',
26
+ },
27
+ {
28
+ docCode: 'harness-coding-L1',
29
+ topic: 'harness-coding',
30
+ what: '将任务上下文、执行回写、验证证据和变更闭环纳入 coding harness 控制层。',
31
+ why: '让 frozen L3 到实现结果形成可追踪、可验证、可审计的执行链路。',
32
+ },
33
+ {
34
+ docCode: 'repository-remediation-L1',
35
+ topic: 'repository-remediation',
36
+ what: '通过固定迁移、严格历史豁免和 merge-missing 资产补齐修复历史一致性。',
37
+ why: '在不篡改终态 Task 的前提下消除历史完整性问题并保持未来门禁。',
38
+ },
39
+ ];
40
+ export function planLifecycleReconciliation(paths) {
41
+ const specs = listAllSpecs(paths);
42
+ const byCode = new Map(specs.map(spec => [spec.fm.code, spec]));
43
+ const virtualImplemented = new Set(specs.filter(spec => spec.fm.status === 'implemented').map(spec => spec.fm.code));
44
+ const conflicts = [];
45
+ const implementationActions = [];
46
+ const targetSet = new Set(LIFECYCLE_RECONCILIATION_TARGETS);
47
+ for (const code of LIFECYCLE_RECONCILIATION_TARGETS) {
48
+ const spec = byCode.get(code);
49
+ if (!spec) {
50
+ conflicts.push({ target: code, message: `reconciliation target is missing: ${code}` });
51
+ continue;
52
+ }
53
+ if (spec.fm.status === 'implemented') {
54
+ implementationActions.push(action('skip', code, 'spec already implemented'));
55
+ virtualImplemented.add(code);
56
+ continue;
57
+ }
58
+ const children = specs.filter(child => child.fm.parentCode === code);
59
+ const ready = spec.fm.status === 'confirmed'
60
+ && children.length > 0
61
+ && children.every(child => virtualImplemented.has(child.fm.code));
62
+ if (!ready) {
63
+ conflicts.push({ target: code, message: `fixed reconciliation target is not ready: ${code}` });
64
+ continue;
65
+ }
66
+ implementationActions.push(action('implement', code, 'confirmed parent has only implemented direct children'));
67
+ virtualImplemented.add(code);
68
+ }
69
+ for (const spec of specs) {
70
+ if (targetSet.has(spec.fm.code) || spec.fm.status !== 'confirmed' || (spec.fm.level !== 'L1' && spec.fm.level !== 'L2'))
71
+ continue;
72
+ const children = specs.filter(child => child.fm.parentCode === spec.fm.code);
73
+ if (children.length > 0 && children.every(child => child.fm.status === 'implemented')) {
74
+ conflicts.push({ target: spec.fm.code, message: `ready reconciliation target is outside fixed scope: ${spec.fm.code}` });
75
+ }
76
+ }
77
+ const decisions = listDecisions(paths, { includeAll: true });
78
+ const decisionActions = LIFECYCLE_RECONCILIATION_DECISIONS.map(input => {
79
+ const existing = decisions.find(decision => decision.fm.docCode === input.docCode);
80
+ if (!existing)
81
+ return action('create', input.docCode, 'create missing Decision Card');
82
+ if (existing.fm.what !== input.what || existing.fm.why !== input.why) {
83
+ conflicts.push({ target: input.docCode, message: `existing Decision Card differs for ${input.docCode}` });
84
+ }
85
+ return action('skip', input.docCode, 'Decision Card already exists');
86
+ });
87
+ return { implementationActions, decisionActions, conflicts };
88
+ }
89
+ export function applyLifecycleReconciliation(paths) {
90
+ const plan = planLifecycleReconciliation(paths);
91
+ if (plan.conflicts.length > 0) {
92
+ throw new Error(`RECONCILIATION_CONFLICT: ${plan.conflicts.map(conflict => conflict.message).join('; ')}`);
93
+ }
94
+ withProjectTransaction(paths, 'lifecycle reconciliation', tx => {
95
+ for (const spec of listAllSpecs(paths))
96
+ tx.snapshot(spec.filePath);
97
+ for (const input of LIFECYCLE_RECONCILIATION_DECISIONS) {
98
+ const spec = findSpecByCode(paths, input.docCode);
99
+ if (!spec)
100
+ throw new Error(`Spec not found: ${input.docCode}`);
101
+ tx.snapshot(join(siblingMetaDir(spec.filePath, 'decisions'), `${nextDecisionId(paths, input.topic)}.md`));
102
+ }
103
+ for (const startSpecCode of LIFECYCLE_RECONCILIATION_STARTS) {
104
+ cascadeImplementedHierarchy({ paths, startSpecCode, authority: 'project-reconcile' });
105
+ }
106
+ for (const planned of plan.decisionActions.filter(item => item.action === 'create')) {
107
+ const input = LIFECYCLE_RECONCILIATION_DECISIONS.find(item => item.docCode === planned.target);
108
+ if (!input)
109
+ throw new Error(`missing reconciliation decision input: ${planned.target}`);
110
+ createDecision({ paths, ...input });
111
+ }
112
+ });
113
+ const finalPlan = planLifecycleReconciliation(paths);
114
+ if (finalPlan.conflicts.length > 0 || [...finalPlan.implementationActions, ...finalPlan.decisionActions].some(item => item.action !== 'skip')) {
115
+ throw new Error('RECONCILIATION_INCOMPLETE: reconciliation did not converge to an idempotent state');
116
+ }
117
+ return { ...plan, applied: true };
118
+ }
119
+ function action(actionName, target, detail) {
120
+ return { action: actionName, target, detail };
121
+ }
122
+ //# sourceMappingURL=reconciliation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reconciliation.js","sourceRoot":"","sources":["../../src/core/reconciliation.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ import type { ProjectPaths } from './paths.js';
2
+ import { type CreateDecisionInput } from './decision.js';
3
+ export declare const REPOSITORY_REMEDIATION_V1: "repository-remediation-v1";
4
+ export type RepositoryRemediationId = typeof REPOSITORY_REMEDIATION_V1;
5
+ export interface PlannedAction {
6
+ action: 'create' | 'skip';
7
+ target: string;
8
+ detail: string;
9
+ }
10
+ export interface RemediationConflict {
11
+ target: string;
12
+ message: string;
13
+ }
14
+ export interface RepositoryRemediationPlan {
15
+ migrationId: RepositoryRemediationId;
16
+ decisions: PlannedAction[];
17
+ exemptions: PlannedAction[];
18
+ agentAssets: PlannedAction[];
19
+ conflicts: RemediationConflict[];
20
+ }
21
+ export interface RepositoryRemediationOptions {
22
+ paths: ProjectPaths;
23
+ packageRoot: string;
24
+ migrationId: string;
25
+ now?: string;
26
+ }
27
+ export interface RepositoryRemediationReport extends RepositoryRemediationPlan {
28
+ applied: boolean;
29
+ }
30
+ export declare const REPOSITORY_REMEDIATION_V1_DECISIONS: Omit<CreateDecisionInput, 'paths'>[];
31
+ export declare const REPOSITORY_REMEDIATION_V1_TASKS: readonly [readonly ["spec-manager-ai-ux-L3.1.1-readme", "T-001"], readonly ["spec-manager-ai-ux-L3.1.2-skill", "T-001"], readonly ["spec-manager-ai-ux-L3.1.3-encoding", "T-001"], readonly ["spec-manager-ai-ux-L3.1.4-batch", "T-001"], readonly ["spec-manager-ai-ux-L3.1.5-tests", "T-001"], readonly ["roadmap-openspec-L3.1.1-guide", "T-001"], readonly ["workflow-hardening-L3.1.1-cli", "T-001"], readonly ["workflow-hardening-L3.1.2-hints", "T-001"], readonly ["workflow-hardening-L3.1.3-tools", "T-001"], readonly ["roadmap-openspec-L3.1.2-agents", "T-001"], readonly ["roadmap-openspec-L3.1.3-view", "T-001"], readonly ["l3-approval-L3.1.1-single-freeze", "T-001"], readonly ["roadmap-openspec-L3.1.4-completion", "T-001"], readonly ["workflow-hardening-L3.1.4-placeholder-fix", "T-001"], readonly ["harness-coding-L3.1.1-context", "T-001"], readonly ["harness-coding-L3.1.2-report", "T-001"]];
32
+ export declare const REPOSITORY_REMEDIATION_V1_AGENT_DIRECTORIES: readonly [{
33
+ readonly source: "rules";
34
+ readonly target: ".claude/skills/spec-manager/rules";
35
+ }, {
36
+ readonly source: "templates";
37
+ readonly target: ".claude/skills/spec-manager/templates";
38
+ }];
39
+ export declare function planRepositoryRemediation(options: RepositoryRemediationOptions): RepositoryRemediationPlan;
40
+ export declare function applyRepositoryRemediation(options: RepositoryRemediationOptions): RepositoryRemediationReport;
41
+ //# sourceMappingURL=remediation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"remediation.d.ts","sourceRoot":"","sources":["../../src/core/remediation.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C,OAAO,EAAiD,KAAK,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAYxG,eAAO,MAAM,yBAAyB,EAAG,2BAAoC,CAAC;AAC9E,MAAM,MAAM,uBAAuB,GAAG,OAAO,yBAAyB,CAAC;AAEvE,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,QAAQ,GAAG,MAAM,CAAC;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,yBAAyB;IACxC,WAAW,EAAE,uBAAuB,CAAC;IACrC,SAAS,EAAE,aAAa,EAAE,CAAC;IAC3B,UAAU,EAAE,aAAa,EAAE,CAAC;IAC5B,WAAW,EAAE,aAAa,EAAE,CAAC;IAC7B,SAAS,EAAE,mBAAmB,EAAE,CAAC;CAClC;AAED,MAAM,WAAW,4BAA4B;IAC3C,KAAK,EAAE,YAAY,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,2BAA4B,SAAQ,yBAAyB;IAC5E,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,eAAO,MAAM,mCAAmC,EAAE,IAAI,CAAC,mBAAmB,EAAE,OAAO,CAAC,EAyBnF,CAAC;AAEF,eAAO,MAAM,+BAA+B,g4BAiBlC,CAAC;AAEX,eAAO,MAAM,2CAA2C;;;;;;EAG9C,CAAC;AAEX,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,4BAA4B,GAAG,yBAAyB,CAmD1G;AAED,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,4BAA4B,GAAG,2BAA2B,CAiC7G"}
@@ -0,0 +1,169 @@
1
+ import { join } from 'node:path';
2
+ import { siblingMetaDir } from './paths.js';
3
+ import { createDecision, listDecisions, nextDecisionId } from './decision.js';
4
+ import { exemptionTaskKey, mergeIntegrityExemptions, readIntegrityExemptions, } from './integrity-exemptions.js';
5
+ import { findSpecByCode } from './spec-io.js';
6
+ import { listTasks } from './task.js';
7
+ import { withProjectTransaction } from './transaction.js';
8
+ import { mergeMissingDirectories } from './agents.js';
9
+ export const REPOSITORY_REMEDIATION_V1 = 'repository-remediation-v1';
10
+ export const REPOSITORY_REMEDIATION_V1_DECISIONS = [
11
+ {
12
+ docCode: 'l3-approval-L1',
13
+ topic: 'l3-approval',
14
+ what: '一次明确的 L3 人工审批直接冻结规格,并保留实施前人工门禁。',
15
+ why: '减少重复审批步骤,同时维持实现代码只能基于 frozen L3 的约束。',
16
+ },
17
+ {
18
+ docCode: 'roadmap-openspec-L1',
19
+ topic: 'roadmap-openspec',
20
+ what: '以本地文件为事实源,补齐 rich guide、agent 检测、交互视图与 shell completion。',
21
+ why: '提升 spec-manager 的可发现性与跨 agent 使用体验,同时保持 local-first。',
22
+ },
23
+ {
24
+ docCode: 'spec-manager-ai-ux-L1',
25
+ topic: 'spec-manager-ai-ux',
26
+ what: '通过场景化文档、精简 skill 和核心测试改善 AI 使用 spec-manager 的体验。',
27
+ why: '降低 AI 理解和操作工作流的成本;已被后续废弃的能力不作为当前推荐。',
28
+ },
29
+ {
30
+ docCode: 'workflow-hardening-L1',
31
+ topic: 'workflow-hardening',
32
+ what: '以 CLI 为工作流事实源,统一 agent 入口并强化规格、计划和任务状态校验。',
33
+ why: '防止不同工具入口产生流程漂移,并让错误在实施前被发现。',
34
+ },
35
+ ];
36
+ export const REPOSITORY_REMEDIATION_V1_TASKS = [
37
+ ['spec-manager-ai-ux-L3.1.1-readme', 'T-001'],
38
+ ['spec-manager-ai-ux-L3.1.2-skill', 'T-001'],
39
+ ['spec-manager-ai-ux-L3.1.3-encoding', 'T-001'],
40
+ ['spec-manager-ai-ux-L3.1.4-batch', 'T-001'],
41
+ ['spec-manager-ai-ux-L3.1.5-tests', 'T-001'],
42
+ ['roadmap-openspec-L3.1.1-guide', 'T-001'],
43
+ ['workflow-hardening-L3.1.1-cli', 'T-001'],
44
+ ['workflow-hardening-L3.1.2-hints', 'T-001'],
45
+ ['workflow-hardening-L3.1.3-tools', 'T-001'],
46
+ ['roadmap-openspec-L3.1.2-agents', 'T-001'],
47
+ ['roadmap-openspec-L3.1.3-view', 'T-001'],
48
+ ['l3-approval-L3.1.1-single-freeze', 'T-001'],
49
+ ['roadmap-openspec-L3.1.4-completion', 'T-001'],
50
+ ['workflow-hardening-L3.1.4-placeholder-fix', 'T-001'],
51
+ ['harness-coding-L3.1.1-context', 'T-001'],
52
+ ['harness-coding-L3.1.2-report', 'T-001'],
53
+ ];
54
+ export const REPOSITORY_REMEDIATION_V1_AGENT_DIRECTORIES = [
55
+ { source: 'rules', target: '.claude/skills/spec-manager/rules' },
56
+ { source: 'templates', target: '.claude/skills/spec-manager/templates' },
57
+ ];
58
+ export function planRepositoryRemediation(options) {
59
+ assertMigrationId(options.migrationId);
60
+ const conflicts = [];
61
+ const decisions = listDecisions(options.paths, { includeAll: true });
62
+ const decisionActions = REPOSITORY_REMEDIATION_V1_DECISIONS.map(input => {
63
+ const existing = decisions.find(decision => decision.fm.docCode === input.docCode);
64
+ if (!existing)
65
+ return action('create', input.docCode, 'create missing Decision Card');
66
+ if (existing.fm.what !== input.what || existing.fm.why !== input.why) {
67
+ conflicts.push({ target: input.docCode, message: `existing Decision Card differs for ${input.docCode}` });
68
+ }
69
+ return action('skip', input.docCode, 'Decision Card already exists');
70
+ });
71
+ const exemptionResult = readIntegrityExemptions(options.paths);
72
+ for (const problem of exemptionResult.problems) {
73
+ conflicts.push({ target: problem.sourceId, message: problem.message });
74
+ }
75
+ const existingByTask = new Map(exemptionResult.registry.exemptions.map(exemption => [exemptionTaskKey(exemption), exemption]));
76
+ const tasks = new Map(listTasks(options.paths).map(task => [`${task.specCode}:${task.id}`, task]));
77
+ const exemptionActions = REPOSITORY_REMEDIATION_V1_TASKS.map(([specCode, taskId]) => {
78
+ const key = `${specCode}:${taskId}`;
79
+ const task = tasks.get(key);
80
+ if (!task || task.status !== 'completed' || (task.verifications ?? []).some(v => v.exitCode === 0)) {
81
+ conflicts.push({ target: key, message: `migration target is not an eligible legacy completed task: ${key}` });
82
+ }
83
+ const existing = existingByTask.get(key);
84
+ if (!existing)
85
+ return action('create', key, 'register legacy missing-verification exemption');
86
+ if (existing.migrationId !== REPOSITORY_REMEDIATION_V1) {
87
+ conflicts.push({ target: key, message: `task already has an exemption from ${existing.migrationId}` });
88
+ }
89
+ return action('skip', key, 'legacy exemption already registered');
90
+ });
91
+ const assetReport = mergeMissingDirectories({
92
+ paths: options.paths,
93
+ packageRoot: options.packageRoot,
94
+ directories: [...REPOSITORY_REMEDIATION_V1_AGENT_DIRECTORIES],
95
+ dryRun: true,
96
+ });
97
+ for (const note of assetReport.notes)
98
+ conflicts.push({ target: 'agent-assets', message: note });
99
+ const agentAssets = [
100
+ ...assetReport.created.map(target => action('create', target, 'create missing Claude skill asset')),
101
+ ...assetReport.skipped.map(target => action('skip', target, 'Claude skill asset already exists')),
102
+ ];
103
+ return {
104
+ migrationId: REPOSITORY_REMEDIATION_V1,
105
+ decisions: decisionActions,
106
+ exemptions: exemptionActions,
107
+ agentAssets,
108
+ conflicts,
109
+ };
110
+ }
111
+ export function applyRepositoryRemediation(options) {
112
+ const plan = planRepositoryRemediation(options);
113
+ if (plan.conflicts.length > 0) {
114
+ throw new Error(`REMEDIATION_CONFLICT: ${plan.conflicts.map(conflict => conflict.message).join('; ')}`);
115
+ }
116
+ const now = options.now ?? new Date().toISOString();
117
+ withProjectTransaction(options.paths, options.migrationId, tx => {
118
+ for (const planned of plan.decisions.filter(item => item.action === 'create')) {
119
+ const input = REPOSITORY_REMEDIATION_V1_DECISIONS.find(item => item.docCode === planned.target);
120
+ if (!input)
121
+ throw new Error(`missing decision manifest entry: ${planned.target}`);
122
+ const spec = findSpecByCode(options.paths, input.docCode);
123
+ if (!spec)
124
+ throw new Error(`Spec not found: ${input.docCode}`);
125
+ tx.snapshot(join(siblingMetaDir(spec.filePath, 'decisions'), `${nextDecisionId(options.paths, input.topic)}.md`));
126
+ createDecision({ paths: options.paths, ...input });
127
+ }
128
+ const current = readIntegrityExemptions(options.paths);
129
+ const additions = plan.exemptions
130
+ .filter(item => item.action === 'create')
131
+ .map(item => exemptionForTask(item.target, now));
132
+ const merged = mergeIntegrityExemptions(current.registry, additions);
133
+ tx.write(options.paths.integrityExemptionsFile, `${JSON.stringify(merged, null, 2)}\n`);
134
+ mergeMissingDirectories({
135
+ paths: options.paths,
136
+ packageRoot: options.packageRoot,
137
+ directories: [...REPOSITORY_REMEDIATION_V1_AGENT_DIRECTORIES],
138
+ write: (target, content) => tx.write(target, content),
139
+ });
140
+ });
141
+ const finalPlan = planRepositoryRemediation(options);
142
+ if (finalPlan.conflicts.length > 0 || [...finalPlan.decisions, ...finalPlan.exemptions, ...finalPlan.agentAssets].some(item => item.action !== 'skip')) {
143
+ throw new Error('REMEDIATION_INCOMPLETE: migration did not converge to an idempotent state');
144
+ }
145
+ return { ...plan, applied: true };
146
+ }
147
+ function exemptionForTask(taskKey, createdAt) {
148
+ const separator = taskKey.lastIndexOf(':');
149
+ const specCode = taskKey.slice(0, separator);
150
+ const taskId = taskKey.slice(separator + 1);
151
+ return {
152
+ id: `${REPOSITORY_REMEDIATION_V1}:${specCode}:${taskId}`,
153
+ kind: 'legacy-missing-verification',
154
+ specCode,
155
+ taskId,
156
+ reason: 'Task completed before successful verification became mandatory.',
157
+ createdAt,
158
+ migrationId: REPOSITORY_REMEDIATION_V1,
159
+ };
160
+ }
161
+ function action(actionName, target, detail) {
162
+ return { action: actionName, target, detail };
163
+ }
164
+ function assertMigrationId(migrationId) {
165
+ if (migrationId !== REPOSITORY_REMEDIATION_V1) {
166
+ throw new Error(`UNKNOWN_MIGRATION: ${migrationId}. Supported: ${REPOSITORY_REMEDIATION_V1}`);
167
+ }
168
+ }
169
+ //# sourceMappingURL=remediation.js.map