@rubytech/create-sitedesk-code 0.1.511 → 0.1.512
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/package.json +3 -0
- package/payload/platform/plugins/admin/skills/deck-pages/SKILL.md +2 -2
- package/payload/platform/plugins/admin/skills/skill-builder/SKILL.md +1 -1
- package/payload/platform/plugins/admin/skills/whats-new/SKILL.md +6 -0
- package/payload/platform/plugins/business-assistant/skills/e-sign/SKILL.md +15 -34
- package/payload/platform/plugins/business-assistant/skills/e-sign/stamp.mjs +269 -0
- package/payload/platform/plugins/linkedin-import/skills/linkedin-import/references/profile.md +5 -5
- package/payload/platform/plugins/memory/skills/conversation-archive-enrich/SKILL.md +2 -2
- package/payload/platform/plugins/memory/skills/document-ingest/SKILL.md +1 -1
- package/payload/platform/plugins/x-import/skills/x-import/SKILL.md +1 -1
- package/payload/platform/scripts/check-no-esm-require.mjs +6 -0
- package/payload/platform/scripts/logs-read.sh +117 -36
- package/payload/platform/scripts/logs-read.test.sh +234 -0
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.js +13 -0
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/session-sidecar.d.ts +7 -3
- package/payload/platform/services/claude-session-manager/dist/session-sidecar.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/session-sidecar.js +17 -11
- package/payload/platform/services/claude-session-manager/dist/session-sidecar.js.map +1 -1
- package/payload/server/maxy-edge.js +6 -2
- package/payload/server/public/assets/admin-6QN-k3zQ.js +1 -0
- package/payload/server/public/assets/admin-6QN-k3zQ.js.br +0 -0
- package/payload/server/public/assets/admin-6QN-k3zQ.js.gz +0 -0
- package/payload/server/public/index.html +1 -1
- package/payload/server/server.js +777 -349
- package/payload/server/public/assets/admin-Do53K90C.js +0 -1
- package/payload/server/public/assets/admin-Do53K90C.js.br +0 -0
- package/payload/server/public/assets/admin-Do53K90C.js.gz +0 -0
package/payload/server/server.js
CHANGED
|
@@ -1602,10 +1602,10 @@ var require_dist5 = __commonJS({
|
|
|
1602
1602
|
});
|
|
1603
1603
|
|
|
1604
1604
|
// server/index.ts
|
|
1605
|
-
import { readFileSync as readFileSync48, existsSync as
|
|
1605
|
+
import { readFileSync as readFileSync48, existsSync as existsSync48, watchFile, readdirSync as readdirSync29, statSync as statSync21 } from "fs";
|
|
1606
1606
|
import { spawn as spawn3 } from "child_process";
|
|
1607
1607
|
import { createHash as createHash8 } from "crypto";
|
|
1608
|
-
import { resolve as resolve45, join as
|
|
1608
|
+
import { resolve as resolve45, join as join51, basename as basename14 } from "path";
|
|
1609
1609
|
import { homedir as homedir4 } from "os";
|
|
1610
1610
|
|
|
1611
1611
|
// server/lib/route-cache-watchers.ts
|
|
@@ -2471,6 +2471,44 @@ var assetsVary = async (c, next) => {
|
|
|
2471
2471
|
if (!c.res.headers.has("Vary")) c.res.headers.set("Vary", "Accept-Encoding");
|
|
2472
2472
|
};
|
|
2473
2473
|
|
|
2474
|
+
// server/lib/client-error-reporter.ts
|
|
2475
|
+
var CLIENT_ERROR_SINK_PATH = "/api/_client-error";
|
|
2476
|
+
var clientErrorReporterBody = `(function(){
|
|
2477
|
+
var SINK=${JSON.stringify(CLIENT_ERROR_SINK_PATH)};
|
|
2478
|
+
var send=function(b){
|
|
2479
|
+
try{
|
|
2480
|
+
fetch(SINK,{
|
|
2481
|
+
method:'POST',
|
|
2482
|
+
headers:{'content-type':'application/json'},
|
|
2483
|
+
body:JSON.stringify(Object.assign({url:location.href,ua:navigator.userAgent,version:(window.__MAXY_VERSION__||'unknown')},b)),
|
|
2484
|
+
keepalive:true
|
|
2485
|
+
}).catch(function(){});
|
|
2486
|
+
}catch(e){}
|
|
2487
|
+
};
|
|
2488
|
+
window.addEventListener('error',function(e){
|
|
2489
|
+
var t=e.target;
|
|
2490
|
+
if(t&&t!==window&&t.tagName)send({kind:'subresource',tag:t.tagName,url:t.src||t.href||''});
|
|
2491
|
+
else send({kind:'uncaught',msg:e.message,filename:e.filename,lineno:e.lineno,colno:e.colno,stack:(e.error&&e.error.stack)||''});
|
|
2492
|
+
},true);
|
|
2493
|
+
window.addEventListener('unhandledrejection',function(e){
|
|
2494
|
+
var r=e.reason;
|
|
2495
|
+
send({kind:'unhandled-rejection',msg:String((r&&r.message)||r),stack:(r&&r.stack)||''});
|
|
2496
|
+
});
|
|
2497
|
+
try{
|
|
2498
|
+
new PerformanceObserver(function(list){
|
|
2499
|
+
list.getEntries().forEach(function(entry){
|
|
2500
|
+
var p;
|
|
2501
|
+
try{p=new URL(entry.name,location.href).pathname}catch(_){p=''}
|
|
2502
|
+
if(p===SINK)return;
|
|
2503
|
+
if(entry.responseStatus>=400)send({kind:'subresource',url:entry.name,status:entry.responseStatus});
|
|
2504
|
+
});
|
|
2505
|
+
}).observe({type:'resource',buffered:true});
|
|
2506
|
+
}catch(e){}
|
|
2507
|
+
})();`;
|
|
2508
|
+
var clientErrorReporterScript = `<script>
|
|
2509
|
+
${clientErrorReporterBody}
|
|
2510
|
+
</script>`;
|
|
2511
|
+
|
|
2474
2512
|
// app/lib/whatsapp/inbound/media-download-guard.ts
|
|
2475
2513
|
var TAG2 = "[media-guard]";
|
|
2476
2514
|
var inFlight2 = 0;
|
|
@@ -11596,19 +11634,195 @@ function runReconcileLivenessAudit(statePath, nowMs, intervalMs, emit) {
|
|
|
11596
11634
|
|
|
11597
11635
|
// server/routes/whatsapp-reader.ts
|
|
11598
11636
|
import { readFileSync as readFileSync21, watch as watch2, statSync as statSync8, openSync, readSync, closeSync, existsSync as existsSync17, readdirSync as readdirSync14, realpathSync as realpathSync6 } from "fs";
|
|
11599
|
-
import { basename as basename6, dirname as dirname7, isAbsolute, join as
|
|
11637
|
+
import { basename as basename6, dirname as dirname7, isAbsolute, join as join23, relative as relative3, resolve as resolve17, sep as sep5 } from "path";
|
|
11600
11638
|
|
|
11601
11639
|
// server/routes/admin/sidebar-sessions.ts
|
|
11602
11640
|
import { readdirSync as readdirSync12, readFileSync as readFileSync19 } from "fs";
|
|
11603
|
-
import { readFile as
|
|
11604
|
-
import { dirname as dirname5, join as
|
|
11641
|
+
import { open as open2, readFile as readFile5, stat as stat5 } from "fs/promises";
|
|
11642
|
+
import { dirname as dirname5, join as join21, resolve as resolve15 } from "path";
|
|
11643
|
+
|
|
11644
|
+
// server/lib/session-title-cache.ts
|
|
11645
|
+
import { open, readFile as readFile4, rename as rename2, unlink as unlink3, writeFile as writeFile5 } from "fs/promises";
|
|
11646
|
+
import { join as join18 } from "path";
|
|
11647
|
+
var CACHE_FILENAME = "ai-title-cache.json";
|
|
11648
|
+
var tmpSeq = 0;
|
|
11649
|
+
function nextTmpSeq() {
|
|
11650
|
+
tmpSeq = (tmpSeq + 1) % Number.MAX_SAFE_INTEGER;
|
|
11651
|
+
return tmpSeq;
|
|
11652
|
+
}
|
|
11653
|
+
function errCode(err) {
|
|
11654
|
+
const code = err?.code;
|
|
11655
|
+
if (code) return code;
|
|
11656
|
+
return err instanceof Error && err.message ? err.message : String(err);
|
|
11657
|
+
}
|
|
11658
|
+
function titleCachePath(accountDir) {
|
|
11659
|
+
return join18(accountDir, CACHE_FILENAME);
|
|
11660
|
+
}
|
|
11661
|
+
function parseTitleCacheWithDropped(raw) {
|
|
11662
|
+
const out = /* @__PURE__ */ new Map();
|
|
11663
|
+
let dropped = 0;
|
|
11664
|
+
let parsed;
|
|
11665
|
+
try {
|
|
11666
|
+
parsed = JSON.parse(raw);
|
|
11667
|
+
} catch {
|
|
11668
|
+
return { cache: out, dropped, wellFormed: false };
|
|
11669
|
+
}
|
|
11670
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
11671
|
+
return { cache: out, dropped, wellFormed: false };
|
|
11672
|
+
}
|
|
11673
|
+
for (const [sessionId, value] of Object.entries(parsed)) {
|
|
11674
|
+
if (!sessionId) {
|
|
11675
|
+
dropped += 1;
|
|
11676
|
+
continue;
|
|
11677
|
+
}
|
|
11678
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
11679
|
+
dropped += 1;
|
|
11680
|
+
continue;
|
|
11681
|
+
}
|
|
11682
|
+
const v = value;
|
|
11683
|
+
const aiTitle = v.aiTitle === null ? null : typeof v.aiTitle === "string" ? v.aiTitle : void 0;
|
|
11684
|
+
if (aiTitle === void 0) {
|
|
11685
|
+
dropped += 1;
|
|
11686
|
+
continue;
|
|
11687
|
+
}
|
|
11688
|
+
if (typeof v.scannedBytes !== "number" || !Number.isFinite(v.scannedBytes) || v.scannedBytes < 0) {
|
|
11689
|
+
dropped += 1;
|
|
11690
|
+
continue;
|
|
11691
|
+
}
|
|
11692
|
+
out.set(sessionId, { aiTitle, scannedBytes: v.scannedBytes });
|
|
11693
|
+
}
|
|
11694
|
+
return { cache: out, dropped, wellFormed: true };
|
|
11695
|
+
}
|
|
11696
|
+
function parseTitleCache(raw) {
|
|
11697
|
+
return parseTitleCacheWithDropped(raw).cache;
|
|
11698
|
+
}
|
|
11699
|
+
function serializeTitleCache(cache3) {
|
|
11700
|
+
const obj = {};
|
|
11701
|
+
for (const [sessionId, entry] of cache3) obj[sessionId] = entry;
|
|
11702
|
+
return JSON.stringify(obj);
|
|
11703
|
+
}
|
|
11704
|
+
async function loadTitleCacheOutcome(accountDir) {
|
|
11705
|
+
if (!accountDir) return { cache: /* @__PURE__ */ new Map(), state: "no-dir", dropped: 0 };
|
|
11706
|
+
let raw;
|
|
11707
|
+
try {
|
|
11708
|
+
raw = await readFile4(titleCachePath(accountDir), "utf8");
|
|
11709
|
+
} catch (err) {
|
|
11710
|
+
const code = err.code;
|
|
11711
|
+
if (code === "ENOENT") return { cache: /* @__PURE__ */ new Map(), state: "absent", dropped: 0 };
|
|
11712
|
+
console.error(
|
|
11713
|
+
`[session-title-cache] op=load-failed dir=${accountDir} code=${code ?? "unknown"} reason=${err instanceof Error ? err.message : String(err)}`
|
|
11714
|
+
);
|
|
11715
|
+
return { cache: /* @__PURE__ */ new Map(), state: "unreadable", dropped: 0 };
|
|
11716
|
+
}
|
|
11717
|
+
const { cache: cache3, dropped, wellFormed } = parseTitleCacheWithDropped(raw);
|
|
11718
|
+
const corrupt = !wellFormed || cache3.size === 0 && dropped > 0;
|
|
11719
|
+
return { cache: cache3, state: corrupt ? "corrupt" : "loaded", dropped };
|
|
11720
|
+
}
|
|
11721
|
+
async function loadTitleCache(accountDir) {
|
|
11722
|
+
return (await loadTitleCacheOutcome(accountDir)).cache;
|
|
11723
|
+
}
|
|
11724
|
+
async function saveTitleCacheMerged(accountDir, updates) {
|
|
11725
|
+
if (updates.size === 0) return;
|
|
11726
|
+
const path3 = titleCachePath(accountDir);
|
|
11727
|
+
let merged;
|
|
11728
|
+
try {
|
|
11729
|
+
merged = parseTitleCache(await readFile4(path3, "utf8"));
|
|
11730
|
+
} catch (err) {
|
|
11731
|
+
if (err.code !== "ENOENT") throw err;
|
|
11732
|
+
merged = /* @__PURE__ */ new Map();
|
|
11733
|
+
}
|
|
11734
|
+
for (const [sessionId, entry] of updates) merged.set(sessionId, entry);
|
|
11735
|
+
const tmp = `${path3}.tmp.${process.pid}.${Date.now()}.${nextTmpSeq()}`;
|
|
11736
|
+
try {
|
|
11737
|
+
await writeFile5(tmp, serializeTitleCache(merged), "utf8");
|
|
11738
|
+
await rename2(tmp, path3);
|
|
11739
|
+
} catch (err) {
|
|
11740
|
+
try {
|
|
11741
|
+
await unlink3(tmp);
|
|
11742
|
+
} catch (cleanupErr) {
|
|
11743
|
+
const code = cleanupErr.code;
|
|
11744
|
+
if (code !== "ENOENT") {
|
|
11745
|
+
console.error(`[session-title-cache] op=tmp-cleanup-failed path=${tmp} code=${code ?? "unknown"}`);
|
|
11746
|
+
}
|
|
11747
|
+
}
|
|
11748
|
+
throw err;
|
|
11749
|
+
}
|
|
11750
|
+
}
|
|
11751
|
+
function lastAiTitleIn(text, initial) {
|
|
11752
|
+
let aiTitle = initial;
|
|
11753
|
+
for (const line of text.split("\n")) {
|
|
11754
|
+
if (!line || line[0] !== "{") continue;
|
|
11755
|
+
let parsed;
|
|
11756
|
+
try {
|
|
11757
|
+
parsed = JSON.parse(line);
|
|
11758
|
+
} catch {
|
|
11759
|
+
continue;
|
|
11760
|
+
}
|
|
11761
|
+
if (!parsed || typeof parsed !== "object") continue;
|
|
11762
|
+
const row = parsed;
|
|
11763
|
+
if (row.type !== "ai-title" || typeof row.aiTitle !== "string") continue;
|
|
11764
|
+
const t = row.aiTitle.trim();
|
|
11765
|
+
if (t) aiTitle = t;
|
|
11766
|
+
}
|
|
11767
|
+
return aiTitle;
|
|
11768
|
+
}
|
|
11769
|
+
function scanAiTitleFromBody(body) {
|
|
11770
|
+
const lastNl = body.lastIndexOf("\n");
|
|
11771
|
+
const complete = lastNl === -1 ? "" : body.slice(0, lastNl + 1);
|
|
11772
|
+
return {
|
|
11773
|
+
aiTitle: lastAiTitleIn(body, null),
|
|
11774
|
+
scannedBytes: Buffer.byteLength(complete, "utf8")
|
|
11775
|
+
};
|
|
11776
|
+
}
|
|
11777
|
+
async function scanAiTitleIncremental(path3, size, prior) {
|
|
11778
|
+
const usable = prior !== void 0 && prior.scannedBytes <= size;
|
|
11779
|
+
const start = usable ? prior.scannedBytes : 0;
|
|
11780
|
+
const carried = usable ? prior.aiTitle : null;
|
|
11781
|
+
if (start >= size) return { entry: { aiTitle: carried, scannedBytes: start }, bytesRead: 0 };
|
|
11782
|
+
const length = size - start;
|
|
11783
|
+
let chunk;
|
|
11784
|
+
let handle2;
|
|
11785
|
+
try {
|
|
11786
|
+
handle2 = await open(path3, "r");
|
|
11787
|
+
} catch (err) {
|
|
11788
|
+
return {
|
|
11789
|
+
entry: { aiTitle: carried, scannedBytes: start },
|
|
11790
|
+
bytesRead: 0,
|
|
11791
|
+
failure: `open ${errCode(err)}`
|
|
11792
|
+
};
|
|
11793
|
+
}
|
|
11794
|
+
try {
|
|
11795
|
+
const buf = Buffer.alloc(length);
|
|
11796
|
+
const { bytesRead } = await handle2.read(buf, 0, length, start);
|
|
11797
|
+
chunk = bytesRead < length ? buf.subarray(0, bytesRead) : buf;
|
|
11798
|
+
} catch (err) {
|
|
11799
|
+
return {
|
|
11800
|
+
entry: { aiTitle: carried, scannedBytes: start },
|
|
11801
|
+
bytesRead: 0,
|
|
11802
|
+
failure: `read ${errCode(err)}`
|
|
11803
|
+
};
|
|
11804
|
+
} finally {
|
|
11805
|
+
await handle2.close().catch(() => {
|
|
11806
|
+
});
|
|
11807
|
+
}
|
|
11808
|
+
const text = chunk.toString("utf8");
|
|
11809
|
+
const lastNl = text.lastIndexOf("\n");
|
|
11810
|
+
const complete = lastNl === -1 ? "" : text.slice(0, lastNl + 1);
|
|
11811
|
+
return {
|
|
11812
|
+
entry: {
|
|
11813
|
+
aiTitle: lastAiTitleIn(text, carried),
|
|
11814
|
+
scannedBytes: start + Buffer.byteLength(complete, "utf8")
|
|
11815
|
+
},
|
|
11816
|
+
bytesRead: chunk.length
|
|
11817
|
+
};
|
|
11818
|
+
}
|
|
11605
11819
|
|
|
11606
11820
|
// ../services/claude-session-manager/src/jsonl-path.ts
|
|
11607
11821
|
import { existsSync as existsSync14, readdirSync as readdirSync10 } from "fs";
|
|
11608
11822
|
import { homedir } from "os";
|
|
11609
|
-
import { join as
|
|
11823
|
+
import { join as join19 } from "path";
|
|
11610
11824
|
function findExistingJsonlForSessionId(claudeConfigDir2, sessionId) {
|
|
11611
|
-
const projectsRoot =
|
|
11825
|
+
const projectsRoot = join19(claudeConfigDir2, "projects");
|
|
11612
11826
|
if (!existsSync14(projectsRoot)) return null;
|
|
11613
11827
|
let slugs;
|
|
11614
11828
|
try {
|
|
@@ -11618,9 +11832,9 @@ function findExistingJsonlForSessionId(claudeConfigDir2, sessionId) {
|
|
|
11618
11832
|
}
|
|
11619
11833
|
const basename15 = `${sessionId}.jsonl`;
|
|
11620
11834
|
for (const slug of slugs) {
|
|
11621
|
-
const live =
|
|
11835
|
+
const live = join19(projectsRoot, slug, basename15);
|
|
11622
11836
|
if (existsSync14(live)) return live;
|
|
11623
|
-
const archived =
|
|
11837
|
+
const archived = join19(projectsRoot, slug, "archive", basename15);
|
|
11624
11838
|
if (existsSync14(archived)) return archived;
|
|
11625
11839
|
}
|
|
11626
11840
|
return null;
|
|
@@ -11629,7 +11843,7 @@ function findExistingJsonlForSessionId(claudeConfigDir2, sessionId) {
|
|
|
11629
11843
|
// app/lib/admin-identity/pin-validator.ts
|
|
11630
11844
|
import { createHash as createHash3 } from "crypto";
|
|
11631
11845
|
import { existsSync as existsSync15, readFileSync as readFileSync18, readdirSync as readdirSync11, statSync as statSync6 } from "fs";
|
|
11632
|
-
import { join as
|
|
11846
|
+
import { join as join20 } from "path";
|
|
11633
11847
|
function hashPin(pin) {
|
|
11634
11848
|
return createHash3("sha256").update(pin).digest("hex");
|
|
11635
11849
|
}
|
|
@@ -11737,7 +11951,29 @@ function lastAssistantModel(body) {
|
|
|
11737
11951
|
}
|
|
11738
11952
|
return null;
|
|
11739
11953
|
}
|
|
11740
|
-
|
|
11954
|
+
async function lastAssistantModelFromTail(path3, size, maxBytes = 256 * 1024) {
|
|
11955
|
+
if (size <= 0) return { model: null, bytesRead: 0 };
|
|
11956
|
+
const start = Math.max(0, size - maxBytes);
|
|
11957
|
+
const length = size - start;
|
|
11958
|
+
let handle2;
|
|
11959
|
+
try {
|
|
11960
|
+
handle2 = await open2(path3, "r");
|
|
11961
|
+
} catch (err) {
|
|
11962
|
+
return { model: null, bytesRead: 0, failure: `open ${errCode(err)}` };
|
|
11963
|
+
}
|
|
11964
|
+
let chunk;
|
|
11965
|
+
try {
|
|
11966
|
+
const buf = Buffer.alloc(length);
|
|
11967
|
+
const { bytesRead } = await handle2.read(buf, 0, length, start);
|
|
11968
|
+
chunk = bytesRead < length ? buf.subarray(0, bytesRead) : buf;
|
|
11969
|
+
} catch (err) {
|
|
11970
|
+
return { model: null, bytesRead: 0, failure: `read ${errCode(err)}` };
|
|
11971
|
+
} finally {
|
|
11972
|
+
await handle2.close().catch(() => {
|
|
11973
|
+
});
|
|
11974
|
+
}
|
|
11975
|
+
return { model: lastAssistantModel(chunk.toString("utf8")), bytesRead: chunk.length };
|
|
11976
|
+
}
|
|
11741
11977
|
var ADMIN_ROLE = "admin";
|
|
11742
11978
|
var WEBCHAT_CHANNEL = "webchat";
|
|
11743
11979
|
var app4 = new Hono();
|
|
@@ -11760,7 +11996,7 @@ function enumerateJsonls(projectsRoot) {
|
|
|
11760
11996
|
throw err;
|
|
11761
11997
|
}
|
|
11762
11998
|
for (const slug of slugs) {
|
|
11763
|
-
const slugDir =
|
|
11999
|
+
const slugDir = join21(projectsRoot, slug);
|
|
11764
12000
|
let entries2;
|
|
11765
12001
|
try {
|
|
11766
12002
|
entries2 = readdirSync12(slugDir, { withFileTypes: true });
|
|
@@ -11771,9 +12007,9 @@ function enumerateJsonls(projectsRoot) {
|
|
|
11771
12007
|
}
|
|
11772
12008
|
for (const entry of entries2) {
|
|
11773
12009
|
if (entry.isFile() && SESSION_ID_RE.test(entry.name)) {
|
|
11774
|
-
out.push({ path:
|
|
12010
|
+
out.push({ path: join21(slugDir, entry.name), isSubagent: false, archived: false });
|
|
11775
12011
|
} else if (entry.isDirectory() && entry.name === "subagents") {
|
|
11776
|
-
const subDir =
|
|
12012
|
+
const subDir = join21(slugDir, entry.name);
|
|
11777
12013
|
let subEntries;
|
|
11778
12014
|
try {
|
|
11779
12015
|
subEntries = readdirSync12(subDir, { withFileTypes: true });
|
|
@@ -11784,11 +12020,11 @@ function enumerateJsonls(projectsRoot) {
|
|
|
11784
12020
|
}
|
|
11785
12021
|
for (const sub of subEntries) {
|
|
11786
12022
|
if (sub.isFile() && SESSION_ID_RE.test(sub.name)) {
|
|
11787
|
-
out.push({ path:
|
|
12023
|
+
out.push({ path: join21(subDir, sub.name), isSubagent: true, archived: false });
|
|
11788
12024
|
}
|
|
11789
12025
|
}
|
|
11790
12026
|
} else if (entry.isDirectory() && entry.name === "archive") {
|
|
11791
|
-
const archiveDir =
|
|
12027
|
+
const archiveDir = join21(slugDir, entry.name);
|
|
11792
12028
|
let archiveEntries;
|
|
11793
12029
|
try {
|
|
11794
12030
|
archiveEntries = readdirSync12(archiveDir, { withFileTypes: true });
|
|
@@ -11799,7 +12035,7 @@ function enumerateJsonls(projectsRoot) {
|
|
|
11799
12035
|
}
|
|
11800
12036
|
for (const arc of archiveEntries) {
|
|
11801
12037
|
if (arc.isFile() && SESSION_ID_RE.test(arc.name)) {
|
|
11802
|
-
out.push({ path:
|
|
12038
|
+
out.push({ path: join21(archiveDir, arc.name), isSubagent: false, archived: true });
|
|
11803
12039
|
}
|
|
11804
12040
|
}
|
|
11805
12041
|
}
|
|
@@ -11833,7 +12069,7 @@ function loadUserTitles(accountDir) {
|
|
|
11833
12069
|
if (!accountDir) return /* @__PURE__ */ new Map();
|
|
11834
12070
|
let raw;
|
|
11835
12071
|
try {
|
|
11836
|
-
raw = readFileSync19(
|
|
12072
|
+
raw = readFileSync19(join21(accountDir, "session-titles.json"), "utf8");
|
|
11837
12073
|
} catch {
|
|
11838
12074
|
return /* @__PURE__ */ new Map();
|
|
11839
12075
|
}
|
|
@@ -11843,7 +12079,7 @@ async function loadUserTitlesAsync(accountDir) {
|
|
|
11843
12079
|
if (!accountDir) return /* @__PURE__ */ new Map();
|
|
11844
12080
|
let raw;
|
|
11845
12081
|
try {
|
|
11846
|
-
raw = await
|
|
12082
|
+
raw = await readFile5(join21(accountDir, "session-titles.json"), "utf8");
|
|
11847
12083
|
} catch {
|
|
11848
12084
|
return /* @__PURE__ */ new Map();
|
|
11849
12085
|
}
|
|
@@ -11884,7 +12120,7 @@ function emptySidecarMeta() {
|
|
|
11884
12120
|
async function readSidecarMetaAsync(metaPath) {
|
|
11885
12121
|
let raw;
|
|
11886
12122
|
try {
|
|
11887
|
-
raw = await
|
|
12123
|
+
raw = await readFile5(metaPath, "utf8");
|
|
11888
12124
|
} catch {
|
|
11889
12125
|
return emptySidecarMeta();
|
|
11890
12126
|
}
|
|
@@ -11913,67 +12149,14 @@ function parseSidecarMeta(raw) {
|
|
|
11913
12149
|
accountId: typeof r.accountId === "string" ? r.accountId : null
|
|
11914
12150
|
};
|
|
11915
12151
|
}
|
|
11916
|
-
function startsWithCliMarker(s) {
|
|
11917
|
-
for (const p of CLI_MARKER_PREFIXES) if (s.startsWith(p)) return true;
|
|
11918
|
-
return false;
|
|
11919
|
-
}
|
|
11920
12152
|
function trimToTitle(raw) {
|
|
11921
12153
|
return raw.trim().replace(/\s+/g, " ");
|
|
11922
12154
|
}
|
|
11923
|
-
|
|
11924
|
-
var SOURCE_ATTR = /\bsource="([^"]+)"/;
|
|
11925
|
-
var CHANNEL_SOURCE_MAP = {
|
|
11926
|
-
whatsapp: "whatsapp",
|
|
11927
|
-
"whatsapp-channel": "whatsapp",
|
|
11928
|
-
webchat: "webchat",
|
|
11929
|
-
"webchat-channel": "webchat"
|
|
11930
|
-
};
|
|
11931
|
-
function stripChannelEnvelope(text) {
|
|
11932
|
-
const m = text.match(CHANNEL_WRAPPER);
|
|
11933
|
-
if (!m) return { inner: text, channel: null };
|
|
11934
|
-
let raw = m[1].match(SOURCE_ATTR)?.[1] ?? "";
|
|
11935
|
-
let inner = m[2];
|
|
11936
|
-
const im = inner.match(CHANNEL_WRAPPER);
|
|
11937
|
-
const innerRaw = im?.[1].match(SOURCE_ATTR)?.[1];
|
|
11938
|
-
if (im && innerRaw) {
|
|
11939
|
-
raw = innerRaw;
|
|
11940
|
-
inner = im[2];
|
|
11941
|
-
}
|
|
11942
|
-
return { inner, channel: CHANNEL_SOURCE_MAP[raw] ?? (raw || null) };
|
|
11943
|
-
}
|
|
11944
|
-
function resolveTitle(body, sessionId, userTitles) {
|
|
12155
|
+
function resolveTitleFromParts(sessionId, userTitles, aiTitle) {
|
|
11945
12156
|
const userTitle = userTitles.get(sessionId);
|
|
11946
|
-
|
|
11947
|
-
|
|
11948
|
-
|
|
11949
|
-
if (!line || line[0] !== "{") continue;
|
|
11950
|
-
let parsed;
|
|
11951
|
-
try {
|
|
11952
|
-
parsed = JSON.parse(line);
|
|
11953
|
-
} catch {
|
|
11954
|
-
continue;
|
|
11955
|
-
}
|
|
11956
|
-
if (!parsed || typeof parsed !== "object") continue;
|
|
11957
|
-
const row = parsed;
|
|
11958
|
-
if (row.type === "ai-title" && typeof row.aiTitle === "string") {
|
|
11959
|
-
const t = row.aiTitle.trim();
|
|
11960
|
-
if (t) aiTitle = t;
|
|
11961
|
-
continue;
|
|
11962
|
-
}
|
|
11963
|
-
if (firstUserMessage === null && row.type === "user" && row.message && row.message.role === "user") {
|
|
11964
|
-
const content = row.message.content;
|
|
11965
|
-
if (typeof content !== "string") continue;
|
|
11966
|
-
const trimmed = content.trim();
|
|
11967
|
-
if (!trimmed) continue;
|
|
11968
|
-
if (startsWithCliMarker(trimmed)) continue;
|
|
11969
|
-
firstUserMessage = trimmed;
|
|
11970
|
-
}
|
|
11971
|
-
}
|
|
11972
|
-
const stripped = firstUserMessage !== null ? stripChannelEnvelope(firstUserMessage) : { inner: null, channel: null };
|
|
11973
|
-
const channel = stripped.channel;
|
|
11974
|
-
if (userTitle) return { title: trimToTitle(userTitle), source: "user", channel };
|
|
11975
|
-
if (aiTitle) return { title: trimToTitle(aiTitle), source: "ai", channel };
|
|
11976
|
-
return { title: sessionId.slice(0, 8), source: "prefix", channel };
|
|
12157
|
+
if (userTitle) return { title: trimToTitle(userTitle), source: "user" };
|
|
12158
|
+
if (aiTitle) return { title: trimToTitle(aiTitle), source: "ai" };
|
|
12159
|
+
return { title: sessionId.slice(0, 8), source: "prefix" };
|
|
11977
12160
|
}
|
|
11978
12161
|
app4.get("/", requireAdminSession, async (c) => {
|
|
11979
12162
|
const cacheKey = c.var.cacheKey;
|
|
@@ -11998,7 +12181,7 @@ async function computeSessionList(scopeAccountId) {
|
|
|
11998
12181
|
console.error("[admin-sessions-list] CLAUDE_CONFIG_DIR not set; returning empty list");
|
|
11999
12182
|
return { sessions: [], accountId: scopeAccountId };
|
|
12000
12183
|
}
|
|
12001
|
-
const projectsRoot =
|
|
12184
|
+
const projectsRoot = join21(configDir2, "projects");
|
|
12002
12185
|
const jsonls = enumerateJsonls(projectsRoot);
|
|
12003
12186
|
const liveSessions = await fetchLiveSessions();
|
|
12004
12187
|
const accountDir = scopeAccountId ? resolve15(ACCOUNTS_DIR, scopeAccountId) : null;
|
|
@@ -12029,6 +12212,22 @@ async function computeSessionList(scopeAccountId) {
|
|
|
12029
12212
|
const adminUserIdBySession = /* @__PURE__ */ new Map();
|
|
12030
12213
|
const channelSenderBySession = /* @__PURE__ */ new Map();
|
|
12031
12214
|
const channelMissNoSender = [];
|
|
12215
|
+
const titleCacheDir = account?.accountDir ?? accountDir;
|
|
12216
|
+
const cacheLoad = await loadTitleCacheOutcome(titleCacheDir);
|
|
12217
|
+
const titleCache = cacheLoad.cache;
|
|
12218
|
+
const cacheUpdates = /* @__PURE__ */ new Map();
|
|
12219
|
+
let enumeratedCount = 0;
|
|
12220
|
+
let scopedCount = 0;
|
|
12221
|
+
let titleCacheHits = 0;
|
|
12222
|
+
let bodyScans = 0;
|
|
12223
|
+
let titleReadFails = 0;
|
|
12224
|
+
let titleBytes = 0;
|
|
12225
|
+
let tailReads = 0;
|
|
12226
|
+
let tailModelMiss = 0;
|
|
12227
|
+
let tailReadFails = 0;
|
|
12228
|
+
let tailBytes = 0;
|
|
12229
|
+
let cacheWriteFails = 0;
|
|
12230
|
+
const walkStartedAt = Date.now();
|
|
12032
12231
|
for (const { path: path3, isSubagent, archived } of jsonls) {
|
|
12033
12232
|
const lastSlash = path3.lastIndexOf("/");
|
|
12034
12233
|
const base = path3.slice(lastSlash + 1);
|
|
@@ -12039,24 +12238,40 @@ async function computeSessionList(scopeAccountId) {
|
|
|
12039
12238
|
continue;
|
|
12040
12239
|
}
|
|
12041
12240
|
seenIds.add(sessionId);
|
|
12042
|
-
|
|
12241
|
+
enumeratedCount += 1;
|
|
12043
12242
|
let mtimeMs;
|
|
12243
|
+
let size;
|
|
12044
12244
|
try {
|
|
12045
|
-
|
|
12046
|
-
mtimeMs =
|
|
12245
|
+
const st = await stat5(path3);
|
|
12246
|
+
mtimeMs = st.mtimeMs;
|
|
12247
|
+
size = st.size;
|
|
12047
12248
|
} catch {
|
|
12048
12249
|
continue;
|
|
12049
12250
|
}
|
|
12050
|
-
const
|
|
12051
|
-
const pid = live ? liveSessions.get(sessionId) ?? null : null;
|
|
12052
|
-
const resolved = resolveTitle(body, sessionId, userTitles);
|
|
12053
|
-
titleSourceCounts[resolved.source] += 1;
|
|
12054
|
-
const metaPath = join20(projectDir, `${sessionId}.meta.json`);
|
|
12251
|
+
const metaPath = join21(projectDir, `${sessionId}.meta.json`);
|
|
12055
12252
|
const { bridgeIds, role, channel: sidecarChannel, senderId, personId, adminUserId, accountId: rowAccountId } = await readSidecarMetaAsync(metaPath);
|
|
12056
12253
|
if (multiAccount) {
|
|
12057
12254
|
if (rowAccountId === null) untaggedCount += 1;
|
|
12058
12255
|
if (rowAccountId !== scopeAccountId) continue;
|
|
12059
12256
|
}
|
|
12257
|
+
scopedCount += 1;
|
|
12258
|
+
const live = liveSessions.has(sessionId);
|
|
12259
|
+
const pid = live ? liveSessions.get(sessionId) ?? null : null;
|
|
12260
|
+
const prior = titleCache.get(sessionId);
|
|
12261
|
+
const scan = await scanAiTitleIncremental(path3, size, prior);
|
|
12262
|
+
if (scan.failure) {
|
|
12263
|
+
titleReadFails += 1;
|
|
12264
|
+
console.error(
|
|
12265
|
+
`[admin-sessions-list] op=title-scan-failed sessionId=${sessionId.slice(0, 8)} reason=${scan.failure}`
|
|
12266
|
+
);
|
|
12267
|
+
} else if (scan.bytesRead > 0) bodyScans += 1;
|
|
12268
|
+
else if (prior !== void 0) titleCacheHits += 1;
|
|
12269
|
+
titleBytes += scan.bytesRead;
|
|
12270
|
+
if (!prior || prior.aiTitle !== scan.entry.aiTitle || prior.scannedBytes !== scan.entry.scannedBytes) {
|
|
12271
|
+
cacheUpdates.set(sessionId, scan.entry);
|
|
12272
|
+
}
|
|
12273
|
+
const resolved = resolveTitleFromParts(sessionId, userTitles, scan.entry.aiTitle);
|
|
12274
|
+
titleSourceCounts[resolved.source] += 1;
|
|
12060
12275
|
if (isSessionListExcluded(role, sidecarChannel)) {
|
|
12061
12276
|
excludedPublicWebchatCount += 1;
|
|
12062
12277
|
continue;
|
|
@@ -12065,6 +12280,17 @@ async function computeSessionList(scopeAccountId) {
|
|
|
12065
12280
|
if (adminUserId && role === ADMIN_ROLE && sidecarChannel === WEBCHAT_CHANNEL) {
|
|
12066
12281
|
adminUserIdBySession.set(sessionId, adminUserId);
|
|
12067
12282
|
}
|
|
12283
|
+
const tail = await lastAssistantModelFromTail(path3, size);
|
|
12284
|
+
if (tail.failure) {
|
|
12285
|
+
tailReadFails += 1;
|
|
12286
|
+
console.error(
|
|
12287
|
+
`[admin-sessions-list] op=tail-read-failed sessionId=${sessionId.slice(0, 8)} reason=${tail.failure}`
|
|
12288
|
+
);
|
|
12289
|
+
} else {
|
|
12290
|
+
if (tail.bytesRead > 0) tailReads += 1;
|
|
12291
|
+
if (tail.model === null) tailModelMiss += 1;
|
|
12292
|
+
}
|
|
12293
|
+
tailBytes += tail.bytesRead;
|
|
12068
12294
|
rows.push({
|
|
12069
12295
|
sessionId,
|
|
12070
12296
|
title: resolved.title,
|
|
@@ -12083,7 +12309,7 @@ async function computeSessionList(scopeAccountId) {
|
|
|
12083
12309
|
// diverge from the sidecar (e.g. an ai-titled channel row).
|
|
12084
12310
|
channel: sidecarChannel,
|
|
12085
12311
|
personName: null,
|
|
12086
|
-
model:
|
|
12312
|
+
model: tail.model,
|
|
12087
12313
|
accountId: rowAccountId,
|
|
12088
12314
|
senderId,
|
|
12089
12315
|
whatsappName: null
|
|
@@ -12163,6 +12389,20 @@ async function computeSessionList(scopeAccountId) {
|
|
|
12163
12389
|
console.error(`[admin-sessions-list] op=channel-name-unresolved sessionId=${m.sessionId.slice(0, 8)} channel=${m.channel} senderId= reason=no-senderId`);
|
|
12164
12390
|
}
|
|
12165
12391
|
rows.sort((a, b) => a.startedAt < b.startedAt ? 1 : -1);
|
|
12392
|
+
if (titleCacheDir && cacheUpdates.size > 0) {
|
|
12393
|
+
try {
|
|
12394
|
+
await saveTitleCacheMerged(titleCacheDir, cacheUpdates);
|
|
12395
|
+
} catch (err) {
|
|
12396
|
+
cacheWriteFails += 1;
|
|
12397
|
+
console.error(
|
|
12398
|
+
`[admin-sessions-list] op=title-cache-write-failed dir=${titleCacheDir} code=${errCode(err)} reason=${err instanceof Error ? err.message : String(err)}`
|
|
12399
|
+
);
|
|
12400
|
+
}
|
|
12401
|
+
}
|
|
12402
|
+
const bytesMB = (titleBytes + tailBytes) / (1024 * 1024);
|
|
12403
|
+
console.log(
|
|
12404
|
+
`[admin-sessions-list] op=list-walk enumerated=${enumeratedCount} scoped=${scopedCount} cacheLoad=${cacheLoad.state} cacheEntries=${titleCache.size} cacheDropped=${cacheLoad.dropped} titleCacheHits=${titleCacheHits} bodyScans=${bodyScans} titleReadFails=${titleReadFails} tailReads=${tailReads} tailModelMiss=${tailModelMiss} tailReadFails=${tailReadFails} titleBytesMB=${(titleBytes / (1024 * 1024)).toFixed(3)} bytesMB=${bytesMB.toFixed(3)} cacheWriteFails=${cacheWriteFails} ms=${Date.now() - walkStartedAt}`
|
|
12405
|
+
);
|
|
12166
12406
|
console.log(
|
|
12167
12407
|
`[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} (operator=${operatorResolvedCount} store=${storeResolvedCount}) 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"}`
|
|
12168
12408
|
);
|
|
@@ -12194,15 +12434,15 @@ var WEBCHAT_REPLY_TOOL = "mcp__webchat-channel__reply";
|
|
|
12194
12434
|
var CHANNEL_REPLY_TOOL = "mcp__channel__reply";
|
|
12195
12435
|
var CHANNEL_REPLY_DOCUMENT_TOOL = "mcp__channel__reply-document";
|
|
12196
12436
|
var SEND_USER_FILE_TOOL = "SendUserFile";
|
|
12197
|
-
var
|
|
12437
|
+
var CLI_MARKER_PREFIXES = ["<local-command-", "<command-name>", "<command-message>"];
|
|
12198
12438
|
var HARNESS_LIFECYCLE_PREFIXES = ["<task-notification>"];
|
|
12199
12439
|
var CC_IMAGE_VISION_HINT = /^\[Image:[^\]]*Multiply coordinates by [\d.]+ to map to original image\.\]$/;
|
|
12200
12440
|
var COMPACT_SUMMARY_PREFIX = "This session is being continued from a previous conversation that ran out of context.";
|
|
12201
12441
|
function isCompactSummaryRow(row, content) {
|
|
12202
12442
|
return row.isCompactSummary === true || content !== null && content.startsWith(COMPACT_SUMMARY_PREFIX);
|
|
12203
12443
|
}
|
|
12204
|
-
var
|
|
12205
|
-
var
|
|
12444
|
+
var CHANNEL_WRAPPER = /^<channel\b([^>]*)>\n?([\s\S]*?)\n?<\/channel>$/;
|
|
12445
|
+
var SOURCE_ATTR = /\bsource="([^"]+)"/;
|
|
12206
12446
|
var SOURCE_MAP = {
|
|
12207
12447
|
whatsapp: "whatsapp",
|
|
12208
12448
|
"whatsapp-channel": "whatsapp",
|
|
@@ -12212,18 +12452,18 @@ var SOURCE_MAP = {
|
|
|
12212
12452
|
"webchat-channel": "webchat"
|
|
12213
12453
|
};
|
|
12214
12454
|
function isScheduleSource(text) {
|
|
12215
|
-
const m = text.match(
|
|
12455
|
+
const m = text.match(CHANNEL_WRAPPER);
|
|
12216
12456
|
if (!m) return false;
|
|
12217
|
-
return m[1].match(
|
|
12457
|
+
return m[1].match(SOURCE_ATTR)?.[1] === "schedule";
|
|
12218
12458
|
}
|
|
12219
12459
|
function unwrapChannel(text) {
|
|
12220
|
-
const m = text.match(
|
|
12460
|
+
const m = text.match(CHANNEL_WRAPPER);
|
|
12221
12461
|
if (!m) return { text };
|
|
12222
|
-
let source = SOURCE_MAP[m[1].match(
|
|
12462
|
+
let source = SOURCE_MAP[m[1].match(SOURCE_ATTR)?.[1] ?? ""];
|
|
12223
12463
|
let inner = m[2];
|
|
12224
|
-
const im = inner.match(
|
|
12464
|
+
const im = inner.match(CHANNEL_WRAPPER);
|
|
12225
12465
|
if (im) {
|
|
12226
|
-
const innerSource = SOURCE_MAP[im[1].match(
|
|
12466
|
+
const innerSource = SOURCE_MAP[im[1].match(SOURCE_ATTR)?.[1] ?? ""];
|
|
12227
12467
|
if (innerSource) {
|
|
12228
12468
|
source = innerSource;
|
|
12229
12469
|
inner = im[2];
|
|
@@ -12395,7 +12635,7 @@ function parseTranscript(lines, queuedPendingSuppress = /* @__PURE__ */ new Map(
|
|
|
12395
12635
|
}
|
|
12396
12636
|
if (row.type === "queue-operation" && row.operation === "enqueue") {
|
|
12397
12637
|
const content = asString(row.content);
|
|
12398
|
-
if (content !== null &&
|
|
12638
|
+
if (content !== null && CHANNEL_WRAPPER.test(content)) {
|
|
12399
12639
|
const u = unwrapChannel(content);
|
|
12400
12640
|
turnCtx.lastChannelSource = u.source;
|
|
12401
12641
|
if (!isScheduleSource(content)) {
|
|
@@ -12428,7 +12668,7 @@ function parseTranscript(lines, queuedPendingSuppress = /* @__PURE__ */ new Map(
|
|
|
12428
12668
|
}
|
|
12429
12669
|
const text = asString(msg.content);
|
|
12430
12670
|
if (text === null) continue;
|
|
12431
|
-
if (
|
|
12671
|
+
if (CLI_MARKER_PREFIXES.some((p) => text.startsWith(p))) continue;
|
|
12432
12672
|
if (HARNESS_LIFECYCLE_PREFIXES.some((p) => text.startsWith(p))) continue;
|
|
12433
12673
|
if (CC_IMAGE_VISION_HINT.test(text)) continue;
|
|
12434
12674
|
const isChannel = row.isMeta === true && typeof row.origin === "object" && row.origin !== null && row.origin.kind === "channel" || // Native Claude Code channels (maxy-lite) journal the delivery twin as a PLAIN
|
|
@@ -12436,7 +12676,7 @@ function parseTranscript(lines, queuedPendingSuppress = /* @__PURE__ */ new Map(
|
|
|
12436
12676
|
// `isMeta`/`origin` stamp. Detect it by the wrapper so it is treated as the
|
|
12437
12677
|
// channel twin and consumes the enqueue row's suppression — otherwise the
|
|
12438
12678
|
// enqueue row AND this row both render and every channel message doubles.
|
|
12439
|
-
|
|
12679
|
+
CHANNEL_WRAPPER.test(text);
|
|
12440
12680
|
if (isChannel) {
|
|
12441
12681
|
const u = unwrapChannel(text);
|
|
12442
12682
|
turnCtx.lastChannelSource = u.source;
|
|
@@ -12454,7 +12694,7 @@ function parseTranscript(lines, queuedPendingSuppress = /* @__PURE__ */ new Map(
|
|
|
12454
12694
|
|
|
12455
12695
|
// app/lib/whatsapp-reader/enrich-attachments.ts
|
|
12456
12696
|
import { readFileSync as readFileSync20, readdirSync as readdirSync13, existsSync as existsSync16, statSync as statSync7, realpathSync as realpathSync5 } from "fs";
|
|
12457
|
-
import { basename as basename5, dirname as dirname6, join as
|
|
12697
|
+
import { basename as basename5, dirname as dirname6, join as join22, resolve as resolve16, sep as sep4 } from "path";
|
|
12458
12698
|
var ADMIN_UPLOAD_PATH = /\/uploads\/(?!public\/)([0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12})\//gi;
|
|
12459
12699
|
function adminAttachmentIds(text) {
|
|
12460
12700
|
const ids = [];
|
|
@@ -12467,7 +12707,7 @@ function adminAttachmentIds(text) {
|
|
|
12467
12707
|
function adminAttachmentsFromText(text, uploadsBase) {
|
|
12468
12708
|
const out = [];
|
|
12469
12709
|
for (const id of adminAttachmentIds(text)) {
|
|
12470
|
-
const meta = readAttachmentMeta(
|
|
12710
|
+
const meta = readAttachmentMeta(join22(uploadsBase, id));
|
|
12471
12711
|
if (meta) out.push(meta);
|
|
12472
12712
|
}
|
|
12473
12713
|
return out;
|
|
@@ -12517,7 +12757,7 @@ function claudeUploadAttachmentsFromText(text, sessionId) {
|
|
|
12517
12757
|
function readSidecar(dir, attachmentId) {
|
|
12518
12758
|
let parsed;
|
|
12519
12759
|
try {
|
|
12520
|
-
parsed = JSON.parse(readFileSync20(
|
|
12760
|
+
parsed = JSON.parse(readFileSync20(join22(dir, `${attachmentId}.meta.json`), "utf8"));
|
|
12521
12761
|
} catch {
|
|
12522
12762
|
return null;
|
|
12523
12763
|
}
|
|
@@ -12546,7 +12786,7 @@ function listSessionAttachmentsInDir(dir) {
|
|
|
12546
12786
|
}
|
|
12547
12787
|
const sidecars = [];
|
|
12548
12788
|
for (const name of entries2) {
|
|
12549
|
-
const sidecar = readSidecar(
|
|
12789
|
+
const sidecar = readSidecar(join22(dir, name), name);
|
|
12550
12790
|
if (sidecar) sidecars.push(sidecar);
|
|
12551
12791
|
}
|
|
12552
12792
|
sidecars.sort((a, b) => a.storedAt.localeCompare(b.storedAt));
|
|
@@ -12706,25 +12946,59 @@ app5.get("/conversations", requireAdminSession, async (c) => {
|
|
|
12706
12946
|
}
|
|
12707
12947
|
const cfg = claudeConfigDir();
|
|
12708
12948
|
if (!cfg) return c.json({ conversations: [] });
|
|
12709
|
-
const projectsRoot =
|
|
12949
|
+
const projectsRoot = join23(cfg, "projects");
|
|
12710
12950
|
const userTitles = loadUserTitles(ACCOUNTS_DIR ?? null);
|
|
12711
12951
|
const rows = [];
|
|
12712
12952
|
let sessionRowsExcludedUntagged = 0;
|
|
12953
|
+
const account = multiAccount ? validAccounts.find((a) => a.accountId === scopeAccountId) ?? null : resolveAccount();
|
|
12954
|
+
const titleCache = await loadTitleCache(account?.accountDir ?? null);
|
|
12955
|
+
const titleCacheUpdates = /* @__PURE__ */ new Map();
|
|
12956
|
+
let enumeratedCount = 0;
|
|
12957
|
+
let bodyReadCount = 0;
|
|
12958
|
+
let bodyReadFails = 0;
|
|
12959
|
+
let titleCacheHits = 0;
|
|
12960
|
+
let bodyScans = 0;
|
|
12961
|
+
const walkStartedAt = Date.now();
|
|
12962
|
+
const untaggedSenders = /* @__PURE__ */ new Set();
|
|
12713
12963
|
for (const { path: path3 } of enumerateJsonls(projectsRoot)) {
|
|
12964
|
+
enumeratedCount += 1;
|
|
12714
12965
|
const sessionId = basename6(path3).replace(/\.jsonl$/, "");
|
|
12715
12966
|
const projectDir = dirname7(path3);
|
|
12716
|
-
const meta = readSidecarMeta(
|
|
12967
|
+
const meta = readSidecarMeta(join23(projectDir, `${sessionId}.meta.json`));
|
|
12717
12968
|
if (!isReaderChannelSession(meta.role, meta.channel)) continue;
|
|
12718
12969
|
if (multiAccount) {
|
|
12719
|
-
if (meta.accountId === null)
|
|
12970
|
+
if (meta.accountId === null) {
|
|
12971
|
+
sessionRowsExcludedUntagged += 1;
|
|
12972
|
+
if (meta.senderId) untaggedSenders.add(meta.senderId);
|
|
12973
|
+
}
|
|
12720
12974
|
if (meta.accountId !== scopeAccountId) continue;
|
|
12721
12975
|
}
|
|
12722
12976
|
let body = "";
|
|
12977
|
+
let bodyRead = false;
|
|
12723
12978
|
try {
|
|
12724
12979
|
body = readFileSync21(path3, "utf8");
|
|
12725
|
-
|
|
12980
|
+
bodyRead = true;
|
|
12981
|
+
bodyReadCount += 1;
|
|
12982
|
+
} catch (err) {
|
|
12983
|
+
bodyReadFails += 1;
|
|
12984
|
+
console.error(
|
|
12985
|
+
`[wa-reader] op=body-read-failed sessionId=${sessionId.slice(0, 8)} code=${errCode(err)}`
|
|
12986
|
+
);
|
|
12726
12987
|
}
|
|
12727
|
-
|
|
12988
|
+
let aiTitle = null;
|
|
12989
|
+
if (bodyRead) {
|
|
12990
|
+
const cached3 = titleCache.get(sessionId);
|
|
12991
|
+
if (cached3 && cached3.scannedBytes === Buffer.byteLength(body, "utf8")) {
|
|
12992
|
+
aiTitle = cached3.aiTitle;
|
|
12993
|
+
titleCacheHits += 1;
|
|
12994
|
+
} else {
|
|
12995
|
+
const scanned = scanAiTitleFromBody(body);
|
|
12996
|
+
aiTitle = scanned.aiTitle;
|
|
12997
|
+
titleCacheUpdates.set(sessionId, scanned);
|
|
12998
|
+
bodyScans += 1;
|
|
12999
|
+
}
|
|
13000
|
+
}
|
|
13001
|
+
const { title } = resolveTitleFromParts(sessionId, userTitles, aiTitle);
|
|
12728
13002
|
const turns = parseTranscript(body.split("\n"));
|
|
12729
13003
|
const lastMessageAt = lastTurnTs(turns);
|
|
12730
13004
|
const modelGated = isModelGated(turns);
|
|
@@ -12742,8 +13016,24 @@ app5.get("/conversations", requireAdminSession, async (c) => {
|
|
|
12742
13016
|
model: lastAssistantModel(body)
|
|
12743
13017
|
});
|
|
12744
13018
|
}
|
|
13019
|
+
if (sessionRowsExcludedUntagged > 0) {
|
|
13020
|
+
console.log(
|
|
13021
|
+
`[wa-reader] op=untagged-sidecars count=${sessionRowsExcludedUntagged} senders=${[...untaggedSenders].sort().join(",")} route=conversations`
|
|
13022
|
+
);
|
|
13023
|
+
}
|
|
12745
13024
|
const sessionRows = selectReaderChannelSessions(rows).filter((r) => r.channel !== "whatsapp");
|
|
12746
|
-
|
|
13025
|
+
if (account && titleCacheUpdates.size > 0) {
|
|
13026
|
+
try {
|
|
13027
|
+
await saveTitleCacheMerged(account.accountDir, titleCacheUpdates);
|
|
13028
|
+
} catch (err) {
|
|
13029
|
+
console.error(
|
|
13030
|
+
`[wa-reader] op=title-cache-write-failed dir=${account.accountDir} reason=${err instanceof Error ? err.message : String(err)}`
|
|
13031
|
+
);
|
|
13032
|
+
}
|
|
13033
|
+
}
|
|
13034
|
+
console.log(
|
|
13035
|
+
`[wa-reader] op=list-walk enumerated=${enumeratedCount} read=${bodyReadCount} readFails=${bodyReadFails} titleCacheHits=${titleCacheHits} bodyScans=${bodyScans} ms=${Date.now() - walkStartedAt}`
|
|
13036
|
+
);
|
|
12747
13037
|
let users = [];
|
|
12748
13038
|
if (account) {
|
|
12749
13039
|
try {
|
|
@@ -12844,24 +13134,61 @@ app5.get("/conversations-all", requireAdminSession, async (c) => {
|
|
|
12844
13134
|
const { value, state } = await getOrCompute("conversations-all", houseId, async () => {
|
|
12845
13135
|
const cfg = claudeConfigDir();
|
|
12846
13136
|
if (!cfg) return { conversations: [] };
|
|
12847
|
-
const projectsRoot =
|
|
13137
|
+
const projectsRoot = join23(cfg, "projects");
|
|
12848
13138
|
const userTitles = loadUserTitles(ACCOUNTS_DIR ?? null);
|
|
12849
13139
|
const validAccounts = listValidAccounts();
|
|
12850
13140
|
const validIds = new Set(validAccounts.map((a) => a.accountId));
|
|
12851
13141
|
const houseIds = new Set(validAccounts.filter((a) => a.config.role === "house").map((a) => a.accountId));
|
|
12852
13142
|
const rawByAccount = /* @__PURE__ */ new Map();
|
|
13143
|
+
const cachesByAccount = /* @__PURE__ */ new Map();
|
|
13144
|
+
const accountDirById = new Map(validAccounts.map((a) => [a.accountId, a.accountDir]));
|
|
13145
|
+
let enumeratedCount = 0;
|
|
13146
|
+
let bodyReadCount = 0;
|
|
13147
|
+
let bodyReadFails = 0;
|
|
13148
|
+
let titleCacheHits = 0;
|
|
13149
|
+
let bodyScans = 0;
|
|
13150
|
+
const walkStartedAt = Date.now();
|
|
13151
|
+
let untaggedCount = 0;
|
|
13152
|
+
const untaggedSenders = /* @__PURE__ */ new Set();
|
|
12853
13153
|
for (const { path: path3 } of enumerateJsonls(projectsRoot)) {
|
|
13154
|
+
enumeratedCount += 1;
|
|
12854
13155
|
const sessionId = basename6(path3).replace(/\.jsonl$/, "");
|
|
12855
13156
|
const projectDir = dirname7(path3);
|
|
12856
|
-
const meta = readSidecarMeta(
|
|
13157
|
+
const meta = readSidecarMeta(join23(projectDir, `${sessionId}.meta.json`));
|
|
12857
13158
|
if (!isReaderChannelSession(meta.role, meta.channel)) continue;
|
|
12858
|
-
if (meta.accountId === null
|
|
13159
|
+
if (meta.accountId === null) {
|
|
13160
|
+
untaggedCount += 1;
|
|
13161
|
+
if (meta.senderId) untaggedSenders.add(meta.senderId);
|
|
13162
|
+
continue;
|
|
13163
|
+
}
|
|
13164
|
+
if (!validIds.has(meta.accountId)) continue;
|
|
12859
13165
|
let body = "";
|
|
13166
|
+
let bodyRead = false;
|
|
12860
13167
|
try {
|
|
12861
13168
|
body = readFileSync21(path3, "utf8");
|
|
12862
|
-
|
|
13169
|
+
bodyRead = true;
|
|
13170
|
+
bodyReadCount += 1;
|
|
13171
|
+
} catch (err) {
|
|
13172
|
+
bodyReadFails += 1;
|
|
13173
|
+
console.error(`[wa-reader] op=body-read-failed sessionId=${sessionId.slice(0, 8)} code=${errCode(err)}`);
|
|
13174
|
+
}
|
|
13175
|
+
let aiTitle = null;
|
|
13176
|
+
if (bodyRead) {
|
|
13177
|
+
let cache3 = cachesByAccount.get(meta.accountId);
|
|
13178
|
+
if (cache3 === void 0) {
|
|
13179
|
+
cache3 = await loadTitleCache(accountDirById.get(meta.accountId) ?? null);
|
|
13180
|
+
cachesByAccount.set(meta.accountId, cache3);
|
|
13181
|
+
}
|
|
13182
|
+
const cached3 = cache3.get(sessionId);
|
|
13183
|
+
if (cached3 && cached3.scannedBytes === Buffer.byteLength(body, "utf8")) {
|
|
13184
|
+
aiTitle = cached3.aiTitle;
|
|
13185
|
+
titleCacheHits += 1;
|
|
13186
|
+
} else {
|
|
13187
|
+
aiTitle = scanAiTitleFromBody(body).aiTitle;
|
|
13188
|
+
bodyScans += 1;
|
|
13189
|
+
}
|
|
12863
13190
|
}
|
|
12864
|
-
const { title } =
|
|
13191
|
+
const { title } = resolveTitleFromParts(sessionId, userTitles, aiTitle);
|
|
12865
13192
|
const turns = parseTranscript(body.split("\n"));
|
|
12866
13193
|
const row = {
|
|
12867
13194
|
sessionId,
|
|
@@ -12879,6 +13206,14 @@ app5.get("/conversations-all", requireAdminSession, async (c) => {
|
|
|
12879
13206
|
list.push(row);
|
|
12880
13207
|
rawByAccount.set(meta.accountId, list);
|
|
12881
13208
|
}
|
|
13209
|
+
console.log(
|
|
13210
|
+
`[wa-reader] op=list-walk enumerated=${enumeratedCount} read=${bodyReadCount} readFails=${bodyReadFails} titleCacheHits=${titleCacheHits} bodyScans=${bodyScans} ms=${Date.now() - walkStartedAt}`
|
|
13211
|
+
);
|
|
13212
|
+
if (untaggedCount > 0) {
|
|
13213
|
+
console.log(
|
|
13214
|
+
`[wa-reader] op=untagged-sidecars count=${untaggedCount} senders=${[...untaggedSenders].sort().join(",")} route=conversations-all`
|
|
13215
|
+
);
|
|
13216
|
+
}
|
|
12882
13217
|
let users = [];
|
|
12883
13218
|
try {
|
|
12884
13219
|
users = readUsersFile(USERS_FILE) ?? [];
|
|
@@ -13018,7 +13353,7 @@ function openTaskKey(turns) {
|
|
|
13018
13353
|
}
|
|
13019
13354
|
function readSubagentMeta(dir, hex) {
|
|
13020
13355
|
try {
|
|
13021
|
-
const m = JSON.parse(readFileSync21(
|
|
13356
|
+
const m = JSON.parse(readFileSync21(join23(dir, `agent-${hex}.meta.json`), "utf8"));
|
|
13022
13357
|
if (typeof m.agentType === "string" && typeof m.description === "string" && typeof m.toolUseId === "string") {
|
|
13023
13358
|
return { agentType: m.agentType, description: m.description, toolUseId: m.toolUseId };
|
|
13024
13359
|
}
|
|
@@ -13050,7 +13385,7 @@ function runActivityTick(c) {
|
|
|
13050
13385
|
let size = 0;
|
|
13051
13386
|
let mtimeMs = 0;
|
|
13052
13387
|
try {
|
|
13053
|
-
const st = statSync8(
|
|
13388
|
+
const st = statSync8(join23(c.subagentsDir, name));
|
|
13054
13389
|
size = st.size;
|
|
13055
13390
|
mtimeMs = st.mtimeMs;
|
|
13056
13391
|
} catch {
|
|
@@ -13095,11 +13430,11 @@ app5.get("/stream", requireAdminSession, (c) => {
|
|
|
13095
13430
|
const sessionId = c.req.query("sessionId") ?? "";
|
|
13096
13431
|
const projectDir = c.req.query("projectDir") ?? "";
|
|
13097
13432
|
const cfg = claudeConfigDir();
|
|
13098
|
-
const projectsRoot = cfg ? resolve17(
|
|
13433
|
+
const projectsRoot = cfg ? resolve17(join23(cfg, "projects")) : null;
|
|
13099
13434
|
if (!cfg || !projectsRoot || !SESSION_ID_RE2.test(sessionId)) {
|
|
13100
13435
|
return c.json({ error: "bad session reference" }, 400);
|
|
13101
13436
|
}
|
|
13102
|
-
const jsonlPath = resolve17(
|
|
13437
|
+
const jsonlPath = resolve17(join23(projectDir, `${sessionId}.jsonl`));
|
|
13103
13438
|
if (!jsonlPath.startsWith(projectsRoot + sep5)) {
|
|
13104
13439
|
return c.json({ error: "bad session reference" }, 400);
|
|
13105
13440
|
}
|
|
@@ -13126,7 +13461,7 @@ data: ${JSON.stringify(turn)}
|
|
|
13126
13461
|
let offset = resumeOffset(lastEventId, fileEnd0);
|
|
13127
13462
|
console.log(`[wa-stream] op=open conn=${connId} sessionId=${sessionId} channel=reader resume=${offset}`);
|
|
13128
13463
|
const sessionKey = c.req.query("session_key") ?? "";
|
|
13129
|
-
const subagentsDir = resolve17(
|
|
13464
|
+
const subagentsDir = resolve17(join23(projectDir, sessionId, "subagents"));
|
|
13130
13465
|
console.log(
|
|
13131
13466
|
`[webchat-activity] op=watch-subagents key=${sessionKey} dir=${subagentsDir} exists=${existsSync17(subagentsDir)}`
|
|
13132
13467
|
);
|
|
@@ -13255,7 +13590,7 @@ app5.get("/directives", requireAdminSession, (c) => {
|
|
|
13255
13590
|
const pid = Number(pidPart);
|
|
13256
13591
|
let len = 0;
|
|
13257
13592
|
try {
|
|
13258
|
-
len = statSync8(
|
|
13593
|
+
len = statSync8(join23(dir, name)).size;
|
|
13259
13594
|
} catch {
|
|
13260
13595
|
}
|
|
13261
13596
|
return { name, secs, pid, ts: Number.isFinite(secs) ? new Date(secs * 1e3).toISOString() : null, len };
|
|
@@ -13270,7 +13605,7 @@ app5.get("/directive", requireAdminSession, (c) => {
|
|
|
13270
13605
|
}
|
|
13271
13606
|
const dir = directiveStoreDir(sessionId);
|
|
13272
13607
|
if (!dir) return c.json({ error: "no account" }, 404);
|
|
13273
|
-
const path3 = resolve17(
|
|
13608
|
+
const path3 = resolve17(join23(dir, name));
|
|
13274
13609
|
if (!path3.startsWith(dir + sep5)) return c.json({ error: "bad reference" }, 400);
|
|
13275
13610
|
let body;
|
|
13276
13611
|
try {
|
|
@@ -13328,7 +13663,7 @@ app5.get("/store-stream", requireAdminSession, (c) => {
|
|
|
13328
13663
|
console.log(`[wa-reader] op=store-quote msgId=${r.msgKeyId} quoted=${!!q2}`);
|
|
13329
13664
|
}
|
|
13330
13665
|
if (r.attachmentId) {
|
|
13331
|
-
const meta = readAttachmentMeta(
|
|
13666
|
+
const meta = readAttachmentMeta(join23(uploadsBase, r.attachmentId));
|
|
13332
13667
|
if (meta) return { ...turn, attachments: [meta] };
|
|
13333
13668
|
}
|
|
13334
13669
|
return turn;
|
|
@@ -13709,7 +14044,7 @@ var whatsapp_reader_default = app5;
|
|
|
13709
14044
|
|
|
13710
14045
|
// server/routes/public-reader.ts
|
|
13711
14046
|
import { statSync as statSync9, openSync as openSync2, readSync as readSync2, closeSync as closeSync2, watch as watch3, readFileSync as readFileSync22, readdirSync as readdirSync15 } from "fs";
|
|
13712
|
-
import { basename as basename7, dirname as dirname8, join as
|
|
14047
|
+
import { basename as basename7, dirname as dirname8, join as join24, resolve as resolve18, sep as sep6 } from "path";
|
|
13713
14048
|
|
|
13714
14049
|
// app/lib/whatsapp-reader/delivered-kinds.ts
|
|
13715
14050
|
var PUBLIC_DELIVERED_KINDS = /* @__PURE__ */ new Set([
|
|
@@ -13783,10 +14118,10 @@ function enumeratePublicRows() {
|
|
|
13783
14118
|
const cfg = claudeConfigDir();
|
|
13784
14119
|
if (!cfg) return [];
|
|
13785
14120
|
const rows = [];
|
|
13786
|
-
for (const { path: path3 } of enumerateJsonls(
|
|
14121
|
+
for (const { path: path3 } of enumerateJsonls(join24(cfg, "projects"))) {
|
|
13787
14122
|
const sessionId = basename7(path3).replace(/\.jsonl$/, "");
|
|
13788
14123
|
const projectDir = dirname8(path3);
|
|
13789
|
-
const meta = readSidecarMeta(
|
|
14124
|
+
const meta = readSidecarMeta(join24(projectDir, `${sessionId}.meta.json`));
|
|
13790
14125
|
rows.push({
|
|
13791
14126
|
sessionId,
|
|
13792
14127
|
projectDir,
|
|
@@ -13862,15 +14197,15 @@ app6.get("/stream", (c) => {
|
|
|
13862
14197
|
const sessionId = c.req.query("sessionId") ?? "";
|
|
13863
14198
|
const projectDir = c.req.query("projectDir") ?? "";
|
|
13864
14199
|
const cfg = claudeConfigDir();
|
|
13865
|
-
const projectsRoot = cfg ? resolve18(
|
|
14200
|
+
const projectsRoot = cfg ? resolve18(join24(cfg, "projects")) : null;
|
|
13866
14201
|
if (!cfg || !projectsRoot || !SESSION_ID_RE2.test(sessionId)) {
|
|
13867
14202
|
return c.json({ error: "bad session reference" }, 400);
|
|
13868
14203
|
}
|
|
13869
|
-
const jsonlPath = resolve18(
|
|
14204
|
+
const jsonlPath = resolve18(join24(projectDir, `${sessionId}.jsonl`));
|
|
13870
14205
|
if (!jsonlPath.startsWith(projectsRoot + sep6)) {
|
|
13871
14206
|
return c.json({ error: "bad session reference" }, 400);
|
|
13872
14207
|
}
|
|
13873
|
-
const meta = readSidecarMeta(
|
|
14208
|
+
const meta = readSidecarMeta(join24(projectDir, `${sessionId}.meta.json`));
|
|
13874
14209
|
const isPublicWebchat = meta.role === "public" && meta.channel === "webchat";
|
|
13875
14210
|
const owns = visitor.kind === "person" ? meta.personId === visitor.personId : meta.personId === null && meta.visitorId === visitor.visitorId;
|
|
13876
14211
|
if (!(isPublicWebchat && owns)) {
|
|
@@ -14007,16 +14342,16 @@ var public_reader_default = app6;
|
|
|
14007
14342
|
|
|
14008
14343
|
// server/routes/webchat.ts
|
|
14009
14344
|
import { basename as basename8, dirname as dirname9 } from "path";
|
|
14010
|
-
import { join as
|
|
14345
|
+
import { join as join27 } from "path";
|
|
14011
14346
|
import { existsSync as existsSync19, readdirSync as readdirSync17, readFileSync as readFileSync25, renameSync as renameSync4, statSync as statSync10, writeFileSync as writeFileSync9 } from "fs";
|
|
14012
14347
|
|
|
14013
14348
|
// server/canonical-webchat-override.ts
|
|
14014
14349
|
import { readFileSync as readFileSync23, writeFileSync as writeFileSync7, renameSync as renameSync2 } from "fs";
|
|
14015
|
-
import { join as
|
|
14350
|
+
import { join as join25 } from "path";
|
|
14016
14351
|
var FILE = "canonical-webchat-session.json";
|
|
14017
14352
|
var UUID2 = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/;
|
|
14018
14353
|
function canonicalOverridePath(accountDir) {
|
|
14019
|
-
return
|
|
14354
|
+
return join25(accountDir, FILE);
|
|
14020
14355
|
}
|
|
14021
14356
|
function readRaw(accountDir) {
|
|
14022
14357
|
try {
|
|
@@ -14121,7 +14456,7 @@ function isNewSessionEffortLevel(value) {
|
|
|
14121
14456
|
|
|
14122
14457
|
// ../services/claude-session-manager/src/sidecar-store.ts
|
|
14123
14458
|
import { existsSync as existsSync18, mkdirSync as mkdirSync4, readdirSync as readdirSync16, readFileSync as readFileSync24, renameSync as renameSync3, unlinkSync as unlinkSync2, writeFileSync as writeFileSync8 } from "fs";
|
|
14124
|
-
import { join as
|
|
14459
|
+
import { join as join26 } from "path";
|
|
14125
14460
|
function escapeRegExp(s) {
|
|
14126
14461
|
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
14127
14462
|
}
|
|
@@ -14129,7 +14464,7 @@ function createSidecarStore(config) {
|
|
|
14129
14464
|
const { suffix, validate: validate2 } = config;
|
|
14130
14465
|
const suffixRe = new RegExp(`${escapeRegExp(suffix)}$`);
|
|
14131
14466
|
function pathFor(sessionsDir, id) {
|
|
14132
|
-
return
|
|
14467
|
+
return join26(sessionsDir, `${id}${suffix}`);
|
|
14133
14468
|
}
|
|
14134
14469
|
function write(sessionsDir, id, record) {
|
|
14135
14470
|
mkdirSync4(sessionsDir, { recursive: true });
|
|
@@ -14173,7 +14508,7 @@ function createSidecarStore(config) {
|
|
|
14173
14508
|
const out = [];
|
|
14174
14509
|
for (const name of names) {
|
|
14175
14510
|
if (!suffixRe.test(name)) continue;
|
|
14176
|
-
const path3 =
|
|
14511
|
+
const path3 = join26(sessionsDir, name);
|
|
14177
14512
|
let raw;
|
|
14178
14513
|
try {
|
|
14179
14514
|
raw = readFileSync24(path3, "utf8");
|
|
@@ -14250,13 +14585,13 @@ var UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9
|
|
|
14250
14585
|
function locateSession(sessionId) {
|
|
14251
14586
|
const dir = findSessionProjectDir(sessionId);
|
|
14252
14587
|
if (!dir) return { projectDir: null, channel: null, accountId: null };
|
|
14253
|
-
const meta = readSidecarMeta(
|
|
14588
|
+
const meta = readSidecarMeta(join27(dir, `${sessionId}.meta.json`));
|
|
14254
14589
|
return { projectDir: dir, channel: meta.channel, accountId: meta.accountId };
|
|
14255
14590
|
}
|
|
14256
14591
|
function locateSidecar(sessionId) {
|
|
14257
14592
|
const cfg = claudeConfigDir();
|
|
14258
14593
|
if (!cfg) return null;
|
|
14259
|
-
const projectsRoot =
|
|
14594
|
+
const projectsRoot = join27(cfg, "projects");
|
|
14260
14595
|
let slugs;
|
|
14261
14596
|
try {
|
|
14262
14597
|
slugs = readdirSync17(projectsRoot, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
|
|
@@ -14264,7 +14599,7 @@ function locateSidecar(sessionId) {
|
|
|
14264
14599
|
return null;
|
|
14265
14600
|
}
|
|
14266
14601
|
for (const slug of slugs) {
|
|
14267
|
-
const metaPath =
|
|
14602
|
+
const metaPath = join27(projectsRoot, slug, `${sessionId}.meta.json`);
|
|
14268
14603
|
if (existsSync19(metaPath)) return readSidecarMeta(metaPath);
|
|
14269
14604
|
}
|
|
14270
14605
|
return null;
|
|
@@ -14274,7 +14609,7 @@ function readTargetOwner(sessionId) {
|
|
|
14274
14609
|
if (sidecar !== null) return { found: true, owner: sidecar.adminUserId };
|
|
14275
14610
|
const { projectDir } = locateSession(sessionId);
|
|
14276
14611
|
if (projectDir !== null) {
|
|
14277
|
-
return { found: true, owner: readSidecarMeta(
|
|
14612
|
+
return { found: true, owner: readSidecarMeta(join27(projectDir, `${sessionId}.meta.json`)).adminUserId };
|
|
14278
14613
|
}
|
|
14279
14614
|
return { found: false, owner: null };
|
|
14280
14615
|
}
|
|
@@ -14282,7 +14617,7 @@ function readSourceRowMeta(sessionId) {
|
|
|
14282
14617
|
const sidecar = locateSidecar(sessionId);
|
|
14283
14618
|
if (sidecar !== null) return sidecar;
|
|
14284
14619
|
const { projectDir } = locateSession(sessionId);
|
|
14285
|
-
if (projectDir !== null) return readSidecarMeta(
|
|
14620
|
+
if (projectDir !== null) return readSidecarMeta(join27(projectDir, `${sessionId}.meta.json`));
|
|
14286
14621
|
return null;
|
|
14287
14622
|
}
|
|
14288
14623
|
function ownedByRequester(owner, requesterUserId, primaryUserId) {
|
|
@@ -14295,7 +14630,7 @@ function sessionSidecarExists(sessionId) {
|
|
|
14295
14630
|
function jsonlSizeBytes(projectDir, sessionId) {
|
|
14296
14631
|
if (projectDir === null) return null;
|
|
14297
14632
|
try {
|
|
14298
|
-
return statSync10(
|
|
14633
|
+
return statSync10(join27(projectDir, `${sessionId}.jsonl`)).size;
|
|
14299
14634
|
} catch {
|
|
14300
14635
|
return null;
|
|
14301
14636
|
}
|
|
@@ -14423,10 +14758,10 @@ function latestAdminWebchatSessionId(requesterUserId, primaryUserId, scopeAccoun
|
|
|
14423
14758
|
const cfg = claudeConfigDir();
|
|
14424
14759
|
if (!cfg) return null;
|
|
14425
14760
|
let best = null;
|
|
14426
|
-
for (const { path: path3, isSubagent, archived } of enumerateJsonls(
|
|
14761
|
+
for (const { path: path3, isSubagent, archived } of enumerateJsonls(join27(cfg, "projects"))) {
|
|
14427
14762
|
if (isSubagent || archived) continue;
|
|
14428
14763
|
const id = basename8(path3).slice(0, -".jsonl".length);
|
|
14429
|
-
const meta = readSidecarMeta(
|
|
14764
|
+
const meta = readSidecarMeta(join27(dirname9(path3), `${id}.meta.json`));
|
|
14430
14765
|
if (meta.role !== "admin" || meta.channel !== "webchat") continue;
|
|
14431
14766
|
if (multiAccount && meta.accountId !== scopeAccountId) continue;
|
|
14432
14767
|
let mtimeMs;
|
|
@@ -14730,7 +15065,7 @@ ${note}` : note;
|
|
|
14730
15065
|
console.error(`[webchat:settings] op=${op} outcome=refused value=${value} accountId=none reason=no-account-for-session`);
|
|
14731
15066
|
return c.json({ error: "account unresolved" }, 503);
|
|
14732
15067
|
}
|
|
14733
|
-
const accountJsonPath =
|
|
15068
|
+
const accountJsonPath = join27(account.accountDir, "account.json");
|
|
14734
15069
|
try {
|
|
14735
15070
|
const parsed = JSON.parse(readFileSync25(accountJsonPath, "utf8"));
|
|
14736
15071
|
if (op === "model") parsed.adminModel = value;
|
|
@@ -14778,7 +15113,7 @@ ${note}` : note;
|
|
|
14778
15113
|
const cfg2 = claudeConfigDir();
|
|
14779
15114
|
if (cfg2) {
|
|
14780
15115
|
const source2 = resolveBridgeSource(
|
|
14781
|
-
|
|
15116
|
+
join27(cfg2, "sessions"),
|
|
14782
15117
|
target,
|
|
14783
15118
|
(id) => locateSession(id).projectDir !== null
|
|
14784
15119
|
);
|
|
@@ -14805,7 +15140,7 @@ ${note}` : note;
|
|
|
14805
15140
|
const cfg = claudeConfigDir();
|
|
14806
15141
|
let projectDir = null;
|
|
14807
15142
|
if (cfg) {
|
|
14808
|
-
for (const { path: path3 } of enumerateJsonls(
|
|
15143
|
+
for (const { path: path3 } of enumerateJsonls(join27(cfg, "projects"))) {
|
|
14809
15144
|
if (basename8(path3) === `${sessionId}.jsonl`) {
|
|
14810
15145
|
projectDir = dirname9(path3);
|
|
14811
15146
|
break;
|
|
@@ -14813,7 +15148,7 @@ ${note}` : note;
|
|
|
14813
15148
|
}
|
|
14814
15149
|
}
|
|
14815
15150
|
if (source === "latest" && requesterUserId !== null) {
|
|
14816
|
-
const owner = readSidecarMeta(
|
|
15151
|
+
const owner = readSidecarMeta(join27(projectDir ?? "", `${sessionId}.meta.json`)).adminUserId;
|
|
14817
15152
|
if (owner !== null && owner !== requesterUserId && requesterUserId !== primaryUserId) {
|
|
14818
15153
|
console.error(`[webchat:inbound] op=session-resolve-foreign key=${sessionId.slice(0, 8)} owner=${owner.slice(0, 8)} requester=${requesterUserId.slice(0, 8)}`);
|
|
14819
15154
|
}
|
|
@@ -14846,7 +15181,7 @@ import { resolve as resolve19 } from "path";
|
|
|
14846
15181
|
|
|
14847
15182
|
// app/lib/claude-agent/specialist-roster.ts
|
|
14848
15183
|
import { existsSync as existsSync20, readFileSync as readFileSync26, readdirSync as readdirSync18 } from "fs";
|
|
14849
|
-
import { join as
|
|
15184
|
+
import { join as join28 } from "path";
|
|
14850
15185
|
function field(fm, name) {
|
|
14851
15186
|
const m = fm.match(new RegExp(`^${name}:\\s*(.*?)\\r?$`, "m"));
|
|
14852
15187
|
if (!m) return null;
|
|
@@ -14865,7 +15200,7 @@ function readSpecialistRoster(specialistsDir) {
|
|
|
14865
15200
|
if (!file.endsWith(".md")) continue;
|
|
14866
15201
|
let raw;
|
|
14867
15202
|
try {
|
|
14868
|
-
raw = readFileSync26(
|
|
15203
|
+
raw = readFileSync26(join28(specialistsDir, file), "utf-8");
|
|
14869
15204
|
} catch (err) {
|
|
14870
15205
|
skipped.push({ file, reason: err instanceof Error ? err.message : String(err) });
|
|
14871
15206
|
continue;
|
|
@@ -14982,7 +15317,7 @@ var webchat_greeting_default = app7;
|
|
|
14982
15317
|
|
|
14983
15318
|
// server/routes/telegram.ts
|
|
14984
15319
|
import { homedir as homedir2 } from "os";
|
|
14985
|
-
import { resolve as resolve20, join as
|
|
15320
|
+
import { resolve as resolve20, join as join29 } from "path";
|
|
14986
15321
|
import { existsSync as existsSync21, readFileSync as readFileSync27 } from "fs";
|
|
14987
15322
|
|
|
14988
15323
|
// app/lib/telegram/gateway/instance.ts
|
|
@@ -15042,7 +15377,7 @@ function routeTelegramUpdate(input) {
|
|
|
15042
15377
|
var TAG30 = "[telegram-inbound]";
|
|
15043
15378
|
function configDirName() {
|
|
15044
15379
|
const platformRoot5 = process.env.MAXY_PLATFORM_ROOT ?? resolve20(process.cwd(), "..");
|
|
15045
|
-
const brandPath =
|
|
15380
|
+
const brandPath = join29(platformRoot5, "config", "brand.json");
|
|
15046
15381
|
if (existsSync21(brandPath)) {
|
|
15047
15382
|
try {
|
|
15048
15383
|
return JSON.parse(readFileSync27(brandPath, "utf-8")).configDir ?? ".maxy";
|
|
@@ -15131,16 +15466,16 @@ app8.post("/", async (c) => {
|
|
|
15131
15466
|
var telegram_default = app8;
|
|
15132
15467
|
|
|
15133
15468
|
// server/routes/quickbooks.ts
|
|
15134
|
-
import { join as
|
|
15469
|
+
import { join as join30 } from "path";
|
|
15135
15470
|
import { existsSync as existsSync22, readFileSync as readFileSync28, writeFileSync as writeFileSync10, mkdirSync as mkdirSync5, rmSync, renameSync as renameSync5 } from "fs";
|
|
15136
15471
|
var TAG31 = "[quickbooks]";
|
|
15137
15472
|
var INTUIT_TOKEN_URL = "https://oauth.platform.intuit.com/oauth2/v1/tokens/bearer";
|
|
15138
15473
|
var STATE_RE = /^[A-Za-z0-9_-]+$/;
|
|
15139
15474
|
function pendingPath(accountDir, state) {
|
|
15140
|
-
return
|
|
15475
|
+
return join30(accountDir, "secrets", "quickbooks-pending", `${state}.json`);
|
|
15141
15476
|
}
|
|
15142
15477
|
function storePath(accountDir) {
|
|
15143
|
-
return
|
|
15478
|
+
return join30(accountDir, "secrets", "quickbooks.json");
|
|
15144
15479
|
}
|
|
15145
15480
|
async function completeConsent(args) {
|
|
15146
15481
|
const { accountDir, code, realmId } = args;
|
|
@@ -15207,7 +15542,7 @@ async function completeConsent(args) {
|
|
|
15207
15542
|
refreshTokenExpiry: now + (body.x_refresh_token_expires_in ?? 864e4) * 1e3,
|
|
15208
15543
|
lastRefresh: now
|
|
15209
15544
|
};
|
|
15210
|
-
mkdirSync5(
|
|
15545
|
+
mkdirSync5(join30(accountDir, "secrets"), { recursive: true });
|
|
15211
15546
|
writeFileSync10(storePath(accountDir), JSON.stringify(store2, null, 2), { mode: 384 });
|
|
15212
15547
|
const persisted = JSON.parse(readFileSync28(storePath(accountDir), "utf-8")).connections?.[realmId]?.refreshToken === body.refresh_token;
|
|
15213
15548
|
console.error(`${TAG31} op=token-exchange realmId=${realmId} persisted=${persisted}`);
|
|
@@ -15249,7 +15584,7 @@ function claudeBin() {
|
|
|
15249
15584
|
}
|
|
15250
15585
|
|
|
15251
15586
|
// server/routes/onboarding.ts
|
|
15252
|
-
import { dirname as dirname11, join as
|
|
15587
|
+
import { dirname as dirname11, join as join32 } from "path";
|
|
15253
15588
|
|
|
15254
15589
|
// app/lib/claude-keychain.ts
|
|
15255
15590
|
import { execFileSync as execFileSync3 } from "child_process";
|
|
@@ -15379,7 +15714,7 @@ function readHostCredsBlob(service) {
|
|
|
15379
15714
|
|
|
15380
15715
|
// ../lib/admins-write/src/index.ts
|
|
15381
15716
|
import { existsSync as existsSync23, readFileSync as readFileSync29, writeFileSync as writeFileSync11, renameSync as renameSync6, mkdirSync as mkdirSync6, readdirSync as readdirSync19, statSync as statSync11, appendFileSync as appendFileSync3 } from "fs";
|
|
15382
|
-
import { dirname as dirname10, join as
|
|
15717
|
+
import { dirname as dirname10, join as join31 } from "path";
|
|
15383
15718
|
function id8(value) {
|
|
15384
15719
|
return value.slice(0, 8);
|
|
15385
15720
|
}
|
|
@@ -15452,7 +15787,7 @@ function writeAdminEntry(input) {
|
|
|
15452
15787
|
return result;
|
|
15453
15788
|
}
|
|
15454
15789
|
try {
|
|
15455
|
-
const accountJsonPath =
|
|
15790
|
+
const accountJsonPath = join31(input.accountDir, "account.json");
|
|
15456
15791
|
if (!existsSync23(accountJsonPath)) {
|
|
15457
15792
|
throw new Error(`account.json not found at ${accountJsonPath}`);
|
|
15458
15793
|
}
|
|
@@ -15500,13 +15835,13 @@ function computeAdminStoreDivergence(input) {
|
|
|
15500
15835
|
}
|
|
15501
15836
|
for (const entry of entries2) {
|
|
15502
15837
|
if (entry.startsWith(".")) continue;
|
|
15503
|
-
const accountDir =
|
|
15838
|
+
const accountDir = join31(input.accountsDir, entry);
|
|
15504
15839
|
try {
|
|
15505
15840
|
if (!statSync11(accountDir).isDirectory()) continue;
|
|
15506
15841
|
} catch {
|
|
15507
15842
|
continue;
|
|
15508
15843
|
}
|
|
15509
|
-
const accountJsonPath =
|
|
15844
|
+
const accountJsonPath = join31(accountDir, "account.json");
|
|
15510
15845
|
if (!existsSync23(accountJsonPath)) continue;
|
|
15511
15846
|
let admins = [];
|
|
15512
15847
|
try {
|
|
@@ -15684,7 +16019,7 @@ app10.post("/claude-auth", async (c) => {
|
|
|
15684
16019
|
});
|
|
15685
16020
|
persistKeychainService(
|
|
15686
16021
|
writebackResult,
|
|
15687
|
-
(service) => writeFileSync12(
|
|
16022
|
+
(service) => writeFileSync12(join32(dirname11(CLAUDE_CREDENTIALS_FILE), ".keychain-service"), service, { mode: 384 }),
|
|
15688
16023
|
(line) => console.log(line)
|
|
15689
16024
|
);
|
|
15690
16025
|
if (darwinAuthChild === claudeProc2) darwinAuthChild = null;
|
|
@@ -15950,8 +16285,8 @@ var onboarding_default = app10;
|
|
|
15950
16285
|
|
|
15951
16286
|
// server/routes/client-error.ts
|
|
15952
16287
|
import { appendFileSync as appendFileSync4, existsSync as existsSync25, renameSync as renameSync8, statSync as statSync12 } from "fs";
|
|
15953
|
-
import { join as
|
|
15954
|
-
var CLIENT_ERRORS_LOG =
|
|
16288
|
+
import { join as join33 } from "path";
|
|
16289
|
+
var CLIENT_ERRORS_LOG = join33(LOG_DIR, "client-errors.log");
|
|
15955
16290
|
var MAX_LOG_SIZE = 10 * 1024 * 1024;
|
|
15956
16291
|
var MAX_BODY_SIZE = 8 * 1024;
|
|
15957
16292
|
var MAX_STACK_LEN = 2e3;
|
|
@@ -16340,12 +16675,12 @@ import { resolve as resolve21, basename as basename9 } from "path";
|
|
|
16340
16675
|
|
|
16341
16676
|
// app/lib/logs-read-resolve.ts
|
|
16342
16677
|
import { existsSync as existsSync26 } from "fs";
|
|
16343
|
-
import { join as
|
|
16678
|
+
import { join as join34 } from "path";
|
|
16344
16679
|
function resolveSessionLogPaths(filename, logDirs) {
|
|
16345
16680
|
const tried = [filename];
|
|
16346
16681
|
const hits = [];
|
|
16347
16682
|
for (const dir of logDirs) {
|
|
16348
|
-
const fullPath =
|
|
16683
|
+
const fullPath = join34(dir, filename);
|
|
16349
16684
|
if (existsSync26(fullPath)) {
|
|
16350
16685
|
hits.push({ path: fullPath, dir });
|
|
16351
16686
|
}
|
|
@@ -16527,7 +16862,7 @@ app15.get("/", requireAdminSession, (c) => {
|
|
|
16527
16862
|
var claude_info_default = app15;
|
|
16528
16863
|
|
|
16529
16864
|
// server/routes/admin/attachment.ts
|
|
16530
|
-
import { readFile as
|
|
16865
|
+
import { readFile as readFile6, readdir as readdir2 } from "fs/promises";
|
|
16531
16866
|
import { existsSync as existsSync28 } from "fs";
|
|
16532
16867
|
import { resolve as resolve22 } from "path";
|
|
16533
16868
|
var app16 = new Hono();
|
|
@@ -16538,15 +16873,15 @@ function uploadsDirFor2(accountId, attachmentId) {
|
|
|
16538
16873
|
app16.get("/:attachmentId", requireAdminSession, async (c) => {
|
|
16539
16874
|
const attachmentId = c.req.param("attachmentId");
|
|
16540
16875
|
const cacheKey = c.var.cacheKey;
|
|
16541
|
-
const
|
|
16876
|
+
const shortId3 = attachmentId.slice(0, 8);
|
|
16542
16877
|
const shortSession = (c.req.query("session_key") ?? "").slice(0, 8);
|
|
16543
16878
|
const pinnedAccountId = getAccountIdForSession(cacheKey);
|
|
16544
16879
|
if (!pinnedAccountId) {
|
|
16545
|
-
console.log(`[admin-attachment] op=miss attachmentId=${
|
|
16880
|
+
console.log(`[admin-attachment] op=miss attachmentId=${shortId3} session=${shortSession} status=401 reason=no-account`);
|
|
16546
16881
|
return new Response("Unauthorized", { status: 401 });
|
|
16547
16882
|
}
|
|
16548
16883
|
if (!ATTACHMENT_ID_RE3.test(attachmentId)) {
|
|
16549
|
-
console.log(`[admin-attachment] op=miss attachmentId=${
|
|
16884
|
+
console.log(`[admin-attachment] op=miss attachmentId=${shortId3} session=${shortSession} status=404 reason=bad-id`);
|
|
16550
16885
|
return new Response("Not found", { status: 404 });
|
|
16551
16886
|
}
|
|
16552
16887
|
let accountId = pinnedAccountId;
|
|
@@ -16566,7 +16901,7 @@ app16.get("/:attachmentId", requireAdminSession, async (c) => {
|
|
|
16566
16901
|
}
|
|
16567
16902
|
const shortPinned = pinnedAccountId.slice(0, 8);
|
|
16568
16903
|
const crossAccountNote = found && accountId !== pinnedAccountId ? ` resolvedAccount=${accountId.slice(0, 8)}` : "";
|
|
16569
|
-
console.log(`[admin-attachment] op=lookup attachmentId=${
|
|
16904
|
+
console.log(`[admin-attachment] op=lookup attachmentId=${shortId3} session=${shortSession} pinnedAccount=${shortPinned} found=${found}${crossAccountNote}`);
|
|
16570
16905
|
if (!found) {
|
|
16571
16906
|
return new Response("Not found", { status: 404 });
|
|
16572
16907
|
}
|
|
@@ -16576,7 +16911,7 @@ app16.get("/:attachmentId", requireAdminSession, async (c) => {
|
|
|
16576
16911
|
}
|
|
16577
16912
|
let meta;
|
|
16578
16913
|
try {
|
|
16579
|
-
meta = JSON.parse(await
|
|
16914
|
+
meta = JSON.parse(await readFile6(metaPath, "utf-8"));
|
|
16580
16915
|
} catch {
|
|
16581
16916
|
return new Response("Not found", { status: 404 });
|
|
16582
16917
|
}
|
|
@@ -16586,11 +16921,11 @@ app16.get("/:attachmentId", requireAdminSession, async (c) => {
|
|
|
16586
16921
|
return new Response("Not found", { status: 404 });
|
|
16587
16922
|
}
|
|
16588
16923
|
const filePath = resolve22(dir, dataFile);
|
|
16589
|
-
const buffer = await
|
|
16924
|
+
const buffer = await readFile6(filePath);
|
|
16590
16925
|
const inlineSafe = isInlineSafeMime(meta.mimeType);
|
|
16591
16926
|
const safeName = meta.filename.replace(/["\\\r\n]/g, "_");
|
|
16592
16927
|
if (!inlineSafe) {
|
|
16593
|
-
console.log(`[admin-attachment] op=served attachmentId=${
|
|
16928
|
+
console.log(`[admin-attachment] op=served attachmentId=${shortId3} disposition=attachment reason=non-preview-mime mime=${meta.mimeType}`);
|
|
16594
16929
|
}
|
|
16595
16930
|
return new Response(new Uint8Array(buffer), {
|
|
16596
16931
|
headers: {
|
|
@@ -16604,7 +16939,7 @@ app16.get("/:attachmentId", requireAdminSession, async (c) => {
|
|
|
16604
16939
|
var attachment_default = app16;
|
|
16605
16940
|
|
|
16606
16941
|
// server/routes/admin/session-upload.ts
|
|
16607
|
-
import { readFile as
|
|
16942
|
+
import { readFile as readFile7 } from "fs/promises";
|
|
16608
16943
|
import { existsSync as existsSync29, statSync as statSync14 } from "fs";
|
|
16609
16944
|
var app17 = new Hono();
|
|
16610
16945
|
app17.get("/", requireAdminSession, async (c) => {
|
|
@@ -16634,7 +16969,7 @@ app17.get("/", requireAdminSession, async (c) => {
|
|
|
16634
16969
|
const inlineSafe = isInlineSafeMime(mimeType);
|
|
16635
16970
|
const safeName = file.replace(/["\\\r\n]/g, "_");
|
|
16636
16971
|
console.log(`[session-upload] op=served session=${short2} file=${file} disposition=${inlineSafe ? "inline" : "attachment"} mime=${mimeType}`);
|
|
16637
|
-
const buffer = await
|
|
16972
|
+
const buffer = await readFile7(resolution.absolute);
|
|
16638
16973
|
return new Response(new Uint8Array(buffer), {
|
|
16639
16974
|
headers: {
|
|
16640
16975
|
"Content-Type": mimeType,
|
|
@@ -16653,7 +16988,7 @@ import { readdirSync as readdirSync22, readFileSync as readFileSync33, existsSyn
|
|
|
16653
16988
|
// ../services/claude-session-manager/src/tool-surface.ts
|
|
16654
16989
|
import { readFileSync as readFileSync32, readdirSync as readdirSync21, statSync as statSync15, existsSync as existsSync30 } from "fs";
|
|
16655
16990
|
import { createHash as createHash5 } from "crypto";
|
|
16656
|
-
import { join as
|
|
16991
|
+
import { join as join35 } from "path";
|
|
16657
16992
|
|
|
16658
16993
|
// ../services/claude-session-manager/src/canonical-tool-names.ts
|
|
16659
16994
|
function canonicalToolName(plugin, tool) {
|
|
@@ -16906,13 +17241,13 @@ function loadToolSurface(pluginsRoots) {
|
|
|
16906
17241
|
const riskByTool = /* @__PURE__ */ new Map();
|
|
16907
17242
|
const manifestPaths = /* @__PURE__ */ new Map();
|
|
16908
17243
|
const loadOne = (pluginsRoot, plugin) => {
|
|
16909
|
-
const pluginDir =
|
|
17244
|
+
const pluginDir = join35(pluginsRoot, plugin);
|
|
16910
17245
|
try {
|
|
16911
17246
|
if (!statSync15(pluginDir).isDirectory()) return;
|
|
16912
17247
|
} catch {
|
|
16913
17248
|
return;
|
|
16914
17249
|
}
|
|
16915
|
-
const manifestPath =
|
|
17250
|
+
const manifestPath = join35(pluginDir, "PLUGIN.md");
|
|
16916
17251
|
if (!existsSync30(manifestPath)) return;
|
|
16917
17252
|
const raw = readFileSync32(manifestPath, "utf-8");
|
|
16918
17253
|
const frontmatter = extractFrontmatter(raw, plugin);
|
|
@@ -16958,9 +17293,9 @@ function loadToolSurface(pluginsRoots) {
|
|
|
16958
17293
|
for (const root of roots) {
|
|
16959
17294
|
const entries2 = readdirSync21(root).sort();
|
|
16960
17295
|
for (const plugin of entries2) {
|
|
16961
|
-
const pluginDir =
|
|
17296
|
+
const pluginDir = join35(root, plugin);
|
|
16962
17297
|
loadOne(root, plugin);
|
|
16963
|
-
const subRoot =
|
|
17298
|
+
const subRoot = join35(pluginDir, "plugins");
|
|
16964
17299
|
let subEntries;
|
|
16965
17300
|
try {
|
|
16966
17301
|
if (!statSync15(subRoot).isDirectory()) continue;
|
|
@@ -18228,7 +18563,7 @@ var sessions_default = app19;
|
|
|
18228
18563
|
|
|
18229
18564
|
// app/lib/claude-agent/spawn-context.ts
|
|
18230
18565
|
import { existsSync as existsSync33, readFileSync as readFileSync34, readdirSync as readdirSync23, statSync as statSync16 } from "fs";
|
|
18231
|
-
import { dirname as dirname12, resolve as resolve24, join as
|
|
18566
|
+
import { dirname as dirname12, resolve as resolve24, join as join36 } from "path";
|
|
18232
18567
|
async function resolveOwnerProfileBlock(accountId, userId) {
|
|
18233
18568
|
if (!userId) return { ok: false, reason: "missing-user-id" };
|
|
18234
18569
|
try {
|
|
@@ -18269,8 +18604,8 @@ function frontmatterField(manifest, field2) {
|
|
|
18269
18604
|
function extractPluginToolDescriptions(pluginDir) {
|
|
18270
18605
|
const out = /* @__PURE__ */ new Map();
|
|
18271
18606
|
const candidates = [
|
|
18272
|
-
|
|
18273
|
-
|
|
18607
|
+
join36(pluginDir, "mcp/dist/index.js"),
|
|
18608
|
+
join36(pluginDir, "mcp/src/index.ts")
|
|
18274
18609
|
];
|
|
18275
18610
|
let raw = null;
|
|
18276
18611
|
for (const path3 of candidates) {
|
|
@@ -18328,7 +18663,7 @@ function listPluginDirs(accountPluginsDir) {
|
|
|
18328
18663
|
const platformPlugins = resolve24(PLATFORM_ROOT, "plugins");
|
|
18329
18664
|
if (existsSync33(platformPlugins)) {
|
|
18330
18665
|
for (const name of readdirSync23(platformPlugins)) {
|
|
18331
|
-
const dir =
|
|
18666
|
+
const dir = join36(platformPlugins, name);
|
|
18332
18667
|
try {
|
|
18333
18668
|
if (statSync16(dir).isDirectory()) out.set(name, dir);
|
|
18334
18669
|
} catch {
|
|
@@ -18338,11 +18673,11 @@ function listPluginDirs(accountPluginsDir) {
|
|
|
18338
18673
|
const premiumRoot = resolve24(dirname12(PLATFORM_ROOT), "premium-plugins");
|
|
18339
18674
|
if (existsSync33(premiumRoot)) {
|
|
18340
18675
|
for (const bundle of readdirSync23(premiumRoot)) {
|
|
18341
|
-
const bundlePlugins =
|
|
18676
|
+
const bundlePlugins = join36(premiumRoot, bundle, "plugins");
|
|
18342
18677
|
if (!existsSync33(bundlePlugins)) continue;
|
|
18343
18678
|
try {
|
|
18344
18679
|
for (const name of readdirSync23(bundlePlugins)) {
|
|
18345
|
-
const dir =
|
|
18680
|
+
const dir = join36(bundlePlugins, name);
|
|
18346
18681
|
try {
|
|
18347
18682
|
if (statSync16(dir).isDirectory()) out.set(name, dir);
|
|
18348
18683
|
} catch {
|
|
@@ -18356,7 +18691,7 @@ function listPluginDirs(accountPluginsDir) {
|
|
|
18356
18691
|
try {
|
|
18357
18692
|
for (const name of readdirSync23(accountPluginsDir)) {
|
|
18358
18693
|
if (out.has(name)) continue;
|
|
18359
|
-
const dir =
|
|
18694
|
+
const dir = join36(accountPluginsDir, name);
|
|
18360
18695
|
try {
|
|
18361
18696
|
if (statSync16(dir).isDirectory()) out.set(name, dir);
|
|
18362
18697
|
} catch {
|
|
@@ -18375,7 +18710,7 @@ function listAccountPluginNames(accountPluginsDir) {
|
|
|
18375
18710
|
try {
|
|
18376
18711
|
return readdirSync23(accountPluginsDir).filter((name) => {
|
|
18377
18712
|
try {
|
|
18378
|
-
return statSync16(
|
|
18713
|
+
return statSync16(join36(accountPluginsDir, name)).isDirectory();
|
|
18379
18714
|
} catch {
|
|
18380
18715
|
return false;
|
|
18381
18716
|
}
|
|
@@ -18418,7 +18753,7 @@ function computeActivePlugins(accountId) {
|
|
|
18418
18753
|
for (const name of emitNames) {
|
|
18419
18754
|
const dir = pluginDirs.get(name);
|
|
18420
18755
|
if (!dir) continue;
|
|
18421
|
-
const fm = readFrontmatter(
|
|
18756
|
+
const fm = readFrontmatter(join36(dir, "PLUGIN.md"));
|
|
18422
18757
|
if (!fm) continue;
|
|
18423
18758
|
const description = frontmatterField(`---
|
|
18424
18759
|
${fm}
|
|
@@ -18435,7 +18770,7 @@ ${fm}
|
|
|
18435
18770
|
`plugin-manifest-tool-coverage plugin=${name} tools=${tools.length} with-desc=${withDesc}`
|
|
18436
18771
|
);
|
|
18437
18772
|
if (toolNames.length > 0 && descMap.size === 0) {
|
|
18438
|
-
const hasSource = existsSync33(
|
|
18773
|
+
const hasSource = existsSync33(join36(dir, "mcp/dist/index.js")) || existsSync33(join36(dir, "mcp/src/index.ts"));
|
|
18439
18774
|
if (hasSource) {
|
|
18440
18775
|
console.warn(
|
|
18441
18776
|
`[spawn-context] WARN plugin=${name} mcp source present but tool-description regex matched zero entries \u2014 SDK upgrade may have changed the registration shape`
|
|
@@ -18445,7 +18780,7 @@ ${fm}
|
|
|
18445
18780
|
const skillPaths = parseSkillPathsFromFrontmatter(fm);
|
|
18446
18781
|
const skills = [];
|
|
18447
18782
|
for (const relPath of skillPaths) {
|
|
18448
|
-
const skillPath =
|
|
18783
|
+
const skillPath = join36(dir, relPath);
|
|
18449
18784
|
const skillFm = readFrontmatter(skillPath);
|
|
18450
18785
|
if (!skillFm) continue;
|
|
18451
18786
|
const skillName = frontmatterField(`---
|
|
@@ -18489,7 +18824,7 @@ function computeSpecialistDomains(accountId) {
|
|
|
18489
18824
|
const out = [];
|
|
18490
18825
|
for (const file of entries2.sort()) {
|
|
18491
18826
|
if (!file.endsWith(".md")) continue;
|
|
18492
|
-
const fm = readFrontmatter(
|
|
18827
|
+
const fm = readFrontmatter(join36(specialistsDir, file));
|
|
18493
18828
|
if (!fm) continue;
|
|
18494
18829
|
const wrapped = `---
|
|
18495
18830
|
${fm}
|
|
@@ -18885,10 +19220,10 @@ var events_default = app22;
|
|
|
18885
19220
|
|
|
18886
19221
|
// server/routes/admin/files.ts
|
|
18887
19222
|
import { createReadStream as createReadStream2, createWriteStream as createWriteStream2, existsSync as existsSync35 } from "fs";
|
|
18888
|
-
import { readdir as readdir4, readFile as
|
|
19223
|
+
import { readdir as readdir4, readFile as readFile9, stat as stat7, mkdir as mkdir4, unlink as unlink4, rename as rename3, rmdir } from "fs/promises";
|
|
18889
19224
|
import { realpathSync as realpathSync7 } from "fs";
|
|
18890
19225
|
import { randomUUID as randomUUID10 } from "crypto";
|
|
18891
|
-
import { basename as basename11, dirname as dirname13, join as
|
|
19226
|
+
import { basename as basename11, dirname as dirname13, join as join38, relative as relative5, resolve as resolve27, sep as sep8 } from "path";
|
|
18892
19227
|
import { Readable as Readable2 } from "stream";
|
|
18893
19228
|
|
|
18894
19229
|
// ../lib/graph-trash/src/index.ts
|
|
@@ -19206,7 +19541,7 @@ async function cascadeDeleteDocument(params) {
|
|
|
19206
19541
|
|
|
19207
19542
|
// app/lib/file-index.ts
|
|
19208
19543
|
import * as fsp from "fs/promises";
|
|
19209
|
-
import { resolve as resolve26, relative as relative4, join as
|
|
19544
|
+
import { resolve as resolve26, relative as relative4, join as join37, basename as basename10, extname as extname2, sep as sep7 } from "path";
|
|
19210
19545
|
import { tmpdir as tmpdir2 } from "os";
|
|
19211
19546
|
import { execFile as execFile2 } from "child_process";
|
|
19212
19547
|
import { promisify as promisify2 } from "util";
|
|
@@ -19288,7 +19623,7 @@ async function extractPdf(absolute) {
|
|
|
19288
19623
|
return stdout.trim();
|
|
19289
19624
|
}
|
|
19290
19625
|
async function ocrPdf(absolute) {
|
|
19291
|
-
const outPdf =
|
|
19626
|
+
const outPdf = join37(tmpdir2(), `file-index-ocr-${process.pid}-${Date.now()}.pdf`);
|
|
19292
19627
|
try {
|
|
19293
19628
|
await execFileAsync2(
|
|
19294
19629
|
"ocrmypdf",
|
|
@@ -19350,7 +19685,7 @@ async function readDisplayName(absolute) {
|
|
|
19350
19685
|
const stem = dot === -1 ? base : base.slice(0, dot);
|
|
19351
19686
|
if (base === `${stem}.meta.json`) return null;
|
|
19352
19687
|
try {
|
|
19353
|
-
const raw = await fsp.readFile(
|
|
19688
|
+
const raw = await fsp.readFile(join37(dir, `${stem}.meta.json`), "utf-8");
|
|
19354
19689
|
const meta = JSON.parse(raw);
|
|
19355
19690
|
const dn = meta.displayName ?? meta.filename;
|
|
19356
19691
|
return typeof dn === "string" && dn.length > 0 ? dn : null;
|
|
@@ -19371,7 +19706,7 @@ async function walkSubtree(root, dataRoot, out) {
|
|
|
19371
19706
|
for (const entry of entries2) {
|
|
19372
19707
|
if (entry.isSymbolicLink()) continue;
|
|
19373
19708
|
if (entry.isDirectory() && entry.name === ".uploads-tmp") continue;
|
|
19374
|
-
const abs =
|
|
19709
|
+
const abs = join37(root, entry.name);
|
|
19375
19710
|
if (entry.isDirectory()) {
|
|
19376
19711
|
const sub = await walkSubtree(abs, dataRoot, out);
|
|
19377
19712
|
if (!sub.clean) clean = false;
|
|
@@ -19744,7 +20079,7 @@ var UPLOAD_TMP_DIR = ".uploads-tmp";
|
|
|
19744
20079
|
var UUID_RE4 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
19745
20080
|
async function readMeta(absDir, baseName) {
|
|
19746
20081
|
try {
|
|
19747
|
-
const raw = await
|
|
20082
|
+
const raw = await readFile9(join38(absDir, `${baseName}.meta.json`), "utf8");
|
|
19748
20083
|
const parsed = JSON.parse(raw);
|
|
19749
20084
|
if (typeof parsed?.filename === "string") {
|
|
19750
20085
|
return { filename: parsed.filename, mimeType: typeof parsed.mimeType === "string" ? parsed.mimeType : void 0 };
|
|
@@ -19766,7 +20101,7 @@ async function readAccountNames() {
|
|
|
19766
20101
|
if (!UUID_RE4.test(name)) continue;
|
|
19767
20102
|
const configPath2 = resolve27(accountsDir, name, "account.json");
|
|
19768
20103
|
try {
|
|
19769
|
-
const raw = await
|
|
20104
|
+
const raw = await readFile9(configPath2, "utf8");
|
|
19770
20105
|
const parsed = JSON.parse(raw);
|
|
19771
20106
|
if (typeof parsed?.name === "string" && parsed.name.length > 0) {
|
|
19772
20107
|
map.set(name, parsed.name);
|
|
@@ -19799,7 +20134,7 @@ async function servableFilesIn(dirAbs, uuid) {
|
|
|
19799
20134
|
}
|
|
19800
20135
|
async function enrich(absolute, entry, accountNames) {
|
|
19801
20136
|
if (entry.kind === "directory" && UUID_RE4.test(entry.name)) {
|
|
19802
|
-
const dirAbs =
|
|
20137
|
+
const dirAbs = join38(absolute, entry.name);
|
|
19803
20138
|
const meta = await readMeta(dirAbs, entry.name);
|
|
19804
20139
|
if (meta?.filename) {
|
|
19805
20140
|
const servable = await servableFilesIn(dirAbs, entry.name);
|
|
@@ -19808,7 +20143,7 @@ async function enrich(absolute, entry, accountNames) {
|
|
|
19808
20143
|
let size = null;
|
|
19809
20144
|
let modifiedAt = entry.modifiedAt;
|
|
19810
20145
|
try {
|
|
19811
|
-
const st = await stat7(
|
|
20146
|
+
const st = await stat7(join38(dirAbs, innerName));
|
|
19812
20147
|
size = st.size;
|
|
19813
20148
|
modifiedAt = st.mtime.toISOString();
|
|
19814
20149
|
} catch {
|
|
@@ -20001,7 +20336,7 @@ app23.get("/", requireAdminSession, async (c) => {
|
|
|
20001
20336
|
const childRel = relPath === "" || relPath === "." ? name : `${relPath}/${name}`;
|
|
20002
20337
|
const protectedEntry = isProtectedFromDeletion(childRel).protected;
|
|
20003
20338
|
try {
|
|
20004
|
-
const entryPath =
|
|
20339
|
+
const entryPath = join38(absolute, name);
|
|
20005
20340
|
const s = await stat7(entryPath);
|
|
20006
20341
|
entries2.push({
|
|
20007
20342
|
name,
|
|
@@ -20030,7 +20365,7 @@ app23.get("/", requireAdminSession, async (c) => {
|
|
|
20030
20365
|
const displayPath = buildDisplayPath(relPath, accountNames);
|
|
20031
20366
|
if (groupReq || isAccountRoot(relPath)) {
|
|
20032
20367
|
const acctId = relPath.split("/")[1] ?? accountId;
|
|
20033
|
-
const schemaMd = await
|
|
20368
|
+
const schemaMd = await readFile9(join38(absolute, "SCHEMA.md"), "utf8").catch(() => null);
|
|
20034
20369
|
const groups = classifyAccountRoot(schemaMd, entries2.map((e) => e.name));
|
|
20035
20370
|
console.error(
|
|
20036
20371
|
`[data-schema] op=classify account=${acctId} status=${groups.parsed ? "ok" : "parse-failed"} reason=${groups.reason} entries=${entries2.length} home=${groups.home.join(",") || "none"} system=${groups.system.length} unknown=${groups.unknown.join(",") || "none"}`
|
|
@@ -20068,7 +20403,7 @@ app23.get("/", requireAdminSession, async (c) => {
|
|
|
20068
20403
|
for (const name of homeDirs) {
|
|
20069
20404
|
const base = byName.get(name);
|
|
20070
20405
|
try {
|
|
20071
|
-
const dirents = await readdir4(
|
|
20406
|
+
const dirents = await readdir4(join38(absolute, name), { withFileTypes: true });
|
|
20072
20407
|
const visible = dirents.filter((d) => !d.name.startsWith("."));
|
|
20073
20408
|
visible.sort((a, b) => {
|
|
20074
20409
|
const ad = a.isDirectory() ? 0 : 1;
|
|
@@ -20133,7 +20468,7 @@ app23.get("/download", requireAdminSession, async (c) => {
|
|
|
20133
20468
|
console.error(`[data] op=scratchpad-no-session sessionId="${sessionId.slice(0, 8)}\u2026"`);
|
|
20134
20469
|
return c.json({ error: "Not found" }, 404);
|
|
20135
20470
|
}
|
|
20136
|
-
const meta = readSidecarMeta(
|
|
20471
|
+
const meta = readSidecarMeta(join38(projectDir, `${sessionId}.meta.json`));
|
|
20137
20472
|
if (!meta.accountId || meta.accountId !== accountId) {
|
|
20138
20473
|
console.error(`[data] account-scope-blocked root="scratchpad" sessionId="${sessionId.slice(0, 8)}\u2026" account=${accountId.slice(0, 8)}\u2026`);
|
|
20139
20474
|
return c.json({ error: "Not found" }, 404);
|
|
@@ -20228,7 +20563,7 @@ async function* walkRegularFiles(dirAbsolute) {
|
|
|
20228
20563
|
const dirents = await readdir4(dirAbsolute, { withFileTypes: true });
|
|
20229
20564
|
for (const d of dirents) {
|
|
20230
20565
|
if (d.isSymbolicLink()) continue;
|
|
20231
|
-
const child =
|
|
20566
|
+
const child = join38(dirAbsolute, d.name);
|
|
20232
20567
|
if (d.isDirectory()) {
|
|
20233
20568
|
yield* walkRegularFiles(child);
|
|
20234
20569
|
continue;
|
|
@@ -20257,7 +20592,7 @@ app23.get("/download-zip", requireAdminSession, async (c) => {
|
|
|
20257
20592
|
if (entries2.length >= maxFiles) return c.json({ error: `Too many files (max ${maxFiles})` }, 413);
|
|
20258
20593
|
total += size;
|
|
20259
20594
|
if (total > maxTotalBytes) return c.json({ error: "Selection too large to zip" }, 413);
|
|
20260
|
-
entries2.push({ name: member, data: await
|
|
20595
|
+
entries2.push({ name: member, data: await readFile9(absolute) });
|
|
20261
20596
|
return null;
|
|
20262
20597
|
};
|
|
20263
20598
|
for (const rawPath of rawPaths) {
|
|
@@ -20338,7 +20673,7 @@ async function resolveUploadTarget(c, accountId, uid) {
|
|
|
20338
20673
|
const base = resolveOwnAccountWrite(rawDir, accountId, "POST /api/admin/files/upload");
|
|
20339
20674
|
if (!base.ok) return { ok: false, status: base.status, error: base.error };
|
|
20340
20675
|
const relDir = relpath ? dirname13(relpath) : ".";
|
|
20341
|
-
const destRel = relDir === "." ? base.relative :
|
|
20676
|
+
const destRel = relDir === "." ? base.relative : join38(base.relative, relDir);
|
|
20342
20677
|
if (crossesForeignAccountPartition(destRel, accountId)) {
|
|
20343
20678
|
console.error(`[data] account-scope-blocked endpoint="POST /api/admin/files/upload" path="${destRel}" account=${accountId.slice(0, 8)}\u2026`);
|
|
20344
20679
|
return { ok: false, status: 404, error: "Not found" };
|
|
@@ -20410,7 +20745,7 @@ app23.post("/upload", requireAdminSession, async (c) => {
|
|
|
20410
20745
|
out.once("close", () => res());
|
|
20411
20746
|
out.destroy();
|
|
20412
20747
|
});
|
|
20413
|
-
await
|
|
20748
|
+
await unlink4(tmpPath).catch(() => {
|
|
20414
20749
|
});
|
|
20415
20750
|
const tempRemoved = !existsSync35(tmpPath);
|
|
20416
20751
|
console.error(`[data-upload] op=cleanup uid=${uid} tempRemoved=${tempRemoved}`);
|
|
@@ -20456,7 +20791,7 @@ app23.post("/upload", requireAdminSession, async (c) => {
|
|
|
20456
20791
|
out.once("error", rej);
|
|
20457
20792
|
out.end(() => res());
|
|
20458
20793
|
});
|
|
20459
|
-
await
|
|
20794
|
+
await rename3(tmpPath, destPath);
|
|
20460
20795
|
} catch (err) {
|
|
20461
20796
|
const message = err instanceof Error ? err.message : String(err);
|
|
20462
20797
|
console.error(`[data-upload] op=error uid=${uid} err="${message}" token=${token} rel="${relpath ?? ""}"`);
|
|
@@ -20484,7 +20819,7 @@ async function discardChunkUpload(uploadId, state) {
|
|
|
20484
20819
|
state.out.once("close", () => res());
|
|
20485
20820
|
state.out.destroy();
|
|
20486
20821
|
});
|
|
20487
|
-
await
|
|
20822
|
+
await unlink4(state.tmpPath).catch(() => {
|
|
20488
20823
|
});
|
|
20489
20824
|
const tempRemoved = !existsSync35(state.tmpPath);
|
|
20490
20825
|
console.error(`[data-upload] op=cleanup uid=${uploadId} tempRemoved=${tempRemoved}`);
|
|
@@ -20612,11 +20947,11 @@ async function acceptChunk(c, uploadId, state, seq, body, ceiling) {
|
|
|
20612
20947
|
state.out.once("error", rej);
|
|
20613
20948
|
state.out.end(() => res());
|
|
20614
20949
|
});
|
|
20615
|
-
await
|
|
20950
|
+
await rename3(state.tmpPath, state.destPath);
|
|
20616
20951
|
} catch (err) {
|
|
20617
20952
|
const message = err instanceof Error ? err.message : String(err);
|
|
20618
20953
|
console.error(`[data-upload] op=error uid=${uploadId} err="${message}" token=${state.token} rel="${state.relpath ?? ""}"`);
|
|
20619
|
-
await
|
|
20954
|
+
await unlink4(state.tmpPath).catch(() => {
|
|
20620
20955
|
});
|
|
20621
20956
|
return c.json({ error: message }, 500);
|
|
20622
20957
|
}
|
|
@@ -20668,7 +21003,7 @@ async function sweepStaleUploadTemps() {
|
|
|
20668
21003
|
}
|
|
20669
21004
|
for (const name of entries2) {
|
|
20670
21005
|
try {
|
|
20671
|
-
await
|
|
21006
|
+
await unlink4(resolve27(tmpDir, name));
|
|
20672
21007
|
removed++;
|
|
20673
21008
|
} catch {
|
|
20674
21009
|
}
|
|
@@ -20715,17 +21050,17 @@ app23.delete("/", requireAdminSession, async (c) => {
|
|
|
20715
21050
|
const dot = base.lastIndexOf(".");
|
|
20716
21051
|
const stem = dot === -1 ? base : base.slice(0, dot);
|
|
20717
21052
|
const containerDir = dirname13(absolute);
|
|
20718
|
-
const sidecarPath = UUID_RE4.test(stem) && base !== `${stem}.meta.json` ?
|
|
21053
|
+
const sidecarPath = UUID_RE4.test(stem) && base !== `${stem}.meta.json` ? join38(containerDir, `${stem}.meta.json`) : null;
|
|
20719
21054
|
const isAttachmentContainer = UUID_RE4.test(stem) && basename11(containerDir) === stem;
|
|
20720
|
-
await
|
|
21055
|
+
await unlink4(absolute);
|
|
20721
21056
|
if (sidecarPath) {
|
|
20722
21057
|
try {
|
|
20723
|
-
await
|
|
21058
|
+
await unlink4(sidecarPath);
|
|
20724
21059
|
} catch {
|
|
20725
21060
|
}
|
|
20726
21061
|
}
|
|
20727
21062
|
if (isAttachmentContainer) {
|
|
20728
|
-
await
|
|
21063
|
+
await unlink4(join38(containerDir, `${stem}${EXTRACTED_TEXT_SUFFIX}`)).catch(() => {
|
|
20729
21064
|
});
|
|
20730
21065
|
await rmdir(containerDir).catch(() => {
|
|
20731
21066
|
});
|
|
@@ -20832,7 +21167,7 @@ app23.post("/rename", requireAdminSession, async (c) => {
|
|
|
20832
21167
|
if (e.code === "ENOENT") collision = false;
|
|
20833
21168
|
}
|
|
20834
21169
|
if (collision) return c.json({ error: "A file or folder with that name already exists" }, 409);
|
|
20835
|
-
await
|
|
21170
|
+
await rename3(src.absolute, destAbs);
|
|
20836
21171
|
} catch (err) {
|
|
20837
21172
|
const code = err.code;
|
|
20838
21173
|
if (code === "ENOENT") return c.json({ error: "Not found" }, 404);
|
|
@@ -21835,7 +22170,7 @@ function isHiddenByDefault(label) {
|
|
|
21835
22170
|
// server/lib/top-level-labels.ts
|
|
21836
22171
|
var import_dist5 = __toESM(require_dist4(), 1);
|
|
21837
22172
|
import { readdirSync as readdirSync24, readFileSync as readFileSync36 } from "fs";
|
|
21838
|
-
import { join as
|
|
22173
|
+
import { join as join39, resolve as resolve28 } from "path";
|
|
21839
22174
|
var STATIC_TOP_LEVEL_LABELS = Object.freeze(
|
|
21840
22175
|
/* @__PURE__ */ new Set([
|
|
21841
22176
|
// Base-schema infra (schema-base.md has no top-level section).
|
|
@@ -21939,7 +22274,7 @@ function parseTopLevelLabels(content) {
|
|
|
21939
22274
|
}
|
|
21940
22275
|
function resolveReferencesDir() {
|
|
21941
22276
|
if (process.env.MAXY_PLATFORM_ROOT) {
|
|
21942
|
-
return
|
|
22277
|
+
return join39(process.env.MAXY_PLATFORM_ROOT, "plugins", "memory", "references");
|
|
21943
22278
|
}
|
|
21944
22279
|
return resolve28(import.meta.dirname, "../../../plugins/memory/references");
|
|
21945
22280
|
}
|
|
@@ -21949,7 +22284,7 @@ function parseTableTopLevelLabels(referencesDir) {
|
|
|
21949
22284
|
try {
|
|
21950
22285
|
const fileNames = readdirSync24(referencesDir).filter((f) => f.startsWith("schema-") && f.endsWith(".md")).sort();
|
|
21951
22286
|
for (const fileName of fileNames) {
|
|
21952
|
-
const content = readFileSync36(
|
|
22287
|
+
const content = readFileSync36(join39(referencesDir, fileName), "utf-8");
|
|
21953
22288
|
const parsed = parseTopLevelLabels(content);
|
|
21954
22289
|
if (parsed.length > 0) contributingFiles.push(fileName);
|
|
21955
22290
|
for (const label of parsed) labels.add(label);
|
|
@@ -23288,11 +23623,11 @@ var sidebar_artefacts_default = app30;
|
|
|
23288
23623
|
|
|
23289
23624
|
// server/channel-session-override.ts
|
|
23290
23625
|
import { readFileSync as readFileSync37, writeFileSync as writeFileSync14, renameSync as renameSync10 } from "fs";
|
|
23291
|
-
import { join as
|
|
23626
|
+
import { join as join40 } from "path";
|
|
23292
23627
|
var FILE2 = "channel-session-override.json";
|
|
23293
23628
|
var UUID3 = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/;
|
|
23294
23629
|
function channelOverridePath(accountDir) {
|
|
23295
|
-
return
|
|
23630
|
+
return join40(accountDir, FILE2);
|
|
23296
23631
|
}
|
|
23297
23632
|
function senderKey(channel, senderId) {
|
|
23298
23633
|
return `${channel}:${senderId}`;
|
|
@@ -23688,24 +24023,24 @@ var session_rc_spawn_default = app36;
|
|
|
23688
24023
|
import { randomUUID as randomUUID12 } from "crypto";
|
|
23689
24024
|
|
|
23690
24025
|
// server/wa-descriptor.ts
|
|
23691
|
-
import { resolve as resolve30, join as
|
|
24026
|
+
import { resolve as resolve30, join as join41 } from "path";
|
|
23692
24027
|
function waGatewayUrl() {
|
|
23693
24028
|
return `http://127.0.0.1:${process.env.MAXY_UI_INTERNAL_PORT ?? ""}`;
|
|
23694
24029
|
}
|
|
23695
24030
|
function waServerPath() {
|
|
23696
|
-
return process.env.MAXY_WA_CHANNEL_SERVER_PATH ?? resolve30(process.env.MAXY_PLATFORM_ROOT ??
|
|
24031
|
+
return process.env.MAXY_WA_CHANNEL_SERVER_PATH ?? resolve30(process.env.MAXY_PLATFORM_ROOT ?? join41(__dirname, ".."), "services/whatsapp-channel/dist/server.js");
|
|
23697
24032
|
}
|
|
23698
24033
|
function waChannelDescriptor(senderId) {
|
|
23699
24034
|
return { senderId, gatewayUrl: waGatewayUrl(), serverPath: waServerPath() };
|
|
23700
24035
|
}
|
|
23701
24036
|
|
|
23702
24037
|
// server/telegram-descriptor.ts
|
|
23703
|
-
import { resolve as resolve31, join as
|
|
24038
|
+
import { resolve as resolve31, join as join42 } from "path";
|
|
23704
24039
|
function telegramGatewayUrl() {
|
|
23705
24040
|
return `http://127.0.0.1:${process.env.MAXY_UI_INTERNAL_PORT ?? ""}`;
|
|
23706
24041
|
}
|
|
23707
24042
|
function telegramServerPath() {
|
|
23708
|
-
return process.env.MAXY_TELEGRAM_CHANNEL_SERVER_PATH ?? resolve31(process.env.MAXY_PLATFORM_ROOT ??
|
|
24043
|
+
return process.env.MAXY_TELEGRAM_CHANNEL_SERVER_PATH ?? resolve31(process.env.MAXY_PLATFORM_ROOT ?? join42(__dirname, ".."), "services/telegram-channel/dist/server.js");
|
|
23709
24044
|
}
|
|
23710
24045
|
function telegramChannelDescriptor(senderId) {
|
|
23711
24046
|
return { senderId, gatewayUrl: telegramGatewayUrl(), serverPath: telegramServerPath() };
|
|
@@ -23870,7 +24205,7 @@ app37.post("/", requireAdminSession, async (c) => {
|
|
|
23870
24205
|
var session_reseat_default = app37;
|
|
23871
24206
|
|
|
23872
24207
|
// server/routes/admin/system-stats.ts
|
|
23873
|
-
import { readFile as
|
|
24208
|
+
import { readFile as readFile10 } from "fs/promises";
|
|
23874
24209
|
import { cpus, loadavg, totalmem, freemem } from "os";
|
|
23875
24210
|
function parseCpuStat(blob) {
|
|
23876
24211
|
const line = blob.split("\n", 1)[0] ?? "";
|
|
@@ -23914,11 +24249,11 @@ function parseMeminfo(blob) {
|
|
|
23914
24249
|
}
|
|
23915
24250
|
var SAMPLE_DELAY_MS = 100;
|
|
23916
24251
|
async function sampleLinux() {
|
|
23917
|
-
const a = parseCpuStat(await
|
|
24252
|
+
const a = parseCpuStat(await readFile10("/proc/stat", "utf-8"));
|
|
23918
24253
|
await new Promise((r) => setTimeout(r, SAMPLE_DELAY_MS));
|
|
23919
|
-
const b = parseCpuStat(await
|
|
23920
|
-
const meminfo = parseMeminfo(await
|
|
23921
|
-
const loadavgRaw = (await
|
|
24254
|
+
const b = parseCpuStat(await readFile10("/proc/stat", "utf-8"));
|
|
24255
|
+
const meminfo = parseMeminfo(await readFile10("/proc/meminfo", "utf-8"));
|
|
24256
|
+
const loadavgRaw = (await readFile10("/proc/loadavg", "utf-8")).trim();
|
|
23922
24257
|
const [l1, l5, l15] = loadavgRaw.split(/\s+/, 3).map(Number);
|
|
23923
24258
|
if (![l1, l5, l15].every(Number.isFinite)) {
|
|
23924
24259
|
throw new Error(`malformed /proc/loadavg: ${loadavgRaw}`);
|
|
@@ -23992,10 +24327,10 @@ var system_stats_default = app38;
|
|
|
23992
24327
|
|
|
23993
24328
|
// server/routes/admin/health.ts
|
|
23994
24329
|
import { existsSync as existsSync37, readFileSync as readFileSync38 } from "fs";
|
|
23995
|
-
import { resolve as resolve32, join as
|
|
24330
|
+
import { resolve as resolve32, join as join43 } from "path";
|
|
23996
24331
|
var PLATFORM_ROOT6 = process.env.MAXY_PLATFORM_ROOT ?? resolve32(process.cwd(), "..");
|
|
23997
24332
|
var brandHostname = "maxy";
|
|
23998
|
-
var brandJsonPath =
|
|
24333
|
+
var brandJsonPath = join43(PLATFORM_ROOT6, "config", "brand.json");
|
|
23999
24334
|
if (existsSync37(brandJsonPath)) {
|
|
24000
24335
|
try {
|
|
24001
24336
|
const brand = JSON.parse(readFileSync38(brandJsonPath, "utf-8"));
|
|
@@ -24785,7 +25120,7 @@ var browser_default = app46;
|
|
|
24785
25120
|
|
|
24786
25121
|
// server/routes/admin/calendar.ts
|
|
24787
25122
|
import { existsSync as existsSync38 } from "fs";
|
|
24788
|
-
import { join as
|
|
25123
|
+
import { join as join45 } from "path";
|
|
24789
25124
|
|
|
24790
25125
|
// server/lib/calendar-ics.ts
|
|
24791
25126
|
var CRLF = "\r\n";
|
|
@@ -24885,7 +25220,7 @@ function countVEvents(ics) {
|
|
|
24885
25220
|
|
|
24886
25221
|
// server/lib/calendar-availability.ts
|
|
24887
25222
|
import { readFileSync as readFileSync39 } from "fs";
|
|
24888
|
-
import { join as
|
|
25223
|
+
import { join as join44 } from "path";
|
|
24889
25224
|
var AVAILABILITY_FILENAME = "calendar-availability.json";
|
|
24890
25225
|
var REQUIRED_KEYS = [
|
|
24891
25226
|
"timezone",
|
|
@@ -24894,7 +25229,7 @@ var REQUIRED_KEYS = [
|
|
|
24894
25229
|
"weekly"
|
|
24895
25230
|
];
|
|
24896
25231
|
function readAvailabilityConfig(accountDir) {
|
|
24897
|
-
const path3 =
|
|
25232
|
+
const path3 = join44(accountDir, AVAILABILITY_FILENAME);
|
|
24898
25233
|
let raw;
|
|
24899
25234
|
try {
|
|
24900
25235
|
raw = readFileSync39(path3, "utf-8");
|
|
@@ -25257,7 +25592,7 @@ app47.get("/booking-link", requireAdminSession, (c) => {
|
|
|
25257
25592
|
}
|
|
25258
25593
|
const id82 = account.accountId.slice(0, 8);
|
|
25259
25594
|
try {
|
|
25260
|
-
if (!existsSync38(
|
|
25595
|
+
if (!existsSync38(join45(account.accountDir, AVAILABILITY_FILENAME))) {
|
|
25261
25596
|
console.log(`[calendar] op=booking-link accountId=${id82} bookingDomain=none source=availability-config`);
|
|
25262
25597
|
return c.json({ bookingDomain: null });
|
|
25263
25598
|
}
|
|
@@ -25657,7 +25992,7 @@ async function computeTaskList(accountId) {
|
|
|
25657
25992
|
{ accountId }
|
|
25658
25993
|
);
|
|
25659
25994
|
const graphTotal = totalResult.records.length > 0 ? toNum(totalResult.records[0].get("total")) : 0;
|
|
25660
|
-
const
|
|
25995
|
+
const open3 = [];
|
|
25661
25996
|
const completed = [];
|
|
25662
25997
|
let missingTaskId = 0;
|
|
25663
25998
|
let missingCreatedAt = 0;
|
|
@@ -25692,7 +26027,7 @@ async function computeTaskList(accountId) {
|
|
|
25692
26027
|
assigneeName
|
|
25693
26028
|
};
|
|
25694
26029
|
if (COMPLETED.has(status)) completed.push(row);
|
|
25695
|
-
else if (!HIDDEN_FROM_OPEN.has(status))
|
|
26030
|
+
else if (!HIDDEN_FROM_OPEN.has(status)) open3.push(row);
|
|
25696
26031
|
}
|
|
25697
26032
|
const returned = result.records.length;
|
|
25698
26033
|
if (returned < graphTotal) {
|
|
@@ -25701,9 +26036,9 @@ async function computeTaskList(accountId) {
|
|
|
25701
26036
|
);
|
|
25702
26037
|
}
|
|
25703
26038
|
console.log(
|
|
25704
|
-
`${TAG40} op=list account=${accountId} returned=${returned} graphTotal=${graphTotal} open=${
|
|
26039
|
+
`${TAG40} op=list account=${accountId} returned=${returned} graphTotal=${graphTotal} open=${open3.length} completed=${completed.length} missingTaskId=${missingTaskId} missingCreatedAt=${missingCreatedAt} assigned=${assigned}`
|
|
25705
26040
|
);
|
|
25706
|
-
return { open, completed };
|
|
26041
|
+
return { open: open3, completed };
|
|
25707
26042
|
} catch (err) {
|
|
25708
26043
|
console.error(`${TAG40} op=list error="${err instanceof Error ? err.message : String(err)}"`);
|
|
25709
26044
|
return null;
|
|
@@ -25744,14 +26079,14 @@ app51.post("/", requireAdminSession, async (c) => {
|
|
|
25744
26079
|
console.error(`${TAG41} op=start taskId=${taskId} accountId=${accountId} result=task-not-found`);
|
|
25745
26080
|
return c.json({ error: "task-not-found" }, 404);
|
|
25746
26081
|
}
|
|
25747
|
-
const
|
|
26082
|
+
const open3 = await session.run(
|
|
25748
26083
|
`MATCH (te:TimeEntry {accountId: $accountId, taskId: $taskId}) WHERE te.endedAt IS NULL
|
|
25749
26084
|
RETURN te.entryId AS entryId, te.startedAt AS startedAt
|
|
25750
26085
|
ORDER BY te.startedAt LIMIT 1`,
|
|
25751
26086
|
{ accountId, taskId }
|
|
25752
26087
|
);
|
|
25753
|
-
const priorEntryId =
|
|
25754
|
-
const priorStartedAt =
|
|
26088
|
+
const priorEntryId = open3.records[0]?.get("entryId");
|
|
26089
|
+
const priorStartedAt = open3.records[0]?.get("startedAt");
|
|
25755
26090
|
if (priorEntryId) {
|
|
25756
26091
|
console.log(`${TAG41} op=start taskId=${taskId} accountId=${accountId} result=already-running`);
|
|
25757
26092
|
invalidate("tasks-list", accountId);
|
|
@@ -25799,14 +26134,14 @@ app52.post("/", requireAdminSession, async (c) => {
|
|
|
25799
26134
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
25800
26135
|
const session = getSession();
|
|
25801
26136
|
try {
|
|
25802
|
-
const
|
|
26137
|
+
const open3 = await session.run(
|
|
25803
26138
|
`MATCH (te:TimeEntry {taskId: $taskId, accountId: $accountId}) WHERE te.endedAt IS NULL
|
|
25804
26139
|
RETURN te.entryId AS entryId, te.startedAt AS startedAt
|
|
25805
26140
|
ORDER BY te.startedAt LIMIT 1`,
|
|
25806
26141
|
{ taskId, accountId }
|
|
25807
26142
|
);
|
|
25808
|
-
const entryId =
|
|
25809
|
-
const startedAt =
|
|
26143
|
+
const entryId = open3.records[0]?.get("entryId");
|
|
26144
|
+
const startedAt = open3.records[0]?.get("startedAt");
|
|
25810
26145
|
if (!entryId || !startedAt) {
|
|
25811
26146
|
const cur = await session.run(
|
|
25812
26147
|
`MATCH (t:Task {taskId: $taskId, accountId: $accountId})
|
|
@@ -26807,7 +27142,7 @@ var VISITOR_COOKIE_MAX_AGE_SECONDS = Math.floor(DEFAULT_TTL_MS / 1e3);
|
|
|
26807
27142
|
|
|
26808
27143
|
// app/lib/brand-config.ts
|
|
26809
27144
|
import { existsSync as existsSync42, readFileSync as readFileSync44 } from "fs";
|
|
26810
|
-
import { join as
|
|
27145
|
+
import { join as join46 } from "path";
|
|
26811
27146
|
var cached2 = null;
|
|
26812
27147
|
var cachedAttempted = false;
|
|
26813
27148
|
function readBrandConfig() {
|
|
@@ -26815,7 +27150,7 @@ function readBrandConfig() {
|
|
|
26815
27150
|
cachedAttempted = true;
|
|
26816
27151
|
const platformRoot5 = process.env.MAXY_PLATFORM_ROOT;
|
|
26817
27152
|
if (!platformRoot5) return null;
|
|
26818
|
-
const brandPath =
|
|
27153
|
+
const brandPath = join46(platformRoot5, "config", "brand.json");
|
|
26819
27154
|
if (!existsSync42(brandPath)) return null;
|
|
26820
27155
|
try {
|
|
26821
27156
|
cached2 = JSON.parse(readFileSync44(brandPath, "utf-8"));
|
|
@@ -27570,9 +27905,9 @@ function computeOpenSlots(config, busy, fromISO, toISO) {
|
|
|
27570
27905
|
const weekday = WEEKDAYS[new Date(Date.UTC(y, m - 1, d)).getUTCDay()];
|
|
27571
27906
|
const windows = config.weekly[weekday] ?? [];
|
|
27572
27907
|
for (const [openStr, closeStr] of windows) {
|
|
27573
|
-
const
|
|
27908
|
+
const open3 = parseHHMM(openStr);
|
|
27574
27909
|
const close = parseHHMM(closeStr);
|
|
27575
|
-
const openUtc = zonedWallClockToUtc(y, m, d,
|
|
27910
|
+
const openUtc = zonedWallClockToUtc(y, m, d, open3.hh, open3.mm, tz).getTime();
|
|
27576
27911
|
const closeUtc = zonedWallClockToUtc(y, m, d, close.hh, close.mm, tz).getTime();
|
|
27577
27912
|
for (let s = openUtc; s + durMs <= closeUtc; s += durMs) {
|
|
27578
27913
|
const slotEnd = s + durMs;
|
|
@@ -27659,8 +27994,8 @@ var calendar_public_default = app67;
|
|
|
27659
27994
|
|
|
27660
27995
|
// server/routes/portal-fetch.ts
|
|
27661
27996
|
import { createReadStream as createReadStream3 } from "fs";
|
|
27662
|
-
import { stat as stat9, readFile as
|
|
27663
|
-
import { join as
|
|
27997
|
+
import { stat as stat9, readFile as readFile11, realpath } from "fs/promises";
|
|
27998
|
+
import { join as join47, resolve as resolve38, sep as sep10 } from "path";
|
|
27664
27999
|
import { Readable as Readable3 } from "stream";
|
|
27665
28000
|
var app68 = new Hono();
|
|
27666
28001
|
var TAG50 = "[portal-fetch]";
|
|
@@ -27716,7 +28051,7 @@ async function readAccountSecret(accountId) {
|
|
|
27716
28051
|
const path3 = resolve38(DATA_ROOT, "accounts", accountId, "secrets", "data-portal.env");
|
|
27717
28052
|
let text;
|
|
27718
28053
|
try {
|
|
27719
|
-
text = await
|
|
28054
|
+
text = await readFile11(path3, "utf8");
|
|
27720
28055
|
} catch {
|
|
27721
28056
|
console.error(`${TAG50} op=no-secret account="${accountId}" path="${path3}"`);
|
|
27722
28057
|
return "";
|
|
@@ -27733,7 +28068,7 @@ function isValidAccountId2(value) {
|
|
|
27733
28068
|
}
|
|
27734
28069
|
async function readExposeFolders2(accountDir) {
|
|
27735
28070
|
try {
|
|
27736
|
-
const cfg = JSON.parse(await
|
|
28071
|
+
const cfg = JSON.parse(await readFile11(join47(accountDir, "data-portal.json"), "utf8"));
|
|
27737
28072
|
return Array.isArray(cfg?.exposeFolders) ? cfg.exposeFolders.filter((f) => typeof f === "string") : [];
|
|
27738
28073
|
} catch {
|
|
27739
28074
|
return [];
|
|
@@ -27742,7 +28077,7 @@ async function readExposeFolders2(accountDir) {
|
|
|
27742
28077
|
async function resolveFetchTarget(accountDir, relPath, ownerId) {
|
|
27743
28078
|
let schemaText = null;
|
|
27744
28079
|
try {
|
|
27745
|
-
schemaText = await
|
|
28080
|
+
schemaText = await readFile11(join47(accountDir, "SCHEMA.md"), "utf8");
|
|
27746
28081
|
} catch {
|
|
27747
28082
|
schemaText = null;
|
|
27748
28083
|
}
|
|
@@ -27913,7 +28248,7 @@ function startTimeEntryCensus(openSession, opts = {}) {
|
|
|
27913
28248
|
|
|
27914
28249
|
// app/lib/ledger-census.ts
|
|
27915
28250
|
import { readdirSync as readdirSync28, readFileSync as readFileSync45, statSync as statSync19 } from "fs";
|
|
27916
|
-
import { join as
|
|
28251
|
+
import { join as join48 } from "path";
|
|
27917
28252
|
|
|
27918
28253
|
// ../lib/ledger-core/dist/reconcile.js
|
|
27919
28254
|
var LEDGER_INDEX_NAMES = [
|
|
@@ -27967,7 +28302,7 @@ function countWriteRejects24h(logDir, now) {
|
|
|
27967
28302
|
}
|
|
27968
28303
|
let total = 0;
|
|
27969
28304
|
for (const name of entries2) {
|
|
27970
|
-
const path3 =
|
|
28305
|
+
const path3 = join48(logDir, name);
|
|
27971
28306
|
try {
|
|
27972
28307
|
if (now - statSync19(path3).mtimeMs > DAY_MS) continue;
|
|
27973
28308
|
for (const line of readFileSync45(path3, "utf8").split("\n")) {
|
|
@@ -28341,7 +28676,7 @@ async function startFileWatcher(opts = {}) {
|
|
|
28341
28676
|
}
|
|
28342
28677
|
|
|
28343
28678
|
// app/lib/migrate-uploads.ts
|
|
28344
|
-
import { mkdir as mkdir6, readdir as readdir6, rename as
|
|
28679
|
+
import { mkdir as mkdir6, readdir as readdir6, rename as rename4, rm as rm3 } from "fs/promises";
|
|
28345
28680
|
import { dirname as dirname15, relative as relative7, resolve as resolve40 } from "path";
|
|
28346
28681
|
var ACCOUNT_UUID_RE5 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
28347
28682
|
async function walkFiles(dir) {
|
|
@@ -28375,7 +28710,7 @@ async function relocateTree(srcDir, destDir, dataRoot, accountId, session) {
|
|
|
28375
28710
|
const suffix = relative7(srcDir, oldAbs);
|
|
28376
28711
|
const newAbs = resolve40(destDir, suffix);
|
|
28377
28712
|
await mkdir6(dirname15(newAbs), { recursive: true });
|
|
28378
|
-
await
|
|
28713
|
+
await rename4(oldAbs, newAbs);
|
|
28379
28714
|
moved++;
|
|
28380
28715
|
const oldRel = relative7(dataRoot, oldAbs);
|
|
28381
28716
|
const newRel = relative7(dataRoot, newAbs);
|
|
@@ -28464,9 +28799,9 @@ async function migrateUploads(opts = {}) {
|
|
|
28464
28799
|
}
|
|
28465
28800
|
|
|
28466
28801
|
// app/lib/migrate-admin-webchat-sidecars.ts
|
|
28467
|
-
import { readdir as readdir7, readFile as
|
|
28802
|
+
import { readdir as readdir7, readFile as readFile12, rename as rename5, writeFile as writeFile6, unlink as unlink5 } from "fs/promises";
|
|
28468
28803
|
import { existsSync as existsSync44 } from "fs";
|
|
28469
|
-
import { join as
|
|
28804
|
+
import { join as join49 } from "path";
|
|
28470
28805
|
var ADMIN_ROLE2 = "admin";
|
|
28471
28806
|
var WEBCHAT_CHANNEL2 = "webchat";
|
|
28472
28807
|
var SESSION_META_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\.meta\.json$/i;
|
|
@@ -28477,7 +28812,7 @@ var defaultResolveName = async (_accountId, userId) => {
|
|
|
28477
28812
|
async function readRaw3(path3) {
|
|
28478
28813
|
let raw;
|
|
28479
28814
|
try {
|
|
28480
|
-
raw = await
|
|
28815
|
+
raw = await readFile12(path3, "utf8");
|
|
28481
28816
|
} catch {
|
|
28482
28817
|
return null;
|
|
28483
28818
|
}
|
|
@@ -28491,11 +28826,11 @@ async function readRaw3(path3) {
|
|
|
28491
28826
|
async function writeRaw(path3, obj) {
|
|
28492
28827
|
const tmp = `${path3}.tmp.${process.pid}.${Date.now()}`;
|
|
28493
28828
|
try {
|
|
28494
|
-
await
|
|
28495
|
-
await
|
|
28829
|
+
await writeFile6(tmp, JSON.stringify(obj, null, 2), "utf8");
|
|
28830
|
+
await rename5(tmp, path3);
|
|
28496
28831
|
} catch (err) {
|
|
28497
28832
|
try {
|
|
28498
|
-
if (existsSync44(tmp)) await
|
|
28833
|
+
if (existsSync44(tmp)) await unlink5(tmp);
|
|
28499
28834
|
} catch {
|
|
28500
28835
|
}
|
|
28501
28836
|
throw err;
|
|
@@ -28511,7 +28846,7 @@ async function collectLiveSidecars(projectsRoot) {
|
|
|
28511
28846
|
}
|
|
28512
28847
|
for (const slug of slugs) {
|
|
28513
28848
|
if (!slug.isDirectory()) continue;
|
|
28514
|
-
const slugDir =
|
|
28849
|
+
const slugDir = join49(projectsRoot, slug.name);
|
|
28515
28850
|
let entries2;
|
|
28516
28851
|
try {
|
|
28517
28852
|
entries2 = await readdir7(slugDir, { withFileTypes: true });
|
|
@@ -28520,9 +28855,9 @@ async function collectLiveSidecars(projectsRoot) {
|
|
|
28520
28855
|
}
|
|
28521
28856
|
for (const entry of entries2) {
|
|
28522
28857
|
if (entry.isFile() && SESSION_META_RE.test(entry.name)) {
|
|
28523
|
-
out.push(
|
|
28858
|
+
out.push(join49(slugDir, entry.name));
|
|
28524
28859
|
} else if (entry.isDirectory() && entry.name === "subagents") {
|
|
28525
|
-
const subDir =
|
|
28860
|
+
const subDir = join49(slugDir, entry.name);
|
|
28526
28861
|
let subs;
|
|
28527
28862
|
try {
|
|
28528
28863
|
subs = await readdir7(subDir, { withFileTypes: true });
|
|
@@ -28530,7 +28865,7 @@ async function collectLiveSidecars(projectsRoot) {
|
|
|
28530
28865
|
continue;
|
|
28531
28866
|
}
|
|
28532
28867
|
for (const s of subs) {
|
|
28533
|
-
if (s.isFile() && SESSION_META_RE.test(s.name)) out.push(
|
|
28868
|
+
if (s.isFile() && SESSION_META_RE.test(s.name)) out.push(join49(subDir, s.name));
|
|
28534
28869
|
}
|
|
28535
28870
|
}
|
|
28536
28871
|
}
|
|
@@ -28542,7 +28877,7 @@ function shortId(path3) {
|
|
|
28542
28877
|
return base.slice(0, 8);
|
|
28543
28878
|
}
|
|
28544
28879
|
async function migrateAdminWebchatSidecars(opts = {}) {
|
|
28545
|
-
const projectsRoot = opts.projectsRoot ?? (process.env.CLAUDE_CONFIG_DIR ?
|
|
28880
|
+
const projectsRoot = opts.projectsRoot ?? (process.env.CLAUDE_CONFIG_DIR ? join49(process.env.CLAUDE_CONFIG_DIR, "projects") : null) ?? "";
|
|
28546
28881
|
const usersFile = opts.usersFile ?? USERS_FILE;
|
|
28547
28882
|
const accountId = opts.accountId ?? resolveAccount()?.accountId ?? null;
|
|
28548
28883
|
const resolveName = opts.resolveName ?? defaultResolveName;
|
|
@@ -28616,6 +28951,129 @@ async function migrateAdminWebchatSidecars(opts = {}) {
|
|
|
28616
28951
|
return result;
|
|
28617
28952
|
}
|
|
28618
28953
|
|
|
28954
|
+
// app/lib/migrate-sidecar-account-ids.ts
|
|
28955
|
+
import { readdir as readdir8, readFile as readFile13, rename as rename6, writeFile as writeFile7, unlink as unlink6 } from "fs/promises";
|
|
28956
|
+
import { existsSync as existsSync45 } from "fs";
|
|
28957
|
+
import { join as join50 } from "path";
|
|
28958
|
+
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;
|
|
28959
|
+
function projectSlugForCwd(cwd) {
|
|
28960
|
+
return cwd.replace(/\//g, "-");
|
|
28961
|
+
}
|
|
28962
|
+
async function readRaw4(path3) {
|
|
28963
|
+
let raw;
|
|
28964
|
+
try {
|
|
28965
|
+
raw = await readFile13(path3, "utf8");
|
|
28966
|
+
} catch {
|
|
28967
|
+
return null;
|
|
28968
|
+
}
|
|
28969
|
+
try {
|
|
28970
|
+
const parsed = JSON.parse(raw);
|
|
28971
|
+
return parsed && typeof parsed === "object" ? parsed : null;
|
|
28972
|
+
} catch {
|
|
28973
|
+
return null;
|
|
28974
|
+
}
|
|
28975
|
+
}
|
|
28976
|
+
async function writeRaw2(path3, obj) {
|
|
28977
|
+
const tmp = `${path3}.tmp.${process.pid}.${Date.now()}`;
|
|
28978
|
+
try {
|
|
28979
|
+
await writeFile7(tmp, JSON.stringify(obj, null, 2), "utf8");
|
|
28980
|
+
await rename6(tmp, path3);
|
|
28981
|
+
} catch (err) {
|
|
28982
|
+
try {
|
|
28983
|
+
if (existsSync45(tmp)) await unlink6(tmp);
|
|
28984
|
+
} catch {
|
|
28985
|
+
}
|
|
28986
|
+
throw err;
|
|
28987
|
+
}
|
|
28988
|
+
}
|
|
28989
|
+
function shortId2(path3) {
|
|
28990
|
+
const base = path3.slice(path3.lastIndexOf("/") + 1).replace(/\.meta\.json$/, "");
|
|
28991
|
+
return base.slice(0, 8);
|
|
28992
|
+
}
|
|
28993
|
+
async function collectSidecars(projectsRoot) {
|
|
28994
|
+
const out = [];
|
|
28995
|
+
let slugs;
|
|
28996
|
+
try {
|
|
28997
|
+
slugs = await readdir8(projectsRoot, { withFileTypes: true });
|
|
28998
|
+
} catch {
|
|
28999
|
+
return out;
|
|
29000
|
+
}
|
|
29001
|
+
for (const slug of slugs) {
|
|
29002
|
+
if (!slug.isDirectory()) continue;
|
|
29003
|
+
const slugDir = join50(projectsRoot, slug.name);
|
|
29004
|
+
let entries2;
|
|
29005
|
+
try {
|
|
29006
|
+
entries2 = await readdir8(slugDir, { withFileTypes: true });
|
|
29007
|
+
} catch {
|
|
29008
|
+
continue;
|
|
29009
|
+
}
|
|
29010
|
+
for (const entry of entries2) {
|
|
29011
|
+
if (entry.isFile() && SESSION_META_RE2.test(entry.name)) {
|
|
29012
|
+
out.push({ path: join50(slugDir, entry.name), slug: slug.name });
|
|
29013
|
+
} else if (entry.isDirectory() && (entry.name === "subagents" || entry.name === "archive")) {
|
|
29014
|
+
const subDir = join50(slugDir, entry.name);
|
|
29015
|
+
let subs;
|
|
29016
|
+
try {
|
|
29017
|
+
subs = await readdir8(subDir, { withFileTypes: true });
|
|
29018
|
+
} catch {
|
|
29019
|
+
continue;
|
|
29020
|
+
}
|
|
29021
|
+
for (const s of subs) {
|
|
29022
|
+
if (s.isFile() && SESSION_META_RE2.test(s.name)) {
|
|
29023
|
+
out.push({ path: join50(subDir, s.name), slug: slug.name });
|
|
29024
|
+
}
|
|
29025
|
+
}
|
|
29026
|
+
}
|
|
29027
|
+
}
|
|
29028
|
+
}
|
|
29029
|
+
return out;
|
|
29030
|
+
}
|
|
29031
|
+
async function migrateSidecarAccountIds(opts = {}) {
|
|
29032
|
+
const projectsRoot = opts.projectsRoot ?? (process.env.CLAUDE_CONFIG_DIR ? join50(process.env.CLAUDE_CONFIG_DIR, "projects") : null) ?? "";
|
|
29033
|
+
const accounts = opts.accounts ?? listValidAccounts();
|
|
29034
|
+
const result = {
|
|
29035
|
+
scanned: 0,
|
|
29036
|
+
backfilled: 0,
|
|
29037
|
+
skippedHasId: 0,
|
|
29038
|
+
skippedUnknownSlug: 0,
|
|
29039
|
+
verified: 0
|
|
29040
|
+
};
|
|
29041
|
+
if (!projectsRoot) {
|
|
29042
|
+
console.error("[sidecar-account-backfill] skip reason=no-projects-root");
|
|
29043
|
+
return result;
|
|
29044
|
+
}
|
|
29045
|
+
const accountBySlug = /* @__PURE__ */ new Map();
|
|
29046
|
+
for (const a of accounts) accountBySlug.set(projectSlugForCwd(a.accountDir), a.accountId);
|
|
29047
|
+
for (const { path: path3, slug } of await collectSidecars(projectsRoot)) {
|
|
29048
|
+
const raw = await readRaw4(path3);
|
|
29049
|
+
if (!raw) continue;
|
|
29050
|
+
result.scanned++;
|
|
29051
|
+
if (typeof raw.accountId === "string" && raw.accountId.length > 0) {
|
|
29052
|
+
result.skippedHasId++;
|
|
29053
|
+
continue;
|
|
29054
|
+
}
|
|
29055
|
+
const accountId = accountBySlug.get(slug);
|
|
29056
|
+
if (!accountId) {
|
|
29057
|
+
result.skippedUnknownSlug++;
|
|
29058
|
+
console.error(`[sidecar-account-backfill] skip sessionId=${shortId2(path3)} reason=slug-not-in-registry slug=${slug}`);
|
|
29059
|
+
continue;
|
|
29060
|
+
}
|
|
29061
|
+
raw.accountId = accountId;
|
|
29062
|
+
await writeRaw2(path3, raw);
|
|
29063
|
+
result.backfilled++;
|
|
29064
|
+
const back = await readRaw4(path3);
|
|
29065
|
+
if (back && back.accountId === accountId) {
|
|
29066
|
+
result.verified++;
|
|
29067
|
+
} else {
|
|
29068
|
+
console.error(`[sidecar-account-backfill] post-write-verify-failed sessionId=${shortId2(path3)} accountId=${accountId.slice(0, 8)}`);
|
|
29069
|
+
}
|
|
29070
|
+
}
|
|
29071
|
+
console.error(
|
|
29072
|
+
`[sidecar-account-backfill] op=sidecar-account scanned=${result.scanned} backfilled=${result.backfilled} skipped-has-id=${result.skippedHasId} skipped-unknown-slug=${result.skippedUnknownSlug} verified=${result.verified}`
|
|
29073
|
+
);
|
|
29074
|
+
return result;
|
|
29075
|
+
}
|
|
29076
|
+
|
|
28619
29077
|
// app/lib/whatsapp/gateway/inbound-hub.ts
|
|
28620
29078
|
var InboundHub = class {
|
|
28621
29079
|
senders = /* @__PURE__ */ new Map();
|
|
@@ -30841,7 +31299,7 @@ function buildTelegramSpawnRequest(input) {
|
|
|
30841
31299
|
|
|
30842
31300
|
// app/lib/telegram/outbound/send-document.ts
|
|
30843
31301
|
import { realpathSync as realpathSync10 } from "fs";
|
|
30844
|
-
import { readFile as
|
|
31302
|
+
import { readFile as readFile14, stat as stat11 } from "fs/promises";
|
|
30845
31303
|
import { resolve as resolve42, basename as basename13 } from "path";
|
|
30846
31304
|
var TAG56 = "[telegram:outbound]";
|
|
30847
31305
|
var TELEGRAM_DOCUMENT_MAX_BYTES = 50 * 1024 * 1024;
|
|
@@ -30891,7 +31349,7 @@ async function sendTelegramDocument(input) {
|
|
|
30891
31349
|
};
|
|
30892
31350
|
}
|
|
30893
31351
|
const filename = basename13(resolvedPath);
|
|
30894
|
-
const buffer = Buffer.from(await
|
|
31352
|
+
const buffer = Buffer.from(await readFile14(resolvedPath));
|
|
30895
31353
|
const form = new FormData();
|
|
30896
31354
|
form.append("chat_id", String(chatId));
|
|
30897
31355
|
if (caption) form.append("caption", caption);
|
|
@@ -31245,12 +31703,12 @@ function warnOnChannelAdminBindingDrift() {
|
|
|
31245
31703
|
}
|
|
31246
31704
|
|
|
31247
31705
|
// server/lib/booking-site-accounts.ts
|
|
31248
|
-
import { existsSync as
|
|
31706
|
+
import { existsSync as existsSync46, readFileSync as readFileSync46 } from "fs";
|
|
31249
31707
|
import { resolve as resolve43 } from "path";
|
|
31250
31708
|
function listBookingSiteAccounts(accounts) {
|
|
31251
31709
|
return accounts.filter((a) => {
|
|
31252
31710
|
const availPath = resolve43(a.accountDir, "calendar-availability.json");
|
|
31253
|
-
if (!
|
|
31711
|
+
if (!existsSync46(availPath)) return false;
|
|
31254
31712
|
try {
|
|
31255
31713
|
const cfg = JSON.parse(readFileSync46(availPath, "utf-8"));
|
|
31256
31714
|
return typeof cfg.bookingDbName === "string" && cfg.bookingDbName.length > 0;
|
|
@@ -31290,7 +31748,7 @@ function broadcastAdminShutdown(reason) {
|
|
|
31290
31748
|
|
|
31291
31749
|
// ../lib/entitlement/src/index.ts
|
|
31292
31750
|
import { createPublicKey, createHash as createHash7, verify as cryptoVerify } from "crypto";
|
|
31293
|
-
import { existsSync as
|
|
31751
|
+
import { existsSync as existsSync47, readFileSync as readFileSync47, statSync as statSync20 } from "fs";
|
|
31294
31752
|
import { resolve as resolve44 } from "path";
|
|
31295
31753
|
|
|
31296
31754
|
// ../lib/entitlement/src/canonicalize.ts
|
|
@@ -31339,7 +31797,7 @@ function resolveEntitlement(brand, account) {
|
|
|
31339
31797
|
return logResolved(implicitTrust(account), null);
|
|
31340
31798
|
}
|
|
31341
31799
|
const entitlementPath = resolve44(brand.configDir, "entitlement.json");
|
|
31342
|
-
if (!
|
|
31800
|
+
if (!existsSync47(entitlementPath)) {
|
|
31343
31801
|
return logResolved(anonymousFallback("missing"), { reason: "missing" });
|
|
31344
31802
|
}
|
|
31345
31803
|
const stat12 = statSync20(entitlementPath);
|
|
@@ -31530,12 +31988,12 @@ function clientFrom(c) {
|
|
|
31530
31988
|
}
|
|
31531
31989
|
installMediaDownloadGuard();
|
|
31532
31990
|
var PLATFORM_ROOT8 = process.env.MAXY_PLATFORM_ROOT || "";
|
|
31533
|
-
var BRAND_JSON_PATH = PLATFORM_ROOT8 ?
|
|
31991
|
+
var BRAND_JSON_PATH = PLATFORM_ROOT8 ? join51(PLATFORM_ROOT8, "config", "brand.json") : "";
|
|
31534
31992
|
var BRAND = { productName: "Maxy", hostname: "maxy", configDir: ".maxy", marketingUrl: "https://getmaxy.com" };
|
|
31535
|
-
if (BRAND_JSON_PATH && !
|
|
31993
|
+
if (BRAND_JSON_PATH && !existsSync48(BRAND_JSON_PATH)) {
|
|
31536
31994
|
console.error(`[brand] WARNING: brand.json not found at ${BRAND_JSON_PATH} \u2014 using Maxy defaults`);
|
|
31537
31995
|
}
|
|
31538
|
-
if (BRAND_JSON_PATH &&
|
|
31996
|
+
if (BRAND_JSON_PATH && existsSync48(BRAND_JSON_PATH)) {
|
|
31539
31997
|
try {
|
|
31540
31998
|
const parsed = JSON.parse(readFileSync48(BRAND_JSON_PATH, "utf-8"));
|
|
31541
31999
|
BRAND = { ...BRAND, ...parsed };
|
|
@@ -31569,10 +32027,10 @@ var brandLoginOpts = {
|
|
|
31569
32027
|
appleTouchIconPath: brandAppIcon512Path,
|
|
31570
32028
|
themeColor: BRAND.defaultColors?.primary
|
|
31571
32029
|
};
|
|
31572
|
-
var ALIAS_DOMAINS_PATH =
|
|
32030
|
+
var ALIAS_DOMAINS_PATH = join51(homedir4(), BRAND.configDir, "alias-domains.json");
|
|
31573
32031
|
function loadAliasDomains() {
|
|
31574
32032
|
try {
|
|
31575
|
-
if (!
|
|
32033
|
+
if (!existsSync48(ALIAS_DOMAINS_PATH)) return null;
|
|
31576
32034
|
const parsed = JSON.parse(readFileSync48(ALIAS_DOMAINS_PATH, "utf-8"));
|
|
31577
32035
|
if (!Array.isArray(parsed)) {
|
|
31578
32036
|
console.error("[alias-domains] malformed alias-domains.json \u2014 expected array");
|
|
@@ -31648,7 +32106,7 @@ var waGateway = new WaGateway({
|
|
|
31648
32106
|
fetchStandingRules: fetchAccountStandingRules,
|
|
31649
32107
|
resolveSessionOverride: (accountId, senderId) => resolveChannelOverride(accountId, "whatsapp", senderId),
|
|
31650
32108
|
gatewayUrl: `http://127.0.0.1:${process.env.MAXY_UI_INTERNAL_PORT ?? ""}`,
|
|
31651
|
-
serverPath: process.env.MAXY_WA_CHANNEL_SERVER_PATH ?? resolve45(process.env.MAXY_PLATFORM_ROOT ??
|
|
32109
|
+
serverPath: process.env.MAXY_WA_CHANNEL_SERVER_PATH ?? resolve45(process.env.MAXY_PLATFORM_ROOT ?? join51(__dirname, ".."), "services/whatsapp-channel/dist/server.js"),
|
|
31652
32110
|
// Task 751 / 1390 — file delivery on the native channel. `maxyAccountId` (the
|
|
31653
32111
|
// path-validation scope) is the sender's effective SESSION account, resolved
|
|
31654
32112
|
// once at the inbound gate and threaded here via the gateway's per-sender doc
|
|
@@ -31663,7 +32121,7 @@ var waGateway = new WaGateway({
|
|
|
31663
32121
|
caption,
|
|
31664
32122
|
accountId,
|
|
31665
32123
|
maxyAccountId,
|
|
31666
|
-
platformRoot: resolve45(process.env.MAXY_PLATFORM_ROOT ??
|
|
32124
|
+
platformRoot: resolve45(process.env.MAXY_PLATFORM_ROOT ?? join51(__dirname, ".."))
|
|
31667
32125
|
});
|
|
31668
32126
|
return result.ok ? { ok: true, messageId: result.messageId } : { ok: false, error: result.error };
|
|
31669
32127
|
},
|
|
@@ -31781,7 +32239,7 @@ function runDuplicateSenderAudit() {
|
|
|
31781
32239
|
try {
|
|
31782
32240
|
const configDir2 = process.env.CLAUDE_CONFIG_DIR;
|
|
31783
32241
|
if (!configDir2) return;
|
|
31784
|
-
const projectsRoot =
|
|
32242
|
+
const projectsRoot = join51(configDir2, "projects");
|
|
31785
32243
|
const records = [];
|
|
31786
32244
|
for (const { path: jsonlPath, isSubagent, archived } of enumerateJsonls(projectsRoot)) {
|
|
31787
32245
|
if (isSubagent || archived) continue;
|
|
@@ -32356,7 +32814,7 @@ app69.get("/agent-assets/:slug/:filename", (c) => {
|
|
|
32356
32814
|
console.error(`[agent-assets] path-traversal-rejected slug=${slug} file=${filename}`);
|
|
32357
32815
|
return c.text("Forbidden", 403);
|
|
32358
32816
|
}
|
|
32359
|
-
if (!
|
|
32817
|
+
if (!existsSync48(filePath)) {
|
|
32360
32818
|
console.error(`[agent-assets] serve slug=${slug} file=${filename} status=404`);
|
|
32361
32819
|
return c.text("Not found", 404);
|
|
32362
32820
|
}
|
|
@@ -32386,7 +32844,7 @@ app69.get("/generated/:filename", (c) => {
|
|
|
32386
32844
|
console.error(`[generated] serve file=${filename} status=403`);
|
|
32387
32845
|
return c.text("Forbidden", 403);
|
|
32388
32846
|
}
|
|
32389
|
-
if (!
|
|
32847
|
+
if (!existsSync48(filePath)) {
|
|
32390
32848
|
console.error(`[generated] serve file=${filename} status=404`);
|
|
32391
32849
|
return c.text("Not found", 404);
|
|
32392
32850
|
}
|
|
@@ -32406,7 +32864,7 @@ app69.route("/v", visitor_consent_default);
|
|
|
32406
32864
|
var htmlCache = /* @__PURE__ */ new Map();
|
|
32407
32865
|
var brandLogoPath = "/brand/maxy-monochrome.png";
|
|
32408
32866
|
var brandIconPath = "/brand/maxy-monochrome.png";
|
|
32409
|
-
if (BRAND_JSON_PATH &&
|
|
32867
|
+
if (BRAND_JSON_PATH && existsSync48(BRAND_JSON_PATH)) {
|
|
32410
32868
|
try {
|
|
32411
32869
|
const fullBrand = JSON.parse(readFileSync48(BRAND_JSON_PATH, "utf-8"));
|
|
32412
32870
|
if (fullBrand.assets?.logo) brandLogoPath = `/brand/${fullBrand.assets.logo}`;
|
|
@@ -32435,7 +32893,7 @@ var brandScript = `<script>window.__BRAND__=${JSON.stringify({
|
|
|
32435
32893
|
var brandThemeColor = BRAND.defaultColors?.primary ?? "#000000";
|
|
32436
32894
|
var brandBackgroundColor = BRAND.defaultColors?.background ?? "#ffffff";
|
|
32437
32895
|
var brandAppIconsExist = [brandAppIcon192Path, brandAppIcon512Path, brandMaskableIconPath].every(
|
|
32438
|
-
(p) =>
|
|
32896
|
+
(p) => existsSync48(resolve45(process.cwd(), "public", p.replace(/^\//, "")))
|
|
32439
32897
|
);
|
|
32440
32898
|
var SW_SOURCE = (() => {
|
|
32441
32899
|
try {
|
|
@@ -32447,8 +32905,8 @@ var SW_SOURCE = (() => {
|
|
|
32447
32905
|
function readInstalledVersion() {
|
|
32448
32906
|
try {
|
|
32449
32907
|
if (!PLATFORM_ROOT8) return "unknown";
|
|
32450
|
-
const versionFile =
|
|
32451
|
-
if (!
|
|
32908
|
+
const versionFile = join51(PLATFORM_ROOT8, "config", `.${BRAND.hostname}-version`);
|
|
32909
|
+
if (!existsSync48(versionFile)) return "unknown";
|
|
32452
32910
|
const content = readFileSync48(versionFile, "utf-8").trim();
|
|
32453
32911
|
return content || "unknown";
|
|
32454
32912
|
} catch {
|
|
@@ -32457,36 +32915,6 @@ function readInstalledVersion() {
|
|
|
32457
32915
|
}
|
|
32458
32916
|
var INSTALLED_VERSION = readInstalledVersion();
|
|
32459
32917
|
var versionScript = `<script>window.__MAXY_VERSION__=${JSON.stringify(INSTALLED_VERSION)}</script>`;
|
|
32460
|
-
var clientErrorReporterScript = `<script>
|
|
32461
|
-
(function(){
|
|
32462
|
-
var send=function(b){
|
|
32463
|
-
try{
|
|
32464
|
-
fetch('/api/_client-error',{
|
|
32465
|
-
method:'POST',
|
|
32466
|
-
headers:{'content-type':'application/json'},
|
|
32467
|
-
body:JSON.stringify(Object.assign({url:location.href,ua:navigator.userAgent,version:(window.__MAXY_VERSION__||'unknown')},b)),
|
|
32468
|
-
keepalive:true
|
|
32469
|
-
}).catch(function(){});
|
|
32470
|
-
}catch(e){}
|
|
32471
|
-
};
|
|
32472
|
-
window.addEventListener('error',function(e){
|
|
32473
|
-
var t=e.target;
|
|
32474
|
-
if(t&&t!==window&&t.tagName)send({kind:'subresource',tag:t.tagName,url:t.src||t.href||''});
|
|
32475
|
-
else send({kind:'uncaught',msg:e.message,filename:e.filename,lineno:e.lineno,colno:e.colno,stack:(e.error&&e.error.stack)||''});
|
|
32476
|
-
},true);
|
|
32477
|
-
window.addEventListener('unhandledrejection',function(e){
|
|
32478
|
-
var r=e.reason;
|
|
32479
|
-
send({kind:'unhandled-rejection',msg:String((r&&r.message)||r),stack:(r&&r.stack)||''});
|
|
32480
|
-
});
|
|
32481
|
-
try{
|
|
32482
|
-
new PerformanceObserver(function(list){
|
|
32483
|
-
list.getEntries().forEach(function(entry){
|
|
32484
|
-
if(entry.responseStatus>=400)send({kind:'subresource',url:entry.name,status:entry.responseStatus});
|
|
32485
|
-
});
|
|
32486
|
-
}).observe({type:'resource',buffered:true});
|
|
32487
|
-
}catch(e){}
|
|
32488
|
-
})();
|
|
32489
|
-
</script>`;
|
|
32490
32918
|
function cachedHtml(file) {
|
|
32491
32919
|
let html = htmlCache.get(file);
|
|
32492
32920
|
if (!html) {
|
|
@@ -32507,12 +32935,12 @@ ${clientErrorReporterScript}
|
|
|
32507
32935
|
return html;
|
|
32508
32936
|
}
|
|
32509
32937
|
function loadBrandingCache(agentSlug) {
|
|
32510
|
-
const configDir2 =
|
|
32938
|
+
const configDir2 = join51(homedir4(), BRAND.configDir);
|
|
32511
32939
|
try {
|
|
32512
32940
|
const accountId = getDefaultAccountId();
|
|
32513
32941
|
if (!accountId) return null;
|
|
32514
|
-
const cachePath =
|
|
32515
|
-
if (!
|
|
32942
|
+
const cachePath = join51(configDir2, "branding-cache", accountId, `${agentSlug}.json`);
|
|
32943
|
+
if (!existsSync48(cachePath)) return null;
|
|
32516
32944
|
return JSON.parse(readFileSync48(cachePath, "utf-8"));
|
|
32517
32945
|
} catch {
|
|
32518
32946
|
return null;
|
|
@@ -32760,10 +33188,10 @@ var hostname = process.env.HOSTNAME ?? "127.0.0.1";
|
|
|
32760
33188
|
var httpServer = serve({ fetch: app69.fetch, port, hostname });
|
|
32761
33189
|
console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
32762
33190
|
{
|
|
32763
|
-
const reconcilePlatformRoot = process.env.MAXY_PLATFORM_ROOT ??
|
|
33191
|
+
const reconcilePlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join51(__dirname, "..");
|
|
32764
33192
|
const reconcileScript = resolve45(reconcilePlatformRoot, "plugins/scheduling/mcp/dist/scripts/reconcile-bookings.js");
|
|
32765
33193
|
const runReconcile = (ctx) => {
|
|
32766
|
-
if (!
|
|
33194
|
+
if (!existsSync48(reconcileScript)) return;
|
|
32767
33195
|
try {
|
|
32768
33196
|
const child = spawn3(process.execPath, [reconcileScript], {
|
|
32769
33197
|
env: { ...process.env, PLATFORM_ROOT: reconcilePlatformRoot },
|
|
@@ -32783,7 +33211,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
32783
33211
|
detached: true,
|
|
32784
33212
|
run: runReconcile
|
|
32785
33213
|
});
|
|
32786
|
-
const reconcileStatePath =
|
|
33214
|
+
const reconcileStatePath = join51(MAXY_DIR, "booking-reconcile-state.json");
|
|
32787
33215
|
registerLoop({
|
|
32788
33216
|
name: "calendar-reconcile-liveness",
|
|
32789
33217
|
intervalMs: 6e5,
|
|
@@ -32801,7 +33229,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
32801
33229
|
}
|
|
32802
33230
|
{
|
|
32803
33231
|
const DREAM_CYCLE_SWEEP_INTERVAL_MS = 36e5;
|
|
32804
|
-
const dreamPlatformRoot = process.env.MAXY_PLATFORM_ROOT ??
|
|
33232
|
+
const dreamPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join51(__dirname, "..");
|
|
32805
33233
|
const dreamSweepScript = resolve45(dreamPlatformRoot, "plugins/memory/mcp/dist/scripts/dream-cycle-sweep.js");
|
|
32806
33234
|
registerLoop({
|
|
32807
33235
|
name: "dream-cycle-sweep",
|
|
@@ -32809,7 +33237,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
32809
33237
|
firstRunDelayMs: 3e4,
|
|
32810
33238
|
detached: true,
|
|
32811
33239
|
run: (ctx) => {
|
|
32812
|
-
if (!
|
|
33240
|
+
if (!existsSync48(dreamSweepScript)) return;
|
|
32813
33241
|
try {
|
|
32814
33242
|
const child = spawn3(process.execPath, [dreamSweepScript], {
|
|
32815
33243
|
env: { ...process.env, PLATFORM_ROOT: dreamPlatformRoot },
|
|
@@ -32825,11 +33253,11 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
32825
33253
|
});
|
|
32826
33254
|
}
|
|
32827
33255
|
{
|
|
32828
|
-
const outlookPlatformRoot = process.env.MAXY_PLATFORM_ROOT ??
|
|
33256
|
+
const outlookPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join51(__dirname, "..");
|
|
32829
33257
|
const outlookScript = resolve45(outlookPlatformRoot, "plugins/outlook/mcp/dist/scripts/complete-registration.js");
|
|
32830
33258
|
const OUTLOOK_COMPLETE_INTERVAL_MS = 3e4;
|
|
32831
33259
|
const runOutlookComplete = (ctx) => {
|
|
32832
|
-
if (!
|
|
33260
|
+
if (!existsSync48(outlookScript)) return;
|
|
32833
33261
|
try {
|
|
32834
33262
|
const child = spawn3(process.execPath, [outlookScript], {
|
|
32835
33263
|
env: { ...process.env, PLATFORM_ROOT: outlookPlatformRoot },
|
|
@@ -32851,19 +33279,19 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
32851
33279
|
});
|
|
32852
33280
|
}
|
|
32853
33281
|
{
|
|
32854
|
-
const auditRoot = process.env.MAXY_PLATFORM_ROOT ??
|
|
33282
|
+
const auditRoot = process.env.MAXY_PLATFORM_ROOT ?? join51(__dirname, "..");
|
|
32855
33283
|
const strandedAccountsDir = resolve45(auditRoot, "..", "data/accounts");
|
|
32856
33284
|
const STRANDED_AUDIT_INTERVAL_MS = 3e5;
|
|
32857
33285
|
const STRANDED_AGE_MS = 16 * 6e4;
|
|
32858
33286
|
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;
|
|
32859
33287
|
const runStrandedAudit = () => {
|
|
32860
33288
|
try {
|
|
32861
|
-
if (!
|
|
33289
|
+
if (!existsSync48(strandedAccountsDir)) return;
|
|
32862
33290
|
const now = Date.now();
|
|
32863
33291
|
for (const name of readdirSync29(strandedAccountsDir)) {
|
|
32864
33292
|
if (!STRANDED_UUID_RE.test(name)) continue;
|
|
32865
33293
|
const pendingPath2 = resolve45(strandedAccountsDir, name, "secrets/outlook/pending-devicecode.enc");
|
|
32866
|
-
if (!
|
|
33294
|
+
if (!existsSync48(pendingPath2)) continue;
|
|
32867
33295
|
const ageMs2 = now - statSync21(pendingPath2).mtimeMs;
|
|
32868
33296
|
if (ageMs2 > STRANDED_AGE_MS) {
|
|
32869
33297
|
console.error(`[outlook-mcp] devicecode-stranded account=${name} ageSec=${Math.floor(ageMs2 / 1e3)}`);
|
|
@@ -32881,7 +33309,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
32881
33309
|
});
|
|
32882
33310
|
}
|
|
32883
33311
|
{
|
|
32884
|
-
const googleRoot = process.env.MAXY_PLATFORM_ROOT ??
|
|
33312
|
+
const googleRoot = process.env.MAXY_PLATFORM_ROOT ?? join51(__dirname, "..");
|
|
32885
33313
|
const googleAccountsDir = resolve45(googleRoot, "..", "data/accounts");
|
|
32886
33314
|
const GOOGLE_PENDING_AUDIT_INTERVAL_MS = 3e5;
|
|
32887
33315
|
const runGooglePendingAuditSafe = () => {
|
|
@@ -32900,7 +33328,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
32900
33328
|
const googleAuditScript = resolve45(googleRoot, "plugins/google/mcp/dist/scripts/account-audit.js");
|
|
32901
33329
|
const GOOGLE_ACCOUNT_AUDIT_INTERVAL_MS = 36e5;
|
|
32902
33330
|
const runGoogleAccountAudit = (ctx) => {
|
|
32903
|
-
if (!
|
|
33331
|
+
if (!existsSync48(googleAuditScript)) return;
|
|
32904
33332
|
try {
|
|
32905
33333
|
const child = spawn3(process.execPath, [googleAuditScript], {
|
|
32906
33334
|
env: { ...process.env, PLATFORM_ROOT: googleRoot },
|
|
@@ -32925,7 +33353,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
32925
33353
|
});
|
|
32926
33354
|
}
|
|
32927
33355
|
{
|
|
32928
|
-
const auditPlatformRoot = process.env.MAXY_PLATFORM_ROOT ??
|
|
33356
|
+
const auditPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join51(__dirname, "..");
|
|
32929
33357
|
const STORAGE_AUDIT_INTERVAL_MS = 3e5;
|
|
32930
33358
|
const runStorageAuditSafe = () => runStorageAudit(auditPlatformRoot).catch((err) => {
|
|
32931
33359
|
console.error(`[storage-audit] error="${err.message}"`);
|
|
@@ -32971,7 +33399,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
32971
33399
|
});
|
|
32972
33400
|
}
|
|
32973
33401
|
{
|
|
32974
|
-
const publishPlatformRoot = process.env.MAXY_PLATFORM_ROOT ??
|
|
33402
|
+
const publishPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join51(__dirname, "..");
|
|
32975
33403
|
const publishScript = resolve45(publishPlatformRoot, "plugins/scheduling/mcp/dist/scripts/publish-availability.js");
|
|
32976
33404
|
const PUBLISH_INTERVAL_MS = 3e5;
|
|
32977
33405
|
const bookingAccounts = () => {
|
|
@@ -32983,7 +33411,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
32983
33411
|
}
|
|
32984
33412
|
};
|
|
32985
33413
|
const spawnPublish = (account, ctx) => {
|
|
32986
|
-
if (!
|
|
33414
|
+
if (!existsSync48(publishScript)) return;
|
|
32987
33415
|
try {
|
|
32988
33416
|
const child = spawn3(process.execPath, [publishScript], {
|
|
32989
33417
|
env: {
|
|
@@ -33005,7 +33433,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
33005
33433
|
const availPath = resolve45(account.accountDir, "calendar-availability.json");
|
|
33006
33434
|
let hasBookingSite = false;
|
|
33007
33435
|
try {
|
|
33008
|
-
if (
|
|
33436
|
+
if (existsSync48(availPath)) {
|
|
33009
33437
|
const cfg = JSON.parse(readFileSync48(availPath, "utf-8"));
|
|
33010
33438
|
hasBookingSite = typeof cfg.bookingDbName === "string" && cfg.bookingDbName.length > 0;
|
|
33011
33439
|
}
|
|
@@ -33014,7 +33442,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
33014
33442
|
if (!hasBookingSite) return;
|
|
33015
33443
|
const statePath = resolve45(account.accountDir, "state", "booking-availability", "last-publish.json");
|
|
33016
33444
|
let lastSuccessAt = null;
|
|
33017
|
-
if (
|
|
33445
|
+
if (existsSync48(statePath)) {
|
|
33018
33446
|
try {
|
|
33019
33447
|
const rec = JSON.parse(readFileSync48(statePath, "utf-8"));
|
|
33020
33448
|
lastSuccessAt = rec.lastSuccessAt ?? null;
|
|
@@ -33048,12 +33476,12 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
33048
33476
|
startTimeEntryCensus(() => getSession());
|
|
33049
33477
|
startLedgerCensus(() => getSession());
|
|
33050
33478
|
{
|
|
33051
|
-
const auditPlatformRoot = process.env.MAXY_PLATFORM_ROOT ??
|
|
33479
|
+
const auditPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join51(__dirname, "..");
|
|
33052
33480
|
const auditScript = resolve45(auditPlatformRoot, "plugins/connector/mcp/dist/scripts/audit-connectors.js");
|
|
33053
33481
|
const auditLogDir = process.env.LOG_DIR ?? LOG_DIR;
|
|
33054
33482
|
const CONNECTOR_AUDIT_INTERVAL_MS = 3e5;
|
|
33055
33483
|
const runConnectorAudit = (ctx) => {
|
|
33056
|
-
if (!
|
|
33484
|
+
if (!existsSync48(auditScript)) return;
|
|
33057
33485
|
try {
|
|
33058
33486
|
const child = spawn3(process.execPath, [auditScript], {
|
|
33059
33487
|
env: { ...process.env, PLATFORM_ROOT: auditPlatformRoot, LOG_DIR: auditLogDir },
|
|
@@ -33171,7 +33599,7 @@ try {
|
|
|
33171
33599
|
var ADMINUSER_RECONCILE_INTERVAL_MS = 60 * 60 * 1e3;
|
|
33172
33600
|
async function runAdminUserReconcileTick() {
|
|
33173
33601
|
try {
|
|
33174
|
-
if (!
|
|
33602
|
+
if (!existsSync48(USERS_FILE)) {
|
|
33175
33603
|
console.error("[adminuser-self-heal] skip reason=no-users-file");
|
|
33176
33604
|
return;
|
|
33177
33605
|
}
|
|
@@ -33222,7 +33650,7 @@ registerLoop({
|
|
|
33222
33650
|
});
|
|
33223
33651
|
var USERS_RECONCILE_INTERVAL_MS = 60 * 60 * 1e3;
|
|
33224
33652
|
function countUsersRows() {
|
|
33225
|
-
if (!
|
|
33653
|
+
if (!existsSync48(USERS_FILE)) return 0;
|
|
33226
33654
|
const raw = readFileSync48(USERS_FILE, "utf-8").trim();
|
|
33227
33655
|
if (!raw) return 0;
|
|
33228
33656
|
const users = JSON.parse(raw);
|
|
@@ -33273,7 +33701,7 @@ registerLoop({
|
|
|
33273
33701
|
throw err;
|
|
33274
33702
|
})
|
|
33275
33703
|
});
|
|
33276
|
-
void migrateAdminWebchatSidecars().catch((err) => console.error(`[sidecar-backfill] failed err="${err instanceof Error ? err.message : String(err)}"`));
|
|
33704
|
+
void migrateAdminWebchatSidecars().catch((err) => console.error(`[sidecar-backfill] failed err="${err instanceof Error ? err.message : String(err)}"`)).then(() => migrateSidecarAccountIds()).catch((err) => console.error(`[sidecar-account-backfill] failed err="${err instanceof Error ? err.message : String(err)}"`));
|
|
33277
33705
|
try {
|
|
33278
33706
|
const accounts = enumerateValidAccountIds(getAccountsDirFromEnv());
|
|
33279
33707
|
console.error(`[graph-health] account-enumeration accounts=${accounts.length}`);
|
|
@@ -33356,7 +33784,7 @@ if (bootAccountConfig?.whatsapp) {
|
|
|
33356
33784
|
}
|
|
33357
33785
|
init({
|
|
33358
33786
|
configDir: configDirForWhatsApp,
|
|
33359
|
-
platformRoot: resolve45(process.env.MAXY_PLATFORM_ROOT ??
|
|
33787
|
+
platformRoot: resolve45(process.env.MAXY_PLATFORM_ROOT ?? join51(__dirname, "..")),
|
|
33360
33788
|
accountConfig: bootAccountConfig,
|
|
33361
33789
|
onMessage: async (msg) => {
|
|
33362
33790
|
if (isObserveAccount(msg.accountId)) {
|