@rubytech/create-maxy 1.0.795 → 1.0.797

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 (52) hide show
  1. package/package.json +1 -1
  2. package/payload/platform/neo4j/migrations/003-person-name-eradicate.cypher +24 -0
  3. package/payload/platform/plugins/admin/PLUGIN.md +4 -0
  4. package/payload/platform/plugins/admin/hooks/pre-tool-use.sh +9 -5
  5. package/payload/platform/plugins/admin/mcp/dist/index.js +54 -18
  6. package/payload/platform/plugins/admin/mcp/dist/index.js.map +1 -1
  7. package/payload/platform/plugins/docs/references/internals.md +4 -0
  8. package/payload/platform/plugins/docs/references/settings.md +6 -0
  9. package/payload/platform/plugins/memory/PLUGIN.md +4 -2
  10. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/schema-loader.test.js +11 -0
  11. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/schema-loader.test.js.map +1 -1
  12. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/schema-validator.test.js +124 -1
  13. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/schema-validator.test.js.map +1 -1
  14. package/payload/platform/plugins/memory/mcp/dist/lib/schema-loader.d.ts +12 -0
  15. package/payload/platform/plugins/memory/mcp/dist/lib/schema-loader.d.ts.map +1 -1
  16. package/payload/platform/plugins/memory/mcp/dist/lib/schema-loader.js +41 -2
  17. package/payload/platform/plugins/memory/mcp/dist/lib/schema-loader.js.map +1 -1
  18. package/payload/platform/plugins/memory/mcp/dist/lib/schema-validator.d.ts +9 -0
  19. package/payload/platform/plugins/memory/mcp/dist/lib/schema-validator.d.ts.map +1 -1
  20. package/payload/platform/plugins/memory/mcp/dist/lib/schema-validator.js +44 -0
  21. package/payload/platform/plugins/memory/mcp/dist/lib/schema-validator.js.map +1 -1
  22. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-archive-write.test.js +20 -2
  23. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-archive-write.test.js.map +1 -1
  24. package/payload/platform/plugins/memory/mcp/dist/tools/memory-archive-write.d.ts +1 -1
  25. package/payload/platform/plugins/memory/mcp/dist/tools/memory-archive-write.d.ts.map +1 -1
  26. package/payload/platform/plugins/memory/mcp/dist/tools/memory-archive-write.js +0 -1
  27. package/payload/platform/plugins/memory/mcp/dist/tools/memory-archive-write.js.map +1 -1
  28. package/payload/platform/plugins/memory/references/schema-base.md +11 -1
  29. package/payload/platform/scripts/logs-read.sh +17 -12
  30. package/payload/platform/templates/agents/admin/IDENTITY.md +6 -0
  31. package/payload/server/chunk-BURNRCKP.js +3405 -0
  32. package/payload/server/chunk-JSBRDJBE.js +30 -0
  33. package/payload/server/chunk-KM23Y7SY.js +9896 -0
  34. package/payload/server/client-pool-PV45NUTN.js +29 -0
  35. package/payload/server/maxy-edge.js +3 -2
  36. package/payload/server/neo4j-migrations-IUSBODOP.js +51 -0
  37. package/payload/server/public/assets/admin-Cz8hUAqx.js +352 -0
  38. package/payload/server/public/assets/data-BvV94XHO.js +1 -0
  39. package/payload/server/public/assets/graph-CBu0rtrP.js +1 -0
  40. package/payload/server/public/assets/page-BNM63zsb.js +50 -0
  41. package/payload/server/public/assets/page-DM19J3ur.js +1 -0
  42. package/payload/server/public/assets/useAdminFetch-iYCQ9lT0.js +1 -0
  43. package/payload/server/public/data.html +3 -3
  44. package/payload/server/public/graph.html +3 -3
  45. package/payload/server/public/index.html +4 -4
  46. package/payload/server/server.js +39 -18
  47. package/payload/server/public/assets/admin-D8wbpnrW.js +0 -352
  48. package/payload/server/public/assets/data-BhrQjgR5.js +0 -1
  49. package/payload/server/public/assets/graph-Jj7seS-w.js +0 -1
  50. package/payload/server/public/assets/page-DIG7s5Jp.js +0 -1
  51. package/payload/server/public/assets/page-sZb3wcOM.js +0 -50
  52. package/payload/server/public/assets/share-2-BndjMKeG.js +0 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rubytech/create-maxy",
