@hasna/configs 0.2.33 → 0.2.35

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.
@@ -90,14 +90,14 @@ import { join, relative } from "path";
90
90
  import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync, writeFileSync } from "fs";
91
91
  import { homedir as homedir2 } from "os";
92
92
  import { join as join2 } from "path";
93
- import { readdirSync as readdirSync2, existsSync as existsSync3 } from "fs";
94
- import { join as join3 } from "path";
95
- import { homedir as homedir3 } from "os";
93
+ import { readdirSync as readdirSync3, existsSync as existsSync6 } from "fs";
94
+ import { join as join6 } from "path";
95
+ import { homedir as homedir5 } from "os";
96
96
  import { hostname } from "os";
97
- import { homedir as homedir4 } from "os";
98
- import { join as join4 } from "path";
99
- import { join as join6, dirname } from "path";
100
- import { homedir as homedir5, platform } from "os";
97
+ import { homedir as homedir3 } from "os";
98
+ import { join as join3 } from "path";
99
+ import { join as join5, dirname } from "path";
100
+ import { homedir as homedir4, platform } from "os";
101
101
  function __accessProp2(key) {
102
102
  return this[key];
103
103
  }
@@ -1051,11 +1051,11 @@ function isSyncExcludedTable(table) {
1051
1051
  return SYNC_EXCLUDED_TABLE_PATTERNS.some((p) => p.test(table));
1052
1052
  }
