@agentdocumentformat/cli 0.7.8 → 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 (100) hide show
  1. package/README.md +1 -1
  2. package/dist/adf.mjs +59 -8
  3. package/dist/chunks/{APEv2Parser-2CNNHMXV.mjs → APEv2Parser-WIXRJLHB.mjs} +2 -2
  4. package/dist/chunks/{AiffParser-7BR4RL6G.mjs → AiffParser-ZC4QFOVJ.mjs} +5 -5
  5. package/dist/chunks/{App-7RIIOHJJ.mjs → App-A5GUFCFJ.mjs} +279 -293
  6. package/dist/chunks/{DsdiffParser-CMD4AX7A.mjs → DsdiffParser-UAPAJHFX.mjs} +5 -5
  7. package/dist/chunks/{DsfParser-UOGZDS2M.mjs → DsfParser-NNYZK2QX.mjs} +6 -6
  8. package/dist/chunks/{FlacParser-HB3T3CD4.mjs → FlacParser-MW2W4LO3.mjs} +6 -6
  9. package/dist/chunks/{MP4Parser-66HBRUSX.mjs → MP4Parser-Z57SYOOQ.mjs} +4 -4
  10. package/dist/chunks/{MpegParser-YW6LIUEW.mjs → MpegParser-XIIPAZVM.mjs} +7 -7
  11. package/dist/chunks/{MusepackParser-PAUSXP7D.mjs → MusepackParser-QWNDEYHJ.mjs} +6 -6
  12. package/dist/chunks/{OggParser-NUBV3GWC.mjs → OggParser-WRX53F77.mjs} +9 -9
  13. package/dist/chunks/{WavPackParser-WQAGT7TC.mjs → WavPackParser-MJ7WCSJ5.mjs} +2 -2
  14. package/dist/chunks/{WaveParser-EWLQVDX4.mjs → WaveParser-RAVLHZ5S.mjs} +7 -7
  15. package/dist/chunks/{adf-schema-US4NFHMR.mjs → adf-schema-YJSGLMA4.mjs} +2 -2
  16. package/dist/chunks/auth-manager-AJ32FZWS.mjs +19 -0
  17. package/dist/chunks/auth-manager-C5OBEQK2.mjs +18 -0
  18. package/dist/chunks/auth-manager-TBNKCJ45.mjs +17 -0
  19. package/dist/chunks/{chatgpt-subscription-E4MXTIAT.mjs → chatgpt-subscription-MMGNW5KJ.mjs} +5 -2
  20. package/dist/chunks/chunk-3UGZFWIF.mjs +26 -0
  21. package/dist/chunks/{chunk-5PO5PKRV.mjs → chunk-4OGZFUKA.mjs} +126 -67
  22. package/dist/chunks/{chunk-VN7UH7I5.mjs → chunk-6XQZGYMK.mjs} +246 -67
  23. package/dist/chunks/{chunk-XNPZBLYL.mjs → chunk-75DC5EWN.mjs} +13 -2
  24. package/dist/chunks/chunk-AZYOXXVL.mjs +865 -0
  25. package/dist/chunks/{chunk-6VQEXLE2.mjs → chunk-BHY7QDCM.mjs} +41 -3
  26. package/dist/chunks/chunk-C2S64Y6F.mjs +203 -0
  27. package/dist/chunks/chunk-C4GA5SI4.mjs +12799 -0
  28. package/dist/chunks/chunk-DDTTSKGG.mjs +2443 -0
  29. package/dist/chunks/{chunk-VAUOM3IN.mjs → chunk-DLWCKKIO.mjs} +1 -1
  30. package/dist/chunks/{chunk-QPLEAE6V.mjs → chunk-G6NBFYG5.mjs} +152 -824
  31. package/dist/chunks/{chunk-KXEF4F4E.mjs → chunk-GAZO6UMI.mjs} +1 -1
  32. package/dist/chunks/{chunk-XYTWGHFS.mjs → chunk-H3XLRWVE.mjs} +1 -1
  33. package/dist/chunks/{chunk-7T2YMTWL.mjs → chunk-H4C65MTP.mjs} +4 -4
  34. package/dist/chunks/chunk-HBOFZRUS.mjs +738 -0
  35. package/dist/chunks/chunk-JVPZIMXW.mjs +976 -0
  36. package/dist/chunks/{chunk-XYV3VCIX.mjs → chunk-JZFONJSL.mjs} +79 -20
  37. package/dist/chunks/chunk-KDDVQKCG.mjs +65 -0
  38. package/dist/chunks/chunk-KRPKWOMB.mjs +290 -0
  39. package/dist/chunks/{chunk-G6PH7RPW.mjs → chunk-LCMANRYY.mjs} +3 -3
  40. package/dist/chunks/{chunk-ZESQMP66.mjs → chunk-LGL6ML37.mjs} +3 -3
  41. package/dist/chunks/chunk-LKFHERRV.mjs +145 -0
  42. package/dist/chunks/chunk-LTX74NU6.mjs +29 -0
  43. package/dist/chunks/chunk-M2F7C2UJ.mjs +425 -0
  44. package/dist/chunks/{chunk-62NE4LG4.mjs → chunk-MQAMI5BF.mjs} +5 -5
  45. package/dist/chunks/chunk-MZRXFWPQ.mjs +278 -0
  46. package/dist/chunks/{chunk-PRMGZZM5.mjs → chunk-NZLEPJ5M.mjs} +2 -0
  47. package/dist/chunks/{chunk-CD3ATSXE.mjs → chunk-NZO5O4VN.mjs} +1 -1
  48. package/dist/chunks/{chunk-I3UYSITV.mjs → chunk-O7XKQ6CH.mjs} +1 -1
  49. package/dist/chunks/chunk-P3RG5LQA.mjs +244 -0
  50. package/dist/chunks/chunk-PAK5JCO2.mjs +48 -0
  51. package/dist/chunks/chunk-PC63YFB7.mjs +34 -0
  52. package/dist/chunks/{daemon-control-HKFVSQTQ.mjs → chunk-PRPTKMQW.mjs} +67 -26
  53. package/dist/chunks/{chunk-LFMB4PAA.mjs → chunk-TKXIH27X.mjs} +974 -113
  54. package/dist/chunks/{chunk-5W7KES6P.mjs → chunk-UZPDETEU.mjs} +1 -1
  55. package/dist/chunks/chunk-V2T6NZX2.mjs +517 -0
  56. package/dist/chunks/chunk-V3MM6PCH.mjs +366 -0
  57. package/dist/chunks/chunk-WJGPNHGX.mjs +67 -0
  58. package/dist/chunks/chunk-WVTPPOKK.mjs +290 -0
  59. package/dist/chunks/{chunk-J74STFKE.mjs → chunk-WX6QCUWI.mjs} +272 -51
  60. package/dist/chunks/{chunk-Y5ZLKFLE.mjs → chunk-XNNJQCZP.mjs} +196 -165
  61. package/dist/chunks/{chunk-HDBPBORT.mjs → chunk-XT2BJUFC.mjs} +15 -6
  62. package/dist/chunks/{chunk-HSBV6YFU.mjs → chunk-YRMKSHW3.mjs} +614 -92
  63. package/dist/chunks/{chunk-BNXUAOO4.mjs → chunk-ZGXUOAWZ.mjs} +3186 -959
  64. package/dist/chunks/chunk-ZPB3HYM7.mjs +45 -0
  65. package/dist/chunks/claude-subscription-33BMZB6I.mjs +29 -0
  66. package/dist/chunks/{cli-NMFIAR7Z.mjs → cli-I47IFDHJ.mjs} +797 -56
  67. package/dist/chunks/{commands-KPJWFRUE.mjs → commands-E4EQUHE5.mjs} +4 -3
  68. package/dist/chunks/{daemon-YDIK3AAM.mjs → daemon-FQ5BV3AP.mjs} +82058 -63958
  69. package/dist/chunks/daemon-control-L3CLG63P.mjs +59 -0
  70. package/dist/chunks/{daemon-token-WRSULP7G.mjs → daemon-token-L5QKTHU5.mjs} +3 -1
  71. package/dist/chunks/{discord-DSP4HUWI.mjs → discord-IR62565M.mjs} +3 -52
  72. package/dist/chunks/{email-BRG7KUO2.mjs → email-KHHTJBDW.mjs} +4 -2
  73. package/dist/chunks/{grok-subscription-4PYX7TBF.mjs → grok-subscription-E74FS5EG.mjs} +5 -2
  74. package/dist/chunks/{lib-N7FCZWKH.mjs → lib-L27L5PXM.mjs} +22 -22
  75. package/dist/chunks/{open-VAU7PXT6.mjs → open-TLGS2Z3Q.mjs} +4 -4
  76. package/dist/chunks/{parser-JVY2PWSM.mjs → parser-7GARNT5L.mjs} +1 -1
  77. package/dist/chunks/{pipeline-executor-O77NTGLP.mjs → pipeline-executor-FD4FBWQA.mjs} +6 -5
  78. package/dist/chunks/prompt-RRHZX4YT.mjs +13 -0
  79. package/dist/chunks/remote-access-cli-XXAPQWH6.mjs +268 -0
  80. package/dist/chunks/remote-hello-UFWUBDQI.mjs +37 -0
  81. package/dist/chunks/sdk-5FD2ZP7N.mjs +28422 -0
  82. package/dist/chunks/{slack-OCNNF4DX.mjs → slack-IYC5RAB5.mjs} +3 -4
  83. package/dist/chunks/{store-HUVDJPYN.mjs → store-ZRN2WCFB.mjs} +6 -3
  84. package/dist/chunks/tailscale-WLJATFMB.mjs +25 -0
  85. package/dist/chunks/{theme-SFE3JMA2.mjs → theme-HLBDTF6F.mjs} +1 -1
  86. package/dist/chunks/{themes-YLXLOIJF.mjs → themes-BQ72P446.mjs} +2 -2
  87. package/dist/chunks/{token-6G3HCMNX.mjs → token-6D22WECM.mjs} +20 -16
  88. package/dist/chunks/{token-util-UXYSDQIW.mjs → token-util-YF3ZWBZ4.mjs} +1 -2
  89. package/dist/chunks/{tui-UQJLK7XI.mjs → tui-SPSPDADM.mjs} +17 -14
  90. package/dist/chunks/{welcome-XHXFV7SH.mjs → welcome-J5JZZAM5.mjs} +1 -1
  91. package/dist/chunks/{whatsapp-AJMRQBT7.mjs → whatsapp-YJFFVN4Q.mjs} +9 -9
  92. package/package.json +1 -1
  93. package/dist/chunks/chunk-GKKCMXIZ.mjs +0 -94
  94. package/dist/chunks/chunk-IHDDCZBS.mjs +0 -112
  95. package/dist/chunks/chunk-KWFOS5WC.mjs +0 -41
  96. package/dist/chunks/chunk-UEZR2CNS.mjs +0 -65
  97. package/dist/chunks/chunk-VMHTYDH4.mjs +0 -172
  98. package/dist/chunks/chunk-Y2QA53AN.mjs +0 -259
  99. package/dist/chunks/{chunk-NBTUWMGP.mjs → chunk-2MTE22CR.mjs} +3 -3
  100. package/dist/chunks/{telegram-2EFGKIVK.mjs → telegram-JYY2VDTI.mjs} +5 -5
