@@ -185,6 +185,8 @@ const publishCmd = Command.make(
185185 const serverDir = path . join ( repoRoot , "apps/server" ) ;
186186 const packageJsonPath = path . join ( serverDir , "package.json" ) ;
187187 const backupPath = `${ packageJsonPath } .bak` ;
188+ const version = Option . getOrElse ( config . appVersion , ( ) => serverPackageJson . version ) ;
189+ const publishTarget = `${ serverPackageJson . name } @${ version } ` ;
188190
189191 // Assert build assets exist
190192 for ( const relPath of [ "dist/index.mjs" , "dist/client/index.html" ] ) {
@@ -201,7 +203,6 @@ const publishCmd = Command.make(
201203 Effect . gen ( function * ( ) {
202204 // Resolve catalog dependencies before any file mutations. If this throws,
203205 // acquire fails and no release hook runs, so filesystem must still be untouched.
204- const version = Option . getOrElse ( config . appVersion , ( ) => serverPackageJson . version ) ;
205206 const pkg = {
206207 name : serverPackageJson . name ,
207208 repository : serverPackageJson . repository ,
@@ -230,6 +231,25 @@ const publishCmd = Command.make(
230231 // Use: npm publish
231232 ( ) =>
232233 Effect . gen ( function * ( ) {
234+ const versionExists = yield * runCommand (
235+ ChildProcess . make ( "npm" , [ "view" , publishTarget , "version" ] , {
236+ cwd : serverDir ,
237+ stdout : config . verbose ? "inherit" : "ignore" ,
238+ stderr : "inherit" ,
239+ shell : process . platform === "win32" ,
240+ } ) ,
241+ ) . pipe (
242+ Effect . as ( true ) ,
243+ Effect . catchTag ( "CliError" , ( ) => Effect . succeed ( false ) ) ,
244+ ) ;
245+
246+ if ( versionExists ) {
247+ yield * Effect . logWarning (
248+ `[cli] ${ publishTarget } is already published; skipping npm publish.` ,
249+ ) ;
250+ return ;
251+ }
252+
233253 const args = [ "publish" , "--access" , config . access , "--tag" , config . tag ] ;
234254 if ( config . provenance ) args . push ( "--provenance" ) ;
235255 if ( config . dryRun ) args . push ( "--dry-run" ) ;
0 commit comments