@peonai/swarm 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.dockerignore +6 -0
- package/Dockerfile +9 -0
- package/README.md +29 -0
- package/app/api/health/route.ts +2 -0
- package/app/api/v1/admin/agents/[id]/route.ts +12 -0
- package/app/api/v1/admin/agents/route.ts +31 -0
- package/app/api/v1/admin/audit/route.ts +23 -0
- package/app/api/v1/admin/cleanup/route.ts +21 -0
- package/app/api/v1/admin/export/route.ts +15 -0
- package/app/api/v1/admin/history/route.ts +23 -0
- package/app/api/v1/admin/profile/route.ts +23 -0
- package/app/api/v1/admin/settings/route.ts +44 -0
- package/app/api/v1/auth/route.ts +5 -0
- package/app/api/v1/memory/route.ts +105 -0
- package/app/api/v1/persona/[agentId]/route.ts +13 -0
- package/app/api/v1/persona/me/route.ts +12 -0
- package/app/api/v1/profile/observe/route.ts +34 -0
- package/app/api/v1/profile/route.ts +72 -0
- package/app/api/v1/reflect/route.ts +96 -0
- package/app/globals.css +190 -0
- package/app/i18n.ts +161 -0
- package/app/layout.tsx +12 -0
- package/app/page.tsx +561 -0
- package/docker-compose.yml +34 -0
- package/docs/DEBATE-ROUND1.md +244 -0
- package/docs/DEBATE-ROUND2.md +158 -0
- package/docs/REQUIREMENTS.md +162 -0
- package/docs/docs.html +272 -0
- package/docs/index.html +228 -0
- package/docs/script.js +103 -0
- package/docs/style.css +418 -0
- package/lib/auth.ts +63 -0
- package/lib/db.ts +63 -0
- package/lib/embedding.ts +29 -0
- package/lib/schema.ts +134 -0
- package/mcp-server.ts +56 -0
- package/next-env.d.ts +6 -0
- package/next.config.ts +5 -0
- package/package.json +34 -0
- package/packages/cli/README.md +33 -0
- package/packages/cli/bin/swarm.mjs +274 -0
- package/packages/cli/package.json +10 -0
- package/postcss.config.mjs +2 -0
- package/skill/CLAUDE.md +40 -0
- package/skill/CODEX.md +43 -0
- package/skill/GEMINI.md +38 -0
- package/skill/IFLOW.md +38 -0
- package/skill/OPENCODE.md +38 -0
- package/skill/swarm-ai-skill/SKILL.md +74 -0
- package/skill/swarm-ai-skill/env.sh +4 -0
- package/skill/swarm-ai-skill/scripts/bootstrap.sh +21 -0
- package/skill/swarm-ai-skill/scripts/env.sh +4 -0
- package/skill/swarm-ai-skill/scripts/env.sh.example +3 -0
- package/skill/swarm-ai-skill/scripts/memory-read.sh +8 -0
- package/skill/swarm-ai-skill/scripts/memory-write.sh +10 -0
- package/skill/swarm-ai-skill/scripts/observe.sh +9 -0
- package/skill/swarm-ai-skill/scripts/profile-read.sh +9 -0
- package/skill/swarm-ai-skill/scripts/profile-update.sh +9 -0
- package/skill/swarm-ai-skill/scripts/session-start.sh +19 -0
- package/tsconfig.json +21 -0
- package/tsconfig.tsbuildinfo +1 -0
package/docs/style.css
ADDED
|
@@ -0,0 +1,418 @@
|
|
|
1
|
+
:root {
|
|
2
|
+
--bg: #0a0a0f;
|
|
3
|
+
--bg2: #12121a;
|
|
4
|
+
--surface: #1a1a25;
|
|
5
|
+
--border: #2a2a3a;
|
|
6
|
+
--text: #e8e8ed;
|
|
7
|
+
--text2: #9898a8;
|
|
8
|
+
--amber: #f0a830;
|
|
9
|
+
--amber2: #d4922a;
|
|
10
|
+
--amber-glow: rgba(240,168,48,0.15);
|
|
11
|
+
--green: #34d399;
|
|
12
|
+
--blue: #60a5fa;
|
|
13
|
+
--red: #f87171;
|
|
14
|
+
--font: 'Inter', -apple-system, sans-serif;
|
|
15
|
+
--mono: 'JetBrains Mono', monospace;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
|
|
19
|
+
|
|
20
|
+
html { scroll-behavior: smooth; }
|
|
21
|
+
|
|
22
|
+
body {
|
|
23
|
+
font-family: var(--font);
|
|
24
|
+
background: var(--bg);
|
|
25
|
+
color: var(--text);
|
|
26
|
+
line-height: 1.6;
|
|
27
|
+
-webkit-font-smoothing: antialiased;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.container { max-width: 1100px; margin: 0 auto; padding: 0 24px; }
|
|
31
|
+
|
|
32
|
+
a { color: var(--amber); text-decoration: none; }
|
|
33
|
+
a:hover { color: var(--amber2); }
|
|
34
|
+
|
|
35
|
+
/* Nav */
|
|
36
|
+
.nav {
|
|
37
|
+
position: fixed; top: 0; left: 0; right: 0; z-index: 100;
|
|
38
|
+
background: rgba(10,10,15,0.85);
|
|
39
|
+
backdrop-filter: blur(12px);
|
|
40
|
+
border-bottom: 1px solid var(--border);
|
|
41
|
+
}
|
|
42
|
+
.nav-inner {
|
|
43
|
+
max-width: 1100px; margin: 0 auto; padding: 0 24px;
|
|
44
|
+
display: flex; align-items: center; justify-content: space-between; height: 60px;
|
|
45
|
+
}
|
|
46
|
+
.nav-logo {
|
|
47
|
+
display: flex; align-items: center; gap: 10px;
|
|
48
|
+
color: var(--text); font-weight: 600; font-size: 1.1rem;
|
|
49
|
+
}
|
|
50
|
+
.nav-logo svg { color: var(--amber); }
|
|
51
|
+
.nav-links { display: flex; align-items: center; gap: 28px; }
|
|
52
|
+
.nav-links a { color: var(--text2); font-size: 0.9rem; transition: color 0.2s; }
|
|
53
|
+
.nav-links a:hover { color: var(--text); }
|
|
54
|
+
.nav-cta {
|
|
55
|
+
background: var(--amber); color: var(--bg) !important; padding: 6px 16px;
|
|
56
|
+
border-radius: 6px; font-weight: 600; font-size: 0.85rem;
|
|
57
|
+
}
|
|
58
|
+
.nav-cta:hover { background: var(--amber2); }
|
|
59
|
+
|
|
60
|
+
/* Hero */
|
|
61
|
+
.hero {
|
|
62
|
+
position: relative; min-height: 100vh; display: flex; align-items: center;
|
|
63
|
+
justify-content: center; overflow: hidden; padding-top: 60px;
|
|
64
|
+
}
|
|
65
|
+
#hexCanvas {
|
|
66
|
+
position: absolute; inset: 0; width: 100%; height: 100%; opacity: 0.4;
|
|
67
|
+
}
|
|
68
|
+
.hero-content {
|
|
69
|
+
position: relative; z-index: 1; text-align: center; max-width: 700px; padding: 0 24px;
|
|
70
|
+
}
|
|
71
|
+
.hero-eyebrow {
|
|
72
|
+
font-size: 0.85rem; text-transform: uppercase; letter-spacing: 3px;
|
|
73
|
+
color: var(--amber); margin-bottom: 20px; font-weight: 500;
|
|
74
|
+
}
|
|
75
|
+
.hero h1 {
|
|
76
|
+
font-size: clamp(2.4rem, 6vw, 4rem); font-weight: 700; line-height: 1.15;
|
|
77
|
+
margin-bottom: 24px;
|
|
78
|
+
background: linear-gradient(135deg, var(--text) 0%, var(--amber) 100%);
|
|
79
|
+
-webkit-background-clip: text; -webkit-text-fill-color: transparent;
|
|
80
|
+
background-clip: text;
|
|
81
|
+
}
|
|
82
|
+
.hero-sub { font-size: 1.15rem; color: var(--text2); max-width: 540px; margin: 0 auto 36px; }
|
|
83
|
+
.hero-actions { display: flex; gap: 16px; justify-content: center; }
|
|
84
|
+
.hero-code {
|
|
85
|
+
background: rgba(240,168,48,0.08); border: 1px solid rgba(240,168,48,0.2);
|
|
86
|
+
border-radius: 8px; padding: 14px 28px; font-family: var(--mono); font-size: 1.1rem;
|
|
87
|
+
color: var(--amber); margin: 0 auto 28px; width: fit-content;
|
|
88
|
+
}
|
|
89
|
+
.hero-code code { background: none; padding: 0; }
|
|
90
|
+
|
|
91
|
+
.btn {
|
|
92
|
+
display: inline-flex; align-items: center; padding: 12px 28px;
|
|
93
|
+
border-radius: 8px; font-weight: 600; font-size: 0.95rem; transition: all 0.2s;
|
|
94
|
+
}
|
|
95
|
+
.btn-primary { background: var(--amber); color: var(--bg); }
|
|
96
|
+
.btn-primary:hover { background: var(--amber2); transform: translateY(-1px); box-shadow: 0 8px 30px var(--amber-glow); }
|
|
97
|
+
.btn-ghost { border: 1px solid var(--border); color: var(--text); }
|
|
98
|
+
.btn-ghost:hover { border-color: var(--amber); color: var(--amber); }
|
|
99
|
+
|
|
100
|
+
/* Sections */
|
|
101
|
+
.section { padding: 120px 0; }
|
|
102
|
+
.section-label {
|
|
103
|
+
font-size: 0.8rem; text-transform: uppercase; letter-spacing: 3px;
|
|
104
|
+
color: var(--amber); margin-bottom: 16px; font-weight: 500;
|
|
105
|
+
}
|
|
106
|
+
.section h2 { font-size: clamp(1.8rem, 4vw, 2.6rem); font-weight: 700; margin-bottom: 20px; line-height: 1.2; }
|
|
107
|
+
.section-desc { font-size: 1.1rem; color: var(--text2); max-width: 640px; margin-bottom: 48px; }
|
|
108
|
+
|
|
109
|
+
/* Problem */
|
|
110
|
+
.section-problem { background: var(--bg2); }
|
|
111
|
+
.silo-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 20px; }
|
|
112
|
+
.silo-card {
|
|
113
|
+
background: var(--surface); border: 1px solid var(--border); border-radius: 12px;
|
|
114
|
+
padding: 32px 24px; text-align: center; transition: transform 0.3s, border-color 0.3s;
|
|
115
|
+
}
|
|
116
|
+
.silo-card:hover { transform: translateY(-4px); }
|
|
117
|
+
.silo-card h3 { font-size: 1rem; margin: 16px 0 8px; }
|
|
118
|
+
.silo-card p { font-size: 0.9rem; color: var(--text2); font-style: italic; }
|
|
119
|
+
.silo-card-accent { border-color: var(--amber); background: linear-gradient(135deg, var(--surface), rgba(240,168,48,0.08)); }
|
|
120
|
+
.silo-card-accent p { color: var(--amber); font-style: normal; font-weight: 500; }
|
|
121
|
+
.silo-icon { color: var(--text2); }
|
|
122
|
+
.silo-card-accent .silo-icon { color: var(--amber); }
|
|
123
|
+
|
|
124
|
+
/* Features */
|
|
125
|
+
.feature-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 24px; margin-top: 48px; }
|
|
126
|
+
.feature-card {
|
|
127
|
+
background: var(--surface); border: 1px solid var(--border); border-radius: 12px;
|
|
128
|
+
padding: 28px; transition: transform 0.3s, border-color 0.3s;
|
|
129
|
+
}
|
|
130
|
+
.feature-card:hover { transform: translateY(-4px); border-color: rgba(240,168,48,0.3); }
|
|
131
|
+
.feature-icon { margin-bottom: 16px; }
|
|
132
|
+
.feature-card h3 { font-size: 1.05rem; margin-bottom: 8px; }
|
|
133
|
+
.feature-card p { font-size: 0.9rem; color: var(--text2); }
|
|
134
|
+
|
|
135
|
+
/* CTA */
|
|
136
|
+
.section-cta { padding: 100px 0; background: linear-gradient(180deg, var(--bg) 0%, var(--bg2) 100%); }
|
|
137
|
+
|
|
138
|
+
/* Steps */
|
|
139
|
+
.steps { display: grid; grid-template-columns: repeat(3, 1fr); gap: 40px; margin-top: 48px; }
|
|
140
|
+
.step { position: relative; }
|
|
141
|
+
.step-num {
|
|
142
|
+
font-size: 3rem; font-weight: 700; color: var(--amber); opacity: 0.3;
|
|
143
|
+
line-height: 1; margin-bottom: 16px;
|
|
144
|
+
}
|
|
145
|
+
.step-line {
|
|
146
|
+
width: 40px; height: 2px; background: var(--amber); margin-bottom: 16px; opacity: 0.5;
|
|
147
|
+
}
|
|
148
|
+
.step h3 { font-size: 1.2rem; margin-bottom: 10px; }
|
|
149
|
+
.step p { color: var(--text2); font-size: 0.95rem; }
|
|
150
|
+
|
|
151
|
+
/* Architecture */
|
|
152
|
+
.section-arch { background: var(--bg2); }
|
|
153
|
+
.arch-diagram { text-align: center; margin-top: 48px; }
|
|
154
|
+
.arch-agents { display: flex; justify-content: center; gap: 24px; margin-bottom: 32px; }
|
|
155
|
+
.arch-node {
|
|
156
|
+
background: var(--surface); border: 1px solid var(--border); border-radius: 8px;
|
|
157
|
+
padding: 12px 24px; font-size: 0.9rem; font-weight: 500;
|
|
158
|
+
}
|
|
159
|
+
.arch-lines { height: 60px; max-width: 400px; margin: 0 auto; }
|
|
160
|
+
.arch-lines svg { width: 100%; height: 100%; }
|
|
161
|
+
.arch-center { margin-bottom: 24px; }
|
|
162
|
+
.arch-server {
|
|
163
|
+
display: inline-block; background: linear-gradient(135deg, var(--amber), var(--amber2));
|
|
164
|
+
color: var(--bg); padding: 20px 40px; border-radius: 12px;
|
|
165
|
+
font-weight: 700; font-size: 1.1rem;
|
|
166
|
+
box-shadow: 0 12px 40px var(--amber-glow);
|
|
167
|
+
}
|
|
168
|
+
.arch-server span { display: block; font-size: 0.8rem; font-weight: 400; opacity: 0.8; margin-top: 4px; }
|
|
169
|
+
.arch-layers { display: flex; justify-content: center; gap: 12px; margin-top: 24px; }
|
|
170
|
+
.arch-layer {
|
|
171
|
+
background: var(--surface); border: 1px solid var(--border); border-radius: 6px;
|
|
172
|
+
padding: 8px 18px; font-size: 0.8rem; color: var(--text2);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/* Integration */
|
|
176
|
+
.section-integration { background: var(--bg); }
|
|
177
|
+
.integration-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 20px; }
|
|
178
|
+
.integration-card {
|
|
179
|
+
background: var(--surface); border: 1px solid var(--border); border-radius: 12px; padding: 28px;
|
|
180
|
+
}
|
|
181
|
+
.integration-card h3 { font-size: 1.05rem; margin-bottom: 8px; color: var(--amber); }
|
|
182
|
+
.integration-card p { font-size: 0.9rem; color: var(--text2); margin-bottom: 12px; }
|
|
183
|
+
.integration-card pre {
|
|
184
|
+
background: var(--bg); border: 1px solid var(--border); border-radius: 8px;
|
|
185
|
+
padding: 12px 16px; overflow-x: auto;
|
|
186
|
+
}
|
|
187
|
+
.integration-card code { font-family: var(--mono); font-size: 0.82rem; color: var(--green); }
|
|
188
|
+
|
|
189
|
+
/* Profile */
|
|
190
|
+
.section-profile { background: var(--bg2); }
|
|
191
|
+
.profile-demo { display: grid; grid-template-columns: 1fr 1fr; gap: 40px; margin-top: 48px; }
|
|
192
|
+
.profile-layer {
|
|
193
|
+
background: var(--surface); border: 1px solid var(--border); border-radius: 10px;
|
|
194
|
+
margin-bottom: 16px; overflow: hidden;
|
|
195
|
+
}
|
|
196
|
+
.layer-header {
|
|
197
|
+
padding: 10px 16px; font-family: var(--mono); font-size: 0.85rem; font-weight: 500;
|
|
198
|
+
background: rgba(240,168,48,0.08); border-bottom: 1px solid var(--border); color: var(--amber);
|
|
199
|
+
}
|
|
200
|
+
.ttl-badge {
|
|
201
|
+
font-size: 0.7rem; background: rgba(248,113,113,0.15); color: var(--red);
|
|
202
|
+
padding: 2px 8px; border-radius: 4px; margin-left: 8px;
|
|
203
|
+
}
|
|
204
|
+
.layer-body { padding: 12px 16px; }
|
|
205
|
+
.layer-field {
|
|
206
|
+
display: flex; align-items: center; gap: 12px; padding: 6px 0;
|
|
207
|
+
font-size: 0.85rem; border-bottom: 1px solid rgba(42,42,58,0.5);
|
|
208
|
+
}
|
|
209
|
+
.layer-field:last-child { border-bottom: none; }
|
|
210
|
+
.field-key { font-family: var(--mono); color: var(--blue); min-width: 100px; }
|
|
211
|
+
.field-val { font-family: var(--mono); color: var(--green); flex: 1; }
|
|
212
|
+
.field-meta { font-size: 0.75rem; color: var(--text2); }
|
|
213
|
+
.profile-info h3 { font-size: 1rem; margin: 20px 0 6px; color: var(--text); }
|
|
214
|
+
.profile-info h3:first-child { margin-top: 0; }
|
|
215
|
+
.profile-info p { font-size: 0.9rem; color: var(--text2); }
|
|
216
|
+
|
|
217
|
+
/* API */
|
|
218
|
+
.api-table-wrap { overflow-x: auto; margin-top: 40px; }
|
|
219
|
+
.api-table { width: 100%; border-collapse: collapse; }
|
|
220
|
+
.api-table th {
|
|
221
|
+
text-align: left; padding: 12px 16px; font-size: 0.8rem; text-transform: uppercase;
|
|
222
|
+
letter-spacing: 1px; color: var(--text2); border-bottom: 2px solid var(--border);
|
|
223
|
+
}
|
|
224
|
+
.api-table td { padding: 14px 16px; border-bottom: 1px solid var(--border); font-size: 0.9rem; }
|
|
225
|
+
.method {
|
|
226
|
+
font-family: var(--mono); font-size: 0.75rem; font-weight: 600; padding: 3px 8px;
|
|
227
|
+
border-radius: 4px;
|
|
228
|
+
}
|
|
229
|
+
.method.get { background: rgba(96,165,250,0.15); color: var(--blue); }
|
|
230
|
+
.method.post { background: rgba(52,211,153,0.15); color: var(--green); }
|
|
231
|
+
.method.patch { background: rgba(240,168,48,0.15); color: var(--amber); }
|
|
232
|
+
.api-example {
|
|
233
|
+
margin-top: 32px; background: var(--surface); border: 1px solid var(--border); border-radius: 12px; overflow: hidden;
|
|
234
|
+
}
|
|
235
|
+
.api-example-header {
|
|
236
|
+
padding: 12px 20px; font-size: 0.85rem; font-weight: 500;
|
|
237
|
+
background: rgba(240,168,48,0.06); border-bottom: 1px solid var(--border);
|
|
238
|
+
}
|
|
239
|
+
.api-example pre { padding: 20px; overflow-x: auto; }
|
|
240
|
+
.api-example code { font-family: var(--mono); font-size: 0.82rem; color: var(--text); }
|
|
241
|
+
|
|
242
|
+
/* Quickstart */
|
|
243
|
+
.section-start { background: var(--bg2); }
|
|
244
|
+
.start-steps { margin-top: 48px; }
|
|
245
|
+
.start-step {
|
|
246
|
+
display: flex; gap: 24px; margin-bottom: 32px; align-items: flex-start;
|
|
247
|
+
}
|
|
248
|
+
.start-step-num {
|
|
249
|
+
width: 40px; height: 40px; border-radius: 50%; flex-shrink: 0;
|
|
250
|
+
background: var(--amber); color: var(--bg); display: flex; align-items: center;
|
|
251
|
+
justify-content: center; font-weight: 700; font-size: 1rem;
|
|
252
|
+
}
|
|
253
|
+
.start-step-content { flex: 1; }
|
|
254
|
+
.start-step-content h3 { font-size: 1.05rem; margin-bottom: 12px; }
|
|
255
|
+
.start-step-content pre {
|
|
256
|
+
background: var(--bg); border: 1px solid var(--border); border-radius: 8px;
|
|
257
|
+
padding: 16px 20px; overflow-x: auto;
|
|
258
|
+
}
|
|
259
|
+
.start-step-content code { font-family: var(--mono); font-size: 0.82rem; color: var(--green); }
|
|
260
|
+
|
|
261
|
+
/* Footer */
|
|
262
|
+
.footer { padding: 48px 0; border-top: 1px solid var(--border); }
|
|
263
|
+
.footer-inner { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 16px; }
|
|
264
|
+
.footer-brand { display: flex; align-items: center; gap: 8px; color: var(--text2); font-weight: 500; }
|
|
265
|
+
.footer-brand svg { color: var(--amber); }
|
|
266
|
+
.footer-links { display: flex; gap: 24px; }
|
|
267
|
+
.footer-links a { color: var(--text2); font-size: 0.9rem; }
|
|
268
|
+
.footer-links a:hover { color: var(--amber); }
|
|
269
|
+
.footer-copy { color: var(--text2); font-size: 0.8rem; }
|
|
270
|
+
|
|
271
|
+
/* ===== Animations ===== */
|
|
272
|
+
|
|
273
|
+
/* Hero entrance */
|
|
274
|
+
.hero-content { opacity: 0; animation: heroIn 1s ease-out 0.3s forwards; }
|
|
275
|
+
@keyframes heroIn {
|
|
276
|
+
from { opacity: 0; transform: translateY(30px); }
|
|
277
|
+
to { opacity: 1; transform: translateY(0); }
|
|
278
|
+
}
|
|
279
|
+
.hero-eyebrow { opacity: 0; animation: fadeSlideUp 0.6s ease-out 0.5s forwards; }
|
|
280
|
+
.hero h1 { opacity: 0; animation: fadeSlideUp 0.8s ease-out 0.7s forwards; }
|
|
281
|
+
.hero-sub { opacity: 0; animation: fadeSlideUp 0.6s ease-out 1s forwards; }
|
|
282
|
+
.hero-actions { opacity: 0; animation: fadeSlideUp 0.6s ease-out 1.2s forwards; }
|
|
283
|
+
|
|
284
|
+
@keyframes fadeSlideUp {
|
|
285
|
+
from { opacity: 0; transform: translateY(20px); }
|
|
286
|
+
to { opacity: 1; transform: translateY(0); }
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/* Accent card glow pulse */
|
|
290
|
+
.silo-card-accent { animation: glowPulse 3s ease-in-out infinite; }
|
|
291
|
+
@keyframes glowPulse {
|
|
292
|
+
0%, 100% { box-shadow: 0 0 20px rgba(240,168,48,0.1); }
|
|
293
|
+
50% { box-shadow: 0 0 40px rgba(240,168,48,0.25), 0 0 80px rgba(240,168,48,0.08); }
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/* Staggered children reveal */
|
|
297
|
+
.section .stagger { opacity: 0; transform: translateY(24px); transition: opacity 0.5s ease-out, transform 0.5s ease-out; }
|
|
298
|
+
.section.visible .stagger { opacity: 1; transform: translateY(0); }
|
|
299
|
+
.section.visible .stagger:nth-child(1) { transition-delay: 0.1s; }
|
|
300
|
+
.section.visible .stagger:nth-child(2) { transition-delay: 0.2s; }
|
|
301
|
+
.section.visible .stagger:nth-child(3) { transition-delay: 0.3s; }
|
|
302
|
+
.section.visible .stagger:nth-child(4) { transition-delay: 0.4s; }
|
|
303
|
+
.section.visible .stagger:nth-child(5) { transition-delay: 0.5s; }
|
|
304
|
+
.section.visible .stagger:nth-child(6) { transition-delay: 0.6s; }
|
|
305
|
+
|
|
306
|
+
/* Step line grow */
|
|
307
|
+
.step-line { width: 0; transition: width 0.8s ease-out; }
|
|
308
|
+
.section.visible .step .step-line { width: 40px; }
|
|
309
|
+
.section.visible .step:nth-child(1) .step-line { transition-delay: 0.2s; }
|
|
310
|
+
.section.visible .step:nth-child(2) .step-line { transition-delay: 0.4s; }
|
|
311
|
+
.section.visible .step:nth-child(3) .step-line { transition-delay: 0.6s; }
|
|
312
|
+
|
|
313
|
+
/* Feature card hover glow */
|
|
314
|
+
.feature-card { position: relative; overflow: hidden; }
|
|
315
|
+
.feature-card::after {
|
|
316
|
+
content: ''; position: absolute; inset: 0; border-radius: 12px;
|
|
317
|
+
background: radial-gradient(circle at var(--mx, 50%) var(--my, 50%), rgba(240,168,48,0.08) 0%, transparent 60%);
|
|
318
|
+
opacity: 0; transition: opacity 0.3s;
|
|
319
|
+
}
|
|
320
|
+
.feature-card:hover::after { opacity: 1; }
|
|
321
|
+
|
|
322
|
+
/* Arch server pulse */
|
|
323
|
+
.arch-server { animation: serverGlow 4s ease-in-out infinite; }
|
|
324
|
+
@keyframes serverGlow {
|
|
325
|
+
0%, 100% { box-shadow: 0 12px 40px rgba(240,168,48,0.15); }
|
|
326
|
+
50% { box-shadow: 0 16px 60px rgba(240,168,48,0.35); }
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/* Arch node hover */
|
|
330
|
+
.arch-node { transition: transform 0.3s, border-color 0.3s, box-shadow 0.3s; }
|
|
331
|
+
.arch-node:hover {
|
|
332
|
+
transform: translateY(-3px); border-color: var(--amber);
|
|
333
|
+
box-shadow: 0 4px 20px rgba(240,168,48,0.1);
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/* Data flow dots on arch lines */
|
|
337
|
+
@keyframes flowDot {
|
|
338
|
+
0% { offset-distance: 0%; opacity: 0; }
|
|
339
|
+
10% { opacity: 1; }
|
|
340
|
+
90% { opacity: 1; }
|
|
341
|
+
100% { offset-distance: 100%; opacity: 0; }
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
/* Nav slide in */
|
|
345
|
+
.nav { animation: navSlide 0.5s ease-out; }
|
|
346
|
+
@keyframes navSlide {
|
|
347
|
+
from { transform: translateY(-100%); }
|
|
348
|
+
to { transform: translateY(0); }
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
/* Floating particles */
|
|
352
|
+
.particle {
|
|
353
|
+
position: absolute; width: 3px; height: 3px; border-radius: 50%;
|
|
354
|
+
background: var(--amber); opacity: 0; z-index: 0;
|
|
355
|
+
animation: particleFloat linear infinite;
|
|
356
|
+
}
|
|
357
|
+
@keyframes particleFloat {
|
|
358
|
+
0% { opacity: 0; transform: translateY(0) scale(0); }
|
|
359
|
+
15% { opacity: 0.6; transform: scale(1); }
|
|
360
|
+
85% { opacity: 0.3; }
|
|
361
|
+
100% { opacity: 0; transform: translateY(-120px) scale(0.5); }
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
/* Scroll animations */
|
|
365
|
+
.section { opacity: 0; transform: translateY(30px); transition: opacity 0.6s ease-out, transform 0.6s ease-out; }
|
|
366
|
+
.section.visible { opacity: 1; transform: translateY(0); }
|
|
367
|
+
|
|
368
|
+
/* Responsive */
|
|
369
|
+
@media (max-width: 768px) {
|
|
370
|
+
.nav-links a:not(.nav-cta) { display: none; }
|
|
371
|
+
.silo-grid { grid-template-columns: repeat(2, 1fr); }
|
|
372
|
+
.steps { grid-template-columns: 1fr; gap: 32px; }
|
|
373
|
+
.arch-agents { flex-wrap: wrap; }
|
|
374
|
+
.integration-grid { grid-template-columns: 1fr; }
|
|
375
|
+
.profile-demo { grid-template-columns: 1fr; }
|
|
376
|
+
.arch-layers { flex-wrap: wrap; }
|
|
377
|
+
.feature-grid { grid-template-columns: 1fr; }
|
|
378
|
+
.section { padding: 80px 0; }
|
|
379
|
+
.docs-sidebar { display: none; }
|
|
380
|
+
.docs-main { margin-left: 0; }
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
/* Docs page layout */
|
|
384
|
+
.docs-page { padding-top: 60px; }
|
|
385
|
+
.docs-layout { display: flex; min-height: calc(100vh - 60px); }
|
|
386
|
+
.docs-sidebar {
|
|
387
|
+
position: fixed; top: 60px; left: 0; bottom: 0; width: 240px;
|
|
388
|
+
background: var(--bg2); border-right: 1px solid var(--border);
|
|
389
|
+
padding: 32px 20px; overflow-y: auto;
|
|
390
|
+
}
|
|
391
|
+
.sidebar-section { margin-bottom: 28px; }
|
|
392
|
+
.sidebar-title {
|
|
393
|
+
font-size: 0.7rem; text-transform: uppercase; letter-spacing: 2px;
|
|
394
|
+
color: var(--text2); margin-bottom: 10px; font-weight: 600;
|
|
395
|
+
}
|
|
396
|
+
.docs-sidebar a {
|
|
397
|
+
display: block; padding: 5px 0; font-size: 0.88rem; color: var(--text2); transition: color 0.2s;
|
|
398
|
+
}
|
|
399
|
+
.docs-sidebar a:hover { color: var(--amber); }
|
|
400
|
+
.docs-main {
|
|
401
|
+
margin-left: 240px; flex: 1; padding: 48px 56px; max-width: 860px;
|
|
402
|
+
}
|
|
403
|
+
.doc-section { margin-bottom: 72px; }
|
|
404
|
+
.doc-section h1 { font-size: 2rem; margin-bottom: 12px; }
|
|
405
|
+
.doc-section h2 { font-size: 1.3rem; margin: 36px 0 12px; color: var(--text); }
|
|
406
|
+
.doc-section p { color: var(--text2); margin-bottom: 16px; line-height: 1.7; }
|
|
407
|
+
.doc-section ul { color: var(--text2); margin: 0 0 16px 20px; }
|
|
408
|
+
.doc-section li { margin-bottom: 6px; }
|
|
409
|
+
.doc-section pre {
|
|
410
|
+
background: var(--surface); border: 1px solid var(--border); border-radius: 8px;
|
|
411
|
+
padding: 16px 20px; overflow-x: auto; margin-bottom: 20px;
|
|
412
|
+
}
|
|
413
|
+
.doc-section code { font-family: var(--mono); font-size: 0.85rem; }
|
|
414
|
+
.doc-section p code {
|
|
415
|
+
background: var(--surface); padding: 2px 6px; border-radius: 4px; font-size: 0.82rem;
|
|
416
|
+
}
|
|
417
|
+
.doc-section pre code { color: var(--green); }
|
|
418
|
+
.method.delete { background: rgba(248,113,113,0.15); color: var(--red); }
|
package/lib/auth.ts
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
2
|
+
import { jwtVerify } from 'jose';
|
|
3
|
+
import { getAgentByKey } from './schema';
|
|
4
|
+
|
|
5
|
+
const JWT_SECRET = new TextEncoder().encode(process.env.SWARM_JWT_SECRET || 'swarm-dev-secret');
|
|
6
|
+
|
|
7
|
+
async function verifyJwt(token: string): Promise<{ userId: string } | null> {
|
|
8
|
+
try {
|
|
9
|
+
const { payload } = await jwtVerify(token, JWT_SECRET);
|
|
10
|
+
return payload.userId ? { userId: payload.userId as string } : null;
|
|
11
|
+
} catch { return null; }
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function withAuth(handler: (req: NextRequest, agent: { id: string; userId: string; permissions: string }) => Promise<NextResponse>) {
|
|
15
|
+
return async (req: NextRequest) => {
|
|
16
|
+
const key = req.headers.get('authorization')?.replace('Bearer ', '');
|
|
17
|
+
if (!key) return NextResponse.json({ error: 'Missing API key' }, { status: 401 });
|
|
18
|
+
const agent = await getAgentByKey(key);
|
|
19
|
+
if (!agent) return NextResponse.json({ error: 'Invalid API key' }, { status: 401 });
|
|
20
|
+
return handler(req, agent);
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function withAdmin(handler: (req: NextRequest, userId: string) => Promise<NextResponse>) {
|
|
25
|
+
return async (req: NextRequest) => {
|
|
26
|
+
// Accept admin token OR JWT from admin user
|
|
27
|
+
const token = req.headers.get('x-admin-token') || req.nextUrl.searchParams.get('token');
|
|
28
|
+
if (token === (process.env.SWARM_ADMIN_TOKEN || 'swarm-admin-dev')) {
|
|
29
|
+
const { ensureDefaultUser } = await import('./schema');
|
|
30
|
+
return handler(req, await ensureDefaultUser());
|
|
31
|
+
}
|
|
32
|
+
const jwt = req.headers.get('authorization')?.replace('Bearer ', '');
|
|
33
|
+
if (jwt) {
|
|
34
|
+
const payload = await verifyJwt(jwt);
|
|
35
|
+
if (payload?.userId) return handler(req, payload.userId);
|
|
36
|
+
}
|
|
37
|
+
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export { initSchema } from './schema';
|
|
42
|
+
|
|
43
|
+
export function withAuthOrAdmin(handler: (req: NextRequest, agent: { id: string; userId: string; permissions: string }) => Promise<NextResponse>) {
|
|
44
|
+
return async (req: NextRequest) => {
|
|
45
|
+
// Try agent API key first
|
|
46
|
+
const key = req.headers.get('authorization')?.replace('Bearer ', '');
|
|
47
|
+
if (key) {
|
|
48
|
+
const agent = await getAgentByKey(key);
|
|
49
|
+
if (agent) return handler(req, agent);
|
|
50
|
+
// Try JWT
|
|
51
|
+
const payload = await verifyJwt(key);
|
|
52
|
+
if (payload?.userId) return handler(req, { id: 'admin', userId: payload.userId, permissions: 'read,write' });
|
|
53
|
+
}
|
|
54
|
+
// Try admin token
|
|
55
|
+
const token = req.headers.get('x-admin-token') || req.nextUrl.searchParams.get('token');
|
|
56
|
+
if (token === (process.env.SWARM_ADMIN_TOKEN || 'swarm-admin-dev')) {
|
|
57
|
+
const { ensureDefaultUser } = await import('./schema');
|
|
58
|
+
const userId = await ensureDefaultUser();
|
|
59
|
+
return handler(req, { id: 'admin', userId, permissions: 'read,write' });
|
|
60
|
+
}
|
|
61
|
+
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
|
|
62
|
+
};
|
|
63
|
+
}
|
package/lib/db.ts
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/* db.ts — dual backend: SQLite (dev) / PostgreSQL (prod)
|
|
2
|
+
All methods return Promises for uniform async interface */
|
|
3
|
+
import { mkdirSync } from 'fs';
|
|
4
|
+
import { join, dirname } from 'path';
|
|
5
|
+
|
|
6
|
+
const DATABASE_URL = process.env.DATABASE_URL;
|
|
7
|
+
|
|
8
|
+
export interface Stmt {
|
|
9
|
+
run(...p: any[]): Promise<any>;
|
|
10
|
+
get(...p: any[]): Promise<any>;
|
|
11
|
+
all(...p: any[]): Promise<any[]>;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface DB {
|
|
15
|
+
exec(sql: string): Promise<void>;
|
|
16
|
+
prepare(sql: string): Stmt;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
let db: DB;
|
|
20
|
+
|
|
21
|
+
if (DATABASE_URL) {
|
|
22
|
+
/* ── PostgreSQL ── */
|
|
23
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
24
|
+
const { Pool } = require('pg');
|
|
25
|
+
const pool = new Pool({ connectionString: DATABASE_URL });
|
|
26
|
+
|
|
27
|
+
db = {
|
|
28
|
+
async exec(sql: string) { await pool.query(sql); },
|
|
29
|
+
prepare(sql: string) {
|
|
30
|
+
let idx = 0;
|
|
31
|
+
const pgSql = sql.replace(/\?/g, () => `$${++idx}`);
|
|
32
|
+
return {
|
|
33
|
+
async run(...params: any[]) { return pool.query(pgSql, params); },
|
|
34
|
+
async get(...params: any[]) { const r = await pool.query(pgSql, params); return r.rows[0] || null; },
|
|
35
|
+
async all(...params: any[]) { const r = await pool.query(pgSql, params); return r.rows; },
|
|
36
|
+
};
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
} else {
|
|
40
|
+
/* ── SQLite ── */
|
|
41
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
42
|
+
const { DatabaseSync } = require('node:sqlite');
|
|
43
|
+
const DB_PATH = process.env.SWARM_DB_PATH || join(process.cwd(), 'data/swarm.db');
|
|
44
|
+
mkdirSync(dirname(DB_PATH), { recursive: true });
|
|
45
|
+
const sqlite = new DatabaseSync(DB_PATH);
|
|
46
|
+
sqlite.exec('PRAGMA journal_mode = WAL');
|
|
47
|
+
sqlite.exec('PRAGMA foreign_keys = ON');
|
|
48
|
+
|
|
49
|
+
db = {
|
|
50
|
+
async exec(sql: string) { sqlite.exec(sql); },
|
|
51
|
+
prepare(sql: string) {
|
|
52
|
+
const stmt = sqlite.prepare(sql);
|
|
53
|
+
return {
|
|
54
|
+
async run(...p: any[]) { return stmt.run(...p); },
|
|
55
|
+
async get(...p: any[]) { return stmt.get(...p); },
|
|
56
|
+
async all(...p: any[]) { return stmt.all(...p); },
|
|
57
|
+
};
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export default db;
|
|
63
|
+
export const isPg = !!DATABASE_URL;
|
package/lib/embedding.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/* embedding.ts — OpenAI-compatible embedding API, graceful fallback */
|
|
2
|
+
const EMBED_URL = process.env.EMBED_URL || '';
|
|
3
|
+
const EMBED_KEY = process.env.EMBED_KEY || '';
|
|
4
|
+
const EMBED_MODEL = process.env.EMBED_MODEL || 'text-embedding-3-small';
|
|
5
|
+
|
|
6
|
+
export const embeddingEnabled = !!(EMBED_URL && EMBED_KEY);
|
|
7
|
+
|
|
8
|
+
export async function embed(text: string): Promise<number[]> {
|
|
9
|
+
if (!embeddingEnabled) return [];
|
|
10
|
+
const res = await fetch(EMBED_URL, {
|
|
11
|
+
method: 'POST',
|
|
12
|
+
headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${EMBED_KEY}` },
|
|
13
|
+
body: JSON.stringify({ model: EMBED_MODEL, input: text }),
|
|
14
|
+
});
|
|
15
|
+
if (!res.ok) throw new Error(`Embedding API ${res.status}`);
|
|
16
|
+
const data = await res.json();
|
|
17
|
+
return data.data[0].embedding;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function cosine(a: number[], b: number[]): number {
|
|
21
|
+
if (!a.length || !b.length) return 0;
|
|
22
|
+
let dot = 0, na = 0, nb = 0;
|
|
23
|
+
for (let i = 0; i < a.length; i++) { dot += a[i] * b[i]; na += a[i] * a[i]; nb += b[i] * b[i]; }
|
|
24
|
+
return dot / (Math.sqrt(na) * Math.sqrt(nb) || 1);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function getEmbeddingConfig() {
|
|
28
|
+
return { url: EMBED_URL, model: EMBED_MODEL, enabled: embeddingEnabled };
|
|
29
|
+
}
|