@robzilla1738/agentswarm 0.5.0 → 0.7.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 (37) hide show
  1. package/README.md +29 -12
  2. package/dist/agent.js +6 -15
  3. package/dist/cli.js +31 -4
  4. package/dist/config.js +44 -1
  5. package/dist/crawltools.js +3 -22
  6. package/dist/executor.js +276 -60
  7. package/dist/hub.js +67 -3
  8. package/dist/journal.js +39 -5
  9. package/dist/memory.js +17 -11
  10. package/dist/pdftext.js +211 -0
  11. package/dist/prompts.js +23 -15
  12. package/dist/report.js +39 -1
  13. package/dist/run.js +8 -0
  14. package/dist/sandbox.js +11 -0
  15. package/dist/searchcore.js +55 -2
  16. package/dist/state.js +67 -17
  17. package/dist/tools.js +208 -19
  18. package/dist/util.js +117 -3
  19. package/dist/webtools.js +185 -32
  20. package/package.json +1 -1
  21. package/ui/out/404/index.html +1 -1
  22. package/ui/out/404.html +1 -1
  23. package/ui/out/_next/static/chunks/677-a62d486d6734bcf3.js +1 -0
  24. package/ui/out/_next/static/chunks/app/run/page-c29f95c51af08c60.js +1 -0
  25. package/ui/out/_next/static/chunks/app/settings/page-41a5d8ba43ecfd4a.js +1 -0
  26. package/ui/out/_next/static/css/{9f7bd82b8e4c762c.css → d95c2ba395730031.css} +1 -1
  27. package/ui/out/index.html +1 -1
  28. package/ui/out/index.txt +3 -3
  29. package/ui/out/run/index.html +1 -1
  30. package/ui/out/run/index.txt +3 -3
  31. package/ui/out/settings/index.html +1 -1
  32. package/ui/out/settings/index.txt +3 -3
  33. package/ui/out/_next/static/chunks/677-859e8d42add1806b.js +0 -1
  34. package/ui/out/_next/static/chunks/app/run/page-2420c9e4c963d9b3.js +0 -1
  35. package/ui/out/_next/static/chunks/app/settings/page-092a6bf42dfde57d.js +0 -1
  36. /package/ui/out/_next/static/{errjtBR_bKoee8ogLp8xk → JFkx5KtNi0DYyqm_THzbY}/_buildManifest.js +0 -0
  37. /package/ui/out/_next/static/{errjtBR_bKoee8ogLp8xk → JFkx5KtNi0DYyqm_THzbY}/_ssgManifest.js +0 -0
package/dist/util.js CHANGED
@@ -33,8 +33,10 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.ansi = exports.sleep = void 0;
36
+ exports.ansi = void 0;
37
37
  exports.rid = rid;
38
+ exports.sleep = sleep;
39
+ exports.mergeSignal = mergeSignal;
38
40
  exports.truncateMiddle = truncateMiddle;
39
41
  exports.clip = clip;
40
42
  exports.oneLine = oneLine;
@@ -48,6 +50,7 @@ exports.ensureDir = ensureDir;
48
50
  exports.readJson = readJson;
49
51
  exports.writeJson = writeJson;
50
52
  exports.pathInside = pathInside;
53
+ exports.validateArtifactFormat = validateArtifactFormat;
51
54
  exports.decodeEntities = decodeEntities;
52
55
  exports.htmlToText = htmlToText;
53
56
  const fs = __importStar(require("fs"));
@@ -61,8 +64,35 @@ function rid(prefix) {
61
64
  const c = ridCounter.toString(36).padStart(2, "0");
62
65
  return `${prefix}_${t}${r}${c}`;
63
66
  }
64
- const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
65
- exports.sleep = sleep;
67
+ /** Resolves after ms; rejects early if the signal aborts first. */
68
+ function sleep(ms, signal) {
69
+ return new Promise((resolve, reject) => {
70
+ if (!signal) {
71
+ setTimeout(resolve, ms);
72
+ return;
73
+ }
74
+ if (signal.aborted) {
75
+ reject(new Error("aborted"));
76
+ return;
77
+ }
78
+ const t = setTimeout(() => {
79
+ signal.removeEventListener("abort", onAbort);
80
+ resolve();
81
+ }, ms);
82
+ const onAbort = () => {
83
+ clearTimeout(t);
84
+ reject(new Error("aborted"));
85
+ };
86
+ signal.addEventListener("abort", onAbort, { once: true });
87
+ });
88
+ }
89
+ /** A timeout signal, combined with the caller's signal when one is given. */
90
+ function mergeSignal(timeoutMs, signal) {
91
+ const t = AbortSignal.timeout(timeoutMs);
92
+ if (!signal)
93
+ return t;
94
+ return typeof AbortSignal.any === "function" ? AbortSignal.any([t, signal]) : signal;
95
+ }
66
96
  // ---------- strings ----------
