@kb-labs/rest-api-app 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.kb/agents/sessions/session-1771531145393-ws3uh6q/turns.json +42 -0
- package/.kb/agents/sessions/session-1771548930486-ui6rtvm/turns.json +33 -0
- package/.kb/agents/sessions/session-1771549691485-nibqroq/turns.json +133 -0
- package/.kb/agents/sessions/session-1771550943182-dkwqdjc/turns.json +130 -0
- package/.kb/agents/sessions/session-1771551564182-cr4bwzn/turns.json +349 -0
- package/.kb/agents/sessions/session-1771552401370-g4ztwd1/turns.json +206 -0
- package/.kb/commit/current/plan.json +248 -0
- package/.kb/commit/current/status.json +472 -0
- package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/commands/health.d.ts +10 -0
- package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/commands/health.js +215 -0
- package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/commands/health.js.map +1 -0
- package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/commands/list.d.ts +10 -0
- package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/commands/list.js +271 -0
- package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/commands/list.js.map +1 -0
- package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/commands/logs.d.ts +10 -0
- package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/commands/logs.js +230 -0
- package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/commands/logs.js.map +1 -0
- package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/commands/metrics.d.ts +10 -0
- package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/commands/metrics.js +228 -0
- package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/commands/metrics.js.map +1 -0
- package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/commands/run.d.ts +11 -0
- package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/commands/run.js +281 -0
- package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/commands/run.js.map +1 -0
- package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/commands/status.d.ts +10 -0
- package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/commands/status.js +266 -0
- package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/commands/status.js.map +1 -0
- package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/commands/workflow-run.d.ts +11 -0
- package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/commands/workflow-run.js +284 -0
- package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/commands/workflow-run.js.map +1 -0
- package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/flags-WLdpSZl4.d.ts +77 -0
- package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/index.d.ts +2 -0
- package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/index.js +441 -0
- package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/index.js.map +1 -0
- package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/manifest.d.ts +196 -0
- package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/manifest.js +441 -0
- package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/manifest.js.map +1 -0
- package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/cron-list-handler.d.ts +19 -0
- package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/cron-list-handler.js +48 -0
- package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/cron-list-handler.js.map +1 -0
- package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/index.d.ts +6 -0
- package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/index.js +170 -0
- package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/index.js.map +1 -0
- package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/job-cancel-handler.d.ts +12 -0
- package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/job-cancel-handler.js +52 -0
- package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/job-cancel-handler.js.map +1 -0
- package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/job-detail-handler.d.ts +22 -0
- package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/job-detail-handler.js +52 -0
- package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/job-detail-handler.js.map +1 -0
- package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/job-logs-handler.d.ts +13 -0
- package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/job-logs-handler.js +52 -0
- package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/job-logs-handler.js.map +1 -0
- package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/job-steps-handler.d.ts +9 -0
- package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/job-steps-handler.js +43 -0
- package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/job-steps-handler.js.map +1 -0
- package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/jobs-list-handler.d.ts +26 -0
- package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/jobs-list-handler.js +63 -0
- package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/jobs-list-handler.js.map +1 -0
- package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/pending-approvals-handler.d.ts +9 -0
- package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/pending-approvals-handler.js +46 -0
- package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/pending-approvals-handler.js.map +1 -0
- package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/resolve-approval-handler.d.ts +16 -0
- package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/resolve-approval-handler.js +58 -0
- package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/resolve-approval-handler.js.map +1 -0
- package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/run-detail-handler.d.ts +9 -0
- package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/run-detail-handler.js +46 -0
- package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/run-detail-handler.js.map +1 -0
- package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/runs-list-handler.d.ts +11 -0
- package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/runs-list-handler.js +50 -0
- package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/runs-list-handler.js.map +1 -0
- package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/stats-handler.d.ts +7 -0
- package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/stats-handler.js +39 -0
- package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/stats-handler.js.map +1 -0
- package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/workflow-detail-handler.d.ts +10 -0
- package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/workflow-detail-handler.js +46 -0
- package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/workflow-detail-handler.js.map +1 -0
- package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/workflow-run-cancel-handler.d.ts +13 -0
- package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/workflow-run-cancel-handler.js +47 -0
- package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/workflow-run-cancel-handler.js.map +1 -0
- package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/workflow-run-handler.d.ts +14 -0
- package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/workflow-run-handler.js +53 -0
- package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/workflow-run-handler.js.map +1 -0
- package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/workflow-runs-handler.d.ts +13 -0
- package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/workflow-runs-handler.js +54 -0
- package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/workflow-runs-handler.js.map +1 -0
- package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/workflows-list-handler.d.ts +12 -0
- package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/workflows-list-handler.js +51 -0
- package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/workflows-list-handler.js.map +1 -0
- package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/ws/logs-channel.d.ts +17 -0
- package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/ws/logs-channel.js +133 -0
- package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/ws/logs-channel.js.map +1 -0
- package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/ws/progress-channel.d.ts +11 -0
- package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/ws/progress-channel.js +46 -0
- package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/ws/progress-channel.js.map +1 -0
- package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/commands/health.d.ts +10 -0
- package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/commands/health.js +215 -0
- package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/commands/health.js.map +1 -0
- package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/commands/list.d.ts +10 -0
- package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/commands/list.js +271 -0
- package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/commands/list.js.map +1 -0
- package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/commands/logs.d.ts +10 -0
- package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/commands/logs.js +230 -0
- package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/commands/logs.js.map +1 -0
- package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/commands/metrics.d.ts +10 -0
- package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/commands/metrics.js +228 -0
- package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/commands/metrics.js.map +1 -0
- package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/commands/run.d.ts +11 -0
- package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/commands/run.js +281 -0
- package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/commands/run.js.map +1 -0
- package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/commands/status.d.ts +10 -0
- package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/commands/status.js +266 -0
- package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/commands/status.js.map +1 -0
- package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/commands/workflow-run.d.ts +11 -0
- package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/commands/workflow-run.js +284 -0
- package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/commands/workflow-run.js.map +1 -0
- package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/flags-WLdpSZl4.d.ts +77 -0
- package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/index.d.ts +2 -0
- package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/index.js +441 -0
- package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/index.js.map +1 -0
- package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/manifest.d.ts +196 -0
- package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/manifest.js +441 -0
- package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/manifest.js.map +1 -0
- package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/cron-list-handler.d.ts +19 -0
- package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/cron-list-handler.js +48 -0
- package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/cron-list-handler.js.map +1 -0
- package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/index.d.ts +6 -0
- package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/index.js +170 -0
- package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/index.js.map +1 -0
- package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/job-cancel-handler.d.ts +12 -0
- package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/job-cancel-handler.js +52 -0
- package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/job-cancel-handler.js.map +1 -0
- package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/job-detail-handler.d.ts +22 -0
- package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/job-detail-handler.js +52 -0
- package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/job-detail-handler.js.map +1 -0
- package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/job-logs-handler.d.ts +13 -0
- package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/job-logs-handler.js +52 -0
- package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/job-logs-handler.js.map +1 -0
- package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/job-steps-handler.d.ts +9 -0
- package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/job-steps-handler.js +43 -0
- package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/job-steps-handler.js.map +1 -0
- package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/jobs-list-handler.d.ts +26 -0
- package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/jobs-list-handler.js +63 -0
- package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/jobs-list-handler.js.map +1 -0
- package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/pending-approvals-handler.d.ts +9 -0
- package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/pending-approvals-handler.js +46 -0
- package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/pending-approvals-handler.js.map +1 -0
- package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/resolve-approval-handler.d.ts +16 -0
- package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/resolve-approval-handler.js +58 -0
- package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/resolve-approval-handler.js.map +1 -0
- package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/run-detail-handler.d.ts +9 -0
- package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/run-detail-handler.js +46 -0
- package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/run-detail-handler.js.map +1 -0
- package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/runs-list-handler.d.ts +11 -0
- package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/runs-list-handler.js +50 -0
- package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/runs-list-handler.js.map +1 -0
- package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/stats-handler.d.ts +7 -0
- package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/stats-handler.js +39 -0
- package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/stats-handler.js.map +1 -0
- package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/workflow-detail-handler.d.ts +10 -0
- package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/workflow-detail-handler.js +46 -0
- package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/workflow-detail-handler.js.map +1 -0
- package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/workflow-run-cancel-handler.d.ts +13 -0
- package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/workflow-run-cancel-handler.js +47 -0
- package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/workflow-run-cancel-handler.js.map +1 -0
- package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/workflow-run-handler.d.ts +14 -0
- package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/workflow-run-handler.js +53 -0
- package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/workflow-run-handler.js.map +1 -0
- package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/workflow-runs-handler.d.ts +13 -0
- package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/workflow-runs-handler.js +54 -0
- package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/workflow-runs-handler.js.map +1 -0
- package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/workflows-list-handler.d.ts +12 -0
- package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/workflows-list-handler.js +51 -0
- package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/workflows-list-handler.js.map +1 -0
- package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/ws/logs-channel.d.ts +17 -0
- package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/ws/logs-channel.js +133 -0
- package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/ws/logs-channel.js.map +1 -0
- package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/ws/progress-channel.d.ts +11 -0
- package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/ws/progress-channel.js +46 -0
- package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/ws/progress-channel.js.map +1 -0
- package/README.md +54 -0
- package/eslint.config.js +23 -0
- package/package.json +72 -0
- package/src/.kb/agents/sessions/session-1773470583796-ximqnfk/kpi-baseline.json +17 -0
- package/src/.kb/memory/sessions/session-1773470583796-ximqnfk/fact-sheet.json +1 -0
- package/src/bootstrap.ts +233 -0
- package/src/diagnostics/header-debug.ts +37 -0
- package/src/events/hub.ts +60 -0
- package/src/events/index.ts +1 -0
- package/src/index.ts +13 -0
- package/src/manifest.ts +21 -0
- package/src/middleware/__tests__/cache.spec.ts +184 -0
- package/src/middleware/__tests__/envelope.spec.ts +268 -0
- package/src/middleware/__tests__/metrics.redis.spec.ts +64 -0
- package/src/middleware/__tests__/rate-limit.spec.ts +283 -0
- package/src/middleware/__tests__/request-id.spec.ts +160 -0
- package/src/middleware/cache.ts +67 -0
- package/src/middleware/envelope.ts +136 -0
- package/src/middleware/error-guard.ts +69 -0
- package/src/middleware/index.ts +37 -0
- package/src/middleware/metrics.ts +810 -0
- package/src/middleware/mock-mode.ts +44 -0
- package/src/middleware/prom-metrics.ts +284 -0
- package/src/middleware/rate-limit-routes.ts +73 -0
- package/src/middleware/rate-limit.ts +72 -0
- package/src/middleware/request-id.ts +41 -0
- package/src/middleware/request-timeout.ts +69 -0
- package/src/middleware/security-headers.ts +24 -0
- package/src/middleware/startup-guard.ts +107 -0
- package/src/observability/service-contract.ts +192 -0
- package/src/plugins/index.ts +118 -0
- package/src/routes/__tests__/adapters-date-helpers.spec.ts +332 -0
- package/src/routes/__tests__/adapters.spec.ts +680 -0
- package/src/routes/__tests__/cache.spec.ts +264 -0
- package/src/routes/__tests__/events.spec.ts +434 -0
- package/src/routes/__tests__/health.spec.ts +414 -0
- package/src/routes/__tests__/logs.spec.ts +494 -0
- package/src/routes/__tests__/observability.spec.ts +392 -0
- package/src/routes/__tests__/plugins.spec.ts +931 -0
- package/src/routes/__tests__/workflow-management.spec.ts +698 -0
- package/src/routes/__tests__/workflows.spec.ts +204 -0
- package/src/routes/adapter-call.ts +220 -0
- package/src/routes/adapters.ts +1206 -0
- package/src/routes/analytics.ts +328 -0
- package/src/routes/cache.ts +104 -0
- package/src/routes/debug-routes.ts +95 -0
- package/src/routes/events.ts +115 -0
- package/src/routes/health.ts +348 -0
- package/src/routes/hello.ts +47 -0
- package/src/routes/index.ts +395 -0
- package/src/routes/jobs.ts +253 -0
- package/src/routes/logs.ts +718 -0
- package/src/routes/metrics.ts +120 -0
- package/src/routes/observability.ts +1388 -0
- package/src/routes/openapi.ts +101 -0
- package/src/routes/platform.ts +143 -0
- package/src/routes/plugins.ts +998 -0
- package/src/routes/readiness.ts +83 -0
- package/src/routes/workflow-management.ts +469 -0
- package/src/routes/workflows.ts +256 -0
- package/src/server.ts +203 -0
- package/src/services/historical-metrics.ts +496 -0
- package/src/services/incident-analyzer.ts +289 -0
- package/src/services/incident-detector.ts +691 -0
- package/src/services/incident-schema.sql +76 -0
- package/src/services/incident-storage.ts +593 -0
- package/src/services/system-metrics-collector.ts +244 -0
- package/src/types/fastify.d.ts +58 -0
- package/src/utils/__tests__/sse-auth.spec.ts +113 -0
- package/src/utils/path-helpers.ts +15 -0
- package/src/utils/repo.ts +42 -0
- package/src/utils/schema.ts +20 -0
- package/src/utils/sse-auth.ts +81 -0
- package/test-sandbox.sh +105 -0
- package/tsconfig.build.json +15 -0
- package/tsconfig.json +9 -0
- package/tsup.config.ts +18 -0
|
@@ -0,0 +1,691 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module @kb-labs/rest-api-app/services/incident-detector
|
|
3
|
+
* Automatic incident detection based on metrics thresholds
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { IncidentStorage, IncidentCreatePayload, IncidentSeverity, IncidentType, RelatedData } from './incident-storage';
|
|
7
|
+
import { metricsCollector } from '../middleware/metrics.js';
|
|
8
|
+
import { platform } from '@kb-labs/core-runtime';
|
|
9
|
+
import type { LogLevel } from '@kb-labs/core-platform';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Detection thresholds configuration
|
|
13
|
+
*/
|
|
14
|
+
export interface DetectionThresholds {
|
|
15
|
+
/** Error rate threshold (percentage, default: 5%) */
|
|
16
|
+
errorRateWarning: number;
|
|
17
|
+
/** Error rate critical threshold (percentage, default: 10%) */
|
|
18
|
+
errorRateCritical: number;
|
|
19
|
+
/** P99 latency warning threshold (ms, default: 2000) */
|
|
20
|
+
latencyP99Warning: number;
|
|
21
|
+
/** P99 latency critical threshold (ms, default: 5000) */
|
|
22
|
+
latencyP99Critical: number;
|
|
23
|
+
/** P95 latency warning threshold (ms, default: 1000) */
|
|
24
|
+
latencyP95Warning: number;
|
|
25
|
+
/** Minimum requests before triggering (default: 10) */
|
|
26
|
+
minRequestsForDetection: number;
|
|
27
|
+
/** Plugin error rate threshold (percentage, default: 10%) */
|
|
28
|
+
pluginErrorRateWarning: number;
|
|
29
|
+
/** Plugin error rate critical threshold (percentage, default: 25%) */
|
|
30
|
+
pluginErrorRateCritical: number;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Detector configuration
|
|
35
|
+
*/
|
|
36
|
+
export interface IncidentDetectorConfig {
|
|
37
|
+
/** Detection interval in milliseconds (default: 30000 - 30s) */
|
|
38
|
+
intervalMs: number;
|
|
39
|
+
/** Thresholds for detection */
|
|
40
|
+
thresholds: DetectionThresholds;
|
|
41
|
+
/** Cooldown period before creating same incident again (ms, default: 5 minutes) */
|
|
42
|
+
cooldownMs: number;
|
|
43
|
+
/** Enable debug logging */
|
|
44
|
+
debug: boolean;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const DEFAULT_THRESHOLDS: DetectionThresholds = {
|
|
48
|
+
errorRateWarning: 5,
|
|
49
|
+
errorRateCritical: 10,
|
|
50
|
+
latencyP99Warning: 2000,
|
|
51
|
+
latencyP99Critical: 5000,
|
|
52
|
+
latencyP95Warning: 1000,
|
|
53
|
+
minRequestsForDetection: 10,
|
|
54
|
+
pluginErrorRateWarning: 10,
|
|
55
|
+
pluginErrorRateCritical: 25,
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
const DEFAULT_CONFIG: IncidentDetectorConfig = {
|
|
59
|
+
intervalMs: 30000, // 30 seconds
|
|
60
|
+
thresholds: DEFAULT_THRESHOLDS,
|
|
61
|
+
cooldownMs: 5 * 60 * 1000, // 5 minutes
|
|
62
|
+
debug: false,
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Track recently created incidents to avoid duplicates
|
|
67
|
+
*/
|
|
68
|
+
interface RecentIncident {
|
|
69
|
+
type: IncidentType;
|
|
70
|
+
key: string; // unique key for deduplication (e.g., "error_rate" or "plugin:@kb-labs/foo")
|
|
71
|
+
timestamp: number;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Automatic incident detector service
|
|
76
|
+
*
|
|
77
|
+
* Periodically analyzes metrics and creates incidents when thresholds are exceeded.
|
|
78
|
+
* Includes deduplication to avoid spamming with repeated incidents.
|
|
79
|
+
*/
|
|
80
|
+
export class IncidentDetector {
|
|
81
|
+
private incidentStorage: IncidentStorage;
|
|
82
|
+
private config: IncidentDetectorConfig;
|
|
83
|
+
private logger: Console | any;
|
|
84
|
+
private intervalHandle: NodeJS.Timeout | null = null;
|
|
85
|
+
private recentIncidents: RecentIncident[] = [];
|
|
86
|
+
private isRunning = false;
|
|
87
|
+
|
|
88
|
+
// Metrics history for "before" comparison (last 10 snapshots)
|
|
89
|
+
private metricsHistory: Array<{
|
|
90
|
+
timestamp: number;
|
|
91
|
+
errorRate: number;
|
|
92
|
+
avgLatency: number;
|
|
93
|
+
totalRequests: number;
|
|
94
|
+
}> = [];
|
|
95
|
+
|
|
96
|
+
constructor(
|
|
97
|
+
incidentStorage: IncidentStorage,
|
|
98
|
+
config: Partial<IncidentDetectorConfig> = {},
|
|
99
|
+
logger: Console | any = console
|
|
100
|
+
) {
|
|
101
|
+
this.incidentStorage = incidentStorage;
|
|
102
|
+
this.config = {
|
|
103
|
+
...DEFAULT_CONFIG,
|
|
104
|
+
...config,
|
|
105
|
+
thresholds: { ...DEFAULT_THRESHOLDS, ...config.thresholds },
|
|
106
|
+
};
|
|
107
|
+
this.logger = logger;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Start automatic detection
|
|
112
|
+
*/
|
|
113
|
+
start(): void {
|
|
114
|
+
if (this.isRunning) {
|
|
115
|
+
this.log('warn', 'Detector already running');
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
this.isRunning = true;
|
|
120
|
+
this.log('info', 'Starting incident detector', {
|
|
121
|
+
intervalMs: this.config.intervalMs,
|
|
122
|
+
thresholds: this.config.thresholds,
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
// Run immediately once
|
|
126
|
+
this.runDetection().catch(err => {
|
|
127
|
+
this.log('error', 'Initial detection failed', { error: err.message });
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
// Schedule periodic detection
|
|
131
|
+
this.intervalHandle = setInterval(() => {
|
|
132
|
+
this.runDetection().catch(err => {
|
|
133
|
+
this.log('error', 'Detection cycle failed', { error: err.message });
|
|
134
|
+
});
|
|
135
|
+
}, this.config.intervalMs);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Stop automatic detection
|
|
140
|
+
*/
|
|
141
|
+
stop(): void {
|
|
142
|
+
if (this.intervalHandle) {
|
|
143
|
+
clearInterval(this.intervalHandle);
|
|
144
|
+
this.intervalHandle = null;
|
|
145
|
+
}
|
|
146
|
+
this.isRunning = false;
|
|
147
|
+
this.log('info', 'Incident detector stopped');
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Run a single detection cycle
|
|
152
|
+
*/
|
|
153
|
+
async runDetection(): Promise<void> {
|
|
154
|
+
const metrics = metricsCollector.getMetrics();
|
|
155
|
+
const now = Date.now();
|
|
156
|
+
|
|
157
|
+
// Save current metrics to history (for "before" comparison)
|
|
158
|
+
const totalErrors = (metrics.requests.clientErrors ?? 0) + (metrics.requests.serverErrors ?? 0);
|
|
159
|
+
const errorRate = metrics.requests.total > 0
|
|
160
|
+
? (totalErrors / metrics.requests.total) * 100
|
|
161
|
+
: 0;
|
|
162
|
+
|
|
163
|
+
this.metricsHistory.push({
|
|
164
|
+
timestamp: now,
|
|
165
|
+
errorRate,
|
|
166
|
+
avgLatency: metrics.latency.average ?? 0,
|
|
167
|
+
totalRequests: metrics.requests.total,
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
// Keep only last 10 snapshots (5 minutes history if running every 30s)
|
|
171
|
+
if (this.metricsHistory.length > 10) {
|
|
172
|
+
this.metricsHistory.shift();
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Clean up old recent incidents (outside cooldown period)
|
|
176
|
+
this.recentIncidents = this.recentIncidents.filter(
|
|
177
|
+
ri => now - ri.timestamp < this.config.cooldownMs
|
|
178
|
+
);
|
|
179
|
+
|
|
180
|
+
// Skip if not enough requests
|
|
181
|
+
if (metrics.requests.total < this.config.thresholds.minRequestsForDetection) {
|
|
182
|
+
this.log('debug', 'Not enough requests for detection', {
|
|
183
|
+
total: metrics.requests.total,
|
|
184
|
+
min: this.config.thresholds.minRequestsForDetection,
|
|
185
|
+
});
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// Detect error rate issues
|
|
190
|
+
await this.detectErrorRate(metrics, now);
|
|
191
|
+
|
|
192
|
+
// Detect latency issues
|
|
193
|
+
await this.detectLatencyIssues(metrics, now);
|
|
194
|
+
|
|
195
|
+
// Detect plugin failures
|
|
196
|
+
await this.detectPluginFailures(metrics, now);
|
|
197
|
+
|
|
198
|
+
this.log('debug', 'Detection cycle complete', {
|
|
199
|
+
recentIncidentsCount: this.recentIncidents.length,
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Detect high error rate
|
|
205
|
+
*/
|
|
206
|
+
private async detectErrorRate(metrics: any, now: number): Promise<void> {
|
|
207
|
+
const totalErrors = (metrics.requests.clientErrors ?? 0) + (metrics.requests.serverErrors ?? 0);
|
|
208
|
+
const errorRate = metrics.requests.total > 0
|
|
209
|
+
? (totalErrors / metrics.requests.total) * 100
|
|
210
|
+
: 0;
|
|
211
|
+
|
|
212
|
+
const key = 'error_rate';
|
|
213
|
+
|
|
214
|
+
if (this.isInCooldown(key)) {
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
let severity: IncidentSeverity | null = null;
|
|
219
|
+
let title = '';
|
|
220
|
+
let details = '';
|
|
221
|
+
|
|
222
|
+
if (errorRate >= this.config.thresholds.errorRateCritical) {
|
|
223
|
+
severity = 'critical';
|
|
224
|
+
title = `Critical Error Rate: ${errorRate.toFixed(1)}%`;
|
|
225
|
+
details = `Error rate has exceeded critical threshold of ${this.config.thresholds.errorRateCritical}%. ` +
|
|
226
|
+
`Current: ${errorRate.toFixed(2)}% (${totalErrors}/${metrics.requests.total} requests). ` +
|
|
227
|
+
`Client errors: ${metrics.requests.clientErrors ?? 0}, Server errors: ${metrics.requests.serverErrors ?? 0}.`;
|
|
228
|
+
} else if (errorRate >= this.config.thresholds.errorRateWarning) {
|
|
229
|
+
severity = 'warning';
|
|
230
|
+
title = `High Error Rate: ${errorRate.toFixed(1)}%`;
|
|
231
|
+
details = `Error rate has exceeded warning threshold of ${this.config.thresholds.errorRateWarning}%. ` +
|
|
232
|
+
`Current: ${errorRate.toFixed(2)}% (${totalErrors}/${metrics.requests.total} requests).`;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
if (severity) {
|
|
236
|
+
await this.createIncident({
|
|
237
|
+
type: 'error_rate',
|
|
238
|
+
severity,
|
|
239
|
+
title,
|
|
240
|
+
details,
|
|
241
|
+
metadata: {
|
|
242
|
+
errorRate,
|
|
243
|
+
totalRequests: metrics.requests.total,
|
|
244
|
+
clientErrors: metrics.requests.clientErrors,
|
|
245
|
+
serverErrors: metrics.requests.serverErrors,
|
|
246
|
+
threshold: severity === 'critical'
|
|
247
|
+
? this.config.thresholds.errorRateCritical
|
|
248
|
+
: this.config.thresholds.errorRateWarning,
|
|
249
|
+
},
|
|
250
|
+
}, key, now);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Detect latency spikes
|
|
256
|
+
*/
|
|
257
|
+
private async detectLatencyIssues(metrics: any, now: number): Promise<void> {
|
|
258
|
+
// We need to fetch p99 from histogram data
|
|
259
|
+
// For now, use average as approximation if p99 not available
|
|
260
|
+
const avgLatency = metrics.latency.average ?? 0;
|
|
261
|
+
|
|
262
|
+
// Try to calculate p99 from histogram if available
|
|
263
|
+
let p99 = avgLatency * 3; // rough approximation
|
|
264
|
+
let p95 = avgLatency * 2;
|
|
265
|
+
|
|
266
|
+
if (metrics.latency.histogram && metrics.latency.histogram.length > 0) {
|
|
267
|
+
// Sort by max latency and take top percentiles
|
|
268
|
+
const sorted = [...metrics.latency.histogram].sort((a: any, b: any) => b.max - a.max);
|
|
269
|
+
if (sorted.length > 0) {
|
|
270
|
+
p99 = sorted[0]?.max ?? p99;
|
|
271
|
+
p95 = sorted[Math.floor(sorted.length * 0.05)]?.max ?? p95;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
const keyP99 = 'latency_p99';
|
|
276
|
+
const keyP95 = 'latency_p95';
|
|
277
|
+
|
|
278
|
+
// Check P99 latency
|
|
279
|
+
if (!this.isInCooldown(keyP99)) {
|
|
280
|
+
let severity: IncidentSeverity | null = null;
|
|
281
|
+
let title = '';
|
|
282
|
+
let details = '';
|
|
283
|
+
|
|
284
|
+
if (p99 >= this.config.thresholds.latencyP99Critical) {
|
|
285
|
+
severity = 'critical';
|
|
286
|
+
title = `Critical P99 Latency: ${p99.toFixed(0)}ms`;
|
|
287
|
+
details = `P99 latency has exceeded critical threshold of ${this.config.thresholds.latencyP99Critical}ms. ` +
|
|
288
|
+
`Current P99: ${p99.toFixed(0)}ms, Average: ${avgLatency.toFixed(0)}ms. ` +
|
|
289
|
+
`This indicates severe performance degradation affecting tail latencies.`;
|
|
290
|
+
} else if (p99 >= this.config.thresholds.latencyP99Warning) {
|
|
291
|
+
severity = 'warning';
|
|
292
|
+
title = `High P99 Latency: ${p99.toFixed(0)}ms`;
|
|
293
|
+
details = `P99 latency has exceeded warning threshold of ${this.config.thresholds.latencyP99Warning}ms. ` +
|
|
294
|
+
`Current P99: ${p99.toFixed(0)}ms, Average: ${avgLatency.toFixed(0)}ms.`;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
if (severity) {
|
|
298
|
+
await this.createIncident({
|
|
299
|
+
type: 'latency_spike',
|
|
300
|
+
severity,
|
|
301
|
+
title,
|
|
302
|
+
details,
|
|
303
|
+
metadata: {
|
|
304
|
+
p99,
|
|
305
|
+
p95,
|
|
306
|
+
average: avgLatency,
|
|
307
|
+
threshold: severity === 'critical'
|
|
308
|
+
? this.config.thresholds.latencyP99Critical
|
|
309
|
+
: this.config.thresholds.latencyP99Warning,
|
|
310
|
+
},
|
|
311
|
+
}, keyP99, now);
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
// Check P95 latency (separate incident)
|
|
316
|
+
if (!this.isInCooldown(keyP95) && p95 >= this.config.thresholds.latencyP95Warning) {
|
|
317
|
+
await this.createIncident({
|
|
318
|
+
type: 'latency_spike',
|
|
319
|
+
severity: 'warning',
|
|
320
|
+
title: `Elevated P95 Latency: ${p95.toFixed(0)}ms`,
|
|
321
|
+
details: `P95 latency has exceeded threshold of ${this.config.thresholds.latencyP95Warning}ms. ` +
|
|
322
|
+
`Current P95: ${p95.toFixed(0)}ms. Consider investigating slow endpoints.`,
|
|
323
|
+
metadata: {
|
|
324
|
+
p95,
|
|
325
|
+
average: avgLatency,
|
|
326
|
+
threshold: this.config.thresholds.latencyP95Warning,
|
|
327
|
+
},
|
|
328
|
+
}, keyP95, now);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* Detect plugin failures
|
|
334
|
+
*/
|
|
335
|
+
private async detectPluginFailures(metrics: any, now: number): Promise<void> {
|
|
336
|
+
if (!metrics.perPlugin || !Array.isArray(metrics.perPlugin)) {
|
|
337
|
+
return;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
for (const plugin of metrics.perPlugin) {
|
|
341
|
+
if (!plugin.pluginId || plugin.requests < 5) {
|
|
342
|
+
continue; // Skip plugins with too few requests
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
const errorRate = plugin.requests > 0
|
|
346
|
+
? ((plugin.errors ?? 0) / plugin.requests) * 100
|
|
347
|
+
: 0;
|
|
348
|
+
|
|
349
|
+
const key = `plugin:${plugin.pluginId}`;
|
|
350
|
+
|
|
351
|
+
if (this.isInCooldown(key)) {
|
|
352
|
+
continue;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
let severity: IncidentSeverity | null = null;
|
|
356
|
+
let title = '';
|
|
357
|
+
let details = '';
|
|
358
|
+
|
|
359
|
+
if (errorRate >= this.config.thresholds.pluginErrorRateCritical) {
|
|
360
|
+
severity = 'critical';
|
|
361
|
+
title = `Plugin Failure: ${plugin.pluginId}`;
|
|
362
|
+
details = `Plugin ${plugin.pluginId} has critical error rate of ${errorRate.toFixed(1)}% ` +
|
|
363
|
+
`(${plugin.errors ?? 0}/${plugin.requests} requests). ` +
|
|
364
|
+
`This exceeds the critical threshold of ${this.config.thresholds.pluginErrorRateCritical}%.`;
|
|
365
|
+
} else if (errorRate >= this.config.thresholds.pluginErrorRateWarning) {
|
|
366
|
+
severity = 'warning';
|
|
367
|
+
title = `Plugin Issues: ${plugin.pluginId}`;
|
|
368
|
+
details = `Plugin ${plugin.pluginId} has elevated error rate of ${errorRate.toFixed(1)}% ` +
|
|
369
|
+
`(${plugin.errors ?? 0}/${plugin.requests} requests).`;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
if (severity) {
|
|
373
|
+
await this.createIncident({
|
|
374
|
+
type: 'plugin_failure',
|
|
375
|
+
severity,
|
|
376
|
+
title,
|
|
377
|
+
details,
|
|
378
|
+
affectedServices: [plugin.pluginId],
|
|
379
|
+
metadata: {
|
|
380
|
+
pluginId: plugin.pluginId,
|
|
381
|
+
errorRate,
|
|
382
|
+
requests: plugin.requests,
|
|
383
|
+
errors: plugin.errors,
|
|
384
|
+
avgLatency: plugin.latency?.average,
|
|
385
|
+
},
|
|
386
|
+
}, key, now);
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
/**
|
|
392
|
+
* Check if incident key is in cooldown
|
|
393
|
+
*/
|
|
394
|
+
private isInCooldown(key: string): boolean {
|
|
395
|
+
return this.recentIncidents.some(ri => ri.key === key);
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
/**
|
|
399
|
+
* Gather related data (logs, metrics, timeline) for incident
|
|
400
|
+
* @private
|
|
401
|
+
*/
|
|
402
|
+
private async gatherRelatedData(
|
|
403
|
+
incidentType: IncidentType,
|
|
404
|
+
timeWindow: number = 5 * 60 * 1000 // 5 minutes default
|
|
405
|
+
): Promise<RelatedData> {
|
|
406
|
+
const now = Date.now();
|
|
407
|
+
const from = now - timeWindow;
|
|
408
|
+
|
|
409
|
+
const relatedData: RelatedData = {
|
|
410
|
+
timeline: [],
|
|
411
|
+
};
|
|
412
|
+
|
|
413
|
+
try {
|
|
414
|
+
// Gather error and fatal logs from time window
|
|
415
|
+
const [errorLogsResult, fatalLogsResult] = await Promise.all([
|
|
416
|
+
platform.logs.query({ level: 'error' as LogLevel, from, to: now }, { limit: 50 }),
|
|
417
|
+
platform.logs.query({ level: 'fatal' as LogLevel, from, to: now }, { limit: 50 }),
|
|
418
|
+
]);
|
|
419
|
+
|
|
420
|
+
const allErrorLogs = [...errorLogsResult.logs, ...fatalLogsResult.logs];
|
|
421
|
+
|
|
422
|
+
if (allErrorLogs.length > 0) {
|
|
423
|
+
// Sort by timestamp descending
|
|
424
|
+
allErrorLogs.sort((a, b) => b.timestamp - a.timestamp);
|
|
425
|
+
|
|
426
|
+
// Extract sample error messages with stack traces (top 5 unique)
|
|
427
|
+
const uniqueErrors = new Set<string>();
|
|
428
|
+
const endpointErrorCount = new Map<string, { count: number; sample: string }>();
|
|
429
|
+
|
|
430
|
+
for (const log of allErrorLogs) {
|
|
431
|
+
// Extract error message with stack trace if available
|
|
432
|
+
let errorMsg = typeof log.message === 'string' ? log.message : JSON.stringify(log.message);
|
|
433
|
+
|
|
434
|
+
// Add structured error info if available
|
|
435
|
+
if ((log as any).err) {
|
|
436
|
+
const err = (log as any).err;
|
|
437
|
+
const stack = err.stack ? `\n${err.stack.split('\n').slice(0, 3).join('\n')}` : '';
|
|
438
|
+
errorMsg = `${err.message || errorMsg}${stack}`;
|
|
439
|
+
|
|
440
|
+
// Add plugin/command context if available
|
|
441
|
+
if ((log as any).plugin) {
|
|
442
|
+
errorMsg = `[${(log as any).plugin}] ${errorMsg}`;
|
|
443
|
+
}
|
|
444
|
+
if ((log as any).command) {
|
|
445
|
+
errorMsg += `\nCommand: ${(log as any).command}`;
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
if (errorMsg && uniqueErrors.size < 5) {
|
|
450
|
+
uniqueErrors.add(errorMsg.substring(0, 500)); // Increased limit for stack traces
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
// Group errors by endpoint (if available in log metadata)
|
|
454
|
+
const endpoint = (log as any).endpoint || (log as any).url || 'unknown';
|
|
455
|
+
const existing = endpointErrorCount.get(endpoint);
|
|
456
|
+
if (existing) {
|
|
457
|
+
existing.count++;
|
|
458
|
+
} else {
|
|
459
|
+
endpointErrorCount.set(endpoint, {
|
|
460
|
+
count: 1,
|
|
461
|
+
sample: errorMsg.substring(0, 200)
|
|
462
|
+
});
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
// Get top 5 endpoints with most errors
|
|
467
|
+
const topEndpoints = Array.from(endpointErrorCount.entries())
|
|
468
|
+
.sort((a, b) => b[1].count - a[1].count)
|
|
469
|
+
.slice(0, 5)
|
|
470
|
+
.map(([endpoint, data]) => ({
|
|
471
|
+
endpoint,
|
|
472
|
+
count: data.count,
|
|
473
|
+
sample: data.sample,
|
|
474
|
+
}));
|
|
475
|
+
|
|
476
|
+
relatedData.logs = {
|
|
477
|
+
errorCount: allErrorLogs.filter(l => l.level === 'error').length,
|
|
478
|
+
warnCount: 0, // Could query warnings separately if needed
|
|
479
|
+
timeRange: [from, now],
|
|
480
|
+
sampleErrors: Array.from(uniqueErrors),
|
|
481
|
+
topEndpoints: topEndpoints.length > 0 ? topEndpoints : undefined,
|
|
482
|
+
};
|
|
483
|
+
|
|
484
|
+
// Add error logs to timeline (top 10 most recent)
|
|
485
|
+
for (const log of allErrorLogs.slice(0, 10)) {
|
|
486
|
+
const msg = typeof log.message === 'string' ? log.message : 'Error occurred';
|
|
487
|
+
const plugin = (log as any).plugin ? `[${(log as any).plugin}] ` : '';
|
|
488
|
+
relatedData.timeline!.push({
|
|
489
|
+
timestamp: log.timestamp,
|
|
490
|
+
event: `${plugin}${msg.substring(0, 100)}`,
|
|
491
|
+
source: 'logs',
|
|
492
|
+
});
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
} catch (error) {
|
|
496
|
+
this.log('warn', 'Failed to gather related logs', {
|
|
497
|
+
error: error instanceof Error ? error.message : String(error),
|
|
498
|
+
});
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
// Add current metrics snapshot (during)
|
|
502
|
+
const currentMetrics = metricsCollector.getMetrics();
|
|
503
|
+
const duringMetrics = {
|
|
504
|
+
errorRate: currentMetrics.requests.total > 0
|
|
505
|
+
? ((currentMetrics.requests.clientErrors + currentMetrics.requests.serverErrors) / currentMetrics.requests.total) * 100
|
|
506
|
+
: 0,
|
|
507
|
+
avgLatency: currentMetrics.latency.average ?? 0,
|
|
508
|
+
totalRequests: currentMetrics.requests.total,
|
|
509
|
+
totalErrors: currentMetrics.requests.clientErrors + currentMetrics.requests.serverErrors,
|
|
510
|
+
};
|
|
511
|
+
|
|
512
|
+
// Calculate "before" metrics from history (average of last 5 snapshots before incident)
|
|
513
|
+
let beforeMetrics: Record<string, number> | undefined;
|
|
514
|
+
if (this.metricsHistory.length >= 2) {
|
|
515
|
+
// Use snapshots before the current one (exclude last snapshot which might be spike)
|
|
516
|
+
const beforeSnapshots = this.metricsHistory.slice(0, -1);
|
|
517
|
+
|
|
518
|
+
if (beforeSnapshots.length > 0) {
|
|
519
|
+
const avgErrorRate = beforeSnapshots.reduce((sum, s) => sum + s.errorRate, 0) / beforeSnapshots.length;
|
|
520
|
+
const avgLatency = beforeSnapshots.reduce((sum, s) => sum + s.avgLatency, 0) / beforeSnapshots.length;
|
|
521
|
+
const avgRequests = beforeSnapshots.reduce((sum, s) => sum + s.totalRequests, 0) / beforeSnapshots.length;
|
|
522
|
+
|
|
523
|
+
beforeMetrics = {
|
|
524
|
+
errorRate: avgErrorRate,
|
|
525
|
+
avgLatency,
|
|
526
|
+
totalRequests: avgRequests,
|
|
527
|
+
};
|
|
528
|
+
|
|
529
|
+
this.log('debug', 'Calculated before metrics', {
|
|
530
|
+
before: beforeMetrics,
|
|
531
|
+
during: duringMetrics,
|
|
532
|
+
snapshotsUsed: beforeSnapshots.length,
|
|
533
|
+
});
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
// Collect top slowest requests from metrics histogram (for latency incidents)
|
|
538
|
+
let topSlowest: Array<{ endpoint: string; method: string; durationMs: number; statusCode?: number }> | undefined;
|
|
539
|
+
let affectedEndpoints: string[] | undefined;
|
|
540
|
+
|
|
541
|
+
if (incidentType === 'latency_spike') {
|
|
542
|
+
const histogram = currentMetrics.latency.histogram;
|
|
543
|
+
|
|
544
|
+
if (histogram && histogram.length > 0) {
|
|
545
|
+
// Sort by max latency descending (slowest first)
|
|
546
|
+
const slowestRoutes = histogram
|
|
547
|
+
.filter(h => h.max > 100) // Only include requests >100ms
|
|
548
|
+
.sort((a, b) => b.max - a.max)
|
|
549
|
+
.slice(0, 10); // Top 10 slowest
|
|
550
|
+
|
|
551
|
+
topSlowest = slowestRoutes.map(h => {
|
|
552
|
+
const [method, ...pathParts] = h.route.split(' ');
|
|
553
|
+
const endpoint = pathParts.join(' ');
|
|
554
|
+
// Get most common status code
|
|
555
|
+
const statusCodes = Object.keys(h.byStatus);
|
|
556
|
+
const mostCommonStatus = statusCodes.length > 0 ? parseInt(statusCodes[0]!, 10) : undefined;
|
|
557
|
+
|
|
558
|
+
return {
|
|
559
|
+
endpoint,
|
|
560
|
+
method: method || 'GET',
|
|
561
|
+
durationMs: Math.round(h.max),
|
|
562
|
+
statusCode: mostCommonStatus,
|
|
563
|
+
};
|
|
564
|
+
});
|
|
565
|
+
|
|
566
|
+
affectedEndpoints = [...new Set(slowestRoutes.map(h => h.route))];
|
|
567
|
+
|
|
568
|
+
this.log('debug', 'Collected slow requests for latency incident', {
|
|
569
|
+
topSlowestCount: topSlowest.length,
|
|
570
|
+
affectedEndpointsCount: affectedEndpoints.length,
|
|
571
|
+
});
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
relatedData.metrics = {
|
|
576
|
+
before: beforeMetrics,
|
|
577
|
+
during: duringMetrics,
|
|
578
|
+
topSlowest,
|
|
579
|
+
affectedEndpoints,
|
|
580
|
+
};
|
|
581
|
+
|
|
582
|
+
// Add detection event to timeline
|
|
583
|
+
relatedData.timeline!.unshift({
|
|
584
|
+
timestamp: now,
|
|
585
|
+
event: `Incident detected: ${incidentType}`,
|
|
586
|
+
source: 'detector',
|
|
587
|
+
});
|
|
588
|
+
|
|
589
|
+
// Sort timeline by timestamp descending (newest first)
|
|
590
|
+
relatedData.timeline!.sort((a, b) => b.timestamp - a.timestamp);
|
|
591
|
+
|
|
592
|
+
return relatedData;
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
/**
|
|
596
|
+
* Create incident and track it
|
|
597
|
+
*/
|
|
598
|
+
private async createIncident(
|
|
599
|
+
payload: IncidentCreatePayload,
|
|
600
|
+
key: string,
|
|
601
|
+
timestamp: number
|
|
602
|
+
): Promise<void> {
|
|
603
|
+
try {
|
|
604
|
+
// Gather related data (logs, metrics, timeline)
|
|
605
|
+
const relatedData = await this.gatherRelatedData(payload.type);
|
|
606
|
+
|
|
607
|
+
// Merge with existing payload
|
|
608
|
+
const enrichedPayload: IncidentCreatePayload = {
|
|
609
|
+
...payload,
|
|
610
|
+
relatedData,
|
|
611
|
+
};
|
|
612
|
+
|
|
613
|
+
const incident = await this.incidentStorage.createIncident(enrichedPayload);
|
|
614
|
+
|
|
615
|
+
// Track for deduplication
|
|
616
|
+
this.recentIncidents.push({
|
|
617
|
+
type: payload.type,
|
|
618
|
+
key,
|
|
619
|
+
timestamp,
|
|
620
|
+
});
|
|
621
|
+
|
|
622
|
+
this.log('info', 'Auto-created incident with context', {
|
|
623
|
+
id: incident.id,
|
|
624
|
+
type: incident.type,
|
|
625
|
+
severity: incident.severity,
|
|
626
|
+
title: incident.title,
|
|
627
|
+
errorLogsCount: relatedData.logs?.errorCount ?? 0,
|
|
628
|
+
timelineEventsCount: relatedData.timeline?.length ?? 0,
|
|
629
|
+
});
|
|
630
|
+
|
|
631
|
+
// Track analytics event
|
|
632
|
+
if (platform.analytics) {
|
|
633
|
+
platform.analytics.track('incident.created', {
|
|
634
|
+
incidentId: incident.id,
|
|
635
|
+
type: incident.type,
|
|
636
|
+
severity: incident.severity,
|
|
637
|
+
source: 'auto-detector',
|
|
638
|
+
errorLogsCount: relatedData.logs?.errorCount ?? 0,
|
|
639
|
+
timelineEventsCount: relatedData.timeline?.length ?? 0,
|
|
640
|
+
hasBeforeMetrics: !!relatedData.metrics?.before,
|
|
641
|
+
affectedServicesCount: payload.affectedServices?.length ?? 0,
|
|
642
|
+
}).catch(() => {
|
|
643
|
+
// Silently ignore analytics errors
|
|
644
|
+
});
|
|
645
|
+
}
|
|
646
|
+
} catch (error) {
|
|
647
|
+
this.log('error', 'Failed to create incident', {
|
|
648
|
+
key,
|
|
649
|
+
error: error instanceof Error ? error.message : String(error),
|
|
650
|
+
});
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
/**
|
|
655
|
+
* Get current detector status
|
|
656
|
+
*/
|
|
657
|
+
getStatus(): {
|
|
658
|
+
running: boolean;
|
|
659
|
+
config: IncidentDetectorConfig;
|
|
660
|
+
recentIncidentsCount: number;
|
|
661
|
+
} {
|
|
662
|
+
return {
|
|
663
|
+
running: this.isRunning,
|
|
664
|
+
config: this.config,
|
|
665
|
+
recentIncidentsCount: this.recentIncidents.length,
|
|
666
|
+
};
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
/**
|
|
670
|
+
* Update thresholds at runtime
|
|
671
|
+
*/
|
|
672
|
+
updateThresholds(thresholds: Partial<DetectionThresholds>): void {
|
|
673
|
+
this.config.thresholds = { ...this.config.thresholds, ...thresholds };
|
|
674
|
+
this.log('info', 'Thresholds updated', { thresholds: this.config.thresholds });
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
private log(level: 'info' | 'warn' | 'error' | 'debug', message: string, meta?: any): void {
|
|
678
|
+
if (level === 'debug' && !this.config.debug) {return;}
|
|
679
|
+
|
|
680
|
+
const prefix = '[IncidentDetector]';
|
|
681
|
+
if (this.logger[level]) {
|
|
682
|
+
if (meta) {
|
|
683
|
+
this.logger[level]({ ...meta }, `${prefix} ${message}`);
|
|
684
|
+
} else {
|
|
685
|
+
this.logger[level](`${prefix} ${message}`);
|
|
686
|
+
}
|
|
687
|
+
} else {
|
|
688
|
+
console.log(`${prefix} [${level}] ${message}`, meta ?? '');
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
}
|