memory-journal-mcp 7.4.0 → 7.5.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.
@@ -1,4 +1,4 @@
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-P5V2VY6N.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, DEFAULT_FLAG_VOCABULARY, parseScopes, BASE_SCOPES, getAllToolNames, globalMetrics, DEFAULT_BRIEFING_CONFIG } from './chunk-VHA46GLM.js';
2
2
  import { logger, GitHubIntegration, ConfigurationError, ResourceNotFoundError, ConnectionError, QueryError, assertNoPathTraversal, ValidationError, MemoryJournalMcpError, validateDateFormatPattern } from './chunk-WXDEVIFL.js';
3
3
  import { createRequire } from 'module';
4
4
  import { McpServer, ResourceTemplate } from '@modelcontextprotocol/sdk/server/mcp.js';
@@ -492,16 +492,14 @@ function rowsToEntries(tagsMgr, rows) {
492
492
  if (rows.length === 0) return [];
493
493
  const entries = rows.map((r) => {
494
494
  const p = r;
495
- const { importanceScore, ...rest } = p;
496
- const entry = {
497
- ...rest,
495
+ return {
496
+ ...p,
498
497
  isPersonal: Boolean(p.isPersonal),
499
498
  // SQLite uses 0/1
500
499
  tags: [],
501
500
  // Attach importanceScore if the query computed it (importance-sorted results)
502
- ...importanceScore !== void 0 ? { importanceScore: Math.round(importanceScore * 100) / 100 } : {}
501
+ ...p.importanceScore !== void 0 ? { importanceScore: Math.round(p.importanceScore * 100) / 100 } : {}
503
502
  };
504
- return entry;
505
503
  });
506
504
  const ids = entries.map((e) => e.id);
507
505
  const tagsMap = tagsMgr.batchGetTagsForEntries(ids);
@@ -546,7 +544,7 @@ function createEntry(context, input) {
546
544
  timestamp,
547
545
  input.isPersonal ?? true ? 1 : 0,
548
546
  input.significanceType || null,
549
- input.autoContext ? 1 : 0,
547
+ input.autoContext ?? null,
550
548
  input.projectNumber ?? null,
551
549
  input.projectOwner || null,
552
550
  input.issueNumber ?? null,
@@ -646,7 +644,7 @@ function updateEntry(context, id, input) {
646
644
  }
647
645
  if (input.autoContext !== void 0) {
648
646
  updates.push("auto_context = ?");
649
- values.push(input.autoContext ? 1 : 0);
647
+ values.push(input.autoContext ?? null);
650
648
  }
651
649
  for (const key of [
652
650
  "projectNumber",
@@ -968,15 +966,6 @@ function searchByDateRange(context, startDate, endDate, options) {
968
966
  return rowsToEntries(tagsMgr, rows);
969
967
  }
970
968
  function sanitizeFtsQuery(query) {
971
- const trimmed = query.trim();
972
- if (trimmed.startsWith('"') && trimmed.endsWith('"') && trimmed.length > 2 && !trimmed.slice(1, -1).includes('"')) {
973
- const inner = trimmed.slice(1, -1).trim();
974
- const words = inner.split(/\s+/).filter(Boolean);
975
- if (words.length > 1) {
976
- return words.join(" AND ");
977
- }
978
- return inner;
979
- }
980
969
  return query;
981
970
  }
982
971
 
@@ -1037,15 +1026,16 @@ function getStatistics(context, groupBy = "week", startDate, endDate, projectBre
1037
1026
  period: r.period,
1038
1027
  significantCount: r.significant_count
1039
1028
  }));
1040
- const relCountRow = db.prepare("SELECT COUNT(*) as count FROM relationships").get();
1029
+ const relCountRow = db.prepare(`SELECT COUNT(*) as count FROM relationships r JOIN memory_journal m ON r.from_entry_id = m.id WHERE m.deleted_at IS NULL${dateFilter}`).get(...dateParams);
1041
1030
  const relTypeRows = db.prepare(
1042
1031
  `
1043
- SELECT relationship_type, COUNT(*) as count
1044
- FROM relationships
1045
- WHERE relationship_type IN ('blocked_by', 'resolved', 'caused')
1046
- GROUP BY relationship_type
1032
+ SELECT r.relationship_type, COUNT(*) as count
1033
+ FROM relationships r
1034
+ JOIN memory_journal m ON r.from_entry_id = m.id
1035
+ WHERE m.deleted_at IS NULL AND r.relationship_type IN ('blocked_by', 'resolved', 'caused')${dateFilter}
1036
+ GROUP BY r.relationship_type
1047
1037
  `
1048
- ).all();
1038
+ ).all(...dateParams);
1049
1039
  const totalRelationships = relCountRow.count;
1050
1040
  const avgPerEntry = totalEntries > 0 ? totalRelationships / totalEntries : 0;
1051
1041
  const currentPeriod = entriesByPeriod[0]?.period ?? "";
@@ -2023,6 +2013,11 @@ var ICON_PROMPT = {
2023
2013
  mimeType: "image/svg+xml",
2024
2014
  sizes: ["24x24"]
2025
2015
  };
2016
+ var ICON_FLAG = {
2017
+ src: 'data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"%3E%3Cpath d="M10.29 3.86L1.82 18a2 2 0 001.71 3h16.94a2 2 0 001.71-3L13.71 3.86a2 2 0 00-3.42 0z"/%3E%3Cline x1="12" y1="9" x2="12" y2="13"/%3E%3Cline x1="12" y1="17" x2="12.01" y2="17"/%3E%3C/svg%3E',
2018
+ mimeType: "image/svg+xml",
2019
+ sizes: ["24x24"]
2020
+ };
2026
2021
 
2027
2022
  // src/handlers/resources/core/briefing/github-section.ts
2028
2023
  async function buildGitHubSection(github, config) {
@@ -2372,6 +2367,51 @@ function buildSkillsDirInfo(skillsDirPath) {
2372
2367
  return void 0;
2373
2368
  }
2374
2369
  }
2370
+ function buildFlagsContext(context) {
2371
+ if (!context.teamDb) return void 0;
2372
+ try {
2373
+ const flagEntries = context.teamDb.searchEntries("", {
2374
+ entryType: "flag",
2375
+ limit: 20
2376
+ });
2377
+ const activeFlags = flagEntries.map((entry) => {
2378
+ const autoCtx = entry.autoContext;
2379
+ if (!autoCtx) return null;
2380
+ try {
2381
+ const parsed = JSON.parse(autoCtx);
2382
+ if (typeof parsed === "object" && parsed !== null && "flag_type" in parsed && "resolved" in parsed) {
2383
+ const ctx = parsed;
2384
+ if (ctx["resolved"] === true) return null;
2385
+ const content = entry.content ?? "";
2386
+ return {
2387
+ id: entry.id,
2388
+ flag_type: String(ctx["flag_type"]),
2389
+ target_user: typeof ctx["target_user"] === "string" ? ctx["target_user"] : null,
2390
+ preview: content.slice(0, 80) + (content.length > 80 ? "..." : ""),
2391
+ timestamp: entry.timestamp
2392
+ };
2393
+ }
2394
+ return null;
2395
+ } catch {
2396
+ return null;
2397
+ }
2398
+ }).filter(
2399
+ (f) => f !== null
2400
+ );
2401
+ if (activeFlags.length === 0) return void 0;
2402
+ return {
2403
+ count: activeFlags.length,
2404
+ flags: activeFlags
2405
+ };
2406
+ } catch (error) {
2407
+ logger.debug("Failed to build flags context", {
2408
+ module: "BRIEFING",
2409
+ operation: "flags-context",
2410
+ error: error instanceof Error ? error.message : String(error)
2411
+ });
2412
+ return void 0;
2413
+ }
2414
+ }
2375
2415
 
2376
2416
  // src/handlers/resources/core/briefing/user-message.ts
2377
2417
  var escapeTableCell = (text) => text.replace(/\\/g, "\\\\").replace(/\|/g, "\\|").replace(/\r?\n/g, "<br>");
@@ -2461,8 +2501,8 @@ function formatUserMessage(opts) {
2461
2501
  parts.push(`\u{1F4C8} ${analyticsInsights.activityTrend}`);
2462
2502
  if (analyticsInsights.significanceSpike !== null)
2463
2503
  parts.push(`\u{1F525} ${analyticsInsights.significanceSpike}`);
2464
- if (analyticsInsights.relationshipDensity !== void 0 && analyticsInsights.relationshipDensity >= 0)
2465
- parts.push(`\u{1F517} Matrix Density: ${analyticsInsights.relationshipDensity}`);
2504
+ if (analyticsInsights.relationshipDensity !== void 0)
2505
+ parts.push(`\u{1F517} Relationship density: ${analyticsInsights.relationshipDensity}`);
2466
2506
  if (analyticsInsights.staleProjects.length > 0)
2467
2507
  parts.push(`\u{1F4A4} ${analyticsInsights.staleProjects.length} stale projects`);
2468
2508
  analyticsRow = `
@@ -2470,6 +2510,15 @@ function formatUserMessage(opts) {
2470
2510
  }
2471
2511
  const summariesOutput = summaryPreviews && summaryPreviews.length > 0 ? summaryPreviews.map((s) => `
2472
2512
  | **Summary** | ${escapeTableCell(s)} |`).join("") : "";
2513
+ let flagsRow = "";
2514
+ if (opts.flagSummary && opts.flagSummary.count > 0) {
2515
+ const flagParts = opts.flagSummary.flags.slice(0, 5).map((f) => {
2516
+ const target = f.target_user ? ` \u2192 @${f.target_user}` : "";
2517
+ return `\u{1F6A9} ${f.flag_type}${target}: ${f.preview.slice(0, 50)}`;
2518
+ });
2519
+ flagsRow = `
2520
+ | **Flags** | ${escapeTableCell(flagParts.join(" \xB7 "))}${opts.flagSummary.count > 5 ? ` (+${String(opts.flagSummary.count - 5)} more)` : ""} |`;
2521
+ }
2473
2522
  return `\u{1F4CB} **Session Context Loaded**
2474
2523
  | Context | Value |
2475
2524
  |---------|-------|
@@ -2478,7 +2527,7 @@ function formatUserMessage(opts) {
2478
2527
  | **CI** | ${escapeTableCell(ciDisplay)} |
2479
2528
  | **Journal** | ${totalEntries} entries |${opts.teamTotalEntries !== void 0 ? `
2480
2529
  | **Team DB** | ${opts.teamTotalEntries} entries |` : ""}
2481
- | **Latest** | ${escapeTableCell(latestPreview)} |${summariesOutput}${issuesRow}${prsRow}${milestoneRow}${insightsRow}${copilotRow}${analyticsRow}${rulesFile ? `
2530
+ | **Latest** | ${escapeTableCell(latestPreview)} |${summariesOutput}${issuesRow}${prsRow}${milestoneRow}${insightsRow}${copilotRow}${analyticsRow}${flagsRow}${rulesFile ? `
2482
2531
  | **Rules** | ${escapeTableCell(rulesFile.name)} (${String(rulesFile.sizeKB)} KB, updated ${rulesFile.lastModified}) |` : ""}${skillsDir ? `
2483
2532
  | **Skills** | ${String(skillsDir.count)} skill${skillsDir.count !== 1 ? "s" : ""} available |` : ""}`;
2484
2533
  }
@@ -2575,6 +2624,7 @@ async function buildBriefingData(context, targetRepo) {
2575
2624
  const rulesFile = buildRulesFileInfo(config.rulesFilePath);
2576
2625
  const skillsDir = buildSkillsDirInfo(config.skillsDirPath);
2577
2626
  const insights = buildInsightsSection(context);
2627
+ const flags = buildFlagsContext(context);
2578
2628
  const latestPreview = journal.latestEntries[0] ? `#${journal.latestEntries[0].id} (${journal.latestEntries[0].type}): ${journal.latestEntries[0].preview}` : "No entries yet";
2579
2629
  const summaryPreviews = journal.sessionSummaries ? journal.sessionSummaries.map((s) => `#${s.id} (${s.type}): ${s.preview}`) : null;
2580
2630
  const userMessage = formatUserMessage({
@@ -2588,12 +2638,18 @@ async function buildBriefingData(context, targetRepo) {
2588
2638
  teamTotalEntries: team?.teamInfo.totalEntries,
2589
2639
  rulesFile,
2590
2640
  skillsDir,
2591
- analyticsInsights: insights ?? void 0
2641
+ analyticsInsights: insights ?? void 0,
2642
+ flagSummary: flags
2592
2643
  });
2593
2644
  return {
2594
2645
  data: {
2595
2646
  version: VERSION,
2596
2647
  serverTime: (/* @__PURE__ */ new Date()).toISOString(),
2648
+ localTime: new Intl.DateTimeFormat("en-US", {
2649
+ dateStyle: "full",
2650
+ timeStyle: "short",
2651
+ timeZone: Intl.DateTimeFormat().resolvedOptions().timeZone
2652
+ }).format(/* @__PURE__ */ new Date()),
2597
2653
  journal: {
2598
2654
  totalEntries: journal.totalEntries,
2599
2655
  latestEntries: journal.latestEntries,
@@ -2605,6 +2661,7 @@ async function buildBriefingData(context, targetRepo) {
2605
2661
  ...rulesFile ? { rulesFile } : {},
2606
2662
  ...skillsDir ? { skillsDir } : {},
2607
2663
  ...insights ? { insights } : {},
2664
+ ...flags ? { activeFlags: flags } : {},
2608
2665
  ...config.projectRegistry ? { registeredWorkspaces: config.projectRegistry } : {},
2609
2666
  behaviors: {
2610
2667
  create: "implementations, decisions, bug-fixes, milestones",
@@ -2708,6 +2765,25 @@ This server leverages the \`neverinfamous-agent-skills\` package. If the user's
2708
2765
 
2709
2766
  - The user can distribute or update these skills across their repositories by running \`npx neverinfamous-agent-skills@latest\`.
2710
2767
  - If you need to create a new skill, reference the bundled \`skill-builder\` instructions!
2768
+
2769
+ ### Hush Protocol (Team Flags)
2770
+
2771
+ Flags are machine-actionable signals stored in the team database. They replace Slack/Teams noise with structured, searchable entries that surface automatically in the briefing.
2772
+
2773
+ **When to create a flag** (\`pass_team_flag\`):
2774
+
2775
+ - \`blocker\` \u2014 work is blocked and requires another person's action
2776
+ - \`needs_review\` \u2014 code, document, or decision needs peer review
2777
+ - \`help_requested\` \u2014 stuck and need guidance or pairing
2778
+ - \`fyi\` \u2014 non-blocking awareness signal (completed migration, config change, etc.)
2779
+
2780
+ **When to resolve** (\`resolve_team_flag\`): After the blocking condition is cleared. Include a brief resolution comment describing what was done. Resolving is idempotent \u2014 safe to call on already-resolved flags.
2781
+
2782
+ **Briefing integration**: The \`memory://briefing\` payload includes \`activeFlags\` when unresolved flags exist. The user's agent rules may instruct you to render these prominently. Always check for and acknowledge active flags at session start.
2783
+
2784
+ **Dashboard**: Read \`memory://flags\` to see all active (unresolved) flags. Read \`memory://flags/vocabulary\` to see the configured flag types.
2785
+
2786
+ **Code Mode**: \`mj.team.passTeamFlag({ flag_type, message })\` and \`mj.team.resolveTeamFlag({ flag_id })\`.
2711
2787
  `;
2712
2788
  var COPILOT_REVIEW_INSTRUCTIONS = `
2713
2789
  ## Copilot Review Patterns
@@ -2744,71 +2820,19 @@ function buildQuickAccess(groups) {
2744
2820
  return table;
2745
2821
  }
2746
2822
  var CODE_MODE_NAMESPACE_ROWS = [
2747
- {
2748
- group: "core",
2749
- label: "Core",
2750
- namespace: "`mj.core.*`",
2751
- example: '`mj.core.createEntry("Implemented feature X")`'
2752
- },
2753
- {
2754
- group: "search",
2755
- label: "Search",
2756
- namespace: "`mj.search.*`",
2757
- example: '`mj.search.searchEntries("performance")`'
2758
- },
2759
- {
2760
- group: "analytics",
2761
- label: "Analytics",
2762
- namespace: "`mj.analytics.*`",
2763
- example: "`mj.analytics.getStatistics()`"
2764
- },
2765
- {
2766
- group: "relationships",
2767
- label: "Relationships",
2768
- namespace: "`mj.relationships.*`",
2769
- example: '`mj.relationships.linkEntries(1, 2, "implements")`'
2770
- },
2771
- {
2772
- group: "io",
2773
- label: "IO",
2774
- namespace: "`mj.io.*`",
2775
- example: '`mj.io.importMarkdown("content")`'
2776
- },
2777
- {
2778
- group: "io",
2779
- label: "Export",
2780
- namespace: "`mj.export.*`",
2781
- example: '`mj.export.exportEntries("json")`'
2782
- },
2783
- {
2784
- group: "admin",
2785
- label: "Admin",
2786
- namespace: "`mj.admin.*`",
2787
- example: "`mj.admin.rebuildVectorIndex()`"
2788
- },
2789
- {
2790
- group: "github",
2791
- label: "GitHub",
2792
- namespace: "`mj.github.*`",
2793
- example: '`mj.github.getGithubIssues({ state: "open" })`'
2794
- },
2795
- {
2796
- group: "backup",
2797
- label: "Backup",
2798
- namespace: "`mj.backup.*`",
2799
- example: "`mj.backup.backupJournal()`"
2800
- },
2801
- {
2802
- group: "team",
2803
- label: "Team",
2804
- namespace: "`mj.team.*`",
2805
- example: '`mj.team.teamCreateEntry("Team update")`'
2806
- }
2823
+ { group: "core", label: "Core", namespace: "`mj.core.*`", example: '`mj.core.createEntry("Implemented feature X")`' },
2824
+ { group: "search", label: "Search", namespace: "`mj.search.*`", example: '`mj.search.searchEntries("performance")`' },
2825
+ { group: "analytics", label: "Analytics", namespace: "`mj.analytics.*`", example: "`mj.analytics.getStatistics()`" },
2826
+ { group: "relationships", label: "Relationships", namespace: "`mj.relationships.*`", example: '`mj.relationships.linkEntries(1, 2, "implements")`' },
2827
+ { group: "io", label: "IO", namespace: "`mj.io.*`", example: '`mj.io.importMarkdown("content")`' },
2828
+ { group: "io", label: "Export", namespace: "`mj.export.*`", example: '`mj.export.exportEntries("json")`' },
2829
+ { group: "admin", label: "Admin", namespace: "`mj.admin.*`", example: "`mj.admin.rebuildVectorIndex()`" },
2830
+ { group: "github", label: "GitHub", namespace: "`mj.github.*`", example: '`mj.github.getGithubIssues({ state: "open" })`' },
2831
+ { group: "backup", label: "Backup", namespace: "`mj.backup.*`", example: "`mj.backup.backupJournal()`" },
2832
+ { group: "team", label: "Team", namespace: "`mj.team.*`", example: '`mj.team.teamCreateEntry("Team update")`' }
2807
2833
  ];
2808
2834
  function buildCodeModeInstructions(groups) {
2809
- const rows = CODE_MODE_NAMESPACE_ROWS.filter((r) => groups.has(r.group)).map(
2810
- (r) => `| ${r.label.padEnd(13)} | ${r.namespace.padEnd(20)} | ${r.example.padEnd(50)} |`
2811
- ).join("\n");
2835
+ 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");
2812
2836
  const fullSection = CODE_MODE_FULL_TEXT;
2813
2837
  const tableStart = fullSection.indexOf("| Group");
2814
2838
  const tableEnd = fullSection.indexOf("\n\n**Features**");
@@ -2957,7 +2981,7 @@ var GOTCHAS_CONTENT = `# memory-journal-mcp \u2014 Field Notes & Gotchas
2957
2981
 
2958
2982
  - **Team cross-database search**: \`search_entries\` and \`search_by_date_range\` automatically merge team DB results when \`TEAM_DB_PATH\` is configured. Results include a \`source\` field ("personal" or "team").
2959
2983
  - **Team vector search**: Team has its own isolated vector index. Use \`team_rebuild_vector_index\` if the team index drifts. \`team_semantic_search\` works identically to personal \`semantic_search\`.
2960
- - **Team tools without \`TEAM_DB_PATH\`**: All 23 team tools return \`{ success: false, error: "Team collaboration is not configured..." }\` \u2014 no crash, no partial results.
2984
+ - **Team tools without \`TEAM_DB_PATH\`**: All 25 team tools return \`{ success: false, error: "Team collaboration is not configured..." }\` \u2014 no crash, no partial results.
2961
2985
  `;
2962
2986
  function generateInstructions(enabledTools, prompts, latestEntry, level = "standard", enabledGroups) {
2963
2987
  const groups = enabledGroups ?? getEnabledGroups(enabledTools);
@@ -4990,15 +5014,41 @@ function getTemplateResourceDefinitions() {
4990
5014
  // src/handlers/resources/team.ts
4991
5015
  function enrichWithAuthor(entries, context) {
4992
5016
  const teamDb = context.teamDb;
4993
- if (!teamDb) return entries.map((e) => ({ ...e, author: null }));
4994
- return entries.map((e) => {
4995
- const authorResult = teamDb.executeRawQuery(
4996
- "SELECT author FROM memory_journal WHERE id = ?",
4997
- [e.id]
4998
- );
4999
- const author = authorResult[0]?.values[0]?.[0] ?? null;
5000
- return { ...e, author };
5001
- });
5017
+ if (!teamDb || entries.length === 0) return entries.map((e) => ({ ...e, author: null }));
5018
+ const ids = entries.map((e) => e.id);
5019
+ const placeholders = ids.map(() => "?").join(",");
5020
+ const authorResult = teamDb.executeRawQuery(
5021
+ `SELECT id, author FROM memory_journal WHERE id IN (${placeholders})`,
5022
+ ids
5023
+ );
5024
+ const authorMap = /* @__PURE__ */ new Map();
5025
+ if (authorResult[0]) {
5026
+ authorResult[0].values.forEach((row) => {
5027
+ authorMap.set(row[0], row[1]);
5028
+ });
5029
+ }
5030
+ return entries.map((e) => ({
5031
+ ...e,
5032
+ author: authorMap.get(e.id) ?? null
5033
+ }));
5034
+ }
5035
+ function parseFlagAutoContext(autoContext) {
5036
+ if (!autoContext) return null;
5037
+ try {
5038
+ const parsed = JSON.parse(autoContext);
5039
+ if (typeof parsed === "object" && parsed !== null && "flag_type" in parsed && "resolved" in parsed) {
5040
+ const ctx = parsed;
5041
+ return {
5042
+ flag_type: String(ctx["flag_type"]),
5043
+ target_user: typeof ctx["target_user"] === "string" ? ctx["target_user"] : null,
5044
+ resolved: Boolean(ctx["resolved"]),
5045
+ link: typeof ctx["link"] === "string" ? ctx["link"] : null
5046
+ };
5047
+ }
5048
+ return null;
5049
+ } catch {
5050
+ return null;
5051
+ }
5002
5052
  }
5003
5053
  function getTeamResourceDefinitions() {
5004
5054
  return [
@@ -5077,6 +5127,77 @@ function getTeamResourceDefinitions() {
5077
5127
  }
5078
5128
  };
5079
5129
  }
5130
+ },
5131
+ // ====================================================================
5132
+ // Flag Resources (Hush Protocol)
5133
+ // ====================================================================
5134
+ {
5135
+ uri: "memory://flags",
5136
+ name: "Active Flags",
5137
+ title: "Active Team Flags Dashboard",
5138
+ description: "Active (unresolved) flags from the Hush Protocol. Shows machine-actionable developer signals that need attention. Requires TEAM_DB_PATH.",
5139
+ mimeType: "application/json",
5140
+ icons: [ICON_FLAG],
5141
+ annotations: withPriority(0.8, ASSISTANT_FOCUSED),
5142
+ handler: (_uri, context) => {
5143
+ if (!context.teamDb) {
5144
+ return {
5145
+ data: {
5146
+ error: "Team database not configured. Set TEAM_DB_PATH to enable.",
5147
+ activeFlags: [],
5148
+ count: 0
5149
+ }
5150
+ };
5151
+ }
5152
+ const flagEntries = context.teamDb.searchEntries("", {
5153
+ entryType: "flag",
5154
+ limit: 100
5155
+ });
5156
+ const enriched = enrichWithAuthor(flagEntries, context);
5157
+ const activeFlags = enriched.map((entry) => {
5158
+ const flagCtx = parseFlagAutoContext(entry.autoContext);
5159
+ if (!flagCtx || flagCtx.resolved) return null;
5160
+ return {
5161
+ id: entry.id,
5162
+ flag_type: flagCtx.flag_type,
5163
+ target_user: flagCtx.target_user,
5164
+ link: flagCtx.link,
5165
+ author: entry.author,
5166
+ timestamp: entry.timestamp,
5167
+ preview: entry.content.slice(0, 120) + (entry.content.length > 120 ? "..." : ""),
5168
+ tags: entry.tags,
5169
+ projectNumber: entry.projectNumber ?? null
5170
+ };
5171
+ }).filter((f) => f !== null);
5172
+ const lastModified = activeFlags[0]?.timestamp ?? (/* @__PURE__ */ new Date()).toISOString();
5173
+ return {
5174
+ data: {
5175
+ activeFlags,
5176
+ count: activeFlags.length
5177
+ },
5178
+ annotations: { lastModified }
5179
+ };
5180
+ }
5181
+ },
5182
+ {
5183
+ uri: "memory://flags/vocabulary",
5184
+ name: "Flag Vocabulary",
5185
+ title: "Hush Protocol Flag Vocabulary",
5186
+ description: "Returns the configured flag vocabulary for the Hush Protocol. Static resource reflecting server-wide configuration.",
5187
+ mimeType: "application/json",
5188
+ icons: [ICON_FLAG],
5189
+ annotations: { ...MEDIUM_PRIORITY, audience: ["assistant"] },
5190
+ handler: (_uri, context) => {
5191
+ const custom = context.briefingConfig?.flagVocabulary;
5192
+ const vocabulary = custom && custom.length > 0 ? custom : [...DEFAULT_FLAG_VOCABULARY];
5193
+ return {
5194
+ data: {
5195
+ vocabulary,
5196
+ count: vocabulary.length,
5197
+ isDefault: !custom || custom.length === 0
5198
+ }
5199
+ };
5200
+ }
5080
5201
  }
5081
5202
  ];
5082
5203
  }
@@ -5289,7 +5410,7 @@ function getHelpResourceDefinitions() {
5289
5410
  var toolIndexModule = null;
5290
5411
  async function getAllToolDefinitionsAsync(context) {
5291
5412
  try {
5292
- toolIndexModule ??= await import('./tools-WZUENKJ6.js');
5413
+ toolIndexModule ??= await import('./tools-HTE4YXMW.js');
5293
5414
  if (toolIndexModule === null) return [];
5294
5415
  const tools = toolIndexModule.getTools(context.db, null);
5295
5416
  return tools.map((t) => ({
@@ -5433,7 +5554,7 @@ var teamCollaborationResource = {
5433
5554
  try {
5434
5555
  const matrix = computeTeamCollaborationMatrix(context.teamDb);
5435
5556
  return {
5436
- data: { success: true, ...matrix },
5557
+ data: { success: true, matrix },
5437
5558
  annotations: { lastModified }
5438
5559
  };
5439
5560
  } catch (error) {
@@ -6596,7 +6717,23 @@ function setupStateful(ctx, app, server) {
6596
6717
  }
6597
6718
  };
6598
6719
  if (ctx.serverConnected) {
6599
- await server.close();
6720
+ try {
6721
+ await Promise.race([
6722
+ server.close(),
6723
+ new Promise(
6724
+ (_, reject) => setTimeout(() => reject(new Error("Timeout closing SDK transport")), 250)
6725
+ )
6726
+ ]);
6727
+ } catch (e) {
6728
+ logger.error("Forcing server transport close due to timeout", {
6729
+ module: "HTTP",
6730
+ error: e instanceof Error ? e.message : String(e)
6731
+ });
6732
+ const internalServer = server;
6733
+ if (internalServer.server !== void 0 && typeof internalServer.server._onclose === "function") {
6734
+ internalServer.server._onclose();
6735
+ }
6736
+ }
6600
6737
  }
6601
6738
  await server.connect(newTransport);
6602
6739
  ctx.serverConnected = true;
@@ -7168,7 +7305,8 @@ async function createServer(options) {
7168
7305
  } : void 0;
7169
7306
  const customToolHandlerConfig = {
7170
7307
  defaultProjectNumber,
7171
- projectRegistry: options.projectRegistry
7308
+ projectRegistry: options.projectRegistry,
7309
+ flagVocabulary: options.flagVocabulary
7172
7310
  };
7173
7311
  const allTools = getTools(
7174
7312
  db,
@@ -7331,7 +7469,8 @@ async function createServer(options) {
7331
7469
  // Ensure defaultProjectNumber is available to resource handlers
7332
7470
  // (may come via briefingConfig from CLI, or directly from server options)
7333
7471
  defaultProjectNumber: options.briefingConfig?.defaultProjectNumber ?? defaultProjectNumber,
7334
- projectRegistry: options.projectRegistry
7472
+ projectRegistry: options.projectRegistry,
7473
+ flagVocabulary: options.flagVocabulary
7335
7474
  };
7336
7475
  const result = await readResource(
7337
7476
  uri.href,
package/dist/cli.js CHANGED
@@ -1,5 +1,5 @@
1
- import { VERSION, createServer } from './chunk-5ZA77VUW.js';
2
- import { DEFAULT_AUDIT_LOG_MAX_SIZE_BYTES } from './chunk-P5V2VY6N.js';
1
+ import { VERSION, createServer } from './chunk-XNOUTCRV.js';
2
+ import { DEFAULT_AUDIT_LOG_MAX_SIZE_BYTES } from './chunk-VHA46GLM.js';
3
3
  import './chunk-OKOVZ5QE.js';
4
4
  import { logger } from './chunk-WXDEVIFL.js';
5
5
  import { Command } from 'commander';
@@ -109,6 +109,9 @@ program.name("memory-journal-mcp").description("Project context management for A
109
109
  ).option(
110
110
  "--workflow-summary <text>",
111
111
  "Workflow summary for memory://workflows resource (env: MEMORY_JOURNAL_WORKFLOW_SUMMARY)"
112
+ ).option(
113
+ "--flag-vocabulary <terms>",
114
+ "Comma-separated flag vocabulary for Hush Protocol (env: FLAG_VOCABULARY, default: blocker,needs_review,help_requested,fyi)"
112
115
  ).action(
113
116
  async (options) => {
114
117
  logger.setLevel(options.logLevel);
@@ -217,7 +220,12 @@ program.name("memory-journal-mcp").description("Project context management for A
217
220
  defaultProjectNumber: options.defaultProject ? parseInt(options.defaultProject, 10) : process.env["DEFAULT_PROJECT_NUMBER"] ? parseInt(process.env["DEFAULT_PROJECT_NUMBER"], 10) : void 0
218
221
  },
219
222
  instructionLevel: options.instructionLevel !== "standard" ? options.instructionLevel : process.env["INSTRUCTION_LEVEL"] ?? "standard",
220
- auditConfig
223
+ auditConfig,
224
+ flagVocabulary: (() => {
225
+ const raw = options.flagVocabulary ?? process.env["FLAG_VOCABULARY"];
226
+ if (!raw) return void 0;
227
+ return raw.split(",").map((s) => s.trim().toLowerCase()).filter(Boolean);
228
+ })()
221
229
  });
222
230
  } catch (error) {
223
231
  logger.error("Failed to start server", {
package/dist/index.d.ts CHANGED
@@ -38,7 +38,7 @@ interface ToolFilterConfig {
38
38
  /**
39
39
  * Entry types for journal entries
40
40
  */
41
- type EntryType = 'personal_reflection' | 'project_decision' | 'technical_achievement' | 'bug_fix' | 'feature_implementation' | 'code_review' | 'meeting_notes' | 'learning' | 'research' | 'planning' | 'retrospective' | 'standup' | 'technical_note' | 'development_note' | 'enhancement' | 'milestone' | 'system_integration_test' | 'test_entry' | 'other';
41
+ type EntryType = 'personal_reflection' | 'project_decision' | 'technical_achievement' | 'bug_fix' | 'feature_implementation' | 'code_review' | 'meeting_notes' | 'learning' | 'research' | 'planning' | 'retrospective' | 'standup' | 'technical_note' | 'development_note' | 'enhancement' | 'milestone' | 'flag' | 'system_integration_test' | 'test_entry' | 'other';
42
42
  /**
43
43
  * Significance types for important entries
44
44
  */
@@ -82,6 +82,7 @@ interface JournalEntry {
82
82
  workflowRunId?: number | null;
83
83
  workflowName?: string | null;
84
84
  workflowStatus?: string | null;
85
+ importanceScore?: number;
85
86
  }
86
87
  /**
87
88
  * Tag entity
@@ -330,6 +331,8 @@ interface ServerConfig {
330
331
  modelName: string;
331
332
  /** Briefing depth for AI client instructions */
332
333
  instructionLevel?: 'essential' | 'standard' | 'full';
334
+ /** Hush Protocol flag vocabulary (defaults: blocker, needs_review, help_requested, fyi) */
335
+ flagVocabulary?: string[];
333
336
  }
334
337
  /**
335
338
  * Default configuration values
@@ -525,7 +528,7 @@ type SandboxMode = 'vm' | 'worker';
525
528
  /**
526
529
  * Tool group definitions mapping group names to tool names
527
530
  *
528
- * All 68 tools are categorized here for filtering support.
531
+ * All 70 tools are categorized here for filtering support.
529
532
  */
530
533
  declare const TOOL_GROUPS: Record<ToolGroup, string[]>;
531
534
  /**
@@ -618,6 +621,8 @@ interface BriefingConfig {
618
621
  defaultProjectNumber?: number;
619
622
  /** Project registry mapping dynamic repo IDs to local paths and kanban boards */
620
623
  projectRegistry?: Record<string, ProjectRegistryEntry>;
624
+ /** Hush Protocol flag vocabulary passed from CLI/env */
625
+ flagVocabulary?: string[];
621
626
  }
622
627
 
623
628
  /** Audit log configuration */
@@ -664,6 +669,7 @@ interface ServerOptions {
664
669
  projectRegistry?: Record<string, ProjectRegistryEntry>;
665
670
  instructionLevel?: 'essential' | 'standard' | 'full';
666
671
  auditConfig?: AuditConfig;
672
+ flagVocabulary?: string[];
667
673
  }
668
674
  /**
669
675
  * Create and start the MCP server
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
- export { VERSION, createServer } from './chunk-5ZA77VUW.js';
2
- export { META_GROUPS, TOOL_GROUPS, calculateTokenSavings, filterTools, getAllToolNames, getFilterSummary, getToolFilterFromEnv, getToolGroup, isToolEnabled, parseToolFilter } from './chunk-P5V2VY6N.js';
1
+ export { VERSION, createServer } from './chunk-XNOUTCRV.js';
2
+ export { META_GROUPS, TOOL_GROUPS, calculateTokenSavings, filterTools, getAllToolNames, getFilterSummary, getToolFilterFromEnv, getToolGroup, isToolEnabled, parseToolFilter } from './chunk-VHA46GLM.js';
3
3
  import './chunk-OKOVZ5QE.js';
4
4
  export { logger } from './chunk-WXDEVIFL.js';
5
5
 
@@ -1,3 +1,3 @@
1
- export { callTool, getGlobalAuditLogger, getTools, initializeAuditLogger } from './chunk-P5V2VY6N.js';
1
+ export { callTool, getGlobalAuditLogger, getTools, initializeAuditLogger } from './chunk-VHA46GLM.js';
2
2
  import './chunk-OKOVZ5QE.js';
3
3
  import './chunk-WXDEVIFL.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "memory-journal-mcp",
3
- "version": "7.4.0",
3
+ "version": "7.5.0",
4
4
  "description": "Project context management for AI-assisted development - Persistent knowledge graphs and intelligent context recall across fragmented AI threads",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -88,6 +88,7 @@
88
88
  "overrides": {
89
89
  "axios": "^1.13.6",
90
90
  "brace-expansion": "^2.0.2",
91
+ "diff": "9.0.0",
91
92
  "glob": "^11.1.0",
92
93
  "onnxruntime-web": "npm:empty-npm-package@1.0.0",
93
94
  "sharp": "npm:empty-npm-package@1.0.0",
package/skills/README.md CHANGED
@@ -45,6 +45,7 @@ The markdown body contains the full instructions the agent follows once the skil
45
45
  | `docker` | Production-grade Docker — multi-stage builds, security hardening, Compose v2, BuildKit, and CI/CD integration |
46
46
  | `github-actions` | GitHub Actions CI/CD — SHA pinning, reusable workflows, caching, matrix strategies, and artifacts v4 |
47
47
  | `github-commander` | GitHub pipeline workflows for orchestrating issues, regressions, and deployments |
48
+ | `github-copilot-cli` | Adversarial pre-push validation and full repository code audits driven by the @github/copilot terminal harness |
48
49
  | `gitlab` | Specialized assistant skill for managing repositories, code search, and CI/CD in GitLab |
49
50
  | `golang` | Master Go development with production-grade best practices from Google and Uber style guides |
50
51
  | `mysql` | Enterprise MySQL production rules — query safety, connection pooling, strict schema configurations |
@@ -67,6 +68,7 @@ This package natively bundles the `github-commander` skill, which equips your AI
67
68
  - **`issue-triage`**: End-to-end bug replication, PR submission, and Kanban lifecycle linking.
68
69
  - **`milestone-sprint`**: Sequential traversal of all open issues mapped to a specific release target.
69
70
  - **`pr-review`**: Exhaustive local execution, typechecking, and heuristic code reviews against base branches.
71
+ - **`copilot-audit`**: AI-evaluating-AI adversarial evaluations covering localized diffs and whole codebases.
70
72
  - **`security-audit`**: Deep Trivy/CodeQL supply chain matrix evaluation.
71
73
  - **`code-quality-audit`**: Enforcement of project guidelines, strict-typing boundaries, and import normalization.
72
74
  - **`perf-audit`**: Bundle-size constraints, runtime hot-path execution, and CI/CD cache-hit evaluations.
@@ -39,6 +39,7 @@ Load this skill when any of these apply:
39
39
  | ----------------------- | --------------------------------- | ------------------------------------------- |
40
40
  | **Issue Triage** | `workflows/issue-triage.md` | Fix a single GitHub issue end-to-end |
41
41
  | **PR Review** | `workflows/pr-review.md` | Review a PR with validation pipeline |
42
+ | **Copilot Audit** | `workflows/copilot-audit.md` | Adversarial Copilot CLI repo/PR review |
42
43
  | **Milestone Sprint** | `workflows/milestone-sprint.md` | Work through milestone issues sequentially |
43
44
  | **Roadmap Kickoff** | `workflows/roadmap-kickoff.md` | Translate planning epics into Kanban issues |
44
45
  | **Update Dependencies** | `workflows/update-deps.md` | Dependency update with audit trail |