1053
1053
  function discoverServices() {
1054
- const dataDir = join3(homedir3(), ".hasna");
1055
- if (!existsSync3(dataDir))
1054
+ const dataDir = join6(homedir5(), ".hasna");
1055
+ if (!existsSync6(dataDir))
1056
1056
  return [];
1057
1057
  try {
1058
- const entries = readdirSync2(dataDir, { withFileTypes: true });
1058
+ const entries = readdirSync3(dataDir, { withFileTypes: true });
1059
1059
  return entries.filter((e) => {
1060
1060
  if (!e.isDirectory())
1061
1061
  return false;
@@ -1067,30 +1067,30 @@ function discoverServices() {
1067
1067
  return [];
1068
1068
  }
1069
1069
  }
1070
- function discoverSyncableServices() {
1070
+ function discoverSyncableServices2() {
1071
1071
  const local = discoverServices();
1072
1072
  const pgSet = new Set(KNOWN_PG_SERVICES);
1073
1073
  return local.filter((s) => pgSet.has(s));
1074
1074
  }
1075
1075
  function getServiceDbPath(service) {
1076
- const dataDir = join3(homedir3(), ".hasna", service);
1077
- if (!existsSync3(dataDir))
1076
+ const dataDir = join6(homedir5(), ".hasna", service);
1077
+ if (!existsSync6(dataDir))
1078
1078
  return null;
1079
1079
  const candidates = [
1080
- join3(dataDir, `${service}.db`),
1081
- join3(dataDir, "data.db"),
1082
- join3(dataDir, "database.db")
1080
+ join6(dataDir, `${service}.db`),
1081
+ join6(dataDir, "data.db"),
1082
+ join6(dataDir, "database.db")
1083
1083
  ];
1084
1084
  try {
1085
- const files = readdirSync2(dataDir);
1085
+ const files = readdirSync3(dataDir);
1086
1086
  for (const f of files) {
1087
1087
  if (f.endsWith(".db") && !f.endsWith("-wal") && !f.endsWith("-shm")) {
1088
- candidates.push(join3(dataDir, f));
1088
+ candidates.push(join6(dataDir, f));
1089
1089
  }
1090
1090
  }
1091
1091
  } catch {}
1092
1092
  for (const p of candidates) {
1093
- if (existsSync3(p))
1093
+ if (existsSync6(p))
1094
1094
  return p;
1095
1095
  }
1096
1096
  return null;
@@ -1397,9 +1397,9 @@ async function syncTransfer(source, target, options, _direction) {
1397
1397
  const batch = rows.slice(offset, offset + batchSize);
1398
1398
  try {
1399
1399
  if (isAsyncAdapter(target)) {
1400
- await batchUpsertPg(target, table, columns, updateCols, pkColumns, batch, columns.includes(conflictColumn) ? conflictColumn : undefined);
1400
+ await batchUpsertPg(target, table, columns, updateCols, pkColumns, batch);
1401
1401
  } else {
1402
- batchUpsertSqlite(target, table, columns, updateCols, pkColumns, batch, columns.includes(conflictColumn) ? conflictColumn : undefined);
1402
+ batchUpsertSqlite(target, table, columns, updateCols, pkColumns, batch);
1403
1403
  }
1404
1404
  result.rowsWritten += batch.length;
1405
1405
  } catch (err) {
@@ -1446,7 +1446,7 @@ async function syncTransfer(source, target, options, _direction) {
1446
1446
  }
1447
1447
  return results;
1448
1448
  }
1449
- async function batchUpsertPg(target, table, columns, updateCols, primaryKeys, batch, conflictColumn) {
1449
+ async function batchUpsertPg(target, table, columns, updateCols, primaryKeys, batch) {
1450
1450
  if (batch.length === 0)
1451
1451
  return;
1452
1452
  const colList = columns.map((c) => `"${c}"`).join(", ");
@@ -1456,22 +1456,20 @@ async function batchUpsertPg(target, table, columns, updateCols, primaryKeys, ba
1456
1456
  }).join(", ");
1457
1457
  const pkList = primaryKeys.map((c) => `"${c}"`).join(", ");
1458
1458
  const setClause = updateCols.length > 0 ? updateCols.map((c) => `"${c}" = EXCLUDED."${c}"`).join(", ") : `"${primaryKeys[0]}" = EXCLUDED."${primaryKeys[0]}"`;
1459
- const whereClause = conflictColumn && updateCols.includes(conflictColumn) ? ` WHERE "${table}"."${conflictColumn}" IS NULL OR EXCLUDED."${conflictColumn}" >= "${table}"."${conflictColumn}"` : "";
1460
1459
  const sql = `INSERT INTO "${table}" (${colList}) VALUES ${valuePlaceholders}
1461
- ON CONFLICT (${pkList}) DO UPDATE SET ${setClause}${whereClause}`;
1460
+ ON CONFLICT (${pkList}) DO UPDATE SET ${setClause}`;
1462
1461
  const params = batch.flatMap((row) => columns.map((c) => row[c] ?? null));
1463
1462
  await target.run(sql, ...params);
1464
1463
  }
1465
- function batchUpsertSqlite(target, table, columns, updateCols, primaryKeys, batch, conflictColumn) {
1464
+ function batchUpsertSqlite(target, table, columns, updateCols, primaryKeys, batch) {
1466
1465
  if (batch.length === 0)
1467
1466
  return;
1468
1467
  const colList = columns.map((c) => `"${c}"`).join(", ");
1469
1468
  const valuePlaceholders = batch.map(() => `(${columns.map(() => "?").join(", ")})`).join(", ");
1470
1469
  const pkList = primaryKeys.map((c) => `"${c}"`).join(", ");
1471
1470
  const setClause = updateCols.length > 0 ? updateCols.map((c) => `"${c}" = EXCLUDED."${c}"`).join(", ") : `"${primaryKeys[0]}" = EXCLUDED."${primaryKeys[0]}"`;
1472
- const whereClause = conflictColumn && updateCols.includes(conflictColumn) ? ` WHERE "${table}"."${conflictColumn}" IS NULL OR EXCLUDED."${conflictColumn}" >= "${table}"."${conflictColumn}"` : "";
1473
1471
  const sql = `INSERT INTO "${table}" (${colList}) VALUES ${valuePlaceholders}
1474
- ON CONFLICT (${pkList}) DO UPDATE SET ${setClause}${whereClause}`;
1472
+ ON CONFLICT (${pkList}) DO UPDATE SET ${setClause}`;
1475
1473
  const params = batch.flatMap((row) => columns.map((c) => coerceForSqlite(row[c])));
1476
1474
  target.run(sql, ...params);
1477
1475
  }
@@ -1696,7 +1694,7 @@ class SyncProgressTracker {
1696
1694
  }
1697
1695
  }
1698
1696
  }
1699
- function registerCloudTools(server, serviceName, opts = {}) {
1697
+ function registerCloudTools(server, serviceName) {
1700
1698
  server.tool(`${serviceName}_cloud_status`, "Show cloud configuration and connection health", {}, async () => {
1701
1699
  const config = getCloudConfig();
1702
1700
  const lines = [
@@ -1729,13 +1727,8 @@ function registerCloudTools(server, serviceName, opts = {}) {
1729
1727
  isError: true
1730
1728
  };
1731
1729
  }
1732
- const local = new SqliteAdapter(opts.dbPath ?? getDbPath(serviceName));
1730
+ const local = new SqliteAdapter(getDbPath(serviceName));
1733
1731
  const cloud = new PgAdapterAsync(getConnectionString(serviceName));
1734
- if (opts.migrations?.length) {
1735
- for (const sql of opts.migrations) {
1736
- await cloud.run(sql);
1737
- }
1738
- }
1739
1732
  const tableList = tablesStr ? tablesStr.split(",").map((t) => t.trim()) : listSqliteTables(local);
1740
1733
  const results = await syncPush(local, cloud, { tables: tableList });
1741
1734
  local.close();
@@ -1757,7 +1750,7 @@ function registerCloudTools(server, serviceName, opts = {}) {
1757
1750
  isError: true
1758
1751
  };
1759
1752
  }
1760
- const local = new SqliteAdapter(opts.dbPath ?? getDbPath(serviceName));
1753
+ const local = new SqliteAdapter(getDbPath(serviceName));
1761
1754
  const cloud = new PgAdapterAsync(getConnectionString(serviceName));
1762
1755
  let tableList;
1763
1756
  if (tablesStr) {
@@ -10062,7 +10055,7 @@ See https://www.postgresql.org/docs/current/libpq-ssl.html for libpq SSL mode de
10062
10055
  __export2(exports_discover, {
10063
10056
  isSyncExcludedTable: () => isSyncExcludedTable,
10064
10057
  getServiceDbPath: () => getServiceDbPath,
10065
- discoverSyncableServices: () => discoverSyncableServices,
10058
+ discoverSyncableServices: () => discoverSyncableServices2,
10066
10059
  discoverServices: () => discoverServices,
10067
10060
  SYNC_EXCLUDED_TABLE_PATTERNS: () => SYNC_EXCLUDED_TABLE_PATTERNS,
10068
10061
  KNOWN_PG_SERVICES: () => KNOWN_PG_SERVICES
@@ -10117,15 +10110,13 @@ See https://www.postgresql.org/docs/current/libpq-ssl.html for libpq SSL mode de
10117
10110
  init_config();
10118
10111
  init_config();
10119
10112
  init_dotfile();
10120
- init_adapter();
10121
10113
  init_config();
10122
- init_discover();
10123
- AUTO_SYNC_CONFIG_PATH = join4(homedir4(), ".hasna", "cloud", "config.json");
10114
+ AUTO_SYNC_CONFIG_PATH = join3(homedir3(), ".hasna", "cloud", "config.json");
10124
10115
  init_config();
10125
10116
  init_adapter();
10126
10117
  init_dotfile();
10127
10118
  init_config();
10128
- CONFIG_DIR2 = join6(homedir5(), ".hasna", "cloud");
10119
+ CONFIG_DIR2 = join5(homedir4(), ".hasna", "cloud");
10129
10120
  init_adapter();
10130
10121
  init_config();
10131
10122
  init_discover();
@@ -10148,7 +10139,7 @@ __export(exports_database, {
10148
10139
  getDatabase: () => getDatabase
10149
10140
  });
10150
10141
  import { mkdirSync as mkdirSync3 } from "fs";
10151
- import { join as join5 } from "path";
10142
+ import { join as join4 } from "path";
10152
10143
  import { randomUUID } from "crypto";
10153
10144
  function getDbPath2() {
10154
10145
  if (process.env["HASNA_CONFIGS_DB_PATH"]) {
@@ -10159,9 +10150,9 @@ function getDbPath2() {
10159
10150
  }
10160
10151
  migrateDotfile("configs");
10161
10152
  const home = process.env["HOME"] || process.env["USERPROFILE"] || "~";
10162
- const dir = join5(home, ".hasna", "configs");
10153
+ const dir = join4(home, ".hasna", "configs");
10163
10154
  mkdirSync3(dir, { recursive: true });
10164
- return join5(dir, "configs.db");
10155
+ return join4(dir, "configs.db");
10165
10156
  }
10166
10157
  function uuid() {
10167
10158
  return randomUUID();
@@ -10508,7 +10499,7 @@ var init_template = __esm(() => {
10508
10499
 
10509
10500
  // src/lib/machine.ts
10510
10501
  import { arch as currentArch, homedir as homedir6, hostname as currentHostname, type as currentOsType } from "os";
10511
- import { existsSync as existsSync6 } from "fs";
10502
+ import { existsSync as existsSync5 } from "fs";
10512
10503
  import { join as join7 } from "path";
10513
10504
  function normalizeOsFamily(os) {
10514
10505
  const value = (os ?? "").trim().toLowerCase();
@@ -10525,7 +10516,7 @@ function detectMachineContext(overrides = {}) {
10525
10516
  const os = overrides.os ?? currentOsType();
10526
10517
  const osFamily = normalizeOsFamily(os);
10527
10518
  const bunBinDir = overrides.bun_bin_dir ?? join7(homeDir, ".bun", "bin");
10528
- const defaultBunPath = osFamily === "macos" && existsSync6(BREW_BUN_PATH) ? BREW_BUN_PATH : join7(bunBinDir, "bun");
10519
+ const defaultBunPath = osFamily === "macos" && existsSync5(BREW_BUN_PATH) ? BREW_BUN_PATH : join7(bunBinDir, "bun");
10529
10520
  return {
10530
10521
  id: "current-machine",
10531
10522
  hostname: overrides.hostname ?? currentHostname(),
@@ -10879,8 +10870,8 @@ var init_redact = __esm(() => {
10879
10870
  });
10880
10871
 
10881
10872
  // src/lib/sync-dir.ts
10882
- import { existsSync as existsSync8, readdirSync as readdirSync3, readFileSync as readFileSync3, statSync } from "fs";
10883
- import { join as join8, relative as relative2 } from "path";
10873
+ import { existsSync as existsSync9, readdirSync as readdirSync2, readFileSync as readFileSync3, statSync } from "fs";
10874
+ import { join as join9, relative as relative2 } from "path";
10884
10875
  import { homedir as homedir9 } from "os";
10885
10876
  function shouldSkip(p) {
10886
10877
  return SKIP.some((s) => p.includes(s));
@@ -10888,9 +10879,9 @@ function shouldSkip(p) {
10888
10879
  async function syncFromDir(dir, opts = {}) {
10889
10880
  const d = opts.db || getDatabase();
10890
10881
  const absDir = expandPath(dir);
10891
- if (!existsSync8(absDir))
10882
+ if (!existsSync9(absDir))
10892
10883
  return { added: 0, updated: 0, unchanged: 0, skipped: [`Not found: ${absDir}`] };
10893
- const files = opts.recursive !== false ? walkDir(absDir) : readdirSync3(absDir).map((f) => join8(absDir, f)).filter((f) => statSync(f).isFile());
10884
+ const files = opts.recursive !== false ? walkDir(absDir) : readdirSync2(absDir).map((f) => join9(absDir, f)).filter((f) => statSync(f).isFile());
10894
10885
  const result = { added: 0, updated: 0, unchanged: 0, skipped: [] };
10895
10886
  const home = homedir9();
10896
10887
  const allConfigs = listConfigs(undefined, d);
@@ -10944,8 +10935,8 @@ async function syncToDir(dir, opts = {}) {
10944
10935
  return result;
10945
10936
  }
10946
10937
  function walkDir(dir, files = []) {
10947
- for (const entry of readdirSync3(dir, { withFileTypes: true })) {
10948
- const full = join8(dir, entry.name);
10938
+ for (const entry of readdirSync2(dir, { withFileTypes: true })) {
10939
+ const full = join9(dir, entry.name);
10949
10940
  if (shouldSkip(full))
10950
10941
  continue;
10951
10942
  if (entry.isDirectory())
@@ -10979,8 +10970,8 @@ __export(exports_sync, {
10979
10970
  PROJECT_CONFIG_FILES: () => PROJECT_CONFIG_FILES,
10980
10971
  KNOWN_CONFIGS: () => KNOWN_CONFIGS
10981
10972
  });
10982
- import { existsSync as existsSync9, readdirSync as readdirSync5, readFileSync as readFileSync4 } from "fs";
10983
- import { extname, join as join9 } from "path";
10973
+ import { existsSync as existsSync10, readdirSync as readdirSync4, readFileSync as readFileSync4 } from "fs";
10974
+ import { extname, join as join10 } from "path";
10984
10975
  import { homedir as homedir10 } from "os";
10985
10976
  async function syncProject(opts) {
10986
10977
  const d = opts.db || getDatabase();
@@ -10990,8 +10981,8 @@ async function syncProject(opts) {
10990
10981
  const allConfigs = listConfigs(undefined, d);
10991
10982
  const machine = detectMachineContext();
10992
10983
  for (const pf of PROJECT_CONFIG_FILES) {
10993
- const abs = join9(absDir, pf.file);
10994
- if (!existsSync9(abs))
10984
+ const abs = join10(absDir, pf.file);
10985
+ if (!existsSync10(abs))
10995
10986
  continue;
10996
10987
  try {
10997
10988
  const rawContent = readFileSync4(abs, "utf-8");
@@ -11022,11 +11013,11 @@ async function syncProject(opts) {
11022
11013
  result.skipped.push(pf.file);
11023
11014
  }
11024
11015
  }
11025
- const rulesDir = join9(absDir, ".claude", "rules");
11026
- if (existsSync9(rulesDir)) {
11027
- const mdFiles = readdirSync5(rulesDir).filter((f) => f.endsWith(".md"));
11016
+ const rulesDir = join10(absDir, ".claude", "rules");
11017
+ if (existsSync10(rulesDir)) {
11018
+ const mdFiles = readdirSync4(rulesDir).filter((f) => f.endsWith(".md"));
11028
11019
  for (const f of mdFiles) {
11029
- const abs = join9(rulesDir, f);
11020
+ const abs = join10(rulesDir, f);
11030
11021
  const raw2 = readFileSync4(abs, "utf-8");
11031
11022
  const redacted = redactContent(raw2, "markdown");
11032
11023
  const machineAware = templateizeMachineContent(redacted.content, machine);
@@ -11065,13 +11056,13 @@ async function syncKnown(opts = {}) {
11065
11056
  for (const known of targets) {
11066
11057
  if (known.rulesDir) {
11067
11058
  const absDir = expandPath(known.rulesDir);
11068
- if (!existsSync9(absDir)) {
11059
+ if (!existsSync10(absDir)) {
11069
11060
  result.skipped.push(known.rulesDir);
11070
11061
  continue;
11071
11062
  }
11072
- const mdFiles = readdirSync5(absDir).filter((f) => f.endsWith(".md"));
11063
+ const mdFiles = readdirSync4(absDir).filter((f) => f.endsWith(".md"));
11073
11064
  for (const f of mdFiles) {
11074
- const abs2 = join9(absDir, f);
11065
+ const abs2 = join10(absDir, f);
11075
11066
  const targetPath = abs2.replace(home, "~");
11076
11067
  const raw2 = readFileSync4(abs2, "utf-8");
11077
11068
  const redacted = redactContent(raw2, "markdown");
@@ -11096,7 +11087,7 @@ async function syncKnown(opts = {}) {
11096
11087
  continue;
11097
11088
  }
11098
11089
  const abs = expandPath(known.path);
11099
- if (!existsSync9(abs)) {
11090
+ if (!existsSync10(abs)) {
11100
11091
  result.skipped.push(known.path);
11101
11092
  continue;
11102
11093
  }
@@ -11161,7 +11152,7 @@ function diffConfig(config) {
11161
11152
  if (!config.target_path)
11162
11153
  return "(reference \u2014 no target path)";
11163
11154
  const path = expandPath(config.target_path);
11164
- if (!existsSync9(path))
11155
+ if (!existsSync10(path))
11165
11156
  return `(file not found on disk: ${path})`;
11166
11157
  const diskContent = readFileSync4(path, "utf-8");
11167
11158
  if (diskContent === config.content)
@@ -14281,6 +14272,9 @@ var require_data = __commonJS((exports, module) => {
14281
14272
  var require_utils3 = __commonJS((exports, module) => {
14282
14273
  var isUUID = RegExp.prototype.test.bind(/^[\da-f]{8}-[\da-f]{4}-[\da-f]{4}-[\da-f]{4}-[\da-f]{12}$/iu);
14283
14274
  var isIPv4 = RegExp.prototype.test.bind(/^(?:(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)$/u);
14275
+ var isHexPair = RegExp.prototype.test.bind(/^[\da-f]{2}$/iu);
14276
+ var isUnreserved = RegExp.prototype.test.bind(/^[\da-z\-._~]$/iu);
14277
+ var isPathCharacter = RegExp.prototype.test.bind(/^[\da-z\-._~!$&'()*+,;=:@/]$/iu);
14284
14278
  function stringArrayToHexStripped(input) {
14285
14279
  let acc = "";
14286
14280
  let code = 0;
@@ -14474,27 +14468,77 @@ var require_utils3 = __commonJS((exports, module) => {
14474
14468
  }
14475
14469
  return output.join("");
14476
14470
  }
14477
- function normalizeComponentEncoding(component, esc2) {
14478
- const func = esc2 !== true ? escape : unescape;
14479
- if (component.scheme !== undefined) {
14480
- component.scheme = func(component.scheme);
14481
- }
14482
- if (component.userinfo !== undefined) {
14483
- component.userinfo = func(component.userinfo);
14484
- }
14485
- if (component.host !== undefined) {
14486
- component.host = func(component.host);
14471
+ var HOST_DELIMS = { "@": "%40", "/": "%2F", "?": "%3F", "#": "%23", ":": "%3A" };
14472
+ var HOST_DELIM_RE = /[@/?#:]/g;
14473
+ var HOST_DELIM_NO_COLON_RE = /[@/?#]/g;
14474
+ function reescapeHostDelimiters(host, isIP) {
14475
+ const re = isIP ? HOST_DELIM_NO_COLON_RE : HOST_DELIM_RE;
14476
+ re.lastIndex = 0;
14477
+ return host.replace(re, (ch) => HOST_DELIMS[ch]);
14478
+ }
14479
+ function normalizePercentEncoding(input, decodeUnreserved = false) {
14480
+ if (input.indexOf("%") === -1) {
14481
+ return input;
14487
14482
  }
14488
- if (component.path !== undefined) {
14489
- component.path = func(component.path);
14483
+ let output = "";
14484
+ for (let i = 0;i < input.length; i++) {
14485
+ if (input[i] === "%" && i + 2 < input.length) {
14486
+ const hex = input.slice(i + 1, i + 3);
14487
+ if (isHexPair(hex)) {
14488
+ const normalizedHex = hex.toUpperCase();
14489
+ const decoded = String.fromCharCode(parseInt(normalizedHex, 16));
14490
+ if (decodeUnreserved && isUnreserved(decoded)) {
14491
+ output += decoded;
14492
+ } else {
14493
+ output += "%" + normalizedHex;
14494
+ }
14495
+ i += 2;
14496
+ continue;
14497
+ }
14498
+ }
14499
+ output += input[i];
14490
14500
  }
14491
- if (component.query !== undefined) {
14492
- component.query = func(component.query);
14501
+ return output;
14502
+ }
14503
+ function normalizePathEncoding(input) {
14504
+ let output = "";
14505
+ for (let i = 0;i < input.length; i++) {
14506
+ if (input[i] === "%" && i + 2 < input.length) {
14507
+ const hex = input.slice(i + 1, i + 3);
14508
+ if (isHexPair(hex)) {
14509
+ const normalizedHex = hex.toUpperCase();
14510
+ const decoded = String.fromCharCode(parseInt(normalizedHex, 16));
14511
+ if (decoded !== "." && isUnreserved(decoded)) {
14512
+ output += decoded;
14513
+ } else {
14514
+ output += "%" + normalizedHex;
14515
+ }
14516
+ i += 2;
14517
+ continue;
14518
+ }
14519
+ }
14520
+ if (isPathCharacter(input[i])) {
14521
+ output += input[i];
14522
+ } else {
14523
+ output += escape(input[i]);
14524
+ }
14493
14525
  }
14494
- if (component.fragment !== undefined) {
14495
- component.fragment = func(component.fragment);
14526
+ return output;
14527
+ }
14528
+ function escapePreservingEscapes(input) {
14529
+ let output = "";
14530
+ for (let i = 0;i < input.length; i++) {
14531
+ if (input[i] === "%" && i + 2 < input.length) {
14532
+ const hex = input.slice(i + 1, i + 3);
14533
+ if (isHexPair(hex)) {
14534
+ output += "%" + hex.toUpperCase();
14535
+ i += 2;
14536
+ continue;
14537
+ }
14538
+ }
14539
+ output += escape(input[i]);
14496
14540
  }
14497
- return component;
14541
+ return output;
14498
14542
  }
14499
14543
  function recomposeAuthority(component) {
14500
14544
  const uriTokens = [];
@@ -14509,7 +14553,7 @@ var require_utils3 = __commonJS((exports, module) => {
14509
14553
  if (ipV6res.isIPV6 === true) {
14510
14554
  host = `[${ipV6res.escapedHost}]`;
14511
14555
  } else {
14512
- host = component.host;
14556
+ host = reescapeHostDelimiters(host, false);
14513
14557
  }
14514
14558
  }
14515
14559
  uriTokens.push(host);
@@ -14523,7 +14567,10 @@ var require_utils3 = __commonJS((exports, module) => {
14523
14567
  module.exports = {
14524
14568
  nonSimpleDomain,
14525
14569
  recomposeAuthority,
14526
- normalizeComponentEncoding,
14570
+ reescapeHostDelimiters,
14571
+ normalizePercentEncoding,
14572
+ normalizePathEncoding,
14573
+ escapePreservingEscapes,
14527
14574
  removeDotSegments,
14528
14575
  isIPv4,
14529
14576
  isUUID,
@@ -14708,11 +14755,11 @@ var require_schemes = __commonJS((exports, module) => {
14708
14755
 
14709
14756
  // node_modules/fast-uri/index.js
14710
14757
  var require_fast_uri = __commonJS((exports, module) => {
14711
- var { normalizeIPv6, removeDotSegments, recomposeAuthority, normalizeComponentEncoding, isIPv4, nonSimpleDomain } = require_utils3();
14758
+ var { normalizeIPv6, removeDotSegments, recomposeAuthority, normalizePercentEncoding, normalizePathEncoding, escapePreservingEscapes, reescapeHostDelimiters, isIPv4, nonSimpleDomain } = require_utils3();
14712
14759
  var { SCHEMES, getSchemeHandler } = require_schemes();
14713
14760
  function normalize(uri, options) {
14714
14761
  if (typeof uri === "string") {
14715
- uri = serialize(parse5(uri, options), options);
14762
+ uri = normalizeString(uri, options);
14716
14763
  } else if (typeof uri === "object") {
14717
14764
  uri = parse5(serialize(uri, options), options);
14718
14765
  }
@@ -14778,19 +14825,9 @@ var require_fast_uri = __commonJS((exports, module) => {
14778
14825
  return target;
14779
14826
  }
14780
14827
  function equal(uriA, uriB, options) {
14781
- if (typeof uriA === "string") {
14782
- uriA = unescape(uriA);
14783
- uriA = serialize(normalizeComponentEncoding(parse5(uriA, options), true), { ...options, skipEscape: true });
14784
- } else if (typeof uriA === "object") {
14785
- uriA = serialize(normalizeComponentEncoding(uriA, true), { ...options, skipEscape: true });
14786
- }
14787
- if (typeof uriB === "string") {
14788
- uriB = unescape(uriB);
14789
- uriB = serialize(normalizeComponentEncoding(parse5(uriB, options), true), { ...options, skipEscape: true });
14790
- } else if (typeof uriB === "object") {
14791
- uriB = serialize(normalizeComponentEncoding(uriB, true), { ...options, skipEscape: true });
14792
- }
14793
- return uriA.toLowerCase() === uriB.toLowerCase();
14828
+ const normalizedA = normalizeComparableURI(uriA, options);
14829
+ const normalizedB = normalizeComparableURI(uriB, options);
14830
+ return normalizedA !== undefined && normalizedB !== undefined && normalizedA.toLowerCase() === normalizedB.toLowerCase();
14794
14831
  }
14795
14832
  function serialize(cmpts, opts) {
14796
14833
  const component = {
@@ -14816,12 +14853,12 @@ var require_fast_uri = __commonJS((exports, module) => {
14816
14853
  schemeHandler.serialize(component, options);
14817
14854
  if (component.path !== undefined) {
14818
14855
  if (!options.skipEscape) {
14819
- component.path = escape(component.path);
14856
+ component.path = escapePreservingEscapes(component.path);
14820
14857
  if (component.scheme !== undefined) {
14821
14858
  component.path = component.path.split("%3A").join(":");
14822
14859
  }
14823
14860
  } else {
14824
- component.path = unescape(component.path);
14861
+ component.path = normalizePercentEncoding(component.path);
14825
14862
  }
14826
14863
  }
14827
14864
  if (options.reference !== "suffix" && component.scheme) {
@@ -14856,7 +14893,16 @@ var require_fast_uri = __commonJS((exports, module) => {
14856
14893
  return uriTokens.join("");
14857
14894
  }
14858
14895
  var URI_PARSE = /^(?:([^#/:?]+):)?(?:\/\/((?:([^#/?@]*)@)?(\[[^#/?\]]+\]|[^#/:?]*)(?::(\d*))?))?([^#?]*)(?:\?([^#]*))?(?:#((?:.|[\n\r])*))?/u;
14859
- function parse5(uri, opts) {
14896
+ function getParseError(parsed, matches) {
14897
+ if (matches[2] !== undefined && parsed.path && parsed.path[0] !== "/") {
14898
+ return 'URI path must start with "/" when authority is present.';
14899
+ }
14900
+ if (typeof parsed.port === "number" && (parsed.port < 0 || parsed.port > 65535)) {
14901
+ return "URI port is malformed.";
14902
+ }
14903
+ return;
14904
+ }
14905
+ function parseWithStatus(uri, opts) {
14860
14906
  const options = Object.assign({}, opts);
14861
14907
  const parsed = {
14862
14908
  scheme: undefined,
@@ -14867,6 +14913,7 @@ var require_fast_uri = __commonJS((exports, module) => {
14867
14913
  query: undefined,
14868
14914
  fragment: undefined
14869
14915
  };
14916
+ let malformedAuthorityOrPort = false;
14870
14917
  let isIP = false;
14871
14918
  if (options.reference === "suffix") {
14872
14919
  if (options.scheme) {
@@ -14887,6 +14934,11 @@ var require_fast_uri = __commonJS((exports, module) => {
14887
14934
  if (isNaN(parsed.port)) {
14888
14935
  parsed.port = matches[5];
14889
14936
  }
14937
+ const parseError = getParseError(parsed, matches);
14938
+ if (parseError !== undefined) {
14939
+ parsed.error = parsed.error || parseError;
14940
+ malformedAuthorityOrPort = true;
14941
+ }
14890
14942
  if (parsed.host) {
14891
14943
  const ipv4result = isIPv4(parsed.host);
14892
14944
  if (ipv4result === false) {
@@ -14925,14 +14977,18 @@ var require_fast_uri = __commonJS((exports, module) => {
14925
14977
  parsed.scheme = unescape(parsed.scheme);
14926
14978
  }
14927
14979
  if (parsed.host !== undefined) {
14928
- parsed.host = unescape(parsed.host);
14980
+ parsed.host = reescapeHostDelimiters(unescape(parsed.host), isIP);
14929
14981
  }
14930
14982
  }
14931
14983
  if (parsed.path) {
14932
- parsed.path = escape(unescape(parsed.path));
14984
+ parsed.path = normalizePathEncoding(parsed.path);
14933
14985
  }
14934
14986
  if (parsed.fragment) {
14935
- parsed.fragment = encodeURI(decodeURIComponent(parsed.fragment));
14987
+ try {
14988
+ parsed.fragment = encodeURI(decodeURIComponent(parsed.fragment));
14989
+ } catch {
14990
+ parsed.error = parsed.error || "URI malformed";
14991
+ }
14936
14992
  }
14937
14993
  }
14938
14994
  if (schemeHandler && schemeHandler.parse) {
@@ -14941,7 +14997,29 @@ var require_fast_uri = __commonJS((exports, module) => {
14941
14997
  } else {
14942
14998
  parsed.error = parsed.error || "URI can not be parsed.";
14943
14999
  }
14944
- return parsed;
15000
+ return { parsed, malformedAuthorityOrPort };
15001
+ }
15002
+ function parse5(uri, opts) {
15003
+ return parseWithStatus(uri, opts).parsed;
15004
+ }
15005
+ function normalizeString(uri, opts) {
15006
+ return normalizeStringWithStatus(uri, opts).normalized;
15007
+ }
15008
+ function normalizeStringWithStatus(uri, opts) {
15009
+ const { parsed, malformedAuthorityOrPort } = parseWithStatus(uri, opts);
15010
+ return {
15011
+ normalized: malformedAuthorityOrPort ? uri : serialize(parsed, opts),
15012
+ malformedAuthorityOrPort
15013
+ };
15014
+ }
15015
+ function normalizeComparableURI(uri, opts) {
15016
+ if (typeof uri === "string") {
15017
+ const { normalized, malformedAuthorityOrPort } = normalizeStringWithStatus(uri, opts);
15018
+ return malformedAuthorityOrPort ? undefined : normalized;
15019
+ }
15020
+ if (typeof uri === "object") {
15021
+ return serialize(uri, opts);
15022
+ }
14945
15023
  }
14946
15024
  var fastUri = {
14947
15025
  SCHEMES,
@@ -15076,7 +15154,7 @@ var require_core = __commonJS((exports) => {
15076
15154
  constructor(opts = {}) {
15077
15155
  this.schemas = {};
15078
15156
  this.refs = {};
15079
- this.formats = {};
15157
+ this.formats = Object.create(null);
15080
15158
  this._compilations = new Set;
15081
15159
  this._loading = {};
15082
15160
  this._cache = new Map;
@@ -17751,7 +17829,7 @@ var require_dist2 = __commonJS((exports, module) => {
17751
17829
  var require_package = __commonJS((exports, module) => {
17752
17830
  module.exports = {
17753
17831
  name: "@hasna/configs",
17754
- version: "0.2.33",
17832
+ version: "0.2.35",
17755
17833
  description: "AI coding agent configuration manager \u2014 store, version, apply, and share all your AI coding configs. CLI + MCP + REST API + Dashboard.",
17756
17834
  type: "module",
17757
17835
  main: "dist/index.js",
@@ -17816,7 +17894,8 @@ var require_package = __commonJS((exports, module) => {
17816
17894
  author: "Andrei Hasna <andrei@hasna.com>",
17817
17895
  license: "Apache-2.0",
17818
17896
  dependencies: {
17819
- "@hasna/cloud": "^0.1.24",
17897
+ "@hasna/cloud": "0.1.24",
17898
+ "@hasna/events": "^0.1.6",
17820
17899
  "@modelcontextprotocol/sdk": "^1.12.1",
17821
17900
  chalk: "^5.4.1",
17822
17901
  commander: "^13.1.0",
@@ -18205,7 +18284,7 @@ var HonoRequest = class {
18205
18284
  return headerData;
18206
18285
  }
18207
18286
  async parseBody(options) {
18208
- return this.bodyCache.parsedBody ??= await parseBody(this, options);
18287
+ return parseBody(this, options);
18209
18288
  }
18210
18289
  #cachedBody = (key) => {
18211
18290
  const { bodyCache, raw } = this;
@@ -18233,6 +18312,9 @@ var HonoRequest = class {
18233
18312
  arrayBuffer() {
18234
18313
  return this.#cachedBody("arrayBuffer");
18235
18314
  }
18315
+ bytes() {
18316
+ return this.#cachedBody("arrayBuffer").then((buffer) => new Uint8Array(buffer));
18317
+ }
18236
18318
  blob() {
18237
18319
  return this.#cachedBody("blob");
18238
18320
  }
@@ -18569,7 +18651,7 @@ var Hono = class _Hono {
18569
18651
  handler = async (c, next) => (await compose([], app.errorHandler)(c, () => r.handler(c, next))).res;
18570
18652
  handler[COMPOSED_HANDLER] = r.handler;
18571
18653
  }
18572
- subApp.#addRoute(r.method, r.path, handler);
18654
+ subApp.#addRoute(r.method, r.path, handler, r.basePath);
18573
18655
  });
18574
18656
  return this;
18575
18657
  }
@@ -18616,7 +18698,7 @@ var Hono = class _Hono {
18616
18698
  const pathPrefixLength = mergedPath === "/" ? 0 : mergedPath.length;
18617
18699
  return (request) => {
18618
18700
  const url = new URL(request.url);
18619
- url.pathname = url.pathname.slice(pathPrefixLength) || "/";
18701
+ url.pathname = this.getPath(request).slice(pathPrefixLength) || "/";
18620
18702
  return new Request(url, request);
18621
18703
  };
18622
18704
  })();
@@ -18630,10 +18712,15 @@ var Hono = class _Hono {
18630
18712
  this.#addRoute(METHOD_NAME_ALL, mergePath(path, "*"), handler);
18631
18713
  return this;
18632
18714
  }
18633
- #addRoute(method, path, handler) {
18715
+ #addRoute(method, path, handler, baseRoutePath) {
18634
18716
  method = method.toUpperCase();
18635
18717
  path = mergePath(this._basePath, path);
18636
- const r = { basePath: this._basePath, path, method, handler };
18718
+ const r = {
18719
+ basePath: baseRoutePath !== undefined ? mergePath(this._basePath, baseRoutePath) : this._basePath,
18720
+ path,
18721
+ method,
18722
+ handler
18723
+ };
18637
18724
  this.router.add(method, path, [handler, r]);
18638
18725
  this.routes.push(r);
18639
18726
  }
@@ -19373,14 +19460,11 @@ var Hono2 = class extends Hono {
19373
19460
 
19374
19461
  // node_modules/hono/dist/middleware/cors/index.js
19375
19462
  var cors = (options) => {
19376
- const defaults = {
19463
+ const opts = {
19377
19464
  origin: "*",
19378
19465
  allowMethods: ["GET", "HEAD", "PUT", "POST", "DELETE", "PATCH"],
19379
19466
  allowHeaders: [],
19380
- exposeHeaders: []
19381
- };
19382
- const opts = {
19383
- ...defaults,
19467
+ exposeHeaders: [],
19384
19468
  ...options
19385
19469
  };
19386
19470
  const findAllowOrigin = ((optsOrigin) => {
@@ -23329,7 +23413,7 @@ var AssertObjectSchema = custom2((v) => v !== null && (typeof v === "object" ||
23329
23413
  var ProgressTokenSchema = union([string2(), number2().int()]);
23330
23414
  var CursorSchema = string2();
23331
23415
  var TaskCreationParamsSchema = looseObject({
23332
- ttl: union([number2(), _null3()]).optional(),
23416
+ ttl: number2().optional(),
23333
23417
  pollInterval: number2().optional()
23334
23418
  });
23335
23419
  var TaskMetadataSchema = object({
@@ -23483,7 +23567,8 @@ var ClientCapabilitiesSchema = object({
23483
23567
  roots: object({
23484
23568
  listChanged: boolean2().optional()
23485
23569
  }).optional(),
23486
- tasks: ClientTasksCapabilitySchema.optional()
23570
+ tasks: ClientTasksCapabilitySchema.optional(),
23571
+ extensions: record(string2(), AssertObjectSchema).optional()
23487
23572
  });
23488
23573
  var InitializeRequestParamsSchema = BaseRequestParamsSchema.extend({
23489
23574
  protocolVersion: string2(),
@@ -23509,7 +23594,8 @@ var ServerCapabilitiesSchema = object({
23509
23594
  tools: object({
23510
23595
  listChanged: boolean2().optional()
23511
23596
  }).optional(),
23512
- tasks: ServerTasksCapabilitySchema.optional()
23597
+ tasks: ServerTasksCapabilitySchema.optional(),
23598
+ extensions: record(string2(), AssertObjectSchema).optional()
23513
23599
  });
23514
23600
  var InitializeResultSchema = ResultSchema.extend({
23515
23601
  protocolVersion: string2(),
@@ -23624,6 +23710,7 @@ var ResourceSchema = object({
23624
23710
  uri: string2(),
23625
23711
  description: optional(string2()),
23626
23712
  mimeType: optional(string2()),
23713
+ size: optional(number2()),
23627
23714
  annotations: AnnotationsSchema.optional(),
23628
23715
  _meta: optional(looseObject({}))
23629
23716
  });
@@ -24981,6 +25068,10 @@ class Protocol {
24981
25068
  this._progressHandlers.clear();
24982
25069
  this._taskProgressTokens.clear();
24983
25070
  this._pendingDebouncedNotifications.clear();
25071
+ for (const info of this._timeoutInfo.values()) {
25072
+ clearTimeout(info.timeoutId);
25073
+ }
25074
+ this._timeoutInfo.clear();
24984
25075
  for (const controller of this._requestHandlerAbortControllers.values()) {
24985
25076
  controller.abort();
24986
25077
  }
@@ -25111,7 +25202,9 @@ class Protocol {
25111
25202
  await capturedTransport?.send(errorResponse);
25112
25203
  }
25113
25204
  }).catch((error2) => this._onerror(new Error(`Failed to send response: ${error2}`))).finally(() => {
25114
- this._requestHandlerAbortControllers.delete(request.id);
25205
+ if (this._requestHandlerAbortControllers.get(request.id) === abortController) {
25206
+ this._requestHandlerAbortControllers.delete(request.id);
25207
+ }
25115
25208
  });
25116
25209
  }
25117
25210
  _onprogress(notification) {
@@ -26429,8 +26522,8 @@ function mountMcpHttpRoutes(app) {
26429
26522
  }
26430
26523
 
26431
26524
  // src/server/index.ts
26432
- import { existsSync as existsSync10, readFileSync as readFileSync5 } from "fs";
26433
- import { join as join10, extname as extname2 } from "path";
26525
+ import { existsSync as existsSync11, readFileSync as readFileSync5 } from "fs";
26526
+ import { join as join11, extname as extname2 } from "path";
26434
26527
  var PORT = Number(process.env["CONFIGS_PORT"] ?? 3457);
26435
26528
  function pickFields(obj, fields) {
26436
26529
  if (!fields)
@@ -26724,12 +26817,12 @@ mountMcpHttpRoutes(app);
26724
26817
  var MIME = { ".html": "text/html", ".js": "application/javascript", ".css": "text/css", ".json": "application/json", ".svg": "image/svg+xml", ".png": "image/png", ".ico": "image/x-icon" };
26725
26818
  function findDashboardDir() {
26726
26819
  const candidates = [
26727
- join10(import.meta.dir, "../../dashboard/dist"),
26728
- join10(import.meta.dir, "../dashboard/dist"),
26729
- join10(import.meta.dir, "../../../dashboard/dist")
26820
+ join11(import.meta.dir, "../../dashboard/dist"),
26821
+ join11(import.meta.dir, "../dashboard/dist"),
26822
+ join11(import.meta.dir, "../../../dashboard/dist")
26730
26823
  ];
26731
26824
  for (const dir of candidates) {
26732
- if (existsSync10(join10(dir, "index.html")))
26825
+ if (existsSync11(join11(dir, "index.html")))
26733
26826
  return dir;
26734
26827
  }
26735
26828
  return null;
@@ -26740,12 +26833,12 @@ if (dashDir) {
26740
26833
  app.get("/*", (c) => {
26741
26834
  const url = new URL(c.req.url);
26742
26835
  let filePath = url.pathname === "/" ? "/index.html" : url.pathname;
26743
- let absPath = __require("path").resolve(join10(dashDir, filePath));
26836
+ let absPath = __require("path").resolve(join11(dashDir, filePath));
26744
26837
  if (!absPath.startsWith(resolvedDashDir))
26745
26838
  return c.json({ error: "Forbidden" }, 403);
26746
- if (!existsSync10(absPath))
26747
- absPath = join10(dashDir, "index.html");
26748
- if (!existsSync10(absPath))
26839
+ if (!existsSync11(absPath))
26840
+ absPath = join11(dashDir, "index.html");
26841
+ if (!existsSync11(absPath))
26749
26842
  return c.json({ error: "Not found" }, 404);
26750
26843
  const content = readFileSync5(absPath);
26751
26844
  const ext = extname2(absPath);