@rubytech/create-realagent-code 0.1.29 → 0.1.31

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 (115) hide show
  1. package/dist/__tests__/init-logging.test.js +85 -0
  2. package/dist/index.js +21 -10
  3. package/dist/init-logging.js +28 -0
  4. package/package.json +1 -1
  5. package/payload/platform/lib/persistent-components/dist/index.d.ts +11 -12
  6. package/payload/platform/lib/persistent-components/dist/index.d.ts.map +1 -1
  7. package/payload/platform/lib/persistent-components/dist/index.js +11 -12
  8. package/payload/platform/lib/persistent-components/dist/index.js.map +1 -1
  9. package/payload/platform/lib/persistent-components/src/index.ts +11 -12
  10. package/payload/platform/neo4j/schema.cypher +6 -3
  11. package/payload/platform/plugins/admin/.claude-plugin/plugin.json +1 -1
  12. package/payload/platform/plugins/admin/PLUGIN.md +1 -3
  13. package/payload/platform/plugins/admin/hooks/onboarding-skill-drift.sh +57 -54
  14. package/payload/platform/plugins/admin/mcp/dist/index.js +15 -50
  15. package/payload/platform/plugins/admin/mcp/dist/index.js.map +1 -1
  16. package/payload/platform/plugins/admin/skills/access-manager/references/operations.md +7 -7
  17. package/payload/platform/plugins/admin/skills/file-presentation/SKILL.md +16 -33
  18. package/payload/platform/plugins/admin/skills/plugin-management/SKILL.md +1 -1
  19. package/payload/platform/plugins/admin/skills/public-agent-manager/SKILL.md +2 -2
  20. package/payload/platform/plugins/admin/skills/stream-log-review/references/analysis-patterns.md +2 -2
  21. package/payload/platform/plugins/anthropic/skills/get-api-key/SKILL.md +2 -4
  22. package/payload/platform/plugins/brochures/PLUGIN.md +1 -1
  23. package/payload/platform/plugins/buyers/PLUGIN.md +1 -2
  24. package/payload/platform/plugins/deep-research/skills/book-mirror/SKILL.md +1 -1
  25. package/payload/platform/plugins/deep-research/skills/strategic-reading/SKILL.md +1 -1
  26. package/payload/platform/plugins/docs/references/plugins-guide.md +2 -2
  27. package/payload/platform/plugins/email/references/email-reference.md +3 -7
  28. package/payload/platform/plugins/estate-business/PLUGIN.md +1 -2
  29. package/payload/platform/plugins/estate-coaching/PLUGIN.md +1 -2
  30. package/payload/platform/plugins/estate-onboarding/PLUGIN.md +1 -2
  31. package/payload/platform/plugins/estate-sales/PLUGIN.md +1 -2
  32. package/payload/platform/plugins/estate-teaching/PLUGIN.md +1 -2
  33. package/payload/platform/plugins/leads/PLUGIN.md +1 -2
  34. package/payload/platform/plugins/listings/PLUGIN.md +1 -2
  35. package/payload/platform/plugins/loop/PLUGIN.md +1 -1
  36. package/payload/platform/plugins/scheduling/PLUGIN.md +1 -1
  37. package/payload/platform/plugins/teaching/PLUGIN.md +2 -1
  38. package/payload/platform/plugins/vendors/PLUGIN.md +1 -2
  39. package/payload/platform/plugins/whatsapp/mcp/dist/index.js +1 -1
  40. package/payload/platform/plugins/whatsapp/mcp/dist/index.js.map +1 -1
  41. package/payload/platform/plugins/whatsapp/skills/connect-whatsapp/SKILL.md +1 -1
  42. package/payload/platform/plugins/whatsapp/skills/manage-whatsapp-config/SKILL.md +2 -8
  43. package/payload/platform/plugins/writer-craft/PLUGIN.md +2 -1
  44. package/payload/platform/scripts/component-knowledgedoc-backfill.ts +1 -1
  45. package/payload/platform/services/claude-session-manager/dist/http-server.d.ts +1 -1
  46. package/payload/platform/services/claude-session-manager/dist/http-server.d.ts.map +1 -1
  47. package/payload/platform/services/claude-session-manager/dist/http-server.js +45 -31
  48. package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
  49. package/payload/platform/services/claude-session-manager/dist/index.js +11 -0
  50. package/payload/platform/services/claude-session-manager/dist/index.js.map +1 -1
  51. package/payload/platform/services/claude-session-manager/dist/jsonl-observer.d.ts +30 -0
  52. package/payload/platform/services/claude-session-manager/dist/jsonl-observer.d.ts.map +1 -0
  53. package/payload/platform/services/claude-session-manager/dist/jsonl-observer.js +175 -0
  54. package/payload/platform/services/claude-session-manager/dist/jsonl-observer.js.map +1 -0
  55. package/payload/platform/services/claude-session-manager/dist/jsonl-path.d.ts +4 -2
  56. package/payload/platform/services/claude-session-manager/dist/jsonl-path.d.ts.map +1 -1
  57. package/payload/platform/services/claude-session-manager/dist/jsonl-path.js +15 -22
  58. package/payload/platform/services/claude-session-manager/dist/jsonl-path.js.map +1 -1
  59. package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts +13 -0
  60. package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts.map +1 -1
  61. package/payload/platform/services/claude-session-manager/dist/pty-spawner.js +26 -4
  62. package/payload/platform/services/claude-session-manager/dist/pty-spawner.js.map +1 -1
  63. package/payload/platform/services/claude-session-manager/dist/session-store.d.ts +9 -0
  64. package/payload/platform/services/claude-session-manager/dist/session-store.d.ts.map +1 -1
  65. package/payload/platform/services/claude-session-manager/dist/session-store.js.map +1 -1
  66. package/payload/platform/services/claude-session-manager/dist/system-prompt.d.ts +10 -7
  67. package/payload/platform/services/claude-session-manager/dist/system-prompt.d.ts.map +1 -1
  68. package/payload/platform/services/claude-session-manager/dist/system-prompt.js +51 -28
  69. package/payload/platform/services/claude-session-manager/dist/system-prompt.js.map +1 -1
  70. package/payload/platform/services/claude-session-manager/scripts/onboarding-advance.sh +61 -0
  71. package/payload/platform/services/claude-session-manager/scripts/onboarding-prompts/step-0.md +5 -0
  72. package/payload/platform/services/claude-session-manager/scripts/onboarding-prompts/step-1.md +3 -0
  73. package/payload/platform/services/claude-session-manager/scripts/onboarding-prompts/step-2.md +3 -0
  74. package/payload/platform/services/claude-session-manager/scripts/onboarding-prompts/step-3.md +8 -0
  75. package/payload/platform/services/claude-session-manager/scripts/onboarding-prompts/step-4.md +9 -0
  76. package/payload/platform/services/claude-session-manager/scripts/onboarding-prompts/step-5.md +3 -0
  77. package/payload/platform/services/claude-session-manager/scripts/onboarding-prompts/step-6.md +5 -0
  78. package/payload/platform/services/claude-session-manager/scripts/onboarding-prompts/step-7.md +5 -0
  79. package/payload/platform/services/claude-session-manager/scripts/onboarding-prompts/step-8.md +5 -0
  80. package/payload/platform/services/claude-session-manager/scripts/onboarding-prompts/step-9.md +8 -0
  81. package/payload/platform/services/claude-session-manager/scripts/onboarding-prompts/step-complete.md +3 -0
  82. package/payload/platform/services/claude-session-manager/scripts/onboarding-prompts/step-unreachable.md +3 -0
  83. package/payload/platform/templates/agents/public/IDENTITY.md +1 -1
  84. package/payload/platform/templates/specialists/agents/content-producer.md +3 -3
  85. package/payload/platform/templates/specialists/agents/personal-assistant.md +2 -2
  86. package/payload/premium-plugins/real-agent/BUNDLE.md +5 -5
  87. package/payload/premium-plugins/real-agent/agents/compliance.md +1 -1
  88. package/payload/premium-plugins/real-agent/agents/negotiator.md +1 -1
  89. package/payload/premium-plugins/real-agent/agents/valuer.md +1 -1
  90. package/payload/premium-plugins/real-agent/plugins/brochures/PLUGIN.md +1 -1
  91. package/payload/premium-plugins/real-agent/plugins/buyers/PLUGIN.md +1 -2
  92. package/payload/premium-plugins/real-agent/plugins/estate-business/PLUGIN.md +1 -2
  93. package/payload/premium-plugins/real-agent/plugins/estate-coaching/PLUGIN.md +1 -2
  94. package/payload/premium-plugins/real-agent/plugins/estate-onboarding/PLUGIN.md +1 -2
  95. package/payload/premium-plugins/real-agent/plugins/estate-sales/PLUGIN.md +1 -2
  96. package/payload/premium-plugins/real-agent/plugins/estate-teaching/PLUGIN.md +1 -2
  97. package/payload/premium-plugins/real-agent/plugins/leads/PLUGIN.md +1 -2
  98. package/payload/premium-plugins/real-agent/plugins/listings/PLUGIN.md +1 -2
  99. package/payload/premium-plugins/real-agent/plugins/loop/PLUGIN.md +1 -1
  100. package/payload/premium-plugins/real-agent/plugins/vendors/PLUGIN.md +1 -2
  101. package/payload/premium-plugins/teaching/PLUGIN.md +2 -1
  102. package/payload/premium-plugins/writer-craft/PLUGIN.md +2 -1
  103. package/payload/server/public/assets/{admin-CDvF5de6.js → admin-Bk2eXMFD.js} +24 -24
  104. package/payload/server/public/assets/{data-K_kS__sL.js → data-ll_OwVNL.js} +1 -1
  105. package/payload/server/public/assets/{graph-DeEigyO_.js → graph-DJ2VWioQ.js} +1 -1
  106. package/payload/server/public/assets/graph-labels-qhU8xZDH.js +1 -0
  107. package/payload/server/public/assets/{page-qSH972X0.js → page-Dk73ZO1F.js} +1 -1
  108. package/payload/server/public/assets/{page-B_rpjIRr.js → page-DsYsdBUK.js} +1 -1
  109. package/payload/server/public/data.html +3 -3
  110. package/payload/server/public/graph.html +3 -3
  111. package/payload/server/public/index.html +4 -4
  112. package/payload/server/server.js +121 -46
  113. package/payload/platform/plugins/admin/references/contextual-ui.md +0 -107
  114. package/payload/platform/scripts/__tests__/admin-persist-audit.test.ts +0 -182
  115. package/payload/server/public/assets/graph-labels-C7I5QvNv.js +0 -1
