@rubytech/create-maxy-code 0.1.561 → 0.1.563
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/plugins/admin/hooks/__tests__/datetime-inject.test.sh +10 -0
- package/payload/platform/plugins/admin/hooks/__tests__/mailbox-inject.test.sh +15 -2
- package/payload/platform/plugins/admin/hooks/__tests__/preference-consult-directive.test.sh +6 -0
- package/payload/platform/plugins/admin/hooks/__tests__/prompt-optimiser-directive.test.sh +10 -0
- package/payload/platform/plugins/admin/hooks/datetime-inject.sh +10 -0
- package/payload/platform/plugins/admin/hooks/mailbox-inject.sh +14 -0
- package/payload/platform/plugins/admin/hooks/preference-consult-directive.sh +9 -0
- package/payload/platform/plugins/admin/hooks/prompt-optimiser-directive.sh +10 -0
- package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +21 -11
- package/payload/platform/plugins/admin/skills/whats-new/SKILL.md +11 -0
- package/payload/platform/plugins/cloudflare/bin/portal-enrol.mjs +19 -5
- package/payload/platform/plugins/cloudflare/mcp/__tests__/authorize.test.ts +6 -0
- package/payload/platform/plugins/cloudflare/mcp/__tests__/portal-enrol.test.ts +77 -6
- package/payload/platform/plugins/cloudflare/mcp/__tests__/portal-session-grant.test.ts +39 -0
- package/payload/platform/plugins/cloudflare/mcp/__tests__/portal-visit-status-write.test.ts +176 -0
- package/payload/platform/plugins/cloudflare/mcp/__tests__/portal-visits-scope.test.ts +112 -0
- package/payload/platform/plugins/cloudflare/skills/data-portal/SKILL.md +23 -0
- package/payload/platform/plugins/cloudflare/skills/data-portal/schema.sql +94 -0
- package/payload/platform/plugins/cloudflare/skills/data-portal/template/functions/api/_lib/session.ts +31 -4
- package/payload/platform/plugins/cloudflare/skills/data-portal/template/functions/api/visit-status.ts +136 -0
- package/payload/platform/plugins/cloudflare/skills/data-portal/template/functions/api/visits.ts +93 -0
- package/payload/platform/plugins/docs/references/deployment.md +14 -8
- package/payload/platform/plugins/docs/references/internals.md +2 -0
- package/payload/platform/plugins/docs/references/platform.md +4 -2
- package/payload/platform/scripts/__tests__/public-prompt-gate-registered.test.sh +114 -0
- package/payload/platform/scripts/smoke-boot-services.sh +14 -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 +26 -10
- package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/index.js +16 -0
- package/payload/platform/services/claude-session-manager/dist/index.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/public-prompt-surface.d.ts +56 -0
- package/payload/platform/services/claude-session-manager/dist/public-prompt-surface.d.ts.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/public-prompt-surface.js +155 -0
- package/payload/platform/services/claude-session-manager/dist/public-prompt-surface.js.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/rc-public-lockdown.d.ts +6 -0
- package/payload/platform/services/claude-session-manager/dist/rc-public-lockdown.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/rc-public-lockdown.js +1 -1
- package/payload/platform/services/claude-session-manager/dist/rc-public-lockdown.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/system-prompt.d.ts +4 -0
- package/payload/platform/services/claude-session-manager/dist/system-prompt.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/system-prompt.js +45 -27
- package/payload/platform/services/claude-session-manager/dist/system-prompt.js.map +1 -1
- package/payload/platform/templates/agents/public/IDENTITY.md +3 -3
- package/payload/server/maxy-edge.js +302 -33
- package/payload/server/public/activity.html +5 -5
- package/payload/server/public/agents.html +4 -4
- package/payload/server/public/assets/{AdminLoginScreens-DLogIsJT.js → AdminLoginScreens-C6e5jf0S.js} +1 -1
- package/payload/server/public/assets/AdminLoginScreens-C6e5jf0S.js.br +0 -0
- package/payload/server/public/assets/AdminLoginScreens-C6e5jf0S.js.gz +0 -0
- package/payload/server/public/assets/AdminShell-DStA0lfm.js +3 -0
- package/payload/server/public/assets/AdminShell-DStA0lfm.js.br +0 -0
- package/payload/server/public/assets/AdminShell-DStA0lfm.js.gz +0 -0
- package/payload/server/public/assets/{activity-AVJSFESV.js → activity--yyBcNfB.js} +1 -1
- package/payload/server/public/assets/activity--yyBcNfB.js.br +0 -0
- package/payload/server/public/assets/activity--yyBcNfB.js.gz +0 -0
- package/payload/server/public/assets/{admin-eFgbld42.js → admin-Dr6Jwe7W.js} +1 -1
- package/payload/server/public/assets/admin-Dr6Jwe7W.js.br +0 -0
- package/payload/server/public/assets/admin-Dr6Jwe7W.js.gz +0 -0
- package/payload/server/public/assets/{agents-CoWLZMf7.js → agents-odyVOb5E.js} +1 -1
- package/payload/server/public/assets/agents-odyVOb5E.js.br +0 -0
- package/payload/server/public/assets/agents-odyVOb5E.js.gz +0 -0
- package/payload/server/public/assets/{browser-C6K66_fw.js → browser-D1K_MoHt.js} +1 -1
- package/payload/server/public/assets/browser-D1K_MoHt.js.br +0 -0
- package/payload/server/public/assets/browser-D1K_MoHt.js.gz +0 -0
- package/payload/server/public/assets/{calendar-Dnw_cP4b.js → calendar-jqh9U7Ic.js} +1 -1
- package/payload/server/public/assets/calendar-jqh9U7Ic.js.br +0 -0
- package/payload/server/public/assets/calendar-jqh9U7Ic.js.gz +0 -0
- package/payload/server/public/assets/chat-QQHBdVor.js +1 -0
- package/payload/server/public/assets/chat-QQHBdVor.js.br +0 -0
- package/payload/server/public/assets/chat-QQHBdVor.js.gz +0 -0
- package/payload/server/public/assets/chevron-left-DwTXgKwr.js +1 -0
- package/payload/server/public/assets/clock-DOmh9iKX.js +1 -0
- package/payload/server/public/assets/clock-DOmh9iKX.js.br +0 -0
- package/payload/server/public/assets/{copy-kuNM0Etw.js → copy-DkuHwkaB.js} +1 -1
- package/payload/server/public/assets/copy-DkuHwkaB.js.br +0 -0
- package/payload/server/public/assets/copy-DkuHwkaB.js.gz +0 -0
- package/payload/server/public/assets/data-DYmTNqrb.js +1 -0
- package/payload/server/public/assets/data-DYmTNqrb.js.br +0 -0
- package/payload/server/public/assets/data-DYmTNqrb.js.gz +0 -0
- package/payload/server/public/assets/{file-text-BWkobrcx.js → file-text-C6o_NRjj.js} +1 -1
- package/payload/server/public/assets/file-text-C6o_NRjj.js.br +0 -0
- package/payload/server/public/assets/file-text-C6o_NRjj.js.gz +0 -0
- package/payload/server/public/assets/{graph-BGjTL5Vz.js → graph-BN30v5hJ.js} +1 -1
- package/payload/server/public/assets/graph-BN30v5hJ.js.br +0 -0
- package/payload/server/public/assets/graph-BN30v5hJ.js.gz +0 -0
- package/payload/server/public/assets/{graph-labels-Dvc5Kw_r.js → graph-labels-DHFyNXQt.js} +1 -1
- package/payload/server/public/assets/graph-labels-DHFyNXQt.js.br +0 -0
- package/payload/server/public/assets/graph-labels-DHFyNXQt.js.gz +0 -0
- package/payload/server/public/assets/{operator-CzBGv_he.js → operator-DwFYA4Fp.js} +1 -1
- package/payload/server/public/assets/operator-DwFYA4Fp.js.br +0 -0
- package/payload/server/public/assets/operator-DwFYA4Fp.js.gz +0 -0
- package/payload/server/public/assets/{page-DaySqamH.js → page-BALVRssF.js} +1 -1
- package/payload/server/public/assets/page-BALVRssF.js.br +0 -0
- package/payload/server/public/assets/page-BALVRssF.js.gz +0 -0
- package/payload/server/public/assets/{page-BIY4Ku8Q.js → page-CEWIP3VF.js} +1 -1
- package/payload/server/public/assets/page-CEWIP3VF.js.br +0 -0
- package/payload/server/public/assets/page-CEWIP3VF.js.gz +0 -0
- package/payload/server/public/assets/play-Bg-BY_oj.js +1 -0
- package/payload/server/public/assets/play-Bg-BY_oj.js.br +0 -0
- package/payload/server/public/assets/play-Bg-BY_oj.js.gz +0 -0
- package/payload/server/public/assets/{public-pwDSvhBv.js → public-Ceb0n7Km.js} +1 -1
- package/payload/server/public/assets/public-Ceb0n7Km.js.br +0 -0
- package/payload/server/public/assets/public-Ceb0n7Km.js.gz +0 -0
- package/payload/server/public/assets/{rotate-ccw-B6s7tkEt.js → rotate-ccw-CDYdx91V.js} +1 -1
- package/payload/server/public/assets/rotate-ccw-CDYdx91V.js.gz +0 -0
- package/payload/server/public/assets/{routines-CFlyRdYg.js → routines-DwNTih0y.js} +1 -1
- package/payload/server/public/assets/routines-DwNTih0y.js.br +0 -0
- package/payload/server/public/assets/routines-DwNTih0y.js.gz +0 -0
- package/payload/server/public/assets/{skills-C45kfL_Q.js → skills-TIDCdOLQ.js} +1 -1
- package/payload/server/public/assets/skills-TIDCdOLQ.js.br +0 -0
- package/payload/server/public/assets/skills-TIDCdOLQ.js.gz +0 -0
- package/payload/server/public/assets/{tasks-BwoCTCu5.js → tasks-eTXvaWnd.js} +1 -1
- package/payload/server/public/assets/tasks-eTXvaWnd.js.br +0 -0
- package/payload/server/public/assets/tasks-eTXvaWnd.js.gz +0 -0
- package/payload/server/public/assets/{triangle-alert-B3bthSzx.js → triangle-alert-JwLSrj17.js} +1 -1
- package/payload/server/public/assets/triangle-alert-JwLSrj17.js.br +0 -0
- package/payload/server/public/assets/triangle-alert-JwLSrj17.js.gz +0 -0
- package/payload/server/public/assets/{useCopyFeedback-BzJAkFEb.js → useCopyFeedback-DjTkNw2p.js} +1 -1
- package/payload/server/public/assets/useCopyFeedback-DjTkNw2p.js.br +0 -0
- package/payload/server/public/assets/useCopyFeedback-DjTkNw2p.js.gz +0 -0
- package/payload/server/public/assets/useMediaQuery-BsBzbWaf.css +1 -0
- package/payload/server/public/assets/useMediaQuery-BsBzbWaf.css.br +0 -0
- package/payload/server/public/assets/useMediaQuery-BsBzbWaf.css.gz +0 -0
- package/payload/server/public/assets/useMediaQuery-D8VDA0RN.js +14 -0
- package/payload/server/public/assets/useMediaQuery-D8VDA0RN.js.br +0 -0
- package/payload/server/public/assets/useMediaQuery-D8VDA0RN.js.gz +0 -0
- package/payload/server/public/assets/{useVoiceRecorder-_qI_BAOo.js → useVoiceRecorder-B8vxObZG.js} +1 -1
- package/payload/server/public/assets/useVoiceRecorder-B8vxObZG.js.br +0 -0
- package/payload/server/public/assets/useVoiceRecorder-B8vxObZG.js.gz +0 -0
- package/payload/server/public/assets/{wrench-Bqux9jaw.js → wrench-DutUiRu7.js} +1 -1
- package/payload/server/public/assets/wrench-DutUiRu7.js.br +0 -0
- package/payload/server/public/assets/wrench-DutUiRu7.js.gz +0 -0
- package/payload/server/public/browser.html +4 -4
- package/payload/server/public/calendar.html +7 -7
- package/payload/server/public/chat.html +13 -13
- package/payload/server/public/data.html +11 -11
- package/payload/server/public/graph.html +9 -9
- package/payload/server/public/index.html +13 -13
- package/payload/server/public/operator.html +14 -14
- package/payload/server/public/public.html +13 -13
- package/payload/server/public/routines.html +7 -7
- package/payload/server/public/skills.html +5 -5
- package/payload/server/public/tasks.html +6 -6
- package/payload/server/server.js +1118 -636
- package/payload/server/public/assets/AdminLoginScreens-DLogIsJT.js.br +0 -0
- package/payload/server/public/assets/AdminLoginScreens-DLogIsJT.js.gz +0 -0
- package/payload/server/public/assets/AdminShell-B67tPTyE.js +0 -2
- package/payload/server/public/assets/AdminShell-B67tPTyE.js.br +0 -0
- package/payload/server/public/assets/AdminShell-B67tPTyE.js.gz +0 -0
- package/payload/server/public/assets/activity-AVJSFESV.js.br +0 -0
- package/payload/server/public/assets/activity-AVJSFESV.js.gz +0 -0
- package/payload/server/public/assets/admin-eFgbld42.js.br +0 -0
- package/payload/server/public/assets/admin-eFgbld42.js.gz +0 -0
- package/payload/server/public/assets/agents-CoWLZMf7.js.br +0 -0
- package/payload/server/public/assets/agents-CoWLZMf7.js.gz +0 -0
- package/payload/server/public/assets/browser-C6K66_fw.js.br +0 -0
- package/payload/server/public/assets/browser-C6K66_fw.js.gz +0 -0
- package/payload/server/public/assets/calendar-Dnw_cP4b.js.br +0 -0
- package/payload/server/public/assets/calendar-Dnw_cP4b.js.gz +0 -0
- package/payload/server/public/assets/chat-Cm0fkpg1.js +0 -1
- package/payload/server/public/assets/chat-Cm0fkpg1.js.br +0 -0
- package/payload/server/public/assets/chat-Cm0fkpg1.js.gz +0 -0
- package/payload/server/public/assets/chevron-left-CjRH-BtF.js +0 -1
- package/payload/server/public/assets/chevron-left-CjRH-BtF.js.br +0 -0
- package/payload/server/public/assets/clock-wbYEt1kM.js +0 -1
- package/payload/server/public/assets/clock-wbYEt1kM.js.br +0 -0
- package/payload/server/public/assets/clock-wbYEt1kM.js.gz +0 -0
- package/payload/server/public/assets/copy-kuNM0Etw.js.br +0 -0
- package/payload/server/public/assets/copy-kuNM0Etw.js.gz +0 -0
- package/payload/server/public/assets/data-c47T2NCd.js +0 -1
- package/payload/server/public/assets/data-c47T2NCd.js.br +0 -1
- package/payload/server/public/assets/data-c47T2NCd.js.gz +0 -0
- package/payload/server/public/assets/file-text-BWkobrcx.js.br +0 -0
- package/payload/server/public/assets/file-text-BWkobrcx.js.gz +0 -0
- package/payload/server/public/assets/graph-BGjTL5Vz.js.br +0 -0
- package/payload/server/public/assets/graph-BGjTL5Vz.js.gz +0 -0
- package/payload/server/public/assets/graph-labels-Dvc5Kw_r.js.br +0 -0
- package/payload/server/public/assets/graph-labels-Dvc5Kw_r.js.gz +0 -0
- package/payload/server/public/assets/operator-CzBGv_he.js.br +0 -0
- package/payload/server/public/assets/operator-CzBGv_he.js.gz +0 -0
- package/payload/server/public/assets/page-BIY4Ku8Q.js.br +0 -0
- package/payload/server/public/assets/page-BIY4Ku8Q.js.gz +0 -0
- package/payload/server/public/assets/page-DaySqamH.js.br +0 -0
- package/payload/server/public/assets/page-DaySqamH.js.gz +0 -0
- package/payload/server/public/assets/play-C8RA52_i.js +0 -1
- package/payload/server/public/assets/play-C8RA52_i.js.br +0 -0
- package/payload/server/public/assets/play-C8RA52_i.js.gz +0 -0
- package/payload/server/public/assets/public-pwDSvhBv.js.br +0 -0
- package/payload/server/public/assets/public-pwDSvhBv.js.gz +0 -0
- package/payload/server/public/assets/rotate-ccw-B6s7tkEt.js.br +0 -0
- package/payload/server/public/assets/rotate-ccw-B6s7tkEt.js.gz +0 -0
- package/payload/server/public/assets/routines-CFlyRdYg.js.br +0 -0
- package/payload/server/public/assets/routines-CFlyRdYg.js.gz +0 -0
- package/payload/server/public/assets/skills-C45kfL_Q.js.br +0 -0
- package/payload/server/public/assets/skills-C45kfL_Q.js.gz +0 -0
- package/payload/server/public/assets/tasks-BwoCTCu5.js.br +0 -0
- package/payload/server/public/assets/tasks-BwoCTCu5.js.gz +0 -0
- package/payload/server/public/assets/triangle-alert-B3bthSzx.js.br +0 -0
- package/payload/server/public/assets/triangle-alert-B3bthSzx.js.gz +0 -0
- package/payload/server/public/assets/useCopyFeedback-BzJAkFEb.js.br +0 -0
- package/payload/server/public/assets/useCopyFeedback-BzJAkFEb.js.gz +0 -0
- package/payload/server/public/assets/useMediaQuery-DJ6XeNN7.js +0 -14
- package/payload/server/public/assets/useMediaQuery-DJ6XeNN7.js.br +0 -0
- package/payload/server/public/assets/useMediaQuery-DJ6XeNN7.js.gz +0 -0
- package/payload/server/public/assets/useMediaQuery-DW_xRrMl.css +0 -1
- package/payload/server/public/assets/useMediaQuery-DW_xRrMl.css.br +0 -0
- package/payload/server/public/assets/useMediaQuery-DW_xRrMl.css.gz +0 -0
- package/payload/server/public/assets/useVoiceRecorder-_qI_BAOo.js.br +0 -0
- package/payload/server/public/assets/useVoiceRecorder-_qI_BAOo.js.gz +0 -0
- package/payload/server/public/assets/wrench-Bqux9jaw.js.br +0 -0
- package/payload/server/public/assets/wrench-Bqux9jaw.js.gz +0 -0
|
@@ -30,9 +30,9 @@ import "./chunk-HYQNUVGO.js";
|
|
|
30
30
|
// server/edge.ts
|
|
31
31
|
import { createServer, request as httpRequest } from "http";
|
|
32
32
|
import { createConnection as createConnection3 } from "net";
|
|
33
|
-
import { readFileSync as
|
|
33
|
+
import { readFileSync as readFileSync5, existsSync as existsSync4, watchFile } from "fs";
|
|
34
34
|
import { homedir } from "os";
|
|
35
|
-
import { join as
|
|
35
|
+
import { join as join3 } from "path";
|
|
36
36
|
|
|
37
37
|
// server/ws-proxy.ts
|
|
38
38
|
import { createConnection } from "net";
|
|
@@ -544,10 +544,6 @@ Content-Length: 0\r
|
|
|
544
544
|
socket.destroy();
|
|
545
545
|
}
|
|
546
546
|
|
|
547
|
-
// server/routes/admin/version.ts
|
|
548
|
-
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
|
|
549
|
-
import { resolve, join as join2 } from "path";
|
|
550
|
-
|
|
551
547
|
// server/lib/client-error-count.ts
|
|
552
548
|
import { existsSync, readFileSync, statSync, openSync, readSync, closeSync } from "fs";
|
|
553
549
|
import { join } from "path";
|
|
@@ -592,11 +588,12 @@ function countClientErrors24h() {
|
|
|
592
588
|
return count;
|
|
593
589
|
}
|
|
594
590
|
|
|
595
|
-
// server/
|
|
591
|
+
// server/lib/brand-config.ts
|
|
592
|
+
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
|
|
593
|
+
import { resolve } from "path";
|
|
596
594
|
var PLATFORM_ROOT = process.env.MAXY_PLATFORM_ROOT ?? resolve(process.cwd(), "..");
|
|
597
595
|
var DEFAULT_HOSTNAME = "maxy";
|
|
598
596
|
var DEFAULT_NPM_PACKAGE = "@rubytech/create-maxy";
|
|
599
|
-
var FETCH_TIMEOUT_MS = 5e3;
|
|
600
597
|
var fallbackLogged = /* @__PURE__ */ new Set();
|
|
601
598
|
function logFallbackOnce(reason, field, usingDefault) {
|
|
602
599
|
const key = `${reason}:${field}`;
|
|
@@ -605,7 +602,7 @@ function logFallbackOnce(reason, field, usingDefault) {
|
|
|
605
602
|
console.log(`[admin/version] brand-config-fallback reason=${reason} field=${field} using=${usingDefault}`);
|
|
606
603
|
}
|
|
607
604
|
function resolveBrandConfig() {
|
|
608
|
-
const brandJsonPath =
|
|
605
|
+
const brandJsonPath = resolve(PLATFORM_ROOT, "config", "brand.json");
|
|
609
606
|
if (!existsSync2(brandJsonPath)) {
|
|
610
607
|
logFallbackOnce("file-missing", "hostname", DEFAULT_HOSTNAME);
|
|
611
608
|
logFallbackOnce("file-missing", "npm.packageName", DEFAULT_NPM_PACKAGE);
|
|
@@ -633,12 +630,18 @@ function resolveBrandConfig() {
|
|
|
633
630
|
}
|
|
634
631
|
return { hostname, npmPackage };
|
|
635
632
|
}
|
|
636
|
-
|
|
637
|
-
|
|
633
|
+
function resolveVersionFile(hostname) {
|
|
634
|
+
return resolve(PLATFORM_ROOT, `config/.${hostname}-version`);
|
|
635
|
+
}
|
|
636
|
+
function readInstalledVersion(versionFile) {
|
|
638
637
|
if (!existsSync2(versionFile)) return "unknown";
|
|
639
638
|
const content = readFileSync2(versionFile, "utf-8").trim();
|
|
640
639
|
return content || "unknown";
|
|
641
640
|
}
|
|
641
|
+
|
|
642
|
+
// server/routes/admin/version.ts
|
|
643
|
+
var FETCH_TIMEOUT_MS = 5e3;
|
|
644
|
+
var PROCESS_STARTED_AT = (/* @__PURE__ */ new Date()).toISOString();
|
|
642
645
|
async function fetchLatest(npmPackage) {
|
|
643
646
|
const registryUrl = `https://registry.npmjs.org/${npmPackage}/latest`;
|
|
644
647
|
try {
|
|
@@ -678,8 +681,8 @@ function isNewer(latest, installed) {
|
|
|
678
681
|
var app = new Hono();
|
|
679
682
|
app.get("/", async (c) => {
|
|
680
683
|
const { hostname, npmPackage } = resolveBrandConfig();
|
|
681
|
-
const versionFile =
|
|
682
|
-
const installed =
|
|
684
|
+
const versionFile = resolveVersionFile(hostname);
|
|
685
|
+
const installed = readInstalledVersion(versionFile);
|
|
683
686
|
const latest = await fetchLatest(npmPackage);
|
|
684
687
|
const updateAvailable = installed !== "unknown" && latest !== null && isNewer(latest, installed);
|
|
685
688
|
const outcome = installed === "unknown" ? "stale-version-file" : latest === null ? "fetch-failed" : "ok";
|
|
@@ -704,11 +707,267 @@ app.post("/alert-surfaced", async (c) => {
|
|
|
704
707
|
});
|
|
705
708
|
var version_default = app;
|
|
706
709
|
|
|
710
|
+
// server/routes/admin/actions.ts
|
|
711
|
+
import { spawn, spawnSync } from "child_process";
|
|
712
|
+
import { mkdirSync, readdirSync, readFileSync as readFileSync3, statSync as statSync2, writeFileSync } from "fs";
|
|
713
|
+
import { randomUUID } from "crypto";
|
|
714
|
+
import { resolve as resolve2 } from "path";
|
|
715
|
+
var TAG = "[admin-action]";
|
|
716
|
+
var ACTIONS_DIR = resolve2(LOG_DIR, "actions");
|
|
717
|
+
var EXIT_MARKER = "[action-exit] code=";
|
|
718
|
+
function isValidActionId(id) {
|
|
719
|
+
return /^[0-9a-f]{8}$/.test(id);
|
|
720
|
+
}
|
|
721
|
+
function isValidPackageName(pkg) {
|
|
722
|
+
return /^(@[a-z0-9][a-z0-9._-]*\/)?[a-z0-9][a-z0-9._-]*$/.test(pkg) && pkg.length <= 214;
|
|
723
|
+
}
|
|
724
|
+
function logPathFor(actionId) {
|
|
725
|
+
return resolve2(ACTIONS_DIR, `${actionId}.log`);
|
|
726
|
+
}
|
|
727
|
+
function sidecarPathFor(actionId) {
|
|
728
|
+
return resolve2(ACTIONS_DIR, `${actionId}.json`);
|
|
729
|
+
}
|
|
730
|
+
function buildUpgradeArgv(opts) {
|
|
731
|
+
const script = `npx -y ${opts.pkg}@latest >> ${opts.logPath} 2>&1; echo "${EXIT_MARKER}$?" >> ${opts.logPath}`;
|
|
732
|
+
return [
|
|
733
|
+
"--user",
|
|
734
|
+
`--unit=${opts.unit}`,
|
|
735
|
+
"--collect",
|
|
736
|
+
`--setenv=PATH=${opts.path}`,
|
|
737
|
+
"/bin/sh",
|
|
738
|
+
"-c",
|
|
739
|
+
script
|
|
740
|
+
];
|
|
741
|
+
}
|
|
742
|
+
function systemdRunPresent() {
|
|
743
|
+
const probe = spawnSync("systemd-run", ["--version"], { stdio: "ignore" });
|
|
744
|
+
return probe.status === 0;
|
|
745
|
+
}
|
|
746
|
+
function logCensus() {
|
|
747
|
+
let logs = 0;
|
|
748
|
+
let oldestAgeH = 0;
|
|
749
|
+
try {
|
|
750
|
+
const now = Date.now();
|
|
751
|
+
for (const f of readdirSync(ACTIONS_DIR)) {
|
|
752
|
+
if (!f.endsWith(".log")) continue;
|
|
753
|
+
logs++;
|
|
754
|
+
const ageH = (now - statSync2(resolve2(ACTIONS_DIR, f)).mtimeMs) / 36e5;
|
|
755
|
+
if (ageH > oldestAgeH) oldestAgeH = ageH;
|
|
756
|
+
}
|
|
757
|
+
} catch {
|
|
758
|
+
}
|
|
759
|
+
const listed = spawnSync("systemctl", ["--user", "list-units", "--no-legend", "maxy-action-*"], {
|
|
760
|
+
encoding: "utf-8"
|
|
761
|
+
});
|
|
762
|
+
const out = (listed.stdout ?? "").trim();
|
|
763
|
+
const units = out ? out.split("\n").length : 0;
|
|
764
|
+
console.log(`[action-census] units=${units} logs=${logs} oldestAgeH=${oldestAgeH.toFixed(1)}`);
|
|
765
|
+
}
|
|
766
|
+
function readExitCode(logText) {
|
|
767
|
+
const idx = logText.lastIndexOf(EXIT_MARKER);
|
|
768
|
+
if (idx === -1) return null;
|
|
769
|
+
const tail = logText.slice(idx + EXIT_MARKER.length).trim();
|
|
770
|
+
const code = Number.parseInt(tail, 10);
|
|
771
|
+
return Number.isNaN(code) ? null : code;
|
|
772
|
+
}
|
|
773
|
+
function readLog(actionId) {
|
|
774
|
+
try {
|
|
775
|
+
return readFileSync3(logPathFor(actionId), "utf-8");
|
|
776
|
+
} catch {
|
|
777
|
+
return "";
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
var app2 = new Hono();
|
|
781
|
+
app2.post("/upgrade", (c) => {
|
|
782
|
+
const actionId = randomUUID().replace(/-/g, "").slice(0, 8);
|
|
783
|
+
const { hostname, npmPackage } = resolveBrandConfig();
|
|
784
|
+
console.log(`${TAG} op=request actionId=${actionId} action=upgrade pkg=${npmPackage}`);
|
|
785
|
+
logCensus();
|
|
786
|
+
if (!isValidPackageName(npmPackage)) {
|
|
787
|
+
console.error(`${TAG} op=preflight actionId=${actionId} reason=malformed-package pkg=${JSON.stringify(npmPackage)}`);
|
|
788
|
+
return c.json({ ok: false, reason: "malformed-package-name" }, 500);
|
|
789
|
+
}
|
|
790
|
+
const present = systemdRunPresent();
|
|
791
|
+
console.log(`${TAG} op=preflight actionId=${actionId} systemdRun=${present ? "present" : "absent"}`);
|
|
792
|
+
if (!present) {
|
|
793
|
+
return c.json({ ok: false, reason: "systemd-run-absent" }, 501);
|
|
794
|
+
}
|
|
795
|
+
const versionBefore = readInstalledVersion(resolveVersionFile(hostname));
|
|
796
|
+
const unit = `maxy-action-${actionId}`;
|
|
797
|
+
const logPath = logPathFor(actionId);
|
|
798
|
+
mkdirSync(ACTIONS_DIR, { recursive: true });
|
|
799
|
+
const sidecar = {
|
|
800
|
+
actionId,
|
|
801
|
+
action: "upgrade",
|
|
802
|
+
pkg: npmPackage,
|
|
803
|
+
unit,
|
|
804
|
+
startedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
805
|
+
versionBefore,
|
|
806
|
+
hostname
|
|
807
|
+
};
|
|
808
|
+
writeFileSync(sidecarPathFor(actionId), JSON.stringify(sidecar), "utf-8");
|
|
809
|
+
const argv = buildUpgradeArgv({ unit, pkg: npmPackage, logPath, path: process.env.PATH ?? "" });
|
|
810
|
+
console.log(`${TAG} op=argv actionId=${actionId} argv=${JSON.stringify(argv)}`);
|
|
811
|
+
const child = spawn("systemd-run", argv, { detached: true, stdio: "ignore" });
|
|
812
|
+
child.unref();
|
|
813
|
+
console.log(`${TAG} op=unit-started actionId=${actionId} unit=${unit} logPath=${logPath}`);
|
|
814
|
+
return c.json({ actionId }, 202);
|
|
815
|
+
});
|
|
816
|
+
app2.get("/latest", (c) => {
|
|
817
|
+
let names = [];
|
|
818
|
+
try {
|
|
819
|
+
names = readdirSync(ACTIONS_DIR).filter((f) => f.endsWith(".json"));
|
|
820
|
+
} catch {
|
|
821
|
+
}
|
|
822
|
+
if (names.length === 0) return c.json({ action: null });
|
|
823
|
+
let newestName = null;
|
|
824
|
+
let newestMs = -1;
|
|
825
|
+
for (const n of names) {
|
|
826
|
+
try {
|
|
827
|
+
const ms = statSync2(resolve2(ACTIONS_DIR, n)).mtimeMs;
|
|
828
|
+
if (ms > newestMs) {
|
|
829
|
+
newestMs = ms;
|
|
830
|
+
newestName = n;
|
|
831
|
+
}
|
|
832
|
+
} catch {
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
if (!newestName) return c.json({ action: null });
|
|
836
|
+
let newest;
|
|
837
|
+
try {
|
|
838
|
+
newest = JSON.parse(readFileSync3(resolve2(ACTIONS_DIR, newestName), "utf-8"));
|
|
839
|
+
} catch (err) {
|
|
840
|
+
console.error(`${TAG} op=latest-unreadable file=${newestName} detail=${String(err)}`);
|
|
841
|
+
return c.json({ action: null });
|
|
842
|
+
}
|
|
843
|
+
const exitCode = readExitCode(readLog(newest.actionId));
|
|
844
|
+
return c.json({ action: { ...newest, running: exitCode === null, exitCode } });
|
|
845
|
+
});
|
|
846
|
+
app2.get("/:actionId/stream", (c) => {
|
|
847
|
+
const actionId = c.req.param("actionId");
|
|
848
|
+
if (!isValidActionId(actionId)) {
|
|
849
|
+
console.error(`${TAG} op=stream-reject actionId=${JSON.stringify(actionId)} reason=malformed`);
|
|
850
|
+
return c.json({ ok: false, reason: "malformed-action-id" }, 400);
|
|
851
|
+
}
|
|
852
|
+
const encoder = new TextEncoder();
|
|
853
|
+
const startedAt = Date.now();
|
|
854
|
+
let offset = Number.parseInt(c.req.header("last-event-id") ?? "0", 10);
|
|
855
|
+
if (!Number.isFinite(offset) || offset < 0) offset = 0;
|
|
856
|
+
let closed = false;
|
|
857
|
+
let timer = null;
|
|
858
|
+
let heartbeat = null;
|
|
859
|
+
let sawOutput = offset > 0;
|
|
860
|
+
const NO_OUTPUT_DEADLINE_MS = 3e4;
|
|
861
|
+
const teardown = (reason) => {
|
|
862
|
+
if (closed) return;
|
|
863
|
+
closed = true;
|
|
864
|
+
if (timer) clearInterval(timer);
|
|
865
|
+
if (heartbeat) clearInterval(heartbeat);
|
|
866
|
+
console.log(
|
|
867
|
+
`${TAG} op=stream-close actionId=${actionId} ranMs=${Date.now() - startedAt} bytes=${offset} reason=${reason}`
|
|
868
|
+
);
|
|
869
|
+
};
|
|
870
|
+
const stream = new ReadableStream({
|
|
871
|
+
start(controller) {
|
|
872
|
+
console.log(`${TAG} op=stream-open actionId=${actionId} fromOffset=${offset}`);
|
|
873
|
+
const tick = () => {
|
|
874
|
+
if (closed) return;
|
|
875
|
+
try {
|
|
876
|
+
const text = readLog(actionId);
|
|
877
|
+
if (text.length > offset) {
|
|
878
|
+
const slice = text.slice(offset);
|
|
879
|
+
offset = text.length;
|
|
880
|
+
if (!sawOutput) {
|
|
881
|
+
sawOutput = true;
|
|
882
|
+
console.log(
|
|
883
|
+
`${TAG} op=first-output actionId=${actionId} waitedMs=${Date.now() - startedAt} head=${JSON.stringify(slice.slice(0, 200))}`
|
|
884
|
+
);
|
|
885
|
+
}
|
|
886
|
+
const lines = slice.split("\n");
|
|
887
|
+
if (lines[lines.length - 1] === "") lines.pop();
|
|
888
|
+
const frame = `id: ${offset}
|
|
889
|
+
` + lines.map((l) => `data: ${l}`).join("\n") + "\n\n";
|
|
890
|
+
controller.enqueue(encoder.encode(frame));
|
|
891
|
+
} else if (!sawOutput && Date.now() - startedAt > NO_OUTPUT_DEADLINE_MS) {
|
|
892
|
+
sawOutput = true;
|
|
893
|
+
console.error(`${TAG} op=no-output actionId=${actionId} waitedMs=${Date.now() - startedAt}`);
|
|
894
|
+
}
|
|
895
|
+
const code = readExitCode(text);
|
|
896
|
+
if (code !== null) {
|
|
897
|
+
let sidecar = null;
|
|
898
|
+
try {
|
|
899
|
+
sidecar = JSON.parse(readFileSync3(sidecarPathFor(actionId), "utf-8"));
|
|
900
|
+
} catch {
|
|
901
|
+
}
|
|
902
|
+
const versionAfter = sidecar ? readInstalledVersion(resolveVersionFile(sidecar.hostname)) : "unknown";
|
|
903
|
+
const versionBefore = sidecar?.versionBefore ?? "unknown";
|
|
904
|
+
const changed = versionBefore !== "unknown" && versionAfter !== "unknown" && versionBefore !== versionAfter;
|
|
905
|
+
console.log(`${TAG} op=exit actionId=${actionId} ranMs=${Date.now() - startedAt} code=${code}`);
|
|
906
|
+
console.log(
|
|
907
|
+
`${TAG} op=version-check actionId=${actionId} before=${versionBefore} after=${versionAfter} changed=${changed}`
|
|
908
|
+
);
|
|
909
|
+
controller.enqueue(
|
|
910
|
+
encoder.encode(
|
|
911
|
+
`event: done
|
|
912
|
+
data: ${JSON.stringify({ code, versionBefore, versionAfter, changed })}
|
|
913
|
+
|
|
914
|
+
`
|
|
915
|
+
)
|
|
916
|
+
);
|
|
917
|
+
teardown("action-exited");
|
|
918
|
+
try {
|
|
919
|
+
controller.close();
|
|
920
|
+
} catch {
|
|
921
|
+
}
|
|
922
|
+
}
|
|
923
|
+
} catch (err) {
|
|
924
|
+
teardown(`tail-failed:${String(err)}`);
|
|
925
|
+
try {
|
|
926
|
+
controller.close();
|
|
927
|
+
} catch {
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
};
|
|
931
|
+
timer = setInterval(tick, 500);
|
|
932
|
+
tick();
|
|
933
|
+
heartbeat = setInterval(() => {
|
|
934
|
+
try {
|
|
935
|
+
controller.enqueue(encoder.encode(": ping\n\n"));
|
|
936
|
+
} catch {
|
|
937
|
+
teardown("heartbeat-enqueue-failed");
|
|
938
|
+
try {
|
|
939
|
+
controller.close();
|
|
940
|
+
} catch {
|
|
941
|
+
}
|
|
942
|
+
}
|
|
943
|
+
}, 2e4);
|
|
944
|
+
c.req.raw.signal.addEventListener("abort", () => {
|
|
945
|
+
teardown("client-aborted");
|
|
946
|
+
try {
|
|
947
|
+
controller.close();
|
|
948
|
+
} catch {
|
|
949
|
+
}
|
|
950
|
+
});
|
|
951
|
+
},
|
|
952
|
+
cancel() {
|
|
953
|
+
teardown("client-closed");
|
|
954
|
+
}
|
|
955
|
+
});
|
|
956
|
+
return new Response(stream, {
|
|
957
|
+
headers: {
|
|
958
|
+
"Content-Type": "text/event-stream",
|
|
959
|
+
"Cache-Control": "no-cache",
|
|
960
|
+
Connection: "keep-alive"
|
|
961
|
+
}
|
|
962
|
+
});
|
|
963
|
+
});
|
|
964
|
+
var actions_default = app2;
|
|
965
|
+
|
|
707
966
|
// server/edge-admin.ts
|
|
708
967
|
function createEdgeAdminApp(opts) {
|
|
709
|
-
const
|
|
710
|
-
|
|
711
|
-
|
|
968
|
+
const app3 = new Hono();
|
|
969
|
+
app3.use("*", clientIpMiddleware);
|
|
970
|
+
app3.use("*", async (c, next) => {
|
|
712
971
|
const start = Date.now();
|
|
713
972
|
console.log(
|
|
714
973
|
`[edge-admin] ts=${(/* @__PURE__ */ new Date()).toISOString()} inbound method=${c.req.method} path=${c.req.path} allowlist-branch=edge-admin`
|
|
@@ -718,14 +977,26 @@ function createEdgeAdminApp(opts) {
|
|
|
718
977
|
`[edge-admin] ts=${(/* @__PURE__ */ new Date()).toISOString()} outcome method=${c.req.method} path=${c.req.path} status=${c.res.status} duration_ms=${Date.now() - start}`
|
|
719
978
|
);
|
|
720
979
|
});
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
980
|
+
app3.use("*", requireAdminCookie(opts.isPublicHost));
|
|
981
|
+
app3.route("/api/admin/version", version_default);
|
|
982
|
+
app3.route("/api/admin/actions", actions_default);
|
|
983
|
+
return app3;
|
|
984
|
+
}
|
|
985
|
+
|
|
986
|
+
// server/edge-admin-path.ts
|
|
987
|
+
var EDGE_ADMIN_PREFIXES = [
|
|
988
|
+
"/api/admin/actions",
|
|
989
|
+
"/api/admin/version"
|
|
990
|
+
];
|
|
991
|
+
function isEdgeAdminPath(url) {
|
|
992
|
+
const q = url.indexOf("?");
|
|
993
|
+
const pathname = q === -1 ? url : url.slice(0, q);
|
|
994
|
+
return EDGE_ADMIN_PREFIXES.some((p) => pathname.startsWith(p));
|
|
724
995
|
}
|
|
725
996
|
|
|
726
997
|
// server/edge-fallback.ts
|
|
727
|
-
import { existsSync as existsSync3, readFileSync as
|
|
728
|
-
import { extname, join as
|
|
998
|
+
import { existsSync as existsSync3, readFileSync as readFileSync4 } from "fs";
|
|
999
|
+
import { extname, join as join2 } from "path";
|
|
729
1000
|
|
|
730
1001
|
// server/lib/proxy-log-path.ts
|
|
731
1002
|
function proxyPathname(url) {
|
|
@@ -761,7 +1032,7 @@ function inlineAsset(filePath) {
|
|
|
761
1032
|
if (!existsSync3(filePath)) return null;
|
|
762
1033
|
const mime = MIME_BY_EXT[extname(filePath).toLowerCase()];
|
|
763
1034
|
if (!mime) return null;
|
|
764
|
-
const bytes =
|
|
1035
|
+
const bytes = readFileSync4(filePath);
|
|
765
1036
|
return `data:${mime};base64,${bytes.toString("base64")}`;
|
|
766
1037
|
}
|
|
767
1038
|
function readString(value, fallback) {
|
|
@@ -770,9 +1041,9 @@ function readString(value, fallback) {
|
|
|
770
1041
|
function loadBrand(brandJsonPath, assetsDir = "") {
|
|
771
1042
|
if (!brandJsonPath || !existsSync3(brandJsonPath)) return { ...BRAND_DEFAULTS };
|
|
772
1043
|
try {
|
|
773
|
-
const parsed = JSON.parse(
|
|
1044
|
+
const parsed = JSON.parse(readFileSync4(brandJsonPath, "utf-8"));
|
|
774
1045
|
const logoFile = typeof parsed.assets?.logo === "string" ? parsed.assets.logo : null;
|
|
775
|
-
const logoDataUri = logoFile && assetsDir ? inlineAsset(
|
|
1046
|
+
const logoDataUri = logoFile && assetsDir ? inlineAsset(join2(assetsDir, logoFile)) : null;
|
|
776
1047
|
return {
|
|
777
1048
|
configDir: readString(parsed.configDir, BRAND_DEFAULTS.configDir),
|
|
778
1049
|
productName: readString(parsed.productName, BRAND_DEFAULTS.productName),
|
|
@@ -875,14 +1146,14 @@ function buildHoldingPage(brand) {
|
|
|
875
1146
|
|
|
876
1147
|
// server/edge.ts
|
|
877
1148
|
var PLATFORM_ROOT2 = process.env.MAXY_PLATFORM_ROOT || "";
|
|
878
|
-
var BRAND_JSON_PATH = PLATFORM_ROOT2 ?
|
|
879
|
-
var BRAND_ASSETS_DIR = PLATFORM_ROOT2 ?
|
|
1149
|
+
var BRAND_JSON_PATH = PLATFORM_ROOT2 ? join3(PLATFORM_ROOT2, "config", "brand.json") : "";
|
|
1150
|
+
var BRAND_ASSETS_DIR = PLATFORM_ROOT2 ? join3(PLATFORM_ROOT2, "..", "server", "public", "brand") : "";
|
|
880
1151
|
var BRAND = loadBrand(BRAND_JSON_PATH, BRAND_ASSETS_DIR);
|
|
881
|
-
var ALIAS_DOMAINS_PATH =
|
|
1152
|
+
var ALIAS_DOMAINS_PATH = join3(homedir(), BRAND.configDir, "alias-domains.json");
|
|
882
1153
|
function loadAliasDomains() {
|
|
883
1154
|
try {
|
|
884
1155
|
if (!existsSync4(ALIAS_DOMAINS_PATH)) return /* @__PURE__ */ new Set();
|
|
885
|
-
const parsed = JSON.parse(
|
|
1156
|
+
const parsed = JSON.parse(readFileSync5(ALIAS_DOMAINS_PATH, "utf-8"));
|
|
886
1157
|
if (!Array.isArray(parsed)) return /* @__PURE__ */ new Set();
|
|
887
1158
|
return new Set(parsed.filter((h) => typeof h === "string"));
|
|
888
1159
|
} catch {
|
|
@@ -1031,11 +1302,9 @@ function forwardUpgrade(req, clientSocket, head) {
|
|
|
1031
1302
|
}
|
|
1032
1303
|
var edgeAdminApp = createEdgeAdminApp({ isPublicHost });
|
|
1033
1304
|
var edgeAdminHandler = getRequestListener(edgeAdminApp.fetch);
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
return pathname.startsWith("/api/admin/actions") || pathname.startsWith("/api/admin/version");
|
|
1038
|
-
}
|
|
1305
|
+
console.log(
|
|
1306
|
+
`[edge] admin-dispatch actions=${isEdgeAdminPath("/api/admin/actions/deadbeef/stream")} version=${isEdgeAdminPath("/api/admin/version")}`
|
|
1307
|
+
);
|
|
1039
1308
|
var server = createServer((req, res) => {
|
|
1040
1309
|
if (isEdgeAdminPath(req.url ?? "")) {
|
|
1041
1310
|
edgeAdminHandler(req, res);
|
|
@@ -5,12 +5,12 @@
|
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
6
|
<title>Activity — Maxy</title>
|
|
7
7
|
<link rel="icon" href="/favicon.ico">
|
|
8
|
-
<script type="module" crossorigin src="/assets/activity
|
|
8
|
+
<script type="module" crossorigin src="/assets/activity--yyBcNfB.js"></script>
|
|
9
9
|
<link rel="modulepreload" crossorigin href="/assets/chunk-CltuBf4Z.js">
|
|
10
|
-
<link rel="modulepreload" crossorigin href="/assets/useMediaQuery-
|
|
11
|
-
<link rel="modulepreload" crossorigin href="/assets/AdminShell-
|
|
12
|
-
<link rel="modulepreload" crossorigin href="/assets/triangle-alert-
|
|
13
|
-
<link rel="stylesheet" crossorigin href="/assets/useMediaQuery-
|
|
10
|
+
<link rel="modulepreload" crossorigin href="/assets/useMediaQuery-D8VDA0RN.js">
|
|
11
|
+
<link rel="modulepreload" crossorigin href="/assets/AdminShell-DStA0lfm.js">
|
|
12
|
+
<link rel="modulepreload" crossorigin href="/assets/triangle-alert-JwLSrj17.js">
|
|
13
|
+
<link rel="stylesheet" crossorigin href="/assets/useMediaQuery-BsBzbWaf.css">
|
|
14
14
|
<link rel="stylesheet" href="/brand-defaults.css">
|
|
15
15
|
</head>
|
|
16
16
|
<body>
|
|
@@ -5,11 +5,11 @@
|
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
6
|
<title>Agents — Maxy</title>
|
|
7
7
|
<link rel="icon" href="/favicon.ico">
|
|
8
|
-
<script type="module" crossorigin src="/assets/agents-
|
|
8
|
+
<script type="module" crossorigin src="/assets/agents-odyVOb5E.js"></script>
|
|
9
9
|
<link rel="modulepreload" crossorigin href="/assets/chunk-CltuBf4Z.js">
|
|
10
|
-
<link rel="modulepreload" crossorigin href="/assets/useMediaQuery-
|
|
11
|
-
<link rel="modulepreload" crossorigin href="/assets/AdminShell-
|
|
12
|
-
<link rel="stylesheet" crossorigin href="/assets/useMediaQuery-
|
|
10
|
+
<link rel="modulepreload" crossorigin href="/assets/useMediaQuery-D8VDA0RN.js">
|
|
11
|
+
<link rel="modulepreload" crossorigin href="/assets/AdminShell-DStA0lfm.js">
|
|
12
|
+
<link rel="stylesheet" crossorigin href="/assets/useMediaQuery-BsBzbWaf.css">
|
|
13
13
|
<link rel="stylesheet" href="/brand-defaults.css">
|
|
14
14
|
</head>
|
|
15
15
|
<body>
|
package/payload/server/public/assets/{AdminLoginScreens-DLogIsJT.js → AdminLoginScreens-C6e5jf0S.js}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{o as e}from"./chunk-CltuBf4Z.js";import{O as t,Q as n,ct as r,et as i,it as a,nt as o}from"./useMediaQuery-DJ6XeNN7.js";import{A as s}from"./useVoiceRecorder-_qI_BAOo.js";import{A as c,O as l,k as u,p as d}from"./AdminShell-B67tPTyE.js";var f=e(r(),1);function p(e=`admin`){let[t,n]=(0,f.useState)(`loading`),[r,i]=(0,f.useState)(``),[o,l]=(0,f.useState)(``),[u,d]=(0,f.useState)(``),[p,m]=(0,f.useState)(!1),[h,g]=(0,f.useState)(!1),[_,v]=(0,f.useState)(!1),[y,b]=(0,f.useState)(!1),[x,S]=(0,f.useState)(!1),[C,w]=(0,f.useState)(null),[T,E]=(0,f.useState)(null),[D,O]=(0,f.useState)(void 0),[k,A]=(0,f.useState)(null),[j,M]=(0,f.useState)(void 0),[N,P]=(0,f.useState)(null),[F,I]=(0,f.useState)(null),[L,R]=(0,f.useState)(void 0),z=(0,f.useRef)(void 0),[B,V]=(0,f.useState)(!1),[H,U]=(0,f.useState)(!0);(0,f.useEffect)(()=>{typeof window>`u`||fetch(`/api/remote-auth/status`).then(e=>e.ok?e.json():null).then(e=>{e?.configured&&V(!0)}).catch(()=>{})},[]);let W=(0,f.useRef)(null),G=(0,f.useRef)(null);(0,f.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();w(r.session_key),I(r.sessionId??null),O(r.businessName),A(r.role??null),M(r.userName===void 0?null:r.userName),P(r.avatar??null);let i=s(r.thinkingView);return z.current=i,R(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}U(!!a.claude_authenticated);let o=!1;try{o=new URLSearchParams(window.location.search).get(`connect`)===`claude`}catch{}if(o){try{let e=new URL(window.location.href);e.searchParams.delete(`connect`),window.history.replaceState(null,``,e.pathname+e.search+e.hash)}catch{}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,f.useEffect)(()=>{t===`chat`&&C&&fetch(`/api/admin/claude-info?session_key=${encodeURIComponent(C)}`).then(e=>{if(e.ok)return e.json()}).then(e=>{e&&E(e)}).catch(()=>{})},[t,C]);let K=(0,f.useRef)(null);(0,f.useEffect)(()=>{if(t!==`chat`)return;let e=setInterval(async()=>{try{let e=await fetch(`/api/health`);if(e.ok){let t=await e.json();U(t.auth_status!==`dead`&&t.auth_status!==`missing`)}}catch{}if(C)try{let e=await fetch(`/api/admin/session?session_key=${encodeURIComponent(C)}`);if(e.status!==401)return;let t=(await e.clone().json().catch(()=>null))?.code??`unknown-401`;if(t===`remote-auth-required`){a(`heartbeat`,`/api/admin/session`);return}console.warn(`[admin-auth] outcome=heartbeat-detected-expiry code=${t}`),K.current?.()}catch{}},300*1e3);return()=>clearInterval(e)},[t,C]),(0,f.useEffect)(()=>{t===`connect-claude`&&fetch(`/api/health`).then(e=>e.ok?e.json():null).then(e=>{e?.claude_authenticated&&(U(!0),n(`enter-pin`))}).catch(()=>{})},[t]);async function q(e,t){g(!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){let e=await r.json().catch(()=>({}));if(r.status===401&&e?.code===`remote-auth-required`){a(`enter-pin`,`/api/admin/session`);return}d(e.error||`Invalid PIN`);return}let o=await r.json();w(o.session_key),I(o.sessionId??null),O(o.businessName),A(o.role??null),M(o.userName===void 0?null:o.userName),P(o.avatar??null);let c=s(o.thinkingView);z.current=c,R(c);try{sessionStorage.setItem(`maxy-admin-session-key`,o.session_key)}catch{}i(``),n(`chat`)}catch(e){console.error(`[admin] connection error:`,e),d(`Could not connect.`)}finally{g(!1)}}let J=(0,f.useCallback)(async e=>{if(e.preventDefault(),h)return;d(``);let t=o.trim();if(!t){d(`Please enter your name.`);return}if(r.length<4){d(`PIN must be at least 4 characters.`);return}let s=r;g(!0);try{let e=await fetch(`/api/onboarding/set-pin`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({pin:s,name:t})});if(!e.ok){let t=await e.json().catch(()=>({}));if(e.status===401&&t?.code===`remote-auth-required`){a(`set-pin`,`/api/onboarding/set-pin`);return}if(e.status===409){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`):d(t.error||`Failed to set PIN.`)}else n(`enter-pin`)}catch{n(`enter-pin`)}return}d(t.error||`Failed to set PIN.`);return}let r=await fetch(`/api/health`);if((r.ok?await r.json():null)?.claude_authenticated){await q(s);return}i(``),n(`connect-claude`)}catch(e){console.error(`[admin] connection error:`,e),d(`Could not connect.`)}finally{g(!1)}},[r,h,o]),Y=(0,f.useCallback)(async e=>{e.preventDefault(),d(``),await q(r)},[r]),X=(0,f.useCallback)(async()=>{S(!0);try{if(!await c())return console.warn(`[admin-ui] claude-disconnect not verified — credentials may persist; staying put`),!1;U(!1),w(null),A(null),M(void 0),P(null);try{sessionStorage.removeItem(`maxy-admin-session-key`)}catch{}return n(`connect-claude`),!0}finally{S(!1)}},[]),Z=(0,f.useCallback)(()=>{w(null),A(null),M(void 0),P(null);try{sessionStorage.removeItem(`maxy-admin-session-key`)}catch{}i(``),d(``),n(`enter-pin`)},[]);return(0,f.useEffect)(()=>{K.current=Z},[Z]),{appState:t,setAppState:n,pin:r,setPin:i,operatorName:o,setOperatorName:l,pinError:u,setPinError:d,showPin:p,setShowPin:m,pinLoading:h,authPolling:_,setAuthPolling:v,authLoading:y,setAuthLoading:b,disconnecting:x,cacheKey:C,setCacheKey:w,claudeInfo:T,setClaudeInfo:E,businessName:D,role:k,userName:j,userAvatar:N,sessionId:F,setSessionId:I,expandAll:L,setExpandAll:R,expandAllDefaultRef:z,remoteAuthEnabled:B,claudeConnected:H,pinInputRef:W,setPinFormRef:G,handleSetPin:J,handleLogin:Y,handleDisconnect:X,handleLogout:Z}}var m=o();function h({inputRef:e,value:t,onChange:n,onComplete:r,showPin:i,autoFocus:a}){let o=(0,f.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,m.jsx)(`div`,{className:`pin-field`,children:Array.from({length:6}).map((n,r)=>(0,m.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 g(e){let{pin:t,setPin:r,showPin:a,setShowPin:o,pinLoading:s,pinError:c,pinInputRef:d,setPinFormRef:f,onSubmit:p,operatorName:g,setOperatorName:_}=e;return(0,m.jsx)(`div`,{className:`connect-page`,children:(0,m.jsxs)(`div`,{className:`connect-content`,children:[(0,m.jsx)(`img`,{src:i,alt:n.productName,className:`connect-logo connect-logo--maxy`}),!n.logoContainsName&&(0,m.jsxs)(`h1`,{className:`connect-title`,children:[`Welcome to `,n.productName]}),(0,m.jsxs)(`p`,{className:`connect-subtitle`,children:[`Tell `,n.productName,` who you are, then choose a PIN.`]}),(0,m.jsxs)(`form`,{ref:f,onSubmit:p,className:`connect-pin-form`,children:[(0,m.jsxs)(`div`,{className:`pin-input-row`,children:[(0,m.jsx)(`input`,{type:`text`,className:`connect-name-input`,placeholder:`Your full name`,value:g,onChange:e=>_(e.target.value),autoComplete:`name`,autoFocus:!0,required:!0,"aria-label":`Your full name`}),(0,m.jsx)(`div`,{style:{width:38,flexShrink:0},"aria-hidden":`true`})]}),(0,m.jsxs)(`div`,{className:`pin-input-row`,children:[(0,m.jsx)(h,{inputRef:d,value:t,onChange:r,onComplete:()=>{},showPin:a}),(0,m.jsx)(l,{variant:`send`,type:`submit`,disabled:!t||!g.trim(),loading:s,"aria-label":`Set PIN`,children:(0,m.jsxs)(`svg`,{viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`,children:[(0,m.jsx)(`line`,{x1:`5`,y1:`12`,x2:`19`,y2:`12`}),(0,m.jsx)(`polyline`,{points:`12 5 19 12 12 19`})]})})]}),(0,m.jsx)(u,{checked:a,onChange:()=>o(e=>!e),label:`Show PIN`})]}),c&&(0,m.jsx)(`p`,{className:`admin-pin-error`,children:c})]})})}function _(e){let{pin:t,setPin:r,showPin:a,setShowPin:o,pinLoading:s,pinError:c,pinInputRef:d,onSubmit:f,remoteAuthEnabled:p,onSignOutRemote:g}=e;return(0,m.jsxs)(`div`,{className:`connect-page`,children:[p&&g&&(0,m.jsx)(`button`,{type:`button`,className:`connect-signout`,onClick:g,children:`Sign out`}),(0,m.jsxs)(`div`,{className:`connect-content`,children:[(0,m.jsx)(`img`,{src:i,alt:n.productName,className:`connect-logo connect-logo--maxy`}),!n.logoContainsName&&(0,m.jsx)(`h1`,{className:`connect-title`,children:n.productName}),(0,m.jsxs)(`form`,{onSubmit:f,className:`connect-pin-form`,children:[(0,m.jsxs)(`div`,{className:`pin-input-row`,children:[(0,m.jsx)(h,{inputRef:d,value:t,onChange:r,onComplete:()=>{},showPin:a,autoFocus:!0}),(0,m.jsx)(l,{variant:`send`,type:`submit`,disabled:!t,loading:s,children:(0,m.jsxs)(`svg`,{viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`,children:[(0,m.jsx)(`line`,{x1:`5`,y1:`12`,x2:`19`,y2:`12`}),(0,m.jsx)(`polyline`,{points:`12 5 19 12 12 19`})]})})]}),(0,m.jsx)(`div`,{className:`pin-options`,children:(0,m.jsx)(u,{checked:a,onChange:()=>o(e=>!e),label:`Show PIN`})})]}),c&&(0,m.jsx)(`p`,{className:`admin-pin-error`,children:c})]})]})}function v(e){let{authPolling:t,setAuthPolling:r,authLoading:a,setAuthLoading:o,pinError:s,setPinError:c,setAppState:u}=e,[p,h]=(0,f.useState)(!1),[g,_]=(0,f.useState)(!1),[v,y]=(0,f.useState)(``),[b,x]=(0,f.useState)(``),[S,C]=(0,f.useState)(``),[w,T]=(0,f.useState)(null),[E,D]=(0,f.useState)(null),[O,k]=(0,f.useState)(!1);(0,f.useEffect)(()=>{try{D(sessionStorage.getItem(`maxy-admin-session-key`))}catch{}k(!0)},[]);async function A(){C(``);try{let e=await(await fetch(`/api/onboarding/claude-auth`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({action:`paste-code`,code:b})})).json();e.accepted?(C(`Code submitted. Finishing sign-in…`),x(``)):C(e.error||`Could not submit code.`)}catch(e){console.error(`[admin] paste-code error:`,e),C(`Could not submit code.`)}}async function j(){_(!0),c(``);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?h(!0):e.error&&c(e.error)}catch(e){console.error(`[admin] browser launch error:`,e),c(`Could not launch browser.`)}_(!1)}async function M(){o(!0),c(``);try{let e=await(await fetch(`/api/onboarding/claude-auth`,{method:`POST`})).json();if(e.started){r(!0),h(!0),o(!1),y(e.transport||``);for(let e=0;e<120;e++){await new Promise(e=>setTimeout(e,2e3));let e=await(await fetch(`/api/onboarding/claude-auth`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({action:`wait`})})).json();if(typeof e.authTargetId==`string`&&T(e.authTargetId),e.authenticated){await fetch(`/api/onboarding/claude-auth`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({action:`stop`})}),u(`enter-pin`);return}}c(`Timed out waiting for sign-in. Try again.`),r(!1)}else e.error&&c(e.error)}catch(e){console.error(`[admin] auth flow error:`,e),c(`Could not start auth flow.`)}o(!1)}async function N(){await fetch(`/api/onboarding/claude-auth`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({action:`stop`})}),r(!1),c(``)}return t||p?(0,m.jsxs)(`div`,{style:{display:`flex`,flexDirection:`column`,height:`100dvh`,overflow:`auto`},children:[(0,m.jsxs)(`header`,{className:`chat-header`,style:{paddingBottom:`12px`,flexShrink:0,position:`relative`,maxWidth:`680px`,width:`100%`,margin:`0 auto`,padding:`24px 20px 12px`},children:[t?(0,m.jsx)(`button`,{onClick:N,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,m.jsx)(`button`,{onClick:()=>h(!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,m.jsx)(`img`,{src:`/brand/claude.png`,alt:`Claude`,className:`chat-logo`}),(0,m.jsx)(`h1`,{className:`chat-tagline`,children:`Connect Claude`}),(0,m.jsx)(`p`,{className:`chat-intro`,children:t?`Sign in and authorize in the browser below.`:`Open your email or prepare your accounts, then sign in.`}),!t&&(0,m.jsx)(`div`,{style:{marginTop:`12px`},children:(0,m.jsx)(l,{variant:`primary`,onClick:M,disabled:a,children:a?(0,m.jsxs)(m.Fragment,{children:[(0,m.jsx)(`span`,{className:`spin`,style:{display:`inline-block`},children:`✱`}),` Connecting…`]}):`Sign in to Claude`})}),t&&v===`native`&&(0,m.jsxs)(`div`,{style:{marginTop:`14px`,maxWidth:`420px`,margin:`14px auto 0`,display:`flex`,flexDirection:`column`,gap:`8px`},children:[(0,m.jsx)(`label`,{style:{fontSize:`12px`,color:`#999`,lineHeight:1.4},children:`If the browser didn't finish sign-in, paste the code or full redirect URL from Claude's page:`}),(0,m.jsxs)(`div`,{style:{display:`flex`,gap:`8px`},children:[(0,m.jsx)(`input`,{type:`text`,value:b,onChange:e=>x(e.target.value),placeholder:`Paste code or redirect URL`,style:{flex:1,padding:`8px 10px`,fontSize:`13px`,border:`1px solid #ccc`,borderRadius:`6px`}}),(0,m.jsx)(l,{variant:`primary`,onClick:A,disabled:!b.trim(),children:`Submit`})]}),S&&(0,m.jsx)(`p`,{style:{fontSize:`12px`,color:`#999`,margin:0},children:S})]})]}),(0,m.jsx)(`div`,{style:{flex:1,display:`flex`,flexDirection:`column`,minHeight:0,gap:`10px`,padding:`0 0 16px`},children:O&&(0,m.jsx)(d,{preferTargetId:w,cacheKey:E,chrome:!1})}),s&&(0,m.jsx)(`p`,{className:`admin-pin-error`,style:{textAlign:`center`,padding:`0 20px 16px`},children:s})]}):(0,m.jsx)(`div`,{className:`connect-page`,children:(0,m.jsxs)(`div`,{className:`connect-content`,children:[(0,m.jsxs)(`div`,{className:`connect-logos`,children:[(0,m.jsx)(`div`,{className:`connect-logo-wrap`,children:(0,m.jsx)(`img`,{src:`/brand/claude.png`,alt:`Claude`,className:`connect-logo`})}),(0,m.jsx)(`svg`,{className:`connect-arrow`,viewBox:`0 0 48 24`,fill:`none`,xmlns:`http://www.w3.org/2000/svg`,children:(0,m.jsx)(`path`,{d:`M0 12h44m0 0l-8-8m8 8l-8 8`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`})}),(0,m.jsxs)(`div`,{className:`connect-logo-wrap`,children:[(0,m.jsx)(`img`,{src:i,alt:n.productName,className:`connect-logo connect-logo--maxy`}),!n.logoContainsName&&(0,m.jsx)(`span`,{className:`connect-logo-label`,children:n.productName})]})]}),(0,m.jsxs)(`h1`,{className:`connect-title`,children:[`Connect Claude to power `,n.productName]}),(0,m.jsx)(`p`,{className:`connect-subtitle`,children:`Sign in with your Anthropic account to get started.`}),(0,m.jsx)(l,{variant:`primary`,onClick:M,disabled:a,children:a?(0,m.jsxs)(m.Fragment,{children:[(0,m.jsx)(`span`,{className:`spin`,style:{display:`inline-block`},children:`✱`}),` Connecting…`]}):`Sign in to Claude`}),(0,m.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,m.jsx)(`button`,{onClick:j,disabled:g,style:{marginTop:`12px`,background:`none`,border:`none`,color:`var(--color-primary, #666)`,fontSize:`13px`,cursor:`pointer`,textDecoration:`underline`,textUnderlineOffset:`3px`},children:g?`Launching…`:`Open browser first`}),s&&(0,m.jsx)(`p`,{className:`admin-pin-error`,children:s})]})})}function y({auth:e}){return e.appState===`loading`?(0,m.jsx)(t,{surface:`gate`}):e.appState===`set-pin`?(0,m.jsx)(g,{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,m.jsx)(v,{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,m.jsx)(_,{pin:e.pin,setPin:e.setPin,showPin:e.showPin,setShowPin:e.setShowPin,pinLoading:e.pinLoading,pinError:e.pinError,pinInputRef:e.pinInputRef,onSubmit:e.handleLogin,remoteAuthEnabled:e.remoteAuthEnabled,onSignOutRemote:()=>{window.location.href=`/__remote-auth/logout`}}):null}export{p as n,y as t};
|
|
1
|
+
import{o as e}from"./chunk-CltuBf4Z.js";import{O as t,Q as n,ct as r,et as i,it as a,nt as o}from"./useMediaQuery-D8VDA0RN.js";import{A as s}from"./useVoiceRecorder-B8vxObZG.js";import{A as c,O as l,k as u,p as d}from"./AdminShell-DStA0lfm.js";var f=e(r(),1);function p(e=`admin`){let[t,n]=(0,f.useState)(`loading`),[r,i]=(0,f.useState)(``),[o,l]=(0,f.useState)(``),[u,d]=(0,f.useState)(``),[p,m]=(0,f.useState)(!1),[h,g]=(0,f.useState)(!1),[_,v]=(0,f.useState)(!1),[y,b]=(0,f.useState)(!1),[x,S]=(0,f.useState)(!1),[C,w]=(0,f.useState)(null),[T,E]=(0,f.useState)(null),[D,O]=(0,f.useState)(void 0),[k,A]=(0,f.useState)(null),[j,M]=(0,f.useState)(void 0),[N,P]=(0,f.useState)(null),[F,I]=(0,f.useState)(null),[L,R]=(0,f.useState)(void 0),z=(0,f.useRef)(void 0),[B,V]=(0,f.useState)(!1),[H,U]=(0,f.useState)(!0);(0,f.useEffect)(()=>{typeof window>`u`||fetch(`/api/remote-auth/status`).then(e=>e.ok?e.json():null).then(e=>{e?.configured&&V(!0)}).catch(()=>{})},[]);let W=(0,f.useRef)(null),G=(0,f.useRef)(null);(0,f.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();w(r.session_key),I(r.sessionId??null),O(r.businessName),A(r.role??null),M(r.userName===void 0?null:r.userName),P(r.avatar??null);let i=s(r.thinkingView);return z.current=i,R(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}U(!!a.claude_authenticated);let o=!1;try{o=new URLSearchParams(window.location.search).get(`connect`)===`claude`}catch{}if(o){try{let e=new URL(window.location.href);e.searchParams.delete(`connect`),window.history.replaceState(null,``,e.pathname+e.search+e.hash)}catch{}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,f.useEffect)(()=>{t===`chat`&&C&&fetch(`/api/admin/claude-info?session_key=${encodeURIComponent(C)}`).then(e=>{if(e.ok)return e.json()}).then(e=>{e&&E(e)}).catch(()=>{})},[t,C]);let K=(0,f.useRef)(null);(0,f.useEffect)(()=>{if(t!==`chat`)return;let e=setInterval(async()=>{try{let e=await fetch(`/api/health`);if(e.ok){let t=await e.json();U(t.auth_status!==`dead`&&t.auth_status!==`missing`)}}catch{}if(C)try{let e=await fetch(`/api/admin/session?session_key=${encodeURIComponent(C)}`);if(e.status!==401)return;let t=(await e.clone().json().catch(()=>null))?.code??`unknown-401`;if(t===`remote-auth-required`){a(`heartbeat`,`/api/admin/session`);return}console.warn(`[admin-auth] outcome=heartbeat-detected-expiry code=${t}`),K.current?.()}catch{}},300*1e3);return()=>clearInterval(e)},[t,C]),(0,f.useEffect)(()=>{t===`connect-claude`&&fetch(`/api/health`).then(e=>e.ok?e.json():null).then(e=>{e?.claude_authenticated&&(U(!0),n(`enter-pin`))}).catch(()=>{})},[t]);async function q(e,t){g(!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){let e=await r.json().catch(()=>({}));if(r.status===401&&e?.code===`remote-auth-required`){a(`enter-pin`,`/api/admin/session`);return}d(e.error||`Invalid PIN`);return}let o=await r.json();w(o.session_key),I(o.sessionId??null),O(o.businessName),A(o.role??null),M(o.userName===void 0?null:o.userName),P(o.avatar??null);let c=s(o.thinkingView);z.current=c,R(c);try{sessionStorage.setItem(`maxy-admin-session-key`,o.session_key)}catch{}i(``),n(`chat`)}catch(e){console.error(`[admin] connection error:`,e),d(`Could not connect.`)}finally{g(!1)}}let J=(0,f.useCallback)(async e=>{if(e.preventDefault(),h)return;d(``);let t=o.trim();if(!t){d(`Please enter your name.`);return}if(r.length<4){d(`PIN must be at least 4 characters.`);return}let s=r;g(!0);try{let e=await fetch(`/api/onboarding/set-pin`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({pin:s,name:t})});if(!e.ok){let t=await e.json().catch(()=>({}));if(e.status===401&&t?.code===`remote-auth-required`){a(`set-pin`,`/api/onboarding/set-pin`);return}if(e.status===409){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`):d(t.error||`Failed to set PIN.`)}else n(`enter-pin`)}catch{n(`enter-pin`)}return}d(t.error||`Failed to set PIN.`);return}let r=await fetch(`/api/health`);if((r.ok?await r.json():null)?.claude_authenticated){await q(s);return}i(``),n(`connect-claude`)}catch(e){console.error(`[admin] connection error:`,e),d(`Could not connect.`)}finally{g(!1)}},[r,h,o]),Y=(0,f.useCallback)(async e=>{e.preventDefault(),d(``),await q(r)},[r]),X=(0,f.useCallback)(async()=>{S(!0);try{if(!await c())return console.warn(`[admin-ui] claude-disconnect not verified — credentials may persist; staying put`),!1;U(!1),w(null),A(null),M(void 0),P(null);try{sessionStorage.removeItem(`maxy-admin-session-key`)}catch{}return n(`connect-claude`),!0}finally{S(!1)}},[]),Z=(0,f.useCallback)(()=>{w(null),A(null),M(void 0),P(null);try{sessionStorage.removeItem(`maxy-admin-session-key`)}catch{}i(``),d(``),n(`enter-pin`)},[]);return(0,f.useEffect)(()=>{K.current=Z},[Z]),{appState:t,setAppState:n,pin:r,setPin:i,operatorName:o,setOperatorName:l,pinError:u,setPinError:d,showPin:p,setShowPin:m,pinLoading:h,authPolling:_,setAuthPolling:v,authLoading:y,setAuthLoading:b,disconnecting:x,cacheKey:C,setCacheKey:w,claudeInfo:T,setClaudeInfo:E,businessName:D,role:k,userName:j,userAvatar:N,sessionId:F,setSessionId:I,expandAll:L,setExpandAll:R,expandAllDefaultRef:z,remoteAuthEnabled:B,claudeConnected:H,pinInputRef:W,setPinFormRef:G,handleSetPin:J,handleLogin:Y,handleDisconnect:X,handleLogout:Z}}var m=o();function h({inputRef:e,value:t,onChange:n,onComplete:r,showPin:i,autoFocus:a}){let o=(0,f.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,m.jsx)(`div`,{className:`pin-field`,children:Array.from({length:6}).map((n,r)=>(0,m.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 g(e){let{pin:t,setPin:r,showPin:a,setShowPin:o,pinLoading:s,pinError:c,pinInputRef:d,setPinFormRef:f,onSubmit:p,operatorName:g,setOperatorName:_}=e;return(0,m.jsx)(`div`,{className:`connect-page`,children:(0,m.jsxs)(`div`,{className:`connect-content`,children:[(0,m.jsx)(`img`,{src:i,alt:n.productName,className:`connect-logo connect-logo--maxy`}),!n.logoContainsName&&(0,m.jsxs)(`h1`,{className:`connect-title`,children:[`Welcome to `,n.productName]}),(0,m.jsxs)(`p`,{className:`connect-subtitle`,children:[`Tell `,n.productName,` who you are, then choose a PIN.`]}),(0,m.jsxs)(`form`,{ref:f,onSubmit:p,className:`connect-pin-form`,children:[(0,m.jsxs)(`div`,{className:`pin-input-row`,children:[(0,m.jsx)(`input`,{type:`text`,className:`connect-name-input`,placeholder:`Your full name`,value:g,onChange:e=>_(e.target.value),autoComplete:`name`,autoFocus:!0,required:!0,"aria-label":`Your full name`}),(0,m.jsx)(`div`,{style:{width:38,flexShrink:0},"aria-hidden":`true`})]}),(0,m.jsxs)(`div`,{className:`pin-input-row`,children:[(0,m.jsx)(h,{inputRef:d,value:t,onChange:r,onComplete:()=>{},showPin:a}),(0,m.jsx)(l,{variant:`send`,type:`submit`,disabled:!t||!g.trim(),loading:s,"aria-label":`Set PIN`,children:(0,m.jsxs)(`svg`,{viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`,children:[(0,m.jsx)(`line`,{x1:`5`,y1:`12`,x2:`19`,y2:`12`}),(0,m.jsx)(`polyline`,{points:`12 5 19 12 12 19`})]})})]}),(0,m.jsx)(u,{checked:a,onChange:()=>o(e=>!e),label:`Show PIN`})]}),c&&(0,m.jsx)(`p`,{className:`admin-pin-error`,children:c})]})})}function _(e){let{pin:t,setPin:r,showPin:a,setShowPin:o,pinLoading:s,pinError:c,pinInputRef:d,onSubmit:f,remoteAuthEnabled:p,onSignOutRemote:g}=e;return(0,m.jsxs)(`div`,{className:`connect-page`,children:[p&&g&&(0,m.jsx)(`button`,{type:`button`,className:`connect-signout`,onClick:g,children:`Sign out`}),(0,m.jsxs)(`div`,{className:`connect-content`,children:[(0,m.jsx)(`img`,{src:i,alt:n.productName,className:`connect-logo connect-logo--maxy`}),!n.logoContainsName&&(0,m.jsx)(`h1`,{className:`connect-title`,children:n.productName}),(0,m.jsxs)(`form`,{onSubmit:f,className:`connect-pin-form`,children:[(0,m.jsxs)(`div`,{className:`pin-input-row`,children:[(0,m.jsx)(h,{inputRef:d,value:t,onChange:r,onComplete:()=>{},showPin:a,autoFocus:!0}),(0,m.jsx)(l,{variant:`send`,type:`submit`,disabled:!t,loading:s,children:(0,m.jsxs)(`svg`,{viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`,children:[(0,m.jsx)(`line`,{x1:`5`,y1:`12`,x2:`19`,y2:`12`}),(0,m.jsx)(`polyline`,{points:`12 5 19 12 12 19`})]})})]}),(0,m.jsx)(`div`,{className:`pin-options`,children:(0,m.jsx)(u,{checked:a,onChange:()=>o(e=>!e),label:`Show PIN`})})]}),c&&(0,m.jsx)(`p`,{className:`admin-pin-error`,children:c})]})]})}function v(e){let{authPolling:t,setAuthPolling:r,authLoading:a,setAuthLoading:o,pinError:s,setPinError:c,setAppState:u}=e,[p,h]=(0,f.useState)(!1),[g,_]=(0,f.useState)(!1),[v,y]=(0,f.useState)(``),[b,x]=(0,f.useState)(``),[S,C]=(0,f.useState)(``),[w,T]=(0,f.useState)(null),[E,D]=(0,f.useState)(null),[O,k]=(0,f.useState)(!1);(0,f.useEffect)(()=>{try{D(sessionStorage.getItem(`maxy-admin-session-key`))}catch{}k(!0)},[]);async function A(){C(``);try{let e=await(await fetch(`/api/onboarding/claude-auth`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({action:`paste-code`,code:b})})).json();e.accepted?(C(`Code submitted. Finishing sign-in…`),x(``)):C(e.error||`Could not submit code.`)}catch(e){console.error(`[admin] paste-code error:`,e),C(`Could not submit code.`)}}async function j(){_(!0),c(``);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?h(!0):e.error&&c(e.error)}catch(e){console.error(`[admin] browser launch error:`,e),c(`Could not launch browser.`)}_(!1)}async function M(){o(!0),c(``);try{let e=await(await fetch(`/api/onboarding/claude-auth`,{method:`POST`})).json();if(e.started){r(!0),h(!0),o(!1),y(e.transport||``);for(let e=0;e<120;e++){await new Promise(e=>setTimeout(e,2e3));let e=await(await fetch(`/api/onboarding/claude-auth`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({action:`wait`})})).json();if(typeof e.authTargetId==`string`&&T(e.authTargetId),e.authenticated){await fetch(`/api/onboarding/claude-auth`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({action:`stop`})}),u(`enter-pin`);return}}c(`Timed out waiting for sign-in. Try again.`),r(!1)}else e.error&&c(e.error)}catch(e){console.error(`[admin] auth flow error:`,e),c(`Could not start auth flow.`)}o(!1)}async function N(){await fetch(`/api/onboarding/claude-auth`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({action:`stop`})}),r(!1),c(``)}return t||p?(0,m.jsxs)(`div`,{style:{display:`flex`,flexDirection:`column`,height:`100dvh`,overflow:`auto`},children:[(0,m.jsxs)(`header`,{className:`chat-header`,style:{paddingBottom:`12px`,flexShrink:0,position:`relative`,maxWidth:`680px`,width:`100%`,margin:`0 auto`,padding:`24px 20px 12px`},children:[t?(0,m.jsx)(`button`,{onClick:N,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,m.jsx)(`button`,{onClick:()=>h(!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,m.jsx)(`img`,{src:`/brand/claude.png`,alt:`Claude`,className:`chat-logo`}),(0,m.jsx)(`h1`,{className:`chat-tagline`,children:`Connect Claude`}),(0,m.jsx)(`p`,{className:`chat-intro`,children:t?`Sign in and authorize in the browser below.`:`Open your email or prepare your accounts, then sign in.`}),!t&&(0,m.jsx)(`div`,{style:{marginTop:`12px`},children:(0,m.jsx)(l,{variant:`primary`,onClick:M,disabled:a,children:a?(0,m.jsxs)(m.Fragment,{children:[(0,m.jsx)(`span`,{className:`spin`,style:{display:`inline-block`},children:`✱`}),` Connecting…`]}):`Sign in to Claude`})}),t&&v===`native`&&(0,m.jsxs)(`div`,{style:{marginTop:`14px`,maxWidth:`420px`,margin:`14px auto 0`,display:`flex`,flexDirection:`column`,gap:`8px`},children:[(0,m.jsx)(`label`,{style:{fontSize:`12px`,color:`#999`,lineHeight:1.4},children:`If the browser didn't finish sign-in, paste the code or full redirect URL from Claude's page:`}),(0,m.jsxs)(`div`,{style:{display:`flex`,gap:`8px`},children:[(0,m.jsx)(`input`,{type:`text`,value:b,onChange:e=>x(e.target.value),placeholder:`Paste code or redirect URL`,style:{flex:1,padding:`8px 10px`,fontSize:`13px`,border:`1px solid #ccc`,borderRadius:`6px`}}),(0,m.jsx)(l,{variant:`primary`,onClick:A,disabled:!b.trim(),children:`Submit`})]}),S&&(0,m.jsx)(`p`,{style:{fontSize:`12px`,color:`#999`,margin:0},children:S})]})]}),(0,m.jsx)(`div`,{style:{flex:1,display:`flex`,flexDirection:`column`,minHeight:0,gap:`10px`,padding:`0 0 16px`},children:O&&(0,m.jsx)(d,{preferTargetId:w,cacheKey:E,chrome:!1})}),s&&(0,m.jsx)(`p`,{className:`admin-pin-error`,style:{textAlign:`center`,padding:`0 20px 16px`},children:s})]}):(0,m.jsx)(`div`,{className:`connect-page`,children:(0,m.jsxs)(`div`,{className:`connect-content`,children:[(0,m.jsxs)(`div`,{className:`connect-logos`,children:[(0,m.jsx)(`div`,{className:`connect-logo-wrap`,children:(0,m.jsx)(`img`,{src:`/brand/claude.png`,alt:`Claude`,className:`connect-logo`})}),(0,m.jsx)(`svg`,{className:`connect-arrow`,viewBox:`0 0 48 24`,fill:`none`,xmlns:`http://www.w3.org/2000/svg`,children:(0,m.jsx)(`path`,{d:`M0 12h44m0 0l-8-8m8 8l-8 8`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`})}),(0,m.jsxs)(`div`,{className:`connect-logo-wrap`,children:[(0,m.jsx)(`img`,{src:i,alt:n.productName,className:`connect-logo connect-logo--maxy`}),!n.logoContainsName&&(0,m.jsx)(`span`,{className:`connect-logo-label`,children:n.productName})]})]}),(0,m.jsxs)(`h1`,{className:`connect-title`,children:[`Connect Claude to power `,n.productName]}),(0,m.jsx)(`p`,{className:`connect-subtitle`,children:`Sign in with your Anthropic account to get started.`}),(0,m.jsx)(l,{variant:`primary`,onClick:M,disabled:a,children:a?(0,m.jsxs)(m.Fragment,{children:[(0,m.jsx)(`span`,{className:`spin`,style:{display:`inline-block`},children:`✱`}),` Connecting…`]}):`Sign in to Claude`}),(0,m.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,m.jsx)(`button`,{onClick:j,disabled:g,style:{marginTop:`12px`,background:`none`,border:`none`,color:`var(--color-primary, #666)`,fontSize:`13px`,cursor:`pointer`,textDecoration:`underline`,textUnderlineOffset:`3px`},children:g?`Launching…`:`Open browser first`}),s&&(0,m.jsx)(`p`,{className:`admin-pin-error`,children:s})]})})}function y({auth:e}){return e.appState===`loading`?(0,m.jsx)(t,{surface:`gate`}):e.appState===`set-pin`?(0,m.jsx)(g,{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,m.jsx)(v,{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,m.jsx)(_,{pin:e.pin,setPin:e.setPin,showPin:e.showPin,setShowPin:e.setShowPin,pinLoading:e.pinLoading,pinError:e.pinError,pinInputRef:e.pinInputRef,onSubmit:e.handleLogin,remoteAuthEnabled:e.remoteAuthEnabled,onSignOutRemote:()=>{window.location.href=`/__remote-auth/logout`}}):null}export{p as n,y as t};
|
|
Binary file
|
|
Binary file
|