99} from "node:fs" ;
1010import { tmpdir } from "node:os" ;
1111import { dirname , join , resolve } from "node:path" ;
12- import { describe , expect , it , vi } from "vitest" ;
12+ import { beforeAll , describe , expect , it , vi } from "vitest" ;
1313import { UI_COPY } from "../lib/ui/copy.js" ;
1414
1515const projectRoot = resolve ( process . cwd ( ) ) ;
@@ -31,41 +31,43 @@ function readPackageVersion(): string {
3131 return parsed . version . trim ( ) ;
3232}
3333
34- const packageVersion = readPackageVersion ( ) ;
35- const currentStableReleaseDoc = `docs/releases/v ${ packageVersion } .md` ;
34+ let packageVersion = "" ;
35+ let currentStableReleaseDoc = "" ;
3636// These stay manual so the docs portal keeps an intentional short stable-history window.
3737const previousStableReleaseDoc = "docs/releases/v1.2.1.md" ;
3838const earlierStableReleaseDoc = "docs/releases/v1.2.0.md" ;
3939
40- const userDocs = [
41- "docs/index.md" ,
42- "docs/README.md" ,
43- "docs/getting-started.md" ,
44- "docs/faq.md" ,
45- "docs/architecture.md" ,
46- "docs/features.md" ,
47- "docs/configuration.md" ,
48- "docs/troubleshooting.md" ,
49- "docs/privacy.md" ,
50- "docs/upgrade.md" ,
51- "docs/reference/commands.md" ,
52- "docs/reference/public-api.md" ,
53- "docs/reference/error-contracts.md" ,
54- "docs/reference/settings.md" ,
55- "docs/reference/storage-paths.md" ,
56- currentStableReleaseDoc ,
57- previousStableReleaseDoc ,
58- earlierStableReleaseDoc ,
59- "docs/releases/v0.1.7.md" ,
60- "docs/releases/v0.1.6.md" ,
61- "docs/releases/v0.1.5.md" ,
62- "docs/releases/v0.1.4.md" ,
63- "docs/releases/v0.1.3.md" ,
64- "docs/releases/v0.1.1.md" ,
65- "docs/releases/v0.1.0.md" ,
66- "docs/releases/v0.1.0-beta.0.md" ,
67- "docs/releases/legacy-pre-0.1-history.md" ,
68- ] ;
40+ function getUserDocs ( ) : string [ ] {
41+ return [
42+ "docs/index.md" ,
43+ "docs/README.md" ,
44+ "docs/getting-started.md" ,
45+ "docs/faq.md" ,
46+ "docs/architecture.md" ,
47+ "docs/features.md" ,
48+ "docs/configuration.md" ,
49+ "docs/troubleshooting.md" ,
50+ "docs/privacy.md" ,
51+ "docs/upgrade.md" ,
52+ "docs/reference/commands.md" ,
53+ "docs/reference/public-api.md" ,
54+ "docs/reference/error-contracts.md" ,
55+ "docs/reference/settings.md" ,
56+ "docs/reference/storage-paths.md" ,
57+ currentStableReleaseDoc ,
58+ previousStableReleaseDoc ,
59+ earlierStableReleaseDoc ,
60+ "docs/releases/v0.1.7.md" ,
61+ "docs/releases/v0.1.6.md" ,
62+ "docs/releases/v0.1.5.md" ,
63+ "docs/releases/v0.1.4.md" ,
64+ "docs/releases/v0.1.3.md" ,
65+ "docs/releases/v0.1.1.md" ,
66+ "docs/releases/v0.1.0.md" ,
67+ "docs/releases/v0.1.0-beta.0.md" ,
68+ "docs/releases/legacy-pre-0.1-history.md" ,
69+ ] ;
70+ }
6971
7072const scopedLegacyAllowedFiles = new Set ( [
7173 "README.md" ,
@@ -88,6 +90,11 @@ const maintainerRunbooks = [
8890 "docs/development/RUNBOOK_CHANGE_ROUTING_POLICY.md" ,
8991] ;
9092
93+ beforeAll ( ( ) => {
94+ packageVersion = readPackageVersion ( ) ;
95+ currentStableReleaseDoc = `docs/releases/v${ packageVersion } .md` ;
96+ } ) ;
97+
9198function read ( filePath : string ) : string {
9299 return readFileSync ( join ( projectRoot , filePath ) , "utf-8" ) ;
93100}
@@ -133,9 +140,9 @@ function compareSemverDescending(left: string, right: string): number {
133140 return 0 ;
134141}
135142
136- describe ( "Documentation Integrity" , ( ) => {
143+ describe ( "Documentation Integrity" , ( ) => {
137144 it ( "has all required user docs and release notes" , ( ) => {
138- for ( const docPath of userDocs ) {
145+ for ( const docPath of getUserDocs ( ) ) {
139146 const fullPath = join ( projectRoot , docPath ) ;
140147 expect ( existsSync ( fullPath ) , `${ docPath } should exist` ) . toBe ( true ) ;
141148 expect (
@@ -188,7 +195,7 @@ describe("Documentation Integrity", () => {
188195 } ) ;
189196
190197 it ( "uses scoped package only in explicit legacy migration notes" , ( ) => {
191- const files = [ "README.md" , ...userDocs ] ;
198+ const files = [ "README.md" , ...getUserDocs ( ) ] ;
192199
193200 for ( const filePath of files ) {
194201 const content = read ( filePath ) ;
@@ -206,7 +213,7 @@ describe("Documentation Integrity", () => {
206213
207214 it ( "does not include opencode wording in user docs" , ( ) => {
208215 const allowedOpencodeFiles = new Set ( [ "docs/reference/storage-paths.md" ] ) ;
209- for ( const filePath of userDocs ) {
216+ for ( const filePath of getUserDocs ( ) ) {
210217 const content = read ( filePath ) . toLowerCase ( ) ;
211218 const hasLegacyHostWord = content . includes ( "opencode" ) ;
212219 if ( hasLegacyHostWord ) {
@@ -219,7 +226,7 @@ describe("Documentation Integrity", () => {
219226 } ) ;
220227
221228 it ( "keeps compatibility command aliases scoped to reference, troubleshooting, or migration docs" , ( ) => {
222- const files = [ "README.md" , ...userDocs ] ;
229+ const files = [ "README.md" , ...getUserDocs ( ) ] ;
223230 const aliasPattern = / \b c o d e x ( m u l t i a u t h | m u l t i - a u t h | m u l t i a u t h ) \b / i;
224231
225232 for ( const filePath of files ) {
0 commit comments