@rubytech/create-realagent 1.0.434 → 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/index.js +22 -1
- package/dist/uninstall.js +44 -26
- package/package.json +1 -1
- package/payload/maxy/server.js +204 -76
- 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/admin/skills/public-agent-manager/skill.md +20 -3
- package/payload/platform/plugins/anthropic/PLUGIN.md +2 -2
- package/payload/platform/plugins/cloudflare/mcp/dist/index.js +22 -12
- package/payload/platform/plugins/cloudflare/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/cloudflare/mcp/dist/lib/cloudflared.d.ts +9 -5
- package/payload/platform/plugins/cloudflare/mcp/dist/lib/cloudflared.d.ts.map +1 -1
- package/payload/platform/plugins/cloudflare/mcp/dist/lib/cloudflared.js +82 -31
- package/payload/platform/plugins/cloudflare/mcp/dist/lib/cloudflared.js.map +1 -1
- 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/scripts/resume-tunnel.sh +14 -1
- package/payload/platform/scripts/vnc.sh +14 -1
- package/payload/platform/templates/agents/admin/IDENTITY.md +1 -1
- package/payload/premium-plugins/real-agency/plugins/real-agency-teaching/PLUGIN.md +1 -2
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
|
|
|
@@ -3184,6 +3184,17 @@ async function ensureVnc() {
|
|
|
3184
3184
|
}
|
|
3185
3185
|
async function ensureCdp() {
|
|
3186
3186
|
if (await waitForPort(9222, 1e3)) return true;
|
|
3187
|
+
const xAlive = await waitForPort(5900, 1e3);
|
|
3188
|
+
if (!xAlive) {
|
|
3189
|
+
console.error("[ensureCdp] X server down on :5900 \u2014 escalating to full VNC restart");
|
|
3190
|
+
const vncOk = await ensureVnc();
|
|
3191
|
+
if (!vncOk) {
|
|
3192
|
+
console.error("[ensureCdp] Full VNC restart failed \u2014 browser-specialist degraded");
|
|
3193
|
+
return false;
|
|
3194
|
+
}
|
|
3195
|
+
return waitForPort(9222, 12e3);
|
|
3196
|
+
}
|
|
3197
|
+
console.error("[ensureCdp] X alive on :5900, restarting Chrome only");
|
|
3187
3198
|
try {
|
|
3188
3199
|
execFileSync("bash", [VNC_SCRIPT, "start-chrome"], { timeout: 2e4 });
|
|
3189
3200
|
} catch {
|
|
@@ -3256,6 +3267,7 @@ function buildX11Env(chromiumWrapperPath) {
|
|
|
3256
3267
|
// app/lib/neo4j-store.ts
|
|
3257
3268
|
import neo4j from "neo4j-driver";
|
|
3258
3269
|
import { randomUUID } from "crypto";
|
|
3270
|
+
import { spawn } from "child_process";
|
|
3259
3271
|
import { readFileSync as readFileSync4 } from "fs";
|
|
3260
3272
|
import { resolve as resolve3 } from "path";
|
|
3261
3273
|
var PLATFORM_ROOT2 = process.env.MAXY_PLATFORM_ROOT ?? resolve3(process.cwd(), "..");
|
|
@@ -3609,47 +3621,162 @@ async function deleteConversation(conversationId) {
|
|
|
3609
3621
|
}
|
|
3610
3622
|
}
|
|
3611
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;
|
|
3612
|
-
|
|
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) {
|
|
3613
3631
|
const trimmed = message.trim();
|
|
3614
|
-
if (trimmed.length < 4) return
|
|
3615
|
-
if (
|
|
3616
|
-
if (
|
|
3617
|
-
|
|
3618
|
-
|
|
3619
|
-
|
|
3620
|
-
|
|
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
|
+
});
|
|
3621
3713
|
}
|
|
3622
3714
|
async function autoLabelSession(conversationId, userMessage) {
|
|
3623
|
-
|
|
3624
|
-
if (!
|
|
3625
|
-
|
|
3626
|
-
|
|
3627
|
-
|
|
3628
|
-
} catch (err) {
|
|
3629
|
-
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;
|
|
3630
3720
|
}
|
|
3631
|
-
|
|
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++;
|
|
3632
3738
|
try {
|
|
3633
|
-
const
|
|
3634
|
-
|
|
3635
|
-
|
|
3636
|
-
|
|
3637
|
-
|
|
3638
|
-
|
|
3639
|
-
|
|
3640
|
-
|
|
3641
|
-
|
|
3642
|
-
|
|
3643
|
-
|
|
3644
|
-
|
|
3645
|
-
);
|
|
3646
|
-
|
|
3647
|
-
|
|
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();
|
|
3648
3774
|
}
|
|
3649
3775
|
} catch (err) {
|
|
3650
|
-
console.error(`[persist]
|
|
3776
|
+
console.error(`[persist] autoLabel: unexpected error \u2014 ${err instanceof Error ? err.message : String(err)}`);
|
|
3651
3777
|
} finally {
|
|
3652
|
-
|
|
3778
|
+
const currentEntry = labelAccumulator.get(conversationId);
|
|
3779
|
+
if (currentEntry) currentEntry.pending = false;
|
|
3653
3780
|
}
|
|
3654
3781
|
}
|
|
3655
3782
|
var INITIAL_CONFIDENCE = 0.5;
|
|
@@ -4541,7 +4668,7 @@ function fetchMcpToolsList(pluginDir) {
|
|
|
4541
4668
|
if (!existsSync5(serverPath)) return Promise.resolve([]);
|
|
4542
4669
|
const startMs = Date.now();
|
|
4543
4670
|
return new Promise((resolvePromise) => {
|
|
4544
|
-
const proc =
|
|
4671
|
+
const proc = spawn2(process.execPath, [serverPath], {
|
|
4545
4672
|
env: {
|
|
4546
4673
|
...process.env,
|
|
4547
4674
|
PLATFORM_ROOT: PLATFORM_ROOT3,
|
|
@@ -5179,7 +5306,7 @@ async function fetchMemoryContext(accountId, query, sessionKey, options) {
|
|
|
5179
5306
|
}
|
|
5180
5307
|
const startMs = Date.now();
|
|
5181
5308
|
return new Promise((resolve16) => {
|
|
5182
|
-
const proc =
|
|
5309
|
+
const proc = spawn2(process.execPath, [serverPath], {
|
|
5183
5310
|
env: {
|
|
5184
5311
|
...process.env,
|
|
5185
5312
|
ACCOUNT_ID: accountId,
|
|
@@ -5274,7 +5401,7 @@ async function compactTrimmedMessages(accountId, trimmedMessages) {
|
|
|
5274
5401
|
if (!existsSync5(serverPath)) return false;
|
|
5275
5402
|
const briefing = trimmedMessages.map((m) => `[${m.role.toUpperCase()}] ${m.content}`).join("\n\n");
|
|
5276
5403
|
return new Promise((resolvePromise) => {
|
|
5277
|
-
const proc =
|
|
5404
|
+
const proc = spawn2(process.execPath, [serverPath], {
|
|
5278
5405
|
env: { ...process.env, ACCOUNT_ID: accountId }
|
|
5279
5406
|
});
|
|
5280
5407
|
let buffer = "";
|
|
@@ -5699,7 +5826,7 @@ async function* runCompactionTurn(accountDir, accountId, systemPrompt, resumeSes
|
|
|
5699
5826
|
resumeSessionId,
|
|
5700
5827
|
COMPACTION_PROMPT
|
|
5701
5828
|
];
|
|
5702
|
-
const proc =
|
|
5829
|
+
const proc = spawn2("claude", args, {
|
|
5703
5830
|
cwd: accountDir,
|
|
5704
5831
|
stdio: ["ignore", "pipe", "pipe"],
|
|
5705
5832
|
env: { ...process.env, PLATFORM_ROOT: PLATFORM_ROOT3, ACCOUNT_DIR: accountDir }
|
|
@@ -6271,7 +6398,13 @@ function buildAttachmentMetaText(attachments) {
|
|
|
6271
6398
|
async function* invokeAdminAgent(message, systemPrompt, accountDir, accountId, adminModel, sessionKey, maxTurns = 20, attachments = [], retryCount = 0, enabledPlugins) {
|
|
6272
6399
|
const userTimestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
6273
6400
|
const resumeSessionId = sessionKey ? getAgentSessionId(sessionKey) : void 0;
|
|
6274
|
-
await ensureCdp();
|
|
6401
|
+
const cdpOk = await ensureCdp();
|
|
6402
|
+
if (!cdpOk) {
|
|
6403
|
+
const cdpLog = agentLogStream("claude-agent-stream", accountDir);
|
|
6404
|
+
cdpLog.write(`[${isoTs()}] [warn] ensureCdp failed \u2014 browser-specialist degraded
|
|
6405
|
+
`);
|
|
6406
|
+
cdpLog.end();
|
|
6407
|
+
}
|
|
6275
6408
|
const mcpConfig = JSON.stringify({ mcpServers: getMcpServers(accountId, enabledPlugins) });
|
|
6276
6409
|
const specialistsDir = resolve4(accountDir, "specialists");
|
|
6277
6410
|
if (!existsSync5(specialistsDir)) agentLogStream("claude-agent-stream", accountDir).write(`[${isoTs()}] [warn] specialists plugin dir missing: ${specialistsDir}
|
|
@@ -6301,7 +6434,7 @@ async function* invokeAdminAgent(message, systemPrompt, accountDir, accountId, a
|
|
|
6301
6434
|
}
|
|
6302
6435
|
const fullMessage = attachments.length > 0 ? message + buildAttachmentMetaText(attachments) : message;
|
|
6303
6436
|
args.push(fullMessage);
|
|
6304
|
-
const proc =
|
|
6437
|
+
const proc = spawn2("claude", args, {
|
|
6305
6438
|
cwd: accountDir,
|
|
6306
6439
|
stdio: ["ignore", "pipe", "pipe"],
|
|
6307
6440
|
env: { ...process.env, PLATFORM_ROOT: PLATFORM_ROOT3, ACCOUNT_DIR: accountDir }
|
|
@@ -6521,7 +6654,9 @@ async function* invokeManagedAdminAgent(message, systemPrompt, accountDir, accou
|
|
|
6521
6654
|
}
|
|
6522
6655
|
const history = getMessageHistory(sessionKey);
|
|
6523
6656
|
const augmentedSystemPrompt = buildManagedSystemPrompt(systemPrompt, history);
|
|
6524
|
-
await ensureCdp();
|
|
6657
|
+
const cdpOk = await ensureCdp();
|
|
6658
|
+
if (!cdpOk) streamLog.write(`[${isoTs()}] [warn] ensureCdp failed \u2014 browser-specialist degraded
|
|
6659
|
+
`);
|
|
6525
6660
|
const mcpConfig = JSON.stringify({ mcpServers: getMcpServers(accountId, enabledPlugins) });
|
|
6526
6661
|
const specialistsDir = resolve4(accountDir, "specialists");
|
|
6527
6662
|
if (!existsSync5(specialistsDir)) streamLog.write(`[${isoTs()}] [warn] specialists plugin dir missing: ${specialistsDir}
|
|
@@ -6548,7 +6683,7 @@ async function* invokeManagedAdminAgent(message, systemPrompt, accountDir, accou
|
|
|
6548
6683
|
specialistsDir,
|
|
6549
6684
|
fullMessage
|
|
6550
6685
|
];
|
|
6551
|
-
const proc =
|
|
6686
|
+
const proc = spawn2("claude", args, {
|
|
6552
6687
|
cwd: accountDir,
|
|
6553
6688
|
stdio: ["ignore", "pipe", "pipe"],
|
|
6554
6689
|
env: { ...process.env, PLATFORM_ROOT: PLATFORM_ROOT3, ACCOUNT_DIR: accountDir }
|
|
@@ -7807,10 +7942,9 @@ function renderLoginPage(opts) {
|
|
|
7807
7942
|
const changeError = opts?.changeError ?? "";
|
|
7808
7943
|
const success = opts?.success ?? "";
|
|
7809
7944
|
const setupError = opts?.setupError ?? "";
|
|
7810
|
-
const
|
|
7811
|
-
const
|
|
7812
|
-
const
|
|
7813
|
-
const bodyFont = opts?.bodyFont ?? "DM Sans";
|
|
7945
|
+
const primaryColor = opts?.primaryColor ?? "#7C8C72";
|
|
7946
|
+
const primaryHoverColor = opts?.primaryHoverColor ?? "#6A7A62";
|
|
7947
|
+
const primarySubtle = opts?.primarySubtle ?? "rgba(124,140,114,0.08)";
|
|
7814
7948
|
const errorHtml = error ? `<p class="msg msg--error">${escapeHtml(error)}</p>` : "";
|
|
7815
7949
|
const changeErrorHtml = changeError ? `<p class="msg msg--error">${escapeHtml(changeError)}</p>` : "";
|
|
7816
7950
|
const successHtml = success ? `<p class="msg msg--success">${escapeHtml(success)}</p>` : "";
|
|
@@ -7834,14 +7968,14 @@ function renderLoginPage(opts) {
|
|
|
7834
7968
|
<head>
|
|
7835
7969
|
<meta charset="utf-8">
|
|
7836
7970
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
7837
|
-
<title>Sign in \u2014
|
|
7971
|
+
<title>Sign in \u2014 Maxy</title>
|
|
7838
7972
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
7839
7973
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
7840
|
-
<link href="https://fonts.googleapis.com/css2?family
|
|
7974
|
+
<link href="https://fonts.googleapis.com/css2?family=Cormorant:wght@300;400&family=DM+Sans:wght@400;500&display=swap" rel="stylesheet">
|
|
7841
7975
|
<style>
|
|
7842
7976
|
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
7843
7977
|
body {
|
|
7844
|
-
font-family: '
|
|
7978
|
+
font-family: 'DM Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
|
7845
7979
|
background: #FAFAF8;
|
|
7846
7980
|
color: #1A1A1A;
|
|
7847
7981
|
min-height: 100vh;
|
|
@@ -7865,7 +7999,7 @@ function renderLoginPage(opts) {
|
|
|
7865
7999
|
object-fit: contain;
|
|
7866
8000
|
}
|
|
7867
8001
|
.title {
|
|
7868
|
-
font-family: '
|
|
8002
|
+
font-family: 'Cormorant', Georgia, serif;
|
|
7869
8003
|
font-weight: 300;
|
|
7870
8004
|
font-size: 28px;
|
|
7871
8005
|
color: #1A1A1A;
|
|
@@ -7903,8 +8037,8 @@ function renderLoginPage(opts) {
|
|
|
7903
8037
|
transition: border-color 0.15s, box-shadow 0.15s;
|
|
7904
8038
|
}
|
|
7905
8039
|
.field-input:focus {
|
|
7906
|
-
border-color:
|
|
7907
|
-
box-shadow: 0 0 0 3px
|
|
8040
|
+
border-color: ${primaryColor};
|
|
8041
|
+
box-shadow: 0 0 0 3px ${primarySubtle};
|
|
7908
8042
|
}
|
|
7909
8043
|
.options {
|
|
7910
8044
|
display: flex;
|
|
@@ -7938,8 +8072,8 @@ function renderLoginPage(opts) {
|
|
|
7938
8072
|
flex-shrink: 0;
|
|
7939
8073
|
}
|
|
7940
8074
|
.check input:checked + .check-box {
|
|
7941
|
-
border-color:
|
|
7942
|
-
color:
|
|
8075
|
+
border-color: ${primaryColor};
|
|
8076
|
+
color: ${primaryColor};
|
|
7943
8077
|
}
|
|
7944
8078
|
.check-label {
|
|
7945
8079
|
font-size: 13px;
|
|
@@ -7964,7 +8098,7 @@ function renderLoginPage(opts) {
|
|
|
7964
8098
|
width: 100%;
|
|
7965
8099
|
padding: 12px;
|
|
7966
8100
|
margin-top: 16px;
|
|
7967
|
-
background:
|
|
8101
|
+
background: ${primaryColor};
|
|
7968
8102
|
color: #fff;
|
|
7969
8103
|
border: none;
|
|
7970
8104
|
border-radius: 10px;
|
|
@@ -7974,7 +8108,7 @@ function renderLoginPage(opts) {
|
|
|
7974
8108
|
cursor: pointer;
|
|
7975
8109
|
transition: background 0.15s;
|
|
7976
8110
|
}
|
|
7977
|
-
.btn:hover:not(:disabled) { background:
|
|
8111
|
+
.btn:hover:not(:disabled) { background: ${primaryHoverColor}; }
|
|
7978
8112
|
.btn:disabled { opacity: 0.5; cursor: not-allowed; }
|
|
7979
8113
|
|
|
7980
8114
|
/* Messages */
|
|
@@ -7984,7 +8118,7 @@ function renderLoginPage(opts) {
|
|
|
7984
8118
|
margin-top: 8px;
|
|
7985
8119
|
}
|
|
7986
8120
|
.msg--error { color: #c44; }
|
|
7987
|
-
.msg--success { color:
|
|
8121
|
+
.msg--success { color: ${primaryColor}; }
|
|
7988
8122
|
|
|
7989
8123
|
/* Strength checklist (setup mode) */
|
|
7990
8124
|
.strength-checklist { margin: 8px 0; }
|
|
@@ -8007,8 +8141,8 @@ function renderLoginPage(opts) {
|
|
|
8007
8141
|
</head>
|
|
8008
8142
|
<body>
|
|
8009
8143
|
<div class="page">
|
|
8010
|
-
<img src="
|
|
8011
|
-
<h1 class="title"
|
|
8144
|
+
<img src="/brand/maxy-monochrome.png" alt="Maxy" class="logo-img">
|
|
8145
|
+
<h1 class="title">Maxy</h1>
|
|
8012
8146
|
<p class="subtitle">${escapeHtml(subtitleText)}</p>
|
|
8013
8147
|
|
|
8014
8148
|
${successHtml}
|
|
@@ -8100,7 +8234,7 @@ function renderLoginPage(opts) {
|
|
|
8100
8234
|
<script>
|
|
8101
8235
|
(function() {
|
|
8102
8236
|
try {
|
|
8103
|
-
var ch = new BroadcastChannel('
|
|
8237
|
+
var ch = new BroadcastChannel('maxy-onboarding');
|
|
8104
8238
|
ch.postMessage({ type: 'remote-password-set' });
|
|
8105
8239
|
ch.close();
|
|
8106
8240
|
} catch(e) {}
|
|
@@ -8158,7 +8292,7 @@ function renderLoginPage(opts) {
|
|
|
8158
8292
|
var met = r.test(p);
|
|
8159
8293
|
if (!met) allMet = false;
|
|
8160
8294
|
el.querySelector('.strength-icon').textContent = met ? '\\u2713' : '\\u25CB';
|
|
8161
|
-
el.style.color = met ? '
|
|
8295
|
+
el.style.color = met ? '${primaryColor}' : '#6B6B6B';
|
|
8162
8296
|
});
|
|
8163
8297
|
var match = p.length > 0 && p === confirm.value;
|
|
8164
8298
|
btn.disabled = !(allMet && match);
|
|
@@ -9056,7 +9190,7 @@ async function POST8(req) {
|
|
|
9056
9190
|
}
|
|
9057
9191
|
|
|
9058
9192
|
// app/api/onboarding/claude-auth/route.ts
|
|
9059
|
-
import { spawn as
|
|
9193
|
+
import { spawn as spawn3, execFileSync as execFileSync2 } from "child_process";
|
|
9060
9194
|
import { openSync, closeSync, writeFileSync as writeFileSync6, writeSync } from "fs";
|
|
9061
9195
|
function checkAuthStatus() {
|
|
9062
9196
|
try {
|
|
@@ -9123,7 +9257,7 @@ async function POST9(req) {
|
|
|
9123
9257
|
const chromiumWrapper = writeChromiumWrapper();
|
|
9124
9258
|
const x11Env = buildX11Env(chromiumWrapper);
|
|
9125
9259
|
const claudeAuthLogFd = openSync(logPath("claude-auth"), "a");
|
|
9126
|
-
const claudeProc =
|
|
9260
|
+
const claudeProc = spawn3("claude", ["auth", "login"], {
|
|
9127
9261
|
env: x11Env,
|
|
9128
9262
|
stdio: ["ignore", "pipe", "pipe"]
|
|
9129
9263
|
});
|
|
@@ -9781,7 +9915,7 @@ async function GET7() {
|
|
|
9781
9915
|
}
|
|
9782
9916
|
|
|
9783
9917
|
// app/api/admin/version/upgrade/route.ts
|
|
9784
|
-
import { spawn as
|
|
9918
|
+
import { spawn as spawn4 } from "child_process";
|
|
9785
9919
|
import { existsSync as existsSync16, statSync as statSync4, writeFileSync as writeFileSync9, readFileSync as readFileSync16, openSync as openSync2, closeSync as closeSync2 } from "fs";
|
|
9786
9920
|
import { resolve as resolve14, join as join4 } from "path";
|
|
9787
9921
|
var PLATFORM_ROOT7 = process.env.MAXY_PLATFORM_ROOT ?? resolve14(process.cwd(), "..");
|
|
@@ -9833,7 +9967,7 @@ async function POST14(req) {
|
|
|
9833
9967
|
invalidateVersionCache();
|
|
9834
9968
|
try {
|
|
9835
9969
|
const logFd = openSync2(LOG_FILE, "w");
|
|
9836
|
-
const child =
|
|
9970
|
+
const child = spawn4("npx", ["-y", `${upgradePkg}@latest`], {
|
|
9837
9971
|
detached: true,
|
|
9838
9972
|
stdio: ["ignore", logFd, logFd],
|
|
9839
9973
|
env: { ...process.env, npm_config_yes: "true" },
|
|
@@ -9968,6 +10102,11 @@ if (BRAND_JSON_PATH && existsSync17(BRAND_JSON_PATH)) {
|
|
|
9968
10102
|
process.exit(1);
|
|
9969
10103
|
}
|
|
9970
10104
|
}
|
|
10105
|
+
var brandLoginOpts = {
|
|
10106
|
+
primaryColor: BRAND.defaultColors?.primary,
|
|
10107
|
+
primaryHoverColor: BRAND.defaultColors?.primaryHover,
|
|
10108
|
+
primarySubtle: BRAND.defaultColors?.primarySubtle
|
|
10109
|
+
};
|
|
9971
10110
|
var ALIAS_DOMAINS_PATH = join5(homedir2(), BRAND.configDir, "alias-domains.json");
|
|
9972
10111
|
function loadAliasDomains() {
|
|
9973
10112
|
try {
|
|
@@ -10302,24 +10441,13 @@ app.get(
|
|
|
10302
10441
|
);
|
|
10303
10442
|
var htmlCache = /* @__PURE__ */ new Map();
|
|
10304
10443
|
var brandLogoPath = "/brand/maxy-monochrome.png";
|
|
10305
|
-
var brandDisplayFont = "Cormorant";
|
|
10306
|
-
var brandBodyFont = "DM Sans";
|
|
10307
10444
|
if (BRAND_JSON_PATH && existsSync17(BRAND_JSON_PATH)) {
|
|
10308
10445
|
try {
|
|
10309
10446
|
const fullBrand = JSON.parse(readFileSync17(BRAND_JSON_PATH, "utf-8"));
|
|
10310
10447
|
if (fullBrand.assets?.logo) brandLogoPath = `/brand/${fullBrand.assets.logo}`;
|
|
10311
|
-
const extractFontName = (stack) => stack.split(",")[0].replace(/'/g, "").trim();
|
|
10312
|
-
if (fullBrand.defaultFonts?.display) brandDisplayFont = extractFontName(fullBrand.defaultFonts.display);
|
|
10313
|
-
if (fullBrand.defaultFonts?.body) brandBodyFont = extractFontName(fullBrand.defaultFonts.body);
|
|
10314
10448
|
} catch {
|
|
10315
10449
|
}
|
|
10316
10450
|
}
|
|
10317
|
-
var brandLoginOpts = {
|
|
10318
|
-
productName: BRAND.productName,
|
|
10319
|
-
logoSrc: brandLogoPath,
|
|
10320
|
-
displayFont: brandDisplayFont,
|
|
10321
|
-
bodyFont: brandBodyFont
|
|
10322
|
-
};
|
|
10323
10451
|
var brandScript = `<script>window.__BRAND__=${JSON.stringify({
|
|
10324
10452
|
productName: BRAND.productName,
|
|
10325
10453
|
hostname: BRAND.hostname,
|