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.
- package/.env.example +215 -0
- package/CHANGELOG.md +49 -0
- package/CONTRIBUTING.md +119 -0
- package/Dockerfile +107 -0
- package/LICENSE +661 -0
- package/README.md +196 -0
- package/config/agents.yml +55 -0
- package/config/budget.yml +15 -0
- package/config/pricing.yml +46 -0
- package/config/settings.yml +168 -0
- package/dist/adapters/claude-code.d.ts +46 -0
- package/dist/adapters/claude-code.js +215 -0
- package/dist/adapters/index.d.ts +4 -0
- package/dist/adapters/index.js +4 -0
- package/dist/adapters/ollama.d.ts +45 -0
- package/dist/adapters/ollama.js +277 -0
- package/dist/adapters/openclaw.d.ts +60 -0
- package/dist/adapters/openclaw.js +289 -0
- package/dist/adapters/registry.d.ts +56 -0
- package/dist/adapters/registry.js +163 -0
- package/dist/agents/executor.d.ts +78 -0
- package/dist/agents/executor.js +657 -0
- package/dist/agents/index.d.ts +10 -0
- package/dist/agents/index.js +27 -0
- package/dist/agents/stop-conditions.d.ts +108 -0
- package/dist/agents/stop-conditions.js +299 -0
- package/dist/agents/types.d.ts +185 -0
- package/dist/agents/types.js +14 -0
- package/dist/ai/embedding-service.d.ts +96 -0
- package/dist/ai/embedding-service.js +333 -0
- package/dist/auth/api-tokens.d.ts +71 -0
- package/dist/auth/api-tokens.js +235 -0
- package/dist/auth/auth-service.d.ts +75 -0
- package/dist/auth/auth-service.js +557 -0
- package/dist/auth/device-identity.d.ts +96 -0
- package/dist/auth/device-identity.js +250 -0
- package/dist/auth/github-oauth.d.ts +20 -0
- package/dist/auth/github-oauth.js +59 -0
- package/dist/auth/jira-oauth.d.ts +25 -0
- package/dist/auth/jira-oauth.js +75 -0
- package/dist/auth/linear-oauth.d.ts +21 -0
- package/dist/auth/linear-oauth.js +59 -0
- package/dist/auth/middleware.d.ts +44 -0
- package/dist/auth/middleware.js +190 -0
- package/dist/auth/pairing-codes.d.ts +109 -0
- package/dist/auth/pairing-codes.js +274 -0
- package/dist/auth/password.d.ts +53 -0
- package/dist/auth/password.js +126 -0
- package/dist/auth/qr-pairing.d.ts +36 -0
- package/dist/auth/qr-pairing.js +138 -0
- package/dist/auth/slack-oauth.d.ts +31 -0
- package/dist/auth/slack-oauth.js +80 -0
- package/dist/backup/index.d.ts +50 -0
- package/dist/backup/index.js +184 -0
- package/dist/browser/adapters.d.ts +25 -0
- package/dist/browser/adapters.js +32 -0
- package/dist/browser/cli.d.ts +19 -0
- package/dist/browser/cli.js +277 -0
- package/dist/browser/compression.d.ts +32 -0
- package/dist/browser/compression.js +269 -0
- package/dist/browser/extensions.d.ts +144 -0
- package/dist/browser/extensions.js +251 -0
- package/dist/browser/index.d.ts +37 -0
- package/dist/browser/index.js +43 -0
- package/dist/browser/refs.d.ts +46 -0
- package/dist/browser/refs.js +120 -0
- package/dist/browser/search.d.ts +36 -0
- package/dist/browser/search.js +193 -0
- package/dist/browser/service.d.ts +94 -0
- package/dist/browser/service.js +358 -0
- package/dist/browser/snapshot.d.ts +19 -0
- package/dist/browser/snapshot.js +250 -0
- package/dist/browser/tools.d.ts +259 -0
- package/dist/browser/tools.js +463 -0
- package/dist/browser/types.d.ts +134 -0
- package/dist/browser/types.js +17 -0
- package/dist/chat/agentic-executor.d.ts +108 -0
- package/dist/chat/agentic-executor.js +739 -0
- package/dist/chat/api-key-detector.d.ts +41 -0
- package/dist/chat/api-key-detector.js +290 -0
- package/dist/chat/auto-reply.d.ts +90 -0
- package/dist/chat/auto-reply.js +272 -0
- package/dist/chat/conversations.d.ts +91 -0
- package/dist/chat/conversations.js +297 -0
- package/dist/chat/execution/audit.d.ts +192 -0
- package/dist/chat/execution/audit.js +323 -0
- package/dist/chat/execution/executor.d.ts +56 -0
- package/dist/chat/execution/executor.js +654 -0
- package/dist/chat/execution/guardrails.d.ts +98 -0
- package/dist/chat/execution/guardrails.js +571 -0
- package/dist/chat/execution/index.d.ts +61 -0
- package/dist/chat/execution/index.js +129 -0
- package/dist/chat/execution/model-capability.d.ts +34 -0
- package/dist/chat/execution/model-capability.js +96 -0
- package/dist/chat/execution/process-pool.d.ts +110 -0
- package/dist/chat/execution/process-pool.js +290 -0
- package/dist/chat/execution/pty.d.ts +92 -0
- package/dist/chat/execution/pty.js +285 -0
- package/dist/chat/execution/rate-limiter.d.ts +87 -0
- package/dist/chat/execution/rate-limiter.js +305 -0
- package/dist/chat/execution/registry.d.ts +54 -0
- package/dist/chat/execution/registry.js +220 -0
- package/dist/chat/execution/sandbox.d.ts +109 -0
- package/dist/chat/execution/sandbox.js +684 -0
- package/dist/chat/execution/secrets.d.ts +45 -0
- package/dist/chat/execution/secrets.js +338 -0
- package/dist/chat/execution/security.d.ts +179 -0
- package/dist/chat/execution/security.js +739 -0
- package/dist/chat/execution/self-correction.d.ts +162 -0
- package/dist/chat/execution/self-correction.js +557 -0
- package/dist/chat/execution/session-manager.d.ts +79 -0
- package/dist/chat/execution/session-manager.js +356 -0
- package/dist/chat/execution/session-spawn/config.d.ts +37 -0
- package/dist/chat/execution/session-spawn/config.js +83 -0
- package/dist/chat/execution/session-spawn/index.d.ts +10 -0
- package/dist/chat/execution/session-spawn/index.js +10 -0
- package/dist/chat/execution/session-spawn/manager.d.ts +35 -0
- package/dist/chat/execution/session-spawn/manager.js +418 -0
- package/dist/chat/execution/session-spawn/types.d.ts +117 -0
- package/dist/chat/execution/session-spawn/types.js +16 -0
- package/dist/chat/execution/smart-prompts.d.ts +34 -0
- package/dist/chat/execution/smart-prompts.js +151 -0
- package/dist/chat/execution/stream-results.d.ts +65 -0
- package/dist/chat/execution/stream-results.js +156 -0
- package/dist/chat/execution/tool-router.d.ts +76 -0
- package/dist/chat/execution/tool-router.js +296 -0
- package/dist/chat/execution/tools/agents-list.d.ts +49 -0
- package/dist/chat/execution/tools/agents-list.js +165 -0
- package/dist/chat/execution/tools/browser.d.ts +12 -0
- package/dist/chat/execution/tools/browser.js +14 -0
- package/dist/chat/execution/tools/canvas.d.ts +61 -0
- package/dist/chat/execution/tools/canvas.js +150 -0
- package/dist/chat/execution/tools/complete-task.d.ts +72 -0
- package/dist/chat/execution/tools/complete-task.js +104 -0
- package/dist/chat/execution/tools/cron-tool.d.ts +204 -0
- package/dist/chat/execution/tools/cron-tool.js +680 -0
- package/dist/chat/execution/tools/discord-actions.d.ts +120 -0
- package/dist/chat/execution/tools/discord-actions.js +361 -0
- package/dist/chat/execution/tools/exec.d.ts +43 -0
- package/dist/chat/execution/tools/exec.js +223 -0
- package/dist/chat/execution/tools/file-ops.d.ts +175 -0
- package/dist/chat/execution/tools/file-ops.js +723 -0
- package/dist/chat/execution/tools/git.d.ts +143 -0
- package/dist/chat/execution/tools/git.js +395 -0
- package/dist/chat/execution/tools/github.d.ts +42 -0
- package/dist/chat/execution/tools/github.js +184 -0
- package/dist/chat/execution/tools/glinr-ops.d.ts +202 -0
- package/dist/chat/execution/tools/glinr-ops.js +694 -0
- package/dist/chat/execution/tools/image-analyze.d.ts +29 -0
- package/dist/chat/execution/tools/image-analyze.js +127 -0
- package/dist/chat/execution/tools/index.d.ts +64 -0
- package/dist/chat/execution/tools/index.js +245 -0
- package/dist/chat/execution/tools/integrations.d.ts +109 -0
- package/dist/chat/execution/tools/integrations.js +237 -0
- package/dist/chat/execution/tools/link-understand.d.ts +34 -0
- package/dist/chat/execution/tools/link-understand.js +307 -0
- package/dist/chat/execution/tools/maintenance.d.ts +29 -0
- package/dist/chat/execution/tools/maintenance.js +105 -0
- package/dist/chat/execution/tools/memory-tools.d.ts +76 -0
- package/dist/chat/execution/tools/memory-tools.js +278 -0
- package/dist/chat/execution/tools/openai-image-gen.d.ts +51 -0
- package/dist/chat/execution/tools/openai-image-gen.js +212 -0
- package/dist/chat/execution/tools/profclaw-ops.d.ts +204 -0
- package/dist/chat/execution/tools/profclaw-ops.js +665 -0
- package/dist/chat/execution/tools/session-spawn.d.ts +146 -0
- package/dist/chat/execution/tools/session-spawn.js +544 -0
- package/dist/chat/execution/tools/session-status.d.ts +38 -0
- package/dist/chat/execution/tools/session-status.js +185 -0
- package/dist/chat/execution/tools/sessions-list.d.ts +49 -0
- package/dist/chat/execution/tools/sessions-list.js +153 -0
- package/dist/chat/execution/tools/sessions-send.d.ts +48 -0
- package/dist/chat/execution/tools/sessions-send.js +207 -0
- package/dist/chat/execution/tools/sessions-spawn.d.ts +51 -0
- package/dist/chat/execution/tools/sessions-spawn.js +137 -0
- package/dist/chat/execution/tools/slack-actions.d.ts +90 -0
- package/dist/chat/execution/tools/slack-actions.js +272 -0
- package/dist/chat/execution/tools/subagent-orchestrate.d.ts +66 -0
- package/dist/chat/execution/tools/subagent-orchestrate.js +313 -0
- package/dist/chat/execution/tools/system.d.ts +121 -0
- package/dist/chat/execution/tools/system.js +415 -0
- package/dist/chat/execution/tools/telegram-actions.d.ts +126 -0
- package/dist/chat/execution/tools/telegram-actions.js +339 -0
- package/dist/chat/execution/tools/test-run.d.ts +43 -0
- package/dist/chat/execution/tools/test-run.js +391 -0
- package/dist/chat/execution/tools/tts-speak.d.ts +39 -0
- package/dist/chat/execution/tools/tts-speak.js +199 -0
- package/dist/chat/execution/tools/web-fetch.d.ts +42 -0
- package/dist/chat/execution/tools/web-fetch.js +247 -0
- package/dist/chat/execution/tools/web-search.d.ts +53 -0
- package/dist/chat/execution/tools/web-search.js +130 -0
- package/dist/chat/execution/types.d.ts +337 -0
- package/dist/chat/execution/types.js +8 -0
- package/dist/chat/execution/workflows/built-in.d.ts +10 -0
- package/dist/chat/execution/workflows/built-in.js +249 -0
- package/dist/chat/execution/workflows/executor.d.ts +13 -0
- package/dist/chat/execution/workflows/executor.js +259 -0
- package/dist/chat/execution/workflows/index.d.ts +5 -0
- package/dist/chat/execution/workflows/index.js +5 -0
- package/dist/chat/execution/workflows/trigger.d.ts +15 -0
- package/dist/chat/execution/workflows/trigger.js +111 -0
- package/dist/chat/execution/workflows/types.d.ts +80 -0
- package/dist/chat/execution/workflows/types.js +2 -0
- package/dist/chat/failover/error.d.ts +73 -0
- package/dist/chat/failover/error.js +412 -0
- package/dist/chat/failover/index.d.ts +10 -0
- package/dist/chat/failover/index.js +11 -0
- package/dist/chat/failover/model-fallback.d.ts +97 -0
- package/dist/chat/failover/model-fallback.js +328 -0
- package/dist/chat/failover/types.d.ts +47 -0
- package/dist/chat/failover/types.js +8 -0
- package/dist/chat/format/chunk.d.ts +59 -0
- package/dist/chat/format/chunk.js +253 -0
- package/dist/chat/format/index.d.ts +7 -0
- package/dist/chat/format/index.js +7 -0
- package/dist/chat/format/tool-result-formatter.d.ts +30 -0
- package/dist/chat/format/tool-result-formatter.js +177 -0
- package/dist/chat/group.d.ts +232 -0
- package/dist/chat/group.js +311 -0
- package/dist/chat/index.d.ts +21 -0
- package/dist/chat/index.js +30 -0
- package/dist/chat/memory.d.ts +108 -0
- package/dist/chat/memory.js +343 -0
- package/dist/chat/message-handler.d.ts +38 -0
- package/dist/chat/message-handler.js +274 -0
- package/dist/chat/proactive/index.d.ts +167 -0
- package/dist/chat/proactive/index.js +721 -0
- package/dist/chat/prompt-adapter.d.ts +52 -0
- package/dist/chat/prompt-adapter.js +245 -0
- package/dist/chat/providers/dingtalk/index.d.ts +69 -0
- package/dist/chat/providers/dingtalk/index.js +225 -0
- package/dist/chat/providers/discord/index.d.ts +264 -0
- package/dist/chat/providers/discord/index.js +657 -0
- package/dist/chat/providers/feishu/index.d.ts +97 -0
- package/dist/chat/providers/feishu/index.js +362 -0
- package/dist/chat/providers/googlechat/index.d.ts +269 -0
- package/dist/chat/providers/googlechat/index.js +634 -0
- package/dist/chat/providers/imessage/index.d.ts +61 -0
- package/dist/chat/providers/imessage/index.js +166 -0
- package/dist/chat/providers/index.d.ts +76 -0
- package/dist/chat/providers/index.js +430 -0
- package/dist/chat/providers/irc/index.d.ts +101 -0
- package/dist/chat/providers/irc/index.js +557 -0
- package/dist/chat/providers/line/index.d.ts +113 -0
- package/dist/chat/providers/line/index.js +434 -0
- package/dist/chat/providers/matrix/index.d.ts +161 -0
- package/dist/chat/providers/matrix/index.js +559 -0
- package/dist/chat/providers/mattermost/index.d.ts +106 -0
- package/dist/chat/providers/mattermost/index.js +425 -0
- package/dist/chat/providers/msteams/index.d.ts +198 -0
- package/dist/chat/providers/msteams/index.js +694 -0
- package/dist/chat/providers/nextcloud/index.d.ts +52 -0
- package/dist/chat/providers/nextcloud/index.js +156 -0
- package/dist/chat/providers/nostr/index.d.ts +60 -0
- package/dist/chat/providers/nostr/index.js +200 -0
- package/dist/chat/providers/qq/index.d.ts +57 -0
- package/dist/chat/providers/qq/index.js +260 -0
- package/dist/chat/providers/registry.d.ts +89 -0
- package/dist/chat/providers/registry.js +213 -0
- package/dist/chat/providers/signal/index.d.ts +88 -0
- package/dist/chat/providers/signal/index.js +357 -0
- package/dist/chat/providers/slack/index.d.ts +52 -0
- package/dist/chat/providers/slack/index.js +477 -0
- package/dist/chat/providers/synology/index.d.ts +50 -0
- package/dist/chat/providers/synology/index.js +138 -0
- package/dist/chat/providers/telegram/index.d.ts +148 -0
- package/dist/chat/providers/telegram/index.js +492 -0
- package/dist/chat/providers/tlon/index.d.ts +44 -0
- package/dist/chat/providers/tlon/index.js +243 -0
- package/dist/chat/providers/twitch/index.d.ts +79 -0
- package/dist/chat/providers/twitch/index.js +349 -0
- package/dist/chat/providers/types.d.ts +437 -0
- package/dist/chat/providers/types.js +14 -0
- package/dist/chat/providers/webchat/index.d.ts +38 -0
- package/dist/chat/providers/webchat/index.js +214 -0
- package/dist/chat/providers/wecom/index.d.ts +62 -0
- package/dist/chat/providers/wecom/index.js +228 -0
- package/dist/chat/providers/whatsapp/index.d.ts +147 -0
- package/dist/chat/providers/whatsapp/index.js +396 -0
- package/dist/chat/providers/zalo/index.d.ts +54 -0
- package/dist/chat/providers/zalo/index.js +158 -0
- package/dist/chat/providers/zalo-personal/index.d.ts +53 -0
- package/dist/chat/providers/zalo-personal/index.js +212 -0
- package/dist/chat/skills.d.ts +82 -0
- package/dist/chat/skills.js +410 -0
- package/dist/chat/system-prompts.d.ts +76 -0
- package/dist/chat/system-prompts.js +407 -0
- package/dist/chat/tool-handler.d.ts +57 -0
- package/dist/chat/tool-handler.js +336 -0
- package/dist/chat/tools.d.ts +373 -0
- package/dist/chat/tools.js +512 -0
- package/dist/cli/commands/agent.d.ts +3 -0
- package/dist/cli/commands/agent.js +108 -0
- package/dist/cli/commands/auth.d.ts +12 -0
- package/dist/cli/commands/auth.js +301 -0
- package/dist/cli/commands/browser.d.ts +3 -0
- package/dist/cli/commands/browser.js +138 -0
- package/dist/cli/commands/canvas.d.ts +3 -0
- package/dist/cli/commands/canvas.js +155 -0
- package/dist/cli/commands/channels.d.ts +3 -0
- package/dist/cli/commands/channels.js +167 -0
- package/dist/cli/commands/chat.d.ts +9 -0
- package/dist/cli/commands/chat.js +360 -0
- package/dist/cli/commands/completion.d.ts +3 -0
- package/dist/cli/commands/completion.js +170 -0
- package/dist/cli/commands/config.d.ts +3 -0
- package/dist/cli/commands/config.js +193 -0
- package/dist/cli/commands/cost.d.ts +3 -0
- package/dist/cli/commands/cost.js +134 -0
- package/dist/cli/commands/daemon.d.ts +3 -0
- package/dist/cli/commands/daemon.js +381 -0
- package/dist/cli/commands/devices.d.ts +3 -0
- package/dist/cli/commands/devices.js +150 -0
- package/dist/cli/commands/doctor.d.ts +3 -0
- package/dist/cli/commands/doctor.js +295 -0
- package/dist/cli/commands/logs.d.ts +3 -0
- package/dist/cli/commands/logs.js +139 -0
- package/dist/cli/commands/mcp.d.ts +15 -0
- package/dist/cli/commands/mcp.js +157 -0
- package/dist/cli/commands/memory.d.ts +3 -0
- package/dist/cli/commands/memory.js +170 -0
- package/dist/cli/commands/models.d.ts +3 -0
- package/dist/cli/commands/models.js +197 -0
- package/dist/cli/commands/nodes.d.ts +3 -0
- package/dist/cli/commands/nodes.js +193 -0
- package/dist/cli/commands/onboard.d.ts +13 -0
- package/dist/cli/commands/onboard.js +360 -0
- package/dist/cli/commands/plugin.d.ts +15 -0
- package/dist/cli/commands/plugin.js +226 -0
- package/dist/cli/commands/provider.d.ts +16 -0
- package/dist/cli/commands/provider.js +320 -0
- package/dist/cli/commands/security.d.ts +3 -0
- package/dist/cli/commands/security.js +180 -0
- package/dist/cli/commands/serve.d.ts +3 -0
- package/dist/cli/commands/serve.js +179 -0
- package/dist/cli/commands/session.d.ts +3 -0
- package/dist/cli/commands/session.js +172 -0
- package/dist/cli/commands/setup.d.ts +13 -0
- package/dist/cli/commands/setup.js +636 -0
- package/dist/cli/commands/skill.d.ts +15 -0
- package/dist/cli/commands/skill.js +191 -0
- package/dist/cli/commands/status.d.ts +3 -0
- package/dist/cli/commands/status.js +71 -0
- package/dist/cli/commands/summary.d.ts +3 -0
- package/dist/cli/commands/summary.js +160 -0
- package/dist/cli/commands/task.d.ts +3 -0
- package/dist/cli/commands/task.js +170 -0
- package/dist/cli/commands/ticket.d.ts +3 -0
- package/dist/cli/commands/ticket.js +421 -0
- package/dist/cli/commands/tools.d.ts +9 -0
- package/dist/cli/commands/tools.js +508 -0
- package/dist/cli/commands/tui.d.ts +3 -0
- package/dist/cli/commands/tui.js +158 -0
- package/dist/cli/commands/tunnel.d.ts +3 -0
- package/dist/cli/commands/tunnel.js +135 -0
- package/dist/cli/commands/webhooks.d.ts +3 -0
- package/dist/cli/commands/webhooks.js +191 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.js +127 -0
- package/dist/cli/utils/api.d.ts +17 -0
- package/dist/cli/utils/api.js +63 -0
- package/dist/cli/utils/config.d.ts +31 -0
- package/dist/cli/utils/config.js +81 -0
- package/dist/cli/utils/output.d.ts +58 -0
- package/dist/cli/utils/output.js +148 -0
- package/dist/core/deployment.d.ts +30 -0
- package/dist/core/deployment.js +114 -0
- package/dist/core/sandbox-config.d.ts +63 -0
- package/dist/core/sandbox-config.js +148 -0
- package/dist/costs/budget.d.ts +28 -0
- package/dist/costs/budget.js +57 -0
- package/dist/costs/persistence.d.ts +77 -0
- package/dist/costs/persistence.js +210 -0
- package/dist/costs/pricing.d.ts +16 -0
- package/dist/costs/pricing.js +39 -0
- package/dist/costs/token-tracker.d.ts +34 -0
- package/dist/costs/token-tracker.js +141 -0
- package/dist/cron/heartbeat.d.ts +23 -0
- package/dist/cron/heartbeat.js +109 -0
- package/dist/cron/index.d.ts +22 -0
- package/dist/cron/index.js +37 -0
- package/dist/cron/issue-poller.d.ts +15 -0
- package/dist/cron/issue-poller.js +174 -0
- package/dist/cron/scheduler.d.ts +315 -0
- package/dist/cron/scheduler.js +1008 -0
- package/dist/cron/stale-checker.d.ts +16 -0
- package/dist/cron/stale-checker.js +61 -0
- package/dist/cron/templates.d.ts +107 -0
- package/dist/cron/templates.js +395 -0
- package/dist/diagnostics/exporters.d.ts +21 -0
- package/dist/diagnostics/exporters.js +138 -0
- package/dist/diagnostics/index.d.ts +10 -0
- package/dist/diagnostics/index.js +9 -0
- package/dist/diagnostics/middleware.d.ts +12 -0
- package/dist/diagnostics/middleware.js +58 -0
- package/dist/diagnostics/tracer.d.ts +133 -0
- package/dist/diagnostics/tracer.js +257 -0
- package/dist/discovery/index.d.ts +8 -0
- package/dist/discovery/index.js +7 -0
- package/dist/discovery/mdns.d.ts +40 -0
- package/dist/discovery/mdns.js +249 -0
- package/dist/gateway/index.d.ts +35 -0
- package/dist/gateway/index.js +36 -0
- package/dist/gateway/router.d.ts +110 -0
- package/dist/gateway/router.js +649 -0
- package/dist/gateway/types.d.ts +275 -0
- package/dist/gateway/types.js +2 -0
- package/dist/gateway/workflows.d.ts +37 -0
- package/dist/gateway/workflows.js +748 -0
- package/dist/hooks/agent-webhook.d.ts +277 -0
- package/dist/hooks/agent-webhook.js +197 -0
- package/dist/hooks/index.d.ts +13 -0
- package/dist/hooks/index.js +15 -0
- package/dist/hooks/prompt-submit.d.ts +45 -0
- package/dist/hooks/prompt-submit.js +111 -0
- package/dist/hooks/schemas.d.ts +563 -0
- package/dist/hooks/schemas.js +108 -0
- package/dist/hooks/session-end.d.ts +25 -0
- package/dist/hooks/session-end.js +153 -0
- package/dist/hooks/tool-use.d.ts +41 -0
- package/dist/hooks/tool-use.js +201 -0
- package/dist/hooks/types.d.ts +76 -0
- package/dist/hooks/types.js +7 -0
- package/dist/integrations/cloudflare-tunnel.d.ts +78 -0
- package/dist/integrations/cloudflare-tunnel.js +268 -0
- package/dist/integrations/github-client.d.ts +27 -0
- package/dist/integrations/github-client.js +79 -0
- package/dist/integrations/github-projects.d.ts +97 -0
- package/dist/integrations/github-projects.js +433 -0
- package/dist/integrations/github-ticket-sync.d.ts +82 -0
- package/dist/integrations/github-ticket-sync.js +352 -0
- package/dist/integrations/github.d.ts +11 -0
- package/dist/integrations/github.js +241 -0
- package/dist/integrations/jira-client.d.ts +30 -0
- package/dist/integrations/jira-client.js +67 -0
- package/dist/integrations/jira.d.ts +13 -0
- package/dist/integrations/jira.js +108 -0
- package/dist/integrations/linear-client.d.ts +23 -0
- package/dist/integrations/linear-client.js +52 -0
- package/dist/integrations/linear.d.ts +15 -0
- package/dist/integrations/linear.js +312 -0
- package/dist/integrations/tailscale.d.ts +68 -0
- package/dist/integrations/tailscale.js +173 -0
- package/dist/integrations/web-search.d.ts +112 -0
- package/dist/integrations/web-search.js +287 -0
- package/dist/intelligence/index.d.ts +8 -0
- package/dist/intelligence/index.js +8 -0
- package/dist/intelligence/ollama.d.ts +50 -0
- package/dist/intelligence/ollama.js +213 -0
- package/dist/intelligence/rules.d.ts +39 -0
- package/dist/intelligence/rules.js +308 -0
- package/dist/labels/index.d.ts +93 -0
- package/dist/labels/index.js +248 -0
- package/dist/mcp/browser-tools.d.ts +10 -0
- package/dist/mcp/browser-tools.js +16 -0
- package/dist/mcp/client.d.ts +54 -0
- package/dist/mcp/client.js +153 -0
- package/dist/mcp/index.d.ts +12 -0
- package/dist/mcp/index.js +13 -0
- package/dist/mcp/server.d.ts +40 -0
- package/dist/mcp/server.js +826 -0
- package/dist/mcp/tool-adapter.d.ts +49 -0
- package/dist/mcp/tool-adapter.js +193 -0
- package/dist/memory/experience-store.d.ts +121 -0
- package/dist/memory/experience-store.js +439 -0
- package/dist/memory/index.d.ts +8 -0
- package/dist/memory/index.js +25 -0
- package/dist/memory/memory-service.d.ts +312 -0
- package/dist/memory/memory-service.js +1172 -0
- package/dist/memory/memory-watcher.d.ts +116 -0
- package/dist/memory/memory-watcher.js +239 -0
- package/dist/middleware/logging.d.ts +34 -0
- package/dist/middleware/logging.js +184 -0
- package/dist/middleware/rate-limit.d.ts +29 -0
- package/dist/middleware/rate-limit.js +91 -0
- package/dist/notifications/in-app.d.ts +28 -0
- package/dist/notifications/in-app.js +53 -0
- package/dist/notifications/index.d.ts +3 -0
- package/dist/notifications/index.js +3 -0
- package/dist/notifications/push.d.ts +74 -0
- package/dist/notifications/push.js +175 -0
- package/dist/notifications/slack.d.ts +32 -0
- package/dist/notifications/slack.js +157 -0
- package/dist/plugins/clawhub.d.ts +70 -0
- package/dist/plugins/clawhub.js +260 -0
- package/dist/plugins/loader.d.ts +23 -0
- package/dist/plugins/loader.js +140 -0
- package/dist/plugins/marketplace.d.ts +77 -0
- package/dist/plugins/marketplace.js +275 -0
- package/dist/plugins/registry.d.ts +122 -0
- package/dist/plugins/registry.js +352 -0
- package/dist/plugins/sandbox.d.ts +77 -0
- package/dist/plugins/sandbox.js +287 -0
- package/dist/plugins/scaffolder.d.ts +28 -0
- package/dist/plugins/scaffolder.js +409 -0
- package/dist/plugins/sdk.d.ts +35 -0
- package/dist/plugins/sdk.js +8 -0
- package/dist/plugins/search/brave.d.ts +9 -0
- package/dist/plugins/search/brave.js +157 -0
- package/dist/plugins/search/duckduckgo.d.ts +9 -0
- package/dist/plugins/search/duckduckgo.js +171 -0
- package/dist/plugins/search/index.d.ts +13 -0
- package/dist/plugins/search/index.js +23 -0
- package/dist/plugins/search/searxng.d.ts +9 -0
- package/dist/plugins/search/searxng.js +170 -0
- package/dist/plugins/search/serper.d.ts +9 -0
- package/dist/plugins/search/serper.js +135 -0
- package/dist/plugins/search/tavily.d.ts +9 -0
- package/dist/plugins/search/tavily.js +146 -0
- package/dist/plugins/types.d.ts +174 -0
- package/dist/plugins/types.js +8 -0
- package/dist/projects/index.d.ts +133 -0
- package/dist/projects/index.js +897 -0
- package/dist/projects/types.d.ts +444 -0
- package/dist/projects/types.js +207 -0
- package/dist/providers/adapters/anthropic.d.ts +26 -0
- package/dist/providers/adapters/anthropic.js +306 -0
- package/dist/providers/adapters/base.d.ts +53 -0
- package/dist/providers/adapters/base.js +99 -0
- package/dist/providers/adapters/ollama.d.ts +30 -0
- package/dist/providers/adapters/ollama.js +292 -0
- package/dist/providers/ai-sdk.d.ts +178 -0
- package/dist/providers/ai-sdk.js +1552 -0
- package/dist/providers/core/index.d.ts +8 -0
- package/dist/providers/core/index.js +10 -0
- package/dist/providers/core/models.d.ts +31 -0
- package/dist/providers/core/models.js +949 -0
- package/dist/providers/core/types.d.ts +117 -0
- package/dist/providers/core/types.js +83 -0
- package/dist/providers/index.d.ts +7 -0
- package/dist/providers/index.js +7 -0
- package/dist/providers/registry.d.ts +93 -0
- package/dist/providers/registry.js +228 -0
- package/dist/providers/schema-utils.d.ts +23 -0
- package/dist/providers/schema-utils.js +545 -0
- package/dist/providers/types.d.ts +609 -0
- package/dist/providers/types.js +279 -0
- package/dist/queue/failure-handler.d.ts +93 -0
- package/dist/queue/failure-handler.js +379 -0
- package/dist/queue/index.d.ts +23 -0
- package/dist/queue/index.js +86 -0
- package/dist/queue/memory-queue.d.ts +30 -0
- package/dist/queue/memory-queue.js +429 -0
- package/dist/queue/notifications.d.ts +6 -0
- package/dist/queue/notifications.js +128 -0
- package/dist/queue/task-queue.d.ts +55 -0
- package/dist/queue/task-queue.js +518 -0
- package/dist/queue/webhook-queue.d.ts +47 -0
- package/dist/queue/webhook-queue.js +158 -0
- package/dist/routes/agents.d.ts +4 -0
- package/dist/routes/agents.js +45 -0
- package/dist/routes/auth.d.ts +19 -0
- package/dist/routes/auth.js +492 -0
- package/dist/routes/backup.d.ts +6 -0
- package/dist/routes/backup.js +71 -0
- package/dist/routes/chat.d.ts +10 -0
- package/dist/routes/chat.js +1678 -0
- package/dist/routes/clawhub.d.ts +8 -0
- package/dist/routes/clawhub.js +89 -0
- package/dist/routes/costs.d.ts +4 -0
- package/dist/routes/costs.js +78 -0
- package/dist/routes/cron.d.ts +11 -0
- package/dist/routes/cron.js +708 -0
- package/dist/routes/devices.d.ts +9 -0
- package/dist/routes/devices.js +490 -0
- package/dist/routes/discord.d.ts +15 -0
- package/dist/routes/discord.js +524 -0
- package/dist/routes/dlq.d.ts +4 -0
- package/dist/routes/dlq.js +64 -0
- package/dist/routes/gateway.d.ts +4 -0
- package/dist/routes/gateway.js +253 -0
- package/dist/routes/health.d.ts +29 -0
- package/dist/routes/health.js +296 -0
- package/dist/routes/hooks.d.ts +4 -0
- package/dist/routes/hooks.js +170 -0
- package/dist/routes/import.d.ts +9 -0
- package/dist/routes/import.js +540 -0
- package/dist/routes/index.d.ts +38 -0
- package/dist/routes/index.js +39 -0
- package/dist/routes/integrations.d.ts +10 -0
- package/dist/routes/integrations.js +200 -0
- package/dist/routes/labels.d.ts +8 -0
- package/dist/routes/labels.js +240 -0
- package/dist/routes/mcp.d.ts +14 -0
- package/dist/routes/mcp.js +125 -0
- package/dist/routes/memory.d.ts +10 -0
- package/dist/routes/memory.js +622 -0
- package/dist/routes/notifications.d.ts +9 -0
- package/dist/routes/notifications.js +154 -0
- package/dist/routes/oobe.d.ts +10 -0
- package/dist/routes/oobe.js +405 -0
- package/dist/routes/openapi.d.ts +9 -0
- package/dist/routes/openapi.js +537 -0
- package/dist/routes/plugins.d.ts +8 -0
- package/dist/routes/plugins.js +108 -0
- package/dist/routes/projects.d.ts +8 -0
- package/dist/routes/projects.js +592 -0
- package/dist/routes/push.d.ts +8 -0
- package/dist/routes/push.js +75 -0
- package/dist/routes/search.d.ts +4 -0
- package/dist/routes/search.js +189 -0
- package/dist/routes/security.d.ts +10 -0
- package/dist/routes/security.js +189 -0
- package/dist/routes/settings.d.ts +4 -0
- package/dist/routes/settings.js +119 -0
- package/dist/routes/setup.d.ts +11 -0
- package/dist/routes/setup.js +525 -0
- package/dist/routes/skills.d.ts +13 -0
- package/dist/routes/skills.js +152 -0
- package/dist/routes/slack.d.ts +12 -0
- package/dist/routes/slack.js +999 -0
- package/dist/routes/states.d.ts +8 -0
- package/dist/routes/states.js +123 -0
- package/dist/routes/stats.d.ts +6 -0
- package/dist/routes/stats.js +369 -0
- package/dist/routes/summaries.d.ts +4 -0
- package/dist/routes/summaries.js +344 -0
- package/dist/routes/sync.d.ts +13 -0
- package/dist/routes/sync.js +268 -0
- package/dist/routes/tasks.d.ts +4 -0
- package/dist/routes/tasks.js +473 -0
- package/dist/routes/telegram.d.ts +14 -0
- package/dist/routes/telegram.js +420 -0
- package/dist/routes/tickets.d.ts +4 -0
- package/dist/routes/tickets.js +1090 -0
- package/dist/routes/tokens.d.ts +4 -0
- package/dist/routes/tokens.js +83 -0
- package/dist/routes/tools.d.ts +14 -0
- package/dist/routes/tools.js +790 -0
- package/dist/routes/tunnels.d.ts +8 -0
- package/dist/routes/tunnels.js +145 -0
- package/dist/routes/users.d.ts +15 -0
- package/dist/routes/users.js +998 -0
- package/dist/routes/voice.d.ts +8 -0
- package/dist/routes/voice.js +127 -0
- package/dist/routes/webchat.d.ts +11 -0
- package/dist/routes/webchat.js +173 -0
- package/dist/routes/webhook-dedup.d.ts +11 -0
- package/dist/routes/webhook-dedup.js +49 -0
- package/dist/routes/webhooks.d.ts +4 -0
- package/dist/routes/webhooks.js +71 -0
- package/dist/routes/whatsapp.d.ts +14 -0
- package/dist/routes/whatsapp.js +391 -0
- package/dist/security/audit-scanner.d.ts +32 -0
- package/dist/security/audit-scanner.js +217 -0
- package/dist/security/fs-guard.d.ts +41 -0
- package/dist/security/fs-guard.js +206 -0
- package/dist/security/prompt-guard.d.ts +47 -0
- package/dist/security/prompt-guard.js +198 -0
- package/dist/security/ssrf-guard.d.ts +38 -0
- package/dist/security/ssrf-guard.js +266 -0
- package/dist/security/types.d.ts +92 -0
- package/dist/security/types.js +8 -0
- package/dist/server/route-loader.d.ts +15 -0
- package/dist/server/route-loader.js +135 -0
- package/dist/server.d.ts +5 -0
- package/dist/server.js +835 -0
- package/dist/settings/index.d.ts +841 -0
- package/dist/settings/index.js +451 -0
- package/dist/skills/compiler.d.ts +83 -0
- package/dist/skills/compiler.js +358 -0
- package/dist/skills/frontmatter.d.ts +33 -0
- package/dist/skills/frontmatter.js +175 -0
- package/dist/skills/index.d.ts +19 -0
- package/dist/skills/index.js +24 -0
- package/dist/skills/installer.d.ts +22 -0
- package/dist/skills/installer.js +220 -0
- package/dist/skills/loader.d.ts +72 -0
- package/dist/skills/loader.js +484 -0
- package/dist/skills/prompt-builder.d.ts +48 -0
- package/dist/skills/prompt-builder.js +135 -0
- package/dist/skills/registry.d.ts +115 -0
- package/dist/skills/registry.js +225 -0
- package/dist/skills/types.d.ts +202 -0
- package/dist/skills/types.js +24 -0
- package/dist/states/index.d.ts +64 -0
- package/dist/states/index.js +142 -0
- package/dist/storage/adapter.d.ts +146 -0
- package/dist/storage/adapter.js +2 -0
- package/dist/storage/index.d.ts +48 -0
- package/dist/storage/index.js +135 -0
- package/dist/storage/libsql.d.ts +99 -0
- package/dist/storage/libsql.js +1873 -0
- package/dist/storage/migrations.d.ts +65 -0
- package/dist/storage/migrations.js +289 -0
- package/dist/storage/schema.d.ts +10185 -0
- package/dist/storage/schema.js +1113 -0
- package/dist/summaries/extractor.d.ts +56 -0
- package/dist/summaries/extractor.js +377 -0
- package/dist/summaries/index.d.ts +13 -0
- package/dist/summaries/index.js +14 -0
- package/dist/summaries/storage.d.ts +51 -0
- package/dist/summaries/storage.js +101 -0
- package/dist/summaries/templates.d.ts +68 -0
- package/dist/summaries/templates.js +245 -0
- package/dist/sync/adapters/base.d.ts +42 -0
- package/dist/sync/adapters/base.js +142 -0
- package/dist/sync/adapters/github.d.ts +45 -0
- package/dist/sync/adapters/github.js +445 -0
- package/dist/sync/adapters/linear.d.ts +40 -0
- package/dist/sync/adapters/linear.js +434 -0
- package/dist/sync/config.d.ts +388 -0
- package/dist/sync/config.js +281 -0
- package/dist/sync/engine.d.ts +112 -0
- package/dist/sync/engine.js +623 -0
- package/dist/sync/index.d.ts +31 -0
- package/dist/sync/index.js +34 -0
- package/dist/sync/integration.d.ts +53 -0
- package/dist/sync/integration.js +231 -0
- package/dist/sync/types.d.ts +249 -0
- package/dist/sync/types.js +30 -0
- package/dist/tickets/index.d.ts +139 -0
- package/dist/tickets/index.js +1406 -0
- package/dist/tickets/types.d.ts +817 -0
- package/dist/tickets/types.js +310 -0
- package/dist/tools/adapters.d.ts +56 -0
- package/dist/tools/adapters.js +183 -0
- package/dist/tools/index.d.ts +66 -0
- package/dist/tools/index.js +105 -0
- package/dist/tools/types.d.ts +117 -0
- package/dist/tools/types.js +20 -0
- package/dist/types/agent.d.ts +101 -0
- package/dist/types/agent.js +2 -0
- package/dist/types/errors.d.ts +150 -0
- package/dist/types/errors.js +338 -0
- package/dist/types/index.d.ts +3 -0
- package/dist/types/index.js +3 -0
- package/dist/types/summary.d.ts +638 -0
- package/dist/types/summary.js +137 -0
- package/dist/types/task.d.ts +123 -0
- package/dist/types/task.js +46 -0
- package/dist/utils/ai-cache.d.ts +72 -0
- package/dist/utils/ai-cache.js +204 -0
- package/dist/utils/ai-inference.d.ts +57 -0
- package/dist/utils/ai-inference.js +190 -0
- package/dist/utils/ai-responder.d.ts +44 -0
- package/dist/utils/ai-responder.js +272 -0
- package/dist/utils/circuit-breaker.d.ts +139 -0
- package/dist/utils/circuit-breaker.js +281 -0
- package/dist/utils/config-loader.d.ts +12 -0
- package/dist/utils/config-loader.js +44 -0
- package/dist/utils/crypto.d.ts +10 -0
- package/dist/utils/crypto.js +59 -0
- package/dist/utils/env-validator.d.ts +44 -0
- package/dist/utils/env-validator.js +236 -0
- package/dist/utils/file-lock.d.ts +85 -0
- package/dist/utils/file-lock.js +204 -0
- package/dist/utils/logger.d.ts +153 -0
- package/dist/utils/logger.js +282 -0
- package/dist/utils/metrics.d.ts +183 -0
- package/dist/utils/metrics.js +345 -0
- package/dist/utils/security.d.ts +90 -0
- package/dist/utils/security.js +347 -0
- package/dist/voice/index.d.ts +79 -0
- package/dist/voice/index.js +144 -0
- package/dist/voice/stt/whisper.d.ts +13 -0
- package/dist/voice/stt/whisper.js +116 -0
- package/dist/voice/tts/elevenlabs.d.ts +18 -0
- package/dist/voice/tts/elevenlabs.js +178 -0
- package/dist/voice/tts/openai-tts.d.ts +19 -0
- package/dist/voice/tts/openai-tts.js +127 -0
- package/dist/voice/tts/system.d.ts +26 -0
- package/dist/voice/tts/system.js +146 -0
- package/dist/voice/wake-word.d.ts +44 -0
- package/dist/voice/wake-word.js +145 -0
- package/docker-compose.yml +222 -0
- package/package.json +154 -0
- package/profclaw.mjs +24 -0
- package/skills/1password/SKILL.md +155 -0
- package/skills/api-tester/SKILL.md +177 -0
- package/skills/apple-notes/SKILL.md +167 -0
- package/skills/apple-reminders/SKILL.md +178 -0
- package/skills/bear-notes/SKILL.md +166 -0
- package/skills/blogwatcher/SKILL.md +177 -0
- package/skills/camsnap/SKILL.md +130 -0
- package/skills/code-generation/SKILL.md +139 -0
- package/skills/code-review/SKILL.md +116 -0
- package/skills/coding-agent/SKILL.md +184 -0
- package/skills/cron-manager/SKILL.md +141 -0
- package/skills/debug-helper/SKILL.md +134 -0
- package/skills/docker-ops/SKILL.md +246 -0
- package/skills/file-manager/SKILL.md +160 -0
- package/skills/git-workflow/SKILL.md +171 -0
- package/skills/github-issues/SKILL.md +244 -0
- package/skills/gog/SKILL.md +191 -0
- package/skills/goplaces/SKILL.md +156 -0
- package/skills/healthcheck/SKILL.md +270 -0
- package/skills/himalaya/SKILL.md +165 -0
- package/skills/mcp-discovery/SKILL.md +109 -0
- package/skills/memory-manager/SKILL.md +151 -0
- package/skills/model-usage/SKILL.md +177 -0
- package/skills/nano-banana-pro/SKILL.md +214 -0
- package/skills/nano-pdf/SKILL.md +165 -0
- package/skills/notion/SKILL.md +147 -0
- package/skills/obsidian/SKILL.md +163 -0
- package/skills/openai-image-gen/SKILL.md +194 -0
- package/skills/openai-whisper/SKILL.md +98 -0
- package/skills/openai-whisper-api/SKILL.md +130 -0
- package/skills/openhue/SKILL.md +203 -0
- package/skills/oracle/SKILL.md +236 -0
- package/skills/phone-control/SKILL.md +201 -0
- package/skills/profclaw-assistant/SKILL.md +81 -0
- package/skills/profclaw-projects/SKILL.md +68 -0
- package/skills/profclaw-tickets/SKILL.md +91 -0
- package/skills/session-logs/SKILL.md +216 -0
- package/skills/sherpa-onnx-tts/SKILL.md +134 -0
- package/skills/skill-creator/SKILL.md +183 -0
- package/skills/songsee/SKILL.md +170 -0
- package/skills/spotify-player/SKILL.md +254 -0
- package/skills/summarize/SKILL.md +155 -0
- package/skills/system-admin/SKILL.md +179 -0
- package/skills/things-mac/SKILL.md +179 -0
- package/skills/tmux/SKILL.md +170 -0
- package/skills/trello/SKILL.md +154 -0
- package/skills/video-frames/SKILL.md +127 -0
- package/skills/weather/SKILL.md +186 -0
- package/skills/web-research/SKILL.md +128 -0
- package/skills/xurl/SKILL.md +198 -0
- package/ui/README.md +73 -0
- package/ui/dist/assets/ActivityView-CkPgKhwm.js +1 -0
- package/ui/dist/assets/AgentList-C3SVdeEz.js +1 -0
- package/ui/dist/assets/AnalyticsDashboard-DVU--vlP.js +1 -0
- package/ui/dist/assets/AreaChart-B5qMEGWj.js +1 -0
- package/ui/dist/assets/CartesianChart-B50bcUJi.js +36 -0
- package/ui/dist/assets/ChatView-BZFJs7w_.js +10 -0
- package/ui/dist/assets/CostsDashboard-ChfH8BlG.js +1 -0
- package/ui/dist/assets/EstimateSelect-CLpB4NQO.js +1 -0
- package/ui/dist/assets/FloatingChatbot-CBzBY9a0.js +2 -0
- package/ui/dist/assets/InviteCodeManagement-DsbdPa6W.js +2 -0
- package/ui/dist/assets/ProjectDetail-BEM3tFXg.js +2 -0
- package/ui/dist/assets/ProjectDetail-D1-0B2xV.css +1 -0
- package/ui/dist/assets/ProjectIcon-CN1FmFAk.js +1 -0
- package/ui/dist/assets/ProjectList-DSDaNhxQ.js +4 -0
- package/ui/dist/assets/Settings-dPVcqC_d.js +6 -0
- package/ui/dist/assets/StatusIndicator-DA3NAo_b.js +1 -0
- package/ui/dist/assets/SummaryDetail-Bjnf9lT8.js +27 -0
- package/ui/dist/assets/SummaryList-ENwKDBKW.js +1 -0
- package/ui/dist/assets/TaskDetail-DnwG6MzB.js +1 -0
- package/ui/dist/assets/TaskList-D9Ug_HiV.js +1 -0
- package/ui/dist/assets/TicketBoard-CviH1571.js +1 -0
- package/ui/dist/assets/TicketDetail-8Jk8O-33.js +1 -0
- package/ui/dist/assets/TicketList-B-iV4rRA.js +1 -0
- package/ui/dist/assets/UserManagement-CPZ8s7s2.js +2 -0
- package/ui/dist/assets/ViewSwitcher-BUyOOWDI.js +1 -0
- package/ui/dist/assets/alert-dialog-BOmnTkN-.js +7 -0
- package/ui/dist/assets/archive-D5my9zOG.js +1 -0
- package/ui/dist/assets/badge-B4ov81_m.js +1 -0
- package/ui/dist/assets/brain-C53ElFLD.js +1 -0
- package/ui/dist/assets/bug-D0TJoCYn.js +1 -0
- package/ui/dist/assets/calendar-BkWIhKa1.js +1 -0
- package/ui/dist/assets/chevron-up-BRTtndUZ.js +1 -0
- package/ui/dist/assets/circle-x-BN89YhbS.js +1 -0
- package/ui/dist/assets/constants-fc7TFI7u.js +1 -0
- package/ui/dist/assets/cpu-B41x1-vV.js +1 -0
- package/ui/dist/assets/database-D9Cnfmzj.js +1 -0
- package/ui/dist/assets/defineProperty-CoXUr7_6.js +2 -0
- package/ui/dist/assets/dialog-DrWB4EYD.js +1 -0
- package/ui/dist/assets/element-adapter-DL0DQilL.js +4 -0
- package/ui/dist/assets/ellipsis-NuUWekvu.js +1 -0
- package/ui/dist/assets/ellipsis-vertical-BueMfuCw.js +1 -0
- package/ui/dist/assets/file-code-HR9829Jc.js +1 -0
- package/ui/dist/assets/folder-open-C_7oYEqe.js +1 -0
- package/ui/dist/assets/funnel-B5gmNXGf.js +1 -0
- package/ui/dist/assets/git-branch-BRMiJmV3.js +1 -0
- package/ui/dist/assets/git-commit-horizontal-CXOUQeJI.js +1 -0
- package/ui/dist/assets/globe-CCspjvus.js +1 -0
- package/ui/dist/assets/hash-g3102kPC.js +1 -0
- package/ui/dist/assets/history-CNqcBBrV.js +1 -0
- package/ui/dist/assets/index-27mTPKuh.js +1 -0
- package/ui/dist/assets/index-BMx3fH-e.js +1 -0
- package/ui/dist/assets/index-C9jNQXzL.js +1 -0
- package/ui/dist/assets/index-CEZ6R2Uw.js +7 -0
- package/ui/dist/assets/index-DURTouJI.js +1 -0
- package/ui/dist/assets/index-WclMPci1.css +1 -0
- package/ui/dist/assets/index-kb4AJXUB.js +67 -0
- package/ui/dist/assets/layers-CLXiHN6o.js +1 -0
- package/ui/dist/assets/layout-dashboard-B07MFhBs.js +1 -0
- package/ui/dist/assets/lightbulb-B2dgG5ks.js +1 -0
- package/ui/dist/assets/link-2-BxNmr9hL.js +1 -0
- package/ui/dist/assets/markdown-renderer-CjU6hBcW.js +36 -0
- package/ui/dist/assets/message-square-Bf2-CVbt.js +1 -0
- package/ui/dist/assets/pencil-D096Ey62.js +1 -0
- package/ui/dist/assets/play-DfdcSI3x.js +1 -0
- package/ui/dist/assets/popover-BV0QJDQq.js +1 -0
- package/ui/dist/assets/progress-DjPEDJfI.js +1 -0
- package/ui/dist/assets/rocket-CPsTc-5G.js +1 -0
- package/ui/dist/assets/select-LsO16slr.js +1 -0
- package/ui/dist/assets/send-BDYBZDUZ.js +1 -0
- package/ui/dist/assets/server-B3k6noce.js +1 -0
- package/ui/dist/assets/settings-2-Cu4xTjhG.js +1 -0
- package/ui/dist/assets/sheet-BScLnPKX.js +1 -0
- package/ui/dist/assets/shield-check-CQqkwufI.js +1 -0
- package/ui/dist/assets/shield-off-ZFruH9KO.js +1 -0
- package/ui/dist/assets/skeleton-CtkIA_MU.js +1 -0
- package/ui/dist/assets/smartphone-DnoksVkc.js +1 -0
- package/ui/dist/assets/square-uD9ZHMfW.js +1 -0
- package/ui/dist/assets/switch-MQPnwGJK.js +1 -0
- package/ui/dist/assets/table-B8cqlywA.js +1 -0
- package/ui/dist/assets/tag-wEJQRWlV.js +1 -0
- package/ui/dist/assets/textarea-D5LJCOGl.js +1 -0
- package/ui/dist/assets/timer-mbGHegmr.js +1 -0
- package/ui/dist/assets/tooltip-Df1CunSp.js +1 -0
- package/ui/dist/assets/trash-2-B4oAXsX-.js +1 -0
- package/ui/dist/assets/trending-up-BGWxvlmZ.js +1 -0
- package/ui/dist/assets/wand-sparkles-CZy4xvL3.js +1 -0
- package/ui/dist/assets/wrench-ByZkjO6m.js +1 -0
- package/ui/dist/audio-worklets/vad-processor.js +132 -0
- package/ui/dist/brand/profclaw-appicon-192.png +0 -0
- package/ui/dist/brand/profclaw-appicon-512.png +0 -0
- package/ui/dist/brand/profclaw-appicon-shadow.svg +51 -0
- package/ui/dist/brand/profclaw-appicon.svg +50 -0
- package/ui/dist/brand/profclaw-favicon-coral-bg-128.png +0 -0
- package/ui/dist/brand/profclaw-favicon-coral-bg-64.png +0 -0
- package/ui/dist/brand/profclaw-favicon-coral-bg.svg +52 -0
- package/ui/dist/brand/profclaw-favicon-coral-body-128.png +0 -0
- package/ui/dist/brand/profclaw-favicon-coral-body.svg +41 -0
- package/ui/dist/brand/profclaw-favicon-shadow-128.png +0 -0
- package/ui/dist/brand/profclaw-favicon-shadow-64.png +0 -0
- package/ui/dist/brand/profclaw-favicon-shadow.svg +51 -0
- package/ui/dist/brand/profclaw-mark-coral-256.png +0 -0
- package/ui/dist/brand/profclaw-mark-coral-64.png +0 -0
- package/ui/dist/brand/profclaw-mark-coral.svg +31 -0
- package/ui/dist/brand/profclaw-mono-white.svg +18 -0
- package/ui/dist/brand/profclaw-text-dark.svg +18 -0
- package/ui/dist/brand/profclaw-text-light.svg +18 -0
- package/ui/dist/brand/profclaw-wordmark-dark.svg +48 -0
- package/ui/dist/brand/profclaw-wordmark-light.svg +48 -0
- package/ui/dist/brand/safari-pinned-tab.svg +15 -0
- package/ui/dist/favicon/android-chrome-192x192.png +0 -0
- package/ui/dist/favicon/android-chrome-384x384.png +0 -0
- package/ui/dist/favicon/android-chrome-512x512.png +0 -0
- package/ui/dist/favicon/apple-touch-icon.png +0 -0
- package/ui/dist/favicon/browserconfig.xml +9 -0
- package/ui/dist/favicon/favicon-16x16.png +0 -0
- package/ui/dist/favicon/favicon-32x32.png +0 -0
- package/ui/dist/favicon/favicon.ico +0 -0
- package/ui/dist/favicon/mstile-150x150.png +0 -0
- package/ui/dist/favicon/safari-pinned-tab.svg +46 -0
- package/ui/dist/favicon/site.webmanifest +22 -0
- package/ui/dist/index.html +32 -0
- package/ui/dist/manifest.json +49 -0
- package/ui/dist/sw.js +124 -0
- package/ui/dist/vite.svg +1 -0
|
@@ -0,0 +1,1090 @@
|
|
|
1
|
+
import { Hono } from "hono";
|
|
2
|
+
import { validateFileUpload, sanitizeFilename } from "../utils/security.js";
|
|
3
|
+
import { createContextualLogger } from "../utils/logger.js";
|
|
4
|
+
const log = createContextualLogger('Tickets');
|
|
5
|
+
import { createTicket, getTicket, getTicketWithRelations, updateTicket, deleteTicket, queryTickets, createExternalLink, getExternalLinks, createTicketRelation, getTicketRelations, deleteTicketRelation, addTicketWatcher, removeTicketWatcher, getTicketWatchers, addTicketAssignee, removeTicketAssignee, getTicketAssignees, addTicketMention, getTicketMentions, addTicketAttachment, getTicketAttachments, deleteTicketAttachment, addTicketReaction, getTicketReactions, deleteTicketReaction, bulkUpdateTickets, bulkDeleteTickets, addComment, getComments, getHistory, CreateTicketSchema, UpdateTicketSchema, BulkUpdateTicketsSchema, BulkDeleteTicketsSchema, TicketRelationType, } from "../tickets/index.js";
|
|
6
|
+
const ticketsRouter = new Hono();
|
|
7
|
+
// === List/Query Tickets ===
|
|
8
|
+
// Sparse fieldset: default fields for list view (Phase 17 optimization)
|
|
9
|
+
const LIST_FIELDS = [
|
|
10
|
+
"id",
|
|
11
|
+
"sequence",
|
|
12
|
+
"projectId",
|
|
13
|
+
"title",
|
|
14
|
+
"type",
|
|
15
|
+
"priority",
|
|
16
|
+
"status",
|
|
17
|
+
"labels",
|
|
18
|
+
"assignee",
|
|
19
|
+
"assigneeAgent",
|
|
20
|
+
"createdAt",
|
|
21
|
+
"updatedAt",
|
|
22
|
+
"startDate",
|
|
23
|
+
"dueDate",
|
|
24
|
+
"estimate",
|
|
25
|
+
"estimateUnit",
|
|
26
|
+
"createdBy",
|
|
27
|
+
];
|
|
28
|
+
// Helper to pick only specified fields from an object
|
|
29
|
+
function pickFields(obj, fields) {
|
|
30
|
+
const result = {};
|
|
31
|
+
for (const field of fields) {
|
|
32
|
+
if (field in obj) {
|
|
33
|
+
result[field] = obj[field];
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return result;
|
|
37
|
+
}
|
|
38
|
+
function encodeCursor(data) {
|
|
39
|
+
return Buffer.from(JSON.stringify(data)).toString("base64url");
|
|
40
|
+
}
|
|
41
|
+
function decodeCursor(cursor) {
|
|
42
|
+
try {
|
|
43
|
+
const json = Buffer.from(cursor, "base64url").toString("utf-8");
|
|
44
|
+
const data = JSON.parse(json);
|
|
45
|
+
if (typeof data.createdAt === "number" && typeof data.id === "string") {
|
|
46
|
+
return data;
|
|
47
|
+
}
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
function getNextCursor(items, limit) {
|
|
55
|
+
if (items.length < limit)
|
|
56
|
+
return null; // No more pages
|
|
57
|
+
const lastItem = items[items.length - 1];
|
|
58
|
+
if (!lastItem?.createdAt)
|
|
59
|
+
return null;
|
|
60
|
+
const createdAt = lastItem.createdAt instanceof Date
|
|
61
|
+
? lastItem.createdAt.getTime()
|
|
62
|
+
: typeof lastItem.createdAt === "string"
|
|
63
|
+
? new Date(lastItem.createdAt).getTime()
|
|
64
|
+
: lastItem.createdAt;
|
|
65
|
+
return encodeCursor({ createdAt, id: lastItem.id });
|
|
66
|
+
}
|
|
67
|
+
ticketsRouter.get("/", async (c) => {
|
|
68
|
+
const queryParams = {};
|
|
69
|
+
// Parse query params
|
|
70
|
+
const projectId = c.req.query("projectId");
|
|
71
|
+
const sprintId = c.req.query("sprintId");
|
|
72
|
+
const inBacklog = c.req.query("inBacklog");
|
|
73
|
+
const status = c.req.query("status");
|
|
74
|
+
const type = c.req.query("type");
|
|
75
|
+
const priority = c.req.query("priority");
|
|
76
|
+
const assignee = c.req.query("assignee");
|
|
77
|
+
const assigneeAgent = c.req.query("assigneeAgent");
|
|
78
|
+
const parentId = c.req.query("parentId");
|
|
79
|
+
const search = c.req.query("search") || c.req.query("q");
|
|
80
|
+
const createdBy = c.req.query("createdBy");
|
|
81
|
+
const label = c.req.query("label");
|
|
82
|
+
const labels = c.req.query("labels");
|
|
83
|
+
const sortBy = c.req.query("sortBy");
|
|
84
|
+
const sortOrder = c.req.query("sortOrder");
|
|
85
|
+
const limit = c.req.query("limit");
|
|
86
|
+
const offset = c.req.query("offset");
|
|
87
|
+
// Cursor-based pagination (Phase 17) - takes precedence over offset
|
|
88
|
+
const cursor = c.req.query("cursor");
|
|
89
|
+
const cursorData = cursor ? decodeCursor(cursor) : null;
|
|
90
|
+
// Sparse fieldset support (Phase 17)
|
|
91
|
+
const fieldsParam = c.req.query("fields"); // Comma-separated field names
|
|
92
|
+
const sparseFields = fieldsParam
|
|
93
|
+
? fieldsParam.split(",").map((f) => f.trim())
|
|
94
|
+
: null;
|
|
95
|
+
const includeFull = c.req.query("full") === "true"; // Backward compat: return full objects
|
|
96
|
+
// Project/Sprint filtering
|
|
97
|
+
if (projectId)
|
|
98
|
+
queryParams.projectId = projectId;
|
|
99
|
+
if (sprintId)
|
|
100
|
+
queryParams.sprintId = sprintId;
|
|
101
|
+
if (inBacklog === "true")
|
|
102
|
+
queryParams.inBacklog = true;
|
|
103
|
+
if (status)
|
|
104
|
+
queryParams.status = status.includes(",") ? status.split(",") : status;
|
|
105
|
+
if (type)
|
|
106
|
+
queryParams.type = type.includes(",") ? type.split(",") : type;
|
|
107
|
+
if (priority)
|
|
108
|
+
queryParams.priority = priority.includes(",")
|
|
109
|
+
? priority.split(",")
|
|
110
|
+
: priority;
|
|
111
|
+
if (assignee)
|
|
112
|
+
queryParams.assignee = assignee;
|
|
113
|
+
if (assigneeAgent)
|
|
114
|
+
queryParams.assigneeAgent = assigneeAgent;
|
|
115
|
+
if (parentId)
|
|
116
|
+
queryParams.parentId = parentId;
|
|
117
|
+
if (search)
|
|
118
|
+
queryParams.search = search;
|
|
119
|
+
if (createdBy === "human" || createdBy === "ai")
|
|
120
|
+
queryParams.createdBy = createdBy;
|
|
121
|
+
if (label)
|
|
122
|
+
queryParams.label = label;
|
|
123
|
+
if (labels)
|
|
124
|
+
queryParams.labels = labels.split(",");
|
|
125
|
+
if (sortBy)
|
|
126
|
+
queryParams.sortBy = sortBy;
|
|
127
|
+
if (sortOrder)
|
|
128
|
+
queryParams.sortOrder = sortOrder;
|
|
129
|
+
const pageLimit = limit ? parseInt(limit) : 50;
|
|
130
|
+
queryParams.limit = pageLimit;
|
|
131
|
+
// Use cursor for pagination if provided, otherwise fall back to offset
|
|
132
|
+
if (cursorData) {
|
|
133
|
+
queryParams.cursorCreatedAt = new Date(cursorData.createdAt);
|
|
134
|
+
queryParams.cursorId = cursorData.id;
|
|
135
|
+
}
|
|
136
|
+
else if (offset) {
|
|
137
|
+
queryParams.offset = parseInt(offset);
|
|
138
|
+
}
|
|
139
|
+
try {
|
|
140
|
+
const result = await queryTickets(queryParams);
|
|
141
|
+
// Apply sparse fieldset - return only list fields by default
|
|
142
|
+
const tickets = !includeFull
|
|
143
|
+
? result.tickets.map((t) => pickFields(t, sparseFields || [...LIST_FIELDS]))
|
|
144
|
+
: result.tickets;
|
|
145
|
+
// Generate next cursor from full tickets (before sparse filtering)
|
|
146
|
+
const nextCursor = getNextCursor(result.tickets, pageLimit);
|
|
147
|
+
return c.json({
|
|
148
|
+
tickets,
|
|
149
|
+
total: result.total,
|
|
150
|
+
limit: pageLimit,
|
|
151
|
+
nextCursor, // For cursor-based pagination
|
|
152
|
+
offset: queryParams.offset || 0,
|
|
153
|
+
sparse: !includeFull, // Indicate if response is sparse
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
catch (error) {
|
|
157
|
+
log.error('Error querying tickets', error instanceof Error ? error : new Error(String(error)));
|
|
158
|
+
return c.json({ error: "Failed to query tickets" }, 500);
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
// === Create Ticket ===
|
|
162
|
+
ticketsRouter.post("/", async (c) => {
|
|
163
|
+
try {
|
|
164
|
+
const body = await c.req.json();
|
|
165
|
+
const parsed = CreateTicketSchema.safeParse(body);
|
|
166
|
+
if (!parsed.success) {
|
|
167
|
+
return c.json({
|
|
168
|
+
error: "Validation failed",
|
|
169
|
+
details: parsed.error.flatten(),
|
|
170
|
+
}, 400);
|
|
171
|
+
}
|
|
172
|
+
const ticket = await createTicket(parsed.data);
|
|
173
|
+
return c.json({
|
|
174
|
+
message: "Ticket created",
|
|
175
|
+
ticket,
|
|
176
|
+
}, 201);
|
|
177
|
+
}
|
|
178
|
+
catch (error) {
|
|
179
|
+
log.error('Error creating ticket', error instanceof Error ? error : new Error(String(error)));
|
|
180
|
+
return c.json({
|
|
181
|
+
error: "Failed to create ticket",
|
|
182
|
+
message: error instanceof Error ? error.message : "Unknown error",
|
|
183
|
+
}, 500);
|
|
184
|
+
}
|
|
185
|
+
});
|
|
186
|
+
// === Bulk Operations ===
|
|
187
|
+
ticketsRouter.post("/bulk-update", async (c) => {
|
|
188
|
+
try {
|
|
189
|
+
const body = await c.req.json();
|
|
190
|
+
const parsed = BulkUpdateTicketsSchema.safeParse(body);
|
|
191
|
+
if (!parsed.success) {
|
|
192
|
+
return c.json({
|
|
193
|
+
error: "Validation failed",
|
|
194
|
+
details: parsed.error.flatten(),
|
|
195
|
+
}, 400);
|
|
196
|
+
}
|
|
197
|
+
const result = await bulkUpdateTickets(parsed.data);
|
|
198
|
+
return c.json({
|
|
199
|
+
message: "Bulk update completed",
|
|
200
|
+
updated: result.updated,
|
|
201
|
+
failed: result.failed,
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
catch (error) {
|
|
205
|
+
log.error('Error bulk updating tickets', error instanceof Error ? error : new Error(String(error)));
|
|
206
|
+
return c.json({ error: "Failed to bulk update tickets" }, 500);
|
|
207
|
+
}
|
|
208
|
+
});
|
|
209
|
+
ticketsRouter.post("/bulk-delete", async (c) => {
|
|
210
|
+
try {
|
|
211
|
+
const body = await c.req.json();
|
|
212
|
+
const parsed = BulkDeleteTicketsSchema.safeParse(body);
|
|
213
|
+
if (!parsed.success) {
|
|
214
|
+
return c.json({
|
|
215
|
+
error: "Validation failed",
|
|
216
|
+
details: parsed.error.flatten(),
|
|
217
|
+
}, 400);
|
|
218
|
+
}
|
|
219
|
+
const result = await bulkDeleteTickets(parsed.data);
|
|
220
|
+
return c.json({
|
|
221
|
+
message: "Bulk delete completed",
|
|
222
|
+
deletedIds: result.deletedIds,
|
|
223
|
+
failed: result.failed,
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
catch (error) {
|
|
227
|
+
log.error('Error bulk deleting tickets', error instanceof Error ? error : new Error(String(error)));
|
|
228
|
+
return c.json({ error: "Failed to bulk delete tickets" }, 500);
|
|
229
|
+
}
|
|
230
|
+
});
|
|
231
|
+
// === Get Single Ticket ===
|
|
232
|
+
ticketsRouter.get("/:id", async (c) => {
|
|
233
|
+
const id = c.req.param("id");
|
|
234
|
+
const includeRelations = c.req.query("include") === "all";
|
|
235
|
+
try {
|
|
236
|
+
const ticket = includeRelations
|
|
237
|
+
? await getTicketWithRelations(id)
|
|
238
|
+
: await getTicket(id);
|
|
239
|
+
if (!ticket) {
|
|
240
|
+
return c.json({ error: "Ticket not found" }, 404);
|
|
241
|
+
}
|
|
242
|
+
return c.json({ ticket });
|
|
243
|
+
}
|
|
244
|
+
catch (error) {
|
|
245
|
+
log.error('Error fetching ticket', error instanceof Error ? error : new Error(String(error)));
|
|
246
|
+
return c.json({ error: "Failed to fetch ticket" }, 500);
|
|
247
|
+
}
|
|
248
|
+
});
|
|
249
|
+
// === Update Ticket ===
|
|
250
|
+
ticketsRouter.patch("/:id", async (c) => {
|
|
251
|
+
const id = c.req.param("id");
|
|
252
|
+
try {
|
|
253
|
+
const body = await c.req.json();
|
|
254
|
+
const parsed = UpdateTicketSchema.safeParse(body);
|
|
255
|
+
if (!parsed.success) {
|
|
256
|
+
return c.json({
|
|
257
|
+
error: "Validation failed",
|
|
258
|
+
details: parsed.error.flatten(),
|
|
259
|
+
}, 400);
|
|
260
|
+
}
|
|
261
|
+
const ticket = await updateTicket(id, parsed.data);
|
|
262
|
+
if (!ticket) {
|
|
263
|
+
return c.json({ error: "Ticket not found" }, 404);
|
|
264
|
+
}
|
|
265
|
+
return c.json({
|
|
266
|
+
message: "Ticket updated",
|
|
267
|
+
ticket,
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
catch (error) {
|
|
271
|
+
log.error('Error updating ticket', error instanceof Error ? error : new Error(String(error)));
|
|
272
|
+
return c.json({
|
|
273
|
+
error: "Failed to update ticket",
|
|
274
|
+
message: error instanceof Error ? error.message : "Unknown error",
|
|
275
|
+
}, 500);
|
|
276
|
+
}
|
|
277
|
+
});
|
|
278
|
+
// === Delete Ticket ===
|
|
279
|
+
ticketsRouter.delete("/:id", async (c) => {
|
|
280
|
+
const id = c.req.param("id");
|
|
281
|
+
try {
|
|
282
|
+
const deleted = await deleteTicket(id);
|
|
283
|
+
if (!deleted) {
|
|
284
|
+
return c.json({ error: "Ticket not found" }, 404);
|
|
285
|
+
}
|
|
286
|
+
return c.json({ message: "Ticket deleted" });
|
|
287
|
+
}
|
|
288
|
+
catch (error) {
|
|
289
|
+
log.error('Error deleting ticket', error instanceof Error ? error : new Error(String(error)));
|
|
290
|
+
return c.json({ error: "Failed to delete ticket" }, 500);
|
|
291
|
+
}
|
|
292
|
+
});
|
|
293
|
+
// === External Links ===
|
|
294
|
+
ticketsRouter.get("/:id/links", async (c) => {
|
|
295
|
+
const id = c.req.param("id");
|
|
296
|
+
try {
|
|
297
|
+
const ticket = await getTicket(id);
|
|
298
|
+
if (!ticket) {
|
|
299
|
+
return c.json({ error: "Ticket not found" }, 404);
|
|
300
|
+
}
|
|
301
|
+
const links = await getExternalLinks(id);
|
|
302
|
+
return c.json({ ticketId: id, links, count: links.length });
|
|
303
|
+
}
|
|
304
|
+
catch (error) {
|
|
305
|
+
log.error('Error fetching links', error instanceof Error ? error : new Error(String(error)));
|
|
306
|
+
return c.json({ error: "Failed to fetch links" }, 500);
|
|
307
|
+
}
|
|
308
|
+
});
|
|
309
|
+
ticketsRouter.post("/:id/links", async (c) => {
|
|
310
|
+
const id = c.req.param("id");
|
|
311
|
+
try {
|
|
312
|
+
const ticket = await getTicket(id);
|
|
313
|
+
if (!ticket) {
|
|
314
|
+
return c.json({ error: "Ticket not found" }, 404);
|
|
315
|
+
}
|
|
316
|
+
const body = await c.req.json();
|
|
317
|
+
const { platform, externalId, externalUrl } = body;
|
|
318
|
+
if (!platform || !externalId) {
|
|
319
|
+
return c.json({ error: "platform and externalId are required" }, 400);
|
|
320
|
+
}
|
|
321
|
+
const link = await createExternalLink(id, {
|
|
322
|
+
platform,
|
|
323
|
+
externalId,
|
|
324
|
+
externalUrl,
|
|
325
|
+
});
|
|
326
|
+
return c.json({
|
|
327
|
+
message: "External link created",
|
|
328
|
+
link,
|
|
329
|
+
}, 201);
|
|
330
|
+
}
|
|
331
|
+
catch (error) {
|
|
332
|
+
log.error('Error creating link', error instanceof Error ? error : new Error(String(error)));
|
|
333
|
+
return c.json({ error: "Failed to create link" }, 500);
|
|
334
|
+
}
|
|
335
|
+
});
|
|
336
|
+
// === Comments ===
|
|
337
|
+
ticketsRouter.get("/:id/comments", async (c) => {
|
|
338
|
+
const id = c.req.param("id");
|
|
339
|
+
try {
|
|
340
|
+
const ticket = await getTicket(id);
|
|
341
|
+
if (!ticket) {
|
|
342
|
+
return c.json({ error: "Ticket not found" }, 404);
|
|
343
|
+
}
|
|
344
|
+
const comments = await getComments(id);
|
|
345
|
+
return c.json({ ticketId: id, comments, count: comments.length });
|
|
346
|
+
}
|
|
347
|
+
catch (error) {
|
|
348
|
+
log.error('Error fetching comments', error instanceof Error ? error : new Error(String(error)));
|
|
349
|
+
return c.json({ error: "Failed to fetch comments" }, 500);
|
|
350
|
+
}
|
|
351
|
+
});
|
|
352
|
+
ticketsRouter.post("/:id/comments", async (c) => {
|
|
353
|
+
const id = c.req.param("id");
|
|
354
|
+
try {
|
|
355
|
+
const ticket = await getTicket(id);
|
|
356
|
+
if (!ticket) {
|
|
357
|
+
return c.json({ error: "Ticket not found" }, 404);
|
|
358
|
+
}
|
|
359
|
+
const body = await c.req.json();
|
|
360
|
+
const { content, author } = body;
|
|
361
|
+
if (!content) {
|
|
362
|
+
return c.json({ error: "content is required" }, 400);
|
|
363
|
+
}
|
|
364
|
+
const commentAuthor = author || {
|
|
365
|
+
type: "human",
|
|
366
|
+
name: "User",
|
|
367
|
+
platform: "profclaw",
|
|
368
|
+
};
|
|
369
|
+
const comment = await addComment(id, content, commentAuthor);
|
|
370
|
+
return c.json({
|
|
371
|
+
message: "Comment added",
|
|
372
|
+
comment,
|
|
373
|
+
}, 201);
|
|
374
|
+
}
|
|
375
|
+
catch (error) {
|
|
376
|
+
log.error('Error adding comment', error instanceof Error ? error : new Error(String(error)));
|
|
377
|
+
return c.json({ error: "Failed to add comment" }, 500);
|
|
378
|
+
}
|
|
379
|
+
});
|
|
380
|
+
// === History ===
|
|
381
|
+
ticketsRouter.get("/:id/history", async (c) => {
|
|
382
|
+
const id = c.req.param("id");
|
|
383
|
+
try {
|
|
384
|
+
const ticket = await getTicket(id);
|
|
385
|
+
if (!ticket) {
|
|
386
|
+
return c.json({ error: "Ticket not found" }, 404);
|
|
387
|
+
}
|
|
388
|
+
const history = await getHistory(id);
|
|
389
|
+
return c.json({ ticketId: id, history, count: history.length });
|
|
390
|
+
}
|
|
391
|
+
catch (error) {
|
|
392
|
+
console.error("[API] Error fetching history:", error);
|
|
393
|
+
return c.json({ error: "Failed to fetch history" }, 500);
|
|
394
|
+
}
|
|
395
|
+
});
|
|
396
|
+
// === Relations ===
|
|
397
|
+
ticketsRouter.get("/:id/relations", async (c) => {
|
|
398
|
+
const id = c.req.param("id");
|
|
399
|
+
try {
|
|
400
|
+
const ticket = await getTicket(id);
|
|
401
|
+
if (!ticket) {
|
|
402
|
+
return c.json({ error: "Ticket not found" }, 404);
|
|
403
|
+
}
|
|
404
|
+
const relations = await getTicketRelations(id);
|
|
405
|
+
return c.json({ ticketId: id, relations, count: relations.length });
|
|
406
|
+
}
|
|
407
|
+
catch (error) {
|
|
408
|
+
console.error("[API] Error fetching relations:", error);
|
|
409
|
+
return c.json({ error: "Failed to fetch relations" }, 500);
|
|
410
|
+
}
|
|
411
|
+
});
|
|
412
|
+
ticketsRouter.post("/:id/relations", async (c) => {
|
|
413
|
+
const id = c.req.param("id");
|
|
414
|
+
try {
|
|
415
|
+
const ticket = await getTicket(id);
|
|
416
|
+
if (!ticket) {
|
|
417
|
+
return c.json({ error: "Ticket not found" }, 404);
|
|
418
|
+
}
|
|
419
|
+
const body = await c.req.json();
|
|
420
|
+
const { targetId, relationType } = body;
|
|
421
|
+
if (!targetId || !relationType) {
|
|
422
|
+
return c.json({ error: "targetId and relationType are required" }, 400);
|
|
423
|
+
}
|
|
424
|
+
if (targetId === id) {
|
|
425
|
+
return c.json({ error: "Ticket cannot relate to itself" }, 400);
|
|
426
|
+
}
|
|
427
|
+
const relationTypeParse = TicketRelationType.safeParse(relationType);
|
|
428
|
+
if (!relationTypeParse.success) {
|
|
429
|
+
return c.json({
|
|
430
|
+
error: `Invalid relationType. Must be one of: ${TicketRelationType.options.join(", ")}`,
|
|
431
|
+
}, 400);
|
|
432
|
+
}
|
|
433
|
+
const targetTicket = await getTicket(targetId);
|
|
434
|
+
if (!targetTicket) {
|
|
435
|
+
return c.json({ error: "Target ticket not found" }, 404);
|
|
436
|
+
}
|
|
437
|
+
const relation = await createTicketRelation(id, targetId, relationTypeParse.data);
|
|
438
|
+
return c.json({
|
|
439
|
+
message: "Relation created",
|
|
440
|
+
relation,
|
|
441
|
+
}, 201);
|
|
442
|
+
}
|
|
443
|
+
catch (error) {
|
|
444
|
+
console.error("[API] Error creating relation:", error);
|
|
445
|
+
return c.json({ error: "Failed to create relation" }, 500);
|
|
446
|
+
}
|
|
447
|
+
});
|
|
448
|
+
ticketsRouter.delete("/:id/relations/:relationId", async (c) => {
|
|
449
|
+
const id = c.req.param("id");
|
|
450
|
+
const relationId = c.req.param("relationId");
|
|
451
|
+
try {
|
|
452
|
+
const ticket = await getTicket(id);
|
|
453
|
+
if (!ticket) {
|
|
454
|
+
return c.json({ error: "Ticket not found" }, 404);
|
|
455
|
+
}
|
|
456
|
+
const deleted = await deleteTicketRelation(relationId, id);
|
|
457
|
+
if (!deleted) {
|
|
458
|
+
return c.json({ error: "Relation not found" }, 404);
|
|
459
|
+
}
|
|
460
|
+
return c.json({ message: "Relation deleted" });
|
|
461
|
+
}
|
|
462
|
+
catch (error) {
|
|
463
|
+
console.error("[API] Error deleting relation:", error);
|
|
464
|
+
return c.json({ error: "Failed to delete relation" }, 500);
|
|
465
|
+
}
|
|
466
|
+
});
|
|
467
|
+
// === Watchers ===
|
|
468
|
+
ticketsRouter.get("/:id/watchers", async (c) => {
|
|
469
|
+
const id = c.req.param("id");
|
|
470
|
+
try {
|
|
471
|
+
const ticket = await getTicket(id);
|
|
472
|
+
if (!ticket) {
|
|
473
|
+
return c.json({ error: "Ticket not found" }, 404);
|
|
474
|
+
}
|
|
475
|
+
const watchers = await getTicketWatchers(id);
|
|
476
|
+
return c.json({ ticketId: id, watchers, count: watchers.length });
|
|
477
|
+
}
|
|
478
|
+
catch (error) {
|
|
479
|
+
console.error("[API] Error fetching watchers:", error);
|
|
480
|
+
return c.json({ error: "Failed to fetch watchers" }, 500);
|
|
481
|
+
}
|
|
482
|
+
});
|
|
483
|
+
ticketsRouter.post("/:id/watchers", async (c) => {
|
|
484
|
+
const id = c.req.param("id");
|
|
485
|
+
try {
|
|
486
|
+
const ticket = await getTicket(id);
|
|
487
|
+
if (!ticket) {
|
|
488
|
+
return c.json({ error: "Ticket not found" }, 404);
|
|
489
|
+
}
|
|
490
|
+
const body = await c.req.json();
|
|
491
|
+
const { userId } = body;
|
|
492
|
+
if (!userId) {
|
|
493
|
+
return c.json({ error: "userId is required" }, 400);
|
|
494
|
+
}
|
|
495
|
+
const watcher = await addTicketWatcher(id, userId);
|
|
496
|
+
return c.json({ message: "Watcher added", watcher }, 201);
|
|
497
|
+
}
|
|
498
|
+
catch (error) {
|
|
499
|
+
console.error("[API] Error adding watcher:", error);
|
|
500
|
+
return c.json({ error: "Failed to add watcher" }, 500);
|
|
501
|
+
}
|
|
502
|
+
});
|
|
503
|
+
ticketsRouter.delete("/:id/watchers/:userId", async (c) => {
|
|
504
|
+
const id = c.req.param("id");
|
|
505
|
+
const userId = c.req.param("userId");
|
|
506
|
+
try {
|
|
507
|
+
const ticket = await getTicket(id);
|
|
508
|
+
if (!ticket) {
|
|
509
|
+
return c.json({ error: "Ticket not found" }, 404);
|
|
510
|
+
}
|
|
511
|
+
const removed = await removeTicketWatcher(id, userId);
|
|
512
|
+
if (!removed) {
|
|
513
|
+
return c.json({ error: "Watcher not found" }, 404);
|
|
514
|
+
}
|
|
515
|
+
return c.json({ message: "Watcher removed" });
|
|
516
|
+
}
|
|
517
|
+
catch (error) {
|
|
518
|
+
console.error("[API] Error removing watcher:", error);
|
|
519
|
+
return c.json({ error: "Failed to remove watcher" }, 500);
|
|
520
|
+
}
|
|
521
|
+
});
|
|
522
|
+
// === Assignees ===
|
|
523
|
+
ticketsRouter.get("/:id/assignees", async (c) => {
|
|
524
|
+
const id = c.req.param("id");
|
|
525
|
+
try {
|
|
526
|
+
const ticket = await getTicket(id);
|
|
527
|
+
if (!ticket) {
|
|
528
|
+
return c.json({ error: "Ticket not found" }, 404);
|
|
529
|
+
}
|
|
530
|
+
const assignees = await getTicketAssignees(id);
|
|
531
|
+
return c.json({ ticketId: id, assignees, count: assignees.length });
|
|
532
|
+
}
|
|
533
|
+
catch (error) {
|
|
534
|
+
console.error("[API] Error fetching assignees:", error);
|
|
535
|
+
return c.json({ error: "Failed to fetch assignees" }, 500);
|
|
536
|
+
}
|
|
537
|
+
});
|
|
538
|
+
ticketsRouter.post("/:id/assignees", async (c) => {
|
|
539
|
+
const id = c.req.param("id");
|
|
540
|
+
try {
|
|
541
|
+
const ticket = await getTicket(id);
|
|
542
|
+
if (!ticket) {
|
|
543
|
+
return c.json({ error: "Ticket not found" }, 404);
|
|
544
|
+
}
|
|
545
|
+
const body = await c.req.json();
|
|
546
|
+
const { userId } = body;
|
|
547
|
+
if (!userId) {
|
|
548
|
+
return c.json({ error: "userId is required" }, 400);
|
|
549
|
+
}
|
|
550
|
+
const assignee = await addTicketAssignee(id, userId);
|
|
551
|
+
return c.json({ message: "Assignee added", assignee }, 201);
|
|
552
|
+
}
|
|
553
|
+
catch (error) {
|
|
554
|
+
console.error("[API] Error adding assignee:", error);
|
|
555
|
+
return c.json({ error: "Failed to add assignee" }, 500);
|
|
556
|
+
}
|
|
557
|
+
});
|
|
558
|
+
ticketsRouter.delete("/:id/assignees/:userId", async (c) => {
|
|
559
|
+
const id = c.req.param("id");
|
|
560
|
+
const userId = c.req.param("userId");
|
|
561
|
+
try {
|
|
562
|
+
const ticket = await getTicket(id);
|
|
563
|
+
if (!ticket) {
|
|
564
|
+
return c.json({ error: "Ticket not found" }, 404);
|
|
565
|
+
}
|
|
566
|
+
const removed = await removeTicketAssignee(id, userId);
|
|
567
|
+
if (!removed) {
|
|
568
|
+
return c.json({ error: "Assignee not found" }, 404);
|
|
569
|
+
}
|
|
570
|
+
return c.json({ message: "Assignee removed" });
|
|
571
|
+
}
|
|
572
|
+
catch (error) {
|
|
573
|
+
console.error("[API] Error removing assignee:", error);
|
|
574
|
+
return c.json({ error: "Failed to remove assignee" }, 500);
|
|
575
|
+
}
|
|
576
|
+
});
|
|
577
|
+
// === Mentions ===
|
|
578
|
+
ticketsRouter.get("/:id/mentions", async (c) => {
|
|
579
|
+
const id = c.req.param("id");
|
|
580
|
+
try {
|
|
581
|
+
const ticket = await getTicket(id);
|
|
582
|
+
if (!ticket) {
|
|
583
|
+
return c.json({ error: "Ticket not found" }, 404);
|
|
584
|
+
}
|
|
585
|
+
const mentions = await getTicketMentions(id);
|
|
586
|
+
return c.json({ ticketId: id, mentions, count: mentions.length });
|
|
587
|
+
}
|
|
588
|
+
catch (error) {
|
|
589
|
+
console.error("[API] Error fetching mentions:", error);
|
|
590
|
+
return c.json({ error: "Failed to fetch mentions" }, 500);
|
|
591
|
+
}
|
|
592
|
+
});
|
|
593
|
+
ticketsRouter.post("/:id/mentions", async (c) => {
|
|
594
|
+
const id = c.req.param("id");
|
|
595
|
+
try {
|
|
596
|
+
const ticket = await getTicket(id);
|
|
597
|
+
if (!ticket) {
|
|
598
|
+
return c.json({ error: "Ticket not found" }, 404);
|
|
599
|
+
}
|
|
600
|
+
const body = await c.req.json();
|
|
601
|
+
const { userId, source, sourceId } = body;
|
|
602
|
+
if (!userId || !source) {
|
|
603
|
+
return c.json({ error: "userId and source are required" }, 400);
|
|
604
|
+
}
|
|
605
|
+
const mention = await addTicketMention({
|
|
606
|
+
ticketId: id,
|
|
607
|
+
userId,
|
|
608
|
+
source,
|
|
609
|
+
sourceId,
|
|
610
|
+
});
|
|
611
|
+
return c.json({ message: "Mention added", mention }, 201);
|
|
612
|
+
}
|
|
613
|
+
catch (error) {
|
|
614
|
+
console.error("[API] Error adding mention:", error);
|
|
615
|
+
return c.json({ error: "Failed to add mention" }, 500);
|
|
616
|
+
}
|
|
617
|
+
});
|
|
618
|
+
// === Attachments ===
|
|
619
|
+
ticketsRouter.get("/:id/attachments", async (c) => {
|
|
620
|
+
const id = c.req.param("id");
|
|
621
|
+
try {
|
|
622
|
+
const ticket = await getTicket(id);
|
|
623
|
+
if (!ticket) {
|
|
624
|
+
return c.json({ error: "Ticket not found" }, 404);
|
|
625
|
+
}
|
|
626
|
+
const attachments = await getTicketAttachments(id);
|
|
627
|
+
return c.json({ ticketId: id, attachments, count: attachments.length });
|
|
628
|
+
}
|
|
629
|
+
catch (error) {
|
|
630
|
+
console.error("[API] Error fetching attachments:", error);
|
|
631
|
+
return c.json({ error: "Failed to fetch attachments" }, 500);
|
|
632
|
+
}
|
|
633
|
+
});
|
|
634
|
+
ticketsRouter.post("/:id/attachments", async (c) => {
|
|
635
|
+
const id = c.req.param("id");
|
|
636
|
+
try {
|
|
637
|
+
const ticket = await getTicket(id);
|
|
638
|
+
if (!ticket) {
|
|
639
|
+
return c.json({ error: "Ticket not found" }, 404);
|
|
640
|
+
}
|
|
641
|
+
const body = await c.req.json();
|
|
642
|
+
const { fileName, fileType, fileSize, url, storagePath, uploadedBy } = body;
|
|
643
|
+
if (!fileName || !url) {
|
|
644
|
+
return c.json({ error: "fileName and url are required" }, 400);
|
|
645
|
+
}
|
|
646
|
+
// Validate file upload
|
|
647
|
+
const validation = validateFileUpload({ fileName, fileType, fileSize }, { category: 'attachment' });
|
|
648
|
+
if (!validation.valid) {
|
|
649
|
+
return c.json({ error: validation.errors.join(', ') }, 400);
|
|
650
|
+
}
|
|
651
|
+
// Sanitize filename
|
|
652
|
+
const safeFileName = sanitizeFilename(fileName);
|
|
653
|
+
const attachment = await addTicketAttachment({
|
|
654
|
+
ticketId: id,
|
|
655
|
+
fileName: safeFileName,
|
|
656
|
+
fileType,
|
|
657
|
+
fileSize,
|
|
658
|
+
url,
|
|
659
|
+
storagePath,
|
|
660
|
+
uploadedBy,
|
|
661
|
+
});
|
|
662
|
+
return c.json({ message: "Attachment added", attachment }, 201);
|
|
663
|
+
}
|
|
664
|
+
catch (error) {
|
|
665
|
+
console.error("[API] Error adding attachment:", error);
|
|
666
|
+
return c.json({ error: "Failed to add attachment" }, 500);
|
|
667
|
+
}
|
|
668
|
+
});
|
|
669
|
+
ticketsRouter.delete("/:id/attachments/:attachmentId", async (c) => {
|
|
670
|
+
const id = c.req.param("id");
|
|
671
|
+
const attachmentId = c.req.param("attachmentId");
|
|
672
|
+
try {
|
|
673
|
+
const ticket = await getTicket(id);
|
|
674
|
+
if (!ticket) {
|
|
675
|
+
return c.json({ error: "Ticket not found" }, 404);
|
|
676
|
+
}
|
|
677
|
+
const deleted = await deleteTicketAttachment(attachmentId, id);
|
|
678
|
+
if (!deleted) {
|
|
679
|
+
return c.json({ error: "Attachment not found" }, 404);
|
|
680
|
+
}
|
|
681
|
+
return c.json({ message: "Attachment deleted" });
|
|
682
|
+
}
|
|
683
|
+
catch (error) {
|
|
684
|
+
console.error("[API] Error deleting attachment:", error);
|
|
685
|
+
return c.json({ error: "Failed to delete attachment" }, 500);
|
|
686
|
+
}
|
|
687
|
+
});
|
|
688
|
+
// === Reactions ===
|
|
689
|
+
ticketsRouter.get("/:id/reactions", async (c) => {
|
|
690
|
+
const id = c.req.param("id");
|
|
691
|
+
try {
|
|
692
|
+
const ticket = await getTicket(id);
|
|
693
|
+
if (!ticket) {
|
|
694
|
+
return c.json({ error: "Ticket not found" }, 404);
|
|
695
|
+
}
|
|
696
|
+
const reactions = await getTicketReactions(id);
|
|
697
|
+
return c.json({ ticketId: id, reactions, count: reactions.length });
|
|
698
|
+
}
|
|
699
|
+
catch (error) {
|
|
700
|
+
console.error("[API] Error fetching reactions:", error);
|
|
701
|
+
return c.json({ error: "Failed to fetch reactions" }, 500);
|
|
702
|
+
}
|
|
703
|
+
});
|
|
704
|
+
ticketsRouter.post("/:id/reactions", async (c) => {
|
|
705
|
+
const id = c.req.param("id");
|
|
706
|
+
try {
|
|
707
|
+
const ticket = await getTicket(id);
|
|
708
|
+
if (!ticket) {
|
|
709
|
+
return c.json({ error: "Ticket not found" }, 404);
|
|
710
|
+
}
|
|
711
|
+
const body = await c.req.json();
|
|
712
|
+
const { userId, emoji } = body;
|
|
713
|
+
if (!userId || !emoji) {
|
|
714
|
+
return c.json({ error: "userId and emoji are required" }, 400);
|
|
715
|
+
}
|
|
716
|
+
const reaction = await addTicketReaction({
|
|
717
|
+
ticketId: id,
|
|
718
|
+
userId,
|
|
719
|
+
emoji,
|
|
720
|
+
});
|
|
721
|
+
return c.json({ message: "Reaction added", reaction }, 201);
|
|
722
|
+
}
|
|
723
|
+
catch (error) {
|
|
724
|
+
console.error("[API] Error adding reaction:", error);
|
|
725
|
+
return c.json({ error: "Failed to add reaction" }, 500);
|
|
726
|
+
}
|
|
727
|
+
});
|
|
728
|
+
ticketsRouter.delete("/:id/reactions/:reactionId", async (c) => {
|
|
729
|
+
const id = c.req.param("id");
|
|
730
|
+
const reactionId = c.req.param("reactionId");
|
|
731
|
+
try {
|
|
732
|
+
const ticket = await getTicket(id);
|
|
733
|
+
if (!ticket) {
|
|
734
|
+
return c.json({ error: "Ticket not found" }, 404);
|
|
735
|
+
}
|
|
736
|
+
const deleted = await deleteTicketReaction(reactionId, id);
|
|
737
|
+
if (!deleted) {
|
|
738
|
+
return c.json({ error: "Reaction not found" }, 404);
|
|
739
|
+
}
|
|
740
|
+
return c.json({ message: "Reaction deleted" });
|
|
741
|
+
}
|
|
742
|
+
catch (error) {
|
|
743
|
+
console.error("[API] Error deleting reaction:", error);
|
|
744
|
+
return c.json({ error: "Failed to delete reaction" }, 500);
|
|
745
|
+
}
|
|
746
|
+
});
|
|
747
|
+
// === Transition Status (Convenience Endpoint) ===
|
|
748
|
+
ticketsRouter.post("/:id/transition", async (c) => {
|
|
749
|
+
const id = c.req.param("id");
|
|
750
|
+
try {
|
|
751
|
+
const body = await c.req.json();
|
|
752
|
+
const { status } = body;
|
|
753
|
+
if (!status) {
|
|
754
|
+
return c.json({ error: "status is required" }, 400);
|
|
755
|
+
}
|
|
756
|
+
const validStatuses = [
|
|
757
|
+
"backlog",
|
|
758
|
+
"todo",
|
|
759
|
+
"in_progress",
|
|
760
|
+
"in_review",
|
|
761
|
+
"done",
|
|
762
|
+
"cancelled",
|
|
763
|
+
];
|
|
764
|
+
if (!validStatuses.includes(status)) {
|
|
765
|
+
return c.json({
|
|
766
|
+
error: `Invalid status. Must be one of: ${validStatuses.join(", ")}`,
|
|
767
|
+
}, 400);
|
|
768
|
+
}
|
|
769
|
+
const ticket = await updateTicket(id, { status });
|
|
770
|
+
if (!ticket) {
|
|
771
|
+
return c.json({ error: "Ticket not found" }, 404);
|
|
772
|
+
}
|
|
773
|
+
return c.json({
|
|
774
|
+
message: `Ticket transitioned to ${status}`,
|
|
775
|
+
ticket,
|
|
776
|
+
});
|
|
777
|
+
}
|
|
778
|
+
catch (error) {
|
|
779
|
+
console.error("[API] Error transitioning ticket:", error);
|
|
780
|
+
return c.json({ error: "Failed to transition ticket" }, 500);
|
|
781
|
+
}
|
|
782
|
+
});
|
|
783
|
+
// === Assign to Agent ===
|
|
784
|
+
ticketsRouter.post("/:id/assign-agent", async (c) => {
|
|
785
|
+
const id = c.req.param("id");
|
|
786
|
+
try {
|
|
787
|
+
const body = await c.req.json();
|
|
788
|
+
const { agent } = body;
|
|
789
|
+
if (!agent) {
|
|
790
|
+
return c.json({ error: "agent is required" }, 400);
|
|
791
|
+
}
|
|
792
|
+
const ticket = await updateTicket(id, { assigneeAgent: agent });
|
|
793
|
+
if (!ticket) {
|
|
794
|
+
return c.json({ error: "Ticket not found" }, 404);
|
|
795
|
+
}
|
|
796
|
+
return c.json({
|
|
797
|
+
message: `Ticket assigned to ${agent}`,
|
|
798
|
+
ticket,
|
|
799
|
+
});
|
|
800
|
+
}
|
|
801
|
+
catch (error) {
|
|
802
|
+
console.error("[API] Error assigning agent:", error);
|
|
803
|
+
return c.json({ error: "Failed to assign agent" }, 500);
|
|
804
|
+
}
|
|
805
|
+
});
|
|
806
|
+
// === AI-Powered Endpoints ===
|
|
807
|
+
import { isAIAvailable, categorizeTicket, suggestTicketImprovements, summarizeTicket, calculateSimilarity, } from "../utils/ai-inference.js";
|
|
808
|
+
import { processComment, generateResponse, getResponderStatus, } from "../utils/ai-responder.js";
|
|
809
|
+
/**
|
|
810
|
+
* POST /tickets/ai/categorize
|
|
811
|
+
* Auto-categorize a ticket based on title and description
|
|
812
|
+
*/
|
|
813
|
+
ticketsRouter.post("/ai/categorize", async (c) => {
|
|
814
|
+
try {
|
|
815
|
+
const body = await c.req.json();
|
|
816
|
+
const { title, description } = body;
|
|
817
|
+
if (!title) {
|
|
818
|
+
return c.json({ error: "title is required" }, 400);
|
|
819
|
+
}
|
|
820
|
+
// Check if AI is available
|
|
821
|
+
const available = await isAIAvailable();
|
|
822
|
+
if (!available) {
|
|
823
|
+
return c.json({
|
|
824
|
+
error: "AI service unavailable",
|
|
825
|
+
fallback: {
|
|
826
|
+
type: "task",
|
|
827
|
+
priority: "medium",
|
|
828
|
+
labels: [],
|
|
829
|
+
confidence: 0,
|
|
830
|
+
},
|
|
831
|
+
}, 503);
|
|
832
|
+
}
|
|
833
|
+
const result = await categorizeTicket(title, description);
|
|
834
|
+
if (!result.success) {
|
|
835
|
+
return c.json({
|
|
836
|
+
error: result.error || "Categorization failed",
|
|
837
|
+
fallback: {
|
|
838
|
+
type: "task",
|
|
839
|
+
priority: "medium",
|
|
840
|
+
labels: [],
|
|
841
|
+
confidence: 0,
|
|
842
|
+
},
|
|
843
|
+
}, 500);
|
|
844
|
+
}
|
|
845
|
+
return c.json({
|
|
846
|
+
categorization: result.data,
|
|
847
|
+
durationMs: result.durationMs,
|
|
848
|
+
});
|
|
849
|
+
}
|
|
850
|
+
catch (error) {
|
|
851
|
+
console.error("[API] Error categorizing ticket:", error);
|
|
852
|
+
return c.json({ error: "Failed to categorize ticket" }, 500);
|
|
853
|
+
}
|
|
854
|
+
});
|
|
855
|
+
/**
|
|
856
|
+
* POST /tickets/ai/suggest
|
|
857
|
+
* Get AI suggestions to improve a ticket
|
|
858
|
+
*/
|
|
859
|
+
ticketsRouter.post("/ai/suggest", async (c) => {
|
|
860
|
+
try {
|
|
861
|
+
const body = await c.req.json();
|
|
862
|
+
const { title, description, type } = body;
|
|
863
|
+
if (!title) {
|
|
864
|
+
return c.json({ error: "title is required" }, 400);
|
|
865
|
+
}
|
|
866
|
+
const available = await isAIAvailable();
|
|
867
|
+
if (!available) {
|
|
868
|
+
return c.json({ error: "AI service unavailable" }, 503);
|
|
869
|
+
}
|
|
870
|
+
const result = await suggestTicketImprovements(title, description, type);
|
|
871
|
+
if (!result.success) {
|
|
872
|
+
return c.json({ error: result.error || "Suggestion failed" }, 500);
|
|
873
|
+
}
|
|
874
|
+
return c.json({
|
|
875
|
+
suggestions: result.data,
|
|
876
|
+
durationMs: result.durationMs,
|
|
877
|
+
});
|
|
878
|
+
}
|
|
879
|
+
catch (error) {
|
|
880
|
+
console.error("[API] Error getting suggestions:", error);
|
|
881
|
+
return c.json({ error: "Failed to get suggestions" }, 500);
|
|
882
|
+
}
|
|
883
|
+
});
|
|
884
|
+
/**
|
|
885
|
+
* GET /tickets/:id/ai/summary
|
|
886
|
+
* Get an AI-generated summary of a ticket
|
|
887
|
+
*/
|
|
888
|
+
ticketsRouter.get("/:id/ai/summary", async (c) => {
|
|
889
|
+
const id = c.req.param("id");
|
|
890
|
+
try {
|
|
891
|
+
const ticket = await getTicketWithRelations(id);
|
|
892
|
+
if (!ticket) {
|
|
893
|
+
return c.json({ error: "Ticket not found" }, 404);
|
|
894
|
+
}
|
|
895
|
+
const available = await isAIAvailable();
|
|
896
|
+
if (!available) {
|
|
897
|
+
// Fallback: return first 100 chars of description
|
|
898
|
+
return c.json({
|
|
899
|
+
summary: ticket.description?.slice(0, 100) || ticket.title,
|
|
900
|
+
source: "fallback",
|
|
901
|
+
});
|
|
902
|
+
}
|
|
903
|
+
const comments = ticket.comments?.map((c) => c.content) || [];
|
|
904
|
+
const result = await summarizeTicket(ticket.title, ticket.description, comments);
|
|
905
|
+
return c.json({
|
|
906
|
+
summary: result.success ? result.data : ticket.title,
|
|
907
|
+
source: result.success ? "ai" : "fallback",
|
|
908
|
+
durationMs: result.durationMs,
|
|
909
|
+
});
|
|
910
|
+
}
|
|
911
|
+
catch (error) {
|
|
912
|
+
console.error("[API] Error summarizing ticket:", error);
|
|
913
|
+
return c.json({ error: "Failed to summarize ticket" }, 500);
|
|
914
|
+
}
|
|
915
|
+
});
|
|
916
|
+
/**
|
|
917
|
+
* GET /tickets/:id/similar
|
|
918
|
+
* Find similar tickets based on title and description
|
|
919
|
+
*/
|
|
920
|
+
ticketsRouter.get("/:id/similar", async (c) => {
|
|
921
|
+
const id = c.req.param("id");
|
|
922
|
+
const limitParam = c.req.query("limit");
|
|
923
|
+
const limit = limitParam ? parseInt(limitParam, 10) : 5;
|
|
924
|
+
try {
|
|
925
|
+
const ticket = await getTicket(id);
|
|
926
|
+
if (!ticket) {
|
|
927
|
+
return c.json({ error: "Ticket not found" }, 404);
|
|
928
|
+
}
|
|
929
|
+
// Get all tickets to compare
|
|
930
|
+
const { tickets: allTickets } = await queryTickets({ limit: 100 });
|
|
931
|
+
// Calculate similarity scores
|
|
932
|
+
const ticketText = `${ticket.title} ${ticket.description || ""}`;
|
|
933
|
+
const similarities = allTickets
|
|
934
|
+
.filter((t) => t.id !== id) // Exclude the ticket itself
|
|
935
|
+
.map((t) => ({
|
|
936
|
+
id: t.id,
|
|
937
|
+
sequence: t.sequence,
|
|
938
|
+
title: t.title,
|
|
939
|
+
status: t.status,
|
|
940
|
+
type: t.type,
|
|
941
|
+
similarity: calculateSimilarity(ticketText, `${t.title} ${t.description || ""}`),
|
|
942
|
+
}))
|
|
943
|
+
.filter((t) => t.similarity > 0.1) // Minimum similarity threshold
|
|
944
|
+
.sort((a, b) => b.similarity - a.similarity)
|
|
945
|
+
.slice(0, limit);
|
|
946
|
+
return c.json({
|
|
947
|
+
ticketId: id,
|
|
948
|
+
similar: similarities,
|
|
949
|
+
count: similarities.length,
|
|
950
|
+
});
|
|
951
|
+
}
|
|
952
|
+
catch (error) {
|
|
953
|
+
console.error("[API] Error finding similar tickets:", error);
|
|
954
|
+
return c.json({ error: "Failed to find similar tickets" }, 500);
|
|
955
|
+
}
|
|
956
|
+
});
|
|
957
|
+
/**
|
|
958
|
+
* GET /tickets/ai/status
|
|
959
|
+
* Check if AI features are available
|
|
960
|
+
*/
|
|
961
|
+
ticketsRouter.get("/ai/status", async (c) => {
|
|
962
|
+
const available = await isAIAvailable();
|
|
963
|
+
return c.json({
|
|
964
|
+
available,
|
|
965
|
+
model: process.env.OLLAMA_MODEL || "llama3.2",
|
|
966
|
+
baseUrl: process.env.OLLAMA_BASE_URL || "http://localhost:11434",
|
|
967
|
+
});
|
|
968
|
+
});
|
|
969
|
+
/**
|
|
970
|
+
* GET /tickets/ai/responder-status
|
|
971
|
+
* Check AI responder status
|
|
972
|
+
*/
|
|
973
|
+
ticketsRouter.get("/ai/responder-status", async (c) => {
|
|
974
|
+
const status = await getResponderStatus();
|
|
975
|
+
return c.json(status);
|
|
976
|
+
});
|
|
977
|
+
/**
|
|
978
|
+
* POST /tickets/:id/comments/ai-respond
|
|
979
|
+
* Generate an AI response to the latest comment or a specific comment
|
|
980
|
+
*/
|
|
981
|
+
ticketsRouter.post("/:id/comments/ai-respond", async (c) => {
|
|
982
|
+
const id = c.req.param("id");
|
|
983
|
+
try {
|
|
984
|
+
const ticket = await getTicketWithRelations(id);
|
|
985
|
+
if (!ticket) {
|
|
986
|
+
return c.json({ error: "Ticket not found" }, 404);
|
|
987
|
+
}
|
|
988
|
+
const body = await c.req.json().catch(() => ({}));
|
|
989
|
+
const { commentId, autoPost = false, minConfidence = 0.6 } = body;
|
|
990
|
+
const comments = ticket.comments || [];
|
|
991
|
+
if (comments.length === 0) {
|
|
992
|
+
return c.json({ error: "No comments to respond to" }, 400);
|
|
993
|
+
}
|
|
994
|
+
// Get the comment to respond to (latest or specific)
|
|
995
|
+
const targetComment = commentId
|
|
996
|
+
? comments.find((c) => c.id === commentId)
|
|
997
|
+
: comments[comments.length - 1];
|
|
998
|
+
if (!targetComment) {
|
|
999
|
+
return c.json({ error: "Comment not found" }, 404);
|
|
1000
|
+
}
|
|
1001
|
+
// Don't respond to AI comments
|
|
1002
|
+
if (targetComment.author.type === "ai" || targetComment.isAiResponse) {
|
|
1003
|
+
return c.json({
|
|
1004
|
+
skipped: true,
|
|
1005
|
+
reason: "Cannot respond to AI comments",
|
|
1006
|
+
});
|
|
1007
|
+
}
|
|
1008
|
+
// Get previous comments for context (excluding the target)
|
|
1009
|
+
const previousComments = comments.filter((c) => c.id !== targetComment.id);
|
|
1010
|
+
// Process the comment and generate response
|
|
1011
|
+
const result = await processComment(targetComment.content, {
|
|
1012
|
+
title: ticket.title,
|
|
1013
|
+
description: ticket.description,
|
|
1014
|
+
type: ticket.type,
|
|
1015
|
+
status: ticket.status,
|
|
1016
|
+
labels: ticket.labels,
|
|
1017
|
+
priority: ticket.priority,
|
|
1018
|
+
}, previousComments, { autoPost, minConfidence });
|
|
1019
|
+
// If auto-post is enabled and we should post
|
|
1020
|
+
if (result.success && result.shouldPost && result.response && autoPost) {
|
|
1021
|
+
const aiComment = await addComment(id, result.response, {
|
|
1022
|
+
type: "ai",
|
|
1023
|
+
name: "profClaw AI",
|
|
1024
|
+
platform: "profclaw",
|
|
1025
|
+
});
|
|
1026
|
+
return c.json({
|
|
1027
|
+
posted: true,
|
|
1028
|
+
comment: aiComment,
|
|
1029
|
+
response: result.response,
|
|
1030
|
+
confidence: result.confidence,
|
|
1031
|
+
responseType: result.responseType,
|
|
1032
|
+
durationMs: result.durationMs,
|
|
1033
|
+
});
|
|
1034
|
+
}
|
|
1035
|
+
// Return the response without posting
|
|
1036
|
+
return c.json({
|
|
1037
|
+
posted: false,
|
|
1038
|
+
response: result.response || null,
|
|
1039
|
+
confidence: result.confidence,
|
|
1040
|
+
responseType: result.responseType,
|
|
1041
|
+
shouldPost: result.shouldPost,
|
|
1042
|
+
durationMs: result.durationMs,
|
|
1043
|
+
});
|
|
1044
|
+
}
|
|
1045
|
+
catch (error) {
|
|
1046
|
+
console.error("[API] Error generating AI response:", error);
|
|
1047
|
+
return c.json({ error: "Failed to generate AI response" }, 500);
|
|
1048
|
+
}
|
|
1049
|
+
});
|
|
1050
|
+
/**
|
|
1051
|
+
* POST /tickets/:id/ai/analyze-comment
|
|
1052
|
+
* Analyze a comment without responding - useful for UI preview
|
|
1053
|
+
*/
|
|
1054
|
+
ticketsRouter.post("/:id/ai/analyze-comment", async (c) => {
|
|
1055
|
+
const id = c.req.param("id");
|
|
1056
|
+
try {
|
|
1057
|
+
const ticket = await getTicket(id);
|
|
1058
|
+
if (!ticket) {
|
|
1059
|
+
return c.json({ error: "Ticket not found" }, 404);
|
|
1060
|
+
}
|
|
1061
|
+
const body = await c.req.json();
|
|
1062
|
+
const { content } = body;
|
|
1063
|
+
if (!content) {
|
|
1064
|
+
return c.json({ error: "content is required" }, 400);
|
|
1065
|
+
}
|
|
1066
|
+
const comments = await getComments(id);
|
|
1067
|
+
// Generate response
|
|
1068
|
+
const result = await generateResponse(content, {
|
|
1069
|
+
title: ticket.title,
|
|
1070
|
+
description: ticket.description,
|
|
1071
|
+
type: ticket.type,
|
|
1072
|
+
status: ticket.status,
|
|
1073
|
+
labels: ticket.labels,
|
|
1074
|
+
priority: ticket.priority,
|
|
1075
|
+
}, comments, "answer");
|
|
1076
|
+
return c.json({
|
|
1077
|
+
response: result.response || null,
|
|
1078
|
+
confidence: result.confidence,
|
|
1079
|
+
responseType: result.responseType,
|
|
1080
|
+
shouldPost: result.shouldPost,
|
|
1081
|
+
durationMs: result.durationMs,
|
|
1082
|
+
});
|
|
1083
|
+
}
|
|
1084
|
+
catch (error) {
|
|
1085
|
+
console.error("[API] Error analyzing comment:", error);
|
|
1086
|
+
return c.json({ error: "Failed to analyze comment" }, 500);
|
|
1087
|
+
}
|
|
1088
|
+
});
|
|
1089
|
+
export { ticketsRouter as ticketsRoutes };
|
|
1090
|
+
//# sourceMappingURL=tickets.js.map
|