chatroom-cli 1.16.4 → 1.16.6
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/dist/index.js +206 -12
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -15948,6 +15948,194 @@ var init_state_recovery = __esm(() => {
|
|
|
15948
15948
|
init_api3();
|
|
15949
15949
|
});
|
|
15950
15950
|
|
|
15951
|
+
// src/infrastructure/local-api/routes/identity.ts
|
|
15952
|
+
async function handleIdentity(_req, ctx) {
|
|
15953
|
+
const identity = {
|
|
15954
|
+
machineId: ctx.machineId,
|
|
15955
|
+
hostname: ctx.config?.hostname ?? "unknown",
|
|
15956
|
+
os: ctx.config?.os ?? "unknown",
|
|
15957
|
+
version: getVersion()
|
|
15958
|
+
};
|
|
15959
|
+
return {
|
|
15960
|
+
status: 200,
|
|
15961
|
+
headers: { "Content-Type": "application/json" },
|
|
15962
|
+
body: JSON.stringify(identity)
|
|
15963
|
+
};
|
|
15964
|
+
}
|
|
15965
|
+
var identityRoute;
|
|
15966
|
+
var init_identity = __esm(() => {
|
|
15967
|
+
init_version();
|
|
15968
|
+
identityRoute = {
|
|
15969
|
+
method: "GET",
|
|
15970
|
+
path: "/api/identity",
|
|
15971
|
+
handler: handleIdentity
|
|
15972
|
+
};
|
|
15973
|
+
});
|
|
15974
|
+
|
|
15975
|
+
// src/infrastructure/local-api/cors.ts
|
|
15976
|
+
function applyCorsHeaders(response) {
|
|
15977
|
+
return {
|
|
15978
|
+
...response,
|
|
15979
|
+
headers: {
|
|
15980
|
+
...CORS_HEADERS,
|
|
15981
|
+
...response.headers ?? {}
|
|
15982
|
+
}
|
|
15983
|
+
};
|
|
15984
|
+
}
|
|
15985
|
+
function buildPreflightResponse() {
|
|
15986
|
+
return {
|
|
15987
|
+
status: 204,
|
|
15988
|
+
headers: CORS_HEADERS,
|
|
15989
|
+
body: ""
|
|
15990
|
+
};
|
|
15991
|
+
}
|
|
15992
|
+
var CORS_HEADERS;
|
|
15993
|
+
var init_cors = __esm(() => {
|
|
15994
|
+
CORS_HEADERS = {
|
|
15995
|
+
"Access-Control-Allow-Origin": "*",
|
|
15996
|
+
"Access-Control-Allow-Methods": "GET, POST, OPTIONS",
|
|
15997
|
+
"Access-Control-Allow-Headers": "Content-Type"
|
|
15998
|
+
};
|
|
15999
|
+
});
|
|
16000
|
+
|
|
16001
|
+
// src/infrastructure/local-api/router.ts
|
|
16002
|
+
class LocalApiRouter {
|
|
16003
|
+
routes = [];
|
|
16004
|
+
registerRoute(route) {
|
|
16005
|
+
this.routes.push(route);
|
|
16006
|
+
}
|
|
16007
|
+
async handleRequest(req, ctx) {
|
|
16008
|
+
if (req.method === "OPTIONS") {
|
|
16009
|
+
return buildPreflightResponse();
|
|
16010
|
+
}
|
|
16011
|
+
const pathname = req.url.split("?")[0] ?? req.url;
|
|
16012
|
+
const route = this.routes.find((r) => r.method === req.method && r.path === pathname);
|
|
16013
|
+
let response;
|
|
16014
|
+
if (route) {
|
|
16015
|
+
try {
|
|
16016
|
+
response = await route.handler(req, ctx);
|
|
16017
|
+
} catch (error) {
|
|
16018
|
+
response = {
|
|
16019
|
+
status: 500,
|
|
16020
|
+
headers: { "Content-Type": "application/json" },
|
|
16021
|
+
body: JSON.stringify({ error: "Internal server error" })
|
|
16022
|
+
};
|
|
16023
|
+
}
|
|
16024
|
+
} else {
|
|
16025
|
+
response = {
|
|
16026
|
+
status: 404,
|
|
16027
|
+
headers: { "Content-Type": "application/json" },
|
|
16028
|
+
body: JSON.stringify({ error: "Not found" })
|
|
16029
|
+
};
|
|
16030
|
+
}
|
|
16031
|
+
return applyCorsHeaders(response);
|
|
16032
|
+
}
|
|
16033
|
+
}
|
|
16034
|
+
var init_router = __esm(() => {
|
|
16035
|
+
init_cors();
|
|
16036
|
+
});
|
|
16037
|
+
|
|
16038
|
+
// src/infrastructure/local-api/server.ts
|
|
16039
|
+
import { createServer } from "node:http";
|
|
16040
|
+
function readBody(req) {
|
|
16041
|
+
return new Promise((resolve2, reject) => {
|
|
16042
|
+
const chunks = [];
|
|
16043
|
+
req.on("data", (chunk) => chunks.push(chunk));
|
|
16044
|
+
req.on("end", () => resolve2(Buffer.concat(chunks).toString("utf-8")));
|
|
16045
|
+
req.on("error", reject);
|
|
16046
|
+
});
|
|
16047
|
+
}
|
|
16048
|
+
async function normalizeRequest(req) {
|
|
16049
|
+
const body = await readBody(req);
|
|
16050
|
+
const headers = {};
|
|
16051
|
+
for (const [key, value] of Object.entries(req.headers)) {
|
|
16052
|
+
if (typeof value === "string") {
|
|
16053
|
+
headers[key] = value;
|
|
16054
|
+
} else if (Array.isArray(value)) {
|
|
16055
|
+
headers[key] = value.join(", ");
|
|
16056
|
+
}
|
|
16057
|
+
}
|
|
16058
|
+
return {
|
|
16059
|
+
method: (req.method ?? "GET").toUpperCase(),
|
|
16060
|
+
url: req.url ?? "/",
|
|
16061
|
+
headers,
|
|
16062
|
+
body: body || undefined
|
|
16063
|
+
};
|
|
16064
|
+
}
|
|
16065
|
+
function writeResponse(res, status, headers, body) {
|
|
16066
|
+
res.writeHead(status, headers);
|
|
16067
|
+
res.end(body);
|
|
16068
|
+
}
|
|
16069
|
+
function createRouter() {
|
|
16070
|
+
const router = new LocalApiRouter;
|
|
16071
|
+
router.registerRoute(identityRoute);
|
|
16072
|
+
return router;
|
|
16073
|
+
}
|
|
16074
|
+
function resolvePort() {
|
|
16075
|
+
const envPort = process.env.CHATROOM_LOCAL_API_PORT;
|
|
16076
|
+
if (envPort) {
|
|
16077
|
+
const parsed = parseInt(envPort, 10);
|
|
16078
|
+
if (!isNaN(parsed) && parsed > 0 && parsed < 65536) {
|
|
16079
|
+
return parsed;
|
|
16080
|
+
}
|
|
16081
|
+
}
|
|
16082
|
+
return LOCAL_API_PORT;
|
|
16083
|
+
}
|
|
16084
|
+
function ts() {
|
|
16085
|
+
return new Date().toISOString().replace("T", " ").slice(0, 19);
|
|
16086
|
+
}
|
|
16087
|
+
async function startLocalApi(ctx, port = resolvePort()) {
|
|
16088
|
+
const router = createRouter();
|
|
16089
|
+
const server = createServer(async (req, res) => {
|
|
16090
|
+
try {
|
|
16091
|
+
const localReq = await normalizeRequest(req);
|
|
16092
|
+
const localRes = await router.handleRequest(localReq, ctx);
|
|
16093
|
+
writeResponse(res, localRes.status, { "Content-Type": "application/json", ...localRes.headers ?? {} }, localRes.body);
|
|
16094
|
+
} catch {
|
|
16095
|
+
writeResponse(res, 500, { "Content-Type": "application/json" }, JSON.stringify({ error: "Internal server error" }));
|
|
16096
|
+
}
|
|
16097
|
+
});
|
|
16098
|
+
await new Promise((resolve2) => {
|
|
16099
|
+
server.listen(port, "127.0.0.1", () => {
|
|
16100
|
+
console.log(`[${ts()}] \uD83C\uDF10 Local API started on http://localhost:${port}`);
|
|
16101
|
+
resolve2();
|
|
16102
|
+
});
|
|
16103
|
+
server.on("error", (err) => {
|
|
16104
|
+
if (err.code === "EADDRINUSE") {
|
|
16105
|
+
console.warn(`[${ts()}] ⚠️ Local API port ${port} already in use — skipping local API`);
|
|
16106
|
+
} else {
|
|
16107
|
+
console.warn(`[${ts()}] ⚠️ Local API failed to start: ${err.message}`);
|
|
16108
|
+
}
|
|
16109
|
+
resolve2();
|
|
16110
|
+
});
|
|
16111
|
+
});
|
|
16112
|
+
const stop = () => new Promise((resolve2, reject) => {
|
|
16113
|
+
if (!server.listening) {
|
|
16114
|
+
resolve2();
|
|
16115
|
+
return;
|
|
16116
|
+
}
|
|
16117
|
+
server.close((err) => {
|
|
16118
|
+
if (err) {
|
|
16119
|
+
reject(err);
|
|
16120
|
+
} else {
|
|
16121
|
+
console.log(`[${ts()}] \uD83C\uDF10 Local API stopped`);
|
|
16122
|
+
resolve2();
|
|
16123
|
+
}
|
|
16124
|
+
});
|
|
16125
|
+
});
|
|
16126
|
+
return { stop };
|
|
16127
|
+
}
|
|
16128
|
+
var LOCAL_API_PORT = 19847;
|
|
16129
|
+
var init_server2 = __esm(() => {
|
|
16130
|
+
init_identity();
|
|
16131
|
+
init_router();
|
|
16132
|
+
});
|
|
16133
|
+
|
|
16134
|
+
// src/infrastructure/local-api/index.ts
|
|
16135
|
+
var init_local_api = __esm(() => {
|
|
16136
|
+
init_server2();
|
|
16137
|
+
});
|
|
16138
|
+
|
|
15951
16139
|
// src/events/daemon/event-bus.ts
|
|
15952
16140
|
class DaemonEventBus {
|
|
15953
16141
|
listeners = new Map;
|
|
@@ -15990,15 +16178,15 @@ function onAgentExited(ctx, payload) {
|
|
|
15990
16178
|
|
|
15991
16179
|
// src/events/daemon/agent/on-agent-started.ts
|
|
15992
16180
|
function onAgentStarted(ctx, payload) {
|
|
15993
|
-
const
|
|
15994
|
-
console.log(`[${
|
|
16181
|
+
const ts2 = formatTimestamp();
|
|
16182
|
+
console.log(`[${ts2}] \uD83D\uDFE2 Agent started: ${payload.role} (PID: ${payload.pid}, harness: ${payload.harness})`);
|
|
15995
16183
|
}
|
|
15996
16184
|
var init_on_agent_started = () => {};
|
|
15997
16185
|
|
|
15998
16186
|
// src/events/daemon/agent/on-agent-stopped.ts
|
|
15999
16187
|
function onAgentStopped(ctx, payload) {
|
|
16000
|
-
const
|
|
16001
|
-
console.log(`[${
|
|
16188
|
+
const ts2 = formatTimestamp();
|
|
16189
|
+
console.log(`[${ts2}] \uD83D\uDD34 Agent stopped: ${payload.role} (PID: ${payload.pid})`);
|
|
16002
16190
|
}
|
|
16003
16191
|
var init_on_agent_stopped = () => {};
|
|
16004
16192
|
|
|
@@ -16127,7 +16315,7 @@ class CrashLoopTracker {
|
|
|
16127
16315
|
const key = `${chatroomId}:${role.toLowerCase()}`;
|
|
16128
16316
|
const windowStart = now - CRASH_LOOP_WINDOW_MS;
|
|
16129
16317
|
const raw = this.history.get(key) ?? [];
|
|
16130
|
-
const recent = raw.filter((
|
|
16318
|
+
const recent = raw.filter((ts2) => ts2 >= windowStart);
|
|
16131
16319
|
recent.push(now);
|
|
16132
16320
|
this.history.set(key, recent);
|
|
16133
16321
|
const restartCount = recent.length;
|
|
@@ -16142,7 +16330,7 @@ class CrashLoopTracker {
|
|
|
16142
16330
|
const key = `${chatroomId}:${role.toLowerCase()}`;
|
|
16143
16331
|
const windowStart = now - CRASH_LOOP_WINDOW_MS;
|
|
16144
16332
|
const raw = this.history.get(key) ?? [];
|
|
16145
|
-
return raw.filter((
|
|
16333
|
+
return raw.filter((ts2) => ts2 >= windowStart).length;
|
|
16146
16334
|
}
|
|
16147
16335
|
}
|
|
16148
16336
|
var CRASH_LOOP_MAX_RESTARTS = 3, CRASH_LOOP_WINDOW_MS;
|
|
@@ -16785,6 +16973,8 @@ async function initDaemon() {
|
|
|
16785
16973
|
registerEventListeners(ctx);
|
|
16786
16974
|
logStartup(ctx, availableModels);
|
|
16787
16975
|
await recoverState(ctx);
|
|
16976
|
+
const localApiHandle = await startLocalApi(ctx);
|
|
16977
|
+
ctx.stopLocalApi = localApiHandle.stop;
|
|
16788
16978
|
return ctx;
|
|
16789
16979
|
} catch (error) {
|
|
16790
16980
|
if (isNetworkError(error)) {
|
|
@@ -16802,6 +16992,7 @@ var CONNECTION_RETRY_INTERVAL_MS = 1000;
|
|
|
16802
16992
|
var init_init2 = __esm(() => {
|
|
16803
16993
|
init_state_recovery();
|
|
16804
16994
|
init_api3();
|
|
16995
|
+
init_local_api();
|
|
16805
16996
|
init_register_listeners();
|
|
16806
16997
|
init_storage();
|
|
16807
16998
|
init_client2();
|
|
@@ -16872,16 +17063,16 @@ async function refreshModels(ctx) {
|
|
|
16872
17063
|
}
|
|
16873
17064
|
function evictStaleDedupEntries(processedCommandIds, processedPingIds, processedGitRefreshIds) {
|
|
16874
17065
|
const evictBefore = Date.now() - AGENT_REQUEST_DEADLINE_MS;
|
|
16875
|
-
for (const [id,
|
|
16876
|
-
if (
|
|
17066
|
+
for (const [id, ts2] of processedCommandIds) {
|
|
17067
|
+
if (ts2 < evictBefore)
|
|
16877
17068
|
processedCommandIds.delete(id);
|
|
16878
17069
|
}
|
|
16879
|
-
for (const [id,
|
|
16880
|
-
if (
|
|
17070
|
+
for (const [id, ts2] of processedPingIds) {
|
|
17071
|
+
if (ts2 < evictBefore)
|
|
16881
17072
|
processedPingIds.delete(id);
|
|
16882
17073
|
}
|
|
16883
|
-
for (const [id,
|
|
16884
|
-
if (
|
|
17074
|
+
for (const [id, ts2] of processedGitRefreshIds) {
|
|
17075
|
+
if (ts2 < evictBefore)
|
|
16885
17076
|
processedGitRefreshIds.delete(id);
|
|
16886
17077
|
}
|
|
16887
17078
|
}
|
|
@@ -16943,6 +17134,9 @@ async function startCommandLoop(ctx) {
|
|
|
16943
17134
|
if (gitSubscriptionHandle)
|
|
16944
17135
|
gitSubscriptionHandle.stop();
|
|
16945
17136
|
await onDaemonShutdown(ctx);
|
|
17137
|
+
if (ctx.stopLocalApi) {
|
|
17138
|
+
await ctx.stopLocalApi().catch(() => {});
|
|
17139
|
+
}
|
|
16946
17140
|
releaseLock();
|
|
16947
17141
|
process.exit(0);
|
|
16948
17142
|
};
|