@oneuptime/common 11.5.7 → 11.5.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (212) hide show
  1. package/Models/DatabaseModels/AIAgentTaskPullRequest.ts +15 -6
  2. package/Models/DatabaseModels/AIRun.ts +68 -0
  3. package/Models/DatabaseModels/AIRunEvent.ts +34 -1
  4. package/Models/DatabaseModels/NetworkDeviceDiscoveryScan.ts +215 -0
  5. package/Models/DatabaseModels/Project.ts +25 -0
  6. package/Models/DatabaseModels/StatusPage.ts +42 -0
  7. package/Server/API/AIAgentTaskAPI.ts +38 -12
  8. package/Server/API/AIAgentTaskLogAPI.ts +49 -0
  9. package/Server/API/AIChatAPI.ts +16 -0
  10. package/Server/API/AIReadinessAPI.ts +84 -0
  11. package/Server/API/CodeFixRunAPI.ts +190 -57
  12. package/Server/API/TelemetryExceptionAPI.ts +6 -1
  13. package/Server/Infrastructure/Postgres/SchemaMigrations/1784105912819-BackfillCodeFixTaskType.ts +41 -0
  14. package/Server/Infrastructure/Postgres/SchemaMigrations/1784124919694-AddAITaskNumberAndRunTranscript.ts +95 -0
  15. package/Server/Infrastructure/Postgres/SchemaMigrations/1784135099754-AllowNullAiAgentOnPullRequest.ts +52 -0
  16. package/Server/Infrastructure/Postgres/SchemaMigrations/1784137457184-AddEnableMcpServerToStatusPage.ts +30 -0
  17. package/Server/Infrastructure/Postgres/SchemaMigrations/1784200000000-AddSnmpV3ColumnsToNetworkDeviceDiscoveryScan.ts +49 -0
  18. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +10 -0
  19. package/Server/Middleware/MasterAdminAuthorization.ts +1 -1
  20. package/Server/Middleware/ProjectAuthorization.ts +1 -1
  21. package/Server/Services/AIRunEventService.ts +15 -1
  22. package/Server/Services/AIRunService.ts +48 -12
  23. package/Server/Services/LlmProviderService.ts +2 -0
  24. package/Server/Services/ProjectService.ts +42 -0
  25. package/Server/Services/StatusPageService.ts +87 -0
  26. package/Server/Services/TelemetryExceptionService.ts +19 -90
  27. package/Server/Types/Markdown.ts +9 -9
  28. package/Server/Types/MarkdownSlugify.ts +47 -0
  29. package/Server/Utils/AI/AIRunPrivacyFilter.ts +106 -0
  30. package/Server/Utils/AI/AIRunTranscript.ts +240 -0
  31. package/Server/Utils/AI/Chat/ChatAgentRunner.ts +9 -0
  32. package/Server/Utils/AI/Chat/ObservabilityChatPrompt.ts +119 -5
  33. package/Server/Utils/AI/CodeFix/CodeFixAgentCompletion.ts +75 -0
  34. package/Server/Utils/AI/CodeFix/CodeFixReadiness.ts +235 -0
  35. package/Server/Utils/AI/SRE/Insights/FixRouting.ts +2 -3
  36. package/Server/Utils/AI/Toolbox/CodeTools.ts +883 -0
  37. package/Server/Utils/AI/Toolbox/CodeWriteTools.ts +519 -0
  38. package/Server/Utils/AI/Toolbox/Index.ts +27 -0
  39. package/Server/Utils/AI/Toolbox/ScheduledMaintenanceTools.ts +279 -0
  40. package/Server/Utils/AnalyticsDatabase/ClickhouseCapacity.ts +19 -1
  41. package/Server/Utils/CodeRepository/GitHub/GitHub.ts +600 -0
  42. package/Server/Utils/CodeRepository/StackTraceRepoResolver.ts +7 -2
  43. package/Server/Utils/LLM/LLMService.ts +397 -18
  44. package/Server/Utils/Monitor/NetworkDeviceHydrationUtil.ts +4 -11
  45. package/Tests/Models/StatusPageEnableMcpServer.test.ts +125 -0
  46. package/Tests/Server/Services/StatusPageServiceMcp.test.ts +223 -0
  47. package/Tests/Server/Services/TelemetryExceptionAIFixReadiness.test.ts +26 -3
  48. package/Tests/Server/Services/TelemetryExceptionCodeFixRun.test.ts +12 -0
  49. package/Tests/Server/Types/Markdown.test.ts +106 -0
  50. package/Tests/Server/Utils/AI/AIRunPrivacyFilter.test.ts +295 -0
  51. package/Tests/Server/Utils/AI/AIRunTranscript.test.ts +182 -0
  52. package/Tests/Server/Utils/AI/CodeFixReadiness.test.ts +411 -0
  53. package/Tests/Server/Utils/AI/CodeTools.test.ts +596 -0
  54. package/Tests/Server/Utils/AI/CodeWriteTools.test.ts +475 -0
  55. package/Tests/Server/Utils/AI/LLMServiceModelCompatibility.test.ts +548 -0
  56. package/Tests/Server/Utils/AI/ObservabilityChatPrompt.test.ts +142 -0
  57. package/Tests/Server/Utils/AI/ScheduledMaintenanceTools.test.ts +176 -0
  58. package/Tests/Server/Utils/AnalyticsDatabase/ClickhouseCapacity.test.ts +63 -0
  59. package/Tests/Server/Utils/GitHubGetFileContent.test.ts +197 -0
  60. package/Tests/Server/Utils/Monitor/NetworkDeviceHydrationUtil.test.ts +502 -0
  61. package/Tests/Types/AI/AIAgentTaskStatus.test.ts +7 -6
  62. package/Tests/Types/AI/AIChatPageContext.test.ts +0 -0
  63. package/Tests/Types/AI/AIRunStatus.test.ts +42 -0
  64. package/Tests/Types/Log/LogSeverity.test.ts +78 -0
  65. package/Tests/UI/Components/BasicFormDropdownNormalization.test.tsx +167 -0
  66. package/Tests/UI/Components/Charts/AxisTickColor.test.tsx +66 -0
  67. package/Tests/UI/Utils/AIChatExport/ChatWidgetData.test.ts +319 -0
  68. package/Tests/UI/Utils/AIChatExport/ChatWidgetMarkdown.test.ts +188 -0
  69. package/Types/AI/AIAgentTaskStatus.ts +13 -0
  70. package/Types/AI/AIChatPageContext.ts +137 -0
  71. package/Types/AI/AIChatTypes.ts +44 -0
  72. package/Types/AI/AIFixReadiness.ts +46 -0
  73. package/Types/AI/AIRunStatus.ts +11 -0
  74. package/Types/Email/EmailTemplateType.ts +2 -0
  75. package/Types/Log/LogSeverity.ts +61 -0
  76. package/Types/Monitor/SnmpMonitor/SnmpVersion.ts +40 -0
  77. package/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.tsx +8 -2
  78. package/UI/Components/Charts/ChartLibrary/BarChart/BarChart.tsx +3 -1
  79. package/UI/Components/Charts/ChartLibrary/LineChart/LineChart.tsx +8 -2
  80. package/UI/Components/EditionLabel/EditionLabel.tsx +821 -331
  81. package/UI/Components/Forms/BasicForm.tsx +26 -8
  82. package/UI/Styles/Theme.css +1314 -0
  83. package/UI/Utils/AIChatExport/ChatWidgetData.ts +316 -0
  84. package/UI/Utils/AIChatExport/ChatWidgetMarkdown.ts +349 -0
  85. package/UI/Utils/AIChatExport/ConversationMarkdown.ts +177 -0
  86. package/UI/Utils/AIChatExport/MarkdownBlocks.ts +327 -0
  87. package/UI/Utils/AIChatExport/MarkdownSafety.ts +215 -0
  88. package/UI/Utils/DownloadFile.ts +54 -0
  89. package/build/dist/Models/DatabaseModels/AIAgentTaskPullRequest.js +15 -7
  90. package/build/dist/Models/DatabaseModels/AIAgentTaskPullRequest.js.map +1 -1
  91. package/build/dist/Models/DatabaseModels/AIRun.js +69 -0
  92. package/build/dist/Models/DatabaseModels/AIRun.js.map +1 -1
  93. package/build/dist/Models/DatabaseModels/AIRunEvent.js +31 -0
  94. package/build/dist/Models/DatabaseModels/AIRunEvent.js.map +1 -1
  95. package/build/dist/Models/DatabaseModels/NetworkDeviceDiscoveryScan.js +225 -0
  96. package/build/dist/Models/DatabaseModels/NetworkDeviceDiscoveryScan.js.map +1 -1
  97. package/build/dist/Models/DatabaseModels/Project.js +27 -0
  98. package/build/dist/Models/DatabaseModels/Project.js.map +1 -1
  99. package/build/dist/Models/DatabaseModels/StatusPage.js +43 -0
  100. package/build/dist/Models/DatabaseModels/StatusPage.js.map +1 -1
  101. package/build/dist/Server/API/AIAgentTaskAPI.js +37 -11
  102. package/build/dist/Server/API/AIAgentTaskAPI.js.map +1 -1
  103. package/build/dist/Server/API/AIAgentTaskLogAPI.js +32 -7
  104. package/build/dist/Server/API/AIAgentTaskLogAPI.js.map +1 -1
  105. package/build/dist/Server/API/AIChatAPI.js +9 -0
  106. package/build/dist/Server/API/AIChatAPI.js.map +1 -1
  107. package/build/dist/Server/API/AIReadinessAPI.js +57 -0
  108. package/build/dist/Server/API/AIReadinessAPI.js.map +1 -0
  109. package/build/dist/Server/API/CodeFixRunAPI.js +165 -51
  110. package/build/dist/Server/API/CodeFixRunAPI.js.map +1 -1
  111. package/build/dist/Server/API/TelemetryExceptionAPI.js +4 -0
  112. package/build/dist/Server/API/TelemetryExceptionAPI.js.map +1 -1
  113. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784105912819-BackfillCodeFixTaskType.js +36 -0
  114. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784105912819-BackfillCodeFixTaskType.js.map +1 -0
  115. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784124919694-AddAITaskNumberAndRunTranscript.js +80 -0
  116. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784124919694-AddAITaskNumberAndRunTranscript.js.map +1 -0
  117. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784135099754-AllowNullAiAgentOnPullRequest.js +37 -0
  118. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784135099754-AllowNullAiAgentOnPullRequest.js.map +1 -0
  119. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784137457184-AddEnableMcpServerToStatusPage.js +23 -0
  120. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784137457184-AddEnableMcpServerToStatusPage.js.map +1 -0
  121. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784200000000-AddSnmpV3ColumnsToNetworkDeviceDiscoveryScan.js +22 -0
  122. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784200000000-AddSnmpV3ColumnsToNetworkDeviceDiscoveryScan.js.map +1 -0
  123. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +10 -0
  124. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  125. package/build/dist/Server/Middleware/MasterAdminAuthorization.js +1 -1
  126. package/build/dist/Server/Middleware/ProjectAuthorization.js +1 -1
  127. package/build/dist/Server/Services/AIRunEventService.js +8 -0
  128. package/build/dist/Server/Services/AIRunEventService.js.map +1 -1
  129. package/build/dist/Server/Services/AIRunService.js +39 -3
  130. package/build/dist/Server/Services/AIRunService.js.map +1 -1
  131. package/build/dist/Server/Services/LlmProviderService.js +2 -0
  132. package/build/dist/Server/Services/LlmProviderService.js.map +1 -1
  133. package/build/dist/Server/Services/ProjectService.js +39 -0
  134. package/build/dist/Server/Services/ProjectService.js.map +1 -1
  135. package/build/dist/Server/Services/StatusPageService.js +81 -0
  136. package/build/dist/Server/Services/StatusPageService.js.map +1 -1
  137. package/build/dist/Server/Services/TelemetryExceptionService.js +14 -61
  138. package/build/dist/Server/Services/TelemetryExceptionService.js.map +1 -1
  139. package/build/dist/Server/Types/Markdown.js +8 -8
  140. package/build/dist/Server/Types/Markdown.js.map +1 -1
  141. package/build/dist/Server/Types/MarkdownSlugify.js +47 -0
  142. package/build/dist/Server/Types/MarkdownSlugify.js.map +1 -0
  143. package/build/dist/Server/Utils/AI/AIRunPrivacyFilter.js +82 -0
  144. package/build/dist/Server/Utils/AI/AIRunPrivacyFilter.js.map +1 -0
  145. package/build/dist/Server/Utils/AI/AIRunTranscript.js +180 -0
  146. package/build/dist/Server/Utils/AI/AIRunTranscript.js.map +1 -0
  147. package/build/dist/Server/Utils/AI/Chat/ChatAgentRunner.js +1 -0
  148. package/build/dist/Server/Utils/AI/Chat/ChatAgentRunner.js.map +1 -1
  149. package/build/dist/Server/Utils/AI/Chat/ObservabilityChatPrompt.js +103 -5
  150. package/build/dist/Server/Utils/AI/Chat/ObservabilityChatPrompt.js.map +1 -1
  151. package/build/dist/Server/Utils/AI/CodeFix/CodeFixAgentCompletion.js +55 -0
  152. package/build/dist/Server/Utils/AI/CodeFix/CodeFixAgentCompletion.js.map +1 -1
  153. package/build/dist/Server/Utils/AI/CodeFix/CodeFixReadiness.js +211 -0
  154. package/build/dist/Server/Utils/AI/CodeFix/CodeFixReadiness.js.map +1 -0
  155. package/build/dist/Server/Utils/AI/SRE/Insights/FixRouting.js.map +1 -1
  156. package/build/dist/Server/Utils/AI/Toolbox/CodeTools.js +654 -0
  157. package/build/dist/Server/Utils/AI/Toolbox/CodeTools.js.map +1 -0
  158. package/build/dist/Server/Utils/AI/Toolbox/CodeWriteTools.js +389 -0
  159. package/build/dist/Server/Utils/AI/Toolbox/CodeWriteTools.js.map +1 -0
  160. package/build/dist/Server/Utils/AI/Toolbox/Index.js +19 -0
  161. package/build/dist/Server/Utils/AI/Toolbox/Index.js.map +1 -1
  162. package/build/dist/Server/Utils/AI/Toolbox/ScheduledMaintenanceTools.js +239 -0
  163. package/build/dist/Server/Utils/AI/Toolbox/ScheduledMaintenanceTools.js.map +1 -0
  164. package/build/dist/Server/Utils/AnalyticsDatabase/ClickhouseCapacity.js +19 -1
  165. package/build/dist/Server/Utils/AnalyticsDatabase/ClickhouseCapacity.js.map +1 -1
  166. package/build/dist/Server/Utils/CodeRepository/GitHub/GitHub.js +439 -0
  167. package/build/dist/Server/Utils/CodeRepository/GitHub/GitHub.js.map +1 -1
  168. package/build/dist/Server/Utils/CodeRepository/StackTraceRepoResolver.js +1 -1
  169. package/build/dist/Server/Utils/CodeRepository/StackTraceRepoResolver.js.map +1 -1
  170. package/build/dist/Server/Utils/LLM/LLMService.js +275 -19
  171. package/build/dist/Server/Utils/LLM/LLMService.js.map +1 -1
  172. package/build/dist/Server/Utils/Monitor/NetworkDeviceHydrationUtil.js +2 -11
  173. package/build/dist/Server/Utils/Monitor/NetworkDeviceHydrationUtil.js.map +1 -1
  174. package/build/dist/Types/AI/AIAgentTaskStatus.js +12 -0
  175. package/build/dist/Types/AI/AIAgentTaskStatus.js.map +1 -1
  176. package/build/dist/Types/AI/AIChatPageContext.js +101 -0
  177. package/build/dist/Types/AI/AIChatPageContext.js.map +1 -0
  178. package/build/dist/Types/AI/AIChatTypes.js +2 -0
  179. package/build/dist/Types/AI/AIChatTypes.js.map +1 -1
  180. package/build/dist/Types/AI/AIFixReadiness.js +9 -0
  181. package/build/dist/Types/AI/AIFixReadiness.js.map +1 -0
  182. package/build/dist/Types/AI/AIRunStatus.js +11 -0
  183. package/build/dist/Types/AI/AIRunStatus.js.map +1 -1
  184. package/build/dist/Types/Email/EmailTemplateType.js +1 -0
  185. package/build/dist/Types/Email/EmailTemplateType.js.map +1 -1
  186. package/build/dist/Types/Log/LogSeverity.js +56 -0
  187. package/build/dist/Types/Log/LogSeverity.js.map +1 -1
  188. package/build/dist/Types/Monitor/SnmpMonitor/SnmpVersion.js +38 -0
  189. package/build/dist/Types/Monitor/SnmpMonitor/SnmpVersion.js.map +1 -1
  190. package/build/dist/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.js +9 -2
  191. package/build/dist/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.js.map +1 -1
  192. package/build/dist/UI/Components/Charts/ChartLibrary/BarChart/BarChart.js +3 -1
  193. package/build/dist/UI/Components/Charts/ChartLibrary/BarChart/BarChart.js.map +1 -1
  194. package/build/dist/UI/Components/Charts/ChartLibrary/LineChart/LineChart.js +9 -2
  195. package/build/dist/UI/Components/Charts/ChartLibrary/LineChart/LineChart.js.map +1 -1
  196. package/build/dist/UI/Components/EditionLabel/EditionLabel.js +424 -139
  197. package/build/dist/UI/Components/EditionLabel/EditionLabel.js.map +1 -1
  198. package/build/dist/UI/Components/Forms/BasicForm.js +24 -6
  199. package/build/dist/UI/Components/Forms/BasicForm.js.map +1 -1
  200. package/build/dist/UI/Utils/AIChatExport/ChatWidgetData.js +217 -0
  201. package/build/dist/UI/Utils/AIChatExport/ChatWidgetData.js.map +1 -0
  202. package/build/dist/UI/Utils/AIChatExport/ChatWidgetMarkdown.js +234 -0
  203. package/build/dist/UI/Utils/AIChatExport/ChatWidgetMarkdown.js.map +1 -0
  204. package/build/dist/UI/Utils/AIChatExport/ConversationMarkdown.js +111 -0
  205. package/build/dist/UI/Utils/AIChatExport/ConversationMarkdown.js.map +1 -0
  206. package/build/dist/UI/Utils/AIChatExport/MarkdownBlocks.js +233 -0
  207. package/build/dist/UI/Utils/AIChatExport/MarkdownBlocks.js.map +1 -0
  208. package/build/dist/UI/Utils/AIChatExport/MarkdownSafety.js +134 -0
  209. package/build/dist/UI/Utils/AIChatExport/MarkdownSafety.js.map +1 -0
  210. package/build/dist/UI/Utils/DownloadFile.js +41 -0
  211. package/build/dist/UI/Utils/DownloadFile.js.map +1 -0
  212. package/package.json +5 -1
@@ -0,0 +1,41 @@
1
+ import { MigrationInterface, QueryRunner } from "typeorm";
2
+
3
+ export class BackfillCodeFixTaskType1784105912819
4
+ implements MigrationInterface
5
+ {
6
+ public name = "BackfillCodeFixTaskType1784105912819";
7
+
8
+ /*
9
+ * A null AIRun.codeFixTaskType on a CodeFix run has always MEANT
10
+ * FixException: every code-fix run created before task recipes existed was
11
+ * an exception fix, and both the server's read path
12
+ * (CodeFixTaskTypeHelper.fromDatabaseValue) and the dashboard normalize the
13
+ * null to FixException so nobody ever sees it.
14
+ *
15
+ * That normalization only covers reads. Now that the AI Tasks list filters
16
+ * through the standard CRUD, a "Fix Exception" filter compiles to
17
+ * `codeFixTaskType IN ('FixException')`, which NULL never matches — the
18
+ * oldest runs would silently vanish from the filtered list. The bespoke
19
+ * endpoint papered over this with an equalToOrNull query it built itself;
20
+ * that endpoint is gone, so the meaning gets written into the data instead.
21
+ *
22
+ * Scoped to runType = 'CodeFix': codeFixTaskType is meaningless on chat and
23
+ * investigation runs and must stay null there.
24
+ */
25
+ public async up(queryRunner: QueryRunner): Promise<void> {
26
+ await queryRunner.query(
27
+ `UPDATE "AIRun" SET "codeFixTaskType" = 'FixException' WHERE "runType" = 'CodeFix' AND "codeFixTaskType" IS NULL`,
28
+ );
29
+ }
30
+
31
+ /*
32
+ * Deliberately a no-op. The rows this set are indistinguishable from rows
33
+ * that already said FixException, so nulling them back would corrupt data
34
+ * this migration never touched. Reverting is also unnecessary: the read path
35
+ * still normalizes null to FixException, so an older build reads these rows
36
+ * exactly as it did before.
37
+ */
38
+ public async down(_queryRunner: QueryRunner): Promise<void> {
39
+ return;
40
+ }
41
+ }
@@ -0,0 +1,95 @@
1
+ import { MigrationInterface, QueryRunner } from "typeorm";
2
+
3
+ /*
4
+ * Two additions, both in service of debugging a code-fix run that went wrong.
5
+ *
6
+ * 1. AIRun.taskNumber + Project.aiRunCounter — the per-project "#42" handle,
7
+ * allocated exactly like Incident.incidentNumber (ProjectService holds the
8
+ * counter behind a Redis semaphore; see incrementAndGetAIRunCounter).
9
+ * 2. AIRunEvent.contentPayload — the verbatim prompt/response/tool transcript.
10
+ *
11
+ * The DDL here was produced by `npm run generate-postgres-migration`. Two
12
+ * unrelated OnCallDutyPolicyScheduleLayer default changes the generator also
13
+ * emitted (pre-existing whitespace drift between the entity defaults and the
14
+ * local schema) were dropped: they are not part of this change.
15
+ *
16
+ * The backfill rides along in the same migration rather than a follow-up so
17
+ * there is no window in which existing tasks are on-screen with a blank
18
+ * number.
19
+ */
20
+ export class AddAITaskNumberAndRunTranscript1784124919694
21
+ implements MigrationInterface
22
+ {
23
+ public name: string = "AddAITaskNumberAndRunTranscript1784124919694";
24
+
25
+ public async up(queryRunner: QueryRunner): Promise<void> {
26
+ await queryRunner.query(
27
+ `ALTER TABLE "Project" ADD "aiRunCounter" integer NOT NULL DEFAULT '0'`,
28
+ );
29
+ await queryRunner.query(`ALTER TABLE "AIRun" ADD "taskNumber" integer`);
30
+ await queryRunner.query(
31
+ `ALTER TABLE "AIRunEvent" ADD "contentPayload" jsonb`,
32
+ );
33
+ await queryRunner.query(
34
+ `CREATE INDEX "IDX_ede30aa8b14a167586bd555fa9" ON "AIRun" ("taskNumber") `,
35
+ );
36
+
37
+ /*
38
+ * Number the tasks that already exist, oldest first, per project — so the
39
+ * list does not read "#1, -, -, #2" the day this ships. Scoped to
40
+ * runType = 'CodeFix' because only code-fix runs are tasks; chat and
41
+ * investigation runs share this table and must stay null.
42
+ *
43
+ * Soft-deleted rows are numbered too. Not to prevent reuse (a skipped row
44
+ * would hold no number to reuse) but to keep the sequence a stable
45
+ * function of creation order: a run that is soft-deleted later must not
46
+ * renumber the runs after it, and an undeleted row must not collide with
47
+ * a number already handed out. The cost is gaps in what the list shows,
48
+ * which is the same thing incidents do.
49
+ */
50
+ await queryRunner.query(`
51
+ WITH numbered AS (
52
+ SELECT
53
+ "_id",
54
+ ROW_NUMBER() OVER (
55
+ PARTITION BY "projectId"
56
+ ORDER BY "createdAt" ASC, "_id" ASC
57
+ ) AS "rowNumber"
58
+ FROM "AIRun"
59
+ WHERE "runType" = 'CodeFix'
60
+ )
61
+ UPDATE "AIRun"
62
+ SET "taskNumber" = numbered."rowNumber"
63
+ FROM numbered
64
+ WHERE "AIRun"."_id" = numbered."_id"
65
+ `);
66
+
67
+ /*
68
+ * Advance each project's counter past what the backfill just handed out,
69
+ * so the next allocation continues the sequence instead of restarting at
70
+ * #1 and colliding. Projects with no code-fix runs keep the 0 default.
71
+ */
72
+ await queryRunner.query(`
73
+ UPDATE "Project"
74
+ SET "aiRunCounter" = "maxPerProject"."maxTaskNumber"
75
+ FROM (
76
+ SELECT "projectId", MAX("taskNumber") AS "maxTaskNumber"
77
+ FROM "AIRun"
78
+ WHERE "runType" = 'CodeFix' AND "taskNumber" IS NOT NULL
79
+ GROUP BY "projectId"
80
+ ) AS "maxPerProject"
81
+ WHERE "Project"."_id" = "maxPerProject"."projectId"
82
+ `);
83
+ }
84
+
85
+ public async down(queryRunner: QueryRunner): Promise<void> {
86
+ await queryRunner.query(
87
+ `DROP INDEX "public"."IDX_ede30aa8b14a167586bd555fa9"`,
88
+ );
89
+ await queryRunner.query(
90
+ `ALTER TABLE "AIRunEvent" DROP COLUMN "contentPayload"`,
91
+ );
92
+ await queryRunner.query(`ALTER TABLE "AIRun" DROP COLUMN "taskNumber"`);
93
+ await queryRunner.query(`ALTER TABLE "Project" DROP COLUMN "aiRunCounter"`);
94
+ }
95
+ }
@@ -0,0 +1,52 @@
1
+ import { MigrationInterface, QueryRunner } from "typeorm";
2
+
3
+ /*
4
+ * A pull request can now be proposed from an AI chat conversation, which has
5
+ * no AIAgent behind it (the AIAgent record belongs to the autonomous fix
6
+ * worker). aiAgentId becomes nullable so chat-authored PRs can be recorded at
7
+ * all — and recording them is what makes them count against the per-repository
8
+ * open-PR cap, which reads AIAgentTaskPullRequest rows.
9
+ *
10
+ * A null aiAgentId therefore means "proposed from chat". Existing rows all
11
+ * have an agent, so dropping NOT NULL needs no backfill and the down migration
12
+ * is safe until the first chat-authored PR exists.
13
+ */
14
+ export class AllowNullAiAgentOnPullRequest1784135099754
15
+ implements MigrationInterface
16
+ {
17
+ public name = "AllowNullAiAgentOnPullRequest1784135099754";
18
+
19
+ public async up(queryRunner: QueryRunner): Promise<void> {
20
+ /*
21
+ * The FK is dropped and re-added because Postgres will not alter a column's
22
+ * nullability while a foreign key references it. ON DELETE CASCADE is
23
+ * preserved exactly as it was.
24
+ */
25
+ await queryRunner.query(
26
+ `ALTER TABLE "AIAgentTaskPullRequest" DROP CONSTRAINT "FK_b1e01ecfe9eecfb555428471073"`,
27
+ );
28
+ await queryRunner.query(
29
+ `ALTER TABLE "AIAgentTaskPullRequest" ALTER COLUMN "aiAgentId" DROP NOT NULL`,
30
+ );
31
+ await queryRunner.query(
32
+ `ALTER TABLE "AIAgentTaskPullRequest" ADD CONSTRAINT "FK_b1e01ecfe9eecfb555428471073" FOREIGN KEY ("aiAgentId") REFERENCES "AIAgent"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
33
+ );
34
+ }
35
+
36
+ public async down(queryRunner: QueryRunner): Promise<void> {
37
+ /*
38
+ * Restoring NOT NULL fails if any chat-authored (null-agent) rows exist.
39
+ * That is deliberate: silently deleting or reassigning a customer's pull
40
+ * request records to satisfy a rollback would be worse than a loud failure.
41
+ */
42
+ await queryRunner.query(
43
+ `ALTER TABLE "AIAgentTaskPullRequest" DROP CONSTRAINT "FK_b1e01ecfe9eecfb555428471073"`,
44
+ );
45
+ await queryRunner.query(
46
+ `ALTER TABLE "AIAgentTaskPullRequest" ALTER COLUMN "aiAgentId" SET NOT NULL`,
47
+ );
48
+ await queryRunner.query(
49
+ `ALTER TABLE "AIAgentTaskPullRequest" ADD CONSTRAINT "FK_b1e01ecfe9eecfb555428471073" FOREIGN KEY ("aiAgentId") REFERENCES "AIAgent"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
50
+ );
51
+ }
52
+ }
@@ -0,0 +1,30 @@
1
+ import { MigrationInterface, QueryRunner } from "typeorm";
2
+
3
+ /*
4
+ * Status page owners can now stop AI agents from reading their status page over
5
+ * the public OneUptime MCP server. MCP access stays on unless it is turned off,
6
+ * so the column defaults to true.
7
+ *
8
+ * ADD COLUMN ... NOT NULL DEFAULT true populates every existing row with true in
9
+ * the same statement, so no backfill is needed and existing status pages keep
10
+ * working exactly as they do today. That is what makes the
11
+ * `enableMcpServer: true` predicate in StatusPageService.isMcpServerEnabled
12
+ * safe — there are no NULL rows for it to silently drop.
13
+ */
14
+ export class AddEnableMcpServerToStatusPage1784137457184
15
+ implements MigrationInterface
16
+ {
17
+ public name = "AddEnableMcpServerToStatusPage1784137457184";
18
+
19
+ public async up(queryRunner: QueryRunner): Promise<void> {
20
+ await queryRunner.query(
21
+ `ALTER TABLE "StatusPage" ADD "enableMcpServer" boolean NOT NULL DEFAULT true`,
22
+ );
23
+ }
24
+
25
+ public async down(queryRunner: QueryRunner): Promise<void> {
26
+ await queryRunner.query(
27
+ `ALTER TABLE "StatusPage" DROP COLUMN "enableMcpServer"`,
28
+ );
29
+ }
30
+ }
@@ -0,0 +1,49 @@
1
+ import { MigrationInterface, QueryRunner } from "typeorm";
2
+
3
+ export class AddSnmpV3ColumnsToNetworkDeviceDiscoveryScan1784200000000
4
+ implements MigrationInterface
5
+ {
6
+ public name = "AddSnmpV3ColumnsToNetworkDeviceDiscoveryScan1784200000000";
7
+
8
+ public async up(queryRunner: QueryRunner): Promise<void> {
9
+ await queryRunner.query(
10
+ `ALTER TABLE "NetworkDeviceDiscoveryScan" ADD "snmpV3SecurityLevel" character varying(100)`,
11
+ );
12
+ await queryRunner.query(
13
+ `ALTER TABLE "NetworkDeviceDiscoveryScan" ADD "snmpV3Username" character varying(100)`,
14
+ );
15
+ await queryRunner.query(
16
+ `ALTER TABLE "NetworkDeviceDiscoveryScan" ADD "snmpV3AuthProtocol" character varying(100)`,
17
+ );
18
+ await queryRunner.query(
19
+ `ALTER TABLE "NetworkDeviceDiscoveryScan" ADD "snmpV3AuthKey" text`,
20
+ );
21
+ await queryRunner.query(
22
+ `ALTER TABLE "NetworkDeviceDiscoveryScan" ADD "snmpV3PrivProtocol" character varying(100)`,
23
+ );
24
+ await queryRunner.query(
25
+ `ALTER TABLE "NetworkDeviceDiscoveryScan" ADD "snmpV3PrivKey" text`,
26
+ );
27
+ }
28
+
29
+ public async down(queryRunner: QueryRunner): Promise<void> {
30
+ await queryRunner.query(
31
+ `ALTER TABLE "NetworkDeviceDiscoveryScan" DROP COLUMN "snmpV3PrivKey"`,
32
+ );
33
+ await queryRunner.query(
34
+ `ALTER TABLE "NetworkDeviceDiscoveryScan" DROP COLUMN "snmpV3PrivProtocol"`,
35
+ );
36
+ await queryRunner.query(
37
+ `ALTER TABLE "NetworkDeviceDiscoveryScan" DROP COLUMN "snmpV3AuthKey"`,
38
+ );
39
+ await queryRunner.query(
40
+ `ALTER TABLE "NetworkDeviceDiscoveryScan" DROP COLUMN "snmpV3AuthProtocol"`,
41
+ );
42
+ await queryRunner.query(
43
+ `ALTER TABLE "NetworkDeviceDiscoveryScan" DROP COLUMN "snmpV3Username"`,
44
+ );
45
+ await queryRunner.query(
46
+ `ALTER TABLE "NetworkDeviceDiscoveryScan" DROP COLUMN "snmpV3SecurityLevel"`,
47
+ );
48
+ }
49
+ }
@@ -450,6 +450,11 @@ import { AddSentinelInsightFlags1784010274994 } from "./1784010274994-AddSentine
450
450
  import { RenameSentinelToAI1784030612266 } from "./1784030612266-RenameSentinelToAI";
