@anraktech/sync 0.7.0 → 0.9.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 +110 -86
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -15,17 +15,16 @@ import { join } from "path";
|
|
|
15
15
|
|
|
16
16
|
// src/logger.ts
|
|
17
17
|
import chalk from "chalk";
|
|
18
|
-
var PREFIX = chalk.bold.blue("[anrak-sync]");
|
|
19
18
|
var log = {
|
|
20
|
-
info: (msg) => console.log(
|
|
21
|
-
success: (msg) => console.log(
|
|
22
|
-
warn: (msg) => console.log(
|
|
23
|
-
error: (msg) => console.error(
|
|
19
|
+
info: (msg) => console.log(chalk.dim(` ${msg}`)),
|
|
20
|
+
success: (msg) => console.log(` ${chalk.green("\u2713")} ${msg}`),
|
|
21
|
+
warn: (msg) => console.log(` ${chalk.yellow("!")} ${msg}`),
|
|
22
|
+
error: (msg) => console.error(` ${chalk.red("\u2717")} ${msg}`),
|
|
24
23
|
debug: (msg) => {
|
|
25
|
-
if (process.env.ANRAK_DEBUG) console.log(
|
|
24
|
+
if (process.env.ANRAK_DEBUG) console.log(chalk.dim(` ${msg}`));
|
|
26
25
|
},
|
|
27
|
-
dim: (msg) => console.log(
|
|
28
|
-
file: (action, path) => console.log(
|
|
26
|
+
dim: (msg) => console.log(chalk.dim(` ${msg}`)),
|
|
27
|
+
file: (action, path) => console.log(` ${chalk.dim("\u203A")} ${chalk.cyan(action)} ${chalk.dim(path)}`)
|
|
29
28
|
};
|
|
30
29
|
|
|
31
30
|
// src/config.ts
|
|
@@ -417,7 +416,7 @@ function resetCache() {
|
|
|
417
416
|
// src/watcher.ts
|
|
418
417
|
import { watch } from "chokidar";
|
|
419
418
|
import { readdirSync as readdirSync2, statSync as statSync2, existsSync as existsSync3 } from "fs";
|
|
420
|
-
import { join as join3, relative as relative2, basename as
|
|
419
|
+
import { join as join3, relative as relative2, basename as basename5, resolve as resolve2 } from "path";
|
|
421
420
|
|
|
422
421
|
// src/uploader.ts
|
|
423
422
|
import { stat as stat2 } from "fs/promises";
|
|
@@ -620,9 +619,20 @@ function sleep(ms) {
|
|
|
620
619
|
import { createInterface } from "readline/promises";
|
|
621
620
|
import { stdin, stdout } from "process";
|
|
622
621
|
import { homedir as homedir2, platform } from "os";
|
|
623
|
-
import { resolve, join as join2 } from "path";
|
|
624
|
-
import { existsSync as existsSync2, readdirSync, statSync } from "fs";
|
|
622
|
+
import { resolve, join as join2, dirname as dirname2 } from "path";
|
|
623
|
+
import { existsSync as existsSync2, readdirSync, statSync, readFileSync as readFileSync2 } from "fs";
|
|
624
|
+
import { fileURLToPath } from "url";
|
|
625
625
|
import chalk2 from "chalk";
|
|
626
|
+
var __filename2 = fileURLToPath(import.meta.url);
|
|
627
|
+
var __dirname2 = dirname2(__filename2);
|
|
628
|
+
var PKG_VERSION = (() => {
|
|
629
|
+
try {
|
|
630
|
+
const pkg2 = JSON.parse(readFileSync2(join2(__dirname2, "..", "package.json"), "utf-8"));
|
|
631
|
+
return pkg2.version;
|
|
632
|
+
} catch {
|
|
633
|
+
return "0.0.0";
|
|
634
|
+
}
|
|
635
|
+
})();
|
|
626
636
|
var HOME = homedir2();
|
|
627
637
|
var IS_MAC = platform() === "darwin";
|
|
628
638
|
var FOLDER_SHORTCUTS = {
|
|
@@ -952,7 +962,8 @@ async function agentTurn(messages, ctx) {
|
|
|
952
962
|
};
|
|
953
963
|
messages.push(assistantMsg);
|
|
954
964
|
for (const tc of toolCalls.values()) {
|
|
955
|
-
|
|
965
|
+
const toolLabel = tc.name.replace(/_/g, " ");
|
|
966
|
+
process.stdout.write(chalk2.dim(` \u25CF ${toolLabel}
|
|
956
967
|
`));
|
|
957
968
|
let args = {};
|
|
958
969
|
try {
|
|
@@ -969,15 +980,29 @@ function startAIAgent(ctx) {
|
|
|
969
980
|
{ role: "system", content: buildSystemPrompt(ctx.config) }
|
|
970
981
|
];
|
|
971
982
|
const rl = createInterface({ input: stdin, output: stdout });
|
|
983
|
+
const cols = Math.min(process.stdout.columns || 70, 70);
|
|
984
|
+
const line = chalk2.dim("\u2500".repeat(cols));
|
|
985
|
+
const watchDisplay = ctx.config.watchFolder.startsWith(HOME) ? "~" + ctx.config.watchFolder.slice(HOME.length) : ctx.config.watchFolder;
|
|
986
|
+
const stats = ctx.bootStats;
|
|
972
987
|
console.log("");
|
|
973
|
-
console.log(
|
|
974
|
-
console.log(
|
|
975
|
-
console.log(chalk2.
|
|
988
|
+
console.log(line);
|
|
989
|
+
console.log("");
|
|
990
|
+
console.log(` ${chalk2.bold("AnrakLegal Sync")} ${chalk2.dim(`v${PKG_VERSION}`)}`);
|
|
991
|
+
console.log("");
|
|
992
|
+
console.log(` ${chalk2.dim("Folder")} ${watchDisplay}`);
|
|
993
|
+
console.log(` ${chalk2.dim("Server")} ${ctx.config.apiUrl}`);
|
|
994
|
+
if (stats) {
|
|
995
|
+
console.log(` ${chalk2.dim("Cases")} ${stats.cases} on server`);
|
|
996
|
+
if (stats.scanned > 0) {
|
|
997
|
+
console.log(` ${chalk2.dim("Files")} ${stats.scanned} scanned${stats.queued > 0 ? `, ${chalk2.yellow(String(stats.queued))} synced` : chalk2.green(" \xB7 up to date")}`);
|
|
998
|
+
}
|
|
999
|
+
}
|
|
1000
|
+
console.log("");
|
|
1001
|
+
console.log(line);
|
|
1002
|
+
console.log("");
|
|
1003
|
+
console.log(chalk2.dim(" Type a message to get started. Examples:"));
|
|
1004
|
+
console.log(chalk2.dim(' "show my cases" "look at downloads" "sync my desktop"'));
|
|
976
1005
|
console.log("");
|
|
977
|
-
console.log(
|
|
978
|
-
chalk2.dim(" Ask me anything \u2014 scan folders, check cases, show status.")
|
|
979
|
-
);
|
|
980
|
-
console.log(chalk2.dim(' Type "quit" to exit.\n'));
|
|
981
1006
|
const PROMPT = `${chalk2.bold.blue("\u276F")} `;
|
|
982
1007
|
async function promptLoop() {
|
|
983
1008
|
while (true) {
|
|
@@ -1114,16 +1139,13 @@ async function scanExternalFolder(config, folderPath, cases) {
|
|
|
1114
1139
|
}
|
|
1115
1140
|
async function startWatching(config) {
|
|
1116
1141
|
const folder = config.watchFolder;
|
|
1117
|
-
log.info(`Scanning ${folder}...`);
|
|
1118
1142
|
let cases = await listCases(config);
|
|
1119
|
-
log.info(`Found ${cases.length} case(s) on server`);
|
|
1120
1143
|
const { scanned, queued } = await scanFolder(config);
|
|
1121
|
-
log.info(`Scanned ${scanned} files, ${queued} need syncing`);
|
|
1122
1144
|
if (queued > 0) {
|
|
1123
1145
|
const result = await processQueue(config, cases);
|
|
1124
|
-
|
|
1125
|
-
`Initial sync: ${result.uploaded} uploaded, ${result.failed} failed`
|
|
1126
|
-
|
|
1146
|
+
if (result.failed > 0) {
|
|
1147
|
+
log.warn(`Initial sync: ${result.uploaded} uploaded, ${result.failed} failed`);
|
|
1148
|
+
}
|
|
1127
1149
|
}
|
|
1128
1150
|
const refreshInterval = setInterval(async () => {
|
|
1129
1151
|
try {
|
|
@@ -1131,7 +1153,6 @@ async function startWatching(config) {
|
|
|
1131
1153
|
} catch {
|
|
1132
1154
|
}
|
|
1133
1155
|
}, 5 * 60 * 1e3);
|
|
1134
|
-
log.info(`Watching for changes...`);
|
|
1135
1156
|
const watcher = watch(folder, {
|
|
1136
1157
|
ignored: /(^|[\/\\])(\.|~\$|Thumbs\.db|desktop\.ini)/,
|
|
1137
1158
|
persistent: true,
|
|
@@ -1160,14 +1181,14 @@ async function startWatching(config) {
|
|
|
1160
1181
|
}, 3e3);
|
|
1161
1182
|
}
|
|
1162
1183
|
watcher.on("add", async (path) => {
|
|
1163
|
-
const filename =
|
|
1184
|
+
const filename = basename5(path);
|
|
1164
1185
|
if (!isSupportedFile(filename) || isIgnoredFile(filename)) return;
|
|
1165
1186
|
log.file("detected", relative2(folder, path));
|
|
1166
1187
|
await enqueue(path, folder);
|
|
1167
1188
|
scheduleProcess();
|
|
1168
1189
|
});
|
|
1169
1190
|
watcher.on("change", async (path) => {
|
|
1170
|
-
const filename =
|
|
1191
|
+
const filename = basename5(path);
|
|
1171
1192
|
if (!isSupportedFile(filename) || isIgnoredFile(filename)) return;
|
|
1172
1193
|
log.file("changed", relative2(folder, path));
|
|
1173
1194
|
await enqueue(path, folder);
|
|
@@ -1181,6 +1202,7 @@ async function startWatching(config) {
|
|
|
1181
1202
|
});
|
|
1182
1203
|
startAIAgent({
|
|
1183
1204
|
config,
|
|
1205
|
+
bootStats: { cases: cases.length, scanned, queued },
|
|
1184
1206
|
getCases: () => cases,
|
|
1185
1207
|
refreshCases: async () => {
|
|
1186
1208
|
cases = await listCases(config);
|
|
@@ -1212,11 +1234,9 @@ async function startWatching(config) {
|
|
|
1212
1234
|
}
|
|
1213
1235
|
|
|
1214
1236
|
// src/updater.ts
|
|
1215
|
-
import { execFileSync } from "child_process";
|
|
1237
|
+
import { execFileSync, spawn } from "child_process";
|
|
1216
1238
|
import chalk3 from "chalk";
|
|
1217
1239
|
var PACKAGE_NAME = "@anraktech/sync";
|
|
1218
|
-
var CHECK_INTERVAL_MS = 4 * 60 * 60 * 1e3;
|
|
1219
|
-
var updateCache = { lastCheck: 0, latestVersion: null };
|
|
1220
1240
|
function compareVersions(current, latest) {
|
|
1221
1241
|
const a = current.split(".").map(Number);
|
|
1222
1242
|
const b = latest.split(".").map(Number);
|
|
@@ -1238,71 +1258,70 @@ async function fetchLatestVersion() {
|
|
|
1238
1258
|
return null;
|
|
1239
1259
|
}
|
|
1240
1260
|
}
|
|
1241
|
-
function
|
|
1242
|
-
console.log("");
|
|
1243
|
-
console.log(
|
|
1244
|
-
chalk3.dim(` Update available: ${currentVersion} \u2192 `) + chalk3.green(latestVersion)
|
|
1245
|
-
);
|
|
1246
|
-
console.log(chalk3.dim(" Updating..."));
|
|
1261
|
+
function installUpdate(latestVersion) {
|
|
1247
1262
|
try {
|
|
1248
1263
|
execFileSync("npm", ["install", "-g", `${PACKAGE_NAME}@${latestVersion}`], {
|
|
1249
1264
|
stdio: "pipe",
|
|
1250
1265
|
timeout: 6e4
|
|
1251
1266
|
});
|
|
1252
|
-
console.log(chalk3.green(" Updated successfully. Restart to use the new version."));
|
|
1253
|
-
console.log("");
|
|
1254
1267
|
return true;
|
|
1255
1268
|
} catch {
|
|
1256
1269
|
try {
|
|
1257
|
-
execFileSync("npm", ["install", "-g", `${PACKAGE_NAME}@${latestVersion}`, "--prefix", process.env.HOME + "/.npm-global"], {
|
|
1270
|
+
execFileSync("npm", ["install", "-g", `${PACKAGE_NAME}@${latestVersion}`, "--prefix", (process.env.HOME ?? "") + "/.npm-global"], {
|
|
1258
1271
|
stdio: "pipe",
|
|
1259
1272
|
timeout: 6e4
|
|
1260
1273
|
});
|
|
1261
|
-
console.log(chalk3.green(" Updated successfully. Restart to use the new version."));
|
|
1262
|
-
console.log("");
|
|
1263
1274
|
return true;
|
|
1264
1275
|
} catch {
|
|
1265
|
-
console.log(
|
|
1266
|
-
chalk3.dim(" Auto-update failed. Run manually: ") + chalk3.cyan(`npm install -g ${PACKAGE_NAME}`)
|
|
1267
|
-
);
|
|
1268
|
-
console.log("");
|
|
1269
1276
|
return false;
|
|
1270
1277
|
}
|
|
1271
1278
|
}
|
|
1272
1279
|
}
|
|
1273
1280
|
async function checkForUpdates(currentVersion) {
|
|
1281
|
+
if (process.env.ANRAK_SKIP_UPDATE) return;
|
|
1274
1282
|
try {
|
|
1275
|
-
const now = Date.now();
|
|
1276
|
-
if (now - updateCache.lastCheck < CHECK_INTERVAL_MS && updateCache.latestVersion) {
|
|
1277
|
-
if (compareVersions(currentVersion, updateCache.latestVersion) > 0) {
|
|
1278
|
-
performUpdate(currentVersion, updateCache.latestVersion);
|
|
1279
|
-
}
|
|
1280
|
-
return;
|
|
1281
|
-
}
|
|
1282
1283
|
const latestVersion = await fetchLatestVersion();
|
|
1283
|
-
updateCache = { lastCheck: now, latestVersion };
|
|
1284
1284
|
if (!latestVersion) return;
|
|
1285
|
-
if (compareVersions(currentVersion, latestVersion)
|
|
1286
|
-
|
|
1285
|
+
if (compareVersions(currentVersion, latestVersion) <= 0) return;
|
|
1286
|
+
process.stdout.write(
|
|
1287
|
+
chalk3.dim(` Updating ${currentVersion} \u2192 `) + chalk3.green(latestVersion) + chalk3.dim(" ...")
|
|
1288
|
+
);
|
|
1289
|
+
if (!installUpdate(latestVersion)) {
|
|
1290
|
+
process.stdout.write(
|
|
1291
|
+
chalk3.dim(" failed. Run: ") + chalk3.cyan(`npm i -g ${PACKAGE_NAME}`) + "\n\n"
|
|
1292
|
+
);
|
|
1293
|
+
return;
|
|
1287
1294
|
}
|
|
1295
|
+
process.stdout.write(chalk3.green(" done") + "\n\n");
|
|
1296
|
+
const child = spawn(process.argv[0], process.argv.slice(1), {
|
|
1297
|
+
stdio: "inherit",
|
|
1298
|
+
env: { ...process.env, ANRAK_SKIP_UPDATE: "1" }
|
|
1299
|
+
});
|
|
1300
|
+
child.on("exit", (code) => process.exit(code ?? 0));
|
|
1301
|
+
child.on("error", () => {
|
|
1302
|
+
});
|
|
1303
|
+
await new Promise(() => {
|
|
1304
|
+
});
|
|
1288
1305
|
} catch {
|
|
1289
1306
|
}
|
|
1290
1307
|
}
|
|
1291
1308
|
|
|
1292
1309
|
// src/cli.ts
|
|
1293
|
-
import { readFileSync as
|
|
1294
|
-
import { fileURLToPath } from "url";
|
|
1295
|
-
import { dirname as
|
|
1296
|
-
var
|
|
1297
|
-
var
|
|
1298
|
-
var pkg = JSON.parse(
|
|
1310
|
+
import { readFileSync as readFileSync3 } from "fs";
|
|
1311
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
1312
|
+
import { dirname as dirname3, join as join4 } from "path";
|
|
1313
|
+
var __filename3 = fileURLToPath2(import.meta.url);
|
|
1314
|
+
var __dirname3 = dirname3(__filename3);
|
|
1315
|
+
var pkg = JSON.parse(readFileSync3(join4(__dirname3, "..", "package.json"), "utf-8"));
|
|
1299
1316
|
await checkForUpdates(pkg.version);
|
|
1300
1317
|
var program = new Command();
|
|
1301
1318
|
program.name("anrak-sync").description("AnrakLegal desktop file sync \u2014 watches local folders, syncs to case management").version(pkg.version);
|
|
1302
1319
|
program.command("init").description("Set up AnrakLegal Sync (first-time configuration)").option("--password", "Use email/password login instead of browser").action(async (opts) => {
|
|
1303
1320
|
const rl = createInterface2({ input: stdin2, output: stdout2 });
|
|
1304
1321
|
try {
|
|
1305
|
-
console.log(
|
|
1322
|
+
console.log(`
|
|
1323
|
+
${chalk4.bold("AnrakLegal Sync")} ${chalk4.dim("\u2014 Setup")}
|
|
1324
|
+
`);
|
|
1306
1325
|
const apiUrl = await rl.question(
|
|
1307
1326
|
` AnrakLegal URL ${chalk4.dim("(https://anrak.legal)")}: `
|
|
1308
1327
|
) || "https://anrak.legal";
|
|
@@ -1396,10 +1415,6 @@ program.command("login").description("Re-authenticate with AnrakLegal").option("
|
|
|
1396
1415
|
});
|
|
1397
1416
|
program.command("start").description("Start watching for file changes and syncing").action(async () => {
|
|
1398
1417
|
const config = requireConfig();
|
|
1399
|
-
console.log(chalk4.bold.blue("\n AnrakLegal Sync\n"));
|
|
1400
|
-
log.info(`Watching: ${config.watchFolder}`);
|
|
1401
|
-
log.info(`Server: ${config.apiUrl}`);
|
|
1402
|
-
console.log("");
|
|
1403
1418
|
try {
|
|
1404
1419
|
await startWatching(config);
|
|
1405
1420
|
} catch (err) {
|
|
@@ -1409,10 +1424,9 @@ program.command("start").description("Start watching for file changes and syncin
|
|
|
1409
1424
|
});
|
|
1410
1425
|
program.command("push").description("One-time sync \u2014 upload all new/changed files, then exit").action(async () => {
|
|
1411
1426
|
const config = requireConfig();
|
|
1412
|
-
console.log(
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
console.log("");
|
|
1427
|
+
console.log(`
|
|
1428
|
+
${chalk4.bold("AnrakLegal Sync")} ${chalk4.dim("\u2014 Push")}
|
|
1429
|
+
`);
|
|
1416
1430
|
try {
|
|
1417
1431
|
await pushSync(config);
|
|
1418
1432
|
} catch (err) {
|
|
@@ -1423,32 +1437,42 @@ program.command("push").description("One-time sync \u2014 upload all new/changed
|
|
|
1423
1437
|
program.command("status").description("Show sync status").action(async () => {
|
|
1424
1438
|
const config = requireConfig();
|
|
1425
1439
|
const stats = getStats();
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
console.log(
|
|
1429
|
-
console.log(
|
|
1440
|
+
const cols = Math.min(process.stdout.columns || 60, 60);
|
|
1441
|
+
const line = chalk4.dim("\u2500".repeat(cols));
|
|
1442
|
+
console.log("");
|
|
1443
|
+
console.log(line);
|
|
1444
|
+
console.log(` ${chalk4.bold("AnrakLegal Sync")} ${chalk4.dim(`v${pkg.version}`)}`);
|
|
1445
|
+
console.log(line);
|
|
1446
|
+
console.log("");
|
|
1447
|
+
console.log(` ${chalk4.dim("Server")} ${config.apiUrl}`);
|
|
1448
|
+
console.log(` ${chalk4.dim("Watch folder")} ${config.watchFolder}`);
|
|
1449
|
+
console.log(` ${chalk4.dim("Config")} ${getConfigDir()}`);
|
|
1430
1450
|
console.log("");
|
|
1431
|
-
console.log(` Files tracked
|
|
1432
|
-
console.log(` Synced
|
|
1433
|
-
console.log(` Pending
|
|
1434
|
-
console.log(` Errors
|
|
1435
|
-
console.log(` Mapped folders
|
|
1451
|
+
console.log(` ${chalk4.dim("Files tracked")} ${stats.totalFiles}`);
|
|
1452
|
+
console.log(` ${chalk4.dim("Synced")} ${chalk4.green(stats.synced)}`);
|
|
1453
|
+
console.log(` ${chalk4.dim("Pending")} ${chalk4.yellow(stats.pending)}`);
|
|
1454
|
+
console.log(` ${chalk4.dim("Errors")} ${stats.errors > 0 ? chalk4.red(stats.errors) : stats.errors}`);
|
|
1455
|
+
console.log(` ${chalk4.dim("Mapped folders")} ${stats.mappedFolders}`);
|
|
1436
1456
|
try {
|
|
1437
1457
|
const cases = await listCases(config);
|
|
1438
|
-
console.log(
|
|
1439
|
-
Server cases
|
|
1440
|
-
console.log(` Auth
|
|
1458
|
+
console.log("");
|
|
1459
|
+
console.log(` ${chalk4.dim("Server cases")} ${cases.length}`);
|
|
1460
|
+
console.log(` ${chalk4.dim("Auth")} ${chalk4.green("valid")}`);
|
|
1441
1461
|
} catch {
|
|
1442
|
-
console.log(
|
|
1443
|
-
Auth
|
|
1462
|
+
console.log("");
|
|
1463
|
+
console.log(` ${chalk4.dim("Auth")} ${chalk4.red("expired")} ${chalk4.dim("\u2014 run")} anrak-sync login`);
|
|
1444
1464
|
}
|
|
1445
1465
|
console.log("");
|
|
1466
|
+
console.log(line);
|
|
1467
|
+
console.log("");
|
|
1446
1468
|
});
|
|
1447
1469
|
program.command("map").description("Show folder-to-case mappings").action(async () => {
|
|
1448
1470
|
const config = requireConfig();
|
|
1449
1471
|
const mappings = getAllMappings();
|
|
1450
1472
|
const entries = Object.entries(mappings);
|
|
1451
|
-
console.log(
|
|
1473
|
+
console.log(`
|
|
1474
|
+
${chalk4.bold("AnrakLegal Sync")} ${chalk4.dim("\u2014 Mappings")}
|
|
1475
|
+
`);
|
|
1452
1476
|
if (entries.length === 0) {
|
|
1453
1477
|
log.info("No mappings yet. Run `anrak-sync push` or `anrak-sync start` to create them.");
|
|
1454
1478
|
} else {
|