67
97
  function truncateMiddle(s, max, label = "bytes") {
68
98
  if (s.length <= max)
@@ -147,6 +177,90 @@ function pathInside(parent, child) {
147
177
  const rel = path.relative(path.resolve(parent), path.resolve(child));
148
178
  return rel === "" || (!rel.startsWith("..") && !path.isAbsolute(rel));
149
179
  }
180
+ // ---------- artifact validation ----------
181
+ /**
182
+ * Cheap structural checks for common deliverable formats — catches a worker
183
+ * shipping malformed JSON/CSV/stub HTML before an LLM verifier spends tokens
184
+ * on it. Returns a problem description, or null when the file looks sound
185
+ * (or is a format we don't check).
186
+ */
187
+ function validateArtifactFormat(absPath) {
188
+ const ext = path.extname(absPath).toLowerCase();
189
+ if (![".json", ".csv", ".html", ".htm"].includes(ext))
190
+ return null;
191
+ let raw;
192
+ try {
193
+ raw = fs.readFileSync(absPath, "utf8");
194
+ }
195
+ catch {
196
+ return null; // existence/size is the caller's check
197
+ }
198
+ if (ext === ".json") {
199
+ try {
200
+ JSON.parse(raw);
201
+ return null;
202
+ }
203
+ catch (e) {
204
+ return `not valid JSON (${errMsg(e)})`;
205
+ }
206
+ }
207
+ if (ext === ".csv") {
208
+ const counts = csvFieldCounts(raw, 50);
209
+ if (!counts.length)
210
+ return "CSV has no records";
211
+ const expect = counts[0];
212
+ const bad = counts.findIndex((c) => c !== expect);
213
+ if (bad > 0)
214
+ return `inconsistent CSV: record 1 has ${expect} field(s), record ${bad + 1} has ${counts[bad]}`;
215
+ return null;
216
+ }
217
+ // .html / .htm — catch empty shells and plain text passed off as HTML.
218
+ if (raw.length < 200 || !/<[a-z!][^>]*>/i.test(raw) || !/<\/[a-z][a-z0-9]*>/i.test(raw)) {
219
+ return "HTML looks like a stub (too short or no real markup)";
220
+ }
221
+ return null;
222
+ }
223
+ /** Field count per CSV record (quote-aware, handles newlines inside quotes). */
224
+ function csvFieldCounts(raw, maxRecords) {
225
+ const counts = [];
226
+ let fields = 1;
227
+ let chars = 0; // non-separator chars seen in the current record
228
+ let inQ = false;
229
+ for (let i = 0; i < raw.length && counts.length < maxRecords; i++) {
230
+ const ch = raw[i];
231
+ if (inQ) {
232
+ if (ch === '"') {
233
+ if (raw[i + 1] === '"')
234
+ i++;
235
+ else
236
+ inQ = false;
237
+ }
238
+ chars++;
239
+ }
240
+ else if (ch === '"') {
241
+ inQ = true;
242
+ chars++;
243
+ }
244
+ else if (ch === ",") {
245
+ fields++;
246
+ chars++;
247
+ }
248
+ else if (ch === "\n" || ch === "\r") {
249
+ if (ch === "\r" && raw[i + 1] === "\n")
250
+ i++;
251
+ if (chars > 0)
252
+ counts.push(fields); // skip blank lines
253
+ fields = 1;
254
+ chars = 0;
255
+ }
256
+ else {
257
+ chars++;
258
+ }
259
+ }
260
+ if (chars > 0 && counts.length < maxRecords)
261
+ counts.push(fields);
262
+ return counts;
263
+ }
150
264
  // ---------- html ----------
151
265
  const ENTITIES = {
152
266
  amp: "&", lt: "<", gt: ">", quot: '"', apos: "'", nbsp: " ",
package/dist/webtools.js CHANGED
@@ -1,9 +1,17 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.webSearch = webSearch;
4
+ exports.searchEngines = searchEngines;
5
+ exports._resetEngineCooldowns = _resetEngineCooldowns;
6
+ exports.tinyfishSearch = tinyfishSearch;
7
+ exports.ddgSearch = ddgSearch;
8
+ exports.bingSearch = bingSearch;
9
+ exports.arxivSearch = arxivSearch;
10
+ exports.crossrefSearch = crossrefSearch;
4
11
  exports.parseBingHtml = parseBingHtml;
5
12
  exports.fetchUrl = fetchUrl;
6
13
  const crawltools_1 = require("./crawltools");
14
+ const pdftext_1 = require("./pdftext");
7
15
  const searchcore_1 = require("./searchcore");
8
16
  const util_1 = require("./util");
9
17
  const UA = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0 Safari/537.36 agentswarm/0.1";
@@ -20,35 +28,58 @@ const DEEP_PASSAGES = 3;
20
28
  * and re-ranks by content quality. Ranking/passage algorithms live in
21
29
  * searchcore.ts.
22
30
  */
23
- async function webSearch(cfg, query, count, signal, deep = false, warn) {
31
+ async function webSearch(cfg, query, count, signal, deep = false, warn, _retried = false) {
24
32
  // Deep searches widen recall by issuing complementary phrasings; the fast
25
33
  // path stays a single query so an agent's tool loop isn't slowed.
26
34
  const queries = deep ? (0, searchcore_1.expandQueries)(query) : [query];
27
35
  const perEngine = Math.min(count, 15);
36
+ const engines = searchEngines(cfg);
28
37
  const engineCalls = [];
29
38
  for (const q of queries) {
30
- if (cfg.searchBackend === "tinyfish" && cfg.tinyfishApiKey) {
31
- engineCalls.push(tinyfishSearch(cfg, q, perEngine, signal));
32
- }
33
- else {
34
- engineCalls.push(ddgSearch(q, perEngine, signal), bingSearch(q, perEngine, signal));
35
- if (cfg.searchBackend === "auto" && cfg.tinyfishApiKey) {
36
- engineCalls.push(tinyfishSearch(cfg, q, perEngine, signal));
39
+ for (const e of engines) {
40
+ let call = e.search(q, perEngine, signal);
41
+ // When TinyFish is the sole engine by configuration, an outage must not
42
+ // blank web research for the whole mission — fall back to the free
43
+ // scraping engines for this call.
44
+ if (engines.length === 1 && e.name === "tinyfish") {
45
+ call = call.catch(async (err) => {
46
+ warn?.(`tinyfish failed (${(0, util_1.errMsg)(err)}); falling back to duckduckgo/bing`);
47
+ const fallback = await Promise.allSettled([ddgSearch(q, perEngine, signal), bingSearch(q, perEngine, signal)]);
48
+ const hits = fallback.flatMap((s) => (s.status === "fulfilled" ? s.value : []));
49
+ if (!hits.length && fallback.every((s) => s.status === "rejected"))
50
+ throw err;
51
+ return hits;
52
+ });
37
53
  }
54
+ engineCalls.push(call);
38
55
  }
39
56
  }
57
+ // Scholarly questions also sweep the keyless academic APIs (deep mode only).
58
+ if (deep && (0, searchcore_1.looksAcademic)(query)) {
59
+ engineCalls.push(arxivSearch(query, perEngine, signal), crossrefSearch(query, perEngine, signal));
60
+ }
40
61
  const settled = await Promise.allSettled(engineCalls);
41
62
  const candidates = settled.flatMap((s) => (s.status === "fulfilled" ? s.value : []));
42
63
  if (!candidates.length) {
43
64
  const firstErr = settled.find((s) => s.status === "rejected");
44
- if (firstErr)
65
+ if (firstErr && settled.every((s) => s.status === "rejected"))
45
66
  throw firstErr.reason;
67
+ // Engines answered but nothing parsed/matched: one retry with a
68
+ // simplified phrasing before giving up.
69
+ if (!_retried) {
70
+ const alt = (0, searchcore_1.reformulate)(query);
71
+ if (alt) {
72
+ warn?.(`no results for "${query}" — retrying as "${alt}"`);
73
+ return webSearch(cfg, alt, count, signal, deep, warn, true);
74
+ }
75
+ }
76
+ // At least one engine answered with a genuine empty result set: that is
77
+ // "no results", not an error, even if another engine failed alongside it.
78
+ if (firstErr)
79
+ warn?.(`no results (and ${(0, util_1.errMsg)(firstErr.reason)})`);
46
80
  return [];
47
81
  }
48
82
  const failures = settled.filter((s) => s.status === "rejected").length;
49
- if (failures && failures === settled.length) {
50
- throw (settled.find((s) => s.status === "rejected")).reason;
51
- }
52
83
  if (failures) {
53
84
  warn?.(`${failures}/${settled.length} search engine calls failed; results come from the rest`);
54
85
  }
@@ -100,7 +131,7 @@ async function fetchReadable(url, signal) {
100
131
  try {
101
132
  const res = await fetch(`https://raw.githubusercontent.com/${gh[1]}/${gh[2]}/${branch}/README.md`, {
102
133
  headers: { "user-agent": UA },
103
- signal: mergeSignal(20_000, signal),
134
+ signal: (0, util_1.mergeSignal)(20_000, signal),
104
135
  });
105
136
  if (res.ok)
106
137
  return clip(await res.text());
@@ -111,16 +142,23 @@ async function fetchReadable(url, signal) {
111
142
  }
112
143
  }
113
144
  const res = await fetch(url, {
114
- headers: { "user-agent": UA, accept: "text/html,text/*;q=0.9,*/*;q=0.5" },
115
- signal: mergeSignal(20_000, signal),
145
+ headers: { "user-agent": UA, accept: "text/html,application/pdf,text/*;q=0.9,*/*;q=0.5" },
146
+ signal: (0, util_1.mergeSignal)(20_000, signal),
116
147
  redirect: "follow",
117
148
  });
118
149
  if (!res.ok)
119
150
  throw new Error(`HTTP ${res.status}`);
120
151
  const ctype = res.headers.get("content-type") || "";
152
+ if (/application\/pdf/i.test(ctype)) {
153
+ const buf = Buffer.from(await res.arrayBuffer());
154
+ const pdf = buf.length <= 20_000_000 ? (0, pdftext_1.extractPdfText)(buf) : null;
155
+ if (!pdf)
156
+ throw new Error("pdf with no extractable text");
157
+ return clip(pdf.text);
158
+ }
121
159
  if (!/text\/|html|xml|json/i.test(ctype))
122
160
  throw new Error(`not textual: ${ctype}`);
123
- const body = await res.text();
161
+ const body = decodeBody(Buffer.from(await res.arrayBuffer()), ctype);
124
162
  const text = /html/i.test(ctype) ? (0, util_1.htmlToText)(body) : body;
125
163
  return clip(text);
126
164
  }
@@ -128,18 +166,59 @@ function clip(text) {
128
166
  const words = text.replace(/\s+/g, " ").trim().split(" ");
129
167
  return words.slice(0, 3000).join(" ");
130
168
  }
131
- function mergeSignal(timeoutMs, signal) {
132
- const t = AbortSignal.timeout(timeoutMs);
133
- if (!signal)
134
- return t;
135
- return typeof AbortSignal.any === "function" ? AbortSignal.any([t, signal]) : signal;
169
+ /**
170
+ * The engine set a web_search call fans out to under the given config —
171
+ * the single source of truth shared by webSearch and the settings
172
+ * diagnostics endpoint, so "Test search" probes exactly what runs use.
173
+ */
174
+ function searchEngines(cfg) {
175
+ if (cfg.searchBackend === "tinyfish" && cfg.tinyfishApiKey) {
176
+ return [{ name: "tinyfish", search: (q, n, s) => tinyfishSearch(cfg, q, n, s) }];
177
+ }
178
+ const engines = [
179
+ { name: "duckduckgo", search: ddgSearch },
180
+ { name: "bing", search: bingSearch },
181
+ ];
182
+ if (cfg.searchBackend === "auto" && cfg.tinyfishApiKey) {
183
+ engines.push({ name: "tinyfish", search: (q, n, s) => tinyfishSearch(cfg, q, n, s) });
184
+ }
185
+ return engines;
186
+ }
187
+ /**
188
+ * Per-engine rate-limit cooldowns: an engine that answers 429/403/503 sits
189
+ * out (60s, or the server's retry-after up to 120s) instead of getting
190
+ * hammered into a long block mid-research. A tiny retry-after (≤5s) is
191
+ * honored once in-call.
192
+ */
193
+ const engineCooldown = new Map();
194
+ /** Test hook. */
195
+ function _resetEngineCooldowns() {
196
+ engineCooldown.clear();
197
+ }
198
+ async function engineFetch(engine, url, init, signal) {
199
+ const until = engineCooldown.get(engine) ?? 0;
200
+ if (until > Date.now()) {
201
+ throw new Error(`${engine} is cooling down after a rate limit (${Math.ceil((until - Date.now()) / 1000)}s left)`);
202
+ }
203
+ for (let attempt = 0;; attempt++) {
204
+ const res = await fetch(url, { ...init, signal: (0, util_1.mergeSignal)(20_000, signal) });
205
+ if (![429, 403, 503].includes(res.status))
206
+ return res;
207
+ const retryAfter = Number(res.headers.get("retry-after"));
208
+ if (attempt === 0 && Number.isFinite(retryAfter) && retryAfter > 0 && retryAfter <= 5) {
209
+ await new Promise((r) => setTimeout(r, retryAfter * 1000));
210
+ continue;
211
+ }
212
+ const ms = Number.isFinite(retryAfter) && retryAfter > 0 ? Math.min(retryAfter, 120) * 1000 : 60_000;
213
+ engineCooldown.set(engine, Date.now() + ms);
214
+ throw new Error(`${engine} rate-limited (HTTP ${res.status}); cooling down ${Math.round(ms / 1000)}s`);
215
+ }
136
216
  }
137
- // ---------------------------------------------------------------- engines
138
217
  async function tinyfishSearch(cfg, query, count, signal) {
139
218
  const url = `https://api.search.tinyfish.ai?query=${encodeURIComponent(query)}`;
140
219
  const res = await fetch(url, {
141
220
  headers: { "X-API-Key": cfg.tinyfishApiKey },
142
- signal: mergeSignal(20_000, signal),
221
+ signal: (0, util_1.mergeSignal)(20_000, signal),
143
222
  });
144
223
  if (!res.ok)
145
224
  throw new Error(`tinyfish search ${res.status}`);
@@ -173,10 +252,9 @@ async function ddgSearch(query, count, signal) {
173
252
  let reachedAny = false;
174
253
  for (const ep of DDG_ENDPOINTS) {
175
254
  try {
176
- const res = await fetch(ep.url + encodeURIComponent(query), {
255
+ const res = await engineFetch("duckduckgo", ep.url + encodeURIComponent(query), {
177
256
  headers: { "user-agent": UA },
178
- signal: mergeSignal(20_000, signal),
179
- });
257
+ }, signal);
180
258
  if (!res.ok)
181
259
  throw new Error(`search failed: HTTP ${res.status}`);
182
260
  reachedAny = true;
@@ -221,14 +299,56 @@ function parseDdgHtml(html, count, linkRe) {
221
299
  }
222
300
  /** Bing's HTML results page: each hit is an <li class="b_algo"> with an <h2><a> link. */
223
301
  async function bingSearch(query, count, signal) {
224
- const res = await fetch(`https://www.bing.com/search?q=${encodeURIComponent(query)}`, {
302
+ const res = await engineFetch("bing", `https://www.bing.com/search?q=${encodeURIComponent(query)}`, {
225
303
  headers: { "user-agent": UA, "accept-language": "en-US,en;q=0.9" },
226
- signal: mergeSignal(20_000, signal),
227
- });
304
+ }, signal);
228
305
  if (!res.ok)
229
306
  throw new Error(`bing search ${res.status}`);
230
307
  return parseBingHtml(await res.text(), count);
231
308
  }
309
+ // ---------------------------------------------------------------- academic engines (keyless)
310
+ /** arXiv's Atom API — preprints with abstracts, no key needed. */
311
+ async function arxivSearch(query, count, signal) {
312
+ const url = `https://export.arxiv.org/api/query?search_query=all:${encodeURIComponent(query)}&max_results=${Math.min(count, 15)}`;
313
+ const res = await engineFetch("arxiv", url, { headers: { "user-agent": UA } }, signal);
314
+ if (!res.ok)
315
+ throw new Error(`arxiv search ${res.status}`);
316
+ const xml = await res.text();
317
+ const out = [];
318
+ for (const entry of xml.split(/<entry>/).slice(1)) {
319
+ if (out.length >= count)
320
+ break;
321
+ const title = strip((/<title>([\s\S]*?)<\/title>/.exec(entry) || [])[1] || "");
322
+ const id = ((/<id>([\s\S]*?)<\/id>/.exec(entry) || [])[1] || "").trim();
323
+ const summary = strip((/<summary>([\s\S]*?)<\/summary>/.exec(entry) || [])[1] || "");
324
+ const published = (/<published>(\d{4}-\d{2}-\d{2})/.exec(entry) || [])[1];
325
+ if (!id || !title || !/^https?:\/\//.test(id))
326
+ continue;
327
+ out.push({ title, url: id, snippet: summary.slice(0, 300), rank: out.length + 1, engine: "arxiv", date: published });
328
+ }
329
+ return out;
330
+ }
331
+ /** Crossref's works API — journal/conference metadata with DOIs, no key needed. */
332
+ async function crossrefSearch(query, count, signal) {
333
+ const url = `https://api.crossref.org/works?query=${encodeURIComponent(query)}&rows=${Math.min(count, 15)}&select=title,DOI,abstract,issued,container-title`;
334
+ const res = await engineFetch("crossref", url, { headers: { "user-agent": UA } }, signal);
335
+ if (!res.ok)
336
+ throw new Error(`crossref search ${res.status}`);
337
+ const data = await res.json();
338
+ const out = [];
339
+ for (const it of data?.message?.items ?? []) {
340
+ if (out.length >= count)
341
+ break;
342
+ const title = strip(String(Array.isArray(it.title) ? it.title[0] ?? "" : it.title ?? ""));
343
+ if (!title || !it.DOI)
344
+ continue;
345
+ const date = Array.isArray(it.issued?.["date-parts"]?.[0]) ? it.issued["date-parts"][0].join("-") : undefined;
346
+ const venue = Array.isArray(it["container-title"]) ? it["container-title"][0] : "";
347
+ const snippet = (strip(String(it.abstract ?? "")) || venue || "").slice(0, 300);
348
+ out.push({ title, url: `https://doi.org/${it.DOI}`, snippet, rank: out.length + 1, engine: "crossref", date });
349
+ }
350
+ return out;
351
+ }
232
352
  function parseBingHtml(html, count) {
233
353
  const hits = [];
234
354
  const blocks = html.split(/<li class="b_algo[^"]*"/i).slice(1);
@@ -302,18 +422,51 @@ async function fetchUrl(cfg, url, raw, maxChars, signal) {
302
422
  }
303
423
  }
304
424
  const res = await fetch(url, {
305
- headers: { "user-agent": UA, accept: "text/html,application/json,text/*;q=0.9,*/*;q=0.5" },
425
+ headers: { "user-agent": UA, accept: "text/html,application/json,application/pdf,text/*;q=0.9,*/*;q=0.5" },
306
426
  signal: signal ?? AbortSignal.timeout(25000),
307
427
  redirect: "follow",
308
428
  });
309
429
  const ctype = res.headers.get("content-type") || "";
310
- const body = await res.text();
311
430
  if (!res.ok) {
312
- return `HTTP ${res.status} ${res.statusText}\n${(0, util_1.truncateMiddle)(body, 2000, "chars")}`;
431
+ // An error page is not content: returning it as a successful result lets
432
+ // "HTTP 403 ... subscribe to continue" become a "fact" in someone's report.
433
+ const body = await res.text().catch(() => "");
434
+ throw new Error(`HTTP ${res.status} ${res.statusText} — page is not usable as a source (paywall/login/blocked?). ` +
435
+ `Try web_search for an alternative source.${body ? ` Server said: ${(0, util_1.oneLine)((0, util_1.htmlToText)(body), 200)}` : ""}`);
313
436
  }
437
+ const buf = Buffer.from(await res.arrayBuffer());
438
+ if (/application\/pdf/i.test(ctype) || buf.subarray(0, 5).toString("latin1") === "%PDF-") {
439
+ if (buf.length > 20_000_000)
440
+ throw new Error(`PDF is ${Math.round(buf.length / 1e6)}MB — too large to extract`);
441
+ const pdf = (0, pdftext_1.extractPdfText)(buf);
442
+ if (!pdf) {
443
+ throw new Error("PDF contains no extractable text (likely scanned or encrypted) — find an HTML version of this source.");
444
+ }
445
+ return (0, util_1.truncateMiddle)(`[PDF, ${pdf.pages} page${pdf.pages > 1 ? "s" : ""}]\n${pdf.text}`, maxChars, "chars");
446
+ }
447
+ const body = decodeBody(buf, ctype);
314
448
  const text = !raw && /html/i.test(ctype) ? (0, util_1.htmlToText)(body) : body;
449
+ if (!raw && /html/i.test(ctype)) {
450
+ const trimmed = text.trim();
451
+ if (trimmed.length < 400 && /subscrib|sign.?in|log.?in|enable javascript|access denied|are you a (human|robot)|captcha/i.test(trimmed)) {
452
+ return `WARNING: this page returned only a paywall/anti-bot shell — the text below is probably not the real content. Try web_search for an alternative source.\n\n${trimmed}`;
453
+ }
454
+ }
315
455
  return (0, util_1.truncateMiddle)(text, maxChars, "chars");
316
456
  }
457
+ /** Decode a response body honoring its content-type charset (UTF-8 fallback). */
458
+ function decodeBody(buf, ctype) {
459
+ const charset = /charset=([\w-]+)/i.exec(ctype)?.[1]?.toLowerCase();
460
+ if (charset && charset !== "utf-8" && charset !== "utf8") {
461
+ try {
462
+ return new TextDecoder(charset).decode(buf);
463
+ }
464
+ catch {
465
+ /* unknown label — fall through to utf-8 */
466
+ }
467
+ }
468
+ return buf.toString("utf8");
469
+ }
317
470
  async function tinyfishFetch(cfg, url, signal) {
318
471
  const res = await fetch("https://api.fetch.tinyfish.ai", {
319
472
  method: "POST",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@robzilla1738/agentswarm",
3
- "version": "0.5.0",
3
+ "version": "0.7.0",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -1 +1 @@
1
- <!DOCTYPE html><!--errjtBR_bKoee8ogLp8xk--><html lang="en" class="__variable_73ee6c __variable_3c557b"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="preload" href="/_next/static/media/4c9affa5bc8f420e-s.p.woff2" as="font" crossorigin="" type="font/woff2"/><link rel="preload" href="/_next/static/media/bb3ef058b751a6ad-s.p.woff2" as="font" crossorigin="" type="font/woff2"/><link rel="stylesheet" href="/_next/static/css/9f7bd82b8e4c762c.css" data-precedence="next"/><link rel="preload" as="script" fetchPriority="low" href="/_next/static/chunks/webpack-38639c05c96dbeca.js"/><script src="/_next/static/chunks/4bd1b696-c023c6e3521b1417.js" async=""></script><script src="/_next/static/chunks/255-2aa030c9ba2867e3.js" async=""></script><script src="/_next/static/chunks/main-app-889ed884f8bc78e3.js" async=""></script><meta name="robots" content="noindex"/><meta name="next-size-adjust" content=""/><title>404: This page could not be found.</title><meta name="theme-color" content="#050505"/><title>agentswarm</title><meta name="description" content="A local agent swarm for long-horizon, autonomous work."/><link rel="icon" href="/icon.png?bdc9175d46e1d0aa" type="image/png" sizes="256x256"/><script src="/_next/static/chunks/polyfills-42372ed130431b0a.js" noModule=""></script></head><body><div hidden=""><!--$--><!--/$--></div><script>try{var t=localStorage.getItem("theme");if(t==="light"||t==="dark")document.documentElement.dataset.theme=t}catch(e){}</script><div style="font-family:system-ui,&quot;Segoe UI&quot;,Roboto,Helvetica,Arial,sans-serif,&quot;Apple Color Emoji&quot;,&quot;Segoe UI Emoji&quot;;height:100vh;text-align:center;display:flex;flex-direction:column;align-items:center;justify-content:center"><div><style>body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}</style><h1 class="next-error-h1" style="display:inline-block;margin:0 20px 0 0;padding:0 23px 0 0;font-size:24px;font-weight:500;vertical-align:top;line-height:49px">404</h1><div style="display:inline-block"><h2 style="font-size:14px;font-weight:400;line-height:49px;margin:0">This page could not be found.</h2></div></div></div><!--$--><!--/$--><script src="/_next/static/chunks/webpack-38639c05c96dbeca.js" id="_R_" async=""></script><script>(self.__next_f=self.__next_f||[]).push([0])</script><script>self.__next_f.push([1,"1:\"$Sreact.fragment\"\n2:I[9766,[],\"\"]\n3:I[8924,[],\"\"]\n4:I[4431,[],\"OutletBoundary\"]\n6:I[5278,[],\"AsyncMetadataOutlet\"]\n8:I[4431,[],\"ViewportBoundary\"]\na:I[4431,[],\"MetadataBoundary\"]\nb:\"$Sreact.suspense\"\nd:I[7150,[],\"\"]\n:HL[\"/_next/static/media/4c9affa5bc8f420e-s.p.woff2\",\"font\",{\"crossOrigin\":\"\",\"type\":\"font/woff2\"}]\n:HL[\"/_next/static/media/bb3ef058b751a6ad-s.p.woff2\",\"font\",{\"crossOrigin\":\"\",\"type\":\"font/woff2\"}]\n:HL[\"/_next/static/css/9f7bd82b8e4c762c.css\",\"style\"]\n"])</script><script>self.__next_f.push([1,"0:{\"P\":null,\"b\":\"errjtBR_bKoee8ogLp8xk\",\"p\":\"\",\"c\":[\"\",\"_not-found\",\"\"],\"i\":false,\"f\":[[[\"\",{\"children\":[\"/_not-found\",{\"children\":[\"__PAGE__\",{}]}]},\"$undefined\",\"$undefined\",true],[\"\",[\"$\",\"$1\",\"c\",{\"children\":[[[\"$\",\"link\",\"0\",{\"rel\":\"stylesheet\",\"href\":\"/_next/static/css/9f7bd82b8e4c762c.css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\",\"nonce\":\"$undefined\"}]],[\"$\",\"html\",null,{\"lang\":\"en\",\"className\":\"__variable_73ee6c __variable_3c557b\",\"children\":[\"$\",\"body\",null,{\"children\":[[\"$\",\"script\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\"try{var t=localStorage.getItem(\\\"theme\\\");if(t===\\\"light\\\"||t===\\\"dark\\\")document.documentElement.dataset.theme=t}catch(e){}\"}}],[\"$\",\"$L2\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L3\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":\"$undefined\",\"forbidden\":\"$undefined\",\"unauthorized\":\"$undefined\"}]]}]}]]}],{\"children\":[\"/_not-found\",[\"$\",\"$1\",\"c\",{\"children\":[null,[\"$\",\"$L2\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L3\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":\"$undefined\",\"forbidden\":\"$undefined\",\"unauthorized\":\"$undefined\"}]]}],{\"children\":[\"__PAGE__\",[\"$\",\"$1\",\"c\",{\"children\":[[[\"$\",\"title\",null,{\"children\":\"404: This page could not be found.\"}],[\"$\",\"div\",null,{\"style\":{\"fontFamily\":\"system-ui,\\\"Segoe UI\\\",Roboto,Helvetica,Arial,sans-serif,\\\"Apple Color Emoji\\\",\\\"Segoe UI Emoji\\\"\",\"height\":\"100vh\",\"textAlign\":\"center\",\"display\":\"flex\",\"flexDirection\":\"column\",\"alignItems\":\"center\",\"justifyContent\":\"center\"},\"children\":[\"$\",\"div\",null,{\"children\":[[\"$\",\"style\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}\"}}],[\"$\",\"h1\",null,{\"className\":\"next-error-h1\",\"style\":{\"display\":\"inline-block\",\"margin\":\"0 20px 0 0\",\"padding\":\"0 23px 0 0\",\"fontSize\":24,\"fontWeight\":500,\"verticalAlign\":\"top\",\"lineHeight\":\"49px\"},\"children\":404}],[\"$\",\"div\",null,{\"style\":{\"display\":\"inline-block\"},\"children\":[\"$\",\"h2\",null,{\"style\":{\"fontSize\":14,\"fontWeight\":400,\"lineHeight\":\"49px\",\"margin\":0},\"children\":\"This page could not be found.\"}]}]]}]}]],null,[\"$\",\"$L4\",null,{\"children\":[\"$L5\",[\"$\",\"$L6\",null,{\"promise\":\"$@7\"}]]}]]}],{},null,false]},null,false]},null,false],[\"$\",\"$1\",\"h\",{\"children\":[[\"$\",\"meta\",null,{\"name\":\"robots\",\"content\":\"noindex\"}],[[\"$\",\"$L8\",null,{\"children\":\"$L9\"}],[\"$\",\"meta\",null,{\"name\":\"next-size-adjust\",\"content\":\"\"}]],[\"$\",\"$La\",null,{\"children\":[\"$\",\"div\",null,{\"hidden\":true,\"children\":[\"$\",\"$b\",null,{\"fallback\":null,\"children\":\"$Lc\"}]}]}]]}],false]],\"m\":\"$undefined\",\"G\":[\"$d\",[]],\"s\":false,\"S\":true}\n"])</script><script>self.__next_f.push([1,"9:[[\"$\",\"meta\",\"0\",{\"charSet\":\"utf-8\"}],[\"$\",\"meta\",\"1\",{\"name\":\"viewport\",\"content\":\"width=device-width, initial-scale=1\"}],[\"$\",\"meta\",\"2\",{\"name\":\"theme-color\",\"content\":\"#050505\"}]]\n5:null\n"])</script><script>self.__next_f.push([1,"e:I[622,[],\"IconMark\"]\n7:{\"metadata\":[[\"$\",\"title\",\"0\",{\"children\":\"agentswarm\"}],[\"$\",\"meta\",\"1\",{\"name\":\"description\",\"content\":\"A local agent swarm for long-horizon, autonomous work.\"}],[\"$\",\"link\",\"2\",{\"rel\":\"icon\",\"href\":\"/icon.png?bdc9175d46e1d0aa\",\"type\":\"image/png\",\"sizes\":\"256x256\"}],[\"$\",\"$Le\",\"3\",{}]],\"error\":null,\"digest\":\"$undefined\"}\n"])</script><script>self.__next_f.push([1,"c:\"$7:metadata\"\n"])</script></body></html>
1
+ <!DOCTYPE html><!--JFkx5KtNi0DYyqm_THzbY--><html lang="en" class="__variable_73ee6c __variable_3c557b"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="preload" href="/_next/static/media/4c9affa5bc8f420e-s.p.woff2" as="font" crossorigin="" type="font/woff2"/><link rel="preload" href="/_next/static/media/bb3ef058b751a6ad-s.p.woff2" as="font" crossorigin="" type="font/woff2"/><link rel="stylesheet" href="/_next/static/css/d95c2ba395730031.css" data-precedence="next"/><link rel="preload" as="script" fetchPriority="low" href="/_next/static/chunks/webpack-38639c05c96dbeca.js"/><script src="/_next/static/chunks/4bd1b696-c023c6e3521b1417.js" async=""></script><script src="/_next/static/chunks/255-2aa030c9ba2867e3.js" async=""></script><script src="/_next/static/chunks/main-app-889ed884f8bc78e3.js" async=""></script><meta name="robots" content="noindex"/><meta name="next-size-adjust" content=""/><title>404: This page could not be found.</title><meta name="theme-color" content="#050505"/><title>agentswarm</title><meta name="description" content="A local agent swarm for long-horizon, autonomous work."/><link rel="icon" href="/icon.png?bdc9175d46e1d0aa" type="image/png" sizes="256x256"/><script src="/_next/static/chunks/polyfills-42372ed130431b0a.js" noModule=""></script></head><body><div hidden=""><!--$--><!--/$--></div><script>try{var t=localStorage.getItem("theme");if(t==="light"||t==="dark")document.documentElement.dataset.theme=t}catch(e){}</script><div style="font-family:system-ui,&quot;Segoe UI&quot;,Roboto,Helvetica,Arial,sans-serif,&quot;Apple Color Emoji&quot;,&quot;Segoe UI Emoji&quot;;height:100vh;text-align:center;display:flex;flex-direction:column;align-items:center;justify-content:center"><div><style>body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}</style><h1 class="next-error-h1" style="display:inline-block;margin:0 20px 0 0;padding:0 23px 0 0;font-size:24px;font-weight:500;vertical-align:top;line-height:49px">404</h1><div style="display:inline-block"><h2 style="font-size:14px;font-weight:400;line-height:49px;margin:0">This page could not be found.</h2></div></div></div><!--$--><!--/$--><script src="/_next/static/chunks/webpack-38639c05c96dbeca.js" id="_R_" async=""></script><script>(self.__next_f=self.__next_f||[]).push([0])</script><script>self.__next_f.push([1,"1:\"$Sreact.fragment\"\n2:I[9766,[],\"\"]\n3:I[8924,[],\"\"]\n4:I[4431,[],\"OutletBoundary\"]\n6:I[5278,[],\"AsyncMetadataOutlet\"]\n8:I[4431,[],\"ViewportBoundary\"]\na:I[4431,[],\"MetadataBoundary\"]\nb:\"$Sreact.suspense\"\nd:I[7150,[],\"\"]\n:HL[\"/_next/static/media/4c9affa5bc8f420e-s.p.woff2\",\"font\",{\"crossOrigin\":\"\",\"type\":\"font/woff2\"}]\n:HL[\"/_next/static/media/bb3ef058b751a6ad-s.p.woff2\",\"font\",{\"crossOrigin\":\"\",\"type\":\"font/woff2\"}]\n:HL[\"/_next/static/css/d95c2ba395730031.css\",\"style\"]\n"])</script><script>self.__next_f.push([1,"0:{\"P\":null,\"b\":\"JFkx5KtNi0DYyqm_THzbY\",\"p\":\"\",\"c\":[\"\",\"_not-found\",\"\"],\"i\":false,\"f\":[[[\"\",{\"children\":[\"/_not-found\",{\"children\":[\"__PAGE__\",{}]}]},\"$undefined\",\"$undefined\",true],[\"\",[\"$\",\"$1\",\"c\",{\"children\":[[[\"$\",\"link\",\"0\",{\"rel\":\"stylesheet\",\"href\":\"/_next/static/css/d95c2ba395730031.css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\",\"nonce\":\"$undefined\"}]],[\"$\",\"html\",null,{\"lang\":\"en\",\"className\":\"__variable_73ee6c __variable_3c557b\",\"children\":[\"$\",\"body\",null,{\"children\":[[\"$\",\"script\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\"try{var t=localStorage.getItem(\\\"theme\\\");if(t===\\\"light\\\"||t===\\\"dark\\\")document.documentElement.dataset.theme=t}catch(e){}\"}}],[\"$\",\"$L2\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L3\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":\"$undefined\",\"forbidden\":\"$undefined\",\"unauthorized\":\"$undefined\"}]]}]}]]}],{\"children\":[\"/_not-found\",[\"$\",\"$1\",\"c\",{\"children\":[null,[\"$\",\"$L2\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L3\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":\"$undefined\",\"forbidden\":\"$undefined\",\"unauthorized\":\"$undefined\"}]]}],{\"children\":[\"__PAGE__\",[\"$\",\"$1\",\"c\",{\"children\":[[[\"$\",\"title\",null,{\"children\":\"404: This page could not be found.\"}],[\"$\",\"div\",null,{\"style\":{\"fontFamily\":\"system-ui,\\\"Segoe UI\\\",Roboto,Helvetica,Arial,sans-serif,\\\"Apple Color Emoji\\\",\\\"Segoe UI Emoji\\\"\",\"height\":\"100vh\",\"textAlign\":\"center\",\"display\":\"flex\",\"flexDirection\":\"column\",\"alignItems\":\"center\",\"justifyContent\":\"center\"},\"children\":[\"$\",\"div\",null,{\"children\":[[\"$\",\"style\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}\"}}],[\"$\",\"h1\",null,{\"className\":\"next-error-h1\",\"style\":{\"display\":\"inline-block\",\"margin\":\"0 20px 0 0\",\"padding\":\"0 23px 0 0\",\"fontSize\":24,\"fontWeight\":500,\"verticalAlign\":\"top\",\"lineHeight\":\"49px\"},\"children\":404}],[\"$\",\"div\",null,{\"style\":{\"display\":\"inline-block\"},\"children\":[\"$\",\"h2\",null,{\"style\":{\"fontSize\":14,\"fontWeight\":400,\"lineHeight\":\"49px\",\"margin\":0},\"children\":\"This page could not be found.\"}]}]]}]}]],null,[\"$\",\"$L4\",null,{\"children\":[\"$L5\",[\"$\",\"$L6\",null,{\"promise\":\"$@7\"}]]}]]}],{},null,false]},null,false]},null,false],[\"$\",\"$1\",\"h\",{\"children\":[[\"$\",\"meta\",null,{\"name\":\"robots\",\"content\":\"noindex\"}],[[\"$\",\"$L8\",null,{\"children\":\"$L9\"}],[\"$\",\"meta\",null,{\"name\":\"next-size-adjust\",\"content\":\"\"}]],[\"$\",\"$La\",null,{\"children\":[\"$\",\"div\",null,{\"hidden\":true,\"children\":[\"$\",\"$b\",null,{\"fallback\":null,\"children\":\"$Lc\"}]}]}]]}],false]],\"m\":\"$undefined\",\"G\":[\"$d\",[]],\"s\":false,\"S\":true}\n"])</script><script>self.__next_f.push([1,"9:[[\"$\",\"meta\",\"0\",{\"charSet\":\"utf-8\"}],[\"$\",\"meta\",\"1\",{\"name\":\"viewport\",\"content\":\"width=device-width, initial-scale=1\"}],[\"$\",\"meta\",\"2\",{\"name\":\"theme-color\",\"content\":\"#050505\"}]]\n5:null\n"])</script><script>self.__next_f.push([1,"e:I[622,[],\"IconMark\"]\n7:{\"metadata\":[[\"$\",\"title\",\"0\",{\"children\":\"agentswarm\"}],[\"$\",\"meta\",\"1\",{\"name\":\"description\",\"content\":\"A local agent swarm for long-horizon, autonomous work.\"}],[\"$\",\"link\",\"2\",{\"rel\":\"icon\",\"href\":\"/icon.png?bdc9175d46e1d0aa\",\"type\":\"image/png\",\"sizes\":\"256x256\"}],[\"$\",\"$Le\",\"3\",{}]],\"error\":null,\"digest\":\"$undefined\"}\n"])</script><script>self.__next_f.push([1,"c:\"$7:metadata\"\n"])</script></body></html>
package/ui/out/404.html CHANGED
@@ -1 +1 @@
1
- <!DOCTYPE html><!--errjtBR_bKoee8ogLp8xk--><html lang="en" class="__variable_73ee6c __variable_3c557b"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="preload" href="/_next/static/media/4c9affa5bc8f420e-s.p.woff2" as="font" crossorigin="" type="font/woff2"/><link rel="preload" href="/_next/static/media/bb3ef058b751a6ad-s.p.woff2" as="font" crossorigin="" type="font/woff2"/><link rel="stylesheet" href="/_next/static/css/9f7bd82b8e4c762c.css" data-precedence="next"/><link rel="preload" as="script" fetchPriority="low" href="/_next/static/chunks/webpack-38639c05c96dbeca.js"/><script src="/_next/static/chunks/4bd1b696-c023c6e3521b1417.js" async=""></script><script src="/_next/static/chunks/255-2aa030c9ba2867e3.js" async=""></script><script src="/_next/static/chunks/main-app-889ed884f8bc78e3.js" async=""></script><meta name="robots" content="noindex"/><meta name="next-size-adjust" content=""/><title>404: This page could not be found.</title><meta name="theme-color" content="#050505"/><title>agentswarm</title><meta name="description" content="A local agent swarm for long-horizon, autonomous work."/><link rel="icon" href="/icon.png?bdc9175d46e1d0aa" type="image/png" sizes="256x256"/><script src="/_next/static/chunks/polyfills-42372ed130431b0a.js" noModule=""></script></head><body><div hidden=""><!--$--><!--/$--></div><script>try{var t=localStorage.getItem("theme");if(t==="light"||t==="dark")document.documentElement.dataset.theme=t}catch(e){}</script><div style="font-family:system-ui,&quot;Segoe UI&quot;,Roboto,Helvetica,Arial,sans-serif,&quot;Apple Color Emoji&quot;,&quot;Segoe UI Emoji&quot;;height:100vh;text-align:center;display:flex;flex-direction:column;align-items:center;justify-content:center"><div><style>body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}</style><h1 class="next-error-h1" style="display:inline-block;margin:0 20px 0 0;padding:0 23px 0 0;font-size:24px;font-weight:500;vertical-align:top;line-height:49px">404</h1><div style="display:inline-block"><h2 style="font-size:14px;font-weight:400;line-height:49px;margin:0">This page could not be found.</h2></div></div></div><!--$--><!--/$--><script src="/_next/static/chunks/webpack-38639c05c96dbeca.js" id="_R_" async=""></script><script>(self.__next_f=self.__next_f||[]).push([0])</script><script>self.__next_f.push([1,"1:\"$Sreact.fragment\"\n2:I[9766,[],\"\"]\n3:I[8924,[],\"\"]\n4:I[4431,[],\"OutletBoundary\"]\n6:I[5278,[],\"AsyncMetadataOutlet\"]\n8:I[4431,[],\"ViewportBoundary\"]\na:I[4431,[],\"MetadataBoundary\"]\nb:\"$Sreact.suspense\"\nd:I[7150,[],\"\"]\n:HL[\"/_next/static/media/4c9affa5bc8f420e-s.p.woff2\",\"font\",{\"crossOrigin\":\"\",\"type\":\"font/woff2\"}]\n:HL[\"/_next/static/media/bb3ef058b751a6ad-s.p.woff2\",\"font\",{\"crossOrigin\":\"\",\"type\":\"font/woff2\"}]\n:HL[\"/_next/static/css/9f7bd82b8e4c762c.css\",\"style\"]\n"])</script><script>self.__next_f.push([1,"0:{\"P\":null,\"b\":\"errjtBR_bKoee8ogLp8xk\",\"p\":\"\",\"c\":[\"\",\"_not-found\",\"\"],\"i\":false,\"f\":[[[\"\",{\"children\":[\"/_not-found\",{\"children\":[\"__PAGE__\",{}]}]},\"$undefined\",\"$undefined\",true],[\"\",[\"$\",\"$1\",\"c\",{\"children\":[[[\"$\",\"link\",\"0\",{\"rel\":\"stylesheet\",\"href\":\"/_next/static/css/9f7bd82b8e4c762c.css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\",\"nonce\":\"$undefined\"}]],[\"$\",\"html\",null,{\"lang\":\"en\",\"className\":\"__variable_73ee6c __variable_3c557b\",\"children\":[\"$\",\"body\",null,{\"children\":[[\"$\",\"script\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\"try{var t=localStorage.getItem(\\\"theme\\\");if(t===\\\"light\\\"||t===\\\"dark\\\")document.documentElement.dataset.theme=t}catch(e){}\"}}],[\"$\",\"$L2\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L3\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":\"$undefined\",\"forbidden\":\"$undefined\",\"unauthorized\":\"$undefined\"}]]}]}]]}],{\"children\":[\"/_not-found\",[\"$\",\"$1\",\"c\",{\"children\":[null,[\"$\",\"$L2\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L3\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":\"$undefined\",\"forbidden\":\"$undefined\",\"unauthorized\":\"$undefined\"}]]}],{\"children\":[\"__PAGE__\",[\"$\",\"$1\",\"c\",{\"children\":[[[\"$\",\"title\",null,{\"children\":\"404: This page could not be found.\"}],[\"$\",\"div\",null,{\"style\":{\"fontFamily\":\"system-ui,\\\"Segoe UI\\\",Roboto,Helvetica,Arial,sans-serif,\\\"Apple Color Emoji\\\",\\\"Segoe UI Emoji\\\"\",\"height\":\"100vh\",\"textAlign\":\"center\",\"display\":\"flex\",\"flexDirection\":\"column\",\"alignItems\":\"center\",\"justifyContent\":\"center\"},\"children\":[\"$\",\"div\",null,{\"children\":[[\"$\",\"style\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}\"}}],[\"$\",\"h1\",null,{\"className\":\"next-error-h1\",\"style\":{\"display\":\"inline-block\",\"margin\":\"0 20px 0 0\",\"padding\":\"0 23px 0 0\",\"fontSize\":24,\"fontWeight\":500,\"verticalAlign\":\"top\",\"lineHeight\":\"49px\"},\"children\":404}],[\"$\",\"div\",null,{\"style\":{\"display\":\"inline-block\"},\"children\":[\"$\",\"h2\",null,{\"style\":{\"fontSize\":14,\"fontWeight\":400,\"lineHeight\":\"49px\",\"margin\":0},\"children\":\"This page could not be found.\"}]}]]}]}]],null,[\"$\",\"$L4\",null,{\"children\":[\"$L5\",[\"$\",\"$L6\",null,{\"promise\":\"$@7\"}]]}]]}],{},null,false]},null,false]},null,false],[\"$\",\"$1\",\"h\",{\"children\":[[\"$\",\"meta\",null,{\"name\":\"robots\",\"content\":\"noindex\"}],[[\"$\",\"$L8\",null,{\"children\":\"$L9\"}],[\"$\",\"meta\",null,{\"name\":\"next-size-adjust\",\"content\":\"\"}]],[\"$\",\"$La\",null,{\"children\":[\"$\",\"div\",null,{\"hidden\":true,\"children\":[\"$\",\"$b\",null,{\"fallback\":null,\"children\":\"$Lc\"}]}]}]]}],false]],\"m\":\"$undefined\",\"G\":[\"$d\",[]],\"s\":false,\"S\":true}\n"])</script><script>self.__next_f.push([1,"9:[[\"$\",\"meta\",\"0\",{\"charSet\":\"utf-8\"}],[\"$\",\"meta\",\"1\",{\"name\":\"viewport\",\"content\":\"width=device-width, initial-scale=1\"}],[\"$\",\"meta\",\"2\",{\"name\":\"theme-color\",\"content\":\"#050505\"}]]\n5:null\n"])</script><script>self.__next_f.push([1,"e:I[622,[],\"IconMark\"]\n7:{\"metadata\":[[\"$\",\"title\",\"0\",{\"children\":\"agentswarm\"}],[\"$\",\"meta\",\"1\",{\"name\":\"description\",\"content\":\"A local agent swarm for long-horizon, autonomous work.\"}],[\"$\",\"link\",\"2\",{\"rel\":\"icon\",\"href\":\"/icon.png?bdc9175d46e1d0aa\",\"type\":\"image/png\",\"sizes\":\"256x256\"}],[\"$\",\"$Le\",\"3\",{}]],\"error\":null,\"digest\":\"$undefined\"}\n"])</script><script>self.__next_f.push([1,"c:\"$7:metadata\"\n"])</script></body></html>
1
+ <!DOCTYPE html><!--JFkx5KtNi0DYyqm_THzbY--><html lang="en" class="__variable_73ee6c __variable_3c557b"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="preload" href="/_next/static/media/4c9affa5bc8f420e-s.p.woff2" as="font" crossorigin="" type="font/woff2"/><link rel="preload" href="/_next/static/media/bb3ef058b751a6ad-s.p.woff2" as="font" crossorigin="" type="font/woff2"/><link rel="stylesheet" href="/_next/static/css/d95c2ba395730031.css" data-precedence="next"/><link rel="preload" as="script" fetchPriority="low" href="/_next/static/chunks/webpack-38639c05c96dbeca.js"/><script src="/_next/static/chunks/4bd1b696-c023c6e3521b1417.js" async=""></script><script src="/_next/static/chunks/255-2aa030c9ba2867e3.js" async=""></script><script src="/_next/static/chunks/main-app-889ed884f8bc78e3.js" async=""></script><meta name="robots" content="noindex"/><meta name="next-size-adjust" content=""/><title>404: This page could not be found.</title><meta name="theme-color" content="#050505"/><title>agentswarm</title><meta name="description" content="A local agent swarm for long-horizon, autonomous work."/><link rel="icon" href="/icon.png?bdc9175d46e1d0aa" type="image/png" sizes="256x256"/><script src="/_next/static/chunks/polyfills-42372ed130431b0a.js" noModule=""></script></head><body><div hidden=""><!--$--><!--/$--></div><script>try{var t=localStorage.getItem("theme");if(t==="light"||t==="dark")document.documentElement.dataset.theme=t}catch(e){}</script><div style="font-family:system-ui,&quot;Segoe UI&quot;,Roboto,Helvetica,Arial,sans-serif,&quot;Apple Color Emoji&quot;,&quot;Segoe UI Emoji&quot;;height:100vh;text-align:center;display:flex;flex-direction:column;align-items:center;justify-content:center"><div><style>body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}</style><h1 class="next-error-h1" style="display:inline-block;margin:0 20px 0 0;padding:0 23px 0 0;font-size:24px;font-weight:500;vertical-align:top;line-height:49px">404</h1><div style="display:inline-block"><h2 style="font-size:14px;font-weight:400;line-height:49px;margin:0">This page could not be found.</h2></div></div></div><!--$--><!--/$--><script src="/_next/static/chunks/webpack-38639c05c96dbeca.js" id="_R_" async=""></script><script>(self.__next_f=self.__next_f||[]).push([0])</script><script>self.__next_f.push([1,"1:\"$Sreact.fragment\"\n2:I[9766,[],\"\"]\n3:I[8924,[],\"\"]\n4:I[4431,[],\"OutletBoundary\"]\n6:I[5278,[],\"AsyncMetadataOutlet\"]\n8:I[4431,[],\"ViewportBoundary\"]\na:I[4431,[],\"MetadataBoundary\"]\nb:\"$Sreact.suspense\"\nd:I[7150,[],\"\"]\n:HL[\"/_next/static/media/4c9affa5bc8f420e-s.p.woff2\",\"font\",{\"crossOrigin\":\"\",\"type\":\"font/woff2\"}]\n:HL[\"/_next/static/media/bb3ef058b751a6ad-s.p.woff2\",\"font\",{\"crossOrigin\":\"\",\"type\":\"font/woff2\"}]\n:HL[\"/_next/static/css/d95c2ba395730031.css\",\"style\"]\n"])</script><script>self.__next_f.push([1,"0:{\"P\":null,\"b\":\"JFkx5KtNi0DYyqm_THzbY\",\"p\":\"\",\"c\":[\"\",\"_not-found\",\"\"],\"i\":false,\"f\":[[[\"\",{\"children\":[\"/_not-found\",{\"children\":[\"__PAGE__\",{}]}]},\"$undefined\",\"$undefined\",true],[\"\",[\"$\",\"$1\",\"c\",{\"children\":[[[\"$\",\"link\",\"0\",{\"rel\":\"stylesheet\",\"href\":\"/_next/static/css/d95c2ba395730031.css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\",\"nonce\":\"$undefined\"}]],[\"$\",\"html\",null,{\"lang\":\"en\",\"className\":\"__variable_73ee6c __variable_3c557b\",\"children\":[\"$\",\"body\",null,{\"children\":[[\"$\",\"script\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\"try{var t=localStorage.getItem(\\\"theme\\\");if(t===\\\"light\\\"||t===\\\"dark\\\")document.documentElement.dataset.theme=t}catch(e){}\"}}],[\"$\",\"$L2\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L3\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":\"$undefined\",\"forbidden\":\"$undefined\",\"unauthorized\":\"$undefined\"}]]}]}]]}],{\"children\":[\"/_not-found\",[\"$\",\"$1\",\"c\",{\"children\":[null,[\"$\",\"$L2\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L3\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":\"$undefined\",\"forbidden\":\"$undefined\",\"unauthorized\":\"$undefined\"}]]}],{\"children\":[\"__PAGE__\",[\"$\",\"$1\",\"c\",{\"children\":[[[\"$\",\"title\",null,{\"children\":\"404: This page could not be found.\"}],[\"$\",\"div\",null,{\"style\":{\"fontFamily\":\"system-ui,\\\"Segoe UI\\\",Roboto,Helvetica,Arial,sans-serif,\\\"Apple Color Emoji\\\",\\\"Segoe UI Emoji\\\"\",\"height\":\"100vh\",\"textAlign\":\"center\",\"display\":\"flex\",\"flexDirection\":\"column\",\"alignItems\":\"center\",\"justifyContent\":\"center\"},\"children\":[\"$\",\"div\",null,{\"children\":[[\"$\",\"style\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}\"}}],[\"$\",\"h1\",null,{\"className\":\"next-error-h1\",\"style\":{\"display\":\"inline-block\",\"margin\":\"0 20px 0 0\",\"padding\":\"0 23px 0 0\",\"fontSize\":24,\"fontWeight\":500,\"verticalAlign\":\"top\",\"lineHeight\":\"49px\"},\"children\":404}],[\"$\",\"div\",null,{\"style\":{\"display\":\"inline-block\"},\"children\":[\"$\",\"h2\",null,{\"style\":{\"fontSize\":14,\"fontWeight\":400,\"lineHeight\":\"49px\",\"margin\":0},\"children\":\"This page could not be found.\"}]}]]}]}]],null,[\"$\",\"$L4\",null,{\"children\":[\"$L5\",[\"$\",\"$L6\",null,{\"promise\":\"$@7\"}]]}]]}],{},null,false]},null,false]},null,false],[\"$\",\"$1\",\"h\",{\"children\":[[\"$\",\"meta\",null,{\"name\":\"robots\",\"content\":\"noindex\"}],[[\"$\",\"$L8\",null,{\"children\":\"$L9\"}],[\"$\",\"meta\",null,{\"name\":\"next-size-adjust\",\"content\":\"\"}]],[\"$\",\"$La\",null,{\"children\":[\"$\",\"div\",null,{\"hidden\":true,\"children\":[\"$\",\"$b\",null,{\"fallback\":null,\"children\":\"$Lc\"}]}]}]]}],false]],\"m\":\"$undefined\",\"G\":[\"$d\",[]],\"s\":false,\"S\":true}\n"])</script><script>self.__next_f.push([1,"9:[[\"$\",\"meta\",\"0\",{\"charSet\":\"utf-8\"}],[\"$\",\"meta\",\"1\",{\"name\":\"viewport\",\"content\":\"width=device-width, initial-scale=1\"}],[\"$\",\"meta\",\"2\",{\"name\":\"theme-color\",\"content\":\"#050505\"}]]\n5:null\n"])</script><script>self.__next_f.push([1,"e:I[622,[],\"IconMark\"]\n7:{\"metadata\":[[\"$\",\"title\",\"0\",{\"children\":\"agentswarm\"}],[\"$\",\"meta\",\"1\",{\"name\":\"description\",\"content\":\"A local agent swarm for long-horizon, autonomous work.\"}],[\"$\",\"link\",\"2\",{\"rel\":\"icon\",\"href\":\"/icon.png?bdc9175d46e1d0aa\",\"type\":\"image/png\",\"sizes\":\"256x256\"}],[\"$\",\"$Le\",\"3\",{}]],\"error\":null,\"digest\":\"$undefined\"}\n"])</script><script>self.__next_f.push([1,"c:\"$7:metadata\"\n"])</script></body></html>