@wenathlan/saddle 1.8.2 → 1.8.5

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 (257) hide show
  1. package/README.md +9 -9
  2. package/browser/playwright.js +22 -0
  3. package/docs/.gitkeep +0 -0
  4. package/docs/gapmatrix.md +3 -3
  5. package/docs/libraryapi.md +1 -0
  6. package/docs/logs/.gitkeep +0 -0
  7. package/docs/packageaudit185.md +23 -0
  8. package/docs/plans/00.index.md +50 -0
  9. package/docs/plans/01.architecture.md +86 -0
  10. package/docs/plans/02.research.computer.use.md +58 -0
  11. package/docs/plans/03.research.captcha.bypass.md +68 -0
  12. package/docs/plans/04.research.sandbox.ai.md +52 -0
  13. package/docs/plans/05.capture.platform.md +57 -0
  14. package/docs/plans/06.dependencies.md +97 -0
  15. package/docs/plans/07.captcha.test.page.md +41 -0
  16. package/docs/plans/08.production.infra.md +70 -0
  17. package/docs/plans/09.database.schema.md +121 -0
  18. package/docs/plans/10.cloudinary.storage.md +57 -0
  19. package/docs/plans/11.movement.logs.json.md +72 -0
  20. package/docs/plans/12.research.atlas.agent.browser.md +79 -0
  21. package/docs/plans/13.research.anti.detection.md +898 -0
  22. package/docs/plans/14.research.proxy.md +1495 -0
  23. package/docs/plans/15.research.retry.rate.limit.md +1958 -0
  24. package/docs/plans/16.research.crawling.md +1417 -0
  25. package/docs/plans/17.research.caching.md +1610 -0
  26. package/docs/plans/18.research.content.extraction.md +1952 -0
  27. package/docs/plans/19.research.errors.events.md +1523 -0
  28. package/docs/plans/20.research.zod.validation.md +1350 -0
  29. package/docs/plans/21.research.batch.concurrency.md +1888 -0
  30. package/docs/plans/22.research.universal.runtime.md +944 -0
  31. package/docs/plans/23.research.ai.integration.md +1465 -0
  32. package/docs/plans/24.research.memory.persistence.md +1979 -0
  33. package/docs/plans/25.research.server.api.md +342 -0
  34. package/docs/plans/26.research.compilation.md +249 -0
  35. package/docs/plans/27.research.html.parsing.md +251 -0
  36. package/docs/plans/28.action.plan.md +50 -0
  37. package/docs/plans/29.api.reference.md +174 -0
  38. package/docs/plans/30.architecture.plan.md +94 -0
  39. package/docs/plans/31.auditoria.dados.md +163 -0
  40. package/docs/plans/32.bots.automacao.computacional.md +214 -0
  41. package/docs/plans/33.bots.codigo.revisao.md +220 -0
  42. package/docs/plans/34.bots.seguranca.cicd.md +366 -0
  43. package/docs/plans/35.comparativo.concorrencia.md +464 -0
  44. package/docs/plans/36.computational.memory.md +340 -0
  45. package/docs/plans/37.deploystrategy.md +394 -0
  46. package/docs/plans/38.flow.md +155 -0
  47. package/docs/plans/39.multi.platform.bot.md +252 -0
  48. package/docs/plans/40.npm.publish.md +250 -0
  49. package/docs/plans/41.o.que.falta.md +407 -0
  50. package/docs/plans/42.pesquisa.concorrencia.md +721 -0
  51. package/docs/plans/43.plan.universal.architecture.md +496 -0
  52. package/docs/plans/44.reference.md +100 -0
  53. package/docs/plans/45.robotarchitecture.md +237 -0
  54. package/docs/plans/46.scdnintegration.md +284 -0
  55. package/docs/plans/47.multiforge.readme.md +129 -0
  56. package/docs/plans/48.theory.v4.repo.os.md +152 -0
  57. package/docs/plans/49.third.party.infra.md +12 -0
  58. package/docs/plans/50.file.as.compute.md +39 -0
  59. package/docs/plans/51.architecture.virtual.processor.md +80 -0
  60. package/docs/plans/52.manifesto.v8.md +11 -0
  61. package/docs/plans/58.cdn.list.md +23 -0
  62. package/docs/plans/59.sql.frameworks.md +33 -0
  63. package/docs/plans/60.sql.thirdparty.md +26 -0
  64. package/docs/plans/61.objective.multiforge.md +63 -0
  65. package/docs/plans/62.huggingface.upload.md +26 -0
  66. package/docs/plans/63.kaggle.upload.md +24 -0
  67. package/docs/plans/64.npm.storage.md +30 -0
  68. package/docs/plans/65.rclone.terabox.md +32 -0
  69. package/docs/plans/66.buckets.and.models.todo.md +14 -0
  70. package/docs/plans/67.database.todo.md +13 -0
  71. package/docs/plans/68.deploy.packages.todo.md +12 -0
  72. package/docs/plans/69.report.human.operator.md +133 -0
  73. package/docs/plans/70.report.brain2qwerty.ems.md +135 -0
  74. package/docs/plans/71.report.hd.infinito.vram.md +155 -0
  75. package/docs/plans/72.plan.hd.infinito.node.md +146 -0
  76. package/docs/plans/73.plan.scifi.repos.md +125 -0
  77. package/docs/plans/74.000.manifesto.v8.flat.2..md +11 -0
  78. package/docs/plans/README.md +489 -0
  79. package/docs/plans/aggregate_platforms.mjs +146 -0
  80. package/docs/plans/examplesession.json +36 -0
  81. package/docs/plans/missing-facts.md +192 -0
  82. package/docs/plans/models.md +64 -0
  83. package/docs/plans/organize.cjs +270 -0
  84. package/docs/plans/platforms.md +2887 -0
  85. package/docs/plans/sites.md +31322 -0
  86. package/docs/platformpipelineaudit.md +18 -0
  87. package/docs/platformpipelines.md +13 -0
  88. package/docs/registryresearch.md +4 -0
  89. package/docs/release.md +4 -4
  90. package/docs/release182notes.md +2 -0
  91. package/docs/release184notes.md +7 -0
  92. package/docs/release185notes.md +7 -0
  93. package/docs/sources/farm.py +117 -0
  94. package/docs/sources/html/saddle1.html +132 -0
  95. package/docs/sources/html/saddle2.html +157 -0
  96. package/docs/sources/html/saddle3.html +119 -0
  97. package/docs/sources/html/saddle4.html +144 -0
  98. package/docs/sources/html/saddle5.html +72 -0
  99. package/docs/sources/html/saddle6.html +171 -0
  100. package/docs/sources/html/saddle7.html +236 -0
  101. package/docs/sources/saddle.ts +74 -0
  102. package/docs/sources/schema.prisma +88 -0
  103. package/docs/sources/script.sh +64 -0
  104. package/docs/sources/workflows.yml +458 -0
  105. package/docs/talks1/_body.txt +14 -0
  106. package/docs/talks1/_index.md +15 -0
  107. package/docs/talks1/_screenshot.png +0 -0
  108. package/docs/talks1/assistant-01.md +5 -0
  109. package/docs/talks1/assistant-02.md +5 -0
  110. package/docs/talks1/assistant-03.md +531 -0
  111. package/docs/talks1/assistant-04.md +26 -0
  112. package/docs/talks1/assistant-05.md +774 -0
  113. package/docs/talks1/assistant-06.md +1718 -0
  114. package/docs/talks1/scrape-share.cjs +185 -0
  115. package/docs/talks1/scrape-share.ts +183 -0
  116. package/docs/talks1/user-01.md +3 -0
  117. package/docs/talks1/user-02.md +3 -0
  118. package/docs/talks1/user-03.md +88 -0
  119. package/docs/talks1/user-04.md +3 -0
  120. package/docs/talks1/user-05.md +3 -0
  121. package/docs/talks1/user-06.md +88 -0
  122. package/docs/talks1/user-07.md +88 -0
  123. package/docs/talks2/_body.txt +14 -0
  124. package/docs/talks2/_index.md +16 -0
  125. package/docs/talks2/_screenshot.png +0 -0
  126. package/docs/talks2/assistant-01.md +5 -0
  127. package/docs/talks2/assistant-02.md +5 -0
  128. package/docs/talks2/assistant-03.md +424 -0
  129. package/docs/talks2/assistant-04.md +598 -0
  130. package/docs/talks2/assistant-05.md +1280 -0
  131. package/docs/talks2/assistant-06.md +1227 -0
  132. package/docs/talks2/assistant-07.md +1252 -0
  133. package/docs/talks2/user-01.md +3 -0
  134. package/docs/talks2/user-02.md +3 -0
  135. package/docs/talks2/user-03.md +88 -0
  136. package/docs/talks2/user-04.md +88 -0
  137. package/docs/talks2/user-05.md +88 -0
  138. package/docs/talks2/user-06.md +88 -0
  139. package/docs/talks2/user-07.md +3 -0
  140. package/docs/talks3/_body.txt +467 -0
  141. package/docs/talks3/_index.md +10 -0
  142. package/docs/talks3/_screenshot.png +0 -0
  143. package/docs/talks3/assistant-01.md +417 -0
  144. package/docs/talks3/assistant-02.md +417 -0
  145. package/docs/talks3/assistant-03.md +29 -0
  146. package/docs/talks3/assistant-04.md +727 -0
  147. package/docs/talks3/user-01.md +88 -0
  148. package/docs/talks3/user-02.md +88 -0
  149. package/docs/talks3/user-03.md +3 -0
  150. package/docs/talks3/user-04.md +3 -0
  151. package/docs/talks4/_body.txt +14 -0
  152. package/docs/talks4/_index.md +12 -0
  153. package/docs/talks4/_screenshot.png +0 -0
  154. package/docs/talks4/assistant-01.md +5 -0
  155. package/docs/talks4/assistant-02.md +5 -0
  156. package/docs/talks4/assistant-03.md +35 -0
  157. package/docs/talks4/assistant-04.md +512 -0
  158. package/docs/talks4/assistant-05.md +599 -0
  159. package/docs/talks4/user-01.md +3 -0
  160. package/docs/talks4/user-02.md +3 -0
  161. package/docs/talks4/user-03.md +88 -0
  162. package/docs/talks4/user-04.md +88 -0
  163. package/docs/talks4/user-05.md +7 -0
  164. package/docs/talks5/_body.txt +14 -0
  165. package/docs/talks5/_index.md +13 -0
  166. package/docs/talks5/_screenshot.png +0 -0
  167. package/docs/talks5/assistant-01.md +5 -0
  168. package/docs/talks5/assistant-02.md +5 -0
  169. package/docs/talks5/assistant-03.md +690 -0
  170. package/docs/talks5/assistant-04.md +758 -0
  171. package/docs/talks5/assistant-05.md +974 -0
  172. package/docs/talks5/user-01.md +3 -0
  173. package/docs/talks5/user-02.md +3 -0
  174. package/docs/talks5/user-03.md +105 -0
  175. package/docs/talks5/user-04.md +105 -0
  176. package/docs/talks5/user-05.md +63 -0
  177. package/docs/talks5/user-06.md +105 -0
  178. package/docs/talks6/_body.txt +14 -0
  179. package/docs/talks6/_index.md +9 -0
  180. package/docs/talks6/_screenshot.png +0 -0
  181. package/docs/talks6/assistant-01.md +5 -0
  182. package/docs/talks6/assistant-02.md +5 -0
  183. package/docs/talks6/assistant-03.md +1499 -0
  184. package/docs/talks6/user-01.md +3 -0
  185. package/docs/talks6/user-02.md +3 -0
  186. package/docs/talks6/user-03.md +88 -0
  187. package/docs/talks6/user-04.md +88 -0
  188. package/docs/talks7/_body.txt +14 -0
  189. package/docs/talks7/_index.md +10 -0
  190. package/docs/talks7/_screenshot.png +0 -0
  191. package/docs/talks7/assistant-01.md +5 -0
  192. package/docs/talks7/assistant-02.md +5 -0
  193. package/docs/talks7/assistant-03.md +523 -0
  194. package/docs/talks7/assistant-04.md +617 -0
  195. package/docs/talks7/user-01.md +3 -0
  196. package/docs/talks7/user-02.md +3 -0
  197. package/docs/talks7/user-03.md +105 -0
  198. package/docs/talks7/user-04.md +67 -0
  199. package/docs/talks8/conversa1.txt +1322 -0
  200. package/docs/talks8/conversa2.txt +237 -0
  201. package/docs/talks9/Beyond the Obvious_ 50 Plataformas Auto-Hospedadas de Forja de C/303/263digo para Al/303/251m de Gitea e GitLab.md" +174 -0
  202. package/docs/talks9/De NPM a Multi-Linguagem_ Uma Arquitetura T/303/251cnica para a Execu/303/247/303/243o Integrada de C/303/263digo no Ecossistema Node.js.md" +59 -0
  203. package/docs/talks9/De NPM a VMs Virtuais_ Uma An/303/241lise Arquitet/303/264nica para a Realiza/303/247/303/243o do Ciclo de Vida do Projeto SADDLE.md" +91 -0
  204. package/docs/talks9/Mapeamento da Engrenagem Computacional_ Uma Arquitetura para Execu/303/247/303/243o Isolada e Persist/303/252ncia em Ambientes Distribu/303/255dos.md" +116 -0
  205. package/docs/talks9/O Cen/303/241rio Pr/303/241tico do SADDLE_ Uma An/303/241lise de Viabilidade e Modelo de Ciclo de Vida Integrado.md" +128 -0
  206. package/docs/talks9/README (2).md +489 -0
  207. package/docs/talks9/README.md +198 -0
  208. package/docs/talks9/Viabilidade do Saddle_ Uma An/303/241lise T/303/251cnica da Transforma/303/247/303/243o de Armazenamento Remoto em Mem/303/263ria Computacional.md" +80 -0
  209. package/docs/talks9/conversa.txt +544 -0
  210. package/docs/talks9/other (2).md +39 -0
  211. package/docs/talks9/other.md +57 -0
  212. package/docs/talks9/outro.txt +24 -0
  213. package/extension/README.md +3 -3
  214. package/extension/serviceworker.js +63 -4
  215. package/extension/worker.js +3 -1
  216. package/package.json +12 -2
  217. package/packager/manifest.js +1 -1
  218. package/scrape/agent.ts +122 -0
  219. package/scrape/batch.ts +79 -0
  220. package/scrape/biome.json +76 -0
  221. package/scrape/browser.ts +222 -0
  222. package/scrape/cache.ts +84 -0
  223. package/scrape/chunking.ts +193 -0
  224. package/scrape/cli.ts +105 -0
  225. package/scrape/crawler.ts +115 -0
  226. package/scrape/dev-server.ts +94 -0
  227. package/scrape/errors.ts +132 -0
  228. package/scrape/events.ts +26 -0
  229. package/scrape/extract.ts +165 -0
  230. package/scrape/fetch.ts +105 -0
  231. package/scrape/formats.ts +85 -0
  232. package/scrape/headers.ts +71 -0
  233. package/scrape/index.ts +92 -0
  234. package/scrape/jsdom.d.ts +6 -0
  235. package/scrape/llms-txt.ts +84 -0
  236. package/scrape/middleware.ts +90 -0
  237. package/scrape/package-lock.json +9397 -0
  238. package/scrape/package.json +1420 -0
  239. package/scrape/pool.ts +95 -0
  240. package/scrape/port.ts +18 -0
  241. package/scrape/proxy.ts +103 -0
  242. package/scrape/rate-limiter.ts +95 -0
  243. package/scrape/renderer.ts +194 -0
  244. package/scrape/retry.ts +64 -0
  245. package/scrape/robots.ts +137 -0
  246. package/scrape/scrape.ts +123 -0
  247. package/scrape/serialize.ts +310 -0
  248. package/scrape/server.ts +137 -0
  249. package/scrape/session.ts +109 -0
  250. package/scrape/sitemap.ts +131 -0
  251. package/scrape/tokens.ts +45 -0
  252. package/scrape/tsconfig.json +28 -0
  253. package/scrape/types.ts +214 -0
  254. package/scrape/utils.ts +77 -0
  255. package/scrape/vite.config.ts +55 -0
  256. package/scrape/vitest.config.ts +17 -0
  257. package/workflow/templates.js +4 -4
