@rubytech/create-maxy-code 0.1.144 → 0.1.147

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 (130) hide show
  1. package/package.json +1 -1
  2. package/payload/platform/neo4j/schema.cypher +154 -4
  3. package/payload/platform/plugins/admin/PLUGIN.md +1 -1
  4. package/payload/platform/plugins/admin/hooks/post-turn-graph-pass.sh +251 -0
  5. package/payload/platform/plugins/admin/skills/datetime/SKILL.md +63 -5
  6. package/payload/platform/plugins/docs/references/internals.md +16 -0
  7. package/payload/platform/plugins/docs/references/memory-guide.md +10 -0
  8. package/payload/platform/plugins/docs/references/platform.md +1 -1
  9. package/payload/platform/plugins/memory/.claude-plugin/plugin.json +1 -1
  10. package/payload/platform/plugins/memory/PLUGIN.md +25 -3
  11. package/payload/platform/plugins/memory/mcp/dist/index.js +309 -11
  12. package/payload/platform/plugins/memory/mcp/dist/index.js.map +1 -1
  13. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/compiled-truth-revision.test.d.ts +2 -0
  14. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/compiled-truth-revision.test.d.ts.map +1 -0
  15. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/compiled-truth-revision.test.js +33 -0
  16. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/compiled-truth-revision.test.js.map +1 -0
  17. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/graph-write-gate-label.test.d.ts +2 -0
  18. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/graph-write-gate-label.test.d.ts.map +1 -0
  19. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/graph-write-gate-label.test.js +30 -0
  20. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/graph-write-gate-label.test.js.map +1 -0
  21. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/phase-prune-revisions.test.d.ts +2 -0
  22. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/phase-prune-revisions.test.d.ts.map +1 -0
  23. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/phase-prune-revisions.test.js +51 -0
  24. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/phase-prune-revisions.test.js.map +1 -0
  25. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/relative-date.test.d.ts +2 -0
  26. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/relative-date.test.d.ts.map +1 -0
  27. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/relative-date.test.js +68 -0
  28. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/relative-date.test.js.map +1 -0
  29. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/timeline-extractor.test.js +41 -0
  30. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/timeline-extractor.test.js.map +1 -1
  31. package/payload/platform/plugins/memory/mcp/dist/lib/compiled-truth-revision.d.ts +43 -0
  32. package/payload/platform/plugins/memory/mcp/dist/lib/compiled-truth-revision.d.ts.map +1 -0
  33. package/payload/platform/plugins/memory/mcp/dist/lib/compiled-truth-revision.js +33 -0
  34. package/payload/platform/plugins/memory/mcp/dist/lib/compiled-truth-revision.js.map +1 -0
  35. package/payload/platform/plugins/memory/mcp/dist/lib/compiled-truth-rewriter.d.ts +18 -5
  36. package/payload/platform/plugins/memory/mcp/dist/lib/compiled-truth-rewriter.d.ts.map +1 -1
  37. package/payload/platform/plugins/memory/mcp/dist/lib/compiled-truth-rewriter.js +64 -17
  38. package/payload/platform/plugins/memory/mcp/dist/lib/compiled-truth-rewriter.js.map +1 -1
  39. package/payload/platform/plugins/memory/mcp/dist/lib/dream-cycle/index.d.ts +44 -0
  40. package/payload/platform/plugins/memory/mcp/dist/lib/dream-cycle/index.d.ts.map +1 -0
  41. package/payload/platform/plugins/memory/mcp/dist/lib/dream-cycle/index.js +14 -0
  42. package/payload/platform/plugins/memory/mcp/dist/lib/dream-cycle/index.js.map +1 -0
  43. package/payload/platform/plugins/memory/mcp/dist/lib/dream-cycle/phase-citation-audit.d.ts +26 -0
  44. package/payload/platform/plugins/memory/mcp/dist/lib/dream-cycle/phase-citation-audit.d.ts.map +1 -0
  45. package/payload/platform/plugins/memory/mcp/dist/lib/dream-cycle/phase-citation-audit.js +219 -0
  46. package/payload/platform/plugins/memory/mcp/dist/lib/dream-cycle/phase-citation-audit.js.map +1 -0
  47. package/payload/platform/plugins/memory/mcp/dist/lib/dream-cycle/phase-dead-edges.d.ts +19 -0
  48. package/payload/platform/plugins/memory/mcp/dist/lib/dream-cycle/phase-dead-edges.d.ts.map +1 -0
  49. package/payload/platform/plugins/memory/mcp/dist/lib/dream-cycle/phase-dead-edges.js +39 -0
  50. package/payload/platform/plugins/memory/mcp/dist/lib/dream-cycle/phase-dead-edges.js.map +1 -0
  51. package/payload/platform/plugins/memory/mcp/dist/lib/dream-cycle/phase-orphans.d.ts +19 -0
  52. package/payload/platform/plugins/memory/mcp/dist/lib/dream-cycle/phase-orphans.d.ts.map +1 -0
  53. package/payload/platform/plugins/memory/mcp/dist/lib/dream-cycle/phase-orphans.js +42 -0
  54. package/payload/platform/plugins/memory/mcp/dist/lib/dream-cycle/phase-orphans.js.map +1 -0
  55. package/payload/platform/plugins/memory/mcp/dist/lib/dream-cycle/phase-prune-revisions.d.ts +21 -0
  56. package/payload/platform/plugins/memory/mcp/dist/lib/dream-cycle/phase-prune-revisions.d.ts.map +1 -0
  57. package/payload/platform/plugins/memory/mcp/dist/lib/dream-cycle/phase-prune-revisions.js +27 -0
  58. package/payload/platform/plugins/memory/mcp/dist/lib/dream-cycle/phase-prune-revisions.js.map +1 -0
  59. package/payload/platform/plugins/memory/mcp/dist/lib/dream-cycle/phase-stale-truth.d.ts +18 -0
  60. package/payload/platform/plugins/memory/mcp/dist/lib/dream-cycle/phase-stale-truth.d.ts.map +1 -0
  61. package/payload/platform/plugins/memory/mcp/dist/lib/dream-cycle/phase-stale-truth.js +60 -0
  62. package/payload/platform/plugins/memory/mcp/dist/lib/dream-cycle/phase-stale-truth.js.map +1 -0
  63. package/payload/platform/plugins/memory/mcp/dist/lib/graph-write-gate.d.ts +20 -3
  64. package/payload/platform/plugins/memory/mcp/dist/lib/graph-write-gate.d.ts.map +1 -1
  65. package/payload/platform/plugins/memory/mcp/dist/lib/graph-write-gate.js +47 -12
  66. package/payload/platform/plugins/memory/mcp/dist/lib/graph-write-gate.js.map +1 -1
  67. package/payload/platform/plugins/memory/mcp/dist/lib/relative-date.d.ts +13 -0
  68. package/payload/platform/plugins/memory/mcp/dist/lib/relative-date.d.ts.map +1 -0
  69. package/payload/platform/plugins/memory/mcp/dist/lib/relative-date.js +191 -0
  70. package/payload/platform/plugins/memory/mcp/dist/lib/relative-date.js.map +1 -0
  71. package/payload/platform/plugins/memory/mcp/dist/lib/timeline-extractor.d.ts +7 -1
  72. package/payload/platform/plugins/memory/mcp/dist/lib/timeline-extractor.d.ts.map +1 -1
  73. package/payload/platform/plugins/memory/mcp/dist/lib/timeline-extractor.js +37 -9
  74. package/payload/platform/plugins/memory/mcp/dist/lib/timeline-extractor.js.map +1 -1
  75. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-compiled-truth-history.test.d.ts +2 -0
  76. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-compiled-truth-history.test.d.ts.map +1 -0
  77. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-compiled-truth-history.test.js +81 -0
  78. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-compiled-truth-history.test.js.map +1 -0
  79. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-report-tools.test.d.ts +2 -0
  80. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-report-tools.test.d.ts.map +1 -0
  81. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-report-tools.test.js +115 -0
  82. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-report-tools.test.js.map +1 -0
  83. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-update-emit.test.js +1 -0
  84. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-update-emit.test.js.map +1 -1
  85. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-write-emit.test.js +1 -0
  86. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-write-emit.test.js.map +1 -1
  87. package/payload/platform/plugins/memory/mcp/dist/tools/memory-compiled-truth-history.d.ts +19 -0
  88. package/payload/platform/plugins/memory/mcp/dist/tools/memory-compiled-truth-history.d.ts.map +1 -0
  89. package/payload/platform/plugins/memory/mcp/dist/tools/memory-compiled-truth-history.js +50 -0
  90. package/payload/platform/plugins/memory/mcp/dist/tools/memory-compiled-truth-history.js.map +1 -0
  91. package/payload/platform/plugins/memory/mcp/dist/tools/memory-dream-run.d.ts +45 -0
  92. package/payload/platform/plugins/memory/mcp/dist/tools/memory-dream-run.d.ts.map +1 -0
  93. package/payload/platform/plugins/memory/mcp/dist/tools/memory-dream-run.js +170 -0
  94. package/payload/platform/plugins/memory/mcp/dist/tools/memory-dream-run.js.map +1 -0
  95. package/payload/platform/plugins/memory/mcp/dist/tools/memory-report-list.d.ts +28 -0
  96. package/payload/platform/plugins/memory/mcp/dist/tools/memory-report-list.d.ts.map +1 -0
  97. package/payload/platform/plugins/memory/mcp/dist/tools/memory-report-list.js +64 -0
  98. package/payload/platform/plugins/memory/mcp/dist/tools/memory-report-list.js.map +1 -0
  99. package/payload/platform/plugins/memory/mcp/dist/tools/memory-report-read-latest.d.ts +24 -0
  100. package/payload/platform/plugins/memory/mcp/dist/tools/memory-report-read-latest.d.ts.map +1 -0
  101. package/payload/platform/plugins/memory/mcp/dist/tools/memory-report-read-latest.js +49 -0
  102. package/payload/platform/plugins/memory/mcp/dist/tools/memory-report-read-latest.js.map +1 -0
  103. package/payload/platform/plugins/memory/mcp/dist/tools/memory-report-write.d.ts +34 -0
  104. package/payload/platform/plugins/memory/mcp/dist/tools/memory-report-write.d.ts.map +1 -0
  105. package/payload/platform/plugins/memory/mcp/dist/tools/memory-report-write.js +99 -0
  106. package/payload/platform/plugins/memory/mcp/dist/tools/memory-report-write.js.map +1 -0
  107. package/payload/platform/plugins/memory/mcp/dist/tools/memory-review-queue.d.ts +29 -0
  108. package/payload/platform/plugins/memory/mcp/dist/tools/memory-review-queue.d.ts.map +1 -0
  109. package/payload/platform/plugins/memory/mcp/dist/tools/memory-review-queue.js +66 -0
  110. package/payload/platform/plugins/memory/mcp/dist/tools/memory-review-queue.js.map +1 -0
  111. package/payload/platform/plugins/memory/mcp/dist/tools/memory-search.d.ts.map +1 -1
  112. package/payload/platform/plugins/memory/mcp/dist/tools/memory-search.js +122 -2
  113. package/payload/platform/plugins/memory/mcp/dist/tools/memory-search.js.map +1 -1
  114. package/payload/platform/plugins/memory/mcp/dist/tools/memory-update.d.ts +49 -13
  115. package/payload/platform/plugins/memory/mcp/dist/tools/memory-update.d.ts.map +1 -1
  116. package/payload/platform/plugins/memory/mcp/dist/tools/memory-update.js +184 -16
  117. package/payload/platform/plugins/memory/mcp/dist/tools/memory-update.js.map +1 -1
  118. package/payload/platform/plugins/memory/mcp/dist/tools/memory-write.d.ts.map +1 -1
  119. package/payload/platform/plugins/memory/mcp/dist/tools/memory-write.js +53 -10
  120. package/payload/platform/plugins/memory/mcp/dist/tools/memory-write.js.map +1 -1
  121. package/payload/platform/plugins/memory/mcp/vitest.config.ts +6 -0
  122. package/payload/platform/plugins/memory/references/schema-base.md +4 -0
  123. package/payload/platform/plugins/memory/skills/conversation-archive/SKILL.md +3 -4
  124. package/payload/platform/plugins/scheduling/skills/briefing/SKILL.md +13 -2
  125. package/payload/platform/scripts/seed-neo4j.sh +1 -1
  126. package/payload/platform/templates/agents/admin/IDENTITY.md +9 -1
  127. package/payload/platform/templates/specialists/agents/database-operator.md +30 -2
  128. package/payload/server/server.js +195 -91
  129. package/payload/platform/plugins/admin/hooks/signal-detector-stop.sh +0 -309
  130. package/payload/platform/templates/specialists/agents/signal-detector.md +0 -129
