@slats/claude-assets-sync 0.1.0 → 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.
- package/dist/commands/add.cjs +24 -0
- package/dist/commands/add.d.ts +2 -6
- package/dist/commands/add.mjs +24 -0
- package/dist/commands/index.d.ts +1 -2
- package/dist/commands/list.cjs +12 -1
- package/dist/commands/list.d.ts +10 -1
- package/dist/commands/list.mjs +12 -2
- package/dist/commands/remove.cjs +49 -31
- package/dist/commands/remove.mjs +49 -30
- package/dist/commands/types.d.ts +9 -0
- package/dist/commands/update.cjs +27 -0
- package/dist/commands/update.d.ts +16 -0
- package/dist/commands/update.mjs +27 -1
- package/dist/components/add/BulkAddView.cjs +169 -0
- package/dist/components/add/BulkAddView.d.ts +11 -0
- package/dist/components/add/BulkAddView.mjs +167 -0
- package/dist/components/list/ListCommand.cjs +585 -392
- package/dist/components/list/ListCommand.d.ts +0 -3
- package/dist/components/list/ListCommand.mjs +590 -377
- package/dist/components/list/index.d.ts +1 -0
- package/dist/components/list/types.d.ts +14 -0
- package/dist/components/remove/RemoveConfirm.cjs +18 -0
- package/dist/components/remove/RemoveConfirm.d.ts +11 -0
- package/dist/components/remove/RemoveConfirm.mjs +16 -0
- package/dist/components/shared/Confirm.cjs +30 -0
- package/dist/components/shared/Confirm.d.ts +8 -0
- package/dist/components/shared/Confirm.mjs +28 -0
- package/dist/components/shared/MenuItem.cjs +18 -0
- package/dist/components/shared/MenuItem.d.ts +7 -0
- package/dist/components/shared/MenuItem.mjs +16 -0
- package/dist/components/shared/ProgressBar.d.ts +7 -0
- package/dist/components/shared/StepRunner.cjs +58 -0
- package/dist/components/shared/StepRunner.d.ts +15 -0
- package/dist/components/shared/StepRunner.mjs +56 -0
- package/dist/components/shared/Table.cjs +19 -0
- package/dist/components/shared/Table.d.ts +8 -0
- package/dist/components/shared/Table.mjs +17 -0
- package/dist/components/shared/index.d.ts +6 -0
- package/dist/core/cli.cjs +4 -8
- package/dist/core/cli.mjs +5 -9
- package/dist/core/constants.cjs +2 -0
- package/dist/core/constants.d.ts +4 -0
- package/dist/core/constants.mjs +2 -1
- package/dist/core/io.mjs +1 -1
- package/dist/core/listOperations.cjs +228 -0
- package/dist/core/listOperations.d.ts +43 -0
- package/dist/core/listOperations.mjs +205 -0
- package/dist/core/packageScanner.cjs +8 -6
- package/dist/core/packageScanner.mjs +9 -7
- package/dist/core/sync.cjs +9 -15
- package/dist/core/sync.mjs +10 -16
- package/dist/utils/asyncPool.cjs +26 -0
- package/dist/utils/asyncPool.d.ts +5 -0
- package/dist/utils/asyncPool.mjs +24 -0
- package/dist/utils/dependencies.cjs +57 -0
- package/dist/utils/dependencies.d.ts +10 -0
- package/dist/utils/dependencies.mjs +34 -0
- package/dist/utils/package.cjs +5 -0
- package/dist/utils/package.d.ts +6 -1
- package/dist/utils/package.mjs +6 -2
- package/package.json +2 -1
package/dist/commands/add.cjs
CHANGED
|
@@ -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,
|
package/dist/commands/add.d.ts
CHANGED
|
@@ -1,10 +1,6 @@
|
|
|
1
|
-
|
|
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
|
package/dist/commands/add.mjs
CHANGED
|
@@ -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,
|
package/dist/commands/index.d.ts
CHANGED
|
@@ -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
|
package/dist/commands/list.cjs
CHANGED
|
@@ -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;
|
package/dist/commands/list.d.ts
CHANGED
|
@@ -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
|
-
|
|
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 };
|
package/dist/commands/list.mjs
CHANGED
|
@@ -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 };
|
package/dist/commands/remove.cjs
CHANGED
|
@@ -2,8 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
var fs = require('node:fs');
|
|
4
4
|
var path = require('node:path');
|
|
5
|
-
var
|
|
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
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
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
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
}
|
|
119
|
+
else {
|
|
120
|
+
logger.logger.info('Cancelled (non-interactive terminal).');
|
|
121
|
+
return;
|
|
101
122
|
}
|
|
102
123
|
}
|
|
103
|
-
|
|
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;
|
package/dist/commands/remove.mjs
CHANGED
|
@@ -1,11 +1,42 @@
|
|
|
1
1
|
import * as fs from 'node:fs';
|
|
2
2
|
import * as path from 'node:path';
|
|
3
|
-
import
|
|
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
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
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
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
}
|
|
97
|
+
else {
|
|
98
|
+
logger.info('Cancelled (non-interactive terminal).');
|
|
99
|
+
return;
|
|
78
100
|
}
|
|
79
101
|
}
|
|
80
|
-
|
|
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 };
|
package/dist/commands/types.d.ts
CHANGED
|
@@ -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
|
*/
|
package/dist/commands/update.cjs
CHANGED
|
@@ -9,6 +9,32 @@ 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);
|
|
@@ -180,3 +206,4 @@ const runUpdateCommand = async (options, cwd = process.cwd()) => {
|
|
|
180
206
|
};
|
|
181
207
|
|
|
182
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
|
package/dist/commands/update.mjs
CHANGED
|
@@ -7,6 +7,32 @@ 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);
|
|
@@ -177,4 +203,4 @@ const runUpdateCommand = async (options, cwd = process.cwd()) => {
|
|
|
177
203
|
}
|
|
178
204
|
};
|
|
179
205
|
|
|
180
|
-
export { runUpdateCommand };
|
|
206
|
+
export { runUpdateCommand, updatePackageVersionAndSync };
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
4
|
+
var ink = require('ink');
|
|
5
|
+
var Spinner = require('ink-spinner');
|
|
6
|
+
var React = require('react');
|
|
7
|
+
var packageScanner = require('../../core/packageScanner.cjs');
|
|
8
|
+
var sync = require('../../core/sync.cjs');
|
|
9
|
+
var asyncPool = require('../../utils/asyncPool.cjs');
|
|
10
|
+
var dependencies = require('../../utils/dependencies.cjs');
|
|
11
|
+
var StepRunner = require('../shared/StepRunner.cjs');
|
|
12
|
+
var Table = require('../shared/Table.cjs');
|
|
13
|
+
|
|
14
|
+
const BulkAddView = ({ pattern, cwd, local = false, ref, }) => {
|
|
15
|
+
const [phase, setPhase] = React.useState('scanning-deps');
|
|
16
|
+
const [matches, setMatches] = React.useState([]);
|
|
17
|
+
const [scanSteps, setScanSteps] = React.useState([]);
|
|
18
|
+
const [syncSteps, setSyncSteps] = React.useState([]);
|
|
19
|
+
const [results, setResults] = React.useState([]);
|
|
20
|
+
const [errorMessage, setErrorMessage] = React.useState('');
|
|
21
|
+
React.useEffect(() => {
|
|
22
|
+
const run = async () => {
|
|
23
|
+
setPhase('scanning-deps');
|
|
24
|
+
let matched;
|
|
25
|
+
try {
|
|
26
|
+
const deps = dependencies.readProjectDependencies(cwd);
|
|
27
|
+
matched = dependencies.filterByPattern(deps, pattern);
|
|
28
|
+
}
|
|
29
|
+
catch (err) {
|
|
30
|
+
setErrorMessage(err instanceof Error ? err.message : String(err));
|
|
31
|
+
setPhase('error');
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
setMatches(matched);
|
|
35
|
+
if (matched.length === 0) {
|
|
36
|
+
setResults([]);
|
|
37
|
+
setPhase('done');
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
setPhase('scanning-assets');
|
|
41
|
+
const initialScanSteps = matched.map((name) => ({
|
|
42
|
+
name,
|
|
43
|
+
status: 'pending',
|
|
44
|
+
}));
|
|
45
|
+
setScanSteps(initialScanSteps);
|
|
46
|
+
const packagesWithAssets = [];
|
|
47
|
+
const scanResults = [];
|
|
48
|
+
await asyncPool.asyncPool(3, matched, async (pkgName) => {
|
|
49
|
+
setScanSteps((prev) => prev.map((s) => s.name === pkgName ? { ...s, status: 'running' } : s));
|
|
50
|
+
try {
|
|
51
|
+
const trees = await packageScanner.scanPackageAssets(pkgName, {
|
|
52
|
+
local,
|
|
53
|
+
ref,
|
|
54
|
+
cwd,
|
|
55
|
+
});
|
|
56
|
+
const hasAssets = trees.length > 0;
|
|
57
|
+
if (hasAssets) {
|
|
58
|
+
packagesWithAssets.push(pkgName);
|
|
59
|
+
setScanSteps((prev) => prev.map((s) => s.name === pkgName
|
|
60
|
+
? { ...s, status: 'success', output: `${trees.length} asset type(s)` }
|
|
61
|
+
: s));
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
scanResults.push({ name: pkgName, status: 'skipped', assetCount: 0 });
|
|
65
|
+
setScanSteps((prev) => prev.map((s) => s.name === pkgName ? { ...s, status: 'skipped' } : s));
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
catch (err) {
|
|
69
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
70
|
+
const isNoAssets = /no repository|asset path.*does not exist|not found in (local workspace|node_modules)/i.test(msg);
|
|
71
|
+
if (isNoAssets) {
|
|
72
|
+
scanResults.push({ name: pkgName, status: 'skipped', assetCount: 0 });
|
|
73
|
+
setScanSteps((prev) => prev.map((s) => s.name === pkgName ? { ...s, status: 'skipped' } : s));
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
scanResults.push({ name: pkgName, status: 'error', assetCount: 0, error: msg });
|
|
77
|
+
setScanSteps((prev) => prev.map((s) => s.name === pkgName
|
|
78
|
+
? { ...s, status: 'failed', error: msg }
|
|
79
|
+
: s));
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
if (packagesWithAssets.length === 0) {
|
|
84
|
+
setResults(scanResults);
|
|
85
|
+
setPhase('done');
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
setPhase('syncing');
|
|
89
|
+
const initialSyncSteps = packagesWithAssets.map((name) => ({
|
|
90
|
+
name,
|
|
91
|
+
status: 'pending',
|
|
92
|
+
}));
|
|
93
|
+
setSyncSteps(initialSyncSteps);
|
|
94
|
+
await asyncPool.asyncPool(3, packagesWithAssets, async (pkgName) => {
|
|
95
|
+
setSyncSteps((prev) => prev.map((s) => s.name === pkgName ? { ...s, status: 'running' } : s));
|
|
96
|
+
try {
|
|
97
|
+
const result = await sync.syncPackage(pkgName, {
|
|
98
|
+
force: true,
|
|
99
|
+
dryRun: false,
|
|
100
|
+
local,
|
|
101
|
+
ref,
|
|
102
|
+
flat: true,
|
|
103
|
+
}, cwd, undefined, undefined);
|
|
104
|
+
if (result.success && !result.skipped) {
|
|
105
|
+
const assetCount = Object.values(result.syncedFiles ?? {}).reduce((sum, files) => sum + files.length, 0);
|
|
106
|
+
scanResults.push({ name: pkgName, status: 'synced', assetCount });
|
|
107
|
+
setSyncSteps((prev) => prev.map((s) => s.name === pkgName
|
|
108
|
+
? { ...s, status: 'success', output: `${assetCount} file(s)` }
|
|
109
|
+
: s));
|
|
110
|
+
}
|
|
111
|
+
else if (result.skipped) {
|
|
112
|
+
scanResults.push({ name: pkgName, status: 'skipped', assetCount: 0 });
|
|
113
|
+
setSyncSteps((prev) => prev.map((s) => s.name === pkgName ? { ...s, status: 'skipped' } : s));
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
const msg = result.reason ?? 'Sync failed';
|
|
117
|
+
scanResults.push({ name: pkgName, status: 'error', assetCount: 0, error: msg });
|
|
118
|
+
setSyncSteps((prev) => prev.map((s) => s.name === pkgName
|
|
119
|
+
? { ...s, status: 'failed', error: msg }
|
|
120
|
+
: s));
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
catch (err) {
|
|
124
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
125
|
+
scanResults.push({ name: pkgName, status: 'error', assetCount: 0, error: msg });
|
|
126
|
+
setSyncSteps((prev) => prev.map((s) => s.name === pkgName
|
|
127
|
+
? { ...s, status: 'failed', error: msg }
|
|
128
|
+
: s));
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
setResults(scanResults);
|
|
132
|
+
setPhase('done');
|
|
133
|
+
};
|
|
134
|
+
run();
|
|
135
|
+
}, []);
|
|
136
|
+
if (phase === 'scanning-deps') {
|
|
137
|
+
return (jsxRuntime.jsx(ink.Box, { children: jsxRuntime.jsxs(ink.Text, { color: "cyan", children: [jsxRuntime.jsx(Spinner, { type: "dots" }), " Scanning dependencies matching /", pattern, "/..."] }) }));
|
|
138
|
+
}
|
|
139
|
+
if (phase === 'error') {
|
|
140
|
+
return (jsxRuntime.jsx(ink.Box, { flexDirection: "column", children: jsxRuntime.jsxs(ink.Text, { color: "red", children: ["Error: ", errorMessage] }) }));
|
|
141
|
+
}
|
|
142
|
+
if (phase === 'scanning-assets') {
|
|
143
|
+
return (jsxRuntime.jsxs(ink.Box, { flexDirection: "column", children: [jsxRuntime.jsx(ink.Box, { marginBottom: 1, children: jsxRuntime.jsxs(ink.Text, { children: ["Found ", jsxRuntime.jsx(ink.Text, { bold: true, children: matches.length }), " matching package(s). Scanning assets..."] }) }), jsxRuntime.jsx(StepRunner.StepRunner, { steps: scanSteps, currentStep: scanSteps.findIndex((s) => s.status === 'running'), total: scanSteps.length })] }));
|
|
144
|
+
}
|
|
145
|
+
if (phase === 'syncing') {
|
|
146
|
+
return (jsxRuntime.jsxs(ink.Box, { flexDirection: "column", children: [jsxRuntime.jsx(ink.Box, { marginBottom: 1, children: jsxRuntime.jsx(ink.Text, { children: "Syncing packages..." }) }), jsxRuntime.jsx(StepRunner.StepRunner, { steps: syncSteps, currentStep: syncSteps.findIndex((s) => s.status === 'running'), total: syncSteps.length })] }));
|
|
147
|
+
}
|
|
148
|
+
if (phase === 'done') {
|
|
149
|
+
const synced = results.filter((r) => r.status === 'synced').length;
|
|
150
|
+
const skipped = results.filter((r) => r.status === 'skipped').length;
|
|
151
|
+
const errors = results.filter((r) => r.status === 'error').length;
|
|
152
|
+
if (results.length === 0) {
|
|
153
|
+
return (jsxRuntime.jsx(ink.Box, { flexDirection: "column", children: jsxRuntime.jsxs(ink.Text, { color: "yellow", children: ["No packages matched pattern /", pattern, "/"] }) }));
|
|
154
|
+
}
|
|
155
|
+
const rows = results.map((r) => {
|
|
156
|
+
const statusCell = r.status === 'synced'
|
|
157
|
+
? '✓ synced'
|
|
158
|
+
: r.status === 'skipped'
|
|
159
|
+
? '⏭ skipped'
|
|
160
|
+
: `✗ error`;
|
|
161
|
+
const assetsCell = r.status === 'synced' ? String(r.assetCount) : r.error ?? '-';
|
|
162
|
+
return [r.name, statusCell, assetsCell];
|
|
163
|
+
});
|
|
164
|
+
return (jsxRuntime.jsxs(ink.Box, { flexDirection: "column", children: [jsxRuntime.jsx(Table.Table, { headers: ['Package', 'Status', 'Assets'], rows: rows }), jsxRuntime.jsx(ink.Box, { marginTop: 1, children: jsxRuntime.jsxs(ink.Text, { children: [jsxRuntime.jsxs(ink.Text, { color: "green", children: [synced, " synced"] }), jsxRuntime.jsx(ink.Text, { children: ", " }), jsxRuntime.jsxs(ink.Text, { color: "blue", children: [skipped, " skipped"] }), jsxRuntime.jsx(ink.Text, { children: ", " }), jsxRuntime.jsxs(ink.Text, { color: errors > 0 ? 'red' : 'gray', children: [errors, " errors"] })] }) })] }));
|
|
165
|
+
}
|
|
166
|
+
return null;
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
exports.BulkAddView = BulkAddView;
|