@slats/claude-assets-sync 0.0.6 → 0.1.1

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.
Files changed (69) hide show
  1. package/dist/commands/add.cjs +24 -0
  2. package/dist/commands/add.d.ts +2 -6
  3. package/dist/commands/add.mjs +24 -0
  4. package/dist/commands/index.d.ts +1 -2
  5. package/dist/commands/list.cjs +12 -1
  6. package/dist/commands/list.d.ts +10 -1
  7. package/dist/commands/list.mjs +12 -2
  8. package/dist/commands/remove.cjs +49 -31
  9. package/dist/commands/remove.mjs +49 -30
  10. package/dist/commands/types.d.ts +9 -0
  11. package/dist/commands/update.cjs +34 -3
  12. package/dist/commands/update.d.ts +16 -0
  13. package/dist/commands/update.mjs +34 -4
  14. package/dist/components/add/BulkAddView.cjs +169 -0
  15. package/dist/components/add/BulkAddView.d.ts +11 -0
  16. package/dist/components/add/BulkAddView.mjs +167 -0
  17. package/dist/components/list/ListCommand.cjs +585 -392
  18. package/dist/components/list/ListCommand.d.ts +0 -3
  19. package/dist/components/list/ListCommand.mjs +590 -377
  20. package/dist/components/list/index.d.ts +1 -0
  21. package/dist/components/list/types.d.ts +14 -0
  22. package/dist/components/remove/RemoveConfirm.cjs +18 -0
  23. package/dist/components/remove/RemoveConfirm.d.ts +11 -0
  24. package/dist/components/remove/RemoveConfirm.mjs +16 -0
  25. package/dist/components/shared/Confirm.cjs +30 -0
  26. package/dist/components/shared/Confirm.d.ts +8 -0
  27. package/dist/components/shared/Confirm.mjs +28 -0
  28. package/dist/components/shared/MenuItem.cjs +18 -0
  29. package/dist/components/shared/MenuItem.d.ts +7 -0
  30. package/dist/components/shared/MenuItem.mjs +16 -0
  31. package/dist/components/shared/ProgressBar.d.ts +7 -0
  32. package/dist/components/shared/StepRunner.cjs +58 -0
  33. package/dist/components/shared/StepRunner.d.ts +15 -0
  34. package/dist/components/shared/StepRunner.mjs +56 -0
  35. package/dist/components/shared/Table.cjs +19 -0
  36. package/dist/components/shared/Table.d.ts +8 -0
  37. package/dist/components/shared/Table.mjs +17 -0
  38. package/dist/components/shared/index.d.ts +6 -0
  39. package/dist/core/cli.cjs +4 -8
  40. package/dist/core/cli.mjs +5 -9
  41. package/dist/core/constants.cjs +2 -0
  42. package/dist/core/constants.d.ts +5 -1
  43. package/dist/core/constants.mjs +2 -1
  44. package/dist/core/io.mjs +1 -1
  45. package/dist/core/listOperations.cjs +228 -0
  46. package/dist/core/listOperations.d.ts +43 -0
  47. package/dist/core/listOperations.mjs +205 -0
  48. package/dist/core/localSource.cjs +8 -2
  49. package/dist/core/localSource.mjs +8 -2
  50. package/dist/core/packageScanner.cjs +10 -10
  51. package/dist/core/packageScanner.mjs +10 -10
  52. package/dist/core/sync.cjs +10 -16
  53. package/dist/core/sync.mjs +11 -17
  54. package/dist/core/syncMeta.cjs +7 -2
  55. package/dist/core/syncMeta.d.ts +1 -1
  56. package/dist/core/syncMeta.mjs +7 -2
  57. package/dist/utils/asyncPool.cjs +26 -0
  58. package/dist/utils/asyncPool.d.ts +5 -0
  59. package/dist/utils/asyncPool.mjs +24 -0
  60. package/dist/utils/dependencies.cjs +57 -0
  61. package/dist/utils/dependencies.d.ts +10 -0
  62. package/dist/utils/dependencies.mjs +34 -0
  63. package/dist/utils/package.cjs +5 -0
  64. package/dist/utils/package.d.ts +6 -1
  65. package/dist/utils/package.mjs +6 -2
  66. package/dist/version.cjs +1 -1
  67. package/dist/version.d.ts +1 -1
  68. package/dist/version.mjs +1 -1
  69. package/package.json +3 -2
