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

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 +185 -128
  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,66 @@ 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`;
211882
+ function resolveHealthUrl(config2) {
211883
+ const host = config2.server.host === "0.0.0.0" ? "127.0.0.1" : config2.server.host;
211884
+ const url2 = `http://${host}:${config2.server.port}/api/v1/health`;
211845
211885
  return { url: url2, host };
211846
211886
  }
211847
- async function ensureApiDirs() {
211848
- await mkdir3(path13.resolve(process.cwd(), API_LOG_DIR), { recursive: true });
211887
+ async function ensureLogDirs() {
211888
+ await mkdir3(path13.resolve(process.cwd(), SERVER_LOG_DIR), { recursive: true });
211849
211889
  }
211850
- async function readApiPidFile() {
211851
- const pidPath = resolveApiPidPath();
211890
+ async function readPidFile() {
211891
+ const pidPath = resolvePidPath();
211852
211892
  if (!existsSync6(pidPath))
211853
211893
  return null;
211854
211894
  const content = await readFile2(pidPath, "utf-8");
@@ -211859,13 +211899,13 @@ async function readApiPidFile() {
211859
211899
  }
211860
211900
  return pid;
211861
211901
  }
211862
- async function writeApiPidFile(pid) {
211863
- const pidPath = resolveApiPidPath();
211902
+ async function writePidFile(pid) {
211903
+ const pidPath = resolvePidPath();
211864
211904
  await mkdir3(path13.dirname(pidPath), { recursive: true });
211865
211905
  await writeFile3(pidPath, String(pid));
211866
211906
  }
211867
- async function removeApiPidFile() {
211868
- await rm(resolveApiPidPath(), { force: true });
211907
+ async function removePidFile() {
211908
+ await rm(resolvePidPath(), { force: true });
211869
211909
  }
211870
211910
  function isProcessAlive(pid, deps) {
211871
211911
  try {
@@ -211898,11 +211938,14 @@ function findPidByPort(port) {
211898
211938
  return null;
211899
211939
  }
211900
211940
  }
211901
- async function waitForHealth(config2, deps, attempts = 10, intervalMs = 500) {
211902
- const { url: url2 } = resolveApiHealthUrl(config2);
211941
+ async function waitForHealth(config2, deps, options = {}) {
211942
+ const attempts = options.attempts ?? 10;
211943
+ const intervalMs = options.intervalMs ?? 1000;
211944
+ const { url: url2 } = resolveHealthUrl(config2);
211903
211945
  for (let i = 0;i < attempts; i++) {
211946
+ options.onAttempt?.(i + 1, attempts);
211904
211947
  const started = deps.now();
211905
- const timeoutMs = intervalMs > 0 ? Math.min(200, intervalMs) : 500;
211948
+ const timeoutMs = intervalMs > 0 ? Math.min(500, intervalMs) : 500;
211906
211949
  const result = await deps.checkHttp(url2, undefined, timeoutMs);
211907
211950
  if (result.ok && result.status === 200) {
211908
211951
  return true;
@@ -211915,69 +211958,84 @@ async function waitForHealth(config2, deps, attempts = 10, intervalMs = 500) {
211915
211958
  }
211916
211959
  return false;
211917
211960
  }
211918
- async function startApiProcess(config2, deps = {}) {
211961
+ async function startServerProcess(config2, deps = {}) {
211919
211962
  const activeDeps = { ...DEFAULT_DEPS, ...deps };
211920
- const existingPid = await readApiPidFile();
211963
+ const existingPid = await readPidFile();
211921
211964
  if (existingPid && isProcessAlive(existingPid, activeDeps)) {
211922
- return { pid: existingPid, port: config2.api.port, host: config2.api.host, running: true };
211965
+ return { pid: existingPid, port: config2.server.port, host: config2.server.host, running: true };
211923
211966
  }
211924
211967
  if (existingPid) {
211925
- await removeApiPidFile();
211968
+ await removePidFile();
211926
211969
  }
211927
- const { host: healthHost } = resolveApiHealthUrl(config2);
211928
- const preCheck = await activeDeps.checkHttp(`http://${healthHost}:${config2.api.port}/api/v1/health`, undefined, 500);
211970
+ const { host: healthHost } = resolveHealthUrl(config2);
211971
+ const preCheck = await activeDeps.checkHttp(`http://${healthHost}:${config2.server.port}/api/v1/health`, undefined, 500);
211929
211972
  if (preCheck.ok && preCheck.status === 200) {
211930
- const orphanPid = findPidByPort(config2.api.port);
211973
+ const orphanPid = findPidByPort(config2.server.port);
211931
211974
  if (orphanPid) {
211932
- await writeApiPidFile(orphanPid);
211933
- return { pid: orphanPid, port: config2.api.port, host: config2.api.host, running: true };
211975
+ await writePidFile(orphanPid);
211976
+ return { pid: orphanPid, port: config2.server.port, host: config2.server.host, running: true };
211934
211977
  }
211935
211978
  }
211936
- await ensureApiDirs();
211937
- const logPath = resolveApiLogPath();
211938
- const logFd = openSync(logPath, "a");
211939
- const serveEntry = resolveApiServeEntry();
211940
- const child = activeDeps.spawn("bun", [serveEntry], {
211979
+ const tcpCheck = await activeDeps.checkTcp(healthHost, config2.server.port, 500);
211980
+ if (tcpCheck.ok) {
211981
+ throw new Error(`端口已被占用: ${config2.server.host}:${config2.server.port}`);
211982
+ }
211983
+ await ensureLogDirs();
211984
+ const logPath = resolveServerLogPath();
211985
+ const logFd = openSync(logPath, "w");
211986
+ const runtime = resolveRuntime();
211987
+ const serveEntry = resolveServeEntry(runtime);
211988
+ const child = activeDeps.spawn(runtime, [serveEntry], {
211941
211989
  detached: true,
211942
211990
  cwd: process.cwd(),
211943
211991
  stdio: ["ignore", logFd, logFd]
211944
211992
  });
211993
+ const spawnError = await new Promise((resolve2) => {
211994
+ child.once("error", (err) => resolve2(err));
211995
+ setImmediate(() => resolve2(null));
211996
+ });
211945
211997
  closeSync(logFd);
211998
+ if (spawnError) {
211999
+ throw new Error(`Server 启动失败:无法执行 ${runtime}(${spawnError.message})`);
212000
+ }
211946
212001
  if (!child.pid) {
211947
- throw new Error("API 服务启动失败:未获取到 PID");
212002
+ throw new Error("Server 启动失败:未获取到 PID");
211948
212003
  }
211949
212004
  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}`);
212005
+ await writePidFile(child.pid);
212006
+ const healthy = await waitForHealth(config2, activeDeps, {
212007
+ attempts: 10,
212008
+ intervalMs: 1000,
212009
+ onAttempt: (attempt, total) => {
212010
+ process.stdout.write(`\r等待 Server 就绪... (${attempt}/${total})`);
211957
212011
  }
211958
- throw new Error(`API 服务启动失败(健康检查未通过)`);
212012
+ });
212013
+ process.stdout.write("\r" + " ".repeat(40) + "\r");
212014
+ if (!healthy) {
212015
+ throw new Error(`Server 启动失败(健康检查未通过,已等待 10s)
212016
+ 日志: ${logPath}`);
211959
212017
  }
211960
- return { pid: child.pid, port: config2.api.port, host: config2.api.host, running: true };
212018
+ return { pid: child.pid, port: config2.server.port, host: config2.server.host, running: true };
211961
212019
  }
211962
- async function stopApiProcess(config2, deps = {}) {
212020
+ async function stopServerProcess(config2, deps = {}) {
211963
212021
  const activeDeps = { ...DEFAULT_DEPS, ...deps };
211964
- let pid = await readApiPidFile();
212022
+ let pid = await readPidFile();
211965
212023
  if (!pid && config2) {
211966
- pid = findPidByPort(config2.api.port);
212024
+ pid = findPidByPort(config2.server.port);
211967
212025
  if (pid) {
211968
- await writeApiPidFile(pid);
212026
+ await writePidFile(pid);
211969
212027
  }
211970
212028
  }
211971
212029
  if (!pid)
211972
212030
  return;
211973
212031
  if (!isProcessAlive(pid, activeDeps)) {
211974
- await removeApiPidFile();
212032
+ await removePidFile();
211975
212033
  return;
211976
212034
  }
211977
212035
  try {
211978
212036
  activeDeps.kill(pid, "SIGTERM");
211979
212037
  } catch {
211980
- await removeApiPidFile();
212038
+ await removePidFile();
211981
212039
  return;
211982
212040
  }
211983
212041
  const start = activeDeps.now();
@@ -211991,25 +212049,25 @@ async function stopApiProcess(config2, deps = {}) {
211991
212049
  activeDeps.kill(pid, "SIGKILL");
211992
212050
  } catch {}
211993
212051
  }
211994
- await removeApiPidFile();
212052
+ await removePidFile();
211995
212053
  }
211996
- async function getApiProcessInfo(config2, deps = {}) {
212054
+ async function getServerProcessInfo(config2, deps = {}) {
211997
212055
  const activeDeps = { ...DEFAULT_DEPS, ...deps };
211998
- let pid = await readApiPidFile();
212056
+ let pid = await readPidFile();
211999
212057
  if (!pid) {
212000
- pid = findPidByPort(config2.api.port);
212058
+ pid = findPidByPort(config2.server.port);
212001
212059
  if (pid) {
212002
- await writeApiPidFile(pid);
212060
+ await writePidFile(pid);
212003
212061
  }
212004
212062
  }
212005
212063
  if (!pid)
212006
212064
  return null;
212007
212065
  if (!isProcessAlive(pid, activeDeps)) {
212008
- await removeApiPidFile();
212066
+ await removePidFile();
212009
212067
  return null;
212010
212068
  }
212011
- const healthy = await waitForHealth(config2, activeDeps, 1, 0);
212012
- return { pid, port: config2.api.port, host: config2.api.host, running: healthy };
212069
+ const healthy = await waitForHealth(config2, activeDeps, { attempts: 1, intervalMs: 0 });
212070
+ return { pid, port: config2.server.port, host: config2.server.host, running: healthy };
212013
212071
  }
212014
212072
 
212015
212073
  // src/ops/statusCommand.ts
@@ -212142,9 +212200,9 @@ async function runStatusCommand(options = {}) {
212142
212200
  }
212143
212201
  }
212144
212202
  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);
212203
+ const apiInfo = await getServerProcessInfo(config2);
212204
+ const apiStatus = getServerStatusLine(apiInfo);
212205
+ printLine("C4A Server", apiStatus.ok, apiStatus.detail);
212148
212206
  if (staleContainers.length > 0) {
212149
212207
  const names = staleContainers.map((c) => c.name).join(", ");
212150
212208
  console.log(` ${"提示".padEnd(20, " ")} 发现旧配置容器仍在运行:${names}`);
@@ -212196,7 +212254,7 @@ function printLine(label, ok, detail) {
212196
212254
  const status = ok ? `${GREEN5}运行中${RESET5}` : `${RED2}未就绪${RESET5}`;
212197
212255
  console.log(` ${label.padEnd(20, " ")} ${status} ${detail}`);
212198
212256
  }
212199
- function getApiStatusLine(info) {
212257
+ function getServerStatusLine(info) {
212200
212258
  if (!info) {
212201
212259
  return { ok: false, detail: "未启动" };
212202
212260
  }
@@ -212283,24 +212341,23 @@ async function ensureNebulaInit(composePath, startedServices, projectName) {
212283
212341
  }
212284
212342
  return true;
212285
212343
  }
212286
- async function ensureApiStarted(config2) {
212287
- const existingApi = await getApiProcessInfo(config2);
212288
- if (existingApi && existingApi.running) {
212289
- console.log(`API 服务已在运行 (PID: ${existingApi.pid})`);
212344
+ async function ensureServerStarted(config2) {
212345
+ const existing = await getServerProcessInfo(config2);
212346
+ if (existing && existing.running) {
212347
+ console.log(`Server 已在运行 (PID: ${existing.pid})`);
212290
212348
  return true;
212291
212349
  }
212292
- if (existingApi && !existingApi.running) {
212293
- console.log(`API 进程存在但服务无响应 (PID: ${existingApi.pid}),尝试重启...`);
212294
- await stopApiProcess(config2);
212350
+ if (existing && !existing.running) {
212351
+ console.log(`Server 进程存在但服务无响应 (PID: ${existing.pid}),尝试重启...`);
212352
+ await stopServerProcess(config2);
212295
212353
  }
212296
212354
  try {
212297
- const started = await startApiProcess(config2);
212298
- console.log(`API 服务已启动 (PID: ${started.pid}, http://${started.host}:${started.port})`);
212355
+ const started = await startServerProcess(config2);
212356
+ console.log(`Server 已启动 (PID: ${started.pid}, http://${started.host}:${started.port})`);
212299
212357
  return true;
212300
212358
  } catch (error40) {
212301
212359
  const message = error40 instanceof Error ? error40.message : String(error40);
212302
- console.log(`API 服务启动失败: ${message}`);
212303
- console.log(`错误日志: ${resolveApiLogPath()}`);
212360
+ console.log(`Server 启动失败: ${message}`);
212304
212361
  return false;
212305
212362
  }
212306
212363
  }
@@ -212321,13 +212378,13 @@ async function runStartCommand(options = {}) {
212321
212378
  console.log(`当前配置没有需要启动的 Docker 服务。
212322
212379
  `);
212323
212380
  }
212324
- const apiOk = await ensureApiStarted(config2);
212381
+ const apiOk = await ensureServerStarted(config2);
212325
212382
  if (!apiOk)
212326
212383
  return;
212327
212384
  } else {
212328
212385
  const optionsList = [
212329
212386
  { label: "全部启动", value: "__all__" },
212330
- { label: "API 服务", value: "__api__" },
212387
+ { label: "C4A Server", value: "__api__" },
212331
212388
  ...services.map((svc) => ({ label: svc.serviceName, value: svc.serviceName }))
212332
212389
  ];
212333
212390
  const choice2 = await askChoice("选择要启动的服务", optionsList, "__all__");
@@ -212353,13 +212410,13 @@ async function runStartCommand(options = {}) {
212353
212410
  console.log(`当前配置没有需要启动的 Docker 服务。
212354
212411
  `);
212355
212412
  }
212356
- const apiOk = await ensureApiStarted(config2);
212413
+ const apiOk = await ensureServerStarted(config2);
212357
212414
  if (!apiOk) {
212358
212415
  await pauseBeforeReturn();
212359
212416
  return;
212360
212417
  }
212361
212418
  } else if (choice2 === "__api__") {
212362
- const apiOk = await ensureApiStarted(config2);
212419
+ const apiOk = await ensureServerStarted(config2);
212363
212420
  if (!apiOk) {
212364
212421
  await pauseBeforeReturn();
212365
212422
  return;
@@ -212390,7 +212447,7 @@ async function runStopCommand(options = {}) {
212390
212447
  const config2 = await loadServerConfig();
212391
212448
  const { composePath, services, projectName } = await getDockerServices(config2);
212392
212449
  const serviceMap = new Map(services.map((svc) => [svc.serviceName, svc.containerName]));
212393
- const apiInfo = await getApiProcessInfo(config2);
212450
+ const apiInfo = await getServerProcessInfo(config2);
212394
212451
  const apiAvailable = apiInfo !== null;
212395
212452
  if (services.length === 0) {
212396
212453
  console.log(`当前配置没有需要停止的 Docker 服务。
@@ -212413,11 +212470,11 @@ async function runStopCommand(options = {}) {
212413
212470
  let stopApi = false;
212414
212471
  if (mode === "cli") {
212415
212472
  targetServices = runningServices;
212416
- stopApi = apiAvailable;
212473
+ stopApi = true;
212417
212474
  } else {
212418
212475
  const optionsList = [
212419
212476
  { label: "全部停止", value: "__all__" },
212420
- ...apiAvailable ? [{ label: "API 服务", value: "__api__" }] : [],
212477
+ { label: "C4A Server", value: "__api__" },
212421
212478
  ...runningServices.map((name21) => ({ label: name21, value: name21 }))
212422
212479
  ];
212423
212480
  const choice2 = await askChoice("选择要停止的服务", optionsList, "__all__");
@@ -212428,7 +212485,7 @@ async function runStopCommand(options = {}) {
212428
212485
  }
212429
212486
  if (choice2 === "__all__") {
212430
212487
  targetServices = runningServices;
212431
- stopApi = apiAvailable;
212488
+ stopApi = true;
212432
212489
  } else if (choice2 === "__api__") {
212433
212490
  targetServices = [];
212434
212491
  stopApi = true;
@@ -212438,7 +212495,7 @@ async function runStopCommand(options = {}) {
212438
212495
  }
212439
212496
  const dockerTargets = targetServices;
212440
212497
  if (stopApi) {
212441
- await stopApiProcess(config2);
212498
+ await stopServerProcess(config2);
212442
212499
  }
212443
212500
  if (dockerTargets.length > 0) {
212444
212501
  console.log(`
@@ -214363,19 +214420,19 @@ async function runBackupCommand(options) {
214363
214420
  }
214364
214421
  }
214365
214422
 
214366
- // src/ops/restartApi.ts
214367
- async function restartApiIfRunning(config2, log) {
214368
- const info = await getApiProcessInfo(config2);
214423
+ // src/ops/restartServer.ts
214424
+ async function restartServerIfRunning(config2, log) {
214425
+ const info = await getServerProcessInfo(config2);
214369
214426
  if (!info)
214370
214427
  return;
214371
- log("正在重启 API 服务以刷新数据...");
214372
- await stopApiProcess(config2);
214428
+ log("正在重启 Server 以刷新数据...");
214429
+ await stopServerProcess(config2);
214373
214430
  try {
214374
- const started = await startApiProcess(config2);
214375
- log(`API 服务已重启 (PID: ${started.pid})`);
214431
+ const started = await startServerProcess(config2);
214432
+ log(`Server 已重启 (PID: ${started.pid})`);
214376
214433
  } catch (error40) {
214377
214434
  const message = error40 instanceof Error ? error40.message : String(error40);
214378
- log(`API 服务重启失败: ${message}`);
214435
+ log(`Server 重启失败: ${message}`);
214379
214436
  }
214380
214437
  }
214381
214438
 
@@ -214438,7 +214495,7 @@ async function runPurgeCommand(options) {
214438
214495
  await facade.close();
214439
214496
  }
214440
214497
  if (result) {
214441
- await restartApiIfRunning(config2, console.log);
214498
+ await restartServerIfRunning(config2, console.log);
214442
214499
  }
214443
214500
  if (mode === "interactive") {
214444
214501
  await pauseBeforeReturn();
@@ -214448,13 +214505,13 @@ async function runPurgeCommand(options) {
214448
214505
  // src/data/restore.ts
214449
214506
  import path16 from "node:path";
214450
214507
  async function triggerVectorRebuild(config2, log) {
214451
- const info = await getApiProcessInfo(config2);
214508
+ const info = await getServerProcessInfo(config2);
214452
214509
  if (!info) {
214453
- log("⚠️ API 服务未运行,向量索引未重建。启动 API 后可调用 POST /api/v1/vectors/rebuild 手动重建。");
214510
+ log("⚠️ Server 未运行,向量索引未重建。启动后可调用 POST /api/v1/vectors/rebuild 手动重建。");
214454
214511
  return;
214455
214512
  }
214456
- const port = config2.api.port;
214457
- const host = config2.api.host === "0.0.0.0" ? "127.0.0.1" : config2.api.host;
214513
+ const port = config2.server.port;
214514
+ const host = config2.server.host === "0.0.0.0" ? "127.0.0.1" : config2.server.host;
214458
214515
  const url2 = `http://${host}:${port}/api/v1/vectors/rebuild`;
214459
214516
  log("正在通过 API 重建向量索引...");
214460
214517
  try {
@@ -214605,7 +214662,7 @@ async function runRestoreCommand(options) {
214605
214662
  await facade.close();
214606
214663
  }
214607
214664
  if (result) {
214608
- await restartApiIfRunning(config2, console.log);
214665
+ await restartServerIfRunning(config2, console.log);
214609
214666
  await triggerVectorRebuild(config2, console.log);
214610
214667
  }
214611
214668
  if (mode === "interactive") {
@@ -215152,8 +215209,8 @@ var SERVER_CONFIG_NAME = "server.yaml";
215152
215209
  var DEFAULT_SERVER_YAML = `# C4A Server Configuration
215153
215210
  # 由 c4a-server 服务设置菜单生成和管理
215154
215211
 
215155
- api:
215156
- port: 3000
215212
+ server:
215213
+ port: 5100
215157
215214
  host: 0.0.0.0
215158
215215
 
215159
215216
  doc_db: