quoroom 0.1.25 → 0.1.26
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/README.md +6 -0
- package/out/mcp/api-server.js +213 -80
- package/out/mcp/cli.js +225 -90
- package/out/mcp/server.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -187,6 +187,10 @@ brew install quoroom-ai/quoroom/quoroom
|
|
|
187
187
|
|
|
188
188
|
Download from [GitHub Releases](https://github.com/quoroom-ai/room/releases). Installers add `quoroom` to your PATH automatically. No dependencies needed.
|
|
189
189
|
|
|
190
|
+
Installer launchers:
|
|
191
|
+
- macOS `.pkg`: open `/Applications/Quoroom Server.app`
|
|
192
|
+
- Windows `.exe`: Start Menu -> Quoroom Server -> Open Quoroom Server
|
|
193
|
+
|
|
190
194
|
| Platform | Installer | Archive |
|
|
191
195
|
|----------|-----------|---------|
|
|
192
196
|
| macOS (Apple Silicon + Intel) | `.pkg` | `.tar.gz` |
|
|
@@ -210,6 +214,8 @@ Removes Quoroom binaries, all data, and logs. Prompts for confirmation before pr
|
|
|
210
214
|
quoroom serve
|
|
211
215
|
```
|
|
212
216
|
|
|
217
|
+
If you installed with the macOS `.pkg` or Windows `.exe` installer, you can also use the launcher app/shortcut instead of command line.
|
|
218
|
+
|
|
213
219
|
On first run, `quoroom serve` automatically registers the Quoroom MCP server in every AI coding tool you have installed (Claude Code, Claude Desktop, Cursor, Windsurf). Just **restart your AI client once** — after that, all `mcp__quoroom__*` tools are available automatically in every session.
|
|
214
220
|
|
|
215
221
|
Open **http://localhost:3700** (or the port shown in your terminal). The dashboard and API run locally, and your room data stays on your machine by default.
|
package/out/mcp/api-server.js
CHANGED
|
@@ -9914,7 +9914,7 @@ var require_package = __commonJS({
|
|
|
9914
9914
|
"package.json"(exports2, module2) {
|
|
9915
9915
|
module2.exports = {
|
|
9916
9916
|
name: "quoroom",
|
|
9917
|
-
version: "0.1.
|
|
9917
|
+
version: "0.1.26",
|
|
9918
9918
|
description: "Autonomous AI agent collective engine \u2014 Queen, Workers, Quorum",
|
|
9919
9919
|
main: "./out/mcp/server.js",
|
|
9920
9920
|
bin: {
|
|
@@ -13366,6 +13366,8 @@ var AUTO_MODE_USER_WHITELIST = [
|
|
|
13366
13366
|
// delete cloud station (archive)
|
|
13367
13367
|
/^POST \/api\/clerk\/chat$/,
|
|
13368
13368
|
// send message to clerk
|
|
13369
|
+
/^POST \/api\/clerk\/presence$/,
|
|
13370
|
+
// keeper presence heartbeat for auto commentary pace
|
|
13369
13371
|
/^POST \/api\/clerk\/typing$/,
|
|
13370
13372
|
// pause commentary while keeper is typing
|
|
13371
13373
|
/^POST \/api\/clerk\/reset$/,
|
|
@@ -27550,6 +27552,57 @@ ${output}
|
|
|
27550
27552
|
var import_node_crypto3 = require("node:crypto");
|
|
27551
27553
|
var import_node_fs2 = require("node:fs");
|
|
27552
27554
|
var import_node_path2 = require("node:path");
|
|
27555
|
+
|
|
27556
|
+
// src/server/provider-cli.ts
|
|
27557
|
+
var import_node_child_process2 = require("node:child_process");
|
|
27558
|
+
var CLI_PROBE_TIMEOUT_MS = 1500;
|
|
27559
|
+
function getProviderCliCommand(provider, platform = process.platform) {
|
|
27560
|
+
return platform === "win32" ? `${provider}.cmd` : provider;
|
|
27561
|
+
}
|
|
27562
|
+
function safeExec(cmd, args) {
|
|
27563
|
+
try {
|
|
27564
|
+
const stdout = (0, import_node_child_process2.execFileSync)(cmd, args, { timeout: CLI_PROBE_TIMEOUT_MS, stdio: ["ignore", "pipe", "pipe"] }).toString().trim();
|
|
27565
|
+
return { ok: true, stdout, stderr: "" };
|
|
27566
|
+
} catch (err) {
|
|
27567
|
+
const e = err;
|
|
27568
|
+
return {
|
|
27569
|
+
ok: false,
|
|
27570
|
+
stdout: e.stdout?.toString().trim() ?? "",
|
|
27571
|
+
stderr: e.stderr?.toString().trim() || e.message || ""
|
|
27572
|
+
};
|
|
27573
|
+
}
|
|
27574
|
+
}
|
|
27575
|
+
function probeProviderInstalled(provider) {
|
|
27576
|
+
const cmd = getProviderCliCommand(provider);
|
|
27577
|
+
const out = safeExec(cmd, ["--version"]);
|
|
27578
|
+
return out.ok ? { installed: true, version: out.stdout || void 0 } : { installed: false };
|
|
27579
|
+
}
|
|
27580
|
+
function probeProviderConnected(provider) {
|
|
27581
|
+
if (provider === "claude") {
|
|
27582
|
+
return probeProviderInstalled("claude").installed ? true : null;
|
|
27583
|
+
}
|
|
27584
|
+
const cmd = getProviderCliCommand(provider);
|
|
27585
|
+
const attempts = provider === "codex" ? [["login", "status"], ["auth", "status"]] : [["auth", "status"], ["login", "status"]];
|
|
27586
|
+
for (const args of attempts) {
|
|
27587
|
+
const out = safeExec(cmd, args);
|
|
27588
|
+
if (!out.ok) continue;
|
|
27589
|
+
const combined = `${out.stdout}
|
|
27590
|
+
${out.stderr}`.toLowerCase();
|
|
27591
|
+
if (combined.includes("not logged") || combined.includes("logged out") || combined.includes("unauth")) return false;
|
|
27592
|
+
return true;
|
|
27593
|
+
}
|
|
27594
|
+
return null;
|
|
27595
|
+
}
|
|
27596
|
+
function disconnectProvider(provider) {
|
|
27597
|
+
const cmd = getProviderCliCommand(provider);
|
|
27598
|
+
const args = ["logout"];
|
|
27599
|
+
return {
|
|
27600
|
+
command: `${provider} ${args.join(" ")}`,
|
|
27601
|
+
result: safeExec(cmd, args)
|
|
27602
|
+
};
|
|
27603
|
+
}
|
|
27604
|
+
|
|
27605
|
+
// src/server/clerk-profile.ts
|
|
27553
27606
|
var lastProjectDocSyncAt = 0;
|
|
27554
27607
|
var lastProjectDocSnapshot = "Project docs memory not synced yet.";
|
|
27555
27608
|
function findAnyRoomCredential2(db2, credentialName) {
|
|
@@ -27563,17 +27616,25 @@ function findAnyRoomCredential2(db2, credentialName) {
|
|
|
27563
27616
|
}
|
|
27564
27617
|
return null;
|
|
27565
27618
|
}
|
|
27619
|
+
function maskKey(key) {
|
|
27620
|
+
if (!key) return null;
|
|
27621
|
+
const trimmed = key.trim();
|
|
27622
|
+
if (trimmed.length <= 8) return `${trimmed.slice(0, 3)}...`;
|
|
27623
|
+
return `${trimmed.slice(0, 7)}...${trimmed.slice(-4)}`;
|
|
27624
|
+
}
|
|
27566
27625
|
function getClerkApiAuthState(db2, provider) {
|
|
27567
27626
|
const credentialName = provider === "openai_api" ? "openai_api_key" : "anthropic_api_key";
|
|
27568
27627
|
const envVar = provider === "openai_api" ? "OPENAI_API_KEY" : "ANTHROPIC_API_KEY";
|
|
27569
|
-
const
|
|
27570
|
-
const
|
|
27571
|
-
const
|
|
27628
|
+
const roomCredential = findAnyRoomCredential2(db2, credentialName);
|
|
27629
|
+
const savedKey = getClerkApiKey(db2, provider);
|
|
27630
|
+
const envKey = (process.env[envVar] || "").trim() || null;
|
|
27631
|
+
const activeKey = roomCredential || savedKey || envKey;
|
|
27572
27632
|
return {
|
|
27573
|
-
hasRoomCredential,
|
|
27574
|
-
hasSavedKey,
|
|
27575
|
-
hasEnvKey,
|
|
27576
|
-
ready:
|
|
27633
|
+
hasRoomCredential: Boolean(roomCredential),
|
|
27634
|
+
hasSavedKey: Boolean(savedKey),
|
|
27635
|
+
hasEnvKey: Boolean(envKey),
|
|
27636
|
+
ready: Boolean(activeKey),
|
|
27637
|
+
maskedKey: maskKey(activeKey)
|
|
27577
27638
|
};
|
|
27578
27639
|
}
|
|
27579
27640
|
function getClerkApiAuth(db2) {
|
|
@@ -27582,6 +27643,15 @@ function getClerkApiAuth(db2) {
|
|
|
27582
27643
|
anthropic: getClerkApiAuthState(db2, "anthropic_api")
|
|
27583
27644
|
};
|
|
27584
27645
|
}
|
|
27646
|
+
function autoConfigureClerkModel(db2) {
|
|
27647
|
+
if (probeProviderInstalled("claude").installed) return DEFAULT_CLERK_MODEL;
|
|
27648
|
+
const codex = probeProviderInstalled("codex");
|
|
27649
|
+
if (codex.installed && probeProviderConnected("codex") === true) return CLERK_FALLBACK_SUBSCRIPTION_MODEL;
|
|
27650
|
+
const apiAuth = getClerkApiAuth(db2);
|
|
27651
|
+
if (apiAuth.openai.ready) return CLERK_FALLBACK_OPENAI_MODEL;
|
|
27652
|
+
if (apiAuth.anthropic.ready) return CLERK_FALLBACK_ANTHROPIC_MODEL;
|
|
27653
|
+
return null;
|
|
27654
|
+
}
|
|
27585
27655
|
function resolveClerkApiKey(db2, model) {
|
|
27586
27656
|
const provider = getModelProvider(model);
|
|
27587
27657
|
if (provider === "openai_api") {
|
|
@@ -27836,13 +27906,16 @@ var COMMENTARY_INTERVAL_MAX_MS = 3e4;
|
|
|
27836
27906
|
var COMMENTARY_LIGHT_INTERVAL_MIN_MS = 2 * 60 * 60 * 1e3;
|
|
27837
27907
|
var COMMENTARY_LIGHT_INTERVAL_MAX_MS = 3 * 60 * 60 * 1e3;
|
|
27838
27908
|
var USER_PRESENCE_TIMEOUT_MS = 9e4;
|
|
27909
|
+
var ACTIVE_MODE_RESCHEDULE_THRESHOLD_MS = COMMENTARY_INTERVAL_MAX_MS + 1e3;
|
|
27839
27910
|
var SILENCE_THRESHOLD_MS = 6e4;
|
|
27840
27911
|
var MAX_BUFFER_SIZE = 200;
|
|
27841
27912
|
var MIN_ENTRIES_FOR_LLM = 1;
|
|
27842
27913
|
var LLM_TIMEOUT_MS = 2e4;
|
|
27843
27914
|
var COMMENTARY_HOLD_COUNT_KEY = "clerk_commentary_hold_count";
|
|
27915
|
+
var COMMENTARY_MODE_KEY = "clerk_commentary_mode";
|
|
27844
27916
|
var LAST_ASSISTANT_REPLY_AT_KEY = "clerk_last_assistant_reply_at";
|
|
27845
27917
|
var commentaryTimer = null;
|
|
27918
|
+
var nextCommentaryDueAtMs = null;
|
|
27846
27919
|
var unsubscribeEvents = null;
|
|
27847
27920
|
var logBuffer = [];
|
|
27848
27921
|
var lastUserMessageAt = 0;
|
|
@@ -27895,6 +27968,27 @@ function getCommentaryHoldCount(db2) {
|
|
|
27895
27968
|
function isCommentaryHeld(db2) {
|
|
27896
27969
|
return getCommentaryHoldCount(db2) > 0;
|
|
27897
27970
|
}
|
|
27971
|
+
function getCommentaryMode(db2) {
|
|
27972
|
+
const raw = (getSetting(db2, COMMENTARY_MODE_KEY) ?? "").trim().toLowerCase();
|
|
27973
|
+
return raw === "light" ? "light" : "auto";
|
|
27974
|
+
}
|
|
27975
|
+
function parseIsoMs(value) {
|
|
27976
|
+
if (!value) return null;
|
|
27977
|
+
const ms = Date.parse(value);
|
|
27978
|
+
return Number.isFinite(ms) ? ms : null;
|
|
27979
|
+
}
|
|
27980
|
+
function isUserPresent(db2) {
|
|
27981
|
+
const lastSeenMs = parseIsoMs(getSetting(db2, "clerk_user_last_seen_at"));
|
|
27982
|
+
const lastInteractionMs = parseIsoMs(getSetting(db2, "clerk_last_user_message_at"));
|
|
27983
|
+
const newest = Math.max(lastSeenMs ?? 0, lastInteractionMs ?? 0);
|
|
27984
|
+
if (newest <= 0) return false;
|
|
27985
|
+
return Date.now() - newest < USER_PRESENCE_TIMEOUT_MS;
|
|
27986
|
+
}
|
|
27987
|
+
function getCommentaryPace(db2) {
|
|
27988
|
+
const mode = getCommentaryMode(db2);
|
|
27989
|
+
if (mode === "light") return "light";
|
|
27990
|
+
return isUserPresent(db2) ? "active" : "light";
|
|
27991
|
+
}
|
|
27898
27992
|
function requeueEntries(entries) {
|
|
27899
27993
|
if (entries.length === 0) return;
|
|
27900
27994
|
logBuffer = [...entries, ...logBuffer];
|
|
@@ -28229,7 +28323,56 @@ function startCommentaryEngine(db2) {
|
|
|
28229
28323
|
const parsed = Date.parse(lastReplyIso);
|
|
28230
28324
|
if (Number.isFinite(parsed)) lastAssistantReplyAt = parsed;
|
|
28231
28325
|
}
|
|
28326
|
+
const clearSchedule = () => {
|
|
28327
|
+
if (commentaryTimer) {
|
|
28328
|
+
clearTimeout(commentaryTimer);
|
|
28329
|
+
commentaryTimer = null;
|
|
28330
|
+
}
|
|
28331
|
+
nextCommentaryDueAtMs = null;
|
|
28332
|
+
};
|
|
28333
|
+
const scheduleNext = () => {
|
|
28334
|
+
if (!dbRef) return;
|
|
28335
|
+
const pace = getCommentaryPace(dbRef);
|
|
28336
|
+
const min = pace === "active" ? COMMENTARY_INTERVAL_MIN_MS : COMMENTARY_LIGHT_INTERVAL_MIN_MS;
|
|
28337
|
+
const max = pace === "active" ? COMMENTARY_INTERVAL_MAX_MS : COMMENTARY_LIGHT_INTERVAL_MAX_MS;
|
|
28338
|
+
const delay = min + Math.random() * (max - min);
|
|
28339
|
+
nextCommentaryDueAtMs = Date.now() + delay;
|
|
28340
|
+
commentaryTimer = setTimeout(() => {
|
|
28341
|
+
commentaryTimer = null;
|
|
28342
|
+
nextCommentaryDueAtMs = null;
|
|
28343
|
+
void emitCommentary().finally(() => {
|
|
28344
|
+
if (dbRef && commentaryTimer == null) scheduleNext();
|
|
28345
|
+
});
|
|
28346
|
+
}, delay);
|
|
28347
|
+
};
|
|
28348
|
+
const rescheduleIfPresenceRecovered = () => {
|
|
28349
|
+
if (!dbRef) return;
|
|
28350
|
+
if (getCommentaryMode(dbRef) !== "auto") return;
|
|
28351
|
+
if (!isUserPresent(dbRef)) return;
|
|
28352
|
+
if (commentaryTimer == null || nextCommentaryDueAtMs == null) {
|
|
28353
|
+
scheduleNext();
|
|
28354
|
+
return;
|
|
28355
|
+
}
|
|
28356
|
+
const remaining = nextCommentaryDueAtMs - Date.now();
|
|
28357
|
+
if (remaining > ACTIVE_MODE_RESCHEDULE_THRESHOLD_MS) {
|
|
28358
|
+
clearSchedule();
|
|
28359
|
+
scheduleNext();
|
|
28360
|
+
}
|
|
28361
|
+
};
|
|
28362
|
+
const rescheduleForModeChange = () => {
|
|
28363
|
+
if (!dbRef) return;
|
|
28364
|
+
clearSchedule();
|
|
28365
|
+
scheduleNext();
|
|
28366
|
+
};
|
|
28232
28367
|
unsubscribeEvents = eventBus.onAny((event) => {
|
|
28368
|
+
if (event.type === "clerk:presence") {
|
|
28369
|
+
rescheduleIfPresenceRecovered();
|
|
28370
|
+
return;
|
|
28371
|
+
}
|
|
28372
|
+
if (event.type === "clerk:commentary_mode_changed") {
|
|
28373
|
+
rescheduleForModeChange();
|
|
28374
|
+
return;
|
|
28375
|
+
}
|
|
28233
28376
|
if (event.type === "clerk:user_message" || event.type === "clerk:user_typing") {
|
|
28234
28377
|
const payload = event.data;
|
|
28235
28378
|
lastUserMessageAt = typeof payload?.timestamp === "number" ? payload.timestamp : Date.now();
|
|
@@ -28358,23 +28501,6 @@ function startCommentaryEngine(db2) {
|
|
|
28358
28501
|
});
|
|
28359
28502
|
}
|
|
28360
28503
|
});
|
|
28361
|
-
function isUserPresent() {
|
|
28362
|
-
if (!dbRef) return false;
|
|
28363
|
-
const lastSeen = getSetting(dbRef, "clerk_user_last_seen_at");
|
|
28364
|
-
if (!lastSeen) return false;
|
|
28365
|
-
return Date.now() - new Date(lastSeen).getTime() < USER_PRESENCE_TIMEOUT_MS;
|
|
28366
|
-
}
|
|
28367
|
-
function scheduleNext() {
|
|
28368
|
-
const active = isUserPresent();
|
|
28369
|
-
const min = active ? COMMENTARY_INTERVAL_MIN_MS : COMMENTARY_LIGHT_INTERVAL_MIN_MS;
|
|
28370
|
-
const max = active ? COMMENTARY_INTERVAL_MAX_MS : COMMENTARY_LIGHT_INTERVAL_MAX_MS;
|
|
28371
|
-
const delay = min + Math.random() * (max - min);
|
|
28372
|
-
commentaryTimer = setTimeout(() => {
|
|
28373
|
-
void emitCommentary().finally(() => {
|
|
28374
|
-
if (commentaryTimer !== null) scheduleNext();
|
|
28375
|
-
});
|
|
28376
|
-
}, delay);
|
|
28377
|
-
}
|
|
28378
28504
|
scheduleNext();
|
|
28379
28505
|
}
|
|
28380
28506
|
async function emitCommentary() {
|
|
@@ -28440,9 +28566,10 @@ async function emitCommentary() {
|
|
|
28440
28566
|
}
|
|
28441
28567
|
function stopCommentaryEngine() {
|
|
28442
28568
|
if (commentaryTimer) {
|
|
28443
|
-
|
|
28569
|
+
clearTimeout(commentaryTimer);
|
|
28444
28570
|
commentaryTimer = null;
|
|
28445
28571
|
}
|
|
28572
|
+
nextCommentaryDueAtMs = null;
|
|
28446
28573
|
if (unsubscribeEvents) {
|
|
28447
28574
|
unsubscribeEvents();
|
|
28448
28575
|
unsubscribeEvents = null;
|
|
@@ -29327,6 +29454,29 @@ var CLERK_LOG_LINE_MAX = 240;
|
|
|
29327
29454
|
var CLERK_SUMMARY_ITEM_LIMIT = 8;
|
|
29328
29455
|
var CLERK_COMMENTARY_HOLD_COUNT_KEY = "clerk_commentary_hold_count";
|
|
29329
29456
|
var CLERK_LAST_ASSISTANT_REPLY_AT_KEY = "clerk_last_assistant_reply_at";
|
|
29457
|
+
var CLERK_COMMENTARY_MODE_KEY = "clerk_commentary_mode";
|
|
29458
|
+
var CLERK_USER_PRESENCE_TIMEOUT_MS = 9e4;
|
|
29459
|
+
function parseIsoMs2(value) {
|
|
29460
|
+
if (!value) return null;
|
|
29461
|
+
const ms = Date.parse(value);
|
|
29462
|
+
return Number.isFinite(ms) ? ms : null;
|
|
29463
|
+
}
|
|
29464
|
+
function getCommentaryMode2(db2) {
|
|
29465
|
+
const mode = (getSetting(db2, CLERK_COMMENTARY_MODE_KEY) ?? "").trim().toLowerCase();
|
|
29466
|
+
return mode === "light" ? "light" : "auto";
|
|
29467
|
+
}
|
|
29468
|
+
function isKeeperPresent(db2) {
|
|
29469
|
+
const lastSeenMs = parseIsoMs2(getSetting(db2, "clerk_user_last_seen_at"));
|
|
29470
|
+
const lastInteractionMs = parseIsoMs2(getSetting(db2, "clerk_last_user_message_at"));
|
|
29471
|
+
const newest = Math.max(lastSeenMs ?? 0, lastInteractionMs ?? 0);
|
|
29472
|
+
if (newest <= 0) return false;
|
|
29473
|
+
return Date.now() - newest < CLERK_USER_PRESENCE_TIMEOUT_MS;
|
|
29474
|
+
}
|
|
29475
|
+
function getCommentaryPace2(db2) {
|
|
29476
|
+
const mode = getCommentaryMode2(db2);
|
|
29477
|
+
if (mode === "light") return "light";
|
|
29478
|
+
return isKeeperPresent(db2) ? "active" : "light";
|
|
29479
|
+
}
|
|
29330
29480
|
function extractApiError2(payload) {
|
|
29331
29481
|
if (!payload || typeof payload !== "object") return null;
|
|
29332
29482
|
const record = payload;
|
|
@@ -29635,6 +29785,7 @@ function registerClerkRoutes(router) {
|
|
|
29635
29785
|
});
|
|
29636
29786
|
router.post("/api/clerk/presence", (ctx) => {
|
|
29637
29787
|
setSetting(ctx.db, "clerk_user_last_seen_at", (/* @__PURE__ */ new Date()).toISOString());
|
|
29788
|
+
eventBus.emit("clerk", "clerk:presence", { timestamp: Date.now() });
|
|
29638
29789
|
return { data: { ok: true } };
|
|
29639
29790
|
});
|
|
29640
29791
|
router.post("/api/clerk/typing", (ctx) => {
|
|
@@ -29662,13 +29813,30 @@ function registerClerkRoutes(router) {
|
|
|
29662
29813
|
});
|
|
29663
29814
|
router.get("/api/clerk/status", (ctx) => {
|
|
29664
29815
|
const clerkWorkerId = getSetting(ctx.db, "clerk_worker_id");
|
|
29665
|
-
|
|
29816
|
+
let model = getSetting(ctx.db, "clerk_model");
|
|
29817
|
+
let autoConfigured = false;
|
|
29818
|
+
if (!model) {
|
|
29819
|
+
const detected = autoConfigureClerkModel(ctx.db);
|
|
29820
|
+
if (detected) {
|
|
29821
|
+
setSetting(ctx.db, "clerk_model", detected);
|
|
29822
|
+
setSetting(ctx.db, "queen_model", detected);
|
|
29823
|
+
const clerk = ensureClerkWorker(ctx.db);
|
|
29824
|
+
updateWorker(ctx.db, clerk.id, { model: detected });
|
|
29825
|
+
model = detected;
|
|
29826
|
+
autoConfigured = true;
|
|
29827
|
+
}
|
|
29828
|
+
}
|
|
29666
29829
|
const commentaryEnabled = getSetting(ctx.db, "clerk_commentary_enabled") !== "false";
|
|
29830
|
+
const commentaryMode = getCommentaryMode2(ctx.db);
|
|
29831
|
+
const commentaryPace = commentaryEnabled ? getCommentaryPace2(ctx.db) : "light";
|
|
29667
29832
|
return {
|
|
29668
29833
|
data: {
|
|
29669
29834
|
configured: Boolean(clerkWorkerId) || Boolean(model),
|
|
29670
29835
|
model: model || null,
|
|
29836
|
+
autoConfigured,
|
|
29671
29837
|
commentaryEnabled,
|
|
29838
|
+
commentaryMode,
|
|
29839
|
+
commentaryPace,
|
|
29672
29840
|
apiAuth: getClerkApiAuth(ctx.db)
|
|
29673
29841
|
}
|
|
29674
29842
|
};
|
|
@@ -29698,10 +29866,20 @@ function registerClerkRoutes(router) {
|
|
|
29698
29866
|
if (body.commentaryEnabled !== void 0) {
|
|
29699
29867
|
setSetting(ctx.db, "clerk_commentary_enabled", body.commentaryEnabled ? "true" : "false");
|
|
29700
29868
|
}
|
|
29869
|
+
if (body.commentaryMode !== void 0) {
|
|
29870
|
+
const mode = String(body.commentaryMode).trim().toLowerCase();
|
|
29871
|
+
if (mode !== "auto" && mode !== "light") {
|
|
29872
|
+
return { status: 400, error: "commentaryMode must be auto or light" };
|
|
29873
|
+
}
|
|
29874
|
+
setSetting(ctx.db, CLERK_COMMENTARY_MODE_KEY, mode);
|
|
29875
|
+
eventBus.emit("clerk", "clerk:commentary_mode_changed", { mode });
|
|
29876
|
+
}
|
|
29701
29877
|
return {
|
|
29702
29878
|
data: {
|
|
29703
29879
|
model: getSetting(ctx.db, "clerk_model") || null,
|
|
29704
29880
|
commentaryEnabled: getSetting(ctx.db, "clerk_commentary_enabled") !== "false",
|
|
29881
|
+
commentaryMode: getCommentaryMode2(ctx.db),
|
|
29882
|
+
commentaryPace: getCommentaryPace2(ctx.db),
|
|
29705
29883
|
apiAuth: getClerkApiAuth(ctx.db)
|
|
29706
29884
|
}
|
|
29707
29885
|
};
|
|
@@ -31856,7 +32034,7 @@ function registerChatRoutes(router) {
|
|
|
31856
32034
|
|
|
31857
32035
|
// src/server/routes/status.ts
|
|
31858
32036
|
var import_node_os4 = __toESM(require("node:os"));
|
|
31859
|
-
var
|
|
32037
|
+
var import_node_child_process3 = require("node:child_process");
|
|
31860
32038
|
var import_node_util = require("node:util");
|
|
31861
32039
|
|
|
31862
32040
|
// src/server/db.ts
|
|
@@ -32656,7 +32834,7 @@ function semverGt(a, b) {
|
|
|
32656
32834
|
}
|
|
32657
32835
|
function getCurrentVersion() {
|
|
32658
32836
|
try {
|
|
32659
|
-
return true ? "0.1.
|
|
32837
|
+
return true ? "0.1.26" : null.version;
|
|
32660
32838
|
} catch {
|
|
32661
32839
|
return "0.0.0";
|
|
32662
32840
|
}
|
|
@@ -32813,13 +32991,13 @@ var cachedVersion = null;
|
|
|
32813
32991
|
function getVersion3() {
|
|
32814
32992
|
if (cachedVersion) return cachedVersion;
|
|
32815
32993
|
try {
|
|
32816
|
-
cachedVersion = true ? "0.1.
|
|
32994
|
+
cachedVersion = true ? "0.1.26" : null.version;
|
|
32817
32995
|
} catch {
|
|
32818
32996
|
cachedVersion = "unknown";
|
|
32819
32997
|
}
|
|
32820
32998
|
return cachedVersion;
|
|
32821
32999
|
}
|
|
32822
|
-
var execFileAsync = (0, import_node_util.promisify)(
|
|
33000
|
+
var execFileAsync = (0, import_node_util.promisify)(import_node_child_process3.execFile);
|
|
32823
33001
|
var CLI_CACHE_MS = 3e4;
|
|
32824
33002
|
var cachedClaude = { available: false };
|
|
32825
33003
|
var claudeCachedAt = 0;
|
|
@@ -33533,7 +33711,7 @@ function registerRoomMessageRoutes(router) {
|
|
|
33533
33711
|
}
|
|
33534
33712
|
|
|
33535
33713
|
// src/server/provider-auth.ts
|
|
33536
|
-
var
|
|
33714
|
+
var import_node_child_process4 = require("node:child_process");
|
|
33537
33715
|
var import_node_crypto9 = require("node:crypto");
|
|
33538
33716
|
var sessionStore = /* @__PURE__ */ new Map();
|
|
33539
33717
|
var activeByProvider = /* @__PURE__ */ new Map();
|
|
@@ -33544,8 +33722,8 @@ function nowIso() {
|
|
|
33544
33722
|
return (/* @__PURE__ */ new Date()).toISOString();
|
|
33545
33723
|
}
|
|
33546
33724
|
function getProviderCommand(provider) {
|
|
33547
|
-
|
|
33548
|
-
return { command
|
|
33725
|
+
const command = getProviderCliCommand(provider);
|
|
33726
|
+
return { command, args: ["login"] };
|
|
33549
33727
|
}
|
|
33550
33728
|
function isActiveStatus(status2) {
|
|
33551
33729
|
return status2 === "starting" || status2 === "running";
|
|
@@ -33746,7 +33924,7 @@ function startProviderAuthSession(provider) {
|
|
|
33746
33924
|
}
|
|
33747
33925
|
const cmd = getProviderCommand(provider);
|
|
33748
33926
|
const displayCommand = [cmd.command, ...cmd.args].join(" ");
|
|
33749
|
-
const child = (0,
|
|
33927
|
+
const child = (0, import_node_child_process4.spawn)(cmd.command, cmd.args, {
|
|
33750
33928
|
stdio: ["pipe", "pipe", "pipe"],
|
|
33751
33929
|
env: { ...process.env, CI: "1", FORCE_COLOR: "0" }
|
|
33752
33930
|
});
|
|
@@ -33821,51 +33999,6 @@ function startProviderAuthSession(provider) {
|
|
|
33821
33999
|
var import_node_child_process5 = require("node:child_process");
|
|
33822
34000
|
var import_node_crypto10 = require("node:crypto");
|
|
33823
34001
|
var import_node_path5 = __toESM(require("node:path"));
|
|
33824
|
-
|
|
33825
|
-
// src/server/provider-cli.ts
|
|
33826
|
-
var import_node_child_process4 = require("node:child_process");
|
|
33827
|
-
var CLI_PROBE_TIMEOUT_MS = 1500;
|
|
33828
|
-
function safeExec(cmd, args) {
|
|
33829
|
-
try {
|
|
33830
|
-
const stdout = (0, import_node_child_process4.execFileSync)(cmd, args, { timeout: CLI_PROBE_TIMEOUT_MS, stdio: ["ignore", "pipe", "pipe"] }).toString().trim();
|
|
33831
|
-
return { ok: true, stdout, stderr: "" };
|
|
33832
|
-
} catch (err) {
|
|
33833
|
-
const e = err;
|
|
33834
|
-
return {
|
|
33835
|
-
ok: false,
|
|
33836
|
-
stdout: e.stdout?.toString().trim() ?? "",
|
|
33837
|
-
stderr: e.stderr?.toString().trim() || e.message || ""
|
|
33838
|
-
};
|
|
33839
|
-
}
|
|
33840
|
-
}
|
|
33841
|
-
function probeProviderInstalled(provider) {
|
|
33842
|
-
const out = safeExec(provider, ["--version"]);
|
|
33843
|
-
return out.ok ? { installed: true, version: out.stdout || void 0 } : { installed: false };
|
|
33844
|
-
}
|
|
33845
|
-
function probeProviderConnected(provider) {
|
|
33846
|
-
if (provider === "claude") {
|
|
33847
|
-
return probeProviderInstalled("claude").installed ? true : null;
|
|
33848
|
-
}
|
|
33849
|
-
const attempts = provider === "codex" ? [["login", "status"], ["auth", "status"]] : [["auth", "status"], ["login", "status"]];
|
|
33850
|
-
for (const args of attempts) {
|
|
33851
|
-
const out = safeExec(provider, args);
|
|
33852
|
-
if (!out.ok) continue;
|
|
33853
|
-
const combined = `${out.stdout}
|
|
33854
|
-
${out.stderr}`.toLowerCase();
|
|
33855
|
-
if (combined.includes("not logged") || combined.includes("logged out") || combined.includes("unauth")) return false;
|
|
33856
|
-
return true;
|
|
33857
|
-
}
|
|
33858
|
-
return null;
|
|
33859
|
-
}
|
|
33860
|
-
function disconnectProvider(provider) {
|
|
33861
|
-
const args = ["logout"];
|
|
33862
|
-
return {
|
|
33863
|
-
command: `${provider} ${args.join(" ")}`,
|
|
33864
|
-
result: safeExec(provider, args)
|
|
33865
|
-
};
|
|
33866
|
-
}
|
|
33867
|
-
|
|
33868
|
-
// src/server/provider-install.ts
|
|
33869
34002
|
var sessionStore2 = /* @__PURE__ */ new Map();
|
|
33870
34003
|
var activeByProvider2 = /* @__PURE__ */ new Map();
|
|
33871
34004
|
var MAX_LINES2 = Math.max(50, parseInt(process.env.QUOROOM_PROVIDER_INSTALL_MAX_LINES || "300", 10) || 300);
|
package/out/mcp/cli.js
CHANGED
|
@@ -52379,7 +52379,7 @@ var server_exports = {};
|
|
|
52379
52379
|
async function main() {
|
|
52380
52380
|
const server = new McpServer({
|
|
52381
52381
|
name: "quoroom",
|
|
52382
|
-
version: true ? "0.1.
|
|
52382
|
+
version: true ? "0.1.26" : "0.0.0"
|
|
52383
52383
|
});
|
|
52384
52384
|
registerMemoryTools(server);
|
|
52385
52385
|
registerSchedulerTools(server);
|
|
@@ -52886,6 +52886,8 @@ var init_access = __esm({
|
|
|
52886
52886
|
// delete cloud station (archive)
|
|
52887
52887
|
/^POST \/api\/clerk\/chat$/,
|
|
52888
52888
|
// send message to clerk
|
|
52889
|
+
/^POST \/api\/clerk\/presence$/,
|
|
52890
|
+
// keeper presence heartbeat for auto commentary pace
|
|
52889
52891
|
/^POST \/api\/clerk\/typing$/,
|
|
52890
52892
|
// pause commentary while keeper is typing
|
|
52891
52893
|
/^POST \/api\/clerk\/reset$/,
|
|
@@ -54395,7 +54397,7 @@ var require_package = __commonJS({
|
|
|
54395
54397
|
"package.json"(exports2, module2) {
|
|
54396
54398
|
module2.exports = {
|
|
54397
54399
|
name: "quoroom",
|
|
54398
|
-
version: "0.1.
|
|
54400
|
+
version: "0.1.26",
|
|
54399
54401
|
description: "Autonomous AI agent collective engine \u2014 Queen, Workers, Quorum",
|
|
54400
54402
|
main: "./out/mcp/server.js",
|
|
54401
54403
|
bin: {
|
|
@@ -55357,6 +55359,61 @@ var init_decisions = __esm({
|
|
|
55357
55359
|
}
|
|
55358
55360
|
});
|
|
55359
55361
|
|
|
55362
|
+
// src/server/provider-cli.ts
|
|
55363
|
+
function getProviderCliCommand(provider, platform = process.platform) {
|
|
55364
|
+
return platform === "win32" ? `${provider}.cmd` : provider;
|
|
55365
|
+
}
|
|
55366
|
+
function safeExec(cmd, args2) {
|
|
55367
|
+
try {
|
|
55368
|
+
const stdout = (0, import_node_child_process2.execFileSync)(cmd, args2, { timeout: CLI_PROBE_TIMEOUT_MS, stdio: ["ignore", "pipe", "pipe"] }).toString().trim();
|
|
55369
|
+
return { ok: true, stdout, stderr: "" };
|
|
55370
|
+
} catch (err) {
|
|
55371
|
+
const e = err;
|
|
55372
|
+
return {
|
|
55373
|
+
ok: false,
|
|
55374
|
+
stdout: e.stdout?.toString().trim() ?? "",
|
|
55375
|
+
stderr: e.stderr?.toString().trim() || e.message || ""
|
|
55376
|
+
};
|
|
55377
|
+
}
|
|
55378
|
+
}
|
|
55379
|
+
function probeProviderInstalled(provider) {
|
|
55380
|
+
const cmd = getProviderCliCommand(provider);
|
|
55381
|
+
const out = safeExec(cmd, ["--version"]);
|
|
55382
|
+
return out.ok ? { installed: true, version: out.stdout || void 0 } : { installed: false };
|
|
55383
|
+
}
|
|
55384
|
+
function probeProviderConnected(provider) {
|
|
55385
|
+
if (provider === "claude") {
|
|
55386
|
+
return probeProviderInstalled("claude").installed ? true : null;
|
|
55387
|
+
}
|
|
55388
|
+
const cmd = getProviderCliCommand(provider);
|
|
55389
|
+
const attempts = provider === "codex" ? [["login", "status"], ["auth", "status"]] : [["auth", "status"], ["login", "status"]];
|
|
55390
|
+
for (const args2 of attempts) {
|
|
55391
|
+
const out = safeExec(cmd, args2);
|
|
55392
|
+
if (!out.ok) continue;
|
|
55393
|
+
const combined = `${out.stdout}
|
|
55394
|
+
${out.stderr}`.toLowerCase();
|
|
55395
|
+
if (combined.includes("not logged") || combined.includes("logged out") || combined.includes("unauth")) return false;
|
|
55396
|
+
return true;
|
|
55397
|
+
}
|
|
55398
|
+
return null;
|
|
55399
|
+
}
|
|
55400
|
+
function disconnectProvider(provider) {
|
|
55401
|
+
const cmd = getProviderCliCommand(provider);
|
|
55402
|
+
const args2 = ["logout"];
|
|
55403
|
+
return {
|
|
55404
|
+
command: `${provider} ${args2.join(" ")}`,
|
|
55405
|
+
result: safeExec(cmd, args2)
|
|
55406
|
+
};
|
|
55407
|
+
}
|
|
55408
|
+
var import_node_child_process2, CLI_PROBE_TIMEOUT_MS;
|
|
55409
|
+
var init_provider_cli = __esm({
|
|
55410
|
+
"src/server/provider-cli.ts"() {
|
|
55411
|
+
"use strict";
|
|
55412
|
+
import_node_child_process2 = require("node:child_process");
|
|
55413
|
+
CLI_PROBE_TIMEOUT_MS = 1500;
|
|
55414
|
+
}
|
|
55415
|
+
});
|
|
55416
|
+
|
|
55360
55417
|
// src/server/clerk-profile.ts
|
|
55361
55418
|
function findAnyRoomCredential2(db3, credentialName) {
|
|
55362
55419
|
const rooms = listRooms(db3);
|
|
@@ -55369,17 +55426,25 @@ function findAnyRoomCredential2(db3, credentialName) {
|
|
|
55369
55426
|
}
|
|
55370
55427
|
return null;
|
|
55371
55428
|
}
|
|
55429
|
+
function maskKey(key) {
|
|
55430
|
+
if (!key) return null;
|
|
55431
|
+
const trimmed = key.trim();
|
|
55432
|
+
if (trimmed.length <= 8) return `${trimmed.slice(0, 3)}...`;
|
|
55433
|
+
return `${trimmed.slice(0, 7)}...${trimmed.slice(-4)}`;
|
|
55434
|
+
}
|
|
55372
55435
|
function getClerkApiAuthState(db3, provider) {
|
|
55373
55436
|
const credentialName = provider === "openai_api" ? "openai_api_key" : "anthropic_api_key";
|
|
55374
55437
|
const envVar = provider === "openai_api" ? "OPENAI_API_KEY" : "ANTHROPIC_API_KEY";
|
|
55375
|
-
const
|
|
55376
|
-
const
|
|
55377
|
-
const
|
|
55438
|
+
const roomCredential = findAnyRoomCredential2(db3, credentialName);
|
|
55439
|
+
const savedKey = getClerkApiKey(db3, provider);
|
|
55440
|
+
const envKey = (process.env[envVar] || "").trim() || null;
|
|
55441
|
+
const activeKey = roomCredential || savedKey || envKey;
|
|
55378
55442
|
return {
|
|
55379
|
-
hasRoomCredential,
|
|
55380
|
-
hasSavedKey,
|
|
55381
|
-
hasEnvKey,
|
|
55382
|
-
ready:
|
|
55443
|
+
hasRoomCredential: Boolean(roomCredential),
|
|
55444
|
+
hasSavedKey: Boolean(savedKey),
|
|
55445
|
+
hasEnvKey: Boolean(envKey),
|
|
55446
|
+
ready: Boolean(activeKey),
|
|
55447
|
+
maskedKey: maskKey(activeKey)
|
|
55383
55448
|
};
|
|
55384
55449
|
}
|
|
55385
55450
|
function getClerkApiAuth(db3) {
|
|
@@ -55388,6 +55453,15 @@ function getClerkApiAuth(db3) {
|
|
|
55388
55453
|
anthropic: getClerkApiAuthState(db3, "anthropic_api")
|
|
55389
55454
|
};
|
|
55390
55455
|
}
|
|
55456
|
+
function autoConfigureClerkModel(db3) {
|
|
55457
|
+
if (probeProviderInstalled("claude").installed) return DEFAULT_CLERK_MODEL;
|
|
55458
|
+
const codex = probeProviderInstalled("codex");
|
|
55459
|
+
if (codex.installed && probeProviderConnected("codex") === true) return CLERK_FALLBACK_SUBSCRIPTION_MODEL;
|
|
55460
|
+
const apiAuth = getClerkApiAuth(db3);
|
|
55461
|
+
if (apiAuth.openai.ready) return CLERK_FALLBACK_OPENAI_MODEL;
|
|
55462
|
+
if (apiAuth.anthropic.ready) return CLERK_FALLBACK_ANTHROPIC_MODEL;
|
|
55463
|
+
return null;
|
|
55464
|
+
}
|
|
55391
55465
|
function resolveClerkApiKey(db3, model) {
|
|
55392
55466
|
const provider = getModelProvider(model);
|
|
55393
55467
|
if (provider === "openai_api") {
|
|
@@ -55645,6 +55719,7 @@ var init_clerk_profile = __esm({
|
|
|
55645
55719
|
init_agent_executor();
|
|
55646
55720
|
init_db_queries();
|
|
55647
55721
|
init_model_provider();
|
|
55722
|
+
init_provider_cli();
|
|
55648
55723
|
init_clerk_profile_config();
|
|
55649
55724
|
lastProjectDocSyncAt = 0;
|
|
55650
55725
|
lastProjectDocSnapshot = "Project docs memory not synced yet.";
|
|
@@ -55692,6 +55767,27 @@ function getCommentaryHoldCount(db3) {
|
|
|
55692
55767
|
function isCommentaryHeld(db3) {
|
|
55693
55768
|
return getCommentaryHoldCount(db3) > 0;
|
|
55694
55769
|
}
|
|
55770
|
+
function getCommentaryMode(db3) {
|
|
55771
|
+
const raw = (getSetting(db3, COMMENTARY_MODE_KEY) ?? "").trim().toLowerCase();
|
|
55772
|
+
return raw === "light" ? "light" : "auto";
|
|
55773
|
+
}
|
|
55774
|
+
function parseIsoMs(value) {
|
|
55775
|
+
if (!value) return null;
|
|
55776
|
+
const ms = Date.parse(value);
|
|
55777
|
+
return Number.isFinite(ms) ? ms : null;
|
|
55778
|
+
}
|
|
55779
|
+
function isUserPresent(db3) {
|
|
55780
|
+
const lastSeenMs = parseIsoMs(getSetting(db3, "clerk_user_last_seen_at"));
|
|
55781
|
+
const lastInteractionMs = parseIsoMs(getSetting(db3, "clerk_last_user_message_at"));
|
|
55782
|
+
const newest = Math.max(lastSeenMs ?? 0, lastInteractionMs ?? 0);
|
|
55783
|
+
if (newest <= 0) return false;
|
|
55784
|
+
return Date.now() - newest < USER_PRESENCE_TIMEOUT_MS;
|
|
55785
|
+
}
|
|
55786
|
+
function getCommentaryPace(db3) {
|
|
55787
|
+
const mode = getCommentaryMode(db3);
|
|
55788
|
+
if (mode === "light") return "light";
|
|
55789
|
+
return isUserPresent(db3) ? "active" : "light";
|
|
55790
|
+
}
|
|
55695
55791
|
function requeueEntries(entries) {
|
|
55696
55792
|
if (entries.length === 0) return;
|
|
55697
55793
|
logBuffer = [...entries, ...logBuffer];
|
|
@@ -55945,7 +56041,56 @@ function startCommentaryEngine(db3) {
|
|
|
55945
56041
|
const parsed = Date.parse(lastReplyIso);
|
|
55946
56042
|
if (Number.isFinite(parsed)) lastAssistantReplyAt = parsed;
|
|
55947
56043
|
}
|
|
56044
|
+
const clearSchedule = () => {
|
|
56045
|
+
if (commentaryTimer) {
|
|
56046
|
+
clearTimeout(commentaryTimer);
|
|
56047
|
+
commentaryTimer = null;
|
|
56048
|
+
}
|
|
56049
|
+
nextCommentaryDueAtMs = null;
|
|
56050
|
+
};
|
|
56051
|
+
const scheduleNext = () => {
|
|
56052
|
+
if (!dbRef) return;
|
|
56053
|
+
const pace = getCommentaryPace(dbRef);
|
|
56054
|
+
const min = pace === "active" ? COMMENTARY_INTERVAL_MIN_MS : COMMENTARY_LIGHT_INTERVAL_MIN_MS;
|
|
56055
|
+
const max = pace === "active" ? COMMENTARY_INTERVAL_MAX_MS : COMMENTARY_LIGHT_INTERVAL_MAX_MS;
|
|
56056
|
+
const delay = min + Math.random() * (max - min);
|
|
56057
|
+
nextCommentaryDueAtMs = Date.now() + delay;
|
|
56058
|
+
commentaryTimer = setTimeout(() => {
|
|
56059
|
+
commentaryTimer = null;
|
|
56060
|
+
nextCommentaryDueAtMs = null;
|
|
56061
|
+
void emitCommentary().finally(() => {
|
|
56062
|
+
if (dbRef && commentaryTimer == null) scheduleNext();
|
|
56063
|
+
});
|
|
56064
|
+
}, delay);
|
|
56065
|
+
};
|
|
56066
|
+
const rescheduleIfPresenceRecovered = () => {
|
|
56067
|
+
if (!dbRef) return;
|
|
56068
|
+
if (getCommentaryMode(dbRef) !== "auto") return;
|
|
56069
|
+
if (!isUserPresent(dbRef)) return;
|
|
56070
|
+
if (commentaryTimer == null || nextCommentaryDueAtMs == null) {
|
|
56071
|
+
scheduleNext();
|
|
56072
|
+
return;
|
|
56073
|
+
}
|
|
56074
|
+
const remaining = nextCommentaryDueAtMs - Date.now();
|
|
56075
|
+
if (remaining > ACTIVE_MODE_RESCHEDULE_THRESHOLD_MS) {
|
|
56076
|
+
clearSchedule();
|
|
56077
|
+
scheduleNext();
|
|
56078
|
+
}
|
|
56079
|
+
};
|
|
56080
|
+
const rescheduleForModeChange = () => {
|
|
56081
|
+
if (!dbRef) return;
|
|
56082
|
+
clearSchedule();
|
|
56083
|
+
scheduleNext();
|
|
56084
|
+
};
|
|
55948
56085
|
unsubscribeEvents = eventBus.onAny((event) => {
|
|
56086
|
+
if (event.type === "clerk:presence") {
|
|
56087
|
+
rescheduleIfPresenceRecovered();
|
|
56088
|
+
return;
|
|
56089
|
+
}
|
|
56090
|
+
if (event.type === "clerk:commentary_mode_changed") {
|
|
56091
|
+
rescheduleForModeChange();
|
|
56092
|
+
return;
|
|
56093
|
+
}
|
|
55949
56094
|
if (event.type === "clerk:user_message" || event.type === "clerk:user_typing") {
|
|
55950
56095
|
const payload = event.data;
|
|
55951
56096
|
lastUserMessageAt = typeof payload?.timestamp === "number" ? payload.timestamp : Date.now();
|
|
@@ -56074,23 +56219,6 @@ function startCommentaryEngine(db3) {
|
|
|
56074
56219
|
});
|
|
56075
56220
|
}
|
|
56076
56221
|
});
|
|
56077
|
-
function isUserPresent() {
|
|
56078
|
-
if (!dbRef) return false;
|
|
56079
|
-
const lastSeen = getSetting(dbRef, "clerk_user_last_seen_at");
|
|
56080
|
-
if (!lastSeen) return false;
|
|
56081
|
-
return Date.now() - new Date(lastSeen).getTime() < USER_PRESENCE_TIMEOUT_MS;
|
|
56082
|
-
}
|
|
56083
|
-
function scheduleNext() {
|
|
56084
|
-
const active = isUserPresent();
|
|
56085
|
-
const min = active ? COMMENTARY_INTERVAL_MIN_MS : COMMENTARY_LIGHT_INTERVAL_MIN_MS;
|
|
56086
|
-
const max = active ? COMMENTARY_INTERVAL_MAX_MS : COMMENTARY_LIGHT_INTERVAL_MAX_MS;
|
|
56087
|
-
const delay = min + Math.random() * (max - min);
|
|
56088
|
-
commentaryTimer = setTimeout(() => {
|
|
56089
|
-
void emitCommentary().finally(() => {
|
|
56090
|
-
if (commentaryTimer !== null) scheduleNext();
|
|
56091
|
-
});
|
|
56092
|
-
}, delay);
|
|
56093
|
-
}
|
|
56094
56222
|
scheduleNext();
|
|
56095
56223
|
}
|
|
56096
56224
|
async function emitCommentary() {
|
|
@@ -56156,9 +56284,10 @@ async function emitCommentary() {
|
|
|
56156
56284
|
}
|
|
56157
56285
|
function stopCommentaryEngine() {
|
|
56158
56286
|
if (commentaryTimer) {
|
|
56159
|
-
|
|
56287
|
+
clearTimeout(commentaryTimer);
|
|
56160
56288
|
commentaryTimer = null;
|
|
56161
56289
|
}
|
|
56290
|
+
nextCommentaryDueAtMs = null;
|
|
56162
56291
|
if (unsubscribeEvents) {
|
|
56163
56292
|
unsubscribeEvents();
|
|
56164
56293
|
unsubscribeEvents = null;
|
|
@@ -56174,7 +56303,7 @@ function stopCommentaryEngine() {
|
|
|
56174
56303
|
workerNameCache.clear();
|
|
56175
56304
|
cycleWorkerCache.clear();
|
|
56176
56305
|
}
|
|
56177
|
-
var COMMENTARY_INTERVAL_MIN_MS, COMMENTARY_INTERVAL_MAX_MS, COMMENTARY_LIGHT_INTERVAL_MIN_MS, COMMENTARY_LIGHT_INTERVAL_MAX_MS, USER_PRESENCE_TIMEOUT_MS, SILENCE_THRESHOLD_MS, MAX_BUFFER_SIZE, MIN_ENTRIES_FOR_LLM, LLM_TIMEOUT_MS, COMMENTARY_HOLD_COUNT_KEY, LAST_ASSISTANT_REPLY_AT_KEY, commentaryTimer, unsubscribeEvents, logBuffer, lastUserMessageAt, lastAssistantReplyAt, dbRef, generating, lastCommentary, lastFormatMode, commentaryCount, roomNameCache, workerNameCache, cycleWorkerCache, TOOL_NAMES;
|
|
56306
|
+
var COMMENTARY_INTERVAL_MIN_MS, COMMENTARY_INTERVAL_MAX_MS, COMMENTARY_LIGHT_INTERVAL_MIN_MS, COMMENTARY_LIGHT_INTERVAL_MAX_MS, USER_PRESENCE_TIMEOUT_MS, ACTIVE_MODE_RESCHEDULE_THRESHOLD_MS, SILENCE_THRESHOLD_MS, MAX_BUFFER_SIZE, MIN_ENTRIES_FOR_LLM, LLM_TIMEOUT_MS, COMMENTARY_HOLD_COUNT_KEY, COMMENTARY_MODE_KEY, LAST_ASSISTANT_REPLY_AT_KEY, commentaryTimer, nextCommentaryDueAtMs, unsubscribeEvents, logBuffer, lastUserMessageAt, lastAssistantReplyAt, dbRef, generating, lastCommentary, lastFormatMode, commentaryCount, roomNameCache, workerNameCache, cycleWorkerCache, TOOL_NAMES;
|
|
56178
56307
|
var init_clerk_commentary = __esm({
|
|
56179
56308
|
"src/server/clerk-commentary.ts"() {
|
|
56180
56309
|
"use strict";
|
|
@@ -56187,13 +56316,16 @@ var init_clerk_commentary = __esm({
|
|
|
56187
56316
|
COMMENTARY_LIGHT_INTERVAL_MIN_MS = 2 * 60 * 60 * 1e3;
|
|
56188
56317
|
COMMENTARY_LIGHT_INTERVAL_MAX_MS = 3 * 60 * 60 * 1e3;
|
|
56189
56318
|
USER_PRESENCE_TIMEOUT_MS = 9e4;
|
|
56319
|
+
ACTIVE_MODE_RESCHEDULE_THRESHOLD_MS = COMMENTARY_INTERVAL_MAX_MS + 1e3;
|
|
56190
56320
|
SILENCE_THRESHOLD_MS = 6e4;
|
|
56191
56321
|
MAX_BUFFER_SIZE = 200;
|
|
56192
56322
|
MIN_ENTRIES_FOR_LLM = 1;
|
|
56193
56323
|
LLM_TIMEOUT_MS = 2e4;
|
|
56194
56324
|
COMMENTARY_HOLD_COUNT_KEY = "clerk_commentary_hold_count";
|
|
56325
|
+
COMMENTARY_MODE_KEY = "clerk_commentary_mode";
|
|
56195
56326
|
LAST_ASSISTANT_REPLY_AT_KEY = "clerk_last_assistant_reply_at";
|
|
56196
56327
|
commentaryTimer = null;
|
|
56328
|
+
nextCommentaryDueAtMs = null;
|
|
56197
56329
|
unsubscribeEvents = null;
|
|
56198
56330
|
logBuffer = [];
|
|
56199
56331
|
lastUserMessageAt = 0;
|
|
@@ -57167,6 +57299,27 @@ var init_keeper_email = __esm({
|
|
|
57167
57299
|
});
|
|
57168
57300
|
|
|
57169
57301
|
// src/server/routes/clerk.ts
|
|
57302
|
+
function parseIsoMs2(value) {
|
|
57303
|
+
if (!value) return null;
|
|
57304
|
+
const ms = Date.parse(value);
|
|
57305
|
+
return Number.isFinite(ms) ? ms : null;
|
|
57306
|
+
}
|
|
57307
|
+
function getCommentaryMode2(db3) {
|
|
57308
|
+
const mode = (getSetting(db3, CLERK_COMMENTARY_MODE_KEY) ?? "").trim().toLowerCase();
|
|
57309
|
+
return mode === "light" ? "light" : "auto";
|
|
57310
|
+
}
|
|
57311
|
+
function isKeeperPresent(db3) {
|
|
57312
|
+
const lastSeenMs = parseIsoMs2(getSetting(db3, "clerk_user_last_seen_at"));
|
|
57313
|
+
const lastInteractionMs = parseIsoMs2(getSetting(db3, "clerk_last_user_message_at"));
|
|
57314
|
+
const newest = Math.max(lastSeenMs ?? 0, lastInteractionMs ?? 0);
|
|
57315
|
+
if (newest <= 0) return false;
|
|
57316
|
+
return Date.now() - newest < CLERK_USER_PRESENCE_TIMEOUT_MS;
|
|
57317
|
+
}
|
|
57318
|
+
function getCommentaryPace2(db3) {
|
|
57319
|
+
const mode = getCommentaryMode2(db3);
|
|
57320
|
+
if (mode === "light") return "light";
|
|
57321
|
+
return isKeeperPresent(db3) ? "active" : "light";
|
|
57322
|
+
}
|
|
57170
57323
|
function extractApiError2(payload) {
|
|
57171
57324
|
if (!payload || typeof payload !== "object") return null;
|
|
57172
57325
|
const record2 = payload;
|
|
@@ -57475,6 +57628,7 @@ function registerClerkRoutes(router) {
|
|
|
57475
57628
|
});
|
|
57476
57629
|
router.post("/api/clerk/presence", (ctx) => {
|
|
57477
57630
|
setSetting(ctx.db, "clerk_user_last_seen_at", (/* @__PURE__ */ new Date()).toISOString());
|
|
57631
|
+
eventBus.emit("clerk", "clerk:presence", { timestamp: Date.now() });
|
|
57478
57632
|
return { data: { ok: true } };
|
|
57479
57633
|
});
|
|
57480
57634
|
router.post("/api/clerk/typing", (ctx) => {
|
|
@@ -57502,13 +57656,30 @@ function registerClerkRoutes(router) {
|
|
|
57502
57656
|
});
|
|
57503
57657
|
router.get("/api/clerk/status", (ctx) => {
|
|
57504
57658
|
const clerkWorkerId = getSetting(ctx.db, "clerk_worker_id");
|
|
57505
|
-
|
|
57659
|
+
let model = getSetting(ctx.db, "clerk_model");
|
|
57660
|
+
let autoConfigured = false;
|
|
57661
|
+
if (!model) {
|
|
57662
|
+
const detected = autoConfigureClerkModel(ctx.db);
|
|
57663
|
+
if (detected) {
|
|
57664
|
+
setSetting(ctx.db, "clerk_model", detected);
|
|
57665
|
+
setSetting(ctx.db, "queen_model", detected);
|
|
57666
|
+
const clerk = ensureClerkWorker(ctx.db);
|
|
57667
|
+
updateWorker(ctx.db, clerk.id, { model: detected });
|
|
57668
|
+
model = detected;
|
|
57669
|
+
autoConfigured = true;
|
|
57670
|
+
}
|
|
57671
|
+
}
|
|
57506
57672
|
const commentaryEnabled = getSetting(ctx.db, "clerk_commentary_enabled") !== "false";
|
|
57673
|
+
const commentaryMode = getCommentaryMode2(ctx.db);
|
|
57674
|
+
const commentaryPace = commentaryEnabled ? getCommentaryPace2(ctx.db) : "light";
|
|
57507
57675
|
return {
|
|
57508
57676
|
data: {
|
|
57509
57677
|
configured: Boolean(clerkWorkerId) || Boolean(model),
|
|
57510
57678
|
model: model || null,
|
|
57679
|
+
autoConfigured,
|
|
57511
57680
|
commentaryEnabled,
|
|
57681
|
+
commentaryMode,
|
|
57682
|
+
commentaryPace,
|
|
57512
57683
|
apiAuth: getClerkApiAuth(ctx.db)
|
|
57513
57684
|
}
|
|
57514
57685
|
};
|
|
@@ -57538,16 +57709,26 @@ function registerClerkRoutes(router) {
|
|
|
57538
57709
|
if (body.commentaryEnabled !== void 0) {
|
|
57539
57710
|
setSetting(ctx.db, "clerk_commentary_enabled", body.commentaryEnabled ? "true" : "false");
|
|
57540
57711
|
}
|
|
57712
|
+
if (body.commentaryMode !== void 0) {
|
|
57713
|
+
const mode = String(body.commentaryMode).trim().toLowerCase();
|
|
57714
|
+
if (mode !== "auto" && mode !== "light") {
|
|
57715
|
+
return { status: 400, error: "commentaryMode must be auto or light" };
|
|
57716
|
+
}
|
|
57717
|
+
setSetting(ctx.db, CLERK_COMMENTARY_MODE_KEY, mode);
|
|
57718
|
+
eventBus.emit("clerk", "clerk:commentary_mode_changed", { mode });
|
|
57719
|
+
}
|
|
57541
57720
|
return {
|
|
57542
57721
|
data: {
|
|
57543
57722
|
model: getSetting(ctx.db, "clerk_model") || null,
|
|
57544
57723
|
commentaryEnabled: getSetting(ctx.db, "clerk_commentary_enabled") !== "false",
|
|
57724
|
+
commentaryMode: getCommentaryMode2(ctx.db),
|
|
57725
|
+
commentaryPace: getCommentaryPace2(ctx.db),
|
|
57545
57726
|
apiAuth: getClerkApiAuth(ctx.db)
|
|
57546
57727
|
}
|
|
57547
57728
|
};
|
|
57548
57729
|
});
|
|
57549
57730
|
}
|
|
57550
|
-
var VALIDATION_TIMEOUT_MS, CLERK_RECENT_LOG_LIMIT, CLERK_LOG_LINE_MAX, CLERK_SUMMARY_ITEM_LIMIT, CLERK_COMMENTARY_HOLD_COUNT_KEY, CLERK_LAST_ASSISTANT_REPLY_AT_KEY;
|
|
57731
|
+
var VALIDATION_TIMEOUT_MS, CLERK_RECENT_LOG_LIMIT, CLERK_LOG_LINE_MAX, CLERK_SUMMARY_ITEM_LIMIT, CLERK_COMMENTARY_HOLD_COUNT_KEY, CLERK_LAST_ASSISTANT_REPLY_AT_KEY, CLERK_COMMENTARY_MODE_KEY, CLERK_USER_PRESENCE_TIMEOUT_MS;
|
|
57551
57732
|
var init_clerk = __esm({
|
|
57552
57733
|
"src/server/routes/clerk.ts"() {
|
|
57553
57734
|
"use strict";
|
|
@@ -57564,6 +57745,8 @@ var init_clerk = __esm({
|
|
|
57564
57745
|
CLERK_SUMMARY_ITEM_LIMIT = 8;
|
|
57565
57746
|
CLERK_COMMENTARY_HOLD_COUNT_KEY = "clerk_commentary_hold_count";
|
|
57566
57747
|
CLERK_LAST_ASSISTANT_REPLY_AT_KEY = "clerk_last_assistant_reply_at";
|
|
57748
|
+
CLERK_COMMENTARY_MODE_KEY = "clerk_commentary_mode";
|
|
57749
|
+
CLERK_USER_PRESENCE_TIMEOUT_MS = 9e4;
|
|
57567
57750
|
}
|
|
57568
57751
|
});
|
|
57569
57752
|
|
|
@@ -59941,7 +60124,7 @@ function semverGt(a, b) {
|
|
|
59941
60124
|
}
|
|
59942
60125
|
function getCurrentVersion() {
|
|
59943
60126
|
try {
|
|
59944
|
-
return true ? "0.1.
|
|
60127
|
+
return true ? "0.1.26" : null.version;
|
|
59945
60128
|
} catch {
|
|
59946
60129
|
return "0.0.0";
|
|
59947
60130
|
}
|
|
@@ -60124,7 +60307,7 @@ var init_updateChecker = __esm({
|
|
|
60124
60307
|
function getVersion3() {
|
|
60125
60308
|
if (cachedVersion) return cachedVersion;
|
|
60126
60309
|
try {
|
|
60127
|
-
cachedVersion = true ? "0.1.
|
|
60310
|
+
cachedVersion = true ? "0.1.26" : null.version;
|
|
60128
60311
|
} catch {
|
|
60129
60312
|
cachedVersion = "unknown";
|
|
60130
60313
|
}
|
|
@@ -60254,12 +60437,12 @@ function registerStatusRoutes(router) {
|
|
|
60254
60437
|
};
|
|
60255
60438
|
});
|
|
60256
60439
|
}
|
|
60257
|
-
var import_node_os5,
|
|
60440
|
+
var import_node_os5, import_node_child_process3, import_node_util, startedAt, cachedVersion, execFileAsync, CLI_CACHE_MS, cachedClaude, claudeCachedAt, claudeRefreshInFlight, cachedCodex, codexCachedAt, codexRefreshInFlight;
|
|
60258
60441
|
var init_status = __esm({
|
|
60259
60442
|
"src/server/routes/status.ts"() {
|
|
60260
60443
|
"use strict";
|
|
60261
60444
|
import_node_os5 = __toESM(require("node:os"));
|
|
60262
|
-
|
|
60445
|
+
import_node_child_process3 = require("node:child_process");
|
|
60263
60446
|
import_node_util = require("node:util");
|
|
60264
60447
|
init_db2();
|
|
60265
60448
|
init_updateChecker();
|
|
@@ -60267,7 +60450,7 @@ var init_status = __esm({
|
|
|
60267
60450
|
init_auth();
|
|
60268
60451
|
startedAt = Date.now();
|
|
60269
60452
|
cachedVersion = null;
|
|
60270
|
-
execFileAsync = (0, import_node_util.promisify)(
|
|
60453
|
+
execFileAsync = (0, import_node_util.promisify)(import_node_child_process3.execFile);
|
|
60271
60454
|
CLI_CACHE_MS = 3e4;
|
|
60272
60455
|
cachedClaude = { available: false };
|
|
60273
60456
|
claudeCachedAt = 0;
|
|
@@ -60898,8 +61081,8 @@ function nowIso() {
|
|
|
60898
61081
|
return (/* @__PURE__ */ new Date()).toISOString();
|
|
60899
61082
|
}
|
|
60900
61083
|
function getProviderCommand(provider) {
|
|
60901
|
-
|
|
60902
|
-
return { command:
|
|
61084
|
+
const command2 = getProviderCliCommand(provider);
|
|
61085
|
+
return { command: command2, args: ["login"] };
|
|
60903
61086
|
}
|
|
60904
61087
|
function isActiveStatus(status2) {
|
|
60905
61088
|
return status2 === "starting" || status2 === "running";
|
|
@@ -61100,7 +61283,7 @@ function startProviderAuthSession(provider) {
|
|
|
61100
61283
|
}
|
|
61101
61284
|
const cmd = getProviderCommand(provider);
|
|
61102
61285
|
const displayCommand = [cmd.command, ...cmd.args].join(" ");
|
|
61103
|
-
const child = (0,
|
|
61286
|
+
const child = (0, import_node_child_process4.spawn)(cmd.command, cmd.args, {
|
|
61104
61287
|
stdio: ["pipe", "pipe", "pipe"],
|
|
61105
61288
|
env: { ...process.env, CI: "1", FORCE_COLOR: "0" }
|
|
61106
61289
|
});
|
|
@@ -61170,13 +61353,14 @@ function startProviderAuthSession(provider) {
|
|
|
61170
61353
|
});
|
|
61171
61354
|
return { session: toSessionView(session, true), reused: false };
|
|
61172
61355
|
}
|
|
61173
|
-
var
|
|
61356
|
+
var import_node_child_process4, import_node_crypto9, sessionStore, activeByProvider, MAX_LINES, SESSION_TIMEOUT_MS, SESSION_TTL_MS;
|
|
61174
61357
|
var init_provider_auth = __esm({
|
|
61175
61358
|
"src/server/provider-auth.ts"() {
|
|
61176
61359
|
"use strict";
|
|
61177
|
-
|
|
61360
|
+
import_node_child_process4 = require("node:child_process");
|
|
61178
61361
|
import_node_crypto9 = require("node:crypto");
|
|
61179
61362
|
init_event_bus();
|
|
61363
|
+
init_provider_cli();
|
|
61180
61364
|
sessionStore = /* @__PURE__ */ new Map();
|
|
61181
61365
|
activeByProvider = /* @__PURE__ */ new Map();
|
|
61182
61366
|
MAX_LINES = Math.max(50, parseInt(process.env.QUOROOM_PROVIDER_AUTH_MAX_LINES || "300", 10) || 300);
|
|
@@ -61185,55 +61369,6 @@ var init_provider_auth = __esm({
|
|
|
61185
61369
|
}
|
|
61186
61370
|
});
|
|
61187
61371
|
|
|
61188
|
-
// src/server/provider-cli.ts
|
|
61189
|
-
function safeExec(cmd, args2) {
|
|
61190
|
-
try {
|
|
61191
|
-
const stdout = (0, import_node_child_process4.execFileSync)(cmd, args2, { timeout: CLI_PROBE_TIMEOUT_MS, stdio: ["ignore", "pipe", "pipe"] }).toString().trim();
|
|
61192
|
-
return { ok: true, stdout, stderr: "" };
|
|
61193
|
-
} catch (err) {
|
|
61194
|
-
const e = err;
|
|
61195
|
-
return {
|
|
61196
|
-
ok: false,
|
|
61197
|
-
stdout: e.stdout?.toString().trim() ?? "",
|
|
61198
|
-
stderr: e.stderr?.toString().trim() || e.message || ""
|
|
61199
|
-
};
|
|
61200
|
-
}
|
|
61201
|
-
}
|
|
61202
|
-
function probeProviderInstalled(provider) {
|
|
61203
|
-
const out = safeExec(provider, ["--version"]);
|
|
61204
|
-
return out.ok ? { installed: true, version: out.stdout || void 0 } : { installed: false };
|
|
61205
|
-
}
|
|
61206
|
-
function probeProviderConnected(provider) {
|
|
61207
|
-
if (provider === "claude") {
|
|
61208
|
-
return probeProviderInstalled("claude").installed ? true : null;
|
|
61209
|
-
}
|
|
61210
|
-
const attempts = provider === "codex" ? [["login", "status"], ["auth", "status"]] : [["auth", "status"], ["login", "status"]];
|
|
61211
|
-
for (const args2 of attempts) {
|
|
61212
|
-
const out = safeExec(provider, args2);
|
|
61213
|
-
if (!out.ok) continue;
|
|
61214
|
-
const combined = `${out.stdout}
|
|
61215
|
-
${out.stderr}`.toLowerCase();
|
|
61216
|
-
if (combined.includes("not logged") || combined.includes("logged out") || combined.includes("unauth")) return false;
|
|
61217
|
-
return true;
|
|
61218
|
-
}
|
|
61219
|
-
return null;
|
|
61220
|
-
}
|
|
61221
|
-
function disconnectProvider(provider) {
|
|
61222
|
-
const args2 = ["logout"];
|
|
61223
|
-
return {
|
|
61224
|
-
command: `${provider} ${args2.join(" ")}`,
|
|
61225
|
-
result: safeExec(provider, args2)
|
|
61226
|
-
};
|
|
61227
|
-
}
|
|
61228
|
-
var import_node_child_process4, CLI_PROBE_TIMEOUT_MS;
|
|
61229
|
-
var init_provider_cli = __esm({
|
|
61230
|
-
"src/server/provider-cli.ts"() {
|
|
61231
|
-
"use strict";
|
|
61232
|
-
import_node_child_process4 = require("node:child_process");
|
|
61233
|
-
CLI_PROBE_TIMEOUT_MS = 1500;
|
|
61234
|
-
}
|
|
61235
|
-
});
|
|
61236
|
-
|
|
61237
61372
|
// src/server/provider-install.ts
|
|
61238
61373
|
function nowIso2() {
|
|
61239
61374
|
return (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -66447,7 +66582,7 @@ __export(update_exports, {
|
|
|
66447
66582
|
});
|
|
66448
66583
|
function getCurrentVersion2() {
|
|
66449
66584
|
try {
|
|
66450
|
-
return true ? "0.1.
|
|
66585
|
+
return true ? "0.1.26" : null.version;
|
|
66451
66586
|
} catch {
|
|
66452
66587
|
return "0.0.0";
|
|
66453
66588
|
}
|
package/out/mcp/server.js
CHANGED
|
@@ -49147,7 +49147,7 @@ init_db();
|
|
|
49147
49147
|
async function main() {
|
|
49148
49148
|
const server = new McpServer({
|
|
49149
49149
|
name: "quoroom",
|
|
49150
|
-
version: true ? "0.1.
|
|
49150
|
+
version: true ? "0.1.26" : "0.0.0"
|
|
49151
49151
|
});
|
|
49152
49152
|
registerMemoryTools(server);
|
|
49153
49153
|
registerSchedulerTools(server);
|