bopodev-api 0.1.2 → 0.1.3

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 (2) hide show
  1. package/package.json +4 -4
  2. package/src/server.ts +50 -10
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bopodev-api",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "files": [
@@ -15,9 +15,9 @@
15
15
  "nanoid": "^5.1.5",
16
16
  "ws": "^8.19.0",
17
17
  "zod": "^4.1.5",
18
- "bopodev-agent-sdk": "0.1.2",
19
- "bopodev-contracts": "0.1.2",
20
- "bopodev-db": "0.1.2"
18
+ "bopodev-agent-sdk": "0.1.3",
19
+ "bopodev-contracts": "0.1.3",
20
+ "bopodev-db": "0.1.3"
21
21
  },
22
22
  "devDependencies": {
23
23
  "@types/cors": "^2.8.19",
package/src/server.ts CHANGED
@@ -1,6 +1,8 @@
1
1
  import { createServer } from "node:http";
2
+ import { sql } from "drizzle-orm";
2
3
  import { bootstrapDatabase } from "bopodev-db";
3
4
  import { checkRuntimeCommandHealth } from "bopodev-agent-sdk";
5
+ import type { RuntimeCommandHealth } from "bopodev-agent-sdk";
4
6
  import { createApp } from "./app";
5
7
  import { loadGovernanceRealtimeSnapshot } from "./realtime/governance";
6
8
  import { loadOfficeSpaceRealtimeSnapshot } from "./realtime/office-space";
@@ -12,21 +14,35 @@ async function main() {
12
14
  const port = Number(process.env.PORT ?? 4020);
13
15
  const { db } = await bootstrapDatabase(dbPath);
14
16
  const codexCommand = process.env.BOPO_CODEX_COMMAND ?? "codex";
17
+ const skipCodexPreflight = process.env.BOPO_SKIP_CODEX_PREFLIGHT === "1";
18
+ const codexHealthRequired =
19
+ !skipCodexPreflight &&
20
+ (process.env.BOPO_REQUIRE_CODEX_HEALTH === "1" || (await hasCodexAgentsConfigured(db)));
15
21
  const getRuntimeHealth = async () => {
16
- const codex = await checkRuntimeCommandHealth(codexCommand, {
17
- timeoutMs: 5_000
18
- });
22
+ const codex = codexHealthRequired
23
+ ? await checkRuntimeCommandHealth(codexCommand, {
24
+ timeoutMs: 5_000
25
+ })
26
+ : {
27
+ command: codexCommand,
28
+ available: skipCodexPreflight ? false : true,
29
+ exitCode: null,
30
+ elapsedMs: 0,
31
+ error: skipCodexPreflight
32
+ ? "Skipped by configuration: BOPO_SKIP_CODEX_PREFLIGHT=1."
33
+ : "Skipped: no Codex agents configured."
34
+ };
19
35
  return {
20
36
  codex
21
37
  };
22
38
  };
23
- const startupCodexHealth = await checkRuntimeCommandHealth(codexCommand, {
24
- timeoutMs: 5_000
25
- });
26
- const suppressStartupWarnings = process.env.BOPO_SUPPRESS_STARTUP_WARNINGS === "1";
27
- if (!startupCodexHealth.available && !suppressStartupWarnings) {
28
- // eslint-disable-next-line no-console
29
- console.warn("[startup] Codex command preflight failed.", startupCodexHealth);
39
+ if (codexHealthRequired) {
40
+ const startupCodexHealth = await checkRuntimeCommandHealth(codexCommand, {
41
+ timeoutMs: 5_000
42
+ });
43
+ if (!startupCodexHealth.available) {
44
+ emitCodexPreflightWarning(startupCodexHealth);
45
+ }
30
46
  }
31
47
 
32
48
  const server = createServer();
@@ -50,3 +66,27 @@ async function main() {
50
66
  }
51
67
 
52
68
  void main();
69
+
70
+ async function hasCodexAgentsConfigured(db: Awaited<ReturnType<typeof bootstrapDatabase>>["db"]) {
71
+ const result = await db.execute(sql`
72
+ SELECT id
73
+ FROM agents
74
+ WHERE provider_type = 'codex'
75
+ LIMIT 1
76
+ `);
77
+ return (result.rows ?? []).length > 0;
78
+ }
79
+
80
+ function emitCodexPreflightWarning(health: RuntimeCommandHealth) {
81
+ const red = process.stderr.isTTY ? "\x1b[31m" : "";
82
+ const yellow = process.stderr.isTTY ? "\x1b[33m" : "";
83
+ const reset = process.stderr.isTTY ? "\x1b[0m" : "";
84
+ const symbol = `${red}✖${reset}`;
85
+ process.stderr.write(
86
+ `${symbol} ${yellow}Codex preflight failed${reset}: command '${health.command}' is unavailable.\n`
87
+ );
88
+ process.stderr.write(` Install Codex CLI or set BOPO_SKIP_CODEX_PREFLIGHT=1 for local dev.\n`);
89
+ if (process.env.BOPO_VERBOSE_STARTUP_WARNINGS === "1") {
90
+ process.stderr.write(` Details: ${JSON.stringify(health)}\n`);
91
+ }
92
+ }