relayax-cli 0.4.35 → 0.4.36
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.
|
@@ -34,7 +34,13 @@ export declare function computeContentsDiff(contents: ContentEntry[], relayDir:
|
|
|
34
34
|
/**
|
|
35
35
|
* contents 항목 단위로 from → .relay/ 동기화한다.
|
|
36
36
|
*/
|
|
37
|
-
export declare function syncContentsToRelay(contents: ContentEntry[], contentsDiff: ContentDiffEntry[], relayDir: string, projectPath: string):
|
|
37
|
+
export declare function syncContentsToRelay(contents: ContentEntry[], contentsDiff: ContentDiffEntry[], relayDir: string, projectPath: string): {
|
|
38
|
+
removed: string[];
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* .relay/ 내에 있지만 contents 매니페스트에 없는 orphan 항목을 찾는다.
|
|
42
|
+
*/
|
|
43
|
+
export declare function findOrphanItems(contents: ContentEntry[], relayDir: string): string[];
|
|
38
44
|
/**
|
|
39
45
|
* 패키지 홈 디렉토리를 결정한다.
|
|
40
46
|
* 1. 프로젝트에 .relay/가 있으면 → projectPath/.relay/
|
package/dist/commands/package.js
CHANGED
|
@@ -5,6 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.computeContentsDiff = computeContentsDiff;
|
|
7
7
|
exports.syncContentsToRelay = syncContentsToRelay;
|
|
8
|
+
exports.findOrphanItems = findOrphanItems;
|
|
8
9
|
exports.resolveRelayDir = resolveRelayDir;
|
|
9
10
|
exports.initGlobalAgentHome = initGlobalAgentHome;
|
|
10
11
|
exports.registerPackage = registerPackage;
|
|
@@ -214,27 +215,60 @@ function discoverNewItems(contents, projectPath) {
|
|
|
214
215
|
* contents 항목 단위로 from → .relay/ 동기화한다.
|
|
215
216
|
*/
|
|
216
217
|
function syncContentsToRelay(contents, contentsDiff, relayDir, projectPath) {
|
|
218
|
+
const removed = [];
|
|
217
219
|
for (const diffEntry of contentsDiff) {
|
|
220
|
+
const content = contents.find((c) => c.name === diffEntry.name && c.type === diffEntry.type);
|
|
221
|
+
// source_missing: 소스에서 삭제됨 → .relay/에서도 제거
|
|
222
|
+
if (diffEntry.status === 'source_missing') {
|
|
223
|
+
const relaySubPath = content ? deriveRelaySubPath(content) : `${diffEntry.type}s/${diffEntry.name}`;
|
|
224
|
+
const relayTarget = path_1.default.join(relayDir, relaySubPath);
|
|
225
|
+
if (fs_1.default.existsSync(relayTarget)) {
|
|
226
|
+
fs_1.default.rmSync(relayTarget, { recursive: true, force: true });
|
|
227
|
+
removed.push(relaySubPath);
|
|
228
|
+
}
|
|
229
|
+
continue;
|
|
230
|
+
}
|
|
218
231
|
if (diffEntry.status !== 'modified')
|
|
219
232
|
continue;
|
|
220
|
-
const content = contents.find((c) => c.name === diffEntry.name && c.type === diffEntry.type);
|
|
221
233
|
if (!content)
|
|
222
234
|
continue;
|
|
223
235
|
const absFrom = resolveFromPath(getFromPath(content), projectPath);
|
|
224
236
|
const relaySubPath = deriveRelaySubPath(content);
|
|
225
237
|
const relayTarget = path_1.default.join(relayDir, relaySubPath);
|
|
226
|
-
// 단일 파일인 경우 직접 복사
|
|
238
|
+
// 단일 파일인 경우 직접 복사
|
|
227
239
|
if (fs_1.default.existsSync(absFrom) && fs_1.default.statSync(absFrom).isFile()) {
|
|
228
240
|
fs_1.default.mkdirSync(path_1.default.dirname(relayTarget), { recursive: true });
|
|
229
241
|
fs_1.default.copyFileSync(absFrom, relayTarget);
|
|
230
242
|
continue;
|
|
231
243
|
}
|
|
232
|
-
// 디렉토리인 경우 diff 기반 동기화
|
|
244
|
+
// 디렉토리인 경우 diff 기반 동기화 (deleted 포함)
|
|
233
245
|
const sourceFiles = scanPath(absFrom);
|
|
234
246
|
const relayFiles = scanPath(relayTarget);
|
|
235
247
|
const fileDiff = computeDiff(sourceFiles, relayFiles);
|
|
236
248
|
syncToRelay(absFrom, relayTarget, fileDiff);
|
|
237
249
|
}
|
|
250
|
+
return { removed };
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* .relay/ 내에 있지만 contents 매니페스트에 없는 orphan 항목을 찾는다.
|
|
254
|
+
*/
|
|
255
|
+
function findOrphanItems(contents, relayDir) {
|
|
256
|
+
const contentPaths = new Set(contents.map((c) => deriveRelaySubPath(c)));
|
|
257
|
+
const orphans = [];
|
|
258
|
+
for (const dir of SYNC_DIRS) {
|
|
259
|
+
const fullDir = path_1.default.join(relayDir, dir);
|
|
260
|
+
if (!fs_1.default.existsSync(fullDir))
|
|
261
|
+
continue;
|
|
262
|
+
for (const entry of fs_1.default.readdirSync(fullDir, { withFileTypes: true })) {
|
|
263
|
+
if (entry.name.startsWith('.'))
|
|
264
|
+
continue;
|
|
265
|
+
const relPath = `${dir}/${entry.name}`;
|
|
266
|
+
if (!contentPaths.has(relPath)) {
|
|
267
|
+
orphans.push(relPath);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
return orphans;
|
|
238
272
|
}
|
|
239
273
|
// ─── Global Agent Home ───
|
|
240
274
|
/**
|
|
@@ -462,20 +496,31 @@ function registerPackage(program) {
|
|
|
462
496
|
}
|
|
463
497
|
// contents 기반 diff 계산
|
|
464
498
|
const { diff: contentsDiff, newItems } = computeContentsDiff(contents, relayDir, projectPath);
|
|
499
|
+
const orphans = findOrphanItems(contents, relayDir);
|
|
465
500
|
const summary = {
|
|
466
501
|
modified: contentsDiff.filter((d) => d.status === 'modified').length,
|
|
467
502
|
unchanged: contentsDiff.filter((d) => d.status === 'unchanged').length,
|
|
468
503
|
source_missing: contentsDiff.filter((d) => d.status === 'source_missing').length,
|
|
469
504
|
new_available: newItems.length,
|
|
505
|
+
orphaned: orphans.length,
|
|
470
506
|
};
|
|
471
|
-
const hasChanges = summary.modified > 0;
|
|
472
|
-
// --sync: contents 단위 동기화
|
|
507
|
+
const hasChanges = summary.modified > 0 || summary.source_missing > 0 || summary.orphaned > 0;
|
|
508
|
+
// --sync: contents 단위 동기화 + orphan 정리
|
|
473
509
|
if (opts.sync && hasChanges) {
|
|
474
|
-
syncContentsToRelay(contents, contentsDiff, relayDir, projectPath);
|
|
510
|
+
const { removed } = syncContentsToRelay(contents, contentsDiff, relayDir, projectPath);
|
|
511
|
+
// orphan 항목 삭제
|
|
512
|
+
for (const orphan of orphans) {
|
|
513
|
+
const orphanPath = path_1.default.join(relayDir, orphan);
|
|
514
|
+
if (fs_1.default.existsSync(orphanPath)) {
|
|
515
|
+
fs_1.default.rmSync(orphanPath, { recursive: true, force: true });
|
|
516
|
+
removed.push(orphan);
|
|
517
|
+
}
|
|
518
|
+
}
|
|
475
519
|
}
|
|
476
520
|
const result = {
|
|
477
521
|
diff: contentsDiff.filter((d) => d.status !== 'unchanged'),
|
|
478
522
|
new_items: newItems,
|
|
523
|
+
orphans,
|
|
479
524
|
synced: opts.sync === true && hasChanges,
|
|
480
525
|
summary,
|
|
481
526
|
};
|
|
@@ -499,6 +544,12 @@ function registerPackage(program) {
|
|
|
499
544
|
}
|
|
500
545
|
}
|
|
501
546
|
}
|
|
547
|
+
if (orphans.length > 0) {
|
|
548
|
+
console.error('\n \x1b[33m.relay/에만 존재 (소스에서 삭제됨):\x1b[0m');
|
|
549
|
+
for (const orphan of orphans) {
|
|
550
|
+
console.error(` \x1b[31m✗ ${orphan}\x1b[0m`);
|
|
551
|
+
}
|
|
552
|
+
}
|
|
502
553
|
if (newItems.length > 0) {
|
|
503
554
|
console.error('\n 새로 발견된 콘텐츠:');
|
|
504
555
|
for (const item of newItems) {
|
|
@@ -506,7 +557,7 @@ function registerPackage(program) {
|
|
|
506
557
|
}
|
|
507
558
|
}
|
|
508
559
|
console.error('');
|
|
509
|
-
console.error(` 합계: 변경 ${summary.modified}, 유지 ${summary.unchanged}, 원본 없음 ${summary.source_missing}, 신규 ${summary.new_available}`);
|
|
560
|
+
console.error(` 합계: 변경 ${summary.modified}, 유지 ${summary.unchanged}, 원본 없음 ${summary.source_missing}, 신규 ${summary.new_available}, 고아 ${summary.orphaned}`);
|
|
510
561
|
if (opts.sync) {
|
|
511
562
|
console.error('\n✓ .relay/에 반영 완료');
|
|
512
563
|
}
|