@@ -0,0 +1,39 @@
1
+
2
+ Então, por exemplo, a gente não só vai usar a sandbox, não vai só usar os frameworks, as bibliotecas de sandbox que já existem pra poder abrir um container Docker. A gente não só vai utilizar os próprios frameworks e bibliotecas que já existem pra abrir o Docker, mas o ponto principal é, o principal problema aqui é armazenamento. A gente tem várias estratégias de armazenamento. Nós temos os repos, nós temos os buckets, nós temos os datasets, nós temos essas plataformas que é o local onde a gente vai colocar a estrutura do armazenamento. A gente já tem local pra armazenar, então esse é o primeiro passo. A gente tem a segunda estratégia de armazenamento que a gente fazer um deploy na Vercel, na Netlify ou comprar um domínio e fazer a mesma coisa, e a gente colocar dentro do Prisma Schema, dentro do Drizzle ORM, que é, ou seja, que vai utilizar os frameworks de data, de banco de dados pra guardar o armazenamento lá. E, por exemplo, a gente pode upar um site parecido com o GitHub na Vercel, na Netlify, e aonde é que ele vai guardar esse armazenamento? Justamente no Drizzle ORM, justamente no Prisma Schema, justamente nesses frameworks que eles te dão essa possibilidade de você guardar armazenamento nas tabelas, né? E isso guardando no DB, no ponto DB, né, do próprio site. Cê tá entendendo? E onde é que a gente vai guardar esse ponto DB? Justamente no repo, porque assim, quando você faz um deploy na Netlify ou na Vercel, você tem que coligar o seu repositório, entendeu? E onde é que ele vai fazer, aonde é que ele vai guardar esse DB? Justamente no repositório, no repo. Porque o sistema da Vercel e da Netlify é assim, você linka o seu GitHub. Eu sou ventilado, e aí ele liga uma máquina virtual lá e deploya o site, entendeu? Então basicamente é isso.
3
+
4
+
5
+
6
+
7
+
8
+ Dessa lógica de vai tá na biblioteca, toda essa lógica vai tá sendo distribuída e vai tá sendo concluída e vai tá sendo, a biblioteca é o back-end de todo, a lógica é a própria lógica, então a biblioteca, ela literalmente tem toda a lógica pra que os front-ends, eles possam agir de forma séria. Então esse é o objetivo principal. Então a gente tem várias estratégias de armazenamento, as plataformas self-hosted, Forge, nós temos como deployar um site que ainda continua sendo dentro das plataformas Forge, porque a Netlify não vai ser, ele tem que linkar o seu GitHub pra você poder subir um site, certo? De qualquer forma ainda continua sendo o GitHub, GitLab como maneira de armazenar. Então se dá pra fazer isso, a gente dá pra coisar. Outra coisa, a gente tem outra possibilidade. Como a gente consegue subir sites na Vercel ou na Netlify, a gente pode subir a cada máquina virtual que for sancionada, a gente sobe um site que é o site da sandbox, que é justamente o endereço onde a sandbox, ela vai tá agindo. Ou a gente pode fazer isso de forma isolada, que é justamente só se alimentando da biblioteca, certo? Porque assim, é só uma ideia, a gente pode, por exemplo, a pessoa solicitou, ela começou uma nova conversa de chat, aí ele abriu uma nova sandbox. Cada nova sandbox é um link novo da Netlify, isso é uma sugestão. Que aí cada site tem o seu próprio DB, seu próprio Drizzle ORM, seu próprio Prisma, e lá ele consegue salvar todos os dados fazendo a conexão tudo direitinho. Ou seja, esse site, que é o primeiro site, é quando ele um container novo, é na realidade um outro site que já tá pronto pra rodar como container, de memória infinita e tudo mais, entendeu? Ou a gente pode, por exemplo, usar, em vez de fazer deploy, a gente faz o, em vez de fazer deploy na Vercel, né, a gente faz deploy só no GitHub ou só no Source, ou então a gente faz, deixa já os sites prontos e aí ele só salva nesses outros sites, ou ele salva diretamente no repositório da pessoa, né, no repositório que ele autorizar, ou ele publica o site ou ele publica só no repositório que a pessoa autorizar, certo? Ou ele manda pra algum banco de dados de alguns desses sites deployados ou então faz essa estratégia de cada container é um site que vai ser deployado, certo? Na conta da pessoa, porque como a gente vai ter o próprio, como a gente vai ser um app dentro do GitHub, um bot dentro do GitHub, dentro do GitLab, a gente pode fazer a cada coisa que ele fizer é um site deployado no Vercel, onde cujo armazenamento ainda vai estar no GitHub e no GitLab, porque pra fazer o deploy de algum site na Vercel, na Netlify, tem que passar pelo GitHub, pelo GitLab, tem que conectar o repo.
9
+
10
+
11
+
12
+
13
+ Também claro, a gente tem várias estratégias de armazenamento. Nós temos a primeira estratégia que é os forges, que é o primordial, os forges, GitHub, GitLab, Forgejo, Gitea, enfim. A segunda é através da publicação de npm packages, então a gente tem a possibilidade de guardar isso em npm packages, certo? A terceira é a gente fazer deploy em sites na Vercel, na Netlify, que ainda assim dependem da primeira estratégia, que a Netlify faz a mesma coisa e a Vercel faz a mesma, depende do repositório. A quarta estratégia, a gente tem como guardar isso em memória interna, dentro da própria biblioteca, graças a pacotes como Drizzle ORM, Prisma e memória interna, enfim, etc., guardado dentro da própria biblioteca, certo? Ele só precisa ter um alvo pra poder criar um... e basicamente é isso. E como essa biblioteca vai ser, tá sendo guardada nos forges, na primeira, que é a primeira estratégia de armazenamento, que é os forges, que é GitLab, GitHub, então todos os dados vão para o repositório do GitHub, GitLab, certo?
14
+
15
+
16
+
17
+ E tem duas distinções de armazenamento. Nós temos armazenar a biblioteca em si, toda a biblioteca, toda a lógica, e quando a gente tiver com a biblioteca pronta, a gente vai armazenar o sistema, que pode ser a biblioteca em si, mas também a gente pode, por exemplo, deployar num repositório, jogar todo um Linux, todo um sistema Linux ou iniciar todo um sistema Linux dentro do repositório, ou então, iniciar todo um Docker dentro de um repositório distinto, dentro de outro repositório distinto, ou a gente pode ligar o Docker do Seddle, certo? Que causa o mesmo efeito, mas como tem várias estratégias, que é o seguinte, tem o armazenamento dos sistemas, dos containers, que tem que ter um sistema operacional que pode ser feito pela própria Sed. Certo? E tem também a questão dele poder ser separado, ou seja, cada repo tem uma cópia do Ubuntu e lá uma cópia de qualquer distro como sistema operacional, e lá a gente faz a brincadeira, ou a gente, cada repo independente, né, criado novo, tem um Ubuntu ou é ligado um novo Docker, ou é ligado um novo runner. Por isso das pipelines estarem na lógica da biblioteca, porque a gente tem várias opções, a gente pode agir com uma biblioteca unipotente que salva tudo, porque já que tudo tá sendo salvo no repo público do Sedol, então é pra lá que a gente vai fazer. Ou a gente pode, na lógica, abrir outros repos, certo? E basicamente isso. Então assim, tem o Docker, tem a imagem, tem os pacotes, os tipos de pacotes, basicamente é isso.
18
+
19
+
20
+
21
+
22
+ E veja bem, nós temos a lógica que executa o runner, né, porque não adianta nada a gente ter os arquivos, os arquivos nos repositórios, né, seja cópia de distro, seja fazer uma importação de Docker, ou seja a própria biblioteca dentro do Forge, não adianta nada se a gente fizer rodar, como é o princípio, né, que é computacional. Então, o primeiro passo é, a gente vai deployar um site e esse site vai se servir dessas lógicas da biblioteca. Como a gente vai publicar o pacote, então já vai ficar meio fácil, que esse pacote também vai tá sendo deployado no GitHub, no GitLab, nos pacotes como no Maven, no Get e etc. E basicamente é isso. Então assim, vai ser um pacote publicado no NPM e um pacote publicado nos Forges. E tem a outra estratégia, que é a distro. Pode tá sendo deployada em cada repo com a autorização do usuário ou não. Se ele não autorizar, aí a gente vai usar as estratégias de armazenamento que a gente tem pra armazenar essas distros ou pra executar essas distros. Por isso que eu falei, tem dois caminhos, ou pegar o que tá pronto ou fazer do zero pra poder tá pronto. Por exemplo, a gente tem o local de onde armazenar isso, todos esses buckets, todas essas plataformas e etc. A gente tem o runner, que é o quê? Que é a biblioteca. E a gente tem o site, que pode também vir. Então assim, em todo lugar, tudo tem que ter um trigger, tudo tem que ter um cron job. A biblioteca ela tem um cron job automático, o site que depende da biblioteca tem um trigger que também executa as tarefas sozinho, e basicamente é isso. E os pacotes também, o dock e tudo mais.
23
+
24
+
25
+
26
+
27
+
28
+ Então assim ó, imagina assim, no Android a gente tem o hardware, certo? E o sistema dele, como você pode perceber no sistema Android ou em qualquer sistema, ele tem pasta dentro de pasta dentro de pasta. Por exemplo, no Ubuntu ele costuma usar tree, no Android ele também costuma usar tree. Então, onde é que a gente vai implantar esse armazenamento todo? Justamente nos repos. Cê tá entendendo? É justamente nesses sites que dão repositórios, que dão buckets, que dão datasets, e aí a gente vai, por exemplo, botar o sistema operacional aí pra rodar, cê tá entendendo? Outra coisa. Uma coisa, é nesses mesmos aí que a gente vai usar pra fazer computação, é, porque como a gente vai alocar o sistema, por exemplo, a gente vai alocar o Ubuntu, a gente vai alocar, por exemplo, o Windows dentro do repositório, ou a gente vai fazer ele rodar, né, porque os arquivos, o local da gente põe os arquivos do sistema a gente já tem, e aí ele vai sempre puxar disso. Ou a gente pode usar o Docker, né, a imagem do Docker com os runners, certo? Então, isso que eu falei, a gente não vai só utilizar a capacidade de borda computacional dos scripts, das pipelines, do N8N, do GitHub, do GitLab, do Forgejo, etc. A gente também vai fazer isso de forma manual, que é a gente criando os arquivos e upando eles nos repositórios e fazendo a mesma coisa que o GitHub Actions faz, porque a gente vai fazer a mesma coisa. O GitHub Actions pra ele funcionar, ele tem toda uma infraestrutura por trás que tá rodando nos servidores dele, certo? Só que a diferença é que a gente vai tá rodando dentro dos repos, cê tá entendendo? Como virtual processor, virtual file. Então, por exemplo, o GitHub, pra ele poder rodar, ele tem que pescar do servidor dele e a gente vai pescar dos repos, cê tá entendendo? Por exemplo, pra ele poder rodar um runner, ele realmente tem uma máquina virtual ligada lá no servidor. Em vez disso, a gente tem o quê? Tem o repo com o sistema que vai rodar e através de muita codificação do framework Node, a gente vai fazer isso funcionar. Então, por exemplo, a gente não vai usar só a computação de borda, vai utilizar o armazenamento deles pra transformar em armazenamento de borda, pra gente poder copiar o mesmo processo. E muitas vezes a gente também vai usar as pipelines, as imagens em Docker e etc. Os frameworks etc, cê tá entendendo? Então assim, o processamento de borda não vai depender só das pipelines do GitHub ou do Slack do Forge, vai depender da gente fazer o deploy ou eu fazer o deploy desses sistemas manualmente ou dessa codificação manualmente, nesses buckets, nesses repositórios, nesses datasets, e aí, a partir daí a gente cria uma comunicação de API que consegue rodar, cê tá entendendo? Puxando dos locais que a gente quer. Por exemplo, nós temos os sites que a gente mesmo pode fazer o deploy no Netlify, na Vercel, ou a gente compra um domínio e faz o deploy do site e cada site tem um Drizzle ORM, cada site tem um Prisma Schema. Então a gente pode guardar não o armazenamento só nos repos do GitHub, mas nos repos dos sites deployados, dentro do Prisma Schema, dentro do Drizzle ORM, dentro desse framework.
29
+
30
+
31
+
32
+
33
+
34
+
35
+
36
+
37
+ Installed GitHub Apps
38
+ Authorized GitHub Apps
39
+ Authorized OAuth Apps Você colocar aí no readme que ele é um bot de Discord, de GitHub, GitLab, ele é essas três categorias, só pra você dizer que ele é um GitHub app, ou GitLab app, ou Forejo app, enfim, todas essas plataformas aí ele é um app ou um bot, é, authorized app ou um bot, cê tá entendendo? E ele é também um authorized ou auth app, né, que também é um bot, pra todas essas plataformas aí.
@@ -0,0 +1,57 @@
1
+ Vai ter múltiplo uso de cron jobs, de triggers, enfim, a inteligência que o código vai ser inteligente, vai ter muito uso de trigger, de cron job, de automação, etc, etc.
2
+
3
+
4
+
5
+ Então, faltou dizer que ele vai usar pacotes externos de terceiros, como por exemplo o Webpack, como por exemplo o PMP, Manager, ele vai utilizar engines, ele vai utilizar package manager, ele vai utilizar basicamente isso no seu package JSON. E como eu falei, ele vai utilizar a PMP, PNPN, e outros pacotes utilitários como o Webpack, e outros pacotes externos para ajudar. Ele também vai utilizar pacotes de agente browsers que já funcionam, como por exemplo o agente o próprio agente browser da Vercel, como o Fallback. Mas ele também vai ser o próprio. Então assim, todas essas instâncias ele vai ser o próprio e ele vai usar dependências de terceiros. Você está entendendo? para dar uma otimizada, para melhorar e etc. Mas ele também vai ser o próprio dessas instâncias, certo? EEntão assim, ele vai ter que usar o webpac, ele vai ter que usar outros pacotes, ele vai ter que usar todos os pacotes nativos do Node. Vai ter que usar pacotes externos de terceiros que não são nativos do Node. Então basicamente é isso. Ele também vai usar a mentira os pacotes de OCR externos vai ser o próprio pacote de OCR de OCR, mas também vai usar pacotes e bibliotecas de OCR externa de Reg, de Reg, Reg, R-A-G, R-A-G, vai utilizar também não só pacotes para essas tarefas vai utilizar também runners, vai utilizar pacotes por exemplo da Cloudflare, vai utilizar outros excelentíssimos pacotes, não só os novos, mas os emergentes, mas os nativos, para esse tipo de tarefa. Ele vai ser o próprio e vai utilizar bibliotecas externas. Além disso, ele também vai executar vai executar, por exemplo, outros frameworks por causa do bridge dele. Então, por exemplo, ele vai utilizar pacotes que rodam, por exemplo, Python, que rodam, por exemplo, C++, que rodam, por exemplo, Rust, que rodam, por exemplo, outras linguagens de baixo nível, além de Python, através do Node. Por isso que eu falei, Bridge. Você está entendendo? Então, basicamente é isso. Vai utilizar de pacotes e vai utilizar da própria lógica também para rodar outros frameworks e outras linguagens se precisar. Você está entendendo? Basicamente é isso.
6
+
7
+
8
+
9
+
10
+
11
+
12
+
13
+
14
+
15
+
16
+
17
+
18
+
19
+
20
+ Então, por exemplo, a gente não só vai usar a sandbox, não vai só usar os frameworks, as bibliotecas de sandbox que já existem pra poder abrir um container Docker. A gente não só vai utilizar os próprios frameworks e bibliotecas que já existem pra abrir o Docker, mas o ponto principal é, o principal problema aqui é armazenamento. A gente tem várias estratégias de armazenamento. Nós temos os repos, nós temos os buckets, nós temos os datasets, nós temos essas plataformas que é o local onde a gente vai colocar a estrutura do armazenamento. A gente já tem local pra armazenar, então esse é o primeiro passo. A gente tem a segunda estratégia de armazenamento que a gente fazer um deploy na Vercel, na Netlify ou comprar um domínio e fazer a mesma coisa, e a gente colocar dentro do Prisma Schema, dentro do Drizzle ORM, que é, ou seja, que vai utilizar os frameworks de data, de banco de dados pra guardar o armazenamento lá. E, por exemplo, a gente pode upar um site parecido com o GitHub na Vercel, na Netlify, e aonde é que ele vai guardar esse armazenamento? Justamente no Drizzle ORM, justamente no Prisma Schema, justamente nesses frameworks que eles te dão essa possibilidade de você guardar armazenamento nas tabelas, né? E isso guardando no DB, no ponto DB, né, do próprio site. Cê tá entendendo? E onde é que a gente vai guardar esse ponto DB? Justamente no repo, porque assim, quando você faz um deploy na Netlify ou na Vercel, você tem que coligar o seu repositório, entendeu? E onde é que ele vai fazer, aonde é que ele vai guardar esse DB? Justamente no repositório, no repo. Porque o sistema da Vercel e da Netlify é assim, você linka o seu GitHub. Eu sou ventilado, e aí ele liga uma máquina virtual lá e deploya o site, entendeu? Então basicamente é isso.
21
+
22
+
23
+
24
+
25
+
26
+ Dessa lógica de vai tá na biblioteca, toda essa lógica vai tá sendo distribuída e vai tá sendo concluída e vai tá sendo, a biblioteca é o back-end de todo, a lógica é a própria lógica, então a biblioteca, ela literalmente tem toda a lógica pra que os front-ends, eles possam agir de forma séria. Então esse é o objetivo principal. Então a gente tem várias estratégias de armazenamento, as plataformas self-hosted, Forge, nós temos como deployar um site que ainda continua sendo dentro das plataformas Forge, porque a Netlify não vai ser, ele tem que linkar o seu GitHub pra você poder subir um site, certo? De qualquer forma ainda continua sendo o GitHub, GitLab como maneira de armazenar. Então se dá pra fazer isso, a gente dá pra coisar. Outra coisa, a gente tem outra possibilidade. Como a gente consegue subir sites na Vercel ou na Netlify, a gente pode subir a cada máquina virtual que for sancionada, a gente sobe um site que é o site da sandbox, que é justamente o endereço onde a sandbox, ela vai tá agindo. Ou a gente pode fazer isso de forma isolada, que é justamente só se alimentando da biblioteca, certo? Porque assim, é só uma ideia, a gente pode, por exemplo, a pessoa solicitou, ela começou uma nova conversa de chat, aí ele abriu uma nova sandbox. Cada nova sandbox é um link novo da Netlify, isso é uma sugestão. Que aí cada site tem o seu próprio DB, seu próprio Drizzle ORM, seu próprio Prisma, e lá ele consegue salvar todos os dados fazendo a conexão tudo direitinho. Ou seja, esse site, que é o primeiro site, é quando ele um container novo, é na realidade um outro site que já tá pronto pra rodar como container, de memória infinita e tudo mais, entendeu? Ou a gente pode, por exemplo, usar, em vez de fazer deploy, a gente faz o, em vez de fazer deploy na Vercel, né, a gente faz deploy só no GitHub ou só no Source, ou então a gente faz, deixa já os sites prontos e aí ele só salva nesses outros sites, ou ele salva diretamente no repositório da pessoa, né, no repositório que ele autorizar, ou ele publica o site ou ele publica só no repositório que a pessoa autorizar, certo? Ou ele manda pra algum banco de dados de alguns desses sites deployados ou então faz essa estratégia de cada container é um site que vai ser deployado, certo? Na conta da pessoa, porque como a gente vai ter o próprio, como a gente vai ser um app dentro do GitHub, um bot dentro do GitHub, dentro do GitLab, a gente pode fazer a cada coisa que ele fizer é um site deployado no Vercel, onde cujo armazenamento ainda vai estar no GitHub e no GitLab, porque pra fazer o deploy de algum site na Vercel, na Netlify, tem que passar pelo GitHub, pelo GitLab, tem que conectar o repo.
27
+
28
+
29
+
30
+
31
+ Também claro, a gente tem várias estratégias de armazenamento. Nós temos a primeira estratégia que é os forges, que é o primordial, os forges, GitHub, GitLab, Forgejo, Gitea, enfim. A segunda é através da publicação de npm packages, então a gente tem a possibilidade de guardar isso em npm packages, certo? A terceira é a gente fazer deploy em sites na Vercel, na Netlify, que ainda assim dependem da primeira estratégia, que a Netlify faz a mesma coisa e a Vercel faz a mesma, depende do repositório. A quarta estratégia, a gente tem como guardar isso em memória interna, dentro da própria biblioteca, graças a pacotes como Drizzle ORM, Prisma e memória interna, enfim, etc., guardado dentro da própria biblioteca, certo? Ele só precisa ter um alvo pra poder criar um... e basicamente é isso. E como essa biblioteca vai ser, tá sendo guardada nos forges, na primeira, que é a primeira estratégia de armazenamento, que é os forges, que é GitLab, GitHub, então todos os dados vão para o repositório do GitHub, GitLab, certo?
32
+
33
+
34
+
35
+ E tem duas distinções de armazenamento. Nós temos armazenar a biblioteca em si, toda a biblioteca, toda a lógica, e quando a gente tiver com a biblioteca pronta, a gente vai armazenar o sistema, que pode ser a biblioteca em si, mas também a gente pode, por exemplo, deployar num repositório, jogar todo um Linux, todo um sistema Linux ou iniciar todo um sistema Linux dentro do repositório, ou então, iniciar todo um Docker dentro de um repositório distinto, dentro de outro repositório distinto, ou a gente pode ligar o Docker do Seddle, certo? Que causa o mesmo efeito, mas como tem várias estratégias, que é o seguinte, tem o armazenamento dos sistemas, dos containers, que tem que ter um sistema operacional que pode ser feito pela própria Sed. Certo? E tem também a questão dele poder ser separado, ou seja, cada repo tem uma cópia do Ubuntu e lá uma cópia de qualquer distro como sistema operacional, e lá a gente faz a brincadeira, ou a gente, cada repo independente, né, criado novo, tem um Ubuntu ou é ligado um novo Docker, ou é ligado um novo runner. Por isso das pipelines estarem na lógica da biblioteca, porque a gente tem várias opções, a gente pode agir com uma biblioteca unipotente que salva tudo, porque já que tudo tá sendo salvo no repo público do Sedol, então é pra lá que a gente vai fazer. Ou a gente pode, na lógica, abrir outros repos, certo? E basicamente isso. Então assim, tem o Docker, tem a imagem, tem os pacotes, os tipos de pacotes, basicamente é isso.
36
+
37
+
38
+
39
+
40
+ E veja bem, nós temos a lógica que executa o runner, né, porque não adianta nada a gente ter os arquivos, os arquivos nos repositórios, né, seja cópia de distro, seja fazer uma importação de Docker, ou seja a própria biblioteca dentro do Forge, não adianta nada se a gente fizer rodar, como é o princípio, né, que é computacional. Então, o primeiro passo é, a gente vai deployar um site e esse site vai se servir dessas lógicas da biblioteca. Como a gente vai publicar o pacote, então já vai ficar meio fácil, que esse pacote também vai tá sendo deployado no GitHub, no GitLab, nos pacotes como no Maven, no Get e etc. E basicamente é isso. Então assim, vai ser um pacote publicado no NPM e um pacote publicado nos Forges. E tem a outra estratégia, que é a distro. Pode tá sendo deployada em cada repo com a autorização do usuário ou não. Se ele não autorizar, aí a gente vai usar as estratégias de armazenamento que a gente tem pra armazenar essas distros ou pra executar essas distros. Por isso que eu falei, tem dois caminhos, ou pegar o que tá pronto ou fazer do zero pra poder tá pronto. Por exemplo, a gente tem o local de onde armazenar isso, todos esses buckets, todas essas plataformas e etc. A gente tem o runner, que é o quê? Que é a biblioteca. E a gente tem o site, que pode também vir. Então assim, em todo lugar, tudo tem que ter um trigger, tudo tem que ter um cron job. A biblioteca ela tem um cron job automático, o site que depende da biblioteca tem um trigger que também executa as tarefas sozinho, e basicamente é isso. E os pacotes também, o dock e tudo mais.
41
+
42
+
43
+
44
+
45
+
46
+ Então assim ó, imagina assim, no Android a gente tem o hardware, certo? E o sistema dele, como você pode perceber no sistema Android ou em qualquer sistema, ele tem pasta dentro de pasta dentro de pasta. Por exemplo, no Ubuntu ele costuma usar tree, no Android ele também costuma usar tree. Então, onde é que a gente vai implantar esse armazenamento todo? Justamente nos repos. Cê tá entendendo? É justamente nesses sites que dão repositórios, que dão buckets, que dão datasets, e aí a gente vai, por exemplo, botar o sistema operacional aí pra rodar, cê tá entendendo? Outra coisa. Uma coisa, é nesses mesmos aí que a gente vai usar pra fazer computação, é, porque como a gente vai alocar o sistema, por exemplo, a gente vai alocar o Ubuntu, a gente vai alocar, por exemplo, o Windows dentro do repositório, ou a gente vai fazer ele rodar, né, porque os arquivos, o local da gente põe os arquivos do sistema a gente já tem, e aí ele vai sempre puxar disso. Ou a gente pode usar o Docker, né, a imagem do Docker com os runners, certo? Então, isso que eu falei, a gente não vai só utilizar a capacidade de borda computacional dos scripts, das pipelines, do N8N, do GitHub, do GitLab, do Forgejo, etc. A gente também vai fazer isso de forma manual, que é a gente criando os arquivos e upando eles nos repositórios e fazendo a mesma coisa que o GitHub Actions faz, porque a gente vai fazer a mesma coisa. O GitHub Actions pra ele funcionar, ele tem toda uma infraestrutura por trás que tá rodando nos servidores dele, certo? Só que a diferença é que a gente vai tá rodando dentro dos repos, cê tá entendendo? Como virtual processor, virtual file. Então, por exemplo, o GitHub, pra ele poder rodar, ele tem que pescar do servidor dele e a gente vai pescar dos repos, cê tá entendendo? Por exemplo, pra ele poder rodar um runner, ele realmente tem uma máquina virtual ligada lá no servidor. Em vez disso, a gente tem o quê? Tem o repo com o sistema que vai rodar e através de muita codificação do framework Node, a gente vai fazer isso funcionar. Então, por exemplo, a gente não vai usar só a computação de borda, vai utilizar o armazenamento deles pra transformar em armazenamento de borda, pra gente poder copiar o mesmo processo. E muitas vezes a gente também vai usar as pipelines, as imagens em Docker e etc. Os frameworks etc, cê tá entendendo? Então assim, o processamento de borda não vai depender só das pipelines do GitHub ou do Slack do Forge, vai depender da gente fazer o deploy ou eu fazer o deploy desses sistemas manualmente ou dessa codificação manualmente, nesses buckets, nesses repositórios, nesses datasets, e aí, a partir daí a gente cria uma comunicação de API que consegue rodar, cê tá entendendo? Puxando dos locais que a gente quer. Por exemplo, nós temos os sites que a gente mesmo pode fazer o deploy no Netlify, na Vercel, ou a gente compra um domínio e faz o deploy do site e cada site tem um Drizzle ORM, cada site tem um Prisma Schema. Então a gente pode guardar não o armazenamento só nos repos do GitHub, mas nos repos dos sites deployados, dentro do Prisma Schema, dentro do Drizzle ORM, dentro desse framework.
47
+
48
+
49
+
50
+
51
+
52
+
53
+
54
+
55
+ Installed GitHub Apps
56
+ Authorized GitHub Apps
57
+ Authorized OAuth Apps Você colocar aí no readme que ele é um bot de Discord, de GitHub, GitLab, ele é essas três categorias, só pra você dizer que ele é um GitHub app, ou GitLab app, ou Forejo app, enfim, todas essas plataformas aí ele é um app ou um bot, é, authorized app ou um bot, cê tá entendendo? E ele é também um authorized ou auth app, né, que também é um bot, pra todas essas plataformas aí.
@@ -0,0 +1,24 @@
1
+
2
+ - [ ] Oferecer acesso ao destinatário sem configurações adicionais por meio de PWA com Service Worker, Mini App do Telegram, extensão nativa para navegadores e subdomínios de ponte do gateway.
3
+
4
+
5
+ - [ ] Registrar domínios de ápice reais utilizando extensões gratuitas como pp.ua, eu.org e no.kg ou TLDs comerciais acessíveis como .eu, .fr e .tech.
6
+ - [ ] Configurar servidores autoritativos de ponte DNS com suporte a Anycast, DNSSEC e gerenciamento por API através das plataformas deSEC (desec.io) e public-adns.
7
+
8
+ - [ ] Agregar provedores de armazenamento em nuvem para a camada de memória usando Cloudflare R2, Amazon S3 ou Backblaze B2 com suporte a leituras por intervalo (ranged GET) e cota gratuita de 10 GB, HuggingFace Hub para datasets e modelos via API, repositórios Git LFS via GitHub e Forgejo com limites de arquivo de 100 MB, e Terabox.
9
+ - [ ] Implementar mecanismo de exposição para o motor de inferência C kimi-k3 utilizando o plug-in nativo K3ExpertSrc com leitor de tronco para requisições get e getmany, sistema de arquivos virtual FUSE ou dispositivo de bloco virtual com pread e O_DIRECT, ou arquitetura híbrida de leitura contígua.
10
+
11
+ - [ ] Estruturar a entrega da plataforma iniciando pelo núcleo da biblioteca de memória virtual, avançando para documentos de arquitetura com protótipos spike, interfaces web acopladas a APIs de inferência e solução completa ponta a ponta.
12
+ - [ ] Configurar ambientes sandbox para execução de código por agentes de inteligência artificial, ambientes integrados de desenvolvimento para programadores, plataformas SaaS multiusuário e execuções temporárias efêmeras.
13
+ - [ ] Executar o motor de processamento em instâncias dedicadas NVMe com 8 GB ou mais de RAM em provedores como Hetzner, Render, Fly.io e Railway, utilizando ambientes serverless no Vercel ou Netlify, máquinas locais, contêineres Docker e instâncias gratuitas de CI no GitHub Actions, Kaggle e Codeberg com Woodpecker.
14
+ - [ ] Aplicar isolamento de execução com contêineres Docker, microVMs Firecracker sob KVM com baixo overhead, modelo híbrido alternando entre desenvolvimento e produção, e isolamento direto no kernel via HiveBox e LXC.
15
+ - [ ] Desenvolver APIs e orquestradores em TypeScript e Node.js com Drizzle ORM, Python com FastAPI, Rust para binários consolidados de alta performance ou Go para infraestrutura.
16
+ - [ ] Selecionar imagens de execução CPU no Alibaba Cloud PAI-DSW equipadas com 8 cores e 32 GB de RAM, abrangendo ambientes Ubuntu 22.04 com Python 3.11 e PyTorch 2.3.1, Ubuntu 20.04 com Python 3.8, PyTorch 2.0.1 e TensorFlow 1.15.5, Ubuntu 20.04 com Python 3.7 e PyTorch 1.11.0, e Ubuntu 20.04 com Python 3.10 e PaddlePaddle 3.0.0.
17
+ - [ ] Utilizar imagens de execução GPU no Alibaba Cloud PAI-DSW equipadas com 8 cores, 32 GB de RAM e 24 GB de VRAM sob cota de 36 horas, contemplando Ubuntu 22.04 com CUDA 12.8.1, Python 3.11 e PyTorch 2.9.1; Ubuntu 22.04 com CUDA 12.1.0, Python 3.11, PyTorch 2.3.1 e TensorFlow 2.16.1; Ubuntu 22.04 com CUDA 12.1.0, Python 3.10 e PyTorch 2.3.0; Ubuntu 20.04 com CUDA 11.7.1, Python 3.8, PyTorch 2.0.1 e TensorFlow 1.15.5; Ubuntu 20.04 com CUDA 11.3.0, Python 3.7 e PyTorch 1.11.0; e Ubuntu 20.04 com CUDA 12.3, TensorRT 8.6, Python 3.10 e PaddlePaddle 3.0.0.
18
+
19
+ - [ ] Hospedar o código-fonte em repositórios públicos no GitHub, GitLab.com, instâncias auto-hospedadas do Forgejo ou Gitea, Codeberg e infraestruturas com espelhamento automatizado entre plataformas.
20
+ - [ ] Operar módulos de interface e gerenciamento Git abrangendo painéis de compilação com pipelines, tarefas, agendamentos e artefatos, configurações gerais de sistema com serviços, integradores, webhooks, tokens de acesso, controle de repositórios, solicitações de mesclagem, registros de pacotes e monitoramento de cotas de uso.
21
+ - [ ] Gerenciar ambientes de operação e implantação com suporte a clusters Kubernetes, arquivos de estado e módulos do Terraform, conexões Google Cloud, implantações paralelas, serviços de páginas e armazenamento estático.
22
+
23
+ - [ ] Gerenciar parque de 60 máquinas através de CronJobs agendados em Kubernetes, scripts automatizados de bootstrap via cron ou systemd em nós bare metal e rotinas disparadas por runners de CI/CD no Forgejo Actions ou GitLab CI.
24
+ - [ ] Executar cargas de mineração adequadas ao limite de 2 GB de VRAM priorizando mineradores GPU como gminer e lolMiner, mantendo chaveamento e suporte automático para processamento secundário em CPU.
@@ -14,14 +14,14 @@ The manifest requests only `activeTab`, `scripting` and `storage`. It does not r
14
14
 
