@eldrforge/commands-publish 0.1.3 → 0.1.4

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/dist/index.js CHANGED
@@ -1,11 +1,11 @@
1
- import { getDryRunLogger, findDevelopmentBranch, KODRDRIV_DEFAULTS, DEFAULT_TO_COMMIT_ALIAS, Log, DEFAULT_MAX_DIFF_BYTES, Diff, DEFAULT_EXCLUDED_PATTERNS, DEFAULT_OUTPUT_DIRECTORY, toAIConfig, createStorageAdapter, createLoggerAdapter, getOutputPath, getTimestampedResponseFilename, getTimestampedRequestFilename, filterContent, getTimestampedReleaseNotesFilename, improveContentWithLLM, validateReleaseSummary, runGitWithLock, calculateBranchDependentVersion, checkIfTagExists, confirmVersionInteractively, getLogger } from '@eldrforge/core';
2
- import { getCurrentBranch, run, localBranchExists, getDefaultFromRef, safeJsonParse, remoteBranchExists, runSecure, runWithDryRunSupport, validatePackageJson, validateGitRef, safeSyncBranchWithRemote, isBranchInSyncWithRemote } from '@eldrforge/git-tools';
1
+ import { getDryRunLogger, findDevelopmentBranch, KODRDRIV_DEFAULTS, incrementPatchVersion, incrementMajorVersion, incrementMinorVersion, DEFAULT_TO_COMMIT_ALIAS, Log, DEFAULT_MAX_DIFF_BYTES, Diff, DEFAULT_EXCLUDED_PATTERNS, DEFAULT_OUTPUT_DIRECTORY, toAIConfig, createStorageAdapter, createLoggerAdapter, getOutputPath, getTimestampedResponseFilename, getTimestampedRequestFilename, filterContent, getTimestampedReleaseNotesFilename, improveContentWithLLM, validateReleaseSummary, runGitWithLock, calculateBranchDependentVersion, checkIfTagExists, confirmVersionInteractively, getLogger } from '@eldrforge/core';
2
+ import { getCurrentBranch, run, localBranchExists, safeJsonParse, validatePackageJson, getDefaultFromRef, remoteBranchExists, runSecure, runWithDryRunSupport, validateGitRef, safeSyncBranchWithRemote, isBranchInSyncWithRemote } from '@eldrforge/git-tools';
3
+ import { createStorage, calculateTargetVersion } from '@eldrforge/shared';
3
4
  import path from 'path';
4
5
  import * as Commit from '@eldrforge/commands-git';
5
6
  import { Formatter } from '@riotprompt/riotprompt';
6
7
  import 'dotenv/config';
7
8
  import { runAgenticRelease, requireTTY, generateReflectionReport, getUserChoice, STANDARD_CHOICES, getLLMFeedbackInEditor, editContentInEditor, createCompletionWithRetry, createReleasePrompt, runAgenticPublish, formatAgenticPublishResult } from '@eldrforge/ai-service';
8
- import { createStorage, calculateTargetVersion } from '@eldrforge/shared';
9
9
  import * as GitHub from '@eldrforge/github-tools';
10
10
  import fs from 'fs/promises';
11
11
 
@@ -163,7 +163,7 @@ import fs from 'fs/promises';
163
163
  const gitStatus = await run('git status --porcelain');
164
164
  if (gitStatus.stdout.trim()) {
165
165
  await run('git add -A');
166
- await run('git commit -m "chore: update package-lock.json after merge"');
166
+ await run('git commit -m "chore: update dependencies after merge"');
167
167
  }
168
168
  // Stay on working branch for development (removed checkout development)
169
169
  mergedDevelopmentIntoWorking = true;
@@ -255,9 +255,9 @@ import fs from 'fs/promises';
255
255
  // Check if npm install created changes
256
256
  const gitStatus = await run('git status --porcelain');
257
257
  if (gitStatus.stdout.trim()) {
258
- logger.info('DEV_POST_MERGE_COMMIT: Committing changes from npm install | Files: package-lock.json | Purpose: Finalize merge');
258
+ logger.info('DEV_POST_MERGE_COMMIT: Committing changes from npm install | Purpose: Finalize merge');
259
259
  await run('git add -A');
260
- await run('git commit -m "chore: update package-lock.json after merge"');
260
+ await run('git commit -m "chore: update dependencies after merge"');
261
261
  }
