vibe-commander 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/LICENSE +21 -0
- package/dist/adapters/cli/commands/context-resolver.d.ts +29 -0
- package/dist/adapters/cli/commands/context-resolver.js +93 -0
- package/dist/adapters/cli/commands/context.d.ts +26 -0
- package/dist/adapters/cli/commands/context.js +39 -0
- package/dist/adapters/cli/commands/git-helpers.d.ts +43 -0
- package/dist/adapters/cli/commands/git-helpers.js +99 -0
- package/dist/adapters/cli/commands/init-helpers.d.ts +30 -0
- package/dist/adapters/cli/commands/init-helpers.js +112 -0
- package/dist/adapters/cli/commands/init-interactive.d.ts +25 -0
- package/dist/adapters/cli/commands/init-interactive.js +143 -0
- package/dist/adapters/cli/commands/init.d.ts +25 -0
- package/dist/adapters/cli/commands/init.js +73 -0
- package/dist/adapters/cli/commands/io-helpers.d.ts +45 -0
- package/dist/adapters/cli/commands/io-helpers.js +144 -0
- package/dist/adapters/cli/commands/list-units.d.ts +39 -0
- package/dist/adapters/cli/commands/list-units.js +92 -0
- package/dist/adapters/cli/commands/prompt-helpers.d.ts +36 -0
- package/dist/adapters/cli/commands/prompt-helpers.js +113 -0
- package/dist/adapters/cli/commands/set-unit.d.ts +44 -0
- package/dist/adapters/cli/commands/set-unit.js +90 -0
- package/dist/adapters/cli/commands/skill-install.d.ts +31 -0
- package/dist/adapters/cli/commands/skill-install.js +85 -0
- package/dist/adapters/cli/commands/state-helpers.d.ts +28 -0
- package/dist/adapters/cli/commands/state-helpers.js +55 -0
- package/dist/adapters/cli/commands/update-commit.d.ts +42 -0
- package/dist/adapters/cli/commands/update-commit.js +180 -0
- package/dist/adapters/cli/commands/validate.d.ts +40 -0
- package/dist/adapters/cli/commands/validate.js +219 -0
- package/dist/adapters/cli/formatters-list.d.ts +36 -0
- package/dist/adapters/cli/formatters-list.js +106 -0
- package/dist/adapters/cli/formatters-unit.d.ts +44 -0
- package/dist/adapters/cli/formatters-unit.js +287 -0
- package/dist/adapters/cli/formatters.d.ts +2 -0
- package/dist/adapters/cli/formatters.js +3 -0
- package/dist/adapters/cli/index.d.ts +17 -0
- package/dist/adapters/cli/index.js +60 -0
- package/dist/adapters/cli/output.d.ts +58 -0
- package/dist/adapters/cli/output.js +159 -0
- package/dist/adapters/cli/router.d.ts +99 -0
- package/dist/adapters/cli/router.js +419 -0
- package/dist/adapters/cli/scanner.d.ts +19 -0
- package/dist/adapters/cli/scanner.js +227 -0
- package/dist/adapters/pipe/stdin-reader.d.ts +23 -0
- package/dist/adapters/pipe/stdin-reader.js +56 -0
- package/dist/config/loader.d.ts +27 -0
- package/dist/config/loader.js +84 -0
- package/dist/config/resolver.d.ts +71 -0
- package/dist/config/resolver.js +124 -0
- package/dist/config/schema.d.ts +205 -0
- package/dist/config/schema.js +186 -0
- package/dist/core/parsers/backlog-parser.d.ts +25 -0
- package/dist/core/parsers/backlog-parser.js +255 -0
- package/dist/core/parsers/dep-line-parser.d.ts +36 -0
- package/dist/core/parsers/dep-line-parser.js +176 -0
- package/dist/core/parsers/dependency-extractor.d.ts +64 -0
- package/dist/core/parsers/dependency-extractor.js +193 -0
- package/dist/core/parsers/index.d.ts +20 -0
- package/dist/core/parsers/index.js +20 -0
- package/dist/core/parsers/md-utils.d.ts +81 -0
- package/dist/core/parsers/md-utils.js +144 -0
- package/dist/core/parsers/metadata-parser.d.ts +49 -0
- package/dist/core/parsers/metadata-parser.js +133 -0
- package/dist/core/parsers/pairing-question-extractor.d.ts +42 -0
- package/dist/core/parsers/pairing-question-extractor.js +146 -0
- package/dist/core/parsers/plan-parser-helpers.d.ts +61 -0
- package/dist/core/parsers/plan-parser-helpers.js +90 -0
- package/dist/core/parsers/plan-parser.d.ts +55 -0
- package/dist/core/parsers/plan-parser.js +69 -0
- package/dist/core/parsers/title-extractor.d.ts +36 -0
- package/dist/core/parsers/title-extractor.js +101 -0
- package/dist/core/renderers/index.d.ts +15 -0
- package/dist/core/renderers/index.js +18 -0
- package/dist/core/renderers/interpolate.d.ts +92 -0
- package/dist/core/renderers/interpolate.js +117 -0
- package/dist/core/renderers/marker-utils.d.ts +60 -0
- package/dist/core/renderers/marker-utils.js +85 -0
- package/dist/core/renderers/section-renderer.d.ts +31 -0
- package/dist/core/renderers/section-renderer.js +171 -0
- package/dist/core/renderers/section-updater.d.ts +72 -0
- package/dist/core/renderers/section-updater.js +175 -0
- package/dist/core/renderers/template-engine.d.ts +69 -0
- package/dist/core/renderers/template-engine.js +92 -0
- package/dist/core/renderers/updater-helpers.d.ts +45 -0
- package/dist/core/renderers/updater-helpers.js +83 -0
- package/dist/core/resolvers/commit-filter.d.ts +84 -0
- package/dist/core/resolvers/commit-filter.js +95 -0
- package/dist/core/resolvers/config-generator.d.ts +32 -0
- package/dist/core/resolvers/config-generator.js +112 -0
- package/dist/core/resolvers/config-merger.d.ts +26 -0
- package/dist/core/resolvers/config-merger.js +89 -0
- package/dist/core/resolvers/config-validator.d.ts +42 -0
- package/dist/core/resolvers/config-validator.js +61 -0
- package/dist/core/resolvers/dep-commit-resolver.d.ts +63 -0
- package/dist/core/resolvers/dep-commit-resolver.js +158 -0
- package/dist/core/resolvers/dep-doc-resolver.d.ts +70 -0
- package/dist/core/resolvers/dep-doc-resolver.js +84 -0
- package/dist/core/resolvers/index.d.ts +15 -0
- package/dist/core/resolvers/index.js +12 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +8 -0
- package/dist/types/config.d.ts +10 -0
- package/dist/types/config.js +10 -0
- package/dist/types/context.d.ts +55 -0
- package/dist/types/context.js +10 -0
- package/dist/types/index.d.ts +15 -0
- package/dist/types/index.js +10 -0
- package/dist/types/init.d.ts +56 -0
- package/dist/types/init.js +10 -0
- package/dist/types/tool-result.d.ts +75 -0
- package/dist/types/tool-result.js +40 -0
- package/dist/types/unit.d.ts +118 -0
- package/dist/types/unit.js +10 -0
- package/package.json +71 -0
- package/skills/claude/SKILL.md +375 -0
- package/skills/common/cli-reference.md +251 -0
- package/skills/cursor/SKILL.md +353 -0
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 커맨드 파일 섹션 교체기 — Layer 1 순수 함수
|
|
3
|
+
*
|
|
4
|
+
* 커맨드 파일의 특정 섹션만 교체하고 나머지를 보존한다.
|
|
5
|
+
* separator(구분선) + 동급 헤딩 기반으로 섹션 범위를 안전하게 결정한다.
|
|
6
|
+
*
|
|
7
|
+
* HTML 주석 마커(`<!-- vc:begin:{key} -->` / `<!-- vc:end:{key} -->`)가
|
|
8
|
+
* 활성화되면 마커 기반 경계 탐색을 우선 시도하고, 미발견 시 기존
|
|
9
|
+
* 헤더 기반 Fallback으로 처리한다 (점진적 마이그레이션 지원).
|
|
10
|
+
*
|
|
11
|
+
* RULE-007 준수: 전체 파일 덮어쓰기 금지, 대상 섹션만 교체.
|
|
12
|
+
*
|
|
13
|
+
* 형식 레퍼런스: vibe/commands.md
|
|
14
|
+
* PRD §8.3: 커맨드 파일 섹션 교체 규칙
|
|
15
|
+
*
|
|
16
|
+
* @module
|
|
17
|
+
*/
|
|
18
|
+
import type { ToolResult } from '../../types/index.js';
|
|
19
|
+
/**
|
|
20
|
+
* 섹션/필드 업데이트 결과
|
|
21
|
+
*
|
|
22
|
+
* 업데이트 성공 여부를 `updated` 필드로 판별.
|
|
23
|
+
* 섹션/필드 미발견 시 원본 반환 + `updated: false` (에러 아님).
|
|
24
|
+
*/
|
|
25
|
+
export interface UpdateResult {
|
|
26
|
+
/** 업데이트된 전체 콘텐츠 */
|
|
27
|
+
content: string;
|
|
28
|
+
/** 실제로 교체가 이루어졌는지 여부 */
|
|
29
|
+
updated: boolean;
|
|
30
|
+
}
|
|
31
|
+
/** 마커 옵션. sectionKey를 전달하면 마커 기반 탐색/삽입이 활성화된다. */
|
|
32
|
+
export interface MarkerOptions {
|
|
33
|
+
/** 섹션 키 (unitType.key 값, 예: "implement", "refactor") */
|
|
34
|
+
sectionKey: string;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* 커맨드 파일의 특정 섹션 본문을 교체한다
|
|
38
|
+
*
|
|
39
|
+
* **Fallback 체인** (markerOptions 제공 시):
|
|
40
|
+
* 1. 1차 시도: 마커 기반 경계 탐색 (`<!-- vc:begin:{key} -->` ~ `<!-- vc:end:{key} -->`)
|
|
41
|
+
* 2. 2차 시도: 기존 헤더 + separator 기반 텍스트 탐색 (마커 자동 삽입으로 점진적 마이그레이션)
|
|
42
|
+
* 3. 둘 다 실패: 원본 반환 + `updated: false`
|
|
43
|
+
*
|
|
44
|
+
* markerOptions 미제공 시: 기존 헤더 기반 탐색 (마커 없음)
|
|
45
|
+
*
|
|
46
|
+
* @param content - 전체 파일 콘텐츠
|
|
47
|
+
* @param sectionHeader - 대상 섹션 헤더 (예: "# 유닛 구현")
|
|
48
|
+
* @param newBody - 교체할 새 본문
|
|
49
|
+
* @param separator - 섹션 구분자 문자열
|
|
50
|
+
* @param markerOptions - 마커 옵션 (선택). 제공 시 마커 기반 탐색/삽입 활성화
|
|
51
|
+
* @returns 교체된 콘텐츠와 교체 여부
|
|
52
|
+
*/
|
|
53
|
+
export declare function updateSection(content: string, sectionHeader: string, newBody: string, separator: string, markerOptions?: MarkerOptions): ToolResult<UpdateResult>;
|
|
54
|
+
/**
|
|
55
|
+
* 커맨드 파일의 특정 섹션 내 필드 값만 교체한다
|
|
56
|
+
*
|
|
57
|
+
* 섹션 범위 내에서 fieldPattern에 매칭되는 첫 번째 라인을 찾고,
|
|
58
|
+
* 해당 라인의 값 부분(마지막 ": " 이후)을 교체 또는 추가한다.
|
|
59
|
+
*
|
|
60
|
+
* 마커가 존재하면 마커 범위 내에서 필드를 탐색한다.
|
|
61
|
+
*
|
|
62
|
+
* @param content - 전체 파일 콘텐츠
|
|
63
|
+
* @param sectionHeader - 대상 섹션 헤더
|
|
64
|
+
* @param fieldPattern - 필드를 식별하는 정규식
|
|
65
|
+
* @param newValue - 새 값
|
|
66
|
+
* @param separator - 섹션 구분자 문자열
|
|
67
|
+
* @param mode - "replace" 또는 "append"
|
|
68
|
+
* @param markerOptions - 마커 옵션 (선택)
|
|
69
|
+
* @returns 필드가 교체된 콘텐츠와 교체 여부
|
|
70
|
+
*/
|
|
71
|
+
export declare function updateField(content: string, sectionHeader: string, fieldPattern: RegExp, newValue: string, separator: string, mode?: 'replace' | 'append', markerOptions?: MarkerOptions): ToolResult<UpdateResult>;
|
|
72
|
+
//# sourceMappingURL=section-updater.d.ts.map
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 커맨드 파일 섹션 교체기 — Layer 1 순수 함수
|
|
3
|
+
*
|
|
4
|
+
* 커맨드 파일의 특정 섹션만 교체하고 나머지를 보존한다.
|
|
5
|
+
* separator(구분선) + 동급 헤딩 기반으로 섹션 범위를 안전하게 결정한다.
|
|
6
|
+
*
|
|
7
|
+
* HTML 주석 마커(`<!-- vc:begin:{key} -->` / `<!-- vc:end:{key} -->`)가
|
|
8
|
+
* 활성화되면 마커 기반 경계 탐색을 우선 시도하고, 미발견 시 기존
|
|
9
|
+
* 헤더 기반 Fallback으로 처리한다 (점진적 마이그레이션 지원).
|
|
10
|
+
*
|
|
11
|
+
* RULE-007 준수: 전체 파일 덮어쓰기 금지, 대상 섹션만 교체.
|
|
12
|
+
*
|
|
13
|
+
* 형식 레퍼런스: vibe/commands.md
|
|
14
|
+
* PRD §8.3: 커맨드 파일 섹션 교체 규칙
|
|
15
|
+
*
|
|
16
|
+
* @module
|
|
17
|
+
*/
|
|
18
|
+
import { ok } from '../../types/index.js';
|
|
19
|
+
import { normalizeLineEndings, getHeadingPrefix, isSameLevelHeading } from '../parsers/index.js';
|
|
20
|
+
import { findHeaderIndex, getBodyStartIndex, findBodyEndIndex, replaceFieldValue, isSeparatorLine, } from './updater-helpers.js';
|
|
21
|
+
import { findMarkerRange, wrapWithMarkers, createBeginMarker, createEndMarker, } from './marker-utils.js';
|
|
22
|
+
/**
|
|
23
|
+
* 커맨드 파일의 특정 섹션 본문을 교체한다
|
|
24
|
+
*
|
|
25
|
+
* **Fallback 체인** (markerOptions 제공 시):
|
|
26
|
+
* 1. 1차 시도: 마커 기반 경계 탐색 (`<!-- vc:begin:{key} -->` ~ `<!-- vc:end:{key} -->`)
|
|
27
|
+
* 2. 2차 시도: 기존 헤더 + separator 기반 텍스트 탐색 (마커 자동 삽입으로 점진적 마이그레이션)
|
|
28
|
+
* 3. 둘 다 실패: 원본 반환 + `updated: false`
|
|
29
|
+
*
|
|
30
|
+
* markerOptions 미제공 시: 기존 헤더 기반 탐색 (마커 없음)
|
|
31
|
+
*
|
|
32
|
+
* @param content - 전체 파일 콘텐츠
|
|
33
|
+
* @param sectionHeader - 대상 섹션 헤더 (예: "# 유닛 구현")
|
|
34
|
+
* @param newBody - 교체할 새 본문
|
|
35
|
+
* @param separator - 섹션 구분자 문자열
|
|
36
|
+
* @param markerOptions - 마커 옵션 (선택). 제공 시 마커 기반 탐색/삽입 활성화
|
|
37
|
+
* @returns 교체된 콘텐츠와 교체 여부
|
|
38
|
+
*/
|
|
39
|
+
export function updateSection(content, sectionHeader, newBody, separator, markerOptions) {
|
|
40
|
+
const normalized = normalizeLineEndings(content);
|
|
41
|
+
const lines = normalized.split('\n');
|
|
42
|
+
const newBodyLines = newBody.split('\n');
|
|
43
|
+
// 마커 옵션이 제공된 경우: Fallback 체인
|
|
44
|
+
if (markerOptions) {
|
|
45
|
+
const { sectionKey } = markerOptions;
|
|
46
|
+
// 1차: 마커 기반 탐색
|
|
47
|
+
const markerRange = findMarkerRange(lines, sectionKey);
|
|
48
|
+
if (markerRange) {
|
|
49
|
+
return replaceMarkerRange(lines, markerRange, sectionHeader, newBodyLines, separator, sectionKey);
|
|
50
|
+
}
|
|
51
|
+
// 2차: 헤더 기반 Fallback + 마커 자동 삽입 (점진적 마이그레이션)
|
|
52
|
+
return fallbackWithMarkerInjection(lines, content, sectionHeader, newBodyLines, separator, sectionKey);
|
|
53
|
+
}
|
|
54
|
+
// 마커 비활성: 기존 헤더 기반 탐색
|
|
55
|
+
return headerBasedUpdate(lines, content, sectionHeader, newBodyLines, separator);
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* 커맨드 파일의 특정 섹션 내 필드 값만 교체한다
|
|
59
|
+
*
|
|
60
|
+
* 섹션 범위 내에서 fieldPattern에 매칭되는 첫 번째 라인을 찾고,
|
|
61
|
+
* 해당 라인의 값 부분(마지막 ": " 이후)을 교체 또는 추가한다.
|
|
62
|
+
*
|
|
63
|
+
* 마커가 존재하면 마커 범위 내에서 필드를 탐색한다.
|
|
64
|
+
*
|
|
65
|
+
* @param content - 전체 파일 콘텐츠
|
|
66
|
+
* @param sectionHeader - 대상 섹션 헤더
|
|
67
|
+
* @param fieldPattern - 필드를 식별하는 정규식
|
|
68
|
+
* @param newValue - 새 값
|
|
69
|
+
* @param separator - 섹션 구분자 문자열
|
|
70
|
+
* @param mode - "replace" 또는 "append"
|
|
71
|
+
* @param markerOptions - 마커 옵션 (선택)
|
|
72
|
+
* @returns 필드가 교체된 콘텐츠와 교체 여부
|
|
73
|
+
*/
|
|
74
|
+
export function updateField(content, sectionHeader, fieldPattern, newValue, separator, mode = 'replace', markerOptions) {
|
|
75
|
+
const normalized = normalizeLineEndings(content);
|
|
76
|
+
const lines = normalized.split('\n');
|
|
77
|
+
// 마커 옵션이 있으면 마커 범위 내에서 탐색 시도
|
|
78
|
+
if (markerOptions) {
|
|
79
|
+
const markerRange = findMarkerRange(lines, markerOptions.sectionKey);
|
|
80
|
+
if (markerRange) {
|
|
81
|
+
return replaceFieldInRange(lines, content, fieldPattern, newValue, mode, markerRange.start, markerRange.end + 1);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
// 기존 헤더 기반 필드 탐색
|
|
85
|
+
const headerIdx = findHeaderIndex(lines, sectionHeader);
|
|
86
|
+
if (headerIdx === -1) {
|
|
87
|
+
return ok({ content, updated: false });
|
|
88
|
+
}
|
|
89
|
+
const headingPrefix = getHeadingPrefix(sectionHeader);
|
|
90
|
+
const bodyStartIdx = getBodyStartIndex(lines, headerIdx, separator);
|
|
91
|
+
const bodyEndIdx = findBodyEndIndex(lines, bodyStartIdx, separator, headingPrefix, isSameLevelHeading);
|
|
92
|
+
return replaceFieldInRange(lines, content, fieldPattern, newValue, mode, bodyStartIdx, bodyEndIdx);
|
|
93
|
+
}
|
|
94
|
+
// ── 내부 헬퍼 ──
|
|
95
|
+
/**
|
|
96
|
+
* 마커 범위를 새 콘텐츠로 교체한다 (마커 포함 전체 대체)
|
|
97
|
+
*/
|
|
98
|
+
function replaceMarkerRange(lines, markerRange, sectionHeader, newBodyLines, separator, sectionKey) {
|
|
99
|
+
const before = lines.slice(0, markerRange.start);
|
|
100
|
+
const after = lines.slice(markerRange.end + 1);
|
|
101
|
+
const innerLines = [sectionHeader.trim(), separator, ...newBodyLines, separator];
|
|
102
|
+
const markerWrapped = wrapWithMarkers(sectionKey, innerLines);
|
|
103
|
+
const result = [...before, ...markerWrapped, ...after].join('\n');
|
|
104
|
+
return ok({ content: result, updated: true });
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* 헤더 기반 Fallback으로 섹션을 찾고, 마커를 자동 삽입한다 (점진적 마이그레이션)
|
|
108
|
+
*/
|
|
109
|
+
function fallbackWithMarkerInjection(lines, originalContent, sectionHeader, newBodyLines, separator, sectionKey) {
|
|
110
|
+
const headerIdx = findHeaderIndex(lines, sectionHeader);
|
|
111
|
+
if (headerIdx === -1) {
|
|
112
|
+
return ok({ content: originalContent, updated: false });
|
|
113
|
+
}
|
|
114
|
+
const headingPrefix = getHeadingPrefix(sectionHeader);
|
|
115
|
+
const bodyStartIdx = getBodyStartIndex(lines, headerIdx, separator);
|
|
116
|
+
const bodyEndIdx = findBodyEndIndex(lines, bodyStartIdx, separator, headingPrefix, isSameLevelHeading);
|
|
117
|
+
const closingLine = bodyEndIdx < lines.length ? lines[bodyEndIdx] : undefined;
|
|
118
|
+
const closingIsSep = closingLine !== undefined && isSeparatorLine(closingLine, separator);
|
|
119
|
+
// 고아 마커 제거 (begin만 또는 end만 남은 경우)
|
|
120
|
+
const beginMarker = createBeginMarker(sectionKey);
|
|
121
|
+
const endMarker = createEndMarker(sectionKey);
|
|
122
|
+
const isOrphanedMarker = (line) => {
|
|
123
|
+
const trimmed = line.trim();
|
|
124
|
+
return trimmed === beginMarker || trimmed === endMarker;
|
|
125
|
+
};
|
|
126
|
+
const beforeSection = lines.slice(0, headerIdx).filter((l) => !isOrphanedMarker(l));
|
|
127
|
+
const afterSection = (closingIsSep ? lines.slice(bodyEndIdx + 1) : lines.slice(bodyEndIdx)).filter((l) => !isOrphanedMarker(l));
|
|
128
|
+
const innerLines = [
|
|
129
|
+
(lines[headerIdx] ?? sectionHeader).trim(),
|
|
130
|
+
separator,
|
|
131
|
+
...newBodyLines,
|
|
132
|
+
...(closingIsSep ? [separator] : []),
|
|
133
|
+
];
|
|
134
|
+
const markerWrapped = wrapWithMarkers(sectionKey, innerLines);
|
|
135
|
+
const result = [...beforeSection, ...markerWrapped, ...afterSection].join('\n');
|
|
136
|
+
return ok({ content: result, updated: true });
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* 기존 헤더 기반 섹션 교체 (마커 없음, 기존 동작 유지)
|
|
140
|
+
*/
|
|
141
|
+
function headerBasedUpdate(lines, originalContent, sectionHeader, newBodyLines, separator) {
|
|
142
|
+
const headerIdx = findHeaderIndex(lines, sectionHeader);
|
|
143
|
+
if (headerIdx === -1) {
|
|
144
|
+
return ok({ content: originalContent, updated: false });
|
|
145
|
+
}
|
|
146
|
+
const headingPrefix = getHeadingPrefix(sectionHeader);
|
|
147
|
+
const bodyStartIdx = getBodyStartIndex(lines, headerIdx, separator);
|
|
148
|
+
const bodyEndIdx = findBodyEndIndex(lines, bodyStartIdx, separator, headingPrefix, isSameLevelHeading);
|
|
149
|
+
const before = lines.slice(0, bodyStartIdx);
|
|
150
|
+
const after = lines.slice(bodyEndIdx);
|
|
151
|
+
const result = [...before, ...newBodyLines, ...after].join('\n');
|
|
152
|
+
return ok({ content: result, updated: true });
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* 지정된 범위 내에서 필드를 찾아 값을 교체한다
|
|
156
|
+
*/
|
|
157
|
+
function replaceFieldInRange(lines, originalContent, fieldPattern, newValue, mode, rangeStart, rangeEnd) {
|
|
158
|
+
let fieldFound = false;
|
|
159
|
+
for (let i = rangeStart; i < rangeEnd; i++) {
|
|
160
|
+
const line = lines[i];
|
|
161
|
+
if (line === undefined)
|
|
162
|
+
break;
|
|
163
|
+
fieldPattern.lastIndex = 0;
|
|
164
|
+
if (fieldPattern.test(line)) {
|
|
165
|
+
lines[i] = replaceFieldValue(line, newValue, mode);
|
|
166
|
+
fieldFound = true;
|
|
167
|
+
break;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
if (!fieldFound) {
|
|
171
|
+
return ok({ content: originalContent, updated: false });
|
|
172
|
+
}
|
|
173
|
+
return ok({ content: lines.join('\n'), updated: true });
|
|
174
|
+
}
|
|
175
|
+
//# sourceMappingURL=section-updater.js.map
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 템플릿 엔진 — Layer 1 순수 함수
|
|
3
|
+
*
|
|
4
|
+
* UnitMeta에서 PRD 부록 B 전체 템플릿 변수(8개)를 생성하고,
|
|
5
|
+
* headerTemplate에 변수를 보간하는 기능을 제공한다.
|
|
6
|
+
*
|
|
7
|
+
* 기존 interpolate.ts의 ID 기반 변수(unitId, shortId, bareId, slug)에
|
|
8
|
+
* 계획서 메타데이터 변수(title, titleOnly, planPath, phase)를 추가.
|
|
9
|
+
*
|
|
10
|
+
* @module
|
|
11
|
+
*/
|
|
12
|
+
import type { UnitMeta } from '../../types/index.js';
|
|
13
|
+
/**
|
|
14
|
+
* 유닛 제목에서 ID 부분을 제거하고 순수 제목만 추출한다
|
|
15
|
+
*
|
|
16
|
+
* 일반적인 제목 형식: "U-010[Mvp]: 템플릿 렌더러 (renderSection)"
|
|
17
|
+
* → titleOnly: "템플릿 렌더러 (renderSection)"
|
|
18
|
+
*
|
|
19
|
+
* 리팩토링 서브 유닛 형식: "[ID: RU-003-Q5] VERSION 상수 제거"
|
|
20
|
+
* → titleOnly: "VERSION 상수 제거"
|
|
21
|
+
*
|
|
22
|
+
* 콜론이 없으면 전체 제목을 그대로 반환 (Graceful Degradation).
|
|
23
|
+
*
|
|
24
|
+
* @param title - 유닛 전체 제목 (ID 포함)
|
|
25
|
+
* @returns ID를 제거한 순수 제목
|
|
26
|
+
*/
|
|
27
|
+
export declare function extractTitleOnly(title: string): string;
|
|
28
|
+
/**
|
|
29
|
+
* UnitMeta에서 PRD 부록 B 전체 템플릿 변수 맵을 생성한다
|
|
30
|
+
*
|
|
31
|
+
* | 변수 | 설명 | 예시 |
|
|
32
|
+
* |------|------|------|
|
|
33
|
+
* | unitId | 원본 유닛 ID | U-118[Mmp] |
|
|
34
|
+
* | shortId | phase 제거 | U-118 |
|
|
35
|
+
* | bareId | 숫자만 | 118 |
|
|
36
|
+
* | slug | kebab-case | u-118-mmp |
|
|
37
|
+
* | title | 전체 제목 | U-118[Mmp]: 이미지 링크 삽입 |
|
|
38
|
+
* | titleOnly | 순수 제목 | 이미지 링크 삽입 |
|
|
39
|
+
* | planPath | 계획서 경로 | vibe/unit-plans/U-118[Mmp].md |
|
|
40
|
+
* | phase | phase 문자열 | Mmp |
|
|
41
|
+
*
|
|
42
|
+
* @param unit - 유닛 메타데이터
|
|
43
|
+
* @returns 변수명 → 값 맵 (8개 항목)
|
|
44
|
+
*/
|
|
45
|
+
export declare function buildSectionVars(unit: UnitMeta): Record<string, string>;
|
|
46
|
+
/**
|
|
47
|
+
* headerTemplate에 UnitMeta 변수를 보간한다
|
|
48
|
+
*
|
|
49
|
+
* eval() 사용 금지 (RULE-006 준수).
|
|
50
|
+
* 미등록 변수는 원본 플레이스홀더를 유지 (Graceful Degradation).
|
|
51
|
+
*
|
|
52
|
+
* @param template - {{변수}} 플레이스홀더가 포함된 템플릿 문자열
|
|
53
|
+
* @param unit - 유닛 메타데이터
|
|
54
|
+
* @returns 변수가 치환된 문자열
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* ```typescript
|
|
58
|
+
* const unit: UnitMeta = {
|
|
59
|
+
* unitId: 'U-010[Mvp]',
|
|
60
|
+
* title: 'U-010[Mvp]: 템플릿 렌더러',
|
|
61
|
+
* planPath: 'vibe/unit-plans/U-010[Mvp].md',
|
|
62
|
+
* // ...
|
|
63
|
+
* };
|
|
64
|
+
* interpolateTemplate('### {{title}}\n- 계획서: @{{planPath}}', unit);
|
|
65
|
+
* // → '### U-010[Mvp]: 템플릿 렌더러\n- 계획서: @vibe/unit-plans/U-010[Mvp].md'
|
|
66
|
+
* ```
|
|
67
|
+
*/
|
|
68
|
+
export declare function interpolateTemplate(template: string, unit: UnitMeta): string;
|
|
69
|
+
//# sourceMappingURL=template-engine.d.ts.map
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 템플릿 엔진 — Layer 1 순수 함수
|
|
3
|
+
*
|
|
4
|
+
* UnitMeta에서 PRD 부록 B 전체 템플릿 변수(8개)를 생성하고,
|
|
5
|
+
* headerTemplate에 변수를 보간하는 기능을 제공한다.
|
|
6
|
+
*
|
|
7
|
+
* 기존 interpolate.ts의 ID 기반 변수(unitId, shortId, bareId, slug)에
|
|
8
|
+
* 계획서 메타데이터 변수(title, titleOnly, planPath, phase)를 추가.
|
|
9
|
+
*
|
|
10
|
+
* @module
|
|
11
|
+
*/
|
|
12
|
+
import { buildTemplateVars, interpolatePattern } from './interpolate.js';
|
|
13
|
+
/**
|
|
14
|
+
* 유닛 제목에서 ID 부분을 제거하고 순수 제목만 추출한다
|
|
15
|
+
*
|
|
16
|
+
* 일반적인 제목 형식: "U-010[Mvp]: 템플릿 렌더러 (renderSection)"
|
|
17
|
+
* → titleOnly: "템플릿 렌더러 (renderSection)"
|
|
18
|
+
*
|
|
19
|
+
* 리팩토링 서브 유닛 형식: "[ID: RU-003-Q5] VERSION 상수 제거"
|
|
20
|
+
* → titleOnly: "VERSION 상수 제거"
|
|
21
|
+
*
|
|
22
|
+
* 콜론이 없으면 전체 제목을 그대로 반환 (Graceful Degradation).
|
|
23
|
+
*
|
|
24
|
+
* @param title - 유닛 전체 제목 (ID 포함)
|
|
25
|
+
* @returns ID를 제거한 순수 제목
|
|
26
|
+
*/
|
|
27
|
+
export function extractTitleOnly(title) {
|
|
28
|
+
// 1. [ID: ...] 패턴으로 시작하면 해당 부분을 통째로 제거
|
|
29
|
+
const idPrefixMatch = title.match(/^\[ID:\s*[^\]]+\]\s*:?\s*/i);
|
|
30
|
+
if (idPrefixMatch) {
|
|
31
|
+
return title.substring(idPrefixMatch[0].length).trim();
|
|
32
|
+
}
|
|
33
|
+
// 2. 일반적인 "ID: 제목" 패턴 처리
|
|
34
|
+
const colonIndex = title.indexOf(': ');
|
|
35
|
+
if (colonIndex === -1)
|
|
36
|
+
return title;
|
|
37
|
+
return title.substring(colonIndex + 2).trim();
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* UnitMeta에서 PRD 부록 B 전체 템플릿 변수 맵을 생성한다
|
|
41
|
+
*
|
|
42
|
+
* | 변수 | 설명 | 예시 |
|
|
43
|
+
* |------|------|------|
|
|
44
|
+
* | unitId | 원본 유닛 ID | U-118[Mmp] |
|
|
45
|
+
* | shortId | phase 제거 | U-118 |
|
|
46
|
+
* | bareId | 숫자만 | 118 |
|
|
47
|
+
* | slug | kebab-case | u-118-mmp |
|
|
48
|
+
* | title | 전체 제목 | U-118[Mmp]: 이미지 링크 삽입 |
|
|
49
|
+
* | titleOnly | 순수 제목 | 이미지 링크 삽입 |
|
|
50
|
+
* | planPath | 계획서 경로 | vibe/unit-plans/U-118[Mmp].md |
|
|
51
|
+
* | phase | phase 문자열 | Mmp |
|
|
52
|
+
*
|
|
53
|
+
* @param unit - 유닛 메타데이터
|
|
54
|
+
* @returns 변수명 → 값 맵 (8개 항목)
|
|
55
|
+
*/
|
|
56
|
+
export function buildSectionVars(unit) {
|
|
57
|
+
const baseVars = buildTemplateVars(unit.unitId);
|
|
58
|
+
return {
|
|
59
|
+
...baseVars,
|
|
60
|
+
title: unit.title,
|
|
61
|
+
titleOnly: extractTitleOnly(unit.title),
|
|
62
|
+
planPath: unit.planPath,
|
|
63
|
+
phase: unit.phase ?? '',
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* headerTemplate에 UnitMeta 변수를 보간한다
|
|
68
|
+
*
|
|
69
|
+
* eval() 사용 금지 (RULE-006 준수).
|
|
70
|
+
* 미등록 변수는 원본 플레이스홀더를 유지 (Graceful Degradation).
|
|
71
|
+
*
|
|
72
|
+
* @param template - {{변수}} 플레이스홀더가 포함된 템플릿 문자열
|
|
73
|
+
* @param unit - 유닛 메타데이터
|
|
74
|
+
* @returns 변수가 치환된 문자열
|
|
75
|
+
*
|
|
76
|
+
* @example
|
|
77
|
+
* ```typescript
|
|
78
|
+
* const unit: UnitMeta = {
|
|
79
|
+
* unitId: 'U-010[Mvp]',
|
|
80
|
+
* title: 'U-010[Mvp]: 템플릿 렌더러',
|
|
81
|
+
* planPath: 'vibe/unit-plans/U-010[Mvp].md',
|
|
82
|
+
* // ...
|
|
83
|
+
* };
|
|
84
|
+
* interpolateTemplate('### {{title}}\n- 계획서: @{{planPath}}', unit);
|
|
85
|
+
* // → '### U-010[Mvp]: 템플릿 렌더러\n- 계획서: @vibe/unit-plans/U-010[Mvp].md'
|
|
86
|
+
* ```
|
|
87
|
+
*/
|
|
88
|
+
export function interpolateTemplate(template, unit) {
|
|
89
|
+
const vars = buildSectionVars(unit);
|
|
90
|
+
return interpolatePattern(template, vars);
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=template-engine.js.map
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 섹션 업데이트용 내부 헬퍼 함수 — Layer 1 순수 함수
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* 라인이 separator인지 확인한다
|
|
8
|
+
*
|
|
9
|
+
* 앞뒤 공백 및 Windows \r을 무시하고 비교.
|
|
10
|
+
*/
|
|
11
|
+
export declare function isSeparatorLine(line: string, separator: string): boolean;
|
|
12
|
+
/**
|
|
13
|
+
* 섹션 헤더 라인의 인덱스를 찾는다
|
|
14
|
+
*
|
|
15
|
+
* @returns 헤더 인덱스 또는 -1 (미발견)
|
|
16
|
+
*/
|
|
17
|
+
export declare function findHeaderIndex(lines: readonly string[], sectionHeader: string): number;
|
|
18
|
+
/**
|
|
19
|
+
* 섹션 본문의 시작 인덱스를 결정한다
|
|
20
|
+
*
|
|
21
|
+
* 헤더 다음 줄이 separator이면 그 다음 줄(본문 첫 줄),
|
|
22
|
+
* separator가 아니면 헤더 바로 다음 줄이 본문 시작.
|
|
23
|
+
*/
|
|
24
|
+
export declare function getBodyStartIndex(lines: readonly string[], headerIdx: number, separator: string): number;
|
|
25
|
+
/**
|
|
26
|
+
* 섹션 본문의 끝 인덱스를 찾는다 (exclusive)
|
|
27
|
+
*
|
|
28
|
+
* 탐색 순서:
|
|
29
|
+
* 1. separator 라인 → 섹션 경계
|
|
30
|
+
* 2. 동급 헤딩 → 다른 섹션 시작
|
|
31
|
+
* 3. EOF → 마지막 섹션
|
|
32
|
+
*
|
|
33
|
+
* @param isSameLevelHeading - 외부에서 주입받는 헤딩 비교 함수
|
|
34
|
+
*/
|
|
35
|
+
export declare function findBodyEndIndex(lines: readonly string[], bodyStartIdx: number, separator: string, headingPrefix: string | null, isSameLevelHeading: (line: string, prefix: string | null) => boolean): number;
|
|
36
|
+
/**
|
|
37
|
+
* 필드 라인의 값 부분(": " 이후)을 교체 또는 추가한다
|
|
38
|
+
*
|
|
39
|
+
* @param line - 원본 필드 라인
|
|
40
|
+
* @param newValue - 새 값
|
|
41
|
+
* @param mode - "replace": 값 전체 교체, "append": 기존 값에 추가
|
|
42
|
+
* @returns 값이 교체된 라인
|
|
43
|
+
*/
|
|
44
|
+
export declare function replaceFieldValue(line: string, newValue: string, mode: 'replace' | 'append'): string;
|
|
45
|
+
//# sourceMappingURL=updater-helpers.d.ts.map
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 섹션 업데이트용 내부 헬퍼 함수 — Layer 1 순수 함수
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
import { stripCR } from '../parsers/md-utils.js';
|
|
7
|
+
/**
|
|
8
|
+
* 라인이 separator인지 확인한다
|
|
9
|
+
*
|
|
10
|
+
* 앞뒤 공백 및 Windows \r을 무시하고 비교.
|
|
11
|
+
*/
|
|
12
|
+
export function isSeparatorLine(line, separator) {
|
|
13
|
+
return stripCR(line).trim() === separator.trim();
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* 섹션 헤더 라인의 인덱스를 찾는다
|
|
17
|
+
*
|
|
18
|
+
* @returns 헤더 인덱스 또는 -1 (미발견)
|
|
19
|
+
*/
|
|
20
|
+
export function findHeaderIndex(lines, sectionHeader) {
|
|
21
|
+
const needle = sectionHeader.trim();
|
|
22
|
+
return lines.findIndex((l) => stripCR(l).trim() === needle);
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* 섹션 본문의 시작 인덱스를 결정한다
|
|
26
|
+
*
|
|
27
|
+
* 헤더 다음 줄이 separator이면 그 다음 줄(본문 첫 줄),
|
|
28
|
+
* separator가 아니면 헤더 바로 다음 줄이 본문 시작.
|
|
29
|
+
*/
|
|
30
|
+
export function getBodyStartIndex(lines, headerIdx, separator) {
|
|
31
|
+
const nextIdx = headerIdx + 1;
|
|
32
|
+
const nextLine = lines[nextIdx];
|
|
33
|
+
if (nextLine !== undefined && isSeparatorLine(nextLine, separator)) {
|
|
34
|
+
return nextIdx + 1;
|
|
35
|
+
}
|
|
36
|
+
return nextIdx;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* 섹션 본문의 끝 인덱스를 찾는다 (exclusive)
|
|
40
|
+
*
|
|
41
|
+
* 탐색 순서:
|
|
42
|
+
* 1. separator 라인 → 섹션 경계
|
|
43
|
+
* 2. 동급 헤딩 → 다른 섹션 시작
|
|
44
|
+
* 3. EOF → 마지막 섹션
|
|
45
|
+
*
|
|
46
|
+
* @param isSameLevelHeading - 외부에서 주입받는 헤딩 비교 함수
|
|
47
|
+
*/
|
|
48
|
+
export function findBodyEndIndex(lines, bodyStartIdx, separator, headingPrefix, isSameLevelHeading) {
|
|
49
|
+
for (let i = bodyStartIdx; i < lines.length; i++) {
|
|
50
|
+
const line = lines[i];
|
|
51
|
+
if (line === undefined)
|
|
52
|
+
break;
|
|
53
|
+
if (isSeparatorLine(line, separator))
|
|
54
|
+
return i;
|
|
55
|
+
if (isSameLevelHeading(line, headingPrefix))
|
|
56
|
+
return i;
|
|
57
|
+
}
|
|
58
|
+
return lines.length;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* 필드 라인의 값 부분(": " 이후)을 교체 또는 추가한다
|
|
62
|
+
*
|
|
63
|
+
* @param line - 원본 필드 라인
|
|
64
|
+
* @param newValue - 새 값
|
|
65
|
+
* @param mode - "replace": 값 전체 교체, "append": 기존 값에 추가
|
|
66
|
+
* @returns 값이 교체된 라인
|
|
67
|
+
*/
|
|
68
|
+
export function replaceFieldValue(line, newValue, mode) {
|
|
69
|
+
const colonIdx = line.lastIndexOf(': ');
|
|
70
|
+
if (colonIdx === -1)
|
|
71
|
+
return line;
|
|
72
|
+
const prefix = line.substring(0, colonIdx + 2);
|
|
73
|
+
const currentValue = stripCR(line.substring(colonIdx + 2)).trim();
|
|
74
|
+
if (mode === 'replace') {
|
|
75
|
+
return prefix + newValue;
|
|
76
|
+
}
|
|
77
|
+
// append 모드: 현재 값이 빈 마커('-')이거나 비어있으면 교체, 아니면 콤마 구분 추가
|
|
78
|
+
if (currentValue === '-' || currentValue === '') {
|
|
79
|
+
return prefix + newValue;
|
|
80
|
+
}
|
|
81
|
+
return prefix + currentValue + ', ' + newValue;
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=updater-helpers.js.map
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 커밋 교차 검증 필터 — Layer 1 순수 함수
|
|
3
|
+
*
|
|
4
|
+
* `git diff-tree`로 수집된 변경 파일 목록을 기반으로,
|
|
5
|
+
* excludePaths/requirePaths glob 패턴에 따라 커밋을 필터링한다.
|
|
6
|
+
*
|
|
7
|
+
* **순수 함수**: child_process, fs 등 I/O 모듈을 사용하지 않음.
|
|
8
|
+
* 변경 파일 수집은 Adapter(Layer 3)의 책임이며,
|
|
9
|
+
* 이 함수는 이미 수집된 목록을 받아 필터링만 담당한다.
|
|
10
|
+
*
|
|
11
|
+
* **Q2 결정 (Option C — 독립 적용)**:
|
|
12
|
+
* excludePaths와 requirePaths를 독립 필터로 순차 적용.
|
|
13
|
+
* - excludePaths 필터: 변경 파일이 모두 exclude 패턴에 매칭되면 제거 (문서 전용 커밋)
|
|
14
|
+
* - requirePaths 필터: 변경 파일 중 require 패턴에 하나도 매칭 안 되면 제거
|
|
15
|
+
* - 두 필터가 모두 빈 배열이면 기존 동작 유지
|
|
16
|
+
*
|
|
17
|
+
* @module
|
|
18
|
+
*/
|
|
19
|
+
/**
|
|
20
|
+
* 변경 파일 목록을 포함한 커밋 정보
|
|
21
|
+
*/
|
|
22
|
+
export interface CommitWithFiles {
|
|
23
|
+
/** 커밋 SHA */
|
|
24
|
+
sha: string;
|
|
25
|
+
/** 변경된 파일 경로 목록 (프로젝트 루트 기준 상대 경로) */
|
|
26
|
+
changedFiles: string[];
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* 필터 옵션
|
|
30
|
+
*/
|
|
31
|
+
export interface CommitFilterOptions {
|
|
32
|
+
/**
|
|
33
|
+
* 제외할 경로 glob 패턴 목록.
|
|
34
|
+
* 변경 파일이 **모두** 이 패턴에 매칭되는 커밋은 필터링됨.
|
|
35
|
+
*/
|
|
36
|
+
excludePaths?: string[];
|
|
37
|
+
/**
|
|
38
|
+
* 필수 포함 경로 glob 패턴 목록.
|
|
39
|
+
* 변경 파일 중 **하나라도** 이 패턴에 매칭되어야 통과.
|
|
40
|
+
*/
|
|
41
|
+
requirePaths?: string[];
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* 변경 파일 목록을 기반으로 커밋을 필터링한다
|
|
45
|
+
*
|
|
46
|
+
* excludePaths와 requirePaths를 독립 필터로 순차 적용 (Option C).
|
|
47
|
+
* 두 필터가 모두 빈 배열이면 모든 커밋 통과 (Graceful Degradation).
|
|
48
|
+
*
|
|
49
|
+
* @param commits - 변경 파일 목록이 포함된 커밋 배열
|
|
50
|
+
* @param options - 필터 옵션 (excludePaths, requirePaths)
|
|
51
|
+
* @returns 필터를 통과한 커밋 배열
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* ```typescript
|
|
55
|
+
* const commits = [
|
|
56
|
+
* { sha: 'abc1234', changedFiles: ['src/core/parser.ts', 'vibe/unit-plans/U-001.md'] },
|
|
57
|
+
* { sha: 'def5678', changedFiles: ['vibe/unit-plans/U-001.md'] },
|
|
58
|
+
* ];
|
|
59
|
+
* const filtered = filterCommitsByChangedFiles(commits, {
|
|
60
|
+
* excludePaths: ['vibe/**'],
|
|
61
|
+
* });
|
|
62
|
+
* // filtered → [{ sha: 'abc1234', changedFiles: [...] }]
|
|
63
|
+
* // def5678 제거: 변경 파일이 모두 vibe/** 패턴에 매칭됨
|
|
64
|
+
* ```
|
|
65
|
+
*/
|
|
66
|
+
export declare function filterCommitsByChangedFiles(commits: CommitWithFiles[], options?: CommitFilterOptions): CommitWithFiles[];
|
|
67
|
+
/**
|
|
68
|
+
* 파일 경로가 glob 패턴에 매칭되는지 검사한다
|
|
69
|
+
*
|
|
70
|
+
* 지원하는 와일드카드:
|
|
71
|
+
* - `**` — 모든 경로 세그먼트 매칭 (슬래시 포함)
|
|
72
|
+
* - `*` — 단일 경로 세그먼트 매칭 (슬래시 미포함)
|
|
73
|
+
*
|
|
74
|
+
* 예시:
|
|
75
|
+
* - `src/**` → `src/core/foo.ts` ✅, `docs/foo.ts` ❌
|
|
76
|
+
* - `**\/*.md` → `vibe/unit-plans/U-001.md` ✅, `src/core/foo.ts` ❌
|
|
77
|
+
* - `src/*.ts` → `src/foo.ts` ✅, `src/core/foo.ts` ❌
|
|
78
|
+
*
|
|
79
|
+
* @param filePath - 검사할 파일 경로 (프로젝트 루트 기준 상대 경로)
|
|
80
|
+
* @param pattern - glob 패턴
|
|
81
|
+
* @returns 매칭 여부
|
|
82
|
+
*/
|
|
83
|
+
export declare function matchesGlobPattern(filePath: string, pattern: string): boolean;
|
|
84
|
+
//# sourceMappingURL=commit-filter.d.ts.map
|