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.
Files changed (91) hide show
  1. package/README.md +9 -1
  2. package/SKILL.md +2 -2
  3. package/VERSION +1 -1
  4. package/autonomy/hooks/migration-hooks.sh +26 -0
  5. package/autonomy/loki +429 -92
  6. package/autonomy/run.sh +219 -38
  7. package/dashboard/__init__.py +1 -1
  8. package/dashboard/server.py +101 -19
  9. package/docs/INSTALLATION.md +20 -11
  10. package/docs/bug-fixes/agent-01-cli-fixes.md +101 -0
  11. package/docs/bug-fixes/agent-02-purplelab-fixes.md +88 -0
  12. package/docs/bug-fixes/agent-03-dashboard-fixes.md +119 -0
  13. package/docs/bug-fixes/agent-04-memory-fixes.md +105 -0
  14. package/docs/bug-fixes/agent-05-provider-fixes.md +86 -0
  15. package/docs/bug-fixes/agent-06-integration-fixes.md +101 -0
  16. package/docs/bug-fixes/agent-07-dash-run-fixes.md +101 -0
  17. package/docs/bug-fixes/agent-08-docker-fixes.md +164 -0
  18. package/docs/bug-fixes/agent-09-e2e-build-fixes.md +69 -0
  19. package/docs/bug-fixes/agent-10-e2e-fullstack-fixes.md +102 -0
  20. package/docs/bug-fixes/agent-11-e2e-session-fixes.md +70 -0
  21. package/docs/bug-fixes/agent-12-scenario-fixes.md +120 -0
  22. package/docs/bug-fixes/agent-13-enterprise-fixes.md +143 -0
  23. package/docs/bug-fixes/agent-14-uat-newuser-fixes.md +88 -0
  24. package/docs/bug-fixes/agent-15-uat-poweruser-fixes.md +132 -0
  25. package/docs/bug-fixes/agent-19-code-review.md +316 -0
  26. package/docs/bug-fixes/agent-20-architecture-review.md +331 -0
  27. package/docs/competitive/bolt-new-analysis.md +579 -0
  28. package/docs/competitive/emergence-others-analysis.md +605 -0
  29. package/docs/competitive/replit-lovable-analysis.md +622 -0
  30. package/docs/test-scenarios/edge-cases.md +813 -0
  31. package/docs/test-scenarios/enterprise-scenarios.md +732 -0
  32. package/mcp/__init__.py +1 -1
  33. package/mcp/server.py +49 -5
  34. package/memory/consolidation.py +33 -0
  35. package/memory/embeddings.py +10 -1
  36. package/memory/engine.py +83 -38
  37. package/memory/retrieval.py +36 -0
  38. package/memory/storage.py +56 -4
  39. package/memory/token_economics.py +14 -2
  40. package/memory/vector_index.py +36 -7
  41. package/package.json +1 -1
  42. package/providers/gemini.sh +89 -2
  43. package/templates/README.md +1 -1
  44. package/templates/cli-tool.md +30 -0
  45. package/templates/dashboard.md +4 -0
  46. package/templates/data-pipeline.md +4 -0
  47. package/templates/discord-bot.md +47 -0
  48. package/templates/game.md +4 -0
  49. package/templates/microservice.md +4 -0
  50. package/templates/npm-library.md +4 -0
  51. package/templates/rest-api-auth.md +50 -20
  52. package/templates/rest-api.md +15 -0
  53. package/templates/saas-starter.md +1 -1
  54. package/templates/slack-bot.md +36 -0
  55. package/templates/static-landing-page.md +9 -1
  56. package/templates/web-scraper.md +4 -0
  57. package/web-app/dist/assets/Badge-CeBkFjo6.js +1 -0
  58. package/web-app/dist/assets/Button-yuhqo8Fq.js +1 -0
  59. package/web-app/dist/assets/{Card-BMw7NSaV.js → Card-BG17vsX0.js} +1 -1
  60. package/web-app/dist/assets/{HomePage-QyvNpyFv.js → HomePage-BMSQ7Apj.js} +3 -3
  61. package/web-app/dist/assets/{LoginPage-CG_DkANw.js → LoginPage-aH_6iolg.js} +1 -1
  62. package/web-app/dist/assets/{NotFoundPage-CHBJTLTi.js → NotFoundPage-Di8cNtB1.js} +1 -1
  63. package/web-app/dist/assets/ProjectPage-BtRssmw9.js +285 -0
  64. package/web-app/dist/assets/ProjectsPage-B-FTFagc.js +6 -0
  65. package/web-app/dist/assets/{SettingsPage-Dq-c6kXj.js → SettingsPage-DIJPBla4.js} +1 -1
  66. package/web-app/dist/assets/TeamsPage--19fNX7w.js +36 -0
  67. package/web-app/dist/assets/TemplatesPage-ChUQNOOv.js +11 -0
  68. package/web-app/dist/assets/TerminalOutput-Dwrzecyl.js +31 -0
  69. package/web-app/dist/assets/activity-BNRWeu9N.js +6 -0
  70. package/web-app/dist/assets/{arrow-left-Dw9yRwL8.js → arrow-left-Ce6g1_YE.js} +1 -1
  71. package/web-app/dist/assets/circle-alert-LIndawHL.js +11 -0
  72. package/web-app/dist/assets/clock-Bpj4VPlP.js +6 -0
  73. package/web-app/dist/assets/{external-link-DGtaQZrg.js → external-link-BhhdF0iQ.js} +1 -1
  74. package/web-app/dist/assets/folder-open-CM2LgfxI.js +11 -0
  75. package/web-app/dist/assets/index-8-KpWWq7.css +1 -0
  76. package/web-app/dist/assets/index-kPDW4e_b.js +236 -0
  77. package/web-app/dist/assets/lock-sAk3Xe54.js +16 -0
  78. package/web-app/dist/assets/search-CR-2i9by.js +6 -0
  79. package/web-app/dist/assets/server-DuFh4ymA.js +26 -0
  80. package/web-app/dist/assets/trash-2-BmkkT8V_.js +11 -0
  81. package/web-app/dist/index.html +2 -2
  82. package/web-app/server.py +1345 -55
  83. package/web-app/dist/assets/Badge-BFLpnFZM.js +0 -6
  84. package/web-app/dist/assets/Button-BYY9clv_.js +0 -16
  85. package/web-app/dist/assets/ProjectPage-q65bhy76.js +0 -217
  86. package/web-app/dist/assets/ProjectsPage-d4mY9ewI.js +0 -21
  87. package/web-app/dist/assets/TemplatesPage-BEpY-p-Q.js +0 -1
  88. package/web-app/dist/assets/TerminalOutput-CFy7MnPO.js +0 -51
  89. package/web-app/dist/assets/clock-D4pcK_Eq.js +0 -11
  90. package/web-app/dist/assets/index-BnNomb7B.js +0 -196
  91. package/web-app/dist/assets/index-D452pFGl.css +0 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "loki-mode",
