@anraktech/sync 0.5.0 → 0.6.0
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/cli.js +88 -13
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
import { Command } from "commander";
|
|
5
5
|
import { createInterface as createInterface2 } from "readline/promises";
|
|
6
6
|
import { stdin as stdin2, stdout as stdout2 } from "process";
|
|
7
|
-
import { existsSync as
|
|
7
|
+
import { existsSync as existsSync4, statSync as statSync3 } from "fs";
|
|
8
8
|
import { resolve as resolve3 } from "path";
|
|
9
9
|
import chalk3 from "chalk";
|
|
10
10
|
|
|
@@ -416,7 +416,7 @@ function resetCache() {
|
|
|
416
416
|
|
|
417
417
|
// src/watcher.ts
|
|
418
418
|
import { watch } from "chokidar";
|
|
419
|
-
import { readdirSync, statSync, existsSync as
|
|
419
|
+
import { readdirSync as readdirSync2, statSync as statSync2, existsSync as existsSync3 } from "fs";
|
|
420
420
|
import { join as join3, relative as relative2, basename as basename4, resolve as resolve2 } from "path";
|
|
421
421
|
|
|
422
422
|
// src/uploader.ts
|
|
@@ -621,6 +621,7 @@ import { createInterface } from "readline/promises";
|
|
|
621
621
|
import { stdin, stdout } from "process";
|
|
622
622
|
import { homedir as homedir2, platform } from "os";
|
|
623
623
|
import { resolve, join as join2 } from "path";
|
|
624
|
+
import { existsSync as existsSync2, readdirSync, statSync } from "fs";
|
|
624
625
|
import chalk2 from "chalk";
|
|
625
626
|
var HOME = homedir2();
|
|
626
627
|
var IS_MAC = platform() === "darwin";
|
|
@@ -652,17 +653,39 @@ function normalizePath(folderPath) {
|
|
|
652
653
|
return resolve(HOME, trimmed);
|
|
653
654
|
}
|
|
654
655
|
var TOOLS = [
|
|
656
|
+
{
|
|
657
|
+
type: "function",
|
|
658
|
+
function: {
|
|
659
|
+
name: "browse_folder",
|
|
660
|
+
description: "List files and subfolders in a local directory. Shows file names, sizes, types, and whether they are syncable. Use FIRST when user wants to see what's in a folder before syncing.",
|
|
661
|
+
parameters: {
|
|
662
|
+
type: "object",
|
|
663
|
+
properties: {
|
|
664
|
+
folderPath: {
|
|
665
|
+
type: "string",
|
|
666
|
+
description: "Absolute path to the folder to browse"
|
|
667
|
+
},
|
|
668
|
+
filter: {
|
|
669
|
+
type: "string",
|
|
670
|
+
enum: ["all", "syncable", "folders"],
|
|
671
|
+
description: "Filter: 'all' shows everything, 'syncable' shows only supported file types (PDF, DOCX, etc.), 'folders' shows only subfolders. Default: all"
|
|
672
|
+
}
|
|
673
|
+
},
|
|
674
|
+
required: ["folderPath"]
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
},
|
|
655
678
|
{
|
|
656
679
|
type: "function",
|
|
657
680
|
function: {
|
|
658
681
|
name: "scan_folder",
|
|
659
|
-
description: "
|
|
682
|
+
description: "Sync all supported files from a local folder to a matching legal case. Use when user explicitly asks to sync, upload, or push files. If unsure what's in the folder, use browse_folder first.",
|
|
660
683
|
parameters: {
|
|
661
684
|
type: "object",
|
|
662
685
|
properties: {
|
|
663
686
|
folderPath: {
|
|
664
687
|
type: "string",
|
|
665
|
-
description: "Absolute path to the folder
|
|
688
|
+
description: "Absolute path to the folder to sync"
|
|
666
689
|
}
|
|
667
690
|
},
|
|
668
691
|
required: ["folderPath"]
|
|
@@ -718,7 +741,7 @@ Server: ${config.apiUrl}
|
|
|
718
741
|
Home directory: ${HOME}
|
|
719
742
|
Platform: ${IS_MAC ? "macOS" : platform()}
|
|
720
743
|
|
|
721
|
-
You can
|
|
744
|
+
You can browse local folders, scan & sync files, list cases, show sync status, and more.
|
|
722
745
|
|
|
723
746
|
Rules:
|
|
724
747
|
- Be concise. This is a terminal \u2014 1-3 lines unless showing a list.
|
|
@@ -728,12 +751,64 @@ Rules:
|
|
|
728
751
|
"desktop" \u2192 ${join2(HOME, "Desktop")}
|
|
729
752
|
"documents" \u2192 ${join2(HOME, "Documents")}
|
|
730
753
|
"~/SomeFolder" \u2192 ${HOME}/SomeFolder
|
|
754
|
+
- When user says "look at" or "check" a folder, use browse_folder FIRST to show what's there.
|
|
755
|
+
- When user says "sync" or "upload", use scan_folder to actually sync.
|
|
756
|
+
- When browsing, highlight which files are syncable (PDF, DOCX, XLSX, etc.) vs not.
|
|
757
|
+
- Present file lists in a clean table/list format with names and sizes.
|
|
731
758
|
- Call tools to perform actions. Summarize results naturally after.
|
|
732
759
|
- If a tool returns an error, report it clearly to the user.
|
|
733
760
|
- Do NOT use thinking tags or reasoning tags in your output.`;
|
|
734
761
|
}
|
|
735
762
|
async function executeTool(name, args, ctx) {
|
|
736
763
|
switch (name) {
|
|
764
|
+
case "browse_folder": {
|
|
765
|
+
const rawPath = args.folderPath;
|
|
766
|
+
if (!rawPath) return JSON.stringify({ error: "Missing folderPath" });
|
|
767
|
+
const folderPath = normalizePath(rawPath);
|
|
768
|
+
if (!existsSync2(folderPath)) {
|
|
769
|
+
return JSON.stringify({ error: `Folder not found: ${folderPath}` });
|
|
770
|
+
}
|
|
771
|
+
try {
|
|
772
|
+
const s = statSync(folderPath);
|
|
773
|
+
if (!s.isDirectory()) {
|
|
774
|
+
return JSON.stringify({ error: `Not a directory: ${folderPath}` });
|
|
775
|
+
}
|
|
776
|
+
} catch {
|
|
777
|
+
return JSON.stringify({ error: `Cannot access: ${folderPath}` });
|
|
778
|
+
}
|
|
779
|
+
const filter = args.filter || "all";
|
|
780
|
+
const entries = readdirSync(folderPath);
|
|
781
|
+
const items = [];
|
|
782
|
+
for (const entry of entries) {
|
|
783
|
+
if (isIgnoredFile(entry)) continue;
|
|
784
|
+
const fullPath = join2(folderPath, entry);
|
|
785
|
+
let st;
|
|
786
|
+
try {
|
|
787
|
+
st = statSync(fullPath);
|
|
788
|
+
} catch {
|
|
789
|
+
continue;
|
|
790
|
+
}
|
|
791
|
+
if (st.isDirectory()) {
|
|
792
|
+
if (filter !== "syncable") {
|
|
793
|
+
items.push({ name: entry, type: "folder" });
|
|
794
|
+
}
|
|
795
|
+
} else if (st.isFile()) {
|
|
796
|
+
if (filter === "folders") continue;
|
|
797
|
+
const syncable = isSupportedFile(entry);
|
|
798
|
+
if (filter === "syncable" && !syncable) continue;
|
|
799
|
+
const sizeKB = Math.round(st.size / 1024);
|
|
800
|
+
const size = sizeKB > 1024 ? `${(sizeKB / 1024).toFixed(1)} MB` : `${sizeKB} KB`;
|
|
801
|
+
items.push({ name: entry, type: "file", size, syncable });
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
return JSON.stringify({
|
|
805
|
+
folder: folderPath,
|
|
806
|
+
totalItems: items.length,
|
|
807
|
+
items: items.slice(0, 50),
|
|
808
|
+
// Cap at 50 to avoid token explosion
|
|
809
|
+
truncated: items.length > 50
|
|
810
|
+
});
|
|
811
|
+
}
|
|
737
812
|
case "scan_folder": {
|
|
738
813
|
const rawPath = args.folderPath;
|
|
739
814
|
if (!rawPath) return JSON.stringify({ error: "Missing folderPath" });
|
|
@@ -950,7 +1025,7 @@ async function scanFolder(config) {
|
|
|
950
1025
|
function walk(dir) {
|
|
951
1026
|
let entries;
|
|
952
1027
|
try {
|
|
953
|
-
entries =
|
|
1028
|
+
entries = readdirSync2(dir);
|
|
954
1029
|
} catch {
|
|
955
1030
|
return;
|
|
956
1031
|
}
|
|
@@ -959,7 +1034,7 @@ async function scanFolder(config) {
|
|
|
959
1034
|
const fullPath = join3(dir, entry);
|
|
960
1035
|
let s;
|
|
961
1036
|
try {
|
|
962
|
-
s =
|
|
1037
|
+
s = statSync2(fullPath);
|
|
963
1038
|
} catch {
|
|
964
1039
|
continue;
|
|
965
1040
|
}
|
|
@@ -992,11 +1067,11 @@ async function pushSync(config) {
|
|
|
992
1067
|
}
|
|
993
1068
|
async function scanExternalFolder(config, folderPath, cases) {
|
|
994
1069
|
const absPath = resolve2(folderPath);
|
|
995
|
-
if (!
|
|
1070
|
+
if (!existsSync3(absPath)) {
|
|
996
1071
|
log.error(`Folder not found: ${absPath}`);
|
|
997
1072
|
return;
|
|
998
1073
|
}
|
|
999
|
-
if (!
|
|
1074
|
+
if (!statSync2(absPath).isDirectory()) {
|
|
1000
1075
|
log.error(`Not a directory: ${absPath}`);
|
|
1001
1076
|
return;
|
|
1002
1077
|
}
|
|
@@ -1005,7 +1080,7 @@ async function scanExternalFolder(config, folderPath, cases) {
|
|
|
1005
1080
|
function walk(dir) {
|
|
1006
1081
|
let entries;
|
|
1007
1082
|
try {
|
|
1008
|
-
entries =
|
|
1083
|
+
entries = readdirSync2(dir);
|
|
1009
1084
|
} catch {
|
|
1010
1085
|
return;
|
|
1011
1086
|
}
|
|
@@ -1014,7 +1089,7 @@ async function scanExternalFolder(config, folderPath, cases) {
|
|
|
1014
1089
|
const fullPath = join3(dir, entry);
|
|
1015
1090
|
let s;
|
|
1016
1091
|
try {
|
|
1017
|
-
s =
|
|
1092
|
+
s = statSync2(fullPath);
|
|
1018
1093
|
} catch {
|
|
1019
1094
|
continue;
|
|
1020
1095
|
}
|
|
@@ -1185,11 +1260,11 @@ program.command("init").description("Set up AnrakLegal Sync (first-time configur
|
|
|
1185
1260
|
);
|
|
1186
1261
|
const watchFolder = resolve3(watchInput || defaultFolder);
|
|
1187
1262
|
rl2.close();
|
|
1188
|
-
if (!
|
|
1263
|
+
if (!existsSync4(watchFolder)) {
|
|
1189
1264
|
log.warn(
|
|
1190
1265
|
`Folder ${watchFolder} does not exist \u2014 it will be created when you add files`
|
|
1191
1266
|
);
|
|
1192
|
-
} else if (!
|
|
1267
|
+
} else if (!statSync3(watchFolder).isDirectory()) {
|
|
1193
1268
|
log.error(`${watchFolder} is not a directory`);
|
|
1194
1269
|
process.exit(1);
|
|
1195
1270
|
}
|