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.
- package/AGENTS.md +27 -0
- package/CODEBUDDY.md +19 -0
- package/LICENSE +21 -0
- package/README.md +531 -0
- package/dist/cli/audit.d.ts +10 -0
- package/dist/cli/audit.d.ts.map +1 -0
- package/dist/cli/audit.js +62 -0
- package/dist/cli/audit.js.map +1 -0
- package/dist/cli/change.d.ts +10 -0
- package/dist/cli/change.d.ts.map +1 -0
- package/dist/cli/change.js +103 -0
- package/dist/cli/change.js.map +1 -0
- package/dist/cli/common.d.ts +5 -0
- package/dist/cli/common.d.ts.map +1 -0
- package/dist/cli/common.js +17 -0
- package/dist/cli/common.js.map +1 -0
- package/dist/cli/decision.d.ts +13 -0
- package/dist/cli/decision.d.ts.map +1 -0
- package/dist/cli/decision.js +185 -0
- package/dist/cli/decision.js.map +1 -0
- package/dist/cli/dict.d.ts +10 -0
- package/dist/cli/dict.d.ts.map +1 -0
- package/dist/cli/dict.js +73 -0
- package/dist/cli/dict.js.map +1 -0
- package/dist/cli/incident.d.ts +10 -0
- package/dist/cli/incident.d.ts.map +1 -0
- package/dist/cli/incident.js +119 -0
- package/dist/cli/incident.js.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +30 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/project.d.ts +3 -0
- package/dist/cli/project.d.ts.map +1 -0
- package/dist/cli/project.js +144 -0
- package/dist/cli/project.js.map +1 -0
- package/dist/cli/spec.d.ts +3 -0
- package/dist/cli/spec.d.ts.map +1 -0
- package/dist/cli/spec.js +289 -0
- package/dist/cli/spec.js.map +1 -0
- package/dist/cli/task.d.ts +14 -0
- package/dist/cli/task.d.ts.map +1 -0
- package/dist/cli/task.js +287 -0
- package/dist/cli/task.js.map +1 -0
- package/dist/cli/usability.d.ts +3 -0
- package/dist/cli/usability.d.ts.map +1 -0
- package/dist/cli/usability.js +153 -0
- package/dist/cli/usability.js.map +1 -0
- package/dist/core/agents.d.ts +43 -0
- package/dist/core/agents.d.ts.map +1 -0
- package/dist/core/agents.js +194 -0
- package/dist/core/agents.js.map +1 -0
- package/dist/core/archive.d.ts +35 -0
- package/dist/core/archive.d.ts.map +1 -0
- package/dist/core/archive.js +360 -0
- package/dist/core/archive.js.map +1 -0
- package/dist/core/audit-events.d.ts +12 -0
- package/dist/core/audit-events.d.ts.map +1 -0
- package/dist/core/audit-events.js +16 -0
- package/dist/core/audit-events.js.map +1 -0
- package/dist/core/audit.d.ts +78 -0
- package/dist/core/audit.d.ts.map +1 -0
- package/dist/core/audit.js +157 -0
- package/dist/core/audit.js.map +1 -0
- package/dist/core/constants.d.ts +28 -0
- package/dist/core/constants.d.ts.map +1 -0
- package/dist/core/constants.js +30 -0
- package/dist/core/constants.js.map +1 -0
- package/dist/core/decision.d.ts +69 -0
- package/dist/core/decision.d.ts.map +1 -0
- package/dist/core/decision.js +210 -0
- package/dist/core/decision.js.map +1 -0
- package/dist/core/delta.d.ts +85 -0
- package/dist/core/delta.d.ts.map +1 -0
- package/dist/core/delta.js +264 -0
- package/dist/core/delta.js.map +1 -0
- package/dist/core/dict.d.ts +28 -0
- package/dist/core/dict.d.ts.map +1 -0
- package/dist/core/dict.js +57 -0
- package/dist/core/dict.js.map +1 -0
- package/dist/core/frontmatter.d.ts +19 -0
- package/dist/core/frontmatter.d.ts.map +1 -0
- package/dist/core/frontmatter.js +57 -0
- package/dist/core/frontmatter.js.map +1 -0
- package/dist/core/incident.d.ts +45 -0
- package/dist/core/incident.d.ts.map +1 -0
- package/dist/core/incident.js +128 -0
- package/dist/core/incident.js.map +1 -0
- package/dist/core/paths.d.ts +68 -0
- package/dist/core/paths.d.ts.map +1 -0
- package/dist/core/paths.js +162 -0
- package/dist/core/paths.js.map +1 -0
- package/dist/core/repository.d.ts +13 -0
- package/dist/core/repository.d.ts.map +1 -0
- package/dist/core/repository.js +29 -0
- package/dist/core/repository.js.map +1 -0
- package/dist/core/spec-io.d.ts +125 -0
- package/dist/core/spec-io.d.ts.map +1 -0
- package/dist/core/spec-io.js +260 -0
- package/dist/core/spec-io.js.map +1 -0
- package/dist/core/status.d.ts +22 -0
- package/dist/core/status.d.ts.map +1 -0
- package/dist/core/status.js +54 -0
- package/dist/core/status.js.map +1 -0
- package/dist/core/task.d.ts +118 -0
- package/dist/core/task.d.ts.map +1 -0
- package/dist/core/task.js +340 -0
- package/dist/core/task.js.map +1 -0
- package/dist/core/usability.d.ts +25 -0
- package/dist/core/usability.d.ts.map +1 -0
- package/dist/core/usability.js +136 -0
- package/dist/core/usability.js.map +1 -0
- package/dist/core/validate.d.ts +34 -0
- package/dist/core/validate.d.ts.map +1 -0
- package/dist/core/validate.js +195 -0
- package/dist/core/validate.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -0
- package/dist/schemas/change.d.ts +138 -0
- package/dist/schemas/change.d.ts.map +1 -0
- package/dist/schemas/change.js +38 -0
- package/dist/schemas/change.js.map +1 -0
- package/dist/schemas/spec.d.ts +233 -0
- package/dist/schemas/spec.d.ts.map +1 -0
- package/dist/schemas/spec.js +56 -0
- package/dist/schemas/spec.js.map +1 -0
- package/package.json +66 -0
- package/rules/_TEMPLATE.md +20 -0
- package/rules/code-discipline.md +47 -0
- package/rules/codebase-survey.md +37 -0
- package/rules/delta.md +42 -0
- package/rules/doc-governance.md +195 -0
- package/rules/flow-control.md +65 -0
- package/rules/quality-gate.md +73 -0
- package/skill/SKILL.md +90 -0
- package/skill/subskills/adr.md +73 -0
- package/skill/subskills/change.md +118 -0
- package/skill/subskills/design.md +53 -0
- package/skill/subskills/impl.md +100 -0
- package/skill/subskills/plan.md +46 -0
- package/skill/subskills/postmortem.md +77 -0
- package/skill/subskills/prd.md +72 -0
- package/skill/subskills/quick.md +25 -0
- package/skill/subskills/release.md +50 -0
- package/skill/subskills/research.md +35 -0
- package/skill/subskills/runbook.md +44 -0
- package/skill/subskills/testplan.md +48 -0
- package/templates/L0-prd.md +43 -0
- package/templates/L1-prd.md +130 -0
- package/templates/L2-design.md +135 -0
- package/templates/L3-impl.md +125 -0
- package/templates/agent-plan.json +17 -0
- package/templates/agents/AGENTS.md +27 -0
- package/templates/agents/CLAUDE.md +11 -0
- package/templates/agents/CODEBUDDY.md +23 -0
- package/templates/agents/codebuddy-skill/SKILL.md +46 -0
- package/templates/decision.md +42 -0
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Incident 记录
|
|
3
|
+
* 存储位置:.spec-manager/incidents/INC-YYYYMMDD-NNN.md
|
|
4
|
+
* frontmatter:id, ruleId, severity, status, created, specCode?, taskCode?
|
|
5
|
+
* 正文:触发场景、影响、临时修复、永久方案、关联 spec/task
|
|
6
|
+
*/
|
|
7
|
+
import { existsSync, readdirSync } from 'node:fs';
|
|
8
|
+
import { join } from 'node:path';
|
|
9
|
+
import { readFrontmatter, writeFrontmatterAtomic } from './frontmatter.js';
|
|
10
|
+
import { RULE_ID_RE } from './audit.js';
|
|
11
|
+
import { ID_PAD_WIDTH } from './constants.js';
|
|
12
|
+
const VALID_SEVERITY = ['low', 'medium', 'high', 'critical'];
|
|
13
|
+
const VALID_STATUS = ['open', 'mitigated', 'resolved', 'closed'];
|
|
14
|
+
export function listIncidents(paths, opts) {
|
|
15
|
+
if (!existsSync(paths.incidentsDir))
|
|
16
|
+
return [];
|
|
17
|
+
const out = [];
|
|
18
|
+
for (const f of readdirSync(paths.incidentsDir)) {
|
|
19
|
+
if (!f.endsWith('.md') || f.startsWith('.'))
|
|
20
|
+
continue;
|
|
21
|
+
const filePath = join(paths.incidentsDir, f);
|
|
22
|
+
const { data, content } = readFrontmatter(filePath);
|
|
23
|
+
const fm = data;
|
|
24
|
+
if (opts?.status && fm.status !== opts.status)
|
|
25
|
+
continue;
|
|
26
|
+
if (opts?.relatedDecision && !(fm.relatedDecisions ?? []).includes(opts.relatedDecision))
|
|
27
|
+
continue;
|
|
28
|
+
out.push({ id: fm.id, fm, content, filePath });
|
|
29
|
+
}
|
|
30
|
+
return out.sort((a, b) => b.fm.created.localeCompare(a.fm.created));
|
|
31
|
+
}
|
|
32
|
+
export function findIncident(paths, id) {
|
|
33
|
+
for (const i of listIncidents(paths)) {
|
|
34
|
+
if (i.id === id || i.fm.id === id)
|
|
35
|
+
return i;
|
|
36
|
+
}
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
export function nextIncidentId(paths) {
|
|
40
|
+
if (!existsSync(paths.incidentsDir)) {
|
|
41
|
+
const today = new Date().toISOString().slice(0, 10).replace(/-/g, '');
|
|
42
|
+
return `INC-${today}-001`;
|
|
43
|
+
}
|
|
44
|
+
const today = new Date().toISOString().slice(0, 10).replace(/-/g, '');
|
|
45
|
+
const prefix = `INC-${today}-`;
|
|
46
|
+
const existing = readdirSync(paths.incidentsDir)
|
|
47
|
+
.map(f => f.match(/^INC-\d{8}-(\d+)\.md$/))
|
|
48
|
+
.filter((m) => m !== null)
|
|
49
|
+
.map(m => Number(m[1]));
|
|
50
|
+
const max = existing.length > 0 ? Math.max(...existing) : 0;
|
|
51
|
+
return `${prefix}${String(max + 1).padStart(ID_PAD_WIDTH, '0')}`;
|
|
52
|
+
}
|
|
53
|
+
export function createIncident(input) {
|
|
54
|
+
if (!RULE_ID_RE.test(input.ruleId)) {
|
|
55
|
+
throw new Error(`ruleId 格式非法: ${input.ruleId}`);
|
|
56
|
+
}
|
|
57
|
+
if (!VALID_SEVERITY.includes(input.severity)) {
|
|
58
|
+
throw new Error(`severity 非法: ${input.severity}(必须 ${VALID_SEVERITY.join('|')})`);
|
|
59
|
+
}
|
|
60
|
+
if (!input.title.trim()) {
|
|
61
|
+
throw new Error('title 必填');
|
|
62
|
+
}
|
|
63
|
+
const id = nextIncidentId(input.paths);
|
|
64
|
+
const now = new Date().toISOString();
|
|
65
|
+
const fm = {
|
|
66
|
+
id,
|
|
67
|
+
ruleId: input.ruleId,
|
|
68
|
+
severity: input.severity,
|
|
69
|
+
status: 'open',
|
|
70
|
+
title: input.title,
|
|
71
|
+
specCode: input.specCode,
|
|
72
|
+
taskCode: input.taskCode,
|
|
73
|
+
relatedDecisions: input.relatedDecisions && input.relatedDecisions.length > 0
|
|
74
|
+
? input.relatedDecisions
|
|
75
|
+
: undefined,
|
|
76
|
+
created: now,
|
|
77
|
+
updated: now,
|
|
78
|
+
};
|
|
79
|
+
const content = renderContent(fm, input.description ?? '');
|
|
80
|
+
const filePath = join(input.paths.incidentsDir, `${id}.md`);
|
|
81
|
+
writeFrontmatterAtomic(filePath, fm, content);
|
|
82
|
+
return { id, fm, content, filePath };
|
|
83
|
+
}
|
|
84
|
+
export function updateIncidentStatus(paths, id, status, note) {
|
|
85
|
+
const inc = findIncident(paths, id);
|
|
86
|
+
if (!inc)
|
|
87
|
+
throw new Error(`Incident not found: ${id}`);
|
|
88
|
+
if (!VALID_STATUS.includes(status)) {
|
|
89
|
+
throw new Error(`status 非法: ${status}(必须 ${VALID_STATUS.join('|')})`);
|
|
90
|
+
}
|
|
91
|
+
const updated = {
|
|
92
|
+
...inc,
|
|
93
|
+
fm: { ...inc.fm, status, updated: new Date().toISOString() },
|
|
94
|
+
content: inc.content + (note ? `\n\n## ${status} (${new Date().toISOString()})\n${note}\n` : ''),
|
|
95
|
+
};
|
|
96
|
+
writeFrontmatterAtomic(inc.filePath, updated.fm, updated.content);
|
|
97
|
+
return updated;
|
|
98
|
+
}
|
|
99
|
+
function renderContent(fm, description) {
|
|
100
|
+
const lines = [];
|
|
101
|
+
lines.push(`# ${fm.id} — ${fm.title}`);
|
|
102
|
+
lines.push('');
|
|
103
|
+
lines.push(`> 规则: **${fm.ruleId}** | 严重度: **${fm.severity}** | 状态: **${fm.status}**${fm.specCode ? ` | spec: ${fm.specCode}` : ''}${fm.taskCode ? ` | task: ${fm.taskCode}` : ''}`);
|
|
104
|
+
lines.push('');
|
|
105
|
+
lines.push(`> 创建: ${fm.created}`);
|
|
106
|
+
lines.push('');
|
|
107
|
+
lines.push('## 触发场景');
|
|
108
|
+
lines.push(description || '(请补充)');
|
|
109
|
+
lines.push('');
|
|
110
|
+
lines.push('## 影响');
|
|
111
|
+
lines.push('(请补充:影响范围 + 用户痛点)');
|
|
112
|
+
lines.push('');
|
|
113
|
+
lines.push('## 临时修复');
|
|
114
|
+
lines.push('(请补充:紧急止血)');
|
|
115
|
+
lines.push('');
|
|
116
|
+
lines.push('## 永久方案');
|
|
117
|
+
lines.push('(请补充:根因 + 长期修复)');
|
|
118
|
+
lines.push('');
|
|
119
|
+
lines.push('## 关联');
|
|
120
|
+
lines.push('- spec: ' + (fm.specCode ?? '-'));
|
|
121
|
+
lines.push('- task: ' + (fm.taskCode ?? '-'));
|
|
122
|
+
lines.push('- 规则: ' + fm.ruleId);
|
|
123
|
+
if (fm.relatedDecisions && fm.relatedDecisions.length > 0) {
|
|
124
|
+
lines.push('- 决策: ' + fm.relatedDecisions.join(', '));
|
|
125
|
+
}
|
|
126
|
+
return lines.join('\n');
|
|
127
|
+
}
|
|
128
|
+
//# sourceMappingURL=incident.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"incident.js","sourceRoot":"","sources":["../../src/core/incident.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 解析项目根目录。
|
|
3
|
+
* 策略:优先用 SPEC_MANAGER_ROOT 环境变量,否则从 cwd 向上找 .spec-manager/,
|
|
4
|
+
* 找到为止;找不到就用 cwd(让首次 init 有合理默认值)。
|
|
5
|
+
*/
|
|
6
|
+
export declare function resolveProjectRoot(cwd?: string): string;
|
|
7
|
+
export interface ProjectPaths {
|
|
8
|
+
root: string;
|
|
9
|
+
configDir: string;
|
|
10
|
+
configFile: string;
|
|
11
|
+
auditFile: string;
|
|
12
|
+
incidentsDir: string;
|
|
13
|
+
dictFile: string;
|
|
14
|
+
specsDir: string;
|
|
15
|
+
changesDir: string;
|
|
16
|
+
archiveDir: string;
|
|
17
|
+
isInitialized: boolean;
|
|
18
|
+
}
|
|
19
|
+
export declare function getPaths(root?: string): ProjectPaths;
|
|
20
|
+
/**
|
|
21
|
+
* 平铺布局下的 spec 文件路径。
|
|
22
|
+
*
|
|
23
|
+
* 布局:specs/<topic>/<code>.md
|
|
24
|
+
* 点分编号已编码层级关系,无需嵌套目录。
|
|
25
|
+
*
|
|
26
|
+
* @param parentFilePath 保留参数(向后兼容),平铺布局下忽略
|
|
27
|
+
* @param code spec code(如 auth-L1、auth-L2.1、auth-L3.1.1)
|
|
28
|
+
* @param topic topic 名
|
|
29
|
+
* @param date 保留参数(向后兼容),canonical 路径下忽略
|
|
30
|
+
*/
|
|
31
|
+
export declare function specFilePath(paths: ProjectPaths, _parentFilePath: string | null, code: string, topic?: string, _date?: string): string;
|
|
32
|
+
export declare function assertSafeTopic(topic: string): void;
|
|
33
|
+
export declare function assertSafeSpecCode(code: string): void;
|
|
34
|
+
/**
|
|
35
|
+
* 平铺布局下,元数据目录在 topic 级别:
|
|
36
|
+
* specs/<topic>/decisions/、specs/<topic>/tasks/
|
|
37
|
+
*/
|
|
38
|
+
export declare function siblingMetaDir(specFilePath: string, name: 'decisions' | 'tasks'): string;
|
|
39
|
+
export interface SpecFileEntry {
|
|
40
|
+
topic: string;
|
|
41
|
+
code: string;
|
|
42
|
+
filePath: string;
|
|
43
|
+
}
|
|
44
|
+
export interface ParsedSpecFilename {
|
|
45
|
+
code: string;
|
|
46
|
+
format: 'canonical' | 'legacy-date';
|
|
47
|
+
legacyDate?: string;
|
|
48
|
+
}
|
|
49
|
+
export interface SpecPathMigration {
|
|
50
|
+
topic: string;
|
|
51
|
+
code: string;
|
|
52
|
+
from: string;
|
|
53
|
+
to: string;
|
|
54
|
+
legacyDate: string;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* 平铺布局:直接扫描 specs/<topic>/ 下的 .md 文件。
|
|
58
|
+
* 跳过元数据目录(decisions/ tasks/ 等)。
|
|
59
|
+
*/
|
|
60
|
+
export declare function listSpecFiles(paths: ProjectPaths): SpecFileEntry[];
|
|
61
|
+
export declare function listSpecPathMigrations(paths: ProjectPaths): SpecPathMigration[];
|
|
62
|
+
/**
|
|
63
|
+
* 从文件名提取 code。
|
|
64
|
+
* canonical: <code>.md
|
|
65
|
+
* legacy: <code>-<YYYYMMDD>.md
|
|
66
|
+
*/
|
|
67
|
+
export declare function parseSpecFilename(filename: string): ParsedSpecFilename | null;
|
|
68
|
+
//# sourceMappingURL=paths.d.ts.map
|
|
@@ -0,0 +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"}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { existsSync, readdirSync, statSync } from 'node:fs';
|
|
2
|
+
import { dirname, join, resolve } from 'node:path';
|
|
3
|
+
import { SPEC_CODE_RE, TOPIC_RE } from './constants.js';
|
|
4
|
+
/**
|
|
5
|
+
* 解析项目根目录。
|
|
6
|
+
* 策略:优先用 SPEC_MANAGER_ROOT 环境变量,否则从 cwd 向上找 .spec-manager/,
|
|
7
|
+
* 找到为止;找不到就用 cwd(让首次 init 有合理默认值)。
|
|
8
|
+
*/
|
|
9
|
+
export function resolveProjectRoot(cwd = process.cwd()) {
|
|
10
|
+
const envRoot = process.env.SPEC_MANAGER_ROOT;
|
|
11
|
+
if (envRoot)
|
|
12
|
+
return resolve(envRoot);
|
|
13
|
+
let dir = resolve(cwd);
|
|
14
|
+
for (let i = 0; i < 8; i++) {
|
|
15
|
+
if (existsSync(join(dir, '.spec-manager')))
|
|
16
|
+
return dir;
|
|
17
|
+
const parent = dirname(dir);
|
|
18
|
+
if (parent === dir)
|
|
19
|
+
break;
|
|
20
|
+
dir = parent;
|
|
21
|
+
}
|
|
22
|
+
return resolve(cwd);
|
|
23
|
+
}
|
|
24
|
+
export function getPaths(root = resolveProjectRoot()) {
|
|
25
|
+
const configDir = join(root, '.spec-manager');
|
|
26
|
+
const isInitialized = statSafe(configDir)?.isDirectory() ?? false;
|
|
27
|
+
return {
|
|
28
|
+
root,
|
|
29
|
+
configDir,
|
|
30
|
+
configFile: join(configDir, 'config.yaml'),
|
|
31
|
+
auditFile: join(configDir, 'audit.json'),
|
|
32
|
+
incidentsDir: join(configDir, 'incidents'),
|
|
33
|
+
dictFile: join(configDir, 'dict.yaml'),
|
|
34
|
+
specsDir: join(root, 'specs'),
|
|
35
|
+
changesDir: join(root, 'changes'),
|
|
36
|
+
archiveDir: join(root, 'archive'),
|
|
37
|
+
isInitialized,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
function statSafe(p) {
|
|
41
|
+
try {
|
|
42
|
+
return statSync(p);
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* 平铺布局下的 spec 文件路径。
|
|
50
|
+
*
|
|
51
|
+
* 布局:specs/<topic>/<code>.md
|
|
52
|
+
* 点分编号已编码层级关系,无需嵌套目录。
|
|
53
|
+
*
|
|
54
|
+
* @param parentFilePath 保留参数(向后兼容),平铺布局下忽略
|
|
55
|
+
* @param code spec code(如 auth-L1、auth-L2.1、auth-L3.1.1)
|
|
56
|
+
* @param topic topic 名
|
|
57
|
+
* @param date 保留参数(向后兼容),canonical 路径下忽略
|
|
58
|
+
*/
|
|
59
|
+
export function specFilePath(paths, _parentFilePath, code, topic, _date) {
|
|
60
|
+
assertSafeSpecCode(code);
|
|
61
|
+
const t = topic ?? extractTopicFromCode(code);
|
|
62
|
+
assertSafeTopic(t);
|
|
63
|
+
return join(paths.specsDir, t, `${code}.md`);
|
|
64
|
+
}
|
|
65
|
+
function extractTopicFromCode(code) {
|
|
66
|
+
// spec-manager-ai-ux-L1 → spec-manager-ai-ux
|
|
67
|
+
const match = code.match(/^(.+)-L\d/);
|
|
68
|
+
if (match)
|
|
69
|
+
return match[1];
|
|
70
|
+
throw new Error(`specFilePath: 无法从 code 推断 topic,请传 topic 参数`);
|
|
71
|
+
}
|
|
72
|
+
export function assertSafeTopic(topic) {
|
|
73
|
+
if (!TOPIC_RE.test(topic)) {
|
|
74
|
+
throw new Error(`topic 非法: ${topic}(必须匹配 ${TOPIC_RE.source},且不能包含路径分隔符)`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
export function assertSafeSpecCode(code) {
|
|
78
|
+
if (!SPEC_CODE_RE.test(code)) {
|
|
79
|
+
throw new Error(`spec code 非法: ${code}(必须匹配 ${SPEC_CODE_RE.source},且不能包含路径分隔符)`);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* 平铺布局下,元数据目录在 topic 级别:
|
|
84
|
+
* specs/<topic>/decisions/、specs/<topic>/tasks/
|
|
85
|
+
*/
|
|
86
|
+
export function siblingMetaDir(specFilePath, name) {
|
|
87
|
+
return join(dirname(specFilePath), name);
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* 平铺布局:直接扫描 specs/<topic>/ 下的 .md 文件。
|
|
91
|
+
* 跳过元数据目录(decisions/ tasks/ 等)。
|
|
92
|
+
*/
|
|
93
|
+
export function listSpecFiles(paths) {
|
|
94
|
+
const out = [];
|
|
95
|
+
if (!existsSync(paths.specsDir))
|
|
96
|
+
return out;
|
|
97
|
+
for (const topicEntry of readdirSync(paths.specsDir, { withFileTypes: true })) {
|
|
98
|
+
if (!topicEntry.isDirectory() || topicEntry.name.startsWith('.'))
|
|
99
|
+
continue;
|
|
100
|
+
const topicDir = join(paths.specsDir, topicEntry.name);
|
|
101
|
+
for (const file of readdirSync(topicDir, { withFileTypes: true })) {
|
|
102
|
+
if (file.isDirectory())
|
|
103
|
+
continue;
|
|
104
|
+
if (!file.name.endsWith('.md'))
|
|
105
|
+
continue;
|
|
106
|
+
if (file.name.startsWith('.'))
|
|
107
|
+
continue;
|
|
108
|
+
const parsed = parseSpecFilename(file.name);
|
|
109
|
+
if (!parsed)
|
|
110
|
+
continue;
|
|
111
|
+
const filePath = join(topicDir, file.name);
|
|
112
|
+
const dup = out.find(e => e.topic === topicEntry.name && e.code === parsed.code);
|
|
113
|
+
if (dup) {
|
|
114
|
+
throw new Error(`重复 spec code: ${parsed.code} (${dup.filePath}, ${filePath})`);
|
|
115
|
+
}
|
|
116
|
+
out.push({ topic: topicEntry.name, code: parsed.code, filePath });
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return out.sort((a, b) => a.code.localeCompare(b.code));
|
|
120
|
+
}
|
|
121
|
+
export function listSpecPathMigrations(paths) {
|
|
122
|
+
const out = [];
|
|
123
|
+
if (!existsSync(paths.specsDir))
|
|
124
|
+
return out;
|
|
125
|
+
for (const topicEntry of readdirSync(paths.specsDir, { withFileTypes: true })) {
|
|
126
|
+
if (!topicEntry.isDirectory() || topicEntry.name.startsWith('.'))
|
|
127
|
+
continue;
|
|
128
|
+
const topicDir = join(paths.specsDir, topicEntry.name);
|
|
129
|
+
for (const file of readdirSync(topicDir, { withFileTypes: true })) {
|
|
130
|
+
if (file.isDirectory() || file.name.startsWith('.') || !file.name.endsWith('.md'))
|
|
131
|
+
continue;
|
|
132
|
+
const parsed = parseSpecFilename(file.name);
|
|
133
|
+
if (!parsed || parsed.format !== 'legacy-date' || !parsed.legacyDate)
|
|
134
|
+
continue;
|
|
135
|
+
out.push({
|
|
136
|
+
topic: topicEntry.name,
|
|
137
|
+
code: parsed.code,
|
|
138
|
+
from: join(topicDir, file.name),
|
|
139
|
+
to: join(topicDir, `${parsed.code}.md`),
|
|
140
|
+
legacyDate: parsed.legacyDate,
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return out.sort((a, b) => a.code.localeCompare(b.code));
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* 从文件名提取 code。
|
|
148
|
+
* canonical: <code>.md
|
|
149
|
+
* legacy: <code>-<YYYYMMDD>.md
|
|
150
|
+
*/
|
|
151
|
+
export function parseSpecFilename(filename) {
|
|
152
|
+
const legacy = filename.match(/^(.+)-(\d{8})\.md$/);
|
|
153
|
+
if (legacy && SPEC_CODE_RE.test(legacy[1])) {
|
|
154
|
+
return { code: legacy[1], format: 'legacy-date', legacyDate: legacy[2] };
|
|
155
|
+
}
|
|
156
|
+
const old = filename.match(/^(.+)\.md$/);
|
|
157
|
+
if (old && SPEC_CODE_RE.test(old[1])) {
|
|
158
|
+
return { code: old[1], format: 'canonical' };
|
|
159
|
+
}
|
|
160
|
+
return null;
|
|
161
|
+
}
|
|
162
|
+
//# sourceMappingURL=paths.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paths.js","sourceRoot":"","sources":["../../src/core/paths.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { ProjectPaths } from './paths.js';
|
|
2
|
+
export type TopicMetaDir = 'tasks' | 'decisions';
|
|
3
|
+
export interface TopicMetaFile {
|
|
4
|
+
topic: string;
|
|
5
|
+
fileName: string;
|
|
6
|
+
filePath: string;
|
|
7
|
+
}
|
|
8
|
+
export declare function listTopicMetaFiles(paths: ProjectPaths, dirName: TopicMetaDir, opts?: {
|
|
9
|
+
topic?: string;
|
|
10
|
+
extension?: string;
|
|
11
|
+
filePrefix?: string;
|
|
12
|
+
}): TopicMetaFile[];
|
|
13
|
+
//# sourceMappingURL=repository.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repository.d.ts","sourceRoot":"","sources":["../../src/core/repository.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,WAAW,CAAC;AAEjD,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,YAAY,EACnB,OAAO,EAAE,YAAY,EACrB,IAAI,CAAC,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,GACjE,aAAa,EAAE,CAuBjB"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { existsSync, readdirSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
export function listTopicMetaFiles(paths, dirName, opts) {
|
|
4
|
+
const out = [];
|
|
5
|
+
if (!existsSync(paths.specsDir))
|
|
6
|
+
return out;
|
|
7
|
+
for (const topicEntry of readdirSync(paths.specsDir, { withFileTypes: true })) {
|
|
8
|
+
if (!topicEntry.isDirectory() || topicEntry.name.startsWith('.'))
|
|
9
|
+
continue;
|
|
10
|
+
if (opts?.topic && topicEntry.name !== opts.topic)
|
|
11
|
+
continue;
|
|
12
|
+
const metaDir = join(paths.specsDir, topicEntry.name, dirName);
|
|
13
|
+
if (!existsSync(metaDir))
|
|
14
|
+
continue;
|
|
15
|
+
for (const fileName of readdirSync(metaDir)) {
|
|
16
|
+
if (opts?.extension && !fileName.endsWith(opts.extension))
|
|
17
|
+
continue;
|
|
18
|
+
if (opts?.filePrefix && !fileName.startsWith(opts.filePrefix))
|
|
19
|
+
continue;
|
|
20
|
+
out.push({
|
|
21
|
+
topic: topicEntry.name,
|
|
22
|
+
fileName,
|
|
23
|
+
filePath: join(metaDir, fileName),
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return out.sort((a, b) => a.filePath.localeCompare(b.filePath));
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=repository.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repository.js","sourceRoot":"","sources":["../../src/core/repository.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAClD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAWjC,MAAM,UAAU,kBAAkB,CAChC,KAAmB,EACnB,OAAqB,EACrB,IAAkE;IAElE,MAAM,GAAG,GAAoB,EAAE,CAAC;IAChC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,QAAQ,CAAC;QAAE,OAAO,GAAG,CAAC;IAE5C,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,IAAI,IAAI,EAAE,KAAK,IAAI,UAAU,CAAC,IAAI,KAAK,IAAI,CAAC,KAAK;YAAE,SAAS;QAE5D,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,UAAU,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QAC/D,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC;YAAE,SAAS;QAEnC,KAAK,MAAM,QAAQ,IAAI,WAAW,CAAC,OAAO,CAAC,EAAE,CAAC;YAC5C,IAAI,IAAI,EAAE,SAAS,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC;gBAAE,SAAS;YACpE,IAAI,IAAI,EAAE,UAAU,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC,UAAU,CAAC;gBAAE,SAAS;YACxE,GAAG,CAAC,IAAI,CAAC;gBACP,KAAK,EAAE,UAAU,CAAC,IAAI;gBACtB,QAAQ;gBACR,QAAQ,EAAE,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC;aAClC,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,OAAO,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC;AAClE,CAAC"}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Spec 文件的原子读写。
|
|
3
|
+
*
|
|
4
|
+
* 写策略:写临时文件 → rename,保证并发下不会读到半截内容。
|
|
5
|
+
* 读策略:先解析 frontmatter,找不到时返回 null(由调用方决定 fallback)。
|
|
6
|
+
*/
|
|
7
|
+
import type { SpecLevel } from './validate.js';
|
|
8
|
+
import { type ProjectPaths } from './paths.js';
|
|
9
|
+
import { type AuditSink } from './audit-events.js';
|
|
10
|
+
export interface SpecFrontmatter {
|
|
11
|
+
id?: string;
|
|
12
|
+
code: string;
|
|
13
|
+
level: SpecLevel;
|
|
14
|
+
title: string;
|
|
15
|
+
topic: string;
|
|
16
|
+
parentCode: string | null;
|
|
17
|
+
status: 'draft' | 'confirmed' | 'frozen' | 'implemented' | 'archived';
|
|
18
|
+
milestone?: string;
|
|
19
|
+
aiSummary?: string;
|
|
20
|
+
coveredTasks?: string[];
|
|
21
|
+
steps?: StepFrontmatter[];
|
|
22
|
+
relations?: Array<{
|
|
23
|
+
type: string;
|
|
24
|
+
target: string;
|
|
25
|
+
}>;
|
|
26
|
+
created?: string;
|
|
27
|
+
updated?: string;
|
|
28
|
+
changeSummary?: string;
|
|
29
|
+
}
|
|
30
|
+
export interface StepFrontmatter {
|
|
31
|
+
stepNo: number | string;
|
|
32
|
+
stepType: 'llm_call' | 'mcp_tool' | 'human_gate';
|
|
33
|
+
name: string;
|
|
34
|
+
status: 'pending' | 'running' | 'succeeded' | 'failed' | 'skipped';
|
|
35
|
+
toolName?: string;
|
|
36
|
+
inputJson?: string;
|
|
37
|
+
outputJson?: string;
|
|
38
|
+
errorCode?: string;
|
|
39
|
+
errorMessage?: string;
|
|
40
|
+
latencyMs?: number;
|
|
41
|
+
reportedAt?: string;
|
|
42
|
+
}
|
|
43
|
+
export interface SpecRecord {
|
|
44
|
+
fm: SpecFrontmatter;
|
|
45
|
+
content: string;
|
|
46
|
+
filePath: string;
|
|
47
|
+
}
|
|
48
|
+
export declare const DESC_MAX_LEN = 15;
|
|
49
|
+
/**
|
|
50
|
+
* 生成 spec code: 点分编号,层级自文档化。
|
|
51
|
+
* - L1: <topic>-L1
|
|
52
|
+
* - L2: <topic>-L2.1(第 1 个 L2 子 spec)
|
|
53
|
+
* - L3: <topic>-L3.1.1[-desc](可选描述后缀,≤15 字符)
|
|
54
|
+
*
|
|
55
|
+
* parentCode 为空时生成 <topic>-<level>;
|
|
56
|
+
* 非空时生成 <topic>-<level>.<N>[.M...][-desc]。
|
|
57
|
+
*/
|
|
58
|
+
export declare function generateSpecCode(topic: string, level: SpecLevel, parentCode?: string, siblingCount?: number, desc?: string): string;
|
|
59
|
+
export declare function readSpec(filePath: string): SpecRecord | null;
|
|
60
|
+
export declare function findSpecByCode(paths: ProjectPaths, code: string): SpecRecord | null;
|
|
61
|
+
/**
|
|
62
|
+
* 带 mtime 失效的 listAllSpecs。文件未变时复用内存里的解析结果,
|
|
63
|
+
* 避免每次 decision/task/archive/delta 全扫都重新 parse frontmatter。
|
|
64
|
+
*
|
|
65
|
+
* 注意:单进程内有效;多进程或显式调 invalidateSpecCache() 失效。
|
|
66
|
+
*/
|
|
67
|
+
export declare function listAllSpecs(paths: ProjectPaths): SpecRecord[];
|
|
68
|
+
export declare function invalidateSpecCache(filePath?: string): void;
|
|
69
|
+
/**
|
|
70
|
+
* 原子写:先写临时文件,再 rename。
|
|
71
|
+
*/
|
|
72
|
+
export declare function writeSpec(record: SpecRecord): void;
|
|
73
|
+
export declare function createSpec(args: {
|
|
74
|
+
paths: ProjectPaths;
|
|
75
|
+
code: string;
|
|
76
|
+
level: SpecLevel;
|
|
77
|
+
title: string;
|
|
78
|
+
topic: string;
|
|
79
|
+
parentCode: string | null;
|
|
80
|
+
parentRecord?: SpecRecord | null;
|
|
81
|
+
milestone?: string;
|
|
82
|
+
auditSink?: AuditSink;
|
|
83
|
+
}): SpecRecord;
|
|
84
|
+
/**
|
|
85
|
+
* 更新 spec:传 partial 覆盖 frontmatter,更新 content,更新 updated 时间戳。
|
|
86
|
+
* 自动截断 aiSummary 到 300 字符(带 warning)。
|
|
87
|
+
*/
|
|
88
|
+
export interface UpdateResult {
|
|
89
|
+
record: SpecRecord;
|
|
90
|
+
warnings: string[];
|
|
91
|
+
}
|
|
92
|
+
export declare function updateSpec(paths: ProjectPaths, code: string, patch: {
|
|
93
|
+
content?: string;
|
|
94
|
+
aiSummary?: string;
|
|
95
|
+
changeSummary?: string;
|
|
96
|
+
status?: SpecFrontmatter['status'];
|
|
97
|
+
appendStep?: StepFrontmatter;
|
|
98
|
+
replaceStep?: {
|
|
99
|
+
no: number | string;
|
|
100
|
+
step: StepFrontmatter;
|
|
101
|
+
};
|
|
102
|
+
addRelation?: {
|
|
103
|
+
type: string;
|
|
104
|
+
target: string;
|
|
105
|
+
};
|
|
106
|
+
}, opts?: {
|
|
107
|
+
auditSink?: AuditSink;
|
|
108
|
+
}): UpdateResult;
|
|
109
|
+
/**
|
|
110
|
+
* R22: contentTemplate 是不是只剩 createSpec 写出的占位?
|
|
111
|
+
* 占位 = 文件里有 marker 行,且去掉 marker 后正文长度 < PLACEHOLDER_CONTENT_MAX。
|
|
112
|
+
*/
|
|
113
|
+
export declare function isPlaceholderContent(content: string): boolean;
|
|
114
|
+
export interface SpecPathMigrationResult {
|
|
115
|
+
dryRun: boolean;
|
|
116
|
+
migrated: Array<{
|
|
117
|
+
code: string;
|
|
118
|
+
from: string;
|
|
119
|
+
to: string;
|
|
120
|
+
}>;
|
|
121
|
+
}
|
|
122
|
+
export declare function migrateSpecPaths(paths: ProjectPaths, opts?: {
|
|
123
|
+
dryRun?: boolean;
|
|
124
|
+
}): SpecPathMigrationResult;
|
|
125
|
+
//# sourceMappingURL=spec-io.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spec-io.d.ts","sourceRoot":"","sources":["../../src/core/spec-io.ts"],"names":[],"mappings":"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"}
|