@wenathlan/saddle 1.8.16 → 1.8.18

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 (223) hide show
  1. package/README.md +38 -13
  2. package/dist/apps/registry.d.ts +1 -1
  3. package/dist/index.d.ts +1 -0
  4. package/dist/index.d.ts.map +1 -1
  5. package/dist/index.js +1 -0
  6. package/dist/index.js.map +1 -1
  7. package/dist/isolation/contracts.d.ts +118 -0
  8. package/dist/isolation/contracts.d.ts.map +1 -0
  9. package/dist/isolation/contracts.js +84 -0
  10. package/dist/isolation/contracts.js.map +1 -0
  11. package/dist/mcp/server.d.ts +2 -2
  12. package/dist/scrape/robots.js +1 -1
  13. package/docs/artifactavailability.md +18 -2
  14. package/docs/containerplatforms-1.8.17.md +29 -0
  15. package/docs/releasenotes-1.8.16.md +6 -2
  16. package/docs/releasenotes-1.8.17.md +43 -0
  17. package/docs/releasenotes-1.8.18.md +32 -0
  18. package/docs/research-1.8.18-isolation.md +43 -0
  19. package/docs/saddle.archive.1.8.17.tar.gz.gpg +0 -0
  20. package/docs/todo-1.8.16.md +92 -8
  21. package/docs/todo-1.8.18.md +152 -0
  22. package/docs/workflowoperations.md +32 -0
  23. package/extension/manifest.json +1 -1
  24. package/package.json +3 -2
  25. package/docs/logs/.gitkeep +0 -0
  26. package/docs/plans/00.index.md +0 -50
  27. package/docs/plans/01.architecture.md +0 -86
  28. package/docs/plans/02.research.computer.use.md +0 -58
  29. package/docs/plans/03.research.captcha.bypass.md +0 -68
  30. package/docs/plans/04.research.sandbox.ai.md +0 -52
  31. package/docs/plans/05.capture.platform.md +0 -57
  32. package/docs/plans/06.dependencies.md +0 -97
  33. package/docs/plans/07.captcha.test.page.md +0 -41
  34. package/docs/plans/08.production.infra.md +0 -70
  35. package/docs/plans/09.database.schema.md +0 -121
  36. package/docs/plans/10.cloudinary.storage.md +0 -57
  37. package/docs/plans/11.movement.logs.json.md +0 -72
  38. package/docs/plans/12.research.atlas.agent.browser.md +0 -79
  39. package/docs/plans/13.research.anti.detection.md +0 -898
  40. package/docs/plans/14.research.proxy.md +0 -1495
  41. package/docs/plans/15.research.retry.rate.limit.md +0 -1958
  42. package/docs/plans/16.research.crawling.md +0 -1417
  43. package/docs/plans/17.research.caching.md +0 -1610
  44. package/docs/plans/18.research.content.extraction.md +0 -1952
  45. package/docs/plans/19.research.errors.events.md +0 -1523
  46. package/docs/plans/20.research.zod.validation.md +0 -1350
  47. package/docs/plans/21.research.batch.concurrency.md +0 -1888
  48. package/docs/plans/22.research.universal.runtime.md +0 -944
  49. package/docs/plans/23.research.ai.integration.md +0 -1465
  50. package/docs/plans/24.research.memory.persistence.md +0 -1979
  51. package/docs/plans/25.research.server.api.md +0 -342
  52. package/docs/plans/26.research.compilation.md +0 -249
  53. package/docs/plans/27.research.html.parsing.md +0 -251
  54. package/docs/plans/28.action.plan.md +0 -50
  55. package/docs/plans/29.api.reference.md +0 -174
  56. package/docs/plans/30.architecture.plan.md +0 -94
  57. package/docs/plans/31.auditoria.dados.md +0 -163
  58. package/docs/plans/32.bots.automacao.computacional.md +0 -214
  59. package/docs/plans/33.bots.codigo.revisao.md +0 -220
  60. package/docs/plans/34.bots.seguranca.cicd.md +0 -366
  61. package/docs/plans/35.comparativo.concorrencia.md +0 -464
  62. package/docs/plans/36.computational.memory.md +0 -340
  63. package/docs/plans/37.deploystrategy.md +0 -394
  64. package/docs/plans/38.flow.md +0 -155
  65. package/docs/plans/39.multi.platform.bot.md +0 -252
  66. package/docs/plans/40.npm.publish.md +0 -250
  67. package/docs/plans/41.o.que.falta.md +0 -407
  68. package/docs/plans/42.pesquisa.concorrencia.md +0 -721
  69. package/docs/plans/43.plan.universal.architecture.md +0 -496
  70. package/docs/plans/44.reference.md +0 -100
  71. package/docs/plans/45.robotarchitecture.md +0 -237
  72. package/docs/plans/46.scdnintegration.md +0 -284
  73. package/docs/plans/47.multiforge.readme.md +0 -129
  74. package/docs/plans/48.theory.v4.repo.os.md +0 -152
  75. package/docs/plans/49.third.party.infra.md +0 -12
  76. package/docs/plans/50.file.as.compute.md +0 -39
  77. package/docs/plans/51.architecture.virtual.processor.md +0 -80
  78. package/docs/plans/52.manifesto.v8.md +0 -11
  79. package/docs/plans/58.cdn.list.md +0 -23
  80. package/docs/plans/59.sql.frameworks.md +0 -33
  81. package/docs/plans/60.sql.thirdparty.md +0 -26
  82. package/docs/plans/61.objective.multiforge.md +0 -63
  83. package/docs/plans/62.huggingface.upload.md +0 -26
  84. package/docs/plans/63.kaggle.upload.md +0 -24
  85. package/docs/plans/64.npm.storage.md +0 -30
  86. package/docs/plans/65.rclone.terabox.md +0 -32
  87. package/docs/plans/66.buckets.and.models.todo.md +0 -14
  88. package/docs/plans/67.database.todo.md +0 -13
  89. package/docs/plans/68.deploy.packages.todo.md +0 -12
  90. package/docs/plans/69.report.human.operator.md +0 -133
  91. package/docs/plans/70.report.brain2qwerty.ems.md +0 -135
  92. package/docs/plans/71.report.hd.infinito.vram.md +0 -155
  93. package/docs/plans/72.plan.hd.infinito.node.md +0 -146
  94. package/docs/plans/73.plan.scifi.repos.md +0 -125
  95. package/docs/plans/74.000.manifesto.v8.flat.2..md +0 -11
  96. package/docs/plans/README.md +0 -489
  97. package/docs/plans/aggregate_platforms.mjs +0 -146
  98. package/docs/plans/examplesession.json +0 -36
  99. package/docs/plans/missing-facts.md +0 -192
  100. package/docs/plans/models.md +0 -64
  101. package/docs/plans/organize.cjs +0 -270
  102. package/docs/plans/platforms.md +0 -2887
  103. package/docs/plans/sites.md +0 -31322
  104. package/docs/sources/farm.py +0 -117
  105. package/docs/sources/html/saddle1.html +0 -132
  106. package/docs/sources/html/saddle2.html +0 -157
  107. package/docs/sources/html/saddle3.html +0 -119
  108. package/docs/sources/html/saddle4.html +0 -144
  109. package/docs/sources/html/saddle5.html +0 -72
  110. package/docs/sources/html/saddle6.html +0 -171
  111. package/docs/sources/html/saddle7.html +0 -236
  112. package/docs/sources/saddle.ts +0 -74
  113. package/docs/sources/schema.prisma +0 -88
  114. package/docs/sources/script.sh +0 -64
  115. package/docs/sources/workflows.yml +0 -458
  116. package/docs/talks1/_body.txt +0 -14
  117. package/docs/talks1/_index.md +0 -15
  118. package/docs/talks1/_screenshot.png +0 -0
  119. package/docs/talks1/assistant-01.md +0 -5
  120. package/docs/talks1/assistant-02.md +0 -5
  121. package/docs/talks1/assistant-03.md +0 -531
  122. package/docs/talks1/assistant-04.md +0 -26
  123. package/docs/talks1/assistant-05.md +0 -774
  124. package/docs/talks1/assistant-06.md +0 -1718
  125. package/docs/talks1/scrape-share.cjs +0 -185
  126. package/docs/talks1/scrape-share.ts +0 -183
  127. package/docs/talks1/user-01.md +0 -3
  128. package/docs/talks1/user-02.md +0 -3
  129. package/docs/talks1/user-03.md +0 -88
  130. package/docs/talks1/user-04.md +0 -3
  131. package/docs/talks1/user-05.md +0 -3
  132. package/docs/talks1/user-06.md +0 -88
  133. package/docs/talks1/user-07.md +0 -88
  134. package/docs/talks2/_body.txt +0 -14
  135. package/docs/talks2/_index.md +0 -16
  136. package/docs/talks2/_screenshot.png +0 -0
  137. package/docs/talks2/assistant-01.md +0 -5
  138. package/docs/talks2/assistant-02.md +0 -5
  139. package/docs/talks2/assistant-03.md +0 -424
  140. package/docs/talks2/assistant-04.md +0 -598
  141. package/docs/talks2/assistant-05.md +0 -1280
  142. package/docs/talks2/assistant-06.md +0 -1227
  143. package/docs/talks2/assistant-07.md +0 -1252
  144. package/docs/talks2/user-01.md +0 -3
  145. package/docs/talks2/user-02.md +0 -3
  146. package/docs/talks2/user-03.md +0 -88
  147. package/docs/talks2/user-04.md +0 -88
  148. package/docs/talks2/user-05.md +0 -88
  149. package/docs/talks2/user-06.md +0 -88
  150. package/docs/talks2/user-07.md +0 -3
  151. package/docs/talks3/_body.txt +0 -467
  152. package/docs/talks3/_index.md +0 -10
  153. package/docs/talks3/_screenshot.png +0 -0
  154. package/docs/talks3/assistant-01.md +0 -417
  155. package/docs/talks3/assistant-02.md +0 -417
  156. package/docs/talks3/assistant-03.md +0 -29
  157. package/docs/talks3/assistant-04.md +0 -727
  158. package/docs/talks3/user-01.md +0 -88
  159. package/docs/talks3/user-02.md +0 -88
  160. package/docs/talks3/user-03.md +0 -3
  161. package/docs/talks3/user-04.md +0 -3
  162. package/docs/talks4/_body.txt +0 -14
  163. package/docs/talks4/_index.md +0 -12
  164. package/docs/talks4/_screenshot.png +0 -0
  165. package/docs/talks4/assistant-01.md +0 -5
  166. package/docs/talks4/assistant-02.md +0 -5
  167. package/docs/talks4/assistant-03.md +0 -35
  168. package/docs/talks4/assistant-04.md +0 -512
  169. package/docs/talks4/assistant-05.md +0 -599
  170. package/docs/talks4/user-01.md +0 -3
  171. package/docs/talks4/user-02.md +0 -3
  172. package/docs/talks4/user-03.md +0 -88
  173. package/docs/talks4/user-04.md +0 -88
  174. package/docs/talks4/user-05.md +0 -7
  175. package/docs/talks5/_body.txt +0 -14
  176. package/docs/talks5/_index.md +0 -13
  177. package/docs/talks5/_screenshot.png +0 -0
  178. package/docs/talks5/assistant-01.md +0 -5
  179. package/docs/talks5/assistant-02.md +0 -5
  180. package/docs/talks5/assistant-03.md +0 -690
  181. package/docs/talks5/assistant-04.md +0 -758
  182. package/docs/talks5/assistant-05.md +0 -974
  183. package/docs/talks5/user-01.md +0 -3
  184. package/docs/talks5/user-02.md +0 -3
  185. package/docs/talks5/user-03.md +0 -105
  186. package/docs/talks5/user-04.md +0 -105
  187. package/docs/talks5/user-05.md +0 -63
  188. package/docs/talks5/user-06.md +0 -105
  189. package/docs/talks6/_body.txt +0 -14
  190. package/docs/talks6/_index.md +0 -9
  191. package/docs/talks6/_screenshot.png +0 -0
  192. package/docs/talks6/assistant-01.md +0 -5
  193. package/docs/talks6/assistant-02.md +0 -5
  194. package/docs/talks6/assistant-03.md +0 -1499
  195. package/docs/talks6/user-01.md +0 -3
  196. package/docs/talks6/user-02.md +0 -3
  197. package/docs/talks6/user-03.md +0 -88
  198. package/docs/talks6/user-04.md +0 -88
  199. package/docs/talks7/_body.txt +0 -14
  200. package/docs/talks7/_index.md +0 -10
  201. package/docs/talks7/_screenshot.png +0 -0
  202. package/docs/talks7/assistant-01.md +0 -5
  203. package/docs/talks7/assistant-02.md +0 -5
  204. package/docs/talks7/assistant-03.md +0 -523
  205. package/docs/talks7/assistant-04.md +0 -617
  206. package/docs/talks7/user-01.md +0 -3
  207. package/docs/talks7/user-02.md +0 -3
  208. package/docs/talks7/user-03.md +0 -105
  209. package/docs/talks7/user-04.md +0 -67
  210. package/docs/talks8/conversa1.txt +0 -1322
  211. package/docs/talks8/conversa2.txt +0 -237
  212. 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" +0 -174
  213. 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" +0 -59
  214. 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" +0 -91
  215. 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" +0 -116
  216. 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" +0 -128
  217. package/docs/talks9/README (2).md +0 -489
  218. package/docs/talks9/README.md +0 -198
  219. 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" +0 -80
  220. package/docs/talks9/conversa.txt +0 -544
  221. package/docs/talks9/other (2).md +0 -39
  222. package/docs/talks9/other.md +0 -57
  223. package/docs/talks9/outro.txt +0 -24
