@c4a/server-cli 0.4.9 → 0.4.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +185 -128
- package/package.json +1 -1
- package/serve.js +176390 -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
|
-
|
|
43017
|
-
port:
|
|
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, ["
|
|
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
|
|
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 :
|
|
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:
|
|
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 :
|
|
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 :
|
|
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:
|
|
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 :
|
|
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 :
|
|
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 :
|
|
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 :
|
|
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 :
|
|
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 :
|
|
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 :
|
|
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 :
|
|
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 :
|
|
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 :
|
|
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 :
|
|
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 :
|
|
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 :
|
|
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 :
|
|
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/
|
|
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
|
|
211820
|
-
var
|
|
211821
|
-
|
|
211822
|
-
|
|
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, "
|
|
211826
|
-
path13.resolve(currentDir, "..", "..", "
|
|
211827
|
-
path13.resolve(currentDir, "..", "..", "
|
|
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
|
|
211837
|
-
return path13.resolve(process.cwd(), "data",
|
|
211876
|
+
function resolvePidPath() {
|
|
211877
|
+
return path13.resolve(process.cwd(), "data", SERVER_PID_NAME);
|
|
211838
211878
|
}
|
|
211839
|
-
function
|
|
211840
|
-
return path13.resolve(process.cwd(),
|
|
211879
|
+
function resolveServerLogPath() {
|
|
211880
|
+
return path13.resolve(process.cwd(), SERVER_LOG_DIR, makeServerLogName());
|
|
211841
211881
|
}
|
|
211842
|
-
function
|
|
211843
|
-
const host = config2.
|
|
211844
|
-
const url2 = `http://${host}:${config2.
|
|
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
|
|
211848
|
-
await mkdir3(path13.resolve(process.cwd(),
|
|
211887
|
+
async function ensureLogDirs() {
|
|
211888
|
+
await mkdir3(path13.resolve(process.cwd(), SERVER_LOG_DIR), { recursive: true });
|
|
211849
211889
|
}
|
|
211850
|
-
async function
|
|
211851
|
-
const pidPath =
|
|
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
|
|
211863
|
-
const pidPath =
|
|
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
|
|
211868
|
-
await rm(
|
|
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,
|
|
211902
|
-
const
|
|
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(
|
|
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
|
|
211961
|
+
async function startServerProcess(config2, deps = {}) {
|
|
211919
211962
|
const activeDeps = { ...DEFAULT_DEPS, ...deps };
|
|
211920
|
-
const existingPid = await
|
|
211963
|
+
const existingPid = await readPidFile();
|
|
211921
211964
|
if (existingPid && isProcessAlive(existingPid, activeDeps)) {
|
|
211922
|
-
return { pid: existingPid, port: config2.
|
|
211965
|
+
return { pid: existingPid, port: config2.server.port, host: config2.server.host, running: true };
|
|
211923
211966
|
}
|
|
211924
211967
|
if (existingPid) {
|
|
211925
|
-
await
|
|
211968
|
+
await removePidFile();
|
|
211926
211969
|
}
|
|
211927
|
-
const { host: healthHost } =
|
|
211928
|
-
const preCheck = await activeDeps.checkHttp(`http://${healthHost}:${config2.
|
|
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.
|
|
211973
|
+
const orphanPid = findPidByPort(config2.server.port);
|
|
211931
211974
|
if (orphanPid) {
|
|
211932
|
-
await
|
|
211933
|
-
return { pid: orphanPid, port: config2.
|
|
211975
|
+
await writePidFile(orphanPid);
|
|
211976
|
+
return { pid: orphanPid, port: config2.server.port, host: config2.server.host, running: true };
|
|
211934
211977
|
}
|
|
211935
211978
|
}
|
|
211936
|
-
await
|
|
211937
|
-
|
|
211938
|
-
|
|
211939
|
-
|
|
211940
|
-
|
|
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("
|
|
212002
|
+
throw new Error("Server 启动失败:未获取到 PID");
|
|
211948
212003
|
}
|
|
211949
212004
|
child.unref();
|
|
211950
|
-
await
|
|
211951
|
-
const healthy = await waitForHealth(config2, activeDeps
|
|
211952
|
-
|
|
211953
|
-
|
|
211954
|
-
|
|
211955
|
-
|
|
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
|
-
|
|
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.
|
|
212018
|
+
return { pid: child.pid, port: config2.server.port, host: config2.server.host, running: true };
|
|
211961
212019
|
}
|
|
211962
|
-
async function
|
|
212020
|
+
async function stopServerProcess(config2, deps = {}) {
|
|
211963
212021
|
const activeDeps = { ...DEFAULT_DEPS, ...deps };
|
|
211964
|
-
let pid = await
|
|
212022
|
+
let pid = await readPidFile();
|
|
211965
212023
|
if (!pid && config2) {
|
|
211966
|
-
pid = findPidByPort(config2.
|
|
212024
|
+
pid = findPidByPort(config2.server.port);
|
|
211967
212025
|
if (pid) {
|
|
211968
|
-
await
|
|
212026
|
+
await writePidFile(pid);
|
|
211969
212027
|
}
|
|
211970
212028
|
}
|
|
211971
212029
|
if (!pid)
|
|
211972
212030
|
return;
|
|
211973
212031
|
if (!isProcessAlive(pid, activeDeps)) {
|
|
211974
|
-
await
|
|
212032
|
+
await removePidFile();
|
|
211975
212033
|
return;
|
|
211976
212034
|
}
|
|
211977
212035
|
try {
|
|
211978
212036
|
activeDeps.kill(pid, "SIGTERM");
|
|
211979
212037
|
} catch {
|
|
211980
|
-
await
|
|
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
|
|
212052
|
+
await removePidFile();
|
|
211995
212053
|
}
|
|
211996
|
-
async function
|
|
212054
|
+
async function getServerProcessInfo(config2, deps = {}) {
|
|
211997
212055
|
const activeDeps = { ...DEFAULT_DEPS, ...deps };
|
|
211998
|
-
let pid = await
|
|
212056
|
+
let pid = await readPidFile();
|
|
211999
212057
|
if (!pid) {
|
|
212000
|
-
pid = findPidByPort(config2.
|
|
212058
|
+
pid = findPidByPort(config2.server.port);
|
|
212001
212059
|
if (pid) {
|
|
212002
|
-
await
|
|
212060
|
+
await writePidFile(pid);
|
|
212003
212061
|
}
|
|
212004
212062
|
}
|
|
212005
212063
|
if (!pid)
|
|
212006
212064
|
return null;
|
|
212007
212065
|
if (!isProcessAlive(pid, activeDeps)) {
|
|
212008
|
-
await
|
|
212066
|
+
await removePidFile();
|
|
212009
212067
|
return null;
|
|
212010
212068
|
}
|
|
212011
|
-
const healthy = await waitForHealth(config2, activeDeps, 1, 0);
|
|
212012
|
-
return { pid, port: config2.
|
|
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
|
|
212146
|
-
const apiStatus =
|
|
212147
|
-
printLine("
|
|
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
|
|
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
|
|
212287
|
-
const
|
|
212288
|
-
if (
|
|
212289
|
-
console.log(`
|
|
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 (
|
|
212293
|
-
console.log(`
|
|
212294
|
-
await
|
|
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
|
|
212298
|
-
console.log(`
|
|
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(`
|
|
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
|
|
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: "
|
|
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
|
|
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
|
|
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
|
|
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 =
|
|
212473
|
+
stopApi = true;
|
|
212417
212474
|
} else {
|
|
212418
212475
|
const optionsList = [
|
|
212419
212476
|
{ label: "全部停止", value: "__all__" },
|
|
212420
|
-
|
|
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 =
|
|
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
|
|
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/
|
|
214367
|
-
async function
|
|
214368
|
-
const info = await
|
|
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("正在重启
|
|
214372
|
-
await
|
|
214428
|
+
log("正在重启 Server 以刷新数据...");
|
|
214429
|
+
await stopServerProcess(config2);
|
|
214373
214430
|
try {
|
|
214374
|
-
const started = await
|
|
214375
|
-
log(`
|
|
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(`
|
|
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
|
|
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
|
|
214508
|
+
const info = await getServerProcessInfo(config2);
|
|
214452
214509
|
if (!info) {
|
|
214453
|
-
log("⚠️
|
|
214510
|
+
log("⚠️ Server 未运行,向量索引未重建。启动后可调用 POST /api/v1/vectors/rebuild 手动重建。");
|
|
214454
214511
|
return;
|
|
214455
214512
|
}
|
|
214456
|
-
const port = config2.
|
|
214457
|
-
const host = config2.
|
|
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
|
|
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
|
-
|
|
215156
|
-
port:
|
|
215212
|
+
server:
|
|
215213
|
+
port: 5100
|
|
215157
215214
|
host: 0.0.0.0
|
|
215158
215215
|
|
|
215159
215216
|
doc_db:
|