bopodev-api 0.1.28 → 0.1.29

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 (42) hide show
  1. package/package.json +4 -4
  2. package/src/app.ts +17 -69
  3. package/src/lib/run-artifact-paths.ts +8 -0
  4. package/src/middleware/cors-config.ts +36 -0
  5. package/src/middleware/request-actor.ts +10 -16
  6. package/src/middleware/request-id.ts +9 -0
  7. package/src/middleware/request-logging.ts +24 -0
  8. package/src/routes/agents.ts +3 -9
  9. package/src/routes/companies.ts +18 -1
  10. package/src/routes/goals.ts +7 -13
  11. package/src/routes/governance.ts +2 -5
  12. package/src/routes/heartbeats.ts +7 -25
  13. package/src/routes/issues.ts +62 -120
  14. package/src/routes/observability.ts +6 -1
  15. package/src/routes/plugins.ts +5 -17
  16. package/src/routes/projects.ts +7 -25
  17. package/src/routes/templates.ts +6 -21
  18. package/src/scripts/onboard-seed.ts +5 -7
  19. package/src/server.ts +33 -292
  20. package/src/services/company-export-service.ts +63 -0
  21. package/src/services/governance-service.ts +4 -1
  22. package/src/services/heartbeat-service/active-runs.ts +15 -0
  23. package/src/services/heartbeat-service/budget-override.ts +46 -0
  24. package/src/services/heartbeat-service/claims.ts +61 -0
  25. package/src/services/heartbeat-service/cron.ts +58 -0
  26. package/src/services/heartbeat-service/heartbeat-realtime.ts +28 -0
  27. package/src/services/heartbeat-service/heartbeat-run-summary-text.ts +53 -0
  28. package/src/services/{heartbeat-service.ts → heartbeat-service/heartbeat-run.ts} +183 -633
  29. package/src/services/heartbeat-service/index.ts +5 -0
  30. package/src/services/heartbeat-service/stop.ts +90 -0
  31. package/src/services/heartbeat-service/sweep.ts +145 -0
  32. package/src/services/heartbeat-service/types.ts +65 -0
  33. package/src/services/memory-file-service.ts +10 -2
  34. package/src/shutdown/graceful-shutdown.ts +77 -0
  35. package/src/startup/database.ts +41 -0
  36. package/src/startup/deployment-validation.ts +37 -0
  37. package/src/startup/env.ts +17 -0
  38. package/src/startup/runtime-health.ts +128 -0
  39. package/src/startup/scheduler-config.ts +39 -0
  40. package/src/types/express.d.ts +13 -0
  41. package/src/types/request-actor.ts +6 -0
  42. package/src/validation/issue-routes.ts +79 -0
@@ -0,0 +1,53 @@
1
+ const AGENT_COMMENT_EMOJI_REGEX = /[\p{Extended_Pictographic}\uFE0F\u200D]/gu;
2
+
3
+ export function sanitizeAgentSummaryCommentBody(body: string) {
4
+ const sanitized = body.replace(AGENT_COMMENT_EMOJI_REGEX, "").trim();
5
+ return sanitized.length > 0 ? sanitized : "Run update.";
6
+ }
7
+
8
+ function extractSummaryFromJsonLikeText(input: string) {
9
+ const fencedMatch = input.match(/```(?:json)?\s*([\s\S]*?)```/i);
10
+ const candidate = fencedMatch?.[1]?.trim() ?? input.match(/\{[\s\S]*\}\s*$/)?.[0]?.trim();
11
+ if (!candidate) {
12
+ return null;
13
+ }
14
+ try {
15
+ const parsed = JSON.parse(candidate) as Record<string, unknown>;
16
+ const summary = parsed.summary;
17
+ if (typeof summary === "string" && summary.trim().length > 0) {
18
+ return summary.trim();
19
+ }
20
+ } catch {
21
+ // Fall through to regex extraction for loosely-formatted JSON.
22
+ }
23
+ const summaryMatch = candidate.match(/"summary"\s*:\s*"([\s\S]*?)"/);
24
+ const summary = summaryMatch?.[1]
25
+ ?.replace(/\\"/g, "\"")
26
+ .replace(/\\n/g, " ")
27
+ .replace(/\s+/g, " ")
28
+ .trim();
29
+ return summary && summary.length > 0 ? summary : null;
30
+ }
31
+
32
+ export function extractNaturalRunUpdate(executionSummary: string) {
33
+ const normalized = executionSummary.trim();
34
+ const jsonSummary = extractSummaryFromJsonLikeText(normalized);
35
+ const source = jsonSummary ?? normalized;
36
+ const lines = source
37
+ .split("\n")
38
+ .map((line) => line.trim())
39
+ .filter((line) => line.length > 0)
40
+ .filter((line) => !line.startsWith("{") && !line.startsWith("}"));
41
+ const compact = (lines.length > 0 ? lines.slice(0, 2).join(" ") : source)
42
+ .replace(/^run (failure )?summary\s*:\s*/i, "")
43
+ .replace(/^completed all assigned issue steps\s*:\s*/i, "")
44
+ .replace(/^issue status\s*:\s*/i, "")
45
+ .replace(/`+/g, "")
46
+ .replace(/\s+/g, " ")
47
+ .trim();
48
+ const bounded = compact.length > 260 ? `${compact.slice(0, 257).trimEnd()}...` : compact;
49
+ if (!bounded) {
50
+ return "Run update.";
51
+ }
52
+ return /[.!?]$/.test(bounded) ? bounded : `${bounded}.`;
53
+ }