engrm 0.4.13 → 0.4.14

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.
@@ -1154,7 +1154,7 @@ import { existsSync as existsSync3, readFileSync as readFileSync2, writeFileSync
1154
1154
  import { join as join3 } from "node:path";
1155
1155
  import { homedir } from "node:os";
1156
1156
  var STATE_PATH = join3(homedir(), ".engrm", "config-fingerprint.json");
1157
- var CLIENT_VERSION = "0.4.13";
1157
+ var CLIENT_VERSION = "0.4.14";
1158
1158
  function hashFile(filePath) {
1159
1159
  try {
1160
1160
  if (!existsSync3(filePath))
@@ -3147,6 +3147,20 @@ function formatSplashScreen(data) {
3147
3147
  lines.push(` ${line}`);
3148
3148
  }
3149
3149
  }
3150
+ const legend = formatLegend();
3151
+ if (legend.length > 0) {
3152
+ lines.push("");
3153
+ for (const line of legend) {
3154
+ lines.push(` ${line}`);
3155
+ }
3156
+ }
3157
+ const contextIndex = formatContextIndex(data.context);
3158
+ if (contextIndex.length > 0) {
3159
+ lines.push("");
3160
+ for (const line of contextIndex) {
3161
+ lines.push(` ${line}`);
3162
+ }
3163
+ }
3150
3164
  const inspectHints = formatInspectHints(data.context);
3151
3165
  if (inspectHints.length > 0) {
3152
3166
  lines.push("");
@@ -3271,10 +3285,31 @@ function formatContextEconomics(data) {
3271
3285
  if (data.estimatedReadTokens > 0) {
3272
3286
  parts.push(`read now ~${data.estimatedReadTokens.toLocaleString()}t`);
3273
3287
  }
3288
+ if (data.context.observations.length > 0) {
3289
+ parts.push(`${data.context.observations.length} observations loaded`);
3290
+ }
3274
3291
  if (parts.length === 0)
3275
3292
  return [];
3276
3293
  return [`${c2.dim}Context economics:${c2.reset} ${parts.join(" \xB7 ")}`];
3277
3294
  }
3295
+ function formatLegend() {
3296
+ return [
3297
+ `${c2.dim}Legend:${c2.reset} #id | \uD83D\uDD34 bugfix | \uD83D\uDFE3 feature | \uD83D\uDD04 refactor | \u2705 change | \uD83D\uDD35 discovery | \u2696\uFE0F decision`
3298
+ ];
3299
+ }
3300
+ function formatContextIndex(context) {
3301
+ const rows = context.observations.filter((obs) => obs.type !== "digest").slice(0, 6).map((obs) => {
3302
+ const icon = observationIcon(obs.type);
3303
+ const fileHint = extractPrimaryFileHint(obs);
3304
+ return `${icon} #${obs.id} ${truncateInline(obs.title, 110)}${fileHint ? ` ${c2.dim}(${fileHint})${c2.reset}` : ""}`;
3305
+ });
3306
+ if (rows.length === 0)
3307
+ return [];
3308
+ return [
3309
+ `${c2.dim}Context index:${c2.reset} use IDs to fetch deeper detail when needed`,
3310
+ ...rows
3311
+ ];
3312
+ }
3278
3313
  function formatInspectHints(context) {
3279
3314
  const hints = [];
3280
3315
  if ((context.recentSessions?.length ?? 0) > 0) {
@@ -3290,7 +3325,12 @@ function formatInspectHints(context) {
3290
3325
  const unique = Array.from(new Set(hints)).slice(0, 4);
3291
3326
  if (unique.length === 0)
3292
3327
  return [];
3293
- return [`${c2.dim}Inspect:${c2.reset} ${unique.join(" \xB7 ")}`];
3328
+ const ids = context.observations.slice(0, 5).map((obs) => obs.id);
3329
+ const fetchHint = ids.length > 0 ? `get_observations([${ids.join(", ")}])` : null;
3330
+ return [
3331
+ `${c2.dim}Inspect:${c2.reset} ${unique.join(" \xB7 ")}`,
3332
+ ...fetchHint ? [`${c2.dim}Fetch by ID:${c2.reset} ${fetchHint}`] : []
3333
+ ];
3294
3334
  }
3295
3335
  function rememberShownItem(shown, value) {
3296
3336
  if (!value)
@@ -3415,6 +3455,39 @@ function buildProjectSignalLine(context) {
3415
3455
  const top = Object.entries(context.projectTypeCounts).sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0])).slice(0, 4).map(([type, count]) => `${type} ${count}`).join("; ");
3416
3456
  return top || null;
3417
3457
  }
3458
+ function observationIcon(type) {
3459
+ switch (type) {
3460
+ case "bugfix":
3461
+ return "\uD83D\uDD34";
3462
+ case "feature":
3463
+ return "\uD83D\uDFE3";
3464
+ case "refactor":
3465
+ return "\uD83D\uDD04";
3466
+ case "change":
3467
+ return "\u2705";
3468
+ case "discovery":
3469
+ return "\uD83D\uDD35";
3470
+ case "decision":
3471
+ return "\u2696\uFE0F";
3472
+ default:
3473
+ return "\u2022";
3474
+ }
3475
+ }
3476
+ function extractPrimaryFileHint(obs) {
3477
+ const firstRead = parseJsonArraySafe(obs.files_read)[0];
3478
+ const firstModified = parseJsonArraySafe(obs.files_modified)[0];
3479
+ return firstModified ?? firstRead ?? null;
3480
+ }
3481
+ function parseJsonArraySafe(value) {
3482
+ if (!value)
3483
+ return [];
3484
+ try {
3485
+ const parsed = JSON.parse(value);
3486
+ return Array.isArray(parsed) ? parsed.filter((item) => typeof item === "string" && item.trim().length > 0) : [];
3487
+ } catch {
3488
+ return [];
3489
+ }
3490
+ }
3418
3491
  function toSplashLines(value, maxItems) {
3419
3492
  if (!value)
3420
3493
  return [];
@@ -2535,7 +2535,7 @@ function buildBeacon(db, config, sessionId, metrics) {
2535
2535
  sentinel_used: valueSignals.security_findings_count > 0,
2536
2536
  risk_score: riskScore,
2537
2537
  stacks_detected: stacks,
2538
- client_version: "0.4.13",
2538
+ client_version: "0.4.14",
2539
2539
  context_observations_injected: metrics?.contextObsInjected ?? 0,
2540
2540
  context_total_available: metrics?.contextTotalAvailable ?? 0,
2541
2541
  recall_attempts: metrics?.recallAttempts ?? 0,
package/dist/server.js CHANGED
@@ -19764,7 +19764,7 @@ process.on("SIGTERM", () => {
19764
19764
  });
19765
19765
  var server = new McpServer({
19766
19766
  name: "engrm",
19767
- version: "0.4.13"
19767
+ version: "0.4.14"
19768
19768
  });
19769
19769
  server.tool("save_observation", "Save an observation to memory", {
19770
19770
  type: exports_external.enum([
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "engrm",
3
- "version": "0.4.13",
3
+ "version": "0.4.14",
4
4
  "description": "Shared memory across devices, sessions, and coding agents",
5
5
  "mcpName": "io.github.dr12hes/engrm",
6
6
  "type": "module",