memory-journal-mcp 7.1.0 → 7.2.0

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 (124) hide show
  1. package/README.md +59 -51
  2. package/dist/{chunk-GW5DYUQJ.js → chunk-GR4T3SRW.js} +139 -100
  3. package/dist/{chunk-37BQOJDZ.js → chunk-IWKLHSPU.js} +81 -2
  4. package/dist/{chunk-JEGRDY6W.js → chunk-ORV7ZZOE.js} +357 -51
  5. package/dist/cli.js +30 -4
  6. package/dist/github-integration-2TFMXHIJ.js +1 -0
  7. package/dist/index.d.ts +5 -1
  8. package/dist/index.js +3 -3
  9. package/dist/{tools-O44Q52RD.js → tools-CXR2FEB2.js} +2 -2
  10. package/package.json +1 -1
  11. package/skills/README.md +77 -0
  12. package/skills/autonomous-dev/SKILL.md +56 -0
  13. package/skills/bin/sync.js +50 -0
  14. package/skills/bun/SKILL.md +156 -0
  15. package/skills/github-commander/SKILL.md +1 -1
  16. package/skills/github-commander/workflows/code-quality-audit.md +7 -5
  17. package/skills/github-commander/workflows/issue-triage.md +13 -4
  18. package/skills/github-commander/workflows/milestone-sprint.md +9 -1
  19. package/skills/github-commander/workflows/perf-audit.md +2 -0
  20. package/skills/github-commander/workflows/pr-review.md +9 -3
  21. package/skills/github-commander/workflows/roadmap-kickoff.md +79 -0
  22. package/skills/github-commander/workflows/security-audit.md +3 -3
  23. package/skills/github-commander/workflows/update-deps.md +2 -2
  24. package/skills/gitlab/SKILL.md +115 -0
  25. package/skills/gitlab/package-lock.json +392 -0
  26. package/skills/gitlab/package.json +14 -0
  27. package/skills/gitlab/scripts/gitlab-client.ts +125 -0
  28. package/skills/gitlab/scripts/gitlab-helper.ts +80 -0
  29. package/skills/golang/SKILL.md +54 -0
  30. package/skills/mysql/SKILL.md +30 -0
  31. package/skills/package.json +48 -0
  32. package/skills/playwright-standard/SKILL.md +58 -0
  33. package/skills/playwright-standard/examples/fixtures.ts +66 -0
  34. package/skills/playwright-standard/examples/type-stubs.d.ts +10 -0
  35. package/skills/playwright-standard/references/advanced-scenarios.md +59 -0
  36. package/skills/playwright-standard/references/infrastructure.md +43 -0
  37. package/skills/postgres/SKILL.md +33 -0
  38. package/skills/react-best-practices/AGENTS.md +2883 -0
  39. package/skills/react-best-practices/README.md +127 -0
  40. package/skills/react-best-practices/SKILL.md +138 -0
  41. package/skills/react-best-practices/metadata.json +17 -0
  42. package/skills/react-best-practices/rules/_sections.md +46 -0
  43. package/skills/react-best-practices/rules/_template.md +28 -0
  44. package/skills/react-best-practices/rules/advanced-event-handler-refs.md +55 -0
  45. package/skills/react-best-practices/rules/advanced-init-once.md +42 -0
  46. package/skills/react-best-practices/rules/advanced-use-latest.md +39 -0
  47. package/skills/react-best-practices/rules/async-api-routes.md +35 -0
  48. package/skills/react-best-practices/rules/async-defer-await.md +80 -0
  49. package/skills/react-best-practices/rules/async-dependencies.md +48 -0
  50. package/skills/react-best-practices/rules/async-parallel.md +24 -0
  51. package/skills/react-best-practices/rules/async-suspense-boundaries.md +99 -0
  52. package/skills/react-best-practices/rules/bundle-barrel-imports.md +59 -0
  53. package/skills/react-best-practices/rules/bundle-conditional.md +37 -0
  54. package/skills/react-best-practices/rules/bundle-defer-third-party.md +48 -0
  55. package/skills/react-best-practices/rules/bundle-dynamic-imports.md +34 -0
  56. package/skills/react-best-practices/rules/bundle-preload.md +44 -0
  57. package/skills/react-best-practices/rules/client-event-listeners.md +78 -0
  58. package/skills/react-best-practices/rules/client-localstorage-schema.md +74 -0
  59. package/skills/react-best-practices/rules/client-passive-event-listeners.md +48 -0
  60. package/skills/react-best-practices/rules/client-swr-dedup.md +56 -0
  61. package/skills/react-best-practices/rules/js-batch-dom-css.md +110 -0
  62. package/skills/react-best-practices/rules/js-cache-function-results.md +80 -0
  63. package/skills/react-best-practices/rules/js-cache-property-access.md +28 -0
  64. package/skills/react-best-practices/rules/js-cache-storage.md +68 -0
  65. package/skills/react-best-practices/rules/js-combine-iterations.md +32 -0
  66. package/skills/react-best-practices/rules/js-early-exit.md +50 -0
  67. package/skills/react-best-practices/rules/js-hoist-regexp.md +45 -0
  68. package/skills/react-best-practices/rules/js-index-maps.md +37 -0
  69. package/skills/react-best-practices/rules/js-length-check-first.md +50 -0
  70. package/skills/react-best-practices/rules/js-min-max-loop.md +82 -0
  71. package/skills/react-best-practices/rules/js-set-map-lookups.md +24 -0
  72. package/skills/react-best-practices/rules/js-tosorted-immutable.md +57 -0
  73. package/skills/react-best-practices/rules/rendering-activity.md +24 -0
  74. package/skills/react-best-practices/rules/rendering-animate-svg-wrapper.md +38 -0
  75. package/skills/react-best-practices/rules/rendering-conditional-render.md +32 -0
  76. package/skills/react-best-practices/rules/rendering-content-visibility.md +38 -0
  77. package/skills/react-best-practices/rules/rendering-hoist-jsx.md +36 -0
  78. package/skills/react-best-practices/rules/rendering-hydration-no-flicker.md +72 -0
  79. package/skills/react-best-practices/rules/rendering-hydration-suppress-warning.md +26 -0
  80. package/skills/react-best-practices/rules/rendering-svg-precision.md +28 -0
  81. package/skills/react-best-practices/rules/rendering-usetransition-loading.md +75 -0
  82. package/skills/react-best-practices/rules/rerender-defer-reads.md +39 -0
  83. package/skills/react-best-practices/rules/rerender-dependencies.md +45 -0
  84. package/skills/react-best-practices/rules/rerender-derived-state-no-effect.md +40 -0
  85. package/skills/react-best-practices/rules/rerender-derived-state.md +29 -0
  86. package/skills/react-best-practices/rules/rerender-functional-setstate.md +77 -0
  87. package/skills/react-best-practices/rules/rerender-lazy-state-init.md +56 -0
  88. package/skills/react-best-practices/rules/rerender-memo-with-default-value.md +36 -0
  89. package/skills/react-best-practices/rules/rerender-memo.md +44 -0
  90. package/skills/react-best-practices/rules/rerender-move-effect-to-event.md +45 -0
  91. package/skills/react-best-practices/rules/rerender-simple-expression-in-memo.md +35 -0
  92. package/skills/react-best-practices/rules/rerender-transitions.md +40 -0
  93. package/skills/react-best-practices/rules/rerender-use-ref-transient-values.md +73 -0
  94. package/skills/react-best-practices/rules/server-after-nonblocking.md +73 -0
  95. package/skills/react-best-practices/rules/server-auth-actions.md +96 -0
  96. package/skills/react-best-practices/rules/server-cache-lru.md +41 -0
  97. package/skills/react-best-practices/rules/server-cache-react.md +76 -0
  98. package/skills/react-best-practices/rules/server-dedup-props.md +65 -0
  99. package/skills/react-best-practices/rules/server-parallel-fetching.md +83 -0
  100. package/skills/react-best-practices/rules/server-serialization.md +38 -0
  101. package/skills/rust/SKILL.md +86 -0
  102. package/skills/shadcn-ui/SKILL.md +72 -0
  103. package/skills/skill-builder/SKILL.md +457 -0
  104. package/skills/skill-builder/checklist.md +65 -0
  105. package/skills/sqlite/SKILL.md +38 -0
  106. package/skills/typescript/SKILL.md +453 -0
  107. package/skills/typescript/assets/eslint-template.js +102 -0
  108. package/skills/typescript/assets/tsconfig-template.json +45 -0
  109. package/skills/typescript/references/enterprise-patterns.md +531 -0
  110. package/skills/typescript/references/generics.md +493 -0
  111. package/skills/typescript/references/nestjs-integration.md +579 -0
  112. package/skills/typescript/references/react-integration.md +616 -0
  113. package/skills/typescript/references/toolchain.md +547 -0
  114. package/skills/typescript/references/type-system.md +481 -0
  115. package/skills/vitest-standard/SKILL.md +82 -0
  116. package/skills/vitest-standard/examples/service-mock.ts +60 -0
  117. package/skills/vitest-standard/examples/tdd-calculator.ts +41 -0
  118. package/skills/vitest-standard/examples/type-stubs.d.ts +18 -0
  119. package/skills/vitest-standard/references/async-and-errors.md +58 -0
  120. package/skills/vitest-standard/references/coverage-and-config.md +53 -0
  121. package/skills/vitest-standard/references/mocking.md +61 -0
  122. package/skills/vitest-standard/references/tdd-patterns.md +60 -0
  123. package/dist/github-integration-FOJ4U6I5.js +0 -1
  124. package/skills/github-commander/workflows/full-audit.md +0 -134
