@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,279 +0,0 @@
1
- import os from "node:os";
2
- import path from "node:path";
3
- import { promises as fs } from "node:fs";
4
- const OUTLOOK_SESSION_DIR = path.join(os.homedir(), ".aria", "outlook-session");
5
- const OUTLOOK_TOKEN_CACHE = path.join(os.homedir(), ".aria", "cache", "outlook-token.json");
6
- const OUTLOOK_WEB_URL = "https://outlook.office.com/mail/";
7
- // Outlook web uses outlook.office.com-scoped tokens, not graph.microsoft.com.
8
- // The Outlook REST v2 API at outlook.office.com/api/v2.0 accepts these tokens.
9
- const OUTLOOK_REST_API_BASE = "https://outlook.office.com/api/v2.0";
10
- const DEFAULT_BOOTSTRAP_TIMEOUT_MS = 60_000;
11
- async function loadCachedToken() {
12
- try {
13
- const raw = await fs.readFile(OUTLOOK_TOKEN_CACHE, "utf-8");
14
- const cached = JSON.parse(raw);
15
- // Token valid if >5 min remaining
16
- if (cached.bearerToken && cached.expiresAt > Date.now() + 5 * 60_000) {
17
- return cached;
18
- }
19
- }
20
- catch {
21
- // no cache or invalid
22
- }
23
- return null;
24
- }
25
- async function saveCachedToken(token, email) {
26
- // Decode JWT to get expiry
27
- let exp = Date.now() + 60 * 60_000; // default 1h
28
- try {
29
- const part = token.split(".")[1];
30
- if (!part)
31
- throw new Error("no payload");
32
- const payload = JSON.parse(Buffer.from(part, "base64").toString());
33
- if (payload.exp)
34
- exp = payload.exp * 1000;
35
- }
36
- catch {
37
- /* best-effort */
38
- }
39
- const cached = { bearerToken: token, accountEmail: email, expiresAt: exp };
40
- await fs.mkdir(path.dirname(OUTLOOK_TOKEN_CACHE), { recursive: true });
41
- await fs.writeFile(OUTLOOK_TOKEN_CACHE, JSON.stringify(cached, null, 2));
42
- }
43
- // Outlook REST v2 returns PascalCase keys (Subject, From, EmailAddress)
44
- // while Graph API uses camelCase (subject, from, emailAddress).
45
- // Helper to read a field with either casing.
46
- function field(obj, camelKey) {
47
- if (camelKey in obj)
48
- return obj[camelKey];
49
- const pascalKey = camelKey.charAt(0).toUpperCase() + camelKey.slice(1);
50
- return obj[pascalKey];
51
- }
52
- function fieldStr(obj, camelKey) {
53
- const v = field(obj, camelKey);
54
- return typeof v === "string" ? v : "";
55
- }
56
- function parseRecipient(recipient) {
57
- const emailAddress = field(recipient, "emailAddress") ?? null;
58
- if (!emailAddress || typeof emailAddress !== "object")
59
- return null;
60
- return {
61
- name: fieldStr(emailAddress, "name"),
62
- email: fieldStr(emailAddress, "address"),
63
- };
64
- }
65
- function parseRecipients(raw) {
66
- if (!Array.isArray(raw))
67
- return [];
68
- return raw
69
- .filter((r) => !!r && typeof r === "object")
70
- .map(parseRecipient)
71
- .filter((r) => r !== null);
72
- }
73
- function toMessageView(msg) {
74
- const fromRaw = field(msg, "from");
75
- const from = fromRaw && typeof fromRaw === "object"
76
- ? parseRecipient(fromRaw)
77
- : null;
78
- return {
79
- id: fieldStr(msg, "id") || fieldStr(msg, "Id"),
80
- subject: fieldStr(msg, "subject"),
81
- from: from ?? { name: "", email: "" },
82
- toRecipients: parseRecipients(field(msg, "toRecipients")),
83
- receivedDateTime: fieldStr(msg, "receivedDateTime"),
84
- isRead: field(msg, "isRead") === true,
85
- hasAttachments: field(msg, "hasAttachments") === true,
86
- bodyPreview: fieldStr(msg, "bodyPreview"),
87
- conversationId: fieldStr(msg, "conversationId"),
88
- };
89
- }
90
- function toMessageDetail(msg) {
91
- const view = toMessageView(msg);
92
- const bodyRaw = field(msg, "body");
93
- const body = bodyRaw && typeof bodyRaw === "object" ? bodyRaw : {};
94
- return {
95
- ...view,
96
- body: {
97
- contentType: fieldStr(body, "contentType") || "text",
98
- content: fieldStr(body, "content"),
99
- },
100
- ccRecipients: parseRecipients(field(msg, "ccRecipients")),
101
- importance: fieldStr(msg, "importance") || "normal",
102
- };
103
- }
104
- async function waitForMailBearerToken(page, timeoutMs) {
105
- return new Promise((resolve, reject) => {
106
- const timer = setTimeout(() => {
107
- page.off("request", handleRequest);
108
- reject(new Error("Timed out waiting for a Mail-scoped bearer token. " +
109
- "Ensure you are logged in to outlook.office.com."));
110
- }, timeoutMs);
111
- const seen = new Set();
112
- const handleRequest = (request) => {
113
- const authHeader = request.headers()["authorization"];
114
- if (!authHeader || !authHeader.startsWith("Bearer "))
115
- return;
116
- const bearerToken = authHeader.slice(7);
117
- const dedup = bearerToken.substring(0, 30);
118
- if (seen.has(dedup))
119
- return;
120
- seen.add(dedup);
121
- // Decode JWT payload to extract email and scopes
122
- let accountEmail = "";
123
- let scp = "";
124
- try {
125
- const payloadB64 = bearerToken.split(".")[1];
126
- if (payloadB64) {
127
- const payload = JSON.parse(Buffer.from(payloadB64, "base64url").toString("utf8"));
128
- scp = typeof payload.scp === "string" ? payload.scp : "";
129
- accountEmail =
130
- typeof payload.upn === "string"
131
- ? payload.upn
132
- : typeof payload.preferred_username === "string"
133
- ? payload.preferred_username
134
- : typeof payload.unique_name === "string"
135
- ? payload.unique_name
136
- : "";
137
- }
138
- }
139
- catch {
140
- // JWT decode is best-effort
141
- }
142
- // Only accept tokens with Mail.Read scope (from outlook.cloud.microsoft)
143
- if (!scp.includes("Mail.Read"))
144
- return;
145
- clearTimeout(timer);
146
- page.off("request", handleRequest);
147
- resolve({ bearerToken, accountEmail });
148
- };
149
- page.on("request", handleRequest);
150
- });
151
- }
152
- // Stateless client using a cached bearer token (no Playwright needed)
153
- function createStatelessClient(bearerToken, accountEmail) {
154
- const invokeApi = async (method, endpoint, body) => {
155
- const url = `${OUTLOOK_REST_API_BASE}${endpoint}`;
156
- const headers = {
157
- Authorization: `Bearer ${bearerToken}`,
158
- "Content-Type": "application/json",
159
- };
160
- const resp = await fetch(url, {
161
- method,
162
- headers,
163
- body: body ? JSON.stringify(body) : undefined,
164
- });
165
- if (resp.status === 204)
166
- return { status: 204 };
167
- const text = await resp.text();
168
- let json;
169
- try {
170
- json = JSON.parse(text);
171
- }
172
- catch {
173
- throw new Error(`Outlook API ${method} ${endpoint} returned non-JSON (HTTP ${resp.status}).`);
174
- }
175
- if (resp.status >= 400) {
176
- const error = json.error && typeof json.error === "object" ? json.error : {};
177
- const code = typeof error.code === "string" ? error.code : `http_${resp.status}`;
178
- const message = typeof error.message === "string" ? error.message : "Unknown error";
179
- throw new Error(`Outlook API ${method} ${endpoint} failed: ${code} — ${message}`);
180
- }
181
- return json;
182
- };
183
- return buildClientMethods(invokeApi, accountEmail, async () => {
184
- /* no-op close */
185
- });
186
- }
187
- export async function createOutlookDesktopClient(opts) {
188
- const timeoutMs = opts?.bootstrapTimeoutMs ?? DEFAULT_BOOTSTRAP_TIMEOUT_MS;
189
- // Strategy 1: Use cached token if still valid (no Playwright needed)
190
- const cached = await loadCachedToken();
191
- if (cached) {
192
- return createStatelessClient(cached.bearerToken, cached.accountEmail);
193
- }
194
- // Strategy 2: Launch Playwright headful to get a fresh token via SSO
195
- // Must be headful — Microsoft SSO blocks headless Chromium
196
- await fs.mkdir(OUTLOOK_SESSION_DIR, { recursive: true });
197
- const playwright = await import("playwright");
198
- const context = await playwright.chromium.launchPersistentContext(OUTLOOK_SESSION_DIR, {
199
- headless: false,
200
- args: ["--start-maximized"],
201
- viewport: null,
202
- });
203
- const page = context.pages()[0] ?? (await context.newPage());
204
- const bootstrapPromise = waitForMailBearerToken(page, timeoutMs);
205
- await page.goto(OUTLOOK_WEB_URL, {
206
- waitUntil: "domcontentloaded",
207
- timeout: timeoutMs,
208
- });
209
- const { bearerToken, accountEmail } = await bootstrapPromise;
210
- // Cache the token for subsequent calls (avoids launching Playwright)
211
- await saveCachedToken(bearerToken, accountEmail);
212
- // Close browser immediately — we have the token, use stateless client
213
- await page.close().catch(() => undefined);
214
- await context.close().catch(() => undefined);
215
- return createStatelessClient(bearerToken, accountEmail);
216
- }
217
- function buildClientMethods(invokeApi, accountEmail, closeFn) {
218
- return {
219
- getAccountEmail: () => accountEmail,
220
- listMessages: async ({ folder = "inbox", limit = 20, filter, search }) => {
221
- const params = new URLSearchParams();
222
- params.set("$top", String(Math.max(1, Math.min(limit, 50))));
223
- params.set("$select", "Id,Subject,From,ToRecipients,ReceivedDateTime,IsRead,HasAttachments,BodyPreview,ConversationId");
224
- params.set("$orderby", "ReceivedDateTime desc");
225
- if (filter)
226
- params.set("$filter", filter);
227
- if (search)
228
- params.set("$search", `"${search}"`);
229
- const endpoint = `/me/mailFolders/${encodeURIComponent(folder)}/messages?${params.toString()}`;
230
- const json = await invokeApi("GET", endpoint);
231
- const rawMessages = Array.isArray(json.value) ? json.value : [];
232
- const messages = rawMessages
233
- .filter((m) => !!m && typeof m === "object")
234
- .map(toMessageView);
235
- return {
236
- accountEmail,
237
- folder,
238
- messages,
239
- totalCount: typeof json["@odata.count"] === "number" ? json["@odata.count"] : messages.length,
240
- };
241
- },
242
- getMessage: async ({ messageId }) => {
243
- const json = await invokeApi("GET", `/me/messages/${encodeURIComponent(messageId)}`);
244
- return toMessageDetail(json);
245
- },
246
- sendMessage: async ({ to, cc, subject, body, bodyType = "text" }) => {
247
- const toRecipients = to.map((email) => ({
248
- EmailAddress: { Address: email },
249
- }));
250
- const ccRecipients = (cc ?? []).map((email) => ({
251
- EmailAddress: { Address: email },
252
- }));
253
- await invokeApi("POST", "/me/sendMail", {
254
- Message: {
255
- Subject: subject,
256
- Body: { ContentType: bodyType === "html" ? "HTML" : "Text", Content: body },
257
- ToRecipients: toRecipients,
258
- ...(ccRecipients.length > 0 ? { CcRecipients: ccRecipients } : {}),
259
- },
260
- });
261
- return { accountEmail, status: "sent" };
262
- },
263
- replyMessage: async ({ messageId, body, bodyType = "text", replyAll = false }) => {
264
- const replyMethod = replyAll ? "ReplyAll" : "Reply";
265
- await invokeApi("POST", `/me/messages/${encodeURIComponent(messageId)}/${replyMethod}`, {
266
- Comment: body,
267
- ...(bodyType === "html"
268
- ? {
269
- Message: {
270
- Body: { ContentType: "HTML", Content: body },
271
- },
272
- }
273
- : {}),
274
- });
275
- return { accountEmail, status: "sent" };
276
- },
277
- close: closeFn,
278
- };
279
- }
package/dist/policy.js DELETED
@@ -1,149 +0,0 @@
1
- /**
2
- * Tool Policy Engine
3
- *
4
- * Evaluates whether a tool is allowed based on allow/deny lists with group expansion.
5
- * Supports layered policy merging (intersection semantics) for arion + RunOptions policies.
6
- */
7
- /** Built-in tool groups */
8
- export const TOOL_GROUPS = {
9
- "group:memory": [
10
- "remember",
11
- "recall",
12
- "forget",
13
- "recall_knowledge",
14
- "reflect",
15
- "search",
16
- "learn",
17
- "session_history",
18
- ],
19
- "group:web": ["web_search", "web_fetch", "browse", "browser"],
20
- "group:filesystem": ["read_file", "write_file", "edit_file", "glob", "grep", "ls", "apply_patch"],
21
- "group:shell": [
22
- "bash",
23
- "exec",
24
- "spawn",
25
- "kill",
26
- "list_processes",
27
- "wait_process",
28
- "write_stdin",
29
- "process",
30
- ],
31
- "group:arion": [
32
- "hatch_arion",
33
- "wake_arion",
34
- "rest_arion",
35
- "retire_arion",
36
- "delegate_arion",
37
- "manage_network",
38
- "list_clients",
39
- "deploy",
40
- ],
41
- "group:meta": [
42
- "ask_user",
43
- "quest_update",
44
- "quest_list",
45
- "search",
46
- "learn",
47
- "learn_tool",
48
- "learn_skill",
49
- "create_tool",
50
- "create_skill",
51
- "use_skill",
52
- "restart",
53
- "spawn_worker",
54
- "check_delegation",
55
- "pause_delegation",
56
- "resume_delegation",
57
- "quest_report",
58
- "self_diagnose",
59
- ],
60
- };
61
- /**
62
- * Expand group references in a policy list.
63
- * "group:memory" → ["remember", "recall", "forget", "reflect"]
64
- * Individual tool names pass through unchanged.
65
- * Unknown group names are ignored (treated as empty).
66
- */
67
- export function expandGroups(names) {
68
- const result = new Set();
69
- for (const name of names) {
70
- const lower = name.toLowerCase();
71
- if (lower.startsWith("group:")) {
72
- const members = TOOL_GROUPS[lower];
73
- if (members) {
74
- for (const member of members) {
75
- result.add(member.toLowerCase());
76
- }
77
- }
78
- // Unknown group names are silently ignored
79
- }
80
- else {
81
- result.add(lower);
82
- }
83
- }
84
- return result;
85
- }
86
- /**
87
- * Evaluate whether a tool is allowed by a policy.
88
- * Rules:
89
- * 1. If allow is empty/undefined and restrictAllow is false/undefined
90
- * → all tools allowed (then check deny)
91
- * 2. If allow is non-empty OR restrictAllow=true
92
- * → only listed tools/groups allowed (empty allow + restrictAllow=true denies all)
93
- * 3. Deny always wins over allow
94
- */
95
- export function isToolAllowed(toolName, policy) {
96
- const normalized = toolName.toLowerCase();
97
- // Check allow list: when restricted, tool must be in allowed set.
98
- const isAllowRestricted = policy.restrictAllow === true || (policy.allow !== undefined && policy.allow.length > 0);
99
- if (isAllowRestricted) {
100
- const allowed = expandGroups(policy.allow ?? []);
101
- if (!allowed.has(normalized)) {
102
- return false;
103
- }
104
- }
105
- // Check deny list: deny always wins
106
- if (policy.deny && policy.deny.length > 0) {
107
- const denied = expandGroups(policy.deny);
108
- if (denied.has(normalized)) {
109
- return false;
110
- }
111
- }
112
- return true;
113
- }
114
- /**
115
- * Merge two policies (intersection). Used for layered evaluation:
116
- * arion policy ∩ RunOptions policy = effective policy.
117
- * A tool must be allowed by BOTH layers.
118
- */
119
- export function mergePolicies(a, b) {
120
- // Merge deny: union of both deny lists
121
- const mergedDeny = [...(a.deny ?? []), ...(b.deny ?? [])];
122
- // Merge allow with restriction semantics:
123
- // - both restricted: intersection (possibly empty = deny all)
124
- // - one restricted: inherit that restriction
125
- // - neither restricted: unrestricted
126
- const aRestricts = a.restrictAllow === true || (a.allow?.length ?? 0) > 0;
127
- const bRestricts = b.restrictAllow === true || (b.allow?.length ?? 0) > 0;
128
- let mergedAllow;
129
- let mergedRestrictAllow = false;
130
- if (aRestricts && bRestricts) {
131
- const expandedA = expandGroups(a.allow ?? []);
132
- const expandedB = expandGroups(b.allow ?? []);
133
- mergedAllow = [...expandedA].filter((name) => expandedB.has(name));
134
- mergedRestrictAllow = true;
135
- }
136
- else if (aRestricts) {
137
- mergedAllow = [...(a.allow ?? [])];
138
- mergedRestrictAllow = true;
139
- }
140
- else if (bRestricts) {
141
- mergedAllow = [...(b.allow ?? [])];
142
- mergedRestrictAllow = true;
143
- }
144
- return {
145
- ...(mergedAllow !== undefined ? { allow: mergedAllow } : {}),
146
- ...(mergedRestrictAllow ? { restrictAllow: true } : {}),
147
- ...(mergedDeny.length ? { deny: mergedDeny } : {}),
148
- };
149
- }
@@ -1,62 +0,0 @@
1
- import { createProviderAbortSignal, resolveSearchProviderEnv } from "./search-provider.js";
2
- export class BraveSearchProvider {
3
- env;
4
- name = "brave";
5
- requiresApiKey = true;
6
- priority = 1;
7
- constructor(env = process.env) {
8
- this.env = env;
9
- }
10
- isAvailable() {
11
- const apiKey = resolveSearchProviderEnv(this.env).BRAVE_API_KEY;
12
- return Boolean(apiKey && apiKey.trim().length > 0);
13
- }
14
- async search(query, options) {
15
- const apiKey = resolveSearchProviderEnv(this.env).BRAVE_API_KEY;
16
- if (!apiKey) {
17
- throw new Error("BRAVE_API_KEY environment variable is not set");
18
- }
19
- const limit = options?.limit ?? 5;
20
- const url = new URL("https://api.search.brave.com/res/v1/web/search");
21
- url.searchParams.set("q", query);
22
- url.searchParams.set("count", String(limit));
23
- // Handle timeRange option (map to Brave's freshness parameter)
24
- if (options?.timeRange) {
25
- const freshnessMap = {
26
- day: "pd",
27
- week: "pw",
28
- month: "pm",
29
- year: "py",
30
- };
31
- const freshness = freshnessMap[options.timeRange];
32
- if (freshness) {
33
- url.searchParams.set("freshness", freshness);
34
- }
35
- }
36
- const { signal, cleanup } = createProviderAbortSignal(30_000, options?.signal);
37
- try {
38
- const response = await fetch(url.toString(), {
39
- method: "GET",
40
- headers: {
41
- Accept: "application/json",
42
- "X-Subscription-Token": apiKey,
43
- },
44
- signal,
45
- });
46
- if (!response.ok) {
47
- throw new Error(`Brave Search API error: ${response.status} ${response.statusText}`);
48
- }
49
- const json = await response.json();
50
- const webResults = json.web?.results || [];
51
- return webResults.map((r) => ({
52
- title: r.title,
53
- url: r.url,
54
- content: r.description,
55
- score: r.relevance_score,
56
- }));
57
- }
58
- finally {
59
- cleanup();
60
- }
61
- }
62
- }
@@ -1,176 +0,0 @@
1
- import { createProviderAbortSignal } from "./search-provider.js";
2
- export class DuckDuckGoSearchProvider {
3
- name = "duckduckgo";
4
- requiresApiKey = false;
5
- priority = 6;
6
- isAvailable() {
7
- // DuckDuckGo is always available (no API key required)
8
- return true;
9
- }
10
- async search(query, options) {
11
- const limit = options?.limit ?? 5;
12
- // DuckDuckGo HTML search endpoint (we'll parse the HTML response)
13
- // The Instant Answer API doesn't provide web search results, only factoids
14
- const url = new URL("https://html.duckduckgo.com/html/");
15
- url.searchParams.set("q", query);
16
- const { signal, cleanup } = createProviderAbortSignal(30_000, options?.signal);
17
- try {
18
- const response = await fetch(url.toString(), {
19
- method: "GET",
20
- signal,
21
- headers: {
22
- "User-Agent": "Mozilla/5.0 (compatible; ARIA/1.0)",
23
- },
24
- });
25
- if (!response.ok) {
26
- throw new Error(`DuckDuckGo Search error: ${response.status} ${response.statusText}`);
27
- }
28
- const html = await response.text();
29
- // Parse HTML to extract search results
30
- // DuckDuckGo HTML results have result__a (title/url) and result__snippet (description)
31
- const results = [];
32
- // First pass: extract all result__a links (title + url)
33
- const linkMap = new Map();
34
- const linkRegex = /<a(?=[^>]*\bclass=(["'])[^"']*\bresult__a\b[^"']*\1)(?=[^>]*\bhref=(["'])(.*?)\2)[^>]*>([\s\S]*?)<\/a>/gi;
35
- let match;
36
- let resultAnchorCount = 0;
37
- while ((match = linkRegex.exec(html)) !== null) {
38
- const rawHref = match[3];
39
- const rawTitle = match[4];
40
- if (!rawHref || !rawTitle) {
41
- continue;
42
- }
43
- resultAnchorCount++;
44
- const url = this.resolveDuckDuckGoResultUrl(rawHref);
45
- if (!url) {
46
- continue;
47
- }
48
- const title = this.stripHtmlTags(rawTitle);
49
- if (!title) {
50
- continue;
51
- }
52
- linkMap.set(url, { title, url });
53
- }
54
- // If DDG returned result anchors but we extracted zero usable URLs, parsing is stale.
55
- // Throw to allow router fallback rather than silently returning empty results.
56
- if (resultAnchorCount > 0 && linkMap.size === 0) {
57
- throw new Error("Could not resolve any result URLs from DuckDuckGo response");
58
- }
59
- // Second pass: extract snippets
60
- const snippetRegex = /<(?:a|div|span)(?=[^>]*\bclass=(["'])[^"']*\bresult__snippet\b[^"']*\1)[^>]*>([\s\S]*?)<\/(?:a|div|span)>/gi;
61
- const snippets = [];
62
- while ((match = snippetRegex.exec(html)) !== null) {
63
- const rawSnippet = match[2];
64
- snippets.push(this.stripHtmlTags(rawSnippet ?? ""));
65
- }
66
- // Combine results (matching by order, which should align)
67
- const linkEntries = Array.from(linkMap.values());
68
- for (let i = 0; i < Math.min(linkEntries.length, limit); i++) {
69
- const link = linkEntries[i];
70
- if (!link) {
71
- continue;
72
- }
73
- const snippet = snippets[i] || link.title;
74
- results.push({
75
- title: link.title,
76
- url: link.url,
77
- content: snippet,
78
- });
79
- }
80
- return results;
81
- }
82
- finally {
83
- cleanup();
84
- }
85
- }
86
- /**
87
- * Strip HTML tags from a string
88
- */
89
- stripHtmlTags(html) {
90
- return html
91
- .replace(/<[^>]*>/g, "")
92
- .replace(/&nbsp;/g, " ")
93
- .replace(/&amp;/g, "&")
94
- .replace(/&lt;/g, "<")
95
- .replace(/&gt;/g, ">")
96
- .replace(/&quot;/g, '"')
97
- .replace(/&#39;/g, "'")
98
- .trim();
99
- }
100
- /**
101
- * Decode HTML entities in URLs
102
- */
103
- decodeHtmlEntities(text) {
104
- return text
105
- .replace(/&amp;/g, "&")
106
- .replace(/&lt;/g, "<")
107
- .replace(/&gt;/g, ">")
108
- .replace(/&quot;/g, '"')
109
- .replace(/&#39;/g, "'");
110
- }
111
- resolveDuckDuckGoResultUrl(rawHref) {
112
- const decodedHref = this.decodeHtmlEntities(rawHref).trim();
113
- if (!decodedHref) {
114
- return null;
115
- }
116
- let absoluteHref = decodedHref;
117
- if (absoluteHref.startsWith("//")) {
118
- absoluteHref = `https:${absoluteHref}`;
119
- }
120
- else if (absoluteHref.startsWith("/")) {
121
- absoluteHref = `https://duckduckgo.com${absoluteHref}`;
122
- }
123
- let parsed;
124
- try {
125
- parsed = new URL(absoluteHref);
126
- }
127
- catch {
128
- return null;
129
- }
130
- const hostname = parsed.hostname.toLowerCase();
131
- if (hostname === "duckduckgo.com" || hostname.endsWith(".duckduckgo.com")) {
132
- const redirected = parsed.searchParams.get("uddg");
133
- if (!redirected) {
134
- return null;
135
- }
136
- return this.normalizeResultUrl(redirected);
137
- }
138
- return this.normalizeResultUrl(absoluteHref);
139
- }
140
- normalizeResultUrl(candidate) {
141
- let value = candidate.trim();
142
- if (!value) {
143
- return null;
144
- }
145
- if (value.startsWith("//")) {
146
- value = `https:${value}`;
147
- }
148
- // Some uddg values are encoded multiple times; decode at most twice.
149
- for (let i = 0; i < 2; i++) {
150
- try {
151
- const decoded = decodeURIComponent(value);
152
- if (decoded === value) {
153
- break;
154
- }
155
- value = decoded;
156
- }
157
- catch {
158
- break;
159
- }
160
- }
161
- try {
162
- const parsed = new URL(value);
163
- if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
164
- return null;
165
- }
166
- const hostname = parsed.hostname.toLowerCase();
167
- if (hostname === "duckduckgo.com" || hostname.endsWith(".duckduckgo.com")) {
168
- return null;
169
- }
170
- return parsed.toString();
171
- }
172
- catch {
173
- return null;
174
- }
175
- }
176
- }