@rubytech/create-maxy 1.0.884 → 1.0.886

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rubytech/create-maxy",
3
- "version": "1.0.884",
3
+ "version": "1.0.886",
4
4
  "description": "Install Maxy — AI for Productive People",
5
5
  "bin": {
6
6
  "create-maxy": "./dist/index.js"
@@ -498,9 +498,16 @@ OPTIONS {
498
498
  CREATE CONSTRAINT message_id_unique IF NOT EXISTS
499
499
  FOR (m:Message) REQUIRE m.messageId IS UNIQUE;
500
500
 
501
+ // Task 1007 — Message.sessionKey is the canonical conversation pointer.
502
+ // The legacy m.conversationId index stays until follow-up Task 1011 (final
503
+ // cutover, after the full code-rename slice lands and no path reads
504
+ // m.conversationId).
501
505
  CREATE INDEX message_conversation IF NOT EXISTS
502
506
  FOR (m:Message) ON (m.conversationId);
503
507
 
508
+ CREATE INDEX message_session_key IF NOT EXISTS
509
+ FOR (m:Message) ON (m.sessionKey);
510
+
504
511
  CREATE VECTOR INDEX message_embedding IF NOT EXISTS
505
512
  FOR (m:Message) ON (m.embedding)
506
513
  OPTIONS {
@@ -52,7 +52,7 @@ Tools are available via the `admin` MCP server.
52
52
 
53
53
  `logs-read { type: "agent-stream" }` 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.
54
54
 
55
- **Stream log is the primary diagnostic surface for an in-progress conversation.** The parent-process console fan-out tee in [`platform/ui/app/lib/claude-agent/logging.ts`](../../ui/app/lib/claude-agent/logging.ts) appends every `[<tag>]`-prefixed `console.error` / `console.log` line to every active conversation's stream log alongside `server.log`. For diagnosing an in-conversation issue (WhatsApp inbound, Cloudflare action, persist write, baileys error), call `logs-read { type: "agent-stream" }` first — the stream log carries both the agent lifecycle AND the parent-process events that occurred during the session window. `logs-read { type: "server" }` becomes the cross-session escape hatch (filtering across conversations or for events outside any session window), not the default.
55
+ **Stream log is the primary diagnostic surface for an in-progress session.** Every stream log is named by sessionKey and exists from the first token. The parent-process console fan-out tee in [`platform/ui/app/lib/claude-agent/logging.ts`](../../ui/app/lib/claude-agent/logging.ts) appends every `[<tag>]`-prefixed `console.error` / `console.log` line to every active session's stream log alongside `server.log`. For diagnosing an in-session issue (WhatsApp inbound, Cloudflare action, persist write, baileys error), call `logs-read { sessionKey: "<…>" }` first — the stream log carries both the agent lifecycle AND the parent-process events that occurred during the session window. The `conversationId` parameter remains a legacy alias resolving to the same sessionKey-named file. `logs-read { type: "server" }` is the cross-session escape hatch for events outside any single session window.
56
56
 
57
57
  ## Skills
58
58
 
@@ -1255,7 +1255,7 @@ server.tool("agent-list", "List all public (non-admin) agents with their full co
1255
1255
  };
1256
1256
  }
1257
1257
  });
