@rubytech/create-realagent 1.0.818 → 1.0.819

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.
Files changed (34) hide show
  1. package/package.json +1 -1
  2. package/payload/platform/lib/graph-write/dist/__tests__/action-provenance-gate.test.d.ts +2 -0
  3. package/payload/platform/lib/graph-write/dist/__tests__/action-provenance-gate.test.d.ts.map +1 -0
  4. package/payload/platform/lib/graph-write/dist/__tests__/action-provenance-gate.test.js +168 -0
  5. package/payload/platform/lib/graph-write/dist/__tests__/action-provenance-gate.test.js.map +1 -0
  6. package/payload/platform/lib/graph-write/dist/index.d.ts +28 -5
  7. package/payload/platform/lib/graph-write/dist/index.d.ts.map +1 -1
  8. package/payload/platform/lib/graph-write/dist/index.js +97 -3
  9. package/payload/platform/lib/graph-write/dist/index.js.map +1 -1
  10. package/payload/platform/lib/graph-write/src/__tests__/action-provenance-gate.test.ts +191 -0
  11. package/payload/platform/lib/graph-write/src/index.ts +90 -9
  12. package/payload/platform/neo4j/schema.cypher +24 -0
  13. package/payload/platform/plugins/admin/skills/onboarding/SKILL.md +24 -6
  14. package/payload/platform/plugins/docs/references/internals.md +16 -0
  15. package/payload/platform/plugins/memory/PLUGIN.md +6 -0
  16. package/payload/platform/plugins/memory/mcp/dist/index.js +7 -2
  17. package/payload/platform/plugins/memory/mcp/dist/index.js.map +1 -1
  18. package/payload/platform/plugins/memory/mcp/dist/tools/memory-write.d.ts +8 -0
  19. package/payload/platform/plugins/memory/mcp/dist/tools/memory-write.d.ts.map +1 -1
  20. package/payload/platform/plugins/memory/mcp/dist/tools/memory-write.js +26 -2
  21. package/payload/platform/plugins/memory/mcp/dist/tools/memory-write.js.map +1 -1
  22. package/payload/platform/plugins/memory/references/schema-base.md +8 -0
  23. package/payload/platform/plugins/tasks/PLUGIN.md +2 -2
  24. package/payload/platform/plugins/tasks/mcp/dist/index.js +10 -5
  25. package/payload/platform/plugins/tasks/mcp/dist/index.js.map +1 -1
  26. package/payload/platform/plugins/tasks/mcp/dist/tools/task-create.d.ts +27 -1
  27. package/payload/platform/plugins/tasks/mcp/dist/tools/task-create.d.ts.map +1 -1
  28. package/payload/platform/plugins/tasks/mcp/dist/tools/task-create.js +45 -2
  29. package/payload/platform/plugins/tasks/mcp/dist/tools/task-create.js.map +1 -1
  30. package/payload/platform/plugins/tasks/mcp/dist/tools/task-update.d.ts +20 -1
  31. package/payload/platform/plugins/tasks/mcp/dist/tools/task-update.d.ts.map +1 -1
  32. package/payload/platform/plugins/tasks/mcp/dist/tools/task-update.js +46 -6
  33. package/payload/platform/plugins/tasks/mcp/dist/tools/task-update.js.map +1 -1
  34. package/payload/server/server.js +523 -44
@@ -121,8 +121,225 @@ import {
121
121
  writeAdminUserAndPerson
122
122
  } from "./chunk-PXQA2MA3.js";
123
123
 