@@ -1,5 +1,5 @@
1
- import { withSessionInit, withPriority, ASSISTANT_FOCUSED, TOOL_GROUPS, HIGH_PRIORITY, LOW_PRIORITY, MEDIUM_PRIORITY, setDefaultSandboxMode, initializeAuditLogger, parseToolFilter, getFilterSummary, getToolFilterFromEnv, getTools, getEnabledGroups, callTool, getGlobalAuditLogger, sendProgress, SUPPORTED_SCOPES, getRequiredScope, hasScope, getAuditResourceDef, execQuery, transformEntryRow, resolveGitHubRepo, isResourceError, milestoneCompletionPct, parseScopes, BASE_SCOPES, getAllToolNames, globalMetrics, DEFAULT_BRIEFING_CONFIG } from './chunk-JEGRDY6W.js';
2
- import { logger, GitHubIntegration, ConfigurationError, ResourceNotFoundError, ConnectionError, QueryError, assertNoPathTraversal, ValidationError, MemoryJournalMcpError, validateDateFormatPattern } from './chunk-37BQOJDZ.js';
1
+ import { withSessionInit, withPriority, ASSISTANT_FOCUSED, TOOL_GROUPS, HIGH_PRIORITY, LOW_PRIORITY, MEDIUM_PRIORITY, setDefaultSandboxMode, initializeAuditLogger, parseToolFilter, getFilterSummary, getToolFilterFromEnv, getTools, getEnabledGroups, callTool, getGlobalAuditLogger, sendProgress, SUPPORTED_SCOPES, getRequiredScope, hasScope, getAuditResourceDef, execQuery, transformEntryRow, resolveGitHubRepo, isResourceError, milestoneCompletionPct, parseScopes, BASE_SCOPES, getAllToolNames, globalMetrics, DEFAULT_BRIEFING_CONFIG } from './chunk-ORV7ZZOE.js';
2
+ import { logger, GitHubIntegration, ConfigurationError, ResourceNotFoundError, ConnectionError, QueryError, assertNoPathTraversal, ValidationError, MemoryJournalMcpError, validateDateFormatPattern } from './chunk-IWKLHSPU.js';
3
3
  import { createRequire } from 'module';
4
4
  import { McpServer, ResourceTemplate } from '@modelcontextprotocol/sdk/server/mcp.js';
5
5
  import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