262
262
  } catch (mergeError) {
263
263
  if (mergeError.message && mergeError.message.includes('CONFLICT')) {
@@ -299,10 +299,10 @@ import fs from 'fs/promises';
299
299
  // Check if npm install created any changes (e.g., package-lock.json)
300
300
  const gitStatus = await run('git status --porcelain');
301
301
  if (gitStatus.stdout.trim()) {
302
- logger.info('DEV_POST_MERGE_COMMIT: Committing changes from npm install | Files: package-lock.json | Purpose: Finalize merge');
302
+ logger.info('DEV_POST_MERGE_COMMIT: Committing changes from npm install | Purpose: Finalize merge');
303
303
  await run('git add -A');
304
304
  await run(`git commit -m "chore: update package-lock.json after merge"`);
305
- logger.info('DEV_CHANGES_COMMITTED: Changes committed successfully | Files: package-lock.json | Status: committed');
305
+ logger.info('DEV_CHANGES_COMMITTED: Changes committed successfully | Status: committed');
306
306
  }
307
307
  } catch (error) {
308
308
  if (error.message && error.message.includes('CONFLICT')) {
@@ -325,7 +325,7 @@ import fs from 'fs/promises';
325
325
  } else {
326
326
  logger.info('DEV_DEV_MERGE_DRY_RUN: Would merge development if exists | Mode: dry-run | Source: development | Target: working');
327
327
  logger.info('DEV_INSTALL_DRY_RUN: Would run npm install after merge | Mode: dry-run | Command: npm install');
328
- logger.info('DEV_COMMIT_DRY_RUN: Would commit npm install changes | Mode: dry-run | Files: package-lock.json');
328
+ logger.info('DEV_COMMIT_DRY_RUN: Would commit npm install changes | Mode: dry-run');
329
329
  }
330
330
  // Step 4.5: Create retroactive tags if requested (one-time operation)
331
331
  if ((_runConfig_development1 = runConfig.development) === null || _runConfig_development1 === void 0 ? void 0 : _runConfig_development1.createRetroactiveTags) {
@@ -399,30 +399,59 @@ import fs from 'fs/promises';
399
399
  } else if (isDryRun) {
400
400
  logger.info('Tagging disabled (--no-tag-working-branch)');
401
401
  }
402
- // Step 6: Run npm version to bump version with increment level
403
- let versionCommand;
402
+ // Step 6: Bump version manually to avoid npm version's automatic git add
403
+ // Note: npm version --no-git-tag-version still runs "git add package.json package-lock.json"
404
+ // which fails when package-lock.json is gitignored
404
405
  if ([
405
406
  'patch',
406
407
  'minor',
407
408
  'major'
408
409
  ].includes(incrementLevel)) {
409
- versionCommand = `pre${incrementLevel}`;
410
- logger.info(`DEV_VERSION_BUMPING: Bumping version with prerelease tag | Level: ${incrementLevel} | Tag: ${prereleaseTag} | Command: npm version`);
410
+ logger.info(`DEV_VERSION_BUMPING: Bumping version with prerelease tag | Level: ${incrementLevel} | Tag: ${prereleaseTag}`);
411
411
  } else {
412
- // Explicit version like "3.5.0"
413
- const cleanVersion = incrementLevel.replace(/^v/, '');
414
- versionCommand = `${cleanVersion}-${prereleaseTag}.0`;
415
- logger.info(`DEV_VERSION_EXPLICIT: Setting explicit version | Version: ${versionCommand} | Type: explicit`);
412
+ logger.info(`DEV_VERSION_EXPLICIT: Setting explicit version | Version: ${incrementLevel}-${prereleaseTag}.0 | Type: explicit`);
416
413
  }
417
414
  if (!isDryRun) {
418
415
  try {
419
- const versionResult = [
416
+ const storage = createStorage();
417
+ const pkgJsonContents = await storage.readFile('package.json', 'utf-8');
418
+ const pkgJson = safeJsonParse(pkgJsonContents, 'package.json');
419
+ const validatedPkgJson = validatePackageJson(pkgJson, 'package.json');
420
+ const currentVersion = validatedPkgJson.version;
421
+ let newVersion;
422
+ if ([
420
423
  'patch',
421
424
  'minor',
422
425
  'major'
423
- ].includes(incrementLevel) ? await run(`npm version ${versionCommand} --preid=${prereleaseTag}`) : await run(`npm version ${versionCommand}`);
424
- const newVersion = versionResult.stdout.trim();
426
+ ].includes(incrementLevel)) {
427
+ // First increment the base version, then add prerelease tag
428
+ let baseVersion;
429
+ switch(incrementLevel){
430
+ case 'patch':
431
+ baseVersion = incrementPatchVersion(currentVersion);
432
+ break;
433
+ case 'minor':
434
+ baseVersion = incrementMinorVersion(currentVersion);
435
+ break;
436
+ case 'major':
437
+ baseVersion = incrementMajorVersion(currentVersion);
438
+ break;
439
+ default:
440
+ baseVersion = incrementPatchVersion(currentVersion);
441
+ }
442
+ newVersion = `${baseVersion}-${prereleaseTag}.0`;
443
+ } else {
444
+ // Explicit version like "3.5.0"
445
+ const cleanVersion = incrementLevel.replace(/^v/, '');
446
+ newVersion = `${cleanVersion}-${prereleaseTag}.0`;
447
+ }
448
+ // Update package.json with new version
449
+ validatedPkgJson.version = newVersion;
450
+ await storage.writeFile('package.json', JSON.stringify(validatedPkgJson, null, 2) + '\n', 'utf-8');
425
451
  logger.info(`DEV_VERSION_BUMPED: Version bumped successfully | New Version: ${newVersion} | Status: completed`);
452
+ // Manually commit the version bump (package-lock.json is ignored)
453
+ await run('git add package.json');
454
+ await run(`git commit -m "chore: bump to ${newVersion}"`);
426
455
  // Return appropriate message based on what actions were taken
427
456
  if (mergedDevelopmentIntoWorking) {
428
457
  return 'Merged development into working and ready for development';
@@ -445,9 +474,9 @@ import fs from 'fs/promises';
445
474
  'minor',
446
475
  'major'
447
476
  ].includes(incrementLevel)) {
448
- logger.info(`Would run: npm version ${versionCommand} --preid=${prereleaseTag}`);
477
+ logger.info(`Would bump version with prerelease tag: ${incrementLevel} --preid=${prereleaseTag}`);
449
478
  } else {
450
- logger.info(`Would run: npm version ${versionCommand}`);
479
+ logger.info(`Would set explicit version: ${incrementLevel}-${prereleaseTag}.0`);
451
480
  }
452
481
  // Return appropriate message based on what actions were taken
453
482
  if (mergedDevelopmentIntoWorking) {
@@ -1185,15 +1214,15 @@ const isReleaseNecessaryComparedToTarget = async (targetBranch, isDryRun)=>{
1185
1214
  reason: 'No detectable changes via diff; proceeding conservatively'
1186
1215
  };
1187
1216
  }
1188
- // If any files changed other than package.json or package-lock.json, a release is necessary
1189
- const nonVersionFiles = changedFiles.filter((f)=>f !== 'package.json' && f !== 'package-lock.json');
1217
+ // If any files changed other than package.json (package-lock.json is gitignored), a release is necessary
1218
+ const nonVersionFiles = changedFiles.filter((f)=>f !== 'package.json');
1190
1219
  if (nonVersionFiles.length > 0) {
1191
1220
  return {
1192
1221
  necessary: true,
1193
1222
  reason: `Changed files beyond version bump: ${nonVersionFiles.join(', ')}`
1194
1223
  };
1195
1224
  }
1196
- // Only package.json and/or package-lock.json changed. Verify package.json change is only the version field
1225
+ // Only package.json changed. Verify package.json change is only the version field
1197
1226
  try {
1198
1227
  // Read package.json content from both branches
1199
1228
  const { stdout: basePkgStdout } = await runSecure('git', [
@@ -1455,10 +1484,9 @@ const execute = async (runConfig)=>{
1455
1484
  logger.info('PREPUBLISH_SCRIPT_RUNNING: Executing prepublishOnly script | Script: prepublishOnly | Purpose: Run pre-flight checks (clean, lint, build, test)');
1456
1485
  await runWithDryRunSupport('npm run prepublishOnly', isDryRun, {}, true); // Use inherited stdio
1457
1486
  // STEP 2: Commit dependency updates if any (still no version bump)
1458
- logger.verbose('DEPS_STAGING: Staging dependency updates for commit | Files: package.json + package-lock.json | Command: git add | Note: Version bump not yet applied');
1459
- // Check if package-lock.json exists before trying to stage it
1460
- const packageLockExists = await storage.exists('package-lock.json');
1461
- const filesToStage = packageLockExists ? 'package.json package-lock.json' : 'package.json';
1487
+ logger.verbose('DEPS_STAGING: Staging dependency updates for commit | Files: package.json | Command: git add | Note: Version bump not yet applied, package-lock.json ignored');
1488
+ // Skip package-lock.json as it's in .gitignore to avoid private registry refs
1489
+ const filesToStage = 'package.json';
1462
1490
  // Wrap git operations with repository lock to prevent .git/index.lock conflicts
1463
1491
  await runGitWithLock(process.cwd(), async ()=>{
1464
1492
  await runWithDryRunSupport(`git add ${filesToStage}`, isDryRun);
@@ -1522,10 +1550,9 @@ const execute = async (runConfig)=>{
1522
1550
  const { stdout: conflictedFiles } = await run('git diff --name-only --diff-filter=U');
1523
1551
  const conflicts = conflictedFiles.trim().split('\n').filter(Boolean);
1524
1552
  logger.verbose(`MERGE_CONFLICTS_LIST: Conflicted files detected | Files: ${conflicts.join(', ')} | Count: ${conflicts.length}`);
1525
- // Check if conflicts are only in package.json and package-lock.json
1553
+ // Check if conflicts are only in package.json (package-lock.json is gitignored)
1526
1554
  const versionFiles = [
1527
- 'package.json',
1528
- 'package-lock.json'
1555
+ 'package.json'
1529
1556
  ];
1530
1557
  const nonVersionConflicts = conflicts.filter((f)=>!versionFiles.includes(f));
1531
1558
  if (nonVersionConflicts.length > 0) {
@@ -1568,9 +1595,8 @@ const execute = async (runConfig)=>{
1568
1595
  const { stdout: mergeChangesStatus } = await run('git status --porcelain');
1569
1596
  if (mergeChangesStatus.trim()) {
1570
1597
  logger.verbose('POST_MERGE_CHANGES_DETECTED: Changes detected after npm install | Action: Staging for commit | Command: git add');
1571
- // Check if package-lock.json exists before trying to stage it
1572
- const packageLockExistsPostMerge = await storage.exists('package-lock.json');
1573
- const filesToStagePostMerge = packageLockExistsPostMerge ? 'package.json package-lock.json' : 'package.json';
1598
+ // Skip package-lock.json as it's in .gitignore to avoid private registry refs
1599
+ const filesToStagePostMerge = 'package.json';
1574
1600
  await run(`git add ${filesToStagePostMerge}`);
1575
1601
  if (await Diff.hasStagedChanges()) {
1576
1602
  logger.verbose('POST_MERGE_COMMIT: Committing post-merge changes | Files: ' + filesToStagePostMerge + ' | Purpose: Finalize merge');
@@ -1721,9 +1747,8 @@ const execute = async (runConfig)=>{
1721
1747
  }
1722
1748
  // STEP 5: Commit version bump as a separate commit
1723
1749
  logger.verbose('Staging version bump for commit');
1724
- // Check if package-lock.json exists before trying to stage it
1725
- const packageLockExistsVersionBump = await storage.exists('package-lock.json');
1726
- const filesToStageVersionBump = packageLockExistsVersionBump ? 'package.json package-lock.json' : 'package.json';
1750
+ // Skip package-lock.json as it's in .gitignore to avoid private registry refs
1751
+ const filesToStageVersionBump = 'package.json';
1727
1752
  // Wrap git operations with lock
1728
1753
  await runGitWithLock(process.cwd(), async ()=>{
1729
1754
  await runWithDryRunSupport(`git add ${filesToStageVersionBump}`, isDryRun);
@@ -2191,15 +2216,13 @@ const execute = async (runConfig)=>{
2191
2216
  logger.info(`PUBLISH_MERGE_SUCCESS: Merged target into source | Target: ${targetBranch} | Source: ${currentBranch} | Status: merged`);
2192
2217
  }
2193
2218
  }
2194
- // Determine version bump based on branch configuration
2195
- let versionCommand = 'prepatch'; // Default
2196
2219
  let versionTag = 'dev'; // Default
2197
2220
  if (branchDependentVersioning && runConfig.branches) {
2198
2221
  const sourceBranchConfig = runConfig.branches[currentBranch];
2199
2222
  if (sourceBranchConfig === null || sourceBranchConfig === void 0 ? void 0 : sourceBranchConfig.version) {
2200
2223
  // Use configured version strategy for source branch
2201
2224
  if (sourceBranchConfig.version.incrementLevel) {
2202
- versionCommand = `pre${sourceBranchConfig.version.incrementLevel}`;
2225
+ `pre${sourceBranchConfig.version.incrementLevel}`;
2203
2226
  }
2204
2227
  if (sourceBranchConfig.version.tag) {
2205
2228
  versionTag = sourceBranchConfig.version.tag;
@@ -2207,10 +2230,28 @@ const execute = async (runConfig)=>{
2207
2230
  }
2208
2231
  }
2209
2232
  // Bump to next development version
2210
- logger.info(`PUBLISH_DEV_VERSION_BUMPING: Bumping to next development version | Command: ${versionCommand} | Tag: ${versionTag} | Purpose: Prepare for next cycle`);
2233
+ // Note: We manually update package.json instead of using npm version to avoid
2234
+ // npm's automatic "git add package.json package-lock.json" which fails when
2235
+ // package-lock.json is gitignored
2236
+ logger.info(`PUBLISH_DEV_VERSION_BUMPING: Bumping to next development version | Tag: ${versionTag} | Purpose: Prepare for next cycle`);
2211
2237
  try {
2212
- const { stdout: newVersion } = await run(`npm version ${versionCommand} --preid=${versionTag}`);
2213
- logger.info(`PUBLISH_DEV_VERSION_BUMPED: Version bumped successfully | New Version: ${newVersion.trim()} | Type: development | Status: completed`);
2238
+ // Read current package.json
2239
+ const pkgJsonContents = await storage.readFile('package.json', 'utf-8');
2240
+ const pkgJson = safeJsonParse(pkgJsonContents, 'package.json');
2241
+ const validatedPkgJson = validatePackageJson(pkgJson, 'package.json');
2242
+ const currentVer = validatedPkgJson.version;
2243
+ // Import incrementPrereleaseVersion from core
2244
+ const { incrementPrereleaseVersion } = await import('@eldrforge/core');
2245
+ const newVersion = incrementPrereleaseVersion(currentVer, versionTag);
2246
+ // Update package.json with new version
2247
+ validatedPkgJson.version = newVersion;
2248
+ await storage.writeFile('package.json', JSON.stringify(validatedPkgJson, null, 2) + '\n', 'utf-8');
2249
+ logger.info(`PUBLISH_DEV_VERSION_BUMPED: Version bumped successfully | New Version: ${newVersion} | Type: development | Status: completed`);
2250
+ // Manually commit the version bump (package-lock.json is ignored)
2251
+ await runGitWithLock(process.cwd(), async ()=>{
2252
+ await run('git add package.json');
2253
+ await run(`git commit -m "chore: bump to ${newVersion}"`);
2254
+ }, 'commit dev version bump');
2214
2255
  } catch (versionError) {
2215
2256
  logger.warn(`PUBLISH_DEV_VERSION_BUMP_FAILED: Failed to bump version | Error: ${versionError.message} | Impact: Version not updated`);
2216
2257
  logger.warn('PUBLISH_MANUAL_VERSION_BUMP: Manual version bump may be needed | Action: Bump manually for next cycle | Command: npm version');