15
15
  ## boundaries
16
16
 
17
- The content bridge runs in Chrome's isolated world. It exposes bounded page metadata, visible text, stable references and user initiated click or fill commands. The service worker forwards versioned messages and stores only the latest snapshot metadata in session storage. No endpoint, credential, remote script or browser profile is embedded.
17
+ The content bridge runs in Chrome's isolated world. It exposes bounded page metadata, visible text, stable references and user initiated click or fill commands. The service worker forwards versioned messages, persists bounded pending command records and stores the latest snapshot metadata in session storage. Rehydration is explicit; startup never replays a command without a caller action. No endpoint, credential, remote script or browser profile is embedded.
18
18
 
19
19
  `protocol.js` and `serviceworker.js` are reusable ESM contracts. `content.js` is intentionally a classic injected file because programmatic Chrome content scripts are loaded as files; it exposes a small global bridge and avoids arbitrary page JavaScript evaluation.
20
20
 
21
21
  ## deterministic release artifact
22
22
 
23
- The Node-only build adapter creates an isolated unpacked artifact with the release version in its manifest. A caller can run `npm run extension:build -- --version 1.8.1 --output build/extension` and package that directory with the archive tool available in the host environment. The release workflow derives the version from the published tag and attaches `saddle-extension-<version>.zip` without changing the source manifest.
23
+ The Node-only build adapter creates an isolated unpacked artifact with the release version in its manifest. A caller can run `npm run extension:build -- --version 1.8.2 --output build/extension` and package that directory with the archive tool available in the host environment. The release workflow derives the version from the published tag and attaches `saddle-extension-<version>.zip` without changing the source manifest.
24
24
 