124
- // ../lib/graph-trash/dist/index.js
124
+ // ../lib/graph-write/dist/audit.js
125
+ var require_audit = __commonJS({
126
+ "../lib/graph-write/dist/audit.js"(exports) {
127
+ "use strict";
128
+ Object.defineProperty(exports, "__esModule", { value: true });
129
+ exports.auditCypherWrite = auditCypherWrite;
130
+ exports.formatAuditLine = formatAuditLine;
131
+ var EDGE_PATTERN = /\[[^\]]*?:([A-Z_][A-Za-z0-9_]*(?:\|[A-Z_][A-Za-z0-9_]*)*)[^\]]*?\]/g;
132
+ var CREATE_OR_MERGE_NODE = /\b(?:CREATE|MERGE)\s*\(\s*[A-Za-z_][A-Za-z0-9_]*\s*:\s*[A-Z]/g;
133
+ var PROVENANCE_TOKEN = /\bcreatedBy(?:Agent|Tool|Session|Source)\b/g;
134
+ function stripStringLiterals(cypher) {
135
+ return cypher.replace(/'[^']*'|"[^"]*"/g, '""');
136
+ }
137
+ function extractEdgeTypes(cleaned) {
138
+ const out = /* @__PURE__ */ new Set();
139
+ for (const m of cleaned.matchAll(EDGE_PATTERN)) {
140
+ for (const t of m[1].split("|")) {
141
+ const clean = t.trim();
142
+ if (clean)
143
+ out.add(clean);
144
+ }
145
+ }
146
+ return out;
147
+ }
148
+ function countCreateOrMergeNodes(cleaned) {
149
+ const matches = cleaned.match(CREATE_OR_MERGE_NODE);
150
+ return matches ? matches.length : 0;
151
+ }
152
+ function countProvenanceStamps(cleaned) {
153
+ const matches = cleaned.match(PROVENANCE_TOKEN);
154
+ return matches ? matches.length : 0;
155
+ }
156
+ function auditCypherWrite(input) {
157
+ const warnings = [];
158
+ const cleaned = stripStringLiterals(input.cypher);
159
+ const referencedTypes = extractEdgeTypes(cleaned);
160
+ for (const t of referencedTypes) {
161
+ if (!input.schema.relationshipTypes.has(t)) {
162
+ warnings.push({ kind: "unknown-type-warning", type: t });
163
+ }
164
+ }
165
+ if (input.nodesCreated > 0) {
166
+ const createOrMergeNodes = countCreateOrMergeNodes(cleaned);
167
+ if (createOrMergeNodes > 0) {
168
+ const stamps = countProvenanceStamps(cleaned);
169
+ if (stamps < createOrMergeNodes) {
170
+ warnings.push({
171
+ kind: "missing-provenance-warning",
172
+ created: createOrMergeNodes,
173
+ stamped: stamps
174
+ });
175
+ }
176
+ }
177
+ }
178
+ if (input.orphanIds.length > 0) {
179
+ warnings.push({ kind: "orphan-warning", orphanIds: input.orphanIds });
180
+ }
181
+ return warnings;
182
+ }
183
+ function formatAuditLine(line) {
184
+ const prefixField = `query="${line.cypherPrefix.replace(/"/g, "'")}"`;
185
+ switch (line.kind) {
186
+ case "accepted":
187
+ return `[graph-cypher-write] accepted ${prefixField} nodesCreated=${line.nodesCreated} relsCreated=${line.relsCreated} agentName=${line.agentName} sessionId=${line.sessionId}`;
188
+ case "orphan-warning":
189
+ return `[graph-cypher-write] orphan-warning ${prefixField} orphanIds=${line.orphanIds.join(",")}`;
190
+ case "unknown-type-warning":
191
+ return `[graph-cypher-write] unknown-type-warning ${prefixField} type=${line.type}`;
192
+ case "missing-provenance-warning":
193
+ return `[graph-cypher-write] missing-provenance-warning ${prefixField} created=${line.created} stamped=${line.stamped}`;
194
+ }
195
+ }
196
+ }
197
+ });
198
+
199
+ // ../lib/graph-write/dist/index.js
125
200
  var require_dist = __commonJS({
201
+ "../lib/graph-write/dist/index.js"(exports) {
202
+ "use strict";
203
+ var __createBinding = exports && exports.__createBinding || (Object.create ? (function(o, m, k, k2) {
204
+ if (k2 === void 0) k2 = k;
205
+ var desc = Object.getOwnPropertyDescriptor(m, k);
206
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
207
+ desc = { enumerable: true, get: function() {
208
+ return m[k];
209
+ } };
210
+ }
211
+ Object.defineProperty(o, k2, desc);
212
+ }) : (function(o, m, k, k2) {
213
+ if (k2 === void 0) k2 = k;
214
+ o[k2] = m[k];
215
+ }));
216
+ var __exportStar = exports && exports.__exportStar || function(m, exports2) {
217
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports2, p)) __createBinding(exports2, m, p);
218
+ };
219
+ Object.defineProperty(exports, "__esModule", { value: true });
220
+ exports.ACTION_PROVENANCE_LABELS = void 0;
221
+ exports.stampCreatedBy = stampCreatedBy;
222
+ exports.writeNodeWithEdges = writeNodeWithEdges2;
223
+ __exportStar(require_audit(), exports);
224
+ exports.ACTION_PROVENANCE_LABELS = /* @__PURE__ */ new Set([
225
+ "Person",
226
+ "UserProfile",
227
+ "AdminUser",
228
+ "Organization",
229
+ "LocalBusiness",
230
+ "CloudflareTunnel",
231
+ "CloudflareHostname"
232
+ ]);
233
+ function requiresActionProvenance(labels) {
234
+ for (const label of labels) {
235
+ if (exports.ACTION_PROVENANCE_LABELS.has(label))
236
+ return true;
237
+ }
238
+ return false;
239
+ }
240
+ function findProducedFromTaskCandidates(relationships) {
241
+ return relationships.filter((r) => r.type === "PRODUCED" && r.direction === "incoming");
242
+ }
243
+ function stampCreatedBy(props, createdBy) {
244
+ return {
245
+ ...props,
246
+ createdByAgent: createdBy.agent ?? "unknown",
247
+ createdBySession: createdBy.session ?? "unknown",
248
+ createdByTool: createdBy.tool ?? null,
249
+ createdBySource: createdBy.source ?? null
250
+ };
251
+ }
252
+ async function writeNodeWithEdges2(params) {
253
+ const { session, labels, props, relationships, createdBy } = params;
254
+ const agentLabel = createdBy.agent ?? createdBy.source ?? "unknown";
255
+ const labelCsv = labels.join(",");
256
+ const reviewDigestActionTool = typeof props.actionTool === "string" && props.actionTool === "review-digest-compose";
257
+ if (labels.includes("ReviewAlert") || reviewDigestActionTool) {
258
+ const actionToolField = reviewDigestActionTool ? "review-digest-compose" : "n/a";
259
+ process.stderr.write(`[graph-write] reject reason=removed-feature labels=${labelCsv} actionTool=${actionToolField} agent=${agentLabel}
260
+ `);
261
+ throw new Error("Write doctrine violated: review-detector feature removed (Task 884) \u2014 `:ReviewAlert` and `:Event {actionTool:'review-digest-compose'}` writes are not allowed.");
262
+ }
263
+ if (!relationships || relationships.length < 1) {
264
+ process.stderr.write(`[graph-write] reject reason=zero-relationships labels=${labelCsv} agent=${agentLabel}
265
+ `);
266
+ throw new Error("Write doctrine violated: a node must be created with at least one relationship. See .docs/neo4j.md (Write doctrine).");
267
+ }
268
+ const labelStr = labels.map((l) => `\`${l.replace(/`/g, "")}\``).join(":");
269
+ const nodeProps = stampCreatedBy(props, createdBy);
270
+ return await session.executeWrite(async (tx) => {
271
+ const targetIds = relationships.map((r) => r.targetNodeId);
272
+ const check = await tx.run(`UNWIND $ids AS id MATCH (t) WHERE elementId(t) = id RETURN elementId(t) AS id, labels(t) AS labels`, { ids: targetIds });
273
+ const labelsByTarget = /* @__PURE__ */ new Map();
274
+ for (const rec of check.records) {
275
+ labelsByTarget.set(rec.get("id"), rec.get("labels"));
276
+ }
277
+ const found = labelsByTarget.size;
278
+ const uniqueRequested = new Set(targetIds).size;
279
+ if (found !== uniqueRequested) {
280
+ process.stderr.write(`[graph-write] reject reason=unresolved-target labels=${labelCsv} agent=${agentLabel} requested=${uniqueRequested} found=${found}
281
+ `);
282
+ throw new Error(`Write doctrine violated: ${uniqueRequested - found} of ${uniqueRequested} relationship target(s) did not resolve (elementId mismatch). No node created.`);
283
+ }
284
+ let producedByTaskId = null;
285
+ if (requiresActionProvenance(labels) && (createdBy.agent ?? "") !== "system") {
286
+ const candidates = findProducedFromTaskCandidates(relationships);
287
+ const taskCandidates = candidates.filter((r) => {
288
+ const lbls = labelsByTarget.get(r.targetNodeId);
289
+ return Array.isArray(lbls) && lbls.includes("Task");
290
+ });
291
+ if (taskCandidates.length === 0) {
292
+ process.stderr.write(`[graph-write] reject reason=missing-action-provenance labels=${labelCsv} agent=${agentLabel}
293
+ `);
294
+ throw new Error(`Process provenance doctrine violated: write to ${labelCsv} requires an inbound :PRODUCED edge from a :Task (createdBy.agent='${agentLabel}'). See .docs/neo4j.md (Process provenance doctrine).`);
295
+ }
296
+ producedByTaskId = taskCandidates[0].targetNodeId;
297
+ }
298
+ let nodeRes;
299
+ try {
300
+ nodeRes = await tx.run(`CREATE (n:${labelStr} $props) RETURN elementId(n) AS nodeId, labels(n) AS nodeLabels`, { props: nodeProps });
301
+ } catch (err) {
302
+ const code = err?.code ?? "";
303
+ if (code === "Neo.ClientError.Schema.ConstraintValidationFailed" && labels.includes("UserProfile")) {
304
+ const accountIdProp = nodeProps.accountId;
305
+ const userIdProp = nodeProps.userId;
306
+ const acctSlice = typeof accountIdProp === "string" ? accountIdProp.slice(0, 8) : "unknown";
307
+ const userSlice = typeof userIdProp === "string" ? userIdProp.slice(0, 8) : "unknown";
308
+ process.stderr.write(`[graph-write] reject reason=user-profile-uniqueness-violation accountId=${acctSlice} userId=${userSlice} writer=${agentLabel}
309
+ `);
310
+ }
311
+ throw err;
312
+ }
313
+ const nodeId = nodeRes.records[0].get("nodeId");
314
+ const nodeLabels = nodeRes.records[0].get("nodeLabels");
315
+ let edgesCreated = 0;
316
+ for (const rel of relationships) {
317
+ const type = rel.type.replace(/`/g, "");
318
+ const q = rel.direction === "outgoing" ? `MATCH (a), (b) WHERE elementId(a) = $from AND elementId(b) = $to CREATE (a)-[:\`${type}\`]->(b)` : `MATCH (a), (b) WHERE elementId(a) = $from AND elementId(b) = $to CREATE (b)-[:\`${type}\`]->(a)`;
319
+ const r = await tx.run(q, { from: nodeId, to: rel.targetNodeId });
320
+ const created = r.summary.counters.updates().relationshipsCreated;
321
+ if (created === 0) {
322
+ process.stderr.write(`[graph-write] reject reason=unresolved-target-on-create labels=${labelCsv} agent=${agentLabel} relType=${rel.type} targetId=${rel.targetNodeId}
323
+ `);
324
+ throw new Error(`Write doctrine violated: relationship CREATE to target ${rel.targetNodeId} produced 0 edges (target likely deleted concurrently after pre-check). Transaction rolled back.`);
325
+ }
326
+ edgesCreated += created;
327
+ }
328
+ if (edgesCreated !== relationships.length) {
329
+ process.stderr.write(`[graph-write] reject reason=edge-count-mismatch labels=${labelCsv} agent=${agentLabel} requested=${relationships.length} created=${edgesCreated}
330
+ `);
331
+ throw new Error(`Write doctrine violated: expected ${relationships.length} edges, created ${edgesCreated}. Transaction rolled back.`);
332
+ }
333
+ process.stderr.write(`[graph-write] accepted labels=${labelCsv} edges=${edgesCreated} createdByAgent=${createdBy.agent ?? "unknown"} createdByTool=${createdBy.tool ?? createdBy.source ?? "unknown"} producedByTask=${producedByTaskId ?? "none"}
334
+ `);
335
+ return { nodeId, labels: nodeLabels, edgesCreated };
336
+ });
337
+ }
338
+ }
339
+ });
340
+
341
+ // ../lib/graph-trash/dist/index.js
342
+ var require_dist2 = __commonJS({
126
343
  "../lib/graph-trash/dist/index.js"(exports) {
127
344
  "use strict";
128
345
  Object.defineProperty(exports, "__esModule", { value: true });
@@ -618,7 +835,7 @@ var serveStatic = (options = { root: "" }) => {
618
835
  };
619
836
 
620
837
  // server/index.ts
621
- import { readFileSync as readFileSync15, existsSync as existsSync21, watchFile } from "fs";
838
+ import { readFileSync as readFileSync16, existsSync as existsSync22, watchFile } from "fs";
622
839
  import { resolve as resolve21, join as join9, basename as basename5 } from "path";
623
840
  import { homedir as homedir2 } from "os";
624
841
 
@@ -8580,7 +8797,7 @@ var events_default = app20;
8580
8797
  // server/routes/admin/cloudflare.ts
8581
8798
  import { homedir } from "os";
8582
8799
  import { resolve as resolve14 } from "path";
8583
- import { readFileSync as readFileSync13 } from "fs";
8800
+ import { readFileSync as readFileSync14 } from "fs";
8584
8801
 
8585
8802
  // app/lib/dns-label.ts
8586
8803
  var VALID_LABEL = /^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?$/;
@@ -8618,6 +8835,214 @@ function addAliasDomain(hostname2) {
8618
8835
  writeFileSync6(ALIAS_DOMAINS_PATH, JSON.stringify([...existing], null, 2) + "\n", "utf-8");
8619
8836
  }
8620
8837
 
8838
+ // app/lib/cloudflare-task-tracker.ts
8839
+ import { readFileSync as readFileSync13, existsSync as existsSync17 } from "fs";
8840
+ import { randomUUID as randomUUID7 } from "crypto";
8841
+ var import_dist = __toESM(require_dist(), 1);
8842
+ var CREATED_BY_AGENT = "cloudflare-setup-endpoint";
8843
+ var TASK_KIND = "cloudflare-tunnel-login";
8844
+ async function openCloudflareTask(params) {
8845
+ const { accountId, conversationKey, inputsProvided } = params;
8846
+ const taskId = randomUUID7();
8847
+ const now = (/* @__PURE__ */ new Date()).toISOString();
8848
+ const session = getSession();
8849
+ try {
8850
+ const conv = await session.run(
8851
+ `MATCH (c:Conversation {sessionKey: $conversationKey, accountId: $accountId}) RETURN elementId(c) AS id LIMIT 1`,
8852
+ { conversationKey, accountId }
8853
+ );
8854
+ if (conv.records.length === 0) {
8855
+ throw new Error(
8856
+ `cloudflare-task-tracker: no Conversation with sessionKey=${conversationKey.slice(-8)} for accountId \u2014 refusing to create an orphan Task`
8857
+ );
8858
+ }
8859
+ const conversationElementId = conv.records[0].get("id");
8860
+ const props = {
8861
+ taskId,
8862
+ accountId,
8863
+ name: "Cloudflare tunnel login + setup",
8864
+ description: `Deterministic cloudflare setup invoked by /api/admin/cloudflare/setup. inputsProvided=[${inputsProvided.join(", ")}]`,
8865
+ status: "running",
8866
+ priority: "normal",
8867
+ kind: TASK_KIND,
8868
+ inputsProvided,
8869
+ startedAt: now,
8870
+ createdAt: now,
8871
+ updatedAt: now
8872
+ };
8873
+ const relationships = [
8874
+ {
8875
+ type: "RAISED_DURING",
8876
+ direction: "outgoing",
8877
+ targetNodeId: conversationElementId
8878
+ }
8879
+ ];
8880
+ const result = await (0, import_dist.writeNodeWithEdges)({
8881
+ session,
8882
+ labels: ["Task"],
8883
+ props,
8884
+ relationships,
8885
+ createdBy: {
8886
+ agent: CREATED_BY_AGENT,
8887
+ session: conversationKey,
8888
+ tool: "cloudflare-setup-endpoint"
8889
+ }
8890
+ });
8891
+ process.stderr.write(
8892
+ `[task] action-start kind=${TASK_KIND} taskId=${taskId} raisedDuring=${conversationKey.slice(-8)}
8893
+ `
8894
+ );
8895
+ return { taskId, taskElementId: result.nodeId };
8896
+ } finally {
8897
+ await session.close();
8898
+ }
8899
+ }
8900
+ async function appendCloudflareSteps(taskId, accountId, streamLogPath) {
8901
+ if (!existsSync17(streamLogPath)) return [];
8902
+ let content;
8903
+ try {
8904
+ content = readFileSync13(streamLogPath, "utf-8");
8905
+ } catch {
8906
+ return [];
8907
+ }
8908
+ const steps = [];
8909
+ for (const line of content.split(/\r?\n/)) {
8910
+ const m = line.match(/\bphase_line\s+setup-tunnel\s+step=(\S+)/);
8911
+ if (m) steps.push(m[1]);
8912
+ }
8913
+ if (steps.length === 0) return [];
8914
+ const session = getSession();
8915
+ try {
8916
+ await session.run(
8917
+ `MATCH (t:Task {taskId: $taskId, accountId: $accountId})
8918
+ SET t.steps = coalesce(t.steps, []) + $steps,
8919
+ t.updatedAt = $updatedAt`,
8920
+ { taskId, accountId, steps, updatedAt: (/* @__PURE__ */ new Date()).toISOString() }
8921
+ );
8922
+ for (const step of steps) {
8923
+ process.stderr.write(
8924
+ `[task] action-step kind=${TASK_KIND} taskId=${taskId} step=${step}
8925
+ `
8926
+ );
8927
+ }
8928
+ return steps;
8929
+ } finally {
8930
+ await session.close();
8931
+ }
8932
+ }
8933
+ async function completeCloudflareTask(params) {
8934
+ const { taskId, taskElementId, accountId, conversationKey, tunnelId, tunnelName, hostnames, status, errorMessage } = params;
8935
+ const now = (/* @__PURE__ */ new Date()).toISOString();
8936
+ if (status === "failed" && (!errorMessage || errorMessage.trim().length === 0)) {
8937
+ throw new Error(
8938
+ "cloudflare-task-tracker: errorMessage is required when status='failed' (Task 885 process-provenance contract)."
8939
+ );
8940
+ }
8941
+ const session = getSession();
8942
+ try {
8943
+ if (status === "completed" && tunnelId && tunnelName) {
8944
+ const conv = await session.run(
8945
+ `MATCH (c:Conversation {sessionKey: $conversationKey, accountId: $accountId}) RETURN elementId(c) AS id LIMIT 1`,
8946
+ { conversationKey, accountId }
8947
+ );
8948
+ const conversationElementId = conv.records.length > 0 ? conv.records[0].get("id") : null;
8949
+ const tunnelProps = {
8950
+ accountId,
8951
+ tunnelId,
8952
+ tunnelName,
8953
+ createdAt: now,
8954
+ updatedAt: now
8955
+ };
8956
+ const tunnelRels = [
8957
+ { type: "PRODUCED", direction: "incoming", targetNodeId: taskElementId }
8958
+ ];
8959
+ if (conversationElementId) {
8960
+ tunnelRels.push({
8961
+ type: "RAISED_DURING",
8962
+ direction: "outgoing",
8963
+ targetNodeId: conversationElementId
8964
+ });
8965
+ }
8966
+ const tunnelWrite = await (0, import_dist.writeNodeWithEdges)({
8967
+ session,
8968
+ labels: ["CloudflareTunnel"],
8969
+ props: tunnelProps,
8970
+ relationships: tunnelRels,
8971
+ createdBy: {
8972
+ agent: CREATED_BY_AGENT,
8973
+ session: conversationKey,
8974
+ tool: "cloudflare-setup-endpoint"
8975
+ }
8976
+ });
8977
+ for (const h of hostnames ?? []) {
8978
+ const hostRels = [
8979
+ { type: "PRODUCED", direction: "incoming", targetNodeId: taskElementId },
8980
+ {
8981
+ type: "ROUTES_TO",
8982
+ direction: "outgoing",
8983
+ targetNodeId: tunnelWrite.nodeId
8984
+ }
8985
+ ];
8986
+ await (0, import_dist.writeNodeWithEdges)({
8987
+ session,
8988
+ labels: ["CloudflareHostname"],
8989
+ props: {
8990
+ accountId,
8991
+ hostnameValue: h.hostnameValue,
8992
+ tunnelId,
8993
+ isApex: h.isApex,
8994
+ createdAt: now,
8995
+ updatedAt: now
8996
+ },
8997
+ relationships: hostRels,
8998
+ createdBy: {
8999
+ agent: CREATED_BY_AGENT,
9000
+ session: conversationKey,
9001
+ tool: "cloudflare-setup-endpoint"
9002
+ }
9003
+ });
9004
+ }
9005
+ }
9006
+ const setClauses = [
9007
+ "t.status = $status",
9008
+ "t.completedAt = $now",
9009
+ "t.updatedAt = $now"
9010
+ ];
9011
+ const queryParams = { taskId, accountId, status, now };
9012
+ if (status === "failed" && errorMessage) {
9013
+ setClauses.push("t.errorMessage = $errorMessage");
9014
+ queryParams.errorMessage = errorMessage;
9015
+ }
9016
+ const updateRes = await session.run(
9017
+ `MATCH (t:Task {taskId: $taskId, accountId: $accountId})
9018
+ SET ${setClauses.join(", ")}
9019
+ RETURN size(coalesce(t.steps, [])) AS stepsCount`,
9020
+ queryParams
9021
+ );
9022
+ const stepsCount = updateRes.records[0]?.get("stepsCount")?.toNumber?.() ?? 0;
9023
+ process.stderr.write(
9024
+ `[task] action-done kind=${TASK_KIND} taskId=${taskId} status=${status} stepsCount=${stepsCount}
9025
+ `
9026
+ );
9027
+ } finally {
9028
+ await session.close();
9029
+ }
9030
+ }
9031
+ function readTunnelState(brandConfigDir) {
9032
+ const statePath = `${process.env.HOME ?? ""}/${brandConfigDir}/cloudflared/tunnel.state`;
9033
+ if (!existsSync17(statePath)) return null;
9034
+ try {
9035
+ const parsed = JSON.parse(readFileSync13(statePath, "utf-8"));
9036
+ const tunnelId = typeof parsed.tunnelId === "string" ? parsed.tunnelId : null;
9037
+ const tunnelName = typeof parsed.tunnelName === "string" ? parsed.tunnelName : null;
9038
+ const domain = typeof parsed.domain === "string" ? parsed.domain : null;
9039
+ if (!tunnelId || !tunnelName || !domain) return null;
9040
+ return { tunnelId, tunnelName, domain };
9041
+ } catch {
9042
+ return null;
9043
+ }
9044
+ }
9045
+
8621
9046
  // server/routes/admin/cloudflare.ts
8622
9047
  var SETUP_TIMEOUT_MS = 10 * 60 * 1e3;
8623
9048
  var DOMAINS_TIMEOUT_MS = 40 * 1e3;
@@ -8625,7 +9050,7 @@ function loadBrandInfo() {
8625
9050
  const platformRoot2 = process.env.MAXY_PLATFORM_ROOT ?? resolve14(process.cwd(), "..");
8626
9051
  const brandPath = resolve14(platformRoot2, "config", "brand.json");
8627
9052
  try {
8628
- const parsed = JSON.parse(readFileSync13(brandPath, "utf-8"));
9053
+ const parsed = JSON.parse(readFileSync14(brandPath, "utf-8"));
8629
9054
  const hostname2 = typeof parsed.hostname === "string" && parsed.hostname ? parsed.hostname : "maxy";
8630
9055
  const configDir2 = typeof parsed.configDir === "string" && parsed.configDir ? parsed.configDir : ".maxy";
8631
9056
  return { hostname: hostname2, configDir: configDir2 };
@@ -8867,6 +9292,17 @@ app21.post("/setup", requireAdminSession, async (c) => {
8867
9292
  if (await isActionActive("cloudflare-setup")) {
8868
9293
  return err("request", "Another Cloudflare setup is already running. Wait for it to finish before starting a new one.");
8869
9294
  }
9295
+ let cloudflareTask;
9296
+ try {
9297
+ cloudflareTask = await openCloudflareTask({
9298
+ accountId,
9299
+ conversationKey: sessionKey,
9300
+ inputsProvided: ["adminLabel", "adminDomain", publicFqdn ? "publicLabel" : null, apex ? "apex" : null, "password"].filter((s) => typeof s === "string")
9301
+ });
9302
+ log(`phase=task-opened taskId=${cloudflareTask.taskId}`);
9303
+ } catch (e) {
9304
+ return err("script", `Failed to open process-provenance Task record: ${e instanceof Error ? e.message : String(e)}`);
9305
+ }
8870
9306
  let actionId;
8871
9307
  let unit;
8872
9308
  try {
@@ -8879,8 +9315,27 @@ app21.post("/setup", requireAdminSession, async (c) => {
8879
9315
  log(`phase=action-launched id=${actionId} unit=${unit}`);
8880
9316
  void (async () => {
8881
9317
  const status = await waitForExit(unit, SETUP_TIMEOUT_MS);
9318
+ try {
9319
+ const appendedSteps = await appendCloudflareSteps(cloudflareTask.taskId, accountId, streamLogPath);
9320
+ log(`phase=task-steps-appended count=${appendedSteps.length}`);
9321
+ } catch (e) {
9322
+ logErr(`phase=task-steps-append-failed reason="${e instanceof Error ? e.message : String(e)}"`);
9323
+ }
8882
9324
  if (!status || status.execMainStatus !== 0) {
8883
9325
  logErr(`phase=post-exit-skipped reason=${status ? `exit=${status.execMainStatus}` : "unit-gone"} id=${actionId}`);
9326
+ try {
9327
+ const exitReason = status ? `script exited with status ${status.execMainStatus}` : "systemd unit vanished before exit recorded";
9328
+ await completeCloudflareTask({
9329
+ taskId: cloudflareTask.taskId,
9330
+ taskElementId: cloudflareTask.taskElementId,
9331
+ accountId,
9332
+ conversationKey: sessionKey,
9333
+ status: "failed",
9334
+ errorMessage: exitReason
9335
+ });
9336
+ } catch (e) {
9337
+ logErr(`phase=task-close-failed status=failed reason="${e instanceof Error ? e.message : String(e)}"`);
9338
+ }
8884
9339
  return;
8885
9340
  }
8886
9341
  const candidates = [publicFqdn, apex].filter((h) => typeof h === "string" && h.length > 0);
@@ -8900,6 +9355,30 @@ app21.post("/setup", requireAdminSession, async (c) => {
8900
9355
  logErr(`phase=alias-domain-write host=${host} result=error reason="${e instanceof Error ? e.message : String(e)}"`);
8901
9356
  }
8902
9357
  }
9358
+ try {
9359
+ const tunnelState = readTunnelState(brand.configDir);
9360
+ const allHostnames = [adminFqdn, publicFqdn, apex].filter(
9361
+ (h) => typeof h === "string" && h.length > 0
9362
+ );
9363
+ const hostnameRecords = allHostnames.map((value) => ({
9364
+ hostnameValue: value,
9365
+ // Apex heuristic: exactly one dot in the FQDN. Mirrors setup-tunnel.sh:332.
9366
+ isApex: (value.match(/\./g)?.length ?? 0) === 1
9367
+ }));
9368
+ await completeCloudflareTask({
9369
+ taskId: cloudflareTask.taskId,
9370
+ taskElementId: cloudflareTask.taskElementId,
9371
+ accountId,
9372
+ conversationKey: sessionKey,
9373
+ tunnelId: tunnelState?.tunnelId,
9374
+ tunnelName: tunnelState?.tunnelName,
9375
+ hostnames: tunnelState ? hostnameRecords : void 0,
9376
+ status: "completed"
9377
+ });
9378
+ log(`phase=task-closed status=completed tunnelId=${tunnelState?.tunnelId ?? "absent"} hostnames=${allHostnames.length}`);
9379
+ } catch (e) {
9380
+ logErr(`phase=task-close-failed status=completed reason="${e instanceof Error ? e.message : String(e)}"`);
9381
+ }
8903
9382
  log(`phase=done action=${actionId}`);
8904
9383
  })().catch((e) => logErr(`post-exit handler threw: ${e}`));
8905
9384
  const total = Date.now() - started;
@@ -9592,7 +10071,7 @@ app22.delete("/", requireAdminSession, async (c) => {
9592
10071
  var files_default = app22;
9593
10072
 
9594
10073
  // ../lib/graph-search/src/index.ts
9595
- var import_dist = __toESM(require_dist());
10074
+ var import_dist2 = __toESM(require_dist2());
9596
10075
  import { int } from "neo4j-driver";
9597
10076
  var VECTOR_WEIGHT = 0.7;
9598
10077
  var BM25_WEIGHT = 0.3;
@@ -9647,7 +10126,7 @@ async function bm25Only(session, params) {
9647
10126
  ${scopeClause}
9648
10127
  ${agentClause}
9649
10128
  ${labelClause}
9650
- AND ${(0, import_dist.notTrashed)("node")}
10129
+ AND ${(0, import_dist2.notTrashed)("node")}
9651
10130
  ${kwClause}
9652
10131
  RETURN node, score, labels(node) AS nodeLabels, elementId(node) AS nodeId
9653
10132
  ORDER BY score DESC
@@ -9737,7 +10216,7 @@ async function hybrid(session, embed2, params) {
9737
10216
  WHERE node.accountId = $accountId
9738
10217
  ${scopeClause}
9739
10218
  ${agentClause}
9740
- AND ${(0, import_dist.notTrashed)("node")}
10219
+ AND ${(0, import_dist2.notTrashed)("node")}
9741
10220
  ${keywordClause}
9742
10221
  RETURN node, score, labels(node) AS nodeLabels, elementId(node) AS nodeId
9743
10222
  ORDER BY score DESC
@@ -9798,7 +10277,7 @@ async function hybrid(session, embed2, params) {
9798
10277
  const propResult = await session.run(
9799
10278
  `MATCH (node)
9800
10279
  WHERE node.accountId = $accountId
9801
- AND ${(0, import_dist.notTrashed)("node")}
10280
+ AND ${(0, import_dist2.notTrashed)("node")}
9802
10281
  AND node.keywords IS NOT NULL
9803
10282
  AND ANY(kw IN $kwSubs WHERE ANY(nk IN node.keywords WHERE toLower(nk) = kw))
9804
10283
  ${propScopeClause}
@@ -9855,7 +10334,7 @@ async function hybrid(session, embed2, params) {
9855
10334
  `UNWIND $nodeIds AS nid
9856
10335
  MATCH (n)-[r]-(related)
9857
10336
  WHERE elementId(n) = nid
9858
- AND ${(0, import_dist.notTrashed)("related")}
10337
+ AND ${(0, import_dist2.notTrashed)("related")}
9859
10338
  ${expandScopeClause}
9860
10339
  ${expandAgentClause}
9861
10340
  WITH nid, n, r, related
@@ -11031,7 +11510,7 @@ var adherence_default = app30;
11031
11510
  import neo4j3 from "neo4j-driver";
11032
11511
  import { readFile as readFile5, readdir as readdir3, stat as stat5 } from "fs/promises";
11033
11512
  import { resolve as resolve17, relative as relative2, isAbsolute } from "path";
11034
- import { existsSync as existsSync17 } from "fs";
11513
+ import { existsSync as existsSync18 } from "fs";
11035
11514
  var LIMIT = 50;
11036
11515
  var TEXT_MIME_PREFIXES = ["text/", "application/json", "application/markdown"];
11037
11516
  var ADMIN_AGENT_FILES = ["IDENTITY.md", "SOUL.md", "KNOWLEDGE.md"];
@@ -11179,7 +11658,7 @@ async function fetchAgentTemplateRows(accountDir) {
11179
11658
  async function unionSpecialistFilenames(overrideDir, bundledDir) {
11180
11659
  const names = /* @__PURE__ */ new Set();
11181
11660
  for (const dir of [overrideDir, bundledDir]) {
11182
- if (!existsSync17(dir)) continue;
11661
+ if (!existsSync18(dir)) continue;
11183
11662
  try {
11184
11663
  const entries = await readdir3(dir);
11185
11664
  for (const entry of entries) {
@@ -11194,7 +11673,7 @@ async function unionSpecialistFilenames(overrideDir, bundledDir) {
11194
11673
  }
11195
11674
  async function readAgentTemplateRow(inp) {
11196
11675
  let chosenPath = null;
11197
- if (existsSync17(inp.overridePath)) {
11676
+ if (existsSync18(inp.overridePath)) {
11198
11677
  try {
11199
11678
  validateFilePathInAccount(inp.overridePath, inp.overrideRoot);
11200
11679
  chosenPath = inp.overridePath;
@@ -11205,7 +11684,7 @@ async function readAgentTemplateRow(inp) {
11205
11684
  );
11206
11685
  return null;
11207
11686
  }
11208
- } else if (existsSync17(inp.bundledPath)) {
11687
+ } else if (existsSync18(inp.bundledPath)) {
11209
11688
  if (!isWithin(inp.bundledPath, inp.bundledRoot)) {
11210
11689
  console.error(
11211
11690
  `[admin/sidebar-artefacts] agent-template-read-failed agent=${inp.displayName} kind=${inp.logName} error="bundled path outside PLATFORM_ROOT"`
@@ -11247,7 +11726,7 @@ var sidebar_artefacts_default = app31;
11247
11726
  // server/routes/admin/sidebar-artefact-save.ts
11248
11727
  import { mkdir as mkdir4, readdir as readdir4, stat as stat6, writeFile as writeFile5 } from "fs/promises";
11249
11728
  import { resolve as resolve18 } from "path";
11250
- import { existsSync as existsSync18 } from "fs";
11729
+ import { existsSync as existsSync19 } from "fs";
11251
11730
  var ADMIN_AGENT_FILES2 = /* @__PURE__ */ new Set(["IDENTITY.md", "SOUL.md", "KNOWLEDGE.md"]);
11252
11731
  var UUID_RE5 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
11253
11732
  var app32 = new Hono();
@@ -11311,7 +11790,7 @@ async function resolveSavePath(id, accountId, accountDir) {
11311
11790
  }
11312
11791
  if (UUID_RE5.test(id)) {
11313
11792
  const dir = resolve18(ATTACHMENTS_ROOT, accountId, id);
11314
- if (!existsSync18(dir)) {
11793
+ if (!existsSync19(dir)) {
11315
11794
  return { kind: "reject", status: 400, reason: "not-found" };
11316
11795
  }
11317
11796
  try {
@@ -11335,7 +11814,7 @@ var sidebar_artefact_save_default = app32;
11335
11814
 
11336
11815
  // server/routes/admin/sidebar-artefact-content.ts
11337
11816
  import { readFile as readFile6, readdir as readdir5 } from "fs/promises";
11338
- import { existsSync as existsSync19 } from "fs";
11817
+ import { existsSync as existsSync20 } from "fs";
11339
11818
  import { resolve as resolve19 } from "path";
11340
11819
  var UUID_RE6 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
11341
11820
  var app33 = new Hono();
@@ -11349,7 +11828,7 @@ app33.get("/", requireAdminSession, async (c) => {
11349
11828
  return new Response("Not found", { status: 404 });
11350
11829
  }
11351
11830
  const dir = resolve19(ATTACHMENTS_ROOT, accountId, id);
11352
- if (!existsSync19(dir)) {
11831
+ if (!existsSync20(dir)) {
11353
11832
  console.error(`[admin/sidebar-artefact-content] not-found id=${id.slice(0, 8)}`);
11354
11833
  return new Response("Not found", { status: 404 });
11355
11834
  }
@@ -11411,7 +11890,7 @@ app34.route("/sidebar-artefact-content", sidebar_artefact_content_default);
11411
11890
  var admin_default = app34;
11412
11891
 
11413
11892
  // server/routes/sites.ts
11414
- import { existsSync as existsSync20, readFileSync as readFileSync14, realpathSync as realpathSync5, statSync as statSync5 } from "fs";
11893
+ import { existsSync as existsSync21, readFileSync as readFileSync15, realpathSync as realpathSync5, statSync as statSync5 } from "fs";
11415
11894
  import { resolve as resolve20 } from "path";
11416
11895
  var SAFE_SEG_RE = /^[a-z0-9_][a-z0-9_.-]{0,99}$/i;
11417
11896
  var MIME = {
@@ -11478,7 +11957,7 @@ app35.get("/:rel{.*}", (c) => {
11478
11957
  }
11479
11958
  let stat7;
11480
11959
  try {
11481
- stat7 = existsSync20(filePath) ? statSync5(filePath) : null;
11960
+ stat7 = existsSync21(filePath) ? statSync5(filePath) : null;
11482
11961
  } catch {
11483
11962
  stat7 = null;
11484
11963
  }
@@ -11491,7 +11970,7 @@ app35.get("/:rel{.*}", (c) => {
11491
11970
  console.error(`[sites] path-traversal-rejected path=${reqPath} reason=escape status=403`);
11492
11971
  return c.text("Forbidden", 403);
11493
11972
  }
11494
- if (!existsSync20(filePath)) {
11973
+ if (!existsSync21(filePath)) {
11495
11974
  console.error(`[sites] not-found path=${reqPath} status=404`);
11496
11975
  return c.text("Not found", 404);
11497
11976
  }
@@ -11510,7 +11989,7 @@ app35.get("/:rel{.*}", (c) => {
11510
11989
  }
11511
11990
  let body;
11512
11991
  try {
11513
- body = readFileSync14(realPath);
11992
+ body = readFileSync15(realPath);
11514
11993
  } catch (err) {
11515
11994
  const code = err?.code;
11516
11995
  if (code === "EISDIR") {
@@ -11644,12 +12123,12 @@ function clientFrom(c) {
11644
12123
  var PLATFORM_ROOT7 = process.env.MAXY_PLATFORM_ROOT || "";
11645
12124
  var BRAND_JSON_PATH = PLATFORM_ROOT7 ? join9(PLATFORM_ROOT7, "config", "brand.json") : "";
11646
12125
  var BRAND = { productName: "Maxy", hostname: "maxy", configDir: ".maxy", domain: "getmaxy.com" };
11647
- if (BRAND_JSON_PATH && !existsSync21(BRAND_JSON_PATH)) {
12126
+ if (BRAND_JSON_PATH && !existsSync22(BRAND_JSON_PATH)) {
11648
12127
  console.error(`[brand] WARNING: brand.json not found at ${BRAND_JSON_PATH} \u2014 using Maxy defaults`);
11649
12128
  }
11650
- if (BRAND_JSON_PATH && existsSync21(BRAND_JSON_PATH)) {
12129
+ if (BRAND_JSON_PATH && existsSync22(BRAND_JSON_PATH)) {
11651
12130
  try {
11652
- const parsed = JSON.parse(readFileSync15(BRAND_JSON_PATH, "utf-8"));
12131
+ const parsed = JSON.parse(readFileSync16(BRAND_JSON_PATH, "utf-8"));
11653
12132
  BRAND = { ...BRAND, ...parsed };
11654
12133
  } catch (err) {
11655
12134
  console.error(`[brand] Failed to parse brand.json: ${err.message}`);
@@ -11671,8 +12150,8 @@ var brandLoginOpts = {
11671
12150
  var ALIAS_DOMAINS_PATH2 = join9(homedir2(), BRAND.configDir, "alias-domains.json");
11672
12151
  function loadAliasDomains() {
11673
12152
  try {
11674
- if (!existsSync21(ALIAS_DOMAINS_PATH2)) return null;
11675
- const parsed = JSON.parse(readFileSync15(ALIAS_DOMAINS_PATH2, "utf-8"));
12153
+ if (!existsSync22(ALIAS_DOMAINS_PATH2)) return null;
12154
+ const parsed = JSON.parse(readFileSync16(ALIAS_DOMAINS_PATH2, "utf-8"));
11676
12155
  if (!Array.isArray(parsed)) {
11677
12156
  console.error("[alias-domains] malformed alias-domains.json \u2014 expected array");
11678
12157
  return null;
@@ -12018,14 +12497,14 @@ app36.get("/agent-assets/:slug/:filename", (c) => {
12018
12497
  console.error(`[agent-assets] path-traversal-rejected slug=${slug} file=${filename}`);
12019
12498
  return c.text("Forbidden", 403);
12020
12499
  }
12021
- if (!existsSync21(filePath)) {
12500
+ if (!existsSync22(filePath)) {
12022
12501
  console.error(`[agent-assets] serve slug=${slug} file=${filename} status=404`);
12023
12502
  return c.text("Not found", 404);
12024
12503
  }
12025
12504
  const ext = "." + filename.split(".").pop()?.toLowerCase();
12026
12505
  const contentType = IMAGE_MIME[ext] || "application/octet-stream";
12027
12506
  console.log(`[agent-assets] serve slug=${slug} file=${filename} status=200`);
12028
- const body = readFileSync15(filePath);
12507
+ const body = readFileSync16(filePath);
12029
12508
  return c.body(body, 200, {
12030
12509
  "Content-Type": contentType,
12031
12510
  "Cache-Control": "public, max-age=3600"
@@ -12048,14 +12527,14 @@ app36.get("/generated/:filename", (c) => {
12048
12527
  console.error(`[generated] serve file=${filename} status=403`);
12049
12528
  return c.text("Forbidden", 403);
12050
12529
  }
12051
- if (!existsSync21(filePath)) {
12530
+ if (!existsSync22(filePath)) {
12052
12531
  console.error(`[generated] serve file=${filename} status=404`);
12053
12532
  return c.text("Not found", 404);
12054
12533
  }
12055
12534
  const ext = "." + filename.split(".").pop()?.toLowerCase();
12056
12535
  const contentType = IMAGE_MIME[ext] || "application/octet-stream";
12057
12536
  console.log(`[generated] serve file=${filename} status=200`);
12058
- const body = readFileSync15(filePath);
12537
+ const body = readFileSync16(filePath);
12059
12538
  return c.body(body, 200, {
12060
12539
  "Content-Type": contentType,
12061
12540
  "Cache-Control": "public, max-age=86400"
@@ -12065,9 +12544,9 @@ app36.route("/sites", sites_default);
12065
12544
  var htmlCache = /* @__PURE__ */ new Map();
12066
12545
  var brandLogoPath = "/brand/maxy-monochrome.png";
12067
12546
  var brandIconPath = "/brand/maxy-monochrome.png";
12068
- if (BRAND_JSON_PATH && existsSync21(BRAND_JSON_PATH)) {
12547
+ if (BRAND_JSON_PATH && existsSync22(BRAND_JSON_PATH)) {
12069
12548
  try {
12070
- const fullBrand = JSON.parse(readFileSync15(BRAND_JSON_PATH, "utf-8"));
12549
+ const fullBrand = JSON.parse(readFileSync16(BRAND_JSON_PATH, "utf-8"));
12071
12550
  if (fullBrand.assets?.logo) brandLogoPath = `/brand/${fullBrand.assets.logo}`;
12072
12551
  brandIconPath = fullBrand.assets?.icon ? `/brand/${fullBrand.assets.icon}` : brandLogoPath;
12073
12552
  } catch {
@@ -12085,8 +12564,8 @@ function readInstalledVersion() {
12085
12564
  try {
12086
12565
  if (!PLATFORM_ROOT7) return "unknown";
12087
12566
  const versionFile = join9(PLATFORM_ROOT7, "config", `.${BRAND.hostname}-version`);
12088
- if (!existsSync21(versionFile)) return "unknown";
12089
- const content = readFileSync15(versionFile, "utf-8").trim();
12567
+ if (!existsSync22(versionFile)) return "unknown";
12568
+ const content = readFileSync16(versionFile, "utf-8").trim();
12090
12569
  return content || "unknown";
12091
12570
  } catch {
12092
12571
  return "unknown";
@@ -12127,7 +12606,7 @@ var clientErrorReporterScript = `<script>
12127
12606
  function cachedHtml(file) {
12128
12607
  let html = htmlCache.get(file);
12129
12608
  if (!html) {
12130
- html = readFileSync15(resolve21(process.cwd(), "public", file), "utf-8");
12609
+ html = readFileSync16(resolve21(process.cwd(), "public", file), "utf-8");
12131
12610
  const productNameEsc = escapeHtml(BRAND.productName);
12132
12611
  html = html.replace(/<title>([^<]*)<\/title>/, (_match, inner) => `<title>${escapeHtml(inner).replace(/Maxy/g, productNameEsc)}</title>`);
12133
12612
  html = html.replace('href="/favicon.ico"', `href="${escapeHtml(brandFaviconPath)}"`);
@@ -12146,13 +12625,13 @@ function loadBrandingCache(agentSlug) {
12146
12625
  const configDir2 = join9(homedir2(), BRAND.configDir);
12147
12626
  try {
12148
12627
  const accountJsonPath = join9(configDir2, "account.json");
12149
- if (!existsSync21(accountJsonPath)) return null;
12150
- const account = JSON.parse(readFileSync15(accountJsonPath, "utf-8"));
12628
+ if (!existsSync22(accountJsonPath)) return null;
12629
+ const account = JSON.parse(readFileSync16(accountJsonPath, "utf-8"));
12151
12630
  const accountId = account.accountId;
12152
12631
  if (!accountId) return null;
12153
12632
  const cachePath = join9(configDir2, "branding-cache", accountId, `${agentSlug}.json`);
12154
- if (!existsSync21(cachePath)) return null;
12155
- return JSON.parse(readFileSync15(cachePath, "utf-8"));
12633
+ if (!existsSync22(cachePath)) return null;
12634
+ return JSON.parse(readFileSync16(cachePath, "utf-8"));
12156
12635
  } catch {
12157
12636
  return null;
12158
12637
  }
@@ -12161,8 +12640,8 @@ function resolveDefaultSlug() {
12161
12640
  try {
12162
12641
  const configDir2 = join9(homedir2(), BRAND.configDir);
12163
12642
  const accountJsonPath = join9(configDir2, "account.json");
12164
- if (!existsSync21(accountJsonPath)) return null;
12165
- const account = JSON.parse(readFileSync15(accountJsonPath, "utf-8"));
12643
+ if (!existsSync22(accountJsonPath)) return null;
12644
+ const account = JSON.parse(readFileSync16(accountJsonPath, "utf-8"));
12166
12645
  return account.defaultAgent || null;
12167
12646
  } catch {
12168
12647
  return null;
@@ -12235,7 +12714,7 @@ app36.use("/vnc-popout.html", logViewerFetch);
12235
12714
  app36.get("/vnc-popout.html", (c) => {
12236
12715
  let html = htmlCache.get("vnc-popout.html");
12237
12716
  if (!html) {
12238
- html = readFileSync15(resolve21(process.cwd(), "public", "vnc-popout.html"), "utf-8");
12717
+ html = readFileSync16(resolve21(process.cwd(), "public", "vnc-popout.html"), "utf-8");
12239
12718
  const name = escapeHtml(BRAND.productName);
12240
12719
  html = html.replace("<title>Browser \u2014 Maxy</title>", `<title>${name}</title>`);
12241
12720
  html = html.replace("</head>", ` ${brandScript}
@@ -12325,8 +12804,8 @@ try {
12325
12804
  (async () => {
12326
12805
  try {
12327
12806
  let userId = "";
12328
- if (existsSync21(USERS_FILE)) {
12329
- const users = JSON.parse(readFileSync15(USERS_FILE, "utf-8").trim() || "[]");
12807
+ if (existsSync22(USERS_FILE)) {
12808
+ const users = JSON.parse(readFileSync16(USERS_FILE, "utf-8").trim() || "[]");
12330
12809
  userId = users[0]?.userId ?? "";
12331
12810
  }
12332
12811
  await backfillNullUserIdConversations(userId);