@@ -36,6 +36,14 @@ When the conversation produces something worth writing to memory (a new person,
36
36
 
37
37
  Call `memory-write` or `memory-update` directly only when the write is a one-line update against a node whose `elementId` is already in your context (e.g. setting a single property on an existing Person you just found by id) AND the schema choice is unambiguous. Delegate in every other case: new nodes, batched writes, multi-row archive ingest, schema-classification work, anything whose label or edge type requires consulting `schema-base.md` or a vertical schema.
38
38
 
39
+ ## Recalling reports
40
+
41
+ Workflow output that the operator may want back later (daily briefing, dream cycle, ad-hoc analyses) lives as `:Report` nodes — keyword-routed, append-only, embedded for hybrid search. When the operator says "latest <X>", "last night's <X>", "show me <X> report", "what was this morning's briefing", or any other phrasing that names a known report kind, the first tool call is `memory-report-read-latest` with the matching keyword (`daily-briefing`, `dream-cycle`, etc.). Use `memory-report-list` to browse the catalogue (metadata only) when the operator wants a date range or to compare multiple. Reach for `memory-search` instead only when the question is about the contents of a report (e.g. "which briefing mentioned the Cohen offer"), not about the report itself.
42
+
43
+ ## Compiled-truth revision history
44
+
45
+ Every `compiledTruth` on a :Person, :Organization, or :Concept is captured as a `:CompiledTruthRevision` row each time the rewriter writes it. When the operator asks "how has my understanding of X changed over time?", "when did you start saying X about Y?", or "show me the history of what we know about Z", first resolve the entity's `elementId` (via `memory-search`), then call `memory-compiled-truth-history` with that id. Render the rows as a chronological list and surface the delta between adjacent revisions in your own reply — there is no server-side diff.
46
+
39
47
  ## Session-end retrospective
40
48
 
41
49
  When the operator signals end-of-session (`/end`, `/archive`, `end session`, or `archive this session`), the Stop hook blocks this session from closing until you have done three things and called one tool. The hook's instruction block names the three passes verbatim every time it fires; this section is the doctrine behind it.
@@ -63,7 +71,7 @@ When you receive a turn beginning with `[system: <name>-stop-hook]`:
63
71
  2. Execute that single `Task` dispatch. Do not paraphrase the prompt, do not respond conversationally, do not ask the operator for clarification, do not surface the dispatch in chat.
64
72
  3. When the subagent returns its one-line summary, emit a single space character and stop. The Stop hook's next fire will inspect the transcript, see the dispatch you just performed, and allow the stop.
65
73
 
66
- These directives are never operator-driven. The `signal-detector` specialist in particular (gbrain port, Task 303) is dispatched only by `signal-detector-stop.sh` and never by operator intent.
74
+ These directives are never operator-driven. The `database-operator` specialist in particular, when dispatched via `post-turn-graph-pass.sh` (Task 412), runs as a background graph pass that the operator does not see; the dispatch prompt carries the conversation and prior-writes blocks and you must forward both verbatim.
67
75
 
68
76
  ## SOUL.md
69
77
 
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: database-operator
3
- description: "Graph-write executor reachable from admin via the Task tool. Admin names what should land in the graph; database-operator reads the schema, decides operations, executes them against the memory graph, and reports `{label, elementId}` back. (Reachable historically also from the now-dormant Stop hook in `platform/plugins/admin/hooks/turn-completed-graph-write.sh`; that path is preserved as infrastructure but no longer registered, see Task 214.)"
4
- summary: "Executes graph writes on admin's behalf when delegated via the Task tool."
3
+ description: "Graph-write executor reachable from admin via the Task tool. Admin names what should land in the graph; database-operator reads the schema, decides operations, executes them against the memory graph, and reports `{label, elementId}` back. Two invocation modes: (1) **discretionary inline** admin dispatches synchronously when a write must complete before the assistant response ends; (2) **background post-turn pass** fired once per admin-agent end_turn by `platform/plugins/admin/hooks/post-turn-graph-pass.sh` with the full conversation and the list of nodes already written under this conversationId, so any new graph rows the conversation supports get derived and written without the admin agent having to remember every turn (Task 412)."
4
+ summary: "Executes graph writes on admin's behalf when delegated via the Task tool — both inline at admin discretion and as a once-per-turn background pass."
5
5
  model: claude-sonnet-4-6
6
6
  tools: Read, mcp__plugin_memory_memory__memory-write, mcp__plugin_memory_memory__memory-update, mcp__plugin_memory_memory__memory-search, mcp__plugin_memory_memory__memory-archive-write, mcp__plugin_memory_memory__memory-typed-edge-pass, mcp__plugin_memory_memory__session-retrospective-skip-rate, mcp__plugin_memory_memory__profile-update, mcp__plugin_memory_memory__profile-read, mcp__plugin_memory_memory__obsidian-vault-import, mcp__plugin_scheduling_scheduling__schedule-archive-ics, mcp__plugin_contacts_contacts__contact-create, mcp__plugin_contacts_contacts__contact-update, mcp__plugin_work_work__work-create, mcp__plugin_work_work__work-update, mcp__plugin_work_work__project-create, mcp__plugin_work_work__project-update
7
7
  ---
@@ -20,6 +20,34 @@ The `accountId` property is supplied by the writers from server-side environment
20
20
 
21
21
  Decide the precise operations against the schema, execute them with the writers in your tool surface, and report each write back to admin as `{label, elementId}` so admin can confirm the outcome to the operator. If admin's brief is ambiguous about which label, which edge type, or which existing node to attach to, name the ambiguity in your reply rather than guessing.
22
22
 
23
+ ## Background post-turn pass
24
+
25
+ When the dispatch prompt contains a `<conversation>` block and a `<prior-writes>` block, you are running as the post-turn background pass (Task 412). The hook (`platform/plugins/admin/hooks/post-turn-graph-pass.sh`) fires once per admin-agent `end_turn` and supplies:
26
+
27
+ - `accountId`, `sessionId`, `conversationId` — the scope.
28
+ - `<conversation>` — every assistant text turn and every non-`tool_result` user turn for this session, oldest first, formatted as `[role: text]` pairs.
29
+ - `<prior-writes>` — every node already written under this `conversationId` for this account, one per line as `(elementId) :Labels {properties-json}`, oldest first.
30
+
31
+ Your job: read the conversation, decide what new graph rows it supports (mentions of named entities, ideas and learnings the operator stated, contacts named for the first time, tasks the operator committed to, decisions, anything the schema admits), and write them. **Skip writes the `<prior-writes>` list already covers** — a `:MENTIONS` edge from a `:Message` to a `:Person` is already there, do not re-emit it; a `:Person {name: "Adam Langley"}` is already there, attach further edges to its `elementId` instead of creating a duplicate. The hygiene sweeps (Tasks 410, 411) clean up duplicates that slip through MERGE semantics; do not invent dedup logic here beyond the prior-writes skip.
32
+
33
+ The same prerogatives apply: precise label and edge names, evidence-based lookups (`memory-search` before creating any stub for a name that could already exist on another conversation), no synonyms, no invented edge types.
34
+
35
+ Return exactly one line on completion:
36
+
37
+ ```
38
+ db-op: writes=<n> ms=<n>
39
+ ```
40
+
41
+ Where `<n>` is the count of `memory-write` / `memory-update` calls that succeeded. On error (a `memory-write` rejection, a missing tool), surface the reason and stop:
42
+
43
+ ```
44
+ db-op: error reason=<kebab-case-reason>
45
+ ```
46
+
47
+ No prose summary, no listing of names. The operator does not see this turn.
48
+
49
+ When the dispatch prompt has no `<conversation>` block, you are in discretionary inline mode — behaviour is unchanged from the rest of this document.
50
+
23
51
  ## Typed-edge auto-extraction pass (session-end)
24
52
 
25
53
  When admin's brief names the typed-edge pass (Task 305) and supplies a `sinceIso` timestamp, call `memory-typed-edge-pass` with that timestamp exactly once. The tool reads prose-bearing nodes (Message/Page/Meeting/KnowledgeDocument/Idea/Note/Post/Report — `:KnowledgeDocument` covers email threads via `source:'email'` since Task 321) the account wrote since `sinceIso`, asks Haiku for typed-edge proposals against a closed allowlist, validates each one, and MERGEs accepted edges with `createdBy` provenance. Return the full counter object verbatim — admin needs `nodesProcessed` and `accepted` for the `session-retrospective-mark-complete` call. Do not reinterpret the counts or summarise them.
@@ -9310,18 +9310,18 @@ var ALLOWED_EVENTS = /* @__PURE__ */ new Set([
9310
9310
  ]);
9311
9311
  var app17 = new Hono();
9312
9312
  app17.post("/", async (c) => {
9313
- const TAG22 = "[admin:events]";
9313
+ const TAG23 = "[admin:events]";
9314
9314
  let body;
9315
9315
  try {
9316
9316
  body = await c.req.json();
9317
9317
  } catch (err) {
9318
9318
  const detail = err instanceof Error ? err.message : String(err);
9319
- console.error(`${TAG22} reject reason=body-not-json detail=${detail}`);
9319
+ console.error(`${TAG23} reject reason=body-not-json detail=${detail}`);
9320
9320
  return c.json({ ok: false, detail: "Request body was not valid JSON" }, 400);
9321
9321
  }
9322
9322
  const event = typeof body.event === "string" ? body.event : "";
9323
9323
  if (!ALLOWED_EVENTS.has(event)) {
9324
- console.error(`${TAG22} reject reason=event-not-allowed event=${JSON.stringify(event)}`);
9324
+ console.error(`${TAG23} reject reason=event-not-allowed event=${JSON.stringify(event)}`);
9325
9325
  return c.json({ ok: false, detail: `Event "${event}" is not allowed` }, 400);
9326
9326
  }
9327
9327
  const rawFields = body.fields && typeof body.fields === "object" ? body.fields : {};
@@ -12932,36 +12932,140 @@ app32.post("/", requireAdminSession, async (c) => {
12932
12932
  });
12933
12933
  var linkedin_ingest_default = app32;
12934
12934
 
12935
- // server/routes/admin/index.ts
12935
+ // server/routes/admin/post-turn-context.ts
12936
+ import neo4j3 from "neo4j-driver";
12937
+ var TAG21 = "[post-turn-context]";
12938
+ var STRIPPED_PROPERTIES2 = /* @__PURE__ */ new Set([
12939
+ "embedding",
12940
+ "passwordHash",
12941
+ "magicToken",
12942
+ "otpCode",
12943
+ "cacheKey"
12944
+ ]);
12945
+ function isLoopbackAddr2(addr) {
12946
+ return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
12947
+ }
12948
+ function convertValue(value) {
12949
+ if (neo4j3.isDateTime(value) || neo4j3.isDate(value) || neo4j3.isLocalDateTime(value) || neo4j3.isLocalTime(value) || neo4j3.isTime(value) || neo4j3.isDuration(value)) {
12950
+ return value.toString();
12951
+ }
12952
+ if (neo4j3.isInt(value)) {
12953
+ return value.inSafeRange() ? value.toNumber() : value.toString();
12954
+ }
12955
+ if (Array.isArray(value)) {
12956
+ return value.map((v) => convertValue(v));
12957
+ }
12958
+ if (value !== null && typeof value === "object" && value.constructor === Object) {
12959
+ const out = {};
12960
+ for (const [k, v] of Object.entries(value)) {
12961
+ out[k] = convertValue(v);
12962
+ }
12963
+ return out;
12964
+ }
12965
+ return value;
12966
+ }
12967
+ function pruneProperties(raw) {
12968
+ const out = {};
12969
+ for (const [k, v] of Object.entries(raw)) {
12970
+ if (STRIPPED_PROPERTIES2.has(k)) continue;
12971
+ out[k] = convertValue(v);
12972
+ }
12973
+ return out;
12974
+ }
12936
12975
  var app33 = new Hono();
12937
- app33.route("/session", session_default);
12938
- app33.route("/new-session-failure", new_session_failure_default);
12939
- app33.route("/new-session-submit", new_session_submit_default);
12940
- app33.route("/logs", logs_default);
12941
- app33.route("/claude-info", claude_info_default);
12942
- app33.route("/claude-capabilities", claude_capabilities_default);
12943
- app33.route("/attachment", attachment_default);
12944
- app33.route("/agents", agents_default);
12945
- app33.route("/sessions", sessions_default);
12946
- app33.route("/claude-sessions", claude_sessions_default);
12947
- app33.route("/log-ingest", log_ingest_default);
12948
- app33.route("/events", events_default);
12949
- app33.route("/files", files_default);
12950
- app33.route("/graph-search", graph_search_default);
12951
- app33.route("/graph-subgraph", graph_subgraph_default);
12952
- app33.route("/graph-delete", graph_delete_default);
12953
- app33.route("/graph-restore", graph_restore_default);
12954
- app33.route("/graph-labels-in-graph", graph_labels_in_graph_default);
12955
- app33.route("/graph-default-view", graph_default_view_default);
12956
- app33.route("/session-defaults", session_defaults_default);
12957
- app33.route("/file-attach", file_attach_default);
12958
- app33.route("/sidebar-artefacts", sidebar_artefacts_default);
12959
- app33.route("/sidebar-artefact-save", sidebar_artefact_save_default);
12960
- app33.route("/sidebar-artefact-content", sidebar_artefact_content_default);
12961
- app33.route("/system-stats", system_stats_default);
12962
- app33.route("/health-brand", health_default2);
12963
- app33.route("/linkedin-ingest", linkedin_ingest_default);
12964
- var admin_default = app33;
12976
+ app33.get("/", async (c) => {
12977
+ const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
12978
+ if (!isLoopbackAddr2(remoteAddr)) {
12979
+ console.error(`${TAG21} reject reason=non-loopback remoteAddr=${remoteAddr}`);
12980
+ return c.json({ error: "post-turn-context-loopback-only" }, 403);
12981
+ }
12982
+ const xffHeader = c.env?.incoming?.headers?.["x-forwarded-for"];
12983
+ const xffRaw = Array.isArray(xffHeader) ? xffHeader.join(",") : typeof xffHeader === "string" ? xffHeader : "";
12984
+ if (xffRaw.length > 0) {
12985
+ const tokens = xffRaw.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
12986
+ const offender = tokens.find((t) => !isLoopbackAddr2(t));
12987
+ if (offender !== void 0) {
12988
+ console.error(`${TAG21} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
12989
+ return c.json({ error: "post-turn-context-loopback-only" }, 403);
12990
+ }
12991
+ }
12992
+ const conversationId = (c.req.query("conversationId") ?? "").trim();
12993
+ const accountId = (c.req.query("accountId") ?? "").trim();
12994
+ if (!conversationId) return c.json({ error: "conversationId required" }, 400);
12995
+ if (!accountId) return c.json({ error: "accountId required" }, 400);
12996
+ const session = getSession();
12997
+ const started = Date.now();
12998
+ try {
12999
+ const cypher = `
13000
+ MATCH (c:Conversation {conversationId: $conversationId, accountId: $accountId})
13001
+ MATCH (c)<-[:PRODUCED]-(n)
13002
+ WHERE coalesce(n.accountId, $accountId) = $accountId
13003
+ RETURN elementId(n) AS elementId, labels(n) AS labels, properties(n) AS properties, coalesce(n.createdAt, n.observedAt, '') AS sortKey
13004
+ UNION
13005
+ MATCH (n) WHERE n.conversationId = $conversationId AND n.accountId = $accountId
13006
+ RETURN elementId(n) AS elementId, labels(n) AS labels, properties(n) AS properties, coalesce(n.createdAt, n.observedAt, '') AS sortKey
13007
+ `;
13008
+ const res = await session.executeRead(
13009
+ (tx) => tx.run(cypher, { conversationId, accountId })
13010
+ );
13011
+ const writes = res.records.map((r) => ({
13012
+ elementId: r.get("elementId"),
13013
+ labels: r.get("labels"),
13014
+ properties: pruneProperties(r.get("properties")),
13015
+ sortKey: String(r.get("sortKey") ?? "")
13016
+ }));
13017
+ writes.sort((a, b) => a.sortKey.localeCompare(b.sortKey));
13018
+ const total = Date.now() - started;
13019
+ console.log(
13020
+ `${TAG21} conversationId=${conversationId} accountId=${accountId} writes=${writes.length} ms=${total}`
13021
+ );
13022
+ return c.json({
13023
+ writes: writes.map(({ elementId, labels, properties }) => ({ elementId, labels, properties }))
13024
+ });
13025
+ } catch (err) {
13026
+ const elapsed = Date.now() - started;
13027
+ const message = err instanceof Error ? err.message : String(err);
13028
+ console.error(
13029
+ `${TAG21} neo4j-unreachable conversationId=${conversationId} ms=${elapsed} err="${message}"`
13030
+ );
13031
+ return c.json({ error: `post-turn-context unavailable: ${message}` }, 503);
13032
+ } finally {
13033
+ await session.close();
13034
+ }
13035
+ });
13036
+ var post_turn_context_default = app33;
13037
+
13038
+ // server/routes/admin/index.ts
13039
+ var app34 = new Hono();
13040
+ app34.route("/session", session_default);
13041
+ app34.route("/new-session-failure", new_session_failure_default);
13042
+ app34.route("/new-session-submit", new_session_submit_default);
13043
+ app34.route("/logs", logs_default);
13044
+ app34.route("/claude-info", claude_info_default);
13045
+ app34.route("/claude-capabilities", claude_capabilities_default);
13046
+ app34.route("/attachment", attachment_default);
13047
+ app34.route("/agents", agents_default);
13048
+ app34.route("/sessions", sessions_default);
13049
+ app34.route("/claude-sessions", claude_sessions_default);
13050
+ app34.route("/log-ingest", log_ingest_default);
13051
+ app34.route("/events", events_default);
13052
+ app34.route("/files", files_default);
13053
+ app34.route("/graph-search", graph_search_default);
13054
+ app34.route("/graph-subgraph", graph_subgraph_default);
13055
+ app34.route("/graph-delete", graph_delete_default);
13056
+ app34.route("/graph-restore", graph_restore_default);
13057
+ app34.route("/graph-labels-in-graph", graph_labels_in_graph_default);
13058
+ app34.route("/graph-default-view", graph_default_view_default);
13059
+ app34.route("/session-defaults", session_defaults_default);
13060
+ app34.route("/file-attach", file_attach_default);
13061
+ app34.route("/sidebar-artefacts", sidebar_artefacts_default);
13062
+ app34.route("/sidebar-artefact-save", sidebar_artefact_save_default);
13063
+ app34.route("/sidebar-artefact-content", sidebar_artefact_content_default);
13064
+ app34.route("/system-stats", system_stats_default);
13065
+ app34.route("/health-brand", health_default2);
13066
+ app34.route("/linkedin-ingest", linkedin_ingest_default);
13067
+ app34.route("/post-turn-context", post_turn_context_default);
13068
+ var admin_default = app34;
12965
13069
 
12966
13070
  // server/routes/sites.ts
12967
13071
  import { existsSync as existsSync21, readFileSync as readFileSync17, realpathSync as realpathSync5, statSync as statSync7 } from "fs";
@@ -12996,8 +13100,8 @@ function getExt(p) {
12996
13100
  if (idx < p.lastIndexOf("/")) return "";
12997
13101
  return p.slice(idx).toLowerCase();
12998
13102
  }
12999
- var app34 = new Hono();
13000
- app34.get("/:rel{.*}", (c) => {
13103
+ var app35 = new Hono();
13104
+ app35.get("/:rel{.*}", (c) => {
13001
13105
  const reqPath = c.req.path;
13002
13106
  const rawRel = c.req.param("rel") ?? "";
13003
13107
  const trimmed = rawRel.replace(/^\/+/, "").replace(/\/+$/, "");
@@ -13100,7 +13204,7 @@ app34.get("/:rel{.*}", (c) => {
13100
13204
  "X-Content-Type-Options": "nosniff"
13101
13205
  });
13102
13206
  });
13103
- var sites_default = app34;
13207
+ var sites_default = app35;
13104
13208
 
13105
13209
  // app/lib/visitor-token.ts
13106
13210
  import { createHmac, randomBytes, timingSafeEqual } from "crypto";
@@ -13200,7 +13304,7 @@ function readBrandConfig() {
13200
13304
  }
13201
13305
 
13202
13306
  // server/routes/visitor-consent.ts
13203
- var app35 = new Hono();
13307
+ var app36 = new Hono();
13204
13308
  var CONSENT_COOKIE_NAME = "mxy_consent";
13205
13309
  var CONSENT_COOKIE_MAX_AGE_SECONDS = 60 * 60 * 24 * 365;
13206
13310
  var DEFAULT_CONSENT_COPY = {
@@ -13245,17 +13349,17 @@ function siteSlugFromReferer(referer) {
13245
13349
  return "";
13246
13350
  }
13247
13351
  }
13248
- app35.options("/consent", (c) => {
13352
+ app36.options("/consent", (c) => {
13249
13353
  const origin = getOrigin(c);
13250
13354
  setCorsHeaders(c, origin);
13251
13355
  return c.body(null, 204);
13252
13356
  });
13253
- app35.options("/brand-config", (c) => {
13357
+ app36.options("/brand-config", (c) => {
13254
13358
  const origin = getOrigin(c);
13255
13359
  setCorsHeaders(c, origin);
13256
13360
  return c.body(null, 204);
13257
13361
  });
13258
- app35.post("/consent", async (c) => {
13362
+ app36.post("/consent", async (c) => {
13259
13363
  const origin = getOrigin(c);
13260
13364
  setCorsHeaders(c, origin);
13261
13365
  let raw;
@@ -13295,7 +13399,7 @@ app35.post("/consent", async (c) => {
13295
13399
  console.log(`[consent] ${parsed.decision} site=${site} brand=${brandName} tokenBound=${tokenBound}`);
13296
13400
  return c.body(null, 204);
13297
13401
  });
13298
- app35.get("/brand-config", (c) => {
13402
+ app36.get("/brand-config", (c) => {
13299
13403
  const origin = getOrigin(c);
13300
13404
  setCorsHeaders(c, origin);
13301
13405
  const brand = readBrandConfig();
@@ -13305,7 +13409,7 @@ app35.get("/brand-config", (c) => {
13305
13409
  c.header("Cache-Control", "public, max-age=300");
13306
13410
  return c.json({ consent: { copy, palette } });
13307
13411
  });
13308
- var visitor_consent_default = app35;
13412
+ var visitor_consent_default = app36;
13309
13413
 
13310
13414
  // server/routes/listings.ts
13311
13415
  function getCookie(headerValue, name) {
@@ -13332,8 +13436,8 @@ function appendConsentParams(pageUrl, token) {
13332
13436
  }
13333
13437
  var SAFE_SLUG_RE = /^[a-z0-9](?:[a-z0-9-]{0,118}[a-z0-9])?$/;
13334
13438
  var CHAT_SESSION_KEY_RE = /^[A-Za-z0-9][A-Za-z0-9_-]{7,127}$/;
13335
- var app36 = new Hono();
13336
- app36.get("/:slug/click", async (c) => {
13439
+ var app37 = new Hono();
13440
+ app37.get("/:slug/click", async (c) => {
13337
13441
  const slug = c.req.param("slug") ?? "";
13338
13442
  const rawSession = c.req.query("session") ?? "";
13339
13443
  const sessionKey = CHAT_SESSION_KEY_RE.test(rawSession) ? rawSession : "invalid";
@@ -13397,10 +13501,10 @@ app36.get("/:slug/click", async (c) => {
13397
13501
  console.log(`[property-card-click] sessionKey=${sessionKey} listingSlug=${slug} consent=${consentCookie ?? "absent"} ts=${(/* @__PURE__ */ new Date()).toISOString()}`);
13398
13502
  return c.redirect(redirectUrl, 302);
13399
13503
  });
13400
- var listings_default = app36;
13504
+ var listings_default = app37;
13401
13505
 
13402
13506
  // server/routes/visitor-event.ts
13403
- var app37 = new Hono();
13507
+ var app38 = new Hono();
13404
13508
  var BOT_UA_RE = /\b(bot|crawl|spider|slurp|headlesschrome|phantomjs|googlebot|bingbot|yandex|baiduspider|ahrefsbot|semrushbot|mj12bot|dotbot|petalbot)\b/i;
13405
13509
  var buckets = /* @__PURE__ */ new Map();
13406
13510
  var RATE_LIMIT = 60;
@@ -13467,12 +13571,12 @@ function originAllowed(origin, allowlist) {
13467
13571
  return false;
13468
13572
  }
13469
13573
  }
13470
- app37.options("/event", (c) => {
13574
+ app38.options("/event", (c) => {
13471
13575
  const origin = getOrigin2(c);
13472
13576
  setCorsHeaders2(c, origin);
13473
13577
  return c.body(null, 204);
13474
13578
  });
13475
- app37.post("/event", async (c) => {
13579
+ app38.post("/event", async (c) => {
13476
13580
  const origin = getOrigin2(c);
13477
13581
  setCorsHeaders2(c, origin);
13478
13582
  const ua = c.req.header("user-agent") ?? "";
@@ -13677,7 +13781,7 @@ async function writeEvent(opts) {
13677
13781
  );
13678
13782
  }
13679
13783
  }
13680
- var visitor_event_default = app37;
13784
+ var visitor_event_default = app38;
13681
13785
 
13682
13786
  // app/lib/graph-health.ts
13683
13787
  var HOUR_MS = 60 * 60 * 1e3;
@@ -13761,7 +13865,7 @@ function startGraphHealthTimer() {
13761
13865
  }
13762
13866
 
13763
13867
  // app/lib/whatsapp/inbound/claude-bridge.ts
13764
- var TAG21 = "[whatsapp-adaptor]";
13868
+ var TAG22 = "[whatsapp-adaptor]";
13765
13869
  function whatsappTurnTimeoutMs() {
13766
13870
  return Number(process.env.WHATSAPP_PTY_TURN_TIMEOUT_MS ?? String(5 * 6e4));
13767
13871
  }
@@ -13784,7 +13888,7 @@ async function dispatchToClaude(input) {
13784
13888
  await input.reply(result.turnText);
13785
13889
  } catch (err) {
13786
13890
  const m = err instanceof Error ? err.message : String(err);
13787
- console.error(`${TAG21} reject reason=reply-failed senderId=${input.senderId} message=${m}`);
13891
+ console.error(`${TAG22} reject reason=reply-failed senderId=${input.senderId} message=${m}`);
13788
13892
  }
13789
13893
  }
13790
13894
  function startReaper2() {
@@ -14114,9 +14218,9 @@ watchFile(ALIAS_DOMAINS_PATH, { interval: 2e3 }, () => {
14114
14218
  function isPublicHost(host) {
14115
14219
  return host.startsWith("public.") || aliasDomains.has(host);
14116
14220
  }
14117
- var app38 = new Hono();
14118
- app38.use("*", clientIpMiddleware);
14119
- app38.use("*", async (c, next) => {
14221
+ var app39 = new Hono();
14222
+ app39.use("*", clientIpMiddleware);
14223
+ app39.use("*", async (c, next) => {
14120
14224
  await next();
14121
14225
  c.header("X-Content-Type-Options", "nosniff");
14122
14226
  c.header("Referrer-Policy", "strict-origin-when-cross-origin");
@@ -14126,7 +14230,7 @@ app38.use("*", async (c, next) => {
14126
14230
  );
14127
14231
  });
14128
14232
  var HTTP_LOG_PATHS = /* @__PURE__ */ new Set(["/vnc-viewer.html", "/vnc-popout.html"]);
14129
- app38.use("*", async (c, next) => {
14233
+ app39.use("*", async (c, next) => {
14130
14234
  if (!HTTP_LOG_PATHS.has(c.req.path)) {
14131
14235
  await next();
14132
14236
  return;
@@ -14159,7 +14263,7 @@ var PUBLIC_ALLOWED_PREFIXES = [
14159
14263
  "/sites/"
14160
14264
  ];
14161
14265
  var PUBLIC_ALLOWED_EXACT = ["/favicon.ico"];
14162
- app38.use("*", async (c, next) => {
14266
+ app39.use("*", async (c, next) => {
14163
14267
  const host = (c.req.header("host") ?? "").split(":")[0];
14164
14268
  if (!isPublicHost(host)) {
14165
14269
  await next();
@@ -14199,7 +14303,7 @@ function resolveRemoteAuthOpts() {
14199
14303
  return brandLoginOpts;
14200
14304
  }
14201
14305
  var MAX_LOGIN_BODY = 8 * 1024;
14202
- app38.post("/__remote-auth/login", async (c) => {
14306
+ app39.post("/__remote-auth/login", async (c) => {
14203
14307
  const client = clientFrom(c);
14204
14308
  const clientIp = client.ip || "unknown";
14205
14309
  if (!requestIsTlsTerminated(c)) {
@@ -14244,7 +14348,7 @@ app38.post("/__remote-auth/login", async (c) => {
14244
14348
  }
14245
14349
  });
14246
14350
  });
14247
- app38.get("/__remote-auth/logout", (c) => {
14351
+ app39.get("/__remote-auth/logout", (c) => {
14248
14352
  const client = clientFrom(c);
14249
14353
  const clientIp = client.ip || "unknown";
14250
14354
  console.error(`[remote-auth] logout ip=${clientIp}`);
@@ -14257,7 +14361,7 @@ app38.get("/__remote-auth/logout", (c) => {
14257
14361
  }
14258
14362
  });
14259
14363
  });
14260
- app38.post("/__remote-auth/change-password", async (c) => {
14364
+ app39.post("/__remote-auth/change-password", async (c) => {
14261
14365
  const client = clientFrom(c);
14262
14366
  const clientIp = client.ip || "unknown";
14263
14367
  const rateLimited = checkRateLimit(client);
@@ -14308,13 +14412,13 @@ app38.post("/__remote-auth/change-password", async (c) => {
14308
14412
  return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), mode: "change", changeError: "Failed to save password", redirect }), 200);
14309
14413
  }
14310
14414
  });
14311
- app38.get("/__remote-auth/setup", (c) => {
14415
+ app39.get("/__remote-auth/setup", (c) => {
14312
14416
  if (isRemoteAuthConfigured()) {
14313
14417
  return c.redirect("/");
14314
14418
  }
14315
14419
  return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), mode: "setup" }), 200);
14316
14420
  });
14317
- app38.post("/__remote-auth/set-initial-password", async (c) => {
14421
+ app39.post("/__remote-auth/set-initial-password", async (c) => {
14318
14422
  if (isRemoteAuthConfigured()) {
14319
14423
  return c.redirect("/");
14320
14424
  }
@@ -14352,10 +14456,10 @@ app38.post("/__remote-auth/set-initial-password", async (c) => {
14352
14456
  return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), mode: "setup", setupError: "Failed to save password. Please try again." }), 200);
14353
14457
  }
14354
14458
  });
14355
- app38.get("/api/remote-auth/status", (c) => {
14459
+ app39.get("/api/remote-auth/status", (c) => {
14356
14460
  return c.json({ configured: isRemoteAuthConfigured() });
14357
14461
  });
14358
- app38.post("/api/remote-auth/set-password", async (c) => {
14462
+ app39.post("/api/remote-auth/set-password", async (c) => {
14359
14463
  let body;
14360
14464
  try {
14361
14465
  body = await c.req.json();
@@ -14386,9 +14490,9 @@ app38.post("/api/remote-auth/set-password", async (c) => {
14386
14490
  return c.json({ error: "Failed to save password" }, 500);
14387
14491
  }
14388
14492
  });
14389
- app38.route("/api/_client-error", client_error_default);
14493
+ app39.route("/api/_client-error", client_error_default);
14390
14494
  console.log("[client-error-route] mounted");
14391
- app38.use("*", async (c, next) => {
14495
+ app39.use("*", async (c, next) => {
14392
14496
  const host = (c.req.header("host") ?? "").split(":")[0];
14393
14497
  const path2 = c.req.path;
14394
14498
  if (path2 === "/favicon.ico" || path2.startsWith("/assets/") || path2.startsWith("/brand/")) {
@@ -14421,11 +14525,11 @@ app38.use("*", async (c, next) => {
14421
14525
  console.error(`[remote-auth] login required ip=${clientIp} path=${path2} ${disambig}`);
14422
14526
  return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), redirect: path2 }), 200);
14423
14527
  });
14424
- app38.route("/api/health", health_default);
14425
- app38.route("/api/chat", chat_default);
14426
- app38.route("/api/whatsapp", whatsapp_default);
14427
- app38.route("/api/onboarding", onboarding_default);
14428
- app38.route("/api/admin", admin_default);
14528
+ app39.route("/api/health", health_default);
14529
+ app39.route("/api/chat", chat_default);
14530
+ app39.route("/api/whatsapp", whatsapp_default);
14531
+ app39.route("/api/onboarding", onboarding_default);
14532
+ app39.route("/api/admin", admin_default);
14429
14533
  var SAFE_SLUG_RE2 = /^[a-z][a-z0-9-]{2,49}$/;
14430
14534
  var SAFE_FILENAME_RE = /^[a-z0-9_][a-z0-9_.-]{0,99}$/i;
14431
14535
  var IMAGE_MIME = {
@@ -14437,7 +14541,7 @@ var IMAGE_MIME = {
14437
14541
  ".svg": "image/svg+xml",
14438
14542
  ".ico": "image/x-icon"
14439
14543
  };
14440
- app38.get("/agent-assets/:slug/:filename", (c) => {
14544
+ app39.get("/agent-assets/:slug/:filename", (c) => {
14441
14545
  const slug = c.req.param("slug");
14442
14546
  const filename = c.req.param("filename");
14443
14547
  if (!SAFE_SLUG_RE2.test(slug)) {
@@ -14472,7 +14576,7 @@ app38.get("/agent-assets/:slug/:filename", (c) => {
14472
14576
  "Cache-Control": "public, max-age=3600"
14473
14577
  });
14474
14578
  });
14475
- app38.get("/generated/:filename", (c) => {
14579
+ app39.get("/generated/:filename", (c) => {
14476
14580
  const filename = c.req.param("filename");
14477
14581
  if (!SAFE_FILENAME_RE.test(filename) || filename.includes("..")) {
14478
14582
  console.error(`[generated] serve file=${filename} status=403`);
@@ -14502,10 +14606,10 @@ app38.get("/generated/:filename", (c) => {
14502
14606
  "Cache-Control": "public, max-age=86400"
14503
14607
  });
14504
14608
  });
14505
- app38.route("/sites", sites_default);
14506
- app38.route("/listings", listings_default);
14507
- app38.route("/v", visitor_event_default);
14508
- app38.route("/v", visitor_consent_default);
14609
+ app39.route("/sites", sites_default);
14610
+ app39.route("/listings", listings_default);
14611
+ app39.route("/v", visitor_event_default);
14612
+ app39.route("/v", visitor_consent_default);
14509
14613
  var htmlCache = /* @__PURE__ */ new Map();
14510
14614
  var brandLogoPath = "/brand/maxy-monochrome.png";
14511
14615
  var brandIconPath = "/brand/maxy-monochrome.png";
@@ -14642,7 +14746,7 @@ function brandedPublicHtml(agentSlug) {
14642
14746
  function escapeHtml(s) {
14643
14747
  return s.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
14644
14748
  }
14645
- app38.get("/", (c) => {
14749
+ app39.get("/", (c) => {
14646
14750
  const host = (c.req.header("host") ?? "").split(":")[0];
14647
14751
  if (isPublicHost(host)) {
14648
14752
  const defaultSlug = resolveDefaultSlug();
@@ -14650,12 +14754,12 @@ app38.get("/", (c) => {
14650
14754
  }
14651
14755
  return c.html(cachedHtml("index.html"));
14652
14756
  });
14653
- app38.get("/public", (c) => {
14757
+ app39.get("/public", (c) => {
14654
14758
  const host = (c.req.header("host") ?? "").split(":")[0];
14655
14759
  if (isPublicHost(host)) return c.text("Not found", 404);
14656
14760
  return c.html(cachedHtml("public.html"));
14657
14761
  });
14658
- app38.get("/chat", (c) => {
14762
+ app39.get("/chat", (c) => {
14659
14763
  const host = (c.req.header("host") ?? "").split(":")[0];
14660
14764
  if (isPublicHost(host)) return c.text("Not found", 404);
14661
14765
  return c.html(cachedHtml("public.html"));
@@ -14674,9 +14778,9 @@ async function logViewerFetch(c, next) {
14674
14778
  duration_ms: Date.now() - start
14675
14779
  });
14676
14780
  }
14677
- app38.use("/vnc-viewer.html", logViewerFetch);
14678
- app38.use("/vnc-popout.html", logViewerFetch);
14679
- app38.get("/vnc-popout.html", (c) => {
14781
+ app39.use("/vnc-viewer.html", logViewerFetch);
14782
+ app39.use("/vnc-popout.html", logViewerFetch);
14783
+ app39.get("/vnc-popout.html", (c) => {
14680
14784
  let html = htmlCache.get("vnc-popout.html");
14681
14785
  if (!html) {
14682
14786
  html = readFileSync21(resolve21(process.cwd(), "public", "vnc-popout.html"), "utf-8");
@@ -14689,7 +14793,7 @@ app38.get("/vnc-popout.html", (c) => {
14689
14793
  }
14690
14794
  return c.html(html);
14691
14795
  });
14692
- app38.post("/api/vnc/client-event", async (c) => {
14796
+ app39.post("/api/vnc/client-event", async (c) => {
14693
14797
  let body;
14694
14798
  try {
14695
14799
  body = await c.req.json();
@@ -14710,25 +14814,25 @@ app38.post("/api/vnc/client-event", async (c) => {
14710
14814
  });
14711
14815
  return c.json({ ok: true });
14712
14816
  });
14713
- app38.get("/g/:slug", (c) => {
14817
+ app39.get("/g/:slug", (c) => {
14714
14818
  return c.html(brandedPublicHtml());
14715
14819
  });
14716
- app38.get("/graph", (c) => {
14820
+ app39.get("/graph", (c) => {
14717
14821
  const host = (c.req.header("host") ?? "").split(":")[0];
14718
14822
  if (isPublicHost(host)) return c.text("Not found", 404);
14719
14823
  return c.html(cachedHtml("graph.html"));
14720
14824
  });
14721
- app38.get("/sessions", (c) => {
14825
+ app39.get("/sessions", (c) => {
14722
14826
  const host = (c.req.header("host") ?? "").split(":")[0];
14723
14827
  if (isPublicHost(host)) return c.text("Not found", 404);
14724
14828
  return c.html(cachedHtml("sessions.html"));
14725
14829
  });
14726
- app38.get("/data", (c) => {
14830
+ app39.get("/data", (c) => {
14727
14831
  const host = (c.req.header("host") ?? "").split(":")[0];
14728
14832
  if (isPublicHost(host)) return c.text("Not found", 404);
14729
14833
  return c.html(cachedHtml("data.html"));
14730
14834
  });
14731
- app38.get("/:slug", async (c, next) => {
14835
+ app39.get("/:slug", async (c, next) => {
14732
14836
  const slug = c.req.param("slug");
14733
14837
  if (AGENT_SLUG_PATTERN.test(`/${slug}`)) {
14734
14838
  const branding = loadBrandingCache(slug);
@@ -14738,15 +14842,15 @@ app38.get("/:slug", async (c, next) => {
14738
14842
  await next();
14739
14843
  });
14740
14844
  if (brandFaviconPath !== "/favicon.ico") {
14741
- app38.get("/favicon.ico", (c) => {
14845
+ app39.get("/favicon.ico", (c) => {
14742
14846
  c.header("Cache-Control", "public, max-age=300");
14743
14847
  return c.redirect(brandFaviconPath, 302);
14744
14848
  });
14745
14849
  }
14746
- app38.use("/*", serveStatic({ root: "./public" }));
14850
+ app39.use("/*", serveStatic({ root: "./public" }));
14747
14851
  var port = requirePortEnv("MAXY_UI_INTERNAL_PORT", { tag: "ui-server" });
14748
14852
  var hostname = process.env.HOSTNAME ?? "127.0.0.1";
14749
- var httpServer = serve({ fetch: app38.fetch, port, hostname });
14853
+ var httpServer = serve({ fetch: app39.fetch, port, hostname });
14750
14854
  console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
14751
14855
  {
14752
14856
  const loopHist = monitorEventLoopDelay({ resolution: 50 });
@@ -14781,7 +14885,7 @@ for (const m of SUBAPP_MANIFEST) {
14781
14885
  }
14782
14886
  try {
14783
14887
  const registered = [];
14784
- for (const r of app38.routes ?? []) {
14888
+ for (const r of app39.routes ?? []) {
14785
14889
  if (typeof r.path !== "string" || r.path.includes(":") || r.path.includes("*")) continue;
14786
14890
  if (AGENT_SLUG_PATTERN.test(r.path)) {
14787
14891
  registered.push({ method: (r.method ?? "ALL").toUpperCase(), path: r.path });