3
- "version": "1.0.795",
3
+ "version": "1.0.797",
4
4
  "description": "Install Maxy — AI for Productive People",
5
5
  "bin": {
6
6
  "create-maxy": "./dist/index.js"
@@ -0,0 +1,24 @@
1
+ // ============================================================
2
+ // Migration 003 — Person.name eradication (Task 849)
3
+ //
4
+ // Removes the denormalised `name` property from every Person node.
5
+ // `Person.name` is forbidden by schema-base.md "Forbidden Properties":
6
+ // the canonical fields are `givenName` + `familyName`, composed at
7
+ // read time by display-helpers.ts. Persisted `name` was a divergence
8
+ // trap — LLM extraction emitted `name = givenName` ("Dan") alongside
9
+ // the structured pair, so the canvas rendered "Dan" instead of
10
+ // "Dan Brett".
11
+ //
12
+ // Idempotent: subsequent runs find no Persons with `name` set and
13
+ // return removed=0.
14
+ //
15
+ // Applied at boot by platform/ui/app/lib/neo4j-migrations.ts. Safe to
16
+ // run manually:
17
+ // cypher-shell -u neo4j -p <password> -a $NEO4J_URI \
18
+ // -f platform/neo4j/migrations/003-person-name-eradicate.cypher
19
+ // ============================================================
20
+
21
+ MATCH (p:Person)
22
+ WHERE p.name IS NOT NULL
23
+ REMOVE p.name
24
+ RETURN count(p) AS removed
@@ -51,6 +51,10 @@ Platform management tools for both the admin and public agents. The `plugin-read
51
51
 
52
52
  Tools are available via the `admin` MCP server.
53
53
 
54
+ **Three-store admin auth invariant (Task 850).** `admin-add` writes to all three identity stores (`users.json` PIN auth, `account.json` `admins[]` role, Neo4j `:AdminUser`/`:Person` graph identity) with per-leg `[admin-auth-store]` log lines and returns `is_error: true` on any leg failure naming what's already written. `admin-update-pin` writes `users.json` only and emits the same line. Direct `Edit`/`Write` on `account.json` is blocked at the `pre-tool-use` hook — mutations go through `account-update`, `plugin-toggle-enabled`, or the `admin-*` tools. See `.docs/agents.md` § "Three-store admin auth invariant" for the full contract.
55
+
56
+ `logs-read { type: "agent-stream" }` (Task 850) is the canonical name for the per-conversation tool-use/tool-result archive previously called `system`; both names work and the legacy alias is preserved.
57
+
54
58
  ## Skills
55
59
 
56
60
  | Task | When to use | Reference |
@@ -47,11 +47,15 @@ if [ "$AGENT_TYPE" = "admin" ]; then
47
47
  echo "[entitlement] tool-deny: tool=${TOOL_NAME} path=${FILE_PATH} field=entitlement-file" >&2
48
48
  exit 2
49
49
  ;;
50
- # account.json (Task 831) — agent must use the account-update MCP tool
51
- # (or plugin-toggle-enabled for enabledPlugins changes), which whitelists
52
- # editable fields server-side. Direct Edit/Write bypasses that whitelist;
53
- # deny unconditionally including cwd-relative paths.
54
- */data/accounts/*/account.json|*/config/accounts/*/account.json|data/accounts/*/account.json|config/accounts/*/account.json|account.json)
50
+ # account.json (Task 831 + Task 850) — agent must use the account-update
51
+ # MCP tool (or plugin-toggle-enabled for enabledPlugins changes), which
52
+ # whitelists editable fields server-side. Direct Edit/Write bypasses
53
+ # that whitelist; deny unconditionally including cwd-relative paths.
54
+ # Task 850 adds */account.json and *account.json as a backstop so any
55
+ # layout the named patterns miss is still caught — the Adam Mackay
56
+ # incident showed a tier upgrade via raw Edit on account.json reach
57
+ # the disk, exactly the failure mode this hook exists to prevent.
58
+ */data/accounts/*/account.json|*/config/accounts/*/account.json|data/accounts/*/account.json|config/accounts/*/account.json|*/account.json|*account.json|account.json)
55
59
  echo "Blocked: Admin agent cannot edit account.json directly. Use the account-update or plugin-toggle-enabled MCP tools — they whitelist editable fields server-side and exclude tier and purchasedPlugins by design." >&2
56
60
  echo "[entitlement] tool-deny: tool=${TOOL_NAME} path=${FILE_PATH} field=account-json" >&2
57
61
  exit 2
@@ -621,7 +621,7 @@ server.tool("plugin-toggle-enabled", "Enable or disable a plugin in this account
621
621
  // ===================================================================
622
622
  // Admin user management tools
623
623
  // ===================================================================
624
- server.tool("admin-add", "Add a new admin user to this account. Creates a device-level user entry (users.json) and adds them to this account's admins list (account.json). PIN must be at least 4 digits. If no PIN is provided, a unique 4-digit PIN is generated. Returns the userId and PIN to share with the new admin.", {
624
+ server.tool("admin-add", "Add a new admin user to this account. Creates a device-level user entry (users.json) and adds them to this account's admins list (account.json). PIN must be at least 4 digits. If no PIN is provided, a unique 4-digit PIN is generated. Returns the userId and PIN to share with the new admin.\n\nIMPORTANT — retry behaviour: if the user already stated a specific PIN earlier in the conversation and a first admin-add call failed (e.g. tier cap reached, PIN collision), every retry MUST re-pass that PIN as the `pin` parameter. Omitting `pin` on the retry auto-generates a different 4-digit PIN, silently substituting what the user asked for.", {
625
625
  name: z.string().describe("Display name for the new admin (stored on the AdminUser node in Neo4j)."),
626
626
  pin: z.string().optional().describe("Optional PIN (minimum 4 digits). If omitted, a unique 4-digit PIN is generated."),
627
627
  }, async ({ name, pin: rawPin }) => {
@@ -679,14 +679,25 @@ server.tool("admin-add", "Add a new admin user to this account. Creates a device
679
679
  }
680
680
  const pinHash = hashPin(plaintextPin);
681
681
  const userId = crypto.randomUUID();
682
+ // Three-store admin auth invariant (Task 850): users.json (device-level
683
+ // PIN auth), account.json admins[] (account-level role), Neo4j AdminUser
684
+ // (display + graph identity). Each leg emits a [admin-auth-store] line so
685
+ // a future incident can grep one log to know which leg failed; any leg
686
+ // failing makes the tool result is_error: true with a cause line citing
687
+ // what's already been written. No automatic rollback — the cause line is
688
+ // the manual-recovery diagnostic.
689
+ const userIdShort = userId.slice(0, 8);
682
690
  // 1. Write to users.json (device-level). Auth fields only — `name` lives
683
691
  // on the AdminUser node in Neo4j (Task 829).
684
692
  users.push({ userId, pin: pinHash });
685
693
  try {
686
694
  writeUsersJson(users);
695
+ console.error(`[admin-auth-store] action=add userId=${userIdShort} result=ok store=users`);
687
696
  }
688
697
  catch (err) {
689
- return { content: [{ type: "text", text: `${TAG} Failed to write users.json: ${err instanceof Error ? err.message : String(err)}` }], isError: true };
698
+ const errMsg = err instanceof Error ? err.message : String(err);
699
+ console.error(`[admin-auth-store] action=add userId=${userIdShort} result=fail store=users error=${errMsg}`);
700
+ return { content: [{ type: "text", text: `${TAG} Failed to write users.json: ${errMsg}` }], isError: true };
690
701
  }
691
702
  // 2. Write to account.json (account-level)
692
703
  try {
@@ -698,10 +709,12 @@ server.tool("admin-add", "Add a new admin user to this account. Creates a device
698
709
  const configPath = join(getAccountDir(), "account.json");
699
710
  await writeFile(configPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
700
711
  }
712
+ console.error(`[admin-auth-store] action=add userId=${userIdShort} result=ok store=account`);
701
713
  }
702
714
  catch (err) {
703
- console.error(`${TAG} account.json write failed: ${err instanceof Error ? err.message : String(err)}`);
704
- return { content: [{ type: "text", text: `${TAG} User created in users.json but failed to add to account: ${err instanceof Error ? err.message : String(err)}` }], isError: true };
715
+ const errMsg = err instanceof Error ? err.message : String(err);
716
+ console.error(`[admin-auth-store] action=add userId=${userIdShort} result=fail store=account error=${errMsg}`);
717
+ return { content: [{ type: "text", text: `${TAG} users.json updated; account.json write FAILED — manual reconciliation needed: ${errMsg}` }], isError: true };
705
718
  }
706
719
  // 3. Write to Neo4j (graph-level): AdminUser + Person + OWNS atomically,
707
720
  // plus ADMIN_OF edge to the LocalBusiness for this account.
@@ -710,7 +723,12 @@ server.tool("admin-add", "Add a new admin user to this account. Creates a device
710
723
  // in platform/ui/app/lib/neo4j-store.ts (case-insensitive exact match
711
724
  // on givenName + familyName; partial-name ambiguity does NOT match —
712
725
  // rationalisation is a separate agent-mediated concern).
713
- let neo4jWarning = "";
726
+ // Task 850 Neo4j-leg failure now returns is_error: true with the
727
+ // [admin-auth-store] line; previously it set a soft warning string and
728
+ // returned success, which is what hid the Adam Mackay incident from
729
+ // the recovery agent. The user is still functional via users.json +
730
+ // account.json, but the graph state is divergent and the operator
731
+ // must know.
714
732
  let personReused = false;
715
733
  try {
716
734
  const session = getSession();
@@ -759,18 +777,25 @@ server.tool("admin-add", "Add a new admin user to this account. Creates a device
759
777
  finally {
760
778
  await session.close();
761
779
  }
780
+ console.error(`[admin-auth-store] action=add userId=${userIdShort} result=ok store=neo4j personReused=${personReused}`);
762
781
  }
763
782
  catch (err) {
764
783
  const errMsg = err instanceof Error ? err.message : String(err);
765
- console.error(`${TAG} Neo4j sync failed during admin-add: userId=${userId} error=${errMsg} — files written, graph pending`);
766
- neo4jWarning = ` Note: Neo4j sync failed (${errMsg}) — the admin user is functional but the graph will need reconciliation on next seed.`;
784
+ console.error(`[admin-auth-store] action=add userId=${userIdShort} result=fail store=neo4j error=${errMsg}`);
785
+ return {
786
+ content: [{
787
+ type: "text",
788
+ text: `${TAG} users.json + account.json updated for userId ${userId} (PIN: ${plaintextPin}); Neo4j sync FAILED — manual reconciliation needed: ${errMsg}`,
789
+ }],
790
+ isError: true,
791
+ };
767
792
  }
768
- console.error(`${TAG} [admin-identity] adminuser-bound userId=${userId.slice(0, 8)} name=${name.trim()} personReused=${personReused}`);
793
+ console.error(`${TAG} [admin-identity] adminuser-bound userId=${userIdShort} name=${name.trim()} personReused=${personReused}`);
769
794
  console.error(`${TAG} admin added: userId=${userId} userName=${name.trim()} accountId=${ACCOUNT_ID} role=admin addedBy=${callerUserId ?? "unknown"}`);
770
795
  return {
771
796
  content: [{
772
797
  type: "text",
773
- text: `Admin added successfully.\n\n- **Name:** ${name.trim()}\n- **userId:** ${userId}\n- **PIN:** ${plaintextPin}\n- **Role:** admin\n\nShare the PIN with ${name.trim()} so they can log in.${neo4jWarning}`,
798
+ text: `Admin added successfully.\n\n- **Name:** ${name.trim()}\n- **userId:** ${userId}\n- **PIN:** ${plaintextPin}\n- **Role:** admin\n\nShare the PIN with ${name.trim()} so they can log in.`,
774
799
  }],
775
800
  };
776
801
  });
@@ -912,18 +937,22 @@ server.tool("admin-update-pin", "Update an existing admin user's PIN. Defaults t
912
937
  users = readUsersJson();
913
938
  }
914
939
  catch (err) {
940
+ const errMsg = err instanceof Error ? err.message : String(err);
915
941
  console.error(`${TAG} userId=${userIdLabel} result=user-not-found reason=users-json-read-failed`);
916
- return { content: [{ type: "text", text: `${TAG} ${err instanceof Error ? err.message : String(err)}` }], isError: true };
942
+ console.error(`[admin-auth-store] action=update-pin userId=${userIdLabel} result=fail store=users error=${errMsg}`);
943
+ return { content: [{ type: "text", text: `${TAG} ${errMsg}` }], isError: true };
917
944
  }
918
945
  const targetIndex = users.findIndex(u => u.userId === userId);
919
946
  if (targetIndex === -1) {
920
947
  console.error(`${TAG} userId=${userIdLabel} result=user-not-found`);
948
+ console.error(`[admin-auth-store] action=update-pin userId=${userIdLabel} result=fail store=users error=user-not-found`);
921
949
  return { content: [{ type: "text", text: `${TAG} User ${userId} not found in users.json.` }], isError: true };
922
950
  }
923
951
  const newHash = hashPin(newPin);
924
952
  const collidesWithOther = users.some((u, i) => i !== targetIndex && u.pin === newHash);
925
953
  if (collidesWithOther) {
926
954
  console.error(`${TAG} userId=${userIdLabel} result=collision`);
955
+ console.error(`[admin-auth-store] action=update-pin userId=${userIdLabel} result=fail store=users error=pin-collision`);
927
956
  return { content: [{ type: "text", text: `${TAG} That PIN is already in use by another user. Choose a different PIN.` }], isError: true };
928
957
  }
929
958
  users[targetIndex].pin = newHash;
@@ -931,9 +960,12 @@ server.tool("admin-update-pin", "Update an existing admin user's PIN. Defaults t
931
960
  writeUsersJson(users);
932
961
  }
933
962
  catch (err) {
934
- return { content: [{ type: "text", text: `${TAG} Failed to write users.json: ${err instanceof Error ? err.message : String(err)}` }], isError: true };
963
+ const errMsg = err instanceof Error ? err.message : String(err);
964
+ console.error(`[admin-auth-store] action=update-pin userId=${userIdLabel} result=fail store=users error=${errMsg}`);
965
+ return { content: [{ type: "text", text: `${TAG} Failed to write users.json: ${errMsg}` }], isError: true };
935
966
  }
936
967
  console.error(`${TAG} userId=${userIdLabel} result=ok`);
968
+ console.error(`[admin-auth-store] action=update-pin userId=${userIdLabel} result=ok store=users`);
937
969
  const self = userId === callerUserId;
938
970
  return {
939
971
  content: [{ type: "text", text: `PIN updated${self ? "" : ` for userId ${userId}`}. The new PIN takes effect on the next login.` }],
@@ -1147,8 +1179,8 @@ server.tool("agent-list", "List all public (non-admin) agents with their full co
1147
1179
  };
1148
1180
  }
1149
1181
  });
1150
- server.tool("logs-read", "Read recent logs. Task 532: the stream logs (type=system/error/session/public) are now per-conversation — pass `conversationId` to retrieve a single conversation's log from first [spawn] to final [process-exit]. type=system: raw Claude stream-json + agent events + [tool-wait]/[tool-wait-diag]/[tool-wait-proc] telemetry + MCP server stderr via tee. type=session: SSE events sent to client. type=error: Claude subprocess stderr (raw — NODE_DEBUG HTTP/NET/UNDICI traces land in system via the stream tee, not here). type=heartbeat: platform event dispatcher (check-due-events cron). type=public: public agent diagnostic log. type=server: platform server log. type=mcp: MCP server stderr (per-plugin raw). type=vnc: VNC browser viewer lifecycle. type=review: log-review detector decisions. sessionKey: grep legacy sessionKey-tagged lines across all logs (useful for pre-Task-532 artefacts). When conversationId is provided, reads the single per-conversation file for the requested type (or dumps all type files for that conversationId if type is omitted).", {
1151
- type: z.enum(["system", "session", "error", "heartbeat", "public", "server", "mcp", "vnc", "review"]).optional(),
1182
+ server.tool("logs-read", "Read recent logs. Task 532: the stream logs (type=agent-stream/error/session/public) are now per-conversation — pass `conversationId` to retrieve a single conversation's log from first [spawn] to final [process-exit]. type=agent-stream: per-conversation tool-use/tool-result archive (every `[tool-use]` and `[tool-result]` pair with full input + output JSON, plus raw Claude stream-json, agent events, and MCP server stderr via tee). USE THIS when investigating what an agent ACTUALLY did with its tools — server.log only carries `[persist] tool-call persisted` markers, not bodies. (`type=system` is a backwards-compatible alias for the same archive.) type=session: SSE events sent to client. type=error: Claude subprocess stderr (raw — NODE_DEBUG HTTP/NET/UNDICI traces land in agent-stream via the stream tee, not here). type=heartbeat: platform event dispatcher (check-due-events cron). type=public: public agent diagnostic log. type=server: platform server log. type=mcp: MCP server stderr (per-plugin raw). type=vnc: VNC browser viewer lifecycle. type=review: log-review detector decisions. sessionKey: grep legacy sessionKey-tagged lines across all logs (useful for pre-Task-532 artefacts). When conversationId is provided, reads the single per-conversation file for the requested type (or dumps all type files for that conversationId if type is omitted).", {
1183
+ type: z.enum(["agent-stream", "system", "session", "error", "heartbeat", "public", "server", "mcp", "vnc", "review"]).optional(),
1152
1184
  lines: z.number().optional(),
1153
1185
  sessionKey: z.string().optional(),
1154
1186
  conversationId: z.string().optional(),
@@ -1181,16 +1213,17 @@ server.tool("logs-read", "Read recent logs. Task 532: the stream logs (type=syst
1181
1213
  return { content: [{ type: "text", text: `Log directory does not exist: ${LOG_DIR}` }] };
1182
1214
  }
1183
1215
  const prefixMap = {
1184
- system: "claude-agent-stream",
1216
+ "agent-stream": "claude-agent-stream",
1217
+ system: "claude-agent-stream", // Task 850 — backwards-compatible alias for agent-stream
1185
1218
  error: "claude-agent-stderr",
1186
1219
  session: "sse-events",
1187
1220
  public: "public-agent-stream",
1188
1221
  };
1189
- const resolvedType = type ?? "system";
1222
+ const resolvedType = type ?? "agent-stream";
1190
1223
  const prefix = prefixMap[resolvedType];
1191
1224
  if (!prefix) {
1192
1225
  return {
1193
- content: [{ type: "text", text: `type=${resolvedType} is not per-conversation. Valid per-conversation types: system, error, session, public. For platform-scoped types (server, vnc, review, heartbeat, mcp) omit conversationId.` }],
1226
+ content: [{ type: "text", text: `type=${resolvedType} is not per-conversation. Valid per-conversation types: agent-stream, error, session, public. For platform-scoped types (server, vnc, review, heartbeat, mcp) omit conversationId.` }],
1194
1227
  isError: true,
1195
1228
  };
1196
1229
  }
@@ -1234,7 +1267,8 @@ server.tool("logs-read", "Read recent logs. Task 532: the stream logs (type=syst
1234
1267
  // --- Session-key filtered mode: grep across log files ---
1235
1268
  if (sessionKey) {
1236
1269
  const prefixes = {
1237
- system: "claude-agent-stream-",
1270
+ "agent-stream": "claude-agent-stream-",
1271
+ system: "claude-agent-stream-", // Task 850 — backwards-compatible alias
1238
1272
  error: "claude-agent-stderr-",
1239
1273
  session: "sse-events-",
1240
1274
  public: "public-agent-stream-",
@@ -1332,7 +1366,7 @@ server.tool("logs-read", "Read recent logs. Task 532: the stream logs (type=syst
1332
1366
  return { content: [{ type: "text", text: `# Session timeline: ${sessionKey}\n\n${sections.join("\n\n")}` }] };
1333
1367
  }
1334
1368
  // --- Standard mode: tail most recent file of the requested type ---
1335
- const resolvedType = type ?? "system";
1369
+ const resolvedType = type ?? "agent-stream";
1336
1370
  // Heartbeat log is a single fixed file, not prefix-based
1337
1371
  if (resolvedType === "heartbeat") {
1338
1372
  const logFile = resolve(LOG_DIR, "check-due-events.log");
@@ -1381,6 +1415,8 @@ server.tool("logs-read", "Read recent logs. Task 532: the stream logs (type=syst
1381
1415
  }).toString();
1382
1416
  return { content: [{ type: "text", text: `# review.log\n\n${result}` }] };
1383
1417
  }
1418
+ // Task 850 — agent-stream and the legacy system alias both map to
1419
+ // claude-agent-stream-. The fall-through default also covers them.
1384
1420
  const prefix = resolvedType === "error" ? "claude-agent-stderr-"
1385
1421
  : resolvedType === "session" ? "sse-events-"
1386
1422
  : resolvedType === "public" ? "public-agent-stream-"