@agent-team-foundation/first-tree-hub 0.3.2 → 0.3.4

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.
@@ -1,18 +1,18 @@
1
- import { a as getGitHubUsername, b as serverConfigSchema, c as DEFAULT_CONFIG_DIR, d as clientConfigSchema, f as collectMissingPrompts, h as loadAgents, m as initConfig, r as checkBootstrapStatus, s as resolveServerUrl, t as bootstrapToken$1, u as agentConfigSchema, x as setConfigValue, y as resolveConfigReadonly } from "./bootstrap-B9JsJR3Z.mjs";
2
- import { ZodError, z } from "zod";
1
+ import { a as getGitHubUsername, b as serverConfigSchema, c as DEFAULT_CONFIG_DIR, d as clientConfigSchema, f as collectMissingPrompts, h as loadAgents, m as initConfig, r as checkBootstrapStatus, s as resolveServerUrl, t as bootstrapToken$1, u as agentConfigSchema, x as setConfigValue, y as resolveConfigReadonly } from "./bootstrap-CPdLNPme.mjs";
3
2
  import { copyFileSync, existsSync, mkdirSync, readFileSync, readdirSync, renameSync, rmSync, statSync, writeFileSync } from "node:fs";
4
3
  import { dirname, join, resolve } from "node:path";
5
- import { parse } from "yaml";
4
+ import { EventEmitter } from "node:events";
5
+ import WebSocket from "ws";
6
6
  import { createCipheriv, createDecipheriv, createHash, createHmac, randomBytes, randomUUID, timingSafeEqual } from "node:crypto";
7
+ import { query } from "@anthropic-ai/claude-agent-sdk";
8
+ import { execFileSync, execSync } from "node:child_process";
9
+ import { ZodError, z } from "zod";
10
+ import "yaml";
7
11
  import { homedir } from "node:os";
8
12
  import bcrypt from "bcrypt";
9
13
  import { and, desc, eq, gt, inArray, isNotNull, isNull, lt, ne, sql } from "drizzle-orm";
10
14
  import { drizzle } from "drizzle-orm/postgres-js";
11
15
  import postgres from "postgres";
12
- import { execFileSync, execSync } from "node:child_process";
13
- import { EventEmitter } from "node:events";
14
- import WebSocket from "ws";
15
- import { query } from "@anthropic-ai/claude-agent-sdk";
16
16
  import { fileURLToPath } from "node:url";
17
17
  import { migrate } from "drizzle-orm/postgres-js/migrator";
18
18
  import { input, password, select } from "@inquirer/prompts";
@@ -24,40 +24,6 @@ import Fastify from "fastify";
24
24
  import { bigserial, index, integer, jsonb, pgTable, primaryKey, serial, text, timestamp, unique } from "drizzle-orm/pg-core";
25
25
  import { SignJWT, jwtVerify } from "jose";
26
26
  import { Client, EventDispatcher, LoggerLevel, WSClient } from "@larksuiteoapi/node-sdk";
27
- //#region src/core/admin.ts
28
- /**
29
- * Check if any admin user exists.
30
- */
31
- async function hasAdminUser(databaseUrl) {
32
- const client = postgres(databaseUrl, { max: 1 });
33
- try {
34
- return (await client`SELECT count(*)::int AS count FROM admin_users`)[0].count > 0;
35
- } finally {
36
- await client.end();
37
- }
38
- }
39
- /**
40
- * Create an admin user. Returns the generated password.
41
- */
42
- async function createAdminUser$1(databaseUrl, username, password) {
43
- const pw = password ?? randomBytes(12).toString("base64url");
44
- const hash = await bcrypt.hash(pw, 12);
45
- const client = postgres(databaseUrl, { max: 1 });
46
- const db = drizzle(client);
47
- try {
48
- await db.execute(sql`
49
- INSERT INTO admin_users (id, username, password_hash, role)
50
- VALUES (${randomUUID()}, ${username}, ${hash}, 'super_admin')
51
- `);
52
- } finally {
53
- await client.end();
54
- }
55
- return {
56
- username,
57
- password: pw
58
- };
59
- }
60
- //#endregion
61
27
  //#region ../client/dist/index.mjs
62
28
  const FETCH_TIMEOUT_MS = 15e3;
