@devicelink/dlink 0.3.0 → 0.3.1

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 (3) hide show
  1. package/index.js +230 -135
  2. package/index.js.map +4 -4
  3. package/package.json +1 -1
package/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // agent/src/cli/core/engine.ts
4
- import crypto4 from "node:crypto";
4
+ import crypto5 from "node:crypto";
5
5
 
6
6
  // agent/src/cli/core/types.ts
7
7
  var RuntimeFlags = class {
@@ -48,8 +48,8 @@ var Deferred = class {
48
48
  };
49
49
  this.rejectFn = () => {
50
50
  };
51
- this.promise = new Promise((resolve, reject) => {
52
- this.resolveFn = resolve;
51
+ this.promise = new Promise((resolve3, reject) => {
52
+ this.resolveFn = resolve3;
53
53
  this.rejectFn = reject;
54
54
  });
55
55
  }
@@ -272,8 +272,8 @@ var ConfigurationContext = class {
272
272
  };
273
273
 
274
274
  // agent/src/cli/utils/config.builder.ts
275
- import path2 from "node:path";
276
- import os2 from "node:os";
275
+ import path4 from "node:path";
276
+ import os3 from "node:os";
277
277
  import fs2 from "node:fs";
278
278
  import dotenv from "dotenv";
279
279
  import get2 from "lodash/get.js";
@@ -524,8 +524,8 @@ function canonicalizePath(input) {
524
524
  out = out.toLowerCase();
525
525
  return out;
526
526
  }
527
- function getDirectoryTag(path11, groups = [3, 3, 3, 3]) {
528
- const canonical = canonicalizePath(path11);
527
+ function getDirectoryTag(path13, groups = [3, 3, 3, 3]) {
528
+ const canonical = canonicalizePath(path13);
529
529
  const hash = crypto3.createHash("sha256").update(canonical, "utf8").digest("base64url");
530
530
  const clean = hash.replace(/[^a-zA-Z0-9]/g, "").toLowerCase();
531
531
  const needed = groups.reduce((a, b) => a + b, 0);
@@ -533,8 +533,8 @@ function getDirectoryTag(path11, groups = [3, 3, 3, 3]) {
533
533
  let i = 0;
534
534
  return groups.map((len) => padded.slice(i, i += len)).join("-");
535
535
  }
536
- function pathToUuidLikeSha256(path11) {
537
- const canonical = canonicalizePath(path11);
536
+ function pathToUuidLikeSha256(path13) {
537
+ const canonical = canonicalizePath(path13);
538
538
  const hex = crypto3.createHash("sha256").update(canonical, "utf8").digest("hex");
539
539
  const h = hex.slice(0, 32);
540
540
  const part1 = h.slice(0, 8);
@@ -545,6 +545,118 @@ function pathToUuidLikeSha256(path11) {
545
545
  return `${part1}-${part2}-${part3}-${part4}-${part5}`;
546
546
  }
547
547
 
548
+ // common/src/lib/utils/crypto.utils.ts
549
+ import * as crypto4 from "node:crypto";
550
+ function fingerprintFromPublicKeyPem(publicKeyPem) {
551
+ const keyObj = crypto4.createPublicKey(publicKeyPem);
552
+ if (keyObj.asymmetricKeyType !== "ed25519") {
553
+ throw new Error(`Unexpected key type: ${keyObj.asymmetricKeyType}`);
554
+ }
555
+ const spkiDer = keyObj.export({ format: "der", type: "spki" });
556
+ const hash = crypto4.createHash("sha256").update(spkiDer).digest("base64url");
557
+ return hash.slice(0, 16).toUpperCase();
558
+ }
559
+ function signConnect(params) {
560
+ const payload = Buffer.from(`${params.deviceId}|${params.ts}|${params.nonce}`, "utf8");
561
+ const key = crypto4.createPrivateKey(params.privateKeyPem);
562
+ const sig = crypto4.sign(null, payload, key);
563
+ return sig.toString("base64");
564
+ }
565
+ function signRefresh(params) {
566
+ const hash = crypto4.createHash("sha256").update(params.refreshToken, "utf8").digest("hex");
567
+ const payload = Buffer.from(`${params.deviceId}|${params.ts}|${params.nonce}|${hash}`, "utf8");
568
+ const key = crypto4.createPrivateKey(params.privateKeyPem);
569
+ const sig = crypto4.sign(null, payload, key);
570
+ return sig.toString("base64");
571
+ }
572
+
573
+ // common/src/lib/utils/async.utils.ts
574
+ function sleep(ms) {
575
+ return new Promise((resolve3) => setTimeout(resolve3, ms));
576
+ }
577
+
578
+ // common/src/lib/utils/path-display.utils.ts
579
+ import * as path2 from "node:path";
580
+ import * as os2 from "node:os";
581
+ function normalizeSlashes(s) {
582
+ return s.replace(/\\/g, "/");
583
+ }
584
+ function looksLikeWindowsDrivePath(s) {
585
+ return /^[A-Za-z]:[\\/]/.test(s) || /^[A-Za-z]:$/.test(s.trim());
586
+ }
587
+ function normalizeWindowsSeparatorsForMatch(s) {
588
+ if (!looksLikeWindowsDrivePath(s))
589
+ return s;
590
+ return s.replace(/\//g, "\\");
591
+ }
592
+ function toTildeHomePath(absolutePath) {
593
+ if (absolutePath == null)
594
+ return void 0;
595
+ const raw = String(absolutePath).trim();
596
+ if (raw === "")
597
+ return void 0;
598
+ if (raw.startsWith("~")) {
599
+ return normalizeSlashes(raw);
600
+ }
601
+ if (!looksLikeWindowsDrivePath(raw)) {
602
+ try {
603
+ const abs = path2.resolve(raw);
604
+ const home = path2.resolve(os2.homedir());
605
+ const rel = path2.relative(home, abs);
606
+ if (!rel.startsWith("..") && !path2.isAbsolute(rel)) {
607
+ if (rel === "")
608
+ return "~";
609
+ return "~/" + normalizeSlashes(rel);
610
+ }
611
+ } catch {
612
+ }
613
+ }
614
+ const win = normalizeWindowsSeparatorsForMatch(raw);
615
+ const winUsers = win.match(/^([A-Za-z]:)\\(?:[Uu][Ss][Ee][Rr][Ss])\\([^\\]+)(\\.*)?$/);
616
+ if (winUsers) {
617
+ const rest = (winUsers[3] ?? "").replace(/\\/g, "/");
618
+ return rest ? "~" + rest : "~";
619
+ }
620
+ const wsl = raw.match(/^\/mnt\/[a-z]\/(?:[Uu][Ss][Ee][Rr][Ss])\/[^/]+(\/.*)?$/i);
621
+ if (wsl) {
622
+ const rest = wsl[1] ?? "";
623
+ return rest ? "~" + normalizeSlashes(rest) : "~";
624
+ }
625
+ const mac = raw.match(/^\/Users\/[^/]+(\/.*)?$/);
626
+ if (mac) {
627
+ const rest = mac[1] ?? "";
628
+ return rest ? "~" + normalizeSlashes(rest) : "~";
629
+ }
630
+ const lin = raw.match(/^\/home\/[^/]+(\/.*)?$/);
631
+ if (lin) {
632
+ const rest = lin[1] ?? "";
633
+ return rest ? "~" + normalizeSlashes(rest) : "~";
634
+ }
635
+ const fbsd = raw.match(/^\/usr\/home\/[^/]+(\/.*)?$/);
636
+ if (fbsd) {
637
+ const rest = fbsd[1] ?? "";
638
+ return rest ? "~" + normalizeSlashes(rest) : "~";
639
+ }
640
+ const exp = raw.match(/^\/export\/home\/[^/]+(\/.*)?$/);
641
+ if (exp) {
642
+ const rest = exp[1] ?? "";
643
+ return rest ? "~" + normalizeSlashes(rest) : "~";
644
+ }
645
+ try {
646
+ return path2.basename(path2.resolve(raw));
647
+ } catch {
648
+ return raw.split(/[/\\]/).pop() ?? raw;
649
+ }
650
+ }
651
+
652
+ // common/src/lib/utils/path.utils.ts
653
+ import * as path3 from "node:path";
654
+ var isCaseInsensitiveFS = process.platform === "win32";
655
+ function pathDedupeKey(p) {
656
+ const resolved = path3.resolve(p);
657
+ return isCaseInsensitiveFS ? resolved.toLowerCase() : resolved;
658
+ }
659
+
548
660
  // agent/src/cli/utils/config.builder.ts
549
661
  var DEFAULT_CONFIG = {
550
662
  version: 1,
@@ -576,9 +688,9 @@ var ConfigLoader = class {
576
688
  loadProductionEnv() {
577
689
  const candidates = [
578
690
  // npm install: .env.production alongside index.js
579
- path2.resolve(path2.dirname(process.argv[1] ?? "."), ".env.production"),
691
+ path4.resolve(path4.dirname(process.argv[1] ?? "."), ".env.production"),
580
692
  // monorepo dev: agent/.env.production
581
- path2.resolve(process.cwd(), ".env.production")
693
+ path4.resolve(process.cwd(), ".env.production")
582
694
  ];
583
695
  for (const candidate of candidates) {
584
696
  try {
@@ -626,7 +738,7 @@ var ConfigLoader = class {
626
738
  withConfigFile(filename) {
627
739
  try {
628
740
  const configFolder = this.getApplicationConfigFolder();
629
- const configPath = path2.join(configFolder, filename);
741
+ const configPath = path4.join(configFolder, filename);
630
742
  if (fs2.existsSync(configPath)) {
631
743
  const raw = fs2.readFileSync(configPath, "utf8");
632
744
  const parsed = JSON.parse(raw);
@@ -664,36 +776,49 @@ var ConfigLoader = class {
664
776
  return this.argv?.bridgeWsUrl ?? this.safeGetEnvValue("DLINK_BRIDGE_URL") ?? this.safeGetConfigValue("bridgeWsUrl") ?? this.processEnv["DLINK_BRIDGE_URL"] ?? this.productionEnv["DLINK_BRIDGE_URL"] ?? void 0;
665
777
  }
666
778
  getDirectories() {
779
+ const collected = [];
780
+ collected.push(this.createDirectoryFromPath(process.cwd()));
667
781
  if (this.argv?.rootPath) {
668
782
  try {
669
- return this.parseDirectoriesFromString(this.argv.rootPath);
783
+ collected.push(...this.parseDirectoriesFromString(this.argv.rootPath));
670
784
  } catch {
671
- return [this.createDirectoryFromPath(this.argv.rootPath)];
785
+ collected.push(this.createDirectoryFromPath(this.argv.rootPath));
672
786
  }
673
787
  }
674
788
  const envDirs = this.safeGetEnvValue("DLINK_DIRECTORIES") ?? this.safeGetEnvValue("DLINK_ROOTS");
675
789
  if (envDirs) {
676
790
  try {
677
- return this.parseDirectoriesFromString(envDirs);
791
+ collected.push(...this.parseDirectoriesFromString(envDirs));
678
792
  } catch {
679
793
  }
680
794
  }
681
795
  const configDirs = this.safeGetConfigValue("directories") ?? this.safeGetConfigValue("roots");
682
796
  if (configDirs) {
683
797
  try {
684
- return this.parseDirectoriesFromValue(configDirs);
798
+ collected.push(...this.parseDirectoriesFromValue(configDirs));
685
799
  } catch {
686
800
  }
687
801
  }
688
802
  const processDirs = this.processEnv["DLINK_DIRECTORIES"] ?? this.processEnv["DLINK_ROOTS"];
689
803
  if (processDirs) {
690
804
  try {
691
- return this.parseDirectoriesFromString(processDirs);
805
+ collected.push(...this.parseDirectoriesFromString(processDirs));
692
806
  } catch {
693
807
  }
694
808
  }
695
- const cwd = process.cwd();
696
- return [this.createDirectoryFromPath(cwd)];
809
+ return this.deduplicateDirectories(collected);
810
+ }
811
+ deduplicateDirectories(dirs) {
812
+ const seen = /* @__PURE__ */ new Set();
813
+ const result = [];
814
+ for (const dir of dirs) {
815
+ const key = pathDedupeKey(dir.path);
816
+ if (seen.has(key))
817
+ continue;
818
+ seen.add(key);
819
+ result.push(dir);
820
+ }
821
+ return result;
697
822
  }
698
823
  getDevice() {
699
824
  const deviceId = this.getDeviceId();
@@ -703,7 +828,7 @@ var ConfigLoader = class {
703
828
  }
704
829
  let deviceName = this.getDeviceName();
705
830
  if (!deviceName) {
706
- deviceName = os2.hostname() || "Unknown Device";
831
+ deviceName = os3.hostname() || "Unknown Device";
707
832
  }
708
833
  const deviceTag = this.getDeviceTag();
709
834
  const keyBuilder = new KeyBuilder({
@@ -767,7 +892,7 @@ var ConfigLoader = class {
767
892
  const processName = this.processEnv["DLINK_DEVICE_NAME"];
768
893
  if (processName && !isEmpty2(processName))
769
894
  return processName;
770
- const hostname = os2.hostname();
895
+ const hostname = os3.hostname();
771
896
  if (hostname && !isEmpty2(hostname))
772
897
  return hostname;
773
898
  return void 0;
@@ -842,7 +967,7 @@ var ConfigLoader = class {
842
967
  const directoryPath = get2(obj, "path");
843
968
  const name = defaultTo(
844
969
  get2(obj, "name"),
845
- directoryPath ? path2.basename(directoryPath) : ""
970
+ directoryPath ? path4.basename(directoryPath) : ""
846
971
  );
847
972
  if (!isEmpty2(id) && !isEmpty2(directoryPath)) {
848
973
  const tag = getDirectoryTag(directoryPath);
@@ -857,18 +982,18 @@ var ConfigLoader = class {
857
982
  return null;
858
983
  }
859
984
  createDirectoryFromPath(directoryPath) {
860
- const normalizedPath = path2.resolve(directoryPath);
985
+ const normalizedPath = path4.resolve(directoryPath);
861
986
  const id = pathToUuidLikeSha256(normalizedPath);
862
- const name = path2.basename(normalizedPath);
987
+ const name = path4.basename(normalizedPath);
863
988
  const tag = getDirectoryTag(normalizedPath);
864
989
  return { id, name, path: normalizedPath, tag };
865
990
  }
866
991
  getApplicationConfigFolder() {
867
992
  const appData = defaultTo(
868
993
  this.processEnv["APPDATA"],
869
- path2.join(os2.homedir(), "AppData", "Roaming")
994
+ path4.join(os3.homedir(), "AppData", "Roaming")
870
995
  );
871
- return path2.join(appData, "DeviceLink");
996
+ return path4.join(appData, "DeviceLink");
872
997
  }
873
998
  };
874
999
 
@@ -1131,7 +1256,7 @@ var Engine2 = class {
1131
1256
  await this.loopOnce();
1132
1257
  } catch (err) {
1133
1258
  this.notifier.error(`Engine loop error: ${String(err)}`, { scope: "system" /* System */ });
1134
- await new Promise((resolve) => setTimeout(resolve, 250));
1259
+ await new Promise((resolve3) => setTimeout(resolve3, 250));
1135
1260
  }
1136
1261
  }
1137
1262
  }
@@ -1414,12 +1539,12 @@ var Engine2 = class {
1414
1539
  this.wakeFn();
1415
1540
  }
1416
1541
  resetWake() {
1417
- return new Promise((resolve) => {
1418
- this.wakeFn = resolve;
1542
+ return new Promise((resolve3) => {
1543
+ this.wakeFn = resolve3;
1419
1544
  });
1420
1545
  }
1421
1546
  newId() {
1422
- return crypto4.randomBytes(8).toString("hex");
1547
+ return crypto5.randomBytes(8).toString("hex");
1423
1548
  }
1424
1549
  };
1425
1550
  function backoffMs(attempt) {
@@ -1462,10 +1587,10 @@ var EventBus = class {
1462
1587
  };
1463
1588
 
1464
1589
  // agent/src/storage/index.ts
1465
- import * as crypto5 from "node:crypto";
1590
+ import * as crypto6 from "node:crypto";
1466
1591
  import * as fs3 from "node:fs/promises";
1467
- import * as path3 from "node:path";
1468
- import * as os3 from "node:os";
1592
+ import * as path5 from "node:path";
1593
+ import * as os4 from "node:os";
1469
1594
  import defaultTo2 from "lodash/defaultTo.js";
1470
1595
  var SALT = "DeviceLink-SecretStorage-v1";
1471
1596
  var IV_LENGTH = 12;
@@ -1475,12 +1600,12 @@ var SECRETS_FILENAME = "secrets.enc.json";
1475
1600
  function getSecretsPath() {
1476
1601
  const appData = defaultTo2(
1477
1602
  process.env["APPDATA"],
1478
- path3.join(os3.homedir(), "AppData", "Roaming")
1603
+ path5.join(os4.homedir(), "AppData", "Roaming")
1479
1604
  );
1480
- return path3.join(appData, "DeviceLink", SECRETS_FILENAME);
1605
+ return path5.join(appData, "DeviceLink", SECRETS_FILENAME);
1481
1606
  }
1482
1607
  function deriveKey(machineId) {
1483
- return crypto5.pbkdf2Sync(
1608
+ return crypto6.pbkdf2Sync(
1484
1609
  machineId,
1485
1610
  SALT,
1486
1611
  1e5,
@@ -1510,7 +1635,7 @@ var EncryptedFileStorage = class {
1510
1635
  this.loaded = true;
1511
1636
  }
1512
1637
  async save() {
1513
- await fs3.mkdir(path3.dirname(this.secretsPath), { recursive: true });
1638
+ await fs3.mkdir(path5.dirname(this.secretsPath), { recursive: true });
1514
1639
  const plain = JSON.stringify(this.cache);
1515
1640
  const encrypted = this.encrypt(plain);
1516
1641
  const tmp = this.secretsPath + ".tmp";
@@ -1518,8 +1643,8 @@ var EncryptedFileStorage = class {
1518
1643
  await fs3.rename(tmp, this.secretsPath);
1519
1644
  }
1520
1645
  encrypt(plain) {
1521
- const iv = crypto5.randomBytes(IV_LENGTH);
1522
- const cipher = crypto5.createCipheriv("aes-256-gcm", this.key, iv, {
1646
+ const iv = crypto6.randomBytes(IV_LENGTH);
1647
+ const cipher = crypto6.createCipheriv("aes-256-gcm", this.key, iv, {
1523
1648
  authTagLength: TAG_LENGTH
1524
1649
  });
1525
1650
  const enc = Buffer.concat([
@@ -1534,7 +1659,7 @@ var EncryptedFileStorage = class {
1534
1659
  const iv = buf.subarray(0, IV_LENGTH);
1535
1660
  const tag = buf.subarray(IV_LENGTH, IV_LENGTH + TAG_LENGTH);
1536
1661
  const enc = buf.subarray(IV_LENGTH + TAG_LENGTH);
1537
- const decipher = crypto5.createDecipheriv("aes-256-gcm", this.key, iv, {
1662
+ const decipher = crypto6.createDecipheriv("aes-256-gcm", this.key, iv, {
1538
1663
  authTagLength: TAG_LENGTH
1539
1664
  });
1540
1665
  decipher.setAuthTag(tag);
@@ -1655,7 +1780,7 @@ var ConsoleCommandJob = class extends JobType {
1655
1780
  }
1656
1781
  async run(input, ctx) {
1657
1782
  ctx.notifier.info(`Executing console command: ${input.kind}`);
1658
- await new Promise((resolve) => setTimeout(resolve, 2e3));
1783
+ await new Promise((resolve3) => setTimeout(resolve3, 2e3));
1659
1784
  ctx.notifier.info(`Console command executed: ${input.kind}`);
1660
1785
  ctx.notifier.success(`Console command executed: ${input.kind}`);
1661
1786
  return new ConsoleCommandOutput(true);
@@ -1685,7 +1810,7 @@ var ContactServerJob = class extends JobType {
1685
1810
  }
1686
1811
  async run(input, ctx) {
1687
1812
  ctx.notifier.info(`contact server mode=${input.mode}`, { scope: "system" /* System */ });
1688
- await new Promise((resolve) => setTimeout(resolve, 200));
1813
+ await new Promise((resolve3) => setTimeout(resolve3, 200));
1689
1814
  return new ContactServerOutput(true);
1690
1815
  }
1691
1816
  };
@@ -1713,7 +1838,7 @@ var SendServerResultJob = class extends JobType {
1713
1838
  }
1714
1839
  async run(input, ctx) {
1715
1840
  ctx.notifier.info(`send result requestId=${input.requestId}`, { scope: "system" /* System */ });
1716
- await new Promise((resolve) => setTimeout(resolve, 10));
1841
+ await new Promise((resolve3) => setTimeout(resolve3, 10));
1717
1842
  return new SendServerResultOutput(true);
1718
1843
  }
1719
1844
  };
@@ -1732,8 +1857,8 @@ var ApiCall = class {
1732
1857
  return this.handler(this.context, input);
1733
1858
  }
1734
1859
  };
1735
- async function fetchJson(context, path11, init) {
1736
- const url = `${context.configuration.controlBaseUrl}${path11}`;
1860
+ async function fetchJson(context, path13, init) {
1861
+ const url = `${context.configuration.controlBaseUrl}${path13}`;
1737
1862
  const res = await fetch(url, init);
1738
1863
  if (!res.ok) {
1739
1864
  const text = await res.text().catch(() => "");
@@ -1990,36 +2115,6 @@ var Api = class {
1990
2115
  }
1991
2116
  };
1992
2117
 
1993
- // common/src/lib/utils/crypto.utils.ts
1994
- import * as crypto6 from "node:crypto";
1995
- function fingerprintFromPublicKeyPem(publicKeyPem) {
1996
- const keyObj = crypto6.createPublicKey(publicKeyPem);
1997
- if (keyObj.asymmetricKeyType !== "ed25519") {
1998
- throw new Error(`Unexpected key type: ${keyObj.asymmetricKeyType}`);
1999
- }
2000
- const spkiDer = keyObj.export({ format: "der", type: "spki" });
2001
- const hash = crypto6.createHash("sha256").update(spkiDer).digest("base64url");
2002
- return hash.slice(0, 16).toUpperCase();
2003
- }
2004
- function signConnect(params) {
2005
- const payload = Buffer.from(`${params.deviceId}|${params.ts}|${params.nonce}`, "utf8");
2006
- const key = crypto6.createPrivateKey(params.privateKeyPem);
2007
- const sig = crypto6.sign(null, payload, key);
2008
- return sig.toString("base64");
2009
- }
2010
- function signRefresh(params) {
2011
- const hash = crypto6.createHash("sha256").update(params.refreshToken, "utf8").digest("hex");
2012
- const payload = Buffer.from(`${params.deviceId}|${params.ts}|${params.nonce}|${hash}`, "utf8");
2013
- const key = crypto6.createPrivateKey(params.privateKeyPem);
2014
- const sig = crypto6.sign(null, payload, key);
2015
- return sig.toString("base64");
2016
- }
2017
-
2018
- // common/src/lib/utils/async.utils.ts
2019
- function sleep(ms) {
2020
- return new Promise((resolve) => setTimeout(resolve, ms));
2021
- }
2022
-
2023
2118
  // agent/src/cli/jobs/refreshTokens.ts
2024
2119
  function isWrappedOk(x) {
2025
2120
  if (typeof x !== "object" || x === null)
@@ -3578,7 +3673,7 @@ var RecoverableSocket = class {
3578
3673
  }
3579
3674
  async connectWebSocketOnce() {
3580
3675
  const myConnId = ++this.connId;
3581
- return new Promise((resolve, reject) => {
3676
+ return new Promise((resolve3, reject) => {
3582
3677
  if (this.stopped) {
3583
3678
  reject(new Error("Socket is stopped"));
3584
3679
  return;
@@ -3596,7 +3691,7 @@ var RecoverableSocket = class {
3596
3691
  return;
3597
3692
  settled = true;
3598
3693
  cleanup();
3599
- resolve();
3694
+ resolve3();
3600
3695
  };
3601
3696
  const settleReject = (error, ws2) => {
3602
3697
  if (settled)
@@ -4017,8 +4112,8 @@ var WebSocketOrchestrator = class {
4017
4112
 
4018
4113
  // agent/src/cli/utils/configuration.writer.ts
4019
4114
  import fs4 from "node:fs";
4020
- import path4 from "node:path";
4021
- import os4 from "node:os";
4115
+ import path6 from "node:path";
4116
+ import os5 from "node:os";
4022
4117
  import defaultTo3 from "lodash/defaultTo.js";
4023
4118
  var ConfigurationWriter = class {
4024
4119
  /**
@@ -4027,7 +4122,7 @@ var ConfigurationWriter = class {
4027
4122
  */
4028
4123
  static save(config) {
4029
4124
  const configDir = this.getApplicationConfigFolder();
4030
- const configPath = path4.join(configDir, "config.json");
4125
+ const configPath = path6.join(configDir, "config.json");
4031
4126
  const safe = this.stripSecrets(config);
4032
4127
  fs4.mkdirSync(configDir, { recursive: true });
4033
4128
  fs4.writeFileSync(configPath, JSON.stringify(safe, null, 2), "utf8");
@@ -4054,9 +4149,9 @@ var ConfigurationWriter = class {
4054
4149
  static getApplicationConfigFolder() {
4055
4150
  const appData = defaultTo3(
4056
4151
  process.env["APPDATA"],
4057
- path4.join(os4.homedir(), "AppData", "Roaming")
4152
+ path6.join(os5.homedir(), "AppData", "Roaming")
4058
4153
  );
4059
- return path4.join(appData, "DeviceLink");
4154
+ return path6.join(appData, "DeviceLink");
4060
4155
  }
4061
4156
  };
4062
4157
 
@@ -5526,7 +5621,7 @@ var AuthOrchestrator = class {
5526
5621
 
5527
5622
  // agent/src/cli/orchestrators/tools/executers/fs-list.ts
5528
5623
  import fs7 from "node:fs/promises";
5529
- import path7 from "node:path";
5624
+ import path9 from "node:path";
5530
5625
 
5531
5626
  // agent/src/cli/orchestrators/tools/executers/base-executer.ts
5532
5627
  var BaseExecuter = class {
@@ -5562,7 +5657,7 @@ var BaseExecuter = class {
5562
5657
  };
5563
5658
 
5564
5659
  // agent/src/cli/orchestrators/tools/util/ignore.ts
5565
- import path5 from "node:path";
5660
+ import path7 from "node:path";
5566
5661
  import fs5 from "node:fs";
5567
5662
  function matchesDefaultDenylist(relPath) {
5568
5663
  const normalized = relPath.replace(/\\/g, "/");
@@ -5613,7 +5708,7 @@ function loadIgnoreRules(cfg, directory_id, workspace_id) {
5613
5708
  return DEFAULT_IGNORE_PATTERNS;
5614
5709
  }
5615
5710
  const rules = [];
5616
- const ignoreFilePath = path5.join(directory.path, ".devicelinkignore");
5711
+ const ignoreFilePath = path7.join(directory.path, ".devicelinkignore");
5617
5712
  if (fs5.existsSync(ignoreFilePath)) {
5618
5713
  try {
5619
5714
  const content = fs5.readFileSync(ignoreFilePath, "utf-8");
@@ -5661,7 +5756,7 @@ function shouldIgnore(relPath, isDir, ctx, cfg) {
5661
5756
  }
5662
5757
  return { shouldIgnore: false };
5663
5758
  }
5664
- function matchesGlob(path11, pattern, isDir) {
5759
+ function matchesGlob(path13, pattern, isDir) {
5665
5760
  let regexStr = "^";
5666
5761
  let i = 0;
5667
5762
  while (i < pattern.length) {
@@ -5688,15 +5783,15 @@ function matchesGlob(path11, pattern, isDir) {
5688
5783
  regexStr += "$";
5689
5784
  try {
5690
5785
  const regex = new RegExp(regexStr, "i");
5691
- return regex.test(path11);
5786
+ return regex.test(path13);
5692
5787
  } catch {
5693
- return path11.toLowerCase().includes(pattern.toLowerCase());
5788
+ return path13.toLowerCase().includes(pattern.toLowerCase());
5694
5789
  }
5695
5790
  }
5696
5791
 
5697
5792
  // agent/src/cli/orchestrators/tools/util/_util.ts
5698
5793
  import fs6 from "node:fs/promises";
5699
- import path6 from "node:path";
5794
+ import path8 from "node:path";
5700
5795
  function normalizeRelPath(input) {
5701
5796
  const raw = (input ?? "").trim();
5702
5797
  if (!raw)
@@ -5715,7 +5810,7 @@ function normalizeRelPath(input) {
5715
5810
  });
5716
5811
  }
5717
5812
  const posixish = raw.replace(/\\/g, "/");
5718
- const norm = path6.posix.normalize(posixish);
5813
+ const norm = path8.posix.normalize(posixish);
5719
5814
  if (norm === ".." || norm.startsWith("../")) {
5720
5815
  throw toolErr("PATH_ESCAPE", "Path escapes the root.", {
5721
5816
  hint: 'Paths cannot use ".." to escape the configured root directory. Use paths relative to the root, like "src/file.ts" or "subdir/file.ts".'
@@ -5730,19 +5825,19 @@ function normalizeRelPath(input) {
5730
5825
  }
5731
5826
  async function resolveInRoot(rootPath, inputRel) {
5732
5827
  const rel = normalizeRelPath(inputRel);
5733
- const absRoot = path6.resolve(rootPath);
5828
+ const absRoot = path8.resolve(rootPath);
5734
5829
  const realRoot = await fs6.realpath(absRoot);
5735
- const candidate = path6.resolve(realRoot, rel === "." ? "" : rel);
5736
- const relToRoot = path6.relative(realRoot, candidate);
5737
- if (relToRoot.startsWith("..") || path6.isAbsolute(relToRoot)) {
5830
+ const candidate = path8.resolve(realRoot, rel === "." ? "" : rel);
5831
+ const relToRoot = path8.relative(realRoot, candidate);
5832
+ if (relToRoot.startsWith("..") || path8.isAbsolute(relToRoot)) {
5738
5833
  throw toolErr("PATH_ESCAPE", "Path escapes the root.", {
5739
5834
  hint: "The resolved path escapes the configured root directory. Ensure the path stays within the root boundaries."
5740
5835
  });
5741
5836
  }
5742
5837
  try {
5743
5838
  const realCandidate = await fs6.realpath(candidate);
5744
- const rel2 = path6.relative(realRoot, realCandidate);
5745
- if (rel2.startsWith("..") || path6.isAbsolute(rel2)) {
5839
+ const rel2 = path8.relative(realRoot, realCandidate);
5840
+ if (rel2.startsWith("..") || path8.isAbsolute(rel2)) {
5746
5841
  throw toolErr("PATH_ESCAPE", "Symlink/junction escape detected.", {
5747
5842
  hint: "A symlink or junction in the path resolves outside the configured root directory. Ensure all symlinks stay within the root boundaries."
5748
5843
  });
@@ -5755,16 +5850,16 @@ async function resolveInRoot(rootPath, inputRel) {
5755
5850
  for (let i = parts.length; i > 0; i--) {
5756
5851
  const parentRel = parts.slice(0, i).join("/");
5757
5852
  const restRel = parts.slice(i).join("/");
5758
- const parentCandidate = path6.resolve(realRoot, parentRel);
5853
+ const parentCandidate = path8.resolve(realRoot, parentRel);
5759
5854
  try {
5760
5855
  const realParent = await fs6.realpath(parentCandidate);
5761
- const relParent = path6.relative(realRoot, realParent);
5762
- if (relParent.startsWith("..") || path6.isAbsolute(relParent)) {
5856
+ const relParent = path8.relative(realRoot, realParent);
5857
+ if (relParent.startsWith("..") || path8.isAbsolute(relParent)) {
5763
5858
  throw toolErr("PATH_ESCAPE", "Symlink/junction escape detected.", {
5764
5859
  hint: "A symlink or junction in the path resolves outside the configured root directory. Ensure all symlinks stay within the root boundaries."
5765
5860
  });
5766
5861
  }
5767
- return { absTarget: restRel ? path6.join(realParent, restRel) : realParent, rel };
5862
+ return { absTarget: restRel ? path8.join(realParent, restRel) : realParent, rel };
5768
5863
  } catch (err) {
5769
5864
  if (err?.code === "ENOENT")
5770
5865
  continue;
@@ -5946,8 +6041,8 @@ var FsListExecuter = class extends BaseExecuter {
5946
6041
  directory_path: directory.path
5947
6042
  };
5948
6043
  for (const d of visibleDirents) {
5949
- const full = path7.join(absTarget, d.name);
5950
- const rawRelPath = rel === "." ? d.name : path7.posix.join(rel, d.name);
6044
+ const full = path9.join(absTarget, d.name);
6045
+ const rawRelPath = rel === "." ? d.name : path9.posix.join(rel, d.name);
5951
6046
  const entryRelPath = rawRelPath.replace(/\\/g, "/");
5952
6047
  let type = "other";
5953
6048
  if (d.isDirectory())
@@ -5985,7 +6080,7 @@ var FsListExecuter = class extends BaseExecuter {
5985
6080
  } catch {
5986
6081
  }
5987
6082
  }
5988
- const ext = type === "file" ? path7.extname(d.name).slice(1) : void 0;
6083
+ const ext = type === "file" ? path9.extname(d.name).slice(1) : void 0;
5989
6084
  if (ext && (detail === "stat" || detail === "digest")) {
5990
6085
  extCounts.set(ext, (extCounts.get(ext) ?? 0) + 1);
5991
6086
  }
@@ -6197,11 +6292,11 @@ var FsInfoExecuter = class extends BaseExecuter {
6197
6292
 
6198
6293
  // agent/src/cli/orchestrators/tools/executers/fs-tree.ts
6199
6294
  import fs11 from "node:fs/promises";
6200
- import path9 from "node:path";
6295
+ import path11 from "node:path";
6201
6296
 
6202
6297
  // agent/src/cli/orchestrators/tools/executers/fs-grep.ts
6203
6298
  import fs10 from "node:fs/promises";
6204
- import path8 from "node:path";
6299
+ import path10 from "node:path";
6205
6300
  function matchesFileGlob(relPath, fileGlob) {
6206
6301
  let regexStr = "^";
6207
6302
  let i = 0;
@@ -6297,8 +6392,8 @@ async function grepDirectory(absPath, relPath, rootPath, query, mode, fileGlob,
6297
6392
  for (const entry of entries) {
6298
6393
  if (filesScanned.value >= maxFiles || matches.length >= maxMatches)
6299
6394
  break;
6300
- const entryAbsPath = path8.join(absPath, entry.name);
6301
- const entryRelPath = relPath === "." ? entry.name : path8.posix.join(relPath, entry.name);
6395
+ const entryAbsPath = path10.join(absPath, entry.name);
6396
+ const entryRelPath = relPath === "." ? entry.name : path10.posix.join(relPath, entry.name);
6302
6397
  const ignoreResult = shouldIgnore(entryRelPath, entry.isDirectory(), ignoreCtx, cfg);
6303
6398
  if (ignoreResult.shouldIgnore) {
6304
6399
  ignoredCount.value++;
@@ -6591,10 +6686,10 @@ async function buildTree(absPath, relPath, depth, maxDepth, only, includeHidden,
6591
6686
  const errorMessage = toolError2?.message ?? e?.message ?? String(e) ?? "Unknown error";
6592
6687
  summary.total_entries++;
6593
6688
  const node2 = {
6594
- name: path9.basename(relPath) || relPath,
6689
+ name: path11.basename(relPath) || relPath,
6595
6690
  type: "other",
6596
6691
  path: entryRel,
6597
- hidden: path9.basename(relPath)?.startsWith("."),
6692
+ hidden: path11.basename(relPath)?.startsWith("."),
6598
6693
  ignored: false
6599
6694
  };
6600
6695
  if (errorMap) {
@@ -6628,10 +6723,10 @@ async function buildTree(absPath, relPath, depth, maxDepth, only, includeHidden,
6628
6723
  summary.dirs++;
6629
6724
  else if (type === "symlink")
6630
6725
  summary.symlinks++;
6631
- const isHidden = path9.basename(relPath)?.startsWith(".");
6726
+ const isHidden = path11.basename(relPath)?.startsWith(".");
6632
6727
  if (isHidden)
6633
6728
  summary.hidden++;
6634
- const ext = type === "file" ? path9.extname(path9.basename(relPath) || relPath).slice(1) : void 0;
6729
+ const ext = type === "file" ? path11.extname(path11.basename(relPath) || relPath).slice(1) : void 0;
6635
6730
  if (ext && (detail === "stat" || detail === "digest")) {
6636
6731
  extCounts.set(ext, (extCounts.get(ext) ?? 0) + 1);
6637
6732
  }
@@ -6639,7 +6734,7 @@ async function buildTree(absPath, relPath, depth, maxDepth, only, includeHidden,
6639
6734
  summary.total_file_bytes = (summary.total_file_bytes ?? 0) + (stat.size ?? 0);
6640
6735
  }
6641
6736
  const node = {
6642
- name: path9.basename(relPath) || relPath,
6737
+ name: path11.basename(relPath) || relPath,
6643
6738
  type,
6644
6739
  path: entryRel,
6645
6740
  size: (detail === "stat" || detail === "digest") && stat.isFile() ? stat.size : void 0,
@@ -6686,8 +6781,8 @@ async function buildTree(absPath, relPath, depth, maxDepth, only, includeHidden,
6686
6781
  for (const entry of filtered) {
6687
6782
  if (currentCount.value >= maxEntries)
6688
6783
  break;
6689
- const childAbs = path9.join(absPath, entry.name);
6690
- const childRelPath = relPath === "." ? entry.name : path9.posix.join(relPath, entry.name);
6784
+ const childAbs = path11.join(absPath, entry.name);
6785
+ const childRelPath = relPath === "." ? entry.name : path11.posix.join(relPath, entry.name);
6691
6786
  const childRel = childRelPath.replace(/\\/g, "/");
6692
6787
  const preIgnore = shouldIgnore(childRel, entry.isDirectory(), ignoreCtx, cfg);
6693
6788
  if (preIgnore.shouldIgnore) {
@@ -6728,10 +6823,10 @@ async function buildTree(absPath, relPath, depth, maxDepth, only, includeHidden,
6728
6823
  }
6729
6824
  summary.total_entries++;
6730
6825
  const errorNode = {
6731
- name: path9.basename(childRelPath) || childRelPath,
6826
+ name: path11.basename(childRelPath) || childRelPath,
6732
6827
  type: "other",
6733
6828
  path: childRel,
6734
- hidden: path9.basename(childRelPath)?.startsWith("."),
6829
+ hidden: path11.basename(childRelPath)?.startsWith("."),
6735
6830
  ignored: false
6736
6831
  };
6737
6832
  if (only === "files" || only === "dirs") {
@@ -6918,7 +7013,7 @@ var FsTreeExecuter = class extends BaseExecuter {
6918
7013
 
6919
7014
  // agent/src/cli/orchestrators/tools/executers/fs-search.ts
6920
7015
  import fs12 from "node:fs/promises";
6921
- import path10 from "node:path";
7016
+ import path12 from "node:path";
6922
7017
  function matchesGlob2(name, pattern) {
6923
7018
  let regexStr = "^";
6924
7019
  let i = 0;
@@ -7040,8 +7135,8 @@ async function searchDirectory(absPath, relPath, rootPath, query, mode, recursiv
7040
7135
  for (const entry of visibleEntries) {
7041
7136
  if (results.length >= maxResults)
7042
7137
  break;
7043
- const entryAbsPath = path10.join(absPath, entry.name);
7044
- const entryRelPath = relPath === "." ? entry.name : path10.posix.join(relPath, entry.name);
7138
+ const entryAbsPath = path12.join(absPath, entry.name);
7139
+ const entryRelPath = relPath === "." ? entry.name : path12.posix.join(relPath, entry.name);
7045
7140
  const ignoreResult = shouldIgnore(entryRelPath, entry.isDirectory(), ignoreCtx, cfg);
7046
7141
  if (ignoreResult.shouldIgnore) {
7047
7142
  ignoredCount.value++;
@@ -7091,7 +7186,7 @@ async function searchDirectory(absPath, relPath, rootPath, query, mode, recursiv
7091
7186
  } catch {
7092
7187
  }
7093
7188
  }
7094
- const ext = type === "file" ? path10.extname(entry.name).slice(1) : void 0;
7189
+ const ext = type === "file" ? path12.extname(entry.name).slice(1) : void 0;
7095
7190
  const score = calculateScore({ name: entry.name, path: entryRelPath }, preferPaths, avoidPaths);
7096
7191
  results.push({
7097
7192
  name: entry.name,
@@ -7159,8 +7254,8 @@ var FsSearchExecuter = class extends BaseExecuter {
7159
7254
  const st = await fs12.stat(absTarget);
7160
7255
  if (!st.isDirectory()) {
7161
7256
  if (st.isFile()) {
7162
- searchPath = path10.dirname(absTarget);
7163
- const parentRelPath = path10.posix.dirname(rel);
7257
+ searchPath = path12.dirname(absTarget);
7258
+ const parentRelPath = path12.posix.dirname(rel);
7164
7259
  searchRelPath = parentRelPath === "." ? "." : parentRelPath;
7165
7260
  messages.push({
7166
7261
  type: "warning",
@@ -7455,7 +7550,7 @@ var FsListResult = class extends BaseToolResult {
7455
7550
  const itemCount = items?.length ?? 0;
7456
7551
  const totalCount = meta?.count ?? 0;
7457
7552
  const ignoredCount = filtered?.ignored_count ?? 0;
7458
- const path11 = context?.path ?? "unknown";
7553
+ const path13 = context?.path ?? "unknown";
7459
7554
  const parts = [];
7460
7555
  if (itemCount > 0) {
7461
7556
  parts.push(`${itemCount} item${itemCount !== 1 ? "s" : ""}`);
@@ -7467,7 +7562,7 @@ var FsListResult = class extends BaseToolResult {
7467
7562
  parts.push("has_more");
7468
7563
  }
7469
7564
  const description = parts.length > 0 ? parts.join(", ") : "empty";
7470
- return `path=${path11}, ${description}`;
7565
+ return `path=${path13}, ${description}`;
7471
7566
  }
7472
7567
  };
7473
7568
 
@@ -7490,10 +7585,10 @@ var FsReadResult = class extends BaseToolResult {
7490
7585
  return "no result";
7491
7586
  }
7492
7587
  const { bytes_read, eof, context } = this.output;
7493
- const path11 = context?.path ?? "unknown";
7588
+ const path13 = context?.path ?? "unknown";
7494
7589
  const size = bytes_read ?? 0;
7495
7590
  const truncated = !eof;
7496
- const parts = [`path=${path11}`, `${size} bytes`];
7591
+ const parts = [`path=${path13}`, `${size} bytes`];
7497
7592
  if (truncated) {
7498
7593
  parts.push("truncated");
7499
7594
  }
@@ -7520,9 +7615,9 @@ var FsInfoResult = class extends BaseToolResult {
7520
7615
  return "no result";
7521
7616
  }
7522
7617
  const { type, size, context } = this.output;
7523
- const path11 = context?.path ?? "unknown";
7618
+ const path13 = context?.path ?? "unknown";
7524
7619
  const sizeStr = size !== void 0 ? `${size} bytes` : "no size";
7525
- return `path=${path11}, type=${type}, ${sizeStr}`;
7620
+ return `path=${path13}, type=${type}, ${sizeStr}`;
7526
7621
  }
7527
7622
  };
7528
7623
 
@@ -7545,9 +7640,9 @@ var FsTreeResult = class extends BaseToolResult {
7545
7640
  return "no result";
7546
7641
  }
7547
7642
  const { tree, filtered, summary, context } = this.output;
7548
- const path11 = context?.path ?? "unknown";
7643
+ const path13 = context?.path ?? "unknown";
7549
7644
  const ignoredCount = filtered?.ignored_count ?? 0;
7550
- const parts = [`path=${path11}`];
7645
+ const parts = [`path=${path13}`];
7551
7646
  if (summary) {
7552
7647
  const { total_entries, files, dirs } = summary;
7553
7648
  if (total_entries !== void 0) {
@@ -7601,10 +7696,10 @@ var FsSearchResult = class extends BaseToolResult {
7601
7696
  return "no result";
7602
7697
  }
7603
7698
  const { results, meta, filtered, context } = this.output;
7604
- const path11 = context?.path ?? "unknown";
7699
+ const path13 = context?.path ?? "unknown";
7605
7700
  const resultCount = results?.length ?? 0;
7606
7701
  const ignoredCount = filtered?.ignored_count ?? 0;
7607
- const parts = [`path=${path11}`, `${resultCount} result${resultCount !== 1 ? "s" : ""}`];
7702
+ const parts = [`path=${path13}`, `${resultCount} result${resultCount !== 1 ? "s" : ""}`];
7608
7703
  if (ignoredCount > 0) {
7609
7704
  parts.push(`${ignoredCount} ignored`);
7610
7705
  }
@@ -7634,12 +7729,12 @@ var FsGrepResult = class extends BaseToolResult {
7634
7729
  return "no result";
7635
7730
  }
7636
7731
  const { matches, meta, filtered, context } = this.output;
7637
- const path11 = context?.path ?? "unknown";
7732
+ const path13 = context?.path ?? "unknown";
7638
7733
  const matchCount = matches?.length ?? 0;
7639
7734
  const filesScanned = meta?.files_scanned ?? 0;
7640
7735
  const ignoredCount = filtered?.ignored_count ?? 0;
7641
7736
  const parts = [
7642
- `path=${path11}`,
7737
+ `path=${path13}`,
7643
7738
  `${matchCount} match${matchCount !== 1 ? "es" : ""}`,
7644
7739
  `${filesScanned} file${filesScanned !== 1 ? "s" : ""} scanned`
7645
7740
  ];
@@ -8004,7 +8099,7 @@ var DirectoriesJob = class extends JobType {
8004
8099
  return {
8005
8100
  id: r.id,
8006
8101
  name: r.name,
8007
- path: r.path,
8102
+ path: toTildeHomePath(r.path) ?? r.name,
8008
8103
  path_hint: r.tag || void 0
8009
8104
  };
8010
8105
  });