kanbaii 0.1.2 → 0.2.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 (264) hide show
  1. package/dashboard/404.html +1 -1
  2. package/dashboard/_next/static/chunks/23-74779bf2fc2560e3.js +1 -0
  3. package/dashboard/_next/static/chunks/app/layout-c4919caf1b2a656c.js +1 -0
  4. package/dashboard/_next/static/chunks/app/page-0cbaeeff2545315a.js +1 -0
  5. package/dashboard/_next/static/css/7669ae094c660f9a.css +1 -0
  6. package/dashboard/index.html +1 -1
  7. package/dashboard/index.txt +3 -3
  8. package/dist/cli/banner.d.ts +0 -1
  9. package/dist/cli/banner.js +0 -1
  10. package/dist/cli/doctor.d.ts +0 -1
  11. package/dist/cli/doctor.js +0 -1
  12. package/dist/cli/index.d.ts +0 -1
  13. package/dist/cli/index.js +0 -1
  14. package/dist/server/engines/claudeRunner.d.ts +0 -1
  15. package/dist/server/engines/claudeRunner.js +9 -3
  16. package/dist/server/engines/coordinator.d.ts +0 -1
  17. package/dist/server/engines/coordinator.js +0 -1
  18. package/dist/server/engines/coordinatorPrompt.d.ts +0 -1
  19. package/dist/server/engines/coordinatorPrompt.js +2 -2
  20. package/dist/server/engines/dependencyResolver.d.ts +0 -1
  21. package/dist/server/engines/dependencyResolver.js +0 -1
  22. package/dist/server/engines/planner.d.ts +0 -1
  23. package/dist/server/engines/planner.js +0 -1
  24. package/dist/server/engines/plannerStore.d.ts +0 -1
  25. package/dist/server/engines/plannerStore.js +0 -1
  26. package/dist/server/engines/ralph.d.ts +0 -1
  27. package/dist/server/engines/ralph.js +0 -1
  28. package/dist/server/engines/runStore.d.ts +0 -1
  29. package/dist/server/engines/runStore.js +0 -1
  30. package/dist/server/engines/taskRouter.d.ts +0 -1
  31. package/dist/server/engines/taskRouter.js +3 -3
  32. package/dist/server/engines/teams.d.ts +0 -1
  33. package/dist/server/engines/teams.js +0 -1
  34. package/dist/server/engines/workerPool.d.ts +0 -1
  35. package/dist/server/engines/workerPool.js +16 -1
  36. package/dist/server/index.d.ts +0 -1
  37. package/dist/server/index.js +72 -8
  38. package/dist/server/lib/authMiddleware.d.ts +0 -1
  39. package/dist/server/lib/authMiddleware.js +0 -1
  40. package/dist/server/lib/fileWatcher.d.ts +0 -1
  41. package/dist/server/lib/fileWatcher.js +0 -1
  42. package/dist/server/lib/generateId.d.ts +0 -1
  43. package/dist/server/lib/generateId.js +0 -1
  44. package/dist/server/lib/promptSanitizer.d.ts +5 -0
  45. package/dist/server/lib/promptSanitizer.js +23 -0
  46. package/dist/server/lib/rateLimiter.d.ts +4 -0
  47. package/dist/server/lib/rateLimiter.js +33 -0
  48. package/dist/server/lib/requestLogger.d.ts +2 -0
  49. package/dist/server/lib/requestLogger.js +23 -0
  50. package/dist/server/lib/safePath.d.ts +5 -0
  51. package/dist/server/lib/safePath.js +24 -0
  52. package/dist/server/lib/schemas.d.ts +0 -1
  53. package/dist/server/lib/schemas.js +0 -1
  54. package/dist/server/lib/secretsEncryption.d.ts +3 -0
  55. package/dist/server/lib/secretsEncryption.js +38 -0
  56. package/dist/server/lib/typedEmit.d.ts +0 -1
  57. package/dist/server/lib/typedEmit.js +0 -1
  58. package/dist/server/routes/agents.d.ts +0 -1
  59. package/dist/server/routes/agents.js +0 -1
  60. package/dist/server/routes/auth.d.ts +0 -1
  61. package/dist/server/routes/auth.js +0 -1
  62. package/dist/server/routes/costs.d.ts +0 -1
  63. package/dist/server/routes/costs.js +0 -1
  64. package/dist/server/routes/escalation.d.ts +0 -1
  65. package/dist/server/routes/escalation.js +0 -1
  66. package/dist/server/routes/generate.d.ts +0 -1
  67. package/dist/server/routes/generate.js +1 -3
  68. package/dist/server/routes/mcp.d.ts +0 -1
  69. package/dist/server/routes/mcp.js +0 -1
  70. package/dist/server/routes/planner.d.ts +0 -1
  71. package/dist/server/routes/planner.js +0 -1
  72. package/dist/server/routes/plugins.d.ts +0 -1
  73. package/dist/server/routes/plugins.js +0 -1
  74. package/dist/server/routes/projects.d.ts +0 -1
  75. package/dist/server/routes/projects.js +0 -1
  76. package/dist/server/routes/ralph.d.ts +0 -1
  77. package/dist/server/routes/ralph.js +0 -1
  78. package/dist/server/routes/scheduler.d.ts +0 -1
  79. package/dist/server/routes/scheduler.js +0 -1
  80. package/dist/server/routes/settings.d.ts +0 -1
  81. package/dist/server/routes/settings.js +0 -1
  82. package/dist/server/routes/skills.d.ts +0 -1
  83. package/dist/server/routes/skills.js +0 -1
  84. package/dist/server/routes/soul.d.ts +0 -1
  85. package/dist/server/routes/soul.js +0 -1
  86. package/dist/server/routes/system.d.ts +0 -1
  87. package/dist/server/routes/system.js +15 -12
  88. package/dist/server/routes/tasks.d.ts +0 -1
  89. package/dist/server/routes/tasks.js +0 -1
  90. package/dist/server/routes/teams.d.ts +0 -1
  91. package/dist/server/routes/teams.js +0 -1
  92. package/dist/server/routes/terminal.d.ts +0 -1
  93. package/dist/server/routes/terminal.js +0 -1
  94. package/dist/server/routes/voice.d.ts +0 -1
  95. package/dist/server/routes/voice.js +0 -1
  96. package/dist/server/routes/workItems.d.ts +0 -1
  97. package/dist/server/routes/workItems.js +11 -1
  98. package/dist/server/services/agentRegistry.d.ts +0 -1
  99. package/dist/server/services/agentRegistry.js +0 -1
  100. package/dist/server/services/authService.d.ts +0 -1
  101. package/dist/server/services/authService.js +9 -2
  102. package/dist/server/services/claudeUsage.d.ts +0 -1
  103. package/dist/server/services/claudeUsage.js +32 -7
  104. package/dist/server/services/costTracker.d.ts +0 -1
  105. package/dist/server/services/costTracker.js +0 -1
  106. package/dist/server/services/escalationService.d.ts +0 -1
  107. package/dist/server/services/escalationService.js +5 -2
  108. package/dist/server/services/mcpConfig.d.ts +0 -1
  109. package/dist/server/services/mcpConfig.js +1 -2
  110. package/dist/server/services/pluginLoader.d.ts +0 -1
  111. package/dist/server/services/pluginLoader.js +19 -1
  112. package/dist/server/services/projectStore.d.ts +0 -1
  113. package/dist/server/services/projectStore.js +2 -2
  114. package/dist/server/services/schedulerService.d.ts +0 -1
  115. package/dist/server/services/schedulerService.js +0 -1
  116. package/dist/server/services/settingsService.d.ts +0 -1
  117. package/dist/server/services/settingsService.js +34 -3
  118. package/dist/server/services/skillsRegistry.d.ts +0 -1
  119. package/dist/server/services/skillsRegistry.js +0 -1
  120. package/dist/server/services/soulStore.d.ts +0 -1
  121. package/dist/server/services/soulStore.js +0 -1
  122. package/dist/server/services/telegramService.d.ts +0 -1
  123. package/dist/server/services/telegramService.js +0 -1
  124. package/dist/server/services/terminalManager.d.ts +0 -1
  125. package/dist/server/services/terminalManager.js +3 -2
  126. package/dist/server/services/workItemStore.d.ts +10 -4
  127. package/dist/server/services/workItemStore.js +57 -20
  128. package/dist/shared/types.d.ts +1 -1
  129. package/dist/shared/types.js +0 -1
  130. package/package.json +15 -4
  131. package/dashboard/_next/static/chunks/722-5d5f6d00bb07f427.js +0 -1
  132. package/dashboard/_next/static/chunks/app/layout-f76af5203e5cab0e.js +0 -1
  133. package/dashboard/_next/static/chunks/app/page-e5035f252913cddb.js +0 -1
  134. package/dashboard/_next/static/css/1a1fb46093561e14.css +0 -1
  135. package/dist/cli/banner.d.ts.map +0 -1
  136. package/dist/cli/banner.js.map +0 -1
  137. package/dist/cli/doctor.d.ts.map +0 -1
  138. package/dist/cli/doctor.js.map +0 -1
  139. package/dist/cli/index.d.ts.map +0 -1
  140. package/dist/cli/index.js.map +0 -1
  141. package/dist/server/__tests__/api.test.d.ts +0 -2
  142. package/dist/server/__tests__/api.test.d.ts.map +0 -1
  143. package/dist/server/__tests__/api.test.js +0 -279
  144. package/dist/server/__tests__/api.test.js.map +0 -1
  145. package/dist/server/__tests__/projectStore.test.d.ts +0 -2
  146. package/dist/server/__tests__/projectStore.test.d.ts.map +0 -1
  147. package/dist/server/__tests__/projectStore.test.js +0 -153
  148. package/dist/server/__tests__/projectStore.test.js.map +0 -1
  149. package/dist/server/__tests__/setup.d.ts +0 -2
  150. package/dist/server/__tests__/setup.d.ts.map +0 -1
  151. package/dist/server/__tests__/setup.js +0 -14
  152. package/dist/server/__tests__/setup.js.map +0 -1
  153. package/dist/server/__tests__/workItemStore.test.d.ts +0 -2
  154. package/dist/server/__tests__/workItemStore.test.d.ts.map +0 -1
  155. package/dist/server/__tests__/workItemStore.test.js +0 -323
  156. package/dist/server/__tests__/workItemStore.test.js.map +0 -1
  157. package/dist/server/engines/claudeRunner.d.ts.map +0 -1
  158. package/dist/server/engines/claudeRunner.js.map +0 -1
  159. package/dist/server/engines/coordinator.d.ts.map +0 -1
  160. package/dist/server/engines/coordinator.js.map +0 -1
  161. package/dist/server/engines/coordinatorPrompt.d.ts.map +0 -1
  162. package/dist/server/engines/coordinatorPrompt.js.map +0 -1
  163. package/dist/server/engines/dependencyResolver.d.ts.map +0 -1
  164. package/dist/server/engines/dependencyResolver.js.map +0 -1
  165. package/dist/server/engines/planner.d.ts.map +0 -1
  166. package/dist/server/engines/planner.js.map +0 -1
  167. package/dist/server/engines/plannerStore.d.ts.map +0 -1
  168. package/dist/server/engines/plannerStore.js.map +0 -1
  169. package/dist/server/engines/ralph.d.ts.map +0 -1
  170. package/dist/server/engines/ralph.js.map +0 -1
  171. package/dist/server/engines/runStore.d.ts.map +0 -1
  172. package/dist/server/engines/runStore.js.map +0 -1
  173. package/dist/server/engines/taskRouter.d.ts.map +0 -1
  174. package/dist/server/engines/taskRouter.js.map +0 -1
  175. package/dist/server/engines/teams.d.ts.map +0 -1
  176. package/dist/server/engines/teams.js.map +0 -1
  177. package/dist/server/engines/workerPool.d.ts.map +0 -1
  178. package/dist/server/engines/workerPool.js.map +0 -1
  179. package/dist/server/index.d.ts.map +0 -1
  180. package/dist/server/index.js.map +0 -1
  181. package/dist/server/lib/authMiddleware.d.ts.map +0 -1
  182. package/dist/server/lib/authMiddleware.js.map +0 -1
  183. package/dist/server/lib/fileWatcher.d.ts.map +0 -1
  184. package/dist/server/lib/fileWatcher.js.map +0 -1
  185. package/dist/server/lib/generateId.d.ts.map +0 -1
  186. package/dist/server/lib/generateId.js.map +0 -1
  187. package/dist/server/lib/schemas.d.ts.map +0 -1
  188. package/dist/server/lib/schemas.js.map +0 -1
  189. package/dist/server/lib/typedEmit.d.ts.map +0 -1
  190. package/dist/server/lib/typedEmit.js.map +0 -1
  191. package/dist/server/routes/agents.d.ts.map +0 -1
  192. package/dist/server/routes/agents.js.map +0 -1
  193. package/dist/server/routes/auth.d.ts.map +0 -1
  194. package/dist/server/routes/auth.js.map +0 -1
  195. package/dist/server/routes/costs.d.ts.map +0 -1
  196. package/dist/server/routes/costs.js.map +0 -1
  197. package/dist/server/routes/escalation.d.ts.map +0 -1
  198. package/dist/server/routes/escalation.js.map +0 -1
  199. package/dist/server/routes/generate.d.ts.map +0 -1
  200. package/dist/server/routes/generate.js.map +0 -1
  201. package/dist/server/routes/mcp.d.ts.map +0 -1
  202. package/dist/server/routes/mcp.js.map +0 -1
  203. package/dist/server/routes/planner.d.ts.map +0 -1
  204. package/dist/server/routes/planner.js.map +0 -1
  205. package/dist/server/routes/plugins.d.ts.map +0 -1
  206. package/dist/server/routes/plugins.js.map +0 -1
  207. package/dist/server/routes/projects.d.ts.map +0 -1
  208. package/dist/server/routes/projects.js.map +0 -1
  209. package/dist/server/routes/ralph.d.ts.map +0 -1
  210. package/dist/server/routes/ralph.js.map +0 -1
  211. package/dist/server/routes/scheduler.d.ts.map +0 -1
  212. package/dist/server/routes/scheduler.js.map +0 -1
  213. package/dist/server/routes/settings.d.ts.map +0 -1
  214. package/dist/server/routes/settings.js.map +0 -1
  215. package/dist/server/routes/skills.d.ts.map +0 -1
  216. package/dist/server/routes/skills.js.map +0 -1
  217. package/dist/server/routes/soul.d.ts.map +0 -1
  218. package/dist/server/routes/soul.js.map +0 -1
  219. package/dist/server/routes/system.d.ts.map +0 -1
  220. package/dist/server/routes/system.js.map +0 -1
  221. package/dist/server/routes/tasks.d.ts.map +0 -1
  222. package/dist/server/routes/tasks.js.map +0 -1
  223. package/dist/server/routes/teams.d.ts.map +0 -1
  224. package/dist/server/routes/teams.js.map +0 -1
  225. package/dist/server/routes/terminal.d.ts.map +0 -1
  226. package/dist/server/routes/terminal.js.map +0 -1
  227. package/dist/server/routes/voice.d.ts.map +0 -1
  228. package/dist/server/routes/voice.js.map +0 -1
  229. package/dist/server/routes/workItems.d.ts.map +0 -1
  230. package/dist/server/routes/workItems.js.map +0 -1
  231. package/dist/server/services/agentRegistry.d.ts.map +0 -1
  232. package/dist/server/services/agentRegistry.js.map +0 -1
  233. package/dist/server/services/authService.d.ts.map +0 -1
  234. package/dist/server/services/authService.js.map +0 -1
  235. package/dist/server/services/claudeUsage.d.ts.map +0 -1
  236. package/dist/server/services/claudeUsage.js.map +0 -1
  237. package/dist/server/services/costTracker.d.ts.map +0 -1
  238. package/dist/server/services/costTracker.js.map +0 -1
  239. package/dist/server/services/escalationService.d.ts.map +0 -1
  240. package/dist/server/services/escalationService.js.map +0 -1
  241. package/dist/server/services/mcpConfig.d.ts.map +0 -1
  242. package/dist/server/services/mcpConfig.js.map +0 -1
  243. package/dist/server/services/pluginLoader.d.ts.map +0 -1
  244. package/dist/server/services/pluginLoader.js.map +0 -1
  245. package/dist/server/services/projectStore.d.ts.map +0 -1
  246. package/dist/server/services/projectStore.js.map +0 -1
  247. package/dist/server/services/schedulerService.d.ts.map +0 -1
  248. package/dist/server/services/schedulerService.js.map +0 -1
  249. package/dist/server/services/settingsService.d.ts.map +0 -1
  250. package/dist/server/services/settingsService.js.map +0 -1
  251. package/dist/server/services/skillsRegistry.d.ts.map +0 -1
  252. package/dist/server/services/skillsRegistry.js.map +0 -1
  253. package/dist/server/services/soulStore.d.ts.map +0 -1
  254. package/dist/server/services/soulStore.js.map +0 -1
  255. package/dist/server/services/telegramService.d.ts.map +0 -1
  256. package/dist/server/services/telegramService.js.map +0 -1
  257. package/dist/server/services/terminalManager.d.ts.map +0 -1
  258. package/dist/server/services/terminalManager.js.map +0 -1
  259. package/dist/server/services/workItemStore.d.ts.map +0 -1
  260. package/dist/server/services/workItemStore.js.map +0 -1
  261. package/dist/shared/types.d.ts.map +0 -1
  262. package/dist/shared/types.js.map +0 -1
  263. /package/dashboard/_next/static/{WZgWWvl5DWIMdBOLDHyIK → U_eLKLn69LJkGH6AtpAhH}/_buildManifest.js +0 -0
  264. /package/dashboard/_next/static/{WZgWWvl5DWIMdBOLDHyIK → U_eLKLn69LJkGH6AtpAhH}/_ssgManifest.js +0 -0
