@c4a/server-cli 0.4.9 → 0.4.10-beta.2

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 (3) hide show
  1. package/index.js +191 -129
  2. package/package.json +1 -1
  3. package/serve.js +176394 -0
package/index.js CHANGED
@@ -43013,8 +43013,8 @@ var init_base = __esm(() => {
43013
43013
  var DEFAULT_SERVER_CONFIG;
43014
43014
  var init_serverConfig = __esm(() => {
43015
43015
  DEFAULT_SERVER_CONFIG = {
43016
- api: {
43017
- port: 3000,
43016
+ server: {
43017
+ port: 5100,
43018
43018
  host: "0.0.0.0"
43019
43019
  },
43020
43020
  doc_db: {
@@ -47521,6 +47521,9 @@ var init_c4aError = __esm(() => {
47521
47521
  var init_errorCodes = () => {};
47522
47522
 
47523
47523
  // ../core/src/errors/httpStatus.ts
47524
+ function mapErrorCodeToStatus(code) {
47525
+ return ERROR_CODE_HTTP_STATUS[code] ?? 500;
47526
+ }
47524
47527
  var ERROR_CODE_HTTP_STATUS;
47525
47528
  var init_httpStatus = __esm(() => {
47526
47529
  init_errorCodes();
@@ -47565,6 +47568,16 @@ var init_errors2 = __esm(() => {
47565
47568
  });
47566
47569
 
47567
47570
  // ../core/src/utils/id.ts
47571
+ import { createHash, randomUUID } from "node:crypto";
47572
+ function generateId(type, parentId, name) {
47573
+ const input = `${type}:${parentId}:${name}`;
47574
+ const hash = createHash("sha256").update(input).digest("hex");
47575
+ const hex32 = hash.slice(0, 32);
47576
+ return `${type}_${hex32}`;
47577
+ }
47578
+ function generateUUID() {
47579
+ return randomUUID();
47580
+ }
47568
47581
  var init_id = () => {};
47569
47582
 
47570
47583
  // ../core/src/utils/hash.ts
@@ -185007,7 +185020,7 @@ async function saveServerConfig(config) {
185007
185020
  if (existsSync2(configPath)) {
185008
185021
  const content = await readFile(configPath, "utf-8");
185009
185022
  const doc = import_yaml2.default.parseDocument(content);
185010
- applyObjectAtPath(doc, ["api"], config.api);
185023
+ applyObjectAtPath(doc, ["server"], config.server);
185011
185024
  doc.setIn(["doc_db", "provider"], config.doc_db.provider);
185012
185025
  if (config.doc_db.provider === "sqlite") {
185013
185026
  applyObjectAtPath(doc, ["doc_db", "sqlite"], config.doc_db.sqlite);
@@ -197437,7 +197450,7 @@ var createIdGenerator = ({
197437
197450
  }
197438
197451
  return () => `${prefix}${separator}${generator()}`;
197439
197452
  };
197440
- var generateId = createIdGenerator();
197453
+ var generateId2 = createIdGenerator();
197441
197454
  function getErrorMessage2(error40) {
197442
197455
  if (error40 == null) {
197443
197456
  return "unknown error";
@@ -199915,7 +199928,7 @@ var OpenAIChatLanguageModel = class {
199915
199928
  for (const toolCall of (_a16 = choice.message.tool_calls) != null ? _a16 : []) {
199916
199929
  content.push({
199917
199930
  type: "tool-call",
199918
- toolCallId: (_b16 = toolCall.id) != null ? _b16 : generateId(),
199931
+ toolCallId: (_b16 = toolCall.id) != null ? _b16 : generateId2(),
199919
199932
  toolName: toolCall.function.name,
199920
199933
  input: toolCall.function.arguments
199921
199934
  });
@@ -199924,7 +199937,7 @@ var OpenAIChatLanguageModel = class {
199924
199937
  content.push({
199925
199938
  type: "source",
199926
199939
  sourceType: "url",
199927
- id: generateId(),
199940
+ id: generateId2(),
199928
199941
  url: annotation.url_citation.url,
199929
199942
  title: annotation.url_citation.title
199930
199943
  });
@@ -200105,7 +200118,7 @@ var OpenAIChatLanguageModel = class {
200105
200118
  });
200106
200119
  controller.enqueue({
200107
200120
  type: "tool-call",
200108
- toolCallId: (_j = toolCall2.id) != null ? _j : generateId(),
200121
+ toolCallId: (_j = toolCall2.id) != null ? _j : generateId2(),
200109
200122
  toolName: toolCall2.function.name,
200110
200123
  input: toolCall2.function.arguments
200111
200124
  });
@@ -200133,7 +200146,7 @@ var OpenAIChatLanguageModel = class {
200133
200146
  });
200134
200147
  controller.enqueue({
200135
200148
  type: "tool-call",
200136
- toolCallId: (_q = toolCall.id) != null ? _q : generateId(),
200149
+ toolCallId: (_q = toolCall.id) != null ? _q : generateId2(),
200137
200150
  toolName: toolCall.function.name,
200138
200151
  input: toolCall.function.arguments
200139
200152
  });
@@ -200146,7 +200159,7 @@ var OpenAIChatLanguageModel = class {
200146
200159
  controller.enqueue({
200147
200160
  type: "source",
200148
200161
  sourceType: "url",
200149
- id: generateId(),
200162
+ id: generateId2(),
200150
200163
  url: annotation.url_citation.url,
200151
200164
  title: annotation.url_citation.title
200152
200165
  });
@@ -203095,7 +203108,7 @@ var OpenAIResponsesLanguageModel = class {
203095
203108
  content.push({
203096
203109
  type: "source",
203097
203110
  sourceType: "url",
203098
- id: (_f = (_e = (_d = this.config).generateId) == null ? undefined : _e.call(_d)) != null ? _f : generateId(),
203111
+ id: (_f = (_e = (_d = this.config).generateId) == null ? undefined : _e.call(_d)) != null ? _f : generateId2(),
203099
203112
  url: annotation.url,
203100
203113
  title: annotation.title
203101
203114
  });
@@ -203103,7 +203116,7 @@ var OpenAIResponsesLanguageModel = class {
203103
203116
  content.push({
203104
203117
  type: "source",
203105
203118
  sourceType: "document",
203106
- id: (_i = (_h = (_g = this.config).generateId) == null ? undefined : _h.call(_g)) != null ? _i : generateId(),
203119
+ id: (_i = (_h = (_g = this.config).generateId) == null ? undefined : _h.call(_g)) != null ? _i : generateId2(),
203107
203120
  mediaType: "text/plain",
203108
203121
  title: annotation.filename,
203109
203122
  filename: annotation.filename,
@@ -203119,7 +203132,7 @@ var OpenAIResponsesLanguageModel = class {
203119
203132
  content.push({
203120
203133
  type: "source",
203121
203134
  sourceType: "document",
203122
- id: (_l = (_k = (_j = this.config).generateId) == null ? undefined : _k.call(_j)) != null ? _l : generateId(),
203135
+ id: (_l = (_k = (_j = this.config).generateId) == null ? undefined : _k.call(_j)) != null ? _l : generateId2(),
203123
203136
  mediaType: "text/plain",
203124
203137
  title: annotation.filename,
203125
203138
  filename: annotation.filename,
@@ -203135,7 +203148,7 @@ var OpenAIResponsesLanguageModel = class {
203135
203148
  content.push({
203136
203149
  type: "source",
203137
203150
  sourceType: "document",
203138
- id: (_o = (_n = (_m = this.config).generateId) == null ? undefined : _n.call(_m)) != null ? _o : generateId(),
203151
+ id: (_o = (_n = (_m = this.config).generateId) == null ? undefined : _n.call(_m)) != null ? _o : generateId2(),
203139
203152
  mediaType: "application/octet-stream",
203140
203153
  title: annotation.file_id,
203141
203154
  filename: annotation.file_id,
@@ -203219,7 +203232,7 @@ var OpenAIResponsesLanguageModel = class {
203219
203232
  }
203220
203233
  case "mcp_approval_request": {
203221
203234
  const approvalRequestId = (_q = part.approval_request_id) != null ? _q : part.id;
203222
- const dummyToolCallId = (_t = (_s = (_r = this.config).generateId) == null ? undefined : _s.call(_r)) != null ? _t : generateId();
203235
+ const dummyToolCallId = (_t = (_s = (_r = this.config).generateId) == null ? undefined : _s.call(_r)) != null ? _t : generateId2();
203223
203236
  const toolName = `mcp.${part.name}`;
203224
203237
  content.push({
203225
203238
  type: "tool-call",
@@ -203732,7 +203745,7 @@ var OpenAIResponsesLanguageModel = class {
203732
203745
  ongoingToolCalls[value.output_index] = undefined;
203733
203746
  } else if (value.item.type === "mcp_approval_request") {
203734
203747
  ongoingToolCalls[value.output_index] = undefined;
203735
- const dummyToolCallId = (_k = (_j = (_i = self2.config).generateId) == null ? undefined : _j.call(_i)) != null ? _k : generateId();
203748
+ const dummyToolCallId = (_k = (_j = (_i = self2.config).generateId) == null ? undefined : _j.call(_i)) != null ? _k : generateId2();
203736
203749
  const approvalRequestId = (_l = value.item.approval_request_id) != null ? _l : value.item.id;
203737
203750
  approvalRequestIdToDummyToolCallIdFromStream.set(approvalRequestId, dummyToolCallId);
203738
203751
  const toolName = `mcp.${value.item.name}`;
@@ -203993,7 +204006,7 @@ var OpenAIResponsesLanguageModel = class {
203993
204006
  controller.enqueue({
203994
204007
  type: "source",
203995
204008
  sourceType: "url",
203996
- id: (_w = (_v = (_u = self2.config).generateId) == null ? undefined : _v.call(_u)) != null ? _w : generateId(),
204009
+ id: (_w = (_v = (_u = self2.config).generateId) == null ? undefined : _v.call(_u)) != null ? _w : generateId2(),
203997
204010
  url: value.annotation.url,
203998
204011
  title: value.annotation.title
203999
204012
  });
@@ -204001,7 +204014,7 @@ var OpenAIResponsesLanguageModel = class {
204001
204014
  controller.enqueue({
204002
204015
  type: "source",
204003
204016
  sourceType: "document",
204004
- id: (_z = (_y = (_x = self2.config).generateId) == null ? undefined : _y.call(_x)) != null ? _z : generateId(),
204017
+ id: (_z = (_y = (_x = self2.config).generateId) == null ? undefined : _y.call(_x)) != null ? _z : generateId2(),
204005
204018
  mediaType: "text/plain",
204006
204019
  title: value.annotation.filename,
204007
204020
  filename: value.annotation.filename,
@@ -204017,7 +204030,7 @@ var OpenAIResponsesLanguageModel = class {
204017
204030
  controller.enqueue({
204018
204031
  type: "source",
204019
204032
  sourceType: "document",
204020
- id: (_C = (_B = (_A = self2.config).generateId) == null ? undefined : _B.call(_A)) != null ? _C : generateId(),
204033
+ id: (_C = (_B = (_A = self2.config).generateId) == null ? undefined : _B.call(_A)) != null ? _C : generateId2(),
204021
204034
  mediaType: "text/plain",
204022
204035
  title: value.annotation.filename,
204023
204036
  filename: value.annotation.filename,
@@ -204033,7 +204046,7 @@ var OpenAIResponsesLanguageModel = class {
204033
204046
  controller.enqueue({
204034
204047
  type: "source",
204035
204048
  sourceType: "document",
204036
- id: (_F = (_E = (_D = self2.config).generateId) == null ? undefined : _E.call(_D)) != null ? _F : generateId(),
204049
+ id: (_F = (_E = (_D = self2.config).generateId) == null ? undefined : _E.call(_D)) != null ? _F : generateId2(),
204037
204050
  mediaType: "application/octet-stream",
204038
204051
  title: value.annotation.file_id,
204039
204052
  filename: value.annotation.file_id,
@@ -208769,7 +208782,7 @@ var GoogleGenerativeAILanguageModel = class {
208769
208782
  var _a21;
208770
208783
  this.modelId = modelId;
208771
208784
  this.config = config2;
208772
- this.generateId = (_a21 = config2.generateId) != null ? _a21 : generateId;
208785
+ this.generateId = (_a21 = config2.generateId) != null ? _a21 : generateId2;
208773
208786
  }
208774
208787
  get provider() {
208775
208788
  return this.config.provider;
@@ -209661,7 +209674,7 @@ var GoogleGenerativeAIImageModel = class {
209661
209674
  baseURL: this.config.baseURL,
209662
209675
  headers: (_a21 = this.config.headers) != null ? _a21 : {},
209663
209676
  fetch: this.config.fetch,
209664
- generateId: (_b16 = this.config.generateId) != null ? _b16 : generateId
209677
+ generateId: (_b16 = this.config.generateId) != null ? _b16 : generateId2
209665
209678
  });
209666
209679
  const result = await languageModel.doGenerate({
209667
209680
  prompt: languageModelPrompt,
@@ -209963,7 +209976,7 @@ function createGoogleGenerativeAI(options = {}) {
209963
209976
  provider: providerName,
209964
209977
  baseURL,
209965
209978
  headers: getHeaders,
209966
- generateId: (_a24 = options.generateId) != null ? _a24 : generateId,
209979
+ generateId: (_a24 = options.generateId) != null ? _a24 : generateId2,
209967
209980
  supportedUrls: () => ({
209968
209981
  "*": [
209969
209982
  new RegExp(`^${baseURL}/files/.*$`),
@@ -209993,7 +210006,7 @@ function createGoogleGenerativeAI(options = {}) {
209993
210006
  baseURL,
209994
210007
  headers: getHeaders,
209995
210008
  fetch: options.fetch,
209996
- generateId: (_a24 = options.generateId) != null ? _a24 : generateId
210009
+ generateId: (_a24 = options.generateId) != null ? _a24 : generateId2
209997
210010
  });
209998
210011
  };
209999
210012
  const provider = function(modelId) {
@@ -211802,7 +211815,7 @@ async function runLogsCommand(options = {}) {
211802
211815
  // src/ops/statusCommand.ts
211803
211816
  import { existsSync as existsSync7 } from "node:fs";
211804
211817
 
211805
- // src/ops/apiProcess.ts
211818
+ // src/ops/serverProcess.ts
211806
211819
  import { execSync, spawn as spawnChild } from "node:child_process";
211807
211820
  import { closeSync, existsSync as existsSync6, openSync } from "node:fs";
211808
211821
  import { mkdir as mkdir3, readFile as readFile2, rm, writeFile as writeFile3 } from "node:fs/promises";
@@ -211816,39 +211829,71 @@ var DEFAULT_DEPS = {
211816
211829
  sleep: (ms) => new Promise((resolve2) => setTimeout(resolve2, ms)),
211817
211830
  now: () => Date.now()
211818
211831
  };
211819
- var API_PID_NAME = "api.pid";
211820
- var API_LOG_NAME = "api.log";
211821
- var API_LOG_DIR = path13.join("data", "logs");
211822
- function resolveApiServeEntry() {
211832
+ var SERVER_PID_NAME = "server.pid";
211833
+ var SERVER_LOG_DIR = "logs";
211834
+ function makeServerLogName() {
211835
+ const now = new Date;
211836
+ const ts = [
211837
+ now.getFullYear(),
211838
+ String(now.getMonth() + 1).padStart(2, "0"),
211839
+ String(now.getDate()).padStart(2, "0"),
211840
+ ".",
211841
+ String(now.getHours()).padStart(2, "0"),
211842
+ String(now.getMinutes()).padStart(2, "0"),
211843
+ String(now.getSeconds()).padStart(2, "0")
211844
+ ].join("");
211845
+ return `server.${ts}.log`;
211846
+ }
211847
+ var cachedRuntime = null;
211848
+ function resolveRuntime() {
211849
+ if (cachedRuntime)
211850
+ return cachedRuntime;
211851
+ try {
211852
+ execSync("bun --version", { stdio: "ignore", timeout: 3000 });
211853
+ cachedRuntime = "bun";
211854
+ } catch {
211855
+ cachedRuntime = "node";
211856
+ }
211857
+ return cachedRuntime;
211858
+ }
211859
+ function resolveServeEntry(runtime) {
211823
211860
  const currentDir = path13.dirname(fileURLToPath(import.meta.url));
211824
211861
  const candidates = [
211825
- path13.resolve(currentDir, "..", "..", "..", "api", "src", "serve.ts"),
211826
- path13.resolve(currentDir, "..", "..", "api", "src", "serve.ts"),
211827
- path13.resolve(currentDir, "..", "..", "api", "dist", "serve.js"),
211828
- path13.resolve(currentDir, "..", "..", "..", "api", "dist", "serve.js")
211862
+ path13.resolve(currentDir, "serve.js"),
211863
+ path13.resolve(currentDir, "..", "..", "server", "dist", "serve.js"),
211864
+ path13.resolve(currentDir, "..", "..", "..", "server", "dist", "serve.js")
211829
211865
  ];
211866
+ if (runtime === "bun") {
211867
+ candidates.push(path13.resolve(currentDir, "..", "..", "..", "server", "src", "serve.ts"));
211868
+ candidates.push(path13.resolve(currentDir, "..", "..", "server", "src", "serve.ts"));
211869
+ }
211830
211870
  for (const candidate of candidates) {
211831
211871
  if (existsSync6(candidate))
211832
211872
  return candidate;
211833
211873
  }
211834
211874
  return candidates[0];
211835
211875
  }
211836
- function resolveApiPidPath() {
211837
- return path13.resolve(process.cwd(), "data", API_PID_NAME);
211876
+ function resolvePidPath() {
211877
+ return path13.resolve(process.cwd(), "data", SERVER_PID_NAME);
211838
211878
  }
211839
- function resolveApiLogPath() {
211840
- return path13.resolve(process.cwd(), API_LOG_DIR, API_LOG_NAME);
211879
+ function resolveServerLogPath() {
211880
+ return path13.resolve(process.cwd(), SERVER_LOG_DIR, makeServerLogName());
211841
211881
  }
211842
- function resolveApiHealthUrl(config2) {
211843
- const host = config2.api.host === "0.0.0.0" ? "127.0.0.1" : config2.api.host;
211844
- const url2 = `http://${host}:${config2.api.port}/api/v1/health`;
211845
- return { url: url2, host };
211882
+ function resolveHealthUrl(config2) {
211883
+ let host = config2.server.host;
211884
+ if (host === "0.0.0.0")
211885
+ host = "127.0.0.1";
211886
+ else if (host === "::")
211887
+ host = "::1";
211888
+ const urlHost = host.includes(":") ? `[${host}]` : host;
211889
+ const url2 = `http://${urlHost}:${config2.server.port}/api/v1/health`;
211890
+ return { url: url2, host: urlHost, tcpHost: host };
211846
211891
  }
211847
- async function ensureApiDirs() {
211848
- await mkdir3(path13.resolve(process.cwd(), API_LOG_DIR), { recursive: true });
211892
+ async function ensureLogDirs() {
211893
+ await mkdir3(path13.resolve(process.cwd(), SERVER_LOG_DIR), { recursive: true });
211849
211894
  }
211850
- async function readApiPidFile() {
211851
- const pidPath = resolveApiPidPath();
211895
+ async function readPidFile() {
211896
+ const pidPath = resolvePidPath();
211852
211897
  if (!existsSync6(pidPath))
211853
211898
  return null;
211854
211899
  const content = await readFile2(pidPath, "utf-8");
@@ -211859,13 +211904,13 @@ async function readApiPidFile() {
211859
211904
  }
211860
211905
  return pid;
211861
211906
  }
211862
- async function writeApiPidFile(pid) {
211863
- const pidPath = resolveApiPidPath();
211907
+ async function writePidFile(pid) {
211908
+ const pidPath = resolvePidPath();
211864
211909
  await mkdir3(path13.dirname(pidPath), { recursive: true });
211865
211910
  await writeFile3(pidPath, String(pid));
211866
211911
  }
211867
- async function removeApiPidFile() {
211868
- await rm(resolveApiPidPath(), { force: true });
211912
+ async function removePidFile() {
211913
+ await rm(resolvePidPath(), { force: true });
211869
211914
  }
211870
211915
  function isProcessAlive(pid, deps) {
211871
211916
  try {
@@ -211898,11 +211943,14 @@ function findPidByPort(port) {
211898
211943
  return null;
211899
211944
  }
211900
211945
  }
211901
- async function waitForHealth(config2, deps, attempts = 10, intervalMs = 500) {
211902
- const { url: url2 } = resolveApiHealthUrl(config2);
211946
+ async function waitForHealth(config2, deps, options = {}) {
211947
+ const attempts = options.attempts ?? 10;
211948
+ const intervalMs = options.intervalMs ?? 1000;
211949
+ const { url: url2 } = resolveHealthUrl(config2);
211903
211950
  for (let i = 0;i < attempts; i++) {
211951
+ options.onAttempt?.(i + 1, attempts);
211904
211952
  const started = deps.now();
211905
- const timeoutMs = intervalMs > 0 ? Math.min(200, intervalMs) : 500;
211953
+ const timeoutMs = intervalMs > 0 ? Math.min(500, intervalMs) : 500;
211906
211954
  const result = await deps.checkHttp(url2, undefined, timeoutMs);
211907
211955
  if (result.ok && result.status === 200) {
211908
211956
  return true;
@@ -211915,69 +211963,84 @@ async function waitForHealth(config2, deps, attempts = 10, intervalMs = 500) {
211915
211963
  }
211916
211964
  return false;
211917
211965
  }
211918
- async function startApiProcess(config2, deps = {}) {
211966
+ async function startServerProcess(config2, deps = {}) {
211919
211967
  const activeDeps = { ...DEFAULT_DEPS, ...deps };
211920
- const existingPid = await readApiPidFile();
211968
+ const existingPid = await readPidFile();
211921
211969
  if (existingPid && isProcessAlive(existingPid, activeDeps)) {
211922
- return { pid: existingPid, port: config2.api.port, host: config2.api.host, running: true };
211970
+ return { pid: existingPid, port: config2.server.port, host: config2.server.host, running: true };
211923
211971
  }
211924
211972
  if (existingPid) {
211925
- await removeApiPidFile();
211973
+ await removePidFile();
211926
211974
  }
211927
- const { host: healthHost } = resolveApiHealthUrl(config2);
211928
- const preCheck = await activeDeps.checkHttp(`http://${healthHost}:${config2.api.port}/api/v1/health`, undefined, 500);
211975
+ const { host: healthHost, tcpHost } = resolveHealthUrl(config2);
211976
+ const preCheck = await activeDeps.checkHttp(`http://${healthHost}:${config2.server.port}/api/v1/health`, undefined, 500);
211929
211977
  if (preCheck.ok && preCheck.status === 200) {
211930
- const orphanPid = findPidByPort(config2.api.port);
211978
+ const orphanPid = findPidByPort(config2.server.port);
211931
211979
  if (orphanPid) {
211932
- await writeApiPidFile(orphanPid);
211933
- return { pid: orphanPid, port: config2.api.port, host: config2.api.host, running: true };
211980
+ await writePidFile(orphanPid);
211981
+ return { pid: orphanPid, port: config2.server.port, host: config2.server.host, running: true };
211934
211982
  }
211935
211983
  }
211936
- await ensureApiDirs();
211937
- const logPath = resolveApiLogPath();
211938
- const logFd = openSync(logPath, "a");
211939
- const serveEntry = resolveApiServeEntry();
211940
- const child = activeDeps.spawn("bun", [serveEntry], {
211984
+ const tcpCheck = await activeDeps.checkTcp(tcpHost, config2.server.port, 500);
211985
+ if (tcpCheck.ok) {
211986
+ throw new Error(`端口已被占用: ${config2.server.host}:${config2.server.port}`);
211987
+ }
211988
+ await ensureLogDirs();
211989
+ const logPath = resolveServerLogPath();
211990
+ const logFd = openSync(logPath, "w");
211991
+ const runtime = resolveRuntime();
211992
+ const serveEntry = resolveServeEntry(runtime);
211993
+ const child = activeDeps.spawn(runtime, [serveEntry], {
211941
211994
  detached: true,
211942
211995
  cwd: process.cwd(),
211943
211996
  stdio: ["ignore", logFd, logFd]
211944
211997
  });
211998
+ const spawnError = await new Promise((resolve2) => {
211999
+ child.once("error", (err) => resolve2(err));
212000
+ setImmediate(() => resolve2(null));
212001
+ });
211945
212002
  closeSync(logFd);
212003
+ if (spawnError) {
212004
+ throw new Error(`Server 启动失败:无法执行 ${runtime}(${spawnError.message})`);
212005
+ }
211946
212006
  if (!child.pid) {
211947
- throw new Error("API 服务启动失败:未获取到 PID");
212007
+ throw new Error("Server 启动失败:未获取到 PID");
211948
212008
  }
211949
212009
  child.unref();
211950
- await writeApiPidFile(child.pid);
211951
- const healthy = await waitForHealth(config2, activeDeps);
211952
- if (!healthy) {
211953
- const port = config2.api.port;
211954
- const tcp = await activeDeps.checkTcp(healthHost, port, 1000);
211955
- if (tcp.ok) {
211956
- throw new Error(`端口已被占用: ${config2.api.host}:${port}`);
212010
+ await writePidFile(child.pid);
212011
+ const healthy = await waitForHealth(config2, activeDeps, {
212012
+ attempts: 10,
212013
+ intervalMs: 1000,
212014
+ onAttempt: (attempt, total) => {
212015
+ process.stdout.write(`\r等待 Server 就绪... (${attempt}/${total})`);
211957
212016
  }
211958
- throw new Error(`API 服务启动失败(健康检查未通过)`);
212017
+ });
212018
+ process.stdout.write("\r" + " ".repeat(40) + "\r");
212019
+ if (!healthy) {
212020
+ throw new Error(`Server 启动失败(健康检查未通过,已等待 10s)
212021
+ 日志: ${logPath}`);
211959
212022
  }
211960
- return { pid: child.pid, port: config2.api.port, host: config2.api.host, running: true };
212023
+ return { pid: child.pid, port: config2.server.port, host: config2.server.host, running: true };
211961
212024
  }
211962
- async function stopApiProcess(config2, deps = {}) {
212025
+ async function stopServerProcess(config2, deps = {}) {
211963
212026
  const activeDeps = { ...DEFAULT_DEPS, ...deps };
211964
- let pid = await readApiPidFile();
212027
+ let pid = await readPidFile();
211965
212028
  if (!pid && config2) {
211966
- pid = findPidByPort(config2.api.port);
212029
+ pid = findPidByPort(config2.server.port);
211967
212030
  if (pid) {
211968
- await writeApiPidFile(pid);
212031
+ await writePidFile(pid);
211969
212032
  }
211970
212033
  }
211971
212034
  if (!pid)
211972
212035
  return;
211973
212036
  if (!isProcessAlive(pid, activeDeps)) {
211974
- await removeApiPidFile();
212037
+ await removePidFile();
211975
212038
  return;
211976
212039
  }
211977
212040
  try {
211978
212041
  activeDeps.kill(pid, "SIGTERM");
211979
212042
  } catch {
211980
- await removeApiPidFile();
212043
+ await removePidFile();
211981
212044
  return;
211982
212045
  }
211983
212046
  const start = activeDeps.now();
@@ -211991,25 +212054,25 @@ async function stopApiProcess(config2, deps = {}) {
211991
212054
  activeDeps.kill(pid, "SIGKILL");
211992
212055
  } catch {}
211993
212056
  }
211994
- await removeApiPidFile();
212057
+ await removePidFile();
211995
212058
  }
211996
- async function getApiProcessInfo(config2, deps = {}) {
212059
+ async function getServerProcessInfo(config2, deps = {}) {
211997
212060
  const activeDeps = { ...DEFAULT_DEPS, ...deps };
211998
- let pid = await readApiPidFile();
212061
+ let pid = await readPidFile();
211999
212062
  if (!pid) {
212000
- pid = findPidByPort(config2.api.port);
212063
+ pid = findPidByPort(config2.server.port);
212001
212064
  if (pid) {
212002
- await writeApiPidFile(pid);
212065
+ await writePidFile(pid);
212003
212066
  }
212004
212067
  }
212005
212068
  if (!pid)
212006
212069
  return null;
212007
212070
  if (!isProcessAlive(pid, activeDeps)) {
212008
- await removeApiPidFile();
212071
+ await removePidFile();
212009
212072
  return null;
212010
212073
  }
212011
- const healthy = await waitForHealth(config2, activeDeps, 1, 0);
212012
- return { pid, port: config2.api.port, host: config2.api.host, running: healthy };
212074
+ const healthy = await waitForHealth(config2, activeDeps, { attempts: 1, intervalMs: 0 });
212075
+ return { pid, port: config2.server.port, host: config2.server.host, running: healthy };
212013
212076
  }
212014
212077
 
212015
212078
  // src/ops/statusCommand.ts
@@ -212142,9 +212205,9 @@ async function runStatusCommand(options = {}) {
212142
212205
  }
212143
212206
  }
212144
212207
  printLine(`Embedding (${config2.embedding.provider})`, embeddingResult.ready, embeddingDetail);
212145
- const apiInfo = await getApiProcessInfo(config2);
212146
- const apiStatus = getApiStatusLine(apiInfo);
212147
- printLine("API 服务", apiStatus.ok, apiStatus.detail);
212208
+ const apiInfo = await getServerProcessInfo(config2);
212209
+ const apiStatus = getServerStatusLine(apiInfo);
212210
+ printLine("C4A Server", apiStatus.ok, apiStatus.detail);
212148
212211
  if (staleContainers.length > 0) {
212149
212212
  const names = staleContainers.map((c) => c.name).join(", ");
212150
212213
  console.log(` ${"提示".padEnd(20, " ")} 发现旧配置容器仍在运行:${names}`);
@@ -212196,7 +212259,7 @@ function printLine(label, ok, detail) {
212196
212259
  const status = ok ? `${GREEN5}运行中${RESET5}` : `${RED2}未就绪${RESET5}`;
212197
212260
  console.log(` ${label.padEnd(20, " ")} ${status} ${detail}`);
212198
212261
  }
212199
- function getApiStatusLine(info) {
212262
+ function getServerStatusLine(info) {
212200
212263
  if (!info) {
212201
212264
  return { ok: false, detail: "未启动" };
212202
212265
  }
@@ -212283,24 +212346,23 @@ async function ensureNebulaInit(composePath, startedServices, projectName) {
212283
212346
  }
212284
212347
  return true;
212285
212348
  }
212286
- async function ensureApiStarted(config2) {
212287
- const existingApi = await getApiProcessInfo(config2);
212288
- if (existingApi && existingApi.running) {
212289
- console.log(`API 服务已在运行 (PID: ${existingApi.pid})`);
212349
+ async function ensureServerStarted(config2) {
212350
+ const existing = await getServerProcessInfo(config2);
212351
+ if (existing && existing.running) {
212352
+ console.log(`Server 已在运行 (PID: ${existing.pid})`);
212290
212353
  return true;
212291
212354
  }
212292
- if (existingApi && !existingApi.running) {
212293
- console.log(`API 进程存在但服务无响应 (PID: ${existingApi.pid}),尝试重启...`);
212294
- await stopApiProcess(config2);
212355
+ if (existing && !existing.running) {
212356
+ console.log(`Server 进程存在但服务无响应 (PID: ${existing.pid}),尝试重启...`);
212357
+ await stopServerProcess(config2);
212295
212358
  }
212296
212359
  try {
212297
- const started = await startApiProcess(config2);
212298
- console.log(`API 服务已启动 (PID: ${started.pid}, http://${started.host}:${started.port})`);
212360
+ const started = await startServerProcess(config2);
212361
+ console.log(`Server 已启动 (PID: ${started.pid}, http://${started.host}:${started.port})`);
212299
212362
  return true;
212300
212363
  } catch (error40) {
212301
212364
  const message = error40 instanceof Error ? error40.message : String(error40);
212302
- console.log(`API 服务启动失败: ${message}`);
212303
- console.log(`错误日志: ${resolveApiLogPath()}`);
212365
+ console.log(`Server 启动失败: ${message}`);
212304
212366
  return false;
212305
212367
  }
212306
212368
  }
@@ -212321,13 +212383,13 @@ async function runStartCommand(options = {}) {
212321
212383
  console.log(`当前配置没有需要启动的 Docker 服务。
212322
212384
  `);
212323
212385
  }
212324
- const apiOk = await ensureApiStarted(config2);
212386
+ const apiOk = await ensureServerStarted(config2);
212325
212387
  if (!apiOk)
212326
212388
  return;
212327
212389
  } else {
212328
212390
  const optionsList = [
212329
212391
  { label: "全部启动", value: "__all__" },
212330
- { label: "API 服务", value: "__api__" },
212392
+ { label: "C4A Server", value: "__api__" },
212331
212393
  ...services.map((svc) => ({ label: svc.serviceName, value: svc.serviceName }))
212332
212394
  ];
212333
212395
  const choice2 = await askChoice("选择要启动的服务", optionsList, "__all__");
@@ -212353,13 +212415,13 @@ async function runStartCommand(options = {}) {
212353
212415
  console.log(`当前配置没有需要启动的 Docker 服务。
212354
212416
  `);
212355
212417
  }
212356
- const apiOk = await ensureApiStarted(config2);
212418
+ const apiOk = await ensureServerStarted(config2);
212357
212419
  if (!apiOk) {
212358
212420
  await pauseBeforeReturn();
212359
212421
  return;
212360
212422
  }
212361
212423
  } else if (choice2 === "__api__") {
212362
- const apiOk = await ensureApiStarted(config2);
212424
+ const apiOk = await ensureServerStarted(config2);
212363
212425
  if (!apiOk) {
212364
212426
  await pauseBeforeReturn();
212365
212427
  return;
@@ -212390,7 +212452,7 @@ async function runStopCommand(options = {}) {
212390
212452
  const config2 = await loadServerConfig();
212391
212453
  const { composePath, services, projectName } = await getDockerServices(config2);
212392
212454
  const serviceMap = new Map(services.map((svc) => [svc.serviceName, svc.containerName]));
212393
- const apiInfo = await getApiProcessInfo(config2);
212455
+ const apiInfo = await getServerProcessInfo(config2);
212394
212456
  const apiAvailable = apiInfo !== null;
212395
212457
  if (services.length === 0) {
212396
212458
  console.log(`当前配置没有需要停止的 Docker 服务。
@@ -212413,11 +212475,11 @@ async function runStopCommand(options = {}) {
212413
212475
  let stopApi = false;
212414
212476
  if (mode === "cli") {
212415
212477
  targetServices = runningServices;
212416
- stopApi = apiAvailable;
212478
+ stopApi = true;
212417
212479
  } else {
212418
212480
  const optionsList = [
212419
212481
  { label: "全部停止", value: "__all__" },
212420
- ...apiAvailable ? [{ label: "API 服务", value: "__api__" }] : [],
212482
+ { label: "C4A Server", value: "__api__" },
212421
212483
  ...runningServices.map((name21) => ({ label: name21, value: name21 }))
212422
212484
  ];
212423
212485
  const choice2 = await askChoice("选择要停止的服务", optionsList, "__all__");
@@ -212428,7 +212490,7 @@ async function runStopCommand(options = {}) {
212428
212490
  }
212429
212491
  if (choice2 === "__all__") {
212430
212492
  targetServices = runningServices;
212431
- stopApi = apiAvailable;
212493
+ stopApi = true;
212432
212494
  } else if (choice2 === "__api__") {
212433
212495
  targetServices = [];
212434
212496
  stopApi = true;
@@ -212438,7 +212500,7 @@ async function runStopCommand(options = {}) {
212438
212500
  }
212439
212501
  const dockerTargets = targetServices;
212440
212502
  if (stopApi) {
212441
- await stopApiProcess(config2);
212503
+ await stopServerProcess(config2);
212442
212504
  }
212443
212505
  if (dockerTargets.length > 0) {
212444
212506
  console.log(`
@@ -214363,19 +214425,19 @@ async function runBackupCommand(options) {
214363
214425
  }
214364
214426
  }
214365
214427
 
214366
- // src/ops/restartApi.ts
214367
- async function restartApiIfRunning(config2, log) {
214368
- const info = await getApiProcessInfo(config2);
214428
+ // src/ops/restartServer.ts
214429
+ async function restartServerIfRunning(config2, log) {
214430
+ const info = await getServerProcessInfo(config2);
214369
214431
  if (!info)
214370
214432
  return;
214371
- log("正在重启 API 服务以刷新数据...");
214372
- await stopApiProcess(config2);
214433
+ log("正在重启 Server 以刷新数据...");
214434
+ await stopServerProcess(config2);
214373
214435
  try {
214374
- const started = await startApiProcess(config2);
214375
- log(`API 服务已重启 (PID: ${started.pid})`);
214436
+ const started = await startServerProcess(config2);
214437
+ log(`Server 已重启 (PID: ${started.pid})`);
214376
214438
  } catch (error40) {
214377
214439
  const message = error40 instanceof Error ? error40.message : String(error40);
214378
- log(`API 服务重启失败: ${message}`);
214440
+ log(`Server 重启失败: ${message}`);
214379
214441
  }
214380
214442
  }
214381
214443
 
@@ -214438,7 +214500,7 @@ async function runPurgeCommand(options) {
214438
214500
  await facade.close();
214439
214501
  }
214440
214502
  if (result) {
214441
- await restartApiIfRunning(config2, console.log);
214503
+ await restartServerIfRunning(config2, console.log);
214442
214504
  }
214443
214505
  if (mode === "interactive") {
214444
214506
  await pauseBeforeReturn();
@@ -214448,13 +214510,13 @@ async function runPurgeCommand(options) {
214448
214510
  // src/data/restore.ts
214449
214511
  import path16 from "node:path";
214450
214512
  async function triggerVectorRebuild(config2, log) {
214451
- const info = await getApiProcessInfo(config2);
214513
+ const info = await getServerProcessInfo(config2);
214452
214514
  if (!info) {
214453
- log("⚠️ API 服务未运行,向量索引未重建。启动 API 后可调用 POST /api/v1/vectors/rebuild 手动重建。");
214515
+ log("⚠️ Server 未运行,向量索引未重建。启动后可调用 POST /api/v1/vectors/rebuild 手动重建。");
214454
214516
  return;
214455
214517
  }
214456
- const port = config2.api.port;
214457
- const host = config2.api.host === "0.0.0.0" ? "127.0.0.1" : config2.api.host;
214518
+ const port = config2.server.port;
214519
+ const host = config2.server.host === "0.0.0.0" ? "127.0.0.1" : config2.server.host;
214458
214520
  const url2 = `http://${host}:${port}/api/v1/vectors/rebuild`;
214459
214521
  log("正在通过 API 重建向量索引...");
214460
214522
  try {
@@ -214605,7 +214667,7 @@ async function runRestoreCommand(options) {
214605
214667
  await facade.close();
214606
214668
  }
214607
214669
  if (result) {
214608
- await restartApiIfRunning(config2, console.log);
214670
+ await restartServerIfRunning(config2, console.log);
214609
214671
  await triggerVectorRebuild(config2, console.log);
214610
214672
  }
214611
214673
  if (mode === "interactive") {
@@ -215152,8 +215214,8 @@ var SERVER_CONFIG_NAME = "server.yaml";
215152
215214
  var DEFAULT_SERVER_YAML = `# C4A Server Configuration
215153
215215
  # 由 c4a-server 服务设置菜单生成和管理
215154
215216
 
215155
- api:
215156
- port: 3000
215217
+ server:
215218
+ port: 5100
215157
215219
  host: 0.0.0.0
215158
215220
 
215159
215221
  doc_db: