profclaw 0.0.1-beta.1 → 0.0.1-beta.2

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 (151) hide show
  1. package/README.md +1 -1
  2. package/dist/adapters/openclaw.js +1 -1
  3. package/dist/agents/executor.js +38 -6
  4. package/dist/auth/auth-service.js +8 -6
  5. package/dist/auth/device-identity.js +7 -5
  6. package/dist/auth/github-oauth.js +3 -1
  7. package/dist/auth/pairing-codes.js +6 -4
  8. package/dist/browser/service.js +5 -3
  9. package/dist/chat/execution/guardrails.js +3 -1
  10. package/dist/chat/execution/workflows/executor.js +4 -2
  11. package/dist/chat/memory.js +3 -1
  12. package/dist/chat/proactive/index.js +13 -11
  13. package/dist/chat/tools.js +8 -7
  14. package/dist/cli/commands/auth.js +22 -13
  15. package/dist/cli/commands/onboard.js +248 -59
  16. package/dist/cli/commands/setup.js +180 -104
  17. package/dist/cron/issue-poller.js +1 -1
  18. package/dist/hooks/agent-webhook.js +10 -7
  19. package/dist/hooks/prompt-submit.js +5 -6
  20. package/dist/hooks/session-end.js +10 -6
  21. package/dist/hooks/tool-use.js +9 -6
  22. package/dist/integrations/github-ticket-sync.js +8 -6
  23. package/dist/integrations/github.js +8 -6
  24. package/dist/integrations/jira.js +5 -3
  25. package/dist/mcp/server.js +12 -9
  26. package/dist/memory/experience-store.js +15 -14
  27. package/dist/notifications/slack.js +4 -2
  28. package/dist/providers/types.d.ts +2 -2
  29. package/dist/queue/failure-handler.js +15 -13
  30. package/dist/queue/index.js +6 -4
  31. package/dist/queue/memory-queue.js +23 -27
  32. package/dist/queue/task-queue.js +18 -22
  33. package/dist/routes/agents.js +3 -1
  34. package/dist/routes/auth.js +11 -9
  35. package/dist/routes/devices.js +17 -15
  36. package/dist/routes/gateway.js +3 -1
  37. package/dist/routes/hooks.js +7 -5
  38. package/dist/routes/import.js +10 -8
  39. package/dist/routes/labels.js +11 -9
  40. package/dist/routes/oobe.js +8 -6
  41. package/dist/routes/openapi.js +1 -1
  42. package/dist/routes/projects.js +27 -25
  43. package/dist/routes/settings.js +7 -5
  44. package/dist/routes/setup.js +12 -11
  45. package/dist/routes/slack.js +28 -27
  46. package/dist/routes/stats.js +6 -4
  47. package/dist/routes/summaries.js +4 -3
  48. package/dist/routes/sync.js +7 -5
  49. package/dist/routes/tasks.js +10 -8
  50. package/dist/routes/tickets.js +26 -26
  51. package/dist/routes/tokens.js +5 -3
  52. package/dist/routes/users.js +14 -12
  53. package/dist/routes/webhooks.js +5 -3
  54. package/dist/settings/index.js +3 -1
  55. package/dist/storage/index.d.ts +2 -1
  56. package/dist/storage/index.js +9 -4
  57. package/dist/storage/libsql.js +29 -21
  58. package/dist/storage/schema.d.ts +107 -46
  59. package/dist/summaries/storage.js +3 -1
  60. package/dist/tickets/index.js +10 -8
  61. package/dist/utils/circuit-breaker.js +10 -5
  62. package/dist/utils/logger.d.ts +5 -1
  63. package/dist/utils/logger.js +23 -7
  64. package/package.json +4 -3
  65. package/ui/dist/assets/{ActivityView-CkPgKhwm.js → ActivityView-DIPQSJ_d.js} +1 -1
  66. package/ui/dist/assets/{AgentList-C3SVdeEz.js → AgentList-CqyaYrcq.js} +1 -1
  67. package/ui/dist/assets/{AnalyticsDashboard-DVU--vlP.js → AnalyticsDashboard-C-mjuGHT.js} +1 -1
  68. package/ui/dist/assets/{AreaChart-B5qMEGWj.js → AreaChart-CfYWmbtr.js} +1 -1
  69. package/ui/dist/assets/{CartesianChart-B50bcUJi.js → CartesianChart-BaQ3It0c.js} +1 -1
  70. package/ui/dist/assets/{ChatView-BZFJs7w_.js → ChatView-DxxQy6pl.js} +1 -1
  71. package/ui/dist/assets/CostsDashboard-CDBBcGkg.js +1 -0
  72. package/ui/dist/assets/{EstimateSelect-CLpB4NQO.js → EstimateSelect-CDjf5qKl.js} +1 -1
  73. package/ui/dist/assets/{FloatingChatbot-CBzBY9a0.js → FloatingChatbot-CZHjvJIe.js} +1 -1
  74. package/ui/dist/assets/{InviteCodeManagement-DsbdPa6W.js → InviteCodeManagement-DTm-IPTm.js} +1 -1
  75. package/ui/dist/assets/{ProjectDetail-BEM3tFXg.js → ProjectDetail-DlYUcOss.js} +1 -1
  76. package/ui/dist/assets/{ProjectIcon-CN1FmFAk.js → ProjectIcon-BMRpnM04.js} +1 -1
  77. package/ui/dist/assets/{ProjectList-DSDaNhxQ.js → ProjectList-D85TN0i0.js} +1 -1
  78. package/ui/dist/assets/{Settings-dPVcqC_d.js → Settings-CgPqzUvj.js} +3 -3
  79. package/ui/dist/assets/{StatusIndicator-DA3NAo_b.js → StatusIndicator-yig0uZEA.js} +1 -1
  80. package/ui/dist/assets/{SummaryDetail-Bjnf9lT8.js → SummaryDetail-CwLAfHgJ.js} +1 -1
  81. package/ui/dist/assets/{SummaryList-ENwKDBKW.js → SummaryList-BvS5Idnu.js} +1 -1
  82. package/ui/dist/assets/{TaskDetail-DnwG6MzB.js → TaskDetail-zarC1fOt.js} +1 -1
  83. package/ui/dist/assets/{TaskList-D9Ug_HiV.js → TaskList-CyJq3ANE.js} +1 -1
  84. package/ui/dist/assets/{TicketBoard-CviH1571.js → TicketBoard-BlWr3-iH.js} +1 -1
  85. package/ui/dist/assets/{TicketDetail-8Jk8O-33.js → TicketDetail-DmqWKj2W.js} +1 -1
  86. package/ui/dist/assets/{TicketList-B-iV4rRA.js → TicketList-Scj4pMWa.js} +1 -1
  87. package/ui/dist/assets/{UserManagement-CPZ8s7s2.js → UserManagement-BH7uG7dw.js} +1 -1
  88. package/ui/dist/assets/{ViewSwitcher-BUyOOWDI.js → ViewSwitcher-3HzZUdWn.js} +1 -1
  89. package/ui/dist/assets/{alert-dialog-BOmnTkN-.js → alert-dialog-DWPb2IfQ.js} +1 -1
  90. package/ui/dist/assets/{archive-D5my9zOG.js → archive-CGck7gxR.js} +1 -1
  91. package/ui/dist/assets/{badge-B4ov81_m.js → badge-DEmc3Z_l.js} +1 -1
  92. package/ui/dist/assets/{brain-C53ElFLD.js → brain-CfFdLVqb.js} +1 -1
  93. package/ui/dist/assets/{bug-D0TJoCYn.js → bug-DqSGPUUE.js} +1 -1
  94. package/ui/dist/assets/{calendar-BkWIhKa1.js → calendar-BuZ4zbPW.js} +1 -1
  95. package/ui/dist/assets/{chevron-up-BRTtndUZ.js → chevron-up-DcJ4LL_N.js} +1 -1
  96. package/ui/dist/assets/{circle-x-BN89YhbS.js → circle-x-C78PNZjF.js} +1 -1
  97. package/ui/dist/assets/{constants-fc7TFI7u.js → constants-DhDjZe4P.js} +1 -1
  98. package/ui/dist/assets/{cpu-B41x1-vV.js → cpu-Ck6AoG8c.js} +1 -1
  99. package/ui/dist/assets/{database-D9Cnfmzj.js → database-CA2w8Lvt.js} +1 -1
  100. package/ui/dist/assets/{dialog-DrWB4EYD.js → dialog-BOdGWhgE.js} +1 -1
  101. package/ui/dist/assets/{ellipsis-NuUWekvu.js → ellipsis-FhHKRbfl.js} +1 -1
  102. package/ui/dist/assets/{ellipsis-vertical-BueMfuCw.js → ellipsis-vertical-CO0UqE4-.js} +1 -1
  103. package/ui/dist/assets/{file-code-HR9829Jc.js → file-code-ChnhYYj1.js} +1 -1
  104. package/ui/dist/assets/{folder-open-C_7oYEqe.js → folder-open-CHwA1-ve.js} +1 -1
  105. package/ui/dist/assets/{funnel-B5gmNXGf.js → funnel-ByEjRFNB.js} +1 -1
  106. package/ui/dist/assets/{git-branch-BRMiJmV3.js → git-branch-GTOPQgU4.js} +1 -1
  107. package/ui/dist/assets/{git-commit-horizontal-CXOUQeJI.js → git-commit-horizontal-F5M84Kut.js} +1 -1
  108. package/ui/dist/assets/{globe-CCspjvus.js → globe-CQWfr7hT.js} +1 -1
  109. package/ui/dist/assets/{hash-g3102kPC.js → hash-nKC9gtLg.js} +1 -1
  110. package/ui/dist/assets/{history-CNqcBBrV.js → history-DfFSA9xJ.js} +1 -1
  111. package/ui/dist/assets/{index-kb4AJXUB.js → index--JkIxVXb.js} +3 -3
  112. package/ui/dist/assets/index-Ca3vk7Gq.js +1 -0
  113. package/ui/dist/assets/{index-C9jNQXzL.js → index-DHGvP9mp.js} +1 -1
  114. package/ui/dist/assets/index-DeI8lKRR.js +1 -0
  115. package/ui/dist/assets/{index-DURTouJI.js → index-Z4-RtZcs.js} +1 -1
  116. package/ui/dist/assets/{index-CEZ6R2Uw.js → index-a4Fxq0Hb.js} +1 -1
  117. package/ui/dist/assets/{layers-CLXiHN6o.js → layers-DFeLExSa.js} +1 -1
  118. package/ui/dist/assets/{layout-dashboard-B07MFhBs.js → layout-dashboard-WmgjMhWF.js} +1 -1
  119. package/ui/dist/assets/{lightbulb-B2dgG5ks.js → lightbulb-Bo8hEr7B.js} +1 -1
  120. package/ui/dist/assets/{link-2-BxNmr9hL.js → link-2-YqrpQXBH.js} +1 -1
  121. package/ui/dist/assets/{markdown-renderer-CjU6hBcW.js → markdown-renderer-Croje6Xe.js} +1 -1
  122. package/ui/dist/assets/{message-square-Bf2-CVbt.js → message-square-CD0H5hot.js} +1 -1
  123. package/ui/dist/assets/{pencil-D096Ey62.js → pencil-DpFnj5dn.js} +1 -1
  124. package/ui/dist/assets/{play-DfdcSI3x.js → play-DVgea_jT.js} +1 -1
  125. package/ui/dist/assets/{popover-BV0QJDQq.js → popover-JXecfWG5.js} +1 -1
  126. package/ui/dist/assets/{progress-DjPEDJfI.js → progress-C1ghf1Fu.js} +1 -1
  127. package/ui/dist/assets/{rocket-CPsTc-5G.js → rocket-BFxPYGx9.js} +1 -1
  128. package/ui/dist/assets/{select-LsO16slr.js → select-MADP8m6Q.js} +1 -1
  129. package/ui/dist/assets/{send-BDYBZDUZ.js → send-eYnW_7n-.js} +1 -1
  130. package/ui/dist/assets/{server-B3k6noce.js → server-CPMaysH8.js} +1 -1
  131. package/ui/dist/assets/{settings-2-Cu4xTjhG.js → settings-2-scXUOuE_.js} +1 -1
  132. package/ui/dist/assets/{sheet-BScLnPKX.js → sheet-r6NSOxi-.js} +1 -1
  133. package/ui/dist/assets/{shield-check-CQqkwufI.js → shield-check-PEr7nmVw.js} +1 -1
  134. package/ui/dist/assets/{shield-off-ZFruH9KO.js → shield-off-CLtXio62.js} +1 -1
  135. package/ui/dist/assets/{skeleton-CtkIA_MU.js → skeleton-C9oEzNlU.js} +1 -1
  136. package/ui/dist/assets/{smartphone-DnoksVkc.js → smartphone-DusFfY0U.js} +1 -1
  137. package/ui/dist/assets/{square-uD9ZHMfW.js → square-e1yxB2eR.js} +1 -1
  138. package/ui/dist/assets/{switch-MQPnwGJK.js → switch-tNs0n-kz.js} +1 -1
  139. package/ui/dist/assets/{table-B8cqlywA.js → table-CXxtLicg.js} +1 -1
  140. package/ui/dist/assets/{tag-wEJQRWlV.js → tag-tAwMmQ9G.js} +1 -1
  141. package/ui/dist/assets/{textarea-D5LJCOGl.js → textarea-BjiEeIWh.js} +1 -1
  142. package/ui/dist/assets/{timer-mbGHegmr.js → timer-Vel1N3RP.js} +1 -1
  143. package/ui/dist/assets/{tooltip-Df1CunSp.js → tooltip-ZMwtfr1J.js} +1 -1
  144. package/ui/dist/assets/{trash-2-B4oAXsX-.js → trash-2-eM-CNwsZ.js} +1 -1
  145. package/ui/dist/assets/{trending-up-BGWxvlmZ.js → trending-up-BGafmjRo.js} +1 -1
  146. package/ui/dist/assets/{wand-sparkles-CZy4xvL3.js → wand-sparkles-DPvcd9Pi.js} +1 -1
  147. package/ui/dist/assets/{wrench-ByZkjO6m.js → wrench-B8s3zYVV.js} +1 -1
  148. package/ui/dist/index.html +1 -1
  149. package/ui/dist/assets/CostsDashboard-ChfH8BlG.js +0 -1
  150. package/ui/dist/assets/index-27mTPKuh.js +0 -1
  151. package/ui/dist/assets/index-BMx3fH-e.js +0 -1
