@@ -20,6 +20,7 @@ import { createInterface } from "readline";
2020import * as childProcess from "child_process" ;
2121import { REPORT_GENERATORS , CHECK_INFO , generateAllReports } from "../lib/checkup" ;
2222import { createCheckupReport , uploadCheckupReportJson , RpcError , formatRpcErrorForDisplay , withRetry } from "../lib/checkup-api" ;
23+ import { DOCKER_COMPOSE_CONTENT } from "../lib/compose-embedded" ;
2324
2425// Singleton readline interface for stdin prompts
2526let rl : ReturnType < typeof createInterface > | null = null ;
@@ -408,18 +409,18 @@ function getDefaultMonitoringProjectDir(): string {
408409 return path . join ( config . getConfigDir ( ) , "monitoring" ) ;
409410}
410411
411- async function downloadText ( url : string ) : Promise < string > {
412- const controller = new AbortController ( ) ;
413- const timeout = setTimeout ( ( ) => controller . abort ( ) , 15_000 ) ;
414- try {
415- const response = await fetch ( url , { signal : controller . signal } ) ;
416- if ( ! response . ok ) {
417- throw new Error ( `HTTP ${ response . status } for ${ url } ` ) ;
418- }
419- return await response . text ( ) ;
420- } finally {
421- clearTimeout ( timeout ) ;
412+ /**
413+ * Get the stable version for docker image tags.
414+ * Strips dev suffix (e.g., "0.14.0-dev.33" -> "0.14.0") since dev images
415+ * are only published to GitLab registry, not Docker Hub.
416+ */
417+ function getStableImageTag ( ) : string {
418+ // Allow explicit override via environment variable
419+ if ( process . env . PGAI_TAG ) {
420+ return process . env . PGAI_TAG ;
422421 }
422+ // Strip -dev.X suffix for stable Docker Hub images
423+ return pkg . version . replace ( / - d e v \. \d + $ / , "" ) ;
423424}
424425
425426async function ensureDefaultMonitoringProject ( ) : Promise < PathResolution > {
@@ -431,31 +432,8 @@ async function ensureDefaultMonitoringProject(): Promise<PathResolution> {
431432 fs . mkdirSync ( projectDir , { recursive : true , mode : 0o700 } ) ;
432433 }
433434
434- if ( ! fs . existsSync ( composeFile ) ) {
435- const refs = [
436- process . env . PGAI_PROJECT_REF ,
437- pkg . version ,
438- `v${ pkg . version } ` ,
439- "main" ,
440- ] . filter ( ( v ) : v is string => Boolean ( v && v . trim ( ) ) ) ;
441-
442- let lastErr : unknown ;
443- for ( const ref of refs ) {
444- const url = `https://gitlab.com/postgres-ai/postgres_ai/-/raw/${ encodeURIComponent ( ref ) } /docker-compose.yml` ;
445- try {
446- const text = await downloadText ( url ) ;
447- fs . writeFileSync ( composeFile , text , { encoding : "utf8" , mode : 0o600 } ) ;
448- break ;
449- } catch ( err ) {
450- lastErr = err ;
451- }
452- }
453-
454- if ( ! fs . existsSync ( composeFile ) ) {
455- const msg = lastErr instanceof Error ? lastErr . message : String ( lastErr ) ;
456- throw new Error ( `Failed to bootstrap docker-compose.yml: ${ msg } ` ) ;
457- }
458- }
435+ // Write embedded docker-compose.yml (always overwrite to stay in sync with CLI version)
436+ fs . writeFileSync ( composeFile , DOCKER_COMPOSE_CONTENT , { encoding : "utf8" , mode : 0o600 } ) ;
459437
460438 // Ensure instances.yml exists as a FILE (avoid Docker creating a directory)
461439 if ( ! fs . existsSync ( instancesFile ) ) {
@@ -472,9 +450,11 @@ async function ensureDefaultMonitoringProject(): Promise<PathResolution> {
472450 }
473451
474452 // Ensure .env exists and has PGAI_TAG (compose requires it)
453+ // Use stable version by default; dev users can override with PGAI_TAG env var
475454 const envFile = path . resolve ( projectDir , ".env" ) ;
476455 if ( ! fs . existsSync ( envFile ) ) {
477- const envText = `PGAI_TAG=${ pkg . version } \n# PGAI_REGISTRY=registry.gitlab.com/postgres-ai/postgres_ai\n` ;
456+ const stableTag = getStableImageTag ( ) ;
457+ const envText = `PGAI_TAG=${ stableTag } \n# For dev images, use GitLab registry:\n# PGAI_REGISTRY=registry.gitlab.com/postgres-ai/postgres_ai\n# PGAI_TAG=${ pkg . version } \n` ;
478458 fs . writeFileSync ( envFile , envText , { encoding : "utf8" , mode : 0o600 } ) ;
479459 }
480460
0 commit comments