@epiccontext/mcp 0.1.55 → 0.1.57
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/api/client.d.ts +27 -1
- package/dist/api/client.d.ts.map +1 -1
- package/dist/api/client.js +102 -0
- package/dist/api/client.js.map +1 -1
- package/dist/cli/commands/add-app.d.ts +9 -0
- package/dist/cli/commands/add-app.d.ts.map +1 -0
- package/dist/cli/commands/add-app.js +111 -0
- package/dist/cli/commands/add-app.js.map +1 -0
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +37 -16
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/pull.d.ts +2 -0
- package/dist/cli/commands/pull.d.ts.map +1 -1
- package/dist/cli/commands/pull.js +122 -67
- package/dist/cli/commands/pull.js.map +1 -1
- package/dist/cli/commands/push.d.ts +2 -0
- package/dist/cli/commands/push.d.ts.map +1 -1
- package/dist/cli/commands/push.js +130 -75
- package/dist/cli/commands/push.js.map +1 -1
- package/dist/cli/commands/serve.d.ts.map +1 -1
- package/dist/cli/commands/serve.js +2 -1
- package/dist/cli/commands/serve.js.map +1 -1
- package/dist/cli/commands/status.d.ts.map +1 -1
- package/dist/cli/commands/status.js +21 -3
- package/dist/cli/commands/status.js.map +1 -1
- package/dist/cli/commands/validate.d.ts.map +1 -1
- package/dist/cli/commands/validate.js +6 -5
- package/dist/cli/commands/validate.js.map +1 -1
- package/dist/cli/config.d.ts +4 -0
- package/dist/cli/config.d.ts.map +1 -1
- package/dist/cli/config.js +20 -0
- package/dist/cli/config.js.map +1 -1
- package/dist/cli/files.d.ts +9 -1
- package/dist/cli/files.d.ts.map +1 -1
- package/dist/cli/files.js +147 -31
- package/dist/cli/files.js.map +1 -1
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +12 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/mcp/server.d.ts +1 -0
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +12 -0
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/tools/list-documents.d.ts +10 -0
- package/dist/mcp/tools/list-documents.d.ts.map +1 -0
- package/dist/mcp/tools/list-documents.js +86 -0
- package/dist/mcp/tools/list-documents.js.map +1 -0
- package/dist/mcp/tools/read-document.d.ts +10 -0
- package/dist/mcp/tools/read-document.d.ts.map +1 -0
- package/dist/mcp/tools/read-document.js +119 -0
- package/dist/mcp/tools/read-document.js.map +1 -0
- package/dist/mcp/tools/sync-all.d.ts.map +1 -1
- package/dist/mcp/tools/sync-all.js +9 -0
- package/dist/mcp/tools/sync-all.js.map +1 -1
- package/dist/mcp/tools/sync-documents.d.ts +10 -0
- package/dist/mcp/tools/sync-documents.d.ts.map +1 -0
- package/dist/mcp/tools/sync-documents.js +89 -0
- package/dist/mcp/tools/sync-documents.js.map +1 -0
- package/dist/mcp/tools/sync-from-app.d.ts.map +1 -1
- package/dist/mcp/tools/sync-from-app.js +6 -0
- package/dist/mcp/tools/sync-from-app.js.map +1 -1
- package/dist/mcp/tools/sync-to-app.d.ts.map +1 -1
- package/dist/mcp/tools/sync-to-app.js +6 -0
- package/dist/mcp/tools/sync-to-app.js.map +1 -1
- package/dist/skills/generator.d.ts.map +1 -1
- package/dist/skills/generator.js +98 -5
- package/dist/skills/generator.js.map +1 -1
- package/dist/sync/deletions.d.ts +31 -0
- package/dist/sync/deletions.d.ts.map +1 -0
- package/dist/sync/deletions.js +110 -0
- package/dist/sync/deletions.js.map +1 -0
- package/dist/sync/document-files.d.ts +31 -0
- package/dist/sync/document-files.d.ts.map +1 -0
- package/dist/sync/document-files.js +98 -0
- package/dist/sync/document-files.js.map +1 -0
- package/dist/sync/document-manifest.d.ts +22 -0
- package/dist/sync/document-manifest.d.ts.map +1 -0
- package/dist/sync/document-manifest.js +55 -0
- package/dist/sync/document-manifest.js.map +1 -0
- package/dist/sync/document-pull.d.ts +16 -0
- package/dist/sync/document-pull.d.ts.map +1 -0
- package/dist/sync/document-pull.js +149 -0
- package/dist/sync/document-pull.js.map +1 -0
- package/dist/sync/document-push.d.ts +14 -0
- package/dist/sync/document-push.d.ts.map +1 -0
- package/dist/sync/document-push.js +107 -0
- package/dist/sync/document-push.js.map +1 -0
- package/dist/sync/pull.d.ts +4 -0
- package/dist/sync/pull.d.ts.map +1 -1
- package/dist/sync/pull.js +91 -0
- package/dist/sync/pull.js.map +1 -1
- package/dist/sync/push.d.ts +4 -0
- package/dist/sync/push.d.ts.map +1 -1
- package/dist/sync/push.js +44 -1
- package/dist/sync/push.js.map +1 -1
- package/dist/sync/watcher.d.ts.map +1 -1
- package/dist/sync/watcher.js +25 -5
- package/dist/sync/watcher.js.map +1 -1
- package/dist/types/index.d.ts +127 -0
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import * as fs from "fs";
|
|
2
|
+
import * as path from "path";
|
|
3
|
+
import { readDocumentManifest, writeDocumentManifest } from "./document-manifest.js";
|
|
4
|
+
import { ensureDocumentsFolderExists, computeLocalPath } from "./document-files.js";
|
|
5
|
+
/**
|
|
6
|
+
* Pull documents from the cloud to the local DOCUMENTS folder.
|
|
7
|
+
* Only downloads new or updated files (delta sync based on timestamps).
|
|
8
|
+
*/
|
|
9
|
+
export async function pullDocuments(client, documentsPath, options = {}) {
|
|
10
|
+
ensureDocumentsFolderExists(documentsPath);
|
|
11
|
+
const result = {
|
|
12
|
+
downloaded: 0,
|
|
13
|
+
uploaded: 0,
|
|
14
|
+
skipped: 0,
|
|
15
|
+
deleted: 0,
|
|
16
|
+
errors: [],
|
|
17
|
+
};
|
|
18
|
+
// 1. Get cloud documents
|
|
19
|
+
const cloudData = await client.listDocuments();
|
|
20
|
+
const manifest = readDocumentManifest(documentsPath);
|
|
21
|
+
const manifestMap = new Map(manifest.entries.map((e) => [e.id, e]));
|
|
22
|
+
// 2. Process each cloud document
|
|
23
|
+
for (const cloudDoc of cloudData.documents) {
|
|
24
|
+
const localPath = computeLocalPath(cloudDoc.folderPath || null, cloudDoc.fileName);
|
|
25
|
+
const absolutePath = path.join(documentsPath, localPath);
|
|
26
|
+
// Check max file size
|
|
27
|
+
if (options.maxFileSize && cloudDoc.fileSize > options.maxFileSize) {
|
|
28
|
+
result.skipped++;
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
const existingEntry = manifestMap.get(cloudDoc.id);
|
|
32
|
+
let needsDownload = false;
|
|
33
|
+
if (!existingEntry) {
|
|
34
|
+
// New document — not in manifest
|
|
35
|
+
needsDownload = true;
|
|
36
|
+
}
|
|
37
|
+
else if (!fs.existsSync(absolutePath)) {
|
|
38
|
+
// In manifest but missing locally — re-download
|
|
39
|
+
needsDownload = true;
|
|
40
|
+
}
|
|
41
|
+
else if (cloudDoc.updatedAt > (existingEntry.cloudUpdatedAt || "")) {
|
|
42
|
+
// Cloud version is newer
|
|
43
|
+
if (options.force) {
|
|
44
|
+
needsDownload = true;
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
// Check if local is also newer (conflict)
|
|
48
|
+
const localMtime = getFileMtime(absolutePath);
|
|
49
|
+
if (localMtime &&
|
|
50
|
+
existingEntry.localUpdatedAt &&
|
|
51
|
+
localMtime > existingEntry.localUpdatedAt) {
|
|
52
|
+
// Both modified — skip unless forced
|
|
53
|
+
result.skipped++;
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
needsDownload = true;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
// Already in sync
|
|
61
|
+
result.skipped++;
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
if (options.dryRun) {
|
|
65
|
+
result.downloaded++;
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
// Download the file
|
|
69
|
+
try {
|
|
70
|
+
const { data } = await client.downloadDocument(cloudDoc.id);
|
|
71
|
+
// Ensure directory exists
|
|
72
|
+
const dir = path.dirname(absolutePath);
|
|
73
|
+
if (!fs.existsSync(dir)) {
|
|
74
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
75
|
+
}
|
|
76
|
+
// Write atomically: temp file → rename
|
|
77
|
+
const tempPath = absolutePath + ".tmp";
|
|
78
|
+
fs.writeFileSync(tempPath, Buffer.from(data));
|
|
79
|
+
fs.renameSync(tempPath, absolutePath);
|
|
80
|
+
// Update manifest entry
|
|
81
|
+
const entry = {
|
|
82
|
+
id: cloudDoc.id,
|
|
83
|
+
name: cloudDoc.name,
|
|
84
|
+
fileName: cloudDoc.fileName,
|
|
85
|
+
localPath,
|
|
86
|
+
cloudUrl: cloudDoc.fileUrl,
|
|
87
|
+
storagePath: cloudDoc.storagePath,
|
|
88
|
+
mimeType: cloudDoc.mimeType,
|
|
89
|
+
fileSize: cloudDoc.fileSize,
|
|
90
|
+
cloudUpdatedAt: cloudDoc.updatedAt,
|
|
91
|
+
localUpdatedAt: new Date().toISOString(),
|
|
92
|
+
syncStatus: "synced",
|
|
93
|
+
folderId: cloudDoc.folderId,
|
|
94
|
+
folderPath: cloudDoc.folderPath || null,
|
|
95
|
+
};
|
|
96
|
+
// Update in-memory manifest
|
|
97
|
+
const idx = manifest.entries.findIndex((e) => e.id === cloudDoc.id);
|
|
98
|
+
if (idx >= 0) {
|
|
99
|
+
manifest.entries[idx] = entry;
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
manifest.entries.push(entry);
|
|
103
|
+
}
|
|
104
|
+
result.downloaded++;
|
|
105
|
+
}
|
|
106
|
+
catch (error) {
|
|
107
|
+
result.errors.push({
|
|
108
|
+
path: localPath,
|
|
109
|
+
error: error instanceof Error ? error.message : "Download failed",
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
// 3. Check for deleted cloud documents (in manifest but not in cloud)
|
|
114
|
+
const cloudIds = new Set(cloudData.documents.map((d) => d.id));
|
|
115
|
+
for (const entry of [...manifest.entries]) {
|
|
116
|
+
if (!cloudIds.has(entry.id)) {
|
|
117
|
+
entry.syncStatus = "deleted_cloud";
|
|
118
|
+
// Optionally remove local file
|
|
119
|
+
const absolutePath = path.join(documentsPath, entry.localPath);
|
|
120
|
+
if (fs.existsSync(absolutePath) && !options.dryRun) {
|
|
121
|
+
try {
|
|
122
|
+
fs.unlinkSync(absolutePath);
|
|
123
|
+
result.deleted++;
|
|
124
|
+
}
|
|
125
|
+
catch {
|
|
126
|
+
// Leave file but mark in manifest
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
// Remove from manifest
|
|
130
|
+
manifest.entries = manifest.entries.filter((e) => e.id !== entry.id);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
// 4. Save manifest
|
|
134
|
+
if (!options.dryRun) {
|
|
135
|
+
manifest.lastSyncAt = new Date().toISOString();
|
|
136
|
+
writeDocumentManifest(documentsPath, manifest);
|
|
137
|
+
}
|
|
138
|
+
return result;
|
|
139
|
+
}
|
|
140
|
+
function getFileMtime(filePath) {
|
|
141
|
+
try {
|
|
142
|
+
const stats = fs.statSync(filePath);
|
|
143
|
+
return stats.mtime.toISOString();
|
|
144
|
+
}
|
|
145
|
+
catch {
|
|
146
|
+
return null;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
//# sourceMappingURL=document-pull.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"document-pull.js","sourceRoot":"","sources":["../../src/sync/document-pull.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { EpicContextClient } from "../api/client.js";
|
|
2
|
+
import type { DocumentSyncResult } from "../types/index.js";
|
|
3
|
+
export interface DocumentPushOptions {
|
|
4
|
+
/** Preview changes without uploading */
|
|
5
|
+
dryRun?: boolean;
|
|
6
|
+
/** Push only a specific file or folder path */
|
|
7
|
+
path?: string;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Push local documents to the cloud.
|
|
11
|
+
* Only uploads new or modified files (delta sync based on timestamps).
|
|
12
|
+
*/
|
|
13
|
+
export declare function pushDocuments(client: EpicContextClient, documentsPath: string, options?: DocumentPushOptions): Promise<DocumentSyncResult>;
|
|
14
|
+
//# sourceMappingURL=document-push.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"document-push.d.ts","sourceRoot":"","sources":["../../src/sync/document-push.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAC1D,OAAO,KAAK,EAEV,kBAAkB,EACnB,MAAM,mBAAmB,CAAC;AAY3B,MAAM,WAAW,mBAAmB;IAClC,wCAAwC;IACxC,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,+CAA+C;IAC/C,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;GAGG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,iBAAiB,EACzB,aAAa,EAAE,MAAM,EACrB,OAAO,GAAE,mBAAwB,GAChC,OAAO,CAAC,kBAAkB,CAAC,CAoH7B"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import * as fs from "fs";
|
|
2
|
+
import * as path from "path";
|
|
3
|
+
import { readDocumentManifest, writeDocumentManifest, findEntryByLocalPath, } from "./document-manifest.js";
|
|
4
|
+
import { scanDocumentsFolder, ensureDocumentsFolderExists, getMimeType, } from "./document-files.js";
|
|
5
|
+
/**
|
|
6
|
+
* Push local documents to the cloud.
|
|
7
|
+
* Only uploads new or modified files (delta sync based on timestamps).
|
|
8
|
+
*/
|
|
9
|
+
export async function pushDocuments(client, documentsPath, options = {}) {
|
|
10
|
+
ensureDocumentsFolderExists(documentsPath);
|
|
11
|
+
const result = {
|
|
12
|
+
downloaded: 0,
|
|
13
|
+
uploaded: 0,
|
|
14
|
+
skipped: 0,
|
|
15
|
+
deleted: 0,
|
|
16
|
+
errors: [],
|
|
17
|
+
};
|
|
18
|
+
// 1. Scan local files
|
|
19
|
+
let localFiles = scanDocumentsFolder(documentsPath);
|
|
20
|
+
// Filter by path if specified
|
|
21
|
+
if (options.path) {
|
|
22
|
+
const filterPath = options.path.replace(/^\.\//, "");
|
|
23
|
+
localFiles = localFiles.filter((f) => f.relativePath === filterPath ||
|
|
24
|
+
f.relativePath.startsWith(filterPath + "/"));
|
|
25
|
+
}
|
|
26
|
+
// 2. Read manifest
|
|
27
|
+
const manifest = readDocumentManifest(documentsPath);
|
|
28
|
+
// 3. Process each local file
|
|
29
|
+
for (const file of localFiles) {
|
|
30
|
+
const existingEntry = findEntryByLocalPath(manifest, file.relativePath);
|
|
31
|
+
let needsUpload = false;
|
|
32
|
+
if (!existingEntry) {
|
|
33
|
+
// New local file — not in manifest
|
|
34
|
+
needsUpload = true;
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
// Check if local file was modified since last sync
|
|
38
|
+
const localMtime = file.mtime.toISOString();
|
|
39
|
+
if (existingEntry.localUpdatedAt &&
|
|
40
|
+
localMtime > existingEntry.localUpdatedAt) {
|
|
41
|
+
needsUpload = true;
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
result.skipped++;
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
if (options.dryRun) {
|
|
49
|
+
result.uploaded++;
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
// Upload the file
|
|
53
|
+
try {
|
|
54
|
+
const fileBuffer = fs.readFileSync(file.absolutePath);
|
|
55
|
+
const mimeType = getMimeType(file.relativePath);
|
|
56
|
+
// Compute folder path from relative path (everything before the filename)
|
|
57
|
+
const folderPath = path.dirname(file.relativePath);
|
|
58
|
+
const fileName = path.basename(file.relativePath);
|
|
59
|
+
const response = await client.uploadDocument(Buffer.from(fileBuffer), {
|
|
60
|
+
fileName,
|
|
61
|
+
mimeType,
|
|
62
|
+
folderPath: folderPath !== "." ? folderPath : undefined,
|
|
63
|
+
name: fileName.replace(/\.[^.]+$/, ""),
|
|
64
|
+
});
|
|
65
|
+
// Extract document info from response
|
|
66
|
+
const doc = response.document;
|
|
67
|
+
// Update manifest entry
|
|
68
|
+
const entry = {
|
|
69
|
+
id: doc?.id || existingEntry?.id || "",
|
|
70
|
+
name: doc?.name || fileName.replace(/\.[^.]+$/, ""),
|
|
71
|
+
fileName,
|
|
72
|
+
localPath: file.relativePath,
|
|
73
|
+
cloudUrl: doc?.file_url || existingEntry?.cloudUrl || "",
|
|
74
|
+
storagePath: doc?.storage_path || existingEntry?.storagePath || "",
|
|
75
|
+
mimeType,
|
|
76
|
+
fileSize: file.size,
|
|
77
|
+
cloudUpdatedAt: doc?.updated_at || new Date().toISOString(),
|
|
78
|
+
localUpdatedAt: file.mtime.toISOString(),
|
|
79
|
+
syncStatus: "synced",
|
|
80
|
+
folderId: doc?.folder_id || null,
|
|
81
|
+
folderPath: folderPath !== "." ? folderPath : null,
|
|
82
|
+
};
|
|
83
|
+
// Update in-memory manifest
|
|
84
|
+
const idx = manifest.entries.findIndex((e) => e.localPath === file.relativePath);
|
|
85
|
+
if (idx >= 0) {
|
|
86
|
+
manifest.entries[idx] = entry;
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
manifest.entries.push(entry);
|
|
90
|
+
}
|
|
91
|
+
result.uploaded++;
|
|
92
|
+
}
|
|
93
|
+
catch (error) {
|
|
94
|
+
result.errors.push({
|
|
95
|
+
path: file.relativePath,
|
|
96
|
+
error: error instanceof Error ? error.message : "Upload failed",
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
// 4. Save manifest
|
|
101
|
+
if (!options.dryRun) {
|
|
102
|
+
manifest.lastSyncAt = new Date().toISOString();
|
|
103
|
+
writeDocumentManifest(documentsPath, manifest);
|
|
104
|
+
}
|
|
105
|
+
return result;
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=document-push.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"document-push.js","sourceRoot":"","sources":["../../src/sync/document-push.ts"],"names":[],"mappings":"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"}
|
package/dist/sync/pull.d.ts
CHANGED
|
@@ -12,6 +12,10 @@ export interface PullResult {
|
|
|
12
12
|
skippedPaths: string[];
|
|
13
13
|
deletedPaths: string[];
|
|
14
14
|
totalFiles: number;
|
|
15
|
+
/** Number of local files deleted via deletion manifest */
|
|
16
|
+
filesDeletedByManifest?: number;
|
|
17
|
+
/** Paths of files deleted via manifest */
|
|
18
|
+
deletedByManifestPaths?: string[];
|
|
15
19
|
}
|
|
16
20
|
/**
|
|
17
21
|
* Pull from cloud to local CONTEXT folder
|
package/dist/sync/pull.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pull.d.ts","sourceRoot":"","sources":["../../src/sync/pull.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"pull.d.ts","sourceRoot":"","sources":["../../src/sync/pull.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAWrD,MAAM,WAAW,WAAW;IAC1B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,0DAA0D;IAC1D,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,0CAA0C;IAC1C,sBAAsB,CAAC,EAAE,MAAM,EAAE,CAAC;CACnC;AAED;;;;;;;GAOG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,iBAAiB,EACzB,WAAW,EAAE,MAAM,EACnB,OAAO,GAAE,WAAgB,GACxB,OAAO,CAAC,UAAU,CAAC,CAwHrB"}
|
package/dist/sync/pull.js
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import path from "path";
|
|
1
3
|
import { writeContextFolder, ensureContextFolder, deleteOrphanedLocalFiles } from "../cli/files.js";
|
|
4
|
+
import { readDeletionManifest, writeDeletionManifest, mergeDeletionManifests, pruneOldDeletions, } from "./deletions.js";
|
|
2
5
|
/**
|
|
3
6
|
* Pull from cloud to local CONTEXT folder
|
|
4
7
|
* By default, skips files where local version is newer than cloud version
|
|
@@ -51,6 +54,48 @@ export async function pullFromCloud(client, contextPath, options = {}) {
|
|
|
51
54
|
}
|
|
52
55
|
}
|
|
53
56
|
}
|
|
57
|
+
// Process deletion manifest: merge cloud deletions with local manifest,
|
|
58
|
+
// then delete matching local files
|
|
59
|
+
let filesDeletedByManifest = 0;
|
|
60
|
+
const deletedByManifestPaths = [];
|
|
61
|
+
const cloudDeletions = response.deletions || [];
|
|
62
|
+
if (cloudDeletions.length > 0 || readDeletionManifest(contextPath).deletions.length > 0) {
|
|
63
|
+
const localManifest = readDeletionManifest(contextPath);
|
|
64
|
+
const cloudManifest = {
|
|
65
|
+
version: 1,
|
|
66
|
+
deletions: cloudDeletions,
|
|
67
|
+
};
|
|
68
|
+
// Merge cloud deletions into local manifest
|
|
69
|
+
let merged = mergeDeletionManifests(localManifest, cloudManifest);
|
|
70
|
+
// Handle restorations: if a block key appears in files[] AND in the manifest,
|
|
71
|
+
// the block was restored — remove it from the manifest
|
|
72
|
+
const activeFileKeys = new Set();
|
|
73
|
+
for (const file of response.files) {
|
|
74
|
+
// Extract key from file path (last segment without .md)
|
|
75
|
+
const fileName = file.path.split("/").pop();
|
|
76
|
+
if (fileName && fileName.endsWith(".md") && fileName.toLowerCase() !== "readme.md") {
|
|
77
|
+
activeFileKeys.add(fileName.replace(/\.md$/, ""));
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
const restoredEntries = merged.deletions.filter((d) => activeFileKeys.has(d.key));
|
|
81
|
+
if (restoredEntries.length > 0) {
|
|
82
|
+
merged = {
|
|
83
|
+
version: 1,
|
|
84
|
+
deletions: merged.deletions.filter((d) => !activeFileKeys.has(d.key)),
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
// Delete local files matching deletion entries
|
|
88
|
+
for (const deletion of merged.deletions) {
|
|
89
|
+
const deleted = deleteLocalFileForBlock(contextPath, deletion.key, deletion.section);
|
|
90
|
+
if (deleted) {
|
|
91
|
+
filesDeletedByManifest++;
|
|
92
|
+
deletedByManifestPaths.push(deleted);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
// Prune old entries and write back
|
|
96
|
+
const pruned = pruneOldDeletions(merged);
|
|
97
|
+
writeDeletionManifest(contextPath, pruned);
|
|
98
|
+
}
|
|
54
99
|
return {
|
|
55
100
|
success: true,
|
|
56
101
|
filesWritten: written,
|
|
@@ -59,6 +104,52 @@ export async function pullFromCloud(client, contextPath, options = {}) {
|
|
|
59
104
|
skippedPaths,
|
|
60
105
|
deletedPaths,
|
|
61
106
|
totalFiles: filesToWrite.length,
|
|
107
|
+
filesDeletedByManifest,
|
|
108
|
+
deletedByManifestPaths,
|
|
62
109
|
};
|
|
63
110
|
}
|
|
111
|
+
/**
|
|
112
|
+
* Find and delete a local file matching a block key in a section folder.
|
|
113
|
+
* Searches recursively within the section folder for {key}.md.
|
|
114
|
+
* Returns the relative path of the deleted file, or null if not found.
|
|
115
|
+
*/
|
|
116
|
+
function deleteLocalFileForBlock(contextPath, key, section) {
|
|
117
|
+
// Convert section type to folder name (underscores → hyphens)
|
|
118
|
+
const sectionFolder = section.replace(/_/g, "-");
|
|
119
|
+
const sectionPath = path.join(contextPath, sectionFolder);
|
|
120
|
+
if (!fs.existsSync(sectionPath)) {
|
|
121
|
+
// Also try with the original section name (no conversion)
|
|
122
|
+
const altPath = path.join(contextPath, section);
|
|
123
|
+
if (!fs.existsSync(altPath)) {
|
|
124
|
+
return null;
|
|
125
|
+
}
|
|
126
|
+
return searchAndDelete(altPath, contextPath, key);
|
|
127
|
+
}
|
|
128
|
+
return searchAndDelete(sectionPath, contextPath, key);
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Recursively search for {key}.md in a directory and delete it.
|
|
132
|
+
*/
|
|
133
|
+
function searchAndDelete(dirPath, contextPath, key) {
|
|
134
|
+
const targetFilename = `${key}.md`;
|
|
135
|
+
try {
|
|
136
|
+
const entries = fs.readdirSync(dirPath, { withFileTypes: true });
|
|
137
|
+
for (const entry of entries) {
|
|
138
|
+
const fullPath = path.join(dirPath, entry.name);
|
|
139
|
+
if (entry.isFile() && entry.name === targetFilename) {
|
|
140
|
+
fs.unlinkSync(fullPath);
|
|
141
|
+
return path.relative(contextPath, fullPath);
|
|
142
|
+
}
|
|
143
|
+
if (entry.isDirectory() && !entry.name.startsWith(".")) {
|
|
144
|
+
const result = searchAndDelete(fullPath, contextPath, key);
|
|
145
|
+
if (result)
|
|
146
|
+
return result;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
catch {
|
|
151
|
+
// Non-fatal: directory read or delete failed
|
|
152
|
+
}
|
|
153
|
+
return null;
|
|
154
|
+
}
|
|
64
155
|
//# sourceMappingURL=pull.js.map
|
package/dist/sync/pull.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pull.js","sourceRoot":"","sources":["../../src/sync/pull.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"pull.js","sourceRoot":"","sources":["../../src/sync/pull.ts"],"names":[],"mappings":"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"}
|
package/dist/sync/push.d.ts
CHANGED
|
@@ -13,6 +13,10 @@ export interface PushResult {
|
|
|
13
13
|
result: SyncResult;
|
|
14
14
|
/** Blocks that exist in cloud but not locally - would be deleted with deleteOrphans */
|
|
15
15
|
potentialOrphans?: number;
|
|
16
|
+
/** Number of blocks archived via deletion manifest */
|
|
17
|
+
archivedByManifest?: number;
|
|
18
|
+
/** Number of deletions auto-detected from missing local files */
|
|
19
|
+
autoDetectedDeletions?: number;
|
|
16
20
|
}
|
|
17
21
|
/**
|
|
18
22
|
* Push local CONTEXT folder to cloud
|
package/dist/sync/push.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"push.d.ts","sourceRoot":"","sources":["../../src/sync/push.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"push.d.ts","sourceRoot":"","sources":["../../src/sync/push.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAQrD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAEpD,MAAM,WAAW,WAAW;IAC1B,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,kBAAkB,CAAC,EAAE,WAAW,GAAG,aAAa,CAAC;IACjD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;IAChB,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,UAAU,CAAC;IACnB,uFAAuF;IACvF,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,sDAAsD;IACtD,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,iEAAiE;IACjE,qBAAqB,CAAC,EAAE,MAAM,CAAC;CAChC;AAED;;GAEG;AACH,wBAAsB,WAAW,CAC/B,MAAM,EAAE,iBAAiB,EACzB,WAAW,EAAE,MAAM,EACnB,OAAO,GAAE,WAAgB,GACxB,OAAO,CAAC,UAAU,CAAC,CAgGrB"}
|
package/dist/sync/push.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { readContextFolder } from "../cli/files.js";
|
|
2
|
+
import { readDeletionManifest, writeDeletionManifest, addDeletion, pruneOldDeletions, } from "./deletions.js";
|
|
2
3
|
/**
|
|
3
4
|
* Push local CONTEXT folder to cloud
|
|
4
5
|
*/
|
|
@@ -24,7 +25,9 @@ export async function pushToCloud(client, contextPath, options = {}) {
|
|
|
24
25
|
if (options.path) {
|
|
25
26
|
filesToSync = files.filter((f) => f.path.startsWith(options.path));
|
|
26
27
|
}
|
|
27
|
-
//
|
|
28
|
+
// Read the local deletion manifest to send alongside files
|
|
29
|
+
const manifest = readDeletionManifest(contextPath);
|
|
30
|
+
// Import to cloud with deletions
|
|
28
31
|
// SAFETY: deleteOrphans defaults to FALSE to prevent accidental data loss
|
|
29
32
|
// in collaborative environments. Users must explicitly pass --delete-orphans
|
|
30
33
|
// to remove blocks that don't exist in their local folder.
|
|
@@ -32,12 +35,52 @@ export async function pushToCloud(client, contextPath, options = {}) {
|
|
|
32
35
|
dryRun: options.dryRun,
|
|
33
36
|
conflictResolution: options.conflictResolution ?? "folder_wins",
|
|
34
37
|
deleteOrphans: options.deleteOrphans ?? false,
|
|
38
|
+
deletions: manifest.deletions,
|
|
35
39
|
});
|
|
40
|
+
// Auto-detect local deletions from potentialOrphans:
|
|
41
|
+
// If the server reports blocks that exist in cloud but not locally,
|
|
42
|
+
// these are likely files the user deleted. Add them to the manifest
|
|
43
|
+
// and send a follow-up request to archive them.
|
|
44
|
+
let autoDetectedDeletions = 0;
|
|
45
|
+
const orphans = response.result.potentialOrphans;
|
|
46
|
+
if (!options.dryRun && orphans && orphans.length > 0 && !options.path) {
|
|
47
|
+
// Build set of already-known deletions
|
|
48
|
+
const knownDeletions = new Set(manifest.deletions.map((d) => `${d.section}:${d.key}`));
|
|
49
|
+
const newDeletions = orphans.filter((o) => !knownDeletions.has(`${o.sectionType}:${o.key}`));
|
|
50
|
+
if (newDeletions.length > 0) {
|
|
51
|
+
// Add newly detected deletions to the manifest
|
|
52
|
+
for (const orphan of newDeletions) {
|
|
53
|
+
addDeletion(contextPath, {
|
|
54
|
+
key: orphan.key,
|
|
55
|
+
section: orphan.sectionType,
|
|
56
|
+
source: "local",
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
autoDetectedDeletions = newDeletions.length;
|
|
60
|
+
// Send follow-up import with only the new deletions to archive them
|
|
61
|
+
const updatedManifest = readDeletionManifest(contextPath);
|
|
62
|
+
await client.importFiles([], {
|
|
63
|
+
dryRun: false,
|
|
64
|
+
conflictResolution: options.conflictResolution ?? "folder_wins",
|
|
65
|
+
deletions: updatedManifest.deletions,
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
// Prune old entries (>30 days) and write back
|
|
70
|
+
if (!options.dryRun) {
|
|
71
|
+
const currentManifest = readDeletionManifest(contextPath);
|
|
72
|
+
const pruned = pruneOldDeletions(currentManifest);
|
|
73
|
+
if (pruned.deletions.length !== currentManifest.deletions.length) {
|
|
74
|
+
writeDeletionManifest(contextPath, pruned);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
36
77
|
return {
|
|
37
78
|
success: response.success,
|
|
38
79
|
dryRun: response.dryRun,
|
|
39
80
|
filesProcessed: filesToSync.length,
|
|
40
81
|
result: response.result,
|
|
82
|
+
archivedByManifest: response.result.deleted,
|
|
83
|
+
autoDetectedDeletions,
|
|
41
84
|
};
|
|
42
85
|
}
|
|
43
86
|
//# sourceMappingURL=push.js.map
|
package/dist/sync/push.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"push.js","sourceRoot":"","sources":["../../src/sync/push.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"push.js","sourceRoot":"","sources":["../../src/sync/push.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"watcher.d.ts","sourceRoot":"","sources":["../../src/sync/watcher.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"watcher.d.ts","sourceRoot":"","sources":["../../src/sync/watcher.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAI1D,MAAM,WAAW,aAAa;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;IAC/E,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACjC,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAClD;AAED;;GAEG;AACH,qBAAa,WAAW;IAOpB,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,MAAM;IAPhB,OAAO,CAAC,OAAO,CAA0B;IACzC,OAAO,CAAC,cAAc,CAA0B;IAChD,OAAO,CAAC,WAAW,CAA+B;IAClD,OAAO,CAAC,SAAS,CAAS;gBAGhB,MAAM,EAAE,iBAAiB,EACzB,MAAM,EAAE,aAAa;IAG/B;;OAEG;IACH,KAAK,IAAI,IAAI;IAsBb;;OAEG;IACH,IAAI,IAAI,IAAI;IASZ;;OAEG;IACH,OAAO,CAAC,YAAY;IAoCpB;;OAEG;IACH,OAAO,CAAC,YAAY;IAUpB;;OAEG;YACW,qBAAqB;CAyBpC;AAED;;GAEG;AACH,wBAAgB,aAAa,CAC3B,MAAM,EAAE,iBAAiB,EACzB,MAAM,EAAE,aAAa,GACpB,WAAW,CAIb"}
|
package/dist/sync/watcher.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import chokidar from "chokidar";
|
|
2
|
+
import path from "path";
|
|
2
3
|
import { pushToCloud } from "./push.js";
|
|
4
|
+
import { addDeletion } from "./deletions.js";
|
|
3
5
|
/**
|
|
4
6
|
* File watcher for auto-syncing CONTEXT folder changes (local → cloud only)
|
|
5
7
|
*/
|
|
@@ -51,18 +53,36 @@ export class FileWatcher {
|
|
|
51
53
|
/**
|
|
52
54
|
* Handle a file change event
|
|
53
55
|
*/
|
|
54
|
-
handleChange(event,
|
|
56
|
+
handleChange(event, filePath) {
|
|
55
57
|
// Only watch markdown files
|
|
56
|
-
if (!
|
|
58
|
+
if (!filePath.endsWith(".md")) {
|
|
57
59
|
return;
|
|
58
60
|
}
|
|
59
61
|
// Skip README and AI-GUIDE
|
|
60
|
-
const filename =
|
|
62
|
+
const filename = filePath.split("/").pop()?.toLowerCase();
|
|
61
63
|
if (filename === "readme.md" || filename === "ai-guide.md") {
|
|
62
64
|
return;
|
|
63
65
|
}
|
|
64
|
-
|
|
65
|
-
|
|
66
|
+
// When a file is deleted (unlink), record it in the deletion manifest
|
|
67
|
+
// so the next push will propagate the deletion to the cloud
|
|
68
|
+
if (event === "unlink") {
|
|
69
|
+
const relativePath = path.relative(this.config.contextPath, filePath);
|
|
70
|
+
const parts = relativePath.split(path.sep);
|
|
71
|
+
// Section is the first directory (e.g., "product", "brand", "development")
|
|
72
|
+
const section = parts[0]?.replace(/-/g, "_");
|
|
73
|
+
// Key is the filename without .md
|
|
74
|
+
const key = path.basename(filePath, ".md");
|
|
75
|
+
if (section && key) {
|
|
76
|
+
try {
|
|
77
|
+
addDeletion(this.config.contextPath, { key, section, source: "local" });
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
// Non-fatal: manifest write failed, deletion won't propagate automatically
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
this.config.onChange?.(event, filePath);
|
|
85
|
+
this.pendingChanges.add(filePath);
|
|
66
86
|
this.scheduleSync();
|
|
67
87
|
}
|
|
68
88
|
/**
|
package/dist/sync/watcher.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"watcher.js","sourceRoot":"","sources":["../../src/sync/watcher.ts"],"names":[],"mappings":"AAAA,OAAO,QAA4B,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"watcher.js","sourceRoot":"","sources":["../../src/sync/watcher.ts"],"names":[],"mappings":"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"}
|