profclaw 0.0.1-beta.1

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 (942) hide show
  1. package/.env.example +215 -0
  2. package/CHANGELOG.md +49 -0
  3. package/CONTRIBUTING.md +119 -0
  4. package/Dockerfile +107 -0
  5. package/LICENSE +661 -0
  6. package/README.md +196 -0
  7. package/config/agents.yml +55 -0
  8. package/config/budget.yml +15 -0
  9. package/config/pricing.yml +46 -0
  10. package/config/settings.yml +168 -0
  11. package/dist/adapters/claude-code.d.ts +46 -0
  12. package/dist/adapters/claude-code.js +215 -0
  13. package/dist/adapters/index.d.ts +4 -0
  14. package/dist/adapters/index.js +4 -0
  15. package/dist/adapters/ollama.d.ts +45 -0
  16. package/dist/adapters/ollama.js +277 -0
  17. package/dist/adapters/openclaw.d.ts +60 -0
  18. package/dist/adapters/openclaw.js +289 -0
  19. package/dist/adapters/registry.d.ts +56 -0
  20. package/dist/adapters/registry.js +163 -0
  21. package/dist/agents/executor.d.ts +78 -0
  22. package/dist/agents/executor.js +657 -0
  23. package/dist/agents/index.d.ts +10 -0
  24. package/dist/agents/index.js +27 -0
  25. package/dist/agents/stop-conditions.d.ts +108 -0
  26. package/dist/agents/stop-conditions.js +299 -0
  27. package/dist/agents/types.d.ts +185 -0
  28. package/dist/agents/types.js +14 -0
  29. package/dist/ai/embedding-service.d.ts +96 -0
  30. package/dist/ai/embedding-service.js +333 -0
  31. package/dist/auth/api-tokens.d.ts +71 -0
  32. package/dist/auth/api-tokens.js +235 -0
  33. package/dist/auth/auth-service.d.ts +75 -0
  34. package/dist/auth/auth-service.js +557 -0
  35. package/dist/auth/device-identity.d.ts +96 -0
  36. package/dist/auth/device-identity.js +250 -0
  37. package/dist/auth/github-oauth.d.ts +20 -0
  38. package/dist/auth/github-oauth.js +59 -0
  39. package/dist/auth/jira-oauth.d.ts +25 -0
  40. package/dist/auth/jira-oauth.js +75 -0
  41. package/dist/auth/linear-oauth.d.ts +21 -0
  42. package/dist/auth/linear-oauth.js +59 -0
  43. package/dist/auth/middleware.d.ts +44 -0
  44. package/dist/auth/middleware.js +190 -0
  45. package/dist/auth/pairing-codes.d.ts +109 -0
  46. package/dist/auth/pairing-codes.js +274 -0
  47. package/dist/auth/password.d.ts +53 -0
  48. package/dist/auth/password.js +126 -0
  49. package/dist/auth/qr-pairing.d.ts +36 -0
  50. package/dist/auth/qr-pairing.js +138 -0
  51. package/dist/auth/slack-oauth.d.ts +31 -0
  52. package/dist/auth/slack-oauth.js +80 -0
  53. package/dist/backup/index.d.ts +50 -0
  54. package/dist/backup/index.js +184 -0
  55. package/dist/browser/adapters.d.ts +25 -0
  56. package/dist/browser/adapters.js +32 -0
  57. package/dist/browser/cli.d.ts +19 -0
  58. package/dist/browser/cli.js +277 -0
  59. package/dist/browser/compression.d.ts +32 -0
  60. package/dist/browser/compression.js +269 -0
  61. package/dist/browser/extensions.d.ts +144 -0
  62. package/dist/browser/extensions.js +251 -0
  63. package/dist/browser/index.d.ts +37 -0
  64. package/dist/browser/index.js +43 -0
  65. package/dist/browser/refs.d.ts +46 -0
  66. package/dist/browser/refs.js +120 -0
  67. package/dist/browser/search.d.ts +36 -0
  68. package/dist/browser/search.js +193 -0
  69. package/dist/browser/service.d.ts +94 -0
  70. package/dist/browser/service.js +358 -0
  71. package/dist/browser/snapshot.d.ts +19 -0
  72. package/dist/browser/snapshot.js +250 -0
  73. package/dist/browser/tools.d.ts +259 -0
  74. package/dist/browser/tools.js +463 -0
  75. package/dist/browser/types.d.ts +134 -0
  76. package/dist/browser/types.js +17 -0
  77. package/dist/chat/agentic-executor.d.ts +108 -0
  78. package/dist/chat/agentic-executor.js +739 -0
  79. package/dist/chat/api-key-detector.d.ts +41 -0
  80. package/dist/chat/api-key-detector.js +290 -0
  81. package/dist/chat/auto-reply.d.ts +90 -0
  82. package/dist/chat/auto-reply.js +272 -0
  83. package/dist/chat/conversations.d.ts +91 -0
  84. package/dist/chat/conversations.js +297 -0
  85. package/dist/chat/execution/audit.d.ts +192 -0
  86. package/dist/chat/execution/audit.js +323 -0
  87. package/dist/chat/execution/executor.d.ts +56 -0
  88. package/dist/chat/execution/executor.js +654 -0
  89. package/dist/chat/execution/guardrails.d.ts +98 -0
  90. package/dist/chat/execution/guardrails.js +571 -0
  91. package/dist/chat/execution/index.d.ts +61 -0
  92. package/dist/chat/execution/index.js +129 -0
  93. package/dist/chat/execution/model-capability.d.ts +34 -0
  94. package/dist/chat/execution/model-capability.js +96 -0
  95. package/dist/chat/execution/process-pool.d.ts +110 -0
  96. package/dist/chat/execution/process-pool.js +290 -0
  97. package/dist/chat/execution/pty.d.ts +92 -0
  98. package/dist/chat/execution/pty.js +285 -0
  99. package/dist/chat/execution/rate-limiter.d.ts +87 -0
  100. package/dist/chat/execution/rate-limiter.js +305 -0
  101. package/dist/chat/execution/registry.d.ts +54 -0
  102. package/dist/chat/execution/registry.js +220 -0
  103. package/dist/chat/execution/sandbox.d.ts +109 -0
  104. package/dist/chat/execution/sandbox.js +684 -0
  105. package/dist/chat/execution/secrets.d.ts +45 -0
  106. package/dist/chat/execution/secrets.js +338 -0
  107. package/dist/chat/execution/security.d.ts +179 -0
  108. package/dist/chat/execution/security.js +739 -0
  109. package/dist/chat/execution/self-correction.d.ts +162 -0
  110. package/dist/chat/execution/self-correction.js +557 -0
  111. package/dist/chat/execution/session-manager.d.ts +79 -0
  112. package/dist/chat/execution/session-manager.js +356 -0
  113. package/dist/chat/execution/session-spawn/config.d.ts +37 -0
  114. package/dist/chat/execution/session-spawn/config.js +83 -0
  115. package/dist/chat/execution/session-spawn/index.d.ts +10 -0
  116. package/dist/chat/execution/session-spawn/index.js +10 -0
  117. package/dist/chat/execution/session-spawn/manager.d.ts +35 -0
  118. package/dist/chat/execution/session-spawn/manager.js +418 -0
  119. package/dist/chat/execution/session-spawn/types.d.ts +117 -0
  120. package/dist/chat/execution/session-spawn/types.js +16 -0
  121. package/dist/chat/execution/smart-prompts.d.ts +34 -0
  122. package/dist/chat/execution/smart-prompts.js +151 -0
  123. package/dist/chat/execution/stream-results.d.ts +65 -0
  124. package/dist/chat/execution/stream-results.js +156 -0
  125. package/dist/chat/execution/tool-router.d.ts +76 -0
  126. package/dist/chat/execution/tool-router.js +296 -0
  127. package/dist/chat/execution/tools/agents-list.d.ts +49 -0
  128. package/dist/chat/execution/tools/agents-list.js +165 -0
  129. package/dist/chat/execution/tools/browser.d.ts +12 -0
  130. package/dist/chat/execution/tools/browser.js +14 -0
  131. package/dist/chat/execution/tools/canvas.d.ts +61 -0
  132. package/dist/chat/execution/tools/canvas.js +150 -0
  133. package/dist/chat/execution/tools/complete-task.d.ts +72 -0
  134. package/dist/chat/execution/tools/complete-task.js +104 -0
  135. package/dist/chat/execution/tools/cron-tool.d.ts +204 -0
  136. package/dist/chat/execution/tools/cron-tool.js +680 -0
  137. package/dist/chat/execution/tools/discord-actions.d.ts +120 -0
  138. package/dist/chat/execution/tools/discord-actions.js +361 -0
  139. package/dist/chat/execution/tools/exec.d.ts +43 -0
  140. package/dist/chat/execution/tools/exec.js +223 -0
  141. package/dist/chat/execution/tools/file-ops.d.ts +175 -0
  142. package/dist/chat/execution/tools/file-ops.js +723 -0
  143. package/dist/chat/execution/tools/git.d.ts +143 -0
  144. package/dist/chat/execution/tools/git.js +395 -0
  145. package/dist/chat/execution/tools/github.d.ts +42 -0
  146. package/dist/chat/execution/tools/github.js +184 -0
  147. package/dist/chat/execution/tools/glinr-ops.d.ts +202 -0
  148. package/dist/chat/execution/tools/glinr-ops.js +694 -0
  149. package/dist/chat/execution/tools/image-analyze.d.ts +29 -0
  150. package/dist/chat/execution/tools/image-analyze.js +127 -0
  151. package/dist/chat/execution/tools/index.d.ts +64 -0
  152. package/dist/chat/execution/tools/index.js +245 -0
  153. package/dist/chat/execution/tools/integrations.d.ts +109 -0
  154. package/dist/chat/execution/tools/integrations.js +237 -0
  155. package/dist/chat/execution/tools/link-understand.d.ts +34 -0
  156. package/dist/chat/execution/tools/link-understand.js +307 -0
  157. package/dist/chat/execution/tools/maintenance.d.ts +29 -0
  158. package/dist/chat/execution/tools/maintenance.js +105 -0
  159. package/dist/chat/execution/tools/memory-tools.d.ts +76 -0
  160. package/dist/chat/execution/tools/memory-tools.js +278 -0
  161. package/dist/chat/execution/tools/openai-image-gen.d.ts +51 -0
  162. package/dist/chat/execution/tools/openai-image-gen.js +212 -0
  163. package/dist/chat/execution/tools/profclaw-ops.d.ts +204 -0
  164. package/dist/chat/execution/tools/profclaw-ops.js +665 -0
  165. package/dist/chat/execution/tools/session-spawn.d.ts +146 -0
  166. package/dist/chat/execution/tools/session-spawn.js +544 -0
  167. package/dist/chat/execution/tools/session-status.d.ts +38 -0
  168. package/dist/chat/execution/tools/session-status.js +185 -0
  169. package/dist/chat/execution/tools/sessions-list.d.ts +49 -0
  170. package/dist/chat/execution/tools/sessions-list.js +153 -0
  171. package/dist/chat/execution/tools/sessions-send.d.ts +48 -0
  172. package/dist/chat/execution/tools/sessions-send.js +207 -0
  173. package/dist/chat/execution/tools/sessions-spawn.d.ts +51 -0
  174. package/dist/chat/execution/tools/sessions-spawn.js +137 -0
  175. package/dist/chat/execution/tools/slack-actions.d.ts +90 -0
  176. package/dist/chat/execution/tools/slack-actions.js +272 -0
  177. package/dist/chat/execution/tools/subagent-orchestrate.d.ts +66 -0
  178. package/dist/chat/execution/tools/subagent-orchestrate.js +313 -0
  179. package/dist/chat/execution/tools/system.d.ts +121 -0
  180. package/dist/chat/execution/tools/system.js +415 -0
  181. package/dist/chat/execution/tools/telegram-actions.d.ts +126 -0
  182. package/dist/chat/execution/tools/telegram-actions.js +339 -0
  183. package/dist/chat/execution/tools/test-run.d.ts +43 -0
  184. package/dist/chat/execution/tools/test-run.js +391 -0
  185. package/dist/chat/execution/tools/tts-speak.d.ts +39 -0
  186. package/dist/chat/execution/tools/tts-speak.js +199 -0
  187. package/dist/chat/execution/tools/web-fetch.d.ts +42 -0
  188. package/dist/chat/execution/tools/web-fetch.js +247 -0
  189. package/dist/chat/execution/tools/web-search.d.ts +53 -0
  190. package/dist/chat/execution/tools/web-search.js +130 -0
  191. package/dist/chat/execution/types.d.ts +337 -0
  192. package/dist/chat/execution/types.js +8 -0
  193. package/dist/chat/execution/workflows/built-in.d.ts +10 -0
  194. package/dist/chat/execution/workflows/built-in.js +249 -0
  195. package/dist/chat/execution/workflows/executor.d.ts +13 -0
  196. package/dist/chat/execution/workflows/executor.js +259 -0
  197. package/dist/chat/execution/workflows/index.d.ts +5 -0
  198. package/dist/chat/execution/workflows/index.js +5 -0
  199. package/dist/chat/execution/workflows/trigger.d.ts +15 -0
  200. package/dist/chat/execution/workflows/trigger.js +111 -0
  201. package/dist/chat/execution/workflows/types.d.ts +80 -0
  202. package/dist/chat/execution/workflows/types.js +2 -0
  203. package/dist/chat/failover/error.d.ts +73 -0
  204. package/dist/chat/failover/error.js +412 -0
  205. package/dist/chat/failover/index.d.ts +10 -0
  206. package/dist/chat/failover/index.js +11 -0
  207. package/dist/chat/failover/model-fallback.d.ts +97 -0
  208. package/dist/chat/failover/model-fallback.js +328 -0
  209. package/dist/chat/failover/types.d.ts +47 -0
  210. package/dist/chat/failover/types.js +8 -0
  211. package/dist/chat/format/chunk.d.ts +59 -0
  212. package/dist/chat/format/chunk.js +253 -0
  213. package/dist/chat/format/index.d.ts +7 -0
  214. package/dist/chat/format/index.js +7 -0
  215. package/dist/chat/format/tool-result-formatter.d.ts +30 -0
  216. package/dist/chat/format/tool-result-formatter.js +177 -0
  217. package/dist/chat/group.d.ts +232 -0
  218. package/dist/chat/group.js +311 -0
  219. package/dist/chat/index.d.ts +21 -0
  220. package/dist/chat/index.js +30 -0
  221. package/dist/chat/memory.d.ts +108 -0
  222. package/dist/chat/memory.js +343 -0
  223. package/dist/chat/message-handler.d.ts +38 -0
  224. package/dist/chat/message-handler.js +274 -0
  225. package/dist/chat/proactive/index.d.ts +167 -0
  226. package/dist/chat/proactive/index.js +721 -0
  227. package/dist/chat/prompt-adapter.d.ts +52 -0
  228. package/dist/chat/prompt-adapter.js +245 -0
  229. package/dist/chat/providers/dingtalk/index.d.ts +69 -0
  230. package/dist/chat/providers/dingtalk/index.js +225 -0
  231. package/dist/chat/providers/discord/index.d.ts +264 -0
  232. package/dist/chat/providers/discord/index.js +657 -0
  233. package/dist/chat/providers/feishu/index.d.ts +97 -0
  234. package/dist/chat/providers/feishu/index.js +362 -0
  235. package/dist/chat/providers/googlechat/index.d.ts +269 -0
  236. package/dist/chat/providers/googlechat/index.js +634 -0
  237. package/dist/chat/providers/imessage/index.d.ts +61 -0
  238. package/dist/chat/providers/imessage/index.js +166 -0
  239. package/dist/chat/providers/index.d.ts +76 -0
  240. package/dist/chat/providers/index.js +430 -0
  241. package/dist/chat/providers/irc/index.d.ts +101 -0
  242. package/dist/chat/providers/irc/index.js +557 -0
  243. package/dist/chat/providers/line/index.d.ts +113 -0
  244. package/dist/chat/providers/line/index.js +434 -0
  245. package/dist/chat/providers/matrix/index.d.ts +161 -0
  246. package/dist/chat/providers/matrix/index.js +559 -0
  247. package/dist/chat/providers/mattermost/index.d.ts +106 -0
  248. package/dist/chat/providers/mattermost/index.js +425 -0
  249. package/dist/chat/providers/msteams/index.d.ts +198 -0
  250. package/dist/chat/providers/msteams/index.js +694 -0
  251. package/dist/chat/providers/nextcloud/index.d.ts +52 -0
  252. package/dist/chat/providers/nextcloud/index.js +156 -0
  253. package/dist/chat/providers/nostr/index.d.ts +60 -0
  254. package/dist/chat/providers/nostr/index.js +200 -0
  255. package/dist/chat/providers/qq/index.d.ts +57 -0
  256. package/dist/chat/providers/qq/index.js +260 -0
  257. package/dist/chat/providers/registry.d.ts +89 -0
  258. package/dist/chat/providers/registry.js +213 -0
  259. package/dist/chat/providers/signal/index.d.ts +88 -0
  260. package/dist/chat/providers/signal/index.js +357 -0
  261. package/dist/chat/providers/slack/index.d.ts +52 -0
  262. package/dist/chat/providers/slack/index.js +477 -0
  263. package/dist/chat/providers/synology/index.d.ts +50 -0
  264. package/dist/chat/providers/synology/index.js +138 -0
  265. package/dist/chat/providers/telegram/index.d.ts +148 -0
  266. package/dist/chat/providers/telegram/index.js +492 -0
  267. package/dist/chat/providers/tlon/index.d.ts +44 -0
  268. package/dist/chat/providers/tlon/index.js +243 -0
  269. package/dist/chat/providers/twitch/index.d.ts +79 -0
  270. package/dist/chat/providers/twitch/index.js +349 -0
  271. package/dist/chat/providers/types.d.ts +437 -0
  272. package/dist/chat/providers/types.js +14 -0
  273. package/dist/chat/providers/webchat/index.d.ts +38 -0
  274. package/dist/chat/providers/webchat/index.js +214 -0
  275. package/dist/chat/providers/wecom/index.d.ts +62 -0
  276. package/dist/chat/providers/wecom/index.js +228 -0
  277. package/dist/chat/providers/whatsapp/index.d.ts +147 -0
  278. package/dist/chat/providers/whatsapp/index.js +396 -0
  279. package/dist/chat/providers/zalo/index.d.ts +54 -0
  280. package/dist/chat/providers/zalo/index.js +158 -0
  281. package/dist/chat/providers/zalo-personal/index.d.ts +53 -0
  282. package/dist/chat/providers/zalo-personal/index.js +212 -0
  283. package/dist/chat/skills.d.ts +82 -0
  284. package/dist/chat/skills.js +410 -0
  285. package/dist/chat/system-prompts.d.ts +76 -0
  286. package/dist/chat/system-prompts.js +407 -0
  287. package/dist/chat/tool-handler.d.ts +57 -0
  288. package/dist/chat/tool-handler.js +336 -0
  289. package/dist/chat/tools.d.ts +373 -0
  290. package/dist/chat/tools.js +512 -0
  291. package/dist/cli/commands/agent.d.ts +3 -0
  292. package/dist/cli/commands/agent.js +108 -0
  293. package/dist/cli/commands/auth.d.ts +12 -0
  294. package/dist/cli/commands/auth.js +301 -0
  295. package/dist/cli/commands/browser.d.ts +3 -0
  296. package/dist/cli/commands/browser.js +138 -0
  297. package/dist/cli/commands/canvas.d.ts +3 -0
  298. package/dist/cli/commands/canvas.js +155 -0
  299. package/dist/cli/commands/channels.d.ts +3 -0
  300. package/dist/cli/commands/channels.js +167 -0
  301. package/dist/cli/commands/chat.d.ts +9 -0
  302. package/dist/cli/commands/chat.js +360 -0
  303. package/dist/cli/commands/completion.d.ts +3 -0
  304. package/dist/cli/commands/completion.js +170 -0
  305. package/dist/cli/commands/config.d.ts +3 -0
  306. package/dist/cli/commands/config.js +193 -0
  307. package/dist/cli/commands/cost.d.ts +3 -0
  308. package/dist/cli/commands/cost.js +134 -0
  309. package/dist/cli/commands/daemon.d.ts +3 -0
  310. package/dist/cli/commands/daemon.js +381 -0
  311. package/dist/cli/commands/devices.d.ts +3 -0
  312. package/dist/cli/commands/devices.js +150 -0
  313. package/dist/cli/commands/doctor.d.ts +3 -0
  314. package/dist/cli/commands/doctor.js +295 -0
  315. package/dist/cli/commands/logs.d.ts +3 -0
  316. package/dist/cli/commands/logs.js +139 -0
  317. package/dist/cli/commands/mcp.d.ts +15 -0
  318. package/dist/cli/commands/mcp.js +157 -0
  319. package/dist/cli/commands/memory.d.ts +3 -0
  320. package/dist/cli/commands/memory.js +170 -0
  321. package/dist/cli/commands/models.d.ts +3 -0
  322. package/dist/cli/commands/models.js +197 -0
  323. package/dist/cli/commands/nodes.d.ts +3 -0
  324. package/dist/cli/commands/nodes.js +193 -0
  325. package/dist/cli/commands/onboard.d.ts +13 -0
  326. package/dist/cli/commands/onboard.js +360 -0
  327. package/dist/cli/commands/plugin.d.ts +15 -0
  328. package/dist/cli/commands/plugin.js +226 -0
  329. package/dist/cli/commands/provider.d.ts +16 -0
  330. package/dist/cli/commands/provider.js +320 -0
  331. package/dist/cli/commands/security.d.ts +3 -0
  332. package/dist/cli/commands/security.js +180 -0
  333. package/dist/cli/commands/serve.d.ts +3 -0
  334. package/dist/cli/commands/serve.js +179 -0
  335. package/dist/cli/commands/session.d.ts +3 -0
  336. package/dist/cli/commands/session.js +172 -0
  337. package/dist/cli/commands/setup.d.ts +13 -0
  338. package/dist/cli/commands/setup.js +636 -0
  339. package/dist/cli/commands/skill.d.ts +15 -0
  340. package/dist/cli/commands/skill.js +191 -0
  341. package/dist/cli/commands/status.d.ts +3 -0
  342. package/dist/cli/commands/status.js +71 -0
  343. package/dist/cli/commands/summary.d.ts +3 -0
  344. package/dist/cli/commands/summary.js +160 -0
  345. package/dist/cli/commands/task.d.ts +3 -0
  346. package/dist/cli/commands/task.js +170 -0
  347. package/dist/cli/commands/ticket.d.ts +3 -0
  348. package/dist/cli/commands/ticket.js +421 -0
  349. package/dist/cli/commands/tools.d.ts +9 -0
  350. package/dist/cli/commands/tools.js +508 -0
  351. package/dist/cli/commands/tui.d.ts +3 -0
  352. package/dist/cli/commands/tui.js +158 -0
  353. package/dist/cli/commands/tunnel.d.ts +3 -0
  354. package/dist/cli/commands/tunnel.js +135 -0
  355. package/dist/cli/commands/webhooks.d.ts +3 -0
  356. package/dist/cli/commands/webhooks.js +191 -0
  357. package/dist/cli/index.d.ts +3 -0
  358. package/dist/cli/index.js +127 -0
  359. package/dist/cli/utils/api.d.ts +17 -0
  360. package/dist/cli/utils/api.js +63 -0
  361. package/dist/cli/utils/config.d.ts +31 -0
  362. package/dist/cli/utils/config.js +81 -0
  363. package/dist/cli/utils/output.d.ts +58 -0
  364. package/dist/cli/utils/output.js +148 -0
  365. package/dist/core/deployment.d.ts +30 -0
  366. package/dist/core/deployment.js +114 -0
  367. package/dist/core/sandbox-config.d.ts +63 -0
  368. package/dist/core/sandbox-config.js +148 -0
  369. package/dist/costs/budget.d.ts +28 -0
  370. package/dist/costs/budget.js +57 -0
  371. package/dist/costs/persistence.d.ts +77 -0
  372. package/dist/costs/persistence.js +210 -0
  373. package/dist/costs/pricing.d.ts +16 -0
  374. package/dist/costs/pricing.js +39 -0
  375. package/dist/costs/token-tracker.d.ts +34 -0
  376. package/dist/costs/token-tracker.js +141 -0
  377. package/dist/cron/heartbeat.d.ts +23 -0
  378. package/dist/cron/heartbeat.js +109 -0
  379. package/dist/cron/index.d.ts +22 -0
  380. package/dist/cron/index.js +37 -0
  381. package/dist/cron/issue-poller.d.ts +15 -0
  382. package/dist/cron/issue-poller.js +174 -0
  383. package/dist/cron/scheduler.d.ts +315 -0
  384. package/dist/cron/scheduler.js +1008 -0
  385. package/dist/cron/stale-checker.d.ts +16 -0
  386. package/dist/cron/stale-checker.js +61 -0
  387. package/dist/cron/templates.d.ts +107 -0
  388. package/dist/cron/templates.js +395 -0
  389. package/dist/diagnostics/exporters.d.ts +21 -0
  390. package/dist/diagnostics/exporters.js +138 -0
  391. package/dist/diagnostics/index.d.ts +10 -0
  392. package/dist/diagnostics/index.js +9 -0
  393. package/dist/diagnostics/middleware.d.ts +12 -0
  394. package/dist/diagnostics/middleware.js +58 -0
  395. package/dist/diagnostics/tracer.d.ts +133 -0
  396. package/dist/diagnostics/tracer.js +257 -0
  397. package/dist/discovery/index.d.ts +8 -0
  398. package/dist/discovery/index.js +7 -0
  399. package/dist/discovery/mdns.d.ts +40 -0
  400. package/dist/discovery/mdns.js +249 -0
  401. package/dist/gateway/index.d.ts +35 -0
  402. package/dist/gateway/index.js +36 -0
  403. package/dist/gateway/router.d.ts +110 -0
  404. package/dist/gateway/router.js +649 -0
  405. package/dist/gateway/types.d.ts +275 -0
  406. package/dist/gateway/types.js +2 -0
  407. package/dist/gateway/workflows.d.ts +37 -0
  408. package/dist/gateway/workflows.js +748 -0
  409. package/dist/hooks/agent-webhook.d.ts +277 -0
  410. package/dist/hooks/agent-webhook.js +197 -0
  411. package/dist/hooks/index.d.ts +13 -0
  412. package/dist/hooks/index.js +15 -0
  413. package/dist/hooks/prompt-submit.d.ts +45 -0
  414. package/dist/hooks/prompt-submit.js +111 -0
  415. package/dist/hooks/schemas.d.ts +563 -0
  416. package/dist/hooks/schemas.js +108 -0
  417. package/dist/hooks/session-end.d.ts +25 -0
  418. package/dist/hooks/session-end.js +153 -0
  419. package/dist/hooks/tool-use.d.ts +41 -0
  420. package/dist/hooks/tool-use.js +201 -0
  421. package/dist/hooks/types.d.ts +76 -0
  422. package/dist/hooks/types.js +7 -0
  423. package/dist/integrations/cloudflare-tunnel.d.ts +78 -0
  424. package/dist/integrations/cloudflare-tunnel.js +268 -0
  425. package/dist/integrations/github-client.d.ts +27 -0
  426. package/dist/integrations/github-client.js +79 -0
  427. package/dist/integrations/github-projects.d.ts +97 -0
  428. package/dist/integrations/github-projects.js +433 -0
  429. package/dist/integrations/github-ticket-sync.d.ts +82 -0
  430. package/dist/integrations/github-ticket-sync.js +352 -0
  431. package/dist/integrations/github.d.ts +11 -0
  432. package/dist/integrations/github.js +241 -0
  433. package/dist/integrations/jira-client.d.ts +30 -0
  434. package/dist/integrations/jira-client.js +67 -0
  435. package/dist/integrations/jira.d.ts +13 -0
  436. package/dist/integrations/jira.js +108 -0
  437. package/dist/integrations/linear-client.d.ts +23 -0
  438. package/dist/integrations/linear-client.js +52 -0
  439. package/dist/integrations/linear.d.ts +15 -0
  440. package/dist/integrations/linear.js +312 -0
  441. package/dist/integrations/tailscale.d.ts +68 -0
  442. package/dist/integrations/tailscale.js +173 -0
  443. package/dist/integrations/web-search.d.ts +112 -0
  444. package/dist/integrations/web-search.js +287 -0
  445. package/dist/intelligence/index.d.ts +8 -0
  446. package/dist/intelligence/index.js +8 -0
  447. package/dist/intelligence/ollama.d.ts +50 -0
  448. package/dist/intelligence/ollama.js +213 -0
  449. package/dist/intelligence/rules.d.ts +39 -0
  450. package/dist/intelligence/rules.js +308 -0
  451. package/dist/labels/index.d.ts +93 -0
  452. package/dist/labels/index.js +248 -0
  453. package/dist/mcp/browser-tools.d.ts +10 -0
  454. package/dist/mcp/browser-tools.js +16 -0
  455. package/dist/mcp/client.d.ts +54 -0
  456. package/dist/mcp/client.js +153 -0
  457. package/dist/mcp/index.d.ts +12 -0
  458. package/dist/mcp/index.js +13 -0
  459. package/dist/mcp/server.d.ts +40 -0
  460. package/dist/mcp/server.js +826 -0
  461. package/dist/mcp/tool-adapter.d.ts +49 -0
  462. package/dist/mcp/tool-adapter.js +193 -0
  463. package/dist/memory/experience-store.d.ts +121 -0
  464. package/dist/memory/experience-store.js +439 -0
  465. package/dist/memory/index.d.ts +8 -0
  466. package/dist/memory/index.js +25 -0
  467. package/dist/memory/memory-service.d.ts +312 -0
  468. package/dist/memory/memory-service.js +1172 -0
  469. package/dist/memory/memory-watcher.d.ts +116 -0
  470. package/dist/memory/memory-watcher.js +239 -0
  471. package/dist/middleware/logging.d.ts +34 -0
  472. package/dist/middleware/logging.js +184 -0
  473. package/dist/middleware/rate-limit.d.ts +29 -0
  474. package/dist/middleware/rate-limit.js +91 -0
  475. package/dist/notifications/in-app.d.ts +28 -0
  476. package/dist/notifications/in-app.js +53 -0
  477. package/dist/notifications/index.d.ts +3 -0
  478. package/dist/notifications/index.js +3 -0
  479. package/dist/notifications/push.d.ts +74 -0
  480. package/dist/notifications/push.js +175 -0
  481. package/dist/notifications/slack.d.ts +32 -0
  482. package/dist/notifications/slack.js +157 -0
  483. package/dist/plugins/clawhub.d.ts +70 -0
  484. package/dist/plugins/clawhub.js +260 -0
  485. package/dist/plugins/loader.d.ts +23 -0
  486. package/dist/plugins/loader.js +140 -0
  487. package/dist/plugins/marketplace.d.ts +77 -0
  488. package/dist/plugins/marketplace.js +275 -0
  489. package/dist/plugins/registry.d.ts +122 -0
  490. package/dist/plugins/registry.js +352 -0
  491. package/dist/plugins/sandbox.d.ts +77 -0
  492. package/dist/plugins/sandbox.js +287 -0
  493. package/dist/plugins/scaffolder.d.ts +28 -0
  494. package/dist/plugins/scaffolder.js +409 -0
  495. package/dist/plugins/sdk.d.ts +35 -0
  496. package/dist/plugins/sdk.js +8 -0
  497. package/dist/plugins/search/brave.d.ts +9 -0
  498. package/dist/plugins/search/brave.js +157 -0
  499. package/dist/plugins/search/duckduckgo.d.ts +9 -0
  500. package/dist/plugins/search/duckduckgo.js +171 -0
  501. package/dist/plugins/search/index.d.ts +13 -0
  502. package/dist/plugins/search/index.js +23 -0
  503. package/dist/plugins/search/searxng.d.ts +9 -0
  504. package/dist/plugins/search/searxng.js +170 -0
  505. package/dist/plugins/search/serper.d.ts +9 -0
  506. package/dist/plugins/search/serper.js +135 -0
  507. package/dist/plugins/search/tavily.d.ts +9 -0
  508. package/dist/plugins/search/tavily.js +146 -0
  509. package/dist/plugins/types.d.ts +174 -0
  510. package/dist/plugins/types.js +8 -0
  511. package/dist/projects/index.d.ts +133 -0
  512. package/dist/projects/index.js +897 -0
  513. package/dist/projects/types.d.ts +444 -0
  514. package/dist/projects/types.js +207 -0
  515. package/dist/providers/adapters/anthropic.d.ts +26 -0
  516. package/dist/providers/adapters/anthropic.js +306 -0
  517. package/dist/providers/adapters/base.d.ts +53 -0
  518. package/dist/providers/adapters/base.js +99 -0
  519. package/dist/providers/adapters/ollama.d.ts +30 -0
  520. package/dist/providers/adapters/ollama.js +292 -0
  521. package/dist/providers/ai-sdk.d.ts +178 -0
  522. package/dist/providers/ai-sdk.js +1552 -0
  523. package/dist/providers/core/index.d.ts +8 -0
  524. package/dist/providers/core/index.js +10 -0
  525. package/dist/providers/core/models.d.ts +31 -0
  526. package/dist/providers/core/models.js +949 -0
  527. package/dist/providers/core/types.d.ts +117 -0
  528. package/dist/providers/core/types.js +83 -0
  529. package/dist/providers/index.d.ts +7 -0
  530. package/dist/providers/index.js +7 -0
  531. package/dist/providers/registry.d.ts +93 -0
  532. package/dist/providers/registry.js +228 -0
  533. package/dist/providers/schema-utils.d.ts +23 -0
  534. package/dist/providers/schema-utils.js +545 -0
  535. package/dist/providers/types.d.ts +609 -0
  536. package/dist/providers/types.js +279 -0
  537. package/dist/queue/failure-handler.d.ts +93 -0
  538. package/dist/queue/failure-handler.js +379 -0
  539. package/dist/queue/index.d.ts +23 -0
  540. package/dist/queue/index.js +86 -0
  541. package/dist/queue/memory-queue.d.ts +30 -0
  542. package/dist/queue/memory-queue.js +429 -0
  543. package/dist/queue/notifications.d.ts +6 -0
  544. package/dist/queue/notifications.js +128 -0
  545. package/dist/queue/task-queue.d.ts +55 -0
  546. package/dist/queue/task-queue.js +518 -0
  547. package/dist/queue/webhook-queue.d.ts +47 -0
  548. package/dist/queue/webhook-queue.js +158 -0
  549. package/dist/routes/agents.d.ts +4 -0
  550. package/dist/routes/agents.js +45 -0
  551. package/dist/routes/auth.d.ts +19 -0
  552. package/dist/routes/auth.js +492 -0
  553. package/dist/routes/backup.d.ts +6 -0
  554. package/dist/routes/backup.js +71 -0
  555. package/dist/routes/chat.d.ts +10 -0
  556. package/dist/routes/chat.js +1678 -0
  557. package/dist/routes/clawhub.d.ts +8 -0
  558. package/dist/routes/clawhub.js +89 -0
  559. package/dist/routes/costs.d.ts +4 -0
  560. package/dist/routes/costs.js +78 -0
  561. package/dist/routes/cron.d.ts +11 -0
  562. package/dist/routes/cron.js +708 -0
  563. package/dist/routes/devices.d.ts +9 -0
  564. package/dist/routes/devices.js +490 -0
  565. package/dist/routes/discord.d.ts +15 -0
  566. package/dist/routes/discord.js +524 -0
  567. package/dist/routes/dlq.d.ts +4 -0
  568. package/dist/routes/dlq.js +64 -0
  569. package/dist/routes/gateway.d.ts +4 -0
  570. package/dist/routes/gateway.js +253 -0
  571. package/dist/routes/health.d.ts +29 -0
  572. package/dist/routes/health.js +296 -0
  573. package/dist/routes/hooks.d.ts +4 -0
  574. package/dist/routes/hooks.js +170 -0
  575. package/dist/routes/import.d.ts +9 -0
  576. package/dist/routes/import.js +540 -0
  577. package/dist/routes/index.d.ts +38 -0
  578. package/dist/routes/index.js +39 -0
  579. package/dist/routes/integrations.d.ts +10 -0
  580. package/dist/routes/integrations.js +200 -0
  581. package/dist/routes/labels.d.ts +8 -0
  582. package/dist/routes/labels.js +240 -0
  583. package/dist/routes/mcp.d.ts +14 -0
  584. package/dist/routes/mcp.js +125 -0
  585. package/dist/routes/memory.d.ts +10 -0
  586. package/dist/routes/memory.js +622 -0
  587. package/dist/routes/notifications.d.ts +9 -0
  588. package/dist/routes/notifications.js +154 -0
  589. package/dist/routes/oobe.d.ts +10 -0
  590. package/dist/routes/oobe.js +405 -0
  591. package/dist/routes/openapi.d.ts +9 -0
  592. package/dist/routes/openapi.js +537 -0
  593. package/dist/routes/plugins.d.ts +8 -0
  594. package/dist/routes/plugins.js +108 -0
  595. package/dist/routes/projects.d.ts +8 -0
  596. package/dist/routes/projects.js +592 -0
  597. package/dist/routes/push.d.ts +8 -0
  598. package/dist/routes/push.js +75 -0
  599. package/dist/routes/search.d.ts +4 -0
  600. package/dist/routes/search.js +189 -0
  601. package/dist/routes/security.d.ts +10 -0
  602. package/dist/routes/security.js +189 -0
  603. package/dist/routes/settings.d.ts +4 -0
  604. package/dist/routes/settings.js +119 -0
  605. package/dist/routes/setup.d.ts +11 -0
  606. package/dist/routes/setup.js +525 -0
  607. package/dist/routes/skills.d.ts +13 -0
  608. package/dist/routes/skills.js +152 -0
  609. package/dist/routes/slack.d.ts +12 -0
  610. package/dist/routes/slack.js +999 -0
  611. package/dist/routes/states.d.ts +8 -0
  612. package/dist/routes/states.js +123 -0
  613. package/dist/routes/stats.d.ts +6 -0
  614. package/dist/routes/stats.js +369 -0
  615. package/dist/routes/summaries.d.ts +4 -0
  616. package/dist/routes/summaries.js +344 -0
  617. package/dist/routes/sync.d.ts +13 -0
  618. package/dist/routes/sync.js +268 -0
  619. package/dist/routes/tasks.d.ts +4 -0
  620. package/dist/routes/tasks.js +473 -0
  621. package/dist/routes/telegram.d.ts +14 -0
  622. package/dist/routes/telegram.js +420 -0
  623. package/dist/routes/tickets.d.ts +4 -0
  624. package/dist/routes/tickets.js +1090 -0
  625. package/dist/routes/tokens.d.ts +4 -0
  626. package/dist/routes/tokens.js +83 -0
  627. package/dist/routes/tools.d.ts +14 -0
  628. package/dist/routes/tools.js +790 -0
  629. package/dist/routes/tunnels.d.ts +8 -0
  630. package/dist/routes/tunnels.js +145 -0
  631. package/dist/routes/users.d.ts +15 -0
  632. package/dist/routes/users.js +998 -0
  633. package/dist/routes/voice.d.ts +8 -0
  634. package/dist/routes/voice.js +127 -0
  635. package/dist/routes/webchat.d.ts +11 -0
  636. package/dist/routes/webchat.js +173 -0
  637. package/dist/routes/webhook-dedup.d.ts +11 -0
  638. package/dist/routes/webhook-dedup.js +49 -0
  639. package/dist/routes/webhooks.d.ts +4 -0
  640. package/dist/routes/webhooks.js +71 -0
  641. package/dist/routes/whatsapp.d.ts +14 -0
  642. package/dist/routes/whatsapp.js +391 -0
  643. package/dist/security/audit-scanner.d.ts +32 -0
  644. package/dist/security/audit-scanner.js +217 -0
  645. package/dist/security/fs-guard.d.ts +41 -0
  646. package/dist/security/fs-guard.js +206 -0
  647. package/dist/security/prompt-guard.d.ts +47 -0
  648. package/dist/security/prompt-guard.js +198 -0
  649. package/dist/security/ssrf-guard.d.ts +38 -0
  650. package/dist/security/ssrf-guard.js +266 -0
  651. package/dist/security/types.d.ts +92 -0
  652. package/dist/security/types.js +8 -0
  653. package/dist/server/route-loader.d.ts +15 -0
  654. package/dist/server/route-loader.js +135 -0
  655. package/dist/server.d.ts +5 -0
  656. package/dist/server.js +835 -0
  657. package/dist/settings/index.d.ts +841 -0
  658. package/dist/settings/index.js +451 -0
  659. package/dist/skills/compiler.d.ts +83 -0
  660. package/dist/skills/compiler.js +358 -0
  661. package/dist/skills/frontmatter.d.ts +33 -0
  662. package/dist/skills/frontmatter.js +175 -0
  663. package/dist/skills/index.d.ts +19 -0
  664. package/dist/skills/index.js +24 -0
  665. package/dist/skills/installer.d.ts +22 -0
  666. package/dist/skills/installer.js +220 -0
  667. package/dist/skills/loader.d.ts +72 -0
  668. package/dist/skills/loader.js +484 -0
  669. package/dist/skills/prompt-builder.d.ts +48 -0
  670. package/dist/skills/prompt-builder.js +135 -0
  671. package/dist/skills/registry.d.ts +115 -0
  672. package/dist/skills/registry.js +225 -0
  673. package/dist/skills/types.d.ts +202 -0
  674. package/dist/skills/types.js +24 -0
  675. package/dist/states/index.d.ts +64 -0
  676. package/dist/states/index.js +142 -0
  677. package/dist/storage/adapter.d.ts +146 -0
  678. package/dist/storage/adapter.js +2 -0
  679. package/dist/storage/index.d.ts +48 -0
  680. package/dist/storage/index.js +135 -0
  681. package/dist/storage/libsql.d.ts +99 -0
  682. package/dist/storage/libsql.js +1873 -0
  683. package/dist/storage/migrations.d.ts +65 -0
  684. package/dist/storage/migrations.js +289 -0
  685. package/dist/storage/schema.d.ts +10185 -0
  686. package/dist/storage/schema.js +1113 -0
  687. package/dist/summaries/extractor.d.ts +56 -0
  688. package/dist/summaries/extractor.js +377 -0
  689. package/dist/summaries/index.d.ts +13 -0
  690. package/dist/summaries/index.js +14 -0
  691. package/dist/summaries/storage.d.ts +51 -0
  692. package/dist/summaries/storage.js +101 -0
  693. package/dist/summaries/templates.d.ts +68 -0
  694. package/dist/summaries/templates.js +245 -0
  695. package/dist/sync/adapters/base.d.ts +42 -0
  696. package/dist/sync/adapters/base.js +142 -0
  697. package/dist/sync/adapters/github.d.ts +45 -0
  698. package/dist/sync/adapters/github.js +445 -0
  699. package/dist/sync/adapters/linear.d.ts +40 -0
  700. package/dist/sync/adapters/linear.js +434 -0
  701. package/dist/sync/config.d.ts +388 -0
  702. package/dist/sync/config.js +281 -0
  703. package/dist/sync/engine.d.ts +112 -0
  704. package/dist/sync/engine.js +623 -0
  705. package/dist/sync/index.d.ts +31 -0
  706. package/dist/sync/index.js +34 -0
  707. package/dist/sync/integration.d.ts +53 -0
  708. package/dist/sync/integration.js +231 -0
  709. package/dist/sync/types.d.ts +249 -0
  710. package/dist/sync/types.js +30 -0
  711. package/dist/tickets/index.d.ts +139 -0
  712. package/dist/tickets/index.js +1406 -0
  713. package/dist/tickets/types.d.ts +817 -0
  714. package/dist/tickets/types.js +310 -0
  715. package/dist/tools/adapters.d.ts +56 -0
  716. package/dist/tools/adapters.js +183 -0
  717. package/dist/tools/index.d.ts +66 -0
  718. package/dist/tools/index.js +105 -0
  719. package/dist/tools/types.d.ts +117 -0
  720. package/dist/tools/types.js +20 -0
  721. package/dist/types/agent.d.ts +101 -0
  722. package/dist/types/agent.js +2 -0
  723. package/dist/types/errors.d.ts +150 -0
  724. package/dist/types/errors.js +338 -0
  725. package/dist/types/index.d.ts +3 -0
  726. package/dist/types/index.js +3 -0
  727. package/dist/types/summary.d.ts +638 -0
  728. package/dist/types/summary.js +137 -0
  729. package/dist/types/task.d.ts +123 -0
  730. package/dist/types/task.js +46 -0
  731. package/dist/utils/ai-cache.d.ts +72 -0
  732. package/dist/utils/ai-cache.js +204 -0
  733. package/dist/utils/ai-inference.d.ts +57 -0
  734. package/dist/utils/ai-inference.js +190 -0
  735. package/dist/utils/ai-responder.d.ts +44 -0
  736. package/dist/utils/ai-responder.js +272 -0
  737. package/dist/utils/circuit-breaker.d.ts +139 -0
  738. package/dist/utils/circuit-breaker.js +281 -0
  739. package/dist/utils/config-loader.d.ts +12 -0
  740. package/dist/utils/config-loader.js +44 -0
  741. package/dist/utils/crypto.d.ts +10 -0
  742. package/dist/utils/crypto.js +59 -0
  743. package/dist/utils/env-validator.d.ts +44 -0
  744. package/dist/utils/env-validator.js +236 -0
  745. package/dist/utils/file-lock.d.ts +85 -0
  746. package/dist/utils/file-lock.js +204 -0
  747. package/dist/utils/logger.d.ts +153 -0
  748. package/dist/utils/logger.js +282 -0
  749. package/dist/utils/metrics.d.ts +183 -0
  750. package/dist/utils/metrics.js +345 -0
  751. package/dist/utils/security.d.ts +90 -0
  752. package/dist/utils/security.js +347 -0
  753. package/dist/voice/index.d.ts +79 -0
  754. package/dist/voice/index.js +144 -0
  755. package/dist/voice/stt/whisper.d.ts +13 -0
  756. package/dist/voice/stt/whisper.js +116 -0
  757. package/dist/voice/tts/elevenlabs.d.ts +18 -0
  758. package/dist/voice/tts/elevenlabs.js +178 -0
  759. package/dist/voice/tts/openai-tts.d.ts +19 -0
  760. package/dist/voice/tts/openai-tts.js +127 -0
  761. package/dist/voice/tts/system.d.ts +26 -0
  762. package/dist/voice/tts/system.js +146 -0
  763. package/dist/voice/wake-word.d.ts +44 -0
  764. package/dist/voice/wake-word.js +145 -0
  765. package/docker-compose.yml +222 -0
  766. package/package.json +154 -0
  767. package/profclaw.mjs +24 -0
  768. package/skills/1password/SKILL.md +155 -0
  769. package/skills/api-tester/SKILL.md +177 -0
  770. package/skills/apple-notes/SKILL.md +167 -0
  771. package/skills/apple-reminders/SKILL.md +178 -0
  772. package/skills/bear-notes/SKILL.md +166 -0
  773. package/skills/blogwatcher/SKILL.md +177 -0
  774. package/skills/camsnap/SKILL.md +130 -0
  775. package/skills/code-generation/SKILL.md +139 -0
  776. package/skills/code-review/SKILL.md +116 -0
  777. package/skills/coding-agent/SKILL.md +184 -0
  778. package/skills/cron-manager/SKILL.md +141 -0
  779. package/skills/debug-helper/SKILL.md +134 -0
  780. package/skills/docker-ops/SKILL.md +246 -0
  781. package/skills/file-manager/SKILL.md +160 -0
  782. package/skills/git-workflow/SKILL.md +171 -0
  783. package/skills/github-issues/SKILL.md +244 -0
  784. package/skills/gog/SKILL.md +191 -0
  785. package/skills/goplaces/SKILL.md +156 -0
  786. package/skills/healthcheck/SKILL.md +270 -0
  787. package/skills/himalaya/SKILL.md +165 -0
  788. package/skills/mcp-discovery/SKILL.md +109 -0
  789. package/skills/memory-manager/SKILL.md +151 -0
  790. package/skills/model-usage/SKILL.md +177 -0
  791. package/skills/nano-banana-pro/SKILL.md +214 -0
  792. package/skills/nano-pdf/SKILL.md +165 -0
  793. package/skills/notion/SKILL.md +147 -0
  794. package/skills/obsidian/SKILL.md +163 -0
  795. package/skills/openai-image-gen/SKILL.md +194 -0
  796. package/skills/openai-whisper/SKILL.md +98 -0
  797. package/skills/openai-whisper-api/SKILL.md +130 -0
  798. package/skills/openhue/SKILL.md +203 -0
  799. package/skills/oracle/SKILL.md +236 -0
  800. package/skills/phone-control/SKILL.md +201 -0
  801. package/skills/profclaw-assistant/SKILL.md +81 -0
  802. package/skills/profclaw-projects/SKILL.md +68 -0
  803. package/skills/profclaw-tickets/SKILL.md +91 -0
  804. package/skills/session-logs/SKILL.md +216 -0
  805. package/skills/sherpa-onnx-tts/SKILL.md +134 -0
  806. package/skills/skill-creator/SKILL.md +183 -0
  807. package/skills/songsee/SKILL.md +170 -0
  808. package/skills/spotify-player/SKILL.md +254 -0
  809. package/skills/summarize/SKILL.md +155 -0
  810. package/skills/system-admin/SKILL.md +179 -0
  811. package/skills/things-mac/SKILL.md +179 -0
  812. package/skills/tmux/SKILL.md +170 -0
  813. package/skills/trello/SKILL.md +154 -0
  814. package/skills/video-frames/SKILL.md +127 -0
  815. package/skills/weather/SKILL.md +186 -0
  816. package/skills/web-research/SKILL.md +128 -0
  817. package/skills/xurl/SKILL.md +198 -0
  818. package/ui/README.md +73 -0
  819. package/ui/dist/assets/ActivityView-CkPgKhwm.js +1 -0
  820. package/ui/dist/assets/AgentList-C3SVdeEz.js +1 -0
  821. package/ui/dist/assets/AnalyticsDashboard-DVU--vlP.js +1 -0
  822. package/ui/dist/assets/AreaChart-B5qMEGWj.js +1 -0
  823. package/ui/dist/assets/CartesianChart-B50bcUJi.js +36 -0
  824. package/ui/dist/assets/ChatView-BZFJs7w_.js +10 -0
  825. package/ui/dist/assets/CostsDashboard-ChfH8BlG.js +1 -0
  826. package/ui/dist/assets/EstimateSelect-CLpB4NQO.js +1 -0
  827. package/ui/dist/assets/FloatingChatbot-CBzBY9a0.js +2 -0
  828. package/ui/dist/assets/InviteCodeManagement-DsbdPa6W.js +2 -0
  829. package/ui/dist/assets/ProjectDetail-BEM3tFXg.js +2 -0
  830. package/ui/dist/assets/ProjectDetail-D1-0B2xV.css +1 -0
  831. package/ui/dist/assets/ProjectIcon-CN1FmFAk.js +1 -0
  832. package/ui/dist/assets/ProjectList-DSDaNhxQ.js +4 -0
  833. package/ui/dist/assets/Settings-dPVcqC_d.js +6 -0
  834. package/ui/dist/assets/StatusIndicator-DA3NAo_b.js +1 -0
  835. package/ui/dist/assets/SummaryDetail-Bjnf9lT8.js +27 -0
  836. package/ui/dist/assets/SummaryList-ENwKDBKW.js +1 -0
  837. package/ui/dist/assets/TaskDetail-DnwG6MzB.js +1 -0
  838. package/ui/dist/assets/TaskList-D9Ug_HiV.js +1 -0
  839. package/ui/dist/assets/TicketBoard-CviH1571.js +1 -0
  840. package/ui/dist/assets/TicketDetail-8Jk8O-33.js +1 -0
  841. package/ui/dist/assets/TicketList-B-iV4rRA.js +1 -0
  842. package/ui/dist/assets/UserManagement-CPZ8s7s2.js +2 -0
  843. package/ui/dist/assets/ViewSwitcher-BUyOOWDI.js +1 -0
  844. package/ui/dist/assets/alert-dialog-BOmnTkN-.js +7 -0
  845. package/ui/dist/assets/archive-D5my9zOG.js +1 -0
  846. package/ui/dist/assets/badge-B4ov81_m.js +1 -0
  847. package/ui/dist/assets/brain-C53ElFLD.js +1 -0
  848. package/ui/dist/assets/bug-D0TJoCYn.js +1 -0
  849. package/ui/dist/assets/calendar-BkWIhKa1.js +1 -0
  850. package/ui/dist/assets/chevron-up-BRTtndUZ.js +1 -0
  851. package/ui/dist/assets/circle-x-BN89YhbS.js +1 -0
  852. package/ui/dist/assets/constants-fc7TFI7u.js +1 -0
  853. package/ui/dist/assets/cpu-B41x1-vV.js +1 -0
  854. package/ui/dist/assets/database-D9Cnfmzj.js +1 -0
  855. package/ui/dist/assets/defineProperty-CoXUr7_6.js +2 -0
  856. package/ui/dist/assets/dialog-DrWB4EYD.js +1 -0
  857. package/ui/dist/assets/element-adapter-DL0DQilL.js +4 -0
  858. package/ui/dist/assets/ellipsis-NuUWekvu.js +1 -0
  859. package/ui/dist/assets/ellipsis-vertical-BueMfuCw.js +1 -0
  860. package/ui/dist/assets/file-code-HR9829Jc.js +1 -0
  861. package/ui/dist/assets/folder-open-C_7oYEqe.js +1 -0
  862. package/ui/dist/assets/funnel-B5gmNXGf.js +1 -0
  863. package/ui/dist/assets/git-branch-BRMiJmV3.js +1 -0
  864. package/ui/dist/assets/git-commit-horizontal-CXOUQeJI.js +1 -0
  865. package/ui/dist/assets/globe-CCspjvus.js +1 -0
  866. package/ui/dist/assets/hash-g3102kPC.js +1 -0
  867. package/ui/dist/assets/history-CNqcBBrV.js +1 -0
  868. package/ui/dist/assets/index-27mTPKuh.js +1 -0
  869. package/ui/dist/assets/index-BMx3fH-e.js +1 -0
  870. package/ui/dist/assets/index-C9jNQXzL.js +1 -0
  871. package/ui/dist/assets/index-CEZ6R2Uw.js +7 -0
  872. package/ui/dist/assets/index-DURTouJI.js +1 -0
  873. package/ui/dist/assets/index-WclMPci1.css +1 -0
  874. package/ui/dist/assets/index-kb4AJXUB.js +67 -0
  875. package/ui/dist/assets/layers-CLXiHN6o.js +1 -0
  876. package/ui/dist/assets/layout-dashboard-B07MFhBs.js +1 -0
  877. package/ui/dist/assets/lightbulb-B2dgG5ks.js +1 -0
  878. package/ui/dist/assets/link-2-BxNmr9hL.js +1 -0
  879. package/ui/dist/assets/markdown-renderer-CjU6hBcW.js +36 -0
  880. package/ui/dist/assets/message-square-Bf2-CVbt.js +1 -0
  881. package/ui/dist/assets/pencil-D096Ey62.js +1 -0
  882. package/ui/dist/assets/play-DfdcSI3x.js +1 -0
  883. package/ui/dist/assets/popover-BV0QJDQq.js +1 -0
  884. package/ui/dist/assets/progress-DjPEDJfI.js +1 -0
  885. package/ui/dist/assets/rocket-CPsTc-5G.js +1 -0
  886. package/ui/dist/assets/select-LsO16slr.js +1 -0
  887. package/ui/dist/assets/send-BDYBZDUZ.js +1 -0
  888. package/ui/dist/assets/server-B3k6noce.js +1 -0
  889. package/ui/dist/assets/settings-2-Cu4xTjhG.js +1 -0
  890. package/ui/dist/assets/sheet-BScLnPKX.js +1 -0
  891. package/ui/dist/assets/shield-check-CQqkwufI.js +1 -0
  892. package/ui/dist/assets/shield-off-ZFruH9KO.js +1 -0
  893. package/ui/dist/assets/skeleton-CtkIA_MU.js +1 -0
  894. package/ui/dist/assets/smartphone-DnoksVkc.js +1 -0
  895. package/ui/dist/assets/square-uD9ZHMfW.js +1 -0
  896. package/ui/dist/assets/switch-MQPnwGJK.js +1 -0
  897. package/ui/dist/assets/table-B8cqlywA.js +1 -0
  898. package/ui/dist/assets/tag-wEJQRWlV.js +1 -0
  899. package/ui/dist/assets/textarea-D5LJCOGl.js +1 -0
  900. package/ui/dist/assets/timer-mbGHegmr.js +1 -0
  901. package/ui/dist/assets/tooltip-Df1CunSp.js +1 -0
  902. package/ui/dist/assets/trash-2-B4oAXsX-.js +1 -0
  903. package/ui/dist/assets/trending-up-BGWxvlmZ.js +1 -0
  904. package/ui/dist/assets/wand-sparkles-CZy4xvL3.js +1 -0
  905. package/ui/dist/assets/wrench-ByZkjO6m.js +1 -0
  906. package/ui/dist/audio-worklets/vad-processor.js +132 -0
  907. package/ui/dist/brand/profclaw-appicon-192.png +0 -0
  908. package/ui/dist/brand/profclaw-appicon-512.png +0 -0
  909. package/ui/dist/brand/profclaw-appicon-shadow.svg +51 -0
  910. package/ui/dist/brand/profclaw-appicon.svg +50 -0
  911. package/ui/dist/brand/profclaw-favicon-coral-bg-128.png +0 -0
  912. package/ui/dist/brand/profclaw-favicon-coral-bg-64.png +0 -0
  913. package/ui/dist/brand/profclaw-favicon-coral-bg.svg +52 -0
  914. package/ui/dist/brand/profclaw-favicon-coral-body-128.png +0 -0
  915. package/ui/dist/brand/profclaw-favicon-coral-body.svg +41 -0
  916. package/ui/dist/brand/profclaw-favicon-shadow-128.png +0 -0
  917. package/ui/dist/brand/profclaw-favicon-shadow-64.png +0 -0
  918. package/ui/dist/brand/profclaw-favicon-shadow.svg +51 -0
  919. package/ui/dist/brand/profclaw-mark-coral-256.png +0 -0
  920. package/ui/dist/brand/profclaw-mark-coral-64.png +0 -0
  921. package/ui/dist/brand/profclaw-mark-coral.svg +31 -0
  922. package/ui/dist/brand/profclaw-mono-white.svg +18 -0
  923. package/ui/dist/brand/profclaw-text-dark.svg +18 -0
  924. package/ui/dist/brand/profclaw-text-light.svg +18 -0
  925. package/ui/dist/brand/profclaw-wordmark-dark.svg +48 -0
  926. package/ui/dist/brand/profclaw-wordmark-light.svg +48 -0
  927. package/ui/dist/brand/safari-pinned-tab.svg +15 -0
  928. package/ui/dist/favicon/android-chrome-192x192.png +0 -0
  929. package/ui/dist/favicon/android-chrome-384x384.png +0 -0
  930. package/ui/dist/favicon/android-chrome-512x512.png +0 -0
  931. package/ui/dist/favicon/apple-touch-icon.png +0 -0
  932. package/ui/dist/favicon/browserconfig.xml +9 -0
  933. package/ui/dist/favicon/favicon-16x16.png +0 -0
  934. package/ui/dist/favicon/favicon-32x32.png +0 -0
  935. package/ui/dist/favicon/favicon.ico +0 -0
  936. package/ui/dist/favicon/mstile-150x150.png +0 -0
  937. package/ui/dist/favicon/safari-pinned-tab.svg +46 -0
  938. package/ui/dist/favicon/site.webmanifest +22 -0
  939. package/ui/dist/index.html +32 -0
  940. package/ui/dist/manifest.json +49 -0
  941. package/ui/dist/sw.js +124 -0
  942. package/ui/dist/vite.svg +1 -0