@@ -3,10 +3,34 @@
3
3
  var ink = require('ink');
4
4
  var React = require('react');
5
5
  var AddCommand = require('../components/add/AddCommand.cjs');
6
+ var BulkAddView = require('../components/add/BulkAddView.cjs');
6
7
  var sync = require('../core/sync.cjs');
7
8
 
8
9
  async function runAddCommand(options, cwd) {
9
10
  const workingDir = process.cwd();
11
+ if (options.pattern) {
12
+ try {
13
+ new RegExp(options.pattern);
14
+ }
15
+ catch (err) {
16
+ const msg = err instanceof Error ? err.message : String(err);
17
+ throw new Error(`Invalid regex pattern "${options.pattern}": ${msg}`);
18
+ }
19
+ const { waitUntilExit } = ink.render(React.createElement(BulkAddView.BulkAddView, {
20
+ pattern: options.pattern,
21
+ cwd: workingDir,
22
+ local: options.local ?? false,
23
+ ref: options.ref,
24
+ }));
25
+ await waitUntilExit();
26
+ return;
27
+ }
28
+ if (!options.package) {
29
+ console.error('Error: either --package or --pattern must be provided');
30
+ console.error(' Usage: claude-assets-sync add -p <name>');
31
+ console.error(' claude-assets-sync add --pattern <regex>');
32
+ process.exit(1);
33
+ }
10
34
  return new Promise((resolve, reject) => {
11
35
  const { waitUntilExit } = ink.render(React.createElement(AddCommand.AddCommand, {
12
36
  packageName: options.package,
@@ -1,10 +1,6 @@
1
- export interface AddCommandOptions {
2
- package: string;
3
- local?: boolean;
4
- ref?: string;
5
- }
1
+ import type { AddCommandOptions } from '../commands/types.js';
6
2
  /**
7
- * Run the add command with interactive asset selection
3
+ * Run the add command with interactive asset selection or bulk pattern mode
8
4
  *
9
5
  * @param options - Add command options
10
6
  * @param cwd - Current working directory
@@ -1,10 +1,34 @@
1
1
  import { render } from 'ink';
2
2
  import React from 'react';
3
3
  import { AddCommand } from '../components/add/AddCommand.mjs';
4
+ import { BulkAddView } from '../components/add/BulkAddView.mjs';
4
5
  import { syncPackage } from '../core/sync.mjs';
5
6
 
6
7
  async function runAddCommand(options, cwd) {
7
8
  const workingDir = process.cwd();
9
+ if (options.pattern) {
10
+ try {
11
+ new RegExp(options.pattern);
12
+ }
13
+ catch (err) {
14
+ const msg = err instanceof Error ? err.message : String(err);
15
+ throw new Error(`Invalid regex pattern "${options.pattern}": ${msg}`);
16
+ }
17
+ const { waitUntilExit } = render(React.createElement(BulkAddView, {
18
+ pattern: options.pattern,
19
+ cwd: workingDir,
20
+ local: options.local ?? false,
21
+ ref: options.ref,
22
+ }));
23
+ await waitUntilExit();
24
+ return;
25
+ }
26
+ if (!options.package) {
27
+ console.error('Error: either --package or --pattern must be provided');
28
+ console.error(' Usage: claude-assets-sync add -p <name>');
29
+ console.error(' claude-assets-sync add --pattern <regex>');
30
+ process.exit(1);
31
+ }
8
32
  return new Promise((resolve, reject) => {
9
33
  const { waitUntilExit } = render(React.createElement(AddCommand, {
10
34
  packageName: options.package,
@@ -3,13 +3,12 @@
3
3
  */
4
4
  export * from './types';
5
5
  export { runSyncCommand } from './sync';
6
- export { runListCommand } from './list';
6
+ export { runListCommand, registerListCommand } from './list';
7
7
  export { runRemoveCommand } from './remove';
8
8
  export { runStatusCommand } from './status';
9
9
  export { runMigrateCommand } from './migrate';
10
10
  export { runAddCommand } from './add';
11
11
  export { runUpdateCommand } from './update';
12
- export type { AddCommandOptions } from './add';
13
12
  export type { UpdateCommandOptions } from './update';
14
13
  /**
15
14
  * Command metadata for CLI help and documentation
@@ -46,7 +46,8 @@ const runListCommand = async (options, cwd = process.cwd()) => {
46
46
  return;
47
47
  }
48
48
  if (isTTY()) {
49
- ink.render(React.createElement(ListCommand.ListCommand, { cwd: destDir }));
49
+ const { waitUntilExit } = ink.render(React.createElement(ListCommand.ListCommand, { cwd: destDir }));
50
+ await waitUntilExit();
50
51
  return;
51
52
  }
52
53
  const packages = [];
@@ -79,5 +80,15 @@ const runListCommand = async (options, cwd = process.cwd()) => {
79
80
  console.log('');
80
81
  }
81
82
  };
83
+ function registerListCommand(program) {
84
+ program
85
+ .command('list')
86
+ .description('List all synced packages')
87
+ .option('--json', 'Output as JSON')
88
+ .action(async (opts) => {
89
+ await runListCommand({ json: opts.json });
90
+ });
91
+ }
82
92
 
93
+ exports.registerListCommand = registerListCommand;
83
94
  exports.runListCommand = runListCommand;
@@ -1,6 +1,15 @@
1
+ /**
2
+ * List command - list all synced packages
3
+ */
4
+ import type { Command } from 'commander';
1
5
  import type { ListCommandOptions } from './types.js';
2
6
  /**
3
7
  * Run the list command
4
8
  * @param options - List command options
5
9
  */
6
- export declare const runListCommand: (options: ListCommandOptions, cwd?: string) => Promise<void>;
10
+ declare const runListCommand: (options: ListCommandOptions, cwd?: string) => Promise<void>;
11
+ /**
12
+ * Register the list command with the CLI program
13
+ */
14
+ export declare function registerListCommand(program: Command): void;
15
+ export { runListCommand };
@@ -44,7 +44,8 @@ const runListCommand = async (options, cwd = process.cwd()) => {
44
44
  return;
45
45
  }
46
46
  if (isTTY()) {
47
- render(React.createElement(ListCommand, { cwd: destDir }));
47
+ const { waitUntilExit } = render(React.createElement(ListCommand, { cwd: destDir }));
48
+ await waitUntilExit();
48
49
  return;
49
50
  }
50
51
  const packages = [];
@@ -77,5 +78,14 @@ const runListCommand = async (options, cwd = process.cwd()) => {
77
78
  console.log('');
78
79
  }
79
80
  };
81
+ function registerListCommand(program) {
82
+ program
83
+ .command('list')
84
+ .description('List all synced packages')
85
+ .option('--json', 'Output as JSON')
86
+ .action(async (opts) => {
87
+ await runListCommand({ json: opts.json });
88
+ });
89
+ }
80
90
 
81
- export { runListCommand };
91
+ export { registerListCommand, runListCommand };
@@ -2,8 +2,10 @@
2
2
 
3
3
  var fs = require('node:fs');
4
4
  var path = require('node:path');
5
- var readline = require('node:readline/promises');
5
+ var ink = require('ink');
6
6
  var pc = require('picocolors');
7
+ var React = require('react');
8
+ var RemoveConfirm = require('../components/remove/RemoveConfirm.cjs');
7
9
  var syncMeta = require('../core/syncMeta.cjs');
8
10
  var logger = require('../utils/logger.cjs');
9
11
  var packageName = require('../utils/packageName.cjs');
@@ -27,8 +29,36 @@ function _interopNamespaceDefault(e) {
27
29
 
28
30
  var fs__namespace = /*#__PURE__*/_interopNamespaceDefault(fs);
29
31
  var path__namespace = /*#__PURE__*/_interopNamespaceDefault(path);
30
- var readline__namespace = /*#__PURE__*/_interopNamespaceDefault(readline);
31
32
 
33
+ function isTTY() {
34
+ return process.stdout.isTTY === true && process.stdin.isTTY === true;
35
+ }
36
+ function performRemoval(filesToRemove, meta, prefix, packageName, cwd) {
37
+ for (const { path: filePath } of filesToRemove) {
38
+ try {
39
+ const stat = fs__namespace.statSync(filePath);
40
+ if (stat.isDirectory()) {
41
+ fs__namespace.rmSync(filePath, { recursive: true, force: true });
42
+ console.log(`${pc.red('-')} ${filePath}`);
43
+ }
44
+ else {
45
+ fs__namespace.unlinkSync(filePath);
46
+ console.log(`${pc.red('-')} ${filePath}`);
47
+ }
48
+ }
49
+ catch (error) {
50
+ if (error.code !== 'ENOENT') {
51
+ logger.logger.error(`Failed to remove ${filePath}: ${error}`);
52
+ }
53
+ }
54
+ }
55
+ if (meta) {
56
+ delete meta.packages[prefix];
57
+ meta.syncedAt = new Date().toISOString();
58
+ syncMeta.writeUnifiedSyncMeta(cwd, meta);
59
+ }
60
+ logger.logger.success(`\nRemoved package ${packageName}`);
61
+ }
32
62
  const runRemoveCommand = async (options, cwd = process.cwd()) => {
33
63
  const { package: packageName$1, yes, dryRun } = options;
34
64
  const prefix = packageName.packageNameToPrefix(packageName$1);
@@ -71,39 +101,27 @@ const runRemoveCommand = async (options, cwd = process.cwd()) => {
71
101
  return;
72
102
  }
73
103
  if (!yes) {
74
- const rl = readline__namespace.createInterface({
75
- input: process.stdin,
76
- output: process.stdout,
77
- });
78
- const answer = await rl.question(pc.yellow('Remove these files? (y/N): '));
79
- rl.close();
80
- if (answer.toLowerCase() !== 'y') {
81
- logger.logger.info('Cancelled.');
82
- return;
83
- }
84
- }
85
- for (const { path: filePath } of filesToRemove) {
86
- try {
87
- const stat = fs__namespace.statSync(filePath);
88
- if (stat.isDirectory()) {
89
- fs__namespace.rmSync(filePath, { recursive: true, force: true });
90
- console.log(`${pc.red('-')} ${filePath}`);
91
- }
92
- else {
93
- fs__namespace.unlinkSync(filePath);
94
- console.log(`${pc.red('-')} ${filePath}`);
104
+ if (isTTY()) {
105
+ let confirmed = false;
106
+ const { waitUntilExit } = ink.render(React.createElement(RemoveConfirm.RemoveConfirm, {
107
+ packageName: packageName$1,
108
+ filesToRemove,
109
+ onConfirm: (result) => {
110
+ confirmed = result;
111
+ },
112
+ }));
113
+ await waitUntilExit();
114
+ if (!confirmed) {
115
+ logger.logger.info('Cancelled.');
116
+ return;
95
117
  }
96
118
  }
97
- catch (error) {
98
- if (error.code !== 'ENOENT') {
99
- logger.logger.error(`Failed to remove ${filePath}: ${error}`);
100
- }
119
+ else {
120
+ logger.logger.info('Cancelled (non-interactive terminal).');
121
+ return;
101
122
  }
102
123
  }
103
- delete meta.packages[prefix];
104
- meta.syncedAt = new Date().toISOString();
105
- syncMeta.writeUnifiedSyncMeta(cwd, meta);
106
- logger.logger.success(`\nRemoved package ${packageName$1}`);
124
+ performRemoval(filesToRemove, meta, prefix, packageName$1, cwd);
107
125
  };
108
126
 
109
127
  exports.runRemoveCommand = runRemoveCommand;
@@ -1,11 +1,42 @@
1
1
  import * as fs from 'node:fs';
2
2
  import * as path from 'node:path';
3
- import * as readline from 'node:readline/promises';
3
+ import { render } from 'ink';
4
4
  import pc from 'picocolors';
5
+ import React from 'react';
6
+ import { RemoveConfirm } from '../components/remove/RemoveConfirm.mjs';
5
7
  import { readUnifiedSyncMeta, writeUnifiedSyncMeta } from '../core/syncMeta.mjs';
6
8
  import { logger } from '../utils/logger.mjs';
7
9
  import { packageNameToPrefix } from '../utils/packageName.mjs';
8
10
 
11
+ function isTTY() {
12
+ return process.stdout.isTTY === true && process.stdin.isTTY === true;
13
+ }
14
+ function performRemoval(filesToRemove, meta, prefix, packageName, cwd) {
15
+ for (const { path: filePath } of filesToRemove) {
16
+ try {
17
+ const stat = fs.statSync(filePath);
18
+ if (stat.isDirectory()) {
19
+ fs.rmSync(filePath, { recursive: true, force: true });
20
+ console.log(`${pc.red('-')} ${filePath}`);
21
+ }
22
+ else {
23
+ fs.unlinkSync(filePath);
24
+ console.log(`${pc.red('-')} ${filePath}`);
25
+ }
26
+ }
27
+ catch (error) {
28
+ if (error.code !== 'ENOENT') {
29
+ logger.error(`Failed to remove ${filePath}: ${error}`);
30
+ }
31
+ }
32
+ }
33
+ if (meta) {
34
+ delete meta.packages[prefix];
35
+ meta.syncedAt = new Date().toISOString();
36
+ writeUnifiedSyncMeta(cwd, meta);
37
+ }
38
+ logger.success(`\nRemoved package ${packageName}`);
39
+ }
9
40
  const runRemoveCommand = async (options, cwd = process.cwd()) => {
10
41
  const { package: packageName, yes, dryRun } = options;
11
42
  const prefix = packageNameToPrefix(packageName);
@@ -48,39 +79,27 @@ const runRemoveCommand = async (options, cwd = process.cwd()) => {
48
79
  return;
49
80
  }
50
81
  if (!yes) {
51
- const rl = readline.createInterface({
52
- input: process.stdin,
53
- output: process.stdout,
54
- });
55
- const answer = await rl.question(pc.yellow('Remove these files? (y/N): '));
56
- rl.close();
57
- if (answer.toLowerCase() !== 'y') {
58
- logger.info('Cancelled.');
59
- return;
60
- }
61
- }
62
- for (const { path: filePath } of filesToRemove) {
63
- try {
64
- const stat = fs.statSync(filePath);
65
- if (stat.isDirectory()) {
66
- fs.rmSync(filePath, { recursive: true, force: true });
67
- console.log(`${pc.red('-')} ${filePath}`);
68
- }
69
- else {
70
- fs.unlinkSync(filePath);
71
- console.log(`${pc.red('-')} ${filePath}`);
82
+ if (isTTY()) {
83
+ let confirmed = false;
84
+ const { waitUntilExit } = render(React.createElement(RemoveConfirm, {
85
+ packageName,
86
+ filesToRemove,
87
+ onConfirm: (result) => {
88
+ confirmed = result;
89
+ },
90
+ }));
91
+ await waitUntilExit();
92
+ if (!confirmed) {
93
+ logger.info('Cancelled.');
94
+ return;
72
95
  }
73
96
  }
74
- catch (error) {
75
- if (error.code !== 'ENOENT') {
76
- logger.error(`Failed to remove ${filePath}: ${error}`);
77
- }
97
+ else {
98
+ logger.info('Cancelled (non-interactive terminal).');
99
+ return;
78
100
  }
79
101
  }
80
- delete meta.packages[prefix];
81
- meta.syncedAt = new Date().toISOString();
82
- writeUnifiedSyncMeta(cwd, meta);
83
- logger.success(`\nRemoved package ${packageName}`);
102
+ performRemoval(filesToRemove, meta, prefix, packageName, cwd);
84
103
  };
85
104
 
86
105
  export { runRemoveCommand };
@@ -9,6 +9,15 @@ export interface CommandResult {
9
9
  success: boolean;
10
10
  message?: string;
11
11
  }
12
+ /**
13
+ * Options for add command
14
+ */
15
+ export interface AddCommandOptions {
16
+ package?: string;
17
+ pattern?: string;
18
+ local?: boolean;
19
+ ref?: string;
20
+ }
12
21
  /**
13
22
  * Options for sync command
14
23
  */
@@ -1,14 +1,40 @@
1
1
  'use strict';
2
2
 
3
3
  var pc = require('picocolors');
4
+ var constants = require('../core/constants.cjs');
4
5
  var packageScanner = require('../core/packageScanner.cjs');
5
6
  var sync = require('../core/sync.cjs');
6
7
  var syncMeta = require('../core/syncMeta.cjs');
7
- var constants = require('../core/constants.cjs');
8
8
  var logger = require('../utils/logger.cjs');
9
9
  var _package = require('../utils/package.cjs');
10
10
  var packageName = require('../utils/packageName.cjs');
11
11
 
12
+ async function updatePackageVersionAndSync(prefix, meta, options, cwd) {
13
+ const packageInfo = meta.packages[prefix];
14
+ if (!packageInfo) {
15
+ throw new Error(`Package ${prefix} not found in metadata`);
16
+ }
17
+ const packageName = packageInfo.originalName;
18
+ const isLocal = options.local ?? packageInfo.local ?? false;
19
+ const currentPkgInfo = isLocal
20
+ ? _package.readLocalPackageJson(packageName, cwd)
21
+ : _package.readPackageJson(packageName, cwd);
22
+ if (!currentPkgInfo) {
23
+ return { updatedMeta: meta, versionChanged: false };
24
+ }
25
+ const newVersion = currentPkgInfo.version;
26
+ const oldVersion = packageInfo.version;
27
+ if (newVersion === oldVersion) {
28
+ return { updatedMeta: meta, versionChanged: false, oldVersion, newVersion };
29
+ }
30
+ let updatedMeta = syncMeta.updatePackageVersion(meta, prefix, newVersion);
31
+ updatedMeta.syncedAt = new Date().toISOString();
32
+ {
33
+ const destDir = _package.findGitRoot(cwd) ?? cwd;
34
+ await sync.syncPackage(packageName, { force: true, dryRun: false, local: isLocal, ref: options.ref, flat: true }, cwd, packageInfo.exclusions, destDir);
35
+ }
36
+ return { updatedMeta, versionChanged: true, oldVersion, newVersion };
37
+ }
12
38
  const runUpdateCommand = async (options, cwd = process.cwd()) => {
13
39
  const destDir = _package.findGitRoot(cwd) ?? cwd;
14
40
  const meta = syncMeta.readUnifiedSyncMeta(destDir);
@@ -113,8 +139,12 @@ const runUpdateCommand = async (options, cwd = process.cwd()) => {
113
139
  const refreshedUnits = currentUnits.map((current) => {
114
140
  const scanned = scannedUnits.find((s) => s.name === current.name);
115
141
  if (scanned && scanned.isDirectory && current.isDirectory) {
116
- const currentInternal = (current.internalFiles || []).sort().join(',');
117
- const scannedInternal = (scanned.internalFiles || []).sort().join(',');
142
+ const currentInternal = (current.internalFiles || [])
143
+ .sort()
144
+ .join(',');
145
+ const scannedInternal = (scanned.internalFiles || [])
146
+ .sort()
147
+ .join(',');
118
148
  if (currentInternal !== scannedInternal) {
119
149
  internalChanged = true;
120
150
  return { ...current, internalFiles: scanned.internalFiles };
@@ -176,3 +206,4 @@ const runUpdateCommand = async (options, cwd = process.cwd()) => {
176
206
  };
177
207
 
178
208
  exports.runUpdateCommand = runUpdateCommand;
209
+ exports.updatePackageVersionAndSync = updatePackageVersionAndSync;
@@ -1,3 +1,4 @@
1
+ import type { UnifiedSyncMeta } from '../utils/types';
1
2
  export interface UpdateCommandOptions {
2
3
  package?: string;
3
4
  local?: boolean;
@@ -5,6 +6,21 @@ export interface UpdateCommandOptions {
5
6
  dryRun?: boolean;
6
7
  sync?: boolean;
7
8
  }
9
+ export interface UpdatePackageResult {
10
+ updatedMeta: UnifiedSyncMeta;
11
+ versionChanged: boolean;
12
+ oldVersion?: string;
13
+ newVersion?: string;
14
+ }
15
+ /**
16
+ * Higher-level orchestration: read installed version, compare with meta, update if different,
17
+ * optionally re-sync files. Can be called from both CLI and interactive list UI.
18
+ */
19
+ export declare function updatePackageVersionAndSync(prefix: string, meta: UnifiedSyncMeta, options: {
20
+ local?: boolean;
21
+ ref?: string;
22
+ sync?: boolean;
23
+ }, cwd: string): Promise<UpdatePackageResult>;
8
24
  /**
9
25
  * Run the update command
10
26
  * @param options - Update command options
@@ -1,12 +1,38 @@
1
1
  import pc from 'picocolors';
2
+ import { SCHEMA_VERSIONS } from '../core/constants.mjs';
2
3
  import { scanPackageAssets, buildSkillUnitsFromTree } from '../core/packageScanner.mjs';
3
4
  import { syncPackage } from '../core/sync.mjs';
4
5
  import { readUnifiedSyncMeta, updatePackageVersion, updatePackageFilesystemMeta, writeUnifiedSyncMeta } from '../core/syncMeta.mjs';
5
- import { SCHEMA_VERSIONS } from '../core/constants.mjs';
6
6
  import { logger } from '../utils/logger.mjs';
7
7
  import { findGitRoot, readLocalPackageJson, readPackageJson } from '../utils/package.mjs';
8
8
  import { packageNameToPrefix } from '../utils/packageName.mjs';
9
9
 
10
+ async function updatePackageVersionAndSync(prefix, meta, options, cwd) {
11
+ const packageInfo = meta.packages[prefix];
12
+ if (!packageInfo) {
13
+ throw new Error(`Package ${prefix} not found in metadata`);
14
+ }
15
+ const packageName = packageInfo.originalName;
16
+ const isLocal = options.local ?? packageInfo.local ?? false;
17
+ const currentPkgInfo = isLocal
18
+ ? readLocalPackageJson(packageName, cwd)
19
+ : readPackageJson(packageName, cwd);
20
+ if (!currentPkgInfo) {
21
+ return { updatedMeta: meta, versionChanged: false };
22
+ }
23
+ const newVersion = currentPkgInfo.version;
24
+ const oldVersion = packageInfo.version;
25
+ if (newVersion === oldVersion) {
26
+ return { updatedMeta: meta, versionChanged: false, oldVersion, newVersion };
27
+ }
28
+ let updatedMeta = updatePackageVersion(meta, prefix, newVersion);
29
+ updatedMeta.syncedAt = new Date().toISOString();
30
+ {
31
+ const destDir = findGitRoot(cwd) ?? cwd;
32
+ await syncPackage(packageName, { force: true, dryRun: false, local: isLocal, ref: options.ref, flat: true }, cwd, packageInfo.exclusions, destDir);
33
+ }
34
+ return { updatedMeta, versionChanged: true, oldVersion, newVersion };
35
+ }
10
36
  const runUpdateCommand = async (options, cwd = process.cwd()) => {
11
37
  const destDir = findGitRoot(cwd) ?? cwd;
12
38
  const meta = readUnifiedSyncMeta(destDir);
@@ -111,8 +137,12 @@ const runUpdateCommand = async (options, cwd = process.cwd()) => {
111
137
  const refreshedUnits = currentUnits.map((current) => {
112
138
  const scanned = scannedUnits.find((s) => s.name === current.name);
113
139
  if (scanned && scanned.isDirectory && current.isDirectory) {
114
- const currentInternal = (current.internalFiles || []).sort().join(',');
115
- const scannedInternal = (scanned.internalFiles || []).sort().join(',');
140
+ const currentInternal = (current.internalFiles || [])
141
+ .sort()
142
+ .join(',');
143
+ const scannedInternal = (scanned.internalFiles || [])
144
+ .sort()
145
+ .join(',');
116
146
  if (currentInternal !== scannedInternal) {
117
147
  internalChanged = true;
118
148
  return { ...current, internalFiles: scanned.internalFiles };
@@ -173,4 +203,4 @@ const runUpdateCommand = async (options, cwd = process.cwd()) => {
173
203
  }
174
204
  };
175
205
 
176
- export { runUpdateCommand };
206
+ export { runUpdateCommand, updatePackageVersionAndSync };