63
29
  var FirstTreeHubSDK = class {
@@ -496,109 +462,7 @@ defineConfig({
496
462
  webhookMax: field(z.number().default(60), { env: "FIRST_TREE_HUB_RATE_LIMIT_WEBHOOK_MAX" })
497
463
  })
498
464
  });
499
- const CONTEXT_TREE_DIR$1 = join(DEFAULT_DATA_DIR, "context-tree");
500
- /**
501
- * Sync the shared Context Tree git clone.
502
- *
503
- * Clones on first run, pulls on subsequent runs.
504
- * Returns the clone path on success, null on failure (graceful degradation).
505
- */
506
- async function syncContextTree(serverUrl, token, log) {
507
- try {
508
- execFileSync("git", ["--version"], { stdio: "ignore" });
509
- } catch {
510
- log("Context Tree sync skipped: git is not installed");
511
- return null;
512
- }
513
- let repo;
514
- let branch;
515
- try {
516
- const config = await new FirstTreeHubSDK({
517
- serverUrl,
518
- token
519
- }).getContextTreeConfig();
520
- repo = config.repo;
521
- branch = config.branch;
522
- } catch (err) {
523
- log(`Context Tree sync skipped: failed to fetch config from server (${err instanceof Error ? err.message : String(err)})`);
524
- return null;
525
- }
526
- try {
527
- if (existsSync(join(CONTEXT_TREE_DIR$1, ".git"))) {
528
- if (execFileSync("git", [
529
- "rev-parse",
530
- "--abbrev-ref",
531
- "HEAD"
532
- ], {
533
- cwd: CONTEXT_TREE_DIR$1,
534
- encoding: "utf-8",
535
- timeout: 5e3
536
- }).trim() !== branch) {
537
- execFileSync("git", ["checkout", branch], {
538
- cwd: CONTEXT_TREE_DIR$1,
539
- stdio: "pipe",
540
- timeout: 1e4
541
- });
542
- log(`Context Tree switched to branch ${branch}`);
543
- }
544
- execFileSync("git", ["pull", "--ff-only"], {
545
- cwd: CONTEXT_TREE_DIR$1,
546
- stdio: "pipe",
547
- timeout: 3e4
548
- });
549
- log(`Context Tree updated (pull)`);
550
- } else {
551
- mkdirSync(CONTEXT_TREE_DIR$1, { recursive: true });
552
- execFileSync("git", [
553
- "clone",
554
- "--branch",
555
- branch,
556
- "--single-branch",
557
- repo,
558
- CONTEXT_TREE_DIR$1
559
- ], {
560
- stdio: "pipe",
561
- timeout: 6e4
562
- });
563
- log(`Context Tree cloned from ${repo} (branch: ${branch})`);
564
- }
565
- return CONTEXT_TREE_DIR$1;
566
- } catch (err) {
567
- const msg = err instanceof Error ? err.message : String(err);
568
- log(`Context Tree sync failed: ${msg}`);
569
- log("Check that git credentials (SSH key or credential helper) are configured for this repo");
570
- if ((msg.includes("cannot fast-forward") || msg.includes("not possible to fast-forward") || msg.includes("CONFLICT")) && existsSync(join(CONTEXT_TREE_DIR$1, ".git"))) {
571
- log("Diverged history detected, attempting fresh clone...");
572
- try {
573
- rmSync(CONTEXT_TREE_DIR$1, {
574
- recursive: true,
575
- force: true
576
- });
577
- mkdirSync(CONTEXT_TREE_DIR$1, { recursive: true });
578
- execFileSync("git", [
579
- "clone",
580
- "--branch",
581
- branch,
582
- "--single-branch",
583
- repo,
584
- CONTEXT_TREE_DIR$1
585
- ], {
586
- stdio: "pipe",
587
- timeout: 6e4
588
- });
589
- log("Context Tree re-cloned successfully");
590
- return CONTEXT_TREE_DIR$1;
591
- } catch {
592
- log("Context Tree re-clone also failed, continuing without context");
593
- }
594
- }
595
- if (existsSync(join(CONTEXT_TREE_DIR$1, ".git"))) {
596
- log("Using existing Context Tree clone despite sync failure");
597
- return CONTEXT_TREE_DIR$1;
598
- }
599
- return null;
600
- }
601
- }
465
+ join(DEFAULT_DATA_DIR, "context-tree");
602
466
  /**
603
467
  * Bootstrap a workspace with .agent/ directory files.
604
468
  *
@@ -1451,95 +1315,47 @@ const sessionConfigSchema = z.object({
1451
1315
  const agentSlotConfigSchema = z.object({
1452
1316
  token: z.string().min(1),
1453
1317
  type: z.string().min(1),
1454
- session: sessionConfigSchema.default({}),
1318
+ session: sessionConfigSchema.prefault({}),
1455
1319
  concurrency: z.number().int().positive().default(5)
1456
1320
  });
1457
- const runtimeConfigSchema = z.object({
1458
- server: z.string().url().default("http://localhost:8000"),
1459
- agents: z.record(agentSlotConfigSchema).refine((agents) => Object.keys(agents).length > 0, "At least one agent must be defined")
1321
+ z.object({
1322
+ server: z.url().default("http://localhost:8000"),
1323
+ agents: z.record(z.string(), agentSlotConfigSchema).refine((agents) => Object.keys(agents).length > 0, "At least one agent must be defined")
1460
1324
  });
1461
- function expandEnvVars(value) {
1462
- return value.replace(/\$\{([^}]+)\}/g, (_, name) => {
1463
- const envVal = process.env[name];
1464
- if (envVal === void 0) throw new Error(`Environment variable "${name}" is not set`);
1465
- return envVal;
1466
- });
1467
- }
1468
- function deepExpandEnv(obj) {
1469
- if (typeof obj === "string") return expandEnvVars(obj);
1470
- if (Array.isArray(obj)) return obj.map(deepExpandEnv);
1471
- if (obj !== null && typeof obj === "object") {
1472
- const result = {};
1473
- for (const [key, value] of Object.entries(obj)) result[key] = deepExpandEnv(value);
1474
- return result;
1325
+ //#endregion
1326
+ //#region src/core/admin.ts
1327
+ /**
1328
+ * Check if any admin user exists.
1329
+ */
1330
+ async function hasAdminUser(databaseUrl) {
1331
+ const client = postgres(databaseUrl, { max: 1 });
1332
+ try {
1333
+ return (await client`SELECT count(*)::int AS count FROM admin_users`)[0].count > 0;
1334
+ } finally {
1335
+ await client.end();
1475
1336
  }
1476
- return obj;
1477
1337
  }