@@ -1,237 +0,0 @@
1
- # Saddle Robot Architecture
2
-
3
- > Super bot: agent browser, scraper, captcha bypass, GitHub/GitLab/Forgejo/Gitea automation.
4
- > Transform storage memory into computational memory for unlimited processing.
5
-
6
- ## Overview
7
-
8
- Saddle is a self-hosted AI agent platform that combines browser automation,
9
- scraping, captcha bypass, and multi-platform bot functionality into a single
10
- runtime. It operates as a virtual machine agent that can deploy to multiple
11
- platforms and store unlimited memory in remote repositories.
12
-
13
- ## Core Components
14
-
15
- ### 1. Agent Browser Engine
16
-
17
- The browser agent captures user interactions (mouse movement, clicks, scrolling)
18
- and replays them. It uses Brave browser via Playwright with the real user
19
- profile for persistence.
20
-
21
- #### Movement Capture
22
-
23
- ```
24
- Browser → Movement Capture → JSON Log → Storage → Replay
25
- ```
26
-
27
- Supports:
28
- - Virtual mouse movement (arrow trails)
29
- - Click coordinates
30
- - Scroll events
31
- - Keyboard input
32
- - Screenshot capture
33
- - Session recording
34
-
35
- #### Captcha Bypass
36
-
37
- Saddle handles three captcha types:
38
-
39
- | Type | Method | Success Rate |
40
- |------|--------|-------------|
41
- | hCaptcha | Cloudflare Turnstile proxy | High |
42
- | Cloudflare Turnstile | Managed challenge solving | Medium-High |
43
- | reCAPTCHA | Token rotation + headless solve | Medium |
44
-
45
- ### 2. Multi-Platform Bot Engine
46
-
47
- The bot engine operates across platforms through a unified interface:
48
-
49
- ```typescript
50
- interface PlatformAdapter {
51
- name: string
52
- type: 'github' | 'gitlab' | 'forgejo' | 'gitea' | 'discord'
53
- authenticate(token: string): Promise<boolean>
54
- listRepos(): Promise<Repo[]>
55
- createWebhook(payload: WebhookPayload): Promise<void>
56
- executeBot(commands: BotCommand[]): Promise<BotResult>
57
- }
58
- ```
59
-
60
- Platforms supported:
61
- - **GitHub** - Actions, webhooks, PR automation, issue triage
62
- - **GitLab** - CI/CD pipelines, merge requests, webhooks
63
- - **Forgejo** - Self-hosted Git, lightweight alternative
64
- - **Gitea** - Self-hosted Git service, minimal footprint
65
- - **Discord** - Bot commands, webhook reactions, automated responses
66
-
67
- ### 3. Computational Memory System
68
-
69
- This is the core innovation of saddle. It transforms storage memory into
70
- computational memory through a memory engine.
71
-
72
- #### Memory Layers
73
-
74
- | Layer | Type | Source | Capacity |
75
- |-------|------|--------|----------|
76
- | L1 | RAM | System memory | Limited (ephemeral) |
77
- | L2 | GPU VRAM | Graphics memory | Limited (compute-bound) |
78
- | L3 | Storage RAM | Repository storage | Effectively unlimited |
79
- | L4 | External Buckets | HF/Kaggle/ModelScope/Terabox | Unlimited |
80
-
81
- #### Storage-to-Compute Transformation
82
-
83
- ```
84
- Repository Storage (L3)
85
- → Memory Engine reads blobs
86
- → Transforms into virtual RAM
87
- → Processed as computational memory
88
- → Results written back to storage
89
- ```
90
-
91
- The memory engine acts as a bridge between storage objects (files, blobs,
92
- assets) and computational processing. It can load file contents into
93
- memory, process them, and persist results back to storage.
94
-
95
- #### Memory Engine API
96
-
97
- ```typescript
98
- interface MemoryEngine {
99
- loadFromStorage(repo: string, path: string): Promise<MemoryObject>
100
- process(operation: ComputeOperation): Promise<MemoryResult>
101
- persist(result: MemoryResult, target: StorageTarget): Promise<void>
102
- release(memoryId: string): Promise<void>
103
- }
104
- ```
105
-
106
- ## Architecture Diagram
107
-
108
- ```
109
- ┌─────────────────────────────────────────────────────────────────┐
110
- │ Saddle Robot │
111
- │ │
112
- │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌───────────────┐ │
113
- │ │ Browser │ │ Bot │ │ CAPTCHA │ │ Memory Engine │ │
114
- │ │ Agent │ │ Engine │ │ Bypass │ │ (Core) │ │
115
- │ └────┬─────┘ └────┬─────┘ └────┬─────┘ └──────┬────────┘ │
116
- │ │ │ │ │ │
117
- │ ▼ ▼ ▼ ▼ │
118
- │ ┌─────────────────────────────────────────────────────────────┐│
119
- │ │ Unified Processing Layer ││
120
- │ └─────────────────────────────────────────────────────────────┘│
121
- │ │ │ │ │ │
122
- │ ▼ ▼ ▼ ▼ │
123
- │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────────┐ │
124
- │ │ GitHub │ │ GitLab │ │ Forgejo│ │ Discord │ │
125
- │ │ │ │ │ │ │ │ │ │
126
- │ └─────────┘ └─────────┘ └─────────┘ └─────────────┘ │
127
- │ │
128
- │ ┌────────────────────────────────────────────────────────────┐│
129
- │ │ Storage / Memory Backends ││
130
- │ │ HuggingFace │ Kaggle │ ModelScope │ Terabox │ Repos ││
131
- │ └────────────────────────────────────────────────────────────┘│
132
- │ │
133
- │ ┌────────────────────────────────────────────────────────────┐│
134
- │ │ Deploy Targets ││
135
- │ │ Netlify │ Vercel │ Docker │ VM │ Self-Hosted │ GitHub ││
136
- │ └────────────────────────────────────────────────────────────┘│
137
- └─────────────────────────────────────────────────────────────────┘
138
- ```
139
-
140
- ## Deploy Strategies
141
-
142
- ### Strategy 1: HTTPS Communication Between Sites
143
-
144
- Two or more deployed sites communicate via HTTPS. The saddle robot
145
- receives commands from a web interface and executes actions.
146
-
147
- ```
148
- Site A (web interface) ──HTTPS──▶ Site B (saddle robot backend)
149
-
150
- ├──▶ GitHub API
151
- ├──▶ GitLab API
152
- ├──▶ Browser Engine
153
- └──▶ Storage Backends
154
- ```
155
-
156
- ### Strategy 2: GitHub/GitLab/Forge Pipelines
157
-
158
- Use CI/CD pipelines (GitHub Actions, GitLab CI, Forgejo Actions) to
159
- deploy and run the saddle robot as a scheduled or triggered job.
160
-
161
- ### Strategy 3: Docker/VM Deployment
162
-
163
- Package saddle as a Docker container or VM image for self-hosted
164
- deployment with full resource access.
165
-
166
- ```dockerfile
167
- FROM node:20-slim
168
- WORKDIR /app
169
- COPY package*.json ./
170
- RUN npm ci --production
171
- COPY . .
172
- EXPOSE 3000
173
- CMD ["node", "server.js"]
174
- ```
175
-
176
- ## NPM Package Publishing
177
-
178
- Saddle can be published as an NPM package `@wenathlan/saddle` for
179
- distribution as both a library and a CLI tool.
180
-
181
- ### Package Structure
182
-
183
- ```
184
- @wenathlan/saddle/
185
- ├── lib/
186
- │ ├── browser.js (agent browser engine)
187
- │ ├── bot.js (multi-platform bot engine)
188
- │ ├── captcha.js (captcha bypass module)
189
- │ ├── memory-engine.js (storage-to-compute transformation)
190
- │ └── deploy.js (deploy strategy implementations)
191
- ├── bin/
192
- │ └── saddle.js (CLI entry point)
193
- ├── docs/
194
- │ └── index.md (package documentation)
195
- ├── package.json
196
- └── README.md
197
- ```
198
-
199
- ### As Library vs Binary
200
-
201
- | Mode | Entry Point | Usage |
202
- |------|------------|-------|
203
- | Library | `require('@wenathlan/saddle')` | Import as Node module |
204
- | CLI | `saddle --command capture` | Run as terminal command |
205
- | Binary | `node_modules/.bin/saddle` | Direct execution |
206
-
207
- ## SCDN Integration
208
-
209
- Saddle supports integration with Static Content Delivery Networks for
210
- hosting browser assets, capture files, and deployment payloads.
211
-
212
- The SCDN pipeline:
213
- 1. Captures browser session data
214
- 2. Uploads assets to SCDN
215
- 3. References SCDN URLs in bot results
216
- 4. Serves static content from edge locations
217
-
218
- ## Research Status
219
-
220
- | Component | Status | Source |
221
- |-----------|--------|--------|
222
- | Agent browser | Research complete | `12-research-atlas-agent-browser.md` |
223
- | Captcha bypass | Research complete | `03-research-captcha-bypass.md` |
224
- | Sandbox/VM | Research complete | `04-research-sandbox-ai.md` |
225
- | Memory engine | To be implemented | New doc |
226
- | Multi-platform bot | To be implemented | New doc |
227
- | Deploy strategies | To be implemented | New doc |
228
- | SCDN integration | To be implemented | New doc |
229
-
230
- ## Decision Log
231
-
232
- See `docs/talks/` for decision transcripts on architecture choices.
233
- See `docs/logs/` for json movement logs from Brave capture sessions.
234
-
235
- ## License
236
-
237
- MIT
@@ -1,284 +0,0 @@
1
- # SCDN Integration for Saddle Robot
2
-
3
- > Static Content Delivery Network integration for
4
- > hosting browser assets, capture files, and deployment payloads.
5
-
6
- ## Overview
7
-
8
- The saddle robot integrates with Static Content Delivery
9
- Networks (SCDN) to serve browser assets, capture files,
10
- and deployment payloads from edge locations worldwide.
11
-
12
- ## SCDN Use Cases
13
-
14
- 1. Host browser automation assets (scripts, styles,
15
- configuration files)
16
- 2. Serve capture session data (JSON logs, video files)
17
- 3. Deliver deployment payloads to deployed sites
18
- 4. Cache bot responses for faster repeat execution
19
- 5. Distribute browser profiles and extensions
20
-
21
- ## SCDN Pipeline
22
-
23
- ```
24
- Capture Pipeline
25
- ────────────────────────────────────────────────────────
26
- 1. Browser session captures data
27
- 2. Assets uploaded to SCDN via HTTPS
28
- 3. SCDN caches content at edge locations
29
- 4. Bot workers fetch assets from nearest edge
30
- 5. Results stored in repository/bucket storage
31
- ```
32
-
33
- ## Implementation
34
-
35
- ### SCDN Client
36
-
37
- ```typescript
38
- interface SCDNClientConfig {
39
- endpoint: string
40
- token: string
41
- bucketId: string
42
- region?: string
43
- ttlSeconds: number
44
- }
45
-
46
- class SCDNClient {
47
- private config: SCDNClientConfig
48
-
49
- constructor(config: SCDNClientConfig) {
50
- this.config = config
51
- }
52
-
53
- async upload(
54
- path: string,
55
- content: Buffer | string,
56
- options?: { contentType?: string; ttl?: number }
57
- ): Promise<{ url: string; etag: string; size: number }> {
58
- try {
59
- const response = await fetch(
60
- `${this.config.endpoint}/${this.config.bucketId}/${path}`,
61
- {
62
- method: 'PUT',
63
- headers: {
64
- Authorization: `Bearer ${this.config.token}`,
65
- 'Content-Type': options?.contentType ?? 'application/octet-stream',
66
- 'Cache-Control': `max-age=${options?.ttl ?? this.config.ttlSeconds}`,
67
- },
68
- body:
69
- typeof content === 'string'
70
- ? new TextEncoder().encode(content)
71
- : content,
72
- }
73
- )
74
-
75
- if (!response.ok) {
76
- throw new Error(
77
- `SCDN upload failed: ${response.status} ${response.statusText}`
78
- )
79
- }
80
-
81
- const etag = response.headers.get('etag') ?? ''
82
- const url = `${this.config.endpoint}/${this.config.bucketId}/${path}`
83
- const size =
84
- typeof content === 'string'
85
- ? new TextEncoder().encode(content).byteLength
86
- : content.byteLength
87
-
88
- return { url, etag, size }
89
- } catch (error) {
90
- throw new Error(
91
- `SCDNClient.upload("${path}") failed: ${error instanceof Error ? error.message : String(error)}`
92
- )
93
- }
94
- }
95
-
96
- async download(path: string): Promise<Buffer> {
97
- try {
98
- const response = await fetch(
99
- `${this.config.endpoint}/${this.config.bucketId}/${path}`,
100
- {
101
- headers: {
102
- Authorization: `Bearer ${this.config.token}`,
103
- },
104
- }
105
- )
106
-
107
- if (!response.ok) {
108
- throw new Error(
109
- `SCDN download failed: ${response.status} ${response.statusText}`
110
- )
111
- }
112
-
113
- const arrayBuffer = await response.arrayBuffer()
114
- return Buffer.from(arrayBuffer)
115
- } catch (error) {
116
- throw new Error(
117
- `SCDNClient.download("${path}") failed: ${error instanceof Error ? error.message : String(error)}`
118
- )
119
- }
120
- }
121
-
122
- async delete(path: string): Promise<boolean> {
123
- try {
124
- const response = await fetch(
125
- `${this.config.endpoint}/${this.config.bucketId}/${path}`,
126
- {
127
- method: 'DELETE',
128
- headers: {
129
- Authorization: `Bearer ${this.config.token}`,
130
- },
131
- }
132
- )
133
- return response.ok
134
- } catch (error) {
135
- throw new Error(
136
- `SCDNClient.delete("${path}") failed: ${error instanceof Error ? error.message : String(error)}`
137
- )
138
- }
139
- }
140
- }
141
- ```
142
-
143
- ### Asset Upload Flow
144
-
145
- ```typescript
146
- // In browser capture module
147
- import { SCDNClient } from '@wenathlan/saddle/deploy'
148
-
149
- async function uploadCaptureSession(
150
- sessionData: SessionData,
151
- scdnClient: SCDNClient
152
- ): Promise<SessionResult> {
153
- const sessionId = generateSessionId()
154
- const sessionPath = `sessions/${sessionId}.json`
155
- const screenshotPath = `screenshots/${sessionId}.png`
156
-
157
- // Upload session data
158
- const sessionResult = await scdnClient.upload(
159
- sessionPath,
160
- JSON.stringify(sessionData),
161
- { contentType: 'application/json', ttl: 3600 }
162
- )
163
-
164
- // Upload screenshot
165
- const screenshotResult = await scdnClient.upload(
166
- screenshotPath,
167
- sessionData.screenshot,
168
- { contentType: 'image/png', ttl: 86400 }
169
- )
170
-
171
- return {
172
- sessionId,
173
- sessionUrl: sessionResult.url,
174
- screenshotUrl: screenshotResult.url,
175
- }
176
- }
177
- ```
178
-
179
- ## SCDN Providers
180
-
181
- | Provider | Type | Pricing | Edge Locations |
182
- |----------|------|---------|----------------|
183
- | Cloudflare Workers | Edge JS | Free tier + paid | 300+ cities |
184
- | Cloudflare R2 | Object storage | Free egress | 300+ cities |
185
- | AWS CloudFront | CDN + S3 | Pay per use | 400+ cities |
186
- | Bun CDN | Edge runtime | Free tier | Global |
187
- | Deno Deploy | Edge functions | Free tier + paid | Global |
188
- | Vercel Edge Config | Config storage | Includes Vercel | Global |
189
- | Netlify Edge | Edge functions | Free tier + paid | Global |
190
-
191
- ## SCDN + Repository Integration
192
-
193
- ```
194
- SCDN Endpoint ──HTTPS──▶ Repository Webhook
195
-
196
-
197
- Saddle Robot Deploy
198
-
199
-
200
- Browser Capture Session
201
-
202
-
203
- SCDN Asset Upload
204
-
205
-
206
- Store SCDN URLs in Repo
207
- ```
208
-
209
- ## Configuration
210
-
211
- ### Environment Variables
212
-
213
- | Variable | Description | Required |
214
- |----------|-------------|----------|
215
- | `SBOT_SCDN_ENDPOINT` | SCDN API endpoint | Yes |
216
- | `SBOT_SCDN_TOKEN` | SCDN authentication token | Yes |
217
- | `SBOT_SCDN_BUCKET` | Bucket ID for storage | Yes |
218
- | `SBOT_SCDN_REGION` | Preferred edge region | No |
219
- | `SBOT_SCDN_TTL` | Default cache TTL in seconds | No |
220
-
221
- ### Example Configuration
222
-
223
- ```yaml
224
- # .saddle/scdn.yml
225
- scdn:
226
- endpoint: "https://api.scdn.example.com/v1"
227
- bucket: "saddle-assets"
228
- token: "${SBOT_SCDN_TOKEN}"
229
- region: "us-east-1"
230
- ttl: 3600
231
- retry:
232
- maxAttempts: 3
233
- delayMs: 1000
234
- ```
235
-
236
- ## Performance
237
-
238
- | Operation | SCDN (edge) | Direct storage |
239
- |-----------|------------|----------------|
240
- | Upload | 50-200ms | 200-2000ms |
241
- | Download | 10-50ms | 50-500ms |
242
- | Cache hit | 5-20ms | N/A |
243
- | Cache miss | 50-200ms | N/A |
244
-
245
- ## Error Handling
246
-
247
- ```typescript
248
- interface SCDNResult {
249
- success: boolean
250
- url?: string
251
- error?: string
252
- retryCount?: number
253
- }
254
-
255
- async function safeUpload(
256
- client: SCDNClient,
257
- path: string,
258
- content: Buffer,
259
- maxRetries: number = 3
260
- ): Promise<SCDNResult> {
261
- for (let attempt = 1; attempt <= maxRetries; attempt++) {
262
- try {
263
- const result = await client.upload(path, content)
264
- return { success: true, url: result.url }
265
- } catch (error) {
266
- if (attempt === maxRetries) {
267
- return {
268
- success: false,
269
- error: error instanceof Error ? error.message : String(error),
270
- retryCount: attempt,
271
- }
272
- }
273
- await new Promise((resolve) =>
274
- setTimeout(resolve, 1000 * attempt)
275
- )
276
- }
277
- }
278
- return { success: false, error: 'Unexpected error' }
279
- }
280
- ```
281
-
282
- ## License
283
-
284
- MIT
@@ -1,129 +0,0 @@
1
- # OpenCode Multi-Forge - Repo como Processador Virtual
2
-
3
- ## Conceito: Storage = RAM = CPU
4
-
5
- > Memória RAM e armazenamento são a mesma coisa. A diferença é uso: uma guarda, outra processa.
6
- > Transformamos o lugar que guarda arquivo em lugar que processa arquivo.
7
-
8
- ### Como?
9
-
10
- 1. **Swap file**: `fallocate -l 16G /mnt/swapfile && mkswap && swapon` -> disco virou RAM
11
- 2. **tmpfs**: `mount -t tmpfs -o size=8G tmpfs /mnt/ramdisk` -> RAM virou disco ultra rápido
12
- 3. **ZRAM**: comprime RAM para caber 2-3x mais
13
- 4. **Repo como CPU**: GitHub Actions roda código, não só guarda. Cada `workflow_dispatch` é uma chamada de função serverless.
14
-
15
- ### Arquitetura Thin Client (V3)
16
-
17
- ```
18
- [Browser - GitHub Pages 50KB] --light--> [GitHub API] --dispatch--> [Actions Farm]
19
- - Preview 256 bytes - 4 vCPU, 16GB RAM, ilimitado público
20
- - SHA256 via Worker - Storage transformado em RAM via swap
21
- - Terminal fake - Resultado commitado em docs/results/
22
- <--polling-- status + artifact download ------
23
- ```
24
-
25
- ### Multi-Forja = Ilimitado real
26
-
27
- | Forja | Minutos | Storage | Como usar |
28
- |-------|---------|---------|-----------|
29
- | **GitHub Public** | Ilimitado (standard) | 500MB artifacts, 10GB cache/repo | Principal |
30
- | **Forgejo Self-Hosted** | Ilimitado (seu hardware) | Ilimitado | Mirror do repo |
31
- | **Gitea Self-Hosted** | Ilimitado | Ilimitado | Mirror |
32
- | **Codeberg + Woodpecker** | Ilimitado FLOSS | 750MB soft, pede mais via issue | Backup open source |
33
- | **GitLab Free** | 400 min/mês | 10GB por projeto | Fallback Pages |
34
-
35
- **Farm:** Crie 100 repos `opencode-worker-N`, cada um com 500MB free = 50GB distribuído. Script `scripts/farm.py` dispara para o primeiro livre.
36
-
37
- ### Como usar
38
-
39
- 1. Deploy `index.html` no Pages
40
- 2. Configure token com `repo` + `workflow`
41
- 3. Arraste binário -> clica "Enviar para GitHub para processar"
42
- 4. O binário NÃO roda no browser, só preview. O Action roda pesado.
43
- 5. Resultado aparece em `docs/results/{job_id}/` e baixa automático.
44
-
45
- ### Estrutura
46
-
47
- - `index.html` - V2 thin client GitHub only
48
- - `index-v3-multi-forge.html` - V3 com Forgejo/Gitea/Codeberg/GitLab
49
- - `.github/workflows/` - 5 workflows GitHub
50
- - `.forgejo/workflows/` - workflows Forgejo (swap + tmpfs)
51
- - `.gitea/workflows/` - idem Gitea
52
- - `.woodpecker/` - Codeberg Woodpecker CI
53
- - `.gitlab-ci.yml` - GitLab CI
54
- - `scripts/storage-as-ram.sh` - transforma storage em RAM
55
- - `scripts/farm.py` - orquestra N repos
56
-
57
- ### Por que não pesa o navegador?
58
-
59
- - Browser: só File API slice + base64 chunked + fetch
60
- - Heavy: acontece em `/mnt/ramdisk` dentro do runner, com swap de 16GB
61
- - Resultado: commitado no repo, Pages serve como CDN
62
-
63
- Sensação: usuário mexe no binário normal, exporta normal, mas processamento é no repo.
64
-
65
- ---
66
-
67
- # V4 - Teoria Completa: Repo como Casa do OS
68
-
69
- ## Fatos que você trouxe - raciocinando junto
70
-
71
- ### Fato 1: No Linux tudo é arquivo
72
- > Everything is a file - open/read/write/close retornam file descriptor
73
-
74
- No kernel tudo é struct inode + dentry + file_operations. Processo, memória, device, socket - tudo é arquivo.
75
-
76
- ```c
77
- struct file_operations {
78
- .read, .write, .mmap, .open...
79
- }
80
- ```
81
-
82
- Se implementa file_operations, É arquivo. VFS (Virtual File System Switch) abstrai ext4, tmpfs, proc, sysfs.
83
-
84
- Prova que storage e RAM são mesma coisa: ambas são files com backing diferente.
85
-
86
- ### Fato 2: Formatos, mimetypes, magic bytes
87
- Extensão é UX. Verdade está nos primeiros bytes:
88
-
89
- ```
90
- ELF: 7F 45 4C 46
91
- PE: 4D 5A (MZ) + 50 45 00 00 (PE)
92
- PNG: 89 50 4E 47 0D 0A 1A 0A
93
- ZIP: 50 4B 03 04 (por isso DOCX, APK, JAR = ZIP)
94
- ```
95
-
96
- `file` usa libmagic para detectar. MIME type é pra web (Content-Type), magic byte é pra SO decodificar.
97
-
98
- Repo guarda esses bytes estáticos. Quando busca, decodifica via magic.
99
-
100
- ### Fato 3: Encoding e Decoding
101
- Todo arquivo estático precisa encode/decode:
102
-
103
- - Encode: arquivo no disco (bytes estáticos)
104
- - Decode: loader lê magic, escolhe parser, mapeia pra RAM, executa
105
-
106
- Ex: Windows instala, arquivos ficam estáticos. Na hora de rodar, busca paginação, dump de memória, decodifica PE -> mapeia seções -> executa.
107
-
108
- Mesma coisa no nosso caso: repo guarda binário estático com magic, browser faz fetch, decodifica via WASM loader, executa.
109
-
110
- ### Fato 4: Sandbox tem VFS e virtual file - Docker, K8s
111
-
112
- Docker usa OverlayFS:
113
-
114
- ```
115
- lowerdir=/lower1:/lower2 (read-only, camadas da imagem)
116
- upperdir=/upper (writable)
117
- merged=/merged (o que processo vê)
118
- copy_up: primeira escrita copia arquivo inteiro do lower pro upper
119
- ```
120
-
121
- Imagem OCI = stack de tar.gz estáticos. `docker run` = monta overlay + cria namespace.
122
-
123
- Kubernetes ephemeral storage = tmpfs + emptyDir que é RAM.
124
-
125
- Ou seja: arquivos estáticos viram sistema rodando via overlay.
126
-
127
- ### Fato 5: Virtual file e virtual RAM, VMs
128
-
129
- VM = arquivo estático (qc