@@ -11,6 +11,8 @@ import { createHmac, timingSafeEqual, randomUUID } from "crypto";
11
11
  import { getDb } from "../storage/index.js";
12
12
  import { tickets, projects } from "../storage/schema.js";
13
13
  import { eq, desc, like } from "drizzle-orm";
14
+ import { createContextualLogger } from "../utils/logger.js";
15
+ const log = createContextualLogger('Slack');
14
16
  import { getWebhookDedupValue, isDuplicateWebhookEvent, setWebhookDedupValue, } from "./webhook-dedup.js";
15
17
  const slack = new Hono();
16
18
  // Configuration
@@ -37,7 +39,7 @@ function verifySlackSignature(signingSecret, signature, timestamp, body) {
37
39
  // Check timestamp is within 5 minutes
38
40
  const fiveMinutesAgo = Math.floor(Date.now() / 1000) - 60 * 5;
39
41
  if (parseInt(timestamp, 10) < fiveMinutesAgo) {
40
- console.warn("[Slack] Request timestamp too old");
42
+ log.warn('Request timestamp too old');
41
43
  return false;
42
44
  }
43
45
  const sigBasestring = `v0:${timestamp}:${body}`;
@@ -107,7 +109,7 @@ function extractInlineCommand(text) {
107
109
  }
108
110
  async function postSlackResponse(options) {
109
111
  if (!SLACK_BOT_TOKEN) {
110
- console.warn("[Slack] Missing SLACK_BOT_TOKEN for inline command response");
112
+ log.warn('Missing SLACK_BOT_TOKEN for inline command response');
111
113
  return;
112
114
  }
113
115
  const url = options.ephemeral && options.userId
@@ -135,7 +137,7 @@ async function postSlackResponse(options) {
135
137
  body: JSON.stringify(payload),
136
138
  });
137
139
  if (!res.ok) {
138
- console.warn(`[Slack] Failed to post response: ${res.status}`);
140
+ log.warn('Failed to post response', { status: res.status });
139
141
  }
140
142
  }