1258
- eagerTool(server, "logs-read", "Read recent logs. Stream logs (type=agent-stream/error/session/public) are 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. sessionKey: grep legacy sessionKey-tagged lines across all logs (useful for pre-per-conversation 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).", {
1258
+ eagerTool(server, "logs-read", "Read recent logs. Stream logs (type=agent-stream/error/session/public) are per-session — pass `sessionKey` (preferred) or the legacy `conversationId` alias to retrieve a single session's log from first [spawn] to final [process-exit]. type=agent-stream: per-session 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.", {
1259
1259
  type: z.enum(["agent-stream", "system", "session", "error", "heartbeat", "public", "server", "mcp", "vnc"]).optional(),
1260
1260
  lines: z.number().optional(),
1261
1261
  sessionKey: z.string().optional(),
@@ -1263,28 +1263,11 @@ eagerTool(server, "logs-read", "Read recent logs. Stream logs (type=agent-stream
1263
1263
  }, async ({ type, lines = 50, sessionKey, conversationId }) => {
1264
1264
  try {
1265
1265
  const LOG_DIR = resolve(getAccountDir(), "logs");
1266
- // Task 532: conversationId mode reads the exact per-conversation file.
1267
- // Precedes the sessionKey grep path because a conversationId is the
1268
- // tightest identity and answers single-conversation questions without
1269
- // a grep pass across every log file.
1270
- //
1271
- // Task 671: resolves two filename shapes from the same identifier —
1272
- // FULL: {prefix}-{conversationId}.log (post first-completed-turn flush)
1273
- // PREFLUSH: {prefix}-preflush-{id:0:12}.log (pre-flush, first turn;
1274
- // slice is of the sessionKey)
1275
- // Full is tried first; if absent, preflush is the fallback. If both
1276
- // exist, full wins and the preflush sibling is logged to server.log
1277
- // as stale (best-effort housekeeping signal).
1278
- //
1279
- // Identity note: for the abrupt-exit case this branch exists to solve,
1280
- // the operator passes the sessionKey (no conversationId was ever
1281
- // assigned). For post-flush retrievals the operator passes the
1282
- // conversationId and the FULL file is expected to exist.
1283
- //
1284
- // MIRROR: keep the two-shape contract in sync with:
1285
- // - platform/ui/app/lib/logs-read-resolve.ts (canonical TS helper + tests)
1286
- // - platform/scripts/logs-read.sh (per_conversation_mode)
1287
- if (conversationId) {
1266
+ // Task 1006 sessionKey is the single identifier on disk.
1267
+ // `conversationId` is retained as a legacy alias that maps to the
1268
+ // sessionKey-named file; Task 1007 will collapse the alias in the UI.
1269
+ const idForResolve = sessionKey ?? conversationId;
1270
+ if (idForResolve) {
1288
1271
  if (!existsSync(LOG_DIR)) {
1289
1272
  return { content: [{ type: "text", text: `Log directory does not exist: ${LOG_DIR}` }] };
1290
1273
  }
@@ -1299,41 +1282,29 @@ eagerTool(server, "logs-read", "Read recent logs. Stream logs (type=agent-stream
1299
1282
  const prefix = prefixMap[resolvedType];
1300
1283
  if (!prefix) {
1301
1284
  return {
1302
- 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, heartbeat, mcp) omit conversationId.` }],
1285
+ content: [{ type: "text", text: `type=${resolvedType} is not per-session. Valid per-session types: agent-stream, error, session, public. For platform-scoped types (server, vnc, heartbeat, mcp) omit the id.` }],
1303
1286
  isError: true,
1304
1287
  };
1305
1288
  }
1306
- const fullName = `${prefix}-${conversationId}.log`;
1307
- const preflushName = `${prefix}-preflush-${conversationId.slice(0, 12)}.log`;
1308
- const fullPath = resolve(LOG_DIR, fullName);
1309
- const preflushPath = resolve(LOG_DIR, preflushName);
1310
- // Pass 1: full first. If present, emit stale-preflush signal on sibling.
1311
- if (existsSync(fullPath)) {
1312
- if (existsSync(preflushPath)) {
1313
- // Best-effort housekeeping emit retrieval must not fail if
1314
- // server.log is unwritable.
1315
- try {
1316
- const ts = new Date().toISOString();
1317
- appendFileSync(resolve(CONFIG_DIR, "logs", "server.log"), `${ts} [logs-read] stale-preflush-detected path=${preflushPath}\n`);
1318
- }
1319
- catch {
1320
- // swallow
1321
- }
1322
- }
1323
- const result = execFileSync("tail", ["-n", String(lines), fullPath], { timeout: 5000 }).toString();
1324
- return { content: [{ type: "text", text: `# ${fullName} (matched_shape=full)\n\n${result}` }] };
1289
+ const fileName = `${prefix}-${idForResolve}.log`;
1290
+ const filePath = resolve(LOG_DIR, fileName);
1291
+ if (existsSync(filePath)) {
1292
+ const result = execFileSync("tail", ["-n", String(lines), filePath], { timeout: 5000 }).toString();
1293
+ return { content: [{ type: "text", text: `# ${fileName}\n\n${result}` }] };
1294
+ }
1295
+ // Emit missing-on-resolve so the writer-side existence contract is
1296
+ // the authoritative signal. One such line on any device is a P0.
1297
+ try {
1298
+ const ts = new Date().toISOString();
1299
+ appendFileSync(resolve(CONFIG_DIR, "logs", "server.log"), `${ts} [log-tee] missing-on-resolve sessionKey=${idForResolve.slice(0, 8)} surface=mcp-logs-read reason="file-not-found-in-LOG_DIR"\n`);
1325
1300
  }
1326
- // Pass 2: preflush fallback.
1327
- if (existsSync(preflushPath)) {
1328
- const result = execFileSync("tail", ["-n", String(lines), preflushPath], { timeout: 5000 }).toString();
1329
- return { content: [{ type: "text", text: `# ${preflushName} (matched_shape=preflush)\n\n${result}` }] };
1301
+ catch {
1302
+ // best-effort
1330
1303
  }
1331
- // Neither shape present: enumerate both filenames in the miss
1332
- // message so the reader sees exactly what was tried.
1333
1304
  return {
1334
1305
  content: [{
1335
1306
  type: "text",
1336
- text: `No log file found for conversationId=${conversationId} type=${resolvedType}. tried=[${fullPath}, ${preflushPath}] reason=file-not-found-in-either-shape`,
1307
+ text: `No log file found for id=${idForResolve} type=${resolvedType}. tried=[${filePath}] reason=file-not-found`,
1337
1308
  }],
1338
1309
  };
1339
1310
  }