@su-record/vibe 3.2.18 → 3.2.20
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/CLAUDE.md +1 -0
- package/dist/cli/commands/remove.d.ts.map +1 -1
- package/dist/cli/commands/remove.js +15 -6
- package/dist/cli/commands/remove.js.map +1 -1
- package/dist/cli/setup/ProjectSetup.d.ts.map +1 -1
- package/dist/cli/setup/ProjectSetup.js +13 -1
- package/dist/cli/setup/ProjectSetup.js.map +1 -1
- package/dist/tools/dispatch/costGate.d.ts +59 -0
- package/dist/tools/dispatch/costGate.d.ts.map +1 -0
- package/dist/tools/dispatch/costGate.js +85 -0
- package/dist/tools/dispatch/costGate.js.map +1 -0
- package/dist/tools/dispatch/deterministicSignals.d.ts +61 -0
- package/dist/tools/dispatch/deterministicSignals.d.ts.map +1 -0
- package/dist/tools/dispatch/deterministicSignals.js +136 -0
- package/dist/tools/dispatch/deterministicSignals.js.map +1 -0
- package/dist/tools/dispatch/index.d.ts +5 -0
- package/dist/tools/dispatch/index.d.ts.map +1 -0
- package/dist/tools/dispatch/index.js +3 -0
- package/dist/tools/dispatch/index.js.map +1 -0
- package/dist/tools/dispatch/vibePaths.d.ts +7 -0
- package/dist/tools/dispatch/vibePaths.d.ts.map +1 -0
- package/dist/tools/dispatch/vibePaths.js +35 -0
- package/dist/tools/dispatch/vibePaths.js.map +1 -0
- package/dist/tools/index.d.ts +5 -0
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +4 -0
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/spec/index.d.ts +2 -0
- package/dist/tools/spec/index.d.ts.map +1 -1
- package/dist/tools/spec/index.js +2 -0
- package/dist/tools/spec/index.js.map +1 -1
- package/dist/tools/spec/validateSpecDocument.d.ts +30 -0
- package/dist/tools/spec/validateSpecDocument.d.ts.map +1 -0
- package/dist/tools/spec/validateSpecDocument.js +201 -0
- package/dist/tools/spec/validateSpecDocument.js.map +1 -0
- package/hooks/scripts/code-check.js +90 -16
- package/hooks/scripts/lib/anchor.js +15 -4
- package/hooks/scripts/lib/inbox.js +10 -2
- package/package.json +1 -1
- package/skills/vibe/SKILL.md +18 -5
- package/skills/vibe.image/SKILL.md +8 -0
- package/skills/vibe.review/SKILL.md +8 -0
- package/skills/vibe.spec/SKILL.md +21 -0
- package/vibe/rules/loop-contract.md +31 -0
- package/dist/infra/lib/DeepInit.d.ts +0 -60
- package/dist/infra/lib/DeepInit.d.ts.map +0 -1
- package/dist/infra/lib/DeepInit.js +0 -245
- package/dist/infra/lib/DeepInit.js.map +0 -1
- package/dist/infra/lib/FrameworkDetector.d.ts +0 -56
- package/dist/infra/lib/FrameworkDetector.d.ts.map +0 -1
- package/dist/infra/lib/FrameworkDetector.js +0 -287
- package/dist/infra/lib/FrameworkDetector.js.map +0 -1
- package/dist/infra/lib/ModelRouter.d.ts +0 -48
- package/dist/infra/lib/ModelRouter.d.ts.map +0 -1
- package/dist/infra/lib/ModelRouter.js +0 -216
- package/dist/infra/lib/ModelRouter.js.map +0 -1
- package/dist/infra/lib/OrchestrateWorkflow.d.ts +0 -88
- package/dist/infra/lib/OrchestrateWorkflow.d.ts.map +0 -1
- package/dist/infra/lib/OrchestrateWorkflow.js +0 -259
- package/dist/infra/lib/OrchestrateWorkflow.js.map +0 -1
- package/dist/infra/lib/ReviewRace.d.ts +0 -86
- package/dist/infra/lib/ReviewRace.d.ts.map +0 -1
- package/dist/infra/lib/ReviewRace.js +0 -454
- package/dist/infra/lib/ReviewRace.js.map +0 -1
- package/dist/infra/lib/RuleBuildSystem.d.ts +0 -157
- package/dist/infra/lib/RuleBuildSystem.d.ts.map +0 -1
- package/dist/infra/lib/RuleBuildSystem.js +0 -550
- package/dist/infra/lib/RuleBuildSystem.js.map +0 -1
- package/dist/infra/lib/SkillQualityGate.d.ts +0 -42
- package/dist/infra/lib/SkillQualityGate.d.ts.map +0 -1
- package/dist/infra/lib/SkillQualityGate.js +0 -220
- package/dist/infra/lib/SkillQualityGate.js.map +0 -1
- package/dist/infra/lib/SkillRepository.d.ts +0 -134
- package/dist/infra/lib/SkillRepository.d.ts.map +0 -1
- package/dist/infra/lib/SkillRepository.js +0 -500
- package/dist/infra/lib/SkillRepository.js.map +0 -1
- package/dist/infra/lib/UltraQA.d.ts +0 -89
- package/dist/infra/lib/UltraQA.d.ts.map +0 -1
- package/dist/infra/lib/UltraQA.js +0 -301
- package/dist/infra/lib/UltraQA.js.map +0 -1
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/** 읽기용 루트 — 존재하는 레거시 경로를 우선 반환, 없으면 `.vibe/` */
|
|
2
|
+
export declare function projectVibeRoot(projectDir: string): string;
|
|
3
|
+
/** 읽기용 경로 — 레거시 인식 */
|
|
4
|
+
export declare function projectVibePath(projectDir: string, ...sub: string[]): string;
|
|
5
|
+
/** 쓰기용 경로 — 항상 신규 레이아웃(`.vibe/`) */
|
|
6
|
+
export declare function projectVibePathPreferred(projectDir: string, ...sub: string[]): string;
|
|
7
|
+
//# sourceMappingURL=vibePaths.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vibePaths.d.ts","sourceRoot":"","sources":["../../../src/tools/dispatch/vibePaths.ts"],"names":[],"mappings":"AAcA,gDAAgD;AAChD,wBAAgB,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAQ1D;AAED,sBAAsB;AACtB,wBAAgB,eAAe,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,GAAG,EAAE,MAAM,EAAE,GAAG,MAAM,CAE5E;AAED,oCAAoC;AACpC,wBAAgB,wBAAwB,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,GAAG,EAAE,MAAM,EAAE,GAAG,MAAM,CAErF"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* vibe 상태 경로 소유자 (TS 측).
|
|
3
|
+
*
|
|
4
|
+
* 훅 측에는 `hooks/scripts/utils.js` 의 `projectVibeRoot`/`projectVibePath` 가 있는데,
|
|
5
|
+
* TS 도구들이 그것을 쓸 수 없어 `.vibe/` 를 각자 하드코딩했다. 그 결과 레거시
|
|
6
|
+
* 프로젝트(`.claude/vibe/`)에서 읽는 쪽만 조용히 빗나갔다 — 실제로 ANCHOR 가
|
|
7
|
+
* `.last-feature` 를 못 찾아 feature·spec·scope 를 전부 missing 으로 보고했다.
|
|
8
|
+
*
|
|
9
|
+
* 두 런타임이 **같은 해석 규칙**을 갖도록 여기에 미러링한다.
|
|
10
|
+
* 규칙: 읽기는 `.vibe/` → `.claude/vibe/` 순으로 존재하는 쪽, 쓰기는 항상 `.vibe/`.
|
|
11
|
+
*/
|
|
12
|
+
import fs from 'fs';
|
|
13
|
+
import path from 'path';
|
|
14
|
+
/** 읽기용 루트 — 존재하는 레거시 경로를 우선 반환, 없으면 `.vibe/` */
|
|
15
|
+
export function projectVibeRoot(projectDir) {
|
|
16
|
+
try {
|
|
17
|
+
const modern = path.join(projectDir, '.vibe');
|
|
18
|
+
if (fs.existsSync(modern))
|
|
19
|
+
return modern;
|
|
20
|
+
const legacy = path.join(projectDir, '.claude', 'vibe');
|
|
21
|
+
if (fs.existsSync(legacy))
|
|
22
|
+
return legacy;
|
|
23
|
+
}
|
|
24
|
+
catch { /* 접근 불가 → 신규 레이아웃으로 취급 */ }
|
|
25
|
+
return path.join(projectDir, '.vibe');
|
|
26
|
+
}
|
|
27
|
+
/** 읽기용 경로 — 레거시 인식 */
|
|
28
|
+
export function projectVibePath(projectDir, ...sub) {
|
|
29
|
+
return path.join(projectVibeRoot(projectDir), ...sub);
|
|
30
|
+
}
|
|
31
|
+
/** 쓰기용 경로 — 항상 신규 레이아웃(`.vibe/`) */
|
|
32
|
+
export function projectVibePathPreferred(projectDir, ...sub) {
|
|
33
|
+
return path.join(projectDir, '.vibe', ...sub);
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=vibePaths.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vibePaths.js","sourceRoot":"","sources":["../../../src/tools/dispatch/vibePaths.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB,gDAAgD;AAChD,MAAM,UAAU,eAAe,CAAC,UAAkB;IAChD,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;QAC9C,IAAI,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC;YAAE,OAAO,MAAM,CAAC;QACzC,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC;QACxD,IAAI,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC;YAAE,OAAO,MAAM,CAAC;IAC3C,CAAC;IAAC,MAAM,CAAC,CAAC,0BAA0B,CAAC,CAAC;IACtC,OAAO,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;AACxC,CAAC;AAED,sBAAsB;AACtB,MAAM,UAAU,eAAe,CAAC,UAAkB,EAAE,GAAG,GAAa;IAClE,OAAO,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC,UAAU,CAAC,EAAE,GAAG,GAAG,CAAC,CAAC;AACxD,CAAC;AAED,oCAAoC;AACpC,MAAM,UAAU,wBAAwB,CAAC,UAAkB,EAAE,GAAG,GAAa;IAC3E,OAAO,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,OAAO,EAAE,GAAG,GAAG,CAAC,CAAC;AAChD,CAAC"}
|
package/dist/tools/index.d.ts
CHANGED
|
@@ -66,5 +66,10 @@ export type { VibeSpan, SpanType, SpanStatus, } from '../infra/lib/telemetry/Vib
|
|
|
66
66
|
export { ComponentRegistry } from '../infra/lib/ComponentRegistry.js';
|
|
67
67
|
export type { ComponentSpec, ComponentEntry, } from '../infra/lib/ComponentRegistry.js';
|
|
68
68
|
export { validateLoopDefinition } from './loop/index.js';
|
|
69
|
+
export { validateSpecDocument, formatSpecValidation, featureSlugFromPath, } from './spec/index.js';
|
|
70
|
+
export { collectDispatchSignals, detectResumeState, detectStakesSignals, classifyUrl, classifyAttachment, } from './dispatch/index.js';
|
|
71
|
+
export type { DispatchSignals, ResumeState, StakesSignals, UrlKind, AttachmentKind, } from './dispatch/index.js';
|
|
72
|
+
export { evaluateCostGate, formatCostGate } from './dispatch/index.js';
|
|
73
|
+
export type { CostOperation, CostGateConfig, CostGateDecision, } from './dispatch/index.js';
|
|
69
74
|
export type { ParsedLoopDefinition, LoopValidationResult, LoopTrigger, LoopVerify, LoopIsolation, LoopStatus, } from './loop/index.js';
|
|
70
75
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"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"}
|
package/dist/tools/index.js
CHANGED
|
@@ -81,4 +81,8 @@ export { createSpan, completeSpan } from '../infra/lib/telemetry/VibeSpan.js';
|
|
|
81
81
|
export { ComponentRegistry } from '../infra/lib/ComponentRegistry.js';
|
|
82
82
|
// ─── Loop Tools ───
|
|
83
83
|
export { validateLoopDefinition } from './loop/index.js';
|
|
84
|
+
export { validateSpecDocument, formatSpecValidation, featureSlugFromPath, } from './spec/index.js';
|
|
85
|
+
// 디스패처 결정론 신호 — 파일 존재·URL 도메인·첨부 확장자는 모델이 아니라 코드가 판정한다
|
|
86
|
+
export { collectDispatchSignals, detectResumeState, detectStakesSignals, classifyUrl, classifyAttachment, } from './dispatch/index.js';
|
|
87
|
+
export { evaluateCostGate, formatCostGate } from './dispatch/index.js';
|
|
84
88
|
//# sourceMappingURL=index.js.map
|
package/dist/tools/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -11,4 +11,6 @@ export { compileExecutionPacket, getHarnessProfile, validateExecutionPacket, wri
|
|
|
11
11
|
export type { CompileExecutionPacketInput, CompileExecutionPacketResult, ExecutionPacket, ExecutionPacketFileInput, HarnessProfile, HarnessProfileName, PacketError, PacketErrorCode, ValidateExecutionPacketInput, ValidateExecutionPacketResult, WriteExecutionPacketResult, } from './executionPacket.js';
|
|
12
12
|
export { generateTraceabilityMatrix, formatMatrixAsMarkdown, formatMatrixAsHtml } from './traceabilityMatrix.js';
|
|
13
13
|
export type { TraceItem, TraceabilityMatrix, TraceSummary, TraceMatrixOptions } from './traceabilityMatrix.js';
|
|
14
|
+
export { validateSpecDocument, formatSpecValidation, featureSlugFromPath, } from './validateSpecDocument.js';
|
|
15
|
+
export type { SpecValidationResult, SpecFinding, SpecFindingSeverity, } from './validateSpecDocument.js';
|
|
14
16
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/tools/spec/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EACL,qBAAqB,EACrB,sBAAsB,EACtB,qBAAqB,EACrB,gBAAgB,EAChB,kBAAkB,EAClB,mBAAmB,EACnB,oBAAoB,EACpB,mBAAmB,EACnB,eAAe,EACf,aAAa,EACb,aAAa,EACb,gBAAgB,EACjB,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EACL,QAAQ,EACR,YAAY,EACb,MAAM,gBAAgB,CAAC;AACxB,YAAY,EACV,WAAW,EACX,SAAS,EACT,WAAW,EACZ,MAAM,gBAAgB,CAAC;AAGxB,OAAO,EACL,YAAY,EACb,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EACV,oBAAoB,EACpB,aAAa,EACd,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EACL,sBAAsB,EACtB,iBAAiB,EACjB,uBAAuB,EACvB,oBAAoB,GACrB,MAAM,sBAAsB,CAAC;AAC9B,YAAY,EACV,2BAA2B,EAC3B,4BAA4B,EAC5B,eAAe,EACf,wBAAwB,EACxB,cAAc,EACd,kBAAkB,EAClB,WAAW,EACX,eAAe,EACf,4BAA4B,EAC5B,6BAA6B,EAC7B,0BAA0B,GAC3B,MAAM,sBAAsB,CAAC;AAG9B,OAAO,EACL,0BAA0B,EAC1B,sBAAsB,EACtB,kBAAkB,EACnB,MAAM,yBAAyB,CAAC;AACjC,YAAY,EACV,SAAS,EACT,kBAAkB,EAClB,YAAY,EACZ,kBAAkB,EACnB,MAAM,yBAAyB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/tools/spec/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EACL,qBAAqB,EACrB,sBAAsB,EACtB,qBAAqB,EACrB,gBAAgB,EAChB,kBAAkB,EAClB,mBAAmB,EACnB,oBAAoB,EACpB,mBAAmB,EACnB,eAAe,EACf,aAAa,EACb,aAAa,EACb,gBAAgB,EACjB,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EACL,QAAQ,EACR,YAAY,EACb,MAAM,gBAAgB,CAAC;AACxB,YAAY,EACV,WAAW,EACX,SAAS,EACT,WAAW,EACZ,MAAM,gBAAgB,CAAC;AAGxB,OAAO,EACL,YAAY,EACb,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EACV,oBAAoB,EACpB,aAAa,EACd,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EACL,sBAAsB,EACtB,iBAAiB,EACjB,uBAAuB,EACvB,oBAAoB,GACrB,MAAM,sBAAsB,CAAC;AAC9B,YAAY,EACV,2BAA2B,EAC3B,4BAA4B,EAC5B,eAAe,EACf,wBAAwB,EACxB,cAAc,EACd,kBAAkB,EAClB,WAAW,EACX,eAAe,EACf,4BAA4B,EAC5B,6BAA6B,EAC7B,0BAA0B,GAC3B,MAAM,sBAAsB,CAAC;AAG9B,OAAO,EACL,0BAA0B,EAC1B,sBAAsB,EACtB,kBAAkB,EACnB,MAAM,yBAAyB,CAAC;AACjC,YAAY,EACV,SAAS,EACT,kBAAkB,EAClB,YAAY,EACZ,kBAAkB,EACnB,MAAM,yBAAyB,CAAC;AAGjC,OAAO,EACL,oBAAoB,EACpB,oBAAoB,EACpB,mBAAmB,GACpB,MAAM,2BAA2B,CAAC;AACnC,YAAY,EACV,oBAAoB,EACpB,WAAW,EACX,mBAAmB,GACpB,MAAM,2BAA2B,CAAC"}
|
package/dist/tools/spec/index.js
CHANGED
|
@@ -12,4 +12,6 @@ export { generateSpec } from './specGenerator.js';
|
|
|
12
12
|
export { compileExecutionPacket, getHarnessProfile, validateExecutionPacket, writeExecutionPacket, } from './executionPacket.js';
|
|
13
13
|
// Traceability Matrix
|
|
14
14
|
export { generateTraceabilityMatrix, formatMatrixAsMarkdown, formatMatrixAsHtml } from './traceabilityMatrix.js';
|
|
15
|
+
// SPEC Code Guard — 산출물이 하류(run/verify)로 넘어가기 전 노드 단위 검사
|
|
16
|
+
export { validateSpecDocument, formatSpecValidation, featureSlugFromPath, } from './validateSpecDocument.js';
|
|
15
17
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/tools/spec/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,iBAAiB;AACjB,OAAO,EACL,qBAAqB,EACrB,sBAAsB,EACtB,qBAAqB,EACrB,gBAAgB,EAChB,kBAAkB,EAClB,mBAAmB,EACnB,oBAAoB,EACpB,mBAAmB,EACnB,eAAe,EACf,aAAa,EACb,aAAa,EACb,gBAAgB,EACjB,MAAM,oBAAoB,CAAC;AAE5B,aAAa;AACb,OAAO,EACL,QAAQ,EACR,YAAY,EACb,MAAM,gBAAgB,CAAC;AAOxB,iBAAiB;AACjB,OAAO,EACL,YAAY,EACb,MAAM,oBAAoB,CAAC;AAM5B,4BAA4B;AAC5B,OAAO,EACL,sBAAsB,EACtB,iBAAiB,EACjB,uBAAuB,EACvB,oBAAoB,GACrB,MAAM,sBAAsB,CAAC;AAe9B,sBAAsB;AACtB,OAAO,EACL,0BAA0B,EAC1B,sBAAsB,EACtB,kBAAkB,EACnB,MAAM,yBAAyB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/tools/spec/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,iBAAiB;AACjB,OAAO,EACL,qBAAqB,EACrB,sBAAsB,EACtB,qBAAqB,EACrB,gBAAgB,EAChB,kBAAkB,EAClB,mBAAmB,EACnB,oBAAoB,EACpB,mBAAmB,EACnB,eAAe,EACf,aAAa,EACb,aAAa,EACb,gBAAgB,EACjB,MAAM,oBAAoB,CAAC;AAE5B,aAAa;AACb,OAAO,EACL,QAAQ,EACR,YAAY,EACb,MAAM,gBAAgB,CAAC;AAOxB,iBAAiB;AACjB,OAAO,EACL,YAAY,EACb,MAAM,oBAAoB,CAAC;AAM5B,4BAA4B;AAC5B,OAAO,EACL,sBAAsB,EACtB,iBAAiB,EACjB,uBAAuB,EACvB,oBAAoB,GACrB,MAAM,sBAAsB,CAAC;AAe9B,sBAAsB;AACtB,OAAO,EACL,0BAA0B,EAC1B,sBAAsB,EACtB,kBAAkB,EACnB,MAAM,yBAAyB,CAAC;AAQjC,yDAAyD;AACzD,OAAO,EACL,oBAAoB,EACpB,oBAAoB,EACpB,mBAAmB,GACpB,MAAM,2BAA2B,CAAC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export type SpecFindingSeverity = 'P1' | 'P2';
|
|
2
|
+
export interface SpecFinding {
|
|
3
|
+
severity: SpecFindingSeverity;
|
|
4
|
+
code: string;
|
|
5
|
+
message: string;
|
|
6
|
+
/** 1-indexed. 문서 전체에 걸린 문제면 생략 */
|
|
7
|
+
line?: number;
|
|
8
|
+
}
|
|
9
|
+
export interface SpecValidationResult {
|
|
10
|
+
/** P1 이 하나도 없으면 통과 — P2 는 통과를 막지 않는다 */
|
|
11
|
+
valid: boolean;
|
|
12
|
+
findings: SpecFinding[];
|
|
13
|
+
/** 문서에서 발견한 REQ ID 목록 (중복 제거) */
|
|
14
|
+
requirementIds: string[];
|
|
15
|
+
}
|
|
16
|
+
/** 파일명에서 feature 슬러그를 뽑는다 (분할 SPEC 은 디렉토리명) */
|
|
17
|
+
export declare function featureSlugFromPath(specPath: string): string;
|
|
18
|
+
/**
|
|
19
|
+
* SPEC 문서를 검사한다.
|
|
20
|
+
*
|
|
21
|
+
* @param content SPEC 마크다운 원문
|
|
22
|
+
* @param options.specPath 파일 경로 — 주면 REQ 슬러그와 파일명 일치까지 검사한다
|
|
23
|
+
* @returns P1 이 없으면 valid
|
|
24
|
+
*/
|
|
25
|
+
export declare function validateSpecDocument(content: string, options?: {
|
|
26
|
+
specPath?: string;
|
|
27
|
+
}): SpecValidationResult;
|
|
28
|
+
/** 사람이 읽는 한 줄 요약 — 스킬이 그대로 출력한다 */
|
|
29
|
+
export declare function formatSpecValidation(result: SpecValidationResult): string;
|
|
30
|
+
//# sourceMappingURL=validateSpecDocument.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validateSpecDocument.d.ts","sourceRoot":"","sources":["../../../src/tools/spec/validateSpecDocument.ts"],"names":[],"mappings":"AAiBA,MAAM,MAAM,mBAAmB,GAAG,IAAI,GAAG,IAAI,CAAC;AAE9C,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,mBAAmB,CAAC;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,kCAAkC;IAClC,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,oBAAoB;IACnC,wCAAwC;IACxC,KAAK,EAAE,OAAO,CAAC;IACf,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,iCAAiC;IACjC,cAAc,EAAE,MAAM,EAAE,CAAC;CAC1B;AAwBD,+CAA+C;AAC/C,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAG5D;AAqID;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,MAAM,EACf,OAAO,GAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAO,GAClC,oBAAoB,CAwBtB;AAED,mCAAmC;AACnC,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,oBAAoB,GAAG,MAAM,CAUzE"}
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SPEC 문서 Code Guard — `vibe.spec` 산출물이 하류로 넘어가기 전에 검사한다.
|
|
3
|
+
*
|
|
4
|
+
* 배경: vibe 의 결정론 게이트는 전부 파이프라인 **끝**(JUDGE — run-ledger·테스트·RTM)에
|
|
5
|
+
* 몰려 있었다. 중간 노드에는 가드가 없어, 게이트로 쓸 수 없는 SPEC 이 run 까지
|
|
6
|
+
* 흘러간 뒤 verify 단계에서야 걸렸다. 실패를 늦게 발견할수록 비싸다.
|
|
7
|
+
*
|
|
8
|
+
* 여기서 검사하는 것은 취향이 아니라 **하류가 실제로 요구하는 것**이다:
|
|
9
|
+
* - RTM 은 `REQ-{feature}-NNN` 이 없으면 `status: 'empty'` 를 내고, 그건 통과가 아니라
|
|
10
|
+
* 판정불가다 (traceabilityMatrix.ts). 커버리지 게이트가 통째로 죽는다.
|
|
11
|
+
* - `Stakes:` 는 디스패처가 파이프라인 깊이를 정하는 입력이다.
|
|
12
|
+
* - Done Criteria 는 JUDGE 의 입력이다 — 없으면 판정할 것이 없다.
|
|
13
|
+
* - 채워지지 않은 placeholder 는 직역 하네스가 실데이터로 넣는다
|
|
14
|
+
* (dual-harness-doctrine 운영 규칙 2).
|
|
15
|
+
*/
|
|
16
|
+
import path from 'path';
|
|
17
|
+
const REQ_ID = /\bREQ-([a-z0-9-]+)-(\d{3})\b/g;
|
|
18
|
+
const STAKES_LINE = /^\s*[-*]?\s*\*{0,2}Stakes\*{0,2}\s*[::]\s*(.+)$/im;
|
|
19
|
+
const VALID_STAKES = ['demo', 'prototype', 'production'];
|
|
20
|
+
/**
|
|
21
|
+
* 코드 구간(펜스 + 인라인 코드)을 공백으로 지운다 — 줄 번호는 보존한다.
|
|
22
|
+
*
|
|
23
|
+
* SPEC 은 경로 패턴(`styles/{feature}/`), 데이터 모양(`{r,g,b,a}`), 셸 brace
|
|
24
|
+
* expansion(`hooks/{a,b}.js`)을 인라인 코드로 정상적으로 쓴다. 원문을 그대로 훑으면
|
|
25
|
+
* 그것들이 전부 미치환 placeholder 로 잡힌다 (실측: 오탐 28건).
|
|
26
|
+
*/
|
|
27
|
+
function stripCodeSpans(content) {
|
|
28
|
+
const blank = (block) => block.replace(/[^\n]/g, ' ');
|
|
29
|
+
return content
|
|
30
|
+
.replace(/```[\s\S]*?```/g, blank)
|
|
31
|
+
.replace(/`[^`\n]*`/g, blank);
|
|
32
|
+
}
|
|
33
|
+
function lineOf(content, index) {
|
|
34
|
+
return content.slice(0, index).split('\n').length;
|
|
35
|
+
}
|
|
36
|
+
/** 파일명에서 feature 슬러그를 뽑는다 (분할 SPEC 은 디렉토리명) */
|
|
37
|
+
export function featureSlugFromPath(specPath) {
|
|
38
|
+
const base = path.basename(specPath, '.md');
|
|
39
|
+
return base === '_index' ? path.basename(path.dirname(specPath)) : base;
|
|
40
|
+
}
|
|
41
|
+
function collectRequirementIds(content) {
|
|
42
|
+
const out = [];
|
|
43
|
+
for (const m of content.matchAll(REQ_ID)) {
|
|
44
|
+
out.push({ id: m[0], slug: m[1], index: m.index ?? 0 });
|
|
45
|
+
}
|
|
46
|
+
return out;
|
|
47
|
+
}
|
|
48
|
+
function checkRequirements(content, featureSlug, findings) {
|
|
49
|
+
const found = collectRequirementIds(content);
|
|
50
|
+
if (found.length === 0) {
|
|
51
|
+
findings.push({
|
|
52
|
+
severity: 'P1',
|
|
53
|
+
code: 'no-requirement-ids',
|
|
54
|
+
message: 'REQ-* ID 가 하나도 없다 — RTM 이 status:"empty" 를 내고 커버리지 게이트가 판정불가가 된다. '
|
|
55
|
+
+ '모든 기능 요구사항에 REQ-{feature}-NNN 을 붙여라.',
|
|
56
|
+
});
|
|
57
|
+
return [];
|
|
58
|
+
}
|
|
59
|
+
// 파일명과 다른 슬러그는 게이트를 깨지는 않는다 — RTM 은 featureName 을 파일 탐색에만
|
|
60
|
+
// 쓰고 REQ 는 슬러그와 무관하게 전부 파싱한다(traceabilityMatrix.ts extractRequirements).
|
|
61
|
+
// 다만 ID 규약은 REQ-{feature}-NNN 이고(requirementId.ts), 어긋나면 여러 feature 의
|
|
62
|
+
// ID 가 한 문서에서 섞여 추적이 흐려진다 — 그래서 P2 로 알린다.
|
|
63
|
+
if (featureSlug) {
|
|
64
|
+
const mismatched = found.filter(f => f.slug !== featureSlug);
|
|
65
|
+
if (mismatched.length > 0) {
|
|
66
|
+
const slugs = [...new Set(mismatched.map(f => f.slug))];
|
|
67
|
+
findings.push({
|
|
68
|
+
severity: 'P2',
|
|
69
|
+
code: 'requirement-id-slug-mismatch',
|
|
70
|
+
message: `REQ 슬러그(${slugs.join(', ')})가 파일명(${featureSlug})과 다르다 — ${mismatched.length}건. `
|
|
71
|
+
+ 'RTM 집계에는 포함되지만 ID 규약(REQ-{feature}-NNN)에서 벗어나 추적이 흐려진다.',
|
|
72
|
+
line: lineOf(content, mismatched[0].index),
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return [...new Set(found.map(f => f.id))];
|
|
77
|
+
}
|
|
78
|
+
function checkStakes(content, findings) {
|
|
79
|
+
const m = content.match(STAKES_LINE);
|
|
80
|
+
if (!m) {
|
|
81
|
+
findings.push({
|
|
82
|
+
severity: 'P1',
|
|
83
|
+
code: 'no-stakes',
|
|
84
|
+
message: 'Stakes 필드가 없다 — 디스패처가 파이프라인 깊이를 정할 입력이 없다 (demo | prototype | production).',
|
|
85
|
+
});
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
const value = m[1].toLowerCase();
|
|
89
|
+
if (!VALID_STAKES.some(s => value.includes(s))) {
|
|
90
|
+
findings.push({
|
|
91
|
+
severity: 'P1',
|
|
92
|
+
code: 'invalid-stakes',
|
|
93
|
+
message: `Stakes 값을 알 수 없다: "${m[1].trim()}" — demo | prototype | production 중 하나여야 한다.`,
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
function checkDoneCriteria(content, findings) {
|
|
98
|
+
const heading = content.match(/^#{1,3}\s*\d*\.?\s*Done Criteria.*$/im);
|
|
99
|
+
if (!heading) {
|
|
100
|
+
findings.push({
|
|
101
|
+
severity: 'P1',
|
|
102
|
+
code: 'no-done-criteria',
|
|
103
|
+
message: 'Done Criteria 섹션이 없다 — JUDGE 가 판정할 입력이 없다.',
|
|
104
|
+
});
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
// 섹션 본문에 D1 같은 기준 항목이 실제로 있는지
|
|
108
|
+
const after = content.slice((heading.index ?? 0) + heading[0].length);
|
|
109
|
+
const body = after.split(/^#{1,3}\s/m)[0];
|
|
110
|
+
if (!/\bD\d+\b/.test(body)) {
|
|
111
|
+
findings.push({
|
|
112
|
+
severity: 'P1',
|
|
113
|
+
code: 'empty-done-criteria',
|
|
114
|
+
message: 'Done Criteria 섹션에 기준 항목(D1, D2 …)이 없다 — 제목만 있고 판정 기준이 비었다.',
|
|
115
|
+
line: lineOf(content, heading.index ?? 0),
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* 템플릿에서 온 미치환 placeholder — 직역 하네스가 실데이터로 넣는다.
|
|
121
|
+
*
|
|
122
|
+
* 좁게 잡는다. 중괄호 하나만으로는 판단할 수 없다 — 경로 패턴·데이터 모양·brace
|
|
123
|
+
* expansion 이 전부 중괄호를 쓴다. 템플릿 placeholder 는 **산문**이라는 점이
|
|
124
|
+
* 구분점이다: `{Observable functional requirement}` 처럼 공백을 포함한다.
|
|
125
|
+
* 반면 `{feature}` · `{token}` · `{r,g,b,a}` 는 공백이 없다.
|
|
126
|
+
*
|
|
127
|
+
* `<예시>` 는 검사하지 않는다 — dual-harness-doctrine 이 **권장하는** 예시 표기이지
|
|
128
|
+
* 채워야 할 자리가 아니다. `<채워넣을 값>` 만 미치환으로 본다.
|
|
129
|
+
*/
|
|
130
|
+
function checkPlaceholders(content, findings) {
|
|
131
|
+
const scannable = stripCodeSpans(content);
|
|
132
|
+
const patterns = [
|
|
133
|
+
{ re: /\{\{[^}\n]+\}\}/g, code: 'unresolved-template-var', label: '템플릿 변수' },
|
|
134
|
+
{ re: /\{[^}\n]*\s[^}\n]*\}/g, code: 'unfilled-placeholder', label: 'placeholder' },
|
|
135
|
+
{ re: /<채워넣을 값>/g, code: 'unfilled-placeholder', label: 'placeholder' },
|
|
136
|
+
];
|
|
137
|
+
const seen = new Set();
|
|
138
|
+
for (const { re, code, label } of patterns) {
|
|
139
|
+
for (const m of scannable.matchAll(re)) {
|
|
140
|
+
const line = lineOf(scannable, m.index ?? 0);
|
|
141
|
+
if (seen.has(line))
|
|
142
|
+
continue;
|
|
143
|
+
seen.add(line);
|
|
144
|
+
findings.push({
|
|
145
|
+
severity: 'P1',
|
|
146
|
+
code,
|
|
147
|
+
message: `미치환 ${label}: ${m[0].slice(0, 60)} — 직역 하네스는 이 텍스트를 실데이터로 넣는다.`,
|
|
148
|
+
line,
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
function checkScenarios(content, findings) {
|
|
154
|
+
if (!/^#{1,3}\s*\d*\.?\s*Scenarios/im.test(content)) {
|
|
155
|
+
findings.push({
|
|
156
|
+
severity: 'P2',
|
|
157
|
+
code: 'no-scenarios',
|
|
158
|
+
message: 'Scenarios 섹션이 없다 — vibe.run 의 시나리오 루프가 분해할 단위가 없다.',
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* SPEC 문서를 검사한다.
|
|
164
|
+
*
|
|
165
|
+
* @param content SPEC 마크다운 원문
|
|
166
|
+
* @param options.specPath 파일 경로 — 주면 REQ 슬러그와 파일명 일치까지 검사한다
|
|
167
|
+
* @returns P1 이 없으면 valid
|
|
168
|
+
*/
|
|
169
|
+
export function validateSpecDocument(content, options = {}) {
|
|
170
|
+
const findings = [];
|
|
171
|
+
if (content.trim().length === 0) {
|
|
172
|
+
return {
|
|
173
|
+
valid: false,
|
|
174
|
+
findings: [{ severity: 'P1', code: 'empty-spec', message: 'SPEC 이 비어 있다.' }],
|
|
175
|
+
requirementIds: [],
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
const featureSlug = options.specPath ? featureSlugFromPath(options.specPath) : undefined;
|
|
179
|
+
const requirementIds = checkRequirements(content, featureSlug, findings);
|
|
180
|
+
checkStakes(content, findings);
|
|
181
|
+
checkDoneCriteria(content, findings);
|
|
182
|
+
checkPlaceholders(content, findings);
|
|
183
|
+
checkScenarios(content, findings);
|
|
184
|
+
return {
|
|
185
|
+
valid: !findings.some(f => f.severity === 'P1'),
|
|
186
|
+
findings,
|
|
187
|
+
requirementIds,
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
/** 사람이 읽는 한 줄 요약 — 스킬이 그대로 출력한다 */
|
|
191
|
+
export function formatSpecValidation(result) {
|
|
192
|
+
if (result.valid && result.findings.length === 0) {
|
|
193
|
+
return `✅ SPEC guard 통과 — REQ ${result.requirementIds.length}건`;
|
|
194
|
+
}
|
|
195
|
+
const lines = result.findings.map(f => ` ${f.severity} ${f.code}${f.line ? ` (line ${f.line})` : ''}: ${f.message}`);
|
|
196
|
+
const head = result.valid
|
|
197
|
+
? `⚠️ SPEC guard 통과 (P2 ${result.findings.length}건) — REQ ${result.requirementIds.length}건`
|
|
198
|
+
: `❌ SPEC guard 실패 — P1 ${result.findings.filter(f => f.severity === 'P1').length}건`;
|
|
199
|
+
return [head, ...lines].join('\n');
|
|
200
|
+
}
|
|
201
|
+
//# sourceMappingURL=validateSpecDocument.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validateSpecDocument.js","sourceRoot":"","sources":["../../../src/tools/spec/validateSpecDocument.ts"],"names":[],"mappings":"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"}
|
|
@@ -69,36 +69,110 @@ function findUnescaped(str, token) {
|
|
|
69
69
|
return -1;
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
+
/** 정규식 리터럴이 시작될 수 있는 위치인지 — 직전 코드로 나눗셈과 구분한다 */
|
|
73
|
+
function canStartRegex(codeSoFar) {
|
|
74
|
+
const prev = codeSoFar.replace(/\s+$/, '');
|
|
75
|
+
if (prev === '') return true;
|
|
76
|
+
if (/\b(return|typeof|case|in|of|new|delete|void|throw)$/.test(prev)) return true;
|
|
77
|
+
return /[=(,:[!&|?{};+\-*%~^<>]$/.test(prev);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/** 템플릿 리터럴 안에서 종료 백틱과 `${` 중 먼저 오는 것을 찾는다 */
|
|
81
|
+
function nextTemplateStop(rest) {
|
|
82
|
+
for (let i = 0; i < rest.length; i++) {
|
|
83
|
+
if (rest[i] === '\\') { i++; continue; }
|
|
84
|
+
if (rest[i] === '`') return { kind: 'end', index: i };
|
|
85
|
+
if (rest[i] === '$' && rest[i + 1] === '{') return { kind: 'expr', index: i };
|
|
86
|
+
}
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* 템플릿 리터럴 본문을 소비한다. `${` 를 만나면 **코드 구간**으로 넘긴다 —
|
|
92
|
+
* 보간 안은 문자열이 아니라 실행되는 코드다 (`` `${x as any}` `` 를 놓치던 원인).
|
|
93
|
+
*/
|
|
94
|
+
function consumeTemplate(rest, state) {
|
|
95
|
+
const stop = nextTemplateStop(rest);
|
|
96
|
+
if (!stop) return null; // 줄 끝까지 템플릿 — 다음 줄로 상태를 이어간다
|
|
97
|
+
if (stop.kind === 'end') {
|
|
98
|
+
state.stack.pop();
|
|
99
|
+
return rest.slice(stop.index + 1);
|
|
100
|
+
}
|
|
101
|
+
// depth 는 보간 안에서 열린 `{` 수 — 0 일 때의 `}` 만 보간을 닫는다
|
|
102
|
+
state.stack.push({ kind: 'expr', depth: 0 });
|
|
103
|
+
return rest.slice(stop.index + 2);
|
|
104
|
+
}
|
|
105
|
+
|
|
72
106
|
/**
|
|
73
107
|
* 한 줄에서 코드가 아닌 구간(주석·문자열·템플릿 리터럴)을 지운다.
|
|
74
|
-
*
|
|
108
|
+
*
|
|
109
|
+
* 상태는 스택이다 — 템플릿 안의 `${}` 안에 또 템플릿이 올 수 있다.
|
|
110
|
+
* 여러 줄에 걸친 블록 주석·템플릿 리터럴은 스택으로 이어진다.
|
|
111
|
+
*
|
|
75
112
|
* @param {string} line
|
|
76
|
-
* @param {{
|
|
113
|
+
* @param {{ stack: Array<'block'|'template'|'expr'> }} state - 제자리 갱신
|
|
77
114
|
* @returns {string} 코드 구간만 남은 문자열
|
|
78
115
|
*/
|
|
79
116
|
function stripNonCodeLine(line, state) {
|
|
80
117
|
let rest = line;
|
|
81
118
|
let code = '';
|
|
119
|
+
|
|
82
120
|
while (rest.length > 0) {
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
121
|
+
const frame = state.stack[state.stack.length - 1];
|
|
122
|
+
const top = typeof frame === 'object' ? frame.kind : frame;
|
|
123
|
+
|
|
124
|
+
if (top === 'block') {
|
|
125
|
+
const end = findUnescaped(rest, '*/');
|
|
86
126
|
if (end === -1) break;
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
127
|
+
state.stack.pop();
|
|
128
|
+
rest = rest.slice(end + 2);
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
if (top === 'template') {
|
|
132
|
+
const next = consumeTemplate(rest, state);
|
|
133
|
+
if (next === null) break;
|
|
134
|
+
rest = next;
|
|
90
135
|
continue;
|
|
91
136
|
}
|
|
92
|
-
|
|
137
|
+
|
|
138
|
+
// 코드 구간 (최상위 또는 `${}` 안)
|
|
139
|
+
const opener = rest.match(/\/\*|\/\/|`|'|"|\/|\{|\}/);
|
|
93
140
|
if (!opener) return code + rest;
|
|
94
141
|
code += rest.slice(0, opener.index);
|
|
95
142
|
const token = opener[0];
|
|
96
|
-
|
|
143
|
+
const consumed = rest.slice(opener.index + token.length);
|
|
144
|
+
|
|
97
145
|
if (token === '//') break;
|
|
98
|
-
if (token === '
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
146
|
+
if (token === '{') {
|
|
147
|
+
if (top === 'expr') frame.depth++;
|
|
148
|
+
code += '{';
|
|
149
|
+
rest = consumed;
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
if (token === '}') {
|
|
153
|
+
// 보간 안에서 열린 `{` 가 남아 있으면 그걸 닫는 것이지 보간의 끝이 아니다
|
|
154
|
+
// (`${ {a:1}.x as any }` 를 조기 종료하던 원인)
|
|
155
|
+
if (top === 'expr' && frame.depth === 0) state.stack.pop();
|
|
156
|
+
else if (top === 'expr') { frame.depth--; code += '}'; }
|
|
157
|
+
else code += '}';
|
|
158
|
+
rest = consumed;
|
|
159
|
+
continue;
|
|
160
|
+
}
|
|
161
|
+
if (token === '/*') { state.stack.push('block'); rest = consumed; continue; }
|
|
162
|
+
if (token === '`') { state.stack.push('template'); rest = consumed; continue; }
|
|
163
|
+
if (token === '/') {
|
|
164
|
+
// 정규식 리터럴이면 통째로 건너뛴다 — 안의 백틱/따옴표가 상태를 오염시킨다
|
|
165
|
+
if (canStartRegex(code)) {
|
|
166
|
+
const end = findUnescaped(consumed, '/');
|
|
167
|
+
rest = end === -1 ? '' : consumed.slice(end + 1);
|
|
168
|
+
} else {
|
|
169
|
+
code += '/';
|
|
170
|
+
rest = consumed;
|
|
171
|
+
}
|
|
172
|
+
continue;
|
|
173
|
+
}
|
|
174
|
+
const close = findUnescaped(consumed, token); // 홑/겹따옴표는 줄을 넘지 않는다
|
|
175
|
+
rest = close === -1 ? '' : consumed.slice(close + 1);
|
|
102
176
|
}
|
|
103
177
|
return code;
|
|
104
178
|
}
|
|
@@ -115,7 +189,7 @@ function stripNonCodeLine(line, state) {
|
|
|
115
189
|
*/
|
|
116
190
|
function detectAnyType(lines) {
|
|
117
191
|
const findings = [];
|
|
118
|
-
const state = {
|
|
192
|
+
const state = { stack: [] };
|
|
119
193
|
lines.forEach((line, i) => {
|
|
120
194
|
const code = stripNonCodeLine(line, state);
|
|
121
195
|
for (const re of P1_DETECTORS) {
|
|
@@ -153,7 +227,7 @@ function detectAnyType(lines) {
|
|
|
153
227
|
function detectConsoleLogs(lines, filePath) {
|
|
154
228
|
if (!shouldCheckConsole(filePath)) return [];
|
|
155
229
|
const findings = [];
|
|
156
|
-
const state = {
|
|
230
|
+
const state = { stack: [] };
|
|
157
231
|
lines.forEach((line, i) => {
|
|
158
232
|
const code = stripNonCodeLine(line, state);
|
|
159
233
|
if (/console\.log\(/.test(code)) {
|
|
@@ -8,6 +8,8 @@
|
|
|
8
8
|
import fs from 'fs';
|
|
9
9
|
import path from 'path';
|
|
10
10
|
import { readLedger } from './run-ledger.js';
|
|
11
|
+
import { projectVibePath } from '../utils.js';
|
|
12
|
+
import { inboxPath } from './inbox.js';
|
|
11
13
|
|
|
12
14
|
/** 우선순위대로 첫 번째로 존재하는 경로를 고른다 */
|
|
13
15
|
function firstExisting(projectDir, candidates) {
|
|
@@ -17,10 +19,16 @@ function firstExisting(projectDir, candidates) {
|
|
|
17
19
|
return null;
|
|
18
20
|
}
|
|
19
21
|
|
|
20
|
-
/**
|
|
22
|
+
/**
|
|
23
|
+
* `.last-feature` 에 기록된 직전 feature 이름.
|
|
24
|
+
*
|
|
25
|
+
* 경로는 `projectVibePath` 가 소유한다 — `.vibe/` 를 하드코딩하면 레거시
|
|
26
|
+
* 프로젝트(`.claude/vibe/`)에서 못 찾고, feature 가 null 이 되면 spec 탐색까지
|
|
27
|
+
* 연쇄로 무너져 ANCHOR 가 전부 missing 을 보고한다 (감사 2026-08-08 G-D 재현).
|
|
28
|
+
*/
|
|
21
29
|
function readLastFeature(projectDir) {
|
|
22
30
|
try {
|
|
23
|
-
const raw = fs.readFileSync(
|
|
31
|
+
const raw = fs.readFileSync(projectVibePath(projectDir, '.last-feature'), 'utf-8').trim();
|
|
24
32
|
return raw.length > 0 ? raw : null;
|
|
25
33
|
} catch {
|
|
26
34
|
return null;
|
|
@@ -41,7 +49,7 @@ function findSpec(projectDir, feature) {
|
|
|
41
49
|
/** 인박스에서 가장 최근 블록(다음 `## ` 직전까지) */
|
|
42
50
|
function readLatestInboxBlock(projectDir) {
|
|
43
51
|
try {
|
|
44
|
-
const raw = fs.readFileSync(
|
|
52
|
+
const raw = fs.readFileSync(inboxPath(projectDir), 'utf-8');
|
|
45
53
|
const start = raw.indexOf('## ');
|
|
46
54
|
if (start === -1) return null;
|
|
47
55
|
const next = raw.indexOf('\n## ', start + 3);
|
|
@@ -62,7 +70,10 @@ function readLatestInboxBlock(projectDir) {
|
|
|
62
70
|
export function buildAnchor(projectDir, feature) {
|
|
63
71
|
const resolved = feature || readLastFeature(projectDir);
|
|
64
72
|
const spec = findSpec(projectDir, resolved);
|
|
65
|
-
|
|
73
|
+
// scope 도 경로 소유권을 utils 에 맡긴다 — 쓰는 쪽(scope-from-spec)과 다른 루트를
|
|
74
|
+
// 보면 ANCHOR 만 scope 를 놓친다
|
|
75
|
+
const scopeAbs = projectVibePath(projectDir, 'scope.json');
|
|
76
|
+
const scope = fs.existsSync(scopeAbs) ? path.relative(projectDir, scopeAbs) : null;
|
|
66
77
|
const ledger = readLedger(projectDir);
|
|
67
78
|
|
|
68
79
|
const missing = [];
|
|
@@ -8,11 +8,19 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import fs from 'fs';
|
|
10
10
|
import path from 'path';
|
|
11
|
+
import { projectVibePath } from '../utils.js';
|
|
11
12
|
|
|
12
13
|
const HEADER = '# Loop Inbox\n\n> 루프가 남긴 사람 리뷰 큐. 최신 항목이 위에 온다.\n';
|
|
13
14
|
|
|
14
|
-
|
|
15
|
-
|
|
15
|
+
/**
|
|
16
|
+
* 인박스 경로 — 이 모듈이 소유한다.
|
|
17
|
+
*
|
|
18
|
+
* 쓰기는 항상 `.vibe/` 로 한다(신규 레이아웃). 읽기는 레거시(`.claude/vibe/`)도
|
|
19
|
+
* 봐야 하므로 `projectVibePath` 를 쓴다 — 두 쪽이 다른 파일을 보면 기록은 되는데
|
|
20
|
+
* ANCHOR 는 못 읽는 상태가 된다.
|
|
21
|
+
*/
|
|
22
|
+
export function inboxPath(projectDir) {
|
|
23
|
+
return projectVibePath(projectDir, 'loops', 'inbox.md');
|
|
16
24
|
}
|
|
17
25
|
|
|
18
26
|
/**
|