vibe-commander 0.2.2 → 0.2.4
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.
|
@@ -120,9 +120,16 @@ function extractBySource(content, config, idPattern) {
|
|
|
120
120
|
/** 섹션 기반으로 의존성과 비유닛 컨텍스트 항목을 추출한다 */
|
|
121
121
|
function extractFromSection(content, sectionName, idPattern) {
|
|
122
122
|
const sectionLines = findSectionLines(content, sectionName, { allowBoldMarker: true });
|
|
123
|
-
if (sectionLines.length
|
|
124
|
-
return
|
|
125
|
-
|
|
123
|
+
if (sectionLines.length > 0) {
|
|
124
|
+
return parseDependencyLines(sectionLines, idPattern);
|
|
125
|
+
}
|
|
126
|
+
// Fallback: 볼드 마커의 인라인 콘텐츠 추출
|
|
127
|
+
// `**이전 작업에서 가져올 것**: [U-102[Mmp]](url) — 설명` 형태 처리
|
|
128
|
+
const inlineContent = findBoldMarkerInlineContent(content, sectionName);
|
|
129
|
+
if (inlineContent) {
|
|
130
|
+
return parseDependencyLines([`- ${inlineContent}`], idPattern);
|
|
131
|
+
}
|
|
132
|
+
return { deps: [], contextNotes: [] };
|
|
126
133
|
}
|
|
127
134
|
/** YAML frontmatter의 depends 필드에서 의존성을 추출한다 (배열/콤마/단일값) */
|
|
128
135
|
function extractFromFrontmatter(content) {
|
|
@@ -179,13 +186,27 @@ function extractFromMetadataTable(content, tableConfig) {
|
|
|
179
186
|
* 2. 하이픈(-)은 유닛 ID와 혼동될 수 있으므로 반드시 앞뒤 공백 필요
|
|
180
187
|
*/
|
|
181
188
|
const DESC_SEPARATOR_RE = /^(?:(.+?)\s*([—:])\s*(.+)|(.+?)\s+-\s+(.+))$/;
|
|
189
|
+
/**
|
|
190
|
+
* 마크다운 링크 구문을 제거하고 텍스트만 추출한다
|
|
191
|
+
*
|
|
192
|
+
* `[U-102[Mmp]](U-102[Mmp].md)` → `U-102[Mmp]`
|
|
193
|
+
*
|
|
194
|
+
* 중첩 대괄호 1레벨 지원. 링크가 아니면 원본 반환.
|
|
195
|
+
*/
|
|
196
|
+
function stripMarkdownLink(token) {
|
|
197
|
+
const linkMatch = token.match(/^\[((?:[^[\]]*(?:\[[^\]]*\])?[^[\]]*)*)\]\([^)]*\)$/);
|
|
198
|
+
return linkMatch?.[1]?.trim() ?? token;
|
|
199
|
+
}
|
|
182
200
|
/**
|
|
183
201
|
* `U-101 — Token 발급` 같은 토큰에서 unitId와 description을 분리한다
|
|
184
202
|
*
|
|
203
|
+
* 마크다운 링크 구문(`[ID](url)`)이 있으면 먼저 제거한 뒤 처리.
|
|
185
204
|
* 구분자가 없으면 전체가 unitId, description은 빈 문자열.
|
|
186
205
|
*/
|
|
187
206
|
function splitUnitIdAndDescription(rawToken) {
|
|
188
|
-
|
|
207
|
+
// 마크다운 링크 제거: [text](url) → text
|
|
208
|
+
const stripped = stripMarkdownLink(rawToken);
|
|
209
|
+
const match = stripped.match(DESC_SEPARATOR_RE);
|
|
189
210
|
if (match) {
|
|
190
211
|
// 1번 그룹(ID), 3번 그룹(Desc) 또는 4번 그룹(ID), 5번 그룹(Desc)
|
|
191
212
|
const unitId = (match[1] || match[4] || '').trim();
|
|
@@ -194,7 +215,29 @@ function splitUnitIdAndDescription(rawToken) {
|
|
|
194
215
|
return { unitId, description };
|
|
195
216
|
}
|
|
196
217
|
}
|
|
197
|
-
return { unitId:
|
|
218
|
+
return { unitId: stripped, description: '' };
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* 볼드 마커 라인에서 인라인 콘텐츠를 추출한다
|
|
222
|
+
*
|
|
223
|
+
* `**섹션명**: [U-102[Mmp]](url) — 설명` → `[U-102[Mmp]](url) — 설명`
|
|
224
|
+
*
|
|
225
|
+
* findSectionLines가 볼드 마커 라인의 인라인 콘텐츠를 건너뛰는 경우의 Fallback.
|
|
226
|
+
*/
|
|
227
|
+
function findBoldMarkerInlineContent(content, sectionName) {
|
|
228
|
+
const marker = `**${sectionName}**`;
|
|
229
|
+
for (const line of content.split('\n')) {
|
|
230
|
+
const trimmed = line.trim();
|
|
231
|
+
const idx = trimmed.indexOf(marker);
|
|
232
|
+
if (idx === -1)
|
|
233
|
+
continue;
|
|
234
|
+
const afterMarker = trimmed
|
|
235
|
+
.slice(idx + marker.length)
|
|
236
|
+
.replace(/^\s*[:\-—]\s*/, '')
|
|
237
|
+
.trim();
|
|
238
|
+
return afterMarker || null;
|
|
239
|
+
}
|
|
240
|
+
return null;
|
|
198
241
|
}
|
|
199
242
|
/**
|
|
200
243
|
* 본문 전체에서 ID 패턴으로 의존성을 스캔한다 (Fallback 최후 수단)
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
export declare const FRONTMATTER_RE: RegExp;
|
|
11
11
|
/** 마크다운 헤딩 패턴: # ~ ###### 레벨 */
|
|
12
12
|
export declare const HEADING_RE: RegExp;
|
|
13
|
-
/** 볼드 마커 패턴: **섹션명** (콜론/대시
|
|
13
|
+
/** 볼드 마커 패턴: **섹션명** (콜론/대시 허용, 인라인 콘텐츠 포함) */
|
|
14
14
|
export declare const BOLD_MARKER_RE: RegExp;
|
|
15
15
|
/**
|
|
16
16
|
* 섹션 탐색 옵션
|
|
@@ -10,8 +10,8 @@
|
|
|
10
10
|
export const FRONTMATTER_RE = /^---\r?\n([\s\S]*?)\r?\n---/;
|
|
11
11
|
/** 마크다운 헤딩 패턴: # ~ ###### 레벨 */
|
|
12
12
|
export const HEADING_RE = /^(#{1,6})\s+(.+)$/;
|
|
13
|
-
/** 볼드 마커 패턴: **섹션명** (콜론/대시
|
|
14
|
-
export const BOLD_MARKER_RE = /^\*\*[^*]
|
|
13
|
+
/** 볼드 마커 패턴: **섹션명** (콜론/대시 허용, 인라인 콘텐츠 포함) */
|
|
14
|
+
export const BOLD_MARKER_RE = /^\*\*[^*]+\*\*(?:\s*[:\-—]|\s*$)/;
|
|
15
15
|
/**
|
|
16
16
|
* 섹션명에 해당하는 콘텐츠 라인들을 추출한다
|
|
17
17
|
*
|
|
@@ -58,8 +58,8 @@ export function renderSection(context, unitTypeConfig, docPrefix = DEFAULT_DOC_P
|
|
|
58
58
|
/**
|
|
59
59
|
* 의존 유닛 목록과 비유닛 컨텍스트 항목을 렌더링한다
|
|
60
60
|
*
|
|
61
|
-
* 유닛 항목: `-
|
|
62
|
-
* 비유닛 항목: `- {description}` (
|
|
61
|
+
* 유닛 항목: `- {unitId}: {description}`
|
|
62
|
+
* 비유닛 항목: `- {description}` (유닛 ID 없이)
|
|
63
63
|
*/
|
|
64
64
|
function renderDepUnits(lines, context) {
|
|
65
65
|
lines.push('');
|
|
@@ -68,7 +68,7 @@ function renderDepUnits(lines, context) {
|
|
|
68
68
|
const hasContent = context.unit.depends.length > 0 || contextNotes.length > 0;
|
|
69
69
|
if (hasContent) {
|
|
70
70
|
for (const dep of context.unit.depends) {
|
|
71
|
-
lines.push(`-
|
|
71
|
+
lines.push(`- ${dep.unitId}: ${dep.description}`);
|
|
72
72
|
}
|
|
73
73
|
for (const note of contextNotes) {
|
|
74
74
|
lines.push(`- ${note}`);
|
|
@@ -79,17 +79,24 @@ function renderDepUnits(lines, context) {
|
|
|
79
79
|
}
|
|
80
80
|
}
|
|
81
81
|
/**
|
|
82
|
-
* 의존성 문서 경로를 렌더링한다
|
|
82
|
+
* 의존성 문서 경로를 유닛별로 그룹핑하여 렌더링한다
|
|
83
83
|
*
|
|
84
|
-
*
|
|
84
|
+
* 각 의존 유닛의 계획서, 결과서, 런북 3종을 `- @{path}` 형식으로 한줄씩 렌더링.
|
|
85
|
+
* 유닛이 여러 개일 때 유닛 ID 주석으로 그룹 구분.
|
|
85
86
|
*/
|
|
86
87
|
function renderDepDocs(lines, context, docPrefix) {
|
|
87
88
|
lines.push('');
|
|
88
89
|
lines.push('### 의존성 문서:');
|
|
89
|
-
const
|
|
90
|
-
if (
|
|
91
|
-
|
|
92
|
-
|
|
90
|
+
const nonEmptyGroups = context.depDocs.filter((d) => d.found.length > 0);
|
|
91
|
+
if (nonEmptyGroups.length > 0) {
|
|
92
|
+
const useGroupHeaders = nonEmptyGroups.length > 1;
|
|
93
|
+
for (const group of nonEmptyGroups) {
|
|
94
|
+
if (useGroupHeaders) {
|
|
95
|
+
lines.push(`<!-- ${group.unitId} -->`);
|
|
96
|
+
}
|
|
97
|
+
for (const doc of group.found) {
|
|
98
|
+
lines.push(`- ${docPrefix}${doc.path}`);
|
|
99
|
+
}
|
|
93
100
|
}
|
|
94
101
|
}
|
|
95
102
|
else {
|
|
@@ -100,10 +107,11 @@ function renderDepDocs(lines, context, docPrefix) {
|
|
|
100
107
|
* 의존성 커밋 SHA를 렌더링한다
|
|
101
108
|
*
|
|
102
109
|
* 형식: `- {sha}`
|
|
110
|
+
* 헤딩에 "(변경점 확인하여 맥락으로 사용)" 주석 포함
|
|
103
111
|
*/
|
|
104
112
|
function renderDepCommits(lines, context) {
|
|
105
113
|
lines.push('');
|
|
106
|
-
lines.push('### 의존성 Commits:');
|
|
114
|
+
lines.push('### 의존성 Commits (변경점 확인하여 맥락으로 사용):');
|
|
107
115
|
if (context.depCommits.length > 0) {
|
|
108
116
|
for (const sha of context.depCommits) {
|
|
109
117
|
lines.push(`- ${sha}`);
|
package/package.json
CHANGED