@@ -0,0 +1,1406 @@
1
+ /**
2
+ * profClaw Ticket Service
3
+ *
4
+ * Core CRUD operations for AI-native tickets
5
+ */
6
+ import { randomUUID } from "crypto";
7
+ import { eq, and, or, desc, asc, like, sql, inArray, gte, lte, } from "drizzle-orm";
8
+ import { getDb } from "../storage/index.js";
9
+ import { tickets, ticketExternalLinks, ticketRelations, ticketWatchers, ticketAssignees, ticketMentions, ticketAttachments, ticketReactions, ticketComments, ticketHistory, ticketSequence, sprintTickets, } from "../storage/schema.js";
10
+ import { CreateTicketSchema, UpdateTicketSchema, BulkUpdateTicketsSchema, BulkDeleteTicketsSchema, TicketQuerySchema, } from "./types.js";
11
+ import { logger } from "../utils/logger.js";
12
+ // Outbound sync callbacks (async, fire-and-forget)
13
+ let syncCallbacks = {};
14
+ /**
15
+ * Register sync callbacks (called by sync integration module)
16
+ */
17
+ export function registerSyncCallbacks(callbacks) {
18
+ syncCallbacks = callbacks;
19
+ }
20
+ // Re-export types
21
+ export * from "./types.js";
22
+ // === Helpers ===
23
+ function generateId() {
24
+ return randomUUID();
25
+ }
26
+ async function getNextSequence(workspaceId = "default") {
27
+ const db = getDb();
28
+ if (!db)
29
+ throw new Error("Database not initialized");
30
+ // Upsert sequence counter
31
+ const result = await db
32
+ .insert(ticketSequence)
33
+ .values({ workspaceId, lastSequence: 1 })
34
+ .onConflictDoUpdate({
35
+ target: ticketSequence.workspaceId,
36
+ set: { lastSequence: sql `${ticketSequence.lastSequence} + 1` },
37
+ })
38
+ .returning();
39
+ return result[0]?.lastSequence ?? 1;
40
+ }
41
+ // === CRUD Operations ===
42
+ /**
43
+ * Create a new ticket
44
+ */
45
+ export async function createTicket(input) {
46
+ const parsed = CreateTicketSchema.parse(input);
47
+ const db = getDb();
48
+ if (!db)
49
+ throw new Error("Database not initialized");
50
+ const id = generateId();
51
+ const sequence = await getNextSequence();
52
+ const now = new Date().toISOString();
53
+ const ticket = {
54
+ id,
55
+ sequence,
56
+ projectId: parsed.projectId,
57
+ title: parsed.title,
58
+ description: parsed.description || "",
59
+ descriptionHtml: undefined,
60
+ type: parsed.type || "task",
61
+ priority: parsed.priority || "medium",
62
+ status: parsed.status || "backlog",
63
+ labels: parsed.labels || [],
64
+ assignee: parsed.assignee,
65
+ assigneeAgent: parsed.assigneeAgent,
66
+ parentId: parsed.parentId,
67
+ linkedPRs: [],
68
+ linkedCommits: [],
69
+ linkedBranch: undefined,
70
+ createdAt: now,
71
+ updatedAt: now,
72
+ startedAt: undefined,
73
+ completedAt: undefined,
74
+ startDate: parsed.startDate,
75
+ dueDate: parsed.dueDate,
76
+ createdBy: parsed.createdBy || "human",
77
+ aiAgent: parsed.aiAgent,
78
+ aiSessionId: parsed.aiSessionId,
79
+ aiTaskId: parsed.aiTaskId,
80
+ estimate: parsed.estimate,
81
+ estimateUnit: parsed.estimateUnit,
82
+ };
83
+ await db.insert(tickets).values({
84
+ id: ticket.id,
85
+ sequence: ticket.sequence,
86
+ projectId: ticket.projectId,
87
+ title: ticket.title,
88
+ description: ticket.description,
89
+ type: ticket.type,
90
+ priority: ticket.priority,
91
+ status: ticket.status,
92
+ labels: ticket.labels,
93
+ assignee: ticket.assignee,
94
+ assigneeAgent: ticket.assigneeAgent,
95
+ parentId: ticket.parentId,
96
+ linkedPRs: ticket.linkedPRs,
97
+ linkedCommits: ticket.linkedCommits,
98
+ createdBy: ticket.createdBy,
99
+ aiAgent: ticket.aiAgent,
100
+ aiSessionId: ticket.aiSessionId,
101
+ aiTaskId: ticket.aiTaskId,
102
+ startDate: ticket.startDate,
103
+ dueDate: ticket.dueDate,
104
+ estimate: ticket.estimate,
105
+ estimateUnit: ticket.estimateUnit,
106
+ });
107
+ // Record creation in history
108
+ await recordHistory(id, "created", undefined, "created", {
109
+ type: parsed.createdBy || "human",
110
+ name: parsed.aiAgent || "User",
111
+ platform: "profclaw",
112
+ });
113
+ // Create external link if provided
114
+ if (parsed.externalLink) {
115
+ await createExternalLink(id, {
116
+ platform: parsed.externalLink.platform,
117
+ externalId: parsed.externalLink.externalId,
118
+ externalUrl: parsed.externalLink.externalUrl,
119
+ });
120
+ }
121
+ return ticket;
122
+ }
123
+ /**
124
+ * Get a ticket by ID
125
+ */
126
+ export async function getTicket(id) {
127
+ const db = getDb();
128
+ if (!db)
129
+ throw new Error("Database not initialized");
130
+ const result = await db
131
+ .select()
132
+ .from(tickets)
133
+ .where(eq(tickets.id, id))
134
+ .limit(1);
135
+ if (result.length === 0)
136
+ return null;
137
+ const row = result[0];
138
+ return rowToTicket(row);
139
+ }
140
+ /**
141
+ * Get children of a ticket (for epics/parent tickets)
142
+ */
143
+ export async function getChildren(parentId) {
144
+ const db = getDb();
145
+ if (!db)
146
+ throw new Error("Database not initialized");
147
+ const rows = await db
148
+ .select()
149
+ .from(tickets)
150
+ .where(eq(tickets.parentId, parentId))
151
+ .orderBy(asc(tickets.sequence));
152
+ return rows.map(rowToTicket);
153
+ }
154
+ /**
155
+ * Get a ticket with all relations
156
+ */
157
+ export async function getTicketWithRelations(id) {
158
+ const ticket = await getTicket(id);
159
+ if (!ticket)
160
+ return null;
161
+ const [externalLinks, relations, watchers, assignees, mentions, attachments, reactions, comments, history, children, parent,] = await Promise.all([
162
+ getExternalLinks(id),
163
+ getTicketRelations(id),
164
+ getTicketWatchers(id),
165
+ getTicketAssignees(id),
166
+ getTicketMentions(id),
167
+ getTicketAttachments(id),
168
+ getTicketReactions(id),
169
+ getComments(id),
170
+ getHistory(id),
171
+ getChildren(id),
172
+ ticket.parentId ? getTicket(ticket.parentId) : Promise.resolve(null),
173
+ ]);
174
+ return {
175
+ ...ticket,
176
+ externalLinks,
177
+ relations,
178
+ watchers,
179
+ assignees,
180
+ mentions,
181
+ attachments,
182
+ reactions,
183
+ comments,
184
+ history,
185
+ children,
186
+ parent: parent ?? undefined,
187
+ };
188
+ }
189
+ /**
190
+ * Update a ticket
191
+ */
192
+ export async function updateTicket(id, input) {
193
+ const parsed = UpdateTicketSchema.parse(input);
194
+ const db = getDb();
195
+ if (!db)
196
+ throw new Error("Database not initialized");
197
+ const existing = await getTicket(id);
198
+ if (!existing)
199
+ return null;
200
+ const updates = {
201
+ updatedAt: new Date(),
202
+ };
203
+ // Track changes for history
204
+ const changes = [];
205
+ if (parsed.title !== undefined && parsed.title !== existing.title) {
206
+ updates.title = parsed.title;
207
+ changes.push({
208
+ field: "title",
209
+ oldValue: existing.title,
210
+ newValue: parsed.title,
211
+ });
212
+ }
213
+ if (parsed.description !== undefined &&
214
+ parsed.description !== existing.description) {
215
+ updates.description = parsed.description;
216
+ changes.push({
217
+ field: "description",
218
+ oldValue: existing.description,
219
+ newValue: parsed.description,
220
+ });
221
+ }
222
+ if (parsed.type !== undefined && parsed.type !== existing.type) {
223
+ updates.type = parsed.type;
224
+ changes.push({
225
+ field: "type",
226
+ oldValue: existing.type,
227
+ newValue: parsed.type,
228
+ });
229
+ }
230
+ if (parsed.priority !== undefined && parsed.priority !== existing.priority) {
231
+ updates.priority = parsed.priority;
232
+ changes.push({
233
+ field: "priority",
234
+ oldValue: existing.priority,
235
+ newValue: parsed.priority,
236
+ });
237
+ }
238
+ if (parsed.status !== undefined && parsed.status !== existing.status) {
239
+ updates.status = parsed.status;
240
+ changes.push({
241
+ field: "status",
242
+ oldValue: existing.status,
243
+ newValue: parsed.status,
244
+ });
245
+ // Auto-set timestamps based on status
246
+ if (parsed.status === "in_progress" && !existing.startedAt) {
247
+ updates.startedAt = new Date();
248
+ }
249
+ if (parsed.status === "done" || parsed.status === "cancelled") {
250
+ updates.completedAt = new Date();
251
+ }
252
+ }
253
+ if (parsed.labels !== undefined) {
254
+ updates.labels = parsed.labels;
255
+ changes.push({
256
+ field: "labels",
257
+ oldValue: JSON.stringify(existing.labels),
258
+ newValue: JSON.stringify(parsed.labels),
259
+ });
260
+ }
261
+ if (parsed.assignee !== undefined && parsed.assignee !== existing.assignee) {
262
+ updates.assignee = parsed.assignee;
263
+ changes.push({
264
+ field: "assignee",
265
+ oldValue: existing.assignee,
266
+ newValue: parsed.assignee,
267
+ });
268
+ }
269
+ if (parsed.assigneeAgent !== undefined &&
270
+ parsed.assigneeAgent !== existing.assigneeAgent) {
271
+ updates.assigneeAgent = parsed.assigneeAgent;
272
+ changes.push({
273
+ field: "assigneeAgent",
274
+ oldValue: existing.assigneeAgent,
275
+ newValue: parsed.assigneeAgent,
276
+ });
277
+ }
278
+ if (parsed.parentId !== undefined && parsed.parentId !== existing.parentId) {
279
+ updates.parentId = parsed.parentId;
280
+ changes.push({
281
+ field: "parentId",
282
+ oldValue: existing.parentId,
283
+ newValue: parsed.parentId,
284
+ });
285
+ }
286
+ if (parsed.dueDate !== undefined) {
287
+ updates.dueDate = parsed.dueDate ? new Date(parsed.dueDate) : null;
288
+ changes.push({
289
+ field: "dueDate",
290
+ oldValue: existing.dueDate,
291
+ newValue: parsed.dueDate,
292
+ });
293
+ }
294
+ if (parsed.startDate !== undefined) {
295
+ updates.startDate = parsed.startDate ? new Date(parsed.startDate) : null;
296
+ changes.push({
297
+ field: "startDate",
298
+ oldValue: existing.startDate,
299
+ newValue: parsed.startDate,
300
+ });
301
+ }
302
+ if (parsed.estimate !== undefined) {
303
+ updates.estimate = parsed.estimate;
304
+ }
305
+ if (parsed.estimateUnit !== undefined) {
306
+ updates.estimateUnit = parsed.estimateUnit;
307
+ }
308
+ if (parsed.projectId !== undefined &&
309
+ parsed.projectId !== existing.projectId) {
310
+ updates.projectId = parsed.projectId;
311
+ changes.push({
312
+ field: "projectId",
313
+ oldValue: existing.projectId,
314
+ newValue: parsed.projectId,
315
+ });
316
+ }
317
+ await db.update(tickets).set(updates).where(eq(tickets.id, id));
318
+ // Record history for each change
319
+ for (const change of changes) {
320
+ await recordHistory(id, change.field, change.oldValue, change.newValue, {
321
+ type: "human",
322
+ name: "User",
323
+ platform: "profclaw",
324
+ });
325
+ }
326
+ // Trigger outbound sync (fire-and-forget)
327
+ if (syncCallbacks.onTicketChanged && changes.length > 0) {
328
+ syncCallbacks.onTicketChanged(id, parsed).catch((err) => {
329
+ logger.error("[TicketService] Sync callback error", err);
330
+ });
331
+ }
332
+ return getTicket(id);
333
+ }
334
+ /**
335
+ * Delete a ticket
336
+ */
337
+ export async function deleteTicket(id) {
338
+ const db = getDb();
339
+ if (!db)
340
+ throw new Error("Database not initialized");
341
+ // Delete related records first
342
+ await db
343
+ .delete(ticketExternalLinks)
344
+ .where(eq(ticketExternalLinks.ticketId, id));
345
+ await db
346
+ .delete(ticketRelations)
347
+ .where(or(eq(ticketRelations.sourceTicketId, id), eq(ticketRelations.targetTicketId, id)));
348
+ await db.delete(ticketComments).where(eq(ticketComments.ticketId, id));
349
+ await db.delete(ticketHistory).where(eq(ticketHistory.ticketId, id));
350
+ await db.delete(ticketWatchers).where(eq(ticketWatchers.ticketId, id));
351
+ await db.delete(ticketAssignees).where(eq(ticketAssignees.ticketId, id));
352
+ await db.delete(ticketMentions).where(eq(ticketMentions.ticketId, id));
353
+ await db.delete(ticketAttachments).where(eq(ticketAttachments.ticketId, id));
354
+ await db.delete(ticketReactions).where(eq(ticketReactions.ticketId, id));
355
+ await db.delete(tickets).where(eq(tickets.id, id));
356
+ return true;
357
+ }
358
+ // === Bulk Operations ===
359
+ export async function bulkUpdateTickets(input) {
360
+ const parsed = BulkUpdateTicketsSchema.parse(input);
361
+ const updated = [];
362
+ const failed = [];
363
+ for (const id of parsed.ids) {
364
+ try {
365
+ const ticket = await updateTicket(id, parsed.updates);
366
+ if (ticket) {
367
+ updated.push(ticket);
368
+ }
369
+ else {
370
+ failed.push({ id, error: "Ticket not found" });
371
+ }
372
+ }
373
+ catch (error) {
374
+ failed.push({
375
+ id,
376
+ error: error instanceof Error ? error.message : "Unknown error",
377
+ });
378
+ }
379
+ }
380
+ return { updated, failed };
381
+ }
382
+ export async function bulkDeleteTickets(input) {
383
+ const parsed = BulkDeleteTicketsSchema.parse(input);
384
+ const deletedIds = [];
385
+ const failed = [];
386
+ for (const id of parsed.ids) {
387
+ try {
388
+ const deleted = await deleteTicket(id);
389
+ if (deleted) {
390
+ deletedIds.push(id);
391
+ }
392
+ else {
393
+ failed.push({ id, error: "Ticket not found" });
394
+ }
395
+ }
396
+ catch (error) {
397
+ failed.push({
398
+ id,
399
+ error: error instanceof Error ? error.message : "Unknown error",
400
+ });
401
+ }
402
+ }
403
+ return { deletedIds, failed };
404
+ }
405
+ /**
406
+ * Query tickets with filters
407
+ */
408
+ export async function queryTickets(query = {}) {
409
+ const parsed = TicketQuerySchema.parse(query);
410
+ const db = getDb();
411
+ if (!db)
412
+ throw new Error("Database not initialized");
413
+ const conditions = [];
414
+ // Project filter
415
+ if (parsed.projectId) {
416
+ conditions.push(eq(tickets.projectId, parsed.projectId));
417
+ }
418
+ // Status filter
419
+ if (parsed.status) {
420
+ const statuses = Array.isArray(parsed.status)
421
+ ? parsed.status
422
+ : [parsed.status];
423
+ conditions.push(inArray(tickets.status, statuses));
424
+ }
425
+ // Type filter
426
+ if (parsed.type) {
427
+ const types = Array.isArray(parsed.type) ? parsed.type : [parsed.type];
428
+ conditions.push(inArray(tickets.type, types));
429
+ }
430
+ // Priority filter
431
+ if (parsed.priority) {
432
+ const priorities = Array.isArray(parsed.priority)
433
+ ? parsed.priority
434
+ : [parsed.priority];
435
+ conditions.push(inArray(tickets.priority, priorities));
436
+ }
437
+ // Assignee filter
438
+ if (parsed.assignee) {
439
+ conditions.push(eq(tickets.assignee, parsed.assignee));
440
+ }
441
+ // Agent filter
442
+ if (parsed.assigneeAgent) {
443
+ conditions.push(eq(tickets.assigneeAgent, parsed.assigneeAgent));
444
+ }
445
+ // Parent filter
446
+ if (parsed.parentId) {
447
+ conditions.push(eq(tickets.parentId, parsed.parentId));
448
+ }
449
+ // Search
450
+ if (parsed.search) {
451
+ const searchCond = or(like(tickets.title, `%${parsed.search}%`), like(tickets.description, `%${parsed.search}%`));
452
+ if (searchCond)
453
+ conditions.push(searchCond);
454
+ }
455
+ // Date filters
456
+ if (parsed.createdAfter) {
457
+ conditions.push(gte(tickets.createdAt, new Date(parsed.createdAfter)));
458
+ }
459
+ if (parsed.createdBefore) {
460
+ conditions.push(lte(tickets.createdAt, new Date(parsed.createdBefore)));
461
+ }
462
+ if (parsed.startDateAfter) {
463
+ conditions.push(gte(tickets.startDate, new Date(parsed.startDateAfter)));
464
+ }
465
+ if (parsed.startDateBefore) {
466
+ conditions.push(lte(tickets.startDate, new Date(parsed.startDateBefore)));
467
+ }
468
+ // CreatedBy filter (human vs ai)
469
+ if (parsed.createdBy) {
470
+ conditions.push(eq(tickets.createdBy, parsed.createdBy));
471
+ }
472
+ // Single label filter (case-insensitive search in labels JSON array)
473
+ if (parsed.label) {
474
+ // SQLite JSON contains search - labels is stored as JSON array
475
+ conditions.push(sql `EXISTS (SELECT 1 FROM json_each(${tickets.labels}) WHERE json_each.value LIKE ${`%${parsed.label}%`})`);
476
+ }
477
+ // Multiple labels filter
478
+ if (parsed.labels && parsed.labels.length > 0) {
479
+ // All specified labels must be present
480
+ for (const label of parsed.labels) {
481
+ conditions.push(sql `EXISTS (SELECT 1 FROM json_each(${tickets.labels}) WHERE json_each.value LIKE ${`%${label}%`})`);
482
+ }
483
+ }
484
+ // Cursor-based pagination (Phase 17)
485
+ // When cursor is provided, filter for items "after" the cursor
486
+ // For DESC order: createdAt < cursorCreatedAt OR (createdAt = cursorCreatedAt AND id < cursorId)
487
+ // For ASC order: createdAt > cursorCreatedAt OR (createdAt = cursorCreatedAt AND id > cursorId)
488
+ if (parsed.cursorCreatedAt && parsed.cursorId) {
489
+ const cursorTime = parsed.cursorCreatedAt;
490
+ const cursorId = parsed.cursorId;
491
+ const isDesc = parsed.sortOrder !== "asc";
492
+ if (isDesc) {
493
+ const cond = or(sql `${tickets.createdAt} < ${cursorTime}`, and(sql `${tickets.createdAt} = ${cursorTime}`, sql `${tickets.id} < ${cursorId}`));
494
+ if (cond)
495
+ conditions.push(cond);
496
+ }
497
+ else {
498
+ const cond = or(sql `${tickets.createdAt} > ${cursorTime}`, and(sql `${tickets.createdAt} = ${cursorTime}`, sql `${tickets.id} > ${cursorId}`));
499
+ if (cond)
500
+ conditions.push(cond);
501
+ }
502
+ }
503
+ // Build where clause
504
+ let whereClause = conditions.length > 0 ? and(...conditions) : undefined;
505
+ // Handle sprint filtering - requires subquery or join
506
+ let ticketIdsToFilter = [];
507
+ if (parsed.sprintId) {
508
+ // Get ticket IDs in this sprint
509
+ const sprintTicketRows = await db
510
+ .select({ ticketId: sprintTickets.ticketId })
511
+ .from(sprintTickets)
512
+ .where(eq(sprintTickets.sprintId, parsed.sprintId));
513
+ ticketIdsToFilter = sprintTicketRows.map((r) => r.ticketId);
514
+ if (ticketIdsToFilter.length === 0) {
515
+ return { tickets: [], total: 0 };
516
+ }
517
+ // Add IN condition for sprint tickets
518
+ conditions.push(inArray(tickets.id, ticketIdsToFilter));
519
+ whereClause = and(...conditions);
520
+ }
521
+ else if (parsed.inBacklog) {
522
+ // Get all ticket IDs that ARE in a sprint, then exclude them
523
+ const ticketsInSprints = await db
524
+ .selectDistinct({ ticketId: sprintTickets.ticketId })
525
+ .from(sprintTickets);
526
+ const excludeIds = ticketsInSprints.map((r) => r.ticketId);
527
+ if (excludeIds.length > 0) {
528
+ // Add NOT IN condition
529
+ conditions.push(sql `${tickets.id} NOT IN (${sql.join(excludeIds.map((id) => sql `${id}`), sql `, `)})`);
530
+ whereClause = and(...conditions);
531
+ }
532
+ }
533
+ // Get total count
534
+ const countResult = await db
535
+ .select({ count: sql `count(*)` })
536
+ .from(tickets)
537
+ .where(whereClause);
538
+ const total = countResult[0]?.count ?? 0;
539
+ // Sorting
540
+ const sortColumn = parsed.sortBy === "priority"
541
+ ? tickets.priority
542
+ : parsed.sortBy === "updatedAt"
543
+ ? tickets.updatedAt
544
+ : parsed.sortBy === "sequence"
545
+ ? tickets.sequence
546
+ : parsed.sortBy === "dueDate"
547
+ ? tickets.dueDate
548
+ : parsed.sortBy === "startDate"
549
+ ? tickets.startDate
550
+ : tickets.createdAt;
551
+ const sortOrder = parsed.sortOrder === "asc" ? asc(sortColumn) : desc(sortColumn);
552
+ // Pagination
553
+ const limit = parsed.limit || 50;
554
+ const offset = parsed.offset || 0;
555
+ const useCursor = !!(parsed.cursorCreatedAt && parsed.cursorId);
556
+ // When using cursor, don't use offset (cursor already filters)
557
+ const rows = useCursor
558
+ ? await db
559
+ .select()
560
+ .from(tickets)
561
+ .where(whereClause)
562
+ .orderBy(sortOrder)
563
+ .limit(limit)
564
+ : await db
565
+ .select()
566
+ .from(tickets)
567
+ .where(whereClause)
568
+ .orderBy(sortOrder)
569
+ .limit(limit)
570
+ .offset(offset);
571
+ return {
572
+ tickets: rows.map(rowToTicket),
573
+ total,
574
+ };
575
+ }
576
+ // === Relations ===
577
+ export async function createTicketRelation(sourceTicketId, targetTicketId, relationType) {
578
+ const db = getDb();
579
+ if (!db)
580
+ throw new Error("Database not initialized");
581
+ const id = generateId();
582
+ const now = new Date().toISOString();
583
+ await db.insert(ticketRelations).values({
584
+ id,
585
+ sourceTicketId,
586
+ targetTicketId,
587
+ relationType,
588
+ });
589
+ return {
590
+ id,
591
+ sourceTicketId,
592
+ targetTicketId,
593
+ relationType,
594
+ createdAt: now,
595
+ };
596
+ }
597
+ export async function getTicketRelations(ticketId) {
598
+ const db = getDb();
599
+ if (!db)
600
+ throw new Error("Database not initialized");
601
+ const rows = await db
602
+ .select()
603
+ .from(ticketRelations)
604
+ .where(or(eq(ticketRelations.sourceTicketId, ticketId), eq(ticketRelations.targetTicketId, ticketId)))
605
+ .orderBy(desc(ticketRelations.createdAt));
606
+ return rows.map((row) => ({
607
+ id: row.id,
608
+ sourceTicketId: row.sourceTicketId,
609
+ targetTicketId: row.targetTicketId,
610
+ relationType: row.relationType,
611
+ createdAt: toISOString(row.createdAt),
612
+ }));
613
+ }
614
+ export async function deleteTicketRelation(relationId, ticketId) {
615
+ const db = getDb();
616
+ if (!db)
617
+ throw new Error("Database not initialized");
618
+ const conditions = [eq(ticketRelations.id, relationId)];
619
+ if (ticketId) {
620
+ const relationScope = or(eq(ticketRelations.sourceTicketId, ticketId), eq(ticketRelations.targetTicketId, ticketId));
621
+ if (relationScope) {
622
+ conditions.push(relationScope);
623
+ }
624
+ }
625
+ const existing = await db
626
+ .select({ id: ticketRelations.id })
627
+ .from(ticketRelations)
628
+ .where(and(...conditions))
629
+ .limit(1);
630
+ if (existing.length === 0)
631
+ return false;
632
+ await db.delete(ticketRelations).where(eq(ticketRelations.id, relationId));
633
+ return true;
634
+ }
635
+ // === Watchers ===
636
+ export async function addTicketWatcher(ticketId, userId) {
637
+ const db = getDb();
638
+ if (!db)
639
+ throw new Error("Database not initialized");
640
+ const existing = await db
641
+ .select({ id: ticketWatchers.id })
642
+ .from(ticketWatchers)
643
+ .where(and(eq(ticketWatchers.ticketId, ticketId), eq(ticketWatchers.userId, userId)))
644
+ .limit(1);
645
+ if (existing.length > 0) {
646
+ const row = existing[0];
647
+ return {
648
+ id: row.id,
649
+ ticketId,
650
+ userId,
651
+ createdAt: new Date().toISOString(),
652
+ };
653
+ }
654
+ const id = generateId();
655
+ const now = new Date().toISOString();
656
+ await db.insert(ticketWatchers).values({
657
+ id,
658
+ ticketId,
659
+ userId,
660
+ });
661
+ return { id, ticketId, userId, createdAt: now };
662
+ }
663
+ export async function removeTicketWatcher(ticketId, userId) {
664
+ const db = getDb();
665
+ if (!db)
666
+ throw new Error("Database not initialized");
667
+ const existing = await db
668
+ .select({ id: ticketWatchers.id })
669
+ .from(ticketWatchers)
670
+ .where(and(eq(ticketWatchers.ticketId, ticketId), eq(ticketWatchers.userId, userId)))
671
+ .limit(1);
672
+ if (existing.length === 0)
673
+ return false;
674
+ await db
675
+ .delete(ticketWatchers)
676
+ .where(and(eq(ticketWatchers.ticketId, ticketId), eq(ticketWatchers.userId, userId)));
677
+ return true;
678
+ }
679
+ export async function getTicketWatchers(ticketId) {
680
+ const db = getDb();
681
+ if (!db)
682
+ throw new Error("Database not initialized");
683
+ const rows = await db
684
+ .select()
685
+ .from(ticketWatchers)
686
+ .where(eq(ticketWatchers.ticketId, ticketId))
687
+ .orderBy(desc(ticketWatchers.createdAt));
688
+ return rows.map((row) => ({
689
+ id: row.id,
690
+ ticketId: row.ticketId,
691
+ userId: row.userId,
692
+ createdAt: toISOString(row.createdAt),
693
+ }));
694
+ }
695
+ // === Assignees ===
696
+ export async function addTicketAssignee(ticketId, userId) {
697
+ const db = getDb();
698
+ if (!db)
699
+ throw new Error("Database not initialized");
700
+ const existing = await db
701
+ .select({ id: ticketAssignees.id })
702
+ .from(ticketAssignees)
703
+ .where(and(eq(ticketAssignees.ticketId, ticketId), eq(ticketAssignees.userId, userId)))
704
+ .limit(1);
705
+ if (existing.length > 0) {
706
+ const row = existing[0];
707
+ return {
708
+ id: row.id,
709
+ ticketId,
710
+ userId,
711
+ createdAt: new Date().toISOString(),
712
+ };
713
+ }
714
+ const id = generateId();
715
+ const now = new Date().toISOString();
716
+ await db.insert(ticketAssignees).values({
717
+ id,
718
+ ticketId,
719
+ userId,
720
+ });
721
+ return { id, ticketId, userId, createdAt: now };
722
+ }
723
+ export async function removeTicketAssignee(ticketId, userId) {
724
+ const db = getDb();
725
+ if (!db)
726
+ throw new Error("Database not initialized");
727
+ const existing = await db
728
+ .select({ id: ticketAssignees.id })
729
+ .from(ticketAssignees)
730
+ .where(and(eq(ticketAssignees.ticketId, ticketId), eq(ticketAssignees.userId, userId)))
731
+ .limit(1);
732
+ if (existing.length === 0)
733
+ return false;
734
+ await db
735
+ .delete(ticketAssignees)
736
+ .where(and(eq(ticketAssignees.ticketId, ticketId), eq(ticketAssignees.userId, userId)));
737
+ return true;
738
+ }
739
+ export async function getTicketAssignees(ticketId) {
740
+ const db = getDb();
741
+ if (!db)
742
+ throw new Error("Database not initialized");
743
+ const rows = await db
744
+ .select()
745
+ .from(ticketAssignees)
746
+ .where(eq(ticketAssignees.ticketId, ticketId))
747
+ .orderBy(desc(ticketAssignees.createdAt));
748
+ return rows.map((row) => ({
749
+ id: row.id,
750
+ ticketId: row.ticketId,
751
+ userId: row.userId,
752
+ createdAt: toISOString(row.createdAt),
753
+ }));
754
+ }
755
+ // === Mentions ===
756
+ export async function addTicketMention(params) {
757
+ const db = getDb();
758
+ if (!db)
759
+ throw new Error("Database not initialized");
760
+ const id = generateId();
761
+ const now = new Date().toISOString();
762
+ await db.insert(ticketMentions).values({
763
+ id,
764
+ ticketId: params.ticketId,
765
+ userId: params.userId,
766
+ source: params.source,
767
+ sourceId: params.sourceId,
768
+ });
769
+ return {
770
+ id,
771
+ ticketId: params.ticketId,
772
+ userId: params.userId,
773
+ source: params.source,
774
+ sourceId: params.sourceId,
775
+ createdAt: now,
776
+ };
777
+ }
778
+ export async function getTicketMentions(ticketId) {
779
+ const db = getDb();
780
+ if (!db)
781
+ throw new Error("Database not initialized");
782
+ const rows = await db
783
+ .select()
784
+ .from(ticketMentions)
785
+ .where(eq(ticketMentions.ticketId, ticketId))
786
+ .orderBy(desc(ticketMentions.createdAt));
787
+ return rows.map((row) => ({
788
+ id: row.id,
789
+ ticketId: row.ticketId,
790
+ userId: row.userId,
791
+ source: row.source,
792
+ sourceId: row.sourceId ?? undefined,
793
+ createdAt: toISOString(row.createdAt),
794
+ }));
795
+ }
796
+ // === Attachments ===
797
+ export async function addTicketAttachment(params) {
798
+ const db = getDb();
799
+ if (!db)
800
+ throw new Error("Database not initialized");
801
+ const id = generateId();
802
+ const now = new Date().toISOString();
803
+ await db.insert(ticketAttachments).values({
804
+ id,
805
+ ticketId: params.ticketId,
806
+ fileName: params.fileName,
807
+ fileType: params.fileType,
808
+ fileSize: params.fileSize,
809
+ url: params.url,
810
+ storagePath: params.storagePath,
811
+ uploadedBy: params.uploadedBy,
812
+ });
813
+ return {
814
+ id,
815
+ ticketId: params.ticketId,
816
+ fileName: params.fileName,
817
+ fileType: params.fileType,
818
+ fileSize: params.fileSize,
819
+ url: params.url,
820
+ storagePath: params.storagePath,
821
+ uploadedBy: params.uploadedBy,
822
+ createdAt: now,
823
+ };
824
+ }
825
+ export async function getTicketAttachments(ticketId) {
826
+ const db = getDb();
827
+ if (!db)
828
+ throw new Error("Database not initialized");
829
+ const rows = await db
830
+ .select()
831
+ .from(ticketAttachments)
832
+ .where(eq(ticketAttachments.ticketId, ticketId))
833
+ .orderBy(desc(ticketAttachments.createdAt));
834
+ return rows.map((row) => ({
835
+ id: row.id,
836
+ ticketId: row.ticketId,
837
+ fileName: row.fileName,
838
+ fileType: row.fileType ?? undefined,
839
+ fileSize: row.fileSize ?? undefined,
840
+ url: row.url,
841
+ storagePath: row.storagePath ?? undefined,
842
+ uploadedBy: row.uploadedBy ?? undefined,
843
+ createdAt: toISOString(row.createdAt),
844
+ }));
845
+ }
846
+ export async function deleteTicketAttachment(attachmentId, ticketId) {
847
+ const db = getDb();
848
+ if (!db)
849
+ throw new Error("Database not initialized");
850
+ const conditions = [eq(ticketAttachments.id, attachmentId)];
851
+ if (ticketId) {
852
+ conditions.push(eq(ticketAttachments.ticketId, ticketId));
853
+ }
854
+ const existing = await db
855
+ .select({ id: ticketAttachments.id })
856
+ .from(ticketAttachments)
857
+ .where(and(...conditions))
858
+ .limit(1);
859
+ if (existing.length === 0)
860
+ return false;
861
+ await db
862
+ .delete(ticketAttachments)
863
+ .where(eq(ticketAttachments.id, attachmentId));
864
+ return true;
865
+ }
866
+ // === Reactions ===
867
+ export async function addTicketReaction(params) {
868
+ const db = getDb();
869
+ if (!db)
870
+ throw new Error("Database not initialized");
871
+ const existing = await db
872
+ .select({ id: ticketReactions.id })
873
+ .from(ticketReactions)
874
+ .where(and(eq(ticketReactions.ticketId, params.ticketId), eq(ticketReactions.userId, params.userId), eq(ticketReactions.emoji, params.emoji)))
875
+ .limit(1);
876
+ if (existing.length > 0) {
877
+ const row = existing[0];
878
+ return {
879
+ id: row.id,
880
+ ticketId: params.ticketId,
881
+ userId: params.userId,
882
+ emoji: params.emoji,
883
+ createdAt: new Date().toISOString(),
884
+ };
885
+ }
886
+ const id = generateId();
887
+ const now = new Date().toISOString();
888
+ await db.insert(ticketReactions).values({
889
+ id,
890
+ ticketId: params.ticketId,
891
+ userId: params.userId,
892
+ emoji: params.emoji,
893
+ });
894
+ return {
895
+ id,
896
+ ticketId: params.ticketId,
897
+ userId: params.userId,
898
+ emoji: params.emoji,
899
+ createdAt: now,
900
+ };
901
+ }
902
+ export async function getTicketReactions(ticketId) {
903
+ const db = getDb();
904
+ if (!db)
905
+ throw new Error("Database not initialized");
906
+ const rows = await db
907
+ .select()
908
+ .from(ticketReactions)
909
+ .where(eq(ticketReactions.ticketId, ticketId))
910
+ .orderBy(desc(ticketReactions.createdAt));
911
+ return rows.map((row) => ({
912
+ id: row.id,
913
+ ticketId: row.ticketId,
914
+ userId: row.userId,
915
+ emoji: row.emoji,
916
+ createdAt: toISOString(row.createdAt),
917
+ }));
918
+ }
919
+ export async function deleteTicketReaction(reactionId, ticketId) {
920
+ const db = getDb();
921
+ if (!db)
922
+ throw new Error("Database not initialized");
923
+ const conditions = [eq(ticketReactions.id, reactionId)];
924
+ if (ticketId) {
925
+ conditions.push(eq(ticketReactions.ticketId, ticketId));
926
+ }
927
+ const existing = await db
928
+ .select({ id: ticketReactions.id })
929
+ .from(ticketReactions)
930
+ .where(and(...conditions))
931
+ .limit(1);
932
+ if (existing.length === 0)
933
+ return false;
934
+ await db.delete(ticketReactions).where(eq(ticketReactions.id, reactionId));
935
+ return true;
936
+ }
937
+ // === External Links ===
938
+ export async function createExternalLink(ticketId, link) {
939
+ const db = getDb();
940
+ if (!db)
941
+ throw new Error("Database not initialized");
942
+ const id = generateId();
943
+ const now = new Date().toISOString();
944
+ await db.insert(ticketExternalLinks).values({
945
+ id,
946
+ ticketId,
947
+ platform: link.platform,
948
+ externalId: link.externalId,
949
+ externalUrl: link.externalUrl,
950
+ });
951
+ return {
952
+ id,
953
+ ticketId,
954
+ platform: link.platform,
955
+ externalId: link.externalId,
956
+ externalUrl: link.externalUrl,
957
+ syncEnabled: true,
958
+ syncDirection: "bidirectional",
959
+ createdAt: now,
960
+ };
961
+ }
962
+ export async function getExternalLinks(ticketId) {
963
+ const db = getDb();
964
+ if (!db)
965
+ throw new Error("Database not initialized");
966
+ const rows = await db
967
+ .select()
968
+ .from(ticketExternalLinks)
969
+ .where(eq(ticketExternalLinks.ticketId, ticketId));
970
+ return rows.map((row) => ({
971
+ id: row.id,
972
+ ticketId: row.ticketId,
973
+ platform: row.platform,
974
+ externalId: row.externalId,
975
+ externalUrl: row.externalUrl ?? undefined,
976
+ syncEnabled: row.syncEnabled,
977
+ syncDirection: row.syncDirection,
978
+ lastSyncedAt: toOptionalISOString(row.lastSyncedAt),
979
+ syncError: row.syncError ?? undefined,
980
+ createdAt: toISOString(row.createdAt),
981
+ }));
982
+ }
983
+ // === Comments ===
984
+ export async function addComment(ticketId, content, author) {
985
+ const db = getDb();
986
+ if (!db)
987
+ throw new Error("Database not initialized");
988
+ const id = generateId();
989
+ const now = new Date().toISOString();
990
+ await db.insert(ticketComments).values({
991
+ id,
992
+ ticketId,
993
+ content,
994
+ authorType: author.type,
995
+ authorName: author.name,
996
+ authorPlatform: author.platform,
997
+ source: author.platform,
998
+ isAiResponse: author.type === "ai",
999
+ });
1000
+ // Trigger outbound sync (fire-and-forget)
1001
+ if (syncCallbacks.onCommentCreated) {
1002
+ syncCallbacks
1003
+ .onCommentCreated(ticketId, content, author.platform)
1004
+ .catch((err) => {
1005
+ logger.error("[TicketService] Comment sync callback error", err);
1006
+ });
1007
+ }
1008
+ return {
1009
+ id,
1010
+ ticketId,
1011
+ content,
1012
+ author: { type: author.type, name: author.name, platform: author.platform },
1013
+ source: author.platform,
1014
+ isAiResponse: author.type === "ai",
1015
+ createdAt: now,
1016
+ };
1017
+ }
1018
+ export async function getComments(ticketId) {
1019
+ const db = getDb();
1020
+ if (!db)
1021
+ throw new Error("Database not initialized");
1022
+ const rows = await db
1023
+ .select()
1024
+ .from(ticketComments)
1025
+ .where(eq(ticketComments.ticketId, ticketId))
1026
+ .orderBy(asc(ticketComments.createdAt));
1027
+ return rows.map((row) => ({
1028
+ id: row.id,
1029
+ ticketId: row.ticketId,
1030
+ content: row.content,
1031
+ contentHtml: row.contentHtml ?? undefined,
1032
+ author: {
1033
+ type: row.authorType,
1034
+ name: row.authorName,
1035
+ platform: row.authorPlatform,
1036
+ avatarUrl: row.authorAvatarUrl ?? undefined,
1037
+ },
1038
+ source: row.source,
1039
+ externalId: row.externalId ?? undefined,
1040
+ isAiResponse: row.isAiResponse,
1041
+ respondingTo: row.respondingTo ?? undefined,
1042
+ createdAt: toISOString(row.createdAt),
1043
+ updatedAt: toOptionalISOString(row.updatedAt),
1044
+ }));
1045
+ }
1046
+ // === History ===
1047
+ async function recordHistory(ticketId, field, oldValue, newValue, changedBy) {
1048
+ const db = getDb();
1049
+ if (!db)
1050
+ return;
1051
+ await db.insert(ticketHistory).values({
1052
+ id: generateId(),
1053
+ ticketId,
1054
+ field,
1055
+ oldValue,
1056
+ newValue,
1057
+ changedByType: changedBy.type,
1058
+ changedByName: changedBy.name,
1059
+ changedByPlatform: changedBy.platform,
1060
+ });
1061
+ }
1062
+ export async function getHistory(ticketId) {
1063
+ const db = getDb();
1064
+ if (!db)
1065
+ throw new Error("Database not initialized");
1066
+ const rows = await db
1067
+ .select()
1068
+ .from(ticketHistory)
1069
+ .where(eq(ticketHistory.ticketId, ticketId))
1070
+ .orderBy(desc(ticketHistory.timestamp));
1071
+ return rows.map((row) => ({
1072
+ id: row.id,
1073
+ ticketId: row.ticketId,
1074
+ field: row.field,
1075
+ oldValue: row.oldValue ?? undefined,
1076
+ newValue: row.newValue ?? undefined,
1077
+ changedBy: {
1078
+ type: row.changedByType,
1079
+ name: row.changedByName,
1080
+ platform: row.changedByPlatform,
1081
+ },
1082
+ timestamp: toISOString(row.timestamp),
1083
+ }));
1084
+ }
1085
+ // === Sync Helpers ===
1086
+ /**
1087
+ * Get a ticket by its external link (for sync engine)
1088
+ */
1089
+ export async function getTicketByExternalLink(platform, externalId) {
1090
+ const db = getDb();
1091
+ if (!db)
1092
+ throw new Error("Database not initialized");
1093
+ const links = await db
1094
+ .select()
1095
+ .from(ticketExternalLinks)
1096
+ .where(and(eq(ticketExternalLinks.platform, platform), eq(ticketExternalLinks.externalId, externalId)))
1097
+ .limit(1);
1098
+ if (links.length === 0)
1099
+ return null;
1100
+ return getTicket(links[0].ticketId);
1101
+ }
1102
+ /**
1103
+ * Update an external link (for sync engine)
1104
+ */
1105
+ export async function updateExternalLink(id, updates) {
1106
+ const db = getDb();
1107
+ if (!db)
1108
+ throw new Error("Database not initialized");
1109
+ const updateData = {};
1110
+ if (updates.lastSyncedAt)
1111
+ updateData.lastSyncedAt = new Date(updates.lastSyncedAt);
1112
+ if (updates.syncError !== undefined)
1113
+ updateData.syncError = updates.syncError || null;
1114
+ if (updates.syncEnabled !== undefined)
1115
+ updateData.syncEnabled = updates.syncEnabled;
1116
+ await db
1117
+ .update(ticketExternalLinks)
1118
+ .set(updateData)
1119
+ .where(eq(ticketExternalLinks.id, id));
1120
+ }
1121
+ /**
1122
+ * Create a ticket from sync (with external link)
1123
+ */
1124
+ export async function createTicketFromSync(ticket, link) {
1125
+ const db = getDb();
1126
+ if (!db)
1127
+ throw new Error("Database not initialized");
1128
+ const id = generateId();
1129
+ const sequence = await getNextSequence();
1130
+ const newTicket = {
1131
+ ...ticket,
1132
+ id,
1133
+ sequence,
1134
+ };
1135
+ await db.insert(tickets).values({
1136
+ id: newTicket.id,
1137
+ sequence: newTicket.sequence,
1138
+ title: newTicket.title,
1139
+ description: newTicket.description,
1140
+ type: newTicket.type,
1141
+ priority: newTicket.priority,
1142
+ status: newTicket.status,
1143
+ labels: newTicket.labels,
1144
+ assignee: newTicket.assignee,
1145
+ assigneeAgent: newTicket.assigneeAgent,
1146
+ parentId: newTicket.parentId,
1147
+ linkedPRs: newTicket.linkedPRs,
1148
+ linkedCommits: newTicket.linkedCommits,
1149
+ createdBy: newTicket.createdBy,
1150
+ aiAgent: newTicket.aiAgent,
1151
+ aiSessionId: newTicket.aiSessionId,
1152
+ aiTaskId: newTicket.aiTaskId,
1153
+ startDate: newTicket.startDate,
1154
+ dueDate: newTicket.dueDate,
1155
+ estimate: newTicket.estimate,
1156
+ estimateUnit: newTicket.estimateUnit,
1157
+ });
1158
+ // Create external link
1159
+ await createExternalLink(id, link);
1160
+ // Record creation in history
1161
+ await recordHistory(id, "created", undefined, `synced from ${link.platform}`, {
1162
+ type: "human",
1163
+ name: link.platform,
1164
+ platform: link.platform,
1165
+ });
1166
+ return newTicket;
1167
+ }
1168
+ /**
1169
+ * Update a ticket from sync (with source tracking)
1170
+ */
1171
+ export async function updateTicketFromSync(id, updates, source) {
1172
+ const parsed = UpdateTicketSchema.parse(updates);
1173
+ const db = getDb();
1174
+ if (!db)
1175
+ throw new Error("Database not initialized");
1176
+ const existing = await getTicket(id);
1177
+ if (!existing)
1178
+ return null;
1179
+ const dbUpdates = {
1180
+ updatedAt: new Date(),
1181
+ };
1182
+ // Track changes for history
1183
+ const changes = [];
1184
+ if (parsed.title !== undefined && parsed.title !== existing.title) {
1185
+ dbUpdates.title = parsed.title;
1186
+ changes.push({
1187
+ field: "title",
1188
+ oldValue: existing.title,
1189
+ newValue: parsed.title,
1190
+ });
1191
+ }
1192
+ if (parsed.description !== undefined &&
1193
+ parsed.description !== existing.description) {
1194
+ dbUpdates.description = parsed.description;
1195
+ changes.push({
1196
+ field: "description",
1197
+ oldValue: existing.description,
1198
+ newValue: parsed.description,
1199
+ });
1200
+ }
1201
+ if (parsed.type !== undefined && parsed.type !== existing.type) {
1202
+ dbUpdates.type = parsed.type;
1203
+ changes.push({
1204
+ field: "type",
1205
+ oldValue: existing.type,
1206
+ newValue: parsed.type,
1207
+ });
1208
+ }
1209
+ if (parsed.priority !== undefined && parsed.priority !== existing.priority) {
1210
+ dbUpdates.priority = parsed.priority;
1211
+ changes.push({
1212
+ field: "priority",
1213
+ oldValue: existing.priority,
1214
+ newValue: parsed.priority,
1215
+ });
1216
+ }
1217
+ if (parsed.status !== undefined && parsed.status !== existing.status) {
1218
+ dbUpdates.status = parsed.status;
1219
+ changes.push({
1220
+ field: "status",
1221
+ oldValue: existing.status,
1222
+ newValue: parsed.status,
1223
+ });
1224
+ // Auto-set timestamps based on status
1225
+ if (parsed.status === "in_progress" && !existing.startedAt) {
1226
+ dbUpdates.startedAt = new Date();
1227
+ }
1228
+ if (parsed.status === "done" || parsed.status === "cancelled") {
1229
+ dbUpdates.completedAt = new Date();
1230
+ }
1231
+ }
1232
+ if (parsed.labels !== undefined) {
1233
+ dbUpdates.labels = parsed.labels;
1234
+ changes.push({
1235
+ field: "labels",
1236
+ oldValue: JSON.stringify(existing.labels),
1237
+ newValue: JSON.stringify(parsed.labels),
1238
+ });
1239
+ }
1240
+ if (parsed.assignee !== undefined && parsed.assignee !== existing.assignee) {
1241
+ dbUpdates.assignee = parsed.assignee;
1242
+ changes.push({
1243
+ field: "assignee",
1244
+ oldValue: existing.assignee,
1245
+ newValue: parsed.assignee,
1246
+ });
1247
+ }
1248
+ if (parsed.startDate !== undefined) {
1249
+ dbUpdates.startDate = parsed.startDate ? new Date(parsed.startDate) : null;
1250
+ changes.push({
1251
+ field: "startDate",
1252
+ oldValue: existing.startDate,
1253
+ newValue: parsed.startDate,
1254
+ });
1255
+ }
1256
+ if (parsed.dueDate !== undefined) {
1257
+ dbUpdates.dueDate = parsed.dueDate ? new Date(parsed.dueDate) : null;
1258
+ changes.push({
1259
+ field: "dueDate",
1260
+ oldValue: existing.dueDate,
1261
+ newValue: parsed.dueDate,
1262
+ });
1263
+ }
1264
+ if (parsed.startDate !== undefined) {
1265
+ dbUpdates.startDate = parsed.startDate ? new Date(parsed.startDate) : null;
1266
+ changes.push({
1267
+ field: "startDate",
1268
+ oldValue: existing.startDate,
1269
+ newValue: parsed.startDate,
1270
+ });
1271
+ }
1272
+ await db.update(tickets).set(dbUpdates).where(eq(tickets.id, id));
1273
+ // Record history with source
1274
+ for (const change of changes) {
1275
+ await recordHistory(id, change.field, change.oldValue, change.newValue, {
1276
+ type: "human",
1277
+ name: source,
1278
+ platform: source,
1279
+ });
1280
+ }
1281
+ return getTicket(id);
1282
+ }
1283
+ /**
1284
+ * Add a comment from sync (external source)
1285
+ */
1286
+ export async function addCommentFromSync(ticketId, content, author, externalId) {
1287
+ const db = getDb();
1288
+ if (!db)
1289
+ throw new Error("Database not initialized");
1290
+ const id = generateId();
1291
+ const now = new Date().toISOString();
1292
+ await db.insert(ticketComments).values({
1293
+ id,
1294
+ ticketId,
1295
+ content,
1296
+ authorType: author.type,
1297
+ authorName: author.name,
1298
+ authorPlatform: author.platform,
1299
+ source: author.platform,
1300
+ externalId,
1301
+ isAiResponse: author.type === "ai",
1302
+ });
1303
+ return {
1304
+ id,
1305
+ ticketId,
1306
+ content,
1307
+ author,
1308
+ source: author.platform,
1309
+ externalId,
1310
+ isAiResponse: author.type === "ai",
1311
+ createdAt: now,
1312
+ };
1313
+ }
1314
+ // === Helpers ===
1315
+ function toISOString(value) {
1316
+ if (!value)
1317
+ return new Date().toISOString();
1318
+ if (value instanceof Date) {
1319
+ const time = value.getTime();
1320
+ if (isNaN(time) || time < 0 || time > 8640000000000000) {
1321
+ return new Date().toISOString();
1322
+ }
1323
+ return value.toISOString();
1324
+ }
1325
+ if (typeof value === "number") {
1326
+ // Handle numeric timestamps (could be ms or seconds)
1327
+ const timestamp = value > 1e12 ? value : value * 1000; // Assume seconds if too small
1328
+ if (isNaN(timestamp) || timestamp < 0 || timestamp > 8640000000000000) {
1329
+ return new Date().toISOString();
1330
+ }
1331
+ return new Date(timestamp).toISOString();
1332
+ }
1333
+ if (typeof value === "string") {
1334
+ const date = new Date(value);
1335
+ const time = date.getTime();
1336
+ if (isNaN(time) || time < 0 || time > 8640000000000000) {
1337
+ return value; // Return original string if invalid
1338
+ }
1339
+ return date.toISOString();
1340
+ }
1341
+ return new Date().toISOString();
1342
+ }
1343
+ function toOptionalISOString(value) {
1344
+ if (!value)
1345
+ return undefined;
1346
+ if (value instanceof Date) {
1347
+ const time = value.getTime();
1348
+ if (isNaN(time) || time < 0 || time > 8640000000000000) {
1349
+ return undefined;
1350
+ }
1351
+ return value.toISOString();
1352
+ }
1353
+ if (typeof value === "number") {
1354
+ // Handle numeric timestamps (could be ms or seconds)
1355
+ const timestamp = value > 1e12 ? value : value * 1000;
1356
+ if (isNaN(timestamp) || timestamp < 0 || timestamp > 8640000000000000) {
1357
+ return undefined;
1358
+ }
1359
+ return new Date(timestamp).toISOString();
1360
+ }
1361
+ if (typeof value === "string") {
1362
+ const date = new Date(value);
1363
+ const time = date.getTime();
1364
+ if (isNaN(time) || time < 0 || time > 8640000000000000) {
1365
+ return value; // Return original string if invalid
1366
+ }
1367
+ return date.toISOString();
1368
+ }
1369
+ return undefined;
1370
+ }
1371
+ function rowToTicket(row) {
1372
+ return {
1373
+ id: row.id,
1374
+ sequence: row.sequence,
1375
+ workspaceId: row.workspaceId ?? undefined,
1376
+ projectId: row.projectId ?? undefined,
1377
+ projectKey: row.projectKey ?? undefined,
1378
+ projectName: row.projectName ?? undefined,
1379
+ title: row.title,
1380
+ description: row.description,
1381
+ descriptionHtml: row.descriptionHtml ?? undefined,
1382
+ type: row.type,
1383
+ priority: row.priority,
1384
+ status: row.status,
1385
+ labels: row.labels || [],
1386
+ assignee: row.assignee ?? undefined,
1387
+ assigneeAgent: row.assigneeAgent ?? undefined,
1388
+ parentId: row.parentId ?? undefined,
1389
+ linkedPRs: row.linkedPRs || [],
1390
+ linkedCommits: row.linkedCommits || [],
1391
+ linkedBranch: row.linkedBranch ?? undefined,
1392
+ createdAt: toISOString(row.createdAt),
1393
+ updatedAt: toISOString(row.updatedAt),
1394
+ startedAt: toOptionalISOString(row.startedAt),
1395
+ completedAt: toOptionalISOString(row.completedAt),
1396
+ startDate: toOptionalISOString(row.startDate),
1397
+ dueDate: toOptionalISOString(row.dueDate),
1398
+ createdBy: row.createdBy,
1399
+ aiAgent: row.aiAgent ?? undefined,
1400
+ aiSessionId: row.aiSessionId ?? undefined,
1401
+ aiTaskId: row.aiTaskId ?? undefined,
1402
+ estimate: row.estimate ?? undefined,
1403
+ estimateUnit: row.estimateUnit,
1404
+ };
1405
+ }
1406
+ //# sourceMappingURL=index.js.map