loki-mode 6.71.0 → 6.72.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/README.md +9 -1
- package/SKILL.md +2 -2
- package/VERSION +1 -1
- package/autonomy/hooks/migration-hooks.sh +26 -0
- package/autonomy/loki +429 -92
- package/autonomy/run.sh +219 -38
- package/dashboard/__init__.py +1 -1
- package/dashboard/server.py +101 -19
- package/docs/INSTALLATION.md +20 -11
- package/docs/bug-fixes/agent-01-cli-fixes.md +101 -0
- package/docs/bug-fixes/agent-02-purplelab-fixes.md +88 -0
- package/docs/bug-fixes/agent-03-dashboard-fixes.md +119 -0
- package/docs/bug-fixes/agent-04-memory-fixes.md +105 -0
- package/docs/bug-fixes/agent-05-provider-fixes.md +86 -0
- package/docs/bug-fixes/agent-06-integration-fixes.md +101 -0
- package/docs/bug-fixes/agent-07-dash-run-fixes.md +101 -0
- package/docs/bug-fixes/agent-08-docker-fixes.md +164 -0
- package/docs/bug-fixes/agent-09-e2e-build-fixes.md +69 -0
- package/docs/bug-fixes/agent-10-e2e-fullstack-fixes.md +102 -0
- package/docs/bug-fixes/agent-11-e2e-session-fixes.md +70 -0
- package/docs/bug-fixes/agent-12-scenario-fixes.md +120 -0
- package/docs/bug-fixes/agent-13-enterprise-fixes.md +143 -0
- package/docs/bug-fixes/agent-14-uat-newuser-fixes.md +88 -0
- package/docs/bug-fixes/agent-15-uat-poweruser-fixes.md +132 -0
- package/docs/bug-fixes/agent-19-code-review.md +316 -0
- package/docs/bug-fixes/agent-20-architecture-review.md +331 -0
- package/docs/competitive/bolt-new-analysis.md +579 -0
- package/docs/competitive/emergence-others-analysis.md +605 -0
- package/docs/competitive/replit-lovable-analysis.md +622 -0
- package/docs/test-scenarios/edge-cases.md +813 -0
- package/docs/test-scenarios/enterprise-scenarios.md +732 -0
- package/mcp/__init__.py +1 -1
- package/mcp/server.py +49 -5
- package/memory/consolidation.py +33 -0
- package/memory/embeddings.py +10 -1
- package/memory/engine.py +83 -38
- package/memory/retrieval.py +36 -0
- package/memory/storage.py +56 -4
- package/memory/token_economics.py +14 -2
- package/memory/vector_index.py +36 -7
- package/package.json +1 -1
- package/providers/gemini.sh +89 -2
- package/templates/README.md +1 -1
- package/templates/cli-tool.md +30 -0
- package/templates/dashboard.md +4 -0
- package/templates/data-pipeline.md +4 -0
- package/templates/discord-bot.md +47 -0
- package/templates/game.md +4 -0
- package/templates/microservice.md +4 -0
- package/templates/npm-library.md +4 -0
- package/templates/rest-api-auth.md +50 -20
- package/templates/rest-api.md +15 -0
- package/templates/saas-starter.md +1 -1
- package/templates/slack-bot.md +36 -0
- package/templates/static-landing-page.md +9 -1
- package/templates/web-scraper.md +4 -0
- package/web-app/dist/assets/Badge-CeBkFjo6.js +1 -0
- package/web-app/dist/assets/Button-yuhqo8Fq.js +1 -0
- package/web-app/dist/assets/{Card-BMw7NSaV.js → Card-BG17vsX0.js} +1 -1
- package/web-app/dist/assets/{HomePage-QyvNpyFv.js → HomePage-BMSQ7Apj.js} +3 -3
- package/web-app/dist/assets/{LoginPage-CG_DkANw.js → LoginPage-aH_6iolg.js} +1 -1
- package/web-app/dist/assets/{NotFoundPage-CHBJTLTi.js → NotFoundPage-Di8cNtB1.js} +1 -1
- package/web-app/dist/assets/ProjectPage-BtRssmw9.js +285 -0
- package/web-app/dist/assets/ProjectsPage-B-FTFagc.js +6 -0
- package/web-app/dist/assets/{SettingsPage-Dq-c6kXj.js → SettingsPage-DIJPBla4.js} +1 -1
- package/web-app/dist/assets/TeamsPage--19fNX7w.js +36 -0
- package/web-app/dist/assets/TemplatesPage-ChUQNOOv.js +11 -0
- package/web-app/dist/assets/TerminalOutput-Dwrzecyl.js +31 -0
- package/web-app/dist/assets/activity-BNRWeu9N.js +6 -0
- package/web-app/dist/assets/{arrow-left-Dw9yRwL8.js → arrow-left-Ce6g1_YE.js} +1 -1
- package/web-app/dist/assets/circle-alert-LIndawHL.js +11 -0
- package/web-app/dist/assets/clock-Bpj4VPlP.js +6 -0
- package/web-app/dist/assets/{external-link-DGtaQZrg.js → external-link-BhhdF0iQ.js} +1 -1
- package/web-app/dist/assets/folder-open-CM2LgfxI.js +11 -0
- package/web-app/dist/assets/index-8-KpWWq7.css +1 -0
- package/web-app/dist/assets/index-kPDW4e_b.js +236 -0
- package/web-app/dist/assets/lock-sAk3Xe54.js +16 -0
- package/web-app/dist/assets/search-CR-2i9by.js +6 -0
- package/web-app/dist/assets/server-DuFh4ymA.js +26 -0
- package/web-app/dist/assets/trash-2-BmkkT8V_.js +11 -0
- package/web-app/dist/index.html +2 -2
- package/web-app/server.py +1345 -55
- package/web-app/dist/assets/Badge-BFLpnFZM.js +0 -6
- package/web-app/dist/assets/Button-BYY9clv_.js +0 -16
- package/web-app/dist/assets/ProjectPage-q65bhy76.js +0 -217
- package/web-app/dist/assets/ProjectsPage-d4mY9ewI.js +0 -21
- package/web-app/dist/assets/TemplatesPage-BEpY-p-Q.js +0 -1
- package/web-app/dist/assets/TerminalOutput-CFy7MnPO.js +0 -51
- package/web-app/dist/assets/clock-D4pcK_Eq.js +0 -11
- package/web-app/dist/assets/index-BnNomb7B.js +0 -196
- package/web-app/dist/assets/index-D452pFGl.css +0 -1
package/package.json
CHANGED
package/providers/gemini.sh
CHANGED
|
@@ -120,6 +120,61 @@ PROVIDER_DEGRADED_REASONS=(
|
|
|
120
120
|
"No MCP server integration"
|
|
121
121
|
)
|
|
122
122
|
|
|
123
|
+
# BUG-PROV-003 fix: API key resolution with fallback and rotation support.
|
|
124
|
+
# Gemini CLI accepts GOOGLE_API_KEY or GEMINI_API_KEY env vars.
|
|
125
|
+
# If LOKI_GEMINI_API_KEYS is set (comma-separated), rotate through them on auth errors.
|
|
126
|
+
# This function sets GOOGLE_API_KEY for the current invocation.
|
|
127
|
+
_gemini_resolve_api_key() {
|
|
128
|
+
# Already have a key set -- nothing to do
|
|
129
|
+
if [ -n "${GOOGLE_API_KEY:-}" ]; then
|
|
130
|
+
return 0
|
|
131
|
+
fi
|
|
132
|
+
# Try GEMINI_API_KEY as alias
|
|
133
|
+
if [ -n "${GEMINI_API_KEY:-}" ]; then
|
|
134
|
+
export GOOGLE_API_KEY="$GEMINI_API_KEY"
|
|
135
|
+
return 0
|
|
136
|
+
fi
|
|
137
|
+
# Try gcloud ADC (Application Default Credentials) -- gemini CLI supports this natively
|
|
138
|
+
if [ -f "${HOME}/.config/gcloud/application_default_credentials.json" ]; then
|
|
139
|
+
return 0 # Let gemini CLI handle ADC
|
|
140
|
+
fi
|
|
141
|
+
return 1
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
# Rotate to next API key from LOKI_GEMINI_API_KEYS (comma-separated list)
|
|
145
|
+
# Called after auth errors (401/403) to try the next key
|
|
146
|
+
_gemini_rotate_api_key() {
|
|
147
|
+
local keys="${LOKI_GEMINI_API_KEYS:-}"
|
|
148
|
+
[ -z "$keys" ] && return 1 # No key list configured
|
|
149
|
+
|
|
150
|
+
local current="${GOOGLE_API_KEY:-}"
|
|
151
|
+
local IFS=','
|
|
152
|
+
local found_current=false
|
|
153
|
+
local first_key=""
|
|
154
|
+
|
|
155
|
+
for key in $keys; do
|
|
156
|
+
key=$(echo "$key" | tr -d ' ') # trim whitespace
|
|
157
|
+
[ -z "$key" ] && continue
|
|
158
|
+
[ -z "$first_key" ] && first_key="$key"
|
|
159
|
+
|
|
160
|
+
if [ "$found_current" = "true" ]; then
|
|
161
|
+
export GOOGLE_API_KEY="$key"
|
|
162
|
+
return 0
|
|
163
|
+
fi
|
|
164
|
+
if [ "$key" = "$current" ]; then
|
|
165
|
+
found_current=true
|
|
166
|
+
fi
|
|
167
|
+
done
|
|
168
|
+
|
|
169
|
+
# Wrap around to first key (or set first key if current wasn't in list)
|
|
170
|
+
if [ -n "$first_key" ] && [ "$first_key" != "$current" ]; then
|
|
171
|
+
export GOOGLE_API_KEY="$first_key"
|
|
172
|
+
return 0
|
|
173
|
+
fi
|
|
174
|
+
|
|
175
|
+
return 1 # All keys exhausted or only one key
|
|
176
|
+
}
|
|
177
|
+
|
|
123
178
|
# Detection function - check if provider CLI is available
|
|
124
179
|
provider_detect() {
|
|
125
180
|
command -v gemini >/dev/null 2>&1
|
|
@@ -130,13 +185,17 @@ provider_version() {
|
|
|
130
185
|
gemini --version 2>/dev/null | head -1
|
|
131
186
|
}
|
|
132
187
|
|
|
133
|
-
# Invocation function with rate limit fallback
|
|
188
|
+
# Invocation function with rate limit fallback and API key rotation
|
|
134
189
|
# Uses --model flag to specify model, --approval-mode=yolo for autonomous mode
|
|
135
190
|
# Falls back to flash model if pro hits rate limit
|
|
191
|
+
# BUG-PROV-003 fix: rotates API keys on auth errors (401/403)
|
|
136
192
|
# Accepts optional --model <name> as first args to override default model
|
|
137
193
|
# BUG-PROV-010 fix: uses tee to stream output while still capturing for rate-limit check
|
|
138
194
|
# Note: < /dev/null prevents Gemini from pausing on stdin
|
|
139
195
|
provider_invoke() {
|
|
196
|
+
# Resolve API key before invocation
|
|
197
|
+
_gemini_resolve_api_key || true
|
|
198
|
+
|
|
140
199
|
local model
|
|
141
200
|
model=$(provider_get_current_model)
|
|
142
201
|
|
|
@@ -157,6 +216,18 @@ provider_invoke() {
|
|
|
157
216
|
gemini --approval-mode=yolo --model "$model" "$prompt" "$@" < /dev/null 2>"$stderr_file" | tee "$output_file"
|
|
158
217
|
exit_code=${PIPESTATUS[0]}
|
|
159
218
|
|
|
219
|
+
# Check for auth errors (401/403) -- try rotating API key
|
|
220
|
+
if [[ $exit_code -ne 0 ]] && grep -qiE "(401|403|unauthorized|forbidden|invalid.?api.?key|permission.?denied)" "$stderr_file" 2>/dev/null; then
|
|
221
|
+
if _gemini_rotate_api_key; then
|
|
222
|
+
echo "[loki] Auth error on Gemini, rotated to next API key" >&2
|
|
223
|
+
rm -f "$stderr_file" "$output_file"
|
|
224
|
+
output_file=$(mktemp)
|
|
225
|
+
stderr_file=$(mktemp)
|
|
226
|
+
gemini --approval-mode=yolo --model "$model" "$prompt" "$@" < /dev/null 2>"$stderr_file" | tee "$output_file"
|
|
227
|
+
exit_code=${PIPESTATUS[0]}
|
|
228
|
+
fi
|
|
229
|
+
fi
|
|
230
|
+
|
|
160
231
|
# Check for rate limit (429) or quota exceeded (check stderr for error indicators)
|
|
161
232
|
if [[ $exit_code -ne 0 ]] && grep -qiE "(rate.?limit|429|quota|resource.?exhausted)" "$stderr_file" 2>/dev/null; then
|
|
162
233
|
rm -f "$stderr_file" "$output_file"
|
|
@@ -221,11 +292,15 @@ resolve_model_for_tier() {
|
|
|
221
292
|
echo "$model"
|
|
222
293
|
}
|
|
223
294
|
|
|
224
|
-
# Tier-aware invocation with rate limit fallback
|
|
295
|
+
# Tier-aware invocation with rate limit fallback and API key rotation
|
|
225
296
|
# BUG-PROV-001 fix: uses resolve_model_for_tier to select actual model for the tier
|
|
297
|
+
# BUG-PROV-003 fix: rotates API keys on auth errors (401/403)
|
|
226
298
|
# BUG-PROV-010 fix: uses tee to stream output while capturing for rate-limit check
|
|
227
299
|
# Note: < /dev/null prevents Gemini from pausing on stdin
|
|
228
300
|
provider_invoke_with_tier() {
|
|
301
|
+
# Resolve API key before invocation
|
|
302
|
+
_gemini_resolve_api_key || true
|
|
303
|
+
|
|
229
304
|
local tier="$1"
|
|
230
305
|
local prompt="$2"
|
|
231
306
|
shift 2
|
|
@@ -244,6 +319,18 @@ provider_invoke_with_tier() {
|
|
|
244
319
|
gemini --approval-mode=yolo --model "$model" "$prompt" "$@" < /dev/null 2>"$stderr_file" | tee "$output_file"
|
|
245
320
|
exit_code=${PIPESTATUS[0]}
|
|
246
321
|
|
|
322
|
+
# Check for auth errors (401/403) -- try rotating API key
|
|
323
|
+
if [[ $exit_code -ne 0 ]] && grep -qiE "(401|403|unauthorized|forbidden|invalid.?api.?key|permission.?denied)" "$stderr_file" 2>/dev/null; then
|
|
324
|
+
if _gemini_rotate_api_key; then
|
|
325
|
+
echo "[loki] Auth error on Gemini, rotated to next API key" >&2
|
|
326
|
+
rm -f "$stderr_file" "$output_file"
|
|
327
|
+
output_file=$(mktemp)
|
|
328
|
+
stderr_file=$(mktemp)
|
|
329
|
+
gemini --approval-mode=yolo --model "$model" "$prompt" "$@" < /dev/null 2>"$stderr_file" | tee "$output_file"
|
|
330
|
+
exit_code=${PIPESTATUS[0]}
|
|
331
|
+
fi
|
|
332
|
+
fi
|
|
333
|
+
|
|
247
334
|
# Check for rate limit (429) or quota exceeded - fallback to flash
|
|
248
335
|
if [[ $exit_code -ne 0 ]] && grep -qiE "(rate.?limit|429|quota|resource.?exhausted)" "$stderr_file" 2>/dev/null; then
|
|
249
336
|
rm -f "$stderr_file" "$output_file"
|
package/templates/README.md
CHANGED
|
@@ -24,7 +24,7 @@ loki init my-project --template saas-starter
|
|
|
24
24
|
|----------|-------------|------------|-----------|
|
|
25
25
|
| [simple-todo-app.md](simple-todo-app.md) | Minimal todo app for testing Loki Mode basics | React, Express, SQLite | 15-20 min |
|
|
26
26
|
| [static-landing-page.md](static-landing-page.md) | SaaS landing page with hero, features, pricing, FAQ | HTML, CSS, vanilla JS | 10-15 min |
|
|
27
|
-
| [api-only.md](api-only.md) | REST API for notes with full CRUD and tests | Express, in-memory,
|
|
27
|
+
| [api-only.md](api-only.md) | REST API for notes with full CRUD and tests | Express, in-memory, Vitest | 15-20 min |
|
|
28
28
|
|
|
29
29
|
### Standard
|
|
30
30
|
|
package/templates/cli-tool.md
CHANGED
|
@@ -130,8 +130,38 @@ Options:
|
|
|
130
130
|
}
|
|
131
131
|
```
|
|
132
132
|
|
|
133
|
+
## Package Configuration
|
|
134
|
+
|
|
135
|
+
### package.json (required fields)
|
|
136
|
+
```json
|
|
137
|
+
{
|
|
138
|
+
"name": "tidyfiles",
|
|
139
|
+
"bin": {
|
|
140
|
+
"tidyfiles": "./dist/index.js"
|
|
141
|
+
},
|
|
142
|
+
"type": "module",
|
|
143
|
+
"files": ["dist", "man"]
|
|
144
|
+
}
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### Entry Point Shebang
|
|
148
|
+
The compiled entry point (`dist/index.js`) MUST include a shebang line as the first line:
|
|
149
|
+
```
|
|
150
|
+
#!/usr/bin/env node
|
|
151
|
+
```
|
|
152
|
+
Configure tsup to add this automatically via the `banner` option in `tsup.config.ts`:
|
|
153
|
+
```typescript
|
|
154
|
+
export default defineConfig({
|
|
155
|
+
entry: ['src/index.ts'],
|
|
156
|
+
format: ['esm', 'cjs'],
|
|
157
|
+
banner: { js: '#!/usr/bin/env node' },
|
|
158
|
+
});
|
|
159
|
+
```
|
|
160
|
+
|
|
133
161
|
## Requirements
|
|
134
162
|
- TypeScript throughout
|
|
163
|
+
- Entry point must have `#!/usr/bin/env node` shebang for global CLI usage
|
|
164
|
+
- package.json must include `bin` field mapping `tidyfiles` to the compiled entry point
|
|
135
165
|
- Zero-config default behavior (works without a config file)
|
|
136
166
|
- Graceful error handling (permission denied, disk full, file in use)
|
|
137
167
|
- Cross-platform (macOS, Linux, Windows paths)
|
package/templates/dashboard.md
CHANGED
|
@@ -85,3 +85,7 @@ A real-time analytics dashboard that visualizes key business metrics with intera
|
|
|
85
85
|
- Drag-and-drop layout changes persist across page reloads
|
|
86
86
|
- CSV and PNG exports contain accurate data
|
|
87
87
|
- All tests pass
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
**Purpose:** Tests Loki Mode's ability to build a data visualization application with real-time updates, interactive charts, drag-and-drop layouts, and export functionality. Expect ~45-60 minutes for full execution.
|
|
@@ -85,3 +85,7 @@ An ETL data pipeline that ingests data from multiple sources, transforms it thro
|
|
|
85
85
|
- Metrics accurately reflect processing statistics
|
|
86
86
|
- Pipeline resumes correctly after interruption
|
|
87
87
|
- All tests pass
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
**Purpose:** Tests Loki Mode's ability to build a data engineering pipeline with multi-source ingestion, configurable transforms, error recovery, and monitoring. Expect ~30-45 minutes for full execution.
|
package/templates/discord-bot.md
CHANGED
|
@@ -64,6 +64,53 @@ Utility:
|
|
|
64
64
|
6. Moderators use `/warn`, `/mute`, `/kick`, `/ban` as needed
|
|
65
65
|
7. All actions logged to configured audit channel
|
|
66
66
|
|
|
67
|
+
## Environment Variables
|
|
68
|
+
|
|
69
|
+
The bot requires the following environment variables, loaded via `dotenv` from a `.env` file:
|
|
70
|
+
|
|
71
|
+
### Required
|
|
72
|
+
```bash
|
|
73
|
+
DISCORD_TOKEN= # Bot token from Discord Developer Portal
|
|
74
|
+
DISCORD_CLIENT_ID= # Application ID for slash command registration
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### Optional
|
|
78
|
+
```bash
|
|
79
|
+
DISCORD_GUILD_ID= # Development guild ID (for fast command registration during dev)
|
|
80
|
+
LOG_CHANNEL_ID= # Default audit log channel (can be overridden per guild via /config)
|
|
81
|
+
NODE_ENV=production # Set to "production" to disable debug logging
|
|
82
|
+
DATABASE_PATH=./data/sentinel.db # SQLite database file path (default: ./data/sentinel.db)
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### .env.example
|
|
86
|
+
```bash
|
|
87
|
+
# Discord Bot Configuration
|
|
88
|
+
# Get these from https://discord.com/developers/applications
|
|
89
|
+
DISCORD_TOKEN=your-bot-token-here
|
|
90
|
+
DISCORD_CLIENT_ID=your-client-id-here
|
|
91
|
+
|
|
92
|
+
# Optional: Development guild for fast command registration
|
|
93
|
+
# DISCORD_GUILD_ID=your-test-server-id
|
|
94
|
+
|
|
95
|
+
# Optional: Default audit log channel
|
|
96
|
+
# LOG_CHANNEL_ID=your-log-channel-id
|
|
97
|
+
|
|
98
|
+
# Optional: Database path (default: ./data/sentinel.db)
|
|
99
|
+
# DATABASE_PATH=./data/sentinel.db
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Startup Validation
|
|
103
|
+
The bot MUST validate required environment variables on startup and exit with a clear error message if any are missing:
|
|
104
|
+
```typescript
|
|
105
|
+
const requiredEnvVars = ['DISCORD_TOKEN', 'DISCORD_CLIENT_ID'];
|
|
106
|
+
for (const envVar of requiredEnvVars) {
|
|
107
|
+
if (!process.env[envVar]) {
|
|
108
|
+
console.error(`Missing required environment variable: ${envVar}`);
|
|
109
|
+
process.exit(1);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
```
|
|
113
|
+
|
|
67
114
|
## Tech Stack
|
|
68
115
|
- Runtime: Node.js 18+
|
|
69
116
|
- Library: discord.js v14
|
package/templates/game.md
CHANGED
|
@@ -88,3 +88,7 @@ A browser-based 2D game with player controls, enemy AI, scoring, levels, and per
|
|
|
88
88
|
- Level progression increases difficulty noticeably
|
|
89
89
|
- Game runs at stable 60fps on modern browsers
|
|
90
90
|
- All tests pass
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
**Purpose:** Tests Loki Mode's ability to build a browser game with canvas rendering, game loop architecture, enemy AI, collision detection, and audio. Expect ~30-45 minutes for full execution.
|
|
@@ -90,3 +90,7 @@ A containerized microservice with health checks, structured logging, graceful sh
|
|
|
90
90
|
- Graceful shutdown drains connections without dropping requests
|
|
91
91
|
- Prometheus can scrape metrics endpoint
|
|
92
92
|
- All tests pass
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
**Purpose:** Tests Loki Mode's ability to build a production-ready containerized service with health checks, structured logging, graceful shutdown, and observability. Expect ~30-45 minutes for full execution.
|
package/templates/npm-library.md
CHANGED
|
@@ -83,3 +83,7 @@ A well-structured npm package with TypeScript support, comprehensive documentati
|
|
|
83
83
|
- Bundle size stays under defined budget
|
|
84
84
|
- Changelog accurately reflects changes between versions
|
|
85
85
|
- All tests pass
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
**Purpose:** Tests Loki Mode's ability to build a publishable npm package with TypeScript, dual ESM/CJS builds, automated documentation, and high test coverage. Expect ~30-45 minutes for full execution.
|
|
@@ -32,12 +32,12 @@ A production-ready REST API with JWT-based authentication, user registration, lo
|
|
|
32
32
|
|
|
33
33
|
### Option A: Node.js (Express)
|
|
34
34
|
- Runtime: Node.js 20+
|
|
35
|
-
- Framework: Express.js
|
|
35
|
+
- Framework: Express.js with TypeScript
|
|
36
36
|
- Database: PostgreSQL with Prisma ORM
|
|
37
37
|
- Validation: zod
|
|
38
38
|
- Auth: jsonwebtoken, bcrypt
|
|
39
39
|
- Rate Limiting: express-rate-limit
|
|
40
|
-
- Testing:
|
|
40
|
+
- Testing: Vitest + supertest
|
|
41
41
|
|
|
42
42
|
### Option B: Python (FastAPI)
|
|
43
43
|
- Runtime: Python 3.11+
|
|
@@ -50,41 +50,71 @@ A production-ready REST API with JWT-based authentication, user registration, lo
|
|
|
50
50
|
|
|
51
51
|
Choose whichever framework the agent determines is most appropriate, or default to Express.js.
|
|
52
52
|
|
|
53
|
-
### Project Structure (Express)
|
|
53
|
+
### Project Structure (Express + TypeScript)
|
|
54
54
|
```
|
|
55
55
|
/
|
|
56
56
|
├── src/
|
|
57
|
-
│ ├── app.
|
|
58
|
-
│ ├── server.
|
|
57
|
+
│ ├── app.ts # Express app setup
|
|
58
|
+
│ ├── server.ts # Entry point
|
|
59
59
|
│ ├── config/
|
|
60
|
-
│ │ └── index.
|
|
60
|
+
│ │ └── index.ts # Environment config
|
|
61
61
|
│ ├── middleware/
|
|
62
|
-
│ │ ├── auth.
|
|
63
|
-
│ │ ├── validate.
|
|
64
|
-
│ │ └── rateLimiter.
|
|
62
|
+
│ │ ├── auth.ts # JWT verification middleware
|
|
63
|
+
│ │ ├── validate.ts # Request validation middleware
|
|
64
|
+
│ │ └── rateLimiter.ts # Rate limiting middleware
|
|
65
65
|
│ ├── routes/
|
|
66
|
-
│ │ ├── auth.
|
|
67
|
-
│ │ └── users.
|
|
66
|
+
│ │ ├── auth.ts # Auth routes (register, login, refresh, forgot, reset)
|
|
67
|
+
│ │ └── users.ts # User routes (profile, update, change password)
|
|
68
68
|
│ ├── controllers/
|
|
69
|
-
│ │ ├── authController.
|
|
70
|
-
│ │ └── userController.
|
|
69
|
+
│ │ ├── authController.ts # Auth business logic
|
|
70
|
+
│ │ └── userController.ts # User business logic
|
|
71
71
|
│ ├── services/
|
|
72
|
-
│ │ ├── authService.
|
|
73
|
-
│ │ └── emailService.
|
|
72
|
+
│ │ ├── authService.ts # Token generation, password hashing
|
|
73
|
+
│ │ └── emailService.ts # Email sending (console in dev)
|
|
74
74
|
│ └── utils/
|
|
75
|
-
│ └── errors.
|
|
75
|
+
│ └── errors.ts # Custom error classes
|
|
76
76
|
├── prisma/
|
|
77
77
|
│ ├── schema.prisma # Database schema
|
|
78
|
-
│ └── seed.
|
|
78
|
+
│ └── seed.ts # Seed data
|
|
79
79
|
├── tests/
|
|
80
|
-
│ ├── auth.test.
|
|
81
|
-
│ ├── users.test.
|
|
82
|
-
│ └── middleware.test.
|
|
80
|
+
│ ├── auth.test.ts # Auth endpoint tests
|
|
81
|
+
│ ├── users.test.ts # User endpoint tests
|
|
82
|
+
│ └── middleware.test.ts # Middleware tests
|
|
83
83
|
├── .env.example # Environment variable template
|
|
84
|
+
├── tsconfig.json
|
|
84
85
|
├── package.json
|
|
85
86
|
└── README.md
|
|
86
87
|
```
|
|
87
88
|
|
|
89
|
+
## Environment Variables
|
|
90
|
+
|
|
91
|
+
### .env.example
|
|
92
|
+
```bash
|
|
93
|
+
# Server
|
|
94
|
+
PORT=3000
|
|
95
|
+
NODE_ENV=development
|
|
96
|
+
|
|
97
|
+
# Database
|
|
98
|
+
DATABASE_URL=postgresql://user:password@localhost:5432/auth_db
|
|
99
|
+
|
|
100
|
+
# JWT
|
|
101
|
+
JWT_SECRET=your-jwt-secret-min-32-chars
|
|
102
|
+
JWT_ACCESS_EXPIRY=15m
|
|
103
|
+
JWT_REFRESH_EXPIRY=7d
|
|
104
|
+
|
|
105
|
+
# Email (optional, logs to console in dev)
|
|
106
|
+
SMTP_HOST=smtp.example.com
|
|
107
|
+
SMTP_PORT=587
|
|
108
|
+
SMTP_USER=your-email@example.com
|
|
109
|
+
SMTP_PASS=your-password
|
|
110
|
+
EMAIL_FROM=noreply@example.com
|
|
111
|
+
|
|
112
|
+
# CORS
|
|
113
|
+
CORS_ORIGIN=http://localhost:3000
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
The server MUST validate required variables (`DATABASE_URL`, `JWT_SECRET`) on startup and exit with a clear error if missing.
|
|
117
|
+
|
|
88
118
|
## Database Schema
|
|
89
119
|
|
|
90
120
|
```sql
|
package/templates/rest-api.md
CHANGED
|
@@ -68,6 +68,21 @@ A production-ready RESTful API backend with CRUD operations, pagination, filteri
|
|
|
68
68
|
└── README.md
|
|
69
69
|
```
|
|
70
70
|
|
|
71
|
+
## Environment Variables
|
|
72
|
+
|
|
73
|
+
### .env.example
|
|
74
|
+
```bash
|
|
75
|
+
# Server
|
|
76
|
+
PORT=3000
|
|
77
|
+
NODE_ENV=development
|
|
78
|
+
|
|
79
|
+
# Database (SQLite for dev, PostgreSQL for prod)
|
|
80
|
+
DATABASE_URL=file:./dev.db
|
|
81
|
+
|
|
82
|
+
# CORS
|
|
83
|
+
CORS_ORIGIN=http://localhost:5173
|
|
84
|
+
```
|
|
85
|
+
|
|
71
86
|
## Database Schema
|
|
72
87
|
|
|
73
88
|
```sql
|
|
@@ -183,7 +183,7 @@ enum SubStatus {
|
|
|
183
183
|
- `GET /api/auth/verify?token=` - Verify email address
|
|
184
184
|
- `POST /api/auth/forgot-password` - Request password reset
|
|
185
185
|
- `POST /api/auth/reset-password` - Reset with token
|
|
186
|
-
- OAuth handled by NextAuth.js (`/api/auth/[...nextauth]`
|
|
186
|
+
- OAuth handled by NextAuth.js v5 (Auth.js) via `src/lib/auth.ts` config and `/api/auth/[...nextauth]` catch-all route
|
|
187
187
|
|
|
188
188
|
### Billing
|
|
189
189
|
- `POST /api/billing/checkout` - Create Stripe Checkout session
|
package/templates/slack-bot.md
CHANGED
|
@@ -17,6 +17,38 @@ A Slack bot that responds to commands, processes events, and integrates with ext
|
|
|
17
17
|
6. **Help System** - Built-in help command listing all available commands and their usage
|
|
18
18
|
7. **Error Reporting** - Log errors and send admin notifications when commands fail
|
|
19
19
|
|
|
20
|
+
## Environment Variables
|
|
21
|
+
|
|
22
|
+
### Required
|
|
23
|
+
```bash
|
|
24
|
+
SLACK_BOT_TOKEN=xoxb-... # Bot User OAuth Token
|
|
25
|
+
SLACK_SIGNING_SECRET=... # Signing Secret from App Credentials
|
|
26
|
+
SLACK_APP_TOKEN=xapp-... # App-Level Token (for Socket Mode)
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### Optional
|
|
30
|
+
```bash
|
|
31
|
+
PORT=3000 # HTTP server port (default: 3000)
|
|
32
|
+
ADMIN_CHANNEL_ID=C0... # Channel for error notifications
|
|
33
|
+
NODE_ENV=production # Set to "production" for HTTP mode
|
|
34
|
+
DATABASE_PATH=./data/bot.db # SQLite database path
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### .env.example
|
|
38
|
+
```bash
|
|
39
|
+
# Get these from https://api.slack.com/apps
|
|
40
|
+
SLACK_BOT_TOKEN=xoxb-your-token
|
|
41
|
+
SLACK_SIGNING_SECRET=your-signing-secret
|
|
42
|
+
SLACK_APP_TOKEN=xapp-your-app-token
|
|
43
|
+
|
|
44
|
+
# Optional
|
|
45
|
+
# PORT=3000
|
|
46
|
+
# ADMIN_CHANNEL_ID=C0123456789
|
|
47
|
+
# DATABASE_PATH=./data/bot.db
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
The bot MUST validate required environment variables on startup and exit with a clear error if missing.
|
|
51
|
+
|
|
20
52
|
## Technical Requirements
|
|
21
53
|
- Node.js with TypeScript
|
|
22
54
|
- Bolt for Slack SDK (official Slack framework)
|
|
@@ -88,3 +120,7 @@ A Slack bot that responds to commands, processes events, and integrates with ext
|
|
|
88
120
|
- Scheduled messages fire at configured times
|
|
89
121
|
- Error notifications reach admin channel
|
|
90
122
|
- All tests pass
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
**Purpose:** Tests Loki Mode's ability to build a Slack integration with slash commands, event handling, interactive messages, and scheduled notifications. Expect ~30-45 minutes for full execution.
|
|
@@ -68,6 +68,14 @@ Marketing teams needing a quick landing page.
|
|
|
68
68
|
3. `script.js` - Minimal JS (optional)
|
|
69
69
|
4. `README.md` - How to view locally
|
|
70
70
|
|
|
71
|
+
## Success Criteria
|
|
72
|
+
- Page loads without errors (no broken images, missing styles, or JS errors)
|
|
73
|
+
- All 6 sections render correctly (hero, features, social proof, pricing, FAQ, footer)
|
|
74
|
+
- FAQ accordion opens and closes on click
|
|
75
|
+
- Responsive layout works on mobile (375px) and desktop (1440px)
|
|
76
|
+
- Semantic HTML passes basic accessibility checks
|
|
77
|
+
- Page loads in under 2 seconds on a fresh browser
|
|
78
|
+
|
|
71
79
|
---
|
|
72
80
|
|
|
73
|
-
**Purpose:** Tests frontend agent, marketing agent (copy), and design patterns without backend complexity.
|
|
81
|
+
**Purpose:** Tests frontend agent, marketing agent (copy), and design patterns without backend complexity. Expect ~10-15 minutes for full execution.
|
package/templates/web-scraper.md
CHANGED
|
@@ -85,3 +85,7 @@ A configurable web scraping tool that extracts structured data from websites, ha
|
|
|
85
85
|
- Robots.txt rules correctly block disallowed paths
|
|
86
86
|
- All export formats contain valid, complete data
|
|
87
87
|
- All tests pass
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
**Purpose:** Tests Loki Mode's ability to build an async Python tool with HTTP clients, HTML parsing, rate limiting, robots.txt compliance, and multi-format data export. Expect ~30-45 minutes for full execution.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{r as n,j as e}from"./index-kPDW4e_b.js";import{C as m}from"./clock-Bpj4VPlP.js";import{a as p,C as g}from"./circle-alert-LIndawHL.js";function B(t,a=2e3,l=!0){const[c,i]=n.useState(null),[f,o]=n.useState(null),[x,d]=n.useState(!0),s=n.useRef(!0),u=n.useCallback(async()=>{try{const r=await t();s.current&&(i(r),o(null))}catch(r){s.current&&o(r instanceof Error?r.message:"Unknown error")}finally{s.current&&d(!1)}},[t]);return n.useEffect(()=>{if(s.current=!0,!l)return;u();const r=setInterval(u,a);return()=>{s.current=!1,clearInterval(r)}},[u,a,l]),{data:c,error:f,loading:x,refresh:u}}const C={completed:"bg-[#1FC5A8]/10 text-[#1FC5A8]",running:"bg-[#553DE9]/10 text-[#553DE9]",failed:"bg-[#C45B5B]/10 text-[#C45B5B]",started:"bg-[#D4A03C]/10 text-[#D4A03C]",empty:"bg-[#F8F4F0] text-[#6B6960]",version:"bg-[#553DE9]/10 text-[#553DE9]"};function b({status:t}){switch(t){case"completed":return e.jsx(g,{size:12});case"running":return e.jsxs("span",{className:"relative flex h-2 w-2",children:[e.jsx("span",{className:"animate-ping motion-reduce:animate-none absolute inline-flex h-full w-full rounded-full bg-current opacity-75"}),e.jsx("span",{className:"relative inline-flex rounded-full h-2 w-2 bg-current"})]});case"failed":return e.jsx(p,{size:12});case"started":return e.jsx(m,{size:12});default:return null}}function D({status:t,children:a,className:l=""}){return e.jsxs("span",{className:["inline-flex items-center gap-1 rounded-btn px-2.5 py-0.5 text-xs font-semibold",C[t],l].filter(Boolean).join(" "),children:[e.jsx(b,{status:t}),a]})}export{D as B,B as u};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{r as p,j as t}from"./index-kPDW4e_b.js";const m={primary:"bg-[#553DE9] text-white hover:bg-[#4432c4] shadow-button rounded-btn",secondary:"border border-[#553DE9] text-[#553DE9] hover:bg-[#E8E4FD] bg-transparent rounded-btn",ghost:"text-[#36342E] hover:bg-[#F8F4F0] rounded-btn",danger:"bg-[#C45B5B]/10 text-[#C45B5B] border border-[#C45B5B]/20 hover:bg-[#C45B5B]/20 rounded-btn"},b={sm:"px-3 py-1.5 text-xs",md:"px-4 py-2 text-sm",lg:"px-6 py-3 text-base"},u={sm:14,md:16,lg:18};function h({size:e}){return t.jsxs("svg",{className:"animate-spin",width:e,height:e,viewBox:"0 0 24 24",fill:"none",children:[t.jsx("circle",{className:"opacity-25",cx:"12",cy:"12",r:"10",stroke:"currentColor",strokeWidth:"4"}),t.jsx("path",{className:"opacity-75",fill:"currentColor",d:"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"})]})}const B=p.forwardRef(({variant:e="primary",size:o="md",icon:n,iconRight:i,loading:r=!1,disabled:a,className:c="",children:l,...x},d)=>{const s=u[o];return t.jsxs("button",{ref:d,disabled:a||r,className:["inline-flex items-center justify-center gap-2 font-medium transition-colors",m[e],b[o],(a||r)&&"opacity-60 cursor-not-allowed",c].filter(Boolean).join(" "),...x,children:[r?t.jsx(h,{size:s}):n?t.jsx(n,{size:s}):null,l,i&&!r&&t.jsx(i,{size:s})]})});B.displayName="Button";export{B};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{j as s}from"./index-
|
|
1
|
+
import{j as s}from"./index-kPDW4e_b.js";const n={none:"p-0",sm:"p-3",md:"p-4",lg:"p-6"};function p({hover:e=!1,padding:d="md",className:t="",children:a,onClick:r}){return s.jsx("div",{role:r?"button":void 0,tabIndex:r?0:void 0,onClick:r,onKeyDown:r?o=>{(o.key==="Enter"||o.key===" ")&&(o.preventDefault(),r())}:void 0,className:["bg-white border border-[#ECEAE3] rounded-[5px] shadow-card",e&&"hover:shadow-card-hover transition-shadow duration-200",r&&"cursor-pointer",n[d],t].filter(Boolean).join(" "),children:a})}export{p as C};
|