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
package/README.md CHANGED
@@ -11,7 +11,7 @@
11
11
  </p>
12
12
 
13
13
  <p align="center">
14
- <a href="https://profclaw.dev/docs"><b>Docs</b></a> &middot;
14
+ <a href="https://profclaw.ai/docs"><b>Docs</b></a> &middot;
15
15
  <a href="https://github.com/profclaw/profclaw/issues"><b>Report Bug</b></a> &middot;
16
16
  <a href="https://discord.gg/profclaw"><b>Discord</b></a>
17
17
  </p>
@@ -190,7 +190,7 @@ ${task.prompt}
190
190
 
191
191
  ${task.sourceId ? `Closes #${task.sourceId}` : ""}
192
192
 
193
- Co-Authored-By: profClaw <bot@profclaw.dev>"
193
+ Co-Authored-By: profClaw <bot@profclaw.ai>"
194
194
  \`\`\`
195
195
 
196
196
  5. **Push & PR**
@@ -42,6 +42,38 @@ function getStringArray(value) {
42
42
  function toToolArgs(input) {
43
43
  return getRecord(input) ?? {};
44
44
  }
45
+ function getUsageInputTokens(usage) {
46
+ const usageRecord = getRecord(usage);
47
+ if (!usageRecord)
48
+ return 0;
49
+ const inputTokens = usageRecord.inputTokens;
50
+ if (typeof inputTokens === "number")
51
+ return inputTokens;
52
+ const promptTokens = usageRecord.promptTokens;
53
+ return typeof promptTokens === "number" ? promptTokens : 0;
54
+ }
55
+ function getUsageOutputTokens(usage) {
56
+ const usageRecord = getRecord(usage);
57
+ if (!usageRecord)
58
+ return 0;
59
+ const outputTokens = usageRecord.outputTokens;
60
+ if (typeof outputTokens === "number")
61
+ return outputTokens;
62
+ const completionTokens = usageRecord.completionTokens;
63
+ return typeof completionTokens === "number" ? completionTokens : 0;
64
+ }
65
+ function getToolCallInput(toolCall) {
66
+ const toolCallRecord = getRecord(toolCall);
67
+ if (!toolCallRecord)
68
+ return {};
69
+ return toToolArgs(toolCallRecord.input ?? toolCallRecord.args);
70
+ }
71
+ function getToolResultOutput(toolResult) {
72
+ const toolResultRecord = getRecord(toolResult);
73
+ if (!toolResultRecord)
74
+ return undefined;
75
+ return toolResultRecord.output ?? toolResultRecord.result;
76
+ }
45
77
  function toContextProject(value) {
46
78
  const id = getString(value.id);
47
79
  const key = getString(value.key);
@@ -164,8 +196,8 @@ export class AgentExecutor extends EventEmitter {
164
196
  this.state.currentStep++;
165
197
  this.state.updatedAt = Date.now();
166
198
  // Track token budget (AI SDK v6 uses inputTokens/outputTokens)
167
- const stepInput = step.usage?.inputTokens ?? 0;
168
- const stepOutput = step.usage?.outputTokens ?? 0;
199
+ const stepInput = getUsageInputTokens(step.usage);
200
+ const stepOutput = getUsageOutputTokens(step.usage);
169
201
  const tokensUsed = stepInput + stepOutput;
170
202
  this.state.usedBudget += tokensUsed;
171
203
  this.state.inputTokensUsed += stepInput;
@@ -179,14 +211,14 @@ export class AgentExecutor extends EventEmitter {
179
211
  const record = {
180
212
  id: tc.toolCallId ?? randomUUID(),
181
213
  name: tc.toolName,
182
- args: toToolArgs(tc.input),
214
+ args: getToolCallInput(tc),
183
215
  status: "pending",
184
216
  startedAt: Date.now(),
185
217
  };
186
218
  // Find the matching tool result
187
219
  const tr = (step.toolResults ?? []).find((toolResult) => toolResult.toolCallId === tc.toolCallId);
188
220
  if (tr) {
189
- record.result = tr.output;
221
+ record.result = getToolResultOutput(tr);
190
222
  record.completedAt = Date.now();
191
223
  // Check if the tool result indicates a failure
192
224
  if (typeof record.result === "object" && record.result !== null) {
@@ -243,8 +275,8 @@ export class AgentExecutor extends EventEmitter {
243
275
  // Update budget from total usage (AI SDK v6 uses inputTokens/outputTokens)
244
276
  const totalUsage = result.totalUsage;
245
277
  if (totalUsage) {
246
- const totalInput = totalUsage.inputTokens ?? 0;
247
- const totalOutput = totalUsage.outputTokens ?? 0;
278
+ const totalInput = getUsageInputTokens(totalUsage);
279
+ const totalOutput = getUsageOutputTokens(totalUsage);
248
280
  // totalUsage is the authoritative sum; overwrite our step-by-step estimate
249
281
  this.state.usedBudget = totalInput + totalOutput;
250
282
  this.state.inputTokensUsed = totalInput;
@@ -13,6 +13,8 @@ import { getDb } from '../storage/index.js';
13
13
  import { users, sessions, oauthAccounts, userPreferences, githubTokens, } from '../storage/schema.js';
14
14
  import { getGitHubOAuthConfig, getSettingsRaw } from '../settings/index.js';
15
15
  import { hashPassword, verifyPassword as verifyPw } from './password.js';
16
+ import { createContextualLogger } from '../utils/logger.js';
17
+ const log = createContextualLogger('AuthService');
16
18
  /**
17
19
  * Hash a session token for secure storage.
18
20
  * Uses SHA256 which is fast and sufficient for random 32-byte tokens.
@@ -42,7 +44,7 @@ async function upgradePasswordHash(userId, password) {
42
44
  .update(users)
43
45
  .set({ passwordHash: newHash, updatedAt: new Date() })
44
46
  .where(eq(users.id, userId));
45
- console.log(`[Auth] Upgraded password hash to scrypt for user ${userId}`);
47
+ log.info(`Upgraded password hash to scrypt for user ${userId}`);
46
48
  }
47
49
  // SESSION MANAGEMENT
48
50
  export async function createSession(userId, userAgent, ipAddress) {
@@ -197,7 +199,7 @@ export async function signInWithEmail(email, password) {
197
199
  // Transparently upgrade legacy SHA256 hash to scrypt
198
200
  if (needsUpgrade) {
199
201
  upgradePasswordHash(user.id, password).catch((err) => {
200
- console.error('[Auth] Failed to upgrade password hash:', err);
202
+ log.error('Failed to upgrade password hash', err instanceof Error ? err : new Error(String(err)));
201
203
  });
202
204
  }
203
205
  // Check if suspended
@@ -258,7 +260,7 @@ export async function exchangeGitHubCode(code) {
258
260
  });
259
261
  const data = (await response.json());
260
262
  if (data.error || !data.access_token) {
261
- console.error('[Auth] GitHub token exchange failed:', data.error);
263
+ log.error('GitHub token exchange failed', { error: data.error });
262
264
  return null;
263
265
  }
264
266
  return {
@@ -275,7 +277,7 @@ export async function getGitHubUser(accessToken) {
275
277
  },
276
278
  });
277
279
  if (!response.ok) {
278
- console.error('[Auth] Failed to fetch GitHub user:', response.status);
280
+ log.error('Failed to fetch GitHub user', { status: response.status });
279
281
  return null;
280
282
  }
281
283
  return response.json();
@@ -293,7 +295,7 @@ export async function getGitHubPrimaryEmail(accessToken) {
293
295
  },
294
296
  });
295
297
  if (!response.ok) {
296
- console.error('[Auth] Failed to fetch GitHub emails:', response.status);
298
+ log.error('Failed to fetch GitHub emails', { status: response.status });
297
299
  return null;
298
300
  }
299
301
  const emails = (await response.json());
@@ -305,7 +307,7 @@ export async function getGitHubPrimaryEmail(accessToken) {
305
307
  return primaryEmail || null;
306
308
  }
307
309
  catch (error) {
308
- console.error('[Auth] Error fetching GitHub emails:', error);
310
+ log.error('Error fetching GitHub emails', error instanceof Error ? error : new Error(String(error)));
309
311
  return null;
310
312
  }
311
313
  }
@@ -13,6 +13,8 @@ import { generateKeyPairSync, createSign, createVerify, createHash, randomUUID,
13
13
  import { readFileSync, writeFileSync, existsSync, mkdirSync, chmodSync } from 'fs';
14
14
  import { join } from 'path';
15
15
  import { homedir } from 'os';
16
+ import { createContextualLogger } from '../utils/logger.js';
17
+ const log = createContextualLogger('DeviceIdentity');
16
18
  /**
17
19
  * Default identity file path
18
20
  */
@@ -77,10 +79,10 @@ export function loadOrCreateDeviceIdentity(identityDir = DEFAULT_IDENTITY_DIR, o
77
79
  const data = JSON.parse(content);
78
80
  // Validate version
79
81
  if (data.version !== 1) {
80
- console.warn(`[DeviceIdentity] Unknown version ${data.version}, creating new identity`);
82
+ log.warn('Unknown version, creating new identity', { version: data.version });
81
83
  }
82
84
  else {
83
- console.log(`[DeviceIdentity] Loaded existing identity: ${data.deviceId.slice(0, 8)}...`);
85
+ log.info('Loaded existing identity', { deviceIdPrefix: data.deviceId.slice(0, 8) });
84
86
  return {
85
87
  deviceId: data.deviceId,
86
88
  publicKeyPem: data.publicKeyPem,
@@ -92,11 +94,11 @@ export function loadOrCreateDeviceIdentity(identityDir = DEFAULT_IDENTITY_DIR, o
92
94
  }
93
95
  }
94
96
  catch (error) {
95
- console.warn(`[DeviceIdentity] Failed to load identity, creating new one:`, error);
97
+ log.warn('Failed to load identity, creating new one', { error: error instanceof Error ? error.message : String(error) });
96
98
  }
97
99
  }
98
100
  // Create new identity
99
- console.log('[DeviceIdentity] Creating new device identity...');
101
+ log.info('Creating new device identity');
100
102
  const { publicKey, privateKey } = generateKeyPair();
101
103
  const deviceId = deriveDeviceId(publicKey);
102
104
  const identity = {
@@ -114,7 +116,7 @@ export function loadOrCreateDeviceIdentity(identityDir = DEFAULT_IDENTITY_DIR, o
114
116
  ...identity,
115
117
  };
116
118
  writeSecureFile(filePath, JSON.stringify(fileData, null, 2));
117
- console.log(`[DeviceIdentity] Created new identity: ${deviceId.slice(0, 8)}...`);
119
+ log.info('Created new identity', { deviceIdPrefix: deviceId.slice(0, 8) });
118
120
  return identity;
119
121
  }
120
122
  /**
@@ -1,4 +1,6 @@
1
1
  import { getGitHubOAuthConfig } from '../settings/index.js';
2
+ import { createContextualLogger } from '../utils/logger.js';
3
+ const log = createContextualLogger('OAuth');
2
4
  /**
3
5
  * Redirect user to GitHub for OAuth
4
6
  */
@@ -52,7 +54,7 @@ export async function handleGitHubCallback(c) {
52
54
  });
53
55
  }
54
56
  catch (error) {
55
- console.error('[GitHub Auth] Callback error:', error);
57
+ log.error('GitHub callback error', error instanceof Error ? error : new Error(String(error)));
56
58
  return c.json({ error: 'Internal server error' }, 500);
57
59
  }
58
60
  }
@@ -12,6 +12,8 @@
12
12
  */
13
13
  import { randomBytes, randomUUID } from 'crypto';
14
14
  import { getStorage } from '../storage/index.js';
15
+ import { createContextualLogger } from '../utils/logger.js';
16
+ const log = createContextualLogger('PairingCodes');
15
17
  // Code generation alphabet (no ambiguous chars: 0O1I)
16
18
  const PAIRING_CODE_ALPHABET = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789';
17
19
  const PAIRING_CODE_LENGTH = 8;
@@ -117,7 +119,7 @@ export async function requestPairingCode(params) {
117
119
  now,
118
120
  now,
119
121
  ]);
120
- console.log(`[Pairing] Created code ${code} for requester ${params.requesterId}`);
122
+ log.info('Created pairing code', { code, requesterId: params.requesterId });
121
123
  return {
122
124
  code,
123
125
  expiresAt: new Date(expiresAt * 1000),
@@ -133,7 +135,7 @@ export async function approvePairingCode(params) {
133
135
  const rows = await storage.query(`SELECT * FROM pairing_requests