@@ -618,7 +618,7 @@ var serveStatic = (options = { root: "" }) => {
618
618
 
619
619
  // server/index.ts
620
620
  import { readFileSync as readFileSync19, existsSync as existsSync22, watchFile } from "fs";
621
- import { resolve as resolve23, join as join13, basename as basename5 } from "path";
621
+ import { resolve as resolve23, join as join14, basename as basename5 } from "path";
622
622
  import { homedir as homedir5 } from "os";
623
623
 
624
624
  // app/lib/agent-slug-pattern.ts
@@ -8024,7 +8024,7 @@ app14.post("/:id/resume", async (c) => {
8024
8024
  await storeComponentArtefact(accountId, c2.artefactAttachmentId, bytesPick.mimeType, bytesPick.content, filename);
8025
8025
  clearHealPending(accountId, c2.artefactAttachmentId);
8026
8026
  streamLogPath.write(
8027
- `[${(/* @__PURE__ */ new Date()).toISOString()}] [render-component-persist] heal componentName=${c2.name} attachmentId=${c2.artefactAttachmentId.slice(0, 8)} mimeType=${bytesPick.mimeType} bytes=${bytesPick.content.length} outcome=ok
8027
+ `[${(/* @__PURE__ */ new Date()).toISOString()}] [component-persist] heal componentName=${c2.name} attachmentId=${c2.artefactAttachmentId.slice(0, 8)} mimeType=${bytesPick.mimeType} bytes=${bytesPick.content.length} outcome=ok
8028
8028
  `
8029
8029
  );
8030
8030
  return {
@@ -8037,7 +8037,7 @@ app14.post("/:id/resume", async (c) => {
8037
8037
  clearHealPending(accountId, c2.artefactAttachmentId);
8038
8038
  const reason2 = writeErr instanceof Error ? writeErr.message : String(writeErr);
8039
8039
  streamLogPath.write(
8040
- `[${(/* @__PURE__ */ new Date()).toISOString()}] [render-component-persist] heal componentName=${c2.name} attachmentId=${c2.artefactAttachmentId.slice(0, 8)} outcome=disk-fail reason=${JSON.stringify(reason2.slice(0, 200))}
8040
+ `[${(/* @__PURE__ */ new Date()).toISOString()}] [component-persist] heal componentName=${c2.name} attachmentId=${c2.artefactAttachmentId.slice(0, 8)} outcome=disk-fail reason=${JSON.stringify(reason2.slice(0, 200))}
8041
8041
  `
8042
8042
  );
8043
8043
  return base;
@@ -8217,19 +8217,72 @@ async function buildOnboardingPromptBlock(accountId) {
8217
8217
  return { step };
8218
8218
  }
8219
8219
 
8220
- // server/routes/admin/claude-sessions.ts
8220
+ // server/lib/onboarding-advance.ts
8221
+ import { execFile as execFile2 } from "child_process";
8222
+ import { join as join11, resolve as resolvePath2 } from "path";
8221
8223
  var TAG19 = "[claude-session-manager:wrapper]";
8224
+ function onboardingAdvanceScriptPath() {
8225
+ const platformRoot = process.env.MAXY_PLATFORM_ROOT ?? resolvePath2(process.cwd(), "..");
8226
+ return join11(platformRoot, "services", "claude-session-manager", "scripts", "onboarding-advance.sh");
8227
+ }
8228
+ function runOnboardingAdvance(accountId, currentStep) {
8229
+ const scriptPath = onboardingAdvanceScriptPath();
8230
+ const stepArg = currentStep === null ? "null" : String(currentStep);
8231
+ return new Promise((resolve24) => {
8232
+ execFile2(
8233
+ scriptPath,
8234
+ [accountId, stepArg],
8235
+ { maxBuffer: 64 * 1024, timeout: 5e3 },
8236
+ (err, stdout, stderr) => {
8237
+ if (err) {
8238
+ console.error(`${TAG19} [onboarding-state] route-advance script-failed step=${stepArg} sender=${accountId}: ${err.message}`);
8239
+ resolve24(null);
8240
+ return;
8241
+ }
8242
+ if (stderr && stderr.trim()) {
8243
+ process.stderr.write(stderr.endsWith("\n") ? stderr : `${stderr}
8244
+ `);
8245
+ }
8246
+ resolve24(stdout);
8247
+ }
8248
+ );
8249
+ });
8250
+ }
8251
+
8252
+ // server/routes/admin/claude-sessions.ts
8253
+ var TAG20 = "[claude-session-manager:wrapper]";
8222
8254
  function managerBase2() {
8223
8255
  const port2 = Number(process.env.CLAUDE_SESSION_MANAGER_PORT ?? "19400");
8224
8256
  return `http://127.0.0.1:${port2}`;
8225
8257
  }
8258
+ async function resolveConversationIdForBanner(cacheKey, accountId, userId) {
8259
+ const bound = getConversationIdForSession(cacheKey);
8260
+ if (bound) return bound;
8261
+ const ensured = await ensureConversation(
8262
+ accountId,
8263
+ "admin",
8264
+ cacheKey,
8265
+ void 0,
8266
+ void 0,
8267
+ userId
8268
+ ).catch((err) => {
8269
+ console.error(`${TAG20} ensureConversation failed: ${err instanceof Error ? err.message : String(err)}`);
8270
+ return null;
8271
+ });
8272
+ if (ensured?.conversationId) {
8273
+ setConversationIdForSession(cacheKey, ensured.conversationId);
8274
+ return ensured.conversationId;
8275
+ }
8276
+ return null;
8277
+ }
8226
8278
  var app15 = new Hono();
8227
8279
  app15.use("*", requireAdminSession);
8228
8280
  app15.post("/", async (c) => {
8229
8281
  const cacheKey = c.get("cacheKey") ?? "";
8230
8282
  const senderId = getAccountIdForSession(cacheKey) ?? "";
8283
+ const userId = getUserIdForSession(cacheKey);
8231
8284
  if (!senderId) {
8232
- console.error(`${TAG19} reject reason=no-account-id`);
8285
+ console.error(`${TAG20} reject reason=no-account-id`);
8233
8286
  return c.json({ error: "admin-account-not-resolved" }, 500);
8234
8287
  }
8235
8288
  let body = {};
@@ -8239,37 +8292,59 @@ app15.post("/", async (c) => {
8239
8292
  }
8240
8293
  const channel = typeof body.channel === "string" ? body.channel : "browser";
8241
8294
  const initialMessage = typeof body.initialMessage === "string" && body.initialMessage.trim() ? body.initialMessage : null;
8295
+ const onboardingAdvance = body.onboardingAdvance === true;
8242
8296
  const permissionMode = typeof body.permissionMode === "string" ? body.permissionMode : void 0;
8243
8297
  let onboarding;
8298
+ let resolvedStep = 9;
8244
8299
  try {
8245
8300
  const outcome = await buildOnboardingPromptBlock(senderId);
8246
8301
  onboarding = { step: outcome.step };
8302
+ resolvedStep = outcome.step;
8247
8303
  } catch (err) {
8248
- console.error(`${TAG19} onboarding-resolve failed: ${err instanceof Error ? err.message : String(err)}`);
8304
+ console.error(`${TAG20} onboarding-resolve failed: ${err instanceof Error ? err.message : String(err)}`);
8305
+ }
8306
+ let scriptOutput = null;
8307
+ if (onboardingAdvance && resolvedStep !== 9 && onboarding) {
8308
+ scriptOutput = await runOnboardingAdvance(senderId, resolvedStep);
8309
+ if (scriptOutput && scriptOutput.trim()) {
8310
+ onboarding = { step: resolvedStep, resumePrompt: scriptOutput };
8311
+ }
8249
8312
  }
8250
8313
  const upstream = await fetch(`${managerBase2()}/spawn`, {
8251
8314
  method: "POST",
8252
8315
  headers: { "content-type": "application/json" },
8253
8316
  body: JSON.stringify({ senderId, role: "admin", channel, accountId: senderId, onboarding, permissionMode })
8254
8317
  }).catch((err) => {
8255
- console.error(`${TAG19} fetch-failed op=spawn message=${err instanceof Error ? err.message : String(err)}`);
8318
+ console.error(`${TAG20} fetch-failed op=spawn message=${err instanceof Error ? err.message : String(err)}`);
8256
8319
  return null;
8257
8320
  });
8258
8321
  if (!upstream) return c.json({ error: "manager-unreachable" }, 503);
8259
8322
  let spawnedSessionId = null;
8260
- if (upstream.ok && initialMessage) {
8323
+ if (upstream.ok) {
8261
8324
  const buffered = await upstream.clone().json().catch(() => null);
8262
8325
  if (buffered && typeof buffered.sessionId === "string" && buffered.sessionId) {
8263
8326
  spawnedSessionId = buffered.sessionId;
8264
8327
  }
8265
8328
  }
8266
- if (initialMessage && spawnedSessionId) {
8329
+ if (onboardingAdvance && spawnedSessionId && scriptOutput && scriptOutput.trim()) {
8330
+ const conversationId = await resolveConversationIdForBanner(cacheKey, senderId, userId);
8331
+ if (conversationId) {
8332
+ try {
8333
+ await persistMessage(conversationId, "assistant", scriptOutput.trimEnd(), senderId);
8334
+ } catch (err) {
8335
+ console.error(`${TAG20} persist initial assistant message failed: ${err instanceof Error ? err.message : String(err)}`);
8336
+ }
8337
+ } else {
8338
+ console.error(`${TAG20} banner-flow no conversationId resolved \u2014 script output not persisted, only system prompt carries it`);
8339
+ }
8340
+ }
8341
+ if (!onboardingAdvance && initialMessage && spawnedSessionId) {
8267
8342
  fetch(`${managerBase2()}/${encodeURIComponent(spawnedSessionId)}/input`, {
8268
8343
  method: "POST",
8269
8344
  headers: { "content-type": "application/json" },
8270
8345
  body: JSON.stringify({ text: initialMessage })
8271
8346
  }).catch((err) => {
8272
- console.error(`${TAG19} fetch-failed op=initial-input message=${err instanceof Error ? err.message : String(err)}`);
8347
+ console.error(`${TAG20} fetch-failed op=initial-input message=${err instanceof Error ? err.message : String(err)}`);
8273
8348
  });
8274
8349
  }
8275
8350
  return new Response(upstream.body, { status: upstream.status, headers: upstream.headers });
@@ -8281,7 +8356,7 @@ app15.get("/", async (c) => {
8281
8356
  const upstream = await fetch(
8282
8357
  `${managerBase2()}/list?senderId=${encodeURIComponent(senderId)}`
8283
8358
  ).catch((err) => {
8284
- console.error(`${TAG19} fetch-failed op=list message=${err instanceof Error ? err.message : String(err)}`);
8359
+ console.error(`${TAG20} fetch-failed op=list message=${err instanceof Error ? err.message : String(err)}`);
8285
8360
  return null;
8286
8361
  });
8287
8362
  if (!upstream) return c.json({ error: "manager-unreachable" }, 503);
@@ -8311,7 +8386,7 @@ app15.post("/resume", async (c) => {
8311
8386
  claudeSessionId: body.claudeSessionId
8312
8387
  })
8313
8388
  }).catch((err) => {
8314
- console.error(`${TAG19} fetch-failed op=resume message=${err instanceof Error ? err.message : String(err)}`);
8389
+ console.error(`${TAG20} fetch-failed op=resume message=${err instanceof Error ? err.message : String(err)}`);
8315
8390
  return null;
8316
8391
  });
8317
8392
  if (!upstream) return c.json({ error: "manager-unreachable" }, 503);
@@ -8324,7 +8399,7 @@ app15.delete("/:sessionId", async (c) => {
8324
8399
  `${managerBase2()}/${encodeURIComponent(sessionId)}${purge}`,
8325
8400
  { method: "DELETE" }
8326
8401
  ).catch((err) => {
8327
- console.error(`${TAG19} fetch-failed op=delete message=${err instanceof Error ? err.message : String(err)}`);
8402
+ console.error(`${TAG20} fetch-failed op=delete message=${err instanceof Error ? err.message : String(err)}`);
8328
8403
  return null;
8329
8404
  });
8330
8405
  if (!upstream) return c.json({ error: "manager-unreachable" }, 503);
@@ -8341,7 +8416,7 @@ app15.post("/:sessionId/archive", async (c) => {
8341
8416
  body
8342
8417
  }
8343
8418
  ).catch((err) => {
8344
- console.error(`${TAG19} fetch-failed op=archive message=${err instanceof Error ? err.message : String(err)}`);
8419
+ console.error(`${TAG20} fetch-failed op=archive message=${err instanceof Error ? err.message : String(err)}`);
8345
8420
  return null;
8346
8421
  });
8347
8422
  if (!upstream) return c.json({ error: "manager-unreachable" }, 503);
@@ -8352,7 +8427,7 @@ app15.get("/:sessionId/meta", async (c) => {
8352
8427
  const upstream = await fetch(
8353
8428
  `${managerBase2()}/${encodeURIComponent(sessionId)}/meta`
8354
8429
  ).catch((err) => {
8355
- console.error(`${TAG19} fetch-failed op=meta message=${err instanceof Error ? err.message : String(err)}`);
8430
+ console.error(`${TAG20} fetch-failed op=meta message=${err instanceof Error ? err.message : String(err)}`);
8356
8431
  return null;
8357
8432
  });
8358
8433
  if (!upstream) return c.json({ error: "manager-unreachable" }, 503);
@@ -8369,7 +8444,7 @@ app15.patch("/:sessionId", async (c) => {
8369
8444
  body
8370
8445
  }
8371
8446
  ).catch((err) => {
8372
- console.error(`${TAG19} fetch-failed op=patch message=${err instanceof Error ? err.message : String(err)}`);
8447
+ console.error(`${TAG20} fetch-failed op=patch message=${err instanceof Error ? err.message : String(err)}`);
8373
8448
  return null;
8374
8449
  });
8375
8450
  if (!upstream) return c.json({ error: "manager-unreachable" }, 503);
@@ -8386,7 +8461,7 @@ app15.post("/:sessionId/input", async (c) => {
8386
8461
  body: rawBody
8387
8462
  }
8388
8463
  ).catch((err) => {
8389
- console.error(`${TAG19} fetch-failed op=input message=${err instanceof Error ? err.message : String(err)}`);
8464
+ console.error(`${TAG20} fetch-failed op=input message=${err instanceof Error ? err.message : String(err)}`);
8390
8465
  return null;
8391
8466
  });
8392
8467
  if (!upstream) return c.json({ error: "manager-unreachable" }, 503);
@@ -8398,7 +8473,7 @@ app15.get("/:sessionId/log", async (c) => {
8398
8473
  const upstream = await fetch(
8399
8474
  `${managerBase2()}/${encodeURIComponent(sessionId)}/log${follow}`
8400
8475
  ).catch((err) => {
8401
- console.error(`${TAG19} fetch-failed op=log message=${err instanceof Error ? err.message : String(err)}`);
8476
+ console.error(`${TAG20} fetch-failed op=log message=${err instanceof Error ? err.message : String(err)}`);
8402
8477
  return null;
8403
8478
  });
8404
8479
  if (!upstream) return c.json({ error: "manager-unreachable" }, 503);
@@ -8514,13 +8589,13 @@ async function cdpNavigateNewTab(url, opts = {}) {
8514
8589
  // server/routes/admin/device-browser.ts
8515
8590
  var app18 = new Hono();
8516
8591
  app18.post("/navigate", async (c) => {
8517
- const TAG21 = "[device-url:click]";
8592
+ const TAG22 = "[device-url:click]";
8518
8593
  let body;
8519
8594
  try {
8520
8595
  body = await c.req.json();
8521
8596
  } catch (err) {
8522
8597
  const detail = err instanceof Error ? err.message : String(err);
8523
- console.error(`${TAG21} reject reason=body-not-json detail=${detail} browser=fallback navigateResult=error`);
8598
+ console.error(`${TAG22} reject reason=body-not-json detail=${detail} browser=fallback navigateResult=error`);
8524
8599
  return c.json(
8525
8600
  { ok: false, navigateResult: "error", browser: "fallback", detail: "Request body was not valid JSON" },
8526
8601
  400
@@ -8530,7 +8605,7 @@ app18.post("/navigate", async (c) => {
8530
8605
  const intent = typeof body.intent === "string" ? body.intent : "";
8531
8606
  const hostname2 = typeof body.hostname === "string" ? body.hostname : "";
8532
8607
  if (!url) {
8533
- console.error(`${TAG21} reject reason=missing-url intent=${JSON.stringify(intent)} browser=fallback navigateResult=error`);
8608
+ console.error(`${TAG22} reject reason=missing-url intent=${JSON.stringify(intent)} browser=fallback navigateResult=error`);
8534
8609
  return c.json(
8535
8610
  { ok: false, navigateResult: "error", browser: "fallback", detail: "url field is required" },
8536
8611
  400
@@ -8540,7 +8615,7 @@ app18.post("/navigate", async (c) => {
8540
8615
  try {
8541
8616
  parsed = new URL(url);
8542
8617
  } catch {
8543
- console.error(`${TAG21} reject reason=url-malformed intent=${JSON.stringify(intent)} url=${url} browser=fallback navigateResult=error`);
8618
+ console.error(`${TAG22} reject reason=url-malformed intent=${JSON.stringify(intent)} url=${url} browser=fallback navigateResult=error`);
8544
8619
  return c.json(
8545
8620
  { ok: false, navigateResult: "error", browser: "fallback", detail: "url is not a valid URL" },
8546
8621
  400
@@ -8548,7 +8623,7 @@ app18.post("/navigate", async (c) => {
8548
8623
  }
8549
8624
  if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
8550
8625
  console.error(
8551
- `${TAG21} reject reason=scheme-not-allowed scheme=${parsed.protocol} intent=${JSON.stringify(intent)} browser=fallback navigateResult=error`
8626
+ `${TAG22} reject reason=scheme-not-allowed scheme=${parsed.protocol} intent=${JSON.stringify(intent)} browser=fallback navigateResult=error`
8552
8627
  );
8553
8628
  return c.json(
8554
8629
  {
@@ -8564,7 +8639,7 @@ app18.post("/navigate", async (c) => {
8564
8639
  const cdpOk = await ensureCdp(transport);
8565
8640
  if (!cdpOk) {
8566
8641
  console.error(
8567
- `${TAG21} intent=${JSON.stringify(intent)} browser=fallback navigateResult=cdp-unreachable hostname=${JSON.stringify(hostname2)}`
8642
+ `${TAG22} intent=${JSON.stringify(intent)} browser=fallback navigateResult=cdp-unreachable hostname=${JSON.stringify(hostname2)}`
8568
8643
  );
8569
8644
  return c.json(
8570
8645
  {
@@ -8580,7 +8655,7 @@ app18.post("/navigate", async (c) => {
8580
8655
  const browser = outcome.result === "ok" ? "vnc" : "fallback";
8581
8656
  const detailStr = outcome.detail ? ` detail=${JSON.stringify(outcome.detail.length > 230 ? outcome.detail.slice(0, 227) + "..." : outcome.detail)}` : "";
8582
8657
  console.error(
8583
- `${TAG21} intent=${JSON.stringify(intent)} browser=${browser} navigateResult=${outcome.result} hostname=${JSON.stringify(hostname2)} targetId=${outcome.targetId ?? "none"}${detailStr}`
8658
+ `${TAG22} intent=${JSON.stringify(intent)} browser=${browser} navigateResult=${outcome.result} hostname=${JSON.stringify(hostname2)} targetId=${outcome.targetId ?? "none"}${detailStr}`
8584
8659
  );
8585
8660
  if (outcome.result !== "ok") {
8586
8661
  return c.json(
@@ -8611,18 +8686,18 @@ var ALLOWED_EVENTS2 = /* @__PURE__ */ new Set([
8611
8686
  ]);
8612
8687
  var app19 = new Hono();
8613
8688
  app19.post("/", async (c) => {
8614
- const TAG21 = "[admin:events]";
8689
+ const TAG22 = "[admin:events]";
8615
8690
  let body;
8616
8691
  try {
8617
8692
  body = await c.req.json();
8618
8693
  } catch (err) {
8619
8694
  const detail = err instanceof Error ? err.message : String(err);
8620
- console.error(`${TAG21} reject reason=body-not-json detail=${detail}`);
8695
+ console.error(`${TAG22} reject reason=body-not-json detail=${detail}`);
8621
8696
  return c.json({ ok: false, detail: "Request body was not valid JSON" }, 400);
8622
8697
  }
8623
8698
  const event = typeof body.event === "string" ? body.event : "";
8624
8699
  if (!ALLOWED_EVENTS2.has(event)) {
8625
- console.error(`${TAG21} reject reason=event-not-allowed event=${JSON.stringify(event)}`);
8700
+ console.error(`${TAG22} reject reason=event-not-allowed event=${JSON.stringify(event)}`);
8626
8701
  return c.json({ ok: false, detail: `Event "${event}" is not allowed` }, 400);
8627
8702
  }
8628
8703
  const rawFields = body.fields && typeof body.fields === "object" ? body.fields : {};
@@ -9514,7 +9589,7 @@ var cloudflare_default = app20;
9514
9589
  import { createReadStream as createReadStream3 } from "fs";
9515
9590
  import { readdir as readdir2, readFile as readFile4, stat as stat4, mkdir as mkdir3, writeFile as writeFile4, unlink as unlink2 } from "fs/promises";
9516
9591
  import { realpathSync as realpathSync4 } from "fs";
9517
- import { basename as basename4, dirname as dirname6, join as join11, resolve as resolve16, sep as sep3 } from "path";
9592
+ import { basename as basename4, dirname as dirname6, join as join12, resolve as resolve16, sep as sep3 } from "path";
9518
9593
  import { Readable as Readable2 } from "stream";
9519
9594
 
9520
9595
  // app/lib/data-path.ts
@@ -9872,7 +9947,7 @@ async function cascadeDeleteDocument(params) {
9872
9947
  var UUID_RE4 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
9873
9948
  async function readMeta(absDir, baseName) {
9874
9949
  try {
9875
- const raw = await readFile4(join11(absDir, `${baseName}.meta.json`), "utf8");
9950
+ const raw = await readFile4(join12(absDir, `${baseName}.meta.json`), "utf8");
9876
9951
  const parsed = JSON.parse(raw);
9877
9952
  if (typeof parsed?.filename === "string") {
9878
9953
  return { filename: parsed.filename, mimeType: typeof parsed.mimeType === "string" ? parsed.mimeType : void 0 };
@@ -9910,7 +9985,7 @@ async function readAccountNames() {
9910
9985
  }
9911
9986
  async function enrich(absolute, entry, accountNames) {
9912
9987
  if (entry.kind === "directory" && UUID_RE4.test(entry.name)) {
9913
- const meta = await readMeta(join11(absolute, entry.name), entry.name);
9988
+ const meta = await readMeta(join12(absolute, entry.name), entry.name);
9914
9989
  if (meta?.filename) {
9915
9990
  entry.displayName = meta.filename;
9916
9991
  entry.mimeType = meta.mimeType;
@@ -9969,7 +10044,7 @@ app21.get("/", requireAdminSession, async (c) => {
9969
10044
  continue;
9970
10045
  }
9971
10046
  try {
9972
- const entryPath = join11(absolute, name);
10047
+ const entryPath = join12(absolute, name);
9973
10048
  const s = await stat4(entryPath);
9974
10049
  entries.push({
9975
10050
  name,
@@ -10142,7 +10217,7 @@ app21.delete("/", requireAdminSession, async (c) => {
10142
10217
  }
10143
10218
  const dot = base.lastIndexOf(".");
10144
10219
  const stem = dot === -1 ? base : base.slice(0, dot);
10145
- const sidecarPath = UUID_RE4.test(stem) && base !== `${stem}.meta.json` ? join11(dirname6(absolute), `${stem}.meta.json`) : null;
10220
+ const sidecarPath = UUID_RE4.test(stem) && base !== `${stem}.meta.json` ? join12(dirname6(absolute), `${stem}.meta.json`) : null;
10146
10221
  await unlink2(absolute);
10147
10222
  if (sidecarPath) {
10148
10223
  try {
@@ -12193,10 +12268,10 @@ var sidebar_artefact_content_default = app31;
12193
12268
 
12194
12269
  // server/routes/admin/health.ts
12195
12270
  import { existsSync as existsSync19, readFileSync as readFileSync16 } from "fs";
12196
- import { resolve as resolve20, join as join12 } from "path";
12271
+ import { resolve as resolve20, join as join13 } from "path";
12197
12272
  var PLATFORM_ROOT7 = process.env.MAXY_PLATFORM_ROOT ?? resolve20(process.cwd(), "..");
12198
12273
  var brandHostname = "maxy";
12199
- var brandJsonPath = join12(PLATFORM_ROOT7, "config", "brand.json");
12274
+ var brandJsonPath = join13(PLATFORM_ROOT7, "config", "brand.json");
12200
12275
  if (existsSync19(brandJsonPath)) {
12201
12276
  try {
12202
12277
  const brand = JSON.parse(readFileSync16(brandJsonPath, "utf-8"));
@@ -12511,7 +12586,7 @@ function startGraphHealthTimer() {
12511
12586
  }
12512
12587
 
12513
12588
  // app/lib/whatsapp/inbound/claude-bridge.ts
12514
- var TAG20 = "[whatsapp-adaptor]";
12589
+ var TAG21 = "[whatsapp-adaptor]";
12515
12590
  function whatsappTurnTimeoutMs() {
12516
12591
  return Number(process.env.WHATSAPP_PTY_TURN_TIMEOUT_MS ?? String(5 * 6e4));
12517
12592
  }
@@ -12532,7 +12607,7 @@ async function dispatchToClaude(input) {
12532
12607
  await input.reply(result.turnText);
12533
12608
  } catch (err) {
12534
12609
  const m = err instanceof Error ? err.message : String(err);
12535
- console.error(`${TAG20} reject reason=reply-failed senderId=${input.senderId} message=${m}`);
12610
+ console.error(`${TAG21} reject reason=reply-failed senderId=${input.senderId} message=${m}`);
12536
12611
  }
12537
12612
  }
12538
12613
  function startReaper2() {
@@ -12780,7 +12855,7 @@ function clientFrom(c) {
12780
12855
  );
12781
12856
  }
12782
12857
  var PLATFORM_ROOT8 = process.env.MAXY_PLATFORM_ROOT || "";
12783
- var BRAND_JSON_PATH = PLATFORM_ROOT8 ? join13(PLATFORM_ROOT8, "config", "brand.json") : "";
12858
+ var BRAND_JSON_PATH = PLATFORM_ROOT8 ? join14(PLATFORM_ROOT8, "config", "brand.json") : "";
12784
12859
  var BRAND = { productName: "Maxy", hostname: "maxy", configDir: ".maxy", domain: "getmaxy.com" };
12785
12860
  if (BRAND_JSON_PATH && !existsSync22(BRAND_JSON_PATH)) {
12786
12861
  console.error(`[brand] WARNING: brand.json not found at ${BRAND_JSON_PATH} \u2014 using Maxy defaults`);
@@ -12806,7 +12881,7 @@ var brandLoginOpts = {
12806
12881
  bodyFont: BRAND.defaultFonts?.body,
12807
12882
  logoContainsName: !!BRAND.logoContainsName
12808
12883
  };
12809
- var ALIAS_DOMAINS_PATH2 = join13(homedir5(), BRAND.configDir, "alias-domains.json");
12884
+ var ALIAS_DOMAINS_PATH2 = join14(homedir5(), BRAND.configDir, "alias-domains.json");
12810
12885
  function loadAliasDomains() {
12811
12886
  try {
12812
12887
  if (!existsSync22(ALIAS_DOMAINS_PATH2)) return null;
@@ -13252,7 +13327,7 @@ var brandScript = `<script>window.__BRAND__=${JSON.stringify({
13252
13327
  function readInstalledVersion() {
13253
13328
  try {
13254
13329
  if (!PLATFORM_ROOT8) return "unknown";
13255
- const versionFile = join13(PLATFORM_ROOT8, "config", `.${BRAND.hostname}-version`);
13330
+ const versionFile = join14(PLATFORM_ROOT8, "config", `.${BRAND.hostname}-version`);
13256
13331
  if (!existsSync22(versionFile)) return "unknown";
13257
13332
  const content = readFileSync19(versionFile, "utf-8").trim();
13258
13333
  return content || "unknown";
@@ -13311,14 +13386,14 @@ ${clientErrorReporterScript}
13311
13386
  }
13312
13387
  var brandedHtmlCache = /* @__PURE__ */ new Map();
13313
13388
  function loadBrandingCache(agentSlug) {
13314
- const configDir2 = join13(homedir5(), BRAND.configDir);
13389
+ const configDir2 = join14(homedir5(), BRAND.configDir);
13315
13390
  try {
13316
- const accountJsonPath = join13(configDir2, "account.json");
13391
+ const accountJsonPath = join14(configDir2, "account.json");
13317
13392
  if (!existsSync22(accountJsonPath)) return null;
13318
13393
  const account = JSON.parse(readFileSync19(accountJsonPath, "utf-8"));
13319
13394
  const accountId = account.accountId;
13320
13395
  if (!accountId) return null;
13321
- const cachePath = join13(configDir2, "branding-cache", accountId, `${agentSlug}.json`);
13396
+ const cachePath = join14(configDir2, "branding-cache", accountId, `${agentSlug}.json`);
13322
13397
  if (!existsSync22(cachePath)) return null;
13323
13398
  return JSON.parse(readFileSync19(cachePath, "utf-8"));
13324
13399
  } catch {
@@ -13327,8 +13402,8 @@ function loadBrandingCache(agentSlug) {
13327
13402
  }
13328
13403
  function resolveDefaultSlug() {
13329
13404
  try {
13330
- const configDir2 = join13(homedir5(), BRAND.configDir);
13331
- const accountJsonPath = join13(configDir2, "account.json");
13405
+ const configDir2 = join14(homedir5(), BRAND.configDir);
13406
+ const accountJsonPath = join14(configDir2, "account.json");
13332
13407
  if (!existsSync22(accountJsonPath)) return null;
13333
13408
  const account = JSON.parse(readFileSync19(accountJsonPath, "utf-8"));
13334
13409
  return account.defaultAgent || null;
@@ -13650,7 +13725,7 @@ if (bootAccountConfig?.whatsapp) {
13650
13725
  }
13651
13726
  init({
13652
13727
  configDir: configDirForWhatsApp,
13653
- platformRoot: resolve23(process.env.MAXY_PLATFORM_ROOT ?? join13(__dirname, "..")),
13728
+ platformRoot: resolve23(process.env.MAXY_PLATFORM_ROOT ?? join14(__dirname, "..")),
13654
13729
  accountConfig: bootAccountConfig,
13655
13730
  onMessage: async (msg) => {
13656
13731
  if (process.env.WHATSAPP_PTY_BRIDGE_ENABLED === "true" && msg.text && !msg.isOwnerMirror) {
@@ -1,107 +0,0 @@
1
- # Contextual UI Toolkit
2
-
3
- A suite of UI primitives rendered inline in the conversation via `render-component`. Use these when structured interaction improves clarity, reduces ambiguity, or prevents errors — not for every exchange.
4
-
5
- ## Component Catalogue
6
-
7
- | Name | Purpose | Data key fields |
8
- |------|---------|-----------------|
9
- | `single-select` | Choose one option from a list | `options[].{value, label, description?}`, `submitMessage?` |
10
- | `multi-select` | Choose multiple options with checkboxes | `options[].{value, label, description?, badge?, defaultSelected?}`, `submitMessage?`, `skipLabel?` |
11
- | `confirm` | Approve or reject a consequential action | `title`, `description?`, `items?[].{label, value}`, `confirmMessage?`, `rejectMessage?` |
12
- | `info-card` | Display structured entity data (read-only) | `title`, `subtitle?`, `fields[].{label, value, type?}`, `actions?[].{label, message, variant}` |
13
- | `action-list` | List of items with per-item actions | `items[].{id, label, description?, status?, actions[]}`, `doneMessage?` |
14
- | `form` | Collect 2+ pieces of structured input | `fields[].{name, label, type, description?, placeholder?, required?, options?[].{value, label, description?}}`, `submitMessage?` |
15
- | `progress` | Multi-step progress tracker (read-only) | `steps[].{label, status, description?}`, `completedMessage?` |
16
- | `browser-viewer` | VNC iframe for browser automation | `title` |
17
- | `document-editor` | Inline markdown editor — prose content | `title`, `content` (markdown), `filePath?`, `readOnly?` |
18
- | `rich-content-editor` | Rich HTML editor — visual/branded content with images | `title`, `content` (HTML fragment), `filePath?`, `readOnly?`, `brandName?`, `brandLogo?` |
19
- | `grid-editor` | Spreadsheet grid — tabular data editing | `title`, `columns[]`, `rows[][]`, `filePath?`, `brandName?`, `brandLogo?` |
20
-
21
- Editors that accept `filePath` display an **Approve** button in the header bar. Omitting `filePath` renders the editor without an approval action — the user can view and edit but cannot submit content for writing. Always include `filePath` when the content requires user approval before being saved to disk.
22
-
23
- ## Editor Selection
24
-
25
- Three editor modes serve different content types. Choose based on what the user is working with:
26
-
27
- | Content type | Editor | Examples |
28
- |---|---|---|
29
- | Prose — headings, paragraphs, lists | `document-editor` | Knowledge base articles, FAQs, procedures, meeting notes, SOUL files |
30
- | Visual/branded — HTML with images and layout | `rich-content-editor` | Product cards, blog posts, invoices with logos, marketing materials |
31
- | Tabular — columns and rows of values | `grid-editor` | Price lists, contact details, inventory, service catalogues |
32
-
33
- **Decision rule:** If the content has images or needs branded visual layout → `rich-content-editor`. If the content is a table of values → `grid-editor`. Everything else → `document-editor`.
34
-
35
- All three editors support PDF export. Include `brandName` and `brandLogo` (from the business profile in the graph) when the output may be exported as a branded PDF.
36
-
37
- ## When to Use UI vs. Text
38
-
39
- **Use a component when:**
40
- - The user is choosing from 2+ discrete options → `single-select` or `multi-select`
41
- - You need approval before a consequential or irreversible action → `confirm`
42
- - You're presenting a structured entity (contact, task, invoice, status) → `info-card`
43
- - A list has distinct per-item actions → `action-list`
44
- - You need 2+ pieces of information at once → `form`
45
- - A multi-step process benefits from visible progress → `progress`
46
-
47
- **Use an editor when:**
48
- - The user asks to see, review, or edit a document → `document-editor`
49
- - The user needs visual/branded content (product card, invoice, brochure) → `rich-content-editor`
50
- - The user asks about tabular data (prices, contacts, inventory) → `grid-editor`
51
- - "Show me the FAQ" → `document-editor` with the FAQ content
52
- - "Create a product card for the new range" → `rich-content-editor` with generated HTML
53
- - "Show me the price list" → `grid-editor` with columns and rows
54
-
55
- **Use plain text when:**
56
- - Simple yes/no — ask in text
57
- - Open-ended input — ask in text
58
- - Informational response with no structure — just respond
59
- - Single piece of information needed — ask in text
60
- - The interaction is fast and unambiguous without UI
61
-
62
- Components add value when they reduce ambiguity, prevent errors, or present structure that text cannot. Not every interaction needs a widget.
63
-
64
- ## How to Use
65
-
66
- Call `render-component` with `name` (component name) and `data` (structured object matching the component's schema). Then wait for the user's response before continuing — the response arrives as a regular message.
67
-
68
- ### Form field types
69
-
70
- The `form` component supports these field types:
71
-
72
- | Type | Renders as | Value type | Notes |
73
- |------|-----------|------------|-------|
74
- | `text` | Text input | string | Default for short text |
75
- | `textarea` | Multi-line text | string | For longer input |
76
- | `select` | Dropdown | string | Requires `options[]` with `{value, label, description?}` — descriptions are appended to the option label |
77
- | `checkbox` | Toggle checkbox | boolean | Uses the shared Checkbox component. Label appears inline next to the checkbox, not above it |
78
- | `number` | Number input | string | |
79
- | `date` | Date input | string | |
80
-
81
- All field types accept optional `description` (help text below the label) and `defaultValue` (pre-populated value — used if the user doesn't interact with the field) properties.
82
-
83
- For `checkbox` fields, the submitted JSON value is `true` or `false` (boolean), not a string. For all other types, the value is a string.
84
-
85
- ### Submit message templates
86
-
87
- Most components accept a `submitMessage` field that controls the format of the message sent back:
88
- - `single-select`: `"Selected: {{value}}"` — `{{value}}` and `{{label}}` are replaced
89
- - `multi-select`: `"Selected: {{values}}"` — `{{values}}` is comma-separated selected values
90
- - `form`: `"Form submitted: {{json}}"` — `{{json}}` is a JSON string of `{name: value}` pairs. Per-field placeholders `{{fieldName}}` are also supported (e.g. `"model={{model}}, live={{liveMemory}}"`). `{{values}}` is an alias for `{{json}}`
91
- - `confirm`: `confirmMessage` / `rejectMessage` — literal strings
92
- - `action-list`: each item action has its own `message` field
93
- - `info-card`: each action has its own `message` field
94
-
95
- When no template is provided, sensible defaults are used.
96
-
97
- ### Backwards-compatible aliases
98
-
99
- These legacy names still work: `output-style` → `single-select`, `thinking-view` → `single-select`, `plugin-selector` → `multi-select`.
100
-
101
- ## Anti-patterns
102
-
103
- - Rendering a `single-select` for a yes/no question — just ask in text
104
- - Rendering a `form` for a single field — just ask in text
105
- - Chaining multiple components in one response — render one, wait for the response, then decide if another is needed
106
- - Using `info-card` for data the user already knows — only show structured display when it adds value
107
- - Rendering `progress` once and never updating it — progress is for multi-step processes where you re-render with updated step statuses