spec-manager 0.1.0

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 (159) hide show
  1. package/AGENTS.md +27 -0
  2. package/CODEBUDDY.md +19 -0
  3. package/LICENSE +21 -0
  4. package/README.md +531 -0
  5. package/dist/cli/audit.d.ts +10 -0
  6. package/dist/cli/audit.d.ts.map +1 -0
  7. package/dist/cli/audit.js +62 -0
  8. package/dist/cli/audit.js.map +1 -0
  9. package/dist/cli/change.d.ts +10 -0
  10. package/dist/cli/change.d.ts.map +1 -0
  11. package/dist/cli/change.js +103 -0
  12. package/dist/cli/change.js.map +1 -0
  13. package/dist/cli/common.d.ts +5 -0
  14. package/dist/cli/common.d.ts.map +1 -0
  15. package/dist/cli/common.js +17 -0
  16. package/dist/cli/common.js.map +1 -0
  17. package/dist/cli/decision.d.ts +13 -0
  18. package/dist/cli/decision.d.ts.map +1 -0
  19. package/dist/cli/decision.js +185 -0
  20. package/dist/cli/decision.js.map +1 -0
  21. package/dist/cli/dict.d.ts +10 -0
  22. package/dist/cli/dict.d.ts.map +1 -0
  23. package/dist/cli/dict.js +73 -0
  24. package/dist/cli/dict.js.map +1 -0
  25. package/dist/cli/incident.d.ts +10 -0
  26. package/dist/cli/incident.d.ts.map +1 -0
  27. package/dist/cli/incident.js +119 -0
  28. package/dist/cli/incident.js.map +1 -0
  29. package/dist/cli/index.d.ts +3 -0
  30. package/dist/cli/index.d.ts.map +1 -0
  31. package/dist/cli/index.js +30 -0
  32. package/dist/cli/index.js.map +1 -0
  33. package/dist/cli/project.d.ts +3 -0
  34. package/dist/cli/project.d.ts.map +1 -0
  35. package/dist/cli/project.js +144 -0
  36. package/dist/cli/project.js.map +1 -0
  37. package/dist/cli/spec.d.ts +3 -0
  38. package/dist/cli/spec.d.ts.map +1 -0
  39. package/dist/cli/spec.js +289 -0
  40. package/dist/cli/spec.js.map +1 -0
  41. package/dist/cli/task.d.ts +14 -0
  42. package/dist/cli/task.d.ts.map +1 -0
  43. package/dist/cli/task.js +287 -0
  44. package/dist/cli/task.js.map +1 -0
  45. package/dist/cli/usability.d.ts +3 -0
  46. package/dist/cli/usability.d.ts.map +1 -0
  47. package/dist/cli/usability.js +153 -0
  48. package/dist/cli/usability.js.map +1 -0
  49. package/dist/core/agents.d.ts +43 -0
  50. package/dist/core/agents.d.ts.map +1 -0
  51. package/dist/core/agents.js +194 -0
  52. package/dist/core/agents.js.map +1 -0
  53. package/dist/core/archive.d.ts +35 -0
  54. package/dist/core/archive.d.ts.map +1 -0
  55. package/dist/core/archive.js +360 -0
  56. package/dist/core/archive.js.map +1 -0
  57. package/dist/core/audit-events.d.ts +12 -0
  58. package/dist/core/audit-events.d.ts.map +1 -0
  59. package/dist/core/audit-events.js +16 -0
  60. package/dist/core/audit-events.js.map +1 -0
  61. package/dist/core/audit.d.ts +78 -0
  62. package/dist/core/audit.d.ts.map +1 -0
  63. package/dist/core/audit.js +157 -0
  64. package/dist/core/audit.js.map +1 -0
  65. package/dist/core/constants.d.ts +28 -0
  66. package/dist/core/constants.d.ts.map +1 -0
  67. package/dist/core/constants.js +30 -0
  68. package/dist/core/constants.js.map +1 -0
  69. package/dist/core/decision.d.ts +69 -0
  70. package/dist/core/decision.d.ts.map +1 -0
  71. package/dist/core/decision.js +210 -0
  72. package/dist/core/decision.js.map +1 -0
  73. package/dist/core/delta.d.ts +85 -0
  74. package/dist/core/delta.d.ts.map +1 -0
  75. package/dist/core/delta.js +264 -0
  76. package/dist/core/delta.js.map +1 -0
  77. package/dist/core/dict.d.ts +28 -0
  78. package/dist/core/dict.d.ts.map +1 -0
  79. package/dist/core/dict.js +57 -0
  80. package/dist/core/dict.js.map +1 -0
  81. package/dist/core/frontmatter.d.ts +19 -0
  82. package/dist/core/frontmatter.d.ts.map +1 -0
  83. package/dist/core/frontmatter.js +57 -0
  84. package/dist/core/frontmatter.js.map +1 -0
  85. package/dist/core/incident.d.ts +45 -0
  86. package/dist/core/incident.d.ts.map +1 -0
  87. package/dist/core/incident.js +128 -0
  88. package/dist/core/incident.js.map +1 -0
  89. package/dist/core/paths.d.ts +68 -0
  90. package/dist/core/paths.d.ts.map +1 -0
  91. package/dist/core/paths.js +162 -0
  92. package/dist/core/paths.js.map +1 -0
  93. package/dist/core/repository.d.ts +13 -0
  94. package/dist/core/repository.d.ts.map +1 -0
  95. package/dist/core/repository.js +29 -0
  96. package/dist/core/repository.js.map +1 -0
  97. package/dist/core/spec-io.d.ts +125 -0
  98. package/dist/core/spec-io.d.ts.map +1 -0
  99. package/dist/core/spec-io.js +260 -0
  100. package/dist/core/spec-io.js.map +1 -0
  101. package/dist/core/status.d.ts +22 -0
  102. package/dist/core/status.d.ts.map +1 -0
  103. package/dist/core/status.js +54 -0
  104. package/dist/core/status.js.map +1 -0
  105. package/dist/core/task.d.ts +118 -0
  106. package/dist/core/task.d.ts.map +1 -0
  107. package/dist/core/task.js +340 -0
  108. package/dist/core/task.js.map +1 -0
  109. package/dist/core/usability.d.ts +25 -0
  110. package/dist/core/usability.d.ts.map +1 -0
  111. package/dist/core/usability.js +136 -0
  112. package/dist/core/usability.js.map +1 -0
  113. package/dist/core/validate.d.ts +34 -0
  114. package/dist/core/validate.d.ts.map +1 -0
  115. package/dist/core/validate.js +195 -0
  116. package/dist/core/validate.js.map +1 -0
  117. package/dist/index.d.ts +11 -0
  118. package/dist/index.d.ts.map +1 -0
  119. package/dist/index.js +12 -0
  120. package/dist/index.js.map +1 -0
  121. package/dist/schemas/change.d.ts +138 -0
  122. package/dist/schemas/change.d.ts.map +1 -0
  123. package/dist/schemas/change.js +38 -0
  124. package/dist/schemas/change.js.map +1 -0
  125. package/dist/schemas/spec.d.ts +233 -0
  126. package/dist/schemas/spec.d.ts.map +1 -0
  127. package/dist/schemas/spec.js +56 -0
  128. package/dist/schemas/spec.js.map +1 -0
  129. package/package.json +66 -0
  130. package/rules/_TEMPLATE.md +20 -0
  131. package/rules/code-discipline.md +47 -0
  132. package/rules/codebase-survey.md +37 -0
  133. package/rules/delta.md +42 -0
  134. package/rules/doc-governance.md +195 -0
  135. package/rules/flow-control.md +65 -0
  136. package/rules/quality-gate.md +73 -0
  137. package/skill/SKILL.md +90 -0
  138. package/skill/subskills/adr.md +73 -0
  139. package/skill/subskills/change.md +118 -0
  140. package/skill/subskills/design.md +53 -0
  141. package/skill/subskills/impl.md +100 -0
  142. package/skill/subskills/plan.md +46 -0
  143. package/skill/subskills/postmortem.md +77 -0
  144. package/skill/subskills/prd.md +72 -0
  145. package/skill/subskills/quick.md +25 -0
  146. package/skill/subskills/release.md +50 -0
  147. package/skill/subskills/research.md +35 -0
  148. package/skill/subskills/runbook.md +44 -0
  149. package/skill/subskills/testplan.md +48 -0
  150. package/templates/L0-prd.md +43 -0
  151. package/templates/L1-prd.md +130 -0
  152. package/templates/L2-design.md +135 -0
  153. package/templates/L3-impl.md +125 -0
  154. package/templates/agent-plan.json +17 -0
  155. package/templates/agents/AGENTS.md +27 -0
  156. package/templates/agents/CLAUDE.md +11 -0
  157. package/templates/agents/CODEBUDDY.md +23 -0
  158. package/templates/agents/codebuddy-skill/SKILL.md +46 -0
  159. package/templates/decision.md +42 -0