451
451
  import { MigrationName1784033837629 } from "./1784033837629-MigrationName";
452
452
  import { AddCreatedByUserToUser1784048917994 } from "./1784048917994-AddCreatedByUserToUser";
453
+ import { BackfillCodeFixTaskType1784105912819 } from "./1784105912819-BackfillCodeFixTaskType";
454
+ import { AddAITaskNumberAndRunTranscript1784124919694 } from "./1784124919694-AddAITaskNumberAndRunTranscript";
455
+ import { AllowNullAiAgentOnPullRequest1784135099754 } from "./1784135099754-AllowNullAiAgentOnPullRequest";
456
+ import { AddEnableMcpServerToStatusPage1784137457184 } from "./1784137457184-AddEnableMcpServerToStatusPage";
457
+ import { AddSnmpV3ColumnsToNetworkDeviceDiscoveryScan1784200000000 } from "./1784200000000-AddSnmpV3ColumnsToNetworkDeviceDiscoveryScan";
453
458
 
454
459
  export default [
455
460
  InitialMigration,
@@ -904,4 +909,9 @@ export default [
904
909
  RenameSentinelToAI1784030612266,
905
910
  MigrationName1784033837629,
906
911
  AddCreatedByUserToUser1784048917994,
912
+ BackfillCodeFixTaskType1784105912819,
913
+ AddAITaskNumberAndRunTranscript1784124919694,
914
+ AllowNullAiAgentOnPullRequest1784135099754,
915
+ AddEnableMcpServerToStatusPage1784137457184,
916
+ AddSnmpV3ColumnsToNetworkDeviceDiscoveryScan1784200000000,
907
917
  ];
@@ -59,7 +59,7 @@ export default class MasterAdminAuthorization {
59
59
  * Same as isAuthorizedMasterAdminMiddleware, but ALSO accepts the instance-wide
60
60
  * master API key (Admin Dashboard → Settings → API Key) supplied in the
61
61
  * `apikey` header. The master key has root/master-admin access, so this lets
62
- * automated callers reach the master-admin instance-health endpoints with the
62
+ * automated callers reach the master-admin OneUptime Health endpoints with the
63
63
  * key instead of a logged-in master-admin session.
64
64
  *
65
65
  * Deliberately scoped to the read-only health / diagnostics routes only. It is
@@ -65,7 +65,7 @@ export default class ProjectMiddleware {
65
65
  * (Admin Dashboard → Settings → API Key) and that key is currently enabled.
66
66
  * The master key has root/master-admin access, so this is shared with
67
67
  * MasterAdminAuthorization to let the key reach master-admin-only endpoints
68
- * (e.g. instance health) as well.
68
+ * (e.g. OneUptime Health) as well.
69
69
  */
70
70
  @CaptureSpan()
71
71
  public static async isMasterApiKey(apiKey: ObjectID): Promise<boolean> {
@@ -2,13 +2,17 @@ import PositiveNumber from "../../Types/PositiveNumber";
2
2
  import ObjectID from "../../Types/ObjectID";
3
3
  import { JSONObject } from "../../Types/JSON";
4
4
  import AIRunEventType from "../../Types/AI/AIRunEventType";
5
- import { AIRunEventResultSummary } from "../../Types/AI/AIChatTypes";
5
+ import {
6
+ AIRunEventContentPayload,
7
+ AIRunEventResultSummary,
8
+ } from "../../Types/AI/AIChatTypes";
6
9
  import CountBy from "../Types/Database/CountBy";
7
10
  import FindBy from "../Types/Database/FindBy";
8
11
  import { OnFind } from "../Types/Database/Hooks";
9
12
  import DatabaseService from "./DatabaseService";
10
13
  import Model from "../../Models/DatabaseModels/AIRunEvent";
11
14
  import { pinQueryToRequestingUser } from "../Utils/AI/AIChatPrivacyFilter";
15
+ import AIRunTranscript from "../Utils/AI/AIRunTranscript";
12
16
  import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
13
17
  import logger from "../Utils/Logger";
14
18
 
@@ -36,6 +40,7 @@ export class Service extends DatabaseService<Model> {
36
40
  toolArguments?: JSONObject | undefined;
37
41
  resultSummary?: AIRunEventResultSummary | undefined;
38
42
  citationId?: string | undefined;
43
+ contentPayload?: AIRunEventContentPayload | undefined;
39
44
  }): Promise<void> {
40
45
  try {
41
46
  const sequence: number = (
@@ -63,6 +68,15 @@ export class Service extends DatabaseService<Model> {
63
68
  if (data.citationId) {
64
69
  event.citationId = data.citationId;
65
70
  }
71
+ /*
72
+ * Capped here rather than at the call sites, so no caller can write an
73
+ * unbounded transcript row by forgetting to clamp.
74
+ */
75
+ if (data.contentPayload) {
76
+ event.contentPayload = AIRunTranscript.clampPayload(
77
+ data.contentPayload,
78
+ );
79
+ }
66
80
 
67
81
  await this.create({
68
82
  data: event,
@@ -12,12 +12,15 @@ import CodeFixTaskType, {
12
12
  import SortOrder from "../../Types/BaseDatabase/SortOrder";
13
13
  import QueryHelper from "../Types/Database/QueryHelper";
14
14
  import CountBy from "../Types/Database/CountBy";
15
+ import CreateBy from "../Types/Database/CreateBy";
15
16
  import FindBy from "../Types/Database/FindBy";
16
- import { OnFind } from "../Types/Database/Hooks";
17
+ import { OnCreate, OnFind } from "../Types/Database/Hooks";
17
18
  import DatabaseService from "./DatabaseService";
19
+ import ProjectService from "./ProjectService";
18
20
  import Model from "../../Models/DatabaseModels/AIRun";
19
- import { pinQueryToRequestingUser } from "../Utils/AI/AIChatPrivacyFilter";
21
+ import { applyAIRunPrivacyFilter } from "../Utils/AI/AIRunPrivacyFilter";
20
22
  import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
23
+ import logger from "../Utils/Logger";
21
24
  import { UpdateQueryBuilder, UpdateResult } from "typeorm";
22
25
  import { QueryDeepPartialEntity } from "typeorm/query-builder/QueryPartialEntity";
23
26
 
@@ -328,26 +331,59 @@ export class Service extends DatabaseService<Model> {
328
331
  return { runId: run.id, verdict: data.verdict };
329
332
  }
330
333
 
334
+ /*
335
+ * Stamp CodeFix runs with the project's next task number, so every AI task
336
+ * has the short human-citable handle "#42" that incidents and alerts have.
337
+ *
338
+ * CodeFix only, on purpose: chat turns and investigations share this table
339
+ * but are not tasks, and numbering them would advance the counter on every
340
+ * Ask-AI message — the AI Tasks list would then read #7, #31, #244.
341
+ *
342
+ * Best-effort. The counter needs Redis (Semaphore) and a second write; a
343
+ * blip there must not lose a fix run, because the number is a display
344
+ * convenience and the run itself is the work. On failure the run is created
345
+ * with a null taskNumber, which the list renders as "-" and the detail page
346
+ * hides — the run stays fully usable, just uncitable.
347
+ */
348
+ protected override async onBeforeCreate(
349
+ createBy: CreateBy<Model>,
350
+ ): Promise<OnCreate<Model>> {
351
+ const projectId: ObjectID | undefined =
352
+ createBy.data.projectId || createBy.props.tenantId || undefined;
353
+
354
+ if (createBy.data.runType === AIRunType.CodeFix && projectId) {
355
+ try {
356
+ createBy.data.taskNumber =
357
+ await ProjectService.incrementAndGetAIRunCounter(projectId);
358
+ } catch (error) {
359
+ logger.error(
360
+ `Could not allocate a task number for a code-fix run in project ${projectId.toString()}; creating it unnumbered: ${error}`,
361
+ );
362
+ }
363
+ }
364
+
365
+ return { createBy, carryForward: null };
366
+ }
367
+
331
368
  protected override async onBeforeFind(
332
369
  findBy: FindBy<Model>,
333
370
  ): Promise<OnFind<Model>> {
334
- findBy.query = pinQueryToRequestingUser(
335
- findBy.query,
336
- findBy.props,
337
- "userId",
338
- );
371
+ findBy.query = applyAIRunPrivacyFilter(findBy.query, findBy.props);
339
372
  return { findBy, carryForward: null };
340
373
  }
341
374
 
375
+ /*
376
+ * countBy MUST repeat the filter. DatabaseService has no onBeforeCount hook
377
+ * (only onCountSuccess / onCountError), and BaseAPI.getList issues findBy
378
+ * and countBy with the SAME client query, so filtering in onBeforeFind alone
379
+ * would return a correctly-scoped list beside an unscoped project-wide
380
+ * count on every page. IncidentService repeats it for the same reason.
381
+ */
342
382
  @CaptureSpan()
343
383
  public override async countBy(
344
384
  countBy: CountBy<Model>,
345
385
  ): Promise<PositiveNumber> {
346
- countBy.query = pinQueryToRequestingUser(
347
- countBy.query,
348
- countBy.props,
349
- "userId",
350
- );
386
+ countBy.query = applyAIRunPrivacyFilter(countBy.query, countBy.props);
351
387
  return super.countBy(countBy);
352
388
  }
353
389
  }
@@ -333,6 +333,7 @@ export class Service extends DatabaseService<Model> {
333
333
  select: {
334
334
  _id: true,
335
335
  name: true,
336
+ description: true,
336
337
  llmType: true,
337
338
  modelName: true,
338
339
  isDefault: true,
@@ -356,6 +357,7 @@ export class Service extends DatabaseService<Model> {
356
357
  select: {
357
358
  _id: true,
358
359
  name: true,
360
+ description: true,
359
361
  llmType: true,
360
362
  modelName: true,
361
363
  isDefault: true,
@@ -2144,6 +2144,48 @@ export class ProjectService extends DatabaseService<Model> {
2144
2144
  }
2145
2145
  }
2146
2146
 
2147
+ /*
2148
+ * Allocate the next AI task number for a project. Unlike the counters
2149
+ * above there is no companion prefix column — AI task numbers are not
2150
+ * user-customizable, so the caller renders a plain "#N".
2151
+ */
2152
+ @CaptureSpan()
2153
+ public async incrementAndGetAIRunCounter(
2154
+ projectId: ObjectID,
2155
+ ): Promise<number> {
2156
+ const mutex: SemaphoreMutex = await Semaphore.lock({
2157
+ key: projectId.toString(),
2158
+ namespace: "ProjectService.aiRunCounter",
2159
+ });
2160
+
2161
+ try {
2162
+ await this.atomicIncrementColumnValueByOne({
2163
+ id: projectId,
2164
+ columnName: "aiRunCounter",
2165
+ });
2166
+
2167
+ const project: Model | null = await this.findOneById({
2168
+ id: projectId,
2169
+ select: {
2170
+ aiRunCounter: true,
2171
+ },
2172
+ props: {
2173
+ isRoot: true,
2174
+ },
2175
+ });
2176
+
2177
+ if (!project || project.aiRunCounter === undefined) {
2178
+ throw new BadDataException(
2179
+ `Could not read aiRunCounter for project ${projectId.toString()}`,
2180
+ );
2181
+ }
2182
+
2183
+ return project.aiRunCounter;
2184
+ } finally {
2185
+ await Semaphore.release(mutex);
2186
+ }
2187
+ }
2188
+
2147
2189
  @CaptureSpan()
2148
2190
  public async isSMSNotificationsEnabled(
2149
2191
  projectId: ObjectID,
@@ -118,6 +118,93 @@ export class Service extends DatabaseService<StatusPage> {
118
118
  this.statusPageUrlCache.clear();
119
119
  }
120
120
 
121
+ /*
122
+ * Mirrors `resolveStatusPageIdOrThrow` in `Common/Server/API/StatusPageAPI.ts`
123
+ * (module-private there), but returns null instead of throwing so callers can
124
+ * collapse "no such page" and "page exists but is gated" into one answer.
125
+ * The dot check — not a UUID check — is the discriminator, so both resolvers
126
+ * agree on dotless hostnames like "localhost".
127
+ */
128
+ @CaptureSpan()
129
+ public async resolveStatusPageIdOrNull(
130
+ statusPageIdOrDomain: string,
131
+ ): Promise<ObjectID | null> {
132
+ if (!statusPageIdOrDomain) {
133
+ return null;
134
+ }
135
+
136
+ if (statusPageIdOrDomain.includes(".")) {
137
+ const statusPageDomain: StatusPageDomain | null =
138
+ await StatusPageDomainService.findOneBy({
139
+ query: {
140
+ fullDomain: statusPageIdOrDomain,
141
+ domain: {
142
+ isVerified: true,
143
+ } as any,
144
+ },
145
+ select: {
146
+ statusPageId: true,
147
+ },
148
+ props: {
149
+ isRoot: true,
150
+ },
151
+ });
152
+
153
+ if (!statusPageDomain || !statusPageDomain.statusPageId) {
154
+ return null;
155
+ }
156
+
157
+ return statusPageDomain.statusPageId;
158
+ }
159
+
160
+ try {
161
+ ObjectID.validateUUID(statusPageIdOrDomain);
162
+ return new ObjectID(statusPageIdOrDomain);
163
+ } catch (err) {
164
+ logger.error(
165
+ `Error converting statusPageIdOrDomain to ObjectID: ${statusPageIdOrDomain}`,
166
+ );
167
+ logger.error(err);
168
+ return null;
169
+ }
170
+ }
171
+
172
+ /*
173
+ * Folds existence and the `enableMcpServer` flag into a single query so the
174
+ * caller cannot distinguish "not found" from "disabled". The public MCP tools
175
+ * need no API key, so a distinct "disabled" message would be a status page
176
+ * enumeration oracle.
177
+ *
178
+ * Throws on database failure rather than returning false, so the caller
179
+ * reports an error instead of reporting the page as gated.
180
+ */
181
+ @CaptureSpan()
182
+ public async isMcpServerEnabled(
183
+ statusPageIdOrDomain: string,
184
+ ): Promise<boolean> {
185
+ const statusPageId: ObjectID | null =
186
+ await this.resolveStatusPageIdOrNull(statusPageIdOrDomain);
187
+
188
+ if (!statusPageId) {
189
+ return false;
190
+ }
191
+
192
+ const statusPage: StatusPage | null = await this.findOneBy({
193
+ query: {
194
+ _id: statusPageId,
195
+ enableMcpServer: true,
196
+ },
197
+ select: {
198
+ _id: true,
199
+ },
200
+ props: {
201
+ isRoot: true,
202
+ },
203
+ });
204
+
205
+ return Boolean(statusPage);
206
+ }
207
+
121
208
  public static getDefaultEmailFooterText(): string {
122
209
  return "This is an automated email sent to you because you are subscribed to this Status Page.";
123
210
  }