@@ -48,6 +48,8 @@ const projectStore = __importStar(require("../services/projectStore"));
48
48
  const soulStore_1 = require("../services/soulStore");
49
49
  const escalationService_1 = require("../services/escalationService");
50
50
  const costTracker_1 = require("../services/costTracker");
51
+ const MAX_COMPLETED_RESULTS = 100;
52
+ const MAX_WORKER_AGE_MS = 30 * 60 * 1000; // 30 minutes
51
53
  let _workers = new Map();
52
54
  let _completedResults = [];
53
55
  let _maxWorkers = 3;
@@ -230,6 +232,7 @@ async function assignTask(opts) {
230
232
  totalFailed: _completedResults.filter(r => !r.success).length,
231
233
  totalTasks: _completedResults.length,
232
234
  });
235
+ cleanup();
233
236
  })();
234
237
  return { workerId };
235
238
  }
@@ -241,4 +244,16 @@ function stopAllWorkers() {
241
244
  catch { }
242
245
  }
243
246
  }
244
- //# sourceMappingURL=workerPool.js.map
247
+ function cleanup() {
248
+ const now = Date.now();
249
+ for (const [id, { info }] of _workers) {
250
+ if (info.status !== 'running' && info.completedAt) {
251
+ const age = now - new Date(info.completedAt).getTime();
252
+ if (age > MAX_WORKER_AGE_MS)
253
+ _workers.delete(id);
254
+ }
255
+ }
256
+ if (_completedResults.length > MAX_COMPLETED_RESULTS) {
257
+ _completedResults = _completedResults.slice(-MAX_COMPLETED_RESULTS);
258
+ }
259
+ }
@@ -6,4 +6,3 @@ export declare function createApp(): {
6
6
  io: Server<ClientToServerEvents, ServerToClientEvents, import("socket.io").DefaultEventsMap, any>;
7
7
  watcher: import("./lib/fileWatcher").FileWatcher;
8
8
  };
