loki-mode 6.60.0 → 6.62.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 (64) hide show
  1. package/SKILL.md +2 -2
  2. package/VERSION +1 -1
  3. package/autonomy/app-runner.sh +34 -8
  4. package/autonomy/completion-council.sh +70 -32
  5. package/autonomy/issue-parser.sh +4 -7
  6. package/autonomy/loki +238 -119
  7. package/autonomy/notification-checker.py +49 -23
  8. package/autonomy/run.sh +162 -79
  9. package/autonomy/sandbox.sh +91 -24
  10. package/bin/loki-mode.js +1 -2
  11. package/bin/postinstall.js +10 -4
  12. package/dashboard/__init__.py +1 -1
  13. package/dashboard/control.py +46 -36
  14. package/dashboard/database.py +21 -4
  15. package/dashboard/server.py +107 -78
  16. package/docs/BUG-AUDIT-v6.61.0.md +957 -0
  17. package/docs/INSTALLATION.md +2 -2
  18. package/events/bus.py +129 -28
  19. package/events/bus.ts +41 -27
  20. package/events/emit.sh +1 -1
  21. package/integrations/openclaw/README.md +139 -0
  22. package/integrations/openclaw/SKILL.md +88 -0
  23. package/integrations/openclaw/bridge/__init__.py +1 -0
  24. package/integrations/openclaw/bridge/__main__.py +88 -0
  25. package/integrations/openclaw/bridge/schema_map.py +180 -0
  26. package/integrations/openclaw/bridge/watcher.py +100 -0
  27. package/integrations/openclaw/scripts/format-progress.sh +80 -0
  28. package/integrations/openclaw/scripts/poll-status.sh +74 -0
  29. package/integrations/vibe-kanban.md +289 -0
  30. package/mcp/__init__.py +1 -1
  31. package/mcp/server.py +96 -73
  32. package/memory/consolidation.py +21 -6
  33. package/memory/engine.py +53 -26
  34. package/memory/layers/index_layer.py +16 -3
  35. package/memory/layers/timeline_layer.py +16 -3
  36. package/memory/retrieval.py +4 -1
  37. package/memory/schemas.py +4 -2
  38. package/memory/storage.py +25 -4
  39. package/memory/token_economics.py +9 -2
  40. package/memory/vector_index.py +2 -2
  41. package/package.json +3 -1
  42. package/providers/cline.sh +5 -4
  43. package/providers/codex.sh +27 -5
  44. package/providers/gemini.sh +59 -23
  45. package/providers/loader.sh +3 -2
  46. package/skills/parallel-workflows.md +9 -7
  47. package/state/__init__.py +10 -0
  48. package/state/index.ts +18 -0
  49. package/state/manager.py +1801 -0
  50. package/state/manager.ts +1774 -0
  51. package/state/sqlite_backend.py +188 -0
  52. package/state/test_manager.py +703 -0
  53. package/state/test_manager.ts +366 -0
  54. package/templates/README.md +19 -4
  55. package/templates/dashboard.md +45 -0
  56. package/templates/data-pipeline.md +45 -0
  57. package/templates/game.md +48 -0
  58. package/templates/microservice.md +49 -0
  59. package/templates/npm-library.md +42 -0
  60. package/templates/rest-api.md +170 -33
  61. package/templates/slack-bot.md +48 -0
  62. package/templates/web-scraper.md +45 -0
  63. package/web-app/server.py +360 -191
  64. package/templates/saas-app.md +0 -42
