@aria-cli/tools 1.0.12 → 1.0.14

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 (233) hide show
  1. package/dist/index.js +378 -70
  2. package/dist/network-runtime/index.js +8 -12
  3. package/dist-cjs/index.js +400 -435
  4. package/dist-cjs/network-runtime/index.js +8 -172
  5. package/package.json +8 -6
  6. package/dist/.tsbuildinfo +0 -1
  7. package/dist/ask-user-interaction.js +0 -22
  8. package/dist/cache/web-cache.js +0 -66
  9. package/dist/definitions/arion.js +0 -104
  10. package/dist/definitions/browser/browser.js +0 -418
  11. package/dist/definitions/browser/index.js +0 -4
  12. package/dist/definitions/browser/pw-downloads.js +0 -114
  13. package/dist/definitions/browser/pw-interactions.js +0 -199
  14. package/dist/definitions/browser/pw-responses.js +0 -76
  15. package/dist/definitions/browser/pw-session.js +0 -310
  16. package/dist/definitions/browser/pw-shared.js +0 -66
  17. package/dist/definitions/browser/pw-snapshot.js +0 -301
  18. package/dist/definitions/browser/pw-state.js +0 -62
  19. package/dist/definitions/browser/types.js +0 -4
  20. package/dist/definitions/code-intelligence.js +0 -470
  21. package/dist/definitions/core.js +0 -109
  22. package/dist/definitions/delegation.js +0 -512
  23. package/dist/definitions/deploy.js +0 -65
  24. package/dist/definitions/filesystem.js +0 -196
  25. package/dist/definitions/frg.js +0 -63
  26. package/dist/definitions/index.js +0 -20
  27. package/dist/definitions/memory.js +0 -123
  28. package/dist/definitions/messaging.js +0 -625
  29. package/dist/definitions/meta.js +0 -349
  30. package/dist/definitions/network.js +0 -159
  31. package/dist/definitions/outlook.js +0 -277
  32. package/dist/definitions/patch/apply-patch.js +0 -184
  33. package/dist/definitions/patch/fuzzy-match.js +0 -166
  34. package/dist/definitions/patch/index.js +0 -1
  35. package/dist/definitions/patch/patch-parser.js +0 -207
  36. package/dist/definitions/patch/sandbox-paths.js +0 -105
  37. package/dist/definitions/process/index.js +0 -4
  38. package/dist/definitions/process/process-registry.js +0 -213
  39. package/dist/definitions/process/process.js +0 -386
  40. package/dist/definitions/process/pty-keys.js +0 -254
  41. package/dist/definitions/process/session-slug.js +0 -142
  42. package/dist/definitions/quip.js +0 -195
  43. package/dist/definitions/search.js +0 -60
  44. package/dist/definitions/session-history.js +0 -69
  45. package/dist/definitions/shell.js +0 -181
  46. package/dist/definitions/slack.js +0 -180
  47. package/dist/definitions/web.js +0 -109
  48. package/dist/executors/apply-patch.js +0 -901
  49. package/dist/executors/arion.js +0 -119
  50. package/dist/executors/code-intelligence.js +0 -882
  51. package/dist/executors/deploy.js +0 -848
  52. package/dist/executors/filesystem.js +0 -1122
  53. package/dist/executors/frg-freshness.js +0 -576
  54. package/dist/executors/frg.js +0 -298
  55. package/dist/executors/index.js +0 -46
  56. package/dist/executors/learning-meta.js +0 -1146
  57. package/dist/executors/lsp-client.js +0 -296
  58. package/dist/executors/memory.js +0 -750
  59. package/dist/executors/meta.js +0 -220
  60. package/dist/executors/process-registry.js +0 -465
  61. package/dist/executors/pty-session-store.js +0 -30
  62. package/dist/executors/pty.js +0 -271
  63. package/dist/executors/restart.js +0 -119
  64. package/dist/executors/search-freshness.js +0 -195
  65. package/dist/executors/search-types.js +0 -52
  66. package/dist/executors/search.js +0 -66
  67. package/dist/executors/self-diagnose.js +0 -398
  68. package/dist/executors/session-history.js +0 -283
  69. package/dist/executors/shell-safety.js +0 -473
  70. package/dist/executors/shell.js +0 -954
  71. package/dist/executors/utils.js +0 -33
  72. package/dist/executors/web.js +0 -542
  73. package/dist/extraction/content-extraction.js +0 -235
  74. package/dist/extraction/index.js +0 -4
  75. package/dist/headless-control-contract.js +0 -967
  76. package/dist/local-control-http-auth.js +0 -2
  77. package/dist/mcp/client.js +0 -181
  78. package/dist/mcp/connection.js +0 -480
  79. package/dist/mcp/index.js +0 -10
  80. package/dist/mcp/jsonrpc.js +0 -144
  81. package/dist/mcp/types.js +0 -7
  82. package/dist/network-control-adapter.js +0 -72
  83. package/dist/network-runtime/address-types.js +0 -165
  84. package/dist/network-runtime/db-owner-fencing.js +0 -69
  85. package/dist/network-runtime/delivery-receipts.js +0 -267
  86. package/dist/network-runtime/direct-endpoint-authority.js +0 -25
  87. package/dist/network-runtime/local-control-contract.js +0 -627
  88. package/dist/network-runtime/node-store-contract.js +0 -34
  89. package/dist/network-runtime/pair-route-contract.js +0 -77
  90. package/dist/network-runtime/peer-capabilities.js +0 -28
  91. package/dist/network-runtime/peer-principal-ref.js +0 -12
  92. package/dist/network-runtime/peer-state-machine.js +0 -121
  93. package/dist/network-runtime/protocol-schemas.js +0 -205
  94. package/dist/network-runtime/runtime-bootstrap-contract.js +0 -60
  95. package/dist/outlook/desktop-session.js +0 -279
  96. package/dist/policy.js +0 -149
  97. package/dist/providers/brave.js +0 -62
  98. package/dist/providers/duckduckgo.js +0 -176
  99. package/dist/providers/exa.js +0 -63
  100. package/dist/providers/firecrawl.js +0 -55
  101. package/dist/providers/index.js +0 -7
  102. package/dist/providers/jina.js +0 -49
  103. package/dist/providers/router.js +0 -96
  104. package/dist/providers/search-provider.js +0 -32
  105. package/dist/providers/tavily.js +0 -54
  106. package/dist/quip/desktop-session.js +0 -317
  107. package/dist/registry/index.js +0 -1
  108. package/dist/registry/registry.js +0 -756
  109. package/dist/runtime-socket-local-control-client.js +0 -330
  110. package/dist/security/dns-normalization.js +0 -19
  111. package/dist/security/dns-pinning.js +0 -123
  112. package/dist/security/external-content.js +0 -91
  113. package/dist/security/ssrf.js +0 -181
  114. package/dist/slack/desktop-session.js +0 -324
  115. package/dist/tool-factory.js +0 -47
  116. package/dist/types.js +0 -7
  117. package/dist/utils/retry.js +0 -132
  118. package/dist/utils/safe-parse-json.js +0 -160
  119. package/dist/utils/url.js +0 -19
  120. package/dist-cjs/.tsbuildinfo +0 -1
  121. package/dist-cjs/ask-user-interaction.js +0 -27
  122. package/dist-cjs/cache/web-cache.js +0 -70
  123. package/dist-cjs/definitions/arion.js +0 -107
  124. package/dist-cjs/definitions/browser/browser.js +0 -421
  125. package/dist-cjs/definitions/browser/index.js +0 -8
  126. package/dist-cjs/definitions/browser/pw-downloads.js +0 -117
  127. package/dist-cjs/definitions/browser/pw-interactions.js +0 -213
  128. package/dist-cjs/definitions/browser/pw-responses.js +0 -84
  129. package/dist-cjs/definitions/browser/pw-session.js +0 -326
  130. package/dist-cjs/definitions/browser/pw-shared.js +0 -72
  131. package/dist-cjs/definitions/browser/pw-snapshot.js +0 -307
  132. package/dist-cjs/definitions/browser/pw-state.js +0 -70
  133. package/dist-cjs/definitions/browser/types.js +0 -5
  134. package/dist-cjs/definitions/code-intelligence.js +0 -473
  135. package/dist-cjs/definitions/core.js +0 -133
  136. package/dist-cjs/definitions/delegation.js +0 -515
  137. package/dist-cjs/definitions/deploy.js +0 -68
  138. package/dist-cjs/definitions/filesystem.js +0 -199
  139. package/dist-cjs/definitions/frg.js +0 -66
  140. package/dist-cjs/definitions/index.js +0 -43
  141. package/dist-cjs/definitions/memory.js +0 -126
  142. package/dist-cjs/definitions/messaging.js +0 -631
  143. package/dist-cjs/definitions/meta.js +0 -352
  144. package/dist-cjs/definitions/network.js +0 -162
  145. package/dist-cjs/definitions/outlook.js +0 -280
  146. package/dist-cjs/definitions/patch/apply-patch.js +0 -191
  147. package/dist-cjs/definitions/patch/fuzzy-match.js +0 -172
  148. package/dist-cjs/definitions/patch/index.js +0 -5
  149. package/dist-cjs/definitions/patch/patch-parser.js +0 -215
  150. package/dist-cjs/definitions/patch/sandbox-paths.js +0 -113
  151. package/dist-cjs/definitions/process/index.js +0 -8
  152. package/dist-cjs/definitions/process/process-registry.js +0 -231
  153. package/dist-cjs/definitions/process/process.js +0 -389
  154. package/dist-cjs/definitions/process/pty-keys.js +0 -259
  155. package/dist-cjs/definitions/process/session-slug.js +0 -145
  156. package/dist-cjs/definitions/quip.js +0 -198
  157. package/dist-cjs/definitions/search.js +0 -63
  158. package/dist-cjs/definitions/session-history.js +0 -72
  159. package/dist-cjs/definitions/shell.js +0 -184
  160. package/dist-cjs/definitions/slack.js +0 -183
  161. package/dist-cjs/definitions/web.js +0 -112
  162. package/dist-cjs/executors/apply-patch.js +0 -938
  163. package/dist-cjs/executors/arion.js +0 -125
  164. package/dist-cjs/executors/code-intelligence.js +0 -925
  165. package/dist-cjs/executors/deploy.js +0 -869
  166. package/dist-cjs/executors/filesystem.js +0 -1167
  167. package/dist-cjs/executors/frg-freshness.js +0 -627
  168. package/dist-cjs/executors/frg.js +0 -334
  169. package/dist-cjs/executors/index.js +0 -143
  170. package/dist-cjs/executors/learning-meta.js +0 -1165
  171. package/dist-cjs/executors/lsp-client.js +0 -310
  172. package/dist-cjs/executors/memory.js +0 -796
  173. package/dist-cjs/executors/meta.js +0 -226
  174. package/dist-cjs/executors/process-registry.js +0 -469
  175. package/dist-cjs/executors/pty-session-store.js +0 -34
  176. package/dist-cjs/executors/pty.js +0 -312
  177. package/dist-cjs/executors/restart.js +0 -155
  178. package/dist-cjs/executors/search-freshness.js +0 -234
  179. package/dist-cjs/executors/search-types.js +0 -56
  180. package/dist-cjs/executors/search.js +0 -102
  181. package/dist-cjs/executors/self-diagnose.js +0 -434
  182. package/dist-cjs/executors/session-history.js +0 -320
  183. package/dist-cjs/executors/shell-safety.js +0 -478
  184. package/dist-cjs/executors/shell.js +0 -1001
  185. package/dist-cjs/executors/utils.js +0 -73
  186. package/dist-cjs/executors/web.js +0 -547
  187. package/dist-cjs/extraction/content-extraction.js +0 -243
  188. package/dist-cjs/extraction/index.js +0 -8
  189. package/dist-cjs/headless-control-contract.js +0 -972
  190. package/dist-cjs/local-control-http-auth.js +0 -5
  191. package/dist-cjs/mcp/client.js +0 -185
  192. package/dist-cjs/mcp/connection.js +0 -484
  193. package/dist-cjs/mcp/index.js +0 -30
  194. package/dist-cjs/mcp/jsonrpc.js +0 -148
  195. package/dist-cjs/mcp/types.js +0 -8
  196. package/dist-cjs/network-control-adapter.js +0 -77
  197. package/dist-cjs/network-runtime/address-types.js +0 -168
  198. package/dist-cjs/network-runtime/db-owner-fencing.js +0 -76
  199. package/dist-cjs/network-runtime/delivery-receipts.js +0 -276
  200. package/dist-cjs/network-runtime/direct-endpoint-authority.js +0 -29
  201. package/dist-cjs/network-runtime/local-control-contract.js +0 -633
  202. package/dist-cjs/network-runtime/node-store-contract.js +0 -38
  203. package/dist-cjs/network-runtime/pair-route-contract.js +0 -80
  204. package/dist-cjs/network-runtime/peer-capabilities.js +0 -37
  205. package/dist-cjs/network-runtime/peer-principal-ref.js +0 -15
  206. package/dist-cjs/network-runtime/peer-state-machine.js +0 -129
  207. package/dist-cjs/network-runtime/protocol-schemas.js +0 -212
  208. package/dist-cjs/network-runtime/runtime-bootstrap-contract.js +0 -63
  209. package/dist-cjs/outlook/desktop-session.js +0 -318
  210. package/dist-cjs/policy.js +0 -155
  211. package/dist-cjs/providers/brave.js +0 -66
  212. package/dist-cjs/providers/duckduckgo.js +0 -180
  213. package/dist-cjs/providers/exa.js +0 -67
  214. package/dist-cjs/providers/firecrawl.js +0 -59
  215. package/dist-cjs/providers/index.js +0 -17
  216. package/dist-cjs/providers/jina.js +0 -53
  217. package/dist-cjs/providers/router.js +0 -100
  218. package/dist-cjs/providers/search-provider.js +0 -36
  219. package/dist-cjs/providers/tavily.js +0 -58
  220. package/dist-cjs/quip/desktop-session.js +0 -353
  221. package/dist-cjs/registry/index.js +0 -6
  222. package/dist-cjs/registry/registry.js +0 -761
  223. package/dist-cjs/runtime-socket-local-control-client.js +0 -367
  224. package/dist-cjs/security/dns-normalization.js +0 -22
  225. package/dist-cjs/security/dns-pinning.js +0 -160
  226. package/dist-cjs/security/external-content.js +0 -95
  227. package/dist-cjs/security/ssrf.js +0 -221
  228. package/dist-cjs/slack/desktop-session.js +0 -366
  229. package/dist-cjs/tool-factory.js +0 -50
  230. package/dist-cjs/types.js +0 -8
  231. package/dist-cjs/utils/retry.js +0 -169
  232. package/dist-cjs/utils/safe-parse-json.js +0 -164
  233. package/dist-cjs/utils/url.js +0 -23
