@rubytech/create-realagent 1.0.435 → 1.0.436
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/uninstall.js +44 -26
- package/package.json +1 -1
- package/payload/maxy/server.js +160 -44
- package/payload/platform/plugins/admin/mcp/dist/index.js +379 -10
- package/payload/platform/plugins/admin/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/admin/skills/onboarding/skill.md +1 -1
- package/payload/platform/plugins/admin/skills/plugin-management/skill.md +16 -58
- package/payload/platform/plugins/anthropic/PLUGIN.md +2 -2
- package/payload/platform/plugins/email/mcp/dist/scripts/email-auto-respond.d.ts +1 -1
- package/payload/platform/plugins/email/mcp/dist/scripts/email-auto-respond.js +30 -4
- package/payload/platform/plugins/email/mcp/dist/scripts/email-auto-respond.js.map +1 -1
- package/payload/platform/plugins/email/mcp/dist/scripts/email-fetch.js +31 -3
- package/payload/platform/plugins/email/mcp/dist/scripts/email-fetch.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/check-due-events.d.ts +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/check-due-events.js +30 -2
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/check-due-events.js.map +1 -1
- package/payload/platform/templates/agents/admin/IDENTITY.md +1 -1
package/dist/uninstall.js
CHANGED
|
@@ -4,12 +4,29 @@ import { resolve, join } from "node:path";
|
|
|
4
4
|
import { homedir } from "node:os";
|
|
5
5
|
import { createInterface } from "node:readline";
|
|
6
6
|
const HOME = homedir();
|
|
7
|
-
const
|
|
8
|
-
|
|
7
|
+
const PAYLOAD_DIR = resolve(import.meta.dirname, "../payload");
|
|
8
|
+
// Brand manifest — read from payload to derive brand-specific installation paths.
|
|
9
|
+
// No fallback: if brand.json is missing, the package is corrupted.
|
|
10
|
+
const BRAND_PATH = join(PAYLOAD_DIR, "platform", "config", "brand.json");
|
|
11
|
+
if (!existsSync(BRAND_PATH)) {
|
|
12
|
+
console.error("FATAL: brand.json not found in payload. Package may be corrupted.");
|
|
13
|
+
process.exit(1);
|
|
14
|
+
}
|
|
15
|
+
let BRAND;
|
|
16
|
+
try {
|
|
17
|
+
BRAND = JSON.parse(readFileSync(BRAND_PATH, "utf-8"));
|
|
18
|
+
}
|
|
19
|
+
catch (err) {
|
|
20
|
+
console.error(`FATAL: Failed to parse brand.json: ${err.message}`);
|
|
21
|
+
process.exit(1);
|
|
22
|
+
}
|
|
23
|
+
const INSTALL_DIR = resolve(HOME, BRAND.installDir);
|
|
24
|
+
const CONFIG_DIR = resolve(HOME, BRAND.configDir);
|
|
25
|
+
const LOG_FILE = join("/tmp", `${BRAND.productName.toLowerCase().replace(/\s+/g, "-")}-uninstall-${new Date().toISOString().replace(/[:.]/g, "-")}.log`);
|
|
9
26
|
const TOTAL = "10";
|
|
10
27
|
// ---------------------------------------------------------------------------
|
|
11
28
|
// Logging — timestamped to console AND persistent log file in /tmp
|
|
12
|
-
// (Log lives in /tmp because the uninstall deletes
|
|
29
|
+
// (Log lives in /tmp because the uninstall deletes the config directory)
|
|
13
30
|
// ---------------------------------------------------------------------------
|
|
14
31
|
function logFile(msg) {
|
|
15
32
|
try {
|
|
@@ -67,13 +84,13 @@ export function isMaxyInstalled() {
|
|
|
67
84
|
// ---------------------------------------------------------------------------
|
|
68
85
|
function stopServices() {
|
|
69
86
|
log("1", "Stopping services...");
|
|
70
|
-
// Stop
|
|
87
|
+
// Stop platform user service
|
|
71
88
|
try {
|
|
72
|
-
spawnSync("systemctl", ["--user", "stop", "
|
|
73
|
-
console.log(
|
|
89
|
+
spawnSync("systemctl", ["--user", "stop", BRAND.serviceName.replace(".service", "")], { stdio: "pipe", timeout: 15_000 });
|
|
90
|
+
console.log(` Stopped ${BRAND.serviceName}`);
|
|
74
91
|
}
|
|
75
92
|
catch {
|
|
76
|
-
console.log(
|
|
93
|
+
console.log(` ${BRAND.serviceName} not running`);
|
|
77
94
|
}
|
|
78
95
|
// Stop Neo4j
|
|
79
96
|
try {
|
|
@@ -210,7 +227,7 @@ export function exportData(exportPath) {
|
|
|
210
227
|
console.log(" neo4j-admin not found — skipping database export.");
|
|
211
228
|
}
|
|
212
229
|
// Copy account config
|
|
213
|
-
const accountsDir = resolve(
|
|
230
|
+
const accountsDir = resolve(CONFIG_DIR, "accounts");
|
|
214
231
|
if (existsSync(accountsDir)) {
|
|
215
232
|
try {
|
|
216
233
|
const dest = join(exportPath, "accounts");
|
|
@@ -222,11 +239,11 @@ export function exportData(exportPath) {
|
|
|
222
239
|
}
|
|
223
240
|
}
|
|
224
241
|
else {
|
|
225
|
-
console.log(
|
|
242
|
+
console.log(` No account config found at ${accountsDir}`);
|
|
226
243
|
}
|
|
227
244
|
// Copy secrets (password, API key) so a fresh install could reuse them
|
|
228
245
|
for (const file of [".neo4j-password", ".anthropic-api-key", ".admin-pin"]) {
|
|
229
|
-
const src = resolve(
|
|
246
|
+
const src = resolve(CONFIG_DIR, file);
|
|
230
247
|
if (existsSync(src)) {
|
|
231
248
|
try {
|
|
232
249
|
cpSync(src, join(exportPath, file));
|
|
@@ -243,8 +260,8 @@ export function exportData(exportPath) {
|
|
|
243
260
|
function removeAppDirs() {
|
|
244
261
|
log("4", "Removing application directories...");
|
|
245
262
|
const dirs = [
|
|
246
|
-
{ path:
|
|
247
|
-
{ path:
|
|
263
|
+
{ path: INSTALL_DIR, label: `~/${BRAND.installDir}` },
|
|
264
|
+
{ path: CONFIG_DIR, label: `~/${BRAND.configDir}` },
|
|
248
265
|
{ path: resolve(HOME, ".cloudflared"), label: "~/.cloudflared" },
|
|
249
266
|
{ path: resolve(HOME, ".claude"), label: "~/.claude" },
|
|
250
267
|
{ path: resolve(HOME, ".ollama"), label: "~/.ollama" },
|
|
@@ -336,8 +353,8 @@ function removeSystemConfig() {
|
|
|
336
353
|
return;
|
|
337
354
|
}
|
|
338
355
|
const files = [
|
|
339
|
-
{ path:
|
|
340
|
-
{ path:
|
|
356
|
+
{ path: `/etc/avahi/services/${BRAND.hostname}.service`, label: "Avahi mDNS service" },
|
|
357
|
+
{ path: `/etc/NetworkManager/conf.d/${BRAND.hostname}-no-powersave.conf`, label: "WiFi power save config" },
|
|
341
358
|
{ path: "/etc/apt/sources.list.d/neo4j.list", label: "Neo4j apt repository" },
|
|
342
359
|
{ path: "/usr/share/keyrings/neo4j.gpg", label: "Neo4j GPG key" },
|
|
343
360
|
];
|
|
@@ -364,16 +381,17 @@ function removeSystemConfig() {
|
|
|
364
381
|
function removeSystemdService() {
|
|
365
382
|
log("8", "Removing systemd service...");
|
|
366
383
|
// Disable the service
|
|
384
|
+
const svcUnit = BRAND.serviceName.replace(".service", "");
|
|
367
385
|
try {
|
|
368
|
-
spawnSync("systemctl", ["--user", "disable",
|
|
386
|
+
spawnSync("systemctl", ["--user", "disable", svcUnit], { stdio: "pipe" });
|
|
369
387
|
}
|
|
370
388
|
catch { /* already disabled or missing */ }
|
|
371
389
|
// Remove service file
|
|
372
|
-
const serviceFile = resolve(HOME,
|
|
390
|
+
const serviceFile = resolve(HOME, `.config/systemd/user/${BRAND.serviceName}`);
|
|
373
391
|
if (existsSync(serviceFile)) {
|
|
374
392
|
try {
|
|
375
393
|
rmSync(serviceFile);
|
|
376
|
-
console.log(
|
|
394
|
+
console.log(` Removed ${BRAND.serviceName}`);
|
|
377
395
|
}
|
|
378
396
|
catch (err) {
|
|
379
397
|
console.log(` Failed to remove service file: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -440,8 +458,8 @@ function restoreHostname() {
|
|
|
440
458
|
}
|
|
441
459
|
try {
|
|
442
460
|
const hostname = execFileSync("hostname", [], { encoding: "utf-8" }).trim();
|
|
443
|
-
if (hostname !==
|
|
444
|
-
console.log(` Hostname is '${hostname}' — not '
|
|
461
|
+
if (hostname !== BRAND.hostname) {
|
|
462
|
+
console.log(` Hostname is '${hostname}' — not '${BRAND.hostname}', nothing to restore.`);
|
|
445
463
|
return;
|
|
446
464
|
}
|
|
447
465
|
// The installer doesn't save the original hostname, so we use a sensible default
|
|
@@ -461,14 +479,14 @@ function showRemovalSummary() {
|
|
|
461
479
|
console.log("");
|
|
462
480
|
console.log("The following will be removed:");
|
|
463
481
|
console.log("");
|
|
464
|
-
console.log(
|
|
465
|
-
console.log(
|
|
482
|
+
console.log(` Services: ${BRAND.serviceName}, Neo4j, cloudflared, VNC, Ollama`);
|
|
483
|
+
console.log(` App dirs: ~/${BRAND.installDir}/, ~/${BRAND.configDir}/, ~/.claude/, ~/.cloudflared/, ~/.ollama/`);
|
|
466
484
|
console.log(" Database: Neo4j data and transaction logs");
|
|
467
485
|
console.log(" Packages: neo4j, openjdk-17, tigervnc, websockify, novnc, cloudflared");
|
|
468
486
|
console.log(" Config: avahi service, WiFi power save, apt repos, GPG keys");
|
|
469
|
-
console.log(
|
|
487
|
+
console.log(` Systemd: ${BRAND.serviceName} unit file, user lingering`);
|
|
470
488
|
console.log(" Ollama: binary and models");
|
|
471
|
-
console.log(
|
|
489
|
+
console.log(` Hostname: restored from '${BRAND.hostname}' to 'raspberrypi'`);
|
|
472
490
|
console.log(" Cloudflare: tunnel and DNS records deleted from Cloudflare's edge");
|
|
473
491
|
console.log("");
|
|
474
492
|
console.log(" Node.js and shared system utilities (curl, git, etc.) are NOT removed.");
|
|
@@ -492,13 +510,13 @@ async function confirmUninstall() {
|
|
|
492
510
|
export async function runUninstall(options) {
|
|
493
511
|
const PKG_VERSION = JSON.parse(readFileSync(resolve(import.meta.dirname, "../package.json"), "utf-8")).version;
|
|
494
512
|
console.log("================================================================");
|
|
495
|
-
console.log(`
|
|
513
|
+
console.log(` ${BRAND.productName} Uninstall (create-maxy v${PKG_VERSION})`);
|
|
496
514
|
console.log("================================================================");
|
|
497
515
|
console.log(` Log: ${LOG_FILE}`);
|
|
498
516
|
console.log("");
|
|
499
517
|
// Check if Maxy is installed
|
|
500
518
|
if (!isMaxyInstalled()) {
|
|
501
|
-
console.error(
|
|
519
|
+
console.error(`${BRAND.productName} is not installed (~/${BRAND.installDir} not found). Nothing to uninstall.`);
|
|
502
520
|
process.exit(1);
|
|
503
521
|
}
|
|
504
522
|
// Show what will be removed
|
|
@@ -546,7 +564,7 @@ export async function runUninstall(options) {
|
|
|
546
564
|
console.log("================================================================");
|
|
547
565
|
if (failures.length === 0) {
|
|
548
566
|
console.log("");
|
|
549
|
-
console.log(
|
|
567
|
+
console.log(` ${BRAND.productName} has been completely removed.`);
|
|
550
568
|
console.log("");
|
|
551
569
|
console.log(" To reinstall: npx -y @rubytech/create-maxy");
|
|
552
570
|
}
|
package/package.json
CHANGED
package/payload/maxy/server.js
CHANGED
|
@@ -3128,7 +3128,7 @@ async function GET() {
|
|
|
3128
3128
|
|
|
3129
3129
|
// app/lib/claude-agent.ts
|
|
3130
3130
|
import Anthropic from "@anthropic-ai/sdk";
|
|
3131
|
-
import { spawn } from "child_process";
|
|
3131
|
+
import { spawn as spawn2 } from "child_process";
|
|
3132
3132
|
import { resolve as resolve4 } from "path";
|
|
3133
3133
|
import { readFileSync as readFileSync5, readdirSync, existsSync as existsSync5, mkdirSync as mkdirSync2, createWriteStream, statSync as statSync2, unlinkSync } from "fs";
|
|
3134
3134
|
|
|
@@ -3267,6 +3267,7 @@ function buildX11Env(chromiumWrapperPath) {
|
|
|
3267
3267
|
// app/lib/neo4j-store.ts
|
|
3268
3268
|
import neo4j from "neo4j-driver";
|
|
3269
3269
|
import { randomUUID } from "crypto";
|
|
3270
|
+
import { spawn } from "child_process";
|
|
3270
3271
|
import { readFileSync as readFileSync4 } from "fs";
|
|
3271
3272
|
import { resolve as resolve3 } from "path";
|
|
3272
3273
|
var PLATFORM_ROOT2 = process.env.MAXY_PLATFORM_ROOT ?? resolve3(process.cwd(), "..");
|
|
@@ -3620,47 +3621,162 @@ async function deleteConversation(conversationId) {
|
|
|
3620
3621
|
}
|
|
3621
3622
|
}
|
|
3622
3623
|
var GENERIC_MESSAGE = /^(h(i|ello|ey|owdy)|yo|sup|thanks|thank you|ok|okay|yes|no|good\s*(morning|afternoon|evening|night)|greetings|what'?s\s*up)[\s!?.,:;]*$/i;
|
|
3623
|
-
|
|
3624
|
+
var SESSION_LABEL_MSG_CAP = 500;
|
|
3625
|
+
var SESSION_LABEL_TIMEOUT_MS = 15e3;
|
|
3626
|
+
var SESSION_LABEL_MODEL = "claude-haiku-4-5-20251001";
|
|
3627
|
+
var SESSION_LABEL_MAX_WORDS = 6;
|
|
3628
|
+
var SESSION_LABEL_MAX_ATTEMPTS = 3;
|
|
3629
|
+
var SESSION_LABEL_MAX_STDERR = 2048;
|
|
3630
|
+
function isMessageUseful(message) {
|
|
3624
3631
|
const trimmed = message.trim();
|
|
3625
|
-
if (trimmed.length < 4) return
|
|
3626
|
-
if (
|
|
3627
|
-
if (
|
|
3628
|
-
|
|
3629
|
-
|
|
3630
|
-
|
|
3631
|
-
|
|
3632
|
+
if (trimmed.length < 4) return false;
|
|
3633
|
+
if (trimmed.startsWith('{"')) return false;
|
|
3634
|
+
if (GENERIC_MESSAGE.test(trimmed)) return false;
|
|
3635
|
+
if (trimmed.startsWith("[New session.")) return false;
|
|
3636
|
+
return true;
|
|
3637
|
+
}
|
|
3638
|
+
var labelAccumulator = /* @__PURE__ */ new Map();
|
|
3639
|
+
var _spawnOverride = null;
|
|
3640
|
+
var SESSION_LABEL_SYSTEM = `You are a session labeler. Given the opening messages of a conversation with an AI assistant, produce a concise topic label.
|
|
3641
|
+
|
|
3642
|
+
Rules:
|
|
3643
|
+
- Exactly 3 to 6 words
|
|
3644
|
+
- Summarize the user's intent, do not copy verbatim
|
|
3645
|
+
- Capitalize the first word only (sentence case)
|
|
3646
|
+
- No punctuation, no quotes
|
|
3647
|
+
- If the messages are too vague or meaningless to summarize, respond with exactly: SKIP`;
|
|
3648
|
+
async function generateSessionLabel(messages) {
|
|
3649
|
+
const cappedMessages = messages.map((m) => m.slice(0, SESSION_LABEL_MSG_CAP));
|
|
3650
|
+
const userContent = cappedMessages.map((m, i) => `Message ${i + 1}: ${m}`).join("\n");
|
|
3651
|
+
const prompt = `${SESSION_LABEL_SYSTEM}
|
|
3652
|
+
|
|
3653
|
+
${userContent}`;
|
|
3654
|
+
const args = [
|
|
3655
|
+
"--print",
|
|
3656
|
+
"--model",
|
|
3657
|
+
SESSION_LABEL_MODEL,
|
|
3658
|
+
"--max-turns",
|
|
3659
|
+
"1",
|
|
3660
|
+
"--permission-mode",
|
|
3661
|
+
"dontAsk",
|
|
3662
|
+
prompt
|
|
3663
|
+
];
|
|
3664
|
+
return new Promise((resolve16) => {
|
|
3665
|
+
let stdout = "";
|
|
3666
|
+
let stderr = "";
|
|
3667
|
+
const spawnFn = _spawnOverride ?? spawn;
|
|
3668
|
+
const proc = spawnFn("claude", args, {
|
|
3669
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
3670
|
+
});
|
|
3671
|
+
proc.stdout?.on("data", (chunk) => {
|
|
3672
|
+
stdout += chunk.toString("utf-8");
|
|
3673
|
+
});
|
|
3674
|
+
proc.stderr?.on("data", (chunk) => {
|
|
3675
|
+
if (stderr.length < SESSION_LABEL_MAX_STDERR) {
|
|
3676
|
+
stderr += chunk.toString("utf-8").slice(0, SESSION_LABEL_MAX_STDERR - stderr.length);
|
|
3677
|
+
}
|
|
3678
|
+
});
|
|
3679
|
+
const timer = setTimeout(() => {
|
|
3680
|
+
proc.kill("SIGTERM");
|
|
3681
|
+
console.error("[persist] autoLabel: haiku subprocess timed out");
|
|
3682
|
+
resolve16(null);
|
|
3683
|
+
}, SESSION_LABEL_TIMEOUT_MS);
|
|
3684
|
+
proc.on("error", (err) => {
|
|
3685
|
+
clearTimeout(timer);
|
|
3686
|
+
console.error(`[persist] autoLabel: subprocess error \u2014 ${err.message}`);
|
|
3687
|
+
resolve16(null);
|
|
3688
|
+
});
|
|
3689
|
+
proc.on("close", (code) => {
|
|
3690
|
+
clearTimeout(timer);
|
|
3691
|
+
if (code !== 0) {
|
|
3692
|
+
console.error(`[persist] autoLabel: subprocess exited code=${code}${stderr ? ` stderr=${stderr.trim().slice(0, 200)}` : ""}`);
|
|
3693
|
+
resolve16(null);
|
|
3694
|
+
return;
|
|
3695
|
+
}
|
|
3696
|
+
const text = stdout.trim();
|
|
3697
|
+
if (!text) {
|
|
3698
|
+
console.error("[persist] autoLabel: haiku returned empty response");
|
|
3699
|
+
resolve16(null);
|
|
3700
|
+
return;
|
|
3701
|
+
}
|
|
3702
|
+
if (text === "SKIP") {
|
|
3703
|
+
console.error("[persist] autoLabel: haiku returned SKIP \u2014 messages too vague");
|
|
3704
|
+
resolve16(null);
|
|
3705
|
+
return;
|
|
3706
|
+
}
|
|
3707
|
+
const words = text.split(/\s+/).slice(0, SESSION_LABEL_MAX_WORDS);
|
|
3708
|
+
const label = words.join(" ");
|
|
3709
|
+
console.error(`[persist] autoLabel: haiku response="${label}"`);
|
|
3710
|
+
resolve16(label);
|
|
3711
|
+
});
|
|
3712
|
+
});
|
|
3632
3713
|
}
|
|
3633
3714
|
async function autoLabelSession(conversationId, userMessage) {
|
|
3634
|
-
|
|
3635
|
-
if (!
|
|
3636
|
-
|
|
3637
|
-
|
|
3638
|
-
|
|
3639
|
-
} catch (err) {
|
|
3640
|
-
console.error(`[persist] Conversation embedding failed, labelling without: ${err instanceof Error ? err.message : String(err)}`);
|
|
3715
|
+
if (!conversationId) return;
|
|
3716
|
+
if (!isMessageUseful(userMessage)) {
|
|
3717
|
+
const reason = userMessage.trim().startsWith('{"') ? "JSON envelope" : userMessage.trim().length < 4 ? "too short" : GENERIC_MESSAGE.test(userMessage.trim()) ? "greeting" : "directive";
|
|
3718
|
+
console.error(`[persist] autoLabel: skipped ${conversationId.slice(0, 8)}\u2026 \u2014 ${reason}`);
|
|
3719
|
+
return;
|
|
3641
3720
|
}
|
|
3642
|
-
|
|
3721
|
+
let entry = labelAccumulator.get(conversationId);
|
|
3722
|
+
if (!entry) {
|
|
3723
|
+
entry = { messages: [], pending: false, attempts: 0 };
|
|
3724
|
+
labelAccumulator.set(conversationId, entry);
|
|
3725
|
+
}
|
|
3726
|
+
if (entry.attempts >= SESSION_LABEL_MAX_ATTEMPTS) {
|
|
3727
|
+
console.error(`[persist] autoLabel: evicted ${conversationId.slice(0, 8)}\u2026 after ${SESSION_LABEL_MAX_ATTEMPTS} attempts`);
|
|
3728
|
+
labelAccumulator.delete(conversationId);
|
|
3729
|
+
return;
|
|
3730
|
+
}
|
|
3731
|
+
entry.messages.push(userMessage.trim());
|
|
3732
|
+
if (entry.pending) {
|
|
3733
|
+
console.error(`[persist] autoLabel: accumulated for ${conversationId.slice(0, 8)}\u2026 (pending, ${entry.messages.length} msgs)`);
|
|
3734
|
+
return;
|
|
3735
|
+
}
|
|
3736
|
+
entry.pending = true;
|
|
3737
|
+
entry.attempts++;
|
|
3643
3738
|
try {
|
|
3644
|
-
const
|
|
3645
|
-
|
|
3646
|
-
|
|
3647
|
-
|
|
3648
|
-
|
|
3649
|
-
|
|
3650
|
-
|
|
3651
|
-
|
|
3652
|
-
|
|
3653
|
-
|
|
3654
|
-
|
|
3655
|
-
|
|
3656
|
-
);
|
|
3657
|
-
|
|
3658
|
-
|
|
3739
|
+
const label = await generateSessionLabel(entry.messages);
|
|
3740
|
+
if (!label) {
|
|
3741
|
+
entry.pending = false;
|
|
3742
|
+
return;
|
|
3743
|
+
}
|
|
3744
|
+
const fullLabel = `${label} \xB7 ${conversationId.slice(0, 8)}`;
|
|
3745
|
+
let embedding = null;
|
|
3746
|
+
try {
|
|
3747
|
+
embedding = await embed(fullLabel);
|
|
3748
|
+
} catch (err) {
|
|
3749
|
+
console.error(`[persist] Conversation embedding failed, labelling without: ${err instanceof Error ? err.message : String(err)}`);
|
|
3750
|
+
}
|
|
3751
|
+
const session = getSession();
|
|
3752
|
+
try {
|
|
3753
|
+
const result = await session.run(
|
|
3754
|
+
`MATCH (c:Conversation {conversationId: $conversationId})
|
|
3755
|
+
WHERE c.name IS NULL
|
|
3756
|
+
WITH c
|
|
3757
|
+
OPTIONAL MATCH (m:Message)-[:PART_OF]->(c)
|
|
3758
|
+
WHERE m.role = 'user'
|
|
3759
|
+
WITH c, count(m) AS userCount
|
|
3760
|
+
WHERE userCount <= 3
|
|
3761
|
+
SET c.name = $label, c.updatedAt = datetime()
|
|
3762
|
+
${embedding ? ", c.embedding = $embedding" : ""}
|
|
3763
|
+
RETURN c.name AS name`,
|
|
3764
|
+
{ conversationId, label: fullLabel, ...embedding ? { embedding } : {} }
|
|
3765
|
+
);
|
|
3766
|
+
if (result.records.length > 0) {
|
|
3767
|
+
console.error(`[persist] Auto-labeled session ${conversationId.slice(0, 8)}\u2026: "${fullLabel}"${embedding ? " (embedded)" : ""}`);
|
|
3768
|
+
labelAccumulator.delete(conversationId);
|
|
3769
|
+
}
|
|
3770
|
+
} catch (err) {
|
|
3771
|
+
console.error(`[persist] autoLabelSession failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
3772
|
+
} finally {
|
|
3773
|
+
await session.close();
|
|
3659
3774
|
}
|
|
3660
3775
|
} catch (err) {
|
|
3661
|
-
console.error(`[persist]
|
|
3776
|
+
console.error(`[persist] autoLabel: unexpected error \u2014 ${err instanceof Error ? err.message : String(err)}`);
|
|
3662
3777
|
} finally {
|
|
3663
|
-
|
|
3778
|
+
const currentEntry = labelAccumulator.get(conversationId);
|
|
3779
|
+
if (currentEntry) currentEntry.pending = false;
|
|
3664
3780
|
}
|
|
3665
3781
|
}
|
|
3666
3782
|
var INITIAL_CONFIDENCE = 0.5;
|
|
@@ -4552,7 +4668,7 @@ function fetchMcpToolsList(pluginDir) {
|
|
|
4552
4668
|
if (!existsSync5(serverPath)) return Promise.resolve([]);
|
|
4553
4669
|
const startMs = Date.now();
|
|
4554
4670
|
return new Promise((resolvePromise) => {
|
|
4555
|
-
const proc =
|
|
4671
|
+
const proc = spawn2(process.execPath, [serverPath], {
|
|
4556
4672
|
env: {
|
|
4557
4673
|
...process.env,
|
|
4558
4674
|
PLATFORM_ROOT: PLATFORM_ROOT3,
|
|
@@ -5190,7 +5306,7 @@ async function fetchMemoryContext(accountId, query, sessionKey, options) {
|
|
|
5190
5306
|
}
|
|
5191
5307
|
const startMs = Date.now();
|
|
5192
5308
|
return new Promise((resolve16) => {
|
|
5193
|
-
const proc =
|
|
5309
|
+
const proc = spawn2(process.execPath, [serverPath], {
|
|
5194
5310
|
env: {
|
|
5195
5311
|
...process.env,
|
|
5196
5312
|
ACCOUNT_ID: accountId,
|
|
@@ -5285,7 +5401,7 @@ async function compactTrimmedMessages(accountId, trimmedMessages) {
|
|
|
5285
5401
|
if (!existsSync5(serverPath)) return false;
|
|
5286
5402
|
const briefing = trimmedMessages.map((m) => `[${m.role.toUpperCase()}] ${m.content}`).join("\n\n");
|
|
5287
5403
|
return new Promise((resolvePromise) => {
|
|
5288
|
-
const proc =
|
|
5404
|
+
const proc = spawn2(process.execPath, [serverPath], {
|
|
5289
5405
|
env: { ...process.env, ACCOUNT_ID: accountId }
|
|
5290
5406
|
});
|
|
5291
5407
|
let buffer = "";
|
|
@@ -5710,7 +5826,7 @@ async function* runCompactionTurn(accountDir, accountId, systemPrompt, resumeSes
|
|
|
5710
5826
|
resumeSessionId,
|
|
5711
5827
|
COMPACTION_PROMPT
|
|
5712
5828
|
];
|
|
5713
|
-
const proc =
|
|
5829
|
+
const proc = spawn2("claude", args, {
|
|
5714
5830
|
cwd: accountDir,
|
|
5715
5831
|
stdio: ["ignore", "pipe", "pipe"],
|
|
5716
5832
|
env: { ...process.env, PLATFORM_ROOT: PLATFORM_ROOT3, ACCOUNT_DIR: accountDir }
|
|
@@ -6318,7 +6434,7 @@ async function* invokeAdminAgent(message, systemPrompt, accountDir, accountId, a
|
|
|
6318
6434
|
}
|
|
6319
6435
|
const fullMessage = attachments.length > 0 ? message + buildAttachmentMetaText(attachments) : message;
|
|
6320
6436
|
args.push(fullMessage);
|
|
6321
|
-
const proc =
|
|
6437
|
+
const proc = spawn2("claude", args, {
|
|
6322
6438
|
cwd: accountDir,
|
|
6323
6439
|
stdio: ["ignore", "pipe", "pipe"],
|
|
6324
6440
|
env: { ...process.env, PLATFORM_ROOT: PLATFORM_ROOT3, ACCOUNT_DIR: accountDir }
|
|
@@ -6567,7 +6683,7 @@ async function* invokeManagedAdminAgent(message, systemPrompt, accountDir, accou
|
|
|
6567
6683
|
specialistsDir,
|
|
6568
6684
|
fullMessage
|
|
6569
6685
|
];
|
|
6570
|
-
const proc =
|
|
6686
|
+
const proc = spawn2("claude", args, {
|
|
6571
6687
|
cwd: accountDir,
|
|
6572
6688
|
stdio: ["ignore", "pipe", "pipe"],
|
|
6573
6689
|
env: { ...process.env, PLATFORM_ROOT: PLATFORM_ROOT3, ACCOUNT_DIR: accountDir }
|
|
@@ -9074,7 +9190,7 @@ async function POST8(req) {
|
|
|
9074
9190
|
}
|
|
9075
9191
|
|
|
9076
9192
|
// app/api/onboarding/claude-auth/route.ts
|
|
9077
|
-
import { spawn as
|
|
9193
|
+
import { spawn as spawn3, execFileSync as execFileSync2 } from "child_process";
|
|
9078
9194
|
import { openSync, closeSync, writeFileSync as writeFileSync6, writeSync } from "fs";
|
|
9079
9195
|
function checkAuthStatus() {
|
|
9080
9196
|
try {
|
|
@@ -9141,7 +9257,7 @@ async function POST9(req) {
|
|
|
9141
9257
|
const chromiumWrapper = writeChromiumWrapper();
|
|
9142
9258
|
const x11Env = buildX11Env(chromiumWrapper);
|
|
9143
9259
|
const claudeAuthLogFd = openSync(logPath("claude-auth"), "a");
|
|
9144
|
-
const claudeProc =
|
|
9260
|
+
const claudeProc = spawn3("claude", ["auth", "login"], {
|
|
9145
9261
|
env: x11Env,
|
|
9146
9262
|
stdio: ["ignore", "pipe", "pipe"]
|
|
9147
9263
|
});
|
|
@@ -9799,7 +9915,7 @@ async function GET7() {
|
|
|
9799
9915
|
}
|
|
9800
9916
|
|
|
9801
9917
|
// app/api/admin/version/upgrade/route.ts
|
|
9802
|
-
import { spawn as
|
|
9918
|
+
import { spawn as spawn4 } from "child_process";
|
|
9803
9919
|
import { existsSync as existsSync16, statSync as statSync4, writeFileSync as writeFileSync9, readFileSync as readFileSync16, openSync as openSync2, closeSync as closeSync2 } from "fs";
|
|
9804
9920
|
import { resolve as resolve14, join as join4 } from "path";
|
|
9805
9921
|
var PLATFORM_ROOT7 = process.env.MAXY_PLATFORM_ROOT ?? resolve14(process.cwd(), "..");
|
|
@@ -9851,7 +9967,7 @@ async function POST14(req) {
|
|
|
9851
9967
|
invalidateVersionCache();
|
|
9852
9968
|
try {
|
|
9853
9969
|
const logFd = openSync2(LOG_FILE, "w");
|
|
9854
|
-
const child =
|
|
9970
|
+
const child = spawn4("npx", ["-y", `${upgradePkg}@latest`], {
|
|
9855
9971
|
detached: true,
|
|
9856
9972
|
stdio: ["ignore", logFd, logFd],
|
|
9857
9973
|
env: { ...process.env, npm_config_yes: "true" },
|