@@ -0,0 +1,366 @@
1
+ /**
2
+ * Tests for TypeScript State Manager
3
+ *
4
+ * Run with: npx ts-node state/test_manager.ts
5
+ * Or with Deno: deno run --allow-read --allow-write state/test_manager.ts
6
+ */
7
+
8
+ import * as fs from "fs";
9
+ import * as path from "path";
10
+ import * as os from "os";
11
+
12
+ import {
13
+ StateManager,
14
+ StateChange,
15
+ ManagedFile,
16
+ getStateDiff,
17
+ getStateManager,
18
+ resetStateManager,
19
+ ConflictStrategy,
20
+ VersionVector,
21
+ PendingUpdate,
22
+ ConflictInfo,
23
+ } from "./manager";
24
+
25
+ // Test helpers
26
+ function assert(condition: boolean, message: string): void {
27
+ if (!condition) {
28
+ throw new Error(`Assertion failed: ${message}`);
29
+ }
30
+ }
31
+
32
+ function assertEqual<T>(actual: T, expected: T, message: string): void {
33
+ const actualStr = JSON.stringify(actual);
34
+ const expectedStr = JSON.stringify(expected);
35
+ if (actualStr !== expectedStr) {
36
+ throw new Error(
37
+ `Assertion failed: ${message}\n Expected: ${expectedStr}\n Actual: ${actualStr}`
38
+ );
39
+ }
40
+ }
41
+
42
+ // Test runner
43
+ async function runTests(): Promise<void> {
44
+ // Create temp directory
45
+ const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "state-manager-test-"));
46
+ const lokiDir = path.join(tempDir, ".loki");
47
+
48
+ console.log("Testing StateManager (TypeScript)...");
49
+
50
+ try {
51
+ // Test: Manager initialization
52
+ const manager = new StateManager({ lokiDir, enableWatch: false, enableEvents: false });
53
+ assert(fs.existsSync(path.join(lokiDir, "state")), "state directory should exist");
54
+ assert(fs.existsSync(path.join(lokiDir, "queue")), "queue directory should exist");
55
+ console.log(" [PASS] Manager initialized");
56
+
57
+ // Test: set_state
58
+ const change1 = manager.setState("test.json", { key: "value" });
59
+ assertEqual(change1.changeType, "create", "should be create");
60
+ assertEqual(change1.newValue, { key: "value" }, "should have new value");
61
+ console.log(" [PASS] setState works");
62
+
63
+ // Test: get_state
64
+ const result1 = manager.getState("test.json");
65
+ assertEqual(result1, { key: "value" }, "should get state");
66
+ console.log(" [PASS] getState works");
67
+
68
+ // Test: update_state
69
+ const change2 = manager.updateState("test.json", { another: "field" });
70
+ assertEqual(
71
+ change2.newValue,
72
+ { key: "value", another: "field" },
73
+ "should merge updates"
74
+ );
75
+ console.log(" [PASS] updateState works");
76
+
77
+ // Test: ManagedFile enum
78
+ manager.setState(ManagedFile.ORCHESTRATOR, { phase: "planning" });
79
+ const result2 = manager.getState(ManagedFile.ORCHESTRATOR);
80
+ assertEqual(result2, { phase: "planning" }, "should work with enum");
81
+ console.log(" [PASS] ManagedFile enum works");
82
+
83
+ // Test: subscriptions
84
+ const changes: StateChange[] = [];
85
+ const subscription = manager.subscribe((change) => {
86
+ changes.push(change);
87
+ });
88
+ manager.setState("sub-test.json", { data: 123 });
89
+ assertEqual(changes.length, 1, "should receive change");
90
+ console.log(" [PASS] Subscriptions work");
91
+
92
+ subscription.dispose();
93
+ manager.setState("sub-test.json", { data: 456 });
94
+ assertEqual(changes.length, 1, "should not receive after dispose");
95
+ console.log(" [PASS] Unsubscribe works");
96
+
97
+ // Test: convenience methods
98
+ manager.setOrchestratorState({ phase: "dev" });
99
+ assertEqual(manager.getOrchestratorState(), { phase: "dev" }, "orchestrator state");
100
+ console.log(" [PASS] Convenience methods work");
101
+
102
+ // Test: getStateDiff
103
+ const diff = getStateDiff({ a: 1, b: 2 }, { a: 1, c: 3 });
104
+ assertEqual(diff.added, { c: 3 }, "diff added");
105
+ assertEqual(diff.removed, { b: 2 }, "diff removed");
106
+ assertEqual(diff.changed, {}, "diff changed");
107
+ console.log(" [PASS] getStateDiff works");
108
+
109
+ // Test: delete_state
110
+ manager.setState("to-delete.json", { temp: true });
111
+ const change3 = manager.deleteState("to-delete.json");
112
+ assert(change3 !== null, "should return change");
113
+ assertEqual(change3!.changeType, "delete", "should be delete");
114
+ const result3 = manager.getState("to-delete.json");
115
+ assert(result3 === null, "should be null after delete");
116
+ console.log(" [PASS] deleteState works");
117
+
118
+ // Test: corrupted JSON handling
119
+ const corruptedPath = path.join(lokiDir, "corrupted.json");
120
+ fs.writeFileSync(corruptedPath, "{ this is not valid json }");
121
+ const resultCorrupted = manager.getState("corrupted.json");
122
+ assert(resultCorrupted === null, "corrupted JSON should return null");
123
+ console.log(" [PASS] Corrupted JSON handling works");
124
+
125
+ // Test: empty file handling
126
+ const emptyPath = path.join(lokiDir, "empty.json");
127
+ fs.writeFileSync(emptyPath, "");
128
+ const resultEmpty = manager.getState("empty.json");
129
+ assert(resultEmpty === null, "empty file should return null");
130
+ console.log(" [PASS] Empty file handling works");
131
+
132
+ // Test: partial/truncated JSON handling
133
+ const partialPath = path.join(lokiDir, "partial.json");
134
+ fs.writeFileSync(partialPath, '{"key": "value", "incomplete":');
135
+ const resultPartial = manager.getState("partial.json");
136
+ assert(resultPartial === null, "partial JSON should return null");
137
+ console.log(" [PASS] Partial JSON handling works");
138
+
139
+ // Test: corrupted JSON with default value
140
+ const resultWithDefault = manager.getState("corrupted.json", { fallback: true });
141
+ assertEqual(resultWithDefault, { fallback: true }, "should return default for corrupted");
142
+ console.log(" [PASS] Corrupted JSON with default works");
143
+
144
+ // Cleanup
145
+ manager.stop();
146
+
147
+ console.log("");
148
+ console.log("All basic TypeScript tests passed!");
149
+
150
+ // Run optimistic update tests
151
+ await runOptimisticUpdateTests();
152
+
153
+ } finally {
154
+ // Cleanup temp directory
155
+ fs.rmSync(tempDir, { recursive: true, force: true });
156
+ }
157
+ }
158
+
159
+ // Optimistic Update Tests (SYN-014)
160
+ async function runOptimisticUpdateTests(): Promise<void> {
161
+ const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "optimistic-test-"));
162
+ const lokiDir = path.join(tempDir, ".loki");
163
+
164
+ console.log("");
165
+ console.log("Testing Optimistic Updates (SYN-014)...");
166
+
167
+ try {
168
+ // Test: VersionVector
169
+ console.log(" Testing VersionVector...");
170
+ const vv1 = new VersionVector();
171
+ vv1.increment("source1");
172
+ assert(vv1.get("source1") === 1, "version should be 1");
173
+ vv1.increment("source1");
174
+ assert(vv1.get("source1") === 2, "version should be 2");
175
+ assert(vv1.get("nonexistent") === 0, "nonexistent should be 0");
176
+ console.log(" [PASS] VersionVector increment works");
177
+
178
+ // Test: VersionVector merge
179
+ const vv2 = new VersionVector();
180
+ vv2.increment("source2");
181
+ vv2.increment("source2");
182
+ const merged = vv1.merge(vv2);
183
+ assert(merged.get("source1") === 2, "merged source1 should be 2");
184
+ assert(merged.get("source2") === 2, "merged source2 should be 2");
185
+ console.log(" [PASS] VersionVector merge works");
186
+
187
+ // Test: VersionVector concurrent
188
+ const vvA = new VersionVector();
189
+ vvA.increment("agentA");
190
+ const vvB = new VersionVector();
191
+ vvB.increment("agentB");
192
+ assert(vvA.concurrentWith(vvB), "should be concurrent");
193
+ console.log(" [PASS] VersionVector concurrent detection works");
194
+
195
+ // Test: VersionVector dominates
196
+ const vvDom1 = new VersionVector();
197
+ vvDom1.increment("source1");
198
+ vvDom1.increment("source1");
199
+ const vvDom2 = new VersionVector();
200
+ vvDom2.increment("source1");
201
+ assert(vvDom1.dominates(vvDom2), "vvDom1 should dominate vvDom2");
202
+ assert(!vvDom2.dominates(vvDom1), "vvDom2 should not dominate vvDom1");
203
+ console.log(" [PASS] VersionVector dominates works");
204
+
205
+ // Test: serialization
206
+ const vvSer = new VersionVector({ source1: 3, source2: 2 });
207
+ const dict = vvSer.toDict();
208
+ const vvDeser = VersionVector.fromDict(dict);
209
+ assert(vvDeser.get("source1") === 3, "deserialized source1 should be 3");
210
+ assert(vvDeser.get("source2") === 2, "deserialized source2 should be 2");
211
+ console.log(" [PASS] VersionVector serialization works");
212
+
213
+ // Test: StateManager optimistic updates
214
+ const manager = new StateManager({ lokiDir, enableWatch: false, enableEvents: false });
215
+
216
+ // Test: basic optimistic update
217
+ const pending = manager.optimisticUpdate("test.json", "key1", "value1", "agent1");
218
+ assert(pending.status === "pending", "should be pending");
219
+ assert(pending.key === "key1", "key should match");
220
+ assert(pending.value === "value1", "value should match");
221
+
222
+ const state = manager.getState("test.json");
223
+ assert(state !== null && state.key1 === "value1", "value should be applied");
224
+ console.log(" [PASS] optimisticUpdate works");
225
+
226
+ // Test: version tracking
227
+ manager.optimisticUpdate("test.json", "key2", "value2", "agent2");
228
+ const vv = manager.getVersionVector("test.json");
229
+ assert(vv.get("agent1") === 1, "agent1 version should be 1");
230
+ assert(vv.get("agent2") === 1, "agent2 version should be 1");
231
+ console.log(" [PASS] Version tracking works");
232
+
233
+ // Test: pending updates tracking
234
+ const pendingList = manager.getPendingUpdates("test.json");
235
+ assert(pendingList.length === 2, "should have 2 pending updates");
236
+ console.log(" [PASS] Pending updates tracking works");
237
+
238
+ // Test: conflict detection
239
+ const manager2 = new StateManager({
240
+ lokiDir: path.join(tempDir, ".loki2"),
241
+ enableWatch: false,
242
+ enableEvents: false,
243
+ });
244
+ manager2.optimisticUpdate("conflict.json", "key1", "local_value", "agent1");
245
+
246
+ const remoteState = {
247
+ key1: "remote_value",
248
+ _version_vector: { agent2: 1 },
249
+ };
250
+
251
+ const conflicts = manager2.detectConflicts("conflict.json", remoteState, "agent2");
252
+ assert(conflicts.length === 1, "should have 1 conflict");
253
+ assert(conflicts[0].key === "key1", "conflict key should be key1");
254
+ assert(conflicts[0].localValue === "local_value", "local value should match");
255
+ assert(conflicts[0].remoteValue === "remote_value", "remote value should match");
256
+ console.log(" [PASS] Conflict detection works");
257
+
258
+ // Test: conflict resolution - last write wins
259
+ manager2.setConflictStrategy(ConflictStrategy.LAST_WRITE_WINS);
260
+ const resolved = manager2.resolveConflicts("conflict.json", conflicts);
261
+ assert(resolved.key1 === "remote_value", "remote value should win");
262
+ assert(conflicts[0].resolution === "last_write_wins", "resolution should be last_write_wins");
263
+ console.log(" [PASS] Last-write-wins resolution works");
264
+
265
+ // Test: conflict resolution - merge for dicts
266
+ const manager3 = new StateManager({
267
+ lokiDir: path.join(tempDir, ".loki3"),
268
+ enableWatch: false,
269
+ enableEvents: false,
270
+ });
271
+ manager3.optimisticUpdate("merge.json", "config", { a: 1, b: 2 }, "agent1");
272
+ manager3.setConflictStrategy(ConflictStrategy.MERGE);
273
+
274
+ const remoteDict = {
275
+ config: { b: 3, c: 4 },
276
+ _version_vector: { agent2: 1 },
277
+ };
278
+
279
+ const dictConflicts = manager3.detectConflicts("merge.json", remoteDict, "agent2");
280
+ const resolvedDict = manager3.resolveConflicts("merge.json", dictConflicts);
281
+ const mergedConfig = resolvedDict.config as Record<string, number>;
282
+ assert(mergedConfig.a === 1, "merged a should be 1");
283
+ assert(mergedConfig.b === 3, "merged b should be 3 (remote wins)");
284
+ assert(mergedConfig.c === 4, "merged c should be 4");
285
+ console.log(" [PASS] Merge resolution for dicts works");
286
+
287
+ // Test: commit pending updates
288
+ const manager4 = new StateManager({
289
+ lokiDir: path.join(tempDir, ".loki4"),
290
+ enableWatch: false,
291
+ enableEvents: false,
292
+ });
293
+ manager4.optimisticUpdate("commit.json", "key1", "value1", "agent1");
294
+ manager4.optimisticUpdate("commit.json", "key2", "value2", "agent1");
295
+
296
+ const committed = manager4.commitPendingUpdates("commit.json");
297
+ assert(committed === 2, "should commit 2 updates");
298
+
299
+ const remaining = manager4.getPendingUpdates("commit.json");
300
+ assert(remaining.length === 0, "should have no pending updates");
301
+ console.log(" [PASS] Commit pending updates works");
302
+
303
+ // Test: rollback pending updates
304
+ const manager5 = new StateManager({
305
+ lokiDir: path.join(tempDir, ".loki5"),
306
+ enableWatch: false,
307
+ enableEvents: false,
308
+ });
309
+ const originalState = { original: true };
310
+ manager5.setState("rollback.json", originalState);
311
+
312
+ manager5.optimisticUpdate("rollback.json", "key1", "value1", "agent1");
313
+ manager5.optimisticUpdate("rollback.json", "key2", "value2", "agent1");
314
+
315
+ const rolledBack = manager5.rollbackPendingUpdates("rollback.json", originalState);
316
+ assert(rolledBack === 2, "should rollback 2 updates");
317
+
318
+ const restoredState = manager5.getState("rollback.json");
319
+ assertEqual(restoredState, originalState, "state should be restored");
320
+ console.log(" [PASS] Rollback pending updates works");
321
+
322
+ // Test: sync with remote
323
+ const manager6 = new StateManager({
324
+ lokiDir: path.join(tempDir, ".loki6"),
325
+ enableWatch: false,
326
+ enableEvents: false,
327
+ });
328
+ manager6.setState("sync.json", { existing: "value" });
329
+ manager6.optimisticUpdate("sync.json", "local_key", "local_value", "agent1");
330
+
331
+ const syncRemote = {
332
+ existing: "value",
333
+ remote_key: "remote_value",
334
+ _version_vector: { agent2: 1 },
335
+ };
336
+
337
+ const { resolvedState, conflicts: syncConflicts, committed: syncCommitted } =
338
+ manager6.syncWithRemote("sync.json", syncRemote, "agent2");
339
+
340
+ assert(syncConflicts.length === 0, "should have no conflicts (different keys)");
341
+ assert(syncCommitted === 1, "should commit 1 update");
342
+ assert(resolvedState.local_key === "local_value", "local key should be preserved");
343
+ console.log(" [PASS] Sync with remote works");
344
+
345
+ // Cleanup managers
346
+ manager.stop();
347
+ manager2.stop();
348
+ manager3.stop();
349
+ manager4.stop();
350
+ manager5.stop();
351
+ manager6.stop();
352
+
353
+ console.log("");
354
+ console.log("All Optimistic Update tests passed!");
355
+
356
+ } finally {
357
+ // Cleanup temp directory
358
+ fs.rmSync(tempDir, { recursive: true, force: true });
359
+ }
360
+ }
361
+
362
+ // Run tests
363
+ runTests().catch((err) => {
364
+ console.error("Test failed:", err);
365
+ process.exit(1);
366
+ });
@@ -11,6 +11,9 @@ claude --dangerously-skip-permissions
11
11
 