@@ -1,181 +0,0 @@
1
- /**
2
- * SSRF (Server-Side Request Forgery) protection utilities
3
- *
4
- * Provides IP validation, URL validation, and redirect following with
5
- * SSRF protection for web operations.
6
- */
7
- import * as dns from "node:dns";
8
- import * as net from "node:net";
9
- import { getErrorMessage } from "../executors/utils.js";
10
- import { normalizeLookupResult } from "./dns-normalization.js";
11
- /** Maximum number of redirects to follow manually */
12
- const MAX_REDIRECT_HOPS = 5;
13
- /**
14
- * Validates URL syntax/protocol only (no DNS resolution).
15
- * Use this when DNS validation is enforced by the fetch boundary itself
16
- * (for example, DNS-pinned fetch).
17
- */
18
- export function validateUrlStructure(url) {
19
- try {
20
- const parsed = new URL(url);
21
- if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
22
- return `Invalid URL protocol: ${parsed.protocol}. Only http: and https: are allowed.`;
23
- }
24
- }
25
- catch {
26
- return `Invalid URL format: ${url}`;
27
- }
28
- return null;
29
- }
30
- /**
31
- * Checks whether an IP address belongs to a private/reserved network range.
32
- * Blocks loopback, RFC 1918, link-local, IPv6 private, and unspecified addresses.
33
- */
34
- export function isPrivateAddress(ip) {
35
- // IPv6-mapped IPv4 (::ffff:127.0.0.1) — strip prefix and re-check as IPv4
36
- if (ip.startsWith("::ffff:")) {
37
- return isPrivateAddress(ip.slice(7));
38
- }
39
- // Unspecified addresses
40
- if (ip === "0.0.0.0" || ip === "::" || ip === "[::]") {
41
- return true;
42
- }
43
- // IPv6 loopback
44
- if (ip === "::1") {
45
- return true;
46
- }
47
- // IPv6 private (fc00::/7 — covers fc00:: through fdff::)
48
- if (/^f[cd]/i.test(ip)) {
49
- return true;
50
- }
51
- // IPv6 link-local (fe80::/10)
52
- if (/^fe[89ab]/i.test(ip)) {
53
- return true;
54
- }
55
- // For IPv4 addresses, parse octets
56
- if (net.isIPv4(ip)) {
57
- const parts = ip.split(".").map(Number);
58
- const a = parts[0];
59
- const b = parts[1];
60
- // 127.0.0.0/8 — loopback
61
- if (a === 127)
62
- return true;
63
- // 10.0.0.0/8 — RFC 1918
64
- if (a === 10)
65
- return true;
66
- // 172.16.0.0/12 — RFC 1918 (172.16.x.x – 172.31.x.x)
67
- if (a === 172 && b >= 16 && b <= 31)
68
- return true;
69
- // 192.168.0.0/16 — RFC 1918
70
- if (a === 192 && b === 168)
71
- return true;
72
- // 169.254.0.0/16 — link-local (incl. AWS metadata 169.254.169.254)
73
- if (a === 169 && b === 254)
74
- return true;
75
- // 0.0.0.0/8 — current network
76
- if (a === 0)
77
- return true;
78
- // 100.64.0.0/10 — RFC 6598 shared address space (CGNAT)
79
- if (a === 100 && b >= 64 && b <= 127)
80
- return true;
81
- // 192.0.0.0/24 — RFC 6890 IETF protocol assignments
82
- if (a === 192 && b === 0 && parts[2] === 0)
83
- return true;
84
- // 198.18.0.0/15 — RFC 2544 benchmark testing (198.18.x.x – 198.19.x.x)
85
- if (a === 198 && (b === 18 || b === 19))
86
- return true;
87
- // 240.0.0.0/4 — RFC 1112 future use / reserved (240.x.x.x – 255.x.x.x)
88
- if (a >= 240)
89
- return true;
90
- }
91
- return false;
92
- }
93
- /**
94
- * Validates that a string is a valid HTTP(S) URL and does not resolve
95
- * to a private/reserved IP address (SSRF protection).
96
- * Returns null if valid, error message if invalid.
97
- */
98
- export async function validateUrl(url) {
99
- const structureError = validateUrlStructure(url);
100
- if (structureError) {
101
- return structureError;
102
- }
103
- const parsed = new URL(url);
104
- // Resolve hostname to IP and check for private addresses
105
- try {
106
- const lookupResult = await dns.promises.lookup(parsed.hostname, {
107
- all: true,
108
- verbatim: true,
109
- });
110
- const addresses = normalizeLookupResult(lookupResult).map((entry) => entry.address);
111
- if (addresses.length === 0) {
112
- return `DNS resolution failed for ${parsed.hostname}: no addresses returned`;
113
- }
114
- const privateAddress = addresses.find((address) => isPrivateAddress(address));
115
- if (privateAddress) {
116
- return `Access to private network address denied: ${parsed.hostname} resolved to ${privateAddress}`;
117
- }
118
- }
119
- catch (err) {
120
- return `DNS resolution failed for ${parsed.hostname}: ${getErrorMessage(err)}`;
121
- }
122
- return null;
123
- }
124
- /**
125
- * Best-effort disposal for unread response bodies.
126
- * Redirect and early-return paths must explicitly close bodies they abandon so
127
- * later aborts cannot surface from resources that no caller still owns.
128
- */
129
- export async function discardResponseBody(response) {
130
- const body = response?.body;
131
- if (!body || body.locked) {
132
- return;
133
- }
134
- try {
135
- await body.cancel();
136
- }
137
- catch {
138
- // Discard is best-effort cleanup only.
139
- }
140
- }
141
- export async function followRedirects(initialResponse, requestInit, options = {}) {
142
- const maxHops = options.maxHops ?? MAX_REDIRECT_HOPS;
143
- const fetchFn = options.fetchFn ?? fetch;
144
- const validateRedirectUrl = options.validateRedirectUrl ?? validateUrl;
145
- let response = initialResponse;
146
- let currentUrl = response.url || options.baseUrl || "";
147
- let hops = 0;
148
- while (hops < maxHops && response.status >= 300 && response.status < 400) {
149
- const location = response.headers.get("Location");
150
- if (!location) {
151
- break;
152
- }
153
- let resolvedLocation;
154
- try {
155
- if (currentUrl) {
156
- resolvedLocation = new URL(location, currentUrl).toString();
157
- }
158
- else {
159
- resolvedLocation = new URL(location).toString();
160
- }
161
- }
162
- catch {
163
- await discardResponseBody(response);
164
- throw new Error(`Invalid redirect URL: ${location}`);
165
- }
166
- // Validate the redirect target against SSRF
167
- const redirectError = await validateRedirectUrl(resolvedLocation);
168
- if (redirectError) {
169
- await discardResponseBody(response);
170
- throw new Error(`Redirect blocked (hop ${hops + 1}): ${redirectError}`);
171
- }
172
- await discardResponseBody(response);
173
- response = await fetchFn(resolvedLocation, {
174
- ...requestInit,
175
- redirect: "manual",
176
- });
177
- currentUrl = response.url || resolvedLocation;
178
- hops++;
179
- }
180
- return response;
181
- }
@@ -1,324 +0,0 @@
1
- import crypto from "node:crypto";
2
- import { execFile } from "node:child_process";
3
- import { promises as fs } from "node:fs";
4
- import os from "node:os";
5
- import path from "node:path";
6
- import { promisify } from "node:util";
7
- const execFileAsync = promisify(execFile);
8
- const SLACK_APP_SUPPORT_DIR = path.join(os.homedir(), "Library", "Application Support", "Slack");
9
- const SLACK_LEVELDB_DIR = path.join(SLACK_APP_SUPPORT_DIR, "Local Storage", "leveldb");
10
- const SLACK_COOKIE_DB_PATH = path.join(SLACK_APP_SUPPORT_DIR, "Cookies");
11
- const SLACK_SAFE_STORAGE_SERVICE = "Slack Safe Storage";
12
- const SLACK_APP_ORIGIN = "https://app.slack.com";
13
- const DEFAULT_BOOTSTRAP_TIMEOUT_MS = 30_000;
14
- const TEAM_ID_REGEX = /\bT[A-Z0-9]{8,}\b/g;
15
- const TOKEN_REGEX = /\bxoxc-[A-Za-z0-9-]{20,}\b/g;
16
- export function extractCachedSlackDesktopState(levelDbText) {
17
- const cachedToken = levelDbText.match(TOKEN_REGEX)?.[0] ?? null;
18
- const teamIds = [];
19
- const seen = new Set();
20
- const localConfigSegments = [...levelDbText.matchAll(/localConfig_v2[\s\S]{0,8000}/g)].map((match) => match[0]);
21
- const sources = localConfigSegments.length > 0 ? localConfigSegments : [levelDbText];
22
- for (const source of sources) {
23
- for (const teamId of source.match(TEAM_ID_REGEX) ?? []) {
24
- if (seen.has(teamId))
25
- continue;
26
- seen.add(teamId);
27
- teamIds.push(teamId);
28
- }
29
- }
30
- return { cachedToken, teamIds };
31
- }
32
- export function extractWorkspaceHostFromAppHtml(html) {
33
- const enterpriseHosts = [...html.matchAll(/https:\/\/([A-Za-z0-9.-]+\.enterprise\.slack\.com)/g)]
34
- .map((match) => match[1])
35
- .filter(Boolean);
36
- if (enterpriseHosts.length > 0) {
37
- return enterpriseHosts[0] ?? null;
38
- }
39
- const workspaceHosts = [...html.matchAll(/https:\/\/([A-Za-z0-9.-]+\.slack\.com)/g)]
40
- .map((match) => match[1])
41
- .filter((host) => host !== "api.slack.com" && host !== "app.slack.com");
42
- return workspaceHosts[0] ?? null;
43
- }
44
- export function extractLiveSlackTokenFromMultipartBody(body) {
45
- const match = body.match(/name="token"\r?\n\r?\n([^\r\n]+)/);
46
- return match?.[1] ?? null;
47
- }
48
- function decryptChromiumCookieHex(cookieHex, safeStoragePassword) {
49
- const encryptedValue = Buffer.from(cookieHex, "hex");
50
- if (encryptedValue.length === 0) {
51
- return "";
52
- }
53
- const versionPrefix = encryptedValue.subarray(0, 3).toString("utf8");
54
- if (versionPrefix !== "v10" && versionPrefix !== "v11") {
55
- return encryptedValue.toString("utf8");
56
- }
57
- const key = crypto.pbkdf2Sync(safeStoragePassword, "saltysalt", 1003, 16, "sha1");
58
- const decipher = crypto.createDecipheriv("aes-128-cbc", key, Buffer.alloc(16, 0x20));
59
- let decrypted = Buffer.concat([decipher.update(encryptedValue.subarray(3)), decipher.final()]);
60
- const padLength = decrypted.at(-1) ?? 0;
61
- if (padLength > 0 && padLength <= 16) {
62
- decrypted = decrypted.subarray(0, decrypted.length - padLength);
63
- }
64
- // Chromium cookie DB version 24 prefixes SHA-256(host_key) before the plaintext value.
65
- if (decrypted.length >= 32) {
66
- decrypted = decrypted.subarray(32);
67
- }
68
- return decrypted.toString("utf8");
69
- }
70
- async function readSlackLevelDbText(levelDbDir = SLACK_LEVELDB_DIR) {
71
- const entries = await fs.readdir(levelDbDir);
72
- const files = entries.filter((entry) => entry.endsWith(".ldb") || entry.endsWith(".log")).sort();
73
- const chunks = await Promise.all(files.map(async (entry) => {
74
- const fullPath = path.join(levelDbDir, entry);
75
- return fs.readFile(fullPath, "utf8").catch(async () => {
76
- const bytes = await fs.readFile(fullPath);
77
- return bytes.toString("utf8");
78
- });
79
- }));
80
- return chunks.join("\n");
81
- }
82
- async function readSeedCookies(cookieDbPath = SLACK_COOKIE_DB_PATH) {
83
- const { stdout: passwordStdout } = await execFileAsync("security", [
84
- "find-generic-password",
85
- "-w",
86
- "-s",
87
- SLACK_SAFE_STORAGE_SERVICE,
88
- ]);
89
- const safeStoragePassword = passwordStdout.trim();
90
- const sql = [
91
- "SELECT host_key, name, path, is_secure, is_httponly, hex(encrypted_value)",
92
- "FROM cookies",
93
- "WHERE host_key IN ('.slack.com', 'app.slack.com')",
94
- "AND name IN ('b', 'd')",
95
- "ORDER BY name",
96
- ].join(" ");
97
- const { stdout } = await execFileAsync("sqlite3", ["-separator", "\t", cookieDbPath, sql]);
98
- const cookies = stdout
99
- .split("\n")
100
- .map((line) => line.trim())
101
- .filter(Boolean)
102
- .map((line) => {
103
- const [domain, name, cookiePath, secureFlag, httpOnlyFlag, encryptedHex] = line.split("\t");
104
- if (!domain || !name || !encryptedHex) {
105
- throw new Error(`Unexpected sqlite3 cookie row shape: ${line}`);
106
- }
107
- return {
108
- name,
109
- value: decryptChromiumCookieHex(encryptedHex ?? "", safeStoragePassword),
110
- domain,
111
- path: cookiePath || "/",
112
- secure: secureFlag === "1",
113
- httpOnly: httpOnlyFlag === "1",
114
- };
115
- });
116
- if (cookies.length === 0) {
117
- throw new Error("Slack Desktop auth cookies were not found in the local Chromium cookie store.");
118
- }
119
- return cookies;
120
- }
121
- async function waitForLiveSlackBootstrap(page, timeoutMs) {
122
- return new Promise((resolve, reject) => {
123
- const timer = setTimeout(() => {
124
- page.off("request", handleRequest);
125
- reject(new Error("Timed out while waiting for the live Slack Desktop API bootstrap request."));
126
- }, timeoutMs);
127
- const handleRequest = (request) => {
128
- const requestUrl = request.url();
129
- if (!requestUrl.includes("/api/")) {
130
- return;
131
- }
132
- const liveToken = extractLiveSlackTokenFromMultipartBody(request.postData() ?? "");
133
- if (!liveToken) {
134
- return;
135
- }
136
- clearTimeout(timer);
137
- page.off("request", handleRequest);
138
- resolve({
139
- workspaceHost: new URL(requestUrl).host,
140
- liveToken,
141
- });
142
- };
143
- page.on("request", handleRequest);
144
- });
145
- }
146
- function normalizeRequestForm(liveToken, fields) {
147
- const form = { token: liveToken };
148
- for (const [key, value] of Object.entries(fields)) {
149
- if (value === undefined)
150
- continue;
151
- if (typeof value === "string") {
152
- form[key] = value;
153
- continue;
154
- }
155
- if (typeof value === "number" || typeof value === "boolean") {
156
- form[key] = String(value);
157
- continue;
158
- }
159
- form[key] = JSON.stringify(value);
160
- }
161
- return form;
162
- }
163
- function normalizeChannelRef(channelRef) {
164
- return channelRef.startsWith("#") ? channelRef.slice(1) : channelRef;
165
- }
166
- function looksLikeConversationId(channelRef) {
167
- return /^[CDG][A-Z0-9]{8,}$/.test(channelRef);
168
- }
169
- function toSlackMessageView(message) {
170
- return {
171
- ts: typeof message.ts === "string" ? message.ts : "",
172
- user: typeof message.user === "string"
173
- ? message.user
174
- : typeof message.bot_id === "string"
175
- ? message.bot_id
176
- : null,
177
- text: typeof message.text === "string" ? message.text : "",
178
- subtype: typeof message.subtype === "string" ? message.subtype : null,
179
- threadTs: typeof message.thread_ts === "string" ? message.thread_ts : null,
180
- };
181
- }
182
- export async function createSlackDesktopClient(options) {
183
- const cachedState = extractCachedSlackDesktopState(await readSlackLevelDbText());
184
- const teamId = options?.teamId ?? cachedState.teamIds[0];
185
- if (!teamId) {
186
- throw new Error("No Slack workspace team id was discovered in the local Slack Desktop storage.");
187
- }
188
- const playwright = await import("playwright");
189
- const browser = await playwright.chromium.launch({ headless: true });
190
- const context = await browser.newContext();
191
- await context.addCookies(await readSeedCookies());
192
- const page = await context.newPage();
193
- const bootstrapPromise = waitForLiveSlackBootstrap(page, options?.bootstrapTimeoutMs ?? DEFAULT_BOOTSTRAP_TIMEOUT_MS);
194
- await page.goto(`${SLACK_APP_ORIGIN}/client/${teamId}`, {
195
- waitUntil: "domcontentloaded",
196
- timeout: options?.bootstrapTimeoutMs ?? DEFAULT_BOOTSTRAP_TIMEOUT_MS,
197
- });
198
- const bootstrap = await bootstrapPromise;
199
- const invokeJsonApi = async (method, fields) => {
200
- const response = await context.request.post(`https://${bootstrap.workspaceHost}/api/${method}`, {
201
- form: normalizeRequestForm(bootstrap.liveToken, fields),
202
- headers: {
203
- Origin: SLACK_APP_ORIGIN,
204
- Referer: `${SLACK_APP_ORIGIN}/client/${teamId}`,
205
- },
206
- });
207
- const text = await response.text();
208
- let json;
209
- try {
210
- json = JSON.parse(text);
211
- }
212
- catch {
213
- throw new Error(`Slack API ${method} returned non-JSON response (HTTP ${response.status()}).`);
214
- }
215
- if (json.ok !== true) {
216
- const errorCode = typeof json.error === "string" ? json.error : `http_${response.status()}`;
217
- throw new Error(`Slack API ${method} failed: ${errorCode}`);
218
- }
219
- return json;
220
- };
221
- const resolveConversationId = async (channelRef) => {
222
- const normalized = normalizeChannelRef(channelRef);
223
- if (looksLikeConversationId(normalized)) {
224
- return normalized;
225
- }
226
- let cursor;
227
- for (let pageNumber = 0; pageNumber < 20; pageNumber += 1) {
228
- const response = await invokeJsonApi("conversations.list", {
229
- limit: 200,
230
- exclude_archived: true,
231
- types: "public_channel,private_channel,im,mpim",
232
- cursor,
233
- });
234
- const channels = Array.isArray(response.channels) ? response.channels : [];
235
- const match = channels.find((channel) => {
236
- if (!channel || typeof channel !== "object")
237
- return false;
238
- const name = typeof channel.name === "string" ? channel.name : null;
239
- const nameNormalized = typeof channel.name_normalized === "string" ? channel.name_normalized : null;
240
- return name === normalized || nameNormalized === normalized.toLowerCase();
241
- });
242
- if (match && typeof match.id === "string") {
243
- return match.id;
244
- }
245
- const responseMetadata = response.response_metadata && typeof response.response_metadata === "object"
246
- ? response.response_metadata
247
- : undefined;
248
- const nextCursor = responseMetadata && typeof responseMetadata.next_cursor === "string"
249
- ? responseMetadata.next_cursor.trim()
250
- : "";
251
- if (!nextCursor) {
252
- break;
253
- }
254
- cursor = nextCursor;
255
- }
256
- throw new Error(`Slack conversation "${channelRef}" was not found. Use a channel id like C..., G..., or D... if the name cannot be resolved.`);
257
- };
258
- return {
259
- getTeamId: () => teamId,
260
- getWorkspaceHost: () => bootstrap.workspaceHost,
261
- listMessages: async ({ channel, limit = 20, threadTs }) => {
262
- const channelId = await resolveConversationId(channel);
263
- const method = threadTs ? "conversations.replies" : "conversations.history";
264
- const response = await invokeJsonApi(method, {
265
- channel: channelId,
266
- limit: Math.max(1, Math.min(limit, 100)),
267
- ...(threadTs ? { ts: threadTs } : {}),
268
- });
269
- const responseMetadata = response.response_metadata && typeof response.response_metadata === "object"
270
- ? response.response_metadata
271
- : undefined;
272
- const nextCursor = responseMetadata && typeof responseMetadata.next_cursor === "string"
273
- ? responseMetadata.next_cursor || null
274
- : null;
275
- const rawMessages = Array.isArray(response.messages) ? response.messages : [];
276
- return {
277
- teamId,
278
- workspaceHost: bootstrap.workspaceHost,
279
- channelId,
280
- messages: rawMessages
281
- .filter((message) => !!message && typeof message === "object")
282
- .map(toSlackMessageView),
283
- hasMore: response.has_more === true,
284
- nextCursor,
285
- };
286
- },
287
- sendMessage: async ({ channel, text, threadTs }) => {
288
- const channelId = await resolveConversationId(channel);
289
- const response = await invokeJsonApi("chat.postMessage", {
290
- channel: channelId,
291
- text,
292
- ...(threadTs ? { thread_ts: threadTs } : {}),
293
- });
294
- const ts = typeof response.ts === "string" ? response.ts : null;
295
- if (!ts) {
296
- throw new Error("Slack API chat.postMessage did not return a message timestamp.");
297
- }
298
- return {
299
- teamId,
300
- workspaceHost: bootstrap.workspaceHost,
301
- channelId,
302
- ts,
303
- };
304
- },
305
- addReaction: async ({ channel, timestamp, name }) => {
306
- const channelId = await resolveConversationId(channel);
307
- await invokeJsonApi("reactions.add", {
308
- channel: channelId,
309
- timestamp,
310
- name,
311
- });
312
- return {
313
- teamId,
314
- workspaceHost: bootstrap.workspaceHost,
315
- channelId,
316
- };
317
- },
318
- close: async () => {
319
- await page.close().catch(() => undefined);
320
- await context.close().catch(() => undefined);
321
- await browser.close().catch(() => undefined);
322
- },
323
- };
324
- }
@@ -1,47 +0,0 @@
1
- /**
2
- * @aria/tools - Tool factory function
3
- *
4
- * Creates Tool objects from Zod schemas with runtime validation.
5
- */
6
- import { z } from "zod";
7
- /**
8
- * Factory function for creating Tool objects from Zod schemas.
9
- *
10
- * Converts the Zod schema to JSON Schema 7 for LLM consumption,
11
- * and wraps the execute handler with Zod validation.
12
- *
13
- * @example
14
- * ```ts
15
- * const getWeather = tool({
16
- * name: "get_weather",
17
- * description: "Get weather for a city",
18
- * parameters: z.object({ city: z.string(), units: z.enum(["F", "C"]) }),
19
- * execute: async (input) => ({
20
- * success: true,
21
- * message: `Weather in ${input.city}: sunny`,
22
- * }),
23
- * });
24
- * ```
25
- */
26
- export function tool(options) {
27
- const { name, description, parameters: zodSchema, execute, riskLevel = "safe", isReadOnly = true, category = "meta", loadingTier = "always", } = options;
28
- // Convert Zod schema to JSON Schema 7 using Zod v4's built-in conversion
29
- const jsonSchema = z.toJSONSchema(zodSchema);
30
- // Remove the $schema key since the Tool interface expects a plain JSONSchema7 object
31
- // describing the parameters, not a full standalone schema document
32
- delete jsonSchema.$schema;
33
- return {
34
- name,
35
- description,
36
- category,
37
- parameters: jsonSchema,
38
- riskLevel,
39
- isReadOnly,
40
- loadingTier,
41
- execute: async (input, context) => {
42
- // Validate input with Zod before calling the handler
43
- const parsed = zodSchema.parse(input);
44
- return execute(parsed, context);
45
- },
46
- };
47
- }
package/dist/types.js DELETED
@@ -1,7 +0,0 @@
1
- /**
2
- * @aria/tools - Tool system types
3
- *
4
- * Unified tool interface for all ARIA tools.
5
- * All tools are LLM-callable with optional user confirmation.
6
- */
7
- export {};
@@ -1,132 +0,0 @@
1
- function createAbortError() {
2
- const err = new Error("AbortError");
3
- err.name = "AbortError";
4
- return err;
5
- }
6
- /**
7
- * AbortSignal-aware sleep that rejects immediately if the signal fires during the delay.
8
- */
9
- function abortAwareSleep(ms, signal) {
10
- if (signal?.aborted) {
11
- return Promise.reject(createAbortError());
12
- }
13
- return new Promise((resolve, reject) => {
14
- let settled = false;
15
- let abortHandler;
16
- const timer = setTimeout(() => {
17
- if (settled)
18
- return;
19
- settled = true;
20
- if (signal && abortHandler) {
21
- signal.removeEventListener("abort", abortHandler);
22
- }
23
- resolve();
24
- }, ms);
25
- if (signal) {
26
- abortHandler = () => {
27
- if (settled)
28
- return;
29
- settled = true;
30
- signal.removeEventListener("abort", abortHandler);
31
- clearTimeout(timer);
32
- reject(createAbortError());
33
- };
34
- signal.addEventListener("abort", abortHandler, { once: true });
35
- }
36
- });
37
- }
38
- function isAbortError(err) {
39
- if (!(err instanceof Error))
40
- return false;
41
- const domErr = err;
42
- return domErr.name === "AbortError" || err.message === "AbortError";
43
- }
44
- function getErrorCode(err) {
45
- if (typeof err === "object" &&
46
- err !== null &&
47
- "code" in err &&
48
- typeof err.code === "string") {
49
- return err.code;
50
- }
51
- if (err instanceof Error && err.cause) {
52
- const cause = err.cause;
53
- if (typeof cause.code === "string") {
54
- return cause.code;
55
- }
56
- }
57
- return undefined;
58
- }
59
- export async function fetchWithRetry(url, init, options) {
60
- const maxAttempts = options?.maxAttempts ?? 3;
61
- const baseDelayMs = options?.baseDelayMs ?? 1000;
62
- const maxDelayMs = options?.maxDelayMs ?? 30000;
63
- const retryableStatuses = options?.retryableStatuses ?? [429, 500, 502, 503, 504];
64
- const retryableCodes = options?.retryableCodes ?? [
65
- "ECONNRESET",
66
- "ETIMEDOUT",
67
- "EPIPE",
68
- "ENETUNREACH",
69
- "EHOSTUNREACH",
70
- "ECONNREFUSED",
71
- "EAI_AGAIN",
72
- "UND_ERR_CONNECT_TIMEOUT",
73
- "UND_ERR_SOCKET",
74
- ];
75
- const doFetch = options?.fetchFn ?? fetch;
76
- const signal = init.signal ?? null;
77
- if (signal?.aborted) {
78
- throw createAbortError();
79
- }
80
- let lastError;
81
- for (let attempt = 0; attempt < maxAttempts; attempt++) {
82
- try {
83
- const response = await doFetch(url, init);
84
- // Check for Cloudflare 403 challenge
85
- if (response.status === 403 && response.headers.get("cf-mitigated") === "challenge") {
86
- if (attempt < maxAttempts - 1) {
87
- // Retry with simplified UA
88
- const delay = Math.min(baseDelayMs * 2 ** attempt + Math.random() * 500, maxDelayMs);
89
- await abortAwareSleep(delay, signal);
90
- continue;
91
- }
92
- // Last attempt - throw
93
- throw new Error(`Cloudflare challenge after ${maxAttempts} attempts: ${response.status}`);
94
- }
95
- // Check for retryable status codes
96
- if (!response.ok && retryableStatuses.includes(response.status)) {
97
- if (attempt < maxAttempts - 1) {
98
- const delay = Math.min(baseDelayMs * 2 ** attempt + Math.random() * 500, maxDelayMs);
99
- await abortAwareSleep(delay, signal);
100
- continue;
101
- }
102
- // Last attempt - throw
103
- throw new Error(`Request failed after ${maxAttempts} attempts: ${response.status}`);
104
- }
105
- return response;
106
- }
107
- catch (err) {
108
- // Re-throw AbortError immediately — do not retry aborted requests
109
- if (isAbortError(err)) {
110
- throw err;
111
- }
112
- const code = getErrorCode(err);
113
- if (code && retryableCodes.includes(code) && attempt < maxAttempts - 1) {
114
- const delay = Math.min(baseDelayMs * 2 ** attempt + Math.random() * 500, maxDelayMs);
115
- await abortAwareSleep(delay, signal);
116
- continue;
117
- }
118
- lastError = err;
119
- throw err;
120
- }
121
- }
122
- throw lastError ?? new Error("fetchWithRetry: unreachable");
123
- }
124
- export async function fetchWithSsrf(url, init, retryOptions) {
125
- const { fetchWithDnsPinning } = await import("../security/dns-pinning.js");
126
- return fetchWithRetry(url, init, {
127
- ...retryOptions,
128
- fetchFn: async (attemptUrl, attemptInit) => {
129
- return fetchWithDnsPinning(attemptUrl, attemptInit);
130
- },
131
- });
132
- }