9
- //# sourceMappingURL=index.d.ts.map
@@ -68,6 +68,8 @@ const voice_1 = __importDefault(require("./routes/voice"));
68
68
  const escalation_1 = __importDefault(require("./routes/escalation"));
69
69
  const planner_1 = __importDefault(require("./routes/planner"));
70
70
  const authMiddleware_1 = require("./lib/authMiddleware");
71
+ const requestLogger_1 = require("./lib/requestLogger");
72
+ const rateLimiter_1 = require("./lib/rateLimiter");
71
73
  const claudeUsage_1 = require("./services/claudeUsage");
72
74
  const schedulerService_1 = require("./services/schedulerService");
73
75
  const PORT = parseInt(process.env.KANBAII_PORT || '5555', 10);
@@ -76,19 +78,43 @@ function createApp() {
76
78
  const app = (0, express_1.default)();
77
79
  const httpServer = (0, http_1.createServer)(app);
78
80
  // Socket.IO
81
+ const allowedOrigins = [
82
+ 'http://localhost:3000',
83
+ 'http://localhost:5555',
84
+ `http://localhost:${PORT}`,
85
+ ];
79
86
  const io = new socket_io_1.Server(httpServer, {
80
- cors: { origin: '*', methods: ['GET', 'POST', 'PATCH', 'DELETE'] },
87
+ cors: { origin: allowedOrigins, methods: ['GET', 'POST', 'PATCH', 'DELETE'] },
81
88
  serveClient: false,
82
89
  });
83
90
  (0, typedEmit_1.setIO)(io);
84
91
  // Middleware
85
- app.use((0, cors_1.default)());
86
- app.use(express_1.default.json());
92
+ app.use((0, cors_1.default)({ origin: allowedOrigins }));
93
+ app.use(express_1.default.json({ limit: '2mb' }));
94
+ app.use(requestLogger_1.requestLogger);
87
95
  // Auth middleware (only enforces when enabled in settings)
88
96
  app.use(authMiddleware_1.authMiddleware);
97
+ // Rate limiting
98
+ app.use('/api/', rateLimiter_1.apiLimiter);
99
+ app.use('/api/auth', rateLimiter_1.authLimiter);
100
+ app.use('/api/ralph/start', rateLimiter_1.executionLimiter);
101
+ app.use('/api/teams/start', rateLimiter_1.executionLimiter);
102
+ app.use('/api/voice', rateLimiter_1.voiceLimiter);
89
103
  // Health
90
104
  app.get('/api/health', (_req, res) => {
91
- res.json({ ok: true, version: '0.1.0', uptime: process.uptime() });
105
+ const mem = process.memoryUsage();
106
+ res.json({
107
+ ok: true,
108
+ version: require('../../package.json').version,
109
+ uptime: Math.floor(process.uptime()),
110
+ memory: {
111
+ heapUsedMB: Math.round(mem.heapUsed / 1024 / 1024),
112
+ heapTotalMB: Math.round(mem.heapTotal / 1024 / 1024),
113
+ rssMB: Math.round(mem.rss / 1024 / 1024),
114
+ },
115
+ node: process.version,
116
+ platform: process.platform,
117
+ });
92
118
  });
93
119
  // API Routes
94
120
  app.use('/api/projects', projects_1.default);
@@ -111,6 +137,11 @@ function createApp() {
111
137
  app.use('/api/voice', voice_1.default);
112
138
  app.use('/api/escalation', escalation_1.default);
113
139
  app.use('/api/planner', planner_1.default);
140
+ // Global error handler — catches unhandled errors in routes
141
+ app.use((err, _req, res, _next) => {
142
+ console.error('[server] Unhandled error:', err.message);
143
+ res.status(500).json({ ok: false, error: 'Internal server error' });
144
+ });
114
145
  // Static frontend (production)
115
146
  // Dashboard path: works in both dev (src/server/) and prod (dist/server/)
116
147
  const dashboardDir = path_1.default.resolve(__dirname, '..', '..', 'dashboard');
@@ -176,20 +207,53 @@ function createApp() {
176
207
  }
177
208
  // Start server when run directly
178
209
  if (require.main === module) {
179
- const { httpServer, watcher } = createApp();
210
+ const { httpServer, io, watcher } = createApp();
180
211
  watcher.start();
181
212
  (0, claudeUsage_1.startPolling)(60000);
182
213
  (0, schedulerService_1.startSchedulerLoop)();
183
214
  httpServer.listen(PORT, () => {
184
215
  console.log(`\n ⬡ KANBAII server running on http://localhost:${PORT}\n`);
185
216
  });
186
- // Graceful shutdown
217
+ // Graceful shutdown (guarded against multiple calls)
218
+ let _shuttingDown = false;
187
219
  const shutdown = () => {
220
+ if (_shuttingDown) {
221
+ process.exit(1);
222
+ return;
223
+ } // Second Ctrl+C = force kill
224
+ _shuttingDown = true;
188
225
  console.log('\n Shutting down...');
226
+ // Stop background services FIRST (prevents new work)
227
+ try {
228
+ require('./services/claudeUsage').stopPolling();
229
+ }
230
+ catch { }
231
+ try {
232
+ require('./services/schedulerService').stopSchedulerLoop();
233
+ }
234
+ catch { }
235
+ // Stop active executions
236
+ try {
237
+ require('./engines/coordinator').stopCoordinator();
238
+ }
239
+ catch { }
240
+ try {
241
+ require('./engines/workerPool').stopAllWorkers();
242
+ }
243
+ catch { }
244
+ try {
245
+ require('./engines/ralph').stopRalph();
246
+ }
247
+ catch { }
189
248
  watcher.stop();
190
- httpServer.close(() => process.exit(0));
249
+ io.close();
250
+ httpServer.close(() => {
251
+ console.log(' Server closed.');
252
+ process.exit(0);
253
+ });
254
+ // Force exit after 3 seconds
255
+ setTimeout(() => { console.log(' Force exit.'); process.exit(1); }, 3000).unref();
191
256
  };
192
257
  process.on('SIGINT', shutdown);
193
258
  process.on('SIGTERM', shutdown);
194
259
  }
195
- //# sourceMappingURL=index.js.map
@@ -4,4 +4,3 @@ import { Request, Response, NextFunction } from 'express';
4
4
  * Skips auth routes and health check.
5
5
  */
6
6
  export declare function authMiddleware(req: Request, res: Response, next: NextFunction): void;
7
- //# sourceMappingURL=authMiddleware.d.ts.map
@@ -31,4 +31,3 @@ function authMiddleware(req, res, next) {
31
31
  req.username = payload.username;
32
32
  next();
33
33
  }
34
- //# sourceMappingURL=authMiddleware.js.map
@@ -15,4 +15,3 @@ export declare class FileWatcher extends EventEmitter {
15
15
  private handleEvent;
16
16
  }
17
17
  export declare function createFileWatcher(dataDir: string): FileWatcher;
18
- //# sourceMappingURL=fileWatcher.d.ts.map
@@ -67,4 +67,3 @@ exports.FileWatcher = FileWatcher;
67
67
  function createFileWatcher(dataDir) {
68
68
  return new FileWatcher(dataDir);
69
69
  }
70
- //# sourceMappingURL=fileWatcher.js.map
@@ -12,4 +12,3 @@ export declare function generateId(title: string, prefix?: string): string;
12
12
  * Caller must ensure uniqueness.
13
13
  */
14
14
  export declare function projectSlug(title: string): string;
15
- //# sourceMappingURL=generateId.d.ts.map
@@ -38,4 +38,3 @@ function generateId(title, prefix = '') {
38
38
  function projectSlug(title) {
39
39
  return slugify(title);
40
40
  }
41
- //# sourceMappingURL=generateId.js.map
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Sanitize user-controlled text before injecting into Claude prompts.
3
+ * Strips prompt injection patterns without altering normal text.
4
+ */
5
+ export declare function sanitizeForPrompt(text: string): string;
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.sanitizeForPrompt = sanitizeForPrompt;
4
+ /**
5
+ * Sanitize user-controlled text before injecting into Claude prompts.
6
+ * Strips prompt injection patterns without altering normal text.
7
+ */
8
+ function sanitizeForPrompt(text) {
9
+ if (!text || typeof text !== 'string')
10
+ return '';
11
+ let sanitized = text;
12
+ // Strip system/assistant role markers that could override prompt structure
13
+ sanitized = sanitized.replace(/^(system|assistant|human|user):/gim, '[role]:');
14
+ // Strip XML-like tags that Claude interprets specially
15
+ sanitized = sanitized.replace(/<\/?(?:system|instructions|context|prompt|tool_use|tool_result|thinking)[^>]*>/gi, '');
16
+ // Strip markdown heading overrides that look like injection
17
+ sanitized = sanitized.replace(/^#{1,3}\s*(system|instructions|role|override|ignore|forget)/gim, '[$1]');
18
+ // Limit length to prevent context flooding
19
+ if (sanitized.length > 10000) {
20
+ sanitized = sanitized.slice(0, 10000) + '\n[truncated]';
21
+ }
22
+ return sanitized;
23
+ }
@@ -0,0 +1,4 @@
1
+ export declare const apiLimiter: import("express-rate-limit").RateLimitRequestHandler;
2
+ export declare const authLimiter: import("express-rate-limit").RateLimitRequestHandler;
3
+ export declare const executionLimiter: import("express-rate-limit").RateLimitRequestHandler;
4
+ export declare const voiceLimiter: import("express-rate-limit").RateLimitRequestHandler;
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.voiceLimiter = exports.executionLimiter = exports.authLimiter = exports.apiLimiter = void 0;
7
+ const express_rate_limit_1 = __importDefault(require("express-rate-limit"));
8
+ // General API: 100 requests per minute
9
+ exports.apiLimiter = (0, express_rate_limit_1.default)({
10
+ windowMs: 60 * 1000,
11
+ max: 100,
12
+ standardHeaders: true,
13
+ legacyHeaders: false,
14
+ message: { ok: false, error: 'Too many requests, try again later' },
15
+ });
16
+ // Auth endpoints: 10 attempts per 15 minutes
17
+ exports.authLimiter = (0, express_rate_limit_1.default)({
18
+ windowMs: 15 * 60 * 1000,
19
+ max: 10,
20
+ message: { ok: false, error: 'Too many login attempts' },
21
+ });
22
+ // Execution endpoints (ralph/teams/start): 5 per minute
23
+ exports.executionLimiter = (0, express_rate_limit_1.default)({
24
+ windowMs: 60 * 1000,
25
+ max: 5,
26
+ message: { ok: false, error: 'Too many execution requests' },
27
+ });
28
+ // Voice transcription: 10 per minute
29
+ exports.voiceLimiter = (0, express_rate_limit_1.default)({
30
+ windowMs: 60 * 1000,
31
+ max: 10,
32
+ message: { ok: false, error: 'Too many transcription requests' },
33
+ });
@@ -0,0 +1,2 @@
1
+ import { Request, Response, NextFunction } from 'express';
2
+ export declare function requestLogger(req: Request, res: Response, next: NextFunction): void;
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.requestLogger = requestLogger;
7
+ const crypto_1 = __importDefault(require("crypto"));
8
+ function requestLogger(req, res, next) {
9
+ const id = crypto_1.default.randomBytes(4).toString('hex');
10
+ const start = Date.now();
11
+ req.requestId = id;
12
+ res.on('finish', () => {
13
+ const duration = Date.now() - start;
14
+ if (req.path.startsWith('/api/') && req.path !== '/api/health') {
15
+ const status = res.statusCode;
16
+ const level = status >= 500 ? 'ERROR' : status >= 400 ? 'WARN' : 'INFO';
17
+ if (level !== 'INFO' || duration > 1000) {
18
+ console.log(`[${level}] ${id} ${req.method} ${req.path} ${status} ${duration}ms`);
19
+ }
20
+ }
21
+ });
22
+ next();
23
+ }
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Validate that a slug/filename doesn't escape the base directory.
3
+ * Throws if path traversal detected.
4
+ */
5
+ export declare function safePath(baseDir: string, ...segments: string[]): string;
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.safePath = safePath;
7
+ const path_1 = __importDefault(require("path"));
8
+ /**
9
+ * Validate that a slug/filename doesn't escape the base directory.
10
+ * Throws if path traversal detected.
11
+ */
12
+ function safePath(baseDir, ...segments) {
13
+ for (const seg of segments) {
14
+ if (typeof seg !== 'string' || seg.includes('..') || seg.includes('\0') || /[<>:"|?*]/.test(seg)) {
15
+ throw new Error(`Invalid path segment: ${seg}`);
16
+ }
17
+ }
18
+ const resolved = path_1.default.resolve(baseDir, ...segments);
19
+ const normalizedBase = path_1.default.resolve(baseDir);
20
+ if (!resolved.startsWith(normalizedBase + path_1.default.sep) && resolved !== normalizedBase) {
21
+ throw new Error(`Path escapes base directory`);
22
+ }
23
+ return resolved;
24
+ }
@@ -2009,4 +2009,3 @@ export declare const MoveTaskDto: z.ZodObject<{
2009
2009
  toColumn: "review" | "done" | "backlog" | "todo" | "in-progress";
2010
2010
  toIndex: number;
2011
2011
  }>;
2012
- //# sourceMappingURL=schemas.d.ts.map
@@ -134,4 +134,3 @@ exports.MoveTaskDto = zod_1.z.object({
134
134
  toColumn: exports.TaskColumnSchema,
135
135
  toIndex: zod_1.z.number().int().min(0),
136
136
  });
137
- //# sourceMappingURL=schemas.js.map
@@ -0,0 +1,3 @@
1
+ export declare function encrypt(text: string): string;
2
+ export declare function decrypt(encoded: string): string;
3
+ export declare function isEncrypted(value: string): boolean;
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.encrypt = encrypt;
7
+ exports.decrypt = decrypt;
8
+ exports.isEncrypted = isEncrypted;
9
+ const crypto_1 = __importDefault(require("crypto"));
10
+ const os_1 = __importDefault(require("os"));
11
+ const ALGORITHM = 'aes-256-gcm';
12
+ function deriveKey() {
13
+ const material = [os_1.default.hostname(), os_1.default.homedir(), 'kanbaii-v1'].join(':');
14
+ return crypto_1.default.scryptSync(material, 'kanbaii-salt', 32);
15
+ }
16
+ function encrypt(text) {
17
+ const key = deriveKey();
18
+ const iv = crypto_1.default.randomBytes(16);
19
+ const cipher = crypto_1.default.createCipheriv(ALGORITHM, key, iv);
20
+ let encrypted = cipher.update(text, 'utf-8', 'hex');
21
+ encrypted += cipher.final('hex');
22
+ const tag = cipher.getAuthTag().toString('hex');
23
+ return `enc:${iv.toString('hex')}:${tag}:${encrypted}`;
24
+ }
25
+ function decrypt(encoded) {
26
+ if (!encoded.startsWith('enc:'))
27
+ return encoded;
28
+ const [, ivHex, tagHex, data] = encoded.split(':');
29
+ const key = deriveKey();
30
+ const decipher = crypto_1.default.createDecipheriv(ALGORITHM, key, Buffer.from(ivHex, 'hex'));
31
+ decipher.setAuthTag(Buffer.from(tagHex, 'hex'));
32
+ let decrypted = decipher.update(data, 'hex', 'utf-8');
33
+ decrypted += decipher.final('utf-8');
34
+ return decrypted;
35
+ }
36
+ function isEncrypted(value) {
37
+ return typeof value === 'string' && value.startsWith('enc:');
38
+ }
@@ -4,4 +4,3 @@ export type TypedServer = Server<ClientToServerEvents, ServerToClientEvents>;
4
4
  export declare function setIO(server: TypedServer): void;
5
5
  export declare function getIO(): TypedServer;
6
6
  export declare function emit<E extends keyof ServerToClientEvents>(event: E, ...args: Parameters<ServerToClientEvents[E]>): void;
7
- //# sourceMappingURL=typedEmit.d.ts.map
@@ -15,4 +15,3 @@ function getIO() {
15
15
  function emit(event, ...args) {
16
16
  getIO().emit(event, ...args);
17
17
  }
18
- //# sourceMappingURL=typedEmit.js.map
@@ -1,3 +1,2 @@
1
1
  declare const router: import("express-serve-static-core").Router;
2
2
  export default router;
3
- //# sourceMappingURL=agents.d.ts.map
@@ -96,4 +96,3 @@ router.delete('/:name', (req, res) => {
96
96
  }
97
97
  });
98
98
  exports.default = router;
99
- //# sourceMappingURL=agents.js.map
@@ -1,3 +1,2 @@
1
1
  declare const router: import("express-serve-static-core").Router;
2
2
  export default router;
3
- //# sourceMappingURL=auth.d.ts.map
@@ -89,4 +89,3 @@ router.get('/verify', (req, res) => {
89
89
  res.json({ ok: true, data: { userId: payload.userId, username: payload.username } });
90
90
  });
91
91
  exports.default = router;
92
- //# sourceMappingURL=auth.js.map
@@ -1,3 +1,2 @@
1
1
  declare const router: import("express-serve-static-core").Router;
2
2
  export default router;
3
- //# sourceMappingURL=costs.d.ts.map
@@ -78,4 +78,3 @@ router.delete('/clear', (req, res) => {
78
78
  res.json({ ok: true });
79
79
  });
80
80
  exports.default = router;
81
- //# sourceMappingURL=costs.js.map
@@ -1,3 +1,2 @@
1
1
  declare const router: import("express-serve-static-core").Router;
2
2
  export default router;
3
- //# sourceMappingURL=escalation.d.ts.map
@@ -69,4 +69,3 @@ router.post('/clear', (_req, res) => {
69
69
  res.json({ ok: true });
70
70
  });
71
71
  exports.default = router;
72
- //# sourceMappingURL=escalation.js.map
@@ -1,3 +1,2 @@
1
1
  declare const router: import("express-serve-static-core").Router;
2
2
  export default router;
3
- //# sourceMappingURL=generate.d.ts.map
@@ -11,8 +11,7 @@ function callClaude(prompt) {
11
11
  return new Promise((resolve, reject) => {
12
12
  const proc = (0, child_process_1.spawn)('claude', ['-p', '--output-format', 'text'], {
13
13
  stdio: ['pipe', 'pipe', 'pipe'],
14
- shell: true,
15
- timeout: 120000,
14
+ windowsHide: true,
16
15
  });
17
16
  let stdout = '';
18
17
  let stderr = '';
@@ -121,4 +120,3 @@ Order tasks by execution order (dependencies first). Generate 3-8 tasks.`;
121
120
  }
122
121
  });
123
122
  exports.default = router;
124
- //# sourceMappingURL=generate.js.map
@@ -1,3 +1,2 @@
1
1
  declare const router: import("express-serve-static-core").Router;
2
2
  export default router;
3
- //# sourceMappingURL=mcp.d.ts.map
@@ -75,4 +75,3 @@ router.patch('/servers/:name/toggle', (req, res) => {
75
75
  res.json({ ok: true });
76
76
  });
77
77
  exports.default = router;
78
- //# sourceMappingURL=mcp.js.map
@@ -1,3 +1,2 @@
1
1
  declare const router: import("express-serve-static-core").Router;
2
2
  export default router;
3
- //# sourceMappingURL=planner.d.ts.map
@@ -87,4 +87,3 @@ router.post('/update-item', (req, res) => {
87
87
  res.json({ ok: true, data: { itemId: item.id, status: item.status, message: `Item "${item.title}" updated to ${item.status}. ${item.tasks.length} tasks.` } });
88
88
  });
89
89
  exports.default = router;
90
- //# sourceMappingURL=planner.js.map
@@ -1,3 +1,2 @@
1
1
  declare const router: import("express-serve-static-core").Router;
2
2
  export default router;
3
- //# sourceMappingURL=plugins.d.ts.map
@@ -19,4 +19,3 @@ router.post('/rescan', (_req, res) => {
19
19
  res.json({ ok: true, data: plugins });
20
20
  });
21
21
  exports.default = router;
22
- //# sourceMappingURL=plugins.js.map
@@ -1,3 +1,2 @@
1
1
  declare const router: import("express-serve-static-core").Router;
2
2
  export default router;
3
- //# sourceMappingURL=projects.d.ts.map
@@ -97,4 +97,3 @@ router.delete('/:slug', (req, res) => {
97
97
  }
98
98
  });
99
99
  exports.default = router;
100
- //# sourceMappingURL=projects.js.map
@@ -1,3 +1,2 @@
1
1
  declare const router: import("express-serve-static-core").Router;
2
2
  export default router;
3
- //# sourceMappingURL=ralph.d.ts.map
@@ -45,4 +45,3 @@ router.get('/state', (_req, res) => {
45
45
  res.json({ ok: true, data: runStore_1.runStore.getState() });
46
46
  });
47
47
  exports.default = router;
48
- //# sourceMappingURL=ralph.js.map
@@ -1,3 +1,2 @@
1
1
  declare const router: import("express-serve-static-core").Router;
2
2
  export default router;
3
- //# sourceMappingURL=scheduler.d.ts.map
@@ -115,4 +115,3 @@ router.post('/watchdog', (_req, res) => {
115
115
  res.json({ ok: true, data: { reset: resetCount } });
116
116
  });
117
117
  exports.default = router;
118
- //# sourceMappingURL=scheduler.js.map
@@ -1,3 +1,2 @@
1
1
  declare const router: import("express-serve-static-core").Router;
2
2
  export default router;
3
- //# sourceMappingURL=settings.d.ts.map
@@ -63,4 +63,3 @@ router.patch('/:section', (req, res) => {
63
63
  res.json({ ok: true, data: updated });
64
64
  });
65
65
  exports.default = router;
66
- //# sourceMappingURL=settings.js.map
@@ -1,3 +1,2 @@
1
1
  declare const router: import("express-serve-static-core").Router;
2
2
  export default router;
3
- //# sourceMappingURL=skills.d.ts.map
@@ -59,4 +59,3 @@ router.delete('/:name', (req, res) => {
59
59
  res.json({ ok: true });
60
60
  });
61
61
  exports.default = router;
62
- //# sourceMappingURL=skills.js.map
@@ -1,3 +1,2 @@
1
1
  declare const router: import("express-serve-static-core").Router;
2
2
  export default router;
3
- //# sourceMappingURL=soul.d.ts.map
@@ -129,4 +129,3 @@ router.get('/health', (req, res) => {
129
129
  res.json({ ok: true, data: soulStore.getHealth(req.params.slug) });
130
130
  });
131
131
  exports.default = router;
132
- //# sourceMappingURL=soul.js.map
@@ -1,3 +1,2 @@
1
1
  declare const router: import("express-serve-static-core").Router;
2
2
  export default router;
3
- //# sourceMappingURL=system.d.ts.map
@@ -6,33 +6,36 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  const express_1 = require("express");
7
7
  const child_process_1 = require("child_process");
8
8
  const fs_1 = __importDefault(require("fs"));
9
+ const path_1 = __importDefault(require("path"));
9
10
  const router = (0, express_1.Router)();
10
- // POST /api/open-folder — Open a folder in the system file explorer
11
11
  router.post('/open-folder', (req, res) => {
12
12
  const { path: folderPath } = req.body;
13
- if (!folderPath) {
13
+ if (!folderPath || typeof folderPath !== 'string') {
14
14
  return res.status(400).json({ ok: false, error: 'path is required' });
15
15
  }
16
- if (!fs_1.default.existsSync(folderPath)) {
17
- return res.status(404).json({ ok: false, error: 'Path does not exist' });
16
+ const resolved = path_1.default.resolve(folderPath);
17
+ if (!fs_1.default.existsSync(resolved) || !fs_1.default.statSync(resolved).isDirectory()) {
18
+ return res.status(404).json({ ok: false, error: 'Directory not found' });
18
19
  }
19
20
  const platform = process.platform;
20
21
  let cmd;
22
+ let args;
21
23
  if (platform === 'win32') {
22
- cmd = `explorer "${folderPath}"`;
24
+ cmd = 'explorer';
25
+ args = [resolved];
23
26
  }
24
27
  else if (platform === 'darwin') {
25
- cmd = `open "${folderPath}"`;
28
+ cmd = 'open';
29
+ args = [resolved];
26
30
  }
27
31
  else {
28
- cmd = `xdg-open "${folderPath}"`;
32
+ cmd = 'xdg-open';
33
+ args = [resolved];
29
34
  }
30
- (0, child_process_1.exec)(cmd, (err) => {
31
- if (err) {
32
- return res.status(500).json({ ok: false, error: err.message });
33
- }
35
+ (0, child_process_1.execFile)(cmd, args, (err) => {
36
+ if (err)
37
+ return res.status(500).json({ ok: false, error: 'Failed to open folder' });
34
38
  res.json({ ok: true });
35
39
  });
36
40
  });
37
41
  exports.default = router;
38
- //# sourceMappingURL=system.js.map
@@ -1,3 +1,2 @@
1
1
  declare const router: import("express-serve-static-core").Router;
2
2
  export default router;
3
- //# sourceMappingURL=tasks.d.ts.map