25
25
  ## next slices
26
26
 
27
- The next extension slices should add snapshot diffing, tab and frame identity, resumable command records, optional host permission escalation and browser action results. Browser providers, login profiles, captcha solvers and remote runners remain caller owned adapters.
27
+ The next extension slices should add snapshot diffing, richer tab and frame metadata, optional host permission escalation and browser action results. Browser providers, login profiles, captcha solvers and remote runners remain caller owned adapters.
@@ -11,7 +11,9 @@ export function createworkerrouter(options = {}) {
11
11
  const storage = options.storage;
12
12
  const contentfile = options.contentfile ?? "content.js";
13
13
  const statekey = options.statekey ?? "saddleextensionstate";
14
+ const maxpending = options.maxpending ?? 32;
14
15
  if (typeof tabs?.sendMessage !== "function") throw new TypeError("extension router requires tabs.sendMessage");
16
+ if (!Number.isSafeInteger(maxpending) || maxpending < 1) throw new TypeError("extension router maxpending must be a positive safe integer");
15
17
 
16
18
  async function ensurecontent(tabid) {
17
19
  if (!Number.isInteger(tabid)) throw new TypeError("extension command requires a tab id");
@@ -29,15 +31,72 @@ export function createworkerrouter(options = {}) {
29
31
  if (typeof storage?.set === "function") await storage.set({ [statekey]: value });
30
32
  }
31
33
 
34
+ async function pendingstate() {
35
+ const value = await readstate();
36
+ return { ...value, pending: Array.isArray(value.pending) ? value.pending.filter(validpending) : [] };
37
+ }
38
+
39
+ async function enqueue(request, sender) {
40
+ const state = await pendingstate();
41
+ const record = pendingrecord(request, sender);
42
+ const pending = state.pending.filter((item) => item.requestid !== record.requestid);
43
+ if (pending.length >= maxpending && !state.pending.some((item) => item.requestid === record.requestid)) throw extensionerror("PENDING_LIMIT", "extension pending command limit reached");
44
+ pending.push(record);
45
+ await savestate({ ...state, pending });
46
+ return record;
47
+ }
48
+
49
+ async function complete(requestid, patch = {}) {
50
+ const state = await pendingstate();
51
+ await savestate({ ...state, ...patch, pending: state.pending.filter((item) => item.requestid !== requestid) });
52
+ }
53
+
54
+ async function markfailure(requestid, error) {
55
+ const state = await pendingstate();
56
+ const pending = state.pending.map((item) => item.requestid === requestid ? { ...item, attempts: item.attempts + 1, lasterror: { code: String(error?.code ?? "extension_error"), message: String(error?.message ?? error) }, updatedat: Date.now() } : item);
57
+ await savestate({ ...state, pending });
58
+ }
59
+
60
+ async function dispatch(request, sender = {}) {
61
+ const tabid = request.payload?.tabid ?? sender.tab?.id;
62
+ await ensurecontent(tabid);
63
+ return tabs.sendMessage(tabid, request);
64
+ }
65
+
32
66
  async function handle(message, sender = {}) {
33
67
  const request = assertmessage(message);
34
68
  if (request.type !== "command") throw new TypeError("extension router accepts commands only");
35
69
  const tabid = request.payload?.tabid ?? sender.tab?.id;
36
- await ensurecontent(tabid);
37
- const response = await tabs.sendMessage(tabid, request);
38
- if (response?.type === "response" && response.payload?.snapshotid) await savestate({ tabid, snapshotid: response.payload.snapshotid, updatedat: Date.now() });
70
+ await enqueue(request, { ...sender, tab: { ...sender.tab, id: tabid } });
71
+ try {
72
+ const response = await dispatch(request, { ...sender, tab: { ...sender.tab, id: tabid } });
73
+ await complete(request.id, response?.type === "response" && response.payload?.snapshotid ? { tabid, snapshotid: response.payload.snapshotid, updatedat: Date.now() } : { updatedat: Date.now() });
74
+ return response;
75
+ } catch (error) {
76
+ await markfailure(request.id, error);
77
+ throw error;
78
+ }
79
+ }
80
+
81
+ async function rehydrate() { return pendingstate(); }
82
+
83
+ async function resume(requestid, sender = {}) {
84
+ const state = await pendingstate();
85
+ const pending = state.pending.find((item) => item.requestid === requestid);
86
+ if (!pending) throw extensionerror("PENDING_NOT_FOUND", `pending command not found: ${requestid}`);
87
+ const tabid = pending.tabid ?? sender.tab?.id;
88
+ const response = await dispatch(pending.message, { ...sender, tab: { ...sender.tab, id: tabid } });
89
+ await complete(requestid, response?.type === "response" && response.payload?.snapshotid ? { tabid, snapshotid: response.payload.snapshotid, updatedat: Date.now() } : { updatedat: Date.now() });
39
90
  return response;
40
91
  }
41
92
 
42
- return { ensurecontent, readstate, savestate, handle };
93
+ async function cancel(requestid) { const state = await pendingstate(); await savestate({ ...state, pending: state.pending.filter((item) => item.requestid !== requestid) }); }
94
+
95
+ return { ensurecontent, readstate, savestate, rehydrate, enqueue, resume, cancel, handle };
43
96
  }
97
+
98
+ function pendingrecord(request, sender = {}) { return { requestid: request.id, command: request.command, message: request, tabid: request.payload?.tabid ?? sender.tab?.id, attempts: 0, createdat: Date.now(), updatedat: Date.now() }; }
99
+
100
+ function validpending(value) { return Boolean(value && typeof value === "object" && typeof value.requestid === "string" && value.message && value.message.type === "command" && Number.isSafeInteger(value.attempts) && value.attempts >= 0); }
101
+
102
+ function extensionerror(code, message) { const error = new Error(message); error.code = code; return error; }
@@ -13,8 +13,10 @@ export function startworker(chromeapi = globalThis.chrome) {
13
13
  router.handle(message, sender).then(sendresponse).catch((error) => sendresponse(createerror(message, error)));
14
14
  return true;
15
15
  };
16
+ const startup = () => router.rehydrate().catch(() => undefined);
16
17
  chromeapi.runtime.onMessage.addListener(listener);
17
- return { router, dispose() { chromeapi.runtime.onMessage.removeListener?.(listener); } };
18
+ chromeapi.runtime.onStartup?.addListener(startup);
19
+ return { router, dispose() { chromeapi.runtime.onMessage.removeListener?.(listener); chromeapi.runtime.onStartup?.removeListener?.(startup); } };
18
20
  }
