@rubytech/create-maxy-code 0.1.307 → 0.1.308
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/package.json +1 -1
- package/payload/platform/lib/admin-access-password/__tests__/index.test.ts +114 -0
- package/payload/platform/lib/admin-access-password/dist/index.d.ts +40 -0
- package/payload/platform/lib/admin-access-password/dist/index.d.ts.map +1 -0
- package/payload/platform/lib/admin-access-password/dist/index.js +172 -0
- package/payload/platform/lib/admin-access-password/dist/index.js.map +1 -0
- package/payload/platform/lib/admin-access-password/src/index.ts +152 -0
- package/payload/platform/lib/admin-access-password/tsconfig.json +8 -0
- package/payload/platform/lib/models/dist/index.d.ts +6 -0
- package/payload/platform/lib/models/dist/index.d.ts.map +1 -1
- package/payload/platform/lib/models/dist/index.js +10 -1
- package/payload/platform/lib/models/dist/index.js.map +1 -1
- package/payload/platform/lib/models/src/index.ts +9 -0
- package/payload/platform/package.json +2 -2
- package/payload/platform/plugins/admin/PLUGIN.md +1 -0
- package/payload/platform/plugins/admin/mcp/dist/index.js +60 -19
- package/payload/platform/plugins/admin/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/admin/skills/admin-user-management/SKILL.md +8 -2
- package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +3 -3
- package/payload/platform/plugins/docs/references/admin-ui.md +1 -1
- package/payload/platform/plugins/docs/references/internals.md +1 -1
- package/payload/platform/scripts/check-no-esm-require.mjs +4 -0
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js +1 -0
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/http-server.d.ts +3 -0
- package/payload/platform/services/claude-session-manager/dist/http-server.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/http-server.js +182 -1
- package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts +12 -0
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.js +52 -1
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/session-sidecar.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/session-sidecar.js +9 -3
- package/payload/platform/services/claude-session-manager/dist/session-sidecar.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/webchat-channel-mcp.d.ts +8 -0
- package/payload/platform/services/claude-session-manager/dist/webchat-channel-mcp.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/webchat-channel-mcp.js +7 -0
- package/payload/platform/services/claude-session-manager/dist/webchat-channel-mcp.js.map +1 -1
- package/payload/platform/services/webchat-channel/dist/instructions.d.ts +8 -0
- package/payload/platform/services/webchat-channel/dist/instructions.d.ts.map +1 -0
- package/payload/platform/services/webchat-channel/dist/instructions.js +44 -0
- package/payload/platform/services/webchat-channel/dist/instructions.js.map +1 -0
- package/payload/platform/services/webchat-channel/dist/server.d.ts.map +1 -1
- package/payload/platform/services/webchat-channel/dist/server.js +11 -18
- package/payload/platform/services/webchat-channel/dist/server.js.map +1 -1
- package/payload/server/{chunk-4QFPGAUZ.js → chunk-FBGIHWWM.js} +170 -82
- package/payload/server/maxy-edge.js +1 -1
- package/payload/server/public/assets/{AdminLoginScreens-BsC-EwAn.js → AdminLoginScreens-BZIA9Z6o.js} +1 -1
- package/payload/server/public/assets/AdminShell-iazLHsk7.js +1 -0
- package/payload/server/public/assets/{Checkbox-DoPOlZTV.js → Checkbox-8elc7oXU.js} +1 -1
- package/payload/server/public/assets/{admin-DSwmdCKp.js → admin-BEx6o3fa.js} +1 -1
- package/payload/server/public/assets/{audio-attachment-mime-BA10IzqQ.js → audio-attachment-mime-DzbKNqbH.js} +1 -1
- package/payload/server/public/assets/{brand-C001cin3.css → brand-CmMZe4RK.css} +1 -1
- package/payload/server/public/assets/{browser-BKR1eJJb.js → browser-D16sPVkI.js} +1 -1
- package/payload/server/public/assets/chat-x4PnXhkd.js +1 -0
- package/payload/server/public/assets/{data-CuVmW1WN.js → data-DqG45sq0.js} +1 -1
- package/payload/server/public/assets/{file-download-4_hQmMwU.js → file-download-BvGS7Qmi.js} +1 -1
- package/payload/server/public/assets/{graph-D29p1FJH.js → graph-DKSjcpmR.js} +1 -1
- package/payload/server/public/assets/{graph-labels-DF3QVHkH.js → graph-labels-CVWPQgBV.js} +1 -1
- package/payload/server/public/assets/{operator-CQRaBNN7.js → operator-Cnzbhdh2.js} +1 -1
- package/payload/server/public/assets/page-CH8JQkQN.js +1 -0
- package/payload/server/public/assets/{public-B7BQwWpP.js → public-CA90VhI9.js} +1 -1
- package/payload/server/public/assets/{useSelectionMode-ghXuZicl.js → useSelectionMode-FIodJKzS.js} +1 -1
- package/payload/server/public/browser.html +6 -6
- package/payload/server/public/chat.html +8 -8
- package/payload/server/public/data.html +5 -5
- package/payload/server/public/graph.html +8 -8
- package/payload/server/public/index.html +9 -9
- package/payload/server/public/operator.html +10 -10
- package/payload/server/public/public.html +6 -6
- package/payload/server/server.js +3980 -3516
- package/payload/server/public/assets/AdminShell-CiKKN22G.js +0 -1
- package/payload/server/public/assets/chat-DZXNRiy-.js +0 -1
- package/payload/server/public/assets/page-Dz2F3QtB.js +0 -1
- /package/payload/server/public/assets/{brand-BaRMO3mZ.js → brand-Dh5UlVO2.js} +0 -0
|
@@ -2756,23 +2756,9 @@ function websockifyLog(event, fields = {}) {
|
|
|
2756
2756
|
console.error(`[websockify] ${formatKv({ event, ...fields })}`);
|
|
2757
2757
|
}
|
|
2758
2758
|
|
|
2759
|
-
//
|
|
2760
|
-
|
|
2761
|
-
|
|
2762
|
-
{ key: "length", label: "At least 8 characters", met: password.length >= 8 },
|
|
2763
|
-
{ key: "number", label: "Contains a number", met: /\d/.test(password) },
|
|
2764
|
-
{ key: "special", label: "Contains a special character", met: /[^A-Za-z0-9]/.test(password) },
|
|
2765
|
-
{ key: "whitespace", label: "No spaces", met: password.length > 0 && !/\s/.test(password) }
|
|
2766
|
-
];
|
|
2767
|
-
}
|
|
2768
|
-
function isPasswordValid(password) {
|
|
2769
|
-
return validatePasswordStrength(password).every((r) => r.met);
|
|
2770
|
-
}
|
|
2771
|
-
|
|
2772
|
-
// app/lib/remote-auth.ts
|
|
2773
|
-
import { scrypt, randomBytes, timingSafeEqual, createHmac } from "crypto";
|
|
2774
|
-
import { readFileSync as readFileSync2, writeFileSync, existsSync as existsSync2, mkdirSync as mkdirSync2 } from "fs";
|
|
2775
|
-
import { dirname } from "path";
|
|
2759
|
+
// ../lib/admin-access-password/src/index.ts
|
|
2760
|
+
import { scrypt, randomBytes, timingSafeEqual } from "crypto";
|
|
2761
|
+
import { existsSync as existsSync2, readFileSync as readFileSync2, writeFileSync, renameSync, unlinkSync } from "fs";
|
|
2776
2762
|
var SCRYPT_N = 16384;
|
|
2777
2763
|
var SCRYPT_R = 8;
|
|
2778
2764
|
var SCRYPT_P = 1;
|
|
@@ -2785,56 +2771,155 @@ function scryptAsync(password, salt) {
|
|
|
2785
2771
|
});
|
|
2786
2772
|
});
|
|
2787
2773
|
}
|
|
2788
|
-
async function
|
|
2774
|
+
async function hashAccessPassword(password) {
|
|
2789
2775
|
const salt = randomBytes(32);
|
|
2790
2776
|
const hash = await scryptAsync(password, salt);
|
|
2791
2777
|
return `${salt.toString("hex")}:${hash.toString("hex")}`;
|
|
2792
2778
|
}
|
|
2793
|
-
async function
|
|
2794
|
-
const
|
|
2795
|
-
if (
|
|
2796
|
-
const
|
|
2797
|
-
const
|
|
2798
|
-
if (
|
|
2799
|
-
const salt = Buffer.from(saltHex, "hex");
|
|
2800
|
-
const storedHash = Buffer.from(hashHex, "hex");
|
|
2801
|
-
if (storedHash.length !== SCRYPT_KEYLEN) {
|
|
2802
|
-
return { ok: false, why: "hash-length", hashBytes: storedHash.length };
|
|
2803
|
-
}
|
|
2779
|
+
async function matchesHash(password, stored) {
|
|
2780
|
+
const colon = stored.indexOf(":");
|
|
2781
|
+
if (colon === -1) return false;
|
|
2782
|
+
const salt = Buffer.from(stored.slice(0, colon), "hex");
|
|
2783
|
+
const storedHash = Buffer.from(stored.slice(colon + 1), "hex");
|
|
2784
|
+
if (storedHash.length !== SCRYPT_KEYLEN) return false;
|
|
2804
2785
|
let computed;
|
|
2805
2786
|
try {
|
|
2806
2787
|
computed = await scryptAsync(password, salt);
|
|
2807
2788
|
} catch {
|
|
2808
|
-
return
|
|
2809
|
-
}
|
|
2810
|
-
if (timingSafeEqual(computed, storedHash)) {
|
|
2811
|
-
return { ok: true, hashBytes: storedHash.length };
|
|
2789
|
+
return false;
|
|
2812
2790
|
}
|
|
2813
|
-
return
|
|
2791
|
+
return timingSafeEqual(computed, storedHash);
|
|
2814
2792
|
}
|
|
2815
|
-
function
|
|
2816
|
-
if (!existsSync2(
|
|
2817
|
-
const
|
|
2818
|
-
|
|
2793
|
+
function readUsers(usersFile) {
|
|
2794
|
+
if (!existsSync2(usersFile)) return [];
|
|
2795
|
+
const raw2 = readFileSync2(usersFile, "utf-8").trim();
|
|
2796
|
+
if (!raw2) return [];
|
|
2797
|
+
const parsed = JSON.parse(raw2);
|
|
2798
|
+
if (!Array.isArray(parsed)) throw new Error("users.json is not an array");
|
|
2799
|
+
return parsed;
|
|
2800
|
+
}
|
|
2801
|
+
function writeUsersAtomic(usersFile, users) {
|
|
2802
|
+
const tmp = `${usersFile}.tmp-${process.pid}`;
|
|
2803
|
+
writeFileSync(tmp, JSON.stringify(users, null, 2) + "\n", { mode: 384 });
|
|
2804
|
+
renameSync(tmp, usersFile);
|
|
2805
|
+
}
|
|
2806
|
+
async function setAccessPassword(userId, password, usersFile) {
|
|
2807
|
+
const users = readUsers(usersFile);
|
|
2808
|
+
const idx = users.findIndex((u) => u.userId === userId);
|
|
2809
|
+
if (idx === -1) throw new Error(`no users.json record for userId=${userId}`);
|
|
2810
|
+
users[idx] = { ...users[idx], accessHash: await hashAccessPassword(password) };
|
|
2811
|
+
writeUsersAtomic(usersFile, users);
|
|
2819
2812
|
}
|
|
2820
|
-
function
|
|
2813
|
+
async function verifyAccessPassword(password, usersFile) {
|
|
2814
|
+
let users;
|
|
2821
2815
|
try {
|
|
2822
|
-
|
|
2823
|
-
const content = readFileSync2(REMOTE_PASSWORD_FILE, "utf-8").trim();
|
|
2824
|
-
if (!content || !content.includes(":")) return null;
|
|
2825
|
-
return content;
|
|
2816
|
+
users = readUsers(usersFile);
|
|
2826
2817
|
} catch {
|
|
2827
2818
|
return null;
|
|
2828
2819
|
}
|
|
2820
|
+
for (const u of users) {
|
|
2821
|
+
if (typeof u.accessHash === "string" && await matchesHash(password, u.accessHash)) {
|
|
2822
|
+
return u.userId;
|
|
2823
|
+
}
|
|
2824
|
+
}
|
|
2825
|
+
return null;
|
|
2826
|
+
}
|
|
2827
|
+
function anyAccessPasswordConfigured(usersFile) {
|
|
2828
|
+
let users;
|
|
2829
|
+
try {
|
|
2830
|
+
users = readUsers(usersFile);
|
|
2831
|
+
} catch {
|
|
2832
|
+
return false;
|
|
2833
|
+
}
|
|
2834
|
+
return users.some((u) => typeof u.accessHash === "string" && u.accessHash.length > 0);
|
|
2835
|
+
}
|
|
2836
|
+
function accessStoreUnreadable(usersFile) {
|
|
2837
|
+
if (!existsSync2(usersFile)) return false;
|
|
2838
|
+
try {
|
|
2839
|
+
readUsers(usersFile);
|
|
2840
|
+
return false;
|
|
2841
|
+
} catch {
|
|
2842
|
+
return true;
|
|
2843
|
+
}
|
|
2844
|
+
}
|
|
2845
|
+
function migrateLegacyRemotePassword(usersFile, legacyFile, ownerUserId) {
|
|
2846
|
+
if (!existsSync2(legacyFile)) return "noop-no-legacy";
|
|
2847
|
+
const legacy = readFileSync2(legacyFile, "utf-8").trim();
|
|
2848
|
+
const users = readUsers(usersFile);
|
|
2849
|
+
const idx = users.findIndex((u) => u.userId === ownerUserId);
|
|
2850
|
+
if (idx === -1) return "noop-no-owner";
|
|
2851
|
+
const existing = users[idx].accessHash;
|
|
2852
|
+
if (typeof existing === "string" && existing.length > 0) {
|
|
2853
|
+
unlinkSync(legacyFile);
|
|
2854
|
+
return "noop-owner-has-hash";
|
|
2855
|
+
}
|
|
2856
|
+
if (!legacy.includes(":")) {
|
|
2857
|
+
unlinkSync(legacyFile);
|
|
2858
|
+
return "noop-no-legacy";
|
|
2859
|
+
}
|
|
2860
|
+
users[idx] = { ...users[idx], accessHash: legacy };
|
|
2861
|
+
writeUsersAtomic(usersFile, users);
|
|
2862
|
+
unlinkSync(legacyFile);
|
|
2863
|
+
return "migrated";
|
|
2864
|
+
}
|
|
2865
|
+
function readLegacyRemoteHash(legacyFile) {
|
|
2866
|
+
if (!existsSync2(legacyFile)) return null;
|
|
2867
|
+
const raw2 = readFileSync2(legacyFile, "utf-8").trim();
|
|
2868
|
+
return raw2.includes(":") ? raw2 : null;
|
|
2869
|
+
}
|
|
2870
|
+
|
|
2871
|
+
// app/lib/password-strength.ts
|
|
2872
|
+
function validatePasswordStrength(password) {
|
|
2873
|
+
return [
|
|
2874
|
+
{ key: "length", label: "At least 8 characters", met: password.length >= 8 },
|
|
2875
|
+
{ key: "number", label: "Contains a number", met: /\d/.test(password) },
|
|
2876
|
+
{ key: "special", label: "Contains a special character", met: /[^A-Za-z0-9]/.test(password) },
|
|
2877
|
+
{ key: "whitespace", label: "No spaces", met: password.length > 0 && !/\s/.test(password) }
|
|
2878
|
+
];
|
|
2879
|
+
}
|
|
2880
|
+
function isPasswordValid(password) {
|
|
2881
|
+
return validatePasswordStrength(password).every((r) => r.met);
|
|
2882
|
+
}
|
|
2883
|
+
|
|
2884
|
+
// app/lib/remote-auth.ts
|
|
2885
|
+
import { scrypt as scrypt2, randomBytes as randomBytes2, timingSafeEqual as timingSafeEqual2, createHmac } from "crypto";
|
|
2886
|
+
import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2 } from "fs";
|
|
2887
|
+
import { dirname } from "path";
|
|
2888
|
+
var SCRYPT_N2 = 16384;
|
|
2889
|
+
var SCRYPT_R2 = 8;
|
|
2890
|
+
var SCRYPT_P2 = 1;
|
|
2891
|
+
var SCRYPT_KEYLEN2 = 64;
|
|
2892
|
+
function scryptAsync2(password, salt) {
|
|
2893
|
+
return new Promise((resolve7, reject) => {
|
|
2894
|
+
scrypt2(password, salt, SCRYPT_KEYLEN2, { N: SCRYPT_N2, r: SCRYPT_R2, p: SCRYPT_P2 }, (err, key) => {
|
|
2895
|
+
if (err) reject(err);
|
|
2896
|
+
else resolve7(key);
|
|
2897
|
+
});
|
|
2898
|
+
});
|
|
2899
|
+
}
|
|
2900
|
+
async function hashPassword(password) {
|
|
2901
|
+
const salt = randomBytes2(32);
|
|
2902
|
+
const hash = await scryptAsync2(password, salt);
|
|
2903
|
+
return `${salt.toString("hex")}:${hash.toString("hex")}`;
|
|
2904
|
+
}
|
|
2905
|
+
function isRemoteAuthConfigured() {
|
|
2906
|
+
if (anyAccessPasswordConfigured(USERS_FILE)) return true;
|
|
2907
|
+
if (accessStoreUnreadable(USERS_FILE)) return true;
|
|
2908
|
+
return readLegacyRemoteHash(REMOTE_PASSWORD_FILE) !== null;
|
|
2829
2909
|
}
|
|
2830
2910
|
async function setRemotePassword(password) {
|
|
2831
2911
|
const hash = await hashPassword(password);
|
|
2832
|
-
|
|
2912
|
+
writeFileSync2(REMOTE_PASSWORD_FILE, hash, "utf-8");
|
|
2833
2913
|
}
|
|
2834
2914
|
async function verifyRemotePassword(password) {
|
|
2835
|
-
const
|
|
2836
|
-
if (
|
|
2837
|
-
|
|
2915
|
+
const matchedUserId = await verifyAccessPassword(password, USERS_FILE);
|
|
2916
|
+
if (matchedUserId) return { ok: true, hashBytes: SCRYPT_KEYLEN2, userId: matchedUserId };
|
|
2917
|
+
const legacy = readLegacyRemoteHash(REMOTE_PASSWORD_FILE);
|
|
2918
|
+
if (legacy && await matchesHash(password, legacy)) {
|
|
2919
|
+
return { ok: true, hashBytes: SCRYPT_KEYLEN2, userId: null };
|
|
2920
|
+
}
|
|
2921
|
+
const configured = anyAccessPasswordConfigured(USERS_FILE) || legacy !== null;
|
|
2922
|
+
return { ok: false, why: configured ? "password-mismatch" : "no-password-file", hashBytes: 0 };
|
|
2838
2923
|
}
|
|
2839
2924
|
var SESSION_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
2840
2925
|
var TOKEN_PREFIX = "v1.";
|
|
@@ -2844,20 +2929,20 @@ var cachedSecret = null;
|
|
|
2844
2929
|
function getSecret() {
|
|
2845
2930
|
if (cachedSecret) return cachedSecret;
|
|
2846
2931
|
try {
|
|
2847
|
-
const hex2 =
|
|
2932
|
+
const hex2 = readFileSync3(REMOTE_SESSION_SECRET_FILE, "utf-8").trim();
|
|
2848
2933
|
if (hex2.length === SECRET_BYTES * 2) {
|
|
2849
2934
|
cachedSecret = Buffer.from(hex2, "hex");
|
|
2850
2935
|
return cachedSecret;
|
|
2851
2936
|
}
|
|
2852
2937
|
} catch {
|
|
2853
2938
|
}
|
|
2854
|
-
const fresh =
|
|
2939
|
+
const fresh = randomBytes2(SECRET_BYTES).toString("hex");
|
|
2855
2940
|
try {
|
|
2856
2941
|
mkdirSync2(dirname(REMOTE_SESSION_SECRET_FILE), { recursive: true, mode: 448 });
|
|
2857
|
-
|
|
2942
|
+
writeFileSync2(REMOTE_SESSION_SECRET_FILE, fresh, { mode: 384, flag: "wx" });
|
|
2858
2943
|
} catch {
|
|
2859
2944
|
}
|
|
2860
|
-
const hex =
|
|
2945
|
+
const hex = readFileSync3(REMOTE_SESSION_SECRET_FILE, "utf-8").trim();
|
|
2861
2946
|
cachedSecret = Buffer.from(hex, "hex");
|
|
2862
2947
|
return cachedSecret;
|
|
2863
2948
|
}
|
|
@@ -2872,7 +2957,7 @@ function signPayload(payloadJson, secret) {
|
|
|
2872
2957
|
return base64urlEncode(createHmac("sha256", secret).update(payloadJson).digest());
|
|
2873
2958
|
}
|
|
2874
2959
|
function createRemoteSession(opts = {}) {
|
|
2875
|
-
const payload = { c: opts.now ?? Date.now(), n:
|
|
2960
|
+
const payload = { c: opts.now ?? Date.now(), n: randomBytes2(NONCE_BYTES).toString("hex") };
|
|
2876
2961
|
const payloadJson = JSON.stringify(payload);
|
|
2877
2962
|
const payloadB64 = base64urlEncode(Buffer.from(payloadJson, "utf-8"));
|
|
2878
2963
|
const sig = signPayload(payloadJson, getSecret());
|
|
@@ -2895,7 +2980,7 @@ function parseToken(token) {
|
|
|
2895
2980
|
const expected = signPayload(payloadJson, getSecret());
|
|
2896
2981
|
const expectedBuf = Buffer.from(expected, "utf-8");
|
|
2897
2982
|
const provBuf = Buffer.from(sigB64, "utf-8");
|
|
2898
|
-
const signatureValid = expectedBuf.length === provBuf.length &&
|
|
2983
|
+
const signatureValid = expectedBuf.length === provBuf.length && timingSafeEqual2(expectedBuf, provBuf);
|
|
2899
2984
|
let payload;
|
|
2900
2985
|
try {
|
|
2901
2986
|
payload = JSON.parse(payloadJson);
|
|
@@ -3473,13 +3558,13 @@ function classifyHost(host, operatorDomains2, isPublicHost) {
|
|
|
3473
3558
|
import { watchFile } from "fs";
|
|
3474
3559
|
|
|
3475
3560
|
// app/lib/operator-domains.ts
|
|
3476
|
-
import { existsSync as existsSync3, mkdirSync as mkdirSync3, readFileSync as
|
|
3561
|
+
import { existsSync as existsSync3, mkdirSync as mkdirSync3, readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "fs";
|
|
3477
3562
|
import { dirname as dirname2, resolve as resolve3 } from "path";
|
|
3478
3563
|
var OPERATOR_DOMAINS_PATH = resolve3(MAXY_DIR, "operator-domains.json");
|
|
3479
3564
|
function loadOperatorDomains() {
|
|
3480
3565
|
if (!existsSync3(OPERATOR_DOMAINS_PATH)) return /* @__PURE__ */ new Set();
|
|
3481
3566
|
try {
|
|
3482
|
-
const parsed = JSON.parse(
|
|
3567
|
+
const parsed = JSON.parse(readFileSync4(OPERATOR_DOMAINS_PATH, "utf-8"));
|
|
3483
3568
|
if (!Array.isArray(parsed)) return /* @__PURE__ */ new Set();
|
|
3484
3569
|
return new Set(parsed.filter((h) => typeof h === "string"));
|
|
3485
3570
|
} catch {
|
|
@@ -3506,11 +3591,11 @@ function getOperatorDomains() {
|
|
|
3506
3591
|
|
|
3507
3592
|
// app/lib/claude-agent/account.ts
|
|
3508
3593
|
import { resolve as resolve4 } from "path";
|
|
3509
|
-
import { readFileSync as
|
|
3594
|
+
import { readFileSync as readFileSync6, readdirSync, existsSync as existsSync5, statSync } from "fs";
|
|
3510
3595
|
|
|
3511
3596
|
// ../lib/brand-templating/src/index.ts
|
|
3512
3597
|
import { join as join2 } from "path";
|
|
3513
|
-
import { existsSync as existsSync4, readFileSync as
|
|
3598
|
+
import { existsSync as existsSync4, readFileSync as readFileSync5 } from "fs";
|
|
3514
3599
|
var PLACEHOLDER = "{{productName}}";
|
|
3515
3600
|
var cachedProductName = null;
|
|
3516
3601
|
function brandJsonPath() {
|
|
@@ -3530,7 +3615,7 @@ function getBrandProductName() {
|
|
|
3530
3615
|
}
|
|
3531
3616
|
let parsed;
|
|
3532
3617
|
try {
|
|
3533
|
-
parsed = JSON.parse(
|
|
3618
|
+
parsed = JSON.parse(readFileSync5(path, "utf-8"));
|
|
3534
3619
|
} catch (err) {
|
|
3535
3620
|
throw new Error(
|
|
3536
3621
|
`[skill-loader] brand.json unreadable at ${path}: ${err instanceof Error ? err.message : String(err)}`
|
|
@@ -3594,7 +3679,7 @@ function listValidAccounts() {
|
|
|
3594
3679
|
}
|
|
3595
3680
|
let config;
|
|
3596
3681
|
try {
|
|
3597
|
-
config = JSON.parse(
|
|
3682
|
+
config = JSON.parse(readFileSync6(configPath, "utf-8"));
|
|
3598
3683
|
} catch {
|
|
3599
3684
|
console.error(
|
|
3600
3685
|
`[platform] accounts-state CORRUPT-JSON id=${entry.name} \u2014 account.json failed to parse; treating as stub`
|
|
@@ -3610,7 +3695,7 @@ function resolveAccount() {
|
|
|
3610
3695
|
let usersJsonUserId = null;
|
|
3611
3696
|
if (existsSync5(USERS_FILE)) {
|
|
3612
3697
|
try {
|
|
3613
|
-
const raw2 =
|
|
3698
|
+
const raw2 = readFileSync6(USERS_FILE, "utf-8").trim();
|
|
3614
3699
|
if (raw2) {
|
|
3615
3700
|
const users = JSON.parse(raw2);
|
|
3616
3701
|
if (users.length > 0) {
|
|
@@ -3626,7 +3711,7 @@ function resolveAccount() {
|
|
|
3626
3711
|
if (!entry.isDirectory()) continue;
|
|
3627
3712
|
const configPath = resolve4(ACCOUNTS_DIR, entry.name, "account.json");
|
|
3628
3713
|
if (!existsSync5(configPath)) continue;
|
|
3629
|
-
const raw2 =
|
|
3714
|
+
const raw2 = readFileSync6(configPath, "utf-8");
|
|
3630
3715
|
let config;
|
|
3631
3716
|
try {
|
|
3632
3717
|
config = JSON.parse(raw2);
|
|
@@ -3661,7 +3746,7 @@ function resolveAccount() {
|
|
|
3661
3746
|
function readAgentFile(accountDir, agentName, filename) {
|
|
3662
3747
|
const filePath = resolve4(accountDir, "agents", agentName, filename);
|
|
3663
3748
|
if (!existsSync5(filePath)) return null;
|
|
3664
|
-
const raw2 =
|
|
3749
|
+
const raw2 = readFileSync6(filePath, "utf-8");
|
|
3665
3750
|
if (filename.endsWith(".md")) {
|
|
3666
3751
|
return substituteBrandPlaceholders(raw2, filePath);
|
|
3667
3752
|
}
|
|
@@ -3690,7 +3775,7 @@ function resolveDefaultAgentSlug(accountDir) {
|
|
|
3690
3775
|
}
|
|
3691
3776
|
let config;
|
|
3692
3777
|
try {
|
|
3693
|
-
config = JSON.parse(
|
|
3778
|
+
config = JSON.parse(readFileSync6(configPath, "utf-8"));
|
|
3694
3779
|
} catch (err) {
|
|
3695
3780
|
console.error("[agent-resolve] failed to read account.json:", err);
|
|
3696
3781
|
return null;
|
|
@@ -3765,14 +3850,14 @@ function resolveAgentConfig(accountDir, agentName) {
|
|
|
3765
3850
|
const knowledgeMtime = statSync(knowledgePath).mtimeMs;
|
|
3766
3851
|
const summaryMtime = statSync(summaryPath).mtimeMs;
|
|
3767
3852
|
if (summaryMtime >= knowledgeMtime) {
|
|
3768
|
-
knowledge =
|
|
3853
|
+
knowledge = readFileSync6(summaryPath, "utf-8");
|
|
3769
3854
|
} else {
|
|
3770
3855
|
console.warn(`[agent-config] ${agentName}: KNOWLEDGE-SUMMARY.md is stale (KNOWLEDGE.md is newer) \u2014 using full knowledge`);
|
|
3771
|
-
knowledge =
|
|
3856
|
+
knowledge = readFileSync6(knowledgePath, "utf-8");
|
|
3772
3857
|
}
|
|
3773
3858
|
knowledgeBaked = true;
|
|
3774
3859
|
} else if (hasKnowledge) {
|
|
3775
|
-
knowledge =
|
|
3860
|
+
knowledge = readFileSync6(knowledgePath, "utf-8");
|
|
3776
3861
|
knowledgeBaked = true;
|
|
3777
3862
|
}
|
|
3778
3863
|
let budget = null;
|
|
@@ -3808,7 +3893,7 @@ function resolveUserAccounts(userId) {
|
|
|
3808
3893
|
if (!existsSync5(configPath)) continue;
|
|
3809
3894
|
let config;
|
|
3810
3895
|
try {
|
|
3811
|
-
config = JSON.parse(
|
|
3896
|
+
config = JSON.parse(readFileSync6(configPath, "utf-8"));
|
|
3812
3897
|
} catch {
|
|
3813
3898
|
console.error(`[session] account.json corrupt at ${configPath} \u2014 skipping`);
|
|
3814
3899
|
continue;
|
|
@@ -3893,8 +3978,8 @@ function getSessionKeyBySessionId(_sessionId) {
|
|
|
3893
3978
|
// app/lib/claude-agent/plugin-manifest.ts
|
|
3894
3979
|
import { resolve as resolve5, join as join3 } from "path";
|
|
3895
3980
|
import {
|
|
3896
|
-
readFileSync as
|
|
3897
|
-
writeFileSync as
|
|
3981
|
+
readFileSync as readFileSync7,
|
|
3982
|
+
writeFileSync as writeFileSync4,
|
|
3898
3983
|
readdirSync as readdirSync2,
|
|
3899
3984
|
existsSync as existsSync6,
|
|
3900
3985
|
statSync as statSync2,
|
|
@@ -3915,7 +4000,7 @@ function readBundleSubPlugins(bundlePath) {
|
|
|
3915
4000
|
if (!existsSync6(bundlePath)) return [];
|
|
3916
4001
|
let raw2;
|
|
3917
4002
|
try {
|
|
3918
|
-
raw2 =
|
|
4003
|
+
raw2 = readFileSync7(bundlePath, "utf-8");
|
|
3919
4004
|
} catch {
|
|
3920
4005
|
return [];
|
|
3921
4006
|
}
|
|
@@ -3988,8 +4073,8 @@ function reapDuplicateFlatPremiumSubs(bundles, stagingRoot, pluginsDir) {
|
|
|
3988
4073
|
const flatDir = resolve5(pluginsDir, sub);
|
|
3989
4074
|
const flatManifest = resolve5(flatDir, "PLUGIN.md");
|
|
3990
4075
|
if (!existsSync6(premiumManifest) || !existsSync6(flatManifest)) continue;
|
|
3991
|
-
const premiumSha = createHash2("sha256").update(
|
|
3992
|
-
const flatSha = createHash2("sha256").update(
|
|
4076
|
+
const premiumSha = createHash2("sha256").update(readFileSync7(premiumManifest)).digest("hex");
|
|
4077
|
+
const flatSha = createHash2("sha256").update(readFileSync7(flatManifest)).digest("hex");
|
|
3993
4078
|
if (isBundle) {
|
|
3994
4079
|
if (premiumSha === flatSha) {
|
|
3995
4080
|
try {
|
|
@@ -4051,10 +4136,10 @@ function reconcileEnabledPlugins(accountDir, config, accountId) {
|
|
|
4051
4136
|
const merged = [...currentSet];
|
|
4052
4137
|
const configPath = resolve5(accountDir, "account.json");
|
|
4053
4138
|
try {
|
|
4054
|
-
const raw2 =
|
|
4139
|
+
const raw2 = readFileSync7(configPath, "utf-8");
|
|
4055
4140
|
const parsed = JSON.parse(raw2);
|
|
4056
4141
|
parsed.enabledPlugins = merged;
|
|
4057
|
-
|
|
4142
|
+
writeFileSync4(configPath, JSON.stringify(parsed, null, 2) + "\n");
|
|
4058
4143
|
config.enabledPlugins = merged;
|
|
4059
4144
|
} catch (err) {
|
|
4060
4145
|
console.error(`${TAG} enabled-stamp write failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -4082,10 +4167,10 @@ function cleanupLeakedPremiumSubs(accountDir, config, accountId) {
|
|
|
4082
4167
|
if (removed.length === 0) return;
|
|
4083
4168
|
const configPath = resolve5(accountDir, "account.json");
|
|
4084
4169
|
try {
|
|
4085
|
-
const raw2 =
|
|
4170
|
+
const raw2 = readFileSync7(configPath, "utf-8");
|
|
4086
4171
|
const parsed = JSON.parse(raw2);
|
|
4087
4172
|
parsed.enabledPlugins = kept;
|
|
4088
|
-
|
|
4173
|
+
writeFileSync4(configPath, JSON.stringify(parsed, null, 2) + "\n");
|
|
4089
4174
|
config.enabledPlugins = kept;
|
|
4090
4175
|
console.log(`${TAG} cleanup accountId=${accountId ?? "unknown"} removed=[${removed.join(",")}]`);
|
|
4091
4176
|
} catch (err) {
|
|
@@ -4133,7 +4218,7 @@ function requirePortEnv(envName, options = {}) {
|
|
|
4133
4218
|
// app/lib/neo4j-store.ts
|
|
4134
4219
|
import neo4j from "neo4j-driver";
|
|
4135
4220
|
import { randomUUID } from "crypto";
|
|
4136
|
-
import { readFileSync as
|
|
4221
|
+
import { readFileSync as readFileSync8, readdirSync as readdirSync3, existsSync as existsSync7, openSync, readSync, closeSync, statSync as statSync3 } from "fs";
|
|
4137
4222
|
import { resolve as resolve6 } from "path";
|
|
4138
4223
|
var PLATFORM_ROOT3 = process.env.MAXY_PLATFORM_ROOT ?? resolve6(process.cwd(), "..");
|
|
4139
4224
|
var driver = null;
|
|
@@ -4141,7 +4226,7 @@ function readPassword() {
|
|
|
4141
4226
|
if (process.env.NEO4J_PASSWORD) return process.env.NEO4J_PASSWORD;
|
|
4142
4227
|
const passwordFile = resolve6(PLATFORM_ROOT3, "config/.neo4j-password");
|
|
4143
4228
|
try {
|
|
4144
|
-
return
|
|
4229
|
+
return readFileSync8(passwordFile, "utf-8").trim();
|
|
4145
4230
|
} catch {
|
|
4146
4231
|
throw new Error(
|
|
4147
4232
|
`Neo4j password not found. Expected at ${passwordFile} or in NEO4J_PASSWORD env var.`
|
|
@@ -5190,7 +5275,7 @@ function loadEnabledPluginProfileKeys(accountId) {
|
|
|
5190
5275
|
if (!existsSync7(accountFile)) return {};
|
|
5191
5276
|
let enabled;
|
|
5192
5277
|
try {
|
|
5193
|
-
const raw2 =
|
|
5278
|
+
const raw2 = readFileSync8(accountFile, "utf-8");
|
|
5194
5279
|
const parsed = JSON.parse(raw2);
|
|
5195
5280
|
enabled = Array.isArray(parsed.enabledPlugins) ? parsed.enabledPlugins.filter((p) => typeof p === "string") : [];
|
|
5196
5281
|
} catch (err) {
|
|
@@ -5205,7 +5290,7 @@ function loadEnabledPluginProfileKeys(accountId) {
|
|
|
5205
5290
|
if (!existsSync7(manifestPath)) continue;
|
|
5206
5291
|
let manifest;
|
|
5207
5292
|
try {
|
|
5208
|
-
manifest =
|
|
5293
|
+
manifest = readFileSync8(manifestPath, "utf-8");
|
|
5209
5294
|
} catch {
|
|
5210
5295
|
continue;
|
|
5211
5296
|
}
|
|
@@ -5461,11 +5546,11 @@ async function projectAgent(accountId, accountDir, slug) {
|
|
|
5461
5546
|
);
|
|
5462
5547
|
return;
|
|
5463
5548
|
}
|
|
5464
|
-
config = JSON.parse(
|
|
5549
|
+
config = JSON.parse(readFileSync8(configPath, "utf-8"));
|
|
5465
5550
|
for (const { filename, role } of AGENT_FILE_ROLES) {
|
|
5466
5551
|
const filePath = resolve6(agentDir, filename);
|
|
5467
5552
|
if (!existsSync7(filePath)) continue;
|
|
5468
|
-
const body =
|
|
5553
|
+
const body = readFileSync8(filePath, "utf-8");
|
|
5469
5554
|
presentRoles.push({ role, body, edge: ROLE_TO_EDGE[role] });
|
|
5470
5555
|
}
|
|
5471
5556
|
} catch (err) {
|
|
@@ -5726,6 +5811,7 @@ export {
|
|
|
5726
5811
|
LID_MAP_FILE,
|
|
5727
5812
|
LOG_DIR,
|
|
5728
5813
|
BIN_DIR,
|
|
5814
|
+
REMOTE_PASSWORD_FILE,
|
|
5729
5815
|
INSTALL_OWNER_FILE,
|
|
5730
5816
|
VISITOR_TOKEN_SECRET_FILE,
|
|
5731
5817
|
CLAUDE_CREDENTIALS_FILE,
|
|
@@ -5734,6 +5820,8 @@ export {
|
|
|
5734
5820
|
sanitizeClientCorrId,
|
|
5735
5821
|
httpLog,
|
|
5736
5822
|
websockifyLog,
|
|
5823
|
+
setAccessPassword,
|
|
5824
|
+
migrateLegacyRemotePassword,
|
|
5737
5825
|
validatePasswordStrength,
|
|
5738
5826
|
isPasswordValid,
|
|
5739
5827
|
isRemoteAuthConfigured,
|
package/payload/server/public/assets/{AdminLoginScreens-BsC-EwAn.js → AdminLoginScreens-BZIA9Z6o.js}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{o as e}from"./chunk-Pqm5yXtL.js";import{a as t,o as n,t as r,u as i}from"./brand-BaRMO3mZ.js";import{c as a,p as o}from"./file-download-4_hQmMwU.js";import{p as s}from"./AdminShell-CiKKN22G.js";import{r as c}from"./useSelectionMode-ghXuZicl.js";import{t as l}from"./Checkbox-DoPOlZTV.js";new Set(`image/jpeg,image/png,image/gif,image/webp,application/pdf,text/plain,text/markdown,text/csv,text/html,text/calendar,application/zip,application/x-zip-compressed,audio/ogg,audio/opus,audio/mp4,audio/mpeg,audio/webm,audio/wav,.opus,.ogg,.m4a,.mp3,.wav,.webm`.split(`,`).filter(e=>!e.startsWith(`.`)));function u(e){switch(e){case`expanded`:return!0;case`collapsed`:return!1;default:return}}var d=`admin-landing-redirected`,f=`/graph`;function p(e){return e.variant===`operator`?!1:e.appState===`chat`&&!e.alreadyRedirected}var m=e(i(),1);function h(e=`admin`){let[t,n]=(0,m.useState)(`loading`),[r,i]=(0,m.useState)(``),[a,c]=(0,m.useState)(``),[l,h]=(0,m.useState)(``),[g,_]=(0,m.useState)(!1),[v,y]=(0,m.useState)(!1),[b,x]=(0,m.useState)(!1),[S,C]=(0,m.useState)(!1),[w,T]=(0,m.useState)(!1),[E,D]=(0,m.useState)(null),[O,k]=(0,m.useState)(null),[A,j]=(0,m.useState)(void 0),[M,N]=(0,m.useState)(null),[P,F]=(0,m.useState)(void 0),[I,L]=(0,m.useState)(null),[ee,R]=(0,m.useState)(null),[z,B]=(0,m.useState)([]),[V,H]=(0,m.useState)(!1),[U,W]=(0,m.useState)(void 0),G=(0,m.useRef)(void 0),[K,q]=(0,m.useState)(!1);(0,m.useEffect)(()=>{typeof window>`u`||fetch(`/api/remote-auth/status`).then(e=>e.ok?e.json():null).then(e=>{e?.configured&&q(!0)}).catch(()=>{})},[]);let J=(0,m.useRef)(null),Y=(0,m.useRef)(null);(0,m.useEffect)(()=>{async function e(){let e=null;try{e=sessionStorage.getItem(`maxy-admin-session-key`)}catch{}if(!e)return!1;try{let t=await fetch(`/api/admin/session?session_key=${encodeURIComponent(e)}`);if(t.status===401){try{sessionStorage.removeItem(`maxy-admin-session-key`)}catch{}return!1}if(!t.ok)return!1;let r=await t.json();D(r.session_key),R(r.sessionId??null),j(r.businessName),N(r.role??null),F(r.userName===void 0?null:r.userName),L(r.avatar??null);let i=u(r.thinkingView);return G.current=i,W(i),n(`chat`),!0}catch(e){return console.error(`[admin] session restore failed:`,e),!1}}async function t(r=2){try{let i=await fetch(`/api/health`);if(!i.ok){if(r>0)return await new Promise(e=>setTimeout(e,1500)),t(r-1);console.error(`[admin] health check returned ${i.status} after retries`),n(`set-pin`);return}let a=await i.json();if(!a.pin_configured){n(`set-pin`);return}if(!a.claude_authenticated){n(`connect-claude`);return}if(await e())return;n(`enter-pin`)}catch(e){if(r>0)return await new Promise(e=>setTimeout(e,1500)),t(r-1);console.error(`[admin] health check failed:`,e),n(`set-pin`)}}t()},[]),(0,m.useEffect)(()=>{t===`chat`&&fetch(`/api/admin/claude-info`).then(e=>{if(e.ok)return e.json()}).then(e=>{e&&k(e)}).catch(()=>{})},[t]),(0,m.useEffect)(()=>{if(typeof window>`u`)return;let n=!1;try{n=sessionStorage.getItem(d)===`1`}catch{}if(p({appState:t,alreadyRedirected:n,variant:e})){try{sessionStorage.setItem(d,`1`)}catch{}console.info(`[admin-ui] landing-redirect target=${f}`),window.location.replace(f)}},[t,e]);let X=(0,m.useRef)(null);(0,m.useEffect)(()=>{if(t!==`chat`)return;let e=setInterval(async()=>{try{let e=await fetch(`/api/health`);if(e.ok){let t=await e.json();if(t.auth_status===`dead`||t.auth_status===`missing`){n(`connect-claude`);return}}}catch{}if(E)try{let e=await fetch(`/api/admin/session?session_key=${encodeURIComponent(E)}`);if(e.status!==401)return;let t=(await e.clone().json().catch(()=>null))?.code??`unknown-401`;if(t===`remote-auth-required`){o(`heartbeat`,`/api/admin/session`);return}console.warn(`[admin-auth] outcome=heartbeat-detected-expiry code=${t}`),X.current?.()}catch{}},300*1e3);return()=>clearInterval(e)},[t,E]),(0,m.useEffect)(()=>{t===`connect-claude`&&fetch(`/api/health`).then(e=>e.ok?e.json():null).then(e=>{e?.claude_authenticated&&n(`enter-pin`)}).catch(()=>{})},[t]);async function Z(e,t){y(!0);try{let r=await fetch(`/api/admin/session`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({pin:e,...t?{accountId:t}:{}})});if(!r.ok){h((await r.json().catch(()=>({}))).error||`Invalid PIN`);return}let a=await r.json();if(a.accounts&&!a.session_key){console.log(`[admin] account picker shown: userId=${a.userId} accountCount=${a.accounts.length}`),B(a.accounts),n(`account-picker`);return}D(a.session_key),R(a.sessionId??null),j(a.businessName),N(a.role??null),F(a.userName===void 0?null:a.userName),L(a.avatar??null);let o=u(a.thinkingView);if(G.current=o,W(o),t)try{sessionStorage.setItem(`maxy-account-id`,t)}catch{}try{sessionStorage.setItem(`maxy-admin-session-key`,a.session_key)}catch{}i(``),n(`chat`)}catch(e){console.error(`[admin] connection error:`,e),h(`Could not connect.`)}finally{y(!1),H(!1)}}let Q=(0,m.useCallback)(async e=>{if(e.preventDefault(),v)return;h(``);let t=a.trim();if(!t){h(`Please enter your name.`);return}if(r.length<4){h(`PIN must be at least 4 characters.`);return}let o=r;y(!0);try{let e=await fetch(`/api/onboarding/set-pin`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({pin:o,name:t})});if(!e.ok){let t=await e.json().catch(()=>({}));if(e.status===409){console.log(`[admin] PIN already configured — re-checking health`);try{let e=await fetch(`/api/health`);if(e.ok){let r=await e.json();r.pin_configured&&r.claude_authenticated?n(`enter-pin`):r.pin_configured?n(`connect-claude`):h(t.error||`Failed to set PIN.`)}else n(`enter-pin`)}catch{n(`enter-pin`)}return}h(t.error||`Failed to set PIN.`);return}let r=await fetch(`/api/health`);if((r.ok?await r.json():null)?.claude_authenticated){await Z(o);return}i(``),n(`connect-claude`)}catch(e){console.error(`[admin] connection error:`,e),h(`Could not connect.`)}finally{y(!1)}},[r,v,a]),te=(0,m.useCallback)(async e=>{e.preventDefault(),h(``),await Z(r)},[r]),ne=(0,m.useCallback)(async()=>{T(!0);try{if(!await s())return console.warn(`[admin-ui] claude-disconnect not verified — credentials may persist; staying put`),!1;D(null),N(null),F(void 0),L(null);try{sessionStorage.removeItem(`maxy-admin-session-key`),sessionStorage.removeItem(`maxy-account-id`),sessionStorage.removeItem(d)}catch{}return n(`connect-claude`),!0}finally{T(!1)}},[]),$=(0,m.useCallback)(()=>{D(null),N(null),F(void 0),L(null);try{sessionStorage.removeItem(`maxy-admin-session-key`),sessionStorage.removeItem(`maxy-account-id`),sessionStorage.removeItem(d)}catch{}i(``),h(``),n(`enter-pin`)},[]);return(0,m.useEffect)(()=>{X.current=$},[$]),{appState:t,setAppState:n,pin:r,setPin:i,operatorName:a,setOperatorName:c,pinError:l,setPinError:h,showPin:g,setShowPin:_,pinLoading:v,authPolling:b,setAuthPolling:x,authLoading:S,setAuthLoading:C,disconnecting:w,cacheKey:E,setCacheKey:D,claudeInfo:O,setClaudeInfo:k,businessName:A,role:M,userName:P,userAvatar:I,sessionId:ee,setSessionId:R,accounts:z,accountPickerLoading:V,expandAll:U,setExpandAll:W,expandAllDefaultRef:G,remoteAuthEnabled:K,pinInputRef:J,setPinFormRef:Y,handleSetPin:Q,handleLogin:te,handleAccountSelect:(0,m.useCallback)(async e=>{H(!0),h(``),await Z(r,e)},[r]),handleDisconnect:ne,handleLogout:$,handleChangePin:(0,m.useCallback)(async()=>{if(!r){h(`Enter your current PIN first.`);return}y(!0),h(``);try{let e=await fetch(`/api/onboarding/set-pin`,{method:`DELETE`,headers:{"Content-Type":`application/json`},body:JSON.stringify({currentPin:r})});if(!e.ok){h((await e.json().catch(()=>({error:`Incorrect PIN.`}))).error||`Incorrect PIN.`);return}i(``),h(``),n(`set-pin`)}catch(e){console.error(`[admin-auth] change pin failed:`,e),h(e instanceof Error?e.message:String(e))}finally{y(!1)}},[r])}}var g=n();function _({inputRef:e,value:t,onChange:n,onComplete:r,showPin:i,autoFocus:a}){let o=(0,m.useRef)([]);function s(e,r){r.key===`Backspace`?(r.preventDefault(),t[e]?n(t.slice(0,e)+t.slice(e+1)):e>0&&(n(t.slice(0,e-1)+t.slice(e)),o.current[e-1]?.focus())):r.key===`ArrowLeft`&&e>0?o.current[e-1]?.focus():r.key===`ArrowRight`&&e<5?o.current[e+1]?.focus():r.key===`Enter`&&(r.preventDefault(),r.currentTarget.form?.requestSubmit())}function c(e,i){let a=i.nativeEvent.data;if(!a||!/^\d$/.test(a))return;let s=t.split(``);for(s[e]=a;s.length<e;)s.push(``);let c=s.join(``).replace(/\D/g,``).slice(0,6);n(c),c.length===6?r?.(c):e<5&&o.current[e+1]?.focus()}function l(e){e.preventDefault();let t=e.clipboardData.getData(`text`).replace(/\D/g,``).slice(0,6);t&&(n(t),t.length===6?r?.(t):o.current[t.length]?.focus())}return(0,g.jsx)(`div`,{className:`pin-field`,children:Array.from({length:6}).map((n,r)=>(0,g.jsx)(`input`,{ref:t=>{o.current[r]=t,r===0&&e&&(e.current=t)},type:`text`,inputMode:`numeric`,className:`pin-box${t[r]?` pin-box-filled`:``}`,value:t[r]?i?t[r]:`•`:``,onKeyDown:e=>s(r,e),onInput:e=>c(r,e),onPaste:l,onFocus:e=>e.target.select(),autoFocus:a&&r===0,autoComplete:`off`,maxLength:1,"aria-label":`PIN digit ${r+1}`},r))})}function v(e){let{pin:n,setPin:i,showPin:a,setShowPin:o,pinLoading:s,pinError:u,pinInputRef:d,setPinFormRef:f,onSubmit:p,operatorName:m,setOperatorName:h}=e;return(0,g.jsx)(`div`,{className:`connect-page`,children:(0,g.jsxs)(`div`,{className:`connect-content`,children:[(0,g.jsx)(`img`,{src:t,alt:r.productName,className:`connect-logo connect-logo--maxy`}),!r.logoContainsName&&(0,g.jsxs)(`h1`,{className:`connect-title`,children:[`Welcome to `,r.productName]}),(0,g.jsxs)(`p`,{className:`connect-subtitle`,children:[`Tell `,r.productName,` who you are, then choose a PIN.`]}),(0,g.jsxs)(`form`,{ref:f,onSubmit:p,className:`connect-pin-form`,children:[(0,g.jsxs)(`div`,{className:`pin-input-row`,children:[(0,g.jsx)(`input`,{type:`text`,className:`connect-name-input`,placeholder:`Your full name`,value:m,onChange:e=>h(e.target.value),autoComplete:`name`,autoFocus:!0,required:!0,"aria-label":`Your full name`}),(0,g.jsx)(`div`,{style:{width:38,flexShrink:0},"aria-hidden":`true`})]}),(0,g.jsxs)(`div`,{className:`pin-input-row`,children:[(0,g.jsx)(_,{inputRef:d,value:n,onChange:i,onComplete:()=>{},showPin:a}),(0,g.jsx)(c,{variant:`send`,type:`submit`,disabled:!n||!m.trim(),loading:s,"aria-label":`Set PIN`,children:(0,g.jsxs)(`svg`,{viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`,children:[(0,g.jsx)(`line`,{x1:`5`,y1:`12`,x2:`19`,y2:`12`}),(0,g.jsx)(`polyline`,{points:`12 5 19 12 12 19`})]})})]}),(0,g.jsx)(l,{checked:a,onChange:()=>o(e=>!e),label:`Show PIN`})]}),u&&(0,g.jsx)(`p`,{className:`admin-pin-error`,children:u})]})})}function y(e){let{pin:n,setPin:i,showPin:a,setShowPin:o,pinLoading:s,pinError:u,pinInputRef:d,onSubmit:f,onChangePin:p,remoteAuthEnabled:m,onSignOutRemote:h}=e;return(0,g.jsxs)(`div`,{className:`connect-page`,children:[m&&h&&(0,g.jsx)(`button`,{type:`button`,className:`connect-signout`,onClick:h,children:`Sign out`}),(0,g.jsxs)(`div`,{className:`connect-content`,children:[(0,g.jsx)(`img`,{src:t,alt:r.productName,className:`connect-logo connect-logo--maxy`}),!r.logoContainsName&&(0,g.jsx)(`h1`,{className:`connect-title`,children:r.productName}),(0,g.jsxs)(`form`,{onSubmit:f,className:`connect-pin-form`,children:[(0,g.jsxs)(`div`,{className:`pin-input-row`,children:[(0,g.jsx)(_,{inputRef:d,value:n,onChange:i,onComplete:()=>{},showPin:a,autoFocus:!0}),(0,g.jsx)(c,{variant:`send`,type:`submit`,disabled:!n,loading:s,children:(0,g.jsxs)(`svg`,{viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`,children:[(0,g.jsx)(`line`,{x1:`5`,y1:`12`,x2:`19`,y2:`12`}),(0,g.jsx)(`polyline`,{points:`12 5 19 12 12 19`})]})})]}),(0,g.jsxs)(`div`,{className:`pin-options`,children:[(0,g.jsx)(l,{checked:a,onChange:()=>o(e=>!e),label:`Show PIN`}),(0,g.jsx)(c,{type:`button`,variant:`ghost`,onClick:p,children:`Change PIN`})]})]}),u&&(0,g.jsx)(`p`,{className:`admin-pin-error`,children:u})]})]})}function b(e){let{accounts:n,loading:i,error:o,onSelect:s}=e;return(0,g.jsx)(`div`,{className:`connect-page`,children:(0,g.jsxs)(`div`,{className:`connect-content`,children:[(0,g.jsx)(`img`,{src:t,alt:r.productName,className:`connect-logo connect-logo--maxy`}),!r.logoContainsName&&(0,g.jsx)(`h1`,{className:`connect-title`,children:r.productName}),(0,g.jsx)(`p`,{className:`connect-subtitle`,children:`Select an account`}),(0,g.jsx)(`div`,{className:`account-picker-list`,children:n.map(e=>(0,g.jsxs)(`button`,{className:`account-picker-card`,onClick:()=>s(e.accountId),disabled:i,type:`button`,children:[(0,g.jsx)(`span`,{className:`account-picker-name`,children:e.businessName||e.accountId}),(0,g.jsx)(`span`,{className:`account-picker-role`,children:e.role}),i&&(0,g.jsx)(a,{className:`account-picker-spinner`,size:16})]},e.accountId))}),o&&(0,g.jsx)(`p`,{className:`admin-pin-error`,children:o})]})})}function x(e){let{authPolling:n,setAuthPolling:i,authLoading:a,setAuthLoading:o,pinError:s,setPinError:l,setAppState:u}=e,[d,f]=(0,m.useState)(!1),[p,h]=(0,m.useState)(!1);async function _(){h(!0),l(``);try{let e=await(await fetch(`/api/onboarding/claude-auth`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({action:`launch-browser`})})).json();e.launched?f(!0):e.error&&l(e.error)}catch(e){console.error(`[admin] browser launch error:`,e),l(`Could not launch browser.`)}h(!1)}async function v(){o(!0),l(``);try{let e=await(await fetch(`/api/onboarding/claude-auth`,{method:`POST`})).json();if(e.started){i(!0),f(!0),o(!1);for(let e=0;e<120;e++)if(await new Promise(e=>setTimeout(e,2e3)),(await(await fetch(`/api/onboarding/claude-auth`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({action:`wait`})})).json()).authenticated){await fetch(`/api/onboarding/claude-auth`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({action:`stop`})}),u(`enter-pin`);return}l(`Timed out waiting for sign-in. Try again.`),i(!1)}else e.error&&l(e.error)}catch(e){console.error(`[admin] auth flow error:`,e),l(`Could not start auth flow.`)}o(!1)}async function y(){await fetch(`/api/onboarding/claude-auth`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({action:`stop`})}),i(!1),l(``)}return n||d?(0,g.jsxs)(`div`,{style:{display:`flex`,flexDirection:`column`,height:`100dvh`,overflow:`auto`},children:[(0,g.jsxs)(`header`,{className:`chat-header`,style:{paddingBottom:`12px`,flexShrink:0,position:`relative`,maxWidth:`680px`,width:`100%`,margin:`0 auto`,padding:`24px 20px 12px`},children:[n?(0,g.jsx)(`button`,{onClick:y,style:{position:`absolute`,top:`12px`,right:`12px`,background:`none`,border:`none`,color:`#999`,fontSize:`13px`,cursor:`pointer`,padding:`4px 8px`},"aria-label":`Cancel`,children:`✕`}):(0,g.jsx)(`button`,{onClick:()=>f(!1),style:{position:`absolute`,top:`12px`,right:`12px`,background:`none`,border:`none`,color:`#999`,fontSize:`13px`,cursor:`pointer`,padding:`4px 8px`},"aria-label":`Close browser`,children:`✕`}),(0,g.jsx)(`img`,{src:`/brand/claude.png`,alt:`Claude`,className:`chat-logo`}),(0,g.jsx)(`h1`,{className:`chat-tagline`,children:`Connect Claude`}),(0,g.jsx)(`p`,{className:`chat-intro`,children:n?`Sign in and authorize in the browser below.`:`Open your email or prepare your accounts, then sign in.`}),!n&&(0,g.jsx)(`div`,{style:{marginTop:`12px`},children:(0,g.jsx)(c,{variant:`primary`,onClick:v,disabled:a,children:a?(0,g.jsxs)(g.Fragment,{children:[(0,g.jsx)(`span`,{className:`spin`,style:{display:`inline-block`},children:`✱`}),` Connecting…`]}):`Sign in to Claude`})})]}),(0,g.jsx)(`div`,{style:{flex:1,display:`flex`,flexDirection:`column`,minHeight:0,gap:`10px`,padding:`0 0 16px`},children:(0,g.jsx)(`iframe`,{src:`/vnc-viewer.html`,style:{flex:1,width:`100%`,minHeight:0,border:`none`,background:`#111`,display:`block`},title:`Claude Sign-in`})}),s&&(0,g.jsx)(`p`,{className:`admin-pin-error`,style:{textAlign:`center`,padding:`0 20px 16px`},children:s})]}):(0,g.jsx)(`div`,{className:`connect-page`,children:(0,g.jsxs)(`div`,{className:`connect-content`,children:[(0,g.jsxs)(`div`,{className:`connect-logos`,children:[(0,g.jsx)(`div`,{className:`connect-logo-wrap`,children:(0,g.jsx)(`img`,{src:`/brand/claude.png`,alt:`Claude`,className:`connect-logo`})}),(0,g.jsx)(`svg`,{className:`connect-arrow`,viewBox:`0 0 48 24`,fill:`none`,xmlns:`http://www.w3.org/2000/svg`,children:(0,g.jsx)(`path`,{d:`M0 12h44m0 0l-8-8m8 8l-8 8`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`})}),(0,g.jsxs)(`div`,{className:`connect-logo-wrap`,children:[(0,g.jsx)(`img`,{src:t,alt:r.productName,className:`connect-logo connect-logo--maxy`}),!r.logoContainsName&&(0,g.jsx)(`span`,{className:`connect-logo-label`,children:r.productName})]})]}),(0,g.jsxs)(`h1`,{className:`connect-title`,children:[`Connect Claude to power `,r.productName]}),(0,g.jsx)(`p`,{className:`connect-subtitle`,children:`Sign in with your Anthropic account to get started.`}),(0,g.jsx)(c,{variant:`primary`,onClick:v,disabled:a,children:a?(0,g.jsxs)(g.Fragment,{children:[(0,g.jsx)(`span`,{className:`spin`,style:{display:`inline-block`},children:`✱`}),` Connecting…`]}):`Sign in to Claude`}),(0,g.jsx)(`p`,{style:{marginTop:`6px`,fontSize:`11px`,color:`#999`,maxWidth:`300px`,textAlign:`center`,lineHeight:`1.4`},children:`First time? You may need to sign into your email and Anthropic account in the browser before connecting.`}),(0,g.jsx)(`button`,{onClick:_,disabled:p,style:{marginTop:`12px`,background:`none`,border:`none`,color:`var(--color-primary, #666)`,fontSize:`13px`,cursor:`pointer`,textDecoration:`underline`,textUnderlineOffset:`3px`},children:p?`Launching…`:`Open browser first`}),s&&(0,g.jsx)(`p`,{className:`admin-pin-error`,children:s})]})})}function S({auth:e}){return e.appState===`loading`?(0,g.jsx)(`div`,{className:`connect-page`}):e.appState===`set-pin`?(0,g.jsx)(v,{pin:e.pin,setPin:e.setPin,showPin:e.showPin,setShowPin:e.setShowPin,pinLoading:e.pinLoading,pinError:e.pinError,pinInputRef:e.pinInputRef,setPinFormRef:e.setPinFormRef,onSubmit:e.handleSetPin,operatorName:e.operatorName,setOperatorName:e.setOperatorName}):e.appState===`connect-claude`?(0,g.jsx)(x,{authPolling:e.authPolling,setAuthPolling:e.setAuthPolling,authLoading:e.authLoading,setAuthLoading:e.setAuthLoading,pinError:e.pinError,setPinError:e.setPinError,setAppState:e.setAppState}):e.appState===`enter-pin`?(0,g.jsx)(y,{pin:e.pin,setPin:e.setPin,showPin:e.showPin,setShowPin:e.setShowPin,pinLoading:e.pinLoading,pinError:e.pinError,pinInputRef:e.pinInputRef,onSubmit:e.handleLogin,onChangePin:e.handleChangePin,remoteAuthEnabled:e.remoteAuthEnabled,onSignOutRemote:()=>{console.info(`[admin-ui] remote-auth sign-out → /__remote-auth/logout`),window.location.href=`/__remote-auth/logout`}}):e.appState===`account-picker`?(0,g.jsx)(b,{accounts:e.accounts,loading:e.accountPickerLoading,error:e.pinError,onSelect:e.handleAccountSelect}):null}export{h as n,S as t};
|
|
1
|
+
import{o as e}from"./chunk-Pqm5yXtL.js";import{a as t,o as n,t as r,u as i}from"./brand-Dh5UlVO2.js";import{c as a,p as o}from"./file-download-BvGS7Qmi.js";import{p as s}from"./AdminShell-iazLHsk7.js";import{r as c}from"./useSelectionMode-FIodJKzS.js";import{t as l}from"./Checkbox-8elc7oXU.js";new Set(`image/jpeg,image/png,image/gif,image/webp,application/pdf,text/plain,text/markdown,text/csv,text/html,text/calendar,application/zip,application/x-zip-compressed,audio/ogg,audio/opus,audio/mp4,audio/mpeg,audio/webm,audio/wav,.opus,.ogg,.m4a,.mp3,.wav,.webm`.split(`,`).filter(e=>!e.startsWith(`.`)));function u(e){switch(e){case`expanded`:return!0;case`collapsed`:return!1;default:return}}var d=`admin-landing-redirected`,f=`/graph`;function p(e){return e.variant===`operator`?!1:e.appState===`chat`&&!e.alreadyRedirected}var m=e(i(),1);function h(e=`admin`){let[t,n]=(0,m.useState)(`loading`),[r,i]=(0,m.useState)(``),[a,c]=(0,m.useState)(``),[l,h]=(0,m.useState)(``),[g,_]=(0,m.useState)(!1),[v,y]=(0,m.useState)(!1),[b,x]=(0,m.useState)(!1),[S,C]=(0,m.useState)(!1),[w,T]=(0,m.useState)(!1),[E,D]=(0,m.useState)(null),[O,k]=(0,m.useState)(null),[A,j]=(0,m.useState)(void 0),[M,N]=(0,m.useState)(null),[P,F]=(0,m.useState)(void 0),[I,L]=(0,m.useState)(null),[ee,R]=(0,m.useState)(null),[z,B]=(0,m.useState)([]),[V,H]=(0,m.useState)(!1),[U,W]=(0,m.useState)(void 0),G=(0,m.useRef)(void 0),[K,q]=(0,m.useState)(!1);(0,m.useEffect)(()=>{typeof window>`u`||fetch(`/api/remote-auth/status`).then(e=>e.ok?e.json():null).then(e=>{e?.configured&&q(!0)}).catch(()=>{})},[]);let J=(0,m.useRef)(null),Y=(0,m.useRef)(null);(0,m.useEffect)(()=>{async function e(){let e=null;try{e=sessionStorage.getItem(`maxy-admin-session-key`)}catch{}if(!e)return!1;try{let t=await fetch(`/api/admin/session?session_key=${encodeURIComponent(e)}`);if(t.status===401){try{sessionStorage.removeItem(`maxy-admin-session-key`)}catch{}return!1}if(!t.ok)return!1;let r=await t.json();D(r.session_key),R(r.sessionId??null),j(r.businessName),N(r.role??null),F(r.userName===void 0?null:r.userName),L(r.avatar??null);let i=u(r.thinkingView);return G.current=i,W(i),n(`chat`),!0}catch(e){return console.error(`[admin] session restore failed:`,e),!1}}async function t(r=2){try{let i=await fetch(`/api/health`);if(!i.ok){if(r>0)return await new Promise(e=>setTimeout(e,1500)),t(r-1);console.error(`[admin] health check returned ${i.status} after retries`),n(`set-pin`);return}let a=await i.json();if(!a.pin_configured){n(`set-pin`);return}if(!a.claude_authenticated){n(`connect-claude`);return}if(await e())return;n(`enter-pin`)}catch(e){if(r>0)return await new Promise(e=>setTimeout(e,1500)),t(r-1);console.error(`[admin] health check failed:`,e),n(`set-pin`)}}t()},[]),(0,m.useEffect)(()=>{t===`chat`&&fetch(`/api/admin/claude-info`).then(e=>{if(e.ok)return e.json()}).then(e=>{e&&k(e)}).catch(()=>{})},[t]),(0,m.useEffect)(()=>{if(typeof window>`u`)return;let n=!1;try{n=sessionStorage.getItem(d)===`1`}catch{}if(p({appState:t,alreadyRedirected:n,variant:e})){try{sessionStorage.setItem(d,`1`)}catch{}console.info(`[admin-ui] landing-redirect target=${f}`),window.location.replace(f)}},[t,e]);let X=(0,m.useRef)(null);(0,m.useEffect)(()=>{if(t!==`chat`)return;let e=setInterval(async()=>{try{let e=await fetch(`/api/health`);if(e.ok){let t=await e.json();if(t.auth_status===`dead`||t.auth_status===`missing`){n(`connect-claude`);return}}}catch{}if(E)try{let e=await fetch(`/api/admin/session?session_key=${encodeURIComponent(E)}`);if(e.status!==401)return;let t=(await e.clone().json().catch(()=>null))?.code??`unknown-401`;if(t===`remote-auth-required`){o(`heartbeat`,`/api/admin/session`);return}console.warn(`[admin-auth] outcome=heartbeat-detected-expiry code=${t}`),X.current?.()}catch{}},300*1e3);return()=>clearInterval(e)},[t,E]),(0,m.useEffect)(()=>{t===`connect-claude`&&fetch(`/api/health`).then(e=>e.ok?e.json():null).then(e=>{e?.claude_authenticated&&n(`enter-pin`)}).catch(()=>{})},[t]);async function Z(e,t){y(!0);try{let r=await fetch(`/api/admin/session`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({pin:e,...t?{accountId:t}:{}})});if(!r.ok){h((await r.json().catch(()=>({}))).error||`Invalid PIN`);return}let a=await r.json();if(a.accounts&&!a.session_key){console.log(`[admin] account picker shown: userId=${a.userId} accountCount=${a.accounts.length}`),B(a.accounts),n(`account-picker`);return}D(a.session_key),R(a.sessionId??null),j(a.businessName),N(a.role??null),F(a.userName===void 0?null:a.userName),L(a.avatar??null);let o=u(a.thinkingView);if(G.current=o,W(o),t)try{sessionStorage.setItem(`maxy-account-id`,t)}catch{}try{sessionStorage.setItem(`maxy-admin-session-key`,a.session_key)}catch{}i(``),n(`chat`)}catch(e){console.error(`[admin] connection error:`,e),h(`Could not connect.`)}finally{y(!1),H(!1)}}let Q=(0,m.useCallback)(async e=>{if(e.preventDefault(),v)return;h(``);let t=a.trim();if(!t){h(`Please enter your name.`);return}if(r.length<4){h(`PIN must be at least 4 characters.`);return}let o=r;y(!0);try{let e=await fetch(`/api/onboarding/set-pin`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({pin:o,name:t})});if(!e.ok){let t=await e.json().catch(()=>({}));if(e.status===409){console.log(`[admin] PIN already configured — re-checking health`);try{let e=await fetch(`/api/health`);if(e.ok){let r=await e.json();r.pin_configured&&r.claude_authenticated?n(`enter-pin`):r.pin_configured?n(`connect-claude`):h(t.error||`Failed to set PIN.`)}else n(`enter-pin`)}catch{n(`enter-pin`)}return}h(t.error||`Failed to set PIN.`);return}let r=await fetch(`/api/health`);if((r.ok?await r.json():null)?.claude_authenticated){await Z(o);return}i(``),n(`connect-claude`)}catch(e){console.error(`[admin] connection error:`,e),h(`Could not connect.`)}finally{y(!1)}},[r,v,a]),te=(0,m.useCallback)(async e=>{e.preventDefault(),h(``),await Z(r)},[r]),ne=(0,m.useCallback)(async()=>{T(!0);try{if(!await s())return console.warn(`[admin-ui] claude-disconnect not verified — credentials may persist; staying put`),!1;D(null),N(null),F(void 0),L(null);try{sessionStorage.removeItem(`maxy-admin-session-key`),sessionStorage.removeItem(`maxy-account-id`),sessionStorage.removeItem(d)}catch{}return n(`connect-claude`),!0}finally{T(!1)}},[]),$=(0,m.useCallback)(()=>{D(null),N(null),F(void 0),L(null);try{sessionStorage.removeItem(`maxy-admin-session-key`),sessionStorage.removeItem(`maxy-account-id`),sessionStorage.removeItem(d)}catch{}i(``),h(``),n(`enter-pin`)},[]);return(0,m.useEffect)(()=>{X.current=$},[$]),{appState:t,setAppState:n,pin:r,setPin:i,operatorName:a,setOperatorName:c,pinError:l,setPinError:h,showPin:g,setShowPin:_,pinLoading:v,authPolling:b,setAuthPolling:x,authLoading:S,setAuthLoading:C,disconnecting:w,cacheKey:E,setCacheKey:D,claudeInfo:O,setClaudeInfo:k,businessName:A,role:M,userName:P,userAvatar:I,sessionId:ee,setSessionId:R,accounts:z,accountPickerLoading:V,expandAll:U,setExpandAll:W,expandAllDefaultRef:G,remoteAuthEnabled:K,pinInputRef:J,setPinFormRef:Y,handleSetPin:Q,handleLogin:te,handleAccountSelect:(0,m.useCallback)(async e=>{H(!0),h(``),await Z(r,e)},[r]),handleDisconnect:ne,handleLogout:$,handleChangePin:(0,m.useCallback)(async()=>{if(!r){h(`Enter your current PIN first.`);return}y(!0),h(``);try{let e=await fetch(`/api/onboarding/set-pin`,{method:`DELETE`,headers:{"Content-Type":`application/json`},body:JSON.stringify({currentPin:r})});if(!e.ok){h((await e.json().catch(()=>({error:`Incorrect PIN.`}))).error||`Incorrect PIN.`);return}i(``),h(``),n(`set-pin`)}catch(e){console.error(`[admin-auth] change pin failed:`,e),h(e instanceof Error?e.message:String(e))}finally{y(!1)}},[r])}}var g=n();function _({inputRef:e,value:t,onChange:n,onComplete:r,showPin:i,autoFocus:a}){let o=(0,m.useRef)([]);function s(e,r){r.key===`Backspace`?(r.preventDefault(),t[e]?n(t.slice(0,e)+t.slice(e+1)):e>0&&(n(t.slice(0,e-1)+t.slice(e)),o.current[e-1]?.focus())):r.key===`ArrowLeft`&&e>0?o.current[e-1]?.focus():r.key===`ArrowRight`&&e<5?o.current[e+1]?.focus():r.key===`Enter`&&(r.preventDefault(),r.currentTarget.form?.requestSubmit())}function c(e,i){let a=i.nativeEvent.data;if(!a||!/^\d$/.test(a))return;let s=t.split(``);for(s[e]=a;s.length<e;)s.push(``);let c=s.join(``).replace(/\D/g,``).slice(0,6);n(c),c.length===6?r?.(c):e<5&&o.current[e+1]?.focus()}function l(e){e.preventDefault();let t=e.clipboardData.getData(`text`).replace(/\D/g,``).slice(0,6);t&&(n(t),t.length===6?r?.(t):o.current[t.length]?.focus())}return(0,g.jsx)(`div`,{className:`pin-field`,children:Array.from({length:6}).map((n,r)=>(0,g.jsx)(`input`,{ref:t=>{o.current[r]=t,r===0&&e&&(e.current=t)},type:`text`,inputMode:`numeric`,className:`pin-box${t[r]?` pin-box-filled`:``}`,value:t[r]?i?t[r]:`•`:``,onKeyDown:e=>s(r,e),onInput:e=>c(r,e),onPaste:l,onFocus:e=>e.target.select(),autoFocus:a&&r===0,autoComplete:`off`,maxLength:1,"aria-label":`PIN digit ${r+1}`},r))})}function v(e){let{pin:n,setPin:i,showPin:a,setShowPin:o,pinLoading:s,pinError:u,pinInputRef:d,setPinFormRef:f,onSubmit:p,operatorName:m,setOperatorName:h}=e;return(0,g.jsx)(`div`,{className:`connect-page`,children:(0,g.jsxs)(`div`,{className:`connect-content`,children:[(0,g.jsx)(`img`,{src:t,alt:r.productName,className:`connect-logo connect-logo--maxy`}),!r.logoContainsName&&(0,g.jsxs)(`h1`,{className:`connect-title`,children:[`Welcome to `,r.productName]}),(0,g.jsxs)(`p`,{className:`connect-subtitle`,children:[`Tell `,r.productName,` who you are, then choose a PIN.`]}),(0,g.jsxs)(`form`,{ref:f,onSubmit:p,className:`connect-pin-form`,children:[(0,g.jsxs)(`div`,{className:`pin-input-row`,children:[(0,g.jsx)(`input`,{type:`text`,className:`connect-name-input`,placeholder:`Your full name`,value:m,onChange:e=>h(e.target.value),autoComplete:`name`,autoFocus:!0,required:!0,"aria-label":`Your full name`}),(0,g.jsx)(`div`,{style:{width:38,flexShrink:0},"aria-hidden":`true`})]}),(0,g.jsxs)(`div`,{className:`pin-input-row`,children:[(0,g.jsx)(_,{inputRef:d,value:n,onChange:i,onComplete:()=>{},showPin:a}),(0,g.jsx)(c,{variant:`send`,type:`submit`,disabled:!n||!m.trim(),loading:s,"aria-label":`Set PIN`,children:(0,g.jsxs)(`svg`,{viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`,children:[(0,g.jsx)(`line`,{x1:`5`,y1:`12`,x2:`19`,y2:`12`}),(0,g.jsx)(`polyline`,{points:`12 5 19 12 12 19`})]})})]}),(0,g.jsx)(l,{checked:a,onChange:()=>o(e=>!e),label:`Show PIN`})]}),u&&(0,g.jsx)(`p`,{className:`admin-pin-error`,children:u})]})})}function y(e){let{pin:n,setPin:i,showPin:a,setShowPin:o,pinLoading:s,pinError:u,pinInputRef:d,onSubmit:f,onChangePin:p,remoteAuthEnabled:m,onSignOutRemote:h}=e;return(0,g.jsxs)(`div`,{className:`connect-page`,children:[m&&h&&(0,g.jsx)(`button`,{type:`button`,className:`connect-signout`,onClick:h,children:`Sign out`}),(0,g.jsxs)(`div`,{className:`connect-content`,children:[(0,g.jsx)(`img`,{src:t,alt:r.productName,className:`connect-logo connect-logo--maxy`}),!r.logoContainsName&&(0,g.jsx)(`h1`,{className:`connect-title`,children:r.productName}),(0,g.jsxs)(`form`,{onSubmit:f,className:`connect-pin-form`,children:[(0,g.jsxs)(`div`,{className:`pin-input-row`,children:[(0,g.jsx)(_,{inputRef:d,value:n,onChange:i,onComplete:()=>{},showPin:a,autoFocus:!0}),(0,g.jsx)(c,{variant:`send`,type:`submit`,disabled:!n,loading:s,children:(0,g.jsxs)(`svg`,{viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`,children:[(0,g.jsx)(`line`,{x1:`5`,y1:`12`,x2:`19`,y2:`12`}),(0,g.jsx)(`polyline`,{points:`12 5 19 12 12 19`})]})})]}),(0,g.jsxs)(`div`,{className:`pin-options`,children:[(0,g.jsx)(l,{checked:a,onChange:()=>o(e=>!e),label:`Show PIN`}),(0,g.jsx)(c,{type:`button`,variant:`ghost`,onClick:p,children:`Change PIN`})]})]}),u&&(0,g.jsx)(`p`,{className:`admin-pin-error`,children:u})]})]})}function b(e){let{accounts:n,loading:i,error:o,onSelect:s}=e;return(0,g.jsx)(`div`,{className:`connect-page`,children:(0,g.jsxs)(`div`,{className:`connect-content`,children:[(0,g.jsx)(`img`,{src:t,alt:r.productName,className:`connect-logo connect-logo--maxy`}),!r.logoContainsName&&(0,g.jsx)(`h1`,{className:`connect-title`,children:r.productName}),(0,g.jsx)(`p`,{className:`connect-subtitle`,children:`Select an account`}),(0,g.jsx)(`div`,{className:`account-picker-list`,children:n.map(e=>(0,g.jsxs)(`button`,{className:`account-picker-card`,onClick:()=>s(e.accountId),disabled:i,type:`button`,children:[(0,g.jsx)(`span`,{className:`account-picker-name`,children:e.businessName||e.accountId}),(0,g.jsx)(`span`,{className:`account-picker-role`,children:e.role}),i&&(0,g.jsx)(a,{className:`account-picker-spinner`,size:16})]},e.accountId))}),o&&(0,g.jsx)(`p`,{className:`admin-pin-error`,children:o})]})})}function x(e){let{authPolling:n,setAuthPolling:i,authLoading:a,setAuthLoading:o,pinError:s,setPinError:l,setAppState:u}=e,[d,f]=(0,m.useState)(!1),[p,h]=(0,m.useState)(!1);async function _(){h(!0),l(``);try{let e=await(await fetch(`/api/onboarding/claude-auth`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({action:`launch-browser`})})).json();e.launched?f(!0):e.error&&l(e.error)}catch(e){console.error(`[admin] browser launch error:`,e),l(`Could not launch browser.`)}h(!1)}async function v(){o(!0),l(``);try{let e=await(await fetch(`/api/onboarding/claude-auth`,{method:`POST`})).json();if(e.started){i(!0),f(!0),o(!1);for(let e=0;e<120;e++)if(await new Promise(e=>setTimeout(e,2e3)),(await(await fetch(`/api/onboarding/claude-auth`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({action:`wait`})})).json()).authenticated){await fetch(`/api/onboarding/claude-auth`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({action:`stop`})}),u(`enter-pin`);return}l(`Timed out waiting for sign-in. Try again.`),i(!1)}else e.error&&l(e.error)}catch(e){console.error(`[admin] auth flow error:`,e),l(`Could not start auth flow.`)}o(!1)}async function y(){await fetch(`/api/onboarding/claude-auth`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({action:`stop`})}),i(!1),l(``)}return n||d?(0,g.jsxs)(`div`,{style:{display:`flex`,flexDirection:`column`,height:`100dvh`,overflow:`auto`},children:[(0,g.jsxs)(`header`,{className:`chat-header`,style:{paddingBottom:`12px`,flexShrink:0,position:`relative`,maxWidth:`680px`,width:`100%`,margin:`0 auto`,padding:`24px 20px 12px`},children:[n?(0,g.jsx)(`button`,{onClick:y,style:{position:`absolute`,top:`12px`,right:`12px`,background:`none`,border:`none`,color:`#999`,fontSize:`13px`,cursor:`pointer`,padding:`4px 8px`},"aria-label":`Cancel`,children:`✕`}):(0,g.jsx)(`button`,{onClick:()=>f(!1),style:{position:`absolute`,top:`12px`,right:`12px`,background:`none`,border:`none`,color:`#999`,fontSize:`13px`,cursor:`pointer`,padding:`4px 8px`},"aria-label":`Close browser`,children:`✕`}),(0,g.jsx)(`img`,{src:`/brand/claude.png`,alt:`Claude`,className:`chat-logo`}),(0,g.jsx)(`h1`,{className:`chat-tagline`,children:`Connect Claude`}),(0,g.jsx)(`p`,{className:`chat-intro`,children:n?`Sign in and authorize in the browser below.`:`Open your email or prepare your accounts, then sign in.`}),!n&&(0,g.jsx)(`div`,{style:{marginTop:`12px`},children:(0,g.jsx)(c,{variant:`primary`,onClick:v,disabled:a,children:a?(0,g.jsxs)(g.Fragment,{children:[(0,g.jsx)(`span`,{className:`spin`,style:{display:`inline-block`},children:`✱`}),` Connecting…`]}):`Sign in to Claude`})})]}),(0,g.jsx)(`div`,{style:{flex:1,display:`flex`,flexDirection:`column`,minHeight:0,gap:`10px`,padding:`0 0 16px`},children:(0,g.jsx)(`iframe`,{src:`/vnc-viewer.html`,style:{flex:1,width:`100%`,minHeight:0,border:`none`,background:`#111`,display:`block`},title:`Claude Sign-in`})}),s&&(0,g.jsx)(`p`,{className:`admin-pin-error`,style:{textAlign:`center`,padding:`0 20px 16px`},children:s})]}):(0,g.jsx)(`div`,{className:`connect-page`,children:(0,g.jsxs)(`div`,{className:`connect-content`,children:[(0,g.jsxs)(`div`,{className:`connect-logos`,children:[(0,g.jsx)(`div`,{className:`connect-logo-wrap`,children:(0,g.jsx)(`img`,{src:`/brand/claude.png`,alt:`Claude`,className:`connect-logo`})}),(0,g.jsx)(`svg`,{className:`connect-arrow`,viewBox:`0 0 48 24`,fill:`none`,xmlns:`http://www.w3.org/2000/svg`,children:(0,g.jsx)(`path`,{d:`M0 12h44m0 0l-8-8m8 8l-8 8`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`})}),(0,g.jsxs)(`div`,{className:`connect-logo-wrap`,children:[(0,g.jsx)(`img`,{src:t,alt:r.productName,className:`connect-logo connect-logo--maxy`}),!r.logoContainsName&&(0,g.jsx)(`span`,{className:`connect-logo-label`,children:r.productName})]})]}),(0,g.jsxs)(`h1`,{className:`connect-title`,children:[`Connect Claude to power `,r.productName]}),(0,g.jsx)(`p`,{className:`connect-subtitle`,children:`Sign in with your Anthropic account to get started.`}),(0,g.jsx)(c,{variant:`primary`,onClick:v,disabled:a,children:a?(0,g.jsxs)(g.Fragment,{children:[(0,g.jsx)(`span`,{className:`spin`,style:{display:`inline-block`},children:`✱`}),` Connecting…`]}):`Sign in to Claude`}),(0,g.jsx)(`p`,{style:{marginTop:`6px`,fontSize:`11px`,color:`#999`,maxWidth:`300px`,textAlign:`center`,lineHeight:`1.4`},children:`First time? You may need to sign into your email and Anthropic account in the browser before connecting.`}),(0,g.jsx)(`button`,{onClick:_,disabled:p,style:{marginTop:`12px`,background:`none`,border:`none`,color:`var(--color-primary, #666)`,fontSize:`13px`,cursor:`pointer`,textDecoration:`underline`,textUnderlineOffset:`3px`},children:p?`Launching…`:`Open browser first`}),s&&(0,g.jsx)(`p`,{className:`admin-pin-error`,children:s})]})})}function S({auth:e}){return e.appState===`loading`?(0,g.jsx)(`div`,{className:`connect-page`}):e.appState===`set-pin`?(0,g.jsx)(v,{pin:e.pin,setPin:e.setPin,showPin:e.showPin,setShowPin:e.setShowPin,pinLoading:e.pinLoading,pinError:e.pinError,pinInputRef:e.pinInputRef,setPinFormRef:e.setPinFormRef,onSubmit:e.handleSetPin,operatorName:e.operatorName,setOperatorName:e.setOperatorName}):e.appState===`connect-claude`?(0,g.jsx)(x,{authPolling:e.authPolling,setAuthPolling:e.setAuthPolling,authLoading:e.authLoading,setAuthLoading:e.setAuthLoading,pinError:e.pinError,setPinError:e.setPinError,setAppState:e.setAppState}):e.appState===`enter-pin`?(0,g.jsx)(y,{pin:e.pin,setPin:e.setPin,showPin:e.showPin,setShowPin:e.setShowPin,pinLoading:e.pinLoading,pinError:e.pinError,pinInputRef:e.pinInputRef,onSubmit:e.handleLogin,onChangePin:e.handleChangePin,remoteAuthEnabled:e.remoteAuthEnabled,onSignOutRemote:()=>{console.info(`[admin-ui] remote-auth sign-out → /__remote-auth/logout`),window.location.href=`/__remote-auth/logout`}}):e.appState===`account-picker`?(0,g.jsx)(b,{accounts:e.accounts,loading:e.accountPickerLoading,error:e.pinError,onSelect:e.handleAccountSelect}):null}export{h as n,S as t};
|