1478
- function loadRuntimeConfig(configPath) {
1479
- const expanded = deepExpandEnv(parse(readFileSync(configPath, "utf-8")));
1480
- return runtimeConfigSchema.parse(expanded);
1481
- }
1482
- const DEFAULT_SHUTDOWN_TIMEOUT = 3e4;
1483
- var AgentRuntime = class {
1484
- slots = [];
1485
- config;
1486
- shutdownTimeout;
1487
- stopping = false;
1488
- constructor(options) {
1489
- this.config = options.config;
1490
- this.shutdownTimeout = options.shutdownTimeout ?? DEFAULT_SHUTDOWN_TIMEOUT;
1491
- for (const [name, agentConfig] of Object.entries(this.config.agents)) {
1492
- const handlerFactory = getHandlerFactory(agentConfig.type);
1493
- this.slots.push(new AgentSlot({
1494
- name,
1495
- serverUrl: this.config.server,
1496
- token: agentConfig.token,
1497
- type: agentConfig.type,
1498
- handlerFactory,
1499
- session: agentConfig.session,
1500
- concurrency: agentConfig.concurrency
1501
- }));
1502
- }
1503
- }
1504
- /** Start all agent slots and block until shutdown signal. */
1505
- async start() {
1506
- const log = (msg) => process.stderr.write(`[runtime] ${msg}\n`);
1507
- const firstToken = Object.values(this.config.agents)[0]?.token;
1508
- let contextTreePath = null;
1509
- if (firstToken) contextTreePath = await syncContextTree(this.config.server, firstToken, log);
1510
- if (!contextTreePath) log("WARNING: Context Tree sync failed — agents will start without organizational context");
1511
- log(`Starting ${this.slots.length} agent(s)...`);
1512
- const results = await Promise.allSettled(this.slots.map((slot) => slot.start(contextTreePath)));
1513
- let failed = 0;
1514
- for (const result of results) if (result.status === "rejected") {
1515
- log(`Failed to start agent: ${result.reason instanceof Error ? result.reason.message : result.reason}`);
1516
- failed++;
1517
- }
1518
- if (failed === this.slots.length) throw new Error("All agents failed to start");
1519
- log("Ready. Press Ctrl+C to stop.");
1520
- await new Promise((resolve) => {
1521
- const shutdown = async () => {
1522
- if (this.stopping) return;
1523
- this.stopping = true;
1524
- log("Shutting down...");
1525
- const timer = setTimeout(() => {
1526
- log("Shutdown timeout reached, forcing exit");
1527
- process.exit(1);
1528
- }, this.shutdownTimeout);
1529
- await this.stop();
1530
- clearTimeout(timer);
1531
- log("Stopped");
1532
- resolve();
1533
- };
1534
- process.on("SIGINT", shutdown);
1535
- process.on("SIGTERM", shutdown);
1536
- });
1537
- }
1538
- /** Stop all slots. */
1539
- async stop() {
1540
- await Promise.allSettled(this.slots.map((slot) => slot.stop()));
1338
+ /**
1339
+ * Create an admin user. Returns the generated password.
1340
+ */
1341
+ async function createAdminUser$1(databaseUrl, username, password) {
1342
+ const pw = password ?? randomBytes(12).toString("base64url");
1343
+ const hash = await bcrypt.hash(pw, 12);
1344
+ const client = postgres(databaseUrl, { max: 1 });
1345
+ const db = drizzle(client);
1346
+ try {
1347
+ await db.execute(sql`
1348
+ INSERT INTO admin_users (id, username, password_hash, role)
1349
+ VALUES (${randomUUID()}, ${username}, ${hash}, 'super_admin')
1350
+ `);
1351
+ } finally {
1352
+ await client.end();
1541
1353
  }
1542
- };
1354
+ return {
1355
+ username,
1356
+ password: pw
1357
+ };
1358
+ }
1543
1359
  //#endregion
1544
1360
  //#region src/core/client-runtime.ts
1545
1361
  /**
@@ -2564,13 +2380,16 @@ async function onboardContinue(args) {
2564
2380
  process.stderr.write("\n✅ Onboard complete!\n\n");
2565
2381
  process.stderr.write(` Human: ${mergedArgs.id}\n`);
2566
2382
  if (mergedArgs.assistant) process.stderr.write(` Assistant: ${mergedArgs.assistant}\n`);
2567
- process.stderr.write(` Token: ~/.first-tree-hub/agents/${agentToBootstrap}/agent.yaml\n`);
2383
+ process.stderr.write(` Token: ~/.first-tree-hub/config/agents/${agentToBootstrap}/agent.yaml\n`);
2568
2384
  if (mergedArgs.feishuBotAppId) process.stderr.write(` Feishu: bot bound (${mergedArgs.feishuBotAppId})\n`);
2385
+ setConfigValue(join(DEFAULT_CONFIG_DIR, "client.yaml"), "server.url", serverUrl);
2569
2386
  if (mergedArgs.type === "human") {
2570
2387
  process.stderr.write("\n Next step — bind your Feishu account:\n");
2571
2388
  process.stderr.write(` Send this message to the bot in Feishu: /bind ${mergedArgs.id}\n`);
2572
2389
  if (!mergedArgs.feishuBotAppId) process.stderr.write(" (requires a Feishu bot to be configured in the system)\n");
2573
2390
  }
2391
+ process.stderr.write("\n Start the agent:\n");
2392
+ process.stderr.write(" first-tree-hub client start\n");
2574
2393
  process.stderr.write("\n");
2575
2394
  }
2576
2395
  function createMemberNodeMd(repoPath, data) {
@@ -2813,12 +2632,12 @@ const adapterStatusSchema = z.enum(["active", "inactive"]);
2813
2632
  const createAdapterConfigSchema = z.object({
2814
2633
  platform: adapterPlatformSchema,
2815
2634
  agentId: z.string().min(1),
2816
- credentials: z.record(z.unknown()),
2635
+ credentials: z.record(z.string(), z.unknown()),
2817
2636
  status: adapterStatusSchema.default("active")
2818
2637
  });
2819
2638
  const updateAdapterConfigSchema = z.object({
2820
2639
  agentId: z.string().min(1).optional(),
2821
- credentials: z.record(z.unknown()).optional(),
2640
+ credentials: z.record(z.string(), z.unknown()).optional(),
2822
2641
  status: adapterStatusSchema.optional()
2823
2642
  });
2824
2643
  z.object({
@@ -2917,7 +2736,7 @@ z.object({
2917
2736
  type: agentTypeSchema,
2918
2737
  displayName: z.string().max(200).optional(),
2919
2738
  organizationId: z.string().max(100).optional(),
2920
- metadata: z.record(z.unknown()).optional()
2739
+ metadata: z.record(z.string(), z.unknown()).optional()
2921
2740
  });
2922
2741
  z.object({
2923
2742
  syncedAt: z.string(),
@@ -2946,7 +2765,7 @@ z.object({
2946
2765
  treePath: z.string().nullable(),
2947
2766
  inboxId: z.string(),
2948
2767
  status: z.string(),
2949
- metadata: z.record(z.unknown()),
2768
+ metadata: z.record(z.string(), z.unknown()),
2950
2769
  presenceStatus: presenceStatusSchema.optional(),
2951
2770
  createdAt: z.string(),
2952
2771
  updatedAt: z.string()
@@ -2983,7 +2802,7 @@ const createChatSchema = z.object({
2983
2802
  type: chatTypeSchema,
2984
2803
  topic: z.string().max(500).optional(),
2985
2804
  participantIds: z.array(z.string()).min(1),
2986
- metadata: z.record(z.unknown()).optional()
2805
+ metadata: z.record(z.string(), z.unknown()).optional()
2987
2806
  });
2988
2807
  const chatParticipantSchema = z.object({
2989
2808
  agentId: z.string(),
@@ -2997,7 +2816,7 @@ z.object({
2997
2816
  type: z.string(),
2998
2817
  topic: z.string().nullable(),
2999
2818
  lifecyclePolicy: z.string().nullable().optional(),
3000
- metadata: z.record(z.unknown()),
2819
+ metadata: z.record(z.string(), z.unknown()),
3001
2820
  createdAt: z.string(),
3002
2821
  updatedAt: z.string()
3003
2822
  }).extend({ participants: z.array(chatParticipantSchema) });
@@ -3020,7 +2839,7 @@ const messageFormatSchema = z.enum([
3020
2839
  const sendMessageSchema = z.object({
3021
2840
  format: messageFormatSchema.default("text"),
3022
2841
  content: z.unknown(),
3023
- metadata: z.record(z.unknown()).optional(),
2842
+ metadata: z.record(z.string(), z.unknown()).optional(),
3024
2843
  inReplyTo: z.string().optional(),
3025
2844
  replyToInbox: z.string().optional(),
3026
2845
  replyToChat: z.string().optional()
@@ -3028,7 +2847,7 @@ const sendMessageSchema = z.object({
3028
2847
  const sendToAgentSchema = z.object({
3029
2848
  format: messageFormatSchema.default("text"),
3030
2849
  content: z.unknown(),
3031
- metadata: z.record(z.unknown()).optional(),
2850
+ metadata: z.record(z.string(), z.unknown()).optional(),
3032
2851
  replyToInbox: z.string().optional(),
3033
2852
  replyToChat: z.string().optional()
3034
2853
  });
@@ -3038,7 +2857,7 @@ const messageSchema = z.object({
3038
2857
  senderId: z.string(),
3039
2858
  format: z.string(),
3040
2859
  content: z.unknown(),
3041
- metadata: z.record(z.unknown()),
2860
+ metadata: z.record(z.string(), z.unknown()),
3042
2861
  replyToInbox: z.string().nullable(),
3043
2862
  replyToChat: z.string().nullable(),
3044
2863
  inReplyTo: z.string().nullable(),
@@ -6594,4 +6413,4 @@ function resolveWebDist() {
6594
6413
  } catch {}
6595
6414
  }
6596
6415
  //#endregion
6597
- export { ClientRuntime as A, registerBuiltinHandlers as B, checkWebSocket as C, ensurePostgres as D, status as E, SdkError as F, hasAdminUser as H, SessionRegistry as I, cleanWorkspaces as L, AgentSlot as M, DEFAULT_WORKSPACE_TTL_MS as N, isDockerAvailable as O, FirstTreeHubSDK as P, getHandlerFactory as R, checkServerReachable as S, blank as T, createAdminUser$1 as V, checkDocker as _, formatCheckReport as a, checkServerConfig as b, onboardContinue as c, runMigrations as d, checkAgentConfigs as f, checkDatabase as g, checkContextTreeRepo as h, promptMissingFields as i, AgentRuntime as j, stopPostgres as k, onboardCreate as l, checkClientConfig as m, isInteractive as n, loadOnboardState as o, checkAgentTokens as p, promptAddAgent as r, onboardCheck as s, startServer as t, saveOnboardState as u, checkGitHubToken as v, printResults as w, checkServerHealth as x, checkNodeVersion as y, loadRuntimeConfig as z };
6416
+ export { ClientRuntime as A, checkWebSocket as C, ensurePostgres as D, status as E, SessionRegistry as F, cleanWorkspaces as I, hasAdminUser as M, FirstTreeHubSDK as N, isDockerAvailable as O, SdkError as P, checkServerReachable as S, blank as T, checkDocker as _, formatCheckReport as a, checkServerConfig as b, onboardContinue as c, runMigrations as d, checkAgentConfigs as f, checkDatabase as g, checkContextTreeRepo as h, promptMissingFields as i, createAdminUser$1 as j, stopPostgres as k, onboardCreate as l, checkClientConfig as m, isInteractive as n, loadOnboardState as o, checkAgentTokens as p, promptAddAgent as r, onboardCheck as s, startServer as t, saveOnboardState as u, checkGitHubToken as v, printResults as w, checkServerHealth as x, checkNodeVersion as y };
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { a as getGitHubUsername, i as getGitHubToken, o as resolveAgentToken, r as checkBootstrapStatus, s as resolveServerUrl, t as bootstrapToken } from "./bootstrap-B9JsJR3Z.mjs";
2
- import { A as ClientRuntime, C as checkWebSocket, D as ensurePostgres, E as status, F as SdkError, H as hasAdminUser, O as isDockerAvailable, P as FirstTreeHubSDK, S as checkServerReachable, T as blank, V as createAdminUser, _ as checkDocker, a as formatCheckReport, b as checkServerConfig, c as onboardContinue, d as runMigrations, f as checkAgentConfigs, g as checkDatabase, h as checkContextTreeRepo, i as promptMissingFields, k as stopPostgres, l as onboardCreate, m as checkClientConfig, n as isInteractive, p as checkAgentTokens, r as promptAddAgent, s as onboardCheck, t as startServer, v as checkGitHubToken, w as printResults, x as checkServerHealth, y as checkNodeVersion } from "./core-vR5jYKHZ.mjs";
1
+ import { A as ClientRuntime, C as checkWebSocket, D as ensurePostgres, E as status, M as hasAdminUser, N as FirstTreeHubSDK, O as isDockerAvailable, P as SdkError, S as checkServerReachable, T as blank, _ as checkDocker, a as formatCheckReport, b as checkServerConfig, c as onboardContinue, d as runMigrations, f as checkAgentConfigs, g as checkDatabase, h as checkContextTreeRepo, i as promptMissingFields, j as createAdminUser, k as stopPostgres, l as onboardCreate, m as checkClientConfig, n as isInteractive, p as checkAgentTokens, r as promptAddAgent, s as onboardCheck, t as startServer, v as checkGitHubToken, w as printResults, x as checkServerHealth, y as checkNodeVersion } from "./core-CZjUVAU-.mjs";
2
+ import { a as getGitHubUsername, i as getGitHubToken, o as resolveAgentToken, r as checkBootstrapStatus, s as resolveServerUrl, t as bootstrapToken } from "./bootstrap-CPdLNPme.mjs";
3
3
  import { n as bindFeishuUser, t as bindFeishuBot } from "./feishu-Y4m2zFc3.mjs";
4
4
  export { ClientRuntime, FirstTreeHubSDK, SdkError, bindFeishuBot, bindFeishuUser, blank, bootstrapToken, checkAgentConfigs, checkAgentTokens, checkBootstrapStatus, checkClientConfig, checkContextTreeRepo, checkDatabase, checkDocker, checkGitHubToken, checkNodeVersion, checkServerConfig, checkServerHealth, checkServerReachable, checkWebSocket, createAdminUser, ensurePostgres, formatCheckReport, getGitHubToken, getGitHubUsername, hasAdminUser, isDockerAvailable, isInteractive, onboardCheck, onboardContinue, onboardCreate, printResults, promptAddAgent, promptMissingFields, resolveAgentToken, resolveServerUrl, runMigrations, startServer, status, stopPostgres };