19
21
 
20
22
  if (globalThis.chrome?.runtime?.onMessage) startworker();
package/package.json CHANGED
@@ -1,15 +1,24 @@
1
1
  {
2
2
  "name": "@wenathlan/saddle",
3
- "version": "1.8.2",
3
+ "version": "1.8.5",
4
4
  "description": "binary computing engine that turns distributed storage into a publishable working set",
5
5
  "type": "module",
6
+ "private": false,
6
7
  "license": "GPL-3.0-only",
8
+ "author": "Wenathlan",
9
+ "sideEffects": false,
10
+ "main": "./index.js",
11
+ "module": "./index.js",
12
+ "browser": "./index.js",
13
+ "packageManager": "npm@12.0.2",
7
14
  "publishConfig": { "access": "public" },
8
15
  "repository": { "type": "git", "url": "https://github.com/wenathlan/saddle.git" },
9
16
  "bugs": { "url": "https://github.com/wenathlan/saddle/issues" },
10
17
  "homepage": "https://github.com/wenathlan/saddle#readme",
11
18
  "keywords": ["distributed computing", "virtual memory", "runner", "storage", "automation"],
12
- "engines": { "node": ">=22" },
19
+ "engines": { "node": ">=26.7.0", "npm": ">=10.9.2" },
20
+ "peerDependencies": { "playwright": "^1.62.1" },
21
+ "peerDependenciesMeta": { "playwright": { "optional": true } },
13
22
  "bin": { "saddle": "./cli/main.js" },
14
23
  "exports": {
15
24
  ".": "./index.js",
@@ -23,6 +32,7 @@
23
32
  "./modes": "./modes/resolve.js",
24
33
  "./mode": "./modes/matrix.js",
25
34
  "./browser": "./browser/index.js",
35
+ "./browser-playwright": "./browser/playwright.js",
26
36
  "./bot": "./bot/bot.js",
27
37
  "./captcha": "./captcha/contract.js",
28
38
  "./deploy": "./deploy/index.js",
@@ -19,7 +19,7 @@ export function binaryplan(manifest, options = {}) {
19
19
  }
20
20
 
21
21
  export function containerplan(manifest, options = {}) {
22
- const base = options.base ?? "node:22-alpine";
22
+ const base = options.base ?? "node:26.7.0-alpine";
23
23
  const workdir = options.workdir ?? "/app";
24
24
  const command = options.command ?? ["node", manifest.entry];
25
25
  const lines = [`from ${base}`, `workdir ${workdir}`, "copy package.json package-lock.json ./", "run npm ci --omit=dev", "copy . .", `cmd ${JSON.stringify(command)}`];
@@ -0,0 +1,122 @@
1
+ import type { ScrapeResult, AgentOutput } from './types.js';
2
+ import { estimateTokens } from './tokens.js';
3
+ import { chunkMarkdown } from './chunking.js';
4
+
5
+ export interface AgentFormatOptions {
6
+ includeSummary?: boolean;
7
+ includeKeyPoints?: boolean;
8
+ includeUrls?: boolean;
9
+ includeRaw?: boolean;
10
+ maxTokens?: number;
11
+ chunkSize?: number;
12
+ model?: 'gpt-4o' | 'gpt-4' | 'gpt-3.5-turbo' | 'claude' | 'gemini' | 'default';
13
+ }
14
+
15
+ const DEFAULT_OPTIONS: Required<AgentFormatOptions> = {
16
+ includeSummary: true,
17
+ includeKeyPoints: true,
18
+ includeUrls: true,
19
+ includeRaw: true,
20
+ maxTokens: 8000,
21
+ chunkSize: 512,
22
+ model: 'default',
23
+ };
24
+
25
+ function generateSummary(result: ScrapeResult): string {
26
+ const wordCount = result.text.split(/\s+/).length;
27
+ return `This page titled "${result.title}" contains approximately ${wordCount} words with ${result.links.length} links and ${result.images.length} images.`;
28
+ }
29
+
30
+ function generateKeyPoints(result: ScrapeResult): string[] {
31
+ const points: string[] = [];
32
+ const text = result.text.slice(0, 5000);
33
+
34
+ if (result.metadata.author) points.push(`Author: ${result.metadata.author}`);
35
+ if (result.metadata.publishedDate) points.push(`Published: ${result.metadata.publishedDate}`);
36
+ if (result.metadata.description) points.push(`Description: ${result.metadata.description.slice(0, 200)}`);
37
+
38
+ const sentences = text.match(/[^.!?]+[.!?]+/g) || [];
39
+ for (const s of sentences.slice(0, 5)) {
40
+ const trimmed = s.trim();
41
+ if (trimmed.length > 30) points.push(trimmed);
42
+ }
43
+
44
+ return points.slice(0, 8);
45
+ }
46
+
47
+ function buildSystemPrompt(result: ScrapeResult): string {
48
+ let prompt = `# Web Page Content\n\n`;
49
+ prompt += `## Title\n${result.title}\n\n`;
50
+ prompt += `## URL\n${result.url}\n\n`;
51
+
52
+ if (result.metadata.description) {
53
+ prompt += `## Description\n${result.metadata.description}\n\n`;
54
+ }
55
+
56
+ if (result.tables.length > 0) {
57
+ prompt += `## Tables (${result.tables.length} found)\n`;
58
+ for (const t of result.tables.slice(0, 3)) {
59
+ prompt += `- ${t.caption || 'Unnamed table'}: ${t.headers.join(', ')}\n`;
60
+ }
61
+ prompt += '\n';
62
+ }
63
+
64
+ prompt += `## Content\n${result.content}\n\n`;
65
+ return prompt;
66
+ }
67
+
68
+ export function formatForAgent(result: ScrapeResult, options?: AgentFormatOptions): AgentOutput {
69
+ const opts = { ...DEFAULT_OPTIONS, ...options };
70
+ let content = '';
71
+
72
+ if (opts.includeSummary) {
73
+ content += `## Summary\n${generateSummary(result)}\n\n`;
74
+ }
75
+
76
+ if (opts.includeKeyPoints) {
77
+ const points = generateKeyPoints(result);
78
+ content += `## Key Points\n${points.map(p => `- ${p}`).join('\n')}\n\n`;
79
+ }
80
+
81
+ if (opts.includeUrls) {
82
+ const externalUrls = result.links.filter(l => l.isExternal).slice(0, 15);
83
+ if (externalUrls.length) {
84
+ content += `## External Links\n${externalUrls.map(l => `- [${l.text || l.href}](${l.href})`).join('\n')}\n\n`;
85
+ }
86
+ const internalUrls = result.links.filter(l => l.isInternal).slice(0, 10);
87
+ if (internalUrls.length) {
88
+ content += `## Internal Links\n${internalUrls.map(l => `- [${l.text || l.href}](${l.href})`).join('\n')}\n\n`;
89
+ }
90
+ }
91
+
92
+ if (opts.includeRaw) {
93
+ content += `## Full Content\n${result.content}\n\n`;
94
+ }
95
+
96
+ const totalTokens = estimateTokens(content, opts.model);
97
+
98
+ if (totalTokens > opts.maxTokens) {
99
+ const charLimit = Math.floor(opts.maxTokens * 4);
100
+ content = content.slice(0, charLimit) + '\n\n... (truncated)';
101
+ }
102
+
103
+ const chunks = chunkMarkdown(content, { maxTokens: opts.chunkSize });
104
+
105
+ const output: AgentOutput = {
106
+ summary: generateSummary(result),
107
+ content,
108
+ keyPoints: generateKeyPoints(result),
109
+ relevantUrls: result.links.filter(l => l.isExternal).map(l => l.href).slice(0, 10),
110
+ tokens: estimateTokens(content, opts.model),
111
+ };
112
+
113
+ if (chunks.length > 1) {
114
+ (output as unknown as Record<string, unknown>).chunks = chunks.map(c => c.content);
115
+ }
116
+
117
+ return output;
118
+ }
119
+
120
+ export function buildContext(result: ScrapeResult): string {
121
+ return buildSystemPrompt(result);
122
+ }
@@ -0,0 +1,79 @@
1
+ import pLimit from 'p-limit';
2
+ import type { ScrapeOptions, ScrapeResult, BatchOptions } from './types.js';
3
+ import { scrapeUrl } from './scrape.js';
4
+
5
+ export interface BatchResult {
6
+ results: ScrapeResult[];
7
+ errors: { url: string; error: Error }[];
8
+ successful: number;
9
+ failed: number;
10
+ duration: number;
11
+ }
12
+
13
+ export async function batchScrape(options: BatchOptions, scrapeOpts: ScrapeOptions = {}): Promise<BatchResult> {
14
+ const startTime = Date.now();
15
+ const limit = pLimit(options.concurrency || 5);
16
+ const results: ScrapeResult[] = [];
17
+ const errors: { url: string; error: Error }[] = [];
18
+
19
+ const tasks = options.urls.map((url) =>
20
+ limit(async () => {
21
+ try {
22
+ const result = await scrapeUrl(url, { ...scrapeOpts, mode: scrapeOpts.mode || 'auto' });
23
+ results.push(result);
24
+ options.onProgress?.(results.length + errors.length, options.urls.length, url);
25
+ } catch (error) {
26
+ errors.push({ url, error: error as Error });
27
+ options.onError?.(url, error as Error);
28
+ options.onProgress?.(results.length + errors.length, options.urls.length, url);
29
+ }
30
+ })
31
+ );
32
+
33
+ await Promise.allSettled(tasks);
34
+
35
+ return {
36
+ results,
37
+ errors,
38
+ successful: results.length,
39
+ failed: errors.length,
40
+ duration: Date.now() - startTime,
41
+ };
42
+ }
43
+
44
+ export async function batchScrapeSequential(
45
+ urls: string[],
46
+ options: ScrapeOptions = {},
47
+ callbacks?: {
48
+ onResult?: (result: ScrapeResult, index: number) => void;
49
+ onError?: (url: string, error: Error, index: number) => void;
50
+ delayMs?: number;
51
+ }
52
+ ): Promise<BatchResult> {
53
+ const startTime = Date.now();
54
+ const results: ScrapeResult[] = [];
55
+ const errors: { url: string; error: Error }[] = [];
56
+
57
+ for (let i = 0; i < urls.length; i++) {
58
+ try {
59
+ const result = await scrapeUrl(urls[i], options);
60
+ results.push(result);
61
+ callbacks?.onResult?.(result, i);
62
+ } catch (error) {
63
+ errors.push({ url: urls[i], error: error as Error });
64
+ callbacks?.onError?.(urls[i], error as Error, i);
65
+ }
66
+
67
+ if (callbacks?.delayMs && i < urls.length - 1) {
68
+ await new Promise(r => setTimeout(r, callbacks.delayMs));
69
+ }
70
+ }
71
+
72
+ return {
73
+ results,
74
+ errors,
75
+ successful: results.length,
76
+ failed: errors.length,
77
+ duration: Date.now() - startTime,
78
+ };
79
+ }
@@ -0,0 +1,76 @@
1
+ {
2
+ "$schema": "https://biomejs.dev/schemas/2.4.15/schema.json",
3
+ "formatter": {
4
+ "enabled": true,
5
+ "indentStyle": "tab",
6
+ "indentWidth": 2,
7
+ "lineWidth": 100,
8
+ "lineEnding": "lf",
9
+ "formatWithErrors": false
10
+ },
11
+ "linter": {
12
+ "enabled": true,
13
+ "rules": {
14
+ "recommended": true,
15
+ "a11y": {
16
+ "noStaticElementInteractions": "off",
17
+ "useKeyWithClickEvents": "off",
18
+ "useSemanticElements": "off"
19
+ },
20
+ "correctness": {
21
+ "useExhaustiveDependencies": "off"
22
+ },
23
+ "style": {
24
+ "noNonNullAssertion": "off",
25
+ "useNodejsImportProtocol": "off",
26
+ "useConst": "error"
27
+ },
28
+ "suspicious": {
29
+ "noExplicitAny": "off",
30
+ "noEmptyBlock": "warn"
31
+ },
32
+ "complexity": {
33
+ "noUselessFragments": "warn",
34
+ "noForEach": "off"
35
+ },
36
+ "performance": {
37
+ "noDelete": "off"
38
+ }
39
+ }
40
+ },
41
+ "assist": {
42
+ "enabled": true,
43
+ "actions": {
44
+ "source": {
45
+ "organizeImports": "on"
46
+ }
47
+ }
48
+ },
49
+ "javascript": {
50
+ "formatter": {
51
+ "quoteStyle": "double",
52
+ "semicolons": "always",
53
+ "trailingCommas": "es5",
54
+ "arrowParentheses": "always"
55
+ }
56
+ },
57
+ "css": {
58
+ "parser": {
59
+ "cssModules": true,
60
+ "allowWrongLineComments": true
61
+ },
62
+ "formatter": {
63
+ "enabled": true
64
+ }
65
+ },
66
+ "files": {
67
+ "includes": ["*.ts", "web/**", "tests/**"],
68
+ "ignore": ["node_modules", "dist", "*.min.*"],
69
+ "ignoreUnknown": true
70
+ },
71
+ "vcs": {
72
+ "enabled": true,
73
+ "clientKind": "git",
74
+ "useIgnoreFile": true
75
+ }
76
+ }