@@ -0,0 +1,16 @@
1
+ import { hit } from './audit.js';
2
+ export const writeAuditSink = {
3
+ hit(event) {
4
+ hit(event);
5
+ },
6
+ };
7
+ export class CollectingAuditSink {
8
+ events = [];
9
+ hit(event) {
10
+ this.events.push(event);
11
+ }
12
+ }
13
+ export function recordAuditHit(event, sink = writeAuditSink) {
14
+ sink.hit(event);
15
+ }
16
+ //# sourceMappingURL=audit-events.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit-events.js","sourceRoot":"","sources":["../../src/core/audit-events.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAiB,MAAM,YAAY,CAAC;AAQhD,MAAM,CAAC,MAAM,cAAc,GAAc;IACvC,GAAG,CAAC,KAAiB;QACnB,GAAG,CAAC,KAAK,CAAC,CAAC;IACb,CAAC;CACF,CAAC;AAEF,MAAM,OAAO,mBAAmB;IACrB,MAAM,GAAiB,EAAE,CAAC;IAEnC,GAAG,CAAC,KAAiB;QACnB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC1B,CAAC;CACF;AAED,MAAM,UAAU,cAAc,CAAC,KAAiB,EAAE,OAAkB,cAAc;IAChF,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;AAClB,CAAC"}
@@ -0,0 +1,78 @@
1
+ /**
2
+ * 规则审计(本地版)
3
+ *
4
+ * 数据结构(.spec-manager/audit.json):
5
+ * {
6
+ * sessionId: string,
7
+ * startedAt: string (ISO),
8
+ * topic: string,
9
+ * rules: { R1: 0, R2: 0, ..., R24: 0 },
10
+ * pending: PendingEntry[],
11
+ * lastUpdated: string (ISO)
12
+ * }
13
+ *
14
+ * PendingEntry 字段:{ ruleId, timestamp, specCode?, taskCode? }
15
+ *
16
+ * at-least-once 语义:
17
+ * - hit() 永远 append pending 队列(即使已 session-bound)
18
+ * - report() 把 pending 中 reported=false 的标记为 reported=true
19
+ * (本地版"report"=标记已审计,不发任何网络请求;如未来要接远程后端,
20
+ * 在 report() 里加 POST 即可,pending 机制不变)
21
+ */
22
+ import type { ProjectPaths } from './paths.js';
23
+ export declare const RULE_ID_RE: RegExp;
24
+ export declare const ALL_RULE_IDS: string[];
25
+ /** 最低合规基线:这些规则的 hit 计数必须 ≥1 */
26
+ export declare const COMPLIANCE_BASELINE: readonly string[];
27
+ export interface PendingEntry {
28
+ ruleId: string;
29
+ timestamp: string;
30
+ specCode?: string;
31
+ taskCode?: string;
32
+ reported: boolean;
33
+ }
34
+ export interface AuditState {
35
+ sessionId: string;
36
+ startedAt: string;
37
+ topic: string;
38
+ rules: Record<string, number>;
39
+ pending: PendingEntry[];
40
+ lastUpdated: string;
41
+ }
42
+ export declare function readAudit(paths: ProjectPaths): AuditState;
43
+ export declare function writeAudit(paths: ProjectPaths, state: AuditState): void;
44
+ export interface HitInput {
45
+ paths: ProjectPaths;
46
+ ruleId: string;
47
+ specCode?: string;
48
+ taskCode?: string;
49
+ }
50
+ export declare function hit(input: HitInput): AuditState;
51
+ export declare function startSession(paths: ProjectPaths, opts: {
52
+ sessionId: string;
53
+ topic?: string;
54
+ }): AuditState;
55
+ export interface ReportResult {
56
+ markedReported: number;
57
+ remaining: number;
58
+ }
59
+ /**
60
+ * 标记 pending 中 reported=false 的条目为 reported=true。
61
+ * 本地版"report"语义 = 落库到 .spec-manager/audit-archive.json
62
+ */
63
+ export declare function report(paths: ProjectPaths): ReportResult;
64
+ export declare function showSummary(paths: ProjectPaths, opts?: {
65
+ ruleId?: string;
66
+ }): string;
67
+ export interface ComplianceResult {
68
+ pass: boolean;
69
+ details: Array<{
70
+ ruleId: string;
71
+ count: number;
72
+ min: number;
73
+ pass: boolean;
74
+ }>;
75
+ }
76
+ /** 检查最低合规基线:R1≥1, R4≥1, R13≥1, R22≥1 */
77
+ export declare function checkCompliance(state: AuditState): ComplianceResult;
78
+ //# sourceMappingURL=audit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit.d.ts","sourceRoot":"","sources":["../../src/core/audit.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAIH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C,eAAO,MAAM,UAAU,QAA6B,CAAC;AACrD,eAAO,MAAM,YAAY,UAAoD,CAAC;AAE9E,+BAA+B;AAC/B,eAAO,MAAM,mBAAmB,EAAE,SAAS,MAAM,EAA+B,CAAC;AAKjF,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;CACrB;AAQD,wBAAgB,SAAS,CAAC,KAAK,EAAE,YAAY,GAAG,UAAU,CAqBzD;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,UAAU,GAAG,IAAI,CAOvE;AAED,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,YAAY,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,wBAAgB,GAAG,CAAC,KAAK,EAAE,QAAQ,GAAG,UAAU,CAgB/C;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,UAAU,CAWzG;AAED,MAAM,WAAW,YAAY;IAC3B,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;GAGG;AACH,wBAAgB,MAAM,CAAC,KAAK,EAAE,YAAY,GAAG,YAAY,CAqBxD;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,YAAY,EAAE,IAAI,CAAC,EAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAyBnF;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,KAAK,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;CAC/E;AAED,wCAAwC;AACxC,wBAAgB,eAAe,CAAC,KAAK,EAAE,UAAU,GAAG,gBAAgB,CAMnE"}
@@ -0,0 +1,157 @@
1
+ /**
2
+ * 规则审计(本地版)
3
+ *
4
+ * 数据结构(.spec-manager/audit.json):
5
+ * {
6
+ * sessionId: string,
7
+ * startedAt: string (ISO),
8
+ * topic: string,
9
+ * rules: { R1: 0, R2: 0, ..., R24: 0 },
10
+ * pending: PendingEntry[],
11
+ * lastUpdated: string (ISO)
12
+ * }
13
+ *
14
+ * PendingEntry 字段:{ ruleId, timestamp, specCode?, taskCode? }
15
+ *
16
+ * at-least-once 语义:
17
+ * - hit() 永远 append pending 队列(即使已 session-bound)
18
+ * - report() 把 pending 中 reported=false 的标记为 reported=true
19
+ * (本地版"report"=标记已审计,不发任何网络请求;如未来要接远程后端,
20
+ * 在 report() 里加 POST 即可,pending 机制不变)
21
+ */
22
+ import { existsSync, readFileSync, writeFileSync, mkdirSync, renameSync } from 'node:fs';
23
+ import { dirname, join } from 'node:path';
24
+ export const RULE_ID_RE = /^R([1-9]|1[0-9]|2[0-4])$/;
25
+ export const ALL_RULE_IDS = Array.from({ length: 24 }, (_, i) => `R${i + 1}`);
26
+ /** 最低合规基线:这些规则的 hit 计数必须 ≥1 */
27
+ export const COMPLIANCE_BASELINE = ['R1', 'R4', 'R13', 'R22'];
28
+ for (const id of COMPLIANCE_BASELINE) {
29
+ if (!RULE_ID_RE.test(id))
30
+ throw new Error(`COMPLIANCE_BASELINE contains invalid ruleId: ${id}`);
31
+ }
32
+ function emptyRules() {
33
+ const r = {};
34
+ for (const id of ALL_RULE_IDS)
35
+ r[id] = 0;
36
+ return r;
37
+ }
38
+ export function readAudit(paths) {
39
+ if (!existsSync(paths.auditFile)) {
40
+ return {
41
+ sessionId: '',
42
+ startedAt: '',
43
+ topic: '',
44
+ rules: emptyRules(),
45
+ pending: [],
46
+ lastUpdated: '',
47
+ };
48
+ }
49
+ const raw = JSON.parse(readFileSync(paths.auditFile, 'utf8'));
50
+ // 兜底:缺失 rules 时填充完整 24 条
51
+ for (const id of ALL_RULE_IDS) {
52
+ if (typeof raw.rules?.[id] !== 'number') {
53
+ raw.rules = raw.rules ?? {};
54
+ raw.rules[id] = 0;
55
+ }
56
+ }
57
+ raw.pending = raw.pending ?? [];
58
+ return raw;
59
+ }
60
+ export function writeAudit(paths, state) {
61
+ const dir = dirname(paths.auditFile);
62
+ if (!existsSync(dir))
63
+ mkdirSync(dir, { recursive: true });
64
+ const tmp = join(dir, `.audit-${Date.now()}.tmp`);
65
+ writeFileSync(tmp, JSON.stringify(state, null, 2), 'utf8');
66
+ // rename 替换原文件
67
+ renameSync(tmp, paths.auditFile);
68
+ }
69
+ export function hit(input) {
70
+ if (!RULE_ID_RE.test(input.ruleId)) {
71
+ throw new Error(`ruleId 格式非法: ${input.ruleId}(必须 /^R([1-9]|1[0-9]|2[0-4])$/)`);
72
+ }
73
+ const state = readAudit(input.paths);
74
+ state.rules[input.ruleId] = (state.rules[input.ruleId] ?? 0) + 1;
75
+ state.pending.push({
76
+ ruleId: input.ruleId,
77
+ timestamp: new Date().toISOString(),
78
+ specCode: input.specCode,
79
+ taskCode: input.taskCode,
80
+ reported: false,
81
+ });
82
+ state.lastUpdated = new Date().toISOString();
83
+ writeAudit(input.paths, state);
84
+ return state;
85
+ }
86
+ export function startSession(paths, opts) {
87
+ const state = {
88
+ sessionId: opts.sessionId,
89
+ startedAt: new Date().toISOString(),
90
+ topic: opts.topic ?? '',
91
+ rules: emptyRules(),
92
+ pending: [],
93
+ lastUpdated: new Date().toISOString(),
94
+ };
95
+ writeAudit(paths, state);
96
+ return state;
97
+ }
98
+ /**
99
+ * 标记 pending 中 reported=false 的条目为 reported=true。
100
+ * 本地版"report"语义 = 落库到 .spec-manager/audit-archive.json
101
+ */
102
+ export function report(paths) {
103
+ const state = readAudit(paths);
104
+ let marked = 0;
105
+ for (const e of state.pending) {
106
+ if (!e.reported) {
107
+ e.reported = true;
108
+ marked++;
109
+ }
110
+ }
111
+ // 把已 reported 的条目移到 archive(本地存档)
112
+ const archivePath = join(dirname(paths.auditFile), 'audit-archive.json');
113
+ let archive = [];
114
+ if (existsSync(archivePath)) {
115
+ archive = JSON.parse(readFileSync(archivePath, 'utf8'));
116
+ }
117
+ archive.push(...state.pending);
118
+ state.pending = [];
119
+ state.lastUpdated = new Date().toISOString();
120
+ writeAudit(paths, state);
121
+ writeFileSync(archivePath, JSON.stringify(archive, null, 2), 'utf8');
122
+ return { markedReported: marked, remaining: 0 };
123
+ }
124
+ export function showSummary(paths, opts) {
125
+ const state = readAudit(paths);
126
+ const lines = [];
127
+ lines.push(`session: ${state.sessionId || '(无)'} topic: ${state.topic || '(无)'} updated: ${state.lastUpdated}`);
128
+ lines.push('');
129
+ lines.push('rule hit counts:');
130
+ for (const id of ALL_RULE_IDS) {
131
+ const n = state.rules[id] ?? 0;
132
+ if (opts?.ruleId && opts.ruleId !== id)
133
+ continue;
134
+ const sym = n > 0 ? '✓' : '·';
135
+ lines.push(` ${sym} ${id}: ${n}`);
136
+ }
137
+ lines.push('');
138
+ const unreported = state.pending.filter(e => !e.reported);
139
+ lines.push(`pending: ${state.pending.length}(未 report: ${unreported.length})`);
140
+ // 合规基线检查
141
+ const baseline = checkCompliance(state);
142
+ lines.push('');
143
+ lines.push(`compliance: ${baseline.pass ? '✓ PASS' : '✗ FAIL'}`);
144
+ for (const item of baseline.details) {
145
+ lines.push(` ${item.pass ? '✓' : '✗'} ${item.ruleId}: ${item.count} (min ${item.min})`);
146
+ }
147
+ return lines.join('\n');
148
+ }
149
+ /** 检查最低合规基线:R1≥1, R4≥1, R13≥1, R22≥1 */
150
+ export function checkCompliance(state) {
151
+ const details = COMPLIANCE_BASELINE.map(ruleId => {
152
+ const count = state.rules[ruleId] ?? 0;
153
+ return { ruleId, count, min: 1, pass: count >= 1 };
154
+ });
155
+ return { pass: details.every(d => d.pass), details };
156
+ }
157
+ //# sourceMappingURL=audit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit.js","sourceRoot":"","sources":["../../src/core/audit.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * 项目内魔数集中地。修改前先确认是否有测试覆盖。
3
+ */
4
+ /** Decision card what 字段最大字符数 */
5
+ export declare const DECISION_WHAT_MAX = 500;
6
+ /** Decision card why 字段最大字符数 */
7
+ export declare const DECISION_WHY_MAX = 500;
8
+ /** Spec aiSummary 字段最大字符数(R13/R21 强约束) */
9
+ export declare const AI_SUMMARY_MAX = 300;
10
+ /** PlanJson 步骤数上限(R11) */
11
+ export declare const PLAN_STEPS_MAX = 20;
12
+ /** Decision/Task/Incident ID 编号位数(如 DC-001 / T-001 / INC-...-001) */
13
+ export declare const ID_PAD_WIDTH = 3;
14
+ /** createSpec 写入的占位正文标记,R22 校验用 */
15
+ export declare const PLACEHOLDER_MARKER = "<!-- \u5728\u6B64\u7C98\u8D34\u6B63\u6587 -->";
16
+ /** R22: 占位正文判定阈值 — 去掉 marker 后正文长度低于此值视为占位 */
17
+ export declare const PLACEHOLDER_CONTENT_MAX = 200;
18
+ /** Task 文件扩展名 */
19
+ export declare const TASK_FILE_EXT = ".json";
20
+ /** Task ID 前缀 */
21
+ export declare const TASK_ID_PREFIX = "T-";
22
+ /** topic 必须是安全的单段路径名 */
23
+ export declare const TOPIC_RE: RegExp;
24
+ /** spec code: <topic>-L1 / <topic>-L2.1 / <topic>-L3.1.1[-desc];desc 不能是 8 位日期 */
25
+ export declare const SPEC_CODE_RE: RegExp;
26
+ /** 当天日期 YYYYMMDD */
27
+ export declare function todayYYYYMMDD(): string;
28
+ //# sourceMappingURL=constants.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/core/constants.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,iCAAiC;AACjC,eAAO,MAAM,iBAAiB,MAAM,CAAC;AAErC,gCAAgC;AAChC,eAAO,MAAM,gBAAgB,MAAM,CAAC;AAEpC,0CAA0C;AAC1C,eAAO,MAAM,cAAc,MAAM,CAAC;AAElC,0BAA0B;AAC1B,eAAO,MAAM,cAAc,KAAK,CAAC;AAEjC,qEAAqE;AACrE,eAAO,MAAM,YAAY,IAAI,CAAC;AAE9B,mCAAmC;AACnC,eAAO,MAAM,kBAAkB,kDAAoB,CAAC;AAEpD,8CAA8C;AAC9C,eAAO,MAAM,uBAAuB,MAAM,CAAC;AAE3C,iBAAiB;AACjB,eAAO,MAAM,aAAa,UAAU,CAAC;AAErC,iBAAiB;AACjB,eAAO,MAAM,cAAc,OAAO,CAAC;AAEnC,wBAAwB;AACxB,eAAO,MAAM,QAAQ,QAAyB,CAAC;AAE/C,kFAAkF;AAClF,eAAO,MAAM,YAAY,QAA4E,CAAC;AAEtG,oBAAoB;AACpB,wBAAgB,aAAa,IAAI,MAAM,CAEtC"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * 项目内魔数集中地。修改前先确认是否有测试覆盖。
3
+ */
4
+ /** Decision card what 字段最大字符数 */
5
+ export const DECISION_WHAT_MAX = 500;
6
+ /** Decision card why 字段最大字符数 */
7
+ export const DECISION_WHY_MAX = 500;
8
+ /** Spec aiSummary 字段最大字符数(R13/R21 强约束) */
9
+ export const AI_SUMMARY_MAX = 300;
10
+ /** PlanJson 步骤数上限(R11) */
11
+ export const PLAN_STEPS_MAX = 20;
12
+ /** Decision/Task/Incident ID 编号位数(如 DC-001 / T-001 / INC-...-001) */
13
+ export const ID_PAD_WIDTH = 3;
14
+ /** createSpec 写入的占位正文标记,R22 校验用 */
15
+ export const PLACEHOLDER_MARKER = '<!-- 在此粘贴正文 -->';
16
+ /** R22: 占位正文判定阈值 — 去掉 marker 后正文长度低于此值视为占位 */
17
+ export const PLACEHOLDER_CONTENT_MAX = 200;
18
+ /** Task 文件扩展名 */
19
+ export const TASK_FILE_EXT = '.json';
20
+ /** Task ID 前缀 */
21
+ export const TASK_ID_PREFIX = 'T-';
22
+ /** topic 必须是安全的单段路径名 */
23
+ export const TOPIC_RE = /^[a-z0-9][a-z0-9-]*$/;
24
+ /** spec code: <topic>-L1 / <topic>-L2.1 / <topic>-L3.1.1[-desc];desc 不能是 8 位日期 */
25
+ export const SPEC_CODE_RE = /^[a-z0-9][a-z0-9-]*-L[0-3](?:\.\d+)*(?:-(?!\d{8}$)[a-z0-9][a-z0-9-]*)?$/;
26
+ /** 当天日期 YYYYMMDD */
27
+ export function todayYYYYMMDD() {
28
+ return new Date().toISOString().slice(0, 10).replace(/-/g, '');
29
+ }
30
+ //# sourceMappingURL=constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/core/constants.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,iCAAiC;AACjC,MAAM,CAAC,MAAM,iBAAiB,GAAG,GAAG,CAAC;AAErC,gCAAgC;AAChC,MAAM,CAAC,MAAM,gBAAgB,GAAG,GAAG,CAAC;AAEpC,0CAA0C;AAC1C,MAAM,CAAC,MAAM,cAAc,GAAG,GAAG,CAAC;AAElC,0BAA0B;AAC1B,MAAM,CAAC,MAAM,cAAc,GAAG,EAAE,CAAC;AAEjC,qEAAqE;AACrE,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,CAAC;AAE9B,mCAAmC;AACnC,MAAM,CAAC,MAAM,kBAAkB,GAAG,iBAAiB,CAAC;AAEpD,8CAA8C;AAC9C,MAAM,CAAC,MAAM,uBAAuB,GAAG,GAAG,CAAC;AAE3C,iBAAiB;AACjB,MAAM,CAAC,MAAM,aAAa,GAAG,OAAO,CAAC;AAErC,iBAAiB;AACjB,MAAM,CAAC,MAAM,cAAc,GAAG,IAAI,CAAC;AAEnC,wBAAwB;AACxB,MAAM,CAAC,MAAM,QAAQ,GAAG,sBAAsB,CAAC;AAE/C,kFAAkF;AAClF,MAAM,CAAC,MAAM,YAAY,GAAG,yEAAyE,CAAC;AAEtG,oBAAoB;AACpB,MAAM,UAAU,aAAa;IAC3B,OAAO,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;AACjE,CAAC"}
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Decision Cards — 结构化 what/why/affectedCriteria
3
+ * 存储位置:specs/<topic>/<L1-code>/decisions/<id>.md
4
+ * 一决策一文件,frontmatter 索引元数据,正文可读详情。
5
+ */
6
+ import { type ProjectPaths } from './paths.js';
7
+ export type DecisionStatus = 'active' | 'superseded' | 'partial';
8
+ export interface DecisionRecord {
9
+ id: string;
10
+ fm: {
11
+ id: string;
12
+ docCode: string;
13
+ topic: string;
14
+ what: string;
15
+ why?: string;
16
+ status: DecisionStatus;
17
+ supersededById: string | null;
18
+ affectedCriteria?: string[];
19
+ created: string;
20
+ updated: string;
21
+ };
22
+ content: string;
23
+ filePath: string;
24
+ }
25
+ export declare function listDecisions(paths: ProjectPaths, opts?: {
26
+ topic?: string;
27
+ docCode?: string;
28
+ includeAll?: boolean;
29
+ criteria?: string | string[];
30
+ }): DecisionRecord[];
31
+ export declare function findDecision(paths: ProjectPaths, id: string): DecisionRecord | null;
32
+ export declare function nextDecisionId(paths: ProjectPaths, topic: string): string;
33
+ export interface CreateDecisionInput {
34
+ paths: ProjectPaths;
35
+ docCode: string;
36
+ topic: string;
37
+ what: string;
38
+ why?: string;
39
+ affectedCriteria?: string[];
40
+ }
41
+ export declare function createDecision(input: CreateDecisionInput): DecisionRecord;
42
+ export declare function supersedeDecision(paths: ProjectPaths, oldId: string, newId: string): void;
43
+ /**
44
+ * 删除决策。仅 active 状态可删;superseded/partial 状态需先恢复或归档(避免丢失审计轨迹)。
45
+ */
46
+ export declare function deleteDecision(paths: ProjectPaths, id: string): void;
47
+ export interface UpdateDecisionInput {
48
+ paths: ProjectPaths;
49
+ id: string;
50
+ what?: string;
51
+ why?: string;
52
+ affectedCriteria?: string[];
53
+ }
54
+ /**
55
+ * 编辑决策的 what/why/affectedCriteria。状态变更走 supersede / set-partial。
56
+ * superseded 状态的决策不可编辑(避免改历史)。
57
+ */
58
+ export declare function updateDecision(input: UpdateDecisionInput): DecisionRecord;
59
+ export interface SetPartialInput {
60
+ paths: ProjectPaths;
61
+ id: string;
62
+ reason: string;
63
+ }
64
+ /**
65
+ * 把决策标记为 partial(部分被取代/部分作废),需 --reason 解释。
66
+ * 区别于 supersede:partial 不指向新决策 ID,只标记"局部失效"。
67
+ */
68
+ export declare function setDecisionPartial(input: SetPartialInput): DecisionRecord;
69
+ //# sourceMappingURL=decision.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"decision.d.ts","sourceRoot":"","sources":["../../src/core/decision.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,EAAkB,KAAK,YAAY,EAAE,MAAM,YAAY,CAAC;AAK/D,MAAM,MAAM,cAAc,GAAG,QAAQ,GAAG,YAAY,GAAG,SAAS,CAAC;AAEjE,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE;QACF,EAAE,EAAE,MAAM,CAAC;QACX,OAAO,EAAE,MAAM,CAAC;QAChB,KAAK,EAAE,MAAM,CAAC;QACd,IAAI,EAAE,MAAM,CAAC;QACb,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,MAAM,EAAE,cAAc,CAAC;QACvB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;QAC9B,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;QAC5B,OAAO,EAAE,MAAM,CAAC;QAChB,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC;IACF,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAKD,wBAAgB,aAAa,CAC3B,KAAK,EAAE,YAAY,EACnB,IAAI,CAAC,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAA;CAAE,GAC9F,cAAc,EAAE,CAelB;AAeD,wBAAgB,YAAY,CAAC,KAAK,EAAE,YAAY,EAAE,EAAE,EAAE,MAAM,GAAG,cAAc,GAAG,IAAI,CAKnF;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAOzE;AAED,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,YAAY,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;CAC7B;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,mBAAmB,GAAG,cAAc,CAoCzE;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAgBzF;AAwBD;;GAEG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,YAAY,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI,CAUpE;AAED,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,YAAY,CAAC;IACpB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;CAC7B;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,mBAAmB,GAAG,cAAc,CAyBzE;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,YAAY,CAAC;IACpB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,eAAe,GAAG,cAAc,CAkBzE"}
@@ -0,0 +1,210 @@
1
+ /**
2
+ * Decision Cards — 结构化 what/why/affectedCriteria
3
+ * 存储位置:specs/<topic>/<L1-code>/decisions/<id>.md
4
+ * 一决策一文件,frontmatter 索引元数据,正文可读详情。
5
+ */
6
+ import { unlinkSync } from 'node:fs';
7
+ import { join } from 'node:path';
8
+ import { readFrontmatter, writeFrontmatterAtomic } from './frontmatter.js';
9
+ import { siblingMetaDir } from './paths.js';
10
+ import { findSpecByCode } from './spec-io.js';
11
+ import { DECISION_WHAT_MAX, DECISION_WHY_MAX, ID_PAD_WIDTH } from './constants.js';
12
+ import { listTopicMetaFiles } from './repository.js';
13
+ const WHAT_MAX = DECISION_WHAT_MAX;
14
+ const WHY_MAX = DECISION_WHY_MAX;
15
+ export function listDecisions(paths, opts) {
16
+ const out = [];
17
+ const criteriaFilter = normalizeCriteriaFilter(opts?.criteria);
18
+ const files = listTopicMetaFiles(paths, 'decisions', { topic: opts?.topic, extension: '.md' });
19
+ for (const file of files) {
20
+ const { data, content } = readFrontmatter(file.filePath);
21
+ const fm = data;
22
+ if (opts?.topic && fm.topic !== opts.topic)
23
+ continue;
24
+ if (opts?.docCode && fm.docCode !== opts.docCode)
25
+ continue;
26
+ if (!opts?.includeAll && fm.status !== 'active')
27
+ continue;
28
+ if (criteriaFilter && !decisionAffectsAny(fm.affectedCriteria, criteriaFilter))
29
+ continue;
30
+ out.push({ id: fm.id, fm, content, filePath: file.filePath });
31
+ }
32
+ out.sort((a, b) => a.fm.created.localeCompare(b.fm.created));
33
+ return out;
34
+ }
35
+ function normalizeCriteriaFilter(input) {
36
+ if (input === undefined)
37
+ return null;
38
+ const arr = Array.isArray(input) ? input : input.split(',');
39
+ const trimmed = arr.map(s => s.trim()).filter(Boolean);
40
+ return trimmed.length > 0 ? trimmed : null;
41
+ }
42
+ function decisionAffectsAny(affected, criteria) {
43
+ if (!affected || affected.length === 0)
44
+ return false;
45
+ const set = new Set(affected);
46
+ return criteria.some(c => set.has(c));
47
+ }
48
+ export function findDecision(paths, id) {
49
+ for (const d of listDecisions(paths, { includeAll: true })) {
50
+ if (d.id === id || d.fm.id === id)
51
+ return d;
52
+ }
53
+ return null;
54
+ }
55
+ export function nextDecisionId(paths, topic) {
56
+ let max = 0;
57
+ for (const file of listTopicMetaFiles(paths, 'decisions', { topic, extension: '.md' })) {
58
+ const m = file.fileName.match(/^DC-(\d+)\.md$/);
59
+ if (m)
60
+ max = Math.max(max, Number(m[1]));
61
+ }
62
+ return `DC-${String(max + 1).padStart(ID_PAD_WIDTH, '0')}`;
63
+ }
64
+ export function createDecision(input) {
65
+ // R18 校验:只能给 implemented L1 建决策
66
+ const spec = findSpecByCode(input.paths, input.docCode);
67
+ if (!spec) {
68
+ throw new Error(`Spec not found: ${input.docCode}`);
69
+ }
70
+ if (spec.fm.level !== 'L1') {
71
+ throw new Error(`Decision card 只能关联 L1 spec,${input.docCode} 是 ${spec.fm.level}`);
72
+ }
73
+ if (spec.fm.status !== 'implemented') {
74
+ throw new Error(`R18: L1 必须 implemented 才能建决策卡片,当前 status=${spec.fm.status}`);
75
+ }
76
+ if (input.what.length > WHAT_MAX) {
77
+ throw new Error(`what 长度 ${input.what.length} > ${WHAT_MAX}`);
78
+ }
79
+ if (input.why && input.why.length > WHY_MAX) {
80
+ throw new Error(`why 长度 ${input.why.length} > ${WHY_MAX}`);
81
+ }
82
+ const id = nextDecisionId(input.paths, input.topic);
83
+ const now = new Date().toISOString();
84
+ const fm = {
85
+ id,
86
+ docCode: input.docCode,
87
+ topic: input.topic,
88
+ what: input.what,
89
+ why: input.why,
90
+ status: 'active',
91
+ supersededById: null,
92
+ affectedCriteria: input.affectedCriteria,
93
+ created: now,
94
+ updated: now,
95
+ };
96
+ const content = renderContent(fm);
97
+ const filePath = join(siblingMetaDir(spec.filePath, 'decisions'), `${id}.md`);
98
+ writeFrontmatterAtomic(filePath, fm, content);
99
+ return { id, fm, content, filePath };
100
+ }
101
+ export function supersedeDecision(paths, oldId, newId) {
102
+ const old = findDecision(paths, oldId);
103
+ if (!old)
104
+ throw new Error(`Decision not found: ${oldId}`);
105
+ const newDec = findDecision(paths, newId);
106
+ if (!newDec)
107
+ throw new Error(`New decision not found: ${newId}`);
108
+ const updated = {
109
+ ...old,
110
+ fm: {
111
+ ...old.fm,
112
+ status: 'superseded',
113
+ supersededById: newId,
114
+ updated: new Date().toISOString(),
115
+ },
116
+ };
117
+ updated.content = renderContent(updated.fm);
118
+ writeFrontmatterAtomic(old.filePath, updated.fm, updated.content);
119
+ }
120
+ function renderContent(fm) {
121
+ const lines = [];
122
+ lines.push(`# ${fm.id} — ${fm.what}`);
123
+ lines.push('');
124
+ lines.push(`> 关联 spec: **${fm.docCode}** | 状态: **${fm.status}**${fm.supersededById ? ` | 被 ${fm.supersededById} 取代` : ''}`);
125
+ lines.push('');
126
+ lines.push('## 决定');
127
+ lines.push(fm.what);
128
+ lines.push('');
129
+ if (fm.why) {
130
+ lines.push('## 为什么');
131
+ lines.push(fm.why);
132
+ lines.push('');
133
+ }
134
+ if (fm.affectedCriteria && fm.affectedCriteria.length > 0) {
135
+ lines.push('## 影响的验收标准');
136
+ for (const c of fm.affectedCriteria)
137
+ lines.push(`- ${c}`);
138
+ lines.push('');
139
+ }
140
+ return lines.join('\n');
141
+ }
142
+ /**
143
+ * 删除决策。仅 active 状态可删;superseded/partial 状态需先恢复或归档(避免丢失审计轨迹)。
144
+ */
145
+ export function deleteDecision(paths, id) {
146
+ const d = findDecision(paths, id);
147
+ if (!d)
148
+ throw new Error(`Decision not found: ${id}`);
149
+ if (d.fm.status !== 'active') {
150
+ throw new Error(`Decision ${id} 是 ${d.fm.status} 状态,不能直接删除;` +
151
+ `如确需删除,先用 set-partial 标记或 supersede 取代`);
152
+ }
153
+ unlinkSync(d.filePath);
154
+ }
155
+ /**
156
+ * 编辑决策的 what/why/affectedCriteria。状态变更走 supersede / set-partial。
157
+ * superseded 状态的决策不可编辑(避免改历史)。
158
+ */
159
+ export function updateDecision(input) {
160
+ const existing = findDecision(input.paths, input.id);
161
+ if (!existing)
162
+ throw new Error(`Decision not found: ${input.id}`);
163
+ if (existing.fm.status !== 'active') {
164
+ throw new Error(`不能编辑 ${existing.fm.status} 状态的决策(只能编辑 active);用 supersede / set-partial 推进`);
165
+ }
166
+ if (input.what === undefined && input.why === undefined && input.affectedCriteria === undefined) {
167
+ throw new Error('未提供任何可更新字段(what/why/affectedCriteria)');
168
+ }
169
+ if (input.what !== undefined && input.what.length > WHAT_MAX) {
170
+ throw new Error(`what 长度 ${input.what.length} > ${WHAT_MAX}`);
171
+ }
172
+ if (input.why !== undefined && input.why.length > WHY_MAX) {
173
+ throw new Error(`why 长度 ${input.why.length} > ${WHY_MAX}`);
174
+ }
175
+ const fm = {
176
+ ...existing.fm,
177
+ what: input.what ?? existing.fm.what,
178
+ why: input.why ?? existing.fm.why,
179
+ affectedCriteria: input.affectedCriteria ?? existing.fm.affectedCriteria,
180
+ updated: new Date().toISOString(),
181
+ };
182
+ const content = renderContent(fm);
183
+ writeFrontmatterAtomic(existing.filePath, fm, content);
184
+ return { id: existing.id, fm, content, filePath: existing.filePath };
185
+ }
186
+ /**
187
+ * 把决策标记为 partial(部分被取代/部分作废),需 --reason 解释。
188
+ * 区别于 supersede:partial 不指向新决策 ID,只标记"局部失效"。
189
+ */
190
+ export function setDecisionPartial(input) {
191
+ const existing = findDecision(input.paths, input.id);
192
+ if (!existing)
193
+ throw new Error(`Decision not found: ${input.id}`);
194
+ if (existing.fm.status !== 'active') {
195
+ throw new Error(`Decision ${input.id} 已经是 ${existing.fm.status},无需重复标记`);
196
+ }
197
+ if (!input.reason.trim()) {
198
+ throw new Error('partial 必须提供 reason(说明哪些部分失效 / 为什么)');
199
+ }
200
+ const fm = {
201
+ ...existing.fm,
202
+ status: 'partial',
203
+ supersededById: null,
204
+ updated: new Date().toISOString(),
205
+ };
206
+ const content = renderContent(fm) + `\n## Partial 标记\n\n${input.reason}\n`;
207
+ writeFrontmatterAtomic(existing.filePath, fm, content);
208
+ return { id: existing.id, fm, content, filePath: existing.filePath };
209
+ }
210
+ //# sourceMappingURL=decision.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"decision.js","sourceRoot":"","sources":["../../src/core/decision.ts"],"names":[],"mappings":"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"}