134
136
  WHERE code = ? AND status = 'pending' AND expires_at > ?`, [params.code.toUpperCase(), Math.floor(Date.now() / 1000)]);
135
137
  if (rows.length === 0) {
136
- console.log(`[Pairing] Code ${params.code} not found or expired`);
138
+ log.info('Code not found or expired', { code: params.code });
137
139
  return null;
138
140
  }
139
141
  const row = rows[0];
@@ -143,7 +145,7 @@ export async function approvePairingCode(params) {
143
145
  await storage.execute(`UPDATE pairing_requests
144
146
  SET status = 'approved', resolved_by = ?, resolved_at = ?, token = ?
145
147
  WHERE id = ?`, [params.approvedBy, now, token, row.id]);
146
- console.log(`[Pairing] Code ${params.code} approved by ${params.approvedBy}`);
148
+ log.info('Code approved', { code: params.code, approvedBy: params.approvedBy });
147
149
  return {
148
150
  request: {
149
151
  id: row.id,
@@ -175,7 +177,7 @@ export async function rejectPairingCode(params) {
175
177
  await storage.execute(`UPDATE pairing_requests
176
178
  SET status = 'rejected', resolved_by = ?, resolved_at = ?
177
179
  WHERE code = ? AND status = 'pending'`, [params.rejectedBy, now, params.code.toUpperCase()]);
178
- console.log(`[Pairing] Code ${params.code} rejected by ${params.rejectedBy}`);
180
+ log.info('Code rejected', { code: params.code, rejectedBy: params.rejectedBy });
179
181
  return true;
180
182
  }
181
183
  /**
@@ -8,6 +8,8 @@ import { chromium } from 'playwright-core';
8
8
  import { captureSnapshot, formatSnapshotResponse } from './snapshot.js';
9
9
  import { searchSnapshot, formatSearchResponse } from './search.js';
10
10
  import { getRefTracker, resetRefTracker, clearAllTrackers } from './refs.js';
11
+ import { createContextualLogger } from '../utils/logger.js';
12
+ const log = createContextualLogger('Browser');
11
13
  // Default configuration
12
14
  const DEFAULT_CONFIG = {
13
15
  headless: process.env.BROWSER_HEADLESS !== 'false',
@@ -34,7 +36,7 @@ class BrowserService {
34
36
  */
35
37
  async ensureBrowser() {
36
38
  if (!this.browser || !this.browser.isConnected()) {
37
- console.log('[Browser] Launching browser...');
39
+ log.info('Launching browser');
38
40
  this.browser = await chromium.launch({
39
41
  headless: this.config.headless,
40
42
  executablePath: this.config.executablePath,
@@ -48,7 +50,7 @@ class BrowserService {
48
50
  viewport: { width: 1280, height: 720 },
49
51
  userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
50
52
  });
51
- console.log('[Browser] Browser launched');
53
+ log.info('Browser launched');
52
54
  }
53
55
  return this.browser;
54
56
  }
@@ -312,7 +314,7 @@ class BrowserService {
312
314
  this.browser = null;
313
315
  }
314
316
  clearAllTrackers();
315
- console.log('[Browser] Browser closed');
317
+ log.info('Browser closed');
316
318
  }
317
319
  /**
318
320
  * Check if browser is running
@@ -9,6 +9,8 @@
9
9
  * 8.3 Safety Bounds
10
10
  * 8.4 Quality Scoring
11
11
  */
12
+ import { createContextualLogger } from '../../utils/logger.js';
13
+ const log = createContextualLogger('Guardrails');
12
14
  // 8.1 Output Validation
13
15
  const MAX_RESPONSE_CHARS = 50_000;
14
16
  const STUTTER_THRESHOLD = 3; // same sentence repeated 3+ times
@@ -533,7 +535,7 @@ export async function runGuardrails(response, toolCalls, context) {
533
535
  }
534
536
  }
535
537
  if (!passed) {
536
- console.error('[guardrails] Guardrail check failed', {
538
+ log.warn('Guardrail check failed', {
537
539
  validationIssues: validation.issues.length,
538
540
  hallucinationFlags: hallucination.flags.length,
539
541
  safetyBlocked: safety.blocked.length,
@@ -1,3 +1,5 @@
1
+ import { createContextualLogger } from '../../../utils/logger.js';
2
+ const log = createContextualLogger('Workflow');
1
3
  // Map from executionId -> AbortController for cancellation
2
4
  const activeExecutions = new Map();
3
5
  /**
@@ -231,7 +233,7 @@ export class WorkflowExecutor {
231
233
  ]);
232
234
  }
233
235
  catch (error) {
234
- console.error(`[workflow] Step "${step.id}" timed out:`, error);
236
+ log.error('Step timed out', error instanceof Error ? error : new Error(String(error)), { stepId: step.id });
235
237
  return {
236
238
  success: false,
237
239
  error: {
@@ -245,7 +247,7 @@ export class WorkflowExecutor {
245
247
  return await context.toolExecutor(step.tool, params);
246
248
  }
247
249
  catch (error) {
248
- console.error(`[workflow] Step "${step.id}" threw:`, error);
250
+ log.error('Step threw error', error instanceof Error ? error : new Error(String(error)), { stepId: step.id });
249
251
  return {
250
252
  success: false,
251
253
  error: {
@@ -12,6 +12,8 @@
12
12
  * - Sliding window with importance scoring
13
13
  */
14
14
  import { MODEL_CATALOG } from '../providers/core/models.js';
15
+ import { createContextualLogger } from '../utils/logger.js';
16
+ const log = createContextualLogger('Memory');
15
17
  export const DEFAULT_MEMORY_CONFIG = {
16
18
  compactThreshold: 0.7,
17
19
  preserveRecentCount: 6, // Keep last 3 exchanges (user + assistant)
@@ -215,7 +217,7 @@ SUMMARY:`;
215
217
  }