@@ -1828,7 +1828,7 @@ async function buildGitHubSection(github, config) {
1828
1828
  const [ciStatus, issuesAndPrs, milestones, insights, copilotReviews] = await Promise.all([
1829
1829
  fetchCiStatus(github, owner, repo, config),
1830
1830
  fetchIssuesAndPrs(github, owner, repo, config),
1831
- fetchMilestones(github, owner, repo),
1831
+ fetchMilestones(github, owner, repo, config.milestoneCount ?? 3),
1832
1832
  fetchInsights(github, owner, repo),
1833
1833
  config.copilotReviews ? fetchCopilotReviews(github, owner, repo) : Promise.resolve(void 0)
1834
1834
  ]);
@@ -1959,9 +1959,10 @@ async function fetchIssuesAndPrs(github, owner, repo, config) {
1959
1959
  return { openIssues: 0, openPRs: 0 };
1960
1960
  }
1961
1961
  }
1962
- async function fetchMilestones(github, owner, repo) {
1962
+ async function fetchMilestones(github, owner, repo, limit) {
1963
+ if (limit <= 0) return [];
1963
1964
  try {
1964
- const msList = await github.getMilestones(owner, repo, "open", 3);
1965
+ const msList = await github.getMilestones(owner, repo, "open", limit);
1965
1966
  return msList.map((m) => {
1966
1967
  const pct = milestoneCompletionPct(m.openIssues, m.closedIssues);
1967
1968
  return {
@@ -2039,8 +2040,8 @@ async function fetchCopilotReviews(github, owner, repo) {
2039
2040
  }
2040
2041
  }
2041
2042
  var PREVIEW_LENGTH = 80;
2042
- function buildJournalContext(context, config) {
2043
- const recentEntries = context.db.getRecentEntries(config.entryCount);
2043
+ function buildJournalContext(context, config, projectNumber) {
2044
+ const recentEntries = typeof projectNumber === "number" ? context.db.searchEntries("", { limit: config.entryCount, projectNumber }) : context.db.getRecentEntries(config.entryCount);
2044
2045
  const latestEntries = recentEntries.map((e) => {
2045
2046
  const content = e.content ?? "";
2046
2047
  return {
@@ -2050,16 +2051,47 @@ function buildJournalContext(context, config) {
2050
2051
  preview: content.slice(0, PREVIEW_LENGTH) + (content.length > PREVIEW_LENGTH ? "..." : "")
2051
2052
  };
2052
2053
  });
2054
+ const summaryEntries = typeof projectNumber === "number" ? context.db.searchEntries("", {
2055
+ limit: config.summaryCount,
2056
+ projectNumber,
2057
+ tags: ["session-summary"]
2058
+ }) : context.db.searchEntries("", {
2059
+ limit: config.summaryCount,
2060
+ tags: ["session-summary"]
2061
+ });
2062
+ const retroEntries = summaryEntries.length === 0 ? typeof projectNumber === "number" ? context.db.searchEntries("", {
2063
+ limit: config.summaryCount,
2064
+ projectNumber,
2065
+ entryType: "retrospective"
2066
+ }) : context.db.searchEntries("", {
2067
+ limit: config.summaryCount,
2068
+ entryType: "retrospective"
2069
+ }) : [];
2070
+ const finalSummaryEntries = summaryEntries.length > 0 ? summaryEntries : retroEntries;
2071
+ let latestSessionSummary;
2072
+ let sessionSummaries;
2073
+ if (finalSummaryEntries.length > 0) {
2074
+ sessionSummaries = finalSummaryEntries.map((entry) => {
2075
+ const c = entry.content ?? "";
2076
+ return {
2077
+ id: entry.id,
2078
+ timestamp: entry.timestamp,
2079
+ type: entry.entryType,
2080
+ preview: c.slice(0, PREVIEW_LENGTH) + (c.length > PREVIEW_LENGTH ? "..." : "")
2081
+ };
2082
+ });
2083
+ latestSessionSummary = sessionSummaries[0];
2084
+ }
2053
2085
  const totalEntries = context.db.getActiveEntryCount();
2054
2086
  const lastModified = recentEntries[0]?.timestamp ?? (/* @__PURE__ */ new Date()).toISOString();
2055
- return { totalEntries, latestEntries, lastModified };
2087
+ return { totalEntries, latestEntries, latestSessionSummary, sessionSummaries, lastModified };
2056
2088
  }
2057
2089
  var TEAM_PREVIEW_LENGTH = 60;
2058
- function buildTeamContext(context, config) {
2090
+ function buildTeamContext(context, config, projectNumber) {
2059
2091
  if (!context.teamDb) return void 0;
2060
2092
  try {
2061
2093
  const teamTotalEntries = context.teamDb.getActiveEntryCount();
2062
- const teamRecent = context.teamDb.getRecentEntries(1);
2094
+ const teamRecent = typeof projectNumber === "number" ? context.teamDb.searchEntries("", { limit: 1, projectNumber }) : context.teamDb.getRecentEntries(1);
2063
2095
  const teamLatestEntry = teamRecent[0];
2064
2096
  const teamContent = teamLatestEntry ? teamLatestEntry["content"] ?? "" : "";
2065
2097
  const teamLatest = teamLatestEntry ? `#${String(teamLatestEntry["id"])}: ${teamContent.slice(0, TEAM_PREVIEW_LENGTH)}${teamContent.length > TEAM_PREVIEW_LENGTH ? "..." : ""}` : null;
@@ -2069,7 +2101,7 @@ function buildTeamContext(context, config) {
2069
2101
  };
2070
2102
  let teamLatestEntries = void 0;
2071
2103
  if (config.includeTeam) {
2072
- const teamEntries = context.teamDb.getRecentEntries(config.entryCount);
2104
+ const teamEntries = typeof projectNumber === "number" ? context.teamDb.searchEntries("", { limit: config.entryCount, projectNumber }) : context.teamDb.getRecentEntries(config.entryCount);
2073
2105
  teamLatestEntries = teamEntries.map((e) => {
2074
2106
  const content = e.content ?? "";
2075
2107
  return {
@@ -2136,8 +2168,18 @@ function buildSkillsDirInfo(skillsDirPath) {
2136
2168
  }
2137
2169
 
2138
2170
  // src/handlers/resources/core/briefing/user-message.ts
2171
+ var escapeTableCell = (text) => text.replace(/\\/g, "\\\\").replace(/\|/g, "\\|").replace(/\r?\n/g, "<br>");
2139
2172
  function formatUserMessage(opts) {
2140
- const { repoName, branchName, totalEntries, latestPreview, github, rulesFile, skillsDir } = opts;
2173
+ const {
2174
+ repoName,
2175
+ branchName,
2176
+ totalEntries,
2177
+ latestPreview,
2178
+ summaryPreviews,
2179
+ github,
2180
+ rulesFile,
2181
+ skillsDir
2182
+ } = opts;
2141
2183
  let ciDisplay = opts.ciStatus;
2142
2184
  if (github?.workflowSummary) {
2143
2185
  const ws = github.workflowSummary;
@@ -2165,7 +2207,7 @@ function formatUserMessage(opts) {
2165
2207
  if (github.openIssueList && github.openIssueList.length > 0) {
2166
2208
  const titles = github.openIssueList.map((i) => `#${String(i.number)} ${i.title}`).join(" \xB7 ");
2167
2209
  issuesRow = `
2168
- | **Issues** | ${String(github.openIssues)} open: ${titles} |`;
2210
+ | **Issues** | ${String(github.openIssues)} open: ${escapeTableCell(titles)} |`;
2169
2211
  } else {
2170
2212
  issuesRow = `
2171
2213
  | **Issues** | ${String(github.openIssues)} open |`;
@@ -2181,14 +2223,14 @@ function formatUserMessage(opts) {
2181
2223
  } else if (github.openPrList && github.openPrList.length > 0) {
2182
2224
  const titles = github.openPrList.map((p) => `#${String(p.number)} ${p.title}`).join(" \xB7 ");
2183
2225
  prsRow = `
2184
- | **PRs** | ${String(github.openPRs)} open: ${titles} |`;
2226
+ | **PRs** | ${String(github.openPRs)} open: ${escapeTableCell(titles)} |`;
2185
2227
  } else {
2186
2228
  prsRow = `
2187
2229
  | **PRs** | ${String(github.openPRs)} open |`;
2188
2230
  }
2189
2231
  }
2190
2232
  const milestoneRow = github?.milestones && github.milestones.length > 0 ? `
2191
- | **Milestones** | ${github.milestones.map((m) => `${m.title} (${m.progress}${m.dueOn ? `, due ${m.dueOn.split("T")[0] ?? ""}` : ""})`).join(", ")} |` : "";
2233
+ | **Milestones** | ${escapeTableCell(github.milestones.map((m) => `${m.title} (${m.progress}${m.dueOn ? `, due ${m.dueOn.split("T")[0] ?? ""}` : ""})`).join(", "))} |` : "";
2192
2234
  let insightsRow = "";
2193
2235
  if (github?.insights) {
2194
2236
  const parts = [];
@@ -2206,16 +2248,18 @@ function formatUserMessage(opts) {
2206
2248
  }
2207
2249
  const copilotRow = github?.copilotReviews ? `
2208
2250
  | **Copilot** | ${String(github.copilotReviews.reviewed)} reviewed \xB7 ${String(github.copilotReviews.approved)} approved${github.copilotReviews.changesRequested > 0 ? ` \xB7 ${String(github.copilotReviews.changesRequested)} changes requested` : ""}${github.copilotReviews.totalComments > 0 ? ` (${String(github.copilotReviews.totalComments)} comments)` : ""} |` : "";
2251
+ const summariesOutput = summaryPreviews && summaryPreviews.length > 0 ? summaryPreviews.map((s) => `
2252
+ | **Summary** | ${escapeTableCell(s)} |`).join("") : "";
2209
2253
  return `\u{1F4CB} **Session Context Loaded**
2210
2254
  | Context | Value |
2211
2255
  |---------|-------|
2212
- | **Project** | ${repoName} |
2213
- | **Branch** | ${branchName} |
2214
- | **CI** | ${ciDisplay} |
2256
+ | **Project** | ${escapeTableCell(repoName)} |
2257
+ | **Branch** | ${escapeTableCell(branchName)} |
2258
+ | **CI** | ${escapeTableCell(ciDisplay)} |
2215
2259
  | **Journal** | ${totalEntries} entries |${opts.teamTotalEntries !== void 0 ? `
2216
2260
  | **Team DB** | ${opts.teamTotalEntries} entries |` : ""}
2217
- | **Latest** | ${latestPreview} |${issuesRow}${prsRow}${milestoneRow}${insightsRow}${copilotRow}${rulesFile ? `
2218
- | **Rules** | ${rulesFile.name} (${String(rulesFile.sizeKB)} KB, updated ${rulesFile.lastModified}) |` : ""}${skillsDir ? `
2261
+ | **Latest** | ${escapeTableCell(latestPreview)} |${summariesOutput}${issuesRow}${prsRow}${milestoneRow}${insightsRow}${copilotRow}${rulesFile ? `
2262
+ | **Rules** | ${escapeTableCell(rulesFile.name)} (${String(rulesFile.sizeKB)} KB, updated ${rulesFile.lastModified}) |` : ""}${skillsDir ? `
2219
2263
  | **Skills** | ${String(skillsDir.count)} skill${skillsDir.count !== 1 ? "s" : ""} available |` : ""}`;
2220
2264
  }
2221
2265
 
@@ -2252,24 +2296,28 @@ var dynamicBriefingResource = {
2252
2296
  }
2253
2297
  };
2254
2298
  async function buildBriefingData(context, targetRepo) {
2255
- const config = context.briefingConfig ?? DEFAULT_BRIEFING_CONFIG;
2299
+ const config = { ...DEFAULT_BRIEFING_CONFIG, ...context.briefingConfig };
2256
2300
  let activeGithub = context.github;
2301
+ let activeProjectNumber = config.defaultProjectNumber;
2257
2302
  if (targetRepo && config.projectRegistry?.[targetRepo]) {
2258
2303
  const repoPath = config.projectRegistry[targetRepo].path;
2259
2304
  activeGithub = new GitHubIntegration(repoPath);
2305
+ activeProjectNumber = config.projectRegistry[targetRepo].project_number ?? void 0;
2260
2306
  }
2261
- const journal = buildJournalContext(context, config);
2307
+ const journal = buildJournalContext(context, config, activeProjectNumber);
2262
2308
  const github = await buildGitHubSection(activeGithub, config);
2263
- const team = buildTeamContext(context, config);
2309
+ const team = buildTeamContext(context, config, activeProjectNumber);
2264
2310
  const rulesFile = buildRulesFileInfo(config.rulesFilePath);
2265
2311
  const skillsDir = buildSkillsDirInfo(config.skillsDirPath);
2266
2312
  const latestPreview = journal.latestEntries[0] ? `#${journal.latestEntries[0].id} (${journal.latestEntries[0].type}): ${journal.latestEntries[0].preview}` : "No entries yet";
2313
+ const summaryPreviews = journal.sessionSummaries ? journal.sessionSummaries.map((s) => `#${s.id} (${s.type}): ${s.preview}`) : null;
2267
2314
  const userMessage = formatUserMessage({
2268
2315
  repoName: github?.repo ?? "local",
2269
2316
  branchName: github?.branch ?? "unknown",
2270
2317
  ciStatus: github?.ci ?? "unknown",
2271
2318
  totalEntries: journal.totalEntries,
2272
2319
  latestPreview,
2320
+ summaryPreviews,
2273
2321
  github,
2274
2322
  teamTotalEntries: team?.teamInfo.totalEntries,
2275
2323
  rulesFile,
@@ -2281,7 +2329,8 @@ async function buildBriefingData(context, targetRepo) {
2281
2329
  serverTime: (/* @__PURE__ */ new Date()).toISOString(),
2282
2330
  journal: {
2283
2331
  totalEntries: journal.totalEntries,
2284
- latestEntries: journal.latestEntries
2332
+ latestEntries: journal.latestEntries,
2333
+ ...journal.latestSessionSummary ? { latestSessionSummary: journal.latestSessionSummary } : {}
2285
2334
  },
2286
2335
  github,
2287
2336
  teamContext: team?.teamInfo,
@@ -2324,7 +2373,7 @@ async function buildBriefingData(context, targetRepo) {
2324
2373
  // src/constants/server-instructions.ts
2325
2374
  var CORE_INSTRUCTIONS = `# memory-journal-mcp
2326
2375
 
2327
- ## ESSENTIAL SESSION START!**
2376
+ ## **ESSENTIAL SESSION START!**
2328
2377
 
2329
2378
  1. You **MUST** read the \`memory://briefing/{repo_name}\` at the start of each chat!
2330
2379
  2. Use the standard MCP \`read_resource\` tool for this (do NOT use Code Mode/execute_code).
@@ -2384,6 +2433,13 @@ When you notice the user consistently applies patterns, preferences, or workflow
2384
2433
  - **Always ask the user first** \u2014 never create or modify rules/skills silently
2385
2434
  - Frame suggestions as: "I noticed you always [pattern]. Would you like me to add/update a rule for this?"
2386
2435
  - For skills, explain the workflow it would automate and what triggers it
2436
+
2437
+ ### Native Agent Skills (NPM Distribution)
2438
+
2439
+ This server leverages the \`neverinfamous-agent-skills\` package. If the user's \`SKILLS_DIR_PATH\` environment variable targets these, you have native access to foundational frameworks (\`mastering-typescript\`, \`react-best-practices\`, \`playwright-standard\`, \`golang\`, \`rust\`, \`shadcn-ui\`) and the \`github-commander\` DevOps workflows (\`issue-triage\`, \`pr-review\`, etc.).
2440
+
2441
+ - The user can distribute or update these skills across their repositories by running \`npx neverinfamous-agent-skills@latest\`.
2442
+ - If you need to create a new skill, reference the bundled \`skill-builder\` instructions!
2387
2443
  `;
2388
2444
  var COPILOT_REVIEW_INSTRUCTIONS = `
2389
2445
  ## Copilot Review Patterns
@@ -2420,65 +2476,18 @@ function buildQuickAccess(groups) {
2420
2476
  return table;
2421
2477
  }
2422
2478
  var CODE_MODE_NAMESPACE_ROWS = [
2423
- {
2424
- group: "core",
2425
- label: "Core",
2426
- namespace: "`mj.core.*`",
2427
- example: '`mj.core.createEntry("Implemented feature X")`'
2428
- },
2429
- {
2430
- group: "search",
2431
- label: "Search",
2432
- namespace: "`mj.search.*`",
2433
- example: '`mj.search.searchEntries("performance")`'
2434
- },
2435
- {
2436
- group: "analytics",
2437
- label: "Analytics",
2438
- namespace: "`mj.analytics.*`",
2439
- example: "`mj.analytics.getStatistics()`"
2440
- },
2441
- {
2442
- group: "relationships",
2443
- label: "Relationships",
2444
- namespace: "`mj.relationships.*`",
2445
- example: '`mj.relationships.linkEntries(1, 2, "implements")`'
2446
- },
2447
- {
2448
- group: "io",
2449
- label: "IO",
2450
- namespace: "`mj.io.*`",
2451
- example: '`mj.io.exportEntries("json")`'
2452
- },
2453
- {
2454
- group: "admin",
2455
- label: "Admin",
2456
- namespace: "`mj.admin.*`",
2457
- example: "`mj.admin.rebuildVectorIndex()`"
2458
- },
2459
- {
2460
- group: "github",
2461
- label: "GitHub",
2462
- namespace: "`mj.github.*`",
2463
- example: '`mj.github.getGithubIssues({ state: "open" })`'
2464
- },
2465
- {
2466
- group: "backup",
2467
- label: "Backup",
2468
- namespace: "`mj.backup.*`",
2469
- example: "`mj.backup.backupJournal()`"
2470
- },
2471
- {
2472
- group: "team",
2473
- label: "Team",
2474
- namespace: "`mj.team.*`",
2475
- example: '`mj.team.teamCreateEntry("Team update")`'
2476
- }
2479
+ { group: "core", label: "Core", namespace: "`mj.core.*`", example: '`mj.core.createEntry("Implemented feature X")`' },
2480
+ { group: "search", label: "Search", namespace: "`mj.search.*`", example: '`mj.search.searchEntries("performance")`' },
2481
+ { group: "analytics", label: "Analytics", namespace: "`mj.analytics.*`", example: "`mj.analytics.getStatistics()`" },
2482
+ { group: "relationships", label: "Relationships", namespace: "`mj.relationships.*`", example: '`mj.relationships.linkEntries(1, 2, "implements")`' },
2483
+ { group: "io", label: "IO", namespace: "`mj.io.*`", example: '`mj.io.exportEntries("json")`' },
2484
+ { group: "admin", label: "Admin", namespace: "`mj.admin.*`", example: "`mj.admin.rebuildVectorIndex()`" },
2485
+ { group: "github", label: "GitHub", namespace: "`mj.github.*`", example: '`mj.github.getGithubIssues({ state: "open" })`' },
2486
+ { group: "backup", label: "Backup", namespace: "`mj.backup.*`", example: "`mj.backup.backupJournal()`" },
2487
+ { group: "team", label: "Team", namespace: "`mj.team.*`", example: '`mj.team.teamCreateEntry("Team update")`' }
2477
2488
  ];
2478
2489
  function buildCodeModeInstructions(groups) {
2479
- const rows = CODE_MODE_NAMESPACE_ROWS.filter((r) => groups.has(r.group)).map(
2480
- (r) => `| ${r.label.padEnd(13)} | ${r.namespace.padEnd(20)} | ${r.example.padEnd(50)} |`
2481
- ).join("\n");
2490
+ const rows = CODE_MODE_NAMESPACE_ROWS.filter((r) => groups.has(r.group)).map((r) => `| ${r.label.padEnd(13)} | ${r.namespace.padEnd(20)} | ${r.example.padEnd(50)} |`).join("\n");
2482
2491
  const fullSection = CODE_MODE_FULL_TEXT;
2483
2492
  const tableStart = fullSection.indexOf("| Group");
2484
2493
  const tableEnd = fullSection.indexOf("\n\n**Features**");
@@ -2542,7 +2551,7 @@ var GITHUB_INSTRUCTIONS = `
2542
2551
  - Include \`issue_number\`/\`pr_number\` in \`create_entry\` to auto-link
2543
2552
  - After closing issue/merging PR \u2192 create summary entry with learnings
2544
2553
  - CI failures \u2192 \`actions-failure-digest\` prompt or \`memory://actions/recent\`
2545
- - Kanban: \`get_kanban_board\` \u2192 \`move_kanban_item\` \u2192 document completion (project_number auto-resolves if repo is registered)
2554
+ - Kanban: \`get_kanban_board\` \u2192 \`add_kanban_item\` / \`move_kanban_item\` / \`delete_kanban_item\` \u2192 document completion (project_number auto-resolves if repo is registered)
2546
2555
  - Milestones: \`get_github_milestones\` \u2192 track project progress, \`memory://github/milestones\`
2547
2556
  - **Multi-Project Routing**: If \`memory://briefing\` shows "Registered Workspaces":
2548
2557
  - **Tools**: Pass a \`repo\` parameter to ALL GitHub tools (including \`get_github_context\`) to explicitly target a specific project.
@@ -2873,6 +2882,12 @@ Provide insights on patterns, productivity, and recommendations.`
2873
2882
  LIMIT 20
2874
2883
  `
2875
2884
  );
2885
+ const mappedEntries = entries.map((e) => ({
2886
+ id: e["id"],
2887
+ type: e["entry_type"] ?? e["entryType"],
2888
+ timestamp: e["timestamp"],
2889
+ content: typeof e["content"] === "string" && e["content"].length > 250 ? e["content"].slice(0, 250) + "..." : e["content"]
2890
+ }));
2876
2891
  return {
2877
2892
  messages: [
2878
2893
  {
@@ -2881,7 +2896,7 @@ Provide insights on patterns, productivity, and recommendations.`
2881
2896
  type: "text",
2882
2897
  text: `Track goals and milestones based on significant entries:
2883
2898
 
2884
- ${JSON.stringify(entries, null, 2)}
2899
+ ${JSON.stringify(mappedEntries, null, 2)}
2885
2900
 
2886
2901
  Summarize progress toward goals and highlight achievements.`
2887
2902
  }
@@ -3069,6 +3084,14 @@ ${entrySummary}
3069
3084
  }
3070
3085
 
3071
3086
  // src/handlers/prompts/github.ts
3087
+ function formatPromptEntries(entries, maxCount = 50) {
3088
+ return entries.slice(0, maxCount).map((e) => ({
3089
+ id: e["id"],
3090
+ type: e["entry_type"] ?? e["entryType"],
3091
+ timestamp: e["timestamp"],
3092
+ content: typeof e["content"] === "string" && e["content"].length > 250 ? e["content"].slice(0, 250) + "..." : e["content"]
3093
+ }));
3094
+ }
3072
3095
  function getGitHubPromptDefinitions() {
3073
3096
  return [
3074
3097
  {
@@ -3099,7 +3122,7 @@ function getGitHubPromptDefinitions() {
3099
3122
  type: "text",
3100
3123
  text: `Generate a status summary for Project #${String(projectNumber)}:
3101
3124
 
3102
- Entries: ${JSON.stringify(entries, null, 2)}
3125
+ Entries: ${JSON.stringify(formatPromptEntries(entries), null, 2)}
3103
3126
 
3104
3127
  Provide: overview, recent activity, blockers, next steps.`
3105
3128
  }
@@ -3133,7 +3156,7 @@ Provide: overview, recent activity, blockers, next steps.`
3133
3156
  type: "text",
3134
3157
  text: `Summarize PR #${String(prNumber)} activity:
3135
3158
 
3136
- Journal entries: ${JSON.stringify(entries, null, 2)}
3159
+ Journal entries: ${JSON.stringify(formatPromptEntries(entries), null, 2)}
3137
3160
 
3138
3161
  Provide: summary of changes, decisions made, testing done.`
3139
3162
  }
@@ -3167,7 +3190,7 @@ Provide: summary of changes, decisions made, testing done.`
3167
3190
  type: "text",
3168
3191
  text: `Prepare for code review of PR #${String(prNumber)}:
3169
3192
 
3170
- Context entries: ${JSON.stringify(entries, null, 2)}
3193
+ Context entries: ${JSON.stringify(formatPromptEntries(entries), null, 2)}
3171
3194
 
3172
3195
  Provide: review checklist, areas of concern, testing recommendations.`
3173
3196
  }
@@ -3201,7 +3224,7 @@ Provide: review checklist, areas of concern, testing recommendations.`
3201
3224
  type: "text",
3202
3225
  text: `Retrospective for PR #${String(prNumber)}:
3203
3226
 
3204
- Journal entries: ${JSON.stringify(entries, null, 2)}
3227
+ Journal entries: ${JSON.stringify(formatPromptEntries(entries), null, 2)}
3205
3228
 
3206
3229
  Provide: what went well, challenges, lessons learned.`
3207
3230
  }
@@ -3234,7 +3257,7 @@ Provide: what went well, challenges, lessons learned.`
3234
3257
  type: "text",
3235
3258
  text: `Analyze CI/CD failures from these workflow entries:
3236
3259
 
3237
- ${JSON.stringify(entries, null, 2)}
3260
+ ${JSON.stringify(formatPromptEntries(entries), null, 2)}
3238
3261
 
3239
3262
  Provide: failure patterns, root causes, remediation steps.`
3240
3263
  }
@@ -3271,7 +3294,7 @@ Provide: failure patterns, root causes, remediation steps.`
3271
3294
  type: "text",
3272
3295
  text: `Track milestones for Project #${String(projectNumber)}:
3273
3296
 
3274
- Milestone entries: ${JSON.stringify(entries, null, 2)}
3297
+ Milestone entries: ${JSON.stringify(formatPromptEntries(entries), null, 2)}
3275
3298
 
3276
3299
  Provide: progress summary, upcoming milestones, timeline.`
3277
3300
  }
@@ -3528,6 +3551,9 @@ var statisticsResource = {
3528
3551
  return context.db.getStatistics("week");
3529
3552
  }
3530
3553
  };
3554
+ var cachedRulesContent = null;
3555
+ var rulesLastScanTime = 0;
3556
+ var RULES_CACHE_TTL_MS = 5 * 60 * 1e3;
3531
3557
  var rulesResource = {
3532
3558
  uri: "memory://rules",
3533
3559
  name: "Rules File",
@@ -3536,7 +3562,7 @@ var rulesResource = {
3536
3562
  mimeType: "text/markdown",
3537
3563
  icons: [ICON_BRIEFING],
3538
3564
  annotations: withPriority(0.7, ASSISTANT_FOCUSED),
3539
- handler: (_uri, _context) => {
3565
+ handler: async (_uri, _context) => {
3540
3566
  const rulesPath = process.env["RULES_FILE_PATH"];
3541
3567
  if (!rulesPath) {
3542
3568
  return {
@@ -3547,11 +3573,24 @@ var rulesResource = {
3547
3573
  };
3548
3574
  }
3549
3575
  try {
3550
- const content = fs2.readFileSync(rulesPath, "utf8");
3576
+ if (cachedRulesContent && Date.now() - rulesLastScanTime < RULES_CACHE_TTL_MS) {
3577
+ const stat2 = await fs2.promises.stat(rulesPath).catch(() => ({ mtimeMs: Date.now() }));
3578
+ return {
3579
+ data: cachedRulesContent,
3580
+ annotations: {
3581
+ lastModified: new Date(stat2.mtimeMs).toISOString()
3582
+ }
3583
+ };
3584
+ }
3585
+ const content = await fs2.promises.readFile(rulesPath, "utf8");
3586
+ const stat = await fs2.promises.stat(rulesPath).catch(() => ({ mtimeMs: Date.now() }));
3587
+ const mtimeMs = stat.mtimeMs;
3588
+ cachedRulesContent = content;
3589
+ rulesLastScanTime = Date.now();
3551
3590
  return {
3552
3591
  data: content,
3553
3592
  annotations: {
3554
- lastModified: new Date(fs2.statSync(rulesPath).mtimeMs).toISOString()
3593
+ lastModified: new Date(mtimeMs).toISOString()
3555
3594
  }
3556
3595
  };
3557
3596
  } catch (err) {
@@ -3617,15 +3656,15 @@ function getShippedSkillsDir() {
3617
3656
  return void 0;
3618
3657
  }
3619
3658
  }
3620
- function scanSkillsDir(dir, source) {
3659
+ async function scanSkillsDir(dir, source) {
3621
3660
  if (!fs2.existsSync(dir)) return [];
3622
- const entries = fs2.readdirSync(dir, { withFileTypes: true });
3661
+ const entries = await fs2.promises.readdir(dir, { withFileTypes: true });
3623
3662
  const skills = [];
3624
3663
  for (const entry of entries) {
3625
3664
  if (!entry.isDirectory()) continue;
3626
3665
  const skillMdPath = path4.join(dir, entry.name, "SKILL.md");
3627
3666
  if (!fs2.existsSync(skillMdPath)) continue;
3628
- const content = fs2.readFileSync(skillMdPath, "utf8");
3667
+ const content = await fs2.promises.readFile(skillMdPath, "utf8");
3629
3668
  const lines = content.split("\n");
3630
3669
  const excerptLine = lines.find(
3631
3670
  (l) => l.trim().length > 0 && !l.startsWith("#") && !l.startsWith("---")
@@ -3643,7 +3682,7 @@ var skillsResource = {
3643
3682
  mimeType: "application/json",
3644
3683
  icons: [ICON_BRIEFING],
3645
3684
  annotations: { ...MEDIUM_PRIORITY, audience: ["assistant"] },
3646
- handler: (_uri, _context) => {
3685
+ handler: async (_uri, _context) => {
3647
3686
  const userSkillsDir = process.env["SKILLS_DIR_PATH"];
3648
3687
  const shippedSkillsDir = getShippedSkillsDir();
3649
3688
  const hasAnySource = !!userSkillsDir || !!shippedSkillsDir;
@@ -3670,12 +3709,12 @@ var skillsResource = {
3670
3709
  }
3671
3710
  const skillMap = /* @__PURE__ */ new Map();
3672
3711
  if (shippedSkillsDir) {
3673
- for (const skill of scanSkillsDir(shippedSkillsDir, "shipped")) {
3712
+ for (const skill of await scanSkillsDir(shippedSkillsDir, "shipped")) {
3674
3713
  skillMap.set(skill.name, skill);
3675
3714
  }
3676
3715
  }
3677
3716
  if (userSkillsDir) {
3678
- for (const skill of scanSkillsDir(userSkillsDir, "user")) {
3717
+ for (const skill of await scanSkillsDir(userSkillsDir, "user")) {
3679
3718
  skillMap.set(skill.name, skill);
3680
3719
  }
3681
3720
  }
@@ -4894,7 +4933,7 @@ function getHelpResourceDefinitions() {
4894
4933
  var toolIndexModule = null;
4895
4934
  async function getAllToolDefinitionsAsync(context) {
4896
4935
  try {
4897
- toolIndexModule ??= await import('./tools-O44Q52RD.js');
4936
+ toolIndexModule ??= await import('./tools-CXR2FEB2.js');
4898
4937
  if (toolIndexModule === null) return [];
4899
4938
  const tools = toolIndexModule.getTools(context.db, null);
4900
4939
  return tools.map((t) => ({
@@ -496,6 +496,40 @@ var IssuesManager = class {
496
496
  return null;
497
497
  }
498
498
  }
499
+ async getIssueComments(owner, repo, issueNumber, limit = 30) {
500
+ const _limit = Math.min(limit, 100);
501
+ if (_limit <= 0) return [];
502
+ if (!this.client.octokit) {
503
+ return [];
504
+ }
505
+ const cacheKey = `issue-comments:${owner}:${repo}:${String(issueNumber)}:${String(_limit)}`;
506
+ const cached = this.client.getCached(cacheKey);
507
+ if (cached) return cached;
508
+ try {
509
+ const response = await this.client.octokit.issues.listComments({
510
+ owner,
511
+ repo,
512
+ issue_number: issueNumber,
513
+ per_page: _limit,
514
+ sort: "created",
515
+ direction: "asc"
516
+ });
517
+ const comments = response.data.slice(0, _limit).map((comment) => ({
518
+ author: comment.user?.login ?? "unknown",
519
+ body: comment.body ?? "",
520
+ createdAt: comment.created_at
521
+ }));
522
+ this.client.setCache(cacheKey, comments);
523
+ return comments;
524
+ } catch (error) {
525
+ logger.error("Failed to get issue comments", {
526
+ module: "GitHub",
527
+ entityId: issueNumber,
528
+ error: error instanceof Error ? error.message : String(error)
529
+ });
530
+ return [];
531
+ }
532
+ }
499
533
  async createIssue(owner, repo, title, body, labels, assignees, milestone) {
500
534
  if (!this.client.octokit) {
501
535
  logger.error("Cannot create issue: GitHub API not available", { module: "GitHub" });
@@ -1034,7 +1068,9 @@ var ProjectsManager = class {
1034
1068
  });
1035
1069
  return { success: false, error: errorMessage };
1036
1070
  } finally {
1037
- this.client.invalidateCache("kanban:");
1071
+ if (typeof this.client.invalidateCache === "function") {
1072
+ this.client.invalidateCache("kanban:");
1073
+ }
1038
1074
  }
1039
1075
  }
1040
1076
  async addProjectItem(projectId, contentId) {
@@ -1070,7 +1106,44 @@ var ProjectsManager = class {
1070
1106
  });
1071
1107
  return { success: false, error: errorMessage };
1072
1108
  } finally {
1073
- this.client.invalidateCache("kanban:");
1109
+ if (typeof this.client.invalidateCache === "function") {
1110
+ this.client.invalidateCache("kanban:");
1111
+ }
1112
+ }
1113
+ }
1114
+ async deleteProjectItem(projectId, itemId) {
1115
+ if (!this.client.graphqlWithAuth) {
1116
+ return { success: false, error: "GraphQL not available - no token" };
1117
+ }
1118
+ try {
1119
+ const mutation = `
1120
+ mutation($projectId: ID!, $itemId: ID!) {
1121
+ deleteProjectV2Item(input: { projectId: $projectId, itemId: $itemId }) {
1122
+ deletedItemId
1123
+ }
1124
+ }
1125
+ `;
1126
+ await this.client.graphqlWithAuth(mutation, {
1127
+ projectId,
1128
+ itemId
1129
+ });
1130
+ logger.info("Deleted project item", {
1131
+ module: "GitHub",
1132
+ context: { projectId, itemId }
1133
+ });
1134
+ return { success: true };
1135
+ } catch (error) {
1136
+ const errorMessage = error instanceof Error ? error.message : String(error);
1137
+ logger.error("Failed to delete item from project", {
1138
+ module: "GitHub",
1139
+ context: { projectId, itemId },
1140
+ error: errorMessage
1141
+ });
1142
+ return { success: false, error: errorMessage };
1143
+ } finally {
1144
+ if (typeof this.client.invalidateCache === "function") {
1145
+ this.client.invalidateCache("kanban:");
1146
+ }
1074
1147
  }
1075
1148
  }
1076
1149
  };
@@ -1540,6 +1613,9 @@ var GitHubIntegration = class {
1540
1613
  async getIssue(owner, repo, issueNumber) {
1541
1614
  return this.issuesManager.getIssue(owner, repo, issueNumber);
1542
1615
  }
1616
+ async getIssueComments(owner, repo, issueNumber, limit = 30) {
1617
+ return this.issuesManager.getIssueComments(owner, repo, issueNumber, limit);
1618
+ }
1543
1619
  async createIssue(owner, repo, title, body, labels, assignees, milestone) {
1544
1620
  return this.issuesManager.createIssue(
1545
1621
  owner,
@@ -1634,6 +1710,9 @@ var GitHubIntegration = class {
1634
1710
  async addProjectItem(projectId, contentId) {
1635
1711
  return this.projectsManager.addProjectItem(projectId, contentId);
1636
1712
  }
1713
+ async deleteProjectItem(projectId, itemId) {
1714
+ return this.projectsManager.deleteProjectItem(projectId, itemId);
1715
+ }
1637
1716
  async getMilestones(owner, repo, state = "open", limit = 20) {
1638
1717
  return this.milestonesManager.getMilestones(owner, repo, state, limit);
1639
1718
  }