@@ -0,0 +1,145 @@
1
+ import { createRequire as __adfCreateRequire } from 'node:module';
2
+ import { fileURLToPath as __adfFileURLToPath } from 'node:url';
3
+ import { dirname as __adfDirname } from 'node:path';
4
+ const require = __adfCreateRequire(import.meta.url);
5
+ const __filename = __adfFileURLToPath(import.meta.url);
6
+ const __dirname = __adfDirname(__filename);
7
+ import {
8
+ __export
9
+ } from "./chunk-M2RX3S2T.mjs";
10
+
11
+ // src/shared/utils/file-ref.ts
12
+ var file_ref_exports = {};
13
+ __export(file_ref_exports, {
14
+ adfFileUrl: () => adfFileUrl,
15
+ applyFileRefChanges: () => applyFileRefChanges,
16
+ attachmentMetadata: () => attachmentMetadata,
17
+ attachmentText: () => attachmentText,
18
+ attachmentsOf: () => attachmentsOf,
19
+ deletedFilePlaceholder: () => deletedFilePlaceholder,
20
+ displayAttachment: () => displayAttachment,
21
+ fileRefKind: () => fileRefKind,
22
+ fileRefName: () => fileRefName,
23
+ fileRefText: () => fileRefText,
24
+ isAudioInputMime: () => isAudioInputMime,
25
+ isFileRefBlock: () => isFileRefBlock,
26
+ isVideoInputMime: () => isVideoInputMime,
27
+ isVisionMime: () => isVisionMime,
28
+ mediaKindOfMime: () => mediaKindOfMime,
29
+ splitLegacyUploads: () => splitLegacyUploads
30
+ });
31
+ var VISION_MIMES = /* @__PURE__ */ new Set(["image/png", "image/jpeg", "image/gif", "image/webp"]), AUDIO_INPUT_MIMES = /* @__PURE__ */ new Set([
32
+ "audio/wav",
33
+ "audio/mpeg",
34
+ "audio/mp3",
35
+ "audio/aiff",
36
+ "audio/aac",
37
+ "audio/ogg",
38
+ "audio/flac",
39
+ "audio/x-m4a",
40
+ "audio/webm"
41
+ ]), VIDEO_INPUT_MIMES = /* @__PURE__ */ new Set(["video/mp4", "video/mpeg", "video/quicktime", "video/webm"]);
42
+ function isVisionMime(mime) {
43
+ return !!mime && VISION_MIMES.has(mime);
44
+ }
45
+ function isAudioInputMime(mime) {
46
+ return !!mime && AUDIO_INPUT_MIMES.has(mime);
47
+ }
48
+ function isVideoInputMime(mime) {
49
+ return !!mime && VIDEO_INPUT_MIMES.has(mime);
50
+ }
51
+ function mediaKindOfMime(mime) {
52
+ if (isVisionMime(mime)) return "image";
53
+ if (isAudioInputMime(mime)) return "audio";
54
+ if (isVideoInputMime(mime)) return "video";
55
+ }
56
+ function isFileRefBlock(block) {
57
+ return block.type === "file_ref" && !!block.file_ref && typeof block.file_ref.path == "string";
58
+ }
59
+ function fileRefKind(ref) {
60
+ return mediaKindOfMime(ref.mime_type);
61
+ }
62
+ function fileRefName(ref) {
63
+ let segments = ref.path.split("/");
64
+ return segments[segments.length - 1] || ref.path;
65
+ }
66
+ function deletedFilePlaceholder(ref) {
67
+ return `[deleted: ${fileRefName(ref)}]`;
68
+ }
69
+ function adfFileUrl(path) {
70
+ return `adf-file://${path.split("/").map(encodeURIComponent).join("/")}`;
71
+ }
72
+ function displayAttachment(ref) {
73
+ let kind = fileRefKind(ref);
74
+ return {
75
+ path: ref.path,
76
+ name: fileRefName(ref),
77
+ mime_type: ref.mime_type,
78
+ ...kind ? { kind } : {},
79
+ ...ref.deleted ? { deleted: !0 } : {}
80
+ };
81
+ }
82
+ function attachmentsOf(blocks) {
83
+ let out = [];
84
+ for (let block of blocks) isFileRefBlock(block) && out.push(displayAttachment(block.file_ref));
85
+ return out;
86
+ }
87
+ function attachmentMetadata(content, previews = []) {
88
+ let attachments = attachmentsOf(content);
89
+ if (!(attachments.length === 0 && previews.length === 0))
90
+ return { ...previews.length > 0 ? { imagePreviewUrls: previews } : {}, ...attachments.length > 0 ? { attachments } : {} };
91
+ }
92
+ function attachmentText(a) {
93
+ return a.deleted ? deletedFilePlaceholder(a) : `[${a.kind ?? "file"}: ${a.name}]`;
94
+ }
95
+ var LEGACY_UPLOAD_LINE = /^\[Uploaded file: .+ \(([^,()]+), [^()]+\)\. Use fs_read with path "(.+)" to inspect it\.\]$/;
96
+ function splitLegacyUploads(text) {
97
+ if (!text.includes("[Uploaded file: ")) return { text, attachments: [] };
98
+ let attachments = [], kept = [];
99
+ for (let line of text.split(`
100
+ `)) {
101
+ let match = LEGACY_UPLOAD_LINE.exec(line.trim());
102
+ if (!match) {
103
+ kept.push(line);
104
+ continue;
105
+ }
106
+ let kind = mediaKindOfMime(match[1]);
107
+ attachments.push({ path: match[2], name: fileRefName({ path: match[2] }), mime_type: match[1], ...kind ? { kind } : {} });
108
+ }
109
+ return { text: kept.join(`
110
+ `).trim(), attachments };
111
+ }
112
+ function fileRefText(ref) {
113
+ return ref.deleted ? deletedFilePlaceholder(ref) : `[${fileRefKind(ref) ?? "file"}: ${ref.path}]`;
114
+ }
115
+ function applyFileRefChanges(blocks, changes) {
116
+ let out = null;
117
+ for (let i = 0; i < blocks.length; i++) {
118
+ let block = blocks[i];
119
+ if (!isFileRefBlock(block) || block.file_ref.deleted) continue;
120
+ let ref = block.file_ref;
121
+ for (let change of changes) {
122
+ if (ref.deleted) break;
123
+ change.op === "rename" && ref.path === change.from ? ref = { ...ref, path: change.to } : change.op === "delete" && ref.path === change.path && (ref = { ...ref, deleted: !0 });
124
+ }
125
+ ref !== block.file_ref && (out ??= blocks.slice(), out[i] = { ...block, file_ref: ref });
126
+ }
127
+ return out ?? blocks;
128
+ }
129
+
130
+ export {
131
+ isVisionMime,
132
+ isAudioInputMime,
133
+ isVideoInputMime,
134
+ mediaKindOfMime,
135
+ isFileRefBlock,
136
+ fileRefKind,
137
+ fileRefName,
138
+ deletedFilePlaceholder,
139
+ displayAttachment,
140
+ attachmentsOf,
141
+ splitLegacyUploads,
142
+ fileRefText,
143
+ applyFileRefChanges,
144
+ file_ref_exports
145
+ };
@@ -0,0 +1,29 @@
1
+ import { createRequire as __adfCreateRequire } from 'node:module';
2
+ import { fileURLToPath as __adfFileURLToPath } from 'node:url';
3
+ import { dirname as __adfDirname } from 'node:path';
4
+ const require = __adfCreateRequire(import.meta.url);
5
+ const __filename = __adfFileURLToPath(import.meta.url);
6
+ const __dirname = __adfDirname(__filename);
7
+
8
+ // src/main/utils/secret-file.ts
9
+ import { execFileSync } from "node:child_process";
10
+ import { chmodSync } from "node:fs";
11
+ import { userInfo } from "node:os";
12
+ function restrictToCurrentUserWindows(path, run = (file, args) => {
13
+ execFileSync(file, args, { windowsHide: !0, stdio: ["ignore", "ignore", "pipe"] });
14
+ }) {
15
+ let user = process.env.USERDOMAIN && process.env.USERNAME ? `${process.env.USERDOMAIN}\\${process.env.USERNAME}` : userInfo().username;
16
+ run("icacls", [path, "/inheritance:r", "/grant:r", `${user}:F`]);
17
+ }
18
+ function protectSecretFile(path, opts = {}) {
19
+ try {
20
+ return (opts.platform ?? process.platform) === "win32" ? restrictToCurrentUserWindows(path, opts.run) : chmodSync(path, 384), !0;
21
+ } catch (err) {
22
+ return console.warn(`[SecretFile] Could not restrict ${path} to the current user: ${err instanceof Error ? err.message : String(err)}`), !1;
23
+ }
24
+ }
25
+
26
+ export {
27
+ restrictToCurrentUserWindows,
28
+ protectSecretFile
29
+ };
@@ -0,0 +1,425 @@
1
+ import { createRequire as __adfCreateRequire } from 'node:module';
2
+ import { fileURLToPath as __adfFileURLToPath } from 'node:url';
3
+ import { dirname as __adfDirname } from 'node:path';
4
+ const require = __adfCreateRequire(import.meta.url);
5
+ const __filename = __adfFileURLToPath(import.meta.url);
6
+ const __dirname = __adfDirname(__filename);
7
+ import {
8
+ writeSecretFileAtomic
9
+ } from "./chunk-ZPB3HYM7.mjs";
10
+
11
+ // src/main/services/remote-hello.ts
12
+ import { createHash as createHash3, createHmac, randomBytes as randomBytes3, timingSafeEqual as timingSafeEqual2 } from "node:crypto";
13
+
14
+ // src/main/daemon/remote-access/device-store.ts
15
+ import { createHash as createHash2, randomBytes as randomBytes2, timingSafeEqual } from "node:crypto";
16
+ import { existsSync as existsSync2, readFileSync as readFileSync2 } from "node:fs";
17
+ import { join as join2 } from "node:path";
18
+
19
+ // src/main/daemon/remote-access/config.ts
20
+ import { createHash, randomBytes } from "node:crypto";
21
+ import { existsSync, readFileSync } from "node:fs";
22
+ import { readFile } from "node:fs/promises";
23
+ import { hostname } from "node:os";
24
+ import { join } from "node:path";
25
+ var REMOTE_ACCESS_FILENAME = "remote-access.json", BASE32 = "abcdefghijklmnopqrstuvwxyz234567";
26
+ function base32(bytes) {
27
+ let bits = 0, value = 0, out = "";
28
+ for (let byte of bytes)
29
+ for (value = value << 8 | byte, bits += 8; bits >= 5; )
30
+ out += BASE32[value >>> bits - 5 & 31], bits -= 5;
31
+ return bits > 0 && (out += BASE32[value << 5 - bits & 31]), out;
32
+ }
33
+ function fingerprintOf(daemonId) {
34
+ let fp = base32(createHash("sha256").update(daemonId, "utf-8").digest().subarray(0, 5)).toUpperCase();
35
+ return `${fp.slice(0, 4)}-${fp.slice(4, 8)}`;
36
+ }
37
+ var UNSAFE_DISPLAY_CHARS = /[\u0000-\u001f\u007f-\u009f\u00ad\u061c\u115f\u180e\u200b-\u200f\u2028-\u202e\u2060-\u2064\u2066-\u2069\u3164\ufeff\uffa0\u{e0000}-\u{e007f}]|\u034f/u, UNSAFE_CHARS = UNSAFE_DISPLAY_CHARS;
38
+ function cleanDisplayName(raw, max) {
39
+ if (typeof raw != "string" || raw.length > max * 4 || UNSAFE_CHARS.test(raw)) return null;
40
+ let name = raw.replace(/\s+/g, " ").trim();
41
+ return !name || [...name].length > max ? null : name;
42
+ }
43
+ function defaultComputerName() {
44
+ return cleanDisplayName(hostname(), 63) ?? "ADF computer";
45
+ }
46
+ function defaultRemoteAccessConfig(name = defaultComputerName()) {
47
+ return { v: 1, enabled: !1, name, daemonId: null, allowedNetworks: [] };
48
+ }
49
+ function remoteAccessConfigPath(settingsDir) {
50
+ return join(settingsDir, REMOTE_ACCESS_FILENAME);
51
+ }
52
+ function isRecord(value) {
53
+ return !!value && typeof value == "object" && !Array.isArray(value);
54
+ }
55
+ function loadRemoteAccessConfig(settingsDir, defaultName) {
56
+ let path = remoteAccessConfigPath(settingsDir), defaults = defaultRemoteAccessConfig(defaultName);
57
+ if (!existsSync(path)) return { config: defaults, problem: null };
58
+ let raw;
59
+ try {
60
+ raw = JSON.parse(readFileSync(path, "utf-8"));
61
+ } catch (err) {
62
+ return { config: defaults, problem: `${path} is not valid JSON (${err instanceof Error ? err.message : String(err)}); remote access is off until it is fixed or deleted` };
63
+ }
64
+ if (!isRecord(raw) || raw.v !== 1)
65
+ return { config: defaults, problem: `${path} has an unsupported version; remote access is off until it is fixed or deleted` };
66
+ let networks = parseAllowedNetworks(raw.allowedNetworks), addresses = Array.isArray(raw.addresses) ? raw.addresses.filter((a) => typeof a == "string") : void 0;
67
+ return {
68
+ config: {
69
+ v: 1,
70
+ enabled: raw.enabled === !0,
71
+ name: cleanDisplayName(raw.name, 63) ?? defaults.name,
72
+ daemonId: typeof raw.daemonId == "string" && /^[a-z2-7]{26}$/.test(raw.daemonId) ? raw.daemonId : null,
73
+ allowedNetworks: networks,
74
+ ...addresses && addresses.length ? { addresses } : {}
75
+ },
76
+ problem: null
77
+ };
78
+ }
79
+ function saveRemoteAccessConfig(settingsDir, config) {
80
+ writeSecretFileAtomic(remoteAccessConfigPath(settingsDir), `${JSON.stringify(config, null, 2)}
81
+ `);
82
+ }
83
+ function parseAllowedNetworks(raw) {
84
+ return Array.isArray(raw) ? raw.filter((n) => isRecord(n) && typeof n.id == "string" && /^(lan|tailnet)-[0-9a-f]{16}$/.test(n.id) && (n.kind === "lan" || n.kind === "tailnet") && typeof n.label == "string" && typeof n.addedAt == "string") : [];
85
+ }
86
+ async function readAllowedNetworks(settingsDir) {
87
+ if (!settingsDir) return [];
88
+ try {
89
+ let raw = JSON.parse(await readFile(remoteAccessConfigPath(settingsDir), "utf-8"));
90
+ return isRecord(raw) && raw.v === 1 ? parseAllowedNetworks(raw.allowedNetworks) : [];
91
+ } catch {
92
+ return [];
93
+ }
94
+ }
95
+ function newDaemonId() {
96
+ return base32(randomBytes(16));
97
+ }
98
+
99
+ // src/main/daemon/remote-access/device-store.ts
100
+ var DEVICES_FILENAME = "daemon-devices.json", DEVICE_TOKEN_PREFIX = "adfd_", TOKEN_RE = /^adfd_([a-z2-7]{10})_([A-Za-z0-9_-]{43})$/, TOMBSTONE_DAYS = 30, LAST_SEEN_FLUSH_MS = 5 * 6e4;
101
+ function isDeviceTokenShape(token) {
102
+ return token.startsWith(DEVICE_TOKEN_PREFIX);
103
+ }
104
+ function parseDeviceToken(token) {
105
+ let match = TOKEN_RE.exec(token);
106
+ return match ? { id: match[1], secret: match[2] } : null;
107
+ }
108
+ function sha256Hex(text) {
109
+ return createHash2("sha256").update(text, "utf-8").digest("hex");
110
+ }
111
+ function isRecord2(value) {
112
+ return !!value && typeof value == "object" && !Array.isArray(value);
113
+ }
114
+ function validDevice(value) {
115
+ return isRecord2(value) && typeof value.id == "string" && /^[a-z2-7]{10}$/.test(value.id) && typeof value.label == "string" && (value.origin === "paired" || value.origin === "token") && typeof value.createdAt == "string" && (value.createdBy === "studio" || value.createdBy === "cli") && typeof value.secretSha256 == "string" && /^[0-9a-f]{64}$/.test(value.secretSha256);
116
+ }
117
+ var DeviceStore = class {
118
+ path;
119
+ devices = /* @__PURE__ */ new Map();
120
+ revoked = /* @__PURE__ */ new Map();
121
+ problemText = null;
122
+ lastFlushAt = /* @__PURE__ */ new Map();
123
+ dirty = !1;
124
+ now;
125
+ constructor(settingsDir, opts = {}) {
126
+ this.path = join2(settingsDir, DEVICES_FILENAME), this.now = opts.now ?? Date.now, this.load();
127
+ }
128
+ /** Why no device token is accepted (unreadable file); null when fine. */
129
+ get problem() {
130
+ return this.problemText;
131
+ }
132
+ load() {
133
+ if (existsSync2(this.path))
134
+ try {
135
+ let raw = JSON.parse(readFileSync2(this.path, "utf-8"));
136
+ if (!isRecord2(raw) || raw.v !== 1 || !Array.isArray(raw.devices)) throw new Error("unsupported version or shape");
137
+ for (let device of raw.devices) {
138
+ if (!validDevice(device)) throw new Error("a device record is malformed");
139
+ this.devices.set(device.id, {
140
+ ...device,
141
+ lastSeenAt: typeof device.lastSeenAt == "string" ? device.lastSeenAt : null,
142
+ lastSeenAddress: typeof device.lastSeenAddress == "string" ? device.lastSeenAddress : null
143
+ });
144
+ }
145
+ let cutoff = this.now() - TOMBSTONE_DAYS * 864e5;
146
+ for (let t of Array.isArray(raw.revoked) ? raw.revoked : [])
147
+ isRecord2(t) && typeof t.id == "string" && typeof t.label == "string" && typeof t.revokedAt == "string" && Date.parse(t.revokedAt) >= cutoff && this.revoked.set(t.id, { id: t.id, label: t.label, revokedAt: t.revokedAt });
148
+ } catch (err) {
149
+ this.devices.clear(), this.revoked.clear(), this.problemText = `${this.path} cannot be read (${err instanceof Error ? err.message : String(err)}); no device token is accepted until it is fixed or deleted`;
150
+ }
151
+ }
152
+ list() {
153
+ return [...this.devices.values()].sort((a, b) => a.createdAt.localeCompare(b.createdAt));
154
+ }
155
+ get(id) {
156
+ return this.devices.get(id);
157
+ }
158
+ /** Mint a device: the record is written before the token is returned. Throws when the store is unreadable. */
159
+ create(input) {
160
+ if (this.problemText) throw new Error(this.problemText);
161
+ let id = "";
162
+ do
163
+ id = base32(randomBytes2(7)).slice(0, 10);
164
+ while (this.devices.has(id) || this.revoked.has(id));
165
+ let secret = randomBytes2(32).toString("base64url"), device = {
166
+ id,
167
+ label: input.label,
168
+ origin: input.origin,
169
+ createdAt: new Date(this.now()).toISOString(),
170
+ createdBy: input.createdBy,
171
+ secretSha256: sha256Hex(secret),
172
+ lastSeenAt: null,
173
+ lastSeenAddress: null
174
+ };
175
+ this.devices.set(id, device);
176
+ try {
177
+ this.write();
178
+ } catch (err) {
179
+ throw this.devices.delete(id), err;
180
+ }
181
+ return { device, token: `${DEVICE_TOKEN_PREFIX}${id}_${secret}` };
182
+ }
183
+ /** Remove a device and keep its tombstone; the file is written first. Null for an unknown id. */
184
+ revoke(id) {
185
+ let device = this.devices.get(id);
186
+ if (!device) return null;
187
+ let tombstone = { id, label: device.label, revokedAt: new Date(this.now()).toISOString() };
188
+ this.devices.delete(id), this.revoked.set(id, tombstone);
189
+ try {
190
+ this.write();
191
+ } catch (err) {
192
+ throw this.devices.set(id, device), this.revoked.delete(id), err;
193
+ }
194
+ return this.lastFlushAt.delete(id), device;
195
+ }
196
+ /**
197
+ * The device behind an id, for the authenticated hello (remote-access.md
198
+ * §5.2.1): its record, a tombstone, or unknown (also while the store is
199
+ * unreadable). No secret is compared here.
200
+ */
201
+ lookup(id) {
202
+ if (this.problemText) return { kind: "unknown" };
203
+ let device = this.devices.get(id);
204
+ return device ? { kind: "device", device } : this.revoked.has(id) ? { kind: "revoked" } : { kind: "unknown" };
205
+ }
206
+ /** Constant-time check of a presented `adfd_` token. */
207
+ check(token) {
208
+ if (this.problemText) return { kind: "unknown" };
209
+ let parsed = parseDeviceToken(token);
210
+ if (!parsed) return { kind: "unknown" };
211
+ let device = this.devices.get(parsed.id);
212
+ if (device) {
213
+ let a = Buffer.from(sha256Hex(parsed.secret), "hex"), b = Buffer.from(device.secretSha256, "hex");
214
+ return a.length === b.length && timingSafeEqual(a, b) ? { kind: "device", device } : { kind: "unknown" };
215
+ }
216
+ let tombstone = this.revoked.get(parsed.id);
217
+ return tombstone ? { kind: "revoked", tombstone } : { kind: "unknown" };
218
+ }
219
+ /** A request from the device: exact in memory, written at most every LAST_SEEN_FLUSH_MS (flushDue). */
220
+ touch(id, address) {
221
+ let device = this.devices.get(id);
222
+ device && (device.lastSeenAt = new Date(this.now()).toISOString(), device.lastSeenAddress = address, this.dirty = !0);
223
+ }
224
+ /** Write lastSeen changes when a device's last write is older than LAST_SEEN_FLUSH_MS (or `force`, at shutdown). */
225
+ flushLastSeen(force = !1) {
226
+ if (!this.dirty || this.problemText) return;
227
+ let now = this.now();
228
+ if (force || [...this.devices.values()].some((d) => d.lastSeenAt && now - (this.lastFlushAt.get(d.id) ?? 0) >= LAST_SEEN_FLUSH_MS))
229
+ try {
230
+ this.write();
231
+ for (let id of this.devices.keys()) this.lastFlushAt.set(id, now);
232
+ this.dirty = !1;
233
+ } catch (err) {
234
+ console.error(`[remote-access] Could not write ${this.path}:`, err instanceof Error ? err.message : err);
235
+ }
236
+ }
237
+ write() {
238
+ let file = { v: 1, devices: this.list(), revoked: [...this.revoked.values()] };
239
+ writeSecretFileAtomic(this.path, `${JSON.stringify(file, null, 2)}
240
+ `);
241
+ }
242
+ };
243
+
244
+ // src/main/services/peer-text.ts
245
+ var PEER_BODY_MAX_BYTES = 4096, TXT_VALUE_MAX_BYTES = 255, TERMINAL_SEQUENCES = /\u001b\[[0-?]*[ -/]*[@-~]|\u001b\][^\u0007\u001b\u009c]*(?:\u0007|\u001b\\|\u009c)?|\u001b[PX^_][^\u001b\u009c]*(?:\u001b\\|\u009c)?|\u001b[@-Z\\-_]|\u009b[0-?]*[ -/]*[@-~]|\u009d[^\u0007\u009c]*(?:\u0007|\u009c)?|[\u0090\u0098\u009e\u009f][^\u009c]*\u009c?/g;
246
+ function printable(text) {
247
+ let unsafe = new RegExp(UNSAFE_DISPLAY_CHARS.source, "gu");
248
+ return text.replace(TERMINAL_SEQUENCES, "").split(`
249
+ `).map((line) => line.replace(unsafe, "")).join(`
250
+ `);
251
+ }
252
+ function peerName(raw, max = 63) {
253
+ if (typeof raw != "string" || raw.length > PEER_BODY_MAX_BYTES) return null;
254
+ let cut = [...printable(raw).replace(/\s+/g, " ").trim()].slice(0, max).join("").trim();
255
+ return cleanDisplayName(cut, max);
256
+ }
257
+ function txtWithinBounds(txt) {
258
+ let total = 0;
259
+ for (let [key, value] of Object.entries(txt)) {
260
+ let bytes = Buffer.byteLength(key) + 1 + (typeof value == "string" ? Buffer.byteLength(value) : value instanceof Uint8Array ? value.byteLength : String(value).length);
261
+ if (bytes > TXT_VALUE_MAX_BYTES || (total += bytes + 1, total > PEER_BODY_MAX_BYTES)) return !1;
262
+ }
263
+ return !0;
264
+ }
265
+ async function readCapped(res, max = PEER_BODY_MAX_BYTES) {
266
+ let declared = Number(res.headers.get("content-length"));
267
+ if (Number.isFinite(declared) && declared > max) return null;
268
+ if (!res.body) return "";
269
+ let reader = res.body.getReader(), chunks = [], size = 0;
270
+ try {
271
+ for (; ; ) {
272
+ let { done, value } = await reader.read();
273
+ if (done) break;
274
+ if (size += value.byteLength, size > max)
275
+ return await reader.cancel().catch(() => {
276
+ }), null;
277
+ chunks.push(value);
278
+ }
279
+ } finally {
280
+ reader.releaseLock?.();
281
+ }
282
+ return Buffer.concat(chunks).toString("utf8");
283
+ }
284
+
285
+ // src/main/services/remote-hello.ts
286
+ var FINGERPRINT = /^[A-Z2-7]{4}-[A-Z2-7]{4}$/;
287
+ function parseHello(body) {
288
+ if (!body || body.v !== 1 || typeof body.fingerprint != "string" || !FINGERPRINT.test(body.fingerprint)) return null;
289
+ let name = peerName(body.name);
290
+ return name ? {
291
+ v: 1,
292
+ name,
293
+ fingerprint: body.fingerprint,
294
+ pairingOpen: body.pairingOpen === !0,
295
+ clientApiVersion: typeof body.clientApiVersion == "number" && Number.isInteger(body.clientApiVersion) ? body.clientApiVersion : 0,
296
+ ...body.helloProof === 1 ? { helloProof: 1 } : {}
297
+ } : null;
298
+ }
299
+ async function fetchHello(url, fetchImpl = fetch, timeoutMs = 2500) {
300
+ try {
301
+ let res = await fetchImpl(`${url.replace(/\/+$/, "")}/remote/hello`, { signal: AbortSignal.timeout(timeoutMs), redirect: "manual" });
302
+ if (!res.ok) return null;
303
+ let text = await readCapped(res);
304
+ return text === null ? null : parseHello(JSON.parse(text));
305
+ } catch {
306
+ return null;
307
+ }
308
+ }
309
+ var HELLO_PROOF_DOMAIN = "adf-remote-hello-v1", NONCE = /^[A-Za-z0-9_-]{43}$/, DEVICE_ID = /^[a-z2-7]{10}$/, MAX_ORIGIN = 300;
310
+ function newHelloNonce() {
311
+ return randomBytes3(32).toString("base64url");
312
+ }
313
+ function helloOrigin(raw) {
314
+ if (typeof raw != "string" || raw.length > MAX_ORIGIN) return null;
315
+ try {
316
+ let url = new URL(raw);
317
+ return url.protocol !== "http:" && url.protocol !== "https:" ? null : url.origin;
318
+ } catch {
319
+ return null;
320
+ }
321
+ }
322
+ function helloProofRequest(query) {
323
+ let { nonce, device, origin } = query;
324
+ return typeof nonce != "string" || !NONCE.test(nonce) || typeof device != "string" || !DEVICE_ID.test(device) || typeof origin != "string" || helloOrigin(origin) !== origin ? null : { nonce, device, origin };
325
+ }
326
+ function helloProofMessage(input) {
327
+ return [HELLO_PROOF_DOMAIN, input.nonce, input.fingerprint, input.origin, input.device].join(`
328
+ `);
329
+ }
330
+ function helloProofMac(secretSha256, message) {
331
+ return createHmac("sha256", secretSha256).update(message, "utf-8").digest("base64url");
332
+ }
333
+ function deviceKey(token) {
334
+ let parsed = parseDeviceToken(token);
335
+ return parsed ? { id: parsed.id, key: createHash3("sha256").update(parsed.secret, "utf-8").digest() } : null;
336
+ }
337
+ async function verifyHello(url, token, opts = {}) {
338
+ let device = deviceKey(token);
339
+ if (!device) return { kind: "not_device_token" };
340
+ let origin = helloOrigin(url);
341
+ if (!origin) return { kind: "none" };
342
+ let nonce = opts.nonce ?? newHelloNonce(), query = new URLSearchParams({ nonce, device: device.id, origin }), body;
343
+ try {
344
+ let signals = [AbortSignal.timeout(opts.timeoutMs ?? 5e3), ...opts.signal ? [opts.signal] : []], res = await (opts.fetch ?? fetch)(`${url.replace(/\/+$/, "")}/remote/hello?${query}`, { signal: AbortSignal.any(signals), redirect: "manual" });
345
+ if (res.status === 429)
346
+ return res.body?.cancel().catch(() => {
347
+ }), { kind: "rate_limited", retryAfterMs: retryAfterMs(res.headers.get("retry-after")) };
348
+ if (!res.ok) return { kind: "none" };
349
+ let text = await readCapped(res);
350
+ if (text === null) return { kind: "none" };
351
+ body = JSON.parse(text);
352
+ } catch {
353
+ return { kind: "none" };
354
+ }
355
+ let hello = parseHello(body);
356
+ if (!hello || !body) return { kind: "none" };
357
+ if (body.helloProof !== 1 || !("proof" in body)) return { kind: "unsigned", hello };
358
+ if (body.device === "revoked") return { kind: "revoked", hello };
359
+ if (body.device !== "known") return { kind: "unknown_device", hello };
360
+ if (typeof body.proof != "string") return { kind: "forged", hello };
361
+ let expected = Buffer.from(helloProofMac(device.key, helloProofMessage({ nonce, fingerprint: hello.fingerprint, origin, device: device.id }))), given = Buffer.from(body.proof);
362
+ return given.length === expected.length && timingSafeEqual2(given, expected) ? { kind: "verified", hello } : { kind: "forged", hello };
363
+ }
364
+ function retryAfterMs(header) {
365
+ let seconds = Number(header);
366
+ return Number.isFinite(seconds) && seconds > 0 ? Math.min(60, Math.max(1, Math.ceil(seconds))) * 1e3 : 1e4;
367
+ }
368
+ function rateLimitedSentence(name) {
369
+ return `${name} is rate-limiting connections; retrying.`;
370
+ }
371
+ function olderAdfSentence(name) {
372
+ return `${name} runs an older ADF; update it.`;
373
+ }
374
+ function helloRefusal(check, name, url) {
375
+ switch (check.kind) {
376
+ case "unsigned":
377
+ return olderAdfSentence(name);
378
+ case "forged":
379
+ return `${url} could not prove it is ${name}; the token was not sent.`;
380
+ case "unknown_device":
381
+ return `${name} does not know this computer's token, which was not sent; pair it again.`;
382
+ case "revoked":
383
+ return `${name} removed this computer's access; pair it again.`;
384
+ case "not_device_token":
385
+ return `${name} can prove who it is only for a device token; pair it again.`;
386
+ case "rate_limited":
387
+ return rateLimitedSentence(name);
388
+ default:
389
+ return null;
390
+ }
391
+ }
392
+ async function verifyHelloWaiting(url, token, opts = {}) {
393
+ let { retries = 3, sleep = (ms) => new Promise((r) => setTimeout(r, ms)), onWait, ...verify } = opts, check = await verifyHello(url, token, verify);
394
+ for (let attempt = 0; check.kind === "rate_limited" && attempt < retries; attempt++)
395
+ onWait?.(check.retryAfterMs), await sleep(check.retryAfterMs), check = await verifyHello(url, token, verify);
396
+ return check;
397
+ }
398
+
399
+ export {
400
+ fingerprintOf,
401
+ UNSAFE_DISPLAY_CHARS,
402
+ cleanDisplayName,
403
+ defaultComputerName,
404
+ loadRemoteAccessConfig,
405
+ saveRemoteAccessConfig,
406
+ readAllowedNetworks,
407
+ newDaemonId,
408
+ isDeviceTokenShape,
409
+ DeviceStore,
410
+ printable,
411
+ peerName,
412
+ txtWithinBounds,
413
+ fetchHello,
414
+ HELLO_PROOF_DOMAIN,
415
+ newHelloNonce,
416
+ helloOrigin,
417
+ helloProofRequest,
418
+ helloProofMessage,
419
+ helloProofMac,
420
+ verifyHello,
421
+ rateLimitedSentence,
422
+ olderAdfSentence,
423
+ helloRefusal,
424
+ verifyHelloWaiting
425
+ };
@@ -6,16 +6,16 @@ const __filename = __adfFileURLToPath(import.meta.url);
6
6
  const __dirname = __adfDirname(__filename);
7
7
  import {
8
8
  ID3v2Parser
9
- } from "./chunk-XYTWGHFS.mjs";
9
+ } from "./chunk-H3XLRWVE.mjs";
10
10
  import {
11
11
  ID3v1Parser
12
- } from "./chunk-VAUOM3IN.mjs";
13
- import {
14
- ID3v2Header
15
- } from "./chunk-DXWDD5XJ.mjs";
12
+ } from "./chunk-DLWCKKIO.mjs";
16
13
  import {
17
14
  EndOfStreamError
18
15
  } from "./chunk-HBUENVQL.mjs";
16
+ import {
17
+ ID3v2Header
18
+ } from "./chunk-DXWDD5XJ.mjs";
19
19
  import {
20
20
  BasicParser
21
21
  } from "./chunk-I2HJYHFT.mjs";