@anraktech/sync 0.4.0 → 0.5.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 +61 -29
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -5,7 +5,7 @@ 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
7
|
import { existsSync as existsSync3, statSync as statSync2 } from "fs";
|
|
8
|
-
import { resolve as
|
|
8
|
+
import { resolve as resolve3 } from "path";
|
|
9
9
|
import chalk3 from "chalk";
|
|
10
10
|
|
|
11
11
|
// src/config.ts
|
|
@@ -86,7 +86,7 @@ function openBrowser(url) {
|
|
|
86
86
|
exec(`${cmd} "${url}"`);
|
|
87
87
|
}
|
|
88
88
|
function findFreePort() {
|
|
89
|
-
return new Promise((
|
|
89
|
+
return new Promise((resolve4, reject) => {
|
|
90
90
|
const srv = createServer();
|
|
91
91
|
srv.listen(0, () => {
|
|
92
92
|
const addr = srv.address();
|
|
@@ -96,14 +96,14 @@ function findFreePort() {
|
|
|
96
96
|
return;
|
|
97
97
|
}
|
|
98
98
|
const port = addr.port;
|
|
99
|
-
srv.close(() =>
|
|
99
|
+
srv.close(() => resolve4(port));
|
|
100
100
|
});
|
|
101
101
|
});
|
|
102
102
|
}
|
|
103
103
|
async function browserLogin(apiUrl) {
|
|
104
104
|
const port = await findFreePort();
|
|
105
105
|
return new Promise(
|
|
106
|
-
(
|
|
106
|
+
(resolve4, reject) => {
|
|
107
107
|
let server;
|
|
108
108
|
const timeout = setTimeout(() => {
|
|
109
109
|
server?.close();
|
|
@@ -150,7 +150,7 @@ async function browserLogin(apiUrl) {
|
|
|
150
150
|
const tokens = await resp.json();
|
|
151
151
|
clearTimeout(timeout);
|
|
152
152
|
server.close();
|
|
153
|
-
|
|
153
|
+
resolve4(tokens);
|
|
154
154
|
} catch (err) {
|
|
155
155
|
clearTimeout(timeout);
|
|
156
156
|
server.close();
|
|
@@ -338,11 +338,11 @@ function persist() {
|
|
|
338
338
|
if (cache) saveCache(cache);
|
|
339
339
|
}
|
|
340
340
|
function hashFile(filePath) {
|
|
341
|
-
return new Promise((
|
|
341
|
+
return new Promise((resolve4, reject) => {
|
|
342
342
|
const hash = createHash("sha256");
|
|
343
343
|
const stream = createReadStream(filePath);
|
|
344
344
|
stream.on("data", (chunk) => hash.update(chunk));
|
|
345
|
-
stream.on("end", () =>
|
|
345
|
+
stream.on("end", () => resolve4(hash.digest("hex")));
|
|
346
346
|
stream.on("error", reject);
|
|
347
347
|
});
|
|
348
348
|
}
|
|
@@ -417,7 +417,7 @@ function resetCache() {
|
|
|
417
417
|
// src/watcher.ts
|
|
418
418
|
import { watch } from "chokidar";
|
|
419
419
|
import { readdirSync, statSync, existsSync as existsSync2 } from "fs";
|
|
420
|
-
import { join as
|
|
420
|
+
import { join as join3, relative as relative2, basename as basename4, resolve as resolve2 } from "path";
|
|
421
421
|
|
|
422
422
|
// src/uploader.ts
|
|
423
423
|
import { stat as stat2 } from "fs/promises";
|
|
@@ -619,7 +619,38 @@ function sleep(ms) {
|
|
|
619
619
|
// src/agent.ts
|
|
620
620
|
import { createInterface } from "readline/promises";
|
|
621
621
|
import { stdin, stdout } from "process";
|
|
622
|
+
import { homedir as homedir2, platform } from "os";
|
|
623
|
+
import { resolve, join as join2 } from "path";
|
|
622
624
|
import chalk2 from "chalk";
|
|
625
|
+
var HOME = homedir2();
|
|
626
|
+
var IS_MAC = platform() === "darwin";
|
|
627
|
+
var FOLDER_SHORTCUTS = {
|
|
628
|
+
downloads: join2(HOME, "Downloads"),
|
|
629
|
+
download: join2(HOME, "Downloads"),
|
|
630
|
+
desktop: join2(HOME, "Desktop"),
|
|
631
|
+
documents: join2(HOME, "Documents"),
|
|
632
|
+
document: join2(HOME, "Documents"),
|
|
633
|
+
home: HOME,
|
|
634
|
+
"~": HOME
|
|
635
|
+
};
|
|
636
|
+
function normalizePath(folderPath) {
|
|
637
|
+
const trimmed = folderPath.trim();
|
|
638
|
+
if (trimmed.startsWith("~/") || trimmed === "~") {
|
|
639
|
+
return resolve(trimmed.replace(/^~/, HOME));
|
|
640
|
+
}
|
|
641
|
+
const lower = trimmed.toLowerCase();
|
|
642
|
+
if (FOLDER_SHORTCUTS[lower]) {
|
|
643
|
+
return FOLDER_SHORTCUTS[lower];
|
|
644
|
+
}
|
|
645
|
+
const withoutSlash = lower.replace(/^\//, "");
|
|
646
|
+
if (FOLDER_SHORTCUTS[withoutSlash]) {
|
|
647
|
+
return FOLDER_SHORTCUTS[withoutSlash];
|
|
648
|
+
}
|
|
649
|
+
if (trimmed.startsWith("/") || /^[A-Z]:\\/i.test(trimmed)) {
|
|
650
|
+
return resolve(trimmed);
|
|
651
|
+
}
|
|
652
|
+
return resolve(HOME, trimmed);
|
|
653
|
+
}
|
|
623
654
|
var TOOLS = [
|
|
624
655
|
{
|
|
625
656
|
type: "function",
|
|
@@ -684,21 +715,29 @@ function buildSystemPrompt(config) {
|
|
|
684
715
|
|
|
685
716
|
Watch folder: ${config.watchFolder}
|
|
686
717
|
Server: ${config.apiUrl}
|
|
718
|
+
Home directory: ${HOME}
|
|
719
|
+
Platform: ${IS_MAC ? "macOS" : platform()}
|
|
687
720
|
|
|
688
721
|
You can scan folders, list cases, show sync status, and more using your tools.
|
|
689
722
|
|
|
690
723
|
Rules:
|
|
691
724
|
- Be concise. This is a terminal \u2014 1-3 lines unless showing a list.
|
|
692
725
|
- Do NOT use markdown. Plain text only.
|
|
693
|
-
- When user mentions a folder like "downloads" or "desktop",
|
|
726
|
+
- IMPORTANT: When user mentions a folder like "downloads" or "desktop", ALWAYS use the full absolute path. Examples:
|
|
727
|
+
"downloads" or "my downloads" \u2192 ${join2(HOME, "Downloads")}
|
|
728
|
+
"desktop" \u2192 ${join2(HOME, "Desktop")}
|
|
729
|
+
"documents" \u2192 ${join2(HOME, "Documents")}
|
|
730
|
+
"~/SomeFolder" \u2192 ${HOME}/SomeFolder
|
|
694
731
|
- Call tools to perform actions. Summarize results naturally after.
|
|
732
|
+
- If a tool returns an error, report it clearly to the user.
|
|
695
733
|
- Do NOT use thinking tags or reasoning tags in your output.`;
|
|
696
734
|
}
|
|
697
735
|
async function executeTool(name, args, ctx) {
|
|
698
736
|
switch (name) {
|
|
699
737
|
case "scan_folder": {
|
|
700
|
-
const
|
|
701
|
-
if (!
|
|
738
|
+
const rawPath = args.folderPath;
|
|
739
|
+
if (!rawPath) return JSON.stringify({ error: "Missing folderPath" });
|
|
740
|
+
const folderPath = normalizePath(rawPath);
|
|
702
741
|
try {
|
|
703
742
|
await ctx.scanFolder(folderPath);
|
|
704
743
|
const stats = getStats();
|
|
@@ -800,18 +839,9 @@ async function agentTurn(messages, ctx) {
|
|
|
800
839
|
}
|
|
801
840
|
let textContent = "";
|
|
802
841
|
const toolCalls = /* @__PURE__ */ new Map();
|
|
803
|
-
let isFirstText = true;
|
|
804
842
|
for await (const { delta } of parseSSE(response)) {
|
|
805
843
|
if (delta.content) {
|
|
806
|
-
|
|
807
|
-
process.stdout.write(" ");
|
|
808
|
-
isFirstText = false;
|
|
809
|
-
}
|
|
810
|
-
const cleaned = delta.content.replace(/<\/?think>/g, "");
|
|
811
|
-
if (cleaned) {
|
|
812
|
-
process.stdout.write(cleaned);
|
|
813
|
-
textContent += cleaned;
|
|
814
|
-
}
|
|
844
|
+
textContent += delta.content;
|
|
815
845
|
}
|
|
816
846
|
if (delta.tool_calls) {
|
|
817
847
|
for (const tc of delta.tool_calls) {
|
|
@@ -828,8 +858,10 @@ async function agentTurn(messages, ctx) {
|
|
|
828
858
|
}
|
|
829
859
|
}
|
|
830
860
|
}
|
|
861
|
+
textContent = textContent.replace(/<think>[\s\S]*?<\/think>/g, "").trim();
|
|
831
862
|
if (textContent) {
|
|
832
|
-
process.stdout.write(
|
|
863
|
+
process.stdout.write(` ${textContent}
|
|
864
|
+
`);
|
|
833
865
|
}
|
|
834
866
|
if (toolCalls.size === 0) {
|
|
835
867
|
return textContent;
|
|
@@ -924,7 +956,7 @@ async function scanFolder(config) {
|
|
|
924
956
|
}
|
|
925
957
|
for (const entry of entries) {
|
|
926
958
|
if (isIgnoredFile(entry)) continue;
|
|
927
|
-
const fullPath =
|
|
959
|
+
const fullPath = join3(dir, entry);
|
|
928
960
|
let s;
|
|
929
961
|
try {
|
|
930
962
|
s = statSync(fullPath);
|
|
@@ -959,7 +991,7 @@ async function pushSync(config) {
|
|
|
959
991
|
);
|
|
960
992
|
}
|
|
961
993
|
async function scanExternalFolder(config, folderPath, cases) {
|
|
962
|
-
const absPath =
|
|
994
|
+
const absPath = resolve2(folderPath);
|
|
963
995
|
if (!existsSync2(absPath)) {
|
|
964
996
|
log.error(`Folder not found: ${absPath}`);
|
|
965
997
|
return;
|
|
@@ -979,7 +1011,7 @@ async function scanExternalFolder(config, folderPath, cases) {
|
|
|
979
1011
|
}
|
|
980
1012
|
for (const entry of entries) {
|
|
981
1013
|
if (isIgnoredFile(entry)) continue;
|
|
982
|
-
const fullPath =
|
|
1014
|
+
const fullPath = join3(dir, entry);
|
|
983
1015
|
let s;
|
|
984
1016
|
try {
|
|
985
1017
|
s = statSync(fullPath);
|
|
@@ -990,7 +1022,7 @@ async function scanExternalFolder(config, folderPath, cases) {
|
|
|
990
1022
|
walk(fullPath);
|
|
991
1023
|
} else if (s.isFile() && isSupportedFile(entry)) {
|
|
992
1024
|
fileCount++;
|
|
993
|
-
void enqueue(fullPath,
|
|
1025
|
+
void enqueue(fullPath, join3(absPath, ".."));
|
|
994
1026
|
}
|
|
995
1027
|
}
|
|
996
1028
|
}
|
|
@@ -1107,10 +1139,10 @@ async function startWatching(config) {
|
|
|
1107
1139
|
// src/cli.ts
|
|
1108
1140
|
import { readFileSync as readFileSync2 } from "fs";
|
|
1109
1141
|
import { fileURLToPath } from "url";
|
|
1110
|
-
import { dirname as dirname2, join as
|
|
1142
|
+
import { dirname as dirname2, join as join4 } from "path";
|
|
1111
1143
|
var __filename2 = fileURLToPath(import.meta.url);
|
|
1112
1144
|
var __dirname2 = dirname2(__filename2);
|
|
1113
|
-
var pkg = JSON.parse(readFileSync2(
|
|
1145
|
+
var pkg = JSON.parse(readFileSync2(join4(__dirname2, "..", "package.json"), "utf-8"));
|
|
1114
1146
|
var program = new Command();
|
|
1115
1147
|
program.name("anrak-sync").description("AnrakLegal desktop file sync \u2014 watches local folders, syncs to case management").version(pkg.version);
|
|
1116
1148
|
program.command("init").description("Set up AnrakLegal Sync (first-time configuration)").option("--password", "Use email/password login instead of browser").action(async (opts) => {
|
|
@@ -1151,7 +1183,7 @@ program.command("init").description("Set up AnrakLegal Sync (first-time configur
|
|
|
1151
1183
|
const watchInput = await rl2.question(
|
|
1152
1184
|
` Watch folder ${chalk3.dim(`(${defaultFolder})`)}: `
|
|
1153
1185
|
);
|
|
1154
|
-
const watchFolder =
|
|
1186
|
+
const watchFolder = resolve3(watchInput || defaultFolder);
|
|
1155
1187
|
rl2.close();
|
|
1156
1188
|
if (!existsSync3(watchFolder)) {
|
|
1157
1189
|
log.warn(
|