@rubytech/create-maxy-code 0.1.439 → 0.1.441
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +41 -12
- package/payload/platform/plugins/cloudflare/skills/calendar-site/SKILL.md +15 -5
- package/payload/platform/plugins/cloudflare/skills/calendar-site/template/functions/api/calendar/free-busy.ts +152 -0
- package/payload/platform/plugins/cloudflare/skills/calendar-site/template/public/index.html +6 -3
- package/payload/platform/plugins/cloudflare/skills/calendar-site/template/schema.sql +11 -0
- package/payload/platform/plugins/docs/references/admin-identity-gate.md +32 -17
- package/payload/platform/plugins/docs/references/admin-ui.md +1 -1
- package/payload/platform/plugins/docs/references/calendar-booking.md +1 -1
- package/payload/platform/plugins/docs/references/graph.md +19 -3
- package/payload/platform/plugins/docs/references/internals.md +2 -2
- package/payload/platform/plugins/docs/references/outlook-guide.md +9 -4
- package/payload/platform/plugins/docs/references/troubleshooting.md +8 -0
- package/payload/platform/plugins/graph/.claude-plugin/plugin.json +19 -0
- package/payload/platform/plugins/graph/PLUGIN.md +10 -4
- package/payload/platform/plugins/outlook/.claude-plugin/plugin.json +1 -1
- package/payload/platform/plugins/outlook/PLUGIN.md +7 -3
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/account-register.test.js +100 -10
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/account-register.test.js.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/mail-list.test.d.ts +2 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/mail-list.test.d.ts.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/mail-list.test.js +55 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/mail-list.test.js.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/mailbox-list.test.d.ts +2 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/mailbox-list.test.d.ts.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/mailbox-list.test.js +64 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/mailbox-list.test.js.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/mailbox-registry.test.d.ts +2 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/mailbox-registry.test.d.ts.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/mailbox-registry.test.js +193 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/mailbox-registry.test.js.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/token-store.test.js +58 -1
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/token-store.test.js.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/auth/mailbox-registry.d.ts +81 -0
- package/payload/platform/plugins/outlook/mcp/dist/auth/mailbox-registry.d.ts.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/auth/mailbox-registry.js +171 -0
- package/payload/platform/plugins/outlook/mcp/dist/auth/mailbox-registry.js.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/auth/token-store.d.ts +16 -1
- package/payload/platform/plugins/outlook/mcp/dist/auth/token-store.d.ts.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/auth/token-store.js +25 -3
- package/payload/platform/plugins/outlook/mcp/dist/auth/token-store.js.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/index.js +119 -50
- package/payload/platform/plugins/outlook/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/lib/graph-client.js +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/lib/graph-client.js.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/tools/account-register.d.ts +8 -4
- package/payload/platform/plugins/outlook/mcp/dist/tools/account-register.d.ts.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/tools/account-register.js +22 -3
- package/payload/platform/plugins/outlook/mcp/dist/tools/account-register.js.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/tools/mail-list.d.ts +17 -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 +84 -21
- package/payload/platform/plugins/outlook/mcp/dist/tools/mail-list.js.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/tools/mailbox-list.d.ts +26 -0
- package/payload/platform/plugins/outlook/mcp/dist/tools/mailbox-list.d.ts.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/tools/mailbox-list.js +28 -0
- package/payload/platform/plugins/outlook/mcp/dist/tools/mailbox-list.js.map +1 -0
- package/payload/platform/plugins/outlook/references/auth.md +36 -8
- package/payload/platform/plugins/outlook/references/graph-surfaces.md +15 -1
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/publish-availability.d.ts +27 -0
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/publish-availability.d.ts.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/publish-availability.js +241 -0
- package/payload/platform/plugins/scheduling/mcp/dist/scripts/publish-availability.js.map +1 -0
- package/payload/platform/scripts/__tests__/account-schema-owned-dirs.test.sh +100 -0
- package/payload/platform/scripts/lib/account-schema-owned-dirs.py +207 -0
- package/payload/platform/scripts/lib/account-schema-owned-dirs.sh +33 -0
- package/payload/platform/scripts/lib/provision-account-dir.sh +7 -0
- package/payload/platform/scripts/setup-account.sh +10 -0
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js +1 -0
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/http-server.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/http-server.js +6 -4
- package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/tool-registration-drift.d.ts +7 -6
- package/payload/platform/services/claude-session-manager/dist/tool-registration-drift.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/tool-registration-drift.js +56 -7
- package/payload/platform/services/claude-session-manager/dist/tool-registration-drift.js.map +1 -1
- package/payload/platform/templates/specialists/agents/personal-assistant.md +1 -1
- package/payload/server/{chunk-UGPQCVIW.js → chunk-WC4WJR6X.js} +0 -6
- package/payload/server/maxy-edge.js +1 -1
- package/payload/server/public/assets/{AdminLoginScreens-DeR71H29.js → AdminLoginScreens-CukwQufW.js} +1 -1
- package/payload/server/public/assets/AdminShell-BwEBH6tT.js +2 -0
- package/payload/server/public/assets/{admin-C15h-NL0.js → admin-CdFRCUUZ.js} +1 -1
- package/payload/server/public/assets/{browser-B7xQLIRK.js → browser-BWR59IkB.js} +1 -1
- package/payload/server/public/assets/{calendar-A-vGm6pL.js → calendar-kuTcxX1t.js} +1 -1
- package/payload/server/public/assets/chat-ejnq2rck.js +1 -0
- package/payload/server/public/assets/data-dZbOyLdT.js +1 -0
- package/payload/server/public/assets/{graph-D0orIRAh.js → graph-CboWM2_-.js} +2 -2
- package/payload/server/public/assets/{operator-DZzuotDB.js → operator-oSaB1mya.js} +1 -1
- package/payload/server/public/assets/{page-Ck_pLhAk.js → page-DEkI-Gl1.js} +1 -1
- package/payload/server/public/assets/{page-3g0A19Rv.js → page-DMeJHVfA.js} +5 -5
- package/payload/server/public/assets/{public-WFUQw9AD.js → public-C54tl6V4.js} +1 -1
- package/payload/server/public/assets/{useCopyFeedback-CSk9KjhY.js → useCopyFeedback-DHoYHiK9.js} +1 -1
- package/payload/server/public/assets/{useVoiceRecorder-DCyJQkFK.js → useVoiceRecorder-b7HzTFs0.js} +1 -1
- package/payload/server/public/browser.html +2 -2
- package/payload/server/public/calendar.html +2 -2
- package/payload/server/public/chat.html +5 -5
- package/payload/server/public/data.html +3 -3
- package/payload/server/public/graph.html +3 -3
- package/payload/server/public/index.html +5 -5
- package/payload/server/public/operator.html +6 -6
- package/payload/server/public/public.html +5 -5
- package/payload/server/server.js +255 -112
- package/payload/server/public/assets/AdminShell-DlAVQUda.js +0 -2
- package/payload/server/public/assets/chat-DAae6Z51.js +0 -1
- package/payload/server/public/assets/data-BNWpKx1d.js +0 -1
package/payload/server/server.js
CHANGED
|
@@ -89,7 +89,6 @@ import {
|
|
|
89
89
|
resolveCallback,
|
|
90
90
|
resolveClientIp,
|
|
91
91
|
resolveDefaultAgentSlug,
|
|
92
|
-
retagAccountForUser,
|
|
93
92
|
runAdminUserSelfHeal,
|
|
94
93
|
runUserProfileReconcile,
|
|
95
94
|
safeJson,
|
|
@@ -111,7 +110,7 @@ import {
|
|
|
111
110
|
vncLog,
|
|
112
111
|
walkPremiumBundles,
|
|
113
112
|
writeAdminUserAndPerson
|
|
114
|
-
} from "./chunk-
|
|
113
|
+
} from "./chunk-WC4WJR6X.js";
|
|
115
114
|
import {
|
|
116
115
|
__commonJS,
|
|
117
116
|
__toESM
|
|
@@ -126,7 +125,7 @@ var require_dist = __commonJS({
|
|
|
126
125
|
exports.cosine = cosine;
|
|
127
126
|
exports.deconflictBySubject = deconflictBySubject;
|
|
128
127
|
exports.formatStandingRulesBlock = formatStandingRulesBlock2;
|
|
129
|
-
exports.resolveOwnerUserId =
|
|
128
|
+
exports.resolveOwnerUserId = resolveOwnerUserId2;
|
|
130
129
|
exports.queryActiveRuleCandidates = queryActiveRuleCandidates;
|
|
131
130
|
exports.resolveActiveRules = resolveActiveRules2;
|
|
132
131
|
exports.activeRuleSet = activeRuleSet;
|
|
@@ -166,7 +165,7 @@ var require_dist = __commonJS({
|
|
|
166
165
|
return `## Standing rules
|
|
167
166
|
${lines.join("\n")}`;
|
|
168
167
|
}
|
|
169
|
-
async function
|
|
168
|
+
async function resolveOwnerUserId2(session, accountId) {
|
|
170
169
|
const res = await session.run(`
|
|
171
170
|
MATCH (au:AdminUser {accountId: $accountId, role: 'owner'})
|
|
172
171
|
RETURN au.userId AS userId
|
|
@@ -202,7 +201,7 @@ ${lines.join("\n")}`;
|
|
|
202
201
|
async function resolveCandidates(session, accountId) {
|
|
203
202
|
let ownerUserId;
|
|
204
203
|
try {
|
|
205
|
-
ownerUserId = await
|
|
204
|
+
ownerUserId = await resolveOwnerUserId2(session, accountId);
|
|
206
205
|
} catch {
|
|
207
206
|
return { candidates: [], ownerUserId: null, source: "owner-error" };
|
|
208
207
|
}
|
|
@@ -4756,7 +4755,10 @@ function buildSelfChatDispatch(input) {
|
|
|
4756
4755
|
}),
|
|
4757
4756
|
media: [],
|
|
4758
4757
|
// Self-chat is the owner: the session scopes to the house account (Task 1383).
|
|
4759
|
-
effectiveAccountId: input.accountId
|
|
4758
|
+
effectiveAccountId: input.accountId,
|
|
4759
|
+
// Task 1575 — self-chat is unambiguously the owner, so attribute the spawn
|
|
4760
|
+
// to the owner userId even when the owner phone is unbound in users.json.
|
|
4761
|
+
ownerSelfPhone: true
|
|
4760
4762
|
};
|
|
4761
4763
|
}
|
|
4762
4764
|
async function init(opts) {
|
|
@@ -5566,7 +5568,11 @@ async function handleInboundMessage(conn, msg) {
|
|
|
5566
5568
|
replyContext: extracted.quotedMessage,
|
|
5567
5569
|
// Task 1383 — the gate's single resolution feeds the spawn (house or the
|
|
5568
5570
|
// bound sub-account); the router never re-resolves.
|
|
5569
|
-
effectiveAccountId: accessResult.effectiveAccountId
|
|
5571
|
+
effectiveAccountId: accessResult.effectiveAccountId,
|
|
5572
|
+
// Task 1575 — the gate's owner-self verdict. Only reason:'self-phone' is the
|
|
5573
|
+
// owner's own number; adminPhones/account-manager admits are other admins
|
|
5574
|
+
// and must not inherit the owner userId.
|
|
5575
|
+
ownerSelfPhone: accessResult.reason === "self-phone"
|
|
5570
5576
|
};
|
|
5571
5577
|
if (accessResult.agentType === "public") {
|
|
5572
5578
|
const hoursResult = await isBusinessOpen(conn.accountId);
|
|
@@ -8199,8 +8205,8 @@ import { readFileSync as readFileSync15, watch, statSync as statSync5, openSync,
|
|
|
8199
8205
|
import { basename as basename4, dirname as dirname4, isAbsolute, join as join15, relative as relative2, resolve as resolve12, sep as sep3 } from "path";
|
|
8200
8206
|
|
|
8201
8207
|
// server/routes/admin/sidebar-sessions.ts
|
|
8202
|
-
import { readdirSync as
|
|
8203
|
-
import { dirname as dirname3, join as
|
|
8208
|
+
import { readdirSync as readdirSync7, readFileSync as readFileSync13, statSync as statSync4 } from "fs";
|
|
8209
|
+
import { dirname as dirname3, join as join13, resolve as resolve11 } from "path";
|
|
8204
8210
|
|
|
8205
8211
|
// ../services/claude-session-manager/src/jsonl-path.ts
|
|
8206
8212
|
import { existsSync as existsSync8, readdirSync as readdirSync5 } from "fs";
|
|
@@ -8225,6 +8231,98 @@ function findExistingJsonlForSessionId(claudeConfigDir2, sessionId) {
|
|
|
8225
8231
|
return null;
|
|
8226
8232
|
}
|
|
8227
8233
|
|
|
8234
|
+
// app/lib/admin-identity/pin-validator.ts
|
|
8235
|
+
import { createHash as createHash3 } from "crypto";
|
|
8236
|
+
import { existsSync as existsSync9, readFileSync as readFileSync12, readdirSync as readdirSync6, statSync as statSync3 } from "fs";
|
|
8237
|
+
import { join as join12 } from "path";
|
|
8238
|
+
function hashPin(pin) {
|
|
8239
|
+
return createHash3("sha256").update(pin).digest("hex");
|
|
8240
|
+
}
|
|
8241
|
+
function readUsersFile(usersFilePath) {
|
|
8242
|
+
if (!existsSync9(usersFilePath)) return null;
|
|
8243
|
+
const raw = readFileSync12(usersFilePath, "utf-8").trim();
|
|
8244
|
+
if (!raw) return [];
|
|
8245
|
+
return JSON.parse(raw);
|
|
8246
|
+
}
|
|
8247
|
+
function validatePin(pin, usersFilePath) {
|
|
8248
|
+
let users;
|
|
8249
|
+
try {
|
|
8250
|
+
users = readUsersFile(usersFilePath);
|
|
8251
|
+
} catch (err) {
|
|
8252
|
+
return { kind: "corrupt", message: err instanceof Error ? err.message : String(err) };
|
|
8253
|
+
}
|
|
8254
|
+
if (users === null || users.length === 0) return { kind: "unavailable" };
|
|
8255
|
+
const inputHash = hashPin(pin);
|
|
8256
|
+
const matched = users.find((u) => u.pin === inputHash);
|
|
8257
|
+
return matched ? { kind: "match", userId: matched.userId } : { kind: "miss" };
|
|
8258
|
+
}
|
|
8259
|
+
|
|
8260
|
+
// app/lib/whatsapp/inbound/resolve-admin-userid.ts
|
|
8261
|
+
function classifyAdminUserId(users, admins, senderPhone) {
|
|
8262
|
+
const matched = users.find((u) => typeof u.phone === "string" && phonesMatch(u.phone, senderPhone));
|
|
8263
|
+
if (!matched) return { kind: "no-users-binding" };
|
|
8264
|
+
return admins.some((a) => a.userId === matched.userId) ? { kind: "resolved", userId: matched.userId } : { kind: "userid-not-admin", userId: matched.userId };
|
|
8265
|
+
}
|
|
8266
|
+
function pickAdminUserId(users, admins, senderPhone) {
|
|
8267
|
+
const r = classifyAdminUserId(users, admins, senderPhone);
|
|
8268
|
+
return r.kind === "resolved" ? r.userId : null;
|
|
8269
|
+
}
|
|
8270
|
+
function pickOwnerUserId(admins) {
|
|
8271
|
+
return admins.find((a) => a.role === "owner")?.userId ?? null;
|
|
8272
|
+
}
|
|
8273
|
+
function resolveOwnerUserId(accountId) {
|
|
8274
|
+
try {
|
|
8275
|
+
const account = listValidAccounts().find((a) => a.accountId === accountId);
|
|
8276
|
+
if (account?.config.role === "client") return null;
|
|
8277
|
+
return pickOwnerUserId(account?.config.admins ?? []);
|
|
8278
|
+
} catch {
|
|
8279
|
+
return null;
|
|
8280
|
+
}
|
|
8281
|
+
}
|
|
8282
|
+
function resolveAdminUserId(params) {
|
|
8283
|
+
try {
|
|
8284
|
+
const users = readUsersFile(USERS_FILE);
|
|
8285
|
+
if (!users) return null;
|
|
8286
|
+
const account = listValidAccounts().find((a) => a.accountId === params.accountId);
|
|
8287
|
+
if (account?.config.role === "client") return null;
|
|
8288
|
+
const admins = account?.config.admins ?? [];
|
|
8289
|
+
const direct = pickAdminUserId(users, admins, params.senderPhone);
|
|
8290
|
+
if (direct) return direct;
|
|
8291
|
+
const mapped = resolveViaLidMap(readLidMap() ?? {}, params.senderPhone);
|
|
8292
|
+
if (!mapped) return null;
|
|
8293
|
+
const viaLid = pickAdminUserId(users, admins, mapped);
|
|
8294
|
+
if (viaLid) {
|
|
8295
|
+
console.error(`[lid-map] resolved-via-cache lid=${params.senderPhone} userId=${viaLid.slice(0, 8)}`);
|
|
8296
|
+
}
|
|
8297
|
+
return viaLid;
|
|
8298
|
+
} catch {
|
|
8299
|
+
return null;
|
|
8300
|
+
}
|
|
8301
|
+
}
|
|
8302
|
+
|
|
8303
|
+
// app/lib/whatsapp-reader/resolve-operator-name.ts
|
|
8304
|
+
function resolveOperatorDisplay(userIdRes, nameRes) {
|
|
8305
|
+
if (userIdRes.kind === "no-users-binding") return { name: null, reason: "no-binding" };
|
|
8306
|
+
if (userIdRes.kind === "userid-not-admin") return { name: null, reason: "not-admin" };
|
|
8307
|
+
if (nameRes && nameRes.source === "neo4j") return { name: nameRes.joined, reason: null };
|
|
8308
|
+
if (nameRes && nameRes.reason === "neo4j-unreachable") return { name: null, reason: "neo4j-unreachable" };
|
|
8309
|
+
return { name: null, reason: "no-person-name" };
|
|
8310
|
+
}
|
|
8311
|
+
|
|
8312
|
+
// app/lib/whatsapp-reader/resolve-operator-names.ts
|
|
8313
|
+
async function resolveOperatorNamesBySender(users, admins, senderIds) {
|
|
8314
|
+
const out = /* @__PURE__ */ new Map();
|
|
8315
|
+
const distinct = [...new Set([...senderIds].filter((s) => !!s))];
|
|
8316
|
+
await Promise.all(
|
|
8317
|
+
distinct.map(async (senderId) => {
|
|
8318
|
+
const idRes = classifyAdminUserId(users, admins, senderId);
|
|
8319
|
+
const nameRes = idRes.kind === "resolved" ? await loadAdminUserName(idRes.userId) : null;
|
|
8320
|
+
out.set(senderId, resolveOperatorDisplay(idRes, nameRes));
|
|
8321
|
+
})
|
|
8322
|
+
);
|
|
8323
|
+
return out;
|
|
8324
|
+
}
|
|
8325
|
+
|
|
8228
8326
|
// server/routes/admin/sidebar-sessions.ts
|
|
8229
8327
|
var SESSION_ID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\.jsonl$/i;
|
|
8230
8328
|
function lastAssistantModel(body) {
|
|
@@ -8261,16 +8359,16 @@ function enumerateJsonls(projectsRoot) {
|
|
|
8261
8359
|
const out = [];
|
|
8262
8360
|
let slugs;
|
|
8263
8361
|
try {
|
|
8264
|
-
slugs =
|
|
8362
|
+
slugs = readdirSync7(projectsRoot, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
|
|
8265
8363
|
} catch (err) {
|
|
8266
8364
|
if (err.code === "ENOENT") return out;
|
|
8267
8365
|
throw err;
|
|
8268
8366
|
}
|
|
8269
8367
|
for (const slug of slugs) {
|
|
8270
|
-
const slugDir =
|
|
8368
|
+
const slugDir = join13(projectsRoot, slug);
|
|
8271
8369
|
let entries;
|
|
8272
8370
|
try {
|
|
8273
|
-
entries =
|
|
8371
|
+
entries = readdirSync7(slugDir, { withFileTypes: true });
|
|
8274
8372
|
} catch (err) {
|
|
8275
8373
|
const code = err.code ?? "unknown";
|
|
8276
8374
|
console.error(`[admin-sessions-list] slug-skipped slug=${slug} code=${code}`);
|
|
@@ -8278,12 +8376,12 @@ function enumerateJsonls(projectsRoot) {
|
|
|
8278
8376
|
}
|
|
8279
8377
|
for (const entry of entries) {
|
|
8280
8378
|
if (entry.isFile() && SESSION_ID_RE.test(entry.name)) {
|
|
8281
|
-
out.push({ path:
|
|
8379
|
+
out.push({ path: join13(slugDir, entry.name), isSubagent: false, archived: false });
|
|
8282
8380
|
} else if (entry.isDirectory() && entry.name === "subagents") {
|
|
8283
|
-
const subDir =
|
|
8381
|
+
const subDir = join13(slugDir, entry.name);
|
|
8284
8382
|
let subEntries;
|
|
8285
8383
|
try {
|
|
8286
|
-
subEntries =
|
|
8384
|
+
subEntries = readdirSync7(subDir, { withFileTypes: true });
|
|
8287
8385
|
} catch (err) {
|
|
8288
8386
|
const code = err.code ?? "unknown";
|
|
8289
8387
|
console.error(`[admin-sessions-list] subagents-skipped slug=${slug} code=${code}`);
|
|
@@ -8291,14 +8389,14 @@ function enumerateJsonls(projectsRoot) {
|
|
|
8291
8389
|
}
|
|
8292
8390
|
for (const sub of subEntries) {
|
|
8293
8391
|
if (sub.isFile() && SESSION_ID_RE.test(sub.name)) {
|
|
8294
|
-
out.push({ path:
|
|
8392
|
+
out.push({ path: join13(subDir, sub.name), isSubagent: true, archived: false });
|
|
8295
8393
|
}
|
|
8296
8394
|
}
|
|
8297
8395
|
} else if (entry.isDirectory() && entry.name === "archive") {
|
|
8298
|
-
const archiveDir =
|
|
8396
|
+
const archiveDir = join13(slugDir, entry.name);
|
|
8299
8397
|
let archiveEntries;
|
|
8300
8398
|
try {
|
|
8301
|
-
archiveEntries =
|
|
8399
|
+
archiveEntries = readdirSync7(archiveDir, { withFileTypes: true });
|
|
8302
8400
|
} catch (err) {
|
|
8303
8401
|
const code = err.code ?? "unknown";
|
|
8304
8402
|
console.error(`[admin-sessions-list] archive-skipped slug=${slug} code=${code}`);
|
|
@@ -8306,7 +8404,7 @@ function enumerateJsonls(projectsRoot) {
|
|
|
8306
8404
|
}
|
|
8307
8405
|
for (const arc of archiveEntries) {
|
|
8308
8406
|
if (arc.isFile() && SESSION_ID_RE.test(arc.name)) {
|
|
8309
|
-
out.push({ path:
|
|
8407
|
+
out.push({ path: join13(archiveDir, arc.name), isSubagent: false, archived: true });
|
|
8310
8408
|
}
|
|
8311
8409
|
}
|
|
8312
8410
|
}
|
|
@@ -8339,10 +8437,10 @@ async function fetchLiveSessions() {
|
|
|
8339
8437
|
function loadUserTitles(accountDir) {
|
|
8340
8438
|
const out = /* @__PURE__ */ new Map();
|
|
8341
8439
|
if (!accountDir) return out;
|
|
8342
|
-
const path2 =
|
|
8440
|
+
const path2 = join13(accountDir, "session-titles.json");
|
|
8343
8441
|
let raw;
|
|
8344
8442
|
try {
|
|
8345
|
-
raw =
|
|
8443
|
+
raw = readFileSync13(path2, "utf8");
|
|
8346
8444
|
} catch {
|
|
8347
8445
|
return out;
|
|
8348
8446
|
}
|
|
@@ -8368,7 +8466,7 @@ function readSidecarMeta(metaPath) {
|
|
|
8368
8466
|
const empty = { bridgeIds: [], role: null, channel: null, senderId: null, startedAt: null, personId: null, adminUserId: null, visitorId: null, agentSlug: null, accountId: null };
|
|
8369
8467
|
let raw;
|
|
8370
8468
|
try {
|
|
8371
|
-
raw =
|
|
8469
|
+
raw = readFileSync13(metaPath, "utf8");
|
|
8372
8470
|
} catch {
|
|
8373
8471
|
return empty;
|
|
8374
8472
|
}
|
|
@@ -8466,11 +8564,22 @@ app3.get("/", requireAdminSession, async (c) => {
|
|
|
8466
8564
|
console.error("[admin-sessions-list] CLAUDE_CONFIG_DIR not set; returning empty list");
|
|
8467
8565
|
return c.json({ sessions: [], accountId: scopeAccountId });
|
|
8468
8566
|
}
|
|
8469
|
-
const projectsRoot =
|
|
8567
|
+
const projectsRoot = join13(configDir2, "projects");
|
|
8470
8568
|
const jsonls = enumerateJsonls(projectsRoot);
|
|
8471
8569
|
const liveSessions = await fetchLiveSessions();
|
|
8472
8570
|
const accountDir = scopeAccountId ? resolve11(ACCOUNTS_DIR, scopeAccountId) : null;
|
|
8473
8571
|
const userTitles = loadUserTitles(accountDir);
|
|
8572
|
+
const account = multiAccount ? validAccounts.find((a) => a.accountId === scopeAccountId) ?? null : resolveAccount();
|
|
8573
|
+
let channelUsers = [];
|
|
8574
|
+
if (account) {
|
|
8575
|
+
try {
|
|
8576
|
+
channelUsers = readUsersFile(USERS_FILE) ?? [];
|
|
8577
|
+
} catch (err) {
|
|
8578
|
+
console.error(`[admin-sessions-list] op=users-file-unreadable reason=${err instanceof Error ? err.message : String(err)}`);
|
|
8579
|
+
channelUsers = [];
|
|
8580
|
+
}
|
|
8581
|
+
}
|
|
8582
|
+
const channelAdmins = account?.config.admins ?? [];
|
|
8474
8583
|
const rows = [];
|
|
8475
8584
|
const seenIds = /* @__PURE__ */ new Set();
|
|
8476
8585
|
let liveCount = 0;
|
|
@@ -8484,6 +8593,8 @@ app3.get("/", requireAdminSession, async (c) => {
|
|
|
8484
8593
|
const titleSourceCounts = { user: 0, ai: 0, "first-message": 0, prefix: 0 };
|
|
8485
8594
|
const personIdBySession = /* @__PURE__ */ new Map();
|
|
8486
8595
|
const adminUserIdBySession = /* @__PURE__ */ new Map();
|
|
8596
|
+
const channelSenderBySession = /* @__PURE__ */ new Map();
|
|
8597
|
+
const channelMissNoSender = [];
|
|
8487
8598
|
for (const { path: path2, isSubagent, archived } of jsonls) {
|
|
8488
8599
|
const lastSlash = path2.lastIndexOf("/");
|
|
8489
8600
|
const base = path2.slice(lastSlash + 1);
|
|
@@ -8497,8 +8608,8 @@ app3.get("/", requireAdminSession, async (c) => {
|
|
|
8497
8608
|
let body;
|
|
8498
8609
|
let mtimeMs;
|
|
8499
8610
|
try {
|
|
8500
|
-
body =
|
|
8501
|
-
mtimeMs =
|
|
8611
|
+
body = readFileSync13(path2, "utf8");
|
|
8612
|
+
mtimeMs = statSync4(path2).mtimeMs;
|
|
8502
8613
|
} catch {
|
|
8503
8614
|
continue;
|
|
8504
8615
|
}
|
|
@@ -8506,8 +8617,8 @@ app3.get("/", requireAdminSession, async (c) => {
|
|
|
8506
8617
|
const pid = live ? liveSessions.get(sessionId) ?? null : null;
|
|
8507
8618
|
const resolved = resolveTitle(body, sessionId, userTitles);
|
|
8508
8619
|
titleSourceCounts[resolved.source] += 1;
|
|
8509
|
-
const metaPath =
|
|
8510
|
-
const { bridgeIds, role, channel: sidecarChannel, personId, adminUserId, accountId: rowAccountId } = readSidecarMeta(metaPath);
|
|
8620
|
+
const metaPath = join13(projectDir, `${sessionId}.meta.json`);
|
|
8621
|
+
const { bridgeIds, role, channel: sidecarChannel, senderId, personId, adminUserId, accountId: rowAccountId } = readSidecarMeta(metaPath);
|
|
8511
8622
|
if (multiAccount) {
|
|
8512
8623
|
if (rowAccountId === null) untaggedCount += 1;
|
|
8513
8624
|
if (rowAccountId !== scopeAccountId) continue;
|
|
@@ -8539,8 +8650,13 @@ app3.get("/", requireAdminSession, async (c) => {
|
|
|
8539
8650
|
channel: sidecarChannel,
|
|
8540
8651
|
personName: null,
|
|
8541
8652
|
model: lastAssistantModel(body),
|
|
8542
|
-
accountId: rowAccountId
|
|
8653
|
+
accountId: rowAccountId,
|
|
8654
|
+
senderId
|
|
8543
8655
|
});
|
|
8656
|
+
if ((sidecarChannel === "whatsapp" || sidecarChannel === "telegram") && resolved.source === "prefix") {
|
|
8657
|
+
if (senderId) channelSenderBySession.set(sessionId, senderId);
|
|
8658
|
+
else channelMissNoSender.push({ sessionId, channel: sidecarChannel });
|
|
8659
|
+
}
|
|
8544
8660
|
if (sidecarChannel === "whatsapp") channelInList.whatsapp += 1;
|
|
8545
8661
|
else if (sidecarChannel === "telegram") channelInList.telegram += 1;
|
|
8546
8662
|
else if (sidecarChannel === "webchat") channelInList.webchat += 1;
|
|
@@ -8575,9 +8691,29 @@ app3.get("/", requireAdminSession, async (c) => {
|
|
|
8575
8691
|
})
|
|
8576
8692
|
);
|
|
8577
8693
|
}
|
|
8694
|
+
let channelNamesResolved = 0;
|
|
8695
|
+
const channelNameCandidates = channelSenderBySession.size + channelMissNoSender.length;
|
|
8696
|
+
if (account && channelSenderBySession.size > 0) {
|
|
8697
|
+
const resolvedNames = await resolveOperatorNamesBySender(channelUsers, channelAdmins, channelSenderBySession.values());
|
|
8698
|
+
for (const row of rows) {
|
|
8699
|
+
const rowSenderId = channelSenderBySession.get(row.sessionId);
|
|
8700
|
+
if (!rowSenderId) continue;
|
|
8701
|
+
const r = resolvedNames.get(rowSenderId) ?? { name: null, reason: "no-binding" };
|
|
8702
|
+
if (r.name) {
|
|
8703
|
+
row.personName = r.name;
|
|
8704
|
+
channelNamesResolved += 1;
|
|
8705
|
+
} else {
|
|
8706
|
+
const reason = r.reason === "neo4j-unreachable" ? "neo4j-down" : "classify-miss";
|
|
8707
|
+
console.error(`[admin-sessions-list] op=channel-name-unresolved sessionId=${row.sessionId.slice(0, 8)} channel=${row.channel} senderId=${rowSenderId} reason=${reason}`);
|
|
8708
|
+
}
|
|
8709
|
+
}
|
|
8710
|
+
}
|
|
8711
|
+
for (const m of channelMissNoSender) {
|
|
8712
|
+
console.error(`[admin-sessions-list] op=channel-name-unresolved sessionId=${m.sessionId.slice(0, 8)} channel=${m.channel} senderId= reason=no-senderId`);
|
|
8713
|
+
}
|
|
8578
8714
|
rows.sort((a, b) => a.startedAt < b.startedAt ? 1 : -1);
|
|
8579
8715
|
console.log(
|
|
8580
|
-
`[admin-sessions-list] rows=${rows.length} live=${liveCount} subagents=${subagentCount} archived=${archivedCount} channelInList=whatsapp:${channelInList.whatsapp},telegram:${channelInList.telegram},webchat:${channelInList.webchat} unknownChannel=${unknownChannelCount} excludedPublicWebchat=${excludedPublicWebchatCount} titles user=${titleSourceCounts.user} ai=${titleSourceCounts.ai} first=${titleSourceCounts["first-message"]} prefix=${titleSourceCounts.prefix} personNames=${personNameCount} adminNames=${adminNameCount} accountId=${scopeAccountId ? scopeAccountId.slice(0, 8) : "unset"}`
|
|
8716
|
+
`[admin-sessions-list] rows=${rows.length} live=${liveCount} subagents=${subagentCount} archived=${archivedCount} channelInList=whatsapp:${channelInList.whatsapp},telegram:${channelInList.telegram},webchat:${channelInList.webchat} channelNameCandidates=${channelNameCandidates} channelNamesResolved=${channelNamesResolved} unknownChannel=${unknownChannelCount} excludedPublicWebchat=${excludedPublicWebchatCount} titles user=${titleSourceCounts.user} ai=${titleSourceCounts.ai} first=${titleSourceCounts["first-message"]} prefix=${titleSourceCounts.prefix} personNames=${personNameCount} adminNames=${adminNameCount} accountId=${scopeAccountId ? scopeAccountId.slice(0, 8) : "unset"}`
|
|
8581
8717
|
);
|
|
8582
8718
|
console.log(
|
|
8583
8719
|
`[admin-sessions-list] accountId=${scopeAccountId ? scopeAccountId.slice(0, 8) : "unset"} scope=${multiAccount ? "scoped" : "all"} rows=${rows.length}`
|
|
@@ -8589,71 +8725,6 @@ app3.get("/", requireAdminSession, async (c) => {
|
|
|
8589
8725
|
});
|
|
8590
8726
|
var sidebar_sessions_default = app3;
|
|
8591
8727
|
|
|
8592
|
-
// app/lib/admin-identity/pin-validator.ts
|
|
8593
|
-
import { createHash as createHash3 } from "crypto";
|
|
8594
|
-
import { existsSync as existsSync9, readFileSync as readFileSync13, readdirSync as readdirSync7, statSync as statSync4 } from "fs";
|
|
8595
|
-
import { join as join13 } from "path";
|
|
8596
|
-
function hashPin(pin) {
|
|
8597
|
-
return createHash3("sha256").update(pin).digest("hex");
|
|
8598
|
-
}
|
|
8599
|
-
function readUsersFile(usersFilePath) {
|
|
8600
|
-
if (!existsSync9(usersFilePath)) return null;
|
|
8601
|
-
const raw = readFileSync13(usersFilePath, "utf-8").trim();
|
|
8602
|
-
if (!raw) return [];
|
|
8603
|
-
return JSON.parse(raw);
|
|
8604
|
-
}
|
|
8605
|
-
function validatePin(pin, usersFilePath) {
|
|
8606
|
-
let users;
|
|
8607
|
-
try {
|
|
8608
|
-
users = readUsersFile(usersFilePath);
|
|
8609
|
-
} catch (err) {
|
|
8610
|
-
return { kind: "corrupt", message: err instanceof Error ? err.message : String(err) };
|
|
8611
|
-
}
|
|
8612
|
-
if (users === null || users.length === 0) return { kind: "unavailable" };
|
|
8613
|
-
const inputHash = hashPin(pin);
|
|
8614
|
-
const matched = users.find((u) => u.pin === inputHash);
|
|
8615
|
-
return matched ? { kind: "match", userId: matched.userId } : { kind: "miss" };
|
|
8616
|
-
}
|
|
8617
|
-
|
|
8618
|
-
// app/lib/whatsapp/inbound/resolve-admin-userid.ts
|
|
8619
|
-
function classifyAdminUserId(users, admins, senderPhone) {
|
|
8620
|
-
const matched = users.find((u) => typeof u.phone === "string" && phonesMatch(u.phone, senderPhone));
|
|
8621
|
-
if (!matched) return { kind: "no-users-binding" };
|
|
8622
|
-
return admins.some((a) => a.userId === matched.userId) ? { kind: "resolved", userId: matched.userId } : { kind: "userid-not-admin", userId: matched.userId };
|
|
8623
|
-
}
|
|
8624
|
-
function pickAdminUserId(users, admins, senderPhone) {
|
|
8625
|
-
const r = classifyAdminUserId(users, admins, senderPhone);
|
|
8626
|
-
return r.kind === "resolved" ? r.userId : null;
|
|
8627
|
-
}
|
|
8628
|
-
function resolveAdminUserId(params) {
|
|
8629
|
-
try {
|
|
8630
|
-
const users = readUsersFile(USERS_FILE);
|
|
8631
|
-
if (!users) return null;
|
|
8632
|
-
const account = listValidAccounts().find((a) => a.accountId === params.accountId);
|
|
8633
|
-
const admins = account?.config.admins ?? [];
|
|
8634
|
-
const direct = pickAdminUserId(users, admins, params.senderPhone);
|
|
8635
|
-
if (direct) return direct;
|
|
8636
|
-
const mapped = resolveViaLidMap(readLidMap() ?? {}, params.senderPhone);
|
|
8637
|
-
if (!mapped) return null;
|
|
8638
|
-
const viaLid = pickAdminUserId(users, admins, mapped);
|
|
8639
|
-
if (viaLid) {
|
|
8640
|
-
console.error(`[lid-map] resolved-via-cache lid=${params.senderPhone} userId=${viaLid.slice(0, 8)}`);
|
|
8641
|
-
}
|
|
8642
|
-
return viaLid;
|
|
8643
|
-
} catch {
|
|
8644
|
-
return null;
|
|
8645
|
-
}
|
|
8646
|
-
}
|
|
8647
|
-
|
|
8648
|
-
// app/lib/whatsapp-reader/resolve-operator-name.ts
|
|
8649
|
-
function resolveOperatorDisplay(userIdRes, nameRes) {
|
|
8650
|
-
if (userIdRes.kind === "no-users-binding") return { name: null, reason: "no-binding" };
|
|
8651
|
-
if (userIdRes.kind === "userid-not-admin") return { name: null, reason: "not-admin" };
|
|
8652
|
-
if (nameRes && nameRes.source === "neo4j") return { name: nameRes.joined, reason: null };
|
|
8653
|
-
if (nameRes && nameRes.reason === "neo4j-unreachable") return { name: null, reason: "neo4j-unreachable" };
|
|
8654
|
-
return { name: null, reason: "no-person-name" };
|
|
8655
|
-
}
|
|
8656
|
-
|
|
8657
8728
|
// app/lib/agent-errors.ts
|
|
8658
8729
|
function classifyAgentError(err) {
|
|
8659
8730
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -9063,19 +9134,16 @@ app4.get("/conversations", requireAdminSession, async (c) => {
|
|
|
9063
9134
|
const admins = account?.config.admins ?? [];
|
|
9064
9135
|
const nameBySender = /* @__PURE__ */ new Map();
|
|
9065
9136
|
const distinct = [...new Set(sessionRows.map((r) => r.senderId).filter((s) => !!s))];
|
|
9066
|
-
|
|
9067
|
-
|
|
9068
|
-
|
|
9069
|
-
|
|
9070
|
-
return;
|
|
9071
|
-
}
|
|
9072
|
-
const idRes = classifyAdminUserId(users, admins, senderId);
|
|
9073
|
-
const nameRes = idRes.kind === "resolved" ? await loadAdminUserName(idRes.userId) : null;
|
|
9074
|
-
const { name, reason } = resolveOperatorDisplay(idRes, nameRes);
|
|
9137
|
+
if (account) {
|
|
9138
|
+
const resolved = await resolveOperatorNamesBySender(users, admins, distinct);
|
|
9139
|
+
for (const senderId of distinct) {
|
|
9140
|
+
const { name, reason } = resolved.get(senderId) ?? { name: null, reason: "no-binding" };
|
|
9075
9141
|
if (reason) console.error(`[wa-reader] op=operator-unresolved senderId=${senderId} reason=${reason}`);
|
|
9076
9142
|
nameBySender.set(senderId, name);
|
|
9077
|
-
}
|
|
9078
|
-
|
|
9143
|
+
}
|
|
9144
|
+
} else {
|
|
9145
|
+
for (const senderId of distinct) nameBySender.set(senderId, null);
|
|
9146
|
+
}
|
|
9079
9147
|
const sessionConversations = sessionRows.map((r) => ({
|
|
9080
9148
|
...r,
|
|
9081
9149
|
operatorName: r.senderId ? nameBySender.get(r.senderId) ?? null : null
|
|
@@ -12399,8 +12467,8 @@ app11.post("/switch-account", requireAdminSession, async (c) => {
|
|
|
12399
12467
|
const { userName, avatar } = await resolveUserIdentity(target.accountId, userId);
|
|
12400
12468
|
const payload = await createAdminSession(target.accountId, target.config.thinkingView, userId, userName, operatorRoleFor(target.config, userId), avatar);
|
|
12401
12469
|
unregisterSession(oldCacheKey);
|
|
12402
|
-
retagAccountForUser(userId, target.accountId);
|
|
12403
12470
|
console.log(`[sub-account] op=switch userId=${userId.slice(0, 8)} from=${oldCacheKey.slice(0, 8)} to=${target.accountId.slice(0, 8)}`);
|
|
12471
|
+
console.log(`[sub-account] op=rebind cacheKey=${payload.session_key.slice(0, 8)} account=${target.accountId.slice(0, 8)} siblingsTouched=0`);
|
|
12404
12472
|
return c.json(payload);
|
|
12405
12473
|
});
|
|
12406
12474
|
var session_default = app11;
|
|
@@ -22627,7 +22695,8 @@ var WaGateway = class {
|
|
|
22627
22695
|
serverPath: this.deps.serverPath,
|
|
22628
22696
|
passive: true,
|
|
22629
22697
|
text: input.text,
|
|
22630
|
-
msgId
|
|
22698
|
+
msgId,
|
|
22699
|
+
ownerSelfPhone: input.ownerSelfPhone
|
|
22631
22700
|
});
|
|
22632
22701
|
return;
|
|
22633
22702
|
}
|
|
@@ -22682,7 +22751,10 @@ var WaGateway = class {
|
|
|
22682
22751
|
gatewayUrl: this.deps.gatewayUrl,
|
|
22683
22752
|
serverPath: this.deps.serverPath,
|
|
22684
22753
|
// Task 1526 — a scheduled firing's per-firing seat id; absent on real inbound.
|
|
22685
|
-
sessionIdOverride: input.scheduledSessionId
|
|
22754
|
+
sessionIdOverride: input.scheduledSessionId,
|
|
22755
|
+
// Task 1575 — the gate's owner-self verdict; drives owner attribution
|
|
22756
|
+
// for an unbound owner self-phone at the spawn site.
|
|
22757
|
+
ownerSelfPhone: input.ownerSelfPhone
|
|
22686
22758
|
});
|
|
22687
22759
|
} finally {
|
|
22688
22760
|
this.spawning.delete(input.senderId);
|
|
@@ -24846,7 +24918,7 @@ var waGateway = new WaGateway({
|
|
|
24846
24918
|
});
|
|
24847
24919
|
return result.ok ? { ok: true, messageId: result.messageId } : { ok: false, error: result.error };
|
|
24848
24920
|
},
|
|
24849
|
-
ensureChannelSession: async ({ accountId, effectiveAccountId, senderId, role, personId, gatewayUrl, serverPath, passive, text, msgId, sessionIdOverride }) => {
|
|
24921
|
+
ensureChannelSession: async ({ accountId, effectiveAccountId, senderId, role, personId, gatewayUrl, serverPath, passive, text, msgId, sessionIdOverride, ownerSelfPhone }) => {
|
|
24850
24922
|
if (passive) {
|
|
24851
24923
|
const phoneHash = createHash7("sha256").update(senderId).digest("hex").slice(0, 12);
|
|
24852
24924
|
const prompt = (text ?? "").trim();
|
|
@@ -24895,9 +24967,10 @@ var waGateway = new WaGateway({
|
|
|
24895
24967
|
console.error(`[whatsapp-native] op=account-manager-route senderId=${senderId} managesAccount=${managesAccount} effectiveAccount=${effectiveAccountId} source=gate`);
|
|
24896
24968
|
}
|
|
24897
24969
|
const req = buildWaSpawnRequest({ accountId: effectiveAccountId, senderId, role, personId, gatewayUrl, serverPath, sessionIdOverride });
|
|
24898
|
-
const userId = role === "admin" ? resolveAdminUserId({ accountId: effectiveAccountId, senderPhone: senderId }) ?? void 0 : void 0;
|
|
24970
|
+
const userId = role === "admin" ? resolveAdminUserId({ accountId: effectiveAccountId, senderPhone: senderId }) ?? (ownerSelfPhone ? resolveOwnerUserId(effectiveAccountId) ?? void 0 : void 0) : void 0;
|
|
24899
24971
|
if (role === "admin") {
|
|
24900
|
-
|
|
24972
|
+
const attribution = userId ?? (ownerSelfPhone ? "owner-self-unresolved" : "unbound-empty");
|
|
24973
|
+
console.error(`[whatsapp-native] op=admin-identity senderId=${senderId} userId=${attribution}`);
|
|
24901
24974
|
}
|
|
24902
24975
|
const result = await managerRcSpawn({ ...req, userId });
|
|
24903
24976
|
if ("error" in result) {
|
|
@@ -25850,6 +25923,73 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
25850
25923
|
const loop = setInterval(runReconcile, RECONCILE_INTERVAL_MS);
|
|
25851
25924
|
loop.unref();
|
|
25852
25925
|
}
|
|
25926
|
+
{
|
|
25927
|
+
const publishPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join36(__dirname, "..");
|
|
25928
|
+
const publishScript = resolve33(publishPlatformRoot, "plugins/scheduling/mcp/dist/scripts/publish-availability.js");
|
|
25929
|
+
const PUBLISH_INTERVAL_MS = 3e5;
|
|
25930
|
+
const currentAccount = () => {
|
|
25931
|
+
try {
|
|
25932
|
+
return resolveAccount();
|
|
25933
|
+
} catch (err) {
|
|
25934
|
+
console.error(`[calendar-availability] op=publish result=error reason=account-resolve-failed err="${err.message}"`);
|
|
25935
|
+
return null;
|
|
25936
|
+
}
|
|
25937
|
+
};
|
|
25938
|
+
const spawnPublish = (account) => {
|
|
25939
|
+
if (!existsSync35(publishScript)) return;
|
|
25940
|
+
try {
|
|
25941
|
+
const child = spawn3(process.execPath, [publishScript], {
|
|
25942
|
+
env: {
|
|
25943
|
+
...process.env,
|
|
25944
|
+
PLATFORM_ROOT: publishPlatformRoot,
|
|
25945
|
+
PUBLISH_ACCOUNT_ID: account.accountId,
|
|
25946
|
+
PUBLISH_ACCOUNT_DIR: account.accountDir
|
|
25947
|
+
},
|
|
25948
|
+
stdio: "inherit"
|
|
25949
|
+
});
|
|
25950
|
+
child.unref();
|
|
25951
|
+
child.on("error", (err) => console.error(`[calendar-availability] op=publish result=error reason=spawn-failed err="${err.message}"`));
|
|
25952
|
+
} catch (err) {
|
|
25953
|
+
console.error(`[calendar-availability] op=publish result=error reason=spawn-failed err="${err.message}"`);
|
|
25954
|
+
}
|
|
25955
|
+
};
|
|
25956
|
+
const auditSnapshotAge = (account) => {
|
|
25957
|
+
const availPath = resolve33(account.accountDir, "calendar-availability.json");
|
|
25958
|
+
let hasBookingSite = false;
|
|
25959
|
+
try {
|
|
25960
|
+
if (existsSync35(availPath)) {
|
|
25961
|
+
const cfg = JSON.parse(readFileSync35(availPath, "utf-8"));
|
|
25962
|
+
hasBookingSite = typeof cfg.bookingDbName === "string" && cfg.bookingDbName.length > 0;
|
|
25963
|
+
}
|
|
25964
|
+
} catch {
|
|
25965
|
+
}
|
|
25966
|
+
if (!hasBookingSite) return;
|
|
25967
|
+
const statePath = resolve33(account.accountDir, "state", "booking-availability", "last-publish.json");
|
|
25968
|
+
let lastSuccessAt = null;
|
|
25969
|
+
if (existsSync35(statePath)) {
|
|
25970
|
+
try {
|
|
25971
|
+
const rec = JSON.parse(readFileSync35(statePath, "utf-8"));
|
|
25972
|
+
lastSuccessAt = rec.lastSuccessAt ?? null;
|
|
25973
|
+
} catch {
|
|
25974
|
+
console.error(`[calendar-availability] op=audit accountId=${account.accountId} snapshotAgeMs=na reason=bad-state-file`);
|
|
25975
|
+
return;
|
|
25976
|
+
}
|
|
25977
|
+
}
|
|
25978
|
+
const parsed = lastSuccessAt ? Date.parse(lastSuccessAt) : NaN;
|
|
25979
|
+
const ageMs = Number.isNaN(parsed) ? null : Date.now() - parsed;
|
|
25980
|
+
console.error(`[calendar-availability] op=audit accountId=${account.accountId} snapshotAgeMs=${ageMs ?? "na"}`);
|
|
25981
|
+
};
|
|
25982
|
+
const publishTick = () => {
|
|
25983
|
+
const account = currentAccount();
|
|
25984
|
+
if (!account) return;
|
|
25985
|
+
spawnPublish(account);
|
|
25986
|
+
auditSnapshotAge(account);
|
|
25987
|
+
};
|
|
25988
|
+
const firstPublish = setTimeout(publishTick, 2e4);
|
|
25989
|
+
firstPublish.unref();
|
|
25990
|
+
const publishLoop = setInterval(publishTick, PUBLISH_INTERVAL_MS);
|
|
25991
|
+
publishLoop.unref();
|
|
25992
|
+
}
|
|
25853
25993
|
startTimeEntryCensus(() => getSession());
|
|
25854
25994
|
{
|
|
25855
25995
|
const auditPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join36(__dirname, "..");
|
|
@@ -26159,7 +26299,10 @@ init({
|
|
|
26159
26299
|
passive: decision.passive,
|
|
26160
26300
|
text: msg.text,
|
|
26161
26301
|
reply: msg.reply,
|
|
26162
|
-
media: msg.media
|
|
26302
|
+
media: msg.media,
|
|
26303
|
+
// Task 1575 — carry the gate's owner-self verdict to the spawn site so an
|
|
26304
|
+
// unbound owner self-phone attributes to the owner userId.
|
|
26305
|
+
ownerSelfPhone: msg.ownerSelfPhone
|
|
26163
26306
|
});
|
|
26164
26307
|
} catch (err) {
|
|
26165
26308
|
console.error(
|