12
12
  # Or via CLI
13
13
  ./autonomy/run.sh templates/e-commerce.md
14
+
15
+ # Or scaffold a new project from a template
16
+ loki init my-project --template saas-starter
14
17
  ```
15
18
 
16
19
  ## Templates
@@ -27,12 +30,20 @@ claude --dangerously-skip-permissions
27
30
 
28
31
  | Template | Description | Tech Stack | Est. Time |
29
32
  |----------|-------------|------------|-----------|
33
+ | [rest-api.md](rest-api.md) | REST API with CRUD, pagination, filtering, Swagger docs (no auth) | Express, TypeScript, Prisma, SQLite | 25-35 min |
30
34
  | [rest-api-auth.md](rest-api-auth.md) | REST API with JWT auth, registration, login, refresh, rate limiting | Express/FastAPI, PostgreSQL, JWT, bcrypt | 30-45 min |
31
- | [full-stack-demo.md](full-stack-demo.md) | Bookmark manager with tags, search, and filtering | React, Express, SQLite, TailwindCSS | 30-60 min |
32
35
  | [cli-tool.md](cli-tool.md) | File organizer CLI with subcommands, config, watch mode, undo | Node.js, Commander.js, chalk, chokidar | 30-45 min |
33
36
  | [discord-bot.md](discord-bot.md) | Moderation bot with slash commands, auto-mod, reaction roles | discord.js, SQLite, node-cron | 45-60 min |
34
37
  | [chrome-extension.md](chrome-extension.md) | Tab manager extension with groups, sessions, search, memory monitor | Manifest V3, vanilla JS, Chrome APIs | 30-45 min |
35
38
  | [blog-platform.md](blog-platform.md) | Blog with markdown CMS, categories, RSS feed, SEO | Next.js, CodeMirror, SQLite, TailwindCSS | 45-60 min |
39
+ | [full-stack-demo.md](full-stack-demo.md) | Bookmark manager with tags, search, and filtering | React, Express, SQLite, TailwindCSS | 30-60 min |
40
+ | [web-scraper.md](web-scraper.md) | Configurable scraper with pagination, robots.txt, multi-format export | Python, httpx, BeautifulSoup4, SQLite | 30-45 min |
41
+ | [data-pipeline.md](data-pipeline.md) | ETL pipeline with multi-source ingestion, transforms, monitoring | Python, Pydantic, SQLAlchemy, Click | 30-45 min |
42
+ | [dashboard.md](dashboard.md) | Real-time analytics dashboard with charts, tables, drag-and-drop layout | React, Recharts, TanStack Table, WebSocket | 45-60 min |
43
+ | [game.md](game.md) | Browser-based 2D game with enemy AI, scoring, levels, high scores | HTML5 Canvas, TypeScript, Web Audio API | 30-45 min |
44
+ | [slack-bot.md](slack-bot.md) | Slack bot with slash commands, events, interactive messages, scheduling | Node.js, Bolt SDK, SQLite | 30-45 min |
45
+ | [npm-library.md](npm-library.md) | npm package with TypeScript, dual ESM/CJS, tree shaking, auto docs | TypeScript, tsup, Vitest, typedoc | 30-45 min |
46
+ | [microservice.md](microservice.md) | Containerized service with health checks, logging, Prometheus metrics | Express, TypeScript, Docker, Prisma, pino | 30-45 min |
36
47
 
37
48
  ### Complex
38
49
 
@@ -57,6 +68,7 @@ Every template follows a consistent structure:
57
68
  - **Requirements** - Non-functional requirements
58
69
  - **Testing** - Test strategy and coverage expectations
59
70
  - **Out of Scope** - Explicit boundaries to prevent scope creep
71
+ - **Acceptance Criteria** - Measurable conditions for each feature
60
72
  - **Success Criteria** - How to know when it is done
61
73
  - **Purpose Footer** - What aspect of Loki Mode this template exercises
62
74
 
@@ -69,12 +81,15 @@ Every template follows a consistent structure:
69
81
  **Building something real?** Pick the template closest to your goal and customize it. The complex templates (`saas-starter.md`, `e-commerce.md`, `ai-chatbot.md`) are production-grade starting points.
70
82
 
71
83
  **Testing specific agent types:**
72
- - Frontend agent: `static-landing-page.md`, `chrome-extension.md`
73
- - Backend agent: `api-only.md`, `rest-api-auth.md`, `discord-bot.md`
84
+ - Frontend agent: `static-landing-page.md`, `chrome-extension.md`, `dashboard.md`
85
+ - Backend agent: `api-only.md`, `rest-api.md`, `rest-api-auth.md`, `microservice.md`
74
86
  - Full-stack agent: `full-stack-demo.md`, `blog-platform.md`
75
- - DevOps/CLI agent: `cli-tool.md`
87
+ - DevOps/CLI agent: `cli-tool.md`, `data-pipeline.md`
88
+ - Bot agent: `discord-bot.md`, `slack-bot.md`
76
89
  - Mobile agent: `mobile-app.md`
77
90
  - AI/ML agent: `ai-chatbot.md`
91
+ - Game agent: `game.md`
92
+ - Library agent: `npm-library.md`
78
93
 
79
94
  ## Customizing Templates
80
95
 
@@ -33,6 +33,51 @@ A real-time analytics dashboard that visualizes key business metrics with intera
33
33
  - Responsive design tested at 3 breakpoints (mobile, tablet, desktop)
34
34
  - Accessibility: all charts have aria labels, tables are keyboard navigable
35
35
 
36
+ ## Project Structure
37
+ ```
38
+ /
39
+ ├── src/
40
+ │ ├── components/
41
+ │ │ ├── charts/ # Line, bar, pie, area chart components
42
+ │ │ ├── tables/ # Data table with sorting and filtering
43
+ │ │ ├── layout/ # Dashboard grid, drag-and-drop wrapper
44
+ │ │ └── controls/ # Date picker, export buttons, filters
45
+ │ ├── hooks/
46
+ │ │ ├── useWebSocket.ts # Real-time data subscription
47
+ │ │ └── useLayout.ts # Layout persistence (localStorage)
48
+ │ ├── services/
49
+ │ │ └── api.ts # Mock data API client
50
+ │ ├── types/
51
+ │ │ └── index.ts # Shared TypeScript types
52
+ │ ├── App.tsx
53
+ │ └── main.tsx
54
+ ├── server/
55
+ │ ├── index.ts # Express + WebSocket server
56
+ │ └── mockData.ts # Sample metrics generator
57
+ ├── tests/
58
+ │ ├── charts.test.tsx # Chart rendering tests
59
+ │ └── e2e/ # Playwright tests
60
+ ├── package.json
61
+ └── README.md
62
+ ```
63
+
64
+ ## Out of Scope
65
+ - Real database or data warehouse connections
66
+ - User authentication or multi-tenant dashboards
67
+ - Server-side rendering
68
+ - PDF report generation
69
+ - Alerting or notification rules
70
+ - Historical data backfill
71
+ - Custom chart builder UI
72
+
73
+ ## Acceptance Criteria
74
+ - All four chart types (line, bar, pie, area) render with correct data
75
+ - Date range filter applies to every widget on the dashboard
76
+ - WebSocket pushes update visible charts without page refresh
77
+ - Layout changes via drag-and-drop persist after browser reload
78
+ - CSV export matches displayed table data exactly
79
+ - PNG export captures the selected chart at screen resolution
80
+
36
81
  ## Success Metrics
37
82
  - Dashboard loads with sample data and renders all chart types
38
83
  - Date range filter updates all widgets simultaneously
@@ -33,6 +33,51 @@ An ETL data pipeline that ingests data from multiple sources, transforms it thro
33
33
  - Incremental processing verified across multiple runs
34
34
  - Dead letter queue captures all failure categories
35
35
 
36
+ ## Project Structure
37
+ ```
38
+ /
39
+ ├── src/
40
+ │ ├── pipeline/
41
+ │ │ ├── runner.py # Pipeline execution engine
42
+ │ │ ├── transforms.py # Built-in transform functions
43
+ │ │ └── validators.py # Schema validation logic
44
+ │ ├── sources/
45
+ │ │ ├── csv_source.py # CSV file reader
46
+ │ │ ├── json_source.py # JSON API reader
47
+ │ │ └── db_source.py # PostgreSQL reader
48
+ │ ├── sinks/
49
+ │ │ └── loader.py # Target data store writer
50
+ │ ├── monitoring/
51
+ │ │ └── metrics.py # Processing metrics collector
52
+ │ ├── cli.py # Click CLI entrypoint
53
+ │ └── config.py # YAML config loader
54
+ ├── pipelines/
55
+ │ └── example.yaml # Sample pipeline definition
56
+ ├── tests/
57
+ │ ├── test_transforms.py # Transform function tests
58
+ │ ├── test_validators.py # Schema validation tests
59
+ │ └── test_pipeline.py # Integration tests
60
+ ├── pyproject.toml
61
+ └── README.md
62
+ ```
63
+
64
+ ## Out of Scope
65
+ - Real-time streaming (Kafka, Kinesis)
66
+ - Distributed processing (Spark, Dask)
67
+ - Web-based pipeline builder UI
68
+ - Data lineage or provenance tracking
69
+ - Alerting integrations (PagerDuty, Slack)
70
+ - Cloud-native deployment (Airflow, Dagster)
71
+ - Data catalog or discovery features
72
+
73
+ ## Acceptance Criteria
74
+ - Pipeline definition in YAML configures sources, transforms, and sinks
75
+ - CSV, JSON, and database sources each read data correctly
76
+ - Invalid records are routed to the dead letter queue with error details
77
+ - Incremental mode skips previously processed records on re-run
78
+ - Metrics report records processed, errors, and elapsed time
79
+ - Cron scheduling triggers pipeline runs at configured intervals
80
+
36
81
  ## Success Metrics
37
82
  - Pipeline processes sample dataset end-to-end without errors
38
83
  - Invalid records quarantined with descriptive error messages
package/templates/game.md CHANGED
@@ -33,6 +33,54 @@ A browser-based 2D game with player controls, enemy AI, scoring, levels, and per
33
33
  - Controls responsive on both keyboard and touch (mobile)
34
34
  - No memory leaks during extended play sessions
35
35
 
36
+ ## Project Structure
37
+ ```
38
+ /
39
+ ├── src/
40
+ │ ├── engine/
41
+ │ │ ├── game.ts # Main game loop and state machine
42
+ │ │ ├── renderer.ts # Canvas rendering layer
43
+ │ │ ├── input.ts # Keyboard and touch input handler
44
+ │ │ └── audio.ts # Web Audio API wrapper
45
+ │ ├── entities/
46
+ │ │ ├── player.ts # Player sprite and controls
47
+ │ │ ├── enemy.ts # Enemy types and AI patterns
48
+ │ │ └── projectile.ts # Bullets and projectiles
49
+ │ ├── systems/
50
+ │ │ ├── collision.ts # AABB collision detection
51
+ │ │ ├── scoring.ts # Score and level progression
52
+ │ │ └── highscores.ts # LocalStorage leaderboard
53
+ │ ├── assets/
54
+ │ │ ├── sprites/ # Sprite images
55
+ │ │ └── sounds/ # Sound effect files
56
+ │ ├── main.ts # Entry point
57
+ │ └── config.ts # Game constants and key bindings
58
+ ├── tests/
59
+ │ ├── collision.test.ts # Collision detection tests
60
+ │ └── scoring.test.ts # Score and level logic tests
61
+ ├── index.html
62
+ ├── package.json
63
+ └── README.md
64
+ ```
65
+
66
+ ## Out of Scope
67
+ - Multiplayer or networked gameplay
68
+ - 3D rendering or WebGL
69
+ - Level editor or user-generated content
70
+ - Achievements or progression system beyond levels
71
+ - Mobile app packaging (Capacitor, Electron)
72
+ - Analytics or telemetry
73
+ - In-app purchases or monetization
74
+
75
+ ## Acceptance Criteria
76
+ - Game transitions through menu, playing, paused, and game-over states
77
+ - Player movement responds within one frame of input
78
+ - At least three enemy types exhibit distinct movement patterns
79
+ - Collision detection correctly identifies overlapping sprites
80
+ - Score increases on enemy defeat and displays on screen
81
+ - High score table persists across browser sessions
82
+ - Sound effects play on collision, shoot, and level-up events
83
+
36
84
  ## Success Metrics
37
85
  - Game starts, plays, and ends with proper state transitions
38
86
  - Player can move, shoot, and interact with enemies
@@ -34,6 +34,55 @@ A containerized microservice with health checks, structured logging, graceful sh
34
34
  - Graceful shutdown completes within timeout
35
35
  - Metrics endpoint serves valid Prometheus format
36
36
 
37
+ ## Project Structure
38
+ ```
39
+ /
40
+ ├── src/
41
+ │ ├── app.ts # Express app setup, middleware stack
42
+ │ ├── server.ts # Entry point with graceful shutdown
43
+ │ ├── config/
44
+ │ │ └── index.ts # Env-based config with validation
45
+ │ ├── middleware/
46
+ │ │ ├── requestId.ts # Correlation ID injection
47
+ │ │ ├── healthCheck.ts # Liveness and readiness probes
48
+ │ │ └── metrics.ts # Prometheus metrics collection
49
+ │ ├── routes/
50
+ │ │ └── items.ts # Example resource routes
51
+ │ ├── repositories/
52
+ │ │ └── itemRepo.ts # Repository pattern data access
53
+ │ ├── logger.ts # pino structured logger
54
+ │ └── types/
55
+ │ └── index.ts # Shared types
56
+ ├── prisma/
57
+ │ ├── schema.prisma # Database schema
58
+ │ └── migrations/ # Database migrations
59
+ ├── tests/
60
+ │ ├── items.test.ts # API integration tests
61
+ │ └── healthCheck.test.ts # Health probe tests
62
+ ├── Dockerfile # Multi-stage build
63
+ ├── docker-compose.yml # Local dev with PostgreSQL
64
+ ├── package.json
65
+ └── README.md
66
+ ```
67
+
68
+ ## Out of Scope
69
+ - Service mesh or sidecar proxy configuration
70
+ - Message queue integration (RabbitMQ, Kafka)
71
+ - API gateway or load balancer setup
72
+ - Distributed tracing (OpenTelemetry spans)
73
+ - Secret management (Vault, AWS Secrets Manager)
74
+ - Kubernetes manifests or Helm charts
75
+ - CI/CD pipeline configuration
76
+
77
+ ## Acceptance Criteria
78
+ - Docker image builds with multi-stage Dockerfile under 150MB
79
+ - GET /health/live returns 200 immediately after startup
80
+ - GET /health/ready returns 200 only when database is connected
81
+ - All request logs are valid JSON containing a correlation ID
82
+ - SIGTERM triggers graceful shutdown: stops accepting new connections and drains existing ones
83
+ - GET /metrics returns valid Prometheus exposition format
84
+ - Environment variables validated on startup; missing required vars cause exit 1
85
+
37
86
  ## Success Metrics
38
87
  - Service starts in Docker and responds to API requests
39
88
  - Health probes return healthy status after startup