3
- "version": "6.71.0",
3
+ "version": "6.72.0",
4
4
  "description": "Loki Mode by Autonomi - Multi-agent autonomous startup system for Claude Code, Codex CLI, and Gemini CLI",
5
5
  "keywords": [
6
6
  "agent",
@@ -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"
@@ -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, Jest | 15-20 min |
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
 
@@ -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)
@@ -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.
@@ -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.
@@ -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: Jest + supertest
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.js # Express app setup
58
- │ ├── server.js # Entry point
57
+ │ ├── app.ts # Express app setup
58
+ │ ├── server.ts # Entry point
59
59
  │ ├── config/
60
- │ │ └── index.js # Environment config
60
+ │ │ └── index.ts # Environment config
61
61
  │ ├── middleware/
62
- │ │ ├── auth.js # JWT verification middleware
63
- │ │ ├── validate.js # Request validation middleware
64
- │ │ └── rateLimiter.js # Rate limiting middleware
62
+ │ │ ├── auth.ts # JWT verification middleware
63
+ │ │ ├── validate.ts # Request validation middleware
64
+ │ │ └── rateLimiter.ts # Rate limiting middleware
65
65
  │ ├── routes/
66
- │ │ ├── auth.js # Auth routes (register, login, refresh, forgot, reset)
67
- │ │ └── users.js # User routes (profile, update, change password)
66
+ │ │ ├── auth.ts # Auth routes (register, login, refresh, forgot, reset)
67
+ │ │ └── users.ts # User routes (profile, update, change password)
68
68
  │ ├── controllers/
69
- │ │ ├── authController.js # Auth business logic
70
- │ │ └── userController.js # User business logic
69
+ │ │ ├── authController.ts # Auth business logic
70
+ │ │ └── userController.ts # User business logic
71
71
  │ ├── services/
72
- │ │ ├── authService.js # Token generation, password hashing
73
- │ │ └── emailService.js # Email sending (console in dev)
72
+ │ │ ├── authService.ts # Token generation, password hashing
73
+ │ │ └── emailService.ts # Email sending (console in dev)
74
74
  │ └── utils/
75
- │ └── errors.js # Custom error classes
75
+ │ └── errors.ts # Custom error classes
76
76
  ├── prisma/
77
77
  │ ├── schema.prisma # Database schema
78
- │ └── seed.js # Seed data
78
+ │ └── seed.ts # Seed data
79
79
  ├── tests/
80
- │ ├── auth.test.js # Auth endpoint tests
81
- │ ├── users.test.js # User endpoint tests
82
- │ └── middleware.test.js # Middleware tests
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
@@ -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
@@ -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.
@@ -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-BnNomb7B.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};
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};