@anraktech/sync 0.11.0 → 0.12.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 +158 -7
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -1184,12 +1184,152 @@ function startAIAgent(ctx) {
1184
1184
  console.log(row(`${chalk2.dim("Status")} ${statusLine}`));
1185
1185
  }
1186
1186
  console.log(empty);
1187
- console.log(row(chalk2.dim("Type naturally to manage your files.")));
1188
- console.log(row(chalk2.dim('"show my cases" \xB7 "look at downloads" \xB7 "sync"')));
1187
+ console.log(row(chalk2.dim("Type naturally, or use / commands.")));
1188
+ console.log(row(chalk2.dim("Type /help to see all commands.")));
1189
1189
  console.log(empty);
1190
1190
  console.log(bot);
1191
1191
  console.log("");
1192
1192
  const PROMPT = `${chalk2.bold.blue("\u276F")} `;
1193
+ const slashCommands = {
1194
+ help: {
1195
+ description: "Show all commands",
1196
+ handler: () => {
1197
+ const W2 = Math.min(process.stdout.columns || 60, 60);
1198
+ console.log("");
1199
+ console.log(chalk2.bold(" Commands"));
1200
+ console.log(chalk2.dim(" " + "\u2500".repeat(W2 - 4)));
1201
+ for (const [cmd, { description }] of Object.entries(slashCommands)) {
1202
+ const label = chalk2.cyan(`/${cmd}`);
1203
+ const dots = chalk2.dim(".".repeat(Math.max(2, 18 - cmd.length)));
1204
+ console.log(` ${label} ${dots} ${chalk2.dim(description)}`);
1205
+ }
1206
+ console.log("");
1207
+ console.log(chalk2.dim(" Or just type naturally \u2014 the AI understands plain English."));
1208
+ }
1209
+ },
1210
+ cases: {
1211
+ description: "List your legal cases",
1212
+ handler: async () => {
1213
+ try {
1214
+ await ctx.refreshCases();
1215
+ const cases = ctx.getCases();
1216
+ if (cases.length === 0) {
1217
+ console.log(chalk2.dim(" No cases found."));
1218
+ return;
1219
+ }
1220
+ console.log("");
1221
+ console.log(chalk2.bold(` ${cases.length} case${cases.length !== 1 ? "s" : ""}`));
1222
+ console.log(chalk2.dim(" " + "\u2500".repeat(40)));
1223
+ for (const c of cases) {
1224
+ const docs = c.documents?.length ?? 0;
1225
+ console.log(` ${chalk2.cyan(c.caseNumber)} ${c.caseName} ${chalk2.dim(`${docs} docs`)}`);
1226
+ }
1227
+ } catch (err) {
1228
+ console.log(chalk2.red(` Error: ${err instanceof Error ? err.message : String(err)}`));
1229
+ }
1230
+ }
1231
+ },
1232
+ status: {
1233
+ description: "Show sync status",
1234
+ handler: () => {
1235
+ const s = getStats();
1236
+ const q = queueSize();
1237
+ console.log("");
1238
+ console.log(chalk2.bold(" Sync Status"));
1239
+ console.log(chalk2.dim(" " + "\u2500".repeat(30)));
1240
+ console.log(` ${chalk2.dim("Files tracked")} ${s.totalFiles}`);
1241
+ console.log(` ${chalk2.dim("Synced")} ${chalk2.green(s.synced)}`);
1242
+ console.log(` ${chalk2.dim("Pending")} ${chalk2.yellow(s.pending)}`);
1243
+ console.log(` ${chalk2.dim("Errors")} ${s.errors > 0 ? chalk2.red(s.errors) : s.errors}`);
1244
+ console.log(` ${chalk2.dim("Queue")} ${q}`);
1245
+ console.log(` ${chalk2.dim("Mapped folders")} ${s.mappedFolders}`);
1246
+ }
1247
+ },
1248
+ folder: {
1249
+ description: "Show watch folder path",
1250
+ handler: () => {
1251
+ console.log(` ${chalk2.dim("Watch folder")} ${ctx.config.watchFolder}`);
1252
+ console.log(` ${chalk2.dim("Config dir")} ${getConfigDir()}`);
1253
+ }
1254
+ },
1255
+ mappings: {
1256
+ description: "Show folder \u2192 case mappings",
1257
+ handler: () => {
1258
+ const mappings = getAllMappings();
1259
+ const entries = Object.entries(mappings);
1260
+ if (entries.length === 0) {
1261
+ console.log(chalk2.dim(" No mappings yet. Sync a folder to create one."));
1262
+ return;
1263
+ }
1264
+ console.log("");
1265
+ console.log(chalk2.bold(` ${entries.length} mapping${entries.length !== 1 ? "s" : ""}`));
1266
+ console.log(chalk2.dim(" " + "\u2500".repeat(40)));
1267
+ for (const [folder, m] of entries) {
1268
+ console.log(` ${chalk2.cyan(folder)} \u2192 ${m.caseNumber} ${chalk2.dim(`(${m.caseName})`)}`);
1269
+ }
1270
+ }
1271
+ },
1272
+ login: {
1273
+ description: "Re-authenticate with AnrakLegal",
1274
+ handler: async () => {
1275
+ try {
1276
+ log.info("Opening browser for login...");
1277
+ const tokens = await browserLogin(ctx.config.apiUrl);
1278
+ ctx.config.accessToken = tokens.accessToken;
1279
+ ctx.config.refreshToken = tokens.refreshToken;
1280
+ saveConfig(ctx.config);
1281
+ log.success("Logged in successfully");
1282
+ } catch (err) {
1283
+ console.log(chalk2.red(` Error: ${err instanceof Error ? err.message : String(err)}`));
1284
+ }
1285
+ }
1286
+ },
1287
+ logout: {
1288
+ description: "Clear stored credentials",
1289
+ handler: () => {
1290
+ ctx.config.accessToken = "";
1291
+ ctx.config.refreshToken = "";
1292
+ saveConfig(ctx.config);
1293
+ log.success("Logged out. Run /login to re-authenticate.");
1294
+ }
1295
+ },
1296
+ sync: {
1297
+ description: "Re-scan watch folder and sync",
1298
+ handler: async () => {
1299
+ try {
1300
+ await ctx.triggerScan();
1301
+ const s = getStats();
1302
+ if (s.pending === 0) {
1303
+ log.success("Everything up to date");
1304
+ } else {
1305
+ log.info(`${s.pending} file${s.pending !== 1 ? "s" : ""} pending sync`);
1306
+ }
1307
+ } catch (err) {
1308
+ console.log(chalk2.red(` Error: ${err instanceof Error ? err.message : String(err)}`));
1309
+ }
1310
+ }
1311
+ },
1312
+ clear: {
1313
+ description: "Clear conversation history",
1314
+ handler: () => {
1315
+ history.length = 1;
1316
+ console.log(chalk2.dim(" Conversation cleared."));
1317
+ }
1318
+ },
1319
+ reset: {
1320
+ description: "Clear sync cache (re-uploads on next sync)",
1321
+ handler: () => {
1322
+ resetCache();
1323
+ log.success("Cache cleared. Run /sync to re-sync.");
1324
+ }
1325
+ },
1326
+ quit: {
1327
+ description: "Exit AnrakLegal Sync",
1328
+ handler: () => {
1329
+ process.emit("SIGINT");
1330
+ }
1331
+ }
1332
+ };
1193
1333
  async function promptLoop() {
1194
1334
  while (true) {
1195
1335
  let input;
@@ -1200,15 +1340,26 @@ function startAIAgent(ctx) {
1200
1340
  }
1201
1341
  const trimmed = input.trim();
1202
1342
  if (!trimmed) continue;
1343
+ if (trimmed.startsWith("/")) {
1344
+ const cmd = trimmed.slice(1).toLowerCase().split(/\s+/)[0];
1345
+ if (slashCommands[cmd]) {
1346
+ await slashCommands[cmd].handler();
1347
+ console.log("");
1348
+ continue;
1349
+ }
1350
+ const matches = Object.keys(slashCommands).filter((k) => k.startsWith(cmd));
1351
+ if (matches.length > 0) {
1352
+ console.log(chalk2.dim(` Did you mean: ${matches.map((m) => chalk2.cyan(`/${m}`)).join(", ")}?`));
1353
+ } else {
1354
+ console.log(chalk2.dim(` Unknown command. Type ${chalk2.cyan("/help")} for available commands.`));
1355
+ }
1356
+ console.log("");
1357
+ continue;
1358
+ }
1203
1359
  if (/^(quit|exit|q)$/i.test(trimmed)) {
1204
1360
  process.emit("SIGINT");
1205
1361
  return;
1206
1362
  }
1207
- if (/^(clear|reset|new)$/i.test(trimmed)) {
1208
- history.length = 1;
1209
- console.log(chalk2.dim(" Conversation cleared.\n"));
1210
- continue;
1211
- }
1212
1363
  history.push({ role: "user", content: trimmed });
1213
1364
  while (history.length > 21) {
1214
1365
  history.splice(1, 1);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@anraktech/sync",
3
- "version": "0.11.0",
3
+ "version": "0.12.0",
4
4
  "description": "AnrakLegal desktop file sync agent — watches local folders and syncs to case management",
5
5
  "type": "module",
6
6
  "bin": {