141
143
  // COMMAND HANDLERS
@@ -204,19 +206,18 @@ async function handleTicketList(args) {
204
206
  try {
205
207
  const limit = parseInt(args.limit || "5", 10);
206
208
  const status = args.status;
207
- let query = db
208
- .select()
209
- .from(tickets)
210
- .orderBy(desc(tickets.createdAt))
211
- .limit(limit);
212
- if (status) {
213
- query = db
209
+ const query = status
210
+ ? db
214
211
  .select()
215
212
  .from(tickets)
216
213
  .where(eq(tickets.status, status))
217
214
  .orderBy(desc(tickets.createdAt))
215
+ .limit(limit)
216
+ : db
217
+ .select()
218
+ .from(tickets)
219
+ .orderBy(desc(tickets.createdAt))
218
220
  .limit(limit);
219
- }
220
221
  const results = await query;
221
222
  if (results.length === 0) {
222
223
  return {
@@ -257,7 +258,7 @@ async function handleTicketList(args) {
257
258
  };
258
259
  }
259
260
  catch (error) {
260
- console.error("[Slack] Error listing tickets:", error);
261
+ log.error('Error listing tickets', error instanceof Error ? error : new Error(String(error)));
261
262
  return {
262
263
  response_type: resolveDefaultResponseType(),
263
264
  text: "❌ Failed to list tickets",
@@ -290,7 +291,7 @@ async function handleTicketCreate(args, userId, userName) {
290
291
  const nextSequence = (lastTicket[0]?.sequence || 0) + 1;
291
292
  // Map priority
292
293
  const priorityMap = {
293
- urgent: "urgent",
294
+ urgent: "critical",
294
295
  high: "high",
295
296
  medium: "medium",
296
297
  low: "low",
@@ -302,13 +303,13 @@ async function handleTicketCreate(args, userId, userName) {
302
303
  bug: "bug",
303
304
  feature: "feature",
304
305
  task: "task",
305
- improvement: "improvement",
306
+ improvement: "feature",
306
307
  epic: "epic",
307
308
  };
308
309
  const type = typeMap[args.type?.toLowerCase() || "task"] || "task";
309
310
  const ticketId = randomUUID();
310
311
  const now = new Date();
311
- await db.insert(tickets).values({
312
+ const ticketRow = {
312
313
  id: ticketId,
313
314
  sequence: nextSequence,
314
315
  title,
@@ -316,11 +317,11 @@ async function handleTicketCreate(args, userId, userName) {
316
317
  status: "backlog",
317
318
  priority,
318
319
  type,
319
- createdBy: `slack:${userId}`,
320
- createdByName: userName,
320
+ createdBy: "human",
321
321
  createdAt: now,
322
322
  updatedAt: now,
323
- });
323
+ };
324
+ await db.insert(tickets).values(ticketRow);
324
325
  return {
325
326
  response_type: SLACK_SLASH_EPHEMERAL ? "ephemeral" : "in_channel",
326
327
  blocks: [
@@ -345,7 +346,7 @@ async function handleTicketCreate(args, userId, userName) {
345
346
  };
346
347
  }
347
348
  catch (error) {
348
- console.error("[Slack] Error creating ticket:", error);
349
+ log.error('Error creating ticket', error instanceof Error ? error : new Error(String(error)), { userId, userName });
349
350
  return {
350
351
  response_type: resolveDefaultResponseType(),
351
352
  text: "❌ Failed to create ticket",
@@ -436,7 +437,7 @@ async function handleTicketShow(ticketRef) {
436
437
  };
437
438
  }
438
439
  catch (error) {
439
- console.error("[Slack] Error showing ticket:", error);
440
+ log.error('Error showing ticket', error instanceof Error ? error : new Error(String(error)));
440
441
  return {
441
442
  response_type: resolveDefaultResponseType(),
442
443
  text: "❌ Failed to fetch ticket",
@@ -493,7 +494,7 @@ async function handleTicketSearch(query) {
493
494
  };
494
495
  }
495
496
  catch (error) {
496
- console.error("[Slack] Error searching tickets:", error);
497
+ log.error('Error searching tickets', error instanceof Error ? error : new Error(String(error)));
497
498
  return {
498
499
  response_type: resolveDefaultResponseType(),
499
500
  text: "❌ Failed to search tickets",
@@ -544,7 +545,7 @@ async function handleProjectList() {
544
545
  };
545
546
  }
546
547
  catch (error) {
547
- console.error("[Slack] Error listing projects:", error);
548
+ log.error('Error listing projects', error instanceof Error ? error : new Error(String(error)));
548
549
  return {
549
550
  response_type: resolveDefaultResponseType(),
550
551
  text: "❌ Failed to list projects",
@@ -621,7 +622,7 @@ async function handleProjectShow(projectKey) {
621
622
  };
622
623
  }
623
624
  catch (error) {
624
- console.error("[Slack] Error showing project:", error);
625
+ log.error('Error showing project', error instanceof Error ? error : new Error(String(error)));
625
626
  return {
626
627
  response_type: resolveDefaultResponseType(),
627
628
  text: "❌ Failed to fetch project",
@@ -731,7 +732,7 @@ slack.post("/commands", async (c) => {
731
732
  if (SLACK_SIGNING_SECRET) {
732
733
  const isValid = verifySlackSignature(SLACK_SIGNING_SECRET, signature, timestamp, rawBody);
733
734
  if (!isValid) {
734
- console.warn("[Slack] Invalid signature");
735
+ log.warn('Invalid signature');
735
736
  return c.json({ error: "Invalid signature" }, 401);
736
737
  }
737
738
  }
@@ -751,7 +752,7 @@ slack.post("/commands", async (c) => {
751
752
  trigger_id: params.get("trigger_id") || "",
752
753
  api_app_id: params.get("api_app_id") || "",
753
754
  };
754
- console.log(`[Slack] Command: ${command.command} ${command.text} from @${command.user_name}`);
755
+ log.info('Command received', { command: command.command, text: command.text, user: command.user_name });
755
756
  const commandName = normalizeSlackCommandName(command.command);
756
757
  if (commandName !== SLACK_COMMAND_NAME.toLowerCase()) {
757
758
  return c.json({ error: "Unknown command" }, 404);
@@ -835,7 +836,7 @@ slack.post("/commands", async (c) => {
835
836
  }
836
837
  }
837
838
  catch (error) {
838
- console.error("[Slack] Command error:", error);
839
+ log.error('Command error', error instanceof Error ? error : new Error(String(error)));
839
840
  response = {
840
841
  response_type: resolveDefaultResponseType(),
841
842
  text: "❌ An error occurred processing your command",
@@ -871,7 +872,7 @@ slack.post("/interactive", async (c) => {
871
872
  if (cachedResponse) {
872
873
  return c.json(cachedResponse);
873
874
  }
874
- console.log(`[Slack] Interactive: ${payload.type} - ${payload.actions?.[0]?.action_id}`);
875
+ log.info('Interactive event received', { type: payload.type, actionId: payload.actions?.[0]?.action_id });
875
876
  // Handle different interaction types
876
877
  if (payload.type === "block_actions") {
877
878
  const action = payload.actions?.[0];
@@ -5,7 +5,9 @@ import { Hono } from 'hono';
5
5
  import { getDb } from '../storage/index.js';
6
6
  import { tasks, tickets, summaries, projects, sprints } from '../storage/schema.js';
7
7
  import { eq, and, sql } from 'drizzle-orm';
8
+ import { createContextualLogger } from '../utils/logger.js';
8
9
  export const statsRoutes = new Hono();
10
+ const log = createContextualLogger('Stats');
9
11
  /**
10
12
  * GET /api/stats/dashboard - Get comprehensive dashboard statistics
11
13
  */
@@ -144,7 +146,7 @@ statsRoutes.get('/dashboard', async (c) => {
144
146
  });
145
147
  }
146
148
  catch (error) {
147
- console.error('Error fetching dashboard stats:', error);
149
+ log.error('Error fetching dashboard stats', error instanceof Error ? error : new Error(String(error)));
148
150
  return c.json({
149
151
  tasks: { total: 0, pending: 0, queued: 0, inProgress: 0, completed: 0, failed: 0, cancelled: 0 },
150
152
  tickets: { total: 0, open: 0, inProgress: 0, done: 0, byType: {}, byPriority: {}, aiCreated: 0 },
@@ -259,7 +261,7 @@ statsRoutes.get('/sprints/:id/burndown', async (c) => {
259
261
  });
260
262
  }
261
263
  catch (error) {
262
- console.error('Error fetching sprint burndown:', error);
264
+ log.error('Error fetching sprint burndown', error instanceof Error ? error : new Error(String(error)));
263
265
  return c.json({ error: 'Failed to fetch sprint burndown' }, 500);
264
266
  }
265
267
  });
@@ -315,7 +317,7 @@ statsRoutes.get('/projects/:id/velocity', async (c) => {
315
317
  });
316
318
  }
317
319
  catch (error) {
318
- console.error('Error fetching project velocity:', error);
320
+ log.error('Error fetching project velocity', error instanceof Error ? error : new Error(String(error)));
319
321
  return c.json({ error: 'Failed to fetch velocity data' }, 500);
320
322
  }
321
323
  });
@@ -362,7 +364,7 @@ statsRoutes.get('/projects/:id', async (c) => {
362
364
  });
363
365
  }
364
366
  catch (error) {
365
- console.error('Error fetching project stats:', error);
367
+ log.error('Error fetching project stats', error instanceof Error ? error : new Error(String(error)));
366
368
  return c.json({ error: 'Failed to fetch project stats' }, 500);
367
369
  }
368
370
  });
@@ -3,8 +3,9 @@ import { createSummary, getSummary, querySummaries, searchSummaries, getSummaryS
3
3
  import { generatePRDescription, generateChangelog, generateReleaseNotes, generateCommitMessage, TASK_TYPE_TEMPLATES, } from '../summaries/templates.js';
4
4
  import { getEmbeddingService } from '../ai/embedding-service.js';
5
5
  import { getStorage } from '../storage/index.js';
6
- import { logger as systemLogger } from '../utils/logger.js';
6
+ import { createContextualLogger } from '../utils/logger.js';
7
7
  const summaries = new Hono();
8
+ const log = createContextualLogger('Summaries');
8
9
  // Sparse fieldset: default fields for list view (Phase 17 optimization)
9
10
  const SUMMARY_LIST_FIELDS = [
10
11
  'id', 'taskId', 'sessionId', 'agent', 'model', 'title', 'taskType', 'component',
@@ -109,7 +110,7 @@ summaries.get('/semantic', async (c) => {
109
110
  });
110
111
  }
111
112
  catch (error) {
112
- systemLogger.error('[API] Semantic search error:', error);
113
+ log.error('Semantic search error', error instanceof Error ? error : new Error(String(error)));
113
114
  return c.json({ error: 'Search failed', message: error.message }, 500);
114
115
  }
115
116
  });
@@ -253,7 +254,7 @@ summaries.post('/', async (c) => {
253
254
  }, 201);
254
255
  }
255
256
  catch (error) {
256
- console.error('[API] Error creating summary:', error);
257
+ log.error('Error creating summary', error instanceof Error ? error : new Error(String(error)));
257
258
  return c.json({
258
259
  error: 'Failed to create summary',
259
260
  message: error instanceof Error ? error.message : 'Unknown error',
@@ -8,6 +8,8 @@
8
8
  * - POST /api/sync/trigger
9
9
  */
10
10
  import { Hono } from 'hono';
11
+ import { createContextualLogger } from '../utils/logger.js';
12
+ const log = createContextualLogger('Sync');
11
13
  import { handleSyncWebhook, pushTicketToExternal, getSyncStatus } from '../sync/integration.js';
12
14
  import { hasSyncEngine, getSyncEngine } from '../sync/engine.js';
13
15
  import { loadSyncConfig } from '../sync/config.js';
@@ -73,7 +75,7 @@ syncRoutes.post('/webhook/linear', async (c) => {
73
75
  // Verify signature if secret is configured
74
76
  if (linearConfig.webhookSecret) {
75
77
  if (!verifyLinearSignature(rawBody, signature, linearConfig.webhookSecret)) {
76
- console.warn('[SyncRoutes] Invalid Linear webhook signature');
78
+ log.warn('Invalid Linear webhook signature');
77
79
  return c.json({ error: 'Invalid signature' }, 401);
78
80
  }
79
81
  }
@@ -111,7 +113,7 @@ syncRoutes.post('/webhook/github', async (c) => {
111
113
  // Verify signature if secret is configured
112
114
  if (githubConfig.webhookSecret) {
113
115
  if (!verifyGitHubSignature(rawBody, signature, githubConfig.webhookSecret)) {
114
- console.warn('[SyncRoutes] Invalid GitHub webhook signature');
116
+ log.warn('Invalid GitHub webhook signature');
115
117
  return c.json({ error: 'Invalid signature' }, 401);
116
118
  }
117
119
  }
@@ -133,7 +135,7 @@ syncRoutes.post('/webhook/github', async (c) => {
133
135
  try {
134
136
  const ticketSyncResult = await processGitHubWebhookForTicketSync(eventType, payload);
135
137
  if (ticketSyncResult.action !== 'ignored') {
136
- console.log(`[SyncRoutes] GitHub ticket sync: ${ticketSyncResult.action}`, ticketSyncResult);
138
+ log.info('GitHub ticket sync', { action: ticketSyncResult.action, result: ticketSyncResult });
137
139
  return c.json({
138
140
  message: `Ticket sync: ${ticketSyncResult.action}`,
139
141
  ticketId: ticketSyncResult.ticketId,
@@ -142,7 +144,7 @@ syncRoutes.post('/webhook/github', async (c) => {
142
144
  }
143
145
  }
144
146
  catch (error) {
145
- console.error('[SyncRoutes] Ticket sync error (falling back to legacy):', error);
147
+ log.error('Ticket sync error (falling back to legacy)', error instanceof Error ? error : new Error(String(error)));
146
148
  }
147
149
  // Fallback to legacy sync webhook handler (for sync engine)
148
150
  const result = await handleSyncWebhook('github', payload);
@@ -203,7 +205,7 @@ syncRoutes.post('/trigger', async (c) => {
203
205
  }
204
206
  }
205
207
  catch (error) {
206
- console.error('[SyncRoutes] Sync trigger failed:', error);
208
+ log.error('Sync trigger failed', error instanceof Error ? error : new Error(String(error)));
207
209
  return c.json({
208
210
  error: error instanceof Error ? error.message : 'Sync failed',
209
211
  }, 500);
@@ -2,7 +2,9 @@ import { Hono } from 'hono';
2
2
  import { addTask, getTask, getTasks, cancelTask, retryTask } from '../queue/index.js';
3
3
  import { CreateTaskSchema, TaskStatus } from '../types/task.js';
4
4
  import { getStorage } from '../storage/index.js';
5
+ import { createContextualLogger } from '../utils/logger.js';
5
6
  const tasks = new Hono();
7
+ const log = createContextualLogger('TasksRoutes');
6
8
  const validTaskStatuses = new Set(Object.values(TaskStatus));
7
9
  async function parseJsonBody(c) {
8
10
  try {
@@ -119,7 +121,7 @@ tasks.get('/', async (c) => {
119
121
  });
120
122
  }
121
123
  catch (error) {
122
- console.error('[API] Error loading tasks from DB, falling back to in-memory:', error);
124
+ log.error('Error loading tasks from DB, falling back to in-memory', error instanceof Error ? error : new Error(String(error)));
123
125
  }
124
126
  }
125
127
  // Fallback to in-memory queue (no cursor support for in-memory)
@@ -164,7 +166,7 @@ tasks.post('/', async (c) => {
164
166
  }, 201);
165
167
  }
166
168
  catch (error) {
167
- console.error('[API] Error creating task:', error);
169
+ log.error('Error creating task', error instanceof Error ? error : new Error(String(error)));
168
170
  return c.json({
169
171
  error: 'Failed to create task',
170
172
  message: error instanceof Error ? error.message : 'Unknown error',
@@ -182,7 +184,7 @@ tasks.get('/analytics', async (c) => {
182
184
  return c.json(analytics);
183
185
  }
184
186
  catch (error) {
185
- console.error('[API] Error getting task analytics:', error);
187
+ log.error('Error getting task analytics', error instanceof Error ? error : new Error(String(error)));
186
188
  return c.json({
187
189
  error: 'Failed to get analytics',
188
190
  message: error instanceof Error ? error.message : 'Unknown error',
@@ -251,7 +253,7 @@ tasks.get('/filter', async (c) => {
251
253
  });
252
254
  }
253
255
  catch (error) {
254
- console.error('[API] Error filtering tasks:', error);
256
+ log.error('Error filtering tasks', error instanceof Error ? error : new Error(String(error)));
255
257
  return c.json({
256
258
  error: 'Failed to filter tasks',
257
259
  message: error instanceof Error ? error.message : 'Unknown error',
@@ -276,7 +278,7 @@ tasks.get('/archived', async (c) => {
276
278
  });
277
279
  }
278
280
  catch (error) {
279
- console.error('[API] Error getting archived tasks:', error);
281
+ log.error('Error getting archived tasks', error instanceof Error ? error : new Error(String(error)));
280
282
  return c.json({
281
283
  error: 'Failed to get archived tasks',
282
284
  message: error instanceof Error ? error.message : 'Unknown error',
@@ -306,7 +308,7 @@ tasks.post('/archive', async (c) => {
306
308
  });
307
309
  }
308
310
  catch (error) {
309
- console.error('[API] Error archiving tasks:', error);
311
+ log.error('Error archiving tasks', error instanceof Error ? error : new Error(String(error)));
310
312
  return c.json({
311
313
  error: 'Failed to archive tasks',
312
314
  message: error instanceof Error ? error.message : 'Unknown error',
@@ -400,7 +402,7 @@ tasks.post('/import', async (c) => {
400
402
  });
401
403
  }
402
404
  catch (error) {
403
- console.error('[API] Error importing tasks:', error);
405
+ log.error('Error importing tasks', error instanceof Error ? error : new Error(String(error)));
404
406
  return c.json({
405
407
  error: 'Import failed',
406
408
  message: error instanceof Error ? error.message : 'Unknown error',
@@ -436,7 +438,7 @@ tasks.get('/:id/events', async (c) => {
436
438
  });
437
439
  }
438
440
  catch (error) {
439
- console.error('[API] Error getting task events:', error);
441
+ log.error('Error getting task events', error instanceof Error ? error : new Error(String(error)));
440
442
  return c.json({
441
443
  error: 'Failed to get task events',
442
444
  message: error instanceof Error ? error.message : 'Unknown error',
@@ -389,7 +389,7 @@ ticketsRouter.get("/:id/history", async (c) => {
389
389
  return c.json({ ticketId: id, history, count: history.length });
390
390
  }
391
391
  catch (error) {
392
- console.error("[API] Error fetching history:", error);
392
+ log.error('Error fetching history', error instanceof Error ? error : new Error(String(error)));
393
393
  return c.json({ error: "Failed to fetch history" }, 500);
394
394
  }
395
395
  });
@@ -405,7 +405,7 @@ ticketsRouter.get("/:id/relations", async (c) => {
405
405
  return c.json({ ticketId: id, relations, count: relations.length });
406
406
  }
407
407
  catch (error) {
408
- console.error("[API] Error fetching relations:", error);
408
+ log.error('Error fetching relations', error instanceof Error ? error : new Error(String(error)));
409
409
  return c.json({ error: "Failed to fetch relations" }, 500);
410
410
  }
411
411
  });
@@ -441,7 +441,7 @@ ticketsRouter.post("/:id/relations", async (c) => {
441
441
  }, 201);
442
442
  }
443
443
  catch (error) {
444
- console.error("[API] Error creating relation:", error);
444
+ log.error('Error creating relation', error instanceof Error ? error : new Error(String(error)));
445
445
  return c.json({ error: "Failed to create relation" }, 500);
446
446
  }
447
447
  });
@@ -460,7 +460,7 @@ ticketsRouter.delete("/:id/relations/:relationId", async (c) => {
460
460
  return c.json({ message: "Relation deleted" });
461
461
  }
462
462
  catch (error) {
463
- console.error("[API] Error deleting relation:", error);
463
+ log.error('Error deleting relation', error instanceof Error ? error : new Error(String(error)));
464
464
  return c.json({ error: "Failed to delete relation" }, 500);
465
465
  }
466
466
  });
@@ -476,7 +476,7 @@ ticketsRouter.get("/:id/watchers", async (c) => {
476
476
  return c.json({ ticketId: id, watchers, count: watchers.length });
477
477
  }
478
478
  catch (error) {
479
- console.error("[API] Error fetching watchers:", error);
479
+ log.error('Error fetching watchers', error instanceof Error ? error : new Error(String(error)));
480
480
  return c.json({ error: "Failed to fetch watchers" }, 500);
481
481
  }
482
482
  });
@@ -496,7 +496,7 @@ ticketsRouter.post("/:id/watchers", async (c) => {
496
496
  return c.json({ message: "Watcher added", watcher }, 201);
497
497
  }
498
498
  catch (error) {
499
- console.error("[API] Error adding watcher:", error);
499
+ log.error('Error adding watcher', error instanceof Error ? error : new Error(String(error)));
500
500
  return c.json({ error: "Failed to add watcher" }, 500);
501
501
  }
502
502
  });
@@ -515,7 +515,7 @@ ticketsRouter.delete("/:id/watchers/:userId", async (c) => {
515
515
  return c.json({ message: "Watcher removed" });
516
516
  }
517
517
  catch (error) {
518
- console.error("[API] Error removing watcher:", error);
518
+ log.error('Error removing watcher', error instanceof Error ? error : new Error(String(error)));
519
519
  return c.json({ error: "Failed to remove watcher" }, 500);
520
520
  }
521
521
  });
@@ -531,7 +531,7 @@ ticketsRouter.get("/:id/assignees", async (c) => {
531
531
  return c.json({ ticketId: id, assignees, count: assignees.length });
532
532
  }
533
533
  catch (error) {
534
- console.error("[API] Error fetching assignees:", error);
534
+ log.error('Error fetching assignees', error instanceof Error ? error : new Error(String(error)));
535
535
  return c.json({ error: "Failed to fetch assignees" }, 500);
536
536
  }
537
537
  });
@@ -551,7 +551,7 @@ ticketsRouter.post("/:id/assignees", async (c) => {
551
551
  return c.json({ message: "Assignee added", assignee }, 201);
552
552
  }
553
553
  catch (error) {
554
- console.error("[API] Error adding assignee:", error);
554
+ log.error('Error adding assignee', error instanceof Error ? error : new Error(String(error)));
555
555
  return c.json({ error: "Failed to add assignee" }, 500);
556
556
  }
557
557
  });
@@ -570,7 +570,7 @@ ticketsRouter.delete("/:id/assignees/:userId", async (c) => {
570
570
  return c.json({ message: "Assignee removed" });
571
571
  }
572
572
  catch (error) {
573
- console.error("[API] Error removing assignee:", error);
573
+ log.error('Error removing assignee', error instanceof Error ? error : new Error(String(error)));
574
574
  return c.json({ error: "Failed to remove assignee" }, 500);
575
575
  }
576
576
  });
@@ -586,7 +586,7 @@ ticketsRouter.get("/:id/mentions", async (c) => {
586
586
  return c.json({ ticketId: id, mentions, count: mentions.length });
587
587
  }
588
588
  catch (error) {
589
- console.error("[API] Error fetching mentions:", error);
589
+ log.error('Error fetching mentions', error instanceof Error ? error : new Error(String(error)));
590
590
  return c.json({ error: "Failed to fetch mentions" }, 500);
591
591
  }
592
592
  });
@@ -611,7 +611,7 @@ ticketsRouter.post("/:id/mentions", async (c) => {
611
611
  return c.json({ message: "Mention added", mention }, 201);
612
612
  }
613
613
  catch (error) {
614
- console.error("[API] Error adding mention:", error);
614
+ log.error('Error adding mention', error instanceof Error ? error : new Error(String(error)));
615
615
  return c.json({ error: "Failed to add mention" }, 500);
616
616
  }
617
617
  });
@@ -627,7 +627,7 @@ ticketsRouter.get("/:id/attachments", async (c) => {
627
627
  return c.json({ ticketId: id, attachments, count: attachments.length });
628
628
  }
629
629
  catch (error) {
630
- console.error("[API] Error fetching attachments:", error);
630
+ log.error('Error fetching attachments', error instanceof Error ? error : new Error(String(error)));
631
631
  return c.json({ error: "Failed to fetch attachments" }, 500);
632
632
  }
633
633
  });
@@ -662,7 +662,7 @@ ticketsRouter.post("/:id/attachments", async (c) => {
662
662
  return c.json({ message: "Attachment added", attachment }, 201);
663
663
  }
664
664
  catch (error) {
665
- console.error("[API] Error adding attachment:", error);
665
+ log.error('Error adding attachment', error instanceof Error ? error : new Error(String(error)));
666
666
  return c.json({ error: "Failed to add attachment" }, 500);
667
667
  }
668
668
  });
@@ -681,7 +681,7 @@ ticketsRouter.delete("/:id/attachments/:attachmentId", async (c) => {
681
681
  return c.json({ message: "Attachment deleted" });
682
682
  }
683
683
  catch (error) {
684
- console.error("[API] Error deleting attachment:", error);
684
+ log.error('Error deleting attachment', error instanceof Error ? error : new Error(String(error)));
685
685
  return c.json({ error: "Failed to delete attachment" }, 500);
686
686
  }
687
687
  });
@@ -697,7 +697,7 @@ ticketsRouter.get("/:id/reactions", async (c) => {
697
697
  return c.json({ ticketId: id, reactions, count: reactions.length });
698
698
  }
699
699
  catch (error) {
700
- console.error("[API] Error fetching reactions:", error);
700
+ log.error('Error fetching reactions', error instanceof Error ? error : new Error(String(error)));
701
701
  return c.json({ error: "Failed to fetch reactions" }, 500);
702
702
  }
703
703
  });
@@ -721,7 +721,7 @@ ticketsRouter.post("/:id/reactions", async (c) => {
721
721
  return c.json({ message: "Reaction added", reaction }, 201);
722
722
  }
723
723
  catch (error) {
724
- console.error("[API] Error adding reaction:", error);
724
+ log.error('Error adding reaction', error instanceof Error ? error : new Error(String(error)));
725
725
  return c.json({ error: "Failed to add reaction" }, 500);
726
726
  }
727
727
  });
@@ -740,7 +740,7 @@ ticketsRouter.delete("/:id/reactions/:reactionId", async (c) => {
740
740
  return c.json({ message: "Reaction deleted" });
741
741
  }
742
742
  catch (error) {
743
- console.error("[API] Error deleting reaction:", error);
743
+ log.error('Error deleting reaction', error instanceof Error ? error : new Error(String(error)));
744
744
  return c.json({ error: "Failed to delete reaction" }, 500);
745
745
  }
746
746
  });
@@ -776,7 +776,7 @@ ticketsRouter.post("/:id/transition", async (c) => {
776
776
  });
777
777
  }
778
778
  catch (error) {
779
- console.error("[API] Error transitioning ticket:", error);
779
+ log.error('Error transitioning ticket', error instanceof Error ? error : new Error(String(error)));
780
780
  return c.json({ error: "Failed to transition ticket" }, 500);
781
781
  }
782
782
  });
@@ -799,7 +799,7 @@ ticketsRouter.post("/:id/assign-agent", async (c) => {
799
799
  });
800
800
  }
801
801
  catch (error) {
802
- console.error("[API] Error assigning agent:", error);
802
+ log.error('Error assigning agent', error instanceof Error ? error : new Error(String(error)));
803
803
  return c.json({ error: "Failed to assign agent" }, 500);
804
804
  }
805
805
  });
@@ -848,7 +848,7 @@ ticketsRouter.post("/ai/categorize", async (c) => {
848
848
  });
849
849
  }
850
850
  catch (error) {
851
- console.error("[API] Error categorizing ticket:", error);
851
+ log.error('Error categorizing ticket', error instanceof Error ? error : new Error(String(error)));
852
852
  return c.json({ error: "Failed to categorize ticket" }, 500);
853
853
  }
854
854
  });
@@ -877,7 +877,7 @@ ticketsRouter.post("/ai/suggest", async (c) => {
877
877
  });
878
878
  }
879
879
  catch (error) {
880
- console.error("[API] Error getting suggestions:", error);
880
+ log.error('Error getting suggestions', error instanceof Error ? error : new Error(String(error)));
881
881
  return c.json({ error: "Failed to get suggestions" }, 500);
882
882
  }
883
883
  });
@@ -909,7 +909,7 @@ ticketsRouter.get("/:id/ai/summary", async (c) => {
909
909
  });
910
910
  }
911
911
  catch (error) {
912
- console.error("[API] Error summarizing ticket:", error);
912
+ log.error('Error summarizing ticket', error instanceof Error ? error : new Error(String(error)));
913
913
  return c.json({ error: "Failed to summarize ticket" }, 500);
914
914
  }
915
915
  });
@@ -950,7 +950,7 @@ ticketsRouter.get("/:id/similar", async (c) => {
950
950
  });
951
951
  }
952
952
  catch (error) {
953
- console.error("[API] Error finding similar tickets:", error);
953
+ log.error('Error finding similar tickets', error instanceof Error ? error : new Error(String(error)));
954
954
  return c.json({ error: "Failed to find similar tickets" }, 500);
955
955
  }
956
956
  });
@@ -1043,7 +1043,7 @@ ticketsRouter.post("/:id/comments/ai-respond", async (c) => {
1043
1043
  });
1044
1044
  }
1045
1045
  catch (error) {
1046
- console.error("[API] Error generating AI response:", error);
1046
+ log.error('Error generating AI response', error instanceof Error ? error : new Error(String(error)));
1047
1047
  return c.json({ error: "Failed to generate AI response" }, 500);
1048
1048
  }
1049
1049
  });
@@ -1082,7 +1082,7 @@ ticketsRouter.post("/:id/ai/analyze-comment", async (c) => {
1082
1082
  });
1083
1083
  }
1084
1084
  catch (error) {
1085
- console.error("[API] Error analyzing comment:", error);
1085
+ log.error('Error analyzing comment', error instanceof Error ? error : new Error(String(error)));
1086
1086
  return c.json({ error: "Failed to analyze comment" }, 500);
1087
1087
  }
1088
1088
  });
@@ -1,7 +1,9 @@
1
1
  import { Hono } from 'hono';
2
2
  import { z } from 'zod';
3
3
  import { createApiToken, listApiTokens, revokeApiToken, } from '../auth/api-tokens.js';
4
+ import { createContextualLogger } from '../utils/logger.js';
4
5
  const tokens = new Hono();
6
+ const log = createContextualLogger('TokensRoutes');
5
7
  const createTokenBodySchema = z.object({
6
8
  name: z.string().min(1),
7
9
  scopes: z.array(z.string()).min(1),
@@ -52,7 +54,7 @@ tokens.post('/', async (c) => {
52
54
  }, 201);
53
55
  }
54
56
  catch (error) {
55
- console.error('[API] Error creating token:', error);
57
+ log.error('Error creating token', error instanceof Error ? error : new Error(String(error)));
56
58
  return c.json({ error: 'Failed to create token' }, 500);
57
59
  }
58
60
  });
@@ -63,7 +65,7 @@ tokens.get('/', async (c) => {
63
65
  return c.json({ tokens: tokenList });
64
66
  }
65
67
  catch (error) {
66
- console.error('[API] Error listing tokens:', error);
68
+ log.error('Error listing tokens', error instanceof Error ? error : new Error(String(error)));
67
69
  return c.json({ error: 'Failed to list tokens' }, 500);
68
70
  }
69
71
  });
@@ -75,7 +77,7 @@ tokens.delete('/:id', async (c) => {
75
77
  return c.json({ message: 'Token revoked' });
76
78
  }
77
79
  catch (error) {
78
- console.error('[API] Error revoking token:', error);
80
+ log.error('Error revoking token', error instanceof Error ? error : new Error(String(error)));
79
81
  return c.json({ error: 'Failed to revoke token' }, 500);
80
82
  }
81
83
  });