@rubytech/create-realagent 1.0.807 → 1.0.808

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.
@@ -6,6 +6,7 @@ import {
6
6
  TELEGRAM_ADMIN_WEBHOOK_SECRET_FILE,
7
7
  TELEGRAM_WEBHOOK_SECRET_FILE,
8
8
  USERS_FILE,
9
+ actionLogPath,
9
10
  autoDeliverPremiumPlugins,
10
11
  buildX11Env,
11
12
  callOauthLlm,
@@ -29,6 +30,7 @@ import {
29
30
  launchAction,
30
31
  load,
31
32
  logPath,
33
+ reconcileCloudflareSetupFromLog,
32
34
  recordFailedAttempt,
33
35
  render,
34
36
  renderLoginPage,
@@ -50,7 +52,7 @@ import {
50
52
  vncLog,
51
53
  waitForExit,
52
54
  writeChromiumWrapper
53
- } from "./chunk-LSUMH6OF.js";
55
+ } from "./chunk-V3VLAL7N.js";
54
56
  import {
55
57
  ACCOUNTS_DIR,
56
58
  GREETING_DIRECTIVE,
@@ -114,7 +116,7 @@ import {
114
116
  verifyAndGetConversationUpdatedAt,
115
117
  verifyConversationOwnership,
116
118
  writeAdminUserAndPerson
117
- } from "./chunk-YULDSPAC.js";
119
+ } from "./chunk-CRWLE6BZ.js";
118
120
  import {
119
121
  __commonJS,
120
122
  __toESM
@@ -617,8 +619,8 @@ var serveStatic = (options = { root: "" }) => {
617
619
  };
618
620
 
619
621
  // server/index.ts
620
- import { readFileSync as readFileSync17, existsSync as existsSync24, watchFile } from "fs";
621
- import { resolve as resolve24, join as join10, basename as basename7 } from "path";
622
+ import { readFileSync as readFileSync18, existsSync as existsSync25, watchFile } from "fs";
623
+ import { resolve as resolve24, join as join11, basename as basename7 } from "path";
622
624
  import { homedir as homedir2 } from "os";
623
625
 
624
626
  // app/lib/agent-slug-pattern.ts
@@ -804,6 +806,28 @@ function defaultRules() {
804
806
  scope: "session",
805
807
  suggestedAction: "The WebFetch SPA preflight has fired more than once in this conversation. Either the agent is ignoring the loud-failure directive (retrying WebFetch after seeing WEBFETCH_CANNOT_READ_JS_SPA), or multiple SPA URLs are being asked about. Read the conversation's stream log for the [tool-use] / [tool-result] sequence around each occurrence \u2014 if the agent dispatched WebFetch on the same URL or substituted Playwright silently, revisit the IDENTITY.md `Tool Failure Discipline` paragraph that names structured-error handling."
806
808
  },
809
+ {
810
+ // Task 867 — fires when setup-tunnel.sh emits step=done but no
811
+ // `[persist] role=user … Cloudflare setup completed (actionId: <id>)`
812
+ // line appears within 60s. Covers the three failure modes of the
813
+ // action-relay-queue plumbing: queue-write failed, boot-drain consumer
814
+ // skipped the record, or the agent's hoisted persist threw. The
815
+ // followup pattern is intentionally narrow to the cloudflare-setup
816
+ // relay shape (not a general "any user persist") so a benign user
817
+ // typing in chat does not satisfy the followup. logSource=any so
818
+ // the rule sees both the script tee (in stream logs / server.log)
819
+ // and the [persist] line (server.log).
820
+ id: "cloudflare-setup-relay-not-acknowledged",
821
+ name: "Cloudflare-setup completed but the chat relay never acknowledged",
822
+ type: "absent-followup",
823
+ logSource: "any",
824
+ pattern: "\\[script:setup-tunnel\\] step=done",
825
+ followupPattern: "\\[persist\\] .*role=user.* Cloudflare setup completed \\(actionId:",
826
+ followupWindowMs: 6e4,
827
+ thresholdCount: 0,
828
+ thresholdWindowMinutes: 0,
829
+ suggestedAction: "[Task 867] cloudflare-setup completed but the post-action relay never reached the chat history. Check `[action-relay-queue] phase=enqueued` (queue write), `[action-completion-relay] phase=consumed` (boot-drain ran), and `[persist] role=user \u2026 Cloudflare setup completed` (graph write). One of those is missing; the matching grep recipe is in the Task 867 brief Observability section."
830
+ },
807
831
  {
808
832
  // Task 538: fires when a [spawn] line appears in a conversation's stream
809
833
  // log but no subprocess-lifecycle marker follows within 10s. The three
@@ -8070,7 +8094,8 @@ app9.post("/", async (c) => {
8070
8094
  "unknown",
8071
8095
  "graph-labels-in-graph",
8072
8096
  "graph-default-view",
8073
- "graph-nav"
8097
+ "graph-nav",
8098
+ "event"
8074
8099
  ]);
8075
8100
  const kind = allowedKinds.has(kindRaw) ? kindRaw : "unknown";
8076
8101
  const msg = truncate(body.msg, MAX_MSG_LEN);
@@ -8084,29 +8109,42 @@ app9.post("/", async (c) => {
8084
8109
  const stackTrunc = truncate(body.stack, MAX_STACK_LEN);
8085
8110
  const head = stackHead(body.stack);
8086
8111
  const ts = (/* @__PURE__ */ new Date()).toISOString();
8087
- console.error(
8088
- `[client-error] ts=${ts} ip=${ip} kind=${kind} url=${JSON.stringify(url)} version=${version || "unknown"} ua=${JSON.stringify(ua)} msg=${JSON.stringify(msg)} stack-head=${JSON.stringify(head)} file-line-col=${JSON.stringify(fileLineCol)}`
8089
- );
8090
- rotateIfNeeded();
8091
- try {
8092
- const payload = {
8093
- ts,
8094
- ip,
8095
- kind,
8096
- url,
8097
- version,
8098
- ua,
8099
- msg,
8100
- stack: stackTrunc,
8101
- filename: file,
8102
- lineno: line,
8103
- colno: col,
8104
- tag: typeof body.tag === "string" ? truncate(body.tag, 32) : void 0,
8105
- status: typeof body.status === "number" ? body.status : void 0
8106
- };
8107
- appendFileSync2(CLIENT_ERRORS_LOG, JSON.stringify(payload) + "\n", "utf-8");
8108
- } catch (err) {
8109
- console.error(`[client-error] append failed: ${err instanceof Error ? err.message : String(err)}`);
8112
+ if (kind === "event") {
8113
+ const source = typeof body.source === "string" ? truncate(body.source, 64) : "unknown";
8114
+ const extra = Object.entries(body).filter(([k]) => !["kind", "source", "msg", "url", "ua", "version", "stack", "filename", "lineno", "colno", "tag", "status"].includes(k)).map(([k, v]) => {
8115
+ const safe = typeof v === "string" ? truncate(v, 200) : typeof v === "number" || typeof v === "boolean" ? String(v) : JSON.stringify(v).slice(0, 200);
8116
+ return `${k}=${safe}`;
8117
+ }).join(" ");
8118
+ console.log(
8119
+ `[client-event] ts=${ts} ip=${ip} source=${source} version=${version || "unknown"}${extra ? " " + extra : ""}`
8120
+ );
8121
+ } else {
8122
+ console.error(
8123
+ `[client-error] ts=${ts} ip=${ip} kind=${kind} url=${JSON.stringify(url)} version=${version || "unknown"} ua=${JSON.stringify(ua)} msg=${JSON.stringify(msg)} stack-head=${JSON.stringify(head)} file-line-col=${JSON.stringify(fileLineCol)}`
8124
+ );
8125
+ }
8126
+ if (kind !== "event") {
8127
+ rotateIfNeeded();
8128
+ try {
8129
+ const payload = {
8130
+ ts,
8131
+ ip,
8132
+ kind,
8133
+ url,
8134
+ version,
8135
+ ua,
8136
+ msg,
8137
+ stack: stackTrunc,
8138
+ filename: file,
8139
+ lineno: line,
8140
+ colno: col,
8141
+ tag: typeof body.tag === "string" ? truncate(body.tag, 32) : void 0,
8142
+ status: typeof body.status === "number" ? body.status : void 0
8143
+ };
8144
+ appendFileSync2(CLIENT_ERRORS_LOG, JSON.stringify(payload) + "\n", "utf-8");
8145
+ } catch (err) {
8146
+ console.error(`[client-error] append failed: ${err instanceof Error ? err.message : String(err)}`);
8147
+ }
8110
8148
  }
8111
8149
  return c.json({ ok: true });
8112
8150
  });
@@ -8586,7 +8624,7 @@ var app11 = new Hono();
8586
8624
  app11.post("/cancel", requireAdminSession, async (c) => {
8587
8625
  const session_key = c.var.sessionKey;
8588
8626
  try {
8589
- const { interruptClient: interruptClient2 } = await import("./client-pool-LXE7RIRT.js");
8627
+ const { interruptClient: interruptClient2 } = await import("./client-pool-N2Y57223.js");
8590
8628
  await interruptClient2(session_key);
8591
8629
  return c.json({ ok: true });
8592
8630
  } catch (err) {
@@ -9749,13 +9787,13 @@ async function cdpNavigateNewTab(url, opts = {}) {
9749
9787
  // server/routes/admin/device-browser.ts
9750
9788
  var app19 = new Hono();
9751
9789
  app19.post("/navigate", async (c) => {
9752
- const TAG19 = "[device-url:click]";
9790
+ const TAG20 = "[device-url:click]";
9753
9791
  let body;
9754
9792
  try {
9755
9793
  body = await c.req.json();
9756
9794
  } catch (err) {
9757
9795
  const detail = err instanceof Error ? err.message : String(err);
9758
- console.error(`${TAG19} reject reason=body-not-json detail=${detail} browser=fallback navigateResult=error`);
9796
+ console.error(`${TAG20} reject reason=body-not-json detail=${detail} browser=fallback navigateResult=error`);
9759
9797
  return c.json(
9760
9798
  { ok: false, navigateResult: "error", browser: "fallback", detail: "Request body was not valid JSON" },
9761
9799
  400
@@ -9765,7 +9803,7 @@ app19.post("/navigate", async (c) => {
9765
9803
  const intent = typeof body.intent === "string" ? body.intent : "";
9766
9804
  const hostname2 = typeof body.hostname === "string" ? body.hostname : "";
9767
9805
  if (!url) {
9768
- console.error(`${TAG19} reject reason=missing-url intent=${JSON.stringify(intent)} browser=fallback navigateResult=error`);
9806
+ console.error(`${TAG20} reject reason=missing-url intent=${JSON.stringify(intent)} browser=fallback navigateResult=error`);
9769
9807
  return c.json(
9770
9808
  { ok: false, navigateResult: "error", browser: "fallback", detail: "url field is required" },
9771
9809
  400
@@ -9775,7 +9813,7 @@ app19.post("/navigate", async (c) => {
9775
9813
  try {
9776
9814
  parsed = new URL(url);
9777
9815
  } catch {
9778
- console.error(`${TAG19} reject reason=url-malformed intent=${JSON.stringify(intent)} url=${url} browser=fallback navigateResult=error`);
9816
+ console.error(`${TAG20} reject reason=url-malformed intent=${JSON.stringify(intent)} url=${url} browser=fallback navigateResult=error`);
9779
9817
  return c.json(
9780
9818
  { ok: false, navigateResult: "error", browser: "fallback", detail: "url is not a valid URL" },
9781
9819
  400
@@ -9783,7 +9821,7 @@ app19.post("/navigate", async (c) => {
9783
9821
  }
9784
9822
  if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
9785
9823
  console.error(
9786
- `${TAG19} reject reason=scheme-not-allowed scheme=${parsed.protocol} intent=${JSON.stringify(intent)} browser=fallback navigateResult=error`
9824
+ `${TAG20} reject reason=scheme-not-allowed scheme=${parsed.protocol} intent=${JSON.stringify(intent)} browser=fallback navigateResult=error`
9787
9825
  );
9788
9826
  return c.json(
9789
9827
  {
@@ -9799,7 +9837,7 @@ app19.post("/navigate", async (c) => {
9799
9837
  const cdpOk = await ensureCdp(transport);
9800
9838
  if (!cdpOk) {
9801
9839
  console.error(
9802
- `${TAG19} intent=${JSON.stringify(intent)} browser=fallback navigateResult=cdp-unreachable hostname=${JSON.stringify(hostname2)}`
9840
+ `${TAG20} intent=${JSON.stringify(intent)} browser=fallback navigateResult=cdp-unreachable hostname=${JSON.stringify(hostname2)}`
9803
9841
  );
9804
9842
  return c.json(
9805
9843
  {
@@ -9815,7 +9853,7 @@ app19.post("/navigate", async (c) => {
9815
9853
  const browser = outcome.result === "ok" ? "vnc" : "fallback";
9816
9854
  const detailStr = outcome.detail ? ` detail=${JSON.stringify(outcome.detail.length > 230 ? outcome.detail.slice(0, 227) + "..." : outcome.detail)}` : "";
9817
9855
  console.error(
9818
- `${TAG19} intent=${JSON.stringify(intent)} browser=${browser} navigateResult=${outcome.result} hostname=${JSON.stringify(hostname2)} targetId=${outcome.targetId ?? "none"}${detailStr}`
9856
+ `${TAG20} intent=${JSON.stringify(intent)} browser=${browser} navigateResult=${outcome.result} hostname=${JSON.stringify(hostname2)} targetId=${outcome.targetId ?? "none"}${detailStr}`
9819
9857
  );
9820
9858
  if (outcome.result !== "ok") {
9821
9859
  return c.json(
@@ -9846,18 +9884,18 @@ var ALLOWED_EVENTS = /* @__PURE__ */ new Set([
9846
9884
  ]);
9847
9885
  var app20 = new Hono();
9848
9886
  app20.post("/", async (c) => {
9849
- const TAG19 = "[admin:events]";
9887
+ const TAG20 = "[admin:events]";
9850
9888
  let body;
9851
9889
  try {
9852
9890
  body = await c.req.json();
9853
9891
  } catch (err) {
9854
9892
  const detail = err instanceof Error ? err.message : String(err);
9855
- console.error(`${TAG19} reject reason=body-not-json detail=${detail}`);
9893
+ console.error(`${TAG20} reject reason=body-not-json detail=${detail}`);
9856
9894
  return c.json({ ok: false, detail: "Request body was not valid JSON" }, 400);
9857
9895
  }
9858
9896
  const event = typeof body.event === "string" ? body.event : "";
9859
9897
  if (!ALLOWED_EVENTS.has(event)) {
9860
- console.error(`${TAG19} reject reason=event-not-allowed event=${JSON.stringify(event)}`);
9898
+ console.error(`${TAG20} reject reason=event-not-allowed event=${JSON.stringify(event)}`);
9861
9899
  return c.json({ ok: false, detail: `Event "${event}" is not allowed` }, 400);
9862
9900
  }
9863
9901
  const rawFields = body.fields && typeof body.fields === "object" ? body.fields : {};
@@ -9881,7 +9919,7 @@ var events_default = app20;
9881
9919
  // server/routes/admin/cloudflare.ts
9882
9920
  import { homedir } from "os";
9883
9921
  import { resolve as resolve17 } from "path";
9884
- import { readFileSync as readFileSync15 } from "fs";
9922
+ import { readFileSync as readFileSync16 } from "fs";
9885
9923
 
9886
9924
  // app/lib/dns-label.ts
9887
9925
  var VALID_LABEL = /^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?$/;
@@ -9919,14 +9957,131 @@ function addAliasDomain(hostname2) {
9919
9957
  writeFileSync9(ALIAS_DOMAINS_PATH, JSON.stringify([...existing], null, 2) + "\n", "utf-8");
9920
9958
  }
9921
9959
 
9960
+ // app/lib/action-relay-queue.ts
9961
+ import {
9962
+ existsSync as existsSync20,
9963
+ mkdirSync as mkdirSync9,
9964
+ readdirSync as readdirSync5,
9965
+ readFileSync as readFileSync15,
9966
+ unlinkSync as unlinkSync2,
9967
+ writeFileSync as writeFileSync10
9968
+ } from "fs";
9969
+ import { join as join9 } from "path";
9970
+ var TAG19 = "[action-relay-queue]";
9971
+ var FILE_PREFIX = "action-completion-relay-";
9972
+ var FILE_SUFFIX = ".json";
9973
+ function queueDir(accountDir) {
9974
+ return join9(accountDir, "queue");
9975
+ }
9976
+ function relayFilePath(accountDir, actionId) {
9977
+ return join9(queueDir(accountDir), `${FILE_PREFIX}${actionId}${FILE_SUFFIX}`);
9978
+ }
9979
+ function enqueueActionCompletionRelay(opts) {
9980
+ const dir = queueDir(opts.accountDir);
9981
+ mkdirSync9(dir, { recursive: true });
9982
+ const filePath = relayFilePath(opts.accountDir, opts.actionId);
9983
+ const record = {
9984
+ actionId: opts.actionId,
9985
+ conversationId: opts.conversationId,
9986
+ message: opts.message,
9987
+ queuedAt: (/* @__PURE__ */ new Date()).toISOString()
9988
+ };
9989
+ const body = JSON.stringify(record);
9990
+ try {
9991
+ writeFileSync10(filePath, body, { flag: "wx", encoding: "utf-8" });
9992
+ console.log(
9993
+ `${TAG19} phase=enqueued actionId=${opts.actionId} conversationId=${opts.conversationId} path=${filePath} bytes=${Buffer.byteLength(body, "utf-8")}`
9994
+ );
9995
+ return { enqueued: true, path: filePath };
9996
+ } catch (e) {
9997
+ if (e.code === "EEXIST") {
9998
+ console.log(
9999
+ `${TAG19} phase=enqueue-skipped actionId=${opts.actionId} reason=already-queued`
10000
+ );
10001
+ return { enqueued: false, reason: "already-queued", path: filePath };
10002
+ }
10003
+ throw e;
10004
+ }
10005
+ }
10006
+ function consumeActionCompletionRelays(accountDir) {
10007
+ const dir = queueDir(accountDir);
10008
+ if (!existsSync20(dir)) return [];
10009
+ let entries;
10010
+ try {
10011
+ entries = readdirSync5(dir);
10012
+ } catch (e) {
10013
+ console.error(
10014
+ `${TAG19} phase=readdir-failed dir=${dir} error=${e instanceof Error ? e.message : String(e)}`
10015
+ );
10016
+ return [];
10017
+ }
10018
+ const records = [];
10019
+ for (const name of entries) {
10020
+ if (!name.startsWith(FILE_PREFIX) || !name.endsWith(FILE_SUFFIX)) continue;
10021
+ const filePath = join9(dir, name);
10022
+ let raw;
10023
+ try {
10024
+ raw = readFileSync15(filePath, "utf-8");
10025
+ } catch (e) {
10026
+ console.error(
10027
+ `${TAG19} phase=read-failed file=${name} error=${e instanceof Error ? e.message : String(e)}`
10028
+ );
10029
+ continue;
10030
+ }
10031
+ let parsed;
10032
+ try {
10033
+ parsed = JSON.parse(raw);
10034
+ } catch (e) {
10035
+ console.error(
10036
+ `${TAG19} phase=parse-failed file=${name} error=${e instanceof Error ? e.message : String(e)}`
10037
+ );
10038
+ continue;
10039
+ }
10040
+ if (!isActionCompletionRelay(parsed)) {
10041
+ console.error(
10042
+ `${TAG19} phase=shape-invalid file=${name} keys=${parsed && typeof parsed === "object" ? Object.keys(parsed).join(",") : "non-object"}`
10043
+ );
10044
+ continue;
10045
+ }
10046
+ records.push({ rec: parsed, filePath });
10047
+ }
10048
+ records.sort((a, b) => a.rec.queuedAt.localeCompare(b.rec.queuedAt));
10049
+ const out = [];
10050
+ const now = Date.now();
10051
+ for (const { rec, filePath } of records) {
10052
+ const queuedAtMs = Date.parse(rec.queuedAt);
10053
+ const ageMs = Number.isFinite(queuedAtMs) ? now - queuedAtMs : 0;
10054
+ out.push({ ...rec, ageMs, filePath });
10055
+ }
10056
+ return out;
10057
+ }
10058
+ function deleteConsumedRelay(filePath) {
10059
+ try {
10060
+ unlinkSync2(filePath);
10061
+ } catch (e) {
10062
+ const code = e.code;
10063
+ if (code !== "ENOENT") {
10064
+ console.error(
10065
+ `${TAG19} phase=unlink-failed file=${filePath} error=${e instanceof Error ? e.message : String(e)}`
10066
+ );
10067
+ }
10068
+ }
10069
+ }
10070
+ function isActionCompletionRelay(value) {
10071
+ if (!value || typeof value !== "object") return false;
10072
+ const v = value;
10073
+ return typeof v.actionId === "string" && typeof v.conversationId === "string" && typeof v.message === "string" && typeof v.queuedAt === "string";
10074
+ }
10075
+
9922
10076
  // server/routes/admin/cloudflare.ts
10077
+ import { existsSync as existsSyncFs, readFileSync as readFileSyncFs } from "fs";
9923
10078
  var SETUP_TIMEOUT_MS = 10 * 60 * 1e3;
9924
10079
  var DOMAINS_TIMEOUT_MS = 40 * 1e3;
9925
10080
  function loadBrandInfo() {
9926
10081
  const platformRoot2 = process.env.MAXY_PLATFORM_ROOT ?? resolve17(process.cwd(), "..");
9927
10082
  const brandPath = resolve17(platformRoot2, "config", "brand.json");
9928
10083
  try {
9929
- const parsed = JSON.parse(readFileSync15(brandPath, "utf-8"));
10084
+ const parsed = JSON.parse(readFileSync16(brandPath, "utf-8"));
9930
10085
  const hostname2 = typeof parsed.hostname === "string" && parsed.hostname ? parsed.hostname : "maxy";
9931
10086
  const configDir2 = typeof parsed.configDir === "string" && parsed.configDir ? parsed.configDir : ".maxy";
9932
10087
  return { hostname: hostname2, configDir: configDir2 };
@@ -10222,13 +10377,79 @@ actionId: ${actionId}`,
10222
10377
  };
10223
10378
  return ok(success);
10224
10379
  });
10380
+ var RELAY_MAX_BODY = 8 * 1024;
10381
+ var RELAY_MAX_MESSAGE = 2048;
10382
+ var ACTION_ID_RE = /^[a-z0-9-]+$/;
10383
+ app21.post("/relay-completion", requireAdminSession, async (c) => {
10384
+ const sessionKey = c.var.sessionKey;
10385
+ let raw;
10386
+ try {
10387
+ raw = await c.req.text();
10388
+ } catch {
10389
+ return c.json({ ok: false, reason: "invalid-body" }, 400);
10390
+ }
10391
+ if (Buffer.byteLength(raw, "utf-8") > RELAY_MAX_BODY) {
10392
+ return c.json({ ok: false, reason: "body-too-large" }, 413);
10393
+ }
10394
+ let body;
10395
+ try {
10396
+ body = JSON.parse(raw);
10397
+ } catch {
10398
+ return c.json({ ok: false, reason: "invalid-json" }, 400);
10399
+ }
10400
+ if (!body || typeof body !== "object") {
10401
+ return c.json({ ok: false, reason: "invalid-body" }, 400);
10402
+ }
10403
+ const { actionId, message } = body;
10404
+ if (typeof actionId !== "string" || !ACTION_ID_RE.test(actionId) || actionId.length > 200) {
10405
+ console.error(`[cloudflare-relay-completion] phase=enqueue-skipped reason=invalid-actionid sessionKey=${sessionKey.slice(-8)}`);
10406
+ return c.json({ ok: false, reason: "invalid-actionid" }, 400);
10407
+ }
10408
+ if (typeof message !== "string" || message.length === 0 || message.length > RELAY_MAX_MESSAGE) {
10409
+ return c.json({ ok: false, reason: "invalid-message" }, 400);
10410
+ }
10411
+ const conversationId = getConversationIdForSession(sessionKey);
10412
+ if (!conversationId) {
10413
+ console.error(`[cloudflare-relay-completion] phase=enqueue-skipped reason=missing-conversation-id sessionKey=${sessionKey.slice(-8)}`);
10414
+ return c.json({ ok: false, reason: "missing-conversation-id" }, 400);
10415
+ }
10416
+ const account = resolveAccount();
10417
+ if (!account) {
10418
+ console.error(`[cloudflare-relay-completion] phase=enqueue-skipped reason=missing-account-dir actionId=${actionId}`);
10419
+ return c.json({ ok: false, reason: "missing-account-dir" }, 500);
10420
+ }
10421
+ const logPath2 = actionLogPath(actionId);
10422
+ let auditOutcome = "log-absent";
10423
+ if (existsSyncFs(logPath2)) {
10424
+ try {
10425
+ const lines = readFileSyncFs(logPath2, "utf-8").split("\n");
10426
+ const reconciled = reconcileCloudflareSetupFromLog(lines);
10427
+ auditOutcome = reconciled ? reconciled.kind : "log-incomplete";
10428
+ } catch (e) {
10429
+ auditOutcome = `read-failed:${e instanceof Error ? e.message : String(e)}`;
10430
+ }
10431
+ }
10432
+ console.log(`[cloudflare-relay-completion] phase=enqueue-attempt actionId=${actionId} auditOutcome=${auditOutcome} conversationId=${conversationId}`);
10433
+ try {
10434
+ enqueueActionCompletionRelay({
10435
+ accountDir: account.accountDir,
10436
+ actionId,
10437
+ conversationId,
10438
+ message
10439
+ });
10440
+ } catch (e) {
10441
+ console.error(`[cloudflare-relay-completion] phase=enqueue-failed actionId=${actionId} error=${e instanceof Error ? e.message : String(e)}`);
10442
+ return c.json({ ok: false, reason: "enqueue-failed" }, 500);
10443
+ }
10444
+ return c.body(null, 204);
10445
+ });
10225
10446
  var cloudflare_default = app21;
10226
10447
 
10227
10448
  // server/routes/admin/files.ts
10228
10449
  import { createReadStream as createReadStream3 } from "fs";
10229
10450
  import { readdir as readdir2, readFile as readFile4, stat as stat4, mkdir as mkdir3, writeFile as writeFile4, unlink as unlink2 } from "fs/promises";
10230
10451
  import { realpathSync as realpathSync4 } from "fs";
10231
- import { basename as basename6, dirname as dirname8, join as join9, resolve as resolve19, sep as sep2 } from "path";
10452
+ import { basename as basename6, dirname as dirname8, join as join10, resolve as resolve19, sep as sep2 } from "path";
10232
10453
  import { Readable as Readable2 } from "stream";
10233
10454
 
10234
10455
  // app/lib/data-path.ts
@@ -10586,7 +10807,7 @@ async function cascadeDeleteDocument(params) {
10586
10807
  var UUID_RE3 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
10587
10808
  async function readMeta(absDir, baseName) {
10588
10809
  try {
10589
- const raw = await readFile4(join9(absDir, `${baseName}.meta.json`), "utf8");
10810
+ const raw = await readFile4(join10(absDir, `${baseName}.meta.json`), "utf8");
10590
10811
  const parsed = JSON.parse(raw);
10591
10812
  if (typeof parsed?.filename === "string") {
10592
10813
  return { filename: parsed.filename, mimeType: typeof parsed.mimeType === "string" ? parsed.mimeType : void 0 };
@@ -10624,7 +10845,7 @@ async function readAccountNames() {
10624
10845
  }
10625
10846
  async function enrich(absolute, entry, accountNames) {
10626
10847
  if (entry.kind === "directory" && UUID_RE3.test(entry.name)) {
10627
- const meta = await readMeta(join9(absolute, entry.name), entry.name);
10848
+ const meta = await readMeta(join10(absolute, entry.name), entry.name);
10628
10849
  if (meta?.filename) {
10629
10850
  entry.displayName = meta.filename;
10630
10851
  entry.mimeType = meta.mimeType;
@@ -10683,7 +10904,7 @@ app22.get("/", requireAdminSession, async (c) => {
10683
10904
  continue;
10684
10905
  }
10685
10906
  try {
10686
- const entryPath = join9(absolute, name);
10907
+ const entryPath = join10(absolute, name);
10687
10908
  const s = await stat4(entryPath);
10688
10909
  entries.push({
10689
10910
  name,
@@ -10856,7 +11077,7 @@ app22.delete("/", requireAdminSession, async (c) => {
10856
11077
  }
10857
11078
  const dot = base.lastIndexOf(".");
10858
11079
  const stem = dot === -1 ? base : base.slice(0, dot);
10859
- const sidecarPath = UUID_RE3.test(stem) && base !== `${stem}.meta.json` ? join9(dirname8(absolute), `${stem}.meta.json`) : null;
11080
+ const sidecarPath = UUID_RE3.test(stem) && base !== `${stem}.meta.json` ? join10(dirname8(absolute), `${stem}.meta.json`) : null;
10860
11081
  await unlink2(absolute);
10861
11082
  if (sidecarPath) {
10862
11083
  try {
@@ -12314,7 +12535,7 @@ var adherence_default = app30;
12314
12535
  import neo4j3 from "neo4j-driver";
12315
12536
  import { readFile as readFile5, readdir as readdir3, stat as stat5 } from "fs/promises";
12316
12537
  import { resolve as resolve20, relative as relative2, isAbsolute } from "path";
12317
- import { existsSync as existsSync20 } from "fs";
12538
+ import { existsSync as existsSync21 } from "fs";
12318
12539
  var LIMIT = 50;
12319
12540
  var TEXT_MIME_PREFIXES = ["text/", "application/json", "application/markdown"];
12320
12541
  var ADMIN_AGENT_FILES = ["IDENTITY.md", "SOUL.md", "KNOWLEDGE.md"];
@@ -12462,7 +12683,7 @@ async function fetchAgentTemplateRows(accountDir) {
12462
12683
  async function unionSpecialistFilenames(overrideDir, bundledDir) {
12463
12684
  const names = /* @__PURE__ */ new Set();
12464
12685
  for (const dir of [overrideDir, bundledDir]) {
12465
- if (!existsSync20(dir)) continue;
12686
+ if (!existsSync21(dir)) continue;
12466
12687
  try {
12467
12688
  const entries = await readdir3(dir);
12468
12689
  for (const entry of entries) {
@@ -12477,7 +12698,7 @@ async function unionSpecialistFilenames(overrideDir, bundledDir) {
12477
12698
  }
12478
12699
  async function readAgentTemplateRow(inp) {
12479
12700
  let chosenPath = null;
12480
- if (existsSync20(inp.overridePath)) {
12701
+ if (existsSync21(inp.overridePath)) {
12481
12702
  try {
12482
12703
  validateFilePathInAccount(inp.overridePath, inp.overrideRoot);
12483
12704
  chosenPath = inp.overridePath;
@@ -12488,7 +12709,7 @@ async function readAgentTemplateRow(inp) {
12488
12709
  );
12489
12710
  return null;
12490
12711
  }
12491
- } else if (existsSync20(inp.bundledPath)) {
12712
+ } else if (existsSync21(inp.bundledPath)) {
12492
12713
  if (!isWithin(inp.bundledPath, inp.bundledRoot)) {
12493
12714
  console.error(
12494
12715
  `[admin/sidebar-artefacts] agent-template-read-failed agent=${inp.displayName} kind=${inp.logName} error="bundled path outside PLATFORM_ROOT"`
@@ -12530,7 +12751,7 @@ var sidebar_artefacts_default = app31;
12530
12751
  // server/routes/admin/sidebar-artefact-save.ts
12531
12752
  import { mkdir as mkdir4, readdir as readdir4, stat as stat6, writeFile as writeFile5 } from "fs/promises";
12532
12753
  import { resolve as resolve21 } from "path";
12533
- import { existsSync as existsSync21 } from "fs";
12754
+ import { existsSync as existsSync22 } from "fs";
12534
12755
  var ADMIN_AGENT_FILES2 = /* @__PURE__ */ new Set(["IDENTITY.md", "SOUL.md", "KNOWLEDGE.md"]);
12535
12756
  var UUID_RE4 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
12536
12757
  var app32 = new Hono();
@@ -12594,7 +12815,7 @@ async function resolveSavePath(id, accountId, accountDir) {
12594
12815
  }
12595
12816
  if (UUID_RE4.test(id)) {
12596
12817
  const dir = resolve21(ATTACHMENTS_ROOT, accountId, id);
12597
- if (!existsSync21(dir)) {
12818
+ if (!existsSync22(dir)) {
12598
12819
  return { kind: "reject", status: 400, reason: "not-found" };
12599
12820
  }
12600
12821
  try {
@@ -12618,7 +12839,7 @@ var sidebar_artefact_save_default = app32;
12618
12839
 
12619
12840
  // server/routes/admin/sidebar-artefact-content.ts
12620
12841
  import { readFile as readFile6, readdir as readdir5 } from "fs/promises";
12621
- import { existsSync as existsSync22 } from "fs";
12842
+ import { existsSync as existsSync23 } from "fs";
12622
12843
  import { resolve as resolve22 } from "path";
12623
12844
  var UUID_RE5 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
12624
12845
  var app33 = new Hono();
@@ -12632,7 +12853,7 @@ app33.get("/", requireAdminSession, async (c) => {
12632
12853
  return new Response("Not found", { status: 404 });
12633
12854
  }
12634
12855
  const dir = resolve22(ATTACHMENTS_ROOT, accountId, id);
12635
- if (!existsSync22(dir)) {
12856
+ if (!existsSync23(dir)) {
12636
12857
  console.error(`[admin/sidebar-artefact-content] not-found id=${id.slice(0, 8)}`);
12637
12858
  return new Response("Not found", { status: 404 });
12638
12859
  }
@@ -12694,7 +12915,7 @@ app34.route("/sidebar-artefact-content", sidebar_artefact_content_default);
12694
12915
  var admin_default = app34;
12695
12916
 
12696
12917
  // server/routes/sites.ts
12697
- import { existsSync as existsSync23, readFileSync as readFileSync16, realpathSync as realpathSync5, statSync as statSync8 } from "fs";
12918
+ import { existsSync as existsSync24, readFileSync as readFileSync17, realpathSync as realpathSync5, statSync as statSync8 } from "fs";
12698
12919
  import { resolve as resolve23 } from "path";
12699
12920
  var SAFE_SEG_RE = /^[a-z0-9_][a-z0-9_.-]{0,99}$/i;
12700
12921
  var MIME = {
@@ -12761,7 +12982,7 @@ app35.get("/:rel{.*}", (c) => {
12761
12982
  }
12762
12983
  let stat7;
12763
12984
  try {
12764
- stat7 = existsSync23(filePath) ? statSync8(filePath) : null;
12985
+ stat7 = existsSync24(filePath) ? statSync8(filePath) : null;
12765
12986
  } catch {
12766
12987
  stat7 = null;
12767
12988
  }
@@ -12774,7 +12995,7 @@ app35.get("/:rel{.*}", (c) => {
12774
12995
  console.error(`[sites] path-traversal-rejected path=${reqPath} reason=escape status=403`);
12775
12996
  return c.text("Forbidden", 403);
12776
12997
  }
12777
- if (!existsSync23(filePath)) {
12998
+ if (!existsSync24(filePath)) {
12778
12999
  console.error(`[sites] not-found path=${reqPath} status=404`);
12779
13000
  return c.text("Not found", 404);
12780
13001
  }
@@ -12793,7 +13014,7 @@ app35.get("/:rel{.*}", (c) => {
12793
13014
  }
12794
13015
  let body;
12795
13016
  try {
12796
- body = readFileSync16(realPath);
13017
+ body = readFileSync17(realPath);
12797
13018
  } catch (err) {
12798
13019
  const code = err?.code;
12799
13020
  if (code === "EISDIR") {
@@ -12925,14 +13146,14 @@ function clientFrom(c) {
12925
13146
  );
12926
13147
  }
12927
13148
  var PLATFORM_ROOT7 = process.env.MAXY_PLATFORM_ROOT || "";
12928
- var BRAND_JSON_PATH = PLATFORM_ROOT7 ? join10(PLATFORM_ROOT7, "config", "brand.json") : "";
13149
+ var BRAND_JSON_PATH = PLATFORM_ROOT7 ? join11(PLATFORM_ROOT7, "config", "brand.json") : "";
12929
13150
  var BRAND = { productName: "Maxy", hostname: "maxy", configDir: ".maxy", domain: "getmaxy.com" };
12930
- if (BRAND_JSON_PATH && !existsSync24(BRAND_JSON_PATH)) {
13151
+ if (BRAND_JSON_PATH && !existsSync25(BRAND_JSON_PATH)) {
12931
13152
  console.error(`[brand] WARNING: brand.json not found at ${BRAND_JSON_PATH} \u2014 using Maxy defaults`);
12932
13153
  }
12933
- if (BRAND_JSON_PATH && existsSync24(BRAND_JSON_PATH)) {
13154
+ if (BRAND_JSON_PATH && existsSync25(BRAND_JSON_PATH)) {
12934
13155
  try {
12935
- const parsed = JSON.parse(readFileSync17(BRAND_JSON_PATH, "utf-8"));
13156
+ const parsed = JSON.parse(readFileSync18(BRAND_JSON_PATH, "utf-8"));
12936
13157
  BRAND = { ...BRAND, ...parsed };
12937
13158
  } catch (err) {
12938
13159
  console.error(`[brand] Failed to parse brand.json: ${err.message}`);
@@ -12951,11 +13172,11 @@ var brandLoginOpts = {
12951
13172
  bodyFont: BRAND.defaultFonts?.body,
12952
13173
  logoContainsName: !!BRAND.logoContainsName
12953
13174
  };
12954
- var ALIAS_DOMAINS_PATH2 = join10(homedir2(), BRAND.configDir, "alias-domains.json");
13175
+ var ALIAS_DOMAINS_PATH2 = join11(homedir2(), BRAND.configDir, "alias-domains.json");
12955
13176
  function loadAliasDomains() {
12956
13177
  try {
12957
- if (!existsSync24(ALIAS_DOMAINS_PATH2)) return null;
12958
- const parsed = JSON.parse(readFileSync17(ALIAS_DOMAINS_PATH2, "utf-8"));
13178
+ if (!existsSync25(ALIAS_DOMAINS_PATH2)) return null;
13179
+ const parsed = JSON.parse(readFileSync18(ALIAS_DOMAINS_PATH2, "utf-8"));
12959
13180
  if (!Array.isArray(parsed)) {
12960
13181
  console.error("[alias-domains] malformed alias-domains.json \u2014 expected array");
12961
13182
  return null;
@@ -13301,14 +13522,14 @@ app36.get("/agent-assets/:slug/:filename", (c) => {
13301
13522
  console.error(`[agent-assets] path-traversal-rejected slug=${slug} file=${filename}`);
13302
13523
  return c.text("Forbidden", 403);
13303
13524
  }
13304
- if (!existsSync24(filePath)) {
13525
+ if (!existsSync25(filePath)) {
13305
13526
  console.error(`[agent-assets] serve slug=${slug} file=${filename} status=404`);
13306
13527
  return c.text("Not found", 404);
13307
13528
  }
13308
13529
  const ext = "." + filename.split(".").pop()?.toLowerCase();
13309
13530
  const contentType = IMAGE_MIME[ext] || "application/octet-stream";
13310
13531
  console.log(`[agent-assets] serve slug=${slug} file=${filename} status=200`);
13311
- const body = readFileSync17(filePath);
13532
+ const body = readFileSync18(filePath);
13312
13533
  return c.body(body, 200, {
13313
13534
  "Content-Type": contentType,
13314
13535
  "Cache-Control": "public, max-age=3600"
@@ -13331,14 +13552,14 @@ app36.get("/generated/:filename", (c) => {
13331
13552
  console.error(`[generated] serve file=${filename} status=403`);
13332
13553
  return c.text("Forbidden", 403);
13333
13554
  }
13334
- if (!existsSync24(filePath)) {
13555
+ if (!existsSync25(filePath)) {
13335
13556
  console.error(`[generated] serve file=${filename} status=404`);
13336
13557
  return c.text("Not found", 404);
13337
13558
  }
13338
13559
  const ext = "." + filename.split(".").pop()?.toLowerCase();
13339
13560
  const contentType = IMAGE_MIME[ext] || "application/octet-stream";
13340
13561
  console.log(`[generated] serve file=${filename} status=200`);
13341
- const body = readFileSync17(filePath);
13562
+ const body = readFileSync18(filePath);
13342
13563
  return c.body(body, 200, {
13343
13564
  "Content-Type": contentType,
13344
13565
  "Cache-Control": "public, max-age=86400"
@@ -13348,9 +13569,9 @@ app36.route("/sites", sites_default);
13348
13569
  var htmlCache = /* @__PURE__ */ new Map();
13349
13570
  var brandLogoPath = "/brand/maxy-monochrome.png";
13350
13571
  var brandIconPath = "/brand/maxy-monochrome.png";
13351
- if (BRAND_JSON_PATH && existsSync24(BRAND_JSON_PATH)) {
13572
+ if (BRAND_JSON_PATH && existsSync25(BRAND_JSON_PATH)) {
13352
13573
  try {
13353
- const fullBrand = JSON.parse(readFileSync17(BRAND_JSON_PATH, "utf-8"));
13574
+ const fullBrand = JSON.parse(readFileSync18(BRAND_JSON_PATH, "utf-8"));
13354
13575
  if (fullBrand.assets?.logo) brandLogoPath = `/brand/${fullBrand.assets.logo}`;
13355
13576
  brandIconPath = fullBrand.assets?.icon ? `/brand/${fullBrand.assets.icon}` : brandLogoPath;
13356
13577
  } catch {
@@ -13367,9 +13588,9 @@ var brandScript = `<script>window.__BRAND__=${JSON.stringify({
13367
13588
  function readInstalledVersion() {
13368
13589
  try {
13369
13590
  if (!PLATFORM_ROOT7) return "unknown";
13370
- const versionFile = join10(PLATFORM_ROOT7, "config", `.${BRAND.hostname}-version`);
13371
- if (!existsSync24(versionFile)) return "unknown";
13372
- const content = readFileSync17(versionFile, "utf-8").trim();
13591
+ const versionFile = join11(PLATFORM_ROOT7, "config", `.${BRAND.hostname}-version`);
13592
+ if (!existsSync25(versionFile)) return "unknown";
13593
+ const content = readFileSync18(versionFile, "utf-8").trim();
13373
13594
  return content || "unknown";
13374
13595
  } catch {
13375
13596
  return "unknown";
@@ -13410,7 +13631,7 @@ var clientErrorReporterScript = `<script>
13410
13631
  function cachedHtml(file) {
13411
13632
  let html = htmlCache.get(file);
13412
13633
  if (!html) {
13413
- html = readFileSync17(resolve24(process.cwd(), "public", file), "utf-8");
13634
+ html = readFileSync18(resolve24(process.cwd(), "public", file), "utf-8");
13414
13635
  const productNameEsc = escapeHtml(BRAND.productName);
13415
13636
  html = html.replace(/<title>([^<]*)<\/title>/, (_match, inner) => `<title>${escapeHtml(inner).replace(/Maxy/g, productNameEsc)}</title>`);
13416
13637
  html = html.replace('href="/favicon.ico"', `href="${escapeHtml(brandFaviconPath)}"`);
@@ -13426,26 +13647,26 @@ ${clientErrorReporterScript}
13426
13647
  }
13427
13648
  var brandedHtmlCache = /* @__PURE__ */ new Map();
13428
13649
  function loadBrandingCache(agentSlug) {
13429
- const configDir2 = join10(homedir2(), BRAND.configDir);
13650
+ const configDir2 = join11(homedir2(), BRAND.configDir);
13430
13651
  try {
13431
- const accountJsonPath = join10(configDir2, "account.json");
13432
- if (!existsSync24(accountJsonPath)) return null;
13433
- const account = JSON.parse(readFileSync17(accountJsonPath, "utf-8"));
13652
+ const accountJsonPath = join11(configDir2, "account.json");
13653
+ if (!existsSync25(accountJsonPath)) return null;
13654
+ const account = JSON.parse(readFileSync18(accountJsonPath, "utf-8"));
13434
13655
  const accountId = account.accountId;
13435
13656
  if (!accountId) return null;
13436
- const cachePath = join10(configDir2, "branding-cache", accountId, `${agentSlug}.json`);
13437
- if (!existsSync24(cachePath)) return null;
13438
- return JSON.parse(readFileSync17(cachePath, "utf-8"));
13657
+ const cachePath = join11(configDir2, "branding-cache", accountId, `${agentSlug}.json`);
13658
+ if (!existsSync25(cachePath)) return null;
13659
+ return JSON.parse(readFileSync18(cachePath, "utf-8"));
13439
13660
  } catch {
13440
13661
  return null;
13441
13662
  }
13442
13663
  }
13443
13664
  function resolveDefaultSlug() {
13444
13665
  try {
13445
- const configDir2 = join10(homedir2(), BRAND.configDir);
13446
- const accountJsonPath = join10(configDir2, "account.json");
13447
- if (!existsSync24(accountJsonPath)) return null;
13448
- const account = JSON.parse(readFileSync17(accountJsonPath, "utf-8"));
13666
+ const configDir2 = join11(homedir2(), BRAND.configDir);
13667
+ const accountJsonPath = join11(configDir2, "account.json");
13668
+ if (!existsSync25(accountJsonPath)) return null;
13669
+ const account = JSON.parse(readFileSync18(accountJsonPath, "utf-8"));
13449
13670
  return account.defaultAgent || null;
13450
13671
  } catch {
13451
13672
  return null;
@@ -13518,7 +13739,7 @@ app36.use("/vnc-popout.html", logViewerFetch);
13518
13739
  app36.get("/vnc-popout.html", (c) => {
13519
13740
  let html = htmlCache.get("vnc-popout.html");
13520
13741
  if (!html) {
13521
- html = readFileSync17(resolve24(process.cwd(), "public", "vnc-popout.html"), "utf-8");
13742
+ html = readFileSync18(resolve24(process.cwd(), "public", "vnc-popout.html"), "utf-8");
13522
13743
  const name = escapeHtml(BRAND.productName);
13523
13744
  html = html.replace("<title>Browser \u2014 Maxy</title>", `<title>${name}</title>`);
13524
13745
  html = html.replace("</head>", ` ${brandScript}
@@ -13608,8 +13829,8 @@ try {
13608
13829
  (async () => {
13609
13830
  try {
13610
13831
  let userId = "";
13611
- if (existsSync24(USERS_FILE)) {
13612
- const users = JSON.parse(readFileSync17(USERS_FILE, "utf-8").trim() || "[]");
13832
+ if (existsSync25(USERS_FILE)) {
13833
+ const users = JSON.parse(readFileSync18(USERS_FILE, "utf-8").trim() || "[]");
13613
13834
  userId = users[0]?.userId ?? "";
13614
13835
  }
13615
13836
  await backfillNullUserIdConversations(userId);
@@ -13669,6 +13890,48 @@ for (const dir of bootEnabled) {
13669
13890
  bootDelivered.push(dir);
13670
13891
  }
13671
13892
  console.error(`[plugins] readiness enabled=${bootEnabled.length} delivered=${bootDelivered.length} dist-missing=[${bootDistMissing.join(",")}] missing=[${bootMissing.join(",")}]`);
13893
+ (async () => {
13894
+ if (!bootAccount) {
13895
+ console.log("[action-completion-relay] phase=consumed-skip reason=no-account");
13896
+ return;
13897
+ }
13898
+ let records;
13899
+ try {
13900
+ records = consumeActionCompletionRelays(bootAccount.accountDir);
13901
+ } catch (err) {
13902
+ console.error(`[action-completion-relay] phase=consume-failed error=${err instanceof Error ? err.message : String(err)}`);
13903
+ return;
13904
+ }
13905
+ if (records.length === 0) {
13906
+ console.log(`[action-completion-relay] phase=consumed-empty accountId=${bootAccount.accountId.slice(0, 8)}\u2026`);
13907
+ return;
13908
+ }
13909
+ console.log(`[action-completion-relay] phase=consume-batch count=${records.length} accountId=${bootAccount.accountId.slice(0, 8)}\u2026`);
13910
+ for (const rec of records) {
13911
+ const sessionKey = `cloudflare-relay-boot:${rec.actionId}`;
13912
+ let outcome = "injected";
13913
+ let dispatchError;
13914
+ try {
13915
+ registerSession(sessionKey, "admin", bootAccount.accountId);
13916
+ setConversationIdForSession(sessionKey, rec.conversationId);
13917
+ for await (const _ev of invokeAgent({ type: "admin" }, rec.message, sessionKey)) {
13918
+ }
13919
+ } catch (err) {
13920
+ outcome = "dispatch-failed";
13921
+ dispatchError = err instanceof Error ? err.message : String(err);
13922
+ } finally {
13923
+ unregisterSession(sessionKey);
13924
+ }
13925
+ if (outcome === "injected") {
13926
+ deleteConsumedRelay(rec.filePath);
13927
+ console.log(`[action-completion-relay] phase=consumed actionId=${rec.actionId} conversationId=${rec.conversationId} ageMs=${rec.ageMs} outcome=injected`);
13928
+ } else {
13929
+ console.error(`[action-completion-relay] phase=consumed actionId=${rec.actionId} conversationId=${rec.conversationId} ageMs=${rec.ageMs} outcome=${outcome} reason=${JSON.stringify(dispatchError ?? "")} fileRetained=${JSON.stringify(rec.filePath)}`);
13930
+ }
13931
+ }
13932
+ })().catch((err) => {
13933
+ console.error(`[action-completion-relay] boot-drain rejected: ${err instanceof Error ? err.message : String(err)}`);
13934
+ });
13672
13935
  if (bootAccountConfig?.whatsapp) {
13673
13936
  console.error(`[whatsapp:boot] loading whatsapp config from account.json publicAgent=${bootPublicAgent ?? "none"}`);
13674
13937
  } else {
@@ -13676,7 +13939,7 @@ if (bootAccountConfig?.whatsapp) {
13676
13939
  }
13677
13940
  init({
13678
13941
  configDir: configDirForWhatsApp,
13679
- platformRoot: resolve24(process.env.MAXY_PLATFORM_ROOT ?? join10(__dirname, "..")),
13942
+ platformRoot: resolve24(process.env.MAXY_PLATFORM_ROOT ?? join11(__dirname, "..")),
13680
13943
  accountConfig: bootAccountConfig,
13681
13944
  onMessage: async (msg) => {
13682
13945
  try {