bopodev-api 0.1.24 → 0.1.26
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/package.json +4 -4
- package/src/app.ts +11 -1
- package/src/http.ts +39 -0
- package/src/lib/comment-recipients.ts +105 -0
- package/src/lib/hiring-delegate.ts +7 -6
- package/src/lib/instance-paths.ts +11 -0
- package/src/realtime/attention.ts +47 -0
- package/src/realtime/governance.ts +11 -3
- package/src/realtime/heartbeat-runs.ts +33 -11
- package/src/realtime/hub.ts +34 -2
- package/src/realtime/office-space.ts +17 -1
- package/src/routes/agents.ts +81 -12
- package/src/routes/attention.ts +112 -0
- package/src/routes/companies.ts +13 -5
- package/src/routes/goals.ts +10 -2
- package/src/routes/governance.ts +85 -2
- package/src/routes/heartbeats.ts +81 -43
- package/src/routes/issues.ts +293 -62
- package/src/routes/observability.ts +219 -10
- package/src/routes/projects.ts +7 -2
- package/src/scripts/onboard-seed.ts +8 -7
- package/src/server.ts +3 -1
- package/src/services/attention-service.ts +412 -0
- package/src/services/budget-service.ts +99 -2
- package/src/services/comment-recipient-dispatch-service.ts +158 -0
- package/src/services/governance-service.ts +237 -14
- package/src/services/heartbeat-queue-service.ts +318 -0
- package/src/services/heartbeat-service.ts +2341 -278
- package/src/services/memory-file-service.ts +510 -35
- package/src/services/plugin-runtime.ts +33 -1
- package/src/services/template-apply-service.ts +37 -2
- package/src/worker/scheduler.ts +46 -8
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { AGENT_ROLE_LABELS, AgentRoleKeySchema, type TemplateApplyResponse, type TemplateManifest } from "bopodev-contracts";
|
|
2
2
|
import type { BopoDb } from "bopodev-db";
|
|
3
3
|
import {
|
|
4
4
|
createAgent,
|
|
@@ -59,7 +59,9 @@ export async function applyTemplateManifest(
|
|
|
59
59
|
const createdAgent = await createAgent(db, {
|
|
60
60
|
companyId: input.companyId,
|
|
61
61
|
managerAgentId: managerId,
|
|
62
|
-
role: agent.role,
|
|
62
|
+
role: resolveAgentRoleText(agent.role, agent.roleKey, agent.title),
|
|
63
|
+
roleKey: normalizeRoleKey(agent.roleKey),
|
|
64
|
+
title: normalizeTitle(agent.title),
|
|
63
65
|
name: agent.name,
|
|
64
66
|
providerType: agent.providerType,
|
|
65
67
|
heartbeatCron: agent.heartbeatCron,
|
|
@@ -136,3 +138,36 @@ export async function applyTemplateManifest(
|
|
|
136
138
|
warnings: preview.warnings
|
|
137
139
|
};
|
|
138
140
|
}
|
|
141
|
+
|
|
142
|
+
function normalizeRoleKey(input: string | null | undefined) {
|
|
143
|
+
const normalized = input?.trim().toLowerCase();
|
|
144
|
+
if (!normalized) {
|
|
145
|
+
return null;
|
|
146
|
+
}
|
|
147
|
+
return AgentRoleKeySchema.safeParse(normalized).success ? normalized : null;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function normalizeTitle(input: string | null | undefined) {
|
|
151
|
+
const normalized = input?.trim();
|
|
152
|
+
return normalized ? normalized : null;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function resolveAgentRoleText(
|
|
156
|
+
legacyRole: string | undefined,
|
|
157
|
+
roleKeyInput: string | undefined,
|
|
158
|
+
titleInput: string | null | undefined
|
|
159
|
+
) {
|
|
160
|
+
const normalizedLegacy = legacyRole?.trim();
|
|
161
|
+
if (normalizedLegacy) {
|
|
162
|
+
return normalizedLegacy;
|
|
163
|
+
}
|
|
164
|
+
const normalizedTitle = normalizeTitle(titleInput);
|
|
165
|
+
if (normalizedTitle) {
|
|
166
|
+
return normalizedTitle;
|
|
167
|
+
}
|
|
168
|
+
const roleKey = normalizeRoleKey(roleKeyInput);
|
|
169
|
+
if (roleKey) {
|
|
170
|
+
return AGENT_ROLE_LABELS[roleKey as keyof typeof AGENT_ROLE_LABELS];
|
|
171
|
+
}
|
|
172
|
+
return AGENT_ROLE_LABELS.general;
|
|
173
|
+
}
|
package/src/worker/scheduler.ts
CHANGED
|
@@ -1,23 +1,61 @@
|
|
|
1
1
|
import type { BopoDb } from "bopodev-db";
|
|
2
2
|
import type { RealtimeHub } from "../realtime/hub";
|
|
3
3
|
import { runHeartbeatSweep } from "../services/heartbeat-service";
|
|
4
|
+
import { runHeartbeatQueueSweep } from "../services/heartbeat-queue-service";
|
|
5
|
+
import { runIssueCommentDispatchSweep } from "../services/comment-recipient-dispatch-service";
|
|
4
6
|
|
|
5
7
|
export function createHeartbeatScheduler(db: BopoDb, companyId: string, realtimeHub?: RealtimeHub) {
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
const
|
|
9
|
-
|
|
8
|
+
const heartbeatIntervalMs = Number(process.env.BOPO_HEARTBEAT_SWEEP_MS ?? 60_000);
|
|
9
|
+
const queueIntervalMs = Number(process.env.BOPO_HEARTBEAT_QUEUE_SWEEP_MS ?? 2_000);
|
|
10
|
+
const commentDispatchIntervalMs = Number(process.env.BOPO_COMMENT_DISPATCH_SWEEP_MS ?? 3_000);
|
|
11
|
+
let heartbeatRunning = false;
|
|
12
|
+
let queueRunning = false;
|
|
13
|
+
let commentDispatchRunning = false;
|
|
14
|
+
const heartbeatTimer = setInterval(() => {
|
|
15
|
+
if (heartbeatRunning) {
|
|
10
16
|
return;
|
|
11
17
|
}
|
|
12
|
-
|
|
18
|
+
heartbeatRunning = true;
|
|
13
19
|
void runHeartbeatSweep(db, companyId, { realtimeHub })
|
|
14
20
|
.catch((error) => {
|
|
15
21
|
// eslint-disable-next-line no-console
|
|
16
22
|
console.error("[scheduler] heartbeat sweep failed", error);
|
|
17
23
|
})
|
|
18
24
|
.finally(() => {
|
|
19
|
-
|
|
25
|
+
heartbeatRunning = false;
|
|
20
26
|
});
|
|
21
|
-
},
|
|
22
|
-
|
|
27
|
+
}, heartbeatIntervalMs);
|
|
28
|
+
const queueTimer = setInterval(() => {
|
|
29
|
+
if (queueRunning) {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
queueRunning = true;
|
|
33
|
+
void runHeartbeatQueueSweep(db, companyId, { realtimeHub })
|
|
34
|
+
.catch((error) => {
|
|
35
|
+
// eslint-disable-next-line no-console
|
|
36
|
+
console.error("[scheduler] queue sweep failed", error);
|
|
37
|
+
})
|
|
38
|
+
.finally(() => {
|
|
39
|
+
queueRunning = false;
|
|
40
|
+
});
|
|
41
|
+
}, queueIntervalMs);
|
|
42
|
+
const commentDispatchTimer = setInterval(() => {
|
|
43
|
+
if (commentDispatchRunning) {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
commentDispatchRunning = true;
|
|
47
|
+
void runIssueCommentDispatchSweep(db, companyId, { realtimeHub })
|
|
48
|
+
.catch((error) => {
|
|
49
|
+
// eslint-disable-next-line no-console
|
|
50
|
+
console.error("[scheduler] comment dispatch sweep failed", error);
|
|
51
|
+
})
|
|
52
|
+
.finally(() => {
|
|
53
|
+
commentDispatchRunning = false;
|
|
54
|
+
});
|
|
55
|
+
}, commentDispatchIntervalMs);
|
|
56
|
+
return () => {
|
|
57
|
+
clearInterval(heartbeatTimer);
|
|
58
|
+
clearInterval(queueTimer);
|
|
59
|
+
clearInterval(commentDispatchTimer);
|
|
60
|
+
};
|
|
23
61
|
}
|