@rubytech/create-maxy-code 0.1.573 → 0.1.574
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/admins-write/__tests__/index.test.ts +97 -0
- package/payload/platform/lib/admins-write/dist/index.d.ts +12 -0
- package/payload/platform/lib/admins-write/dist/index.d.ts.map +1 -1
- package/payload/platform/lib/admins-write/dist/index.js +27 -5
- package/payload/platform/lib/admins-write/dist/index.js.map +1 -1
- package/payload/platform/lib/admins-write/src/index.ts +35 -5
- package/payload/platform/lib/admins-write/vitest.config.ts +14 -0
- package/payload/platform/lib/dispatch-read/dist/session.d.ts.map +1 -1
- package/payload/platform/lib/dispatch-read/dist/session.js +19 -4
- package/payload/platform/lib/dispatch-read/dist/session.js.map +1 -1
- package/payload/platform/lib/dispatch-read/src/__tests__/session.test.ts +91 -0
- package/payload/platform/lib/dispatch-read/src/session.ts +25 -6
- package/payload/platform/plugins/admin/.claude-plugin/plugin.json +1 -1
- package/payload/platform/plugins/admin/PLUGIN.md +8 -3
- package/payload/platform/plugins/admin/hooks/__tests__/html-structure-gate.test.sh +264 -0
- package/payload/platform/plugins/admin/hooks/__tests__/quote-render-pdf-conformance.test.sh +122 -24
- package/payload/platform/plugins/admin/hooks/__tests__/specialist-dispatch-gate.test.sh +158 -0
- package/payload/platform/plugins/admin/hooks/html-structure-gate.sh +165 -0
- package/payload/platform/plugins/admin/hooks/quote-render-pdf-conformance.sh +111 -19
- package/payload/platform/plugins/admin/hooks/specialist-dispatch-gate.sh +159 -0
- package/payload/platform/plugins/admin/mcp/dist/admin-bind-classify.d.ts +27 -0
- package/payload/platform/plugins/admin/mcp/dist/admin-bind-classify.d.ts.map +1 -0
- package/payload/platform/plugins/admin/mcp/dist/admin-bind-classify.js +29 -0
- package/payload/platform/plugins/admin/mcp/dist/admin-bind-classify.js.map +1 -0
- package/payload/platform/plugins/admin/mcp/dist/binding-validate.d.ts +11 -0
- package/payload/platform/plugins/admin/mcp/dist/binding-validate.d.ts.map +1 -0
- package/payload/platform/plugins/admin/mcp/dist/binding-validate.js +20 -0
- package/payload/platform/plugins/admin/mcp/dist/binding-validate.js.map +1 -0
- package/payload/platform/plugins/admin/mcp/dist/index.js +133 -1
- package/payload/platform/plugins/admin/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/admin/skills/admin-user-management/SKILL.md +32 -2
- package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +157 -46
- package/payload/platform/plugins/admin/skills/whats-new/SKILL.md +8 -0
- package/payload/platform/plugins/docs/references/admin-ui.md +71 -31
- package/payload/platform/plugins/docs/references/channel-wake-and-prompt.md +38 -13
- package/payload/platform/plugins/docs/references/internals.md +6 -0
- package/payload/platform/plugins/docs/references/outlook-guide.md +31 -1
- package/payload/platform/plugins/docs/references/troubleshooting.md +10 -0
- package/payload/platform/plugins/outlook/PLUGIN.md +3 -1
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/draft-ledger-write-sites.test.d.ts +2 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/draft-ledger-write-sites.test.d.ts.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/draft-ledger-write-sites.test.js +177 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/draft-ledger-write-sites.test.js.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/draft-ledger.test.d.ts +2 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/draft-ledger.test.d.ts.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/draft-ledger.test.js +130 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/draft-ledger.test.js.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/draft-reconcile.test.d.ts +2 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/draft-reconcile.test.d.ts.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/draft-reconcile.test.js +162 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/draft-reconcile.test.js.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/draft-state-fields.test.d.ts +2 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/draft-state-fields.test.d.ts.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/draft-state-fields.test.js +168 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/draft-state-fields.test.js.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/lib/draft-ledger.d.ts +64 -0
- package/payload/platform/plugins/outlook/mcp/dist/lib/draft-ledger.d.ts.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/lib/draft-ledger.js +110 -0
- package/payload/platform/plugins/outlook/mcp/dist/lib/draft-ledger.js.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/lib/draft-reconcile.d.ts +119 -0
- package/payload/platform/plugins/outlook/mcp/dist/lib/draft-reconcile.d.ts.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/lib/draft-reconcile.js +0 -0
- package/payload/platform/plugins/outlook/mcp/dist/lib/draft-reconcile.js.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/scripts/draft-reconcile.d.ts +8 -0
- package/payload/platform/plugins/outlook/mcp/dist/scripts/draft-reconcile.d.ts.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/scripts/draft-reconcile.js +247 -0
- package/payload/platform/plugins/outlook/mcp/dist/scripts/draft-reconcile.js.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/tools/draft-send.d.ts.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/tools/draft-send.js +10 -0
- package/payload/platform/plugins/outlook/mcp/dist/tools/draft-send.js.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/tools/draft.d.ts.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/tools/draft.js +21 -0
- package/payload/platform/plugins/outlook/mcp/dist/tools/draft.js.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/tools/mail-fetch-body.d.ts +16 -0
- package/payload/platform/plugins/outlook/mcp/dist/tools/mail-fetch-body.d.ts.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/tools/mail-fetch-body.js +5 -1
- package/payload/platform/plugins/outlook/mcp/dist/tools/mail-fetch-body.js.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/tools/mail-list.d.ts +4 -0
- package/payload/platform/plugins/outlook/mcp/dist/tools/mail-list.d.ts.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/tools/mail-list.js +2 -1
- package/payload/platform/plugins/outlook/mcp/dist/tools/mail-list.js.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/tools/mail-reply.d.ts.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/tools/mail-reply.js +24 -0
- package/payload/platform/plugins/outlook/mcp/dist/tools/mail-reply.js.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/tools/mail-search.d.ts.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/tools/mail-search.js +2 -1
- package/payload/platform/plugins/outlook/mcp/dist/tools/mail-search.js.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/tools/mail-send.d.ts.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/tools/mail-send.js +29 -0
- package/payload/platform/plugins/outlook/mcp/dist/tools/mail-send.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/__tests__/draft-reconcile-throttle.test.d.ts +2 -0
- package/payload/platform/plugins/scheduling/mcp/dist/__tests__/draft-reconcile-throttle.test.d.ts.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/__tests__/draft-reconcile-throttle.test.js +21 -0
- package/payload/platform/plugins/scheduling/mcp/dist/__tests__/draft-reconcile-throttle.test.js.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/draft-reconcile-throttle.d.ts +13 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/draft-reconcile-throttle.d.ts.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/draft-reconcile-throttle.js +10 -0
- package/payload/platform/plugins/scheduling/mcp/dist/lib/draft-reconcile-throttle.js.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/check-due-events.js +54 -0
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/check-due-events.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/authored-specialist-tools.d.ts +32 -0
- package/payload/platform/services/claude-session-manager/dist/authored-specialist-tools.d.ts.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/authored-specialist-tools.js +144 -0
- package/payload/platform/services/claude-session-manager/dist/authored-specialist-tools.js.map +1 -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/html-structure-census.d.ts +44 -0
- package/payload/platform/services/claude-session-manager/dist/html-structure-census.d.ts.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/html-structure-census.js +185 -0
- package/payload/platform/services/claude-session-manager/dist/html-structure-census.js.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/index.js +125 -0
- package/payload/platform/services/claude-session-manager/dist/index.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/quote-delivery-reconcile.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/quote-delivery-reconcile.js +7 -0
- package/payload/platform/services/claude-session-manager/dist/quote-delivery-reconcile.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/quote-print-census.d.ts +42 -0
- package/payload/platform/services/claude-session-manager/dist/quote-print-census.d.ts.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/quote-print-census.js +254 -0
- package/payload/platform/services/claude-session-manager/dist/quote-print-census.js.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/specialist-census.d.ts +92 -0
- package/payload/platform/services/claude-session-manager/dist/specialist-census.d.ts.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/specialist-census.js +227 -0
- package/payload/platform/services/claude-session-manager/dist/specialist-census.js.map +1 -0
- package/payload/platform/templates/account-settings.json +8 -4
- package/payload/server/server.js +465 -361
package/payload/server/server.js
CHANGED
|
@@ -2983,15 +2983,22 @@ var require_session = __commonJS({
|
|
|
2983
2983
|
exports.withSession = withSession3;
|
|
2984
2984
|
exports.__setDriverForTests = __setDriverForTests;
|
|
2985
2985
|
var node_fs_1 = __require("fs");
|
|
2986
|
+
var node_path_1 = __require("path");
|
|
2986
2987
|
var neo4j_driver_1 = __importDefault(__require("neo4j-driver"));
|
|
2987
2988
|
var driver2 = null;
|
|
2988
2989
|
function password2() {
|
|
2989
2990
|
if (process.env.NEO4J_PASSWORD)
|
|
2990
2991
|
return process.env.NEO4J_PASSWORD;
|
|
2991
|
-
const
|
|
2992
|
-
if (
|
|
2993
|
-
|
|
2994
|
-
|
|
2992
|
+
const root = process.env.MAXY_PLATFORM_ROOT ?? process.env.PLATFORM_ROOT;
|
|
2993
|
+
if (!root) {
|
|
2994
|
+
throw new Error("[dispatch-read] neither MAXY_PLATFORM_ROOT nor PLATFORM_ROOT is set \u2014 cannot locate config/.neo4j-password");
|
|
2995
|
+
}
|
|
2996
|
+
const passwordFile = (0, node_path_1.resolve)(root, "config/.neo4j-password");
|
|
2997
|
+
try {
|
|
2998
|
+
return (0, node_fs_1.readFileSync)(passwordFile, "utf-8").trim();
|
|
2999
|
+
} catch (err) {
|
|
3000
|
+
throw new Error(`[dispatch-read] Neo4j password not found. Expected at ${passwordFile}, or in NEO4J_PASSWORD. Read failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
3001
|
+
}
|
|
2995
3002
|
}
|
|
2996
3003
|
function getDriver2() {
|
|
2997
3004
|
if (driver2)
|
|
@@ -5095,10 +5102,10 @@ var require_dist7 = __commonJS({
|
|
|
5095
5102
|
|
|
5096
5103
|
// server/index.ts
|
|
5097
5104
|
init_dist();
|
|
5098
|
-
import { readFileSync as readFileSync55, existsSync as
|
|
5105
|
+
import { readFileSync as readFileSync55, existsSync as existsSync55, watchFile, readdirSync as readdirSync32, statSync as statSync30 } from "fs";
|
|
5099
5106
|
import { spawn as spawn3 } from "child_process";
|
|
5100
5107
|
import { createHash as createHash8 } from "crypto";
|
|
5101
|
-
import { resolve as
|
|
5108
|
+
import { resolve as resolve52, join as join63, basename as basename17 } from "path";
|
|
5102
5109
|
import { homedir as homedir5 } from "os";
|
|
5103
5110
|
|
|
5104
5111
|
// server/lib/route-cache-watchers.ts
|
|
@@ -6658,20 +6665,20 @@ function buildX11Env(chromiumWrapperPath, transport = "vnc") {
|
|
|
6658
6665
|
// server/routes/health.ts
|
|
6659
6666
|
init_claude_agent();
|
|
6660
6667
|
function checkPort(port2, timeoutMs = 500) {
|
|
6661
|
-
return new Promise((
|
|
6668
|
+
return new Promise((resolve53) => {
|
|
6662
6669
|
const socket = createConnection2(port2, "127.0.0.1");
|
|
6663
6670
|
socket.setTimeout(timeoutMs);
|
|
6664
6671
|
socket.once("connect", () => {
|
|
6665
6672
|
socket.destroy();
|
|
6666
|
-
|
|
6673
|
+
resolve53(true);
|
|
6667
6674
|
});
|
|
6668
6675
|
socket.once("error", () => {
|
|
6669
6676
|
socket.destroy();
|
|
6670
|
-
|
|
6677
|
+
resolve53(false);
|
|
6671
6678
|
});
|
|
6672
6679
|
socket.once("timeout", () => {
|
|
6673
6680
|
socket.destroy();
|
|
6674
|
-
|
|
6681
|
+
resolve53(false);
|
|
6675
6682
|
});
|
|
6676
6683
|
});
|
|
6677
6684
|
}
|
|
@@ -7648,7 +7655,7 @@ async function defaultResolve(accountId) {
|
|
|
7648
7655
|
return resolveSocket2(accountId);
|
|
7649
7656
|
}
|
|
7650
7657
|
async function fetchAvatar(accountId, jid, deps = {}) {
|
|
7651
|
-
const
|
|
7658
|
+
const resolve53 = deps.resolve;
|
|
7652
7659
|
const httpGet = deps.httpGet ?? defaultHttpGet;
|
|
7653
7660
|
const maxAgeMs = deps.maxAgeMs ?? DEFAULT_MAX_AGE_MS;
|
|
7654
7661
|
const cached3 = readAvatar(accountId, jid);
|
|
@@ -7658,7 +7665,7 @@ async function fetchAvatar(accountId, jid, deps = {}) {
|
|
|
7658
7665
|
return "fresh";
|
|
7659
7666
|
}
|
|
7660
7667
|
console.log(`${TAG7} op=cache jid=${jid} hit=false ageMs=${ageMs2}`);
|
|
7661
|
-
const res =
|
|
7668
|
+
const res = resolve53 ? resolve53(accountId) : await defaultResolve(accountId);
|
|
7662
7669
|
if (!res.ok) {
|
|
7663
7670
|
console.log(`${TAG7} op=no-socket jid=${jid} account=${accountId.slice(0, 8)} reason=${res.reason}`);
|
|
7664
7671
|
return "no-socket";
|
|
@@ -9149,8 +9156,8 @@ async function startLogin(opts) {
|
|
|
9149
9156
|
await clearAuth(authDir);
|
|
9150
9157
|
let resolveCode = null;
|
|
9151
9158
|
let rejectCode = null;
|
|
9152
|
-
const codePromise = new Promise((
|
|
9153
|
-
resolveCode =
|
|
9159
|
+
const codePromise = new Promise((resolve53, reject) => {
|
|
9160
|
+
resolveCode = resolve53;
|
|
9154
9161
|
rejectCode = reject;
|
|
9155
9162
|
});
|
|
9156
9163
|
const codeTimer = setTimeout(
|
|
@@ -16891,16 +16898,27 @@ function writeAdminEntry(input) {
|
|
|
16891
16898
|
}
|
|
16892
16899
|
const rowsBefore = users.map((u) => id8(u.userId)).join(",");
|
|
16893
16900
|
const existing = users.findIndex((u) => u.userId === input.userId);
|
|
16901
|
+
const pinRotated = existing !== -1 && users[existing].pin !== input.pin;
|
|
16902
|
+
const boundFields = [
|
|
16903
|
+
input.phone !== void 0 ? "phone" : null,
|
|
16904
|
+
input.telegram !== void 0 ? "telegram" : null
|
|
16905
|
+
].filter(Boolean);
|
|
16894
16906
|
if (existing === -1) {
|
|
16895
|
-
|
|
16907
|
+
const row = { userId: input.userId, pin: input.pin };
|
|
16908
|
+
if (input.phone !== void 0) row.phone = input.phone;
|
|
16909
|
+
if (input.telegram !== void 0) row.telegram = input.telegram;
|
|
16910
|
+
users.push(row);
|
|
16896
16911
|
} else {
|
|
16897
|
-
|
|
16912
|
+
const row = { ...users[existing], pin: input.pin };
|
|
16913
|
+
if (input.phone !== void 0) row.phone = input.phone;
|
|
16914
|
+
if (input.telegram !== void 0) row.telegram = input.telegram;
|
|
16915
|
+
users[existing] = row;
|
|
16898
16916
|
}
|
|
16899
16917
|
writeFileAtomic(input.usersFile, JSON.stringify(users, null, 2) + "\n", 384);
|
|
16900
16918
|
result.usersJsonResult = "ok";
|
|
16901
16919
|
appendUsersAuditLine(input.audit, {
|
|
16902
|
-
action: existing === -1 ? "add" : "set-pin",
|
|
16903
|
-
field: existing === -1 ? "row" : "pin",
|
|
16920
|
+
action: existing === -1 ? "add" : pinRotated ? "set-pin" : "set-binding",
|
|
16921
|
+
field: existing === -1 ? "row" : pinRotated ? "pin" : boundFields.join(","),
|
|
16904
16922
|
rowsBefore,
|
|
16905
16923
|
rowsAfter: users.map((u) => id8(u.userId)).join(",")
|
|
16906
16924
|
});
|
|
@@ -17410,7 +17428,7 @@ var onboarding_default = app13;
|
|
|
17410
17428
|
|
|
17411
17429
|
// server/routes/dispatch.ts
|
|
17412
17430
|
init_dist();
|
|
17413
|
-
import { resolve as
|
|
17431
|
+
import { resolve as resolve23 } from "path";
|
|
17414
17432
|
import { randomUUID as randomUUID5 } from "crypto";
|
|
17415
17433
|
|
|
17416
17434
|
// ../lib/dispatch-read/src/config.ts
|
|
@@ -17454,16 +17472,26 @@ function terminalVisitStatuses(cfg) {
|
|
|
17454
17472
|
}
|
|
17455
17473
|
|
|
17456
17474
|
// ../lib/dispatch-read/src/session.ts
|
|
17457
|
-
import {
|
|
17475
|
+
import { readFileSync as readFileSync32 } from "fs";
|
|
17476
|
+
import { resolve as resolve22 } from "path";
|
|
17458
17477
|
import neo4j from "neo4j-driver";
|
|
17459
17478
|
var driver = null;
|
|
17460
17479
|
function password() {
|
|
17461
17480
|
if (process.env.NEO4J_PASSWORD) return process.env.NEO4J_PASSWORD;
|
|
17462
|
-
const
|
|
17463
|
-
if (
|
|
17464
|
-
|
|
17465
|
-
|
|
17466
|
-
|
|
17481
|
+
const root = process.env.MAXY_PLATFORM_ROOT ?? process.env.PLATFORM_ROOT;
|
|
17482
|
+
if (!root) {
|
|
17483
|
+
throw new Error(
|
|
17484
|
+
"[dispatch-read] neither MAXY_PLATFORM_ROOT nor PLATFORM_ROOT is set \u2014 cannot locate config/.neo4j-password"
|
|
17485
|
+
);
|
|
17486
|
+
}
|
|
17487
|
+
const passwordFile = resolve22(root, "config/.neo4j-password");
|
|
17488
|
+
try {
|
|
17489
|
+
return readFileSync32(passwordFile, "utf-8").trim();
|
|
17490
|
+
} catch (err) {
|
|
17491
|
+
throw new Error(
|
|
17492
|
+
`[dispatch-read] Neo4j password not found. Expected at ${passwordFile}, or in NEO4J_PASSWORD. Read failed: ${err instanceof Error ? err.message : String(err)}`
|
|
17493
|
+
);
|
|
17494
|
+
}
|
|
17467
17495
|
}
|
|
17468
17496
|
function getDriver() {
|
|
17469
17497
|
if (driver) return driver;
|
|
@@ -17903,7 +17931,7 @@ function accountFor(cacheKey) {
|
|
|
17903
17931
|
if (!cacheKey) return null;
|
|
17904
17932
|
const accountId = getAccountIdForSession(cacheKey);
|
|
17905
17933
|
if (!accountId) return null;
|
|
17906
|
-
return { accountId, accountDir:
|
|
17934
|
+
return { accountId, accountDir: resolve23(ACCOUNTS_DIR, accountId) };
|
|
17907
17935
|
}
|
|
17908
17936
|
var app14 = new Hono();
|
|
17909
17937
|
app14.use("*", requireAdminSession);
|
|
@@ -18727,7 +18755,7 @@ init_dist();
|
|
|
18727
18755
|
init_paths();
|
|
18728
18756
|
init_remote_auth();
|
|
18729
18757
|
init_loop_registry();
|
|
18730
|
-
import { appendFileSync as appendFileSync3, existsSync as
|
|
18758
|
+
import { appendFileSync as appendFileSync3, existsSync as existsSync27, renameSync as renameSync9, statSync as statSync19 } from "fs";
|
|
18731
18759
|
import { join as join38 } from "path";
|
|
18732
18760
|
var CLIENT_ERRORS_LOG = join38(LOG_DIR, "client-errors.log");
|
|
18733
18761
|
var MAX_LOG_SIZE = 10 * 1024 * 1024;
|
|
@@ -18786,7 +18814,7 @@ function stackHead(stack) {
|
|
|
18786
18814
|
}
|
|
18787
18815
|
function rotateIfNeeded() {
|
|
18788
18816
|
try {
|
|
18789
|
-
if (!
|
|
18817
|
+
if (!existsSync27(CLIENT_ERRORS_LOG)) return;
|
|
18790
18818
|
const stats = statSync19(CLIENT_ERRORS_LOG);
|
|
18791
18819
|
if (stats.size < MAX_LOG_SIZE) return;
|
|
18792
18820
|
renameSync9(CLIENT_ERRORS_LOG, CLIENT_ERRORS_LOG + ".1");
|
|
@@ -19002,15 +19030,15 @@ function operatorRoleFor(config, userId) {
|
|
|
19002
19030
|
async function buildAccountOptionList(accounts, userId) {
|
|
19003
19031
|
const houseAccount = accounts.find((a) => a.config.role === "house");
|
|
19004
19032
|
console.log(`[admin-accounts] op=list count=${accounts.length} house=${houseAccount?.accountId ?? "none"}`);
|
|
19005
|
-
const
|
|
19033
|
+
const resolve53 = async (a) => {
|
|
19006
19034
|
const businessName = await fetchAccountName(a.accountId) || void 0;
|
|
19007
19035
|
return { accountId: a.accountId, businessName, role: operatorRoleFor(a.config, userId), isHouse: a.config.role === "house" };
|
|
19008
19036
|
};
|
|
19009
19037
|
const houseOptions = await Promise.all(
|
|
19010
|
-
accounts.filter((a) => a.config.role === "house").map(
|
|
19038
|
+
accounts.filter((a) => a.config.role === "house").map(resolve53)
|
|
19011
19039
|
);
|
|
19012
19040
|
const nonHouseOptions = await Promise.all(
|
|
19013
|
-
accounts.filter((a) => a.config.role !== "house").map(
|
|
19041
|
+
accounts.filter((a) => a.config.role !== "house").map(resolve53)
|
|
19014
19042
|
);
|
|
19015
19043
|
const sortKey = (o) => (o.businessName || o.accountId).toLowerCase();
|
|
19016
19044
|
nonHouseOptions.sort((x, y) => {
|
|
@@ -19152,18 +19180,18 @@ var accounts_default = app18;
|
|
|
19152
19180
|
init_dist();
|
|
19153
19181
|
init_paths();
|
|
19154
19182
|
init_claude_agent();
|
|
19155
|
-
import { existsSync as
|
|
19156
|
-
import { resolve as
|
|
19183
|
+
import { existsSync as existsSync29, readdirSync as readdirSync20, readFileSync as readFileSync33, statSync as statSync20 } from "fs";
|
|
19184
|
+
import { resolve as resolve24, basename as basename11 } from "path";
|
|
19157
19185
|
|
|
19158
19186
|
// app/lib/logs-read-resolve.ts
|
|
19159
|
-
import { existsSync as
|
|
19187
|
+
import { existsSync as existsSync28 } from "fs";
|
|
19160
19188
|
import { join as join39 } from "path";
|
|
19161
19189
|
function resolveSessionLogPaths(filename, logDirs) {
|
|
19162
19190
|
const tried = [filename];
|
|
19163
19191
|
const hits = [];
|
|
19164
19192
|
for (const dir of logDirs) {
|
|
19165
19193
|
const fullPath = join39(dir, filename);
|
|
19166
|
-
if (
|
|
19194
|
+
if (existsSync28(fullPath)) {
|
|
19167
19195
|
hits.push({ path: fullPath, dir });
|
|
19168
19196
|
}
|
|
19169
19197
|
}
|
|
@@ -19181,13 +19209,13 @@ app19.get("/", async (c) => {
|
|
|
19181
19209
|
const sessionIdParam = c.req.query("sessionId");
|
|
19182
19210
|
const cacheKeyParam = c.req.query("cacheKey");
|
|
19183
19211
|
const download = c.req.query("download") === "1";
|
|
19184
|
-
const logDirs = listValidAccounts().slice().sort((a, b) => a.accountId.localeCompare(b.accountId)).map((a) =>
|
|
19212
|
+
const logDirs = listValidAccounts().slice().sort((a, b) => a.accountId.localeCompare(b.accountId)).map((a) => resolve24(a.accountDir, "logs"));
|
|
19185
19213
|
logDirs.push(LOG_DIR);
|
|
19186
19214
|
if (fileParam) {
|
|
19187
19215
|
const safe = basename11(fileParam);
|
|
19188
19216
|
const searched = [];
|
|
19189
19217
|
for (const dir of logDirs) {
|
|
19190
|
-
const filePath =
|
|
19218
|
+
const filePath = resolve24(dir, safe);
|
|
19191
19219
|
searched.push(filePath);
|
|
19192
19220
|
try {
|
|
19193
19221
|
const buffer = readFileSync33(filePath);
|
|
@@ -19290,7 +19318,7 @@ app19.get("/", async (c) => {
|
|
|
19290
19318
|
const seen = /* @__PURE__ */ new Set();
|
|
19291
19319
|
const logs = {};
|
|
19292
19320
|
for (const dir of logDirs) {
|
|
19293
|
-
if (!
|
|
19321
|
+
if (!existsSync29(dir)) continue;
|
|
19294
19322
|
let files;
|
|
19295
19323
|
try {
|
|
19296
19324
|
files = readdirSync20(dir).filter((f) => f.endsWith(".log"));
|
|
@@ -19299,10 +19327,10 @@ app19.get("/", async (c) => {
|
|
|
19299
19327
|
console.warn(`[admin/logs] readdir-fail dir=${dir} reason=${reason}`);
|
|
19300
19328
|
continue;
|
|
19301
19329
|
}
|
|
19302
|
-
files.filter((f) => !seen.has(f)).map((f) => ({ name: f, mtime: statSync20(
|
|
19330
|
+
files.filter((f) => !seen.has(f)).map((f) => ({ name: f, mtime: statSync20(resolve24(dir, f)).mtimeMs })).sort((a, b) => b.mtime - a.mtime).forEach(({ name }) => {
|
|
19303
19331
|
seen.add(name);
|
|
19304
19332
|
try {
|
|
19305
|
-
const content = readFileSync33(
|
|
19333
|
+
const content = readFileSync33(resolve24(dir, name));
|
|
19306
19334
|
const tail = content.length > TAIL_BYTES ? content.subarray(content.length - TAIL_BYTES).toString("utf-8") : content.toString("utf-8");
|
|
19307
19335
|
logs[name] = tail.trim() || "(empty)";
|
|
19308
19336
|
} catch (err) {
|
|
@@ -19355,12 +19383,12 @@ init_claude_agent();
|
|
|
19355
19383
|
init_data_path();
|
|
19356
19384
|
init_attachments();
|
|
19357
19385
|
import { readFile as readFile6, readdir as readdir2 } from "fs/promises";
|
|
19358
|
-
import { existsSync as
|
|
19359
|
-
import { resolve as
|
|
19386
|
+
import { existsSync as existsSync30 } from "fs";
|
|
19387
|
+
import { resolve as resolve25 } from "path";
|
|
19360
19388
|
var app21 = new Hono();
|
|
19361
19389
|
var ATTACHMENT_ID_RE2 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
|
|
19362
19390
|
function uploadsDirFor(accountId, attachmentId) {
|
|
19363
|
-
return
|
|
19391
|
+
return resolve25(DATA_ROOT, "accounts", accountId, "uploads", attachmentId);
|
|
19364
19392
|
}
|
|
19365
19393
|
app21.get("/:attachmentId", requireAdminSession, async (c) => {
|
|
19366
19394
|
const attachmentId = c.req.param("attachmentId");
|
|
@@ -19378,12 +19406,12 @@ app21.get("/:attachmentId", requireAdminSession, async (c) => {
|
|
|
19378
19406
|
}
|
|
19379
19407
|
let accountId = pinnedAccountId;
|
|
19380
19408
|
let dir = uploadsDirFor(accountId, attachmentId);
|
|
19381
|
-
let found =
|
|
19409
|
+
let found = existsSync30(dir);
|
|
19382
19410
|
if (!found) {
|
|
19383
19411
|
for (const candidate of listValidAccounts()) {
|
|
19384
19412
|
if (candidate.accountId === pinnedAccountId) continue;
|
|
19385
19413
|
const candidateDir = uploadsDirFor(candidate.accountId, attachmentId);
|
|
19386
|
-
if (
|
|
19414
|
+
if (existsSync30(candidateDir)) {
|
|
19387
19415
|
accountId = candidate.accountId;
|
|
19388
19416
|
dir = candidateDir;
|
|
19389
19417
|
found = true;
|
|
@@ -19397,8 +19425,8 @@ app21.get("/:attachmentId", requireAdminSession, async (c) => {
|
|
|
19397
19425
|
if (!found) {
|
|
19398
19426
|
return new Response("Not found", { status: 404 });
|
|
19399
19427
|
}
|
|
19400
|
-
const metaPath =
|
|
19401
|
-
if (!
|
|
19428
|
+
const metaPath = resolve25(dir, `${attachmentId}.meta.json`);
|
|
19429
|
+
if (!existsSync30(metaPath)) {
|
|
19402
19430
|
return new Response("Not found", { status: 404 });
|
|
19403
19431
|
}
|
|
19404
19432
|
let meta;
|
|
@@ -19412,7 +19440,7 @@ app21.get("/:attachmentId", requireAdminSession, async (c) => {
|
|
|
19412
19440
|
if (!dataFile) {
|
|
19413
19441
|
return new Response("Not found", { status: 404 });
|
|
19414
19442
|
}
|
|
19415
|
-
const filePath =
|
|
19443
|
+
const filePath = resolve25(dir, dataFile);
|
|
19416
19444
|
const buffer = await readFile6(filePath);
|
|
19417
19445
|
const inlineSafe = isInlineSafeMime(meta.mimeType);
|
|
19418
19446
|
const safeName2 = meta.filename.replace(/["\\\r\n]/g, "_");
|
|
@@ -19438,7 +19466,7 @@ init_neo4j_store();
|
|
|
19438
19466
|
init_data_path();
|
|
19439
19467
|
init_attachments();
|
|
19440
19468
|
import { readFile as readFile7 } from "fs/promises";
|
|
19441
|
-
import { existsSync as
|
|
19469
|
+
import { existsSync as existsSync31, statSync as statSync21 } from "fs";
|
|
19442
19470
|
var app22 = new Hono();
|
|
19443
19471
|
app22.get("/", requireAdminSession, async (c) => {
|
|
19444
19472
|
const cacheKey = c.var.cacheKey;
|
|
@@ -19459,7 +19487,7 @@ app22.get("/", requireAdminSession, async (c) => {
|
|
|
19459
19487
|
return c.json({ error: "Not found" }, 404);
|
|
19460
19488
|
}
|
|
19461
19489
|
const resolution = resolveClaudeUploadsPath(`${sessionId}/${file}`);
|
|
19462
|
-
if (!resolution.ok || !
|
|
19490
|
+
if (!resolution.ok || !existsSync31(resolution.absolute) || !statSync21(resolution.absolute).isFile()) {
|
|
19463
19491
|
console.log(`[session-upload] op=miss session=${short2} file=${file} status=404 reason=absent`);
|
|
19464
19492
|
return c.json({ error: "Not found" }, 404);
|
|
19465
19493
|
}
|
|
@@ -19485,12 +19513,12 @@ init_helpers();
|
|
|
19485
19513
|
init_account_scope();
|
|
19486
19514
|
init_neo4j_store();
|
|
19487
19515
|
init_account();
|
|
19488
|
-
import { resolve as
|
|
19489
|
-
import { readdirSync as readdirSync22, readFileSync as readFileSync35, existsSync as
|
|
19516
|
+
import { resolve as resolve26 } from "path";
|
|
19517
|
+
import { readdirSync as readdirSync22, readFileSync as readFileSync35, existsSync as existsSync33, rmSync as rmSync5, renameSync as renameSync10, mkdirSync as mkdirSync7, writeFileSync as writeFileSync15, chmodSync } from "fs";
|
|
19490
19518
|
import { execFileSync as execFileSync6 } from "child_process";
|
|
19491
19519
|
|
|
19492
19520
|
// ../services/claude-session-manager/src/tool-surface.ts
|
|
19493
|
-
import { readFileSync as readFileSync34, readdirSync as readdirSync21, statSync as statSync22, existsSync as
|
|
19521
|
+
import { readFileSync as readFileSync34, readdirSync as readdirSync21, statSync as statSync22, existsSync as existsSync32 } from "fs";
|
|
19494
19522
|
import { createHash as createHash5 } from "crypto";
|
|
19495
19523
|
import { join as join40 } from "path";
|
|
19496
19524
|
|
|
@@ -19736,7 +19764,7 @@ function parseMcpBlock(frontmatter, pluginDir) {
|
|
|
19736
19764
|
function loadToolSurface(pluginsRoots) {
|
|
19737
19765
|
const roots = Array.isArray(pluginsRoots) ? pluginsRoots : [pluginsRoots];
|
|
19738
19766
|
for (const r of roots) {
|
|
19739
|
-
if (!
|
|
19767
|
+
if (!existsSync32(r)) throw new ToolSurfaceError("plugins-root-missing", r);
|
|
19740
19768
|
}
|
|
19741
19769
|
const admin = /* @__PURE__ */ new Set();
|
|
19742
19770
|
const pub = /* @__PURE__ */ new Set();
|
|
@@ -19752,7 +19780,7 @@ function loadToolSurface(pluginsRoots) {
|
|
|
19752
19780
|
return;
|
|
19753
19781
|
}
|
|
19754
19782
|
const manifestPath = join40(pluginDir, "PLUGIN.md");
|
|
19755
|
-
if (!
|
|
19783
|
+
if (!existsSync32(manifestPath)) return;
|
|
19756
19784
|
const raw = readFileSync34(manifestPath, "utf-8");
|
|
19757
19785
|
const frontmatter = extractFrontmatter(raw, plugin);
|
|
19758
19786
|
const tools = parseToolsBlock(frontmatter, plugin);
|
|
@@ -19933,7 +19961,7 @@ function agentRiskClass(tools, riskByTool) {
|
|
|
19933
19961
|
// server/routes/admin/agents.ts
|
|
19934
19962
|
var SLUG_UNSAFE = (s) => s.includes("/") || s.includes("..") || s.includes("\\");
|
|
19935
19963
|
function subdirs(dir) {
|
|
19936
|
-
if (!
|
|
19964
|
+
if (!existsSync33(dir)) return [];
|
|
19937
19965
|
try {
|
|
19938
19966
|
return readdirSync22(dir, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
|
|
19939
19967
|
} catch {
|
|
@@ -19954,7 +19982,7 @@ var SPECIALISTS_DIR = ["specialists", "agents"];
|
|
|
19954
19982
|
var QUARANTINE_DIR = ["specialists", "agents-disabled"];
|
|
19955
19983
|
var DISABLED_STORE = "agents-disabled.json";
|
|
19956
19984
|
function loadRiskSurface() {
|
|
19957
|
-
const roots = [
|
|
19985
|
+
const roots = [resolve26(PLATFORM_ROOT, "plugins"), resolve26(PLATFORM_ROOT, "..", "premium-plugins")].filter((r) => existsSync33(r));
|
|
19958
19986
|
try {
|
|
19959
19987
|
return { riskByTool: loadToolSurface(roots).riskByTool, failed: null };
|
|
19960
19988
|
} catch (err) {
|
|
@@ -19965,8 +19993,8 @@ function loadRiskSurface() {
|
|
|
19965
19993
|
}
|
|
19966
19994
|
}
|
|
19967
19995
|
function readDisabledStoreStrict(accountDir) {
|
|
19968
|
-
const p =
|
|
19969
|
-
if (!
|
|
19996
|
+
const p = resolve26(accountDir, DISABLED_STORE);
|
|
19997
|
+
if (!existsSync33(p)) return /* @__PURE__ */ new Set();
|
|
19970
19998
|
const parsed = JSON.parse(readFileSync35(p, "utf-8"));
|
|
19971
19999
|
if (!Array.isArray(parsed.disabled)) throw new Error("disabled is not an array");
|
|
19972
20000
|
return new Set(parsed.disabled.filter((x) => typeof x === "string"));
|
|
@@ -19980,38 +20008,86 @@ function readDisabledStore(accountDir) {
|
|
|
19980
20008
|
return /* @__PURE__ */ new Set();
|
|
19981
20009
|
}
|
|
19982
20010
|
}
|
|
19983
|
-
function
|
|
19984
|
-
const pluginsDir =
|
|
19985
|
-
const
|
|
20011
|
+
function authoredAgentFiles(accountDir) {
|
|
20012
|
+
const pluginsDir = resolve26(accountDir, "plugins");
|
|
20013
|
+
const byName = /* @__PURE__ */ new Map();
|
|
19986
20014
|
for (const plugin of subdirs(pluginsDir)) {
|
|
19987
|
-
const dir =
|
|
19988
|
-
if (!
|
|
20015
|
+
const dir = resolve26(pluginsDir, plugin, "agents");
|
|
20016
|
+
if (!existsSync33(dir)) continue;
|
|
19989
20017
|
try {
|
|
19990
|
-
for (const entry2 of readdirSync22(dir))
|
|
20018
|
+
for (const entry2 of readdirSync22(dir)) {
|
|
20019
|
+
if (!entry2.endsWith(".md")) continue;
|
|
20020
|
+
const path = resolve26(dir, entry2);
|
|
20021
|
+
const paths = byName.get(entry2);
|
|
20022
|
+
if (paths) paths.push(path);
|
|
20023
|
+
else byName.set(entry2, [path]);
|
|
20024
|
+
}
|
|
19991
20025
|
} catch (err) {
|
|
19992
20026
|
console.error(`[admin/agents] op=authored-scan read-failed plugin=${plugin} error="${err}"`);
|
|
19993
20027
|
}
|
|
19994
20028
|
}
|
|
19995
|
-
return
|
|
20029
|
+
return byName;
|
|
19996
20030
|
}
|
|
19997
20031
|
function shippedSourceDirs(accountDir) {
|
|
19998
20032
|
return [
|
|
19999
|
-
|
|
20000
|
-
|
|
20001
|
-
|
|
20033
|
+
resolve26(accountDir, ...SPECIALISTS_DIR),
|
|
20034
|
+
resolve26(accountDir, ...QUARANTINE_DIR),
|
|
20035
|
+
resolve26(PLATFORM_ROOT, "templates", "specialists", "agents")
|
|
20002
20036
|
];
|
|
20003
20037
|
}
|
|
20038
|
+
function readRowFields(path) {
|
|
20039
|
+
const { fm } = splitFrontmatter(readFileSync35(path, "utf-8"));
|
|
20040
|
+
return {
|
|
20041
|
+
name: fm.name ?? "",
|
|
20042
|
+
description: fm.description ?? "",
|
|
20043
|
+
tools: new Set(parseToolsLine(fm.tools))
|
|
20044
|
+
};
|
|
20045
|
+
}
|
|
20046
|
+
function divergentFields(a, b) {
|
|
20047
|
+
const out = [];
|
|
20048
|
+
if (a.name !== b.name) out.push("name");
|
|
20049
|
+
if (a.description !== b.description) out.push("description");
|
|
20050
|
+
if (a.tools.size !== b.tools.size || [...a.tools].some((t) => !b.tools.has(t))) out.push("tools");
|
|
20051
|
+
return out;
|
|
20052
|
+
}
|
|
20053
|
+
function compareToAuthored(candidatePath, authoredPaths, filename) {
|
|
20054
|
+
let candidate;
|
|
20055
|
+
try {
|
|
20056
|
+
candidate = readRowFields(candidatePath);
|
|
20057
|
+
} catch (err) {
|
|
20058
|
+
console.error(`[admin/agents] op=list-shipped-compare-failed file=${filename} side=found reason="${err}"`);
|
|
20059
|
+
return { verdict: "unreadable" };
|
|
20060
|
+
}
|
|
20061
|
+
let firstDivergence = null;
|
|
20062
|
+
let anyUnreadable = false;
|
|
20063
|
+
for (const path of authoredPaths) {
|
|
20064
|
+
let authored;
|
|
20065
|
+
try {
|
|
20066
|
+
authored = readRowFields(path);
|
|
20067
|
+
} catch (err) {
|
|
20068
|
+
console.error(`[admin/agents] op=list-shipped-compare-failed file=${filename} side=authored reason="${err}"`);
|
|
20069
|
+
anyUnreadable = true;
|
|
20070
|
+
continue;
|
|
20071
|
+
}
|
|
20072
|
+
const fields = divergentFields(candidate, authored);
|
|
20073
|
+
if (fields.length === 0) return { verdict: "matched" };
|
|
20074
|
+
firstDivergence ??= { authoredPath: path, fields };
|
|
20075
|
+
}
|
|
20076
|
+
if (firstDivergence) return { verdict: "divergent", ...firstDivergence };
|
|
20077
|
+
if (anyUnreadable) return { verdict: "unreadable" };
|
|
20078
|
+
return { verdict: "unreadable" };
|
|
20079
|
+
}
|
|
20004
20080
|
function writeDisabledStore(accountDir, disabled) {
|
|
20005
|
-
const path =
|
|
20081
|
+
const path = resolve26(accountDir, DISABLED_STORE);
|
|
20006
20082
|
writeFileSync15(path, `${JSON.stringify({ disabled: [...disabled].sort() }, null, 2)}
|
|
20007
20083
|
`, { mode: 384 });
|
|
20008
20084
|
chmodSync(path, 384);
|
|
20009
20085
|
}
|
|
20010
|
-
function listShipped(accountDir, riskByTool, disabled, riskSurfaceFailed,
|
|
20086
|
+
function listShipped(accountDir, riskByTool, disabled, riskSurfaceFailed, authoredFiles) {
|
|
20011
20087
|
const dirs = shippedSourceDirs(accountDir);
|
|
20012
20088
|
const names = /* @__PURE__ */ new Set();
|
|
20013
20089
|
for (const dir of dirs) {
|
|
20014
|
-
if (!
|
|
20090
|
+
if (!existsSync33(dir)) continue;
|
|
20015
20091
|
try {
|
|
20016
20092
|
for (const entry2 of readdirSync22(dir)) if (entry2.endsWith(".md")) names.add(entry2);
|
|
20017
20093
|
} catch (err) {
|
|
@@ -20021,16 +20097,27 @@ function listShipped(accountDir, riskByTool, disabled, riskSurfaceFailed, author
|
|
|
20021
20097
|
const shipped = [];
|
|
20022
20098
|
let shippedSkipped = 0;
|
|
20023
20099
|
let deduped = 0;
|
|
20100
|
+
let divergent = 0;
|
|
20024
20101
|
for (const filename of [...names].sort()) {
|
|
20025
|
-
const source = dirs.find((d) =>
|
|
20102
|
+
const source = dirs.find((d) => existsSync33(resolve26(d, filename)));
|
|
20026
20103
|
if (!source) continue;
|
|
20027
|
-
|
|
20028
|
-
|
|
20029
|
-
|
|
20030
|
-
|
|
20104
|
+
const authoredPaths = source === dirs[0] || source === dirs[1] ? authoredFiles.get(filename) : void 0;
|
|
20105
|
+
if (authoredPaths) {
|
|
20106
|
+
const cmp = compareToAuthored(resolve26(source, filename), authoredPaths, filename);
|
|
20107
|
+
if (cmp.verdict === "matched") {
|
|
20108
|
+
deduped++;
|
|
20109
|
+
console.log(`[admin/agents] op=list-shipped-dedup file=${filename}`);
|
|
20110
|
+
continue;
|
|
20111
|
+
}
|
|
20112
|
+
if (cmp.verdict === "divergent") {
|
|
20113
|
+
divergent++;
|
|
20114
|
+
console.log(
|
|
20115
|
+
`[admin/agents] op=list-shipped-divergent file=${filename} found=${resolve26(source, filename)} authored=${cmp.authoredPath} fields=${cmp.fields.join(",")}`
|
|
20116
|
+
);
|
|
20117
|
+
}
|
|
20031
20118
|
}
|
|
20032
20119
|
try {
|
|
20033
|
-
const { fm } = splitFrontmatter(readFileSync35(
|
|
20120
|
+
const { fm } = splitFrontmatter(readFileSync35(resolve26(source, filename), "utf-8"));
|
|
20034
20121
|
if (!fm.name) {
|
|
20035
20122
|
shippedSkipped++;
|
|
20036
20123
|
console.error(`[admin/agents] op=list-shipped-skip file=${filename} reason=no-name`);
|
|
@@ -20063,7 +20150,7 @@ function listShipped(accountDir, riskByTool, disabled, riskSurfaceFailed, author
|
|
|
20063
20150
|
console.error(`[admin/agents] op=list-shipped-skip file=${filename} error="${err}"`);
|
|
20064
20151
|
}
|
|
20065
20152
|
}
|
|
20066
|
-
return { shipped, shippedSkipped, deduped };
|
|
20153
|
+
return { shipped, shippedSkipped, deduped, divergent };
|
|
20067
20154
|
}
|
|
20068
20155
|
function parseToolsLine(raw) {
|
|
20069
20156
|
return raw ? raw.split(",").map((t) => t.trim()).filter(Boolean) : [];
|
|
@@ -20084,12 +20171,12 @@ function classify(tools, riskByTool, riskSurfaceFailed) {
|
|
|
20084
20171
|
return agentRiskClass(tools, riskByTool);
|
|
20085
20172
|
}
|
|
20086
20173
|
function listSpecialists(accountDir, riskByTool, riskSurfaceFailed) {
|
|
20087
|
-
const pluginsDir =
|
|
20174
|
+
const pluginsDir = resolve26(accountDir, "plugins");
|
|
20088
20175
|
const specialists = [];
|
|
20089
20176
|
let specialistsSkipped = 0;
|
|
20090
20177
|
for (const plugin of subdirs(pluginsDir).sort()) {
|
|
20091
|
-
const agentsDirP =
|
|
20092
|
-
if (!
|
|
20178
|
+
const agentsDirP = resolve26(pluginsDir, plugin, "agents");
|
|
20179
|
+
if (!existsSync33(agentsDirP)) continue;
|
|
20093
20180
|
let entries2;
|
|
20094
20181
|
try {
|
|
20095
20182
|
entries2 = readdirSync22(agentsDirP, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name));
|
|
@@ -20099,7 +20186,7 @@ function listSpecialists(accountDir, riskByTool, riskSurfaceFailed) {
|
|
|
20099
20186
|
for (const entry2 of entries2) {
|
|
20100
20187
|
if (!entry2.isFile() || !entry2.name.endsWith(".md")) continue;
|
|
20101
20188
|
try {
|
|
20102
|
-
const { fm } = splitFrontmatter(readFileSync35(
|
|
20189
|
+
const { fm } = splitFrontmatter(readFileSync35(resolve26(agentsDirP, entry2.name), "utf-8"));
|
|
20103
20190
|
if (!fm.name) {
|
|
20104
20191
|
specialistsSkipped++;
|
|
20105
20192
|
console.error(`[admin/agents] op=list-specialist-skip plugin=${plugin} file=${entry2.name}`);
|
|
@@ -20131,7 +20218,7 @@ function listSpecialists(accountDir, riskByTool, riskSurfaceFailed) {
|
|
|
20131
20218
|
// have the surface claim an agent is stopped while it is still being
|
|
20132
20219
|
// spawned. Absence from the live dir alone is also not the test: a
|
|
20133
20220
|
// specialist that was never activated was never switched off either.
|
|
20134
|
-
disabled:
|
|
20221
|
+
disabled: existsSync33(resolve26(accountDir, ...QUARANTINE_DIR, entry2.name)) && !existsSync33(resolve26(accountDir, ...SPECIALISTS_DIR, entry2.name))
|
|
20135
20222
|
});
|
|
20136
20223
|
} catch {
|
|
20137
20224
|
specialistsSkipped++;
|
|
@@ -20158,15 +20245,15 @@ app23.get("/", requireAdminSession, (c) => {
|
|
|
20158
20245
|
const disabled = readDisabledStore(account.accountDir);
|
|
20159
20246
|
const agents = [];
|
|
20160
20247
|
let skipped = 0;
|
|
20161
|
-
const agentsDir =
|
|
20162
|
-
if (
|
|
20248
|
+
const agentsDir = resolve26(account.accountDir, "agents");
|
|
20249
|
+
if (existsSync33(agentsDir)) {
|
|
20163
20250
|
try {
|
|
20164
20251
|
const entries2 = readdirSync22(agentsDir, { withFileTypes: true });
|
|
20165
20252
|
for (const entry2 of entries2.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
20166
20253
|
if (!entry2.isDirectory()) continue;
|
|
20167
20254
|
if (entry2.name === "admin") continue;
|
|
20168
|
-
const configPath3 =
|
|
20169
|
-
if (!
|
|
20255
|
+
const configPath3 = resolve26(agentsDir, entry2.name, "config.json");
|
|
20256
|
+
if (!existsSync33(configPath3)) continue;
|
|
20170
20257
|
try {
|
|
20171
20258
|
const config = JSON.parse(readFileSync35(configPath3, "utf-8"));
|
|
20172
20259
|
agents.push({
|
|
@@ -20192,12 +20279,12 @@ app23.get("/", requireAdminSession, (c) => {
|
|
|
20192
20279
|
}
|
|
20193
20280
|
}
|
|
20194
20281
|
const { specialists, specialistsSkipped } = listSpecialists(account.accountDir, riskByTool, riskSurfaceFailed !== null);
|
|
20195
|
-
const { shipped, shippedSkipped, deduped } = listShipped(
|
|
20282
|
+
const { shipped, shippedSkipped, deduped, divergent } = listShipped(
|
|
20196
20283
|
account.accountDir,
|
|
20197
20284
|
riskByTool,
|
|
20198
20285
|
disabled,
|
|
20199
20286
|
riskSurfaceFailed !== null,
|
|
20200
|
-
|
|
20287
|
+
authoredAgentFiles(account.accountDir)
|
|
20201
20288
|
);
|
|
20202
20289
|
const rows = [...agents, ...specialists, ...shipped];
|
|
20203
20290
|
const acct = account.accountId.slice(0, 8);
|
|
@@ -20215,17 +20302,26 @@ app23.get("/", requireAdminSession, (c) => {
|
|
|
20215
20302
|
console.log(
|
|
20216
20303
|
`[agents] op=rule-census account=${acct} rules=${COMBINATION_RULES.length} classified=${classified} fired=${firedRules.size} never=${never.length > 0 ? never.join(",") : "none"}`
|
|
20217
20304
|
);
|
|
20218
|
-
console.log(`[admin/agents] op=list accountId=${acct} agents=${agents.length} specialists=${specialists.length} shipped=${shipped.length} skipped=${skipped} specialistsSkipped=${specialistsSkipped} shippedSkipped=${shippedSkipped} deduped=${deduped}`);
|
|
20305
|
+
console.log(`[admin/agents] op=list accountId=${acct} agents=${agents.length} specialists=${specialists.length} shipped=${shipped.length} skipped=${skipped} specialistsSkipped=${specialistsSkipped} shippedSkipped=${shippedSkipped} deduped=${deduped} divergent=${divergent}`);
|
|
20219
20306
|
return c.json({
|
|
20220
20307
|
agents: rows,
|
|
20221
20308
|
accountId: account.accountId,
|
|
20222
20309
|
skipped,
|
|
20223
20310
|
specialistsSkipped,
|
|
20224
20311
|
shippedSkipped,
|
|
20225
|
-
// How many live-directory candidates were dropped as
|
|
20226
|
-
//
|
|
20227
|
-
//
|
|
20312
|
+
// How many live-directory or quarantine-directory candidates were dropped as
|
|
20313
|
+
// authored duplicates — meaning the two files agree on the three fields the
|
|
20314
|
+
// row shows. `shipped + shippedSkipped + deduped` equals the number of
|
|
20315
|
+
// distinct `.md` names across the three source directories.
|
|
20228
20316
|
deduped,
|
|
20317
|
+
// How many candidates were KEPT because both files read and the three
|
|
20318
|
+
// fields DISAGREE. Never a fourth term in the identity above: a kept
|
|
20319
|
+
// candidate is parsed like any other, so it lands in `shipped`, or in
|
|
20320
|
+
// `shippedSkipped` when its own frontmatter carries no `name:`. A candidate
|
|
20321
|
+
// that could not be compared at all is not counted here — that is
|
|
20322
|
+
// `op=list-shipped-compare-failed`, and reporting it as drift would claim a
|
|
20323
|
+
// disagreement nobody read.
|
|
20324
|
+
divergent,
|
|
20229
20325
|
riskSurfaceFailed: riskSurfaceFailed !== null
|
|
20230
20326
|
});
|
|
20231
20327
|
});
|
|
@@ -20239,9 +20335,9 @@ app23.get("/:slug", requireAdminSession, (c) => {
|
|
|
20239
20335
|
if (SLUG_UNSAFE(slug)) return c.json({ error: "Invalid agent slug" }, 400);
|
|
20240
20336
|
if (c.req.query("origin") === "shipped") {
|
|
20241
20337
|
const dirs = shippedSourceDirs(account.accountDir);
|
|
20242
|
-
const source = dirs.find((d) =>
|
|
20338
|
+
const source = dirs.find((d) => existsSync33(resolve26(d, `${slug}.md`)));
|
|
20243
20339
|
if (!source) return c.json({ error: "Agent not found" }, 404);
|
|
20244
|
-
const { fm, body } = splitFrontmatter(readFileSync35(
|
|
20340
|
+
const { fm, body } = splitFrontmatter(readFileSync35(resolve26(source, `${slug}.md`), "utf-8"));
|
|
20245
20341
|
const { riskByTool, failed: failed2 } = loadRiskSurface();
|
|
20246
20342
|
const tools = parseToolsLine(fm.tools);
|
|
20247
20343
|
const r = classify(tools, riskByTool, failed2 !== null);
|
|
@@ -20271,10 +20367,10 @@ app23.get("/:slug", requireAdminSession, (c) => {
|
|
|
20271
20367
|
const pluginParam = c.req.query("plugin");
|
|
20272
20368
|
if (pluginParam) {
|
|
20273
20369
|
if (SLUG_UNSAFE(pluginParam)) return c.json({ error: "Invalid plugin" }, 400);
|
|
20274
|
-
const file =
|
|
20275
|
-
if (!
|
|
20370
|
+
const file = resolve26(account.accountDir, "plugins", pluginParam, "agents", `${slug}.md`);
|
|
20371
|
+
if (!existsSync33(file)) return c.json({ error: "Agent not found" }, 404);
|
|
20276
20372
|
const { fm, body } = splitFrontmatter(readFileSync35(file, "utf-8"));
|
|
20277
|
-
const skills = subdirs(
|
|
20373
|
+
const skills = subdirs(resolve26(account.accountDir, "plugins", pluginParam, "skills"));
|
|
20278
20374
|
const { riskByTool, failed: failed2 } = loadRiskSurface();
|
|
20279
20375
|
const tools = parseToolsLine(fm.tools);
|
|
20280
20376
|
const r = classify(tools, riskByTool, failed2 !== null);
|
|
@@ -20301,9 +20397,9 @@ app23.get("/:slug", requireAdminSession, (c) => {
|
|
|
20301
20397
|
}
|
|
20302
20398
|
});
|
|
20303
20399
|
}
|
|
20304
|
-
const agentDir =
|
|
20305
|
-
const configPath3 =
|
|
20306
|
-
if (!
|
|
20400
|
+
const agentDir = resolve26(account.accountDir, "agents", slug);
|
|
20401
|
+
const configPath3 = resolve26(agentDir, "config.json");
|
|
20402
|
+
if (!existsSync33(configPath3)) return c.json({ error: "Agent not found" }, 404);
|
|
20307
20403
|
let config;
|
|
20308
20404
|
try {
|
|
20309
20405
|
config = JSON.parse(readFileSync35(configPath3, "utf-8"));
|
|
@@ -20314,9 +20410,9 @@ app23.get("/:slug", requireAdminSession, (c) => {
|
|
|
20314
20410
|
const docs = {};
|
|
20315
20411
|
const present = {};
|
|
20316
20412
|
for (const { file, key: key2 } of OWNED_DOCS) {
|
|
20317
|
-
const p =
|
|
20413
|
+
const p = resolve26(agentDir, file);
|
|
20318
20414
|
try {
|
|
20319
|
-
if (
|
|
20415
|
+
if (existsSync33(p)) {
|
|
20320
20416
|
docs[key2] = readFileSync35(p, "utf-8");
|
|
20321
20417
|
present[key2] = true;
|
|
20322
20418
|
} else {
|
|
@@ -20365,7 +20461,7 @@ async function resolveWritableAccount(c, op, slug) {
|
|
|
20365
20461
|
return account;
|
|
20366
20462
|
}
|
|
20367
20463
|
function reconcileRoutingProse(accountDir, accountId, op, slug) {
|
|
20368
|
-
const script =
|
|
20464
|
+
const script = resolve26(PLATFORM_ROOT, "scripts", "lib", "agents-md-bootstrap.sh");
|
|
20369
20465
|
try {
|
|
20370
20466
|
execFileSync6("bash", [script, accountDir], { encoding: "utf-8", timeout: 1e4 });
|
|
20371
20467
|
return true;
|
|
@@ -20376,8 +20472,8 @@ function reconcileRoutingProse(accountDir, accountId, op, slug) {
|
|
|
20376
20472
|
}
|
|
20377
20473
|
}
|
|
20378
20474
|
function reconcileAuthoredRoutingLine(accountDir, accountId, op, source) {
|
|
20379
|
-
const agentsMd =
|
|
20380
|
-
if (!
|
|
20475
|
+
const agentsMd = resolve26(accountDir, "agents", "admin", "AGENTS.md");
|
|
20476
|
+
if (!existsSync33(agentsMd) || !existsSync33(source)) return false;
|
|
20381
20477
|
try {
|
|
20382
20478
|
const { fm } = splitFrontmatter(readFileSync35(source, "utf-8"));
|
|
20383
20479
|
if (!fm.name) return false;
|
|
@@ -20400,18 +20496,18 @@ app23.post("/:slug/disable", async (c) => {
|
|
|
20400
20496
|
const resolved = await resolveWritableAccount(c, "disable", slug);
|
|
20401
20497
|
if ("status" in resolved) return c.json({ error: resolved.error }, resolved.status);
|
|
20402
20498
|
const filename = `${slug}.md`;
|
|
20403
|
-
const live =
|
|
20404
|
-
const quarantined =
|
|
20405
|
-
if (!
|
|
20499
|
+
const live = resolve26(resolved.accountDir, ...SPECIALISTS_DIR, filename);
|
|
20500
|
+
const quarantined = resolve26(resolved.accountDir, ...QUARANTINE_DIR, filename);
|
|
20501
|
+
if (!authoredAgentFiles(resolved.accountDir).has(filename)) {
|
|
20406
20502
|
console.error(`[admin/agents] op=disable accountId=${resolved.accountId.slice(0, 8)} slug=${slug} origin=not-authored eligible=false outcome=refused reason=not-user-created`);
|
|
20407
20503
|
return c.json({ error: "Only an agent you created can be switched off here. A shipped agent is stopped by suspending the routines that dispatch it." }, 404);
|
|
20408
20504
|
}
|
|
20409
|
-
if (!
|
|
20505
|
+
if (!existsSync33(live)) {
|
|
20410
20506
|
console.error(`[admin/agents] op=disable accountId=${resolved.accountId.slice(0, 8)} slug=${slug} origin=specialist eligible=true outcome=refused reason=not-dispatchable`);
|
|
20411
20507
|
return c.json({ error: "This agent is not in the dispatchable set, so there is nothing to switch off." }, 409);
|
|
20412
20508
|
}
|
|
20413
20509
|
try {
|
|
20414
|
-
mkdirSync7(
|
|
20510
|
+
mkdirSync7(resolve26(resolved.accountDir, ...QUARANTINE_DIR), { recursive: true });
|
|
20415
20511
|
renameSync10(live, quarantined);
|
|
20416
20512
|
} catch (err) {
|
|
20417
20513
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -20428,28 +20524,28 @@ app23.post("/:slug/enable", async (c) => {
|
|
|
20428
20524
|
const resolved = await resolveWritableAccount(c, "enable", slug);
|
|
20429
20525
|
if ("status" in resolved) return c.json({ error: resolved.error }, resolved.status);
|
|
20430
20526
|
const filename = `${slug}.md`;
|
|
20431
|
-
const live =
|
|
20432
|
-
const quarantined =
|
|
20433
|
-
const authored =
|
|
20527
|
+
const live = resolve26(resolved.accountDir, ...SPECIALISTS_DIR, filename);
|
|
20528
|
+
const quarantined = resolve26(resolved.accountDir, ...QUARANTINE_DIR, filename);
|
|
20529
|
+
const authored = authoredAgentFiles(resolved.accountDir).has(filename);
|
|
20434
20530
|
const origin = authored ? "specialist" : "shipped";
|
|
20435
20531
|
let restored = false;
|
|
20436
20532
|
try {
|
|
20437
20533
|
if (authored) {
|
|
20438
|
-
if (!
|
|
20534
|
+
if (!existsSync33(quarantined)) {
|
|
20439
20535
|
console.error(`[admin/agents] op=enable accountId=${resolved.accountId.slice(0, 8)} slug=${slug} origin=specialist eligible=true outcome=refused reason=not-disabled`);
|
|
20440
20536
|
return c.json({ error: "This agent is not disabled" }, 404);
|
|
20441
20537
|
}
|
|
20442
|
-
mkdirSync7(
|
|
20538
|
+
mkdirSync7(resolve26(resolved.accountDir, ...SPECIALISTS_DIR), { recursive: true });
|
|
20443
20539
|
renameSync10(quarantined, live);
|
|
20444
20540
|
restored = true;
|
|
20445
20541
|
} else {
|
|
20446
20542
|
const disabled = readDisabledStoreStrict(resolved.accountDir);
|
|
20447
|
-
if (!
|
|
20543
|
+
if (!existsSync33(quarantined) && !disabled.has(filename)) {
|
|
20448
20544
|
console.error(`[admin/agents] op=enable accountId=${resolved.accountId.slice(0, 8)} slug=${slug} origin=shipped eligible=true outcome=refused reason=not-disabled`);
|
|
20449
20545
|
return c.json({ error: "This agent is not disabled" }, 404);
|
|
20450
20546
|
}
|
|
20451
|
-
if (
|
|
20452
|
-
mkdirSync7(
|
|
20547
|
+
if (existsSync33(quarantined)) {
|
|
20548
|
+
mkdirSync7(resolve26(resolved.accountDir, ...SPECIALISTS_DIR), { recursive: true });
|
|
20453
20549
|
renameSync10(quarantined, live);
|
|
20454
20550
|
restored = true;
|
|
20455
20551
|
}
|
|
@@ -20490,8 +20586,8 @@ app23.delete("/:slug", async (c) => {
|
|
|
20490
20586
|
console.error(`[admin/agents] op=delete rejected reason=${authz.reason} accountId=${account.accountId.slice(0, 8)} slug=${slug}`);
|
|
20491
20587
|
return c.json({ error: "Not authorized for this account" }, 403);
|
|
20492
20588
|
}
|
|
20493
|
-
const agentDir =
|
|
20494
|
-
if (!
|
|
20589
|
+
const agentDir = resolve26(account.accountDir, "agents", slug);
|
|
20590
|
+
if (!existsSync33(agentDir)) {
|
|
20495
20591
|
return c.json({ error: "Agent not found" }, 404);
|
|
20496
20592
|
}
|
|
20497
20593
|
try {
|
|
@@ -20533,8 +20629,8 @@ app23.post("/:slug/project", async (c) => {
|
|
|
20533
20629
|
console.error(`[admin/agents] op=project rejected reason=${authz.reason} accountId=${account.accountId.slice(0, 8)} slug=${slug}`);
|
|
20534
20630
|
return c.json({ error: "Not authorized for this account" }, 403);
|
|
20535
20631
|
}
|
|
20536
|
-
const agentDir =
|
|
20537
|
-
if (!
|
|
20632
|
+
const agentDir = resolve26(account.accountDir, "agents", slug);
|
|
20633
|
+
if (!existsSync33(agentDir)) {
|
|
20538
20634
|
console.error(`[admin/agents] op=project rejected reason=agent-not-on-disk accountId=${account.accountId.slice(0, 8)} slug=${slug} probed=${agentDir}`);
|
|
20539
20635
|
return c.json({ error: "Agent not found on disk" }, 404);
|
|
20540
20636
|
}
|
|
@@ -20558,7 +20654,7 @@ init_account();
|
|
|
20558
20654
|
init_neo4j_store();
|
|
20559
20655
|
import crypto2 from "crypto";
|
|
20560
20656
|
import { resolve as resolvePath } from "path";
|
|
20561
|
-
import { existsSync as
|
|
20657
|
+
import { existsSync as existsSync34, mkdirSync as mkdirSync8, createWriteStream } from "fs";
|
|
20562
20658
|
|
|
20563
20659
|
// app/lib/admin-conversation-cascade.ts
|
|
20564
20660
|
init_neo4j_store();
|
|
@@ -20726,7 +20822,7 @@ function validateAndShapeAttachments(raws, conversationAccountId, sessionId, mes
|
|
|
20726
20822
|
let reason = null;
|
|
20727
20823
|
if (!a.attachmentId || !a.filename || !a.mimeType || !a.storagePath) reason = "schema-fail";
|
|
20728
20824
|
else if (a.accountId !== conversationAccountId) reason = "account-mismatch";
|
|
20729
|
-
else if (!
|
|
20825
|
+
else if (!existsSync34(a.storagePath)) reason = "missing-file";
|
|
20730
20826
|
if (reason) {
|
|
20731
20827
|
invalid++;
|
|
20732
20828
|
try {
|
|
@@ -21259,8 +21355,8 @@ init_claude_agent();
|
|
|
21259
21355
|
// app/lib/claude-agent/spawn-context.ts
|
|
21260
21356
|
init_account();
|
|
21261
21357
|
init_neo4j_store();
|
|
21262
|
-
import { existsSync as
|
|
21263
|
-
import { dirname as dirname14, resolve as
|
|
21358
|
+
import { existsSync as existsSync35, readFileSync as readFileSync36, readdirSync as readdirSync23, statSync as statSync23 } from "fs";
|
|
21359
|
+
import { dirname as dirname14, resolve as resolve27, join as join41 } from "path";
|
|
21264
21360
|
async function resolveOwnerProfileBlock(accountId, userId) {
|
|
21265
21361
|
if (!userId) return { ok: false, reason: "missing-user-id" };
|
|
21266
21362
|
try {
|
|
@@ -21306,7 +21402,7 @@ function extractPluginToolDescriptions(pluginDir) {
|
|
|
21306
21402
|
];
|
|
21307
21403
|
let raw = null;
|
|
21308
21404
|
for (const path of candidates) {
|
|
21309
|
-
if (!
|
|
21405
|
+
if (!existsSync35(path)) continue;
|
|
21310
21406
|
try {
|
|
21311
21407
|
raw = readFileSync36(path, "utf-8");
|
|
21312
21408
|
break;
|
|
@@ -21357,8 +21453,8 @@ function parseSkillPathsFromFrontmatter(fm) {
|
|
|
21357
21453
|
}
|
|
21358
21454
|
function listPluginDirs(accountPluginsDir) {
|
|
21359
21455
|
const out = /* @__PURE__ */ new Map();
|
|
21360
|
-
const platformPlugins =
|
|
21361
|
-
if (
|
|
21456
|
+
const platformPlugins = resolve27(PLATFORM_ROOT, "plugins");
|
|
21457
|
+
if (existsSync35(platformPlugins)) {
|
|
21362
21458
|
for (const name of readdirSync23(platformPlugins)) {
|
|
21363
21459
|
const dir = join41(platformPlugins, name);
|
|
21364
21460
|
try {
|
|
@@ -21367,11 +21463,11 @@ function listPluginDirs(accountPluginsDir) {
|
|
|
21367
21463
|
}
|
|
21368
21464
|
}
|
|
21369
21465
|
}
|
|
21370
|
-
const premiumRoot =
|
|
21371
|
-
if (
|
|
21466
|
+
const premiumRoot = resolve27(dirname14(PLATFORM_ROOT), "premium-plugins");
|
|
21467
|
+
if (existsSync35(premiumRoot)) {
|
|
21372
21468
|
for (const bundle of readdirSync23(premiumRoot)) {
|
|
21373
21469
|
const bundlePlugins = join41(premiumRoot, bundle, "plugins");
|
|
21374
|
-
if (!
|
|
21470
|
+
if (!existsSync35(bundlePlugins)) continue;
|
|
21375
21471
|
try {
|
|
21376
21472
|
for (const name of readdirSync23(bundlePlugins)) {
|
|
21377
21473
|
const dir = join41(bundlePlugins, name);
|
|
@@ -21384,7 +21480,7 @@ function listPluginDirs(accountPluginsDir) {
|
|
|
21384
21480
|
}
|
|
21385
21481
|
}
|
|
21386
21482
|
}
|
|
21387
|
-
if (accountPluginsDir &&
|
|
21483
|
+
if (accountPluginsDir && existsSync35(accountPluginsDir)) {
|
|
21388
21484
|
try {
|
|
21389
21485
|
for (const name of readdirSync23(accountPluginsDir)) {
|
|
21390
21486
|
if (out.has(name)) continue;
|
|
@@ -21400,10 +21496,10 @@ function listPluginDirs(accountPluginsDir) {
|
|
|
21400
21496
|
return out;
|
|
21401
21497
|
}
|
|
21402
21498
|
function accountPluginsDirFor(accountId) {
|
|
21403
|
-
return
|
|
21499
|
+
return resolve27(PLATFORM_ROOT, "..", "data/accounts", accountId, "plugins");
|
|
21404
21500
|
}
|
|
21405
21501
|
function listAccountPluginNames(accountPluginsDir) {
|
|
21406
|
-
if (!
|
|
21502
|
+
if (!existsSync35(accountPluginsDir)) return [];
|
|
21407
21503
|
try {
|
|
21408
21504
|
return readdirSync23(accountPluginsDir).filter((name) => {
|
|
21409
21505
|
try {
|
|
@@ -21417,8 +21513,8 @@ function listAccountPluginNames(accountPluginsDir) {
|
|
|
21417
21513
|
}
|
|
21418
21514
|
}
|
|
21419
21515
|
function readEnabledPlugins(accountId) {
|
|
21420
|
-
const accountFile =
|
|
21421
|
-
if (!
|
|
21516
|
+
const accountFile = resolve27(PLATFORM_ROOT, "..", "data/accounts", accountId, "account.json");
|
|
21517
|
+
if (!existsSync35(accountFile)) return /* @__PURE__ */ new Set();
|
|
21422
21518
|
try {
|
|
21423
21519
|
const parsed = JSON.parse(readFileSync36(accountFile, "utf-8"));
|
|
21424
21520
|
return new Set(
|
|
@@ -21429,7 +21525,7 @@ function readEnabledPlugins(accountId) {
|
|
|
21429
21525
|
}
|
|
21430
21526
|
}
|
|
21431
21527
|
function readFrontmatter(path) {
|
|
21432
|
-
if (!
|
|
21528
|
+
if (!existsSync35(path)) return null;
|
|
21433
21529
|
let raw;
|
|
21434
21530
|
try {
|
|
21435
21531
|
raw = readFileSync36(path, "utf-8");
|
|
@@ -21467,7 +21563,7 @@ ${fm}
|
|
|
21467
21563
|
`plugin-manifest-tool-coverage plugin=${name} tools=${tools.length} with-desc=${withDesc}`
|
|
21468
21564
|
);
|
|
21469
21565
|
if (toolNames.length > 0 && descMap.size === 0) {
|
|
21470
|
-
const hasSource =
|
|
21566
|
+
const hasSource = existsSync35(join41(dir, "mcp/dist/index.js")) || existsSync35(join41(dir, "mcp/src/index.ts"));
|
|
21471
21567
|
if (hasSource) {
|
|
21472
21568
|
console.warn(
|
|
21473
21569
|
`[spawn-context] WARN plugin=${name} mcp source present but tool-description regex matched zero entries \u2014 SDK upgrade may have changed the registration shape`
|
|
@@ -21493,8 +21589,8 @@ ${skillFm}
|
|
|
21493
21589
|
return out;
|
|
21494
21590
|
}
|
|
21495
21591
|
function computeSpecialistDomains(accountId) {
|
|
21496
|
-
const specialistsDir =
|
|
21497
|
-
if (!
|
|
21592
|
+
const specialistsDir = resolve27(PLATFORM_ROOT, "..", "data/accounts", accountId, "specialists", "agents");
|
|
21593
|
+
if (!existsSync35(specialistsDir)) return [];
|
|
21498
21594
|
let entries2;
|
|
21499
21595
|
try {
|
|
21500
21596
|
entries2 = readdirSync23(specialistsDir);
|
|
@@ -21539,8 +21635,8 @@ ${fm}
|
|
|
21539
21635
|
return out;
|
|
21540
21636
|
}
|
|
21541
21637
|
function computeDormantPlugins(accountId) {
|
|
21542
|
-
const accountFile =
|
|
21543
|
-
if (!
|
|
21638
|
+
const accountFile = resolve27(PLATFORM_ROOT, "..", "data/accounts", accountId, "account.json");
|
|
21639
|
+
if (!existsSync35(accountFile)) return [];
|
|
21544
21640
|
let enabled;
|
|
21545
21641
|
try {
|
|
21546
21642
|
const raw = readFileSync36(accountFile, "utf-8");
|
|
@@ -21554,8 +21650,8 @@ function computeDormantPlugins(accountId) {
|
|
|
21554
21650
|
);
|
|
21555
21651
|
return [];
|
|
21556
21652
|
}
|
|
21557
|
-
const pluginsDir =
|
|
21558
|
-
if (!
|
|
21653
|
+
const pluginsDir = resolve27(PLATFORM_ROOT, "plugins");
|
|
21654
|
+
if (!existsSync35(pluginsDir)) return [];
|
|
21559
21655
|
let entries2;
|
|
21560
21656
|
try {
|
|
21561
21657
|
entries2 = readdirSync23(pluginsDir);
|
|
@@ -21565,8 +21661,8 @@ function computeDormantPlugins(accountId) {
|
|
|
21565
21661
|
const out = [];
|
|
21566
21662
|
for (const name of entries2) {
|
|
21567
21663
|
if (enabled.has(name)) continue;
|
|
21568
|
-
const manifestPath =
|
|
21569
|
-
if (!
|
|
21664
|
+
const manifestPath = resolve27(pluginsDir, name, "PLUGIN.md");
|
|
21665
|
+
if (!existsSync35(manifestPath)) continue;
|
|
21570
21666
|
let manifest;
|
|
21571
21667
|
try {
|
|
21572
21668
|
manifest = readFileSync36(manifestPath, "utf-8");
|
|
@@ -21584,11 +21680,11 @@ function computeDormantPlugins(accountId) {
|
|
|
21584
21680
|
|
|
21585
21681
|
// server/routes/admin/claude-sessions.ts
|
|
21586
21682
|
init_neo4j_store();
|
|
21587
|
-
import { existsSync as
|
|
21588
|
-
import { resolve as
|
|
21683
|
+
import { existsSync as existsSync36, readFileSync as readFileSync37 } from "fs";
|
|
21684
|
+
import { resolve as resolve28 } from "path";
|
|
21589
21685
|
function readTunnelState(brandConfigDir) {
|
|
21590
21686
|
const statePath = `${process.env.HOME ?? ""}/${brandConfigDir}/cloudflared/tunnel.state`;
|
|
21591
|
-
if (!
|
|
21687
|
+
if (!existsSync36(statePath)) return null;
|
|
21592
21688
|
try {
|
|
21593
21689
|
const parsed = JSON.parse(readFileSync37(statePath, "utf-8"));
|
|
21594
21690
|
const tunnelId = typeof parsed.tunnelId === "string" ? parsed.tunnelId : null;
|
|
@@ -21601,10 +21697,10 @@ function readTunnelState(brandConfigDir) {
|
|
|
21601
21697
|
}
|
|
21602
21698
|
}
|
|
21603
21699
|
function resolveTunnelUrl() {
|
|
21604
|
-
const platformRoot5 = process.env.MAXY_PLATFORM_ROOT ?? process.env.PLATFORM_ROOT ??
|
|
21700
|
+
const platformRoot5 = process.env.MAXY_PLATFORM_ROOT ?? process.env.PLATFORM_ROOT ?? resolve28(process.cwd(), "..");
|
|
21605
21701
|
let brand;
|
|
21606
21702
|
try {
|
|
21607
|
-
brand = JSON.parse(readFileSync37(
|
|
21703
|
+
brand = JSON.parse(readFileSync37(resolve28(platformRoot5, "config", "brand.json"), "utf-8"));
|
|
21608
21704
|
} catch {
|
|
21609
21705
|
return null;
|
|
21610
21706
|
}
|
|
@@ -22064,11 +22160,11 @@ init_helpers();
|
|
|
22064
22160
|
init_claude_agent();
|
|
22065
22161
|
init_data_path();
|
|
22066
22162
|
init_sidebar_sessions();
|
|
22067
|
-
import { createReadStream as createReadStream2, createWriteStream as createWriteStream2, existsSync as
|
|
22163
|
+
import { createReadStream as createReadStream2, createWriteStream as createWriteStream2, existsSync as existsSync37 } from "fs";
|
|
22068
22164
|
import { readdir as readdir4, readFile as readFile9, stat as stat6, mkdir as mkdir3, unlink as unlink3, rename as rename3, rmdir } from "fs/promises";
|
|
22069
22165
|
import { realpathSync as realpathSync7 } from "fs";
|
|
22070
22166
|
import { randomUUID as randomUUID7 } from "crypto";
|
|
22071
|
-
import { basename as basename13, dirname as dirname15, join as join44, relative as relative6, resolve as
|
|
22167
|
+
import { basename as basename13, dirname as dirname15, join as join44, relative as relative6, resolve as resolve30, sep as sep9 } from "path";
|
|
22072
22168
|
import { Readable as Readable2 } from "stream";
|
|
22073
22169
|
init_attachments();
|
|
22074
22170
|
|
|
@@ -22392,7 +22488,7 @@ async function cascadeDeleteDocument(params) {
|
|
|
22392
22488
|
init_data_path();
|
|
22393
22489
|
init_neo4j_store();
|
|
22394
22490
|
import * as fsp from "fs/promises";
|
|
22395
|
-
import { resolve as
|
|
22491
|
+
import { resolve as resolve29, relative as relative5, join as join43, basename as basename12, extname, sep as sep8 } from "path";
|
|
22396
22492
|
import { tmpdir as tmpdir3 } from "os";
|
|
22397
22493
|
import { execFile } from "child_process";
|
|
22398
22494
|
import { promisify } from "util";
|
|
@@ -22712,7 +22808,7 @@ async function reconcileFileIndex(accountId, opts) {
|
|
|
22712
22808
|
return withSession2(opts, async (session) => {
|
|
22713
22809
|
const walked = [];
|
|
22714
22810
|
const subtreeRoots = [
|
|
22715
|
-
|
|
22811
|
+
resolve29(dataRoot, "accounts", accountId)
|
|
22716
22812
|
];
|
|
22717
22813
|
let clean = true;
|
|
22718
22814
|
for (const root of subtreeRoots) {
|
|
@@ -22795,7 +22891,7 @@ async function reconcileFileIndexDebounced(accountId, opts) {
|
|
|
22795
22891
|
async function indexFile(accountId, relativePath, opts) {
|
|
22796
22892
|
const dataRoot = opts?.dataRoot ?? DATA_ROOT;
|
|
22797
22893
|
const embed2 = opts?.embed ?? embed;
|
|
22798
|
-
const absolute =
|
|
22894
|
+
const absolute = resolve29(dataRoot, relativePath);
|
|
22799
22895
|
await withSession2(opts, async (session) => {
|
|
22800
22896
|
const st = await fsp.stat(absolute);
|
|
22801
22897
|
const wf = {
|
|
@@ -22944,7 +23040,7 @@ async function readMeta2(absDir, baseName) {
|
|
|
22944
23040
|
}
|
|
22945
23041
|
async function readAccountNames() {
|
|
22946
23042
|
const map = /* @__PURE__ */ new Map();
|
|
22947
|
-
const accountsDir =
|
|
23043
|
+
const accountsDir = resolve30(DATA_ROOT, "accounts");
|
|
22948
23044
|
let names;
|
|
22949
23045
|
try {
|
|
22950
23046
|
names = await readdir4(accountsDir);
|
|
@@ -22953,7 +23049,7 @@ async function readAccountNames() {
|
|
|
22953
23049
|
}
|
|
22954
23050
|
for (const name of names) {
|
|
22955
23051
|
if (!UUID_RE3.test(name)) continue;
|
|
22956
|
-
const configPath3 =
|
|
23052
|
+
const configPath3 = resolve30(accountsDir, name, "account.json");
|
|
22957
23053
|
try {
|
|
22958
23054
|
const raw = await readFile9(configPath3, "utf8");
|
|
22959
23055
|
const parsed = JSON.parse(raw);
|
|
@@ -23555,8 +23651,8 @@ async function resolveUploadTarget(c, accountId, uid) {
|
|
|
23555
23651
|
return { ok: false, status: 403, error: "Path is outside your account folder" };
|
|
23556
23652
|
}
|
|
23557
23653
|
}
|
|
23558
|
-
const destDir = relDir === "." ? base.absolute :
|
|
23559
|
-
const destPath =
|
|
23654
|
+
const destDir = relDir === "." ? base.absolute : resolve30(base.absolute, relDir);
|
|
23655
|
+
const destPath = resolve30(destDir, finalName);
|
|
23560
23656
|
if (relpath) {
|
|
23561
23657
|
const firstCreated = await mkdir3(destDir, { recursive: true });
|
|
23562
23658
|
if (firstCreated) console.error(`[data-upload] op=mkdir uid=${uid} token=${token} dir="${destRel}"`);
|
|
@@ -23573,7 +23669,7 @@ async function resolveUploadTarget(c, accountId, uid) {
|
|
|
23573
23669
|
return { ok: true, destDir, destPath, destRel, finalName, mimeType, relpath, token };
|
|
23574
23670
|
}
|
|
23575
23671
|
async function logUploadsTmpCensus(accountId) {
|
|
23576
|
-
const tmpDir =
|
|
23672
|
+
const tmpDir = resolve30(DATA_ROOT, "accounts", accountId, UPLOAD_TMP_DIR);
|
|
23577
23673
|
let live = 0;
|
|
23578
23674
|
try {
|
|
23579
23675
|
live = (await readdir4(tmpDir)).length;
|
|
@@ -23600,9 +23696,9 @@ app29.post("/upload", requireAdminSession, async (c) => {
|
|
|
23600
23696
|
if (!body) return c.json({ error: "Empty request body" }, 400);
|
|
23601
23697
|
console.error(`[data-upload] op=request uid=${uid} account=${accountId} dir="${destRel}" token=${token} rel="${relpath ?? ""}" declaredBytes=${declaredBytes}`);
|
|
23602
23698
|
const ceiling = dataUploadCeiling();
|
|
23603
|
-
const tmpDir =
|
|
23699
|
+
const tmpDir = resolve30(DATA_ROOT, "accounts", accountId, UPLOAD_TMP_DIR);
|
|
23604
23700
|
await mkdir3(tmpDir, { recursive: true });
|
|
23605
|
-
const tmpPath =
|
|
23701
|
+
const tmpPath = resolve30(tmpDir, `${uid}.part`);
|
|
23606
23702
|
const out = createWriteStream2(tmpPath);
|
|
23607
23703
|
const t0 = Date.now();
|
|
23608
23704
|
let received2 = 0;
|
|
@@ -23620,7 +23716,7 @@ app29.post("/upload", requireAdminSession, async (c) => {
|
|
|
23620
23716
|
});
|
|
23621
23717
|
await unlink3(tmpPath).catch(() => {
|
|
23622
23718
|
});
|
|
23623
|
-
const tempRemoved = !
|
|
23719
|
+
const tempRemoved = !existsSync37(tmpPath);
|
|
23624
23720
|
console.error(`[data-upload] op=cleanup uid=${uid} tempRemoved=${tempRemoved}`);
|
|
23625
23721
|
};
|
|
23626
23722
|
const reader = body.getReader();
|
|
@@ -23694,7 +23790,7 @@ async function discardChunkUpload(uploadId, state) {
|
|
|
23694
23790
|
});
|
|
23695
23791
|
await unlink3(state.tmpPath).catch(() => {
|
|
23696
23792
|
});
|
|
23697
|
-
const tempRemoved = !
|
|
23793
|
+
const tempRemoved = !existsSync37(state.tmpPath);
|
|
23698
23794
|
console.error(`[data-upload] op=cleanup uid=${uploadId} tempRemoved=${tempRemoved}`);
|
|
23699
23795
|
}
|
|
23700
23796
|
async function writeChunkBody(body, out, alreadyReceived, ceiling) {
|
|
@@ -23749,9 +23845,9 @@ async function handleChunkUpload(c, accountId) {
|
|
|
23749
23845
|
}
|
|
23750
23846
|
const target = await resolveUploadTarget(c, accountId, uploadId);
|
|
23751
23847
|
if (!target.ok) return c.json({ error: target.error }, target.status);
|
|
23752
|
-
const tmpDir =
|
|
23848
|
+
const tmpDir = resolve30(DATA_ROOT, "accounts", accountId, UPLOAD_TMP_DIR);
|
|
23753
23849
|
await mkdir3(tmpDir, { recursive: true });
|
|
23754
|
-
const tmpPath =
|
|
23850
|
+
const tmpPath = resolve30(tmpDir, `${uploadId}.part`);
|
|
23755
23851
|
const out = createWriteStream2(tmpPath);
|
|
23756
23852
|
const state2 = {
|
|
23757
23853
|
accountId,
|
|
@@ -23857,7 +23953,7 @@ async function evictStaleChunkUploads(ttlMs) {
|
|
|
23857
23953
|
return evicted;
|
|
23858
23954
|
}
|
|
23859
23955
|
async function sweepStaleUploadTemps() {
|
|
23860
|
-
const accountsRoot =
|
|
23956
|
+
const accountsRoot = resolve30(DATA_ROOT, "accounts");
|
|
23861
23957
|
let accounts;
|
|
23862
23958
|
try {
|
|
23863
23959
|
accounts = await readdir4(accountsRoot, { withFileTypes: true });
|
|
@@ -23867,7 +23963,7 @@ async function sweepStaleUploadTemps() {
|
|
|
23867
23963
|
let removed = 0;
|
|
23868
23964
|
for (const acc of accounts) {
|
|
23869
23965
|
if (!acc.isDirectory()) continue;
|
|
23870
|
-
const tmpDir =
|
|
23966
|
+
const tmpDir = resolve30(accountsRoot, acc.name, UPLOAD_TMP_DIR);
|
|
23871
23967
|
let entries2;
|
|
23872
23968
|
try {
|
|
23873
23969
|
entries2 = await readdir4(tmpDir);
|
|
@@ -23876,7 +23972,7 @@ async function sweepStaleUploadTemps() {
|
|
|
23876
23972
|
}
|
|
23877
23973
|
for (const name of entries2) {
|
|
23878
23974
|
try {
|
|
23879
|
-
await unlink3(
|
|
23975
|
+
await unlink3(resolve30(tmpDir, name));
|
|
23880
23976
|
removed++;
|
|
23881
23977
|
} catch {
|
|
23882
23978
|
}
|
|
@@ -23991,7 +24087,7 @@ app29.post("/folder", requireAdminSession, async (c) => {
|
|
|
23991
24087
|
if (!isValidEntryName(name)) return c.json({ error: "Invalid folder name" }, 400);
|
|
23992
24088
|
const parent = resolveSharedOrOwnAccountWrite(rawPath, accountId, "POST /api/admin/files/folder");
|
|
23993
24089
|
if (!parent.ok) return c.json({ error: parent.error }, parent.status);
|
|
23994
|
-
const newAbs =
|
|
24090
|
+
const newAbs = resolve30(parent.absolute, name);
|
|
23995
24091
|
const newRel = `${parent.relative}/${name}`;
|
|
23996
24092
|
try {
|
|
23997
24093
|
const info = await stat6(parent.absolute);
|
|
@@ -24030,7 +24126,7 @@ app29.post("/rename", requireAdminSession, async (c) => {
|
|
|
24030
24126
|
console.error(`[data] file-rename blocked path="${src.relative}" reason="protected"`);
|
|
24031
24127
|
return c.json({ error: "Protected entry \u2014 refusing to rename" }, 403);
|
|
24032
24128
|
}
|
|
24033
|
-
const destAbs =
|
|
24129
|
+
const destAbs = resolve30(dirname15(src.absolute), newName);
|
|
24034
24130
|
const newRel = `${dirname15(src.relative)}/${newName}`.replace(/^\.\//, "");
|
|
24035
24131
|
if (isProtectedFromRename(newRel)) {
|
|
24036
24132
|
console.error(`[data] file-rename blocked path="${newRel}" reason="protected-target"`);
|
|
@@ -25063,7 +25159,7 @@ function isHiddenByDefault(label) {
|
|
|
25063
25159
|
// server/lib/top-level-labels.ts
|
|
25064
25160
|
var import_dist8 = __toESM(require_dist6(), 1);
|
|
25065
25161
|
import { readdirSync as readdirSync24, readFileSync as readFileSync38 } from "fs";
|
|
25066
|
-
import { join as join45, resolve as
|
|
25162
|
+
import { join as join45, resolve as resolve31 } from "path";
|
|
25067
25163
|
var STATIC_TOP_LEVEL_LABELS = Object.freeze(
|
|
25068
25164
|
/* @__PURE__ */ new Set([
|
|
25069
25165
|
// Base-schema infra (schema-base.md has no top-level section).
|
|
@@ -25169,7 +25265,7 @@ function resolveReferencesDir() {
|
|
|
25169
25265
|
if (process.env.MAXY_PLATFORM_ROOT) {
|
|
25170
25266
|
return join45(process.env.MAXY_PLATFORM_ROOT, "plugins", "memory", "references");
|
|
25171
25267
|
}
|
|
25172
|
-
return
|
|
25268
|
+
return resolve31(import.meta.dirname, "../../../plugins/memory/references");
|
|
25173
25269
|
}
|
|
25174
25270
|
function parseTableTopLevelLabels(referencesDir) {
|
|
25175
25271
|
const labels = /* @__PURE__ */ new Set();
|
|
@@ -26355,8 +26451,8 @@ init_claude_agent();
|
|
|
26355
26451
|
init_account();
|
|
26356
26452
|
init_route_cache();
|
|
26357
26453
|
import { readdir as readdir5, stat as stat7 } from "fs/promises";
|
|
26358
|
-
import { resolve as
|
|
26359
|
-
import { existsSync as
|
|
26454
|
+
import { resolve as resolve32, relative as relative7, isAbsolute as isAbsolute4, sep as sep10, basename as basename14 } from "path";
|
|
26455
|
+
import { existsSync as existsSync38 } from "fs";
|
|
26360
26456
|
init_neo4j_store();
|
|
26361
26457
|
init_attachments();
|
|
26362
26458
|
init_data_path();
|
|
@@ -26374,11 +26470,11 @@ app36.get("/", requireAdminSession, async (c) => {
|
|
|
26374
26470
|
return c.json({ error: "Account not found for session" }, 401);
|
|
26375
26471
|
}
|
|
26376
26472
|
const start = Date.now();
|
|
26377
|
-
ensureAccountWatchers(accountId,
|
|
26473
|
+
ensureAccountWatchers(accountId, resolve32(ACCOUNTS_DIR, accountId));
|
|
26378
26474
|
const { value, state } = await getOrCompute("sidebar-artefacts", accountId, async () => {
|
|
26379
26475
|
const accountFiles = await fetchAccountFileArtefacts(accountId);
|
|
26380
26476
|
if (accountFiles === null) return null;
|
|
26381
|
-
const accountDir =
|
|
26477
|
+
const accountDir = resolve32(ACCOUNTS_DIR, accountId);
|
|
26382
26478
|
const agents = await fetchAgentTemplateRows(accountDir);
|
|
26383
26479
|
const artefacts = [...accountFiles, ...agents].sort(
|
|
26384
26480
|
(a, b) => (b.updatedAt ?? "").localeCompare(a.updatedAt ?? "")
|
|
@@ -26435,8 +26531,8 @@ async function fetchAccountFileArtefacts(accountId) {
|
|
|
26435
26531
|
async function fetchAgentTemplateRows(accountDir) {
|
|
26436
26532
|
const rows = [];
|
|
26437
26533
|
for (const filename of ADMIN_AGENT_FILES) {
|
|
26438
|
-
const overridePath =
|
|
26439
|
-
const bundledPath =
|
|
26534
|
+
const overridePath = resolve32(accountDir, "agents", "admin", filename);
|
|
26535
|
+
const bundledPath = resolve32(PLATFORM_ROOT, "templates", "agents", "admin", filename);
|
|
26440
26536
|
const labelStem = filename.replace(/\.md$/, "");
|
|
26441
26537
|
const row = await readAgentTemplateRow({
|
|
26442
26538
|
id: `agent-template:admin:${filename}`,
|
|
@@ -26449,12 +26545,12 @@ async function fetchAgentTemplateRows(accountDir) {
|
|
|
26449
26545
|
});
|
|
26450
26546
|
if (row) rows.push(row);
|
|
26451
26547
|
}
|
|
26452
|
-
const overrideDir =
|
|
26453
|
-
const bundledDir =
|
|
26548
|
+
const overrideDir = resolve32(accountDir, "specialists", "agents");
|
|
26549
|
+
const bundledDir = resolve32(PLATFORM_ROOT, "templates", "specialists", "agents");
|
|
26454
26550
|
const specialistNames = await unionSpecialistFilenames(overrideDir, bundledDir);
|
|
26455
26551
|
for (const filename of specialistNames) {
|
|
26456
|
-
const overridePath =
|
|
26457
|
-
const bundledPath =
|
|
26552
|
+
const overridePath = resolve32(overrideDir, filename);
|
|
26553
|
+
const bundledPath = resolve32(bundledDir, filename);
|
|
26458
26554
|
const row = await readAgentTemplateRow({
|
|
26459
26555
|
id: `agent-template:specialist:${filename}`,
|
|
26460
26556
|
displayName: filename.replace(/\.md$/, ""),
|
|
@@ -26471,7 +26567,7 @@ async function fetchAgentTemplateRows(accountDir) {
|
|
|
26471
26567
|
async function unionSpecialistFilenames(overrideDir, bundledDir) {
|
|
26472
26568
|
const names = /* @__PURE__ */ new Set();
|
|
26473
26569
|
for (const dir of [overrideDir, bundledDir]) {
|
|
26474
|
-
if (!
|
|
26570
|
+
if (!existsSync38(dir)) continue;
|
|
26475
26571
|
try {
|
|
26476
26572
|
const entries2 = await readdir5(dir);
|
|
26477
26573
|
for (const entry2 of entries2) {
|
|
@@ -26486,7 +26582,7 @@ async function unionSpecialistFilenames(overrideDir, bundledDir) {
|
|
|
26486
26582
|
}
|
|
26487
26583
|
async function readAgentTemplateRow(inp) {
|
|
26488
26584
|
let chosenPath = null;
|
|
26489
|
-
if (
|
|
26585
|
+
if (existsSync38(inp.overridePath)) {
|
|
26490
26586
|
try {
|
|
26491
26587
|
validateFilePathInAccount(inp.overridePath, inp.overrideRoot);
|
|
26492
26588
|
chosenPath = inp.overridePath;
|
|
@@ -26497,7 +26593,7 @@ async function readAgentTemplateRow(inp) {
|
|
|
26497
26593
|
);
|
|
26498
26594
|
return null;
|
|
26499
26595
|
}
|
|
26500
|
-
} else if (
|
|
26596
|
+
} else if (existsSync38(inp.bundledPath)) {
|
|
26501
26597
|
if (!isWithin(inp.bundledPath, inp.bundledRoot)) {
|
|
26502
26598
|
console.error(
|
|
26503
26599
|
`[admin/sidebar-artefacts] agent-template-read-failed agent=${inp.displayName} kind=${inp.logName} error="bundled path outside PLATFORM_ROOT"`
|
|
@@ -26957,24 +27053,24 @@ init_session_store();
|
|
|
26957
27053
|
import { randomUUID as randomUUID9 } from "crypto";
|
|
26958
27054
|
|
|
26959
27055
|
// server/wa-descriptor.ts
|
|
26960
|
-
import { resolve as
|
|
27056
|
+
import { resolve as resolve33, join as join46 } from "path";
|
|
26961
27057
|
function waGatewayUrl() {
|
|
26962
27058
|
return `http://127.0.0.1:${process.env.MAXY_UI_INTERNAL_PORT ?? ""}`;
|
|
26963
27059
|
}
|
|
26964
27060
|
function waServerPath() {
|
|
26965
|
-
return process.env.MAXY_WA_CHANNEL_SERVER_PATH ??
|
|
27061
|
+
return process.env.MAXY_WA_CHANNEL_SERVER_PATH ?? resolve33(process.env.MAXY_PLATFORM_ROOT ?? join46(__dirname, ".."), "services/whatsapp-channel/dist/server.js");
|
|
26966
27062
|
}
|
|
26967
27063
|
function waChannelDescriptor(senderId) {
|
|
26968
27064
|
return { senderId, gatewayUrl: waGatewayUrl(), serverPath: waServerPath() };
|
|
26969
27065
|
}
|
|
26970
27066
|
|
|
26971
27067
|
// server/telegram-descriptor.ts
|
|
26972
|
-
import { resolve as
|
|
27068
|
+
import { resolve as resolve34, join as join47 } from "path";
|
|
26973
27069
|
function telegramGatewayUrl() {
|
|
26974
27070
|
return `http://127.0.0.1:${process.env.MAXY_UI_INTERNAL_PORT ?? ""}`;
|
|
26975
27071
|
}
|
|
26976
27072
|
function telegramServerPath() {
|
|
26977
|
-
return process.env.MAXY_TELEGRAM_CHANNEL_SERVER_PATH ??
|
|
27073
|
+
return process.env.MAXY_TELEGRAM_CHANNEL_SERVER_PATH ?? resolve34(process.env.MAXY_PLATFORM_ROOT ?? join47(__dirname, ".."), "services/telegram-channel/dist/server.js");
|
|
26978
27074
|
}
|
|
26979
27075
|
function telegramChannelDescriptor(senderId) {
|
|
26980
27076
|
return { senderId, gatewayUrl: telegramGatewayUrl(), serverPath: telegramServerPath() };
|
|
@@ -27270,23 +27366,23 @@ var system_stats_default = app44;
|
|
|
27270
27366
|
// server/routes/admin/health.ts
|
|
27271
27367
|
init_dist();
|
|
27272
27368
|
init_neo4j_store();
|
|
27273
|
-
import { existsSync as
|
|
27274
|
-
import { resolve as
|
|
27275
|
-
var PLATFORM_ROOT4 = process.env.MAXY_PLATFORM_ROOT ??
|
|
27369
|
+
import { existsSync as existsSync39, readFileSync as readFileSync39 } from "fs";
|
|
27370
|
+
import { resolve as resolve35, join as join48 } from "path";
|
|
27371
|
+
var PLATFORM_ROOT4 = process.env.MAXY_PLATFORM_ROOT ?? resolve35(process.cwd(), "..");
|
|
27276
27372
|
var brandHostname = "maxy";
|
|
27277
27373
|
var brandJsonPath = join48(PLATFORM_ROOT4, "config", "brand.json");
|
|
27278
|
-
if (
|
|
27374
|
+
if (existsSync39(brandJsonPath)) {
|
|
27279
27375
|
try {
|
|
27280
27376
|
const brand = JSON.parse(readFileSync39(brandJsonPath, "utf-8"));
|
|
27281
27377
|
if (brand.hostname) brandHostname = brand.hostname;
|
|
27282
27378
|
} catch {
|
|
27283
27379
|
}
|
|
27284
27380
|
}
|
|
27285
|
-
var VERSION_FILE =
|
|
27381
|
+
var VERSION_FILE = resolve35(PLATFORM_ROOT4, `config/.${brandHostname}-version`);
|
|
27286
27382
|
var PROCESS_STARTED_AT = (/* @__PURE__ */ new Date()).toISOString();
|
|
27287
27383
|
var PROBE_TIMEOUT_MS = 1e3;
|
|
27288
27384
|
function readVersion() {
|
|
27289
|
-
if (!
|
|
27385
|
+
if (!existsSync39(VERSION_FILE)) return "unknown";
|
|
27290
27386
|
return readFileSync39(VERSION_FILE, "utf-8").trim() || "unknown";
|
|
27291
27387
|
}
|
|
27292
27388
|
async function probeConversationDb() {
|
|
@@ -27343,17 +27439,17 @@ import { randomUUID as randomUUID10 } from "crypto";
|
|
|
27343
27439
|
|
|
27344
27440
|
// ../lib/account-ingest-token/src/index.ts
|
|
27345
27441
|
import { randomBytes, timingSafeEqual as timingSafeEqual2 } from "crypto";
|
|
27346
|
-
import { existsSync as
|
|
27347
|
-
import { resolve as
|
|
27442
|
+
import { existsSync as existsSync40, readdirSync as readdirSync25, readFileSync as readFileSync40, writeFileSync as writeFileSync16 } from "fs";
|
|
27443
|
+
import { resolve as resolve36 } from "path";
|
|
27348
27444
|
var UUID_RE4 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
27349
27445
|
var INGEST_TOKEN_FIELD = "ingestToken";
|
|
27350
27446
|
var TOKEN_RE = /^[0-9a-f]{64}$/;
|
|
27351
27447
|
function configPath2(accountsDir, accountId) {
|
|
27352
|
-
return
|
|
27448
|
+
return resolve36(accountsDir, accountId, "account.json");
|
|
27353
27449
|
}
|
|
27354
27450
|
function readConfig2(accountsDir, accountId) {
|
|
27355
27451
|
const path = configPath2(accountsDir, accountId);
|
|
27356
|
-
if (!
|
|
27452
|
+
if (!existsSync40(path)) return null;
|
|
27357
27453
|
try {
|
|
27358
27454
|
const parsed = JSON.parse(readFileSync40(path, "utf-8"));
|
|
27359
27455
|
return parsed !== null && typeof parsed === "object" ? parsed : null;
|
|
@@ -27366,7 +27462,7 @@ function readIngestToken(accountsDir, accountId) {
|
|
|
27366
27462
|
return typeof value === "string" && TOKEN_RE.test(value) ? value : null;
|
|
27367
27463
|
}
|
|
27368
27464
|
function listAccountIdsOnDisk(accountsDir) {
|
|
27369
|
-
if (!
|
|
27465
|
+
if (!existsSync40(accountsDir)) return [];
|
|
27370
27466
|
let entries2;
|
|
27371
27467
|
try {
|
|
27372
27468
|
entries2 = readdirSync25(accountsDir);
|
|
@@ -27374,7 +27470,7 @@ function listAccountIdsOnDisk(accountsDir) {
|
|
|
27374
27470
|
return [];
|
|
27375
27471
|
}
|
|
27376
27472
|
return entries2.filter(
|
|
27377
|
-
(name) => UUID_RE4.test(name) &&
|
|
27473
|
+
(name) => UUID_RE4.test(name) && existsSync40(resolve36(accountsDir, name, "account.json"))
|
|
27378
27474
|
);
|
|
27379
27475
|
}
|
|
27380
27476
|
function resolveAccountIdByIngestToken(accountsDir, token) {
|
|
@@ -28229,7 +28325,7 @@ init_helpers();
|
|
|
28229
28325
|
init_claude_agent();
|
|
28230
28326
|
init_account_scope();
|
|
28231
28327
|
init_neo4j_store();
|
|
28232
|
-
import { existsSync as
|
|
28328
|
+
import { existsSync as existsSync41 } from "fs";
|
|
28233
28329
|
import { randomUUID as randomUUID11 } from "crypto";
|
|
28234
28330
|
import { join as join50 } from "path";
|
|
28235
28331
|
|
|
@@ -28899,7 +28995,7 @@ app53.get("/booking-link", requireAdminSession, (c) => {
|
|
|
28899
28995
|
}
|
|
28900
28996
|
const id82 = account.accountId.slice(0, 8);
|
|
28901
28997
|
try {
|
|
28902
|
-
if (!
|
|
28998
|
+
if (!existsSync41(join50(account.accountDir, AVAILABILITY_FILENAME))) {
|
|
28903
28999
|
console.log(`[calendar] op=booking-link accountId=${id82} bookingDomain=none source=availability-config`);
|
|
28904
29000
|
return c.json({ bookingDomain: null });
|
|
28905
29001
|
}
|
|
@@ -28921,7 +29017,7 @@ var calendar_default = app53;
|
|
|
28921
29017
|
init_dist();
|
|
28922
29018
|
init_helpers();
|
|
28923
29019
|
init_account_scope();
|
|
28924
|
-
import { existsSync as
|
|
29020
|
+
import { existsSync as existsSync42, readFileSync as readFileSync42 } from "fs";
|
|
28925
29021
|
import { join as join51 } from "path";
|
|
28926
29022
|
var app54 = new Hono();
|
|
28927
29023
|
var PORTAL_FILENAME = "data-portal.json";
|
|
@@ -28934,7 +29030,7 @@ app54.get("/portal-link", requireAdminSession, (c) => {
|
|
|
28934
29030
|
const id82 = account.accountId.slice(0, 8);
|
|
28935
29031
|
try {
|
|
28936
29032
|
const path = join51(account.accountDir, PORTAL_FILENAME);
|
|
28937
|
-
if (!
|
|
29033
|
+
if (!existsSync42(path)) {
|
|
28938
29034
|
console.log(`[data-portal] op=portal-link accountId=${id82} portalDomain=none source=data-portal-config`);
|
|
28939
29035
|
return c.json({ portalDomain: null });
|
|
28940
29036
|
}
|
|
@@ -28960,11 +29056,11 @@ init_src2();
|
|
|
28960
29056
|
import cronParser from "cron-parser";
|
|
28961
29057
|
import { int as int2 } from "neo4j-driver";
|
|
28962
29058
|
import { readFileSync as readFileSync44 } from "fs";
|
|
28963
|
-
import { resolve as
|
|
29059
|
+
import { resolve as resolve38 } from "path";
|
|
28964
29060
|
|
|
28965
29061
|
// ../lib/agent-dispatch-rule/src/index.ts
|
|
28966
29062
|
import { readFileSync as readFileSync43 } from "fs";
|
|
28967
|
-
import { resolve as
|
|
29063
|
+
import { resolve as resolve37 } from "path";
|
|
28968
29064
|
function normalizeE1642(value) {
|
|
28969
29065
|
let candidate = value.trim().replace(/[\s\-().]/g, "");
|
|
28970
29066
|
candidate = candidate.replace(/^whatsapp:/i, "");
|
|
@@ -28981,7 +29077,7 @@ function phonesMatch2(a, b) {
|
|
|
28981
29077
|
function readChannelAdmins(accountDir, channel) {
|
|
28982
29078
|
let config = {};
|
|
28983
29079
|
try {
|
|
28984
|
-
config = JSON.parse(readFileSync43(
|
|
29080
|
+
config = JSON.parse(readFileSync43(resolve37(accountDir, "account.json"), "utf-8"));
|
|
28985
29081
|
} catch {
|
|
28986
29082
|
config = {};
|
|
28987
29083
|
}
|
|
@@ -29038,7 +29134,7 @@ function boundSubAccountFor(accountDir, destination) {
|
|
|
29038
29134
|
}
|
|
29039
29135
|
function validateAgentDestination(accountsDir, houseAccountId, creatingAccountId, channel, destination) {
|
|
29040
29136
|
if (channel === "whatsapp") {
|
|
29041
|
-
const houseDir =
|
|
29137
|
+
const houseDir = resolve37(accountsDir, houseAccountId);
|
|
29042
29138
|
const registered = registeredAccountForDestination(houseDir, houseAccountId, destination);
|
|
29043
29139
|
if (registered === null) return { valid: false, reason: "not-registered" };
|
|
29044
29140
|
if (creatingAccountId === houseAccountId) return { valid: true };
|
|
@@ -29050,7 +29146,7 @@ function validateAgentDestination(accountsDir, houseAccountId, creatingAccountId
|
|
|
29050
29146
|
scheduleAccount: creatingAccountId
|
|
29051
29147
|
};
|
|
29052
29148
|
}
|
|
29053
|
-
const { adminUsers } = readChannelAdmins(
|
|
29149
|
+
const { adminUsers } = readChannelAdmins(resolve37(accountsDir, creatingAccountId), "telegram");
|
|
29054
29150
|
const asNumber = Number(destination);
|
|
29055
29151
|
const ok2 = Number.isInteger(asNumber) && adminUsers.includes(asNumber);
|
|
29056
29152
|
return ok2 ? { valid: true } : { valid: false, reason: "not-registered" };
|
|
@@ -29060,7 +29156,7 @@ function listDispatchDestinations(input) {
|
|
|
29060
29156
|
const managers = [];
|
|
29061
29157
|
const admins = [];
|
|
29062
29158
|
if (houseAccountId !== null) {
|
|
29063
|
-
const houseDir =
|
|
29159
|
+
const houseDir = resolve37(accountsDir, houseAccountId);
|
|
29064
29160
|
const { adminPhones, accountManagers } = readChannelAdmins(houseDir, "whatsapp");
|
|
29065
29161
|
const seen = /* @__PURE__ */ new Set();
|
|
29066
29162
|
for (const [phone, subAccountId] of Object.entries(accountManagers)) {
|
|
@@ -29078,7 +29174,7 @@ function listDispatchDestinations(input) {
|
|
|
29078
29174
|
admins.push({ channel: "whatsapp", destination: phone, label: "House admin" });
|
|
29079
29175
|
}
|
|
29080
29176
|
}
|
|
29081
|
-
const { byBot: byBot2 } = readChannelAdmins(
|
|
29177
|
+
const { byBot: byBot2 } = readChannelAdmins(resolve37(accountsDir, accountId), "telegram");
|
|
29082
29178
|
const telegram = byBot2.flatMap((b) => b.adminUsers.map((id) => ({ botId: b.botId, id }))).sort((a, b) => a.id - b.id || a.botId.localeCompare(b.botId)).map(({ botId, id }) => ({
|
|
29083
29179
|
channel: "telegram",
|
|
29084
29180
|
destination: String(id),
|
|
@@ -29135,7 +29231,7 @@ function gateClassification(row) {
|
|
|
29135
29231
|
return typeof row.gateWaived === "string" && row.gateWaived.trim() !== "";
|
|
29136
29232
|
}
|
|
29137
29233
|
function gateWatermarkPath(eventId) {
|
|
29138
|
-
return
|
|
29234
|
+
return resolve38(PLATFORM_ROOT, "..", "state", "scheduling-gate", `${eventId}.json`);
|
|
29139
29235
|
}
|
|
29140
29236
|
function readGateLastCommitAt(eventId) {
|
|
29141
29237
|
try {
|
|
@@ -29968,8 +30064,8 @@ init_dist();
|
|
|
29968
30064
|
init_helpers();
|
|
29969
30065
|
init_account_scope();
|
|
29970
30066
|
init_route_cache();
|
|
29971
|
-
import { existsSync as
|
|
29972
|
-
import { resolve as
|
|
30067
|
+
import { existsSync as existsSync43, readdirSync as readdirSync26, readFileSync as readFileSync45, rmSync as rmSync6 } from "fs";
|
|
30068
|
+
import { resolve as resolve39 } from "path";
|
|
29973
30069
|
var app56 = new Hono();
|
|
29974
30070
|
var NAME_RE = /^[a-z0-9][a-z0-9-]*$/;
|
|
29975
30071
|
function splitSkillMd(text) {
|
|
@@ -29992,7 +30088,7 @@ function stripQuotes(s) {
|
|
|
29992
30088
|
return s;
|
|
29993
30089
|
}
|
|
29994
30090
|
function subdirs2(dir) {
|
|
29995
|
-
if (!
|
|
30091
|
+
if (!existsSync43(dir)) return [];
|
|
29996
30092
|
try {
|
|
29997
30093
|
return readdirSync26(dir, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
|
|
29998
30094
|
} catch {
|
|
@@ -30007,19 +30103,19 @@ app56.get("/", requireAdminSession, async (c) => {
|
|
|
30007
30103
|
}
|
|
30008
30104
|
ensureAccountWatchers(acct.accountId, acct.accountDir);
|
|
30009
30105
|
const { value, state } = await getOrCompute("skills", acct.accountId, async () => {
|
|
30010
|
-
const pluginsDir =
|
|
30106
|
+
const pluginsDir = resolve39(acct.accountDir, "plugins");
|
|
30011
30107
|
const skills = [];
|
|
30012
30108
|
let pluginCount = 0;
|
|
30013
30109
|
for (const plugin of subdirs2(pluginsDir)) {
|
|
30014
30110
|
pluginCount++;
|
|
30015
|
-
const skillsDir =
|
|
30111
|
+
const skillsDir = resolve39(pluginsDir, plugin, "skills");
|
|
30016
30112
|
for (const skill of subdirs2(skillsDir)) {
|
|
30017
|
-
const skillMd =
|
|
30018
|
-
if (!
|
|
30113
|
+
const skillMd = resolve39(skillsDir, skill, "SKILL.md");
|
|
30114
|
+
if (!existsSync43(skillMd)) continue;
|
|
30019
30115
|
try {
|
|
30020
30116
|
const { frontmatter } = splitSkillMd(readFileSync45(skillMd, "utf-8"));
|
|
30021
|
-
const refsDir =
|
|
30022
|
-
const refCount =
|
|
30117
|
+
const refsDir = resolve39(skillsDir, skill, "references");
|
|
30118
|
+
const refCount = existsSync43(refsDir) ? readdirSync26(refsDir, { withFileTypes: true }).filter((e) => e.isFile()).length : 0;
|
|
30023
30119
|
skills.push({ plugin, skill, description: frontmatter.description, refCount });
|
|
30024
30120
|
} catch (err) {
|
|
30025
30121
|
console.error(`[admin:skills] op=list-skip plugin=${plugin} skill=${skill} reason="${err instanceof Error ? err.message : String(err)}"`);
|
|
@@ -30041,15 +30137,15 @@ app56.get("/:plugin/:skill", requireAdminSession, async (c) => {
|
|
|
30041
30137
|
console.error(`[admin:skills] op=get outcome=rejected reason=invalid-name plugin="${plugin}" skill="${skill}"`);
|
|
30042
30138
|
return c.json({ error: "Invalid plugin or skill name" }, 400);
|
|
30043
30139
|
}
|
|
30044
|
-
const skillDir =
|
|
30045
|
-
const skillMd =
|
|
30046
|
-
const found =
|
|
30140
|
+
const skillDir = resolve39(acct.accountDir, "plugins", plugin, "skills", skill);
|
|
30141
|
+
const skillMd = resolve39(skillDir, "SKILL.md");
|
|
30142
|
+
const found = existsSync43(skillMd);
|
|
30047
30143
|
console.log(`[admin:skills] op=get plugin=${plugin} skill=${skill} found=${found}`);
|
|
30048
30144
|
if (!found) return c.json({ error: "Skill not found" }, 404);
|
|
30049
30145
|
try {
|
|
30050
30146
|
const { frontmatter, body } = splitSkillMd(readFileSync45(skillMd, "utf-8"));
|
|
30051
|
-
const refsDir =
|
|
30052
|
-
const references =
|
|
30147
|
+
const refsDir = resolve39(skillDir, "references");
|
|
30148
|
+
const references = existsSync43(refsDir) ? readdirSync26(refsDir, { withFileTypes: true }).filter((e) => e.isFile()).map((e) => e.name).sort() : [];
|
|
30053
30149
|
return c.json({ skill: { plugin, skill, frontmatter, body, references } });
|
|
30054
30150
|
} catch (err) {
|
|
30055
30151
|
const message = err instanceof Error ? err.message : String(err);
|
|
@@ -30066,10 +30162,10 @@ app56.delete("/:plugin/:skill", requireAdminSession, async (c) => {
|
|
|
30066
30162
|
console.error(`[admin:skills] op=delete outcome=rejected reason=invalid-name plugin="${plugin}" skill="${skill}"`);
|
|
30067
30163
|
return c.json({ error: "Invalid plugin or skill name" }, 400);
|
|
30068
30164
|
}
|
|
30069
|
-
const pluginDir =
|
|
30070
|
-
const skillsDir =
|
|
30071
|
-
const skillDir =
|
|
30072
|
-
if (!
|
|
30165
|
+
const pluginDir = resolve39(acct.accountDir, "plugins", plugin);
|
|
30166
|
+
const skillsDir = resolve39(pluginDir, "skills");
|
|
30167
|
+
const skillDir = resolve39(skillsDir, skill);
|
|
30168
|
+
if (!existsSync43(resolve39(skillDir, "SKILL.md"))) {
|
|
30073
30169
|
console.error(`[admin:skills] op=delete outcome=rejected reason=not-found plugin=${plugin} skill=${skill}`);
|
|
30074
30170
|
return c.json({ error: "Skill not found" }, 404);
|
|
30075
30171
|
}
|
|
@@ -30077,7 +30173,7 @@ app56.delete("/:plugin/:skill", requireAdminSession, async (c) => {
|
|
|
30077
30173
|
rmSync6(skillDir, { recursive: true, force: true });
|
|
30078
30174
|
const pluginDirRemoved = subdirs2(skillsDir).length === 0;
|
|
30079
30175
|
if (pluginDirRemoved) rmSync6(pluginDir, { recursive: true, force: true });
|
|
30080
|
-
const skillDirGone = !
|
|
30176
|
+
const skillDirGone = !existsSync43(skillDir);
|
|
30081
30177
|
if (!skillDirGone) {
|
|
30082
30178
|
console.error(`[admin:skills] op=delete plugin=${plugin} skill=${skill} outcome=rejected reason=rm-incomplete skillDirGone=false`);
|
|
30083
30179
|
return c.json({ error: "Delete did not remove the skill directory" }, 503);
|
|
@@ -30721,8 +30817,8 @@ init_neo4j_store();
|
|
|
30721
30817
|
// app/lib/admin-roster.ts
|
|
30722
30818
|
init_account();
|
|
30723
30819
|
init_neo4j_store();
|
|
30724
|
-
import { existsSync as
|
|
30725
|
-
import { resolve as
|
|
30820
|
+
import { existsSync as existsSync44, readdirSync as readdirSync27, readFileSync as readFileSync46 } from "fs";
|
|
30821
|
+
import { resolve as resolve40 } from "path";
|
|
30726
30822
|
function readHouseAdminUserIds(accountsDir = ACCOUNTS_DIR) {
|
|
30727
30823
|
let entries2;
|
|
30728
30824
|
try {
|
|
@@ -30731,8 +30827,8 @@ function readHouseAdminUserIds(accountsDir = ACCOUNTS_DIR) {
|
|
|
30731
30827
|
return [];
|
|
30732
30828
|
}
|
|
30733
30829
|
for (const entry2 of entries2) {
|
|
30734
|
-
const cfgPath =
|
|
30735
|
-
if (!
|
|
30830
|
+
const cfgPath = resolve40(accountsDir, entry2, "account.json");
|
|
30831
|
+
if (!existsSync44(cfgPath)) continue;
|
|
30736
30832
|
try {
|
|
30737
30833
|
const cfg = JSON.parse(readFileSync46(cfgPath, "utf-8"));
|
|
30738
30834
|
if (cfg.role !== "house") continue;
|
|
@@ -31082,7 +31178,7 @@ init_claude_agent();
|
|
|
31082
31178
|
init_account();
|
|
31083
31179
|
init_neo4j_store();
|
|
31084
31180
|
init_src2();
|
|
31085
|
-
import { resolve as
|
|
31181
|
+
import { resolve as resolve41 } from "path";
|
|
31086
31182
|
var TAG49 = "[admin:routines]";
|
|
31087
31183
|
function scopeFor(d, houseDir, houseAccountId) {
|
|
31088
31184
|
if (d.channel !== "whatsapp") return null;
|
|
@@ -31112,7 +31208,7 @@ app67.get("/", requireAdminSession, async (c) => {
|
|
|
31112
31208
|
console.error(`${TAG49} op=destinations account=${accountId.slice(0, 8)} outcome=house-unresolved reason="${message}"`);
|
|
31113
31209
|
}
|
|
31114
31210
|
const destinations = listDispatchDestinations({ accountsDir: ACCOUNTS_DIR, houseAccountId, accountId });
|
|
31115
|
-
const houseDir = houseAccountId === null ? null :
|
|
31211
|
+
const houseDir = houseAccountId === null ? null : resolve41(ACCOUNTS_DIR, houseAccountId);
|
|
31116
31212
|
const byScope = /* @__PURE__ */ new Map();
|
|
31117
31213
|
for (const d of destinations) {
|
|
31118
31214
|
const scope = houseDir === null || houseAccountId === null ? null : scopeFor(d, houseDir, houseAccountId);
|
|
@@ -31462,9 +31558,9 @@ init_dist();
|
|
|
31462
31558
|
|
|
31463
31559
|
// app/lib/access-email.ts
|
|
31464
31560
|
import { spawn as spawn2 } from "child_process";
|
|
31465
|
-
import { resolve as
|
|
31466
|
-
var PLATFORM_ROOT5 = process.env.MAXY_PLATFORM_ROOT ??
|
|
31467
|
-
var SEND_SCRIPT =
|
|
31561
|
+
import { resolve as resolve42 } from "path";
|
|
31562
|
+
var PLATFORM_ROOT5 = process.env.MAXY_PLATFORM_ROOT ?? resolve42(process.cwd(), "..");
|
|
31563
|
+
var SEND_SCRIPT = resolve42(
|
|
31468
31564
|
PLATFORM_ROOT5,
|
|
31469
31565
|
"plugins",
|
|
31470
31566
|
"email",
|
|
@@ -31608,8 +31704,8 @@ var access_default = app72;
|
|
|
31608
31704
|
// server/routes/sites.ts
|
|
31609
31705
|
init_dist();
|
|
31610
31706
|
init_claude_agent();
|
|
31611
|
-
import { existsSync as
|
|
31612
|
-
import { resolve as
|
|
31707
|
+
import { existsSync as existsSync45, readFileSync as readFileSync47, realpathSync as realpathSync8, statSync as statSync25 } from "fs";
|
|
31708
|
+
import { resolve as resolve43 } from "path";
|
|
31613
31709
|
var SAFE_SEG_RE = /^[a-z0-9_][a-z0-9_.-]{0,99}$/i;
|
|
31614
31710
|
var MIME = {
|
|
31615
31711
|
".html": "text/html; charset=utf-8",
|
|
@@ -31666,15 +31762,15 @@ app73.get("/:rel{.*}", (c) => {
|
|
|
31666
31762
|
}
|
|
31667
31763
|
segments.push(seg);
|
|
31668
31764
|
}
|
|
31669
|
-
const rootDir =
|
|
31670
|
-
let filePath = segments.length === 0 ? rootDir :
|
|
31765
|
+
const rootDir = resolve43(account.accountDir, "sites");
|
|
31766
|
+
let filePath = segments.length === 0 ? rootDir : resolve43(rootDir, ...segments);
|
|
31671
31767
|
if (filePath !== rootDir && !filePath.startsWith(rootDir + "/")) {
|
|
31672
31768
|
console.error(`[sites] path-traversal-rejected path=${reqPath} reason=escape status=403`);
|
|
31673
31769
|
return c.text("Forbidden", 403);
|
|
31674
31770
|
}
|
|
31675
31771
|
let stat11;
|
|
31676
31772
|
try {
|
|
31677
|
-
stat11 =
|
|
31773
|
+
stat11 = existsSync45(filePath) ? statSync25(filePath) : null;
|
|
31678
31774
|
} catch {
|
|
31679
31775
|
stat11 = null;
|
|
31680
31776
|
}
|
|
@@ -31687,13 +31783,13 @@ app73.get("/:rel{.*}", (c) => {
|
|
|
31687
31783
|
return c.redirect(target, 301);
|
|
31688
31784
|
}
|
|
31689
31785
|
if (stat11?.isDirectory()) {
|
|
31690
|
-
filePath =
|
|
31786
|
+
filePath = resolve43(filePath, "index.html");
|
|
31691
31787
|
}
|
|
31692
31788
|
if (!filePath.startsWith(rootDir + "/")) {
|
|
31693
31789
|
console.error(`[sites] path-traversal-rejected path=${reqPath} reason=escape status=403`);
|
|
31694
31790
|
return c.text("Forbidden", 403);
|
|
31695
31791
|
}
|
|
31696
|
-
if (!
|
|
31792
|
+
if (!existsSync45(filePath)) {
|
|
31697
31793
|
console.error(`[sites] not-found path=${reqPath} status=404`);
|
|
31698
31794
|
return c.text("Not found", 404);
|
|
31699
31795
|
}
|
|
@@ -31833,7 +31929,7 @@ var VISITOR_COOKIE_MAX_AGE_SECONDS = Math.floor(DEFAULT_TTL_MS / 1e3);
|
|
|
31833
31929
|
init_dist();
|
|
31834
31930
|
|
|
31835
31931
|
// app/lib/brand-config.ts
|
|
31836
|
-
import { existsSync as
|
|
31932
|
+
import { existsSync as existsSync46, readFileSync as readFileSync49 } from "fs";
|
|
31837
31933
|
import { join as join53 } from "path";
|
|
31838
31934
|
var cached2 = null;
|
|
31839
31935
|
var cachedAttempted = false;
|
|
@@ -31843,7 +31939,7 @@ function readBrandConfig() {
|
|
|
31843
31939
|
const platformRoot5 = process.env.MAXY_PLATFORM_ROOT;
|
|
31844
31940
|
if (!platformRoot5) return null;
|
|
31845
31941
|
const brandPath = join53(platformRoot5, "config", "brand.json");
|
|
31846
|
-
if (!
|
|
31942
|
+
if (!existsSync46(brandPath)) return null;
|
|
31847
31943
|
try {
|
|
31848
31944
|
cached2 = JSON.parse(readFileSync49(brandPath, "utf-8"));
|
|
31849
31945
|
return cached2;
|
|
@@ -32348,16 +32444,16 @@ var visitor_event_default = app76;
|
|
|
32348
32444
|
// server/routes/session.ts
|
|
32349
32445
|
init_dist();
|
|
32350
32446
|
init_claude_agent();
|
|
32351
|
-
import { resolve as
|
|
32352
|
-
import { existsSync as
|
|
32447
|
+
import { resolve as resolve44 } from "path";
|
|
32448
|
+
import { existsSync as existsSync47, writeFileSync as writeFileSync18, mkdirSync as mkdirSync10 } from "fs";
|
|
32353
32449
|
init_neo4j_store();
|
|
32354
32450
|
init_paths();
|
|
32355
32451
|
var UUID_RE5 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
32356
32452
|
function writeBrandingCache(accountId, agentSlug, branding) {
|
|
32357
32453
|
try {
|
|
32358
|
-
const cacheDir =
|
|
32454
|
+
const cacheDir = resolve44(MAXY_DIR, "branding-cache", accountId);
|
|
32359
32455
|
mkdirSync10(cacheDir, { recursive: true });
|
|
32360
|
-
writeFileSync18(
|
|
32456
|
+
writeFileSync18(resolve44(cacheDir, `${agentSlug}.json`), JSON.stringify(branding), "utf-8");
|
|
32361
32457
|
} catch (err) {
|
|
32362
32458
|
console.error(`[branding] cache write failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
32363
32459
|
}
|
|
@@ -32438,8 +32534,8 @@ app77.post("/", async (c) => {
|
|
|
32438
32534
|
}
|
|
32439
32535
|
let agentConfig = null;
|
|
32440
32536
|
if (account) {
|
|
32441
|
-
const agentDir =
|
|
32442
|
-
if (!
|
|
32537
|
+
const agentDir = resolve44(account.accountDir, "agents", agentSlug);
|
|
32538
|
+
if (!existsSync47(agentDir) || !existsSync47(resolve44(agentDir, "config.json"))) {
|
|
32443
32539
|
return c.json({ error: "Agent not found" }, 404);
|
|
32444
32540
|
}
|
|
32445
32541
|
agentConfig = resolveAgentConfig(account.accountDir, agentSlug);
|
|
@@ -32623,7 +32719,7 @@ var calendar_public_default = app78;
|
|
|
32623
32719
|
init_dist();
|
|
32624
32720
|
import { createReadStream as createReadStream3 } from "fs";
|
|
32625
32721
|
import { stat as stat8, readFile as readFile11, realpath } from "fs/promises";
|
|
32626
|
-
import { join as join54, resolve as
|
|
32722
|
+
import { join as join54, resolve as resolve45, sep as sep11 } from "path";
|
|
32627
32723
|
import { Readable as Readable3 } from "stream";
|
|
32628
32724
|
init_data_path();
|
|
32629
32725
|
init_attachments();
|
|
@@ -32678,7 +32774,7 @@ ${expiresAtMs}`)
|
|
|
32678
32774
|
return diff2 === 0;
|
|
32679
32775
|
}
|
|
32680
32776
|
async function readAccountSecret(accountId) {
|
|
32681
|
-
const path =
|
|
32777
|
+
const path = resolve45(DATA_ROOT, "accounts", accountId, "secrets", "data-portal.env");
|
|
32682
32778
|
let text;
|
|
32683
32779
|
try {
|
|
32684
32780
|
text = await readFile11(path, "utf8");
|
|
@@ -32714,7 +32810,7 @@ async function resolveFetchTarget(accountDir, relPath, ownerId) {
|
|
|
32714
32810
|
const exposeFolders = await readExposeFolders2(accountDir);
|
|
32715
32811
|
const { exposed } = resolveExposedDirs(schemaText, exposeFolders);
|
|
32716
32812
|
if (exposed.length === 0 && !ownerId) return { ok: false, reason: "not-exposed" };
|
|
32717
|
-
const lexical =
|
|
32813
|
+
const lexical = resolve45(accountDir, relPath);
|
|
32718
32814
|
let root;
|
|
32719
32815
|
let absolute;
|
|
32720
32816
|
try {
|
|
@@ -32763,7 +32859,7 @@ async function handle(c, headOnly) {
|
|
|
32763
32859
|
return c.json({ ok: false, error: "denied" }, 401);
|
|
32764
32860
|
}
|
|
32765
32861
|
const target = await resolveFetchTarget(
|
|
32766
|
-
|
|
32862
|
+
resolve45(DATA_ROOT, "accounts", accountId),
|
|
32767
32863
|
relPath,
|
|
32768
32864
|
owner || void 0
|
|
32769
32865
|
);
|
|
@@ -33496,7 +33592,7 @@ function startGraphHealthTimer() {
|
|
|
33496
33592
|
init_loop_registry();
|
|
33497
33593
|
init_data_path();
|
|
33498
33594
|
var import_dist11 = __toESM(require_dist(), 1);
|
|
33499
|
-
import { existsSync as
|
|
33595
|
+
import { existsSync as existsSync48, statSync as statSync27, readdirSync as readdirSync30 } from "fs";
|
|
33500
33596
|
import { join as join57 } from "path";
|
|
33501
33597
|
var TAG57 = "[shared-census]";
|
|
33502
33598
|
var WIRED_SURFACES = 3;
|
|
@@ -33516,7 +33612,7 @@ function countFiles(dir) {
|
|
|
33516
33612
|
}
|
|
33517
33613
|
function runSharedFolderCensus(dataRoot = DATA_ROOT) {
|
|
33518
33614
|
const root = (0, import_dist11.sharedRoot)(dataRoot);
|
|
33519
|
-
const exists =
|
|
33615
|
+
const exists = existsSync48(root);
|
|
33520
33616
|
let isDir = false;
|
|
33521
33617
|
if (exists) {
|
|
33522
33618
|
try {
|
|
@@ -33542,7 +33638,7 @@ function startSharedFolderCensus() {
|
|
|
33542
33638
|
// app/lib/file-watcher.ts
|
|
33543
33639
|
init_data_path();
|
|
33544
33640
|
import * as fsp2 from "fs/promises";
|
|
33545
|
-
import { resolve as
|
|
33641
|
+
import { resolve as resolve46, sep as sep12 } from "path";
|
|
33546
33642
|
var ACCOUNT_UUID_RE3 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
33547
33643
|
var DEFAULT_COALESCE_MS = 500;
|
|
33548
33644
|
var ROOTS = ["accounts"];
|
|
@@ -33561,7 +33657,7 @@ async function startFileWatcher(opts = {}) {
|
|
|
33561
33657
|
const dropFn = opts.drop ?? dropFileIndex;
|
|
33562
33658
|
for (const r of ROOTS) {
|
|
33563
33659
|
try {
|
|
33564
|
-
await fsp2.mkdir(
|
|
33660
|
+
await fsp2.mkdir(resolve46(dataRoot, r), { recursive: true });
|
|
33565
33661
|
} catch (err) {
|
|
33566
33662
|
console.error(
|
|
33567
33663
|
`[file-watcher] start-failed root="${r}" err="${err.message}" \u2014 index will be maintained by the 5-min reconcile backstop only`
|
|
@@ -33582,7 +33678,7 @@ async function startFileWatcher(opts = {}) {
|
|
|
33582
33678
|
timers.set(relativePath, t);
|
|
33583
33679
|
}
|
|
33584
33680
|
async function runHook(relativePath, accountId) {
|
|
33585
|
-
const absolute =
|
|
33681
|
+
const absolute = resolve46(dataRoot, relativePath);
|
|
33586
33682
|
let exists = false;
|
|
33587
33683
|
try {
|
|
33588
33684
|
const st = await fsp2.stat(absolute);
|
|
@@ -33606,7 +33702,7 @@ async function startFileWatcher(opts = {}) {
|
|
|
33606
33702
|
}
|
|
33607
33703
|
}
|
|
33608
33704
|
async function watchRoot(rootName) {
|
|
33609
|
-
const absRoot =
|
|
33705
|
+
const absRoot = resolve46(dataRoot, rootName);
|
|
33610
33706
|
try {
|
|
33611
33707
|
const iter = fsp2.watch(absRoot, { recursive: true, signal: controller.signal });
|
|
33612
33708
|
for await (const event of iter) {
|
|
@@ -33648,7 +33744,7 @@ init_data_path();
|
|
|
33648
33744
|
init_neo4j_store();
|
|
33649
33745
|
init_account();
|
|
33650
33746
|
import { mkdir as mkdir5, readdir as readdir6, rename as rename4, rm as rm3 } from "fs/promises";
|
|
33651
|
-
import { dirname as dirname17, relative as relative8, resolve as
|
|
33747
|
+
import { dirname as dirname17, relative as relative8, resolve as resolve47 } from "path";
|
|
33652
33748
|
var ACCOUNT_UUID_RE4 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
33653
33749
|
async function walkFiles(dir) {
|
|
33654
33750
|
const out = [];
|
|
@@ -33659,7 +33755,7 @@ async function walkFiles(dir) {
|
|
|
33659
33755
|
return out;
|
|
33660
33756
|
}
|
|
33661
33757
|
for (const e of entries2) {
|
|
33662
|
-
const abs =
|
|
33758
|
+
const abs = resolve47(dir, e.name);
|
|
33663
33759
|
if (e.isDirectory()) {
|
|
33664
33760
|
out.push(...await walkFiles(abs));
|
|
33665
33761
|
} else if (e.isFile()) {
|
|
@@ -33679,7 +33775,7 @@ async function relocateTree(srcDir, destDir, dataRoot, accountId, session) {
|
|
|
33679
33775
|
let moved = 0;
|
|
33680
33776
|
for (const oldAbs of files) {
|
|
33681
33777
|
const suffix = relative8(srcDir, oldAbs);
|
|
33682
|
-
const newAbs =
|
|
33778
|
+
const newAbs = resolve47(destDir, suffix);
|
|
33683
33779
|
await mkdir5(dirname17(newAbs), { recursive: true });
|
|
33684
33780
|
await rename4(oldAbs, newAbs);
|
|
33685
33781
|
moved++;
|
|
@@ -33706,7 +33802,7 @@ async function relocateTree(srcDir, destDir, dataRoot, accountId, session) {
|
|
|
33706
33802
|
}
|
|
33707
33803
|
async function migrateUploads(opts = {}) {
|
|
33708
33804
|
const dataRoot = opts.dataRoot ?? DATA_ROOT;
|
|
33709
|
-
const oldRoot =
|
|
33805
|
+
const oldRoot = resolve47(dataRoot, "uploads");
|
|
33710
33806
|
let topEntries;
|
|
33711
33807
|
try {
|
|
33712
33808
|
topEntries = await readdir6(oldRoot, { withFileTypes: true });
|
|
@@ -33727,8 +33823,8 @@ async function migrateUploads(opts = {}) {
|
|
|
33727
33823
|
const name = entry2.name;
|
|
33728
33824
|
if (ACCOUNT_UUID_RE4.test(name)) {
|
|
33729
33825
|
moved += await relocateTree(
|
|
33730
|
-
|
|
33731
|
-
|
|
33826
|
+
resolve47(oldRoot, name),
|
|
33827
|
+
resolve47(dataRoot, "accounts", name, "uploads"),
|
|
33732
33828
|
dataRoot,
|
|
33733
33829
|
name,
|
|
33734
33830
|
session
|
|
@@ -33740,8 +33836,8 @@ async function migrateUploads(opts = {}) {
|
|
|
33740
33836
|
continue;
|
|
33741
33837
|
}
|
|
33742
33838
|
moved += await relocateTree(
|
|
33743
|
-
|
|
33744
|
-
|
|
33839
|
+
resolve47(oldRoot, "public"),
|
|
33840
|
+
resolve47(dataRoot, "accounts", installAccountId, "uploads", "public"),
|
|
33745
33841
|
dataRoot,
|
|
33746
33842
|
null,
|
|
33747
33843
|
// public uploads carry no graph nodes
|
|
@@ -33775,7 +33871,7 @@ init_pin_validator();
|
|
|
33775
33871
|
init_account();
|
|
33776
33872
|
init_neo4j_store();
|
|
33777
33873
|
import { readdir as readdir7, readFile as readFile12, rename as rename5, writeFile as writeFile5, unlink as unlink4 } from "fs/promises";
|
|
33778
|
-
import { existsSync as
|
|
33874
|
+
import { existsSync as existsSync49 } from "fs";
|
|
33779
33875
|
import { join as join58 } from "path";
|
|
33780
33876
|
var ADMIN_ROLE2 = "admin";
|
|
33781
33877
|
var WEBCHAT_CHANNEL2 = "webchat";
|
|
@@ -33805,7 +33901,7 @@ async function writeRaw(path, obj) {
|
|
|
33805
33901
|
await rename5(tmp, path);
|
|
33806
33902
|
} catch (err) {
|
|
33807
33903
|
try {
|
|
33808
|
-
if (
|
|
33904
|
+
if (existsSync49(tmp)) await unlink4(tmp);
|
|
33809
33905
|
} catch {
|
|
33810
33906
|
}
|
|
33811
33907
|
throw err;
|
|
@@ -33929,7 +34025,7 @@ async function migrateAdminWebchatSidecars(opts = {}) {
|
|
|
33929
34025
|
// app/lib/migrate-sidecar-account-ids.ts
|
|
33930
34026
|
init_account();
|
|
33931
34027
|
import { readdir as readdir8, readFile as readFile13, rename as rename6, writeFile as writeFile6, unlink as unlink5 } from "fs/promises";
|
|
33932
|
-
import { existsSync as
|
|
34028
|
+
import { existsSync as existsSync50 } from "fs";
|
|
33933
34029
|
import { join as join59 } from "path";
|
|
33934
34030
|
var SESSION_META_RE2 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\.meta\.json$/i;
|
|
33935
34031
|
function projectSlugForCwd(cwd) {
|
|
@@ -33956,7 +34052,7 @@ async function writeRaw2(path, obj) {
|
|
|
33956
34052
|
await rename6(tmp, path);
|
|
33957
34053
|
} catch (err) {
|
|
33958
34054
|
try {
|
|
33959
|
-
if (
|
|
34055
|
+
if (existsSync50(tmp)) await unlink5(tmp);
|
|
33960
34056
|
} catch {
|
|
33961
34057
|
}
|
|
33962
34058
|
throw err;
|
|
@@ -35538,7 +35634,7 @@ function createWebchatChannelRoutes(deps) {
|
|
|
35538
35634
|
}
|
|
35539
35635
|
|
|
35540
35636
|
// app/lib/webchat/gateway/resolve-turn-answer.ts
|
|
35541
|
-
import { existsSync as
|
|
35637
|
+
import { existsSync as existsSync51, openSync as openSync9, readSync as readSync8, closeSync as closeSync9, readdirSync as readdirSync31 } from "fs";
|
|
35542
35638
|
import { join as join60 } from "path";
|
|
35543
35639
|
function resolveTurnAnswer(p) {
|
|
35544
35640
|
if (!SESSION_ID_RE2.test(p.sessionId)) return "";
|
|
@@ -35567,7 +35663,7 @@ function resolveTurnAnswer(p) {
|
|
|
35567
35663
|
return segmentText(parts.join("\n\n")).join("\n\n");
|
|
35568
35664
|
}
|
|
35569
35665
|
function findJsonl(projectsRoot, sessionId) {
|
|
35570
|
-
if (!
|
|
35666
|
+
if (!existsSync51(projectsRoot)) return null;
|
|
35571
35667
|
let slugs;
|
|
35572
35668
|
try {
|
|
35573
35669
|
slugs = readdirSync31(projectsRoot, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
|
|
@@ -35576,7 +35672,7 @@ function findJsonl(projectsRoot, sessionId) {
|
|
|
35576
35672
|
}
|
|
35577
35673
|
for (const slug of slugs) {
|
|
35578
35674
|
const live = join60(projectsRoot, slug, `${sessionId}.jsonl`);
|
|
35579
|
-
if (
|
|
35675
|
+
if (existsSync51(live)) return live;
|
|
35580
35676
|
}
|
|
35581
35677
|
return null;
|
|
35582
35678
|
}
|
|
@@ -35644,16 +35740,16 @@ var WebchatGateway = class _WebchatGateway {
|
|
|
35644
35740
|
* The public /api/chat route awaits this to return the reply on the same SSE
|
|
35645
35741
|
* response, preserving the pre-756 POST→single-blob browser contract. */
|
|
35646
35742
|
awaitReply(key2, timeoutMs) {
|
|
35647
|
-
return new Promise((
|
|
35743
|
+
return new Promise((resolve53) => {
|
|
35648
35744
|
const timer = setTimeout(() => {
|
|
35649
35745
|
this.replyAwaiters.delete(key2);
|
|
35650
|
-
|
|
35746
|
+
resolve53({ timeout: true });
|
|
35651
35747
|
}, timeoutMs);
|
|
35652
35748
|
if (timer.unref) timer.unref();
|
|
35653
35749
|
this.replyAwaiters.set(key2, (r) => {
|
|
35654
35750
|
clearTimeout(timer);
|
|
35655
35751
|
this.replyAwaiters.delete(key2);
|
|
35656
|
-
|
|
35752
|
+
resolve53(r);
|
|
35657
35753
|
});
|
|
35658
35754
|
});
|
|
35659
35755
|
}
|
|
@@ -35664,11 +35760,11 @@ var WebchatGateway = class _WebchatGateway {
|
|
|
35664
35760
|
* terminal dialog stays answerable). */
|
|
35665
35761
|
awaitPermissionVerdict(p, timeoutMs) {
|
|
35666
35762
|
const k = _WebchatGateway.promptKey(p.key, p.requestId);
|
|
35667
|
-
return new Promise((
|
|
35763
|
+
return new Promise((resolve53) => {
|
|
35668
35764
|
this.pendingPrompts.get(k)?.resolve({ timeout: true });
|
|
35669
35765
|
const timer = setTimeout(() => {
|
|
35670
35766
|
this.pendingPrompts.delete(k);
|
|
35671
|
-
|
|
35767
|
+
resolve53({ timeout: true });
|
|
35672
35768
|
}, timeoutMs);
|
|
35673
35769
|
if (timer.unref) timer.unref();
|
|
35674
35770
|
this.pendingPrompts.set(k, {
|
|
@@ -35678,7 +35774,7 @@ var WebchatGateway = class _WebchatGateway {
|
|
|
35678
35774
|
clearTimeout(timer);
|
|
35679
35775
|
this.pendingPrompts.delete(k);
|
|
35680
35776
|
this.deps.onPointerChange?.(p.key);
|
|
35681
|
-
|
|
35777
|
+
resolve53(r);
|
|
35682
35778
|
}
|
|
35683
35779
|
});
|
|
35684
35780
|
console.error(`[webchat:perm] op=open key=${keyDisplay(p.key)} id=${p.requestId} tool=${p.toolName}`);
|
|
@@ -36459,7 +36555,7 @@ function parityCensusLines() {
|
|
|
36459
36555
|
|
|
36460
36556
|
// app/lib/webchat/file-delivery.ts
|
|
36461
36557
|
import { realpathSync as realpathSync9 } from "fs";
|
|
36462
|
-
import { resolve as
|
|
36558
|
+
import { resolve as resolve48 } from "path";
|
|
36463
36559
|
|
|
36464
36560
|
// app/lib/channel-pty-bridge/file-delivery.ts
|
|
36465
36561
|
var SEND_USER_FILE = "SendUserFile";
|
|
@@ -36560,7 +36656,7 @@ function makeWebchatSendFile(entry2) {
|
|
|
36560
36656
|
console.error(`${TAG58} file-delivery reject reason=no-account sender=${entry2.senderId}`);
|
|
36561
36657
|
return { ok: false, error: "no-account" };
|
|
36562
36658
|
}
|
|
36563
|
-
const accountDir =
|
|
36659
|
+
const accountDir = resolve48(platformRoot2(), "..", "data/accounts", entry2.accountId);
|
|
36564
36660
|
try {
|
|
36565
36661
|
const resolved = realpathSync9(filePath);
|
|
36566
36662
|
const accountResolved = realpathSync9(accountDir);
|
|
@@ -37363,7 +37459,7 @@ function buildTelegramEnsureSession(deps) {
|
|
|
37363
37459
|
init_attachments();
|
|
37364
37460
|
import { realpathSync as realpathSync10 } from "fs";
|
|
37365
37461
|
import { readFile as readFile14, stat as stat10 } from "fs/promises";
|
|
37366
|
-
import { resolve as
|
|
37462
|
+
import { resolve as resolve49, basename as basename16 } from "path";
|
|
37367
37463
|
var TAG61 = "[telegram:outbound]";
|
|
37368
37464
|
var TELEGRAM_DOCUMENT_MAX_BYTES = 50 * 1024 * 1024;
|
|
37369
37465
|
async function sendTelegramDocument(input) {
|
|
@@ -37374,7 +37470,7 @@ async function sendTelegramDocument(input) {
|
|
|
37374
37470
|
if (!maxyAccountId || !platformRoot5) {
|
|
37375
37471
|
return { ok: false, status: 400, error: "Cannot validate file path: missing account or platform context" };
|
|
37376
37472
|
}
|
|
37377
|
-
const accountDir =
|
|
37473
|
+
const accountDir = resolve49(platformRoot5, "..", "data/accounts", maxyAccountId);
|
|
37378
37474
|
let accountResolved;
|
|
37379
37475
|
try {
|
|
37380
37476
|
accountResolved = realpathSync10(accountDir);
|
|
@@ -37962,7 +38058,7 @@ function* walkTelegramSidecars() {
|
|
|
37962
38058
|
}
|
|
37963
38059
|
|
|
37964
38060
|
// server/telegram-migrate.ts
|
|
37965
|
-
import { readFileSync as readFileSync52, writeFileSync as writeFileSync19, existsSync as
|
|
38061
|
+
import { readFileSync as readFileSync52, writeFileSync as writeFileSync19, existsSync as existsSync52, renameSync as renameSync11, mkdirSync as mkdirSync11 } from "fs";
|
|
37966
38062
|
import { dirname as dirname18, join as join62 } from "path";
|
|
37967
38063
|
function migrateTelegramTwoSlot(input) {
|
|
37968
38064
|
const out = [];
|
|
@@ -38023,7 +38119,7 @@ function migrateTelegramTwoSlot(input) {
|
|
|
38023
38119
|
return out;
|
|
38024
38120
|
}
|
|
38025
38121
|
function moveSecret(from, to) {
|
|
38026
|
-
if (!
|
|
38122
|
+
if (!existsSync52(from)) return;
|
|
38027
38123
|
mkdirSync11(dirname18(to), { recursive: true, mode: 448 });
|
|
38028
38124
|
renameSync11(from, to);
|
|
38029
38125
|
}
|
|
@@ -38072,12 +38168,12 @@ function backfillMisfiledRecords(params) {
|
|
|
38072
38168
|
init_message_store();
|
|
38073
38169
|
|
|
38074
38170
|
// server/lib/booking-site-accounts.ts
|
|
38075
|
-
import { existsSync as
|
|
38076
|
-
import { resolve as
|
|
38171
|
+
import { existsSync as existsSync53, readFileSync as readFileSync53 } from "fs";
|
|
38172
|
+
import { resolve as resolve50 } from "path";
|
|
38077
38173
|
function listBookingSiteAccounts(accounts) {
|
|
38078
38174
|
return accounts.filter((a) => {
|
|
38079
|
-
const availPath =
|
|
38080
|
-
if (!
|
|
38175
|
+
const availPath = resolve50(a.accountDir, "calendar-availability.json");
|
|
38176
|
+
if (!existsSync53(availPath)) return false;
|
|
38081
38177
|
try {
|
|
38082
38178
|
const cfg = JSON.parse(readFileSync53(availPath, "utf-8"));
|
|
38083
38179
|
return typeof cfg.bookingDbName === "string" && cfg.bookingDbName.length > 0;
|
|
@@ -38124,8 +38220,8 @@ init_paths();
|
|
|
38124
38220
|
|
|
38125
38221
|
// ../lib/entitlement/src/index.ts
|
|
38126
38222
|
import { createPublicKey, createHash as createHash7, verify as cryptoVerify } from "crypto";
|
|
38127
|
-
import { existsSync as
|
|
38128
|
-
import { resolve as
|
|
38223
|
+
import { existsSync as existsSync54, readFileSync as readFileSync54, statSync as statSync29 } from "fs";
|
|
38224
|
+
import { resolve as resolve51 } from "path";
|
|
38129
38225
|
|
|
38130
38226
|
// ../lib/entitlement/src/canonicalize.ts
|
|
38131
38227
|
function canonicalize(value) {
|
|
@@ -38160,7 +38256,7 @@ var PUBKEY_SHA256 = "8eee6bcb33545fd13b16d3199a5735ca5db5062834c7b49dfe4f23801d9
|
|
|
38160
38256
|
var GRACE_DAYS = 7;
|
|
38161
38257
|
var GRACE_MS = GRACE_DAYS * 24 * 60 * 60 * 1e3;
|
|
38162
38258
|
function pubkeyPath(brand) {
|
|
38163
|
-
return
|
|
38259
|
+
return resolve51(brand.platformRoot, "lib", "entitlement", "rubytech-pubkey.pem");
|
|
38164
38260
|
}
|
|
38165
38261
|
var memo = null;
|
|
38166
38262
|
function memoKey(mtimeMs, account) {
|
|
@@ -38172,8 +38268,8 @@ function resolveEntitlement(brand, account) {
|
|
|
38172
38268
|
if (brand.commercialMode !== true) {
|
|
38173
38269
|
return logResolved(implicitTrust(account), null);
|
|
38174
38270
|
}
|
|
38175
|
-
const entitlementPath =
|
|
38176
|
-
if (!
|
|
38271
|
+
const entitlementPath = resolve51(brand.configDir, "entitlement.json");
|
|
38272
|
+
if (!existsSync54(entitlementPath)) {
|
|
38177
38273
|
return logResolved(anonymousFallback("missing"), { reason: "missing" });
|
|
38178
38274
|
}
|
|
38179
38275
|
const stat11 = statSync29(entitlementPath);
|
|
@@ -38366,10 +38462,10 @@ installMediaDownloadGuard();
|
|
|
38366
38462
|
var PLATFORM_ROOT6 = process.env.MAXY_PLATFORM_ROOT || "";
|
|
38367
38463
|
var BRAND_JSON_PATH = PLATFORM_ROOT6 ? join63(PLATFORM_ROOT6, "config", "brand.json") : "";
|
|
38368
38464
|
var BRAND = { productName: "Maxy", hostname: "maxy", configDir: ".maxy", marketingUrl: "https://getmaxy.com" };
|
|
38369
|
-
if (BRAND_JSON_PATH && !
|
|
38465
|
+
if (BRAND_JSON_PATH && !existsSync55(BRAND_JSON_PATH)) {
|
|
38370
38466
|
console.error(`[brand] WARNING: brand.json not found at ${BRAND_JSON_PATH} \u2014 using Maxy defaults`);
|
|
38371
38467
|
}
|
|
38372
|
-
if (BRAND_JSON_PATH &&
|
|
38468
|
+
if (BRAND_JSON_PATH && existsSync55(BRAND_JSON_PATH)) {
|
|
38373
38469
|
try {
|
|
38374
38470
|
const parsed = JSON.parse(readFileSync55(BRAND_JSON_PATH, "utf-8"));
|
|
38375
38471
|
BRAND = { ...BRAND, ...parsed };
|
|
@@ -38406,7 +38502,7 @@ var brandLoginOpts = {
|
|
|
38406
38502
|
var ALIAS_DOMAINS_PATH = join63(homedir5(), BRAND.configDir, "alias-domains.json");
|
|
38407
38503
|
function loadAliasDomains() {
|
|
38408
38504
|
try {
|
|
38409
|
-
if (!
|
|
38505
|
+
if (!existsSync55(ALIAS_DOMAINS_PATH)) return null;
|
|
38410
38506
|
const parsed = JSON.parse(readFileSync55(ALIAS_DOMAINS_PATH, "utf-8"));
|
|
38411
38507
|
if (!Array.isArray(parsed)) {
|
|
38412
38508
|
console.error("[alias-domains] malformed alias-domains.json \u2014 expected array");
|
|
@@ -38488,13 +38584,16 @@ registerLoop({
|
|
|
38488
38584
|
return `${lines.length} session(s), ${missing} with a missing answer`;
|
|
38489
38585
|
}
|
|
38490
38586
|
});
|
|
38491
|
-
var whatsappFanTargets = (accountId, senderId) =>
|
|
38492
|
-
|
|
38493
|
-
|
|
38494
|
-
|
|
38495
|
-
|
|
38496
|
-
|
|
38497
|
-
})
|
|
38587
|
+
var whatsappFanTargets = (accountId, senderId) => {
|
|
38588
|
+
warnNonUuidAccount("fan-out", accountId);
|
|
38589
|
+
return adminFanTargets({
|
|
38590
|
+
origin: "whatsapp",
|
|
38591
|
+
originKey: senderId,
|
|
38592
|
+
accountId,
|
|
38593
|
+
adminUserId: resolveAdminUserId({ accountId, senderPhone: senderId }),
|
|
38594
|
+
deps: adminFanDeps("whatsapp", accountId)
|
|
38595
|
+
});
|
|
38596
|
+
};
|
|
38498
38597
|
var waGateway = new WaGateway({
|
|
38499
38598
|
fetchStandingRules: fetchAccountStandingRules,
|
|
38500
38599
|
// Task 2321 — the account's own `## Instruction` body, read from that
|
|
@@ -38521,7 +38620,7 @@ var waGateway = new WaGateway({
|
|
|
38521
38620
|
// resolver and `fanTargetsFor` is a constructor dep, not a callable method.
|
|
38522
38621
|
fanTargetsFor: whatsappFanTargets,
|
|
38523
38622
|
gatewayUrl: `http://127.0.0.1:${process.env.MAXY_UI_INTERNAL_PORT ?? ""}`,
|
|
38524
|
-
serverPath: process.env.MAXY_WA_CHANNEL_SERVER_PATH ??
|
|
38623
|
+
serverPath: process.env.MAXY_WA_CHANNEL_SERVER_PATH ?? resolve52(process.env.MAXY_PLATFORM_ROOT ?? join63(__dirname, ".."), "services/whatsapp-channel/dist/server.js"),
|
|
38525
38624
|
// Task 751 / 1390 — file delivery on the native channel. `maxyAccountId` (the
|
|
38526
38625
|
// path-validation scope) is the sender's effective SESSION account, resolved
|
|
38527
38626
|
// once at the inbound gate and threaded here via the gateway's per-sender doc
|
|
@@ -38536,7 +38635,7 @@ var waGateway = new WaGateway({
|
|
|
38536
38635
|
caption,
|
|
38537
38636
|
accountId,
|
|
38538
38637
|
maxyAccountId,
|
|
38539
|
-
platformRoot:
|
|
38638
|
+
platformRoot: resolve52(process.env.MAXY_PLATFORM_ROOT ?? join63(__dirname, ".."))
|
|
38540
38639
|
});
|
|
38541
38640
|
return result.ok ? { ok: true, messageId: result.messageId } : { ok: false, error: result.error };
|
|
38542
38641
|
},
|
|
@@ -38686,7 +38785,12 @@ var waGateway = new WaGateway({
|
|
|
38686
38785
|
role,
|
|
38687
38786
|
// Task 2521 — resolved per answer, not captured once, so a door that goes
|
|
38688
38787
|
// live after this session started still receives.
|
|
38689
|
-
|
|
38788
|
+
// Task 2531 — `effectiveAccountId`, NOT `accountId`. The reply map is
|
|
38789
|
+
// keyed on the platform UUID (wa-gateway.ts:567) while `accountId` here is
|
|
38790
|
+
// the Baileys credential dirname (see the Task 1850 note above). Passing
|
|
38791
|
+
// the dirname missed every lookup and delivered session 8e5bc4e8's answer
|
|
38792
|
+
// to nothing. `accountId` stays correct on line 718: that is the socket.
|
|
38793
|
+
fanTargets: () => whatsappFanTargets(effectiveAccountId, senderId),
|
|
38690
38794
|
onClose: () => {
|
|
38691
38795
|
if (nativeFileFollowers.get(senderId) === ac) nativeFileFollowers.delete(senderId);
|
|
38692
38796
|
}
|
|
@@ -39342,13 +39446,13 @@ app80.get("/agent-assets/:slug/:filename", (c) => {
|
|
|
39342
39446
|
console.error(`[agent-assets] no-account slug=${slug} file=${filename}`);
|
|
39343
39447
|
return c.text("Not found", 404);
|
|
39344
39448
|
}
|
|
39345
|
-
const filePath =
|
|
39346
|
-
const expectedDir =
|
|
39449
|
+
const filePath = resolve52(account.accountDir, "agents", slug, "assets", filename);
|
|
39450
|
+
const expectedDir = resolve52(account.accountDir, "agents", slug, "assets");
|
|
39347
39451
|
if (!filePath.startsWith(expectedDir + "/")) {
|
|
39348
39452
|
console.error(`[agent-assets] path-traversal-rejected slug=${slug} file=${filename}`);
|
|
39349
39453
|
return c.text("Forbidden", 403);
|
|
39350
39454
|
}
|
|
39351
|
-
if (!
|
|
39455
|
+
if (!existsSync55(filePath)) {
|
|
39352
39456
|
console.error(`[agent-assets] serve slug=${slug} file=${filename} status=404`);
|
|
39353
39457
|
return c.text("Not found", 404);
|
|
39354
39458
|
}
|
|
@@ -39372,13 +39476,13 @@ app80.get("/generated/:filename", (c) => {
|
|
|
39372
39476
|
console.error(`[generated] serve file=${filename} status=404`);
|
|
39373
39477
|
return c.text("Not found", 404);
|
|
39374
39478
|
}
|
|
39375
|
-
const filePath =
|
|
39376
|
-
const expectedDir =
|
|
39479
|
+
const filePath = resolve52(account.accountDir, "generated", filename);
|
|
39480
|
+
const expectedDir = resolve52(account.accountDir, "generated");
|
|
39377
39481
|
if (!filePath.startsWith(expectedDir + "/")) {
|
|
39378
39482
|
console.error(`[generated] serve file=${filename} status=403`);
|
|
39379
39483
|
return c.text("Forbidden", 403);
|
|
39380
39484
|
}
|
|
39381
|
-
if (!
|
|
39485
|
+
if (!existsSync55(filePath)) {
|
|
39382
39486
|
console.error(`[generated] serve file=${filename} status=404`);
|
|
39383
39487
|
return c.text("Not found", 404);
|
|
39384
39488
|
}
|
|
@@ -39398,7 +39502,7 @@ app80.route("/v", visitor_consent_default);
|
|
|
39398
39502
|
var htmlCache = /* @__PURE__ */ new Map();
|
|
39399
39503
|
var brandLogoPath = "/brand/maxy-monochrome.png";
|
|
39400
39504
|
var brandIconPath = "/brand/maxy-monochrome.png";
|
|
39401
|
-
if (BRAND_JSON_PATH &&
|
|
39505
|
+
if (BRAND_JSON_PATH && existsSync55(BRAND_JSON_PATH)) {
|
|
39402
39506
|
try {
|
|
39403
39507
|
const fullBrand = JSON.parse(readFileSync55(BRAND_JSON_PATH, "utf-8"));
|
|
39404
39508
|
if (fullBrand.assets?.logo) brandLogoPath = `/brand/${fullBrand.assets.logo}`;
|
|
@@ -39427,11 +39531,11 @@ var brandScript = `<script>window.__BRAND__=${JSON.stringify({
|
|
|
39427
39531
|
var brandThemeColor = BRAND.defaultColors?.primary ?? "#000000";
|
|
39428
39532
|
var brandBackgroundColor = BRAND.defaultColors?.background ?? "#ffffff";
|
|
39429
39533
|
var brandAppIconsExist = [brandAppIcon192Path, brandAppIcon512Path, brandMaskableIconPath].every(
|
|
39430
|
-
(p) =>
|
|
39534
|
+
(p) => existsSync55(resolve52(process.cwd(), "public", p.replace(/^\//, "")))
|
|
39431
39535
|
);
|
|
39432
39536
|
var SW_SOURCE = (() => {
|
|
39433
39537
|
try {
|
|
39434
|
-
return readFileSync55(
|
|
39538
|
+
return readFileSync55(resolve52(process.cwd(), "public", "sw.js"), "utf-8");
|
|
39435
39539
|
} catch {
|
|
39436
39540
|
return null;
|
|
39437
39541
|
}
|
|
@@ -39440,7 +39544,7 @@ function readInstalledVersion() {
|
|
|
39440
39544
|
try {
|
|
39441
39545
|
if (!PLATFORM_ROOT6) return "unknown";
|
|
39442
39546
|
const versionFile = join63(PLATFORM_ROOT6, "config", `.${BRAND.hostname}-version`);
|
|
39443
|
-
if (!
|
|
39547
|
+
if (!existsSync55(versionFile)) return "unknown";
|
|
39444
39548
|
const content = readFileSync55(versionFile, "utf-8").trim();
|
|
39445
39549
|
return content || "unknown";
|
|
39446
39550
|
} catch {
|
|
@@ -39452,7 +39556,7 @@ var versionScript = `<script>window.__MAXY_VERSION__=${JSON.stringify(INSTALLED_
|
|
|
39452
39556
|
function cachedHtml(file) {
|
|
39453
39557
|
let html = htmlCache.get(file);
|
|
39454
39558
|
if (!html) {
|
|
39455
|
-
html = readFileSync55(
|
|
39559
|
+
html = readFileSync55(resolve52(process.cwd(), "public", file), "utf-8");
|
|
39456
39560
|
const productNameEsc = escapeHtml(BRAND.productName);
|
|
39457
39561
|
html = html.replace(/<title>([^<]*)<\/title>/, (_match, inner) => `<title>${escapeHtml(inner).replace(/Maxy/g, productNameEsc)}</title>`);
|
|
39458
39562
|
html = html.replace('href="/favicon.ico"', `href="${escapeHtml(brandFaviconPath)}"`);
|
|
@@ -39475,7 +39579,7 @@ function loadBrandingCache(agentSlug) {
|
|
|
39475
39579
|
const accountId = verdict.kind === "served" ? verdict.owner.accountId : getDefaultAccountId();
|
|
39476
39580
|
if (!accountId) return null;
|
|
39477
39581
|
const cachePath = join63(configDir, "branding-cache", accountId, `${agentSlug}.json`);
|
|
39478
|
-
if (!
|
|
39582
|
+
if (!existsSync55(cachePath)) return null;
|
|
39479
39583
|
return JSON.parse(readFileSync55(cachePath, "utf-8"));
|
|
39480
39584
|
} catch {
|
|
39481
39585
|
return null;
|
|
@@ -39571,7 +39675,7 @@ app80.use("/vnc-popout.html", logViewerFetch);
|
|
|
39571
39675
|
app80.get("/vnc-popout.html", (c) => {
|
|
39572
39676
|
let html = htmlCache.get("vnc-popout.html");
|
|
39573
39677
|
if (!html) {
|
|
39574
|
-
html = readFileSync55(
|
|
39678
|
+
html = readFileSync55(resolve52(process.cwd(), "public", "vnc-popout.html"), "utf-8");
|
|
39575
39679
|
const name = escapeHtml(BRAND.productName);
|
|
39576
39680
|
html = html.replace("<title>Browser \u2014 Maxy</title>", `<title>${name}</title>`);
|
|
39577
39681
|
html = html.replace("</head>", ` ${brandScript}
|
|
@@ -39731,9 +39835,9 @@ var httpServer = serve({ fetch: app80.fetch, port, hostname });
|
|
|
39731
39835
|
console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
39732
39836
|
{
|
|
39733
39837
|
const reconcilePlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join63(__dirname, "..");
|
|
39734
|
-
const reconcileScript =
|
|
39838
|
+
const reconcileScript = resolve52(reconcilePlatformRoot, "plugins/scheduling/mcp/dist/scripts/reconcile-bookings.js");
|
|
39735
39839
|
const runReconcile = (ctx) => {
|
|
39736
|
-
if (!
|
|
39840
|
+
if (!existsSync55(reconcileScript)) return;
|
|
39737
39841
|
try {
|
|
39738
39842
|
const child = spawn3(process.execPath, [reconcileScript], {
|
|
39739
39843
|
env: { ...process.env, PLATFORM_ROOT: reconcilePlatformRoot },
|
|
@@ -39772,14 +39876,14 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
39772
39876
|
{
|
|
39773
39877
|
const DREAM_CYCLE_SWEEP_INTERVAL_MS = 36e5;
|
|
39774
39878
|
const dreamPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join63(__dirname, "..");
|
|
39775
|
-
const dreamSweepScript =
|
|
39879
|
+
const dreamSweepScript = resolve52(dreamPlatformRoot, "plugins/memory/mcp/dist/scripts/dream-cycle-sweep.js");
|
|
39776
39880
|
registerLoop({
|
|
39777
39881
|
name: "dream-cycle-sweep",
|
|
39778
39882
|
intervalMs: DREAM_CYCLE_SWEEP_INTERVAL_MS,
|
|
39779
39883
|
firstRunDelayMs: 3e4,
|
|
39780
39884
|
detached: true,
|
|
39781
39885
|
run: (ctx) => {
|
|
39782
|
-
if (!
|
|
39886
|
+
if (!existsSync55(dreamSweepScript)) return;
|
|
39783
39887
|
try {
|
|
39784
39888
|
const child = spawn3(process.execPath, [dreamSweepScript], {
|
|
39785
39889
|
env: { ...process.env, PLATFORM_ROOT: dreamPlatformRoot },
|
|
@@ -39796,10 +39900,10 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
39796
39900
|
}
|
|
39797
39901
|
{
|
|
39798
39902
|
const outlookPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join63(__dirname, "..");
|
|
39799
|
-
const outlookScript =
|
|
39903
|
+
const outlookScript = resolve52(outlookPlatformRoot, "plugins/outlook/mcp/dist/scripts/complete-registration.js");
|
|
39800
39904
|
const OUTLOOK_COMPLETE_INTERVAL_MS = 3e4;
|
|
39801
39905
|
const runOutlookComplete = (ctx) => {
|
|
39802
|
-
if (!
|
|
39906
|
+
if (!existsSync55(outlookScript)) return;
|
|
39803
39907
|
try {
|
|
39804
39908
|
const child = spawn3(process.execPath, [outlookScript], {
|
|
39805
39909
|
env: { ...process.env, PLATFORM_ROOT: outlookPlatformRoot },
|
|
@@ -39822,18 +39926,18 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
39822
39926
|
}
|
|
39823
39927
|
{
|
|
39824
39928
|
const auditRoot = process.env.MAXY_PLATFORM_ROOT ?? join63(__dirname, "..");
|
|
39825
|
-
const strandedAccountsDir =
|
|
39929
|
+
const strandedAccountsDir = resolve52(auditRoot, "..", "data/accounts");
|
|
39826
39930
|
const STRANDED_AUDIT_INTERVAL_MS = 3e5;
|
|
39827
39931
|
const STRANDED_AGE_MS = 16 * 6e4;
|
|
39828
39932
|
const STRANDED_UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
39829
39933
|
const runStrandedAudit = () => {
|
|
39830
39934
|
try {
|
|
39831
|
-
if (!
|
|
39935
|
+
if (!existsSync55(strandedAccountsDir)) return;
|
|
39832
39936
|
const now = Date.now();
|
|
39833
39937
|
for (const name of readdirSync32(strandedAccountsDir)) {
|
|
39834
39938
|
if (!STRANDED_UUID_RE.test(name)) continue;
|
|
39835
|
-
const pendingPath2 =
|
|
39836
|
-
if (!
|
|
39939
|
+
const pendingPath2 = resolve52(strandedAccountsDir, name, "secrets/outlook/pending-devicecode.enc");
|
|
39940
|
+
if (!existsSync55(pendingPath2)) continue;
|
|
39837
39941
|
const ageMs2 = now - statSync30(pendingPath2).mtimeMs;
|
|
39838
39942
|
if (ageMs2 > STRANDED_AGE_MS) {
|
|
39839
39943
|
console.error(`[outlook-mcp] devicecode-stranded account=${name} ageSec=${Math.floor(ageMs2 / 1e3)}`);
|
|
@@ -39852,7 +39956,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
39852
39956
|
}
|
|
39853
39957
|
{
|
|
39854
39958
|
const googleRoot = process.env.MAXY_PLATFORM_ROOT ?? join63(__dirname, "..");
|
|
39855
|
-
const googleAccountsDir =
|
|
39959
|
+
const googleAccountsDir = resolve52(googleRoot, "..", "data/accounts");
|
|
39856
39960
|
const GOOGLE_PENDING_AUDIT_INTERVAL_MS = 3e5;
|
|
39857
39961
|
const runGooglePendingAuditSafe = () => {
|
|
39858
39962
|
try {
|
|
@@ -39867,10 +39971,10 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
39867
39971
|
firstRunDelayMs: 27e3,
|
|
39868
39972
|
run: runGooglePendingAuditSafe
|
|
39869
39973
|
});
|
|
39870
|
-
const googleAuditScript =
|
|
39974
|
+
const googleAuditScript = resolve52(googleRoot, "plugins/google/mcp/dist/scripts/account-audit.js");
|
|
39871
39975
|
const GOOGLE_ACCOUNT_AUDIT_INTERVAL_MS = 36e5;
|
|
39872
39976
|
const runGoogleAccountAudit = (ctx) => {
|
|
39873
|
-
if (!
|
|
39977
|
+
if (!existsSync55(googleAuditScript)) return;
|
|
39874
39978
|
try {
|
|
39875
39979
|
const child = spawn3(process.execPath, [googleAuditScript], {
|
|
39876
39980
|
env: { ...process.env, PLATFORM_ROOT: googleRoot },
|
|
@@ -39930,7 +40034,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
39930
40034
|
for (const o of migrateTelegramTwoSlot({
|
|
39931
40035
|
accounts: listValidAccounts().map((a) => ({ accountId: a.accountId, accountDir: a.accountDir })),
|
|
39932
40036
|
secretPathFor: secretPath,
|
|
39933
|
-
legacySecretPathFor: (botType, accountId) =>
|
|
40037
|
+
legacySecretPathFor: (botType, accountId) => resolve52(
|
|
39934
40038
|
homedir5(),
|
|
39935
40039
|
configDirName2(),
|
|
39936
40040
|
`${botType === "admin" ? ".telegram-admin-webhook-secret" : ".telegram-webhook-secret"}.${accountId}`
|
|
@@ -39959,7 +40063,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
39959
40063
|
}
|
|
39960
40064
|
const lines = buildTelegramAuditLines({
|
|
39961
40065
|
accounts,
|
|
39962
|
-
secretFileExists: (botId) =>
|
|
40066
|
+
secretFileExists: (botId) => existsSync55(secretPath(botId)),
|
|
39963
40067
|
agentActive: isActiveAgentSlug,
|
|
39964
40068
|
secretFilesOnDisk,
|
|
39965
40069
|
lastActivityByBot: (botId) => lastByBot.get(botId) ?? null,
|
|
@@ -40098,7 +40202,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
40098
40202
|
}
|
|
40099
40203
|
{
|
|
40100
40204
|
const publishPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join63(__dirname, "..");
|
|
40101
|
-
const publishScript =
|
|
40205
|
+
const publishScript = resolve52(publishPlatformRoot, "plugins/scheduling/mcp/dist/scripts/publish-availability.js");
|
|
40102
40206
|
const PUBLISH_INTERVAL_MS = 3e5;
|
|
40103
40207
|
const bookingAccounts = () => {
|
|
40104
40208
|
try {
|
|
@@ -40109,7 +40213,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
40109
40213
|
}
|
|
40110
40214
|
};
|
|
40111
40215
|
const spawnPublish = (account, ctx) => {
|
|
40112
|
-
if (!
|
|
40216
|
+
if (!existsSync55(publishScript)) return;
|
|
40113
40217
|
try {
|
|
40114
40218
|
const child = spawn3(process.execPath, [publishScript], {
|
|
40115
40219
|
env: {
|
|
@@ -40128,19 +40232,19 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
40128
40232
|
}
|
|
40129
40233
|
};
|
|
40130
40234
|
const auditSnapshotAge = (account) => {
|
|
40131
|
-
const availPath =
|
|
40235
|
+
const availPath = resolve52(account.accountDir, "calendar-availability.json");
|
|
40132
40236
|
let hasBookingSite = false;
|
|
40133
40237
|
try {
|
|
40134
|
-
if (
|
|
40238
|
+
if (existsSync55(availPath)) {
|
|
40135
40239
|
const cfg = JSON.parse(readFileSync55(availPath, "utf-8"));
|
|
40136
40240
|
hasBookingSite = typeof cfg.bookingDbName === "string" && cfg.bookingDbName.length > 0;
|
|
40137
40241
|
}
|
|
40138
40242
|
} catch {
|
|
40139
40243
|
}
|
|
40140
40244
|
if (!hasBookingSite) return;
|
|
40141
|
-
const statePath =
|
|
40245
|
+
const statePath = resolve52(account.accountDir, "state", "booking-availability", "last-publish.json");
|
|
40142
40246
|
let lastSuccessAt = null;
|
|
40143
|
-
if (
|
|
40247
|
+
if (existsSync55(statePath)) {
|
|
40144
40248
|
try {
|
|
40145
40249
|
const rec = JSON.parse(readFileSync55(statePath, "utf-8"));
|
|
40146
40250
|
lastSuccessAt = rec.lastSuccessAt ?? null;
|
|
@@ -40178,11 +40282,11 @@ startPlannerDivergence();
|
|
|
40178
40282
|
startDispatchFieldCensus(() => getSession());
|
|
40179
40283
|
{
|
|
40180
40284
|
const auditPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join63(__dirname, "..");
|
|
40181
|
-
const auditScript =
|
|
40285
|
+
const auditScript = resolve52(auditPlatformRoot, "plugins/connector/mcp/dist/scripts/audit-connectors.js");
|
|
40182
40286
|
const auditLogDir = process.env.LOG_DIR ?? LOG_DIR;
|
|
40183
40287
|
const CONNECTOR_AUDIT_INTERVAL_MS = 3e5;
|
|
40184
40288
|
const runConnectorAudit = (ctx) => {
|
|
40185
|
-
if (!
|
|
40289
|
+
if (!existsSync55(auditScript)) return;
|
|
40186
40290
|
try {
|
|
40187
40291
|
const child = spawn3(process.execPath, [auditScript], {
|
|
40188
40292
|
env: { ...process.env, PLATFORM_ROOT: auditPlatformRoot, LOG_DIR: auditLogDir },
|
|
@@ -40304,7 +40408,7 @@ try {
|
|
|
40304
40408
|
var ADMINUSER_RECONCILE_INTERVAL_MS = 60 * 60 * 1e3;
|
|
40305
40409
|
async function runAdminUserReconcileTick() {
|
|
40306
40410
|
try {
|
|
40307
|
-
if (!
|
|
40411
|
+
if (!existsSync55(USERS_FILE)) {
|
|
40308
40412
|
console.error("[adminuser-self-heal] skip reason=no-users-file");
|
|
40309
40413
|
return;
|
|
40310
40414
|
}
|
|
@@ -40391,7 +40495,7 @@ var runIngestAuditTick = () => {
|
|
|
40391
40495
|
agentExists: (accountId, slug) => {
|
|
40392
40496
|
if (!house) return false;
|
|
40393
40497
|
const dir = isHouseAccountKey(house.accountId, accountId) ? house.accountDir : join63(ACCOUNTS_DIR, accountId);
|
|
40394
|
-
return
|
|
40498
|
+
return existsSync55(join63(dir, "agents", slug, "config.json"));
|
|
40395
40499
|
}
|
|
40396
40500
|
});
|
|
40397
40501
|
} catch (err) {
|
|
@@ -40440,7 +40544,7 @@ registerLoop({
|
|
|
40440
40544
|
houseAccountId: () => resolveAccount()?.accountId ?? null,
|
|
40441
40545
|
activeSlugs: () => listValidAccounts().map((a) => {
|
|
40442
40546
|
const agentsRoot = join63(a.accountDir, "agents");
|
|
40443
|
-
if (!
|
|
40547
|
+
if (!existsSync55(agentsRoot)) return { accountId: a.accountId, slugs: [] };
|
|
40444
40548
|
const slugs = readdirSync32(agentsRoot, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name).filter((slug) => isActiveAgentSlug(a.accountDir, slug));
|
|
40445
40549
|
return { accountId: a.accountId, slugs };
|
|
40446
40550
|
})
|
|
@@ -40454,7 +40558,7 @@ registerLoop({
|
|
|
40454
40558
|
});
|
|
40455
40559
|
var USERS_RECONCILE_INTERVAL_MS = 60 * 60 * 1e3;
|
|
40456
40560
|
function countUsersRows() {
|
|
40457
|
-
if (!
|
|
40561
|
+
if (!existsSync55(USERS_FILE)) return 0;
|
|
40458
40562
|
const raw = readFileSync55(USERS_FILE, "utf-8").trim();
|
|
40459
40563
|
if (!raw) return 0;
|
|
40460
40564
|
const users = JSON.parse(raw);
|
|
@@ -40623,7 +40727,7 @@ if (bootAccountConfig?.whatsapp) {
|
|
|
40623
40727
|
}
|
|
40624
40728
|
init({
|
|
40625
40729
|
configDir: configDirForWhatsApp,
|
|
40626
|
-
platformRoot:
|
|
40730
|
+
platformRoot: resolve52(process.env.MAXY_PLATFORM_ROOT ?? join63(__dirname, "..")),
|
|
40627
40731
|
accountConfig: bootAccountConfig,
|
|
40628
40732
|
// Task 2074 — enrich with the sub-account name and fan out to every open
|
|
40629
40733
|
// admin SSE stream. Fire-and-forget: the manager's persist path must not
|