@anraktech/sync 0.7.0 → 0.8.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.
Files changed (2) hide show
  1. package/dist/cli.js +92 -65
  2. 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(`${PREFIX} ${msg}`),
21
- success: (msg) => console.log(`${PREFIX} ${chalk.green("\u2713")} ${msg}`),
22
- warn: (msg) => console.log(`${PREFIX} ${chalk.yellow("\u26A0")} ${msg}`),
23
- error: (msg) => console.error(`${PREFIX} ${chalk.red("\u2717")} ${msg}`),
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(`${PREFIX} ${chalk.gray(msg)}`);
24
+ if (process.env.ANRAK_DEBUG) console.log(chalk.dim(` ${msg}`));
26
25
  },
27
- dim: (msg) => console.log(`${PREFIX} ${chalk.dim(msg)}`),
28
- file: (action, path) => console.log(`${PREFIX} ${chalk.cyan(action)} ${chalk.dim(path)}`)
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 basename4, resolve as resolve2 } from "path";
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
- process.stdout.write(chalk2.dim(` \u27F3 ${tc.name}...
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(chalk2.bold(" AnrakLegal Sync"));
974
- console.log(chalk2.dim(` Watching ${ctx.config.watchFolder}`));
975
- console.log(chalk2.dim(` Connected to ${ctx.config.apiUrl}`));
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
- log.info(
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 = basename4(path);
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 = basename4(path);
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);
@@ -1239,18 +1261,16 @@ async function fetchLatestVersion() {
1239
1261
  }
1240
1262
  }
1241
1263
  function performUpdate(currentVersion, latestVersion) {
1242
- console.log("");
1243
1264
  console.log(
1244
- chalk3.dim(` Update available: ${currentVersion} \u2192 `) + chalk3.green(latestVersion)
1265
+ chalk3.dim(`
1266
+ Update available: ${currentVersion} \u2192 `) + chalk3.green(latestVersion) + chalk3.dim(" \xB7 installing...")
1245
1267
  );
1246
- console.log(chalk3.dim(" Updating..."));
1247
1268
  try {
1248
1269
  execFileSync("npm", ["install", "-g", `${PACKAGE_NAME}@${latestVersion}`], {
1249
1270
  stdio: "pipe",
1250
1271
  timeout: 6e4
1251
1272
  });
1252
- console.log(chalk3.green(" Updated successfully. Restart to use the new version."));
1253
- console.log("");
1273
+ console.log(chalk3.green(" \u2713 Updated. Restart to use the new version.\n"));
1254
1274
  return true;
1255
1275
  } catch {
1256
1276
  try {
@@ -1263,9 +1283,9 @@ function performUpdate(currentVersion, latestVersion) {
1263
1283
  return true;
1264
1284
  } catch {
1265
1285
  console.log(
1266
- chalk3.dim(" Auto-update failed. Run manually: ") + chalk3.cyan(`npm install -g ${PACKAGE_NAME}`)
1286
+ chalk3.dim(" Update failed. Run: ") + chalk3.cyan(`npm i -g ${PACKAGE_NAME}
1287
+ `)
1267
1288
  );
1268
- console.log("");
1269
1289
  return false;
1270
1290
  }
1271
1291
  }
@@ -1290,19 +1310,21 @@ async function checkForUpdates(currentVersion) {
1290
1310
  }
1291
1311
 
1292
1312
  // src/cli.ts
1293
- import { readFileSync as readFileSync2 } from "fs";
1294
- import { fileURLToPath } from "url";
1295
- import { dirname as dirname2, join as join4 } from "path";
1296
- var __filename2 = fileURLToPath(import.meta.url);
1297
- var __dirname2 = dirname2(__filename2);
1298
- var pkg = JSON.parse(readFileSync2(join4(__dirname2, "..", "package.json"), "utf-8"));
1313
+ import { readFileSync as readFileSync3 } from "fs";
1314
+ import { fileURLToPath as fileURLToPath2 } from "url";
1315
+ import { dirname as dirname3, join as join4 } from "path";
1316
+ var __filename3 = fileURLToPath2(import.meta.url);
1317
+ var __dirname3 = dirname3(__filename3);
1318
+ var pkg = JSON.parse(readFileSync3(join4(__dirname3, "..", "package.json"), "utf-8"));
1299
1319
  await checkForUpdates(pkg.version);
1300
1320
  var program = new Command();
1301
1321
  program.name("anrak-sync").description("AnrakLegal desktop file sync \u2014 watches local folders, syncs to case management").version(pkg.version);
1302
1322
  program.command("init").description("Set up AnrakLegal Sync (first-time configuration)").option("--password", "Use email/password login instead of browser").action(async (opts) => {
1303
1323
  const rl = createInterface2({ input: stdin2, output: stdout2 });
1304
1324
  try {
1305
- console.log(chalk4.bold.blue("\n AnrakLegal Sync \u2014 Setup\n"));
1325
+ console.log(`
1326
+ ${chalk4.bold("AnrakLegal Sync")} ${chalk4.dim("\u2014 Setup")}
1327
+ `);
1306
1328
  const apiUrl = await rl.question(
1307
1329
  ` AnrakLegal URL ${chalk4.dim("(https://anrak.legal)")}: `
1308
1330
  ) || "https://anrak.legal";
@@ -1396,10 +1418,6 @@ program.command("login").description("Re-authenticate with AnrakLegal").option("
1396
1418
  });
1397
1419
  program.command("start").description("Start watching for file changes and syncing").action(async () => {
1398
1420
  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
1421
  try {
1404
1422
  await startWatching(config);
1405
1423
  } catch (err) {
@@ -1409,10 +1427,9 @@ program.command("start").description("Start watching for file changes and syncin
1409
1427
  });
1410
1428
  program.command("push").description("One-time sync \u2014 upload all new/changed files, then exit").action(async () => {
1411
1429
  const config = requireConfig();
1412
- console.log(chalk4.bold.blue("\n AnrakLegal Sync \u2014 Push\n"));
1413
- log.info(`Folder: ${config.watchFolder}`);
1414
- log.info(`Server: ${config.apiUrl}`);
1415
- console.log("");
1430
+ console.log(`
1431
+ ${chalk4.bold("AnrakLegal Sync")} ${chalk4.dim("\u2014 Push")}
1432
+ `);
1416
1433
  try {
1417
1434
  await pushSync(config);
1418
1435
  } catch (err) {
@@ -1423,32 +1440,42 @@ program.command("push").description("One-time sync \u2014 upload all new/changed
1423
1440
  program.command("status").description("Show sync status").action(async () => {
1424
1441
  const config = requireConfig();
1425
1442
  const stats = getStats();
1426
- console.log(chalk4.bold.blue("\n AnrakLegal Sync \u2014 Status\n"));
1427
- console.log(` Server: ${config.apiUrl}`);
1428
- console.log(` Watch folder: ${config.watchFolder}`);
1429
- console.log(` Config: ${getConfigDir()}`);
1443
+ const cols = Math.min(process.stdout.columns || 60, 60);
1444
+ const line = chalk4.dim("\u2500".repeat(cols));
1445
+ console.log("");
1446
+ console.log(line);
1447
+ console.log(` ${chalk4.bold("AnrakLegal Sync")} ${chalk4.dim(`v${pkg.version}`)}`);
1448
+ console.log(line);
1449
+ console.log("");
1450
+ console.log(` ${chalk4.dim("Server")} ${config.apiUrl}`);
1451
+ console.log(` ${chalk4.dim("Watch folder")} ${config.watchFolder}`);
1452
+ console.log(` ${chalk4.dim("Config")} ${getConfigDir()}`);
1430
1453
  console.log("");
1431
- console.log(` Files tracked: ${stats.totalFiles}`);
1432
- console.log(` Synced: ${chalk4.green(stats.synced)}`);
1433
- console.log(` Pending: ${chalk4.yellow(stats.pending)}`);
1434
- console.log(` Errors: ${chalk4.red(stats.errors)}`);
1435
- console.log(` Mapped folders: ${stats.mappedFolders}`);
1454
+ console.log(` ${chalk4.dim("Files tracked")} ${stats.totalFiles}`);
1455
+ console.log(` ${chalk4.dim("Synced")} ${chalk4.green(stats.synced)}`);
1456
+ console.log(` ${chalk4.dim("Pending")} ${chalk4.yellow(stats.pending)}`);
1457
+ console.log(` ${chalk4.dim("Errors")} ${stats.errors > 0 ? chalk4.red(stats.errors) : stats.errors}`);
1458
+ console.log(` ${chalk4.dim("Mapped folders")} ${stats.mappedFolders}`);
1436
1459
  try {
1437
1460
  const cases = await listCases(config);
1438
- console.log(`
1439
- Server cases: ${cases.length}`);
1440
- console.log(` Auth: ${chalk4.green("valid")}`);
1461
+ console.log("");
1462
+ console.log(` ${chalk4.dim("Server cases")} ${cases.length}`);
1463
+ console.log(` ${chalk4.dim("Auth")} ${chalk4.green("valid")}`);
1441
1464
  } catch {
1442
- console.log(`
1443
- Auth: ${chalk4.red("expired \u2014 run anrak-sync login")}`);
1465
+ console.log("");
1466
+ console.log(` ${chalk4.dim("Auth")} ${chalk4.red("expired")} ${chalk4.dim("\u2014 run")} anrak-sync login`);
1444
1467
  }
1445
1468
  console.log("");
1469
+ console.log(line);
1470
+ console.log("");
1446
1471
  });
1447
1472
  program.command("map").description("Show folder-to-case mappings").action(async () => {
1448
1473
  const config = requireConfig();
1449
1474
  const mappings = getAllMappings();
1450
1475
  const entries = Object.entries(mappings);
1451
- console.log(chalk4.bold.blue("\n AnrakLegal Sync \u2014 Mappings\n"));
1476
+ console.log(`
1477
+ ${chalk4.bold("AnrakLegal Sync")} ${chalk4.dim("\u2014 Mappings")}
1478
+ `);
1452
1479
  if (entries.length === 0) {
1453
1480
  log.info("No mappings yet. Run `anrak-sync push` or `anrak-sync start` to create them.");
1454
1481
  } else {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@anraktech/sync",
3
- "version": "0.7.0",
3
+ "version": "0.8.0",
4
4
  "description": "AnrakLegal desktop file sync agent — watches local folders and syncs to case management",
5
5
  "type": "module",
6
6
  "bin": {