216
218
  catch (error) {
217
219
  // Fallback to simple truncation if AI fails
218
- console.warn('[Memory] AI summarization failed, using truncation:', error);
220
+ log.warn('AI summarization failed, using truncation', { error: error instanceof Error ? error.message : String(error) });
219
221
  return `Previous conversation summary (${messages.length} messages): ${messages
220
222
  .slice(-3)
221
223
  .map((m) => m.content.slice(0, 100))
@@ -12,6 +12,8 @@ import { randomUUID } from 'node:crypto';
12
12
  import { EventEmitter } from 'node:events';
13
13
  import { freemem, totalmem } from 'node:os';
14
14
  import { statfs } from 'node:fs/promises';
15
+ import { createContextualLogger } from '../../utils/logger.js';
16
+ const log = createContextualLogger('Proactive');
15
17
  /**
16
18
  * Evaluates a simple condition string against a data record.
17
19
  * Supports: <key> <op> <value> where op is >, <, >=, <=, ==, !=
@@ -53,16 +55,16 @@ function executeAction(action, data) {
53
55
  const message = action.template ? interpolate(action.template, data) : '';
54
56
  switch (action.type) {
55
57
  case 'notify':
56
- console.error(`[proactive] notify target=${action.target ?? 'broadcast'} msg=${message}`);
58
+ log.info('Notify action', { target: action.target ?? 'broadcast', message });
57
59
  return `notified ${action.target ?? 'broadcast'}: ${message}`;
58
60
  case 'message':
59
- console.error(`[proactive] message target=${action.target} msg=${message}`);
61
+ log.info('Message action', { target: action.target, message });
60
62
  return `message sent to ${action.target}: ${message}`;
61
63
  case 'workflow':
62
- console.error(`[proactive] workflow id=${action.workflowId} triggered`);
64
+ log.info('Workflow triggered', { workflowId: action.workflowId });
63
65
  return `workflow ${action.workflowId} triggered`;
64
66
  case 'log':
65
- console.error(`[proactive] log: ${message}`);
67
+ log.info('Log action', { message });
66
68
  return `logged: ${message}`;
67
69
  }
68
70
  }
@@ -125,7 +127,7 @@ export class TriggerManager {
125
127
  results.push({ ruleId: rule.id, executed: true, output });
126
128
  }
127
129
  catch (error) {
128
- console.error(`[proactive] TriggerManager action failed for rule ${rule.id}:`, error);
130
+ log.error('TriggerManager action failed', error instanceof Error ? error : new Error(String(error)), { ruleId: rule.id });
129
131
  results.push({
130
132
  ruleId: rule.id,
131
133
  executed: false,
@@ -402,7 +404,7 @@ export class HealthMonitor extends EventEmitter {
402
404
  const wasOk = !previous || previous.status === 'healthy';
403
405
  const isNowBad = result.status === 'degraded' || result.status === 'down';
404
406
  if (wasOk && isNowBad) {
405
- console.error(`[proactive] health degraded: ${service} - ${result.message ?? result.status}`);
407
+ log.warn('Health degraded', { service, message: result.message ?? result.status });
406
408
  this.emit('degraded', result);
407
409
  }
408
410
  }
@@ -414,7 +416,7 @@ export class HealthMonitor extends EventEmitter {
414
416
  message: `Checker threw: ${error instanceof Error ? error.message : 'Unknown'}`,
415
417
  };
416
418
  this.latest.set(service, bad);
417
- console.error(`[proactive] health check error for ${service}:`, error);
419
+ log.error('Health check error', error instanceof Error ? error : new Error(String(error)), { service });
418
420
  this.emit('degraded', bad);
419
421
  }
420
422
  }
@@ -510,7 +512,7 @@ async function gatherFileContext(keywords) {
510
512
  return sources;
511
513
  }
512
514
  catch (error) {
513
- console.error('[proactive] gatherFileContext failed:', error);
515
+ log.error('gatherFileContext failed', error instanceof Error ? error : new Error(String(error)));
514
516
  return [];
515
517
  }
516
518
  }
@@ -678,7 +680,7 @@ export class BackgroundResearcher {
678
680
  return;
679
681
  }
680
682
  const terms = extractSearchTerms(query);
681
- console.error(`[proactive] research started id=${id} terms=[${terms.join(', ')}]`);
683
+ log.info('Research started', { id, terms });
682
684
  // Build placeholder results; real results injected via inject()
683
685
  const pending = buildPendingResults(query, terms);
684
686
  if (signal?.aborted) {
@@ -694,13 +696,13 @@ export class BackgroundResearcher {
694
696
  results: pending,
695
697
  completedAt: Date.now(),
696
698
  });
697
- console.error(`[proactive] research completed id=${id} results=${pending.length}`);
699
+ log.info('Research completed', { id, resultCount: pending.length });
698
700
  }
699
701
  catch (error) {
700
702
  const current = this.tasks.get(id);
701
703
  if (!current)
702
704
  return;
703
- console.error(`[proactive] research failed id=${id}:`, error);
705
+ log.error('Research failed', error instanceof Error ? error : new Error(String(error)), { id });
704
706
  this.tasks.set(id, {
705
707
  ...current,
706
708
  status: 'failed',
@@ -6,7 +6,7 @@
6
6
  */
7
7
  import { z } from 'zod';
8
8
  import { randomUUID } from 'node:crypto';
9
- import { getClient } from '../storage/index.js';
9
+ import { getDb } from '../storage/index.js';
10
10
  import { projects, tickets, sprints } from '../storage/schema.js';
11
11
  import { eq, sql } from 'drizzle-orm';
12
12
  import { logger } from '../utils/logger.js';
@@ -235,7 +235,7 @@ function getProviderDisplayName(provider) {
235
235
  */
236
236
  async function executeCreateProject(input) {
237
237
  try {
238
- const db = getClient();
238
+ const db = getDb();
239
239
  const id = randomUUID();
240
240
  const key = input.key.toUpperCase();
241
241
  // Check if key already exists
@@ -285,7 +285,7 @@ async function executeCreateProject(input) {
285
285
  */
286
286
  async function executeCreateTicket(input) {
287
287
  try {
288
- const db = getClient();
288
+ const db = getDb();
289
289
  // Find the project by key
290
290
  const project = await db
291
291
  .select()
@@ -319,7 +319,8 @@ async function executeCreateTicket(input) {
319
319
  status: 'backlog',
320
320
  priority: input.priority || 'medium',
321
321
  labels: input.labels || [],
322
- storyPoints: input.storyPoints,
322
+ estimate: input.storyPoints,
323
+ estimateUnit: input.storyPoints !== undefined ? 'points' : undefined,
323
324
  });
324
325
  logger.info(`[ChatTools] Created ticket: ${ticketKey}`, { component: 'ChatTools' });
325
326
  return {
@@ -349,7 +350,7 @@ async function executeCreateTicket(input) {
349
350
  */
350
351
  async function executeCreateSprint(input) {
351
352
  try {
352
- const db = getClient();
353
+ const db = getDb();
353
354
  // Find the project by key
354
355
  const project = await db
355
356
  .select()
@@ -409,7 +410,7 @@ async function executeCreateSprint(input) {
409
410
  */
410
411
  async function executeListProjects(input) {
411
412
  try {
412
- const db = getClient();
413
+ const db = getDb();
413
414
  let query = db.select().from(projects);
414
415
  if (input.status !== 'all') {
415
416
  query = query.where(eq(projects.status, input.status));
@@ -442,7 +443,7 @@ async function executeListProjects(input) {
442
443
  */
443
444
  async function executeSearchTickets(input) {
444
445
  try {
445
- const db = getClient();
446
+ const db = getDb();
446
447
  let ticketList = await db.select().from(tickets).limit(input.limit).all();
447
448
  // Apply filters
448
449
  if (input.projectKey) {
@@ -163,19 +163,28 @@ export function authCommands() {
163
163
  .action(async (options) => {
164
164
  try {
165
165
  const db = await ensureDb();
166
- let query = db
167
- .select({
168
- id: users.id,
169
- email: users.email,
170
- name: users.name,
171
- role: users.role,
172
- status: users.status,
173
- createdAt: users.createdAt,
174
- })
175
- .from(users);
176
- if (options.status) {
177
- query = query.where(eq(users.status, options.status));
178
- }
166
+ const query = options.status
167
+ ? db
168
+ .select({
169
+ id: users.id,
170
+ email: users.email,
171
+ name: users.name,
172
+ role: users.role,
173
+ status: users.status,
174
+ createdAt: users.createdAt,
175
+ })
176
+ .from(users)
177
+ .where(eq(users.status, options.status))
178
+ : db
179
+ .select({
180
+ id: users.id,
181
+ email: users.email,
182
+ name: users.name,
183
+ role: users.role,
184
+ status: users.status,
185
+ createdAt: users.createdAt,
186
+ })
187
+ .from(users);
179
188
  const allUsers = await query.orderBy(users.createdAt);
180
189
  if (options.json) {
181
190
  console.log(JSON.stringify(allUsers, null, 2));