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.
package/README.md CHANGED
@@ -10,7 +10,7 @@
10
10
  [![MCP Registry](https://img.shields.io/badge/MCP_Registry-Published-green)](https://registry.modelcontextprotocol.io/v0/servers?search=io.github.neverinfamous/memory-journal-mcp)
11
11
  [![Security](https://img.shields.io/badge/Security-Enhanced-green.svg)](SECURITY.md)
12
12
  [![TypeScript](https://img.shields.io/badge/TypeScript-Strict-blue.svg)](https://github.com/neverinfamous/memory-journal-mcp)
13
- ![Coverage](https://img.shields.io/badge/Coverage-96.5%25-brightgreen.svg)
13
+ ![Coverage](https://img.shields.io/badge/Coverage-95.83%25-brightgreen.svg)
14
14
  ![Tests](https://img.shields.io/badge/Tests-1782_passed-brightgreen.svg)
15
15
  ![E2E Tests](https://img.shields.io/badge/E2E_Tests-391_passed-brightgreen.svg)
16
16
  [![CI](https://github.com/neverinfamous/memory-journal-mcp/actions/workflows/gatekeeper.yml/badge.svg)](https://github.com/neverinfamous/memory-journal-mcp/actions/workflows/gatekeeper.yml)
@@ -51,7 +51,7 @@ Memory Journal solves this by acting as your project's **long-term memory**, bri
51
51
 
52
52
  ## 🎯 What Sets Us Apart
53
53
 
54
- **68 MCP Tools** · **17 Workflow Prompts** · **34 Resources** · **10 Tool Groups** · **Code Mode** · **GitHub Commander** (Issue Triage, PR Review, Milestone Sprints, Security/Quality/Perf Audits) · **GitHub Integration** (Issues, PRs, Actions, Kanban, Milestones, Insights) · **Team Collaboration** (Shared DB, Vector Search, Cross-Project Insights)
54
+ **70 MCP Tools** · **17 Workflow Prompts** · **36 Resources** · **10 Tool Groups** · **Code Mode** · **GitHub Commander** (Issue Triage, PR Review, Milestone Sprints, Security/Quality/Perf Audits) · **GitHub Integration** (Issues, PRs, Actions, Kanban, Milestones, Insights) · **Team Collaboration** (Shared DB, Vector Search, Cross-Project Insights, Hush Protocol Flags)
55
55
 
56
56
  | Feature | Description |
57
57
  | ----------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
@@ -61,9 +61,10 @@ Memory Journal solves this by acting as your project's **long-term memory**, bri
61
61
  | **Knowledge Graphs** | 8 relationship types linking specs → implementations → tests → PRs with Mermaid visualization |
62
62
  | **Hybrid Search** | Reciprocal Rank Fusion combining FTS5 keywords, semantic vector similarity, auto-heuristics, and date-range filters |
63
63
  | **Code Mode** | Execute multi-step operations in a secure sandbox — up to 90% token savings via `mj.*` API |
64
- | **Configurable Briefing** | 14 env vars / CLI flags control `memory://briefing` content — entries, team, GitHub detail, skills awareness |
64
+ | **Configurable Briefing** | 15 env vars / CLI flags control `memory://briefing` content — entries, team, GitHub detail, skills awareness, chronological grounding |
65
65
  | **Reports & Analytics** | Standups, retrospectives, PR summaries, digests, period analyses, and milestone tracking |
66
- | **Team Collaboration** | 23 tools with full parity CRUD, vector search, relationship graphs, cross-project insights, author attribution |
66
+ | **Hush Protocol (Flags)** | Replace Slack/Teams noise with structured, actionable, and searchable AI flags (blockers, reviews) that automatically surface in session briefings |
67
+ | **Team Collaboration** | 25 tools with full parity — CRUD, vector search, relationship graphs, cross-project insights, author attribution, Hush Protocol flags |
67
68
  | **Data Interoperability** | Bidirectional Markdown roundtripping, unified IO namespace, and schema-safe JSON exports with hard bounds-checked path traversal defenses |
68
69
  | **Backup & Restore** | One-command backup/restore with automated scheduling, retention policies, and safety-net auto-backups |
69
70
  | **Security & Transport** | OAuth 2.1 (RFC 9728/8414, JWT/JWKS, scopes), Streamable HTTP + SSE, rate limiting, CORS, SQL injection prevention, non-root Docker |
@@ -117,7 +118,7 @@ flowchart TB
117
118
  ---
118
119
 
119
120
  <details>
120
- <summary><strong>🤖 Click to view the recommended AI Agent Instructions/Rule</strong></summary>
121
+ <summary><strong>🤖 Recommended AI Agent Instructions/Rule</strong></summary>
121
122
 
122
123
  _Suggested Rule (Add to AGENTS.md, GEMINI.md, system prompts, etc.)_
123
124
 
@@ -134,8 +135,10 @@ Execute BEFORE fulfilling any user request in a new session:
134
135
  - **REQUIRED GROUPS**:
135
136
  - **GitHub**: Combine Repo, Branch, CI, PRs, and Insights.
136
137
  - **GitHub Issues**: List every issue, one per line.
137
- - Also include Entry Counts (Journal/Team), Latest Entries/Summaries, Proactive Analytics/Team Density, Milestones, and Workspaces.
138
- 4. **STOP & WAIT**: After rendering the table, execute the user's prompt but do NOT autonomously resume past tasks or start work on new issues mentioned in the session summary. The briefing is strictly for context.
138
+ - **Active Flags (Hush Protocol)**: If the briefing JSON contains an `activeFlags` object (with `count > 0`), render each flag in a dedicated row using format: `🚩 {flag_type} → @{target_user}: {preview}`. If `count` is 0 or the field is absent, omit the row entirely.
139
+ - Also include Entry Counts (Journal/Team), Latest Entries/Summaries (titles only), Proactive Analytics/Team Density, Milestones, and Workspaces.
140
+ - **FLAG PROMINENCE**: When `activeFlags.count > 0`, prepend a bold callout line **above** the table: `⚠️ **{count} active flag(s)** — review before proceeding.` This ensures blockers and review requests are impossible to miss.
141
+ 4. **STOP & WAIT**: Do NOT autonomously resume past tasks or start work on new issues mentioned in the session summary. The briefing is strictly for context.
139
142
 
140
143
  </details>
141
144
 
@@ -150,11 +153,11 @@ Control which tools are exposed via `MEMORY_JOURNAL_MCP_TOOL_FILTER` (or CLI: `-
150
153
 
151
154
  | Filter | Tools | Use Case |
152
155
  | -------------------- | ----- | ------------------------ |
153
- | `full` | 68 | All tools (default) |
156
+ | `full` | 70 | All tools (default) |
154
157
  | `starter` | ~11 | Core + search + codemode |
155
158
  | `essential` | ~7 | Minimal footprint |
156
159
  | `readonly` | 18 | Disable all mutations |
157
- | `-github` | 50 | Exclude a group |
160
+ | `-github` | 52 | Exclude a group |
158
161
  | `-github,-analytics` | 48 | Exclude multiple groups |
159
162
 
160
163
  **Filter Syntax:** `shortcut` or `group` or `tool_name` (whitelist mode) · `-group` (disable group) · `-tool` (disable tool) · `+tool` (re-enable after group disable)
@@ -169,20 +172,20 @@ Control which tools are exposed via `MEMORY_JOURNAL_MCP_TOOL_FILTER` (or CLI: `-
169
172
 
170
173
  ## 📋 Core Capabilities
171
174
 
172
- ### 🛠️ **68 MCP Tools** (10 Groups)
173
-
174
- | Group | Tools | Description |
175
- | --------------- | ----- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
176
- | `codemode` | 1 | Code Mode (sandboxed code execution) 🌟 **Recommended** |
177
- | `core` | 6 | Entry CRUD, tags, test |
178
- | `search` | 4 | Text search, date range, semantic, vector stats |
179
- | `analytics` | 2 | Statistics, cross-project insights |
180
- | `relationships` | 2 | Link entries, visualize graphs |
181
- | `io` | 3 | JSON/Markdown export and File-level Markdown Data Integration Interoperability (Import/Export) |
182
- | `admin` | 5 | Update, delete, rebuild/add to vector index, merge tags |
183
- | `github` | 18 | Issues, PRs, context, Kanban, **Milestones**, **Insights**, **issue lifecycle**, **Copilot Reviews** |
184
- | `backup` | 4 | Backup, list, restore, cleanup |
185
- | `team` | 23 | CRUD, search, stats, relationships, IO (Markdown import/export), backup, vector search, cross-project insights, matrix (requires `TEAM_DB_PATH`) |
175
+ ### 🛠️ **70 MCP Tools** (10 Groups)
176
+
177
+ | Group | Tools | Description |
178
+ | --------------- | ----- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
179
+ | `codemode` | 1 | Code Mode (sandboxed code execution) 🌟 **Recommended** |
180
+ | `core` | 6 | Entry CRUD, tags, test |
181
+ | `search` | 4 | Text search, date range, semantic, vector stats |
182
+ | `analytics` | 2 | Statistics, cross-project insights |
183
+ | `relationships` | 2 | Link entries, visualize graphs |
184
+ | `io` | 3 | JSON/Markdown export and File-level Markdown Data Integration Interoperability (Import/Export) |
185
+ | `admin` | 5 | Update, delete, rebuild/add to vector index, merge tags |
186
+ | `github` | 18 | Issues, PRs, context, Kanban, **Milestones**, **Insights**, **issue lifecycle**, **Copilot Reviews** |
187
+ | `backup` | 4 | Backup, list, restore, cleanup |
188
+ | `team` | 25 | CRUD, search, stats, relationships, IO (Markdown import/export), backup, vector search, cross-project insights, matrix, **Hush Protocol flags** (requires `TEAM_DB_PATH`) |
186
189
 
187
190
  **[Complete tools reference →](https://github.com/neverinfamous/memory-journal-mcp/wiki/Tools)**
188
191
 
@@ -209,11 +212,11 @@ Control which tools are exposed via `MEMORY_JOURNAL_MCP_TOOL_FILTER` (or CLI: `-
209
212
 
210
213
  **[Complete prompts guide →](https://github.com/neverinfamous/memory-journal-mcp/wiki/Prompts)**
211
214
 
212
- ### 📡 **34 Resources** (25 Static + 9 Template)
215
+ ### 📡 **36 Resources** (27 Static + 9 Template)
213
216
 
214
217
  **Static Resources** (appear in resource lists):
215
218
 
216
- - `memory://briefing` - **Session initialization**: compact context for AI agents (~300 tokens)
219
+ - `memory://briefing` - **Session initialization**: compact context for AI agents (~300 tokens) — includes `localTime` and optional `activeFlags`
217
220
  - `memory://instructions` - **Behavioral guidance**: complete server instructions for AI agents
218
221
  - `memory://recent` - 10 most recent entries
219
222
  - `memory://significant` - Significant milestones and breakthroughs
@@ -238,6 +241,8 @@ Control which tools are exposed via `MEMORY_JOURNAL_MCP_TOOL_FILTER` (or CLI: `-
238
241
  - `memory://metrics/system` - Process-level metrics: memory (MB), uptime (s), Node.js version, platform — MEDIUM priority
239
242
  - `memory://metrics/users` - Per-user call counts (populated when OAuth user identifiers are present) — LOW priority
240
243
  - `memory://audit` - Last 50 write/admin tool call entries from the JSONL audit log (requires `AUDIT_LOG_PATH`)
244
+ - `memory://flags` - Active (unresolved) team flags dashboard (requires `TEAM_DB_PATH`)
245
+ - `memory://flags/vocabulary` - Configured flag vocabulary terms
241
246
 
242
247
  **Template Resources** (require parameters, fetch directly by URI):
243
248
 
@@ -264,12 +269,12 @@ Code executes in a **sandboxed VM context** with multiple layers of security. Al
264
269
  - **Static code validation** — blocked patterns include `require()`, `process`, `eval()`, and filesystem access
265
270
  - **Rate limiting** — 60 executions per minute per client
266
271
  - **Hard timeouts** — configurable execution limit (default 30s)
267
- - **Full API access** — all 10 tool groups are available via `mj.*` (e.g., `mj.core.createEntry()`, `mj.search.searchEntries()`, `mj.github.getGithubIssues()`, `mj.analytics.getStatistics()`)
272
+ - **Full API access** — all 10 tool groups are available via `mj.*` (e.g., `mj.core.createEntry()`, `mj.search.searchEntries()`, `mj.github.getGithubIssues()`, `mj.team.passTeamFlag()`)
268
273
  - **Strict Readonly Contract** — Calling any mutation method under `--tool-filter readonly` safely halts the sandbox to prevent execution, returning a structured `{ success: false, error: "..." }` response to the agent instead of a raw MCP protocol exception.
269
274
 
270
275
  ### ⚡ Code Mode Only (Maximum Token Savings)
271
276
 
272
- Run with **only Code Mode enabled** — a single tool that provides access to all 67 tools' worth of capability through the `mj.*` API:
277
+ Run with **only Code Mode enabled** — a single tool that provides access to all 69 tools' worth of capability through the `mj.*` API:
273
278
 
274
279
  ```json
275
280
  {
@@ -296,6 +301,20 @@ If you prefer individual tool calls, exclude codemode:
296
301
 
297
302
  ---
298
303
 
304
+ ## 🤫 Hush Protocol: Asynchronous Team Collaboration
305
+
306
+ The **Hush Protocol** reimagines team collaboration for AI-augmented workflows by replacing noisy Slack/Teams messages with structured, machine-actionable flags.
307
+
308
+ When you encounter a blocker, need a review, or want to broadcast a milestone, your AI agent can raise a flag in the shared Team Database:
309
+
310
+ - **Actionable Visibility**: Active flags automatically surface at the very top of the `memory://briefing` payload for all team members. When another developer's agent starts a session, it immediately sees your blockers and can help resolve them autonomously.
311
+ - **Structured Types**: Raise specific flag types (`blocker`, `needs_review`, `help_requested`, `fyi`). You can customize your team's vocabulary via the `--flag-vocabulary` configuration.
312
+ - **Searchable History**: Unlike chat messages that disappear into the void, Hush flags are permanent, query-able AI journal entries. Your agents can search past `needs_review` flags to understand how architectural blockers were conquered.
313
+
314
+ **Dashboard & Operations**: Read `memory://flags` to see an active dashboard overview and use `mj.team.passTeamFlag()` / `mj.team.resolveTeamFlag()` to manage them programmatically in Code Mode.
315
+
316
+ ---
317
+
299
318
  ## 🚀 Quick Start
300
319
 
301
320
  ### Option 1: npm (Recommended)
@@ -527,6 +546,7 @@ The GitHub tools (`get_github_issues`, `get_github_prs`, etc.) auto-detect the r
527
546
  | `AUDIT_READS` | Log read-scoped tool calls in addition to write/admin (CLI: `--audit-reads`; default: `false`) |
528
547
  | `AUDIT_LOG_MAX_SIZE` | Maximum audit log file size in bytes before rotation (CLI: `--audit-log-max-size`; default: `10485760`) |
529
548
  | `MCP_METRICS_ENABLED` | Set to `false` to disable in-memory tool call metrics accumulation (default: `true`) |
549
+ | `FLAG_VOCABULARY` | Comma-separated flag types for Hush Protocol (CLI: `--flag-vocabulary`; default: `blocker,needs_review,help_requested,fyi`) |
530
550
 
531
551
  **Multi-Project Workflows**: For agents to seamlessly support multiple projects, provide **`PROJECT_REGISTRY`**.
532
552
 
@@ -630,7 +650,7 @@ Memory Journal provides a **hybrid approach** to GitHub management:
630
650
 
631
651
  ### GitHub Commander Workflows
632
652
 
633
- The server natively bundles the `github-commander` agent skill (accessible via `memory://skills/github-commander`). This extends your AI assistant with 8 autonomous DevOps workflows for repository stewardship: **Issue Triage**, **Milestone Sprints**, **PR Reviews**, **Security Audits**, **Code Quality Audits**, **Performance Audits**, **Roadmap Kickoffs**, and **Dependency Updates**. Configure validation layers using the `PROJECT_*` environment overrides to enforce CI-matching execution locally during agent tasks!
653
+ The server natively bundles the `github-commander` agent skill (accessible via `memory://skills/github-commander`). This extends your AI assistant with 9 autonomous DevOps workflows for repository stewardship: **Issue Triage**, **Milestone Sprints**, **PR Reviews**, **Copilot Audits**, **Security Audits**, **Code Quality Audits**, **Performance Audits**, **Roadmap Kickoffs**, and **Dependency Updates**. Configure validation layers using the `PROJECT_*` environment overrides to enforce CI-matching execution locally during agent tasks!
634
654
 
635
655
  ## 🏗️ Architecture
636
656
 
@@ -641,8 +661,8 @@ flowchart TB
641
661
  AI["🤖 AI Agent<br/>(Cursor, Windsurf, Claude)"]
642
662
 
643
663
  subgraph MCP["Memory Journal MCP Server"]
644
- Tools["🛠️ 67 Tools"]
645
- Resources["📡 34 Resources"]
664
+ Tools["🛠️ 70 Tools"]
665
+ Resources["📡 36 Resources"]
646
666
  Prompts["💬 17 Prompts"]
647
667
  end
648
668
 
@@ -670,7 +690,7 @@ flowchart TB
670
690
  ┌─────────────────────────────────────────────────────────────┐
671
691
  │ MCP Server Layer (TypeScript) │
672
692
  │ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────┐ │
673
- │ │ Tools (67) │ │ Resources (34) │ │ Prompts (17)│ │
693
+ │ │ Tools (70) │ │ Resources (36) │ │ Prompts (17)│ │
674
694
  │ │ with Annotations│ │ with Annotations│ │ │ │
675
695
  │ └─────────────────┘ └─────────────────┘ └─────────────┘ │
676
696
  ├─────────────────────────────────────────────────────────────┤
@@ -100,6 +100,7 @@ var ENTRY_TYPES = [
100
100
  "development_note",
101
101
  "enhancement",
102
102
  "milestone",
103
+ "flag",
103
104
  "system_integration_test",
104
105
  "test_entry",
105
106
  "other"
@@ -114,7 +115,7 @@ var SIGNIFICANCE_TYPES = [
114
115
  "release"
115
116
  ];
116
117
  var MAX_CONTENT_LENGTH = 5e4;
117
- var MAX_QUERY_LIMIT = Number("500");
118
+ var MAX_QUERY_LIMIT = 500;
118
119
  var DATE_MIN_SENTINEL = "1970-01-01";
119
120
  var DATE_MAX_SENTINEL = "2999-12-31";
120
121
  var DATE_FORMAT_REGEX = /^\d{4}-\d{2}-\d{2}$/;
@@ -822,7 +823,7 @@ function getSearchTools(context) {
822
823
  );
823
824
  const entryIds = semanticResults.map((r) => r.entryId);
824
825
  const entriesMap = db.getEntriesByIds(entryIds);
825
- const entries = semanticResults.map((r) => {
826
+ let entries = semanticResults.map((r) => {
826
827
  const entry = entriesMap.get(r.entryId);
827
828
  if (!entry) return null;
828
829
  if (!passMetadataFilters(
@@ -832,7 +833,7 @@ function getSearchTools(context) {
832
833
  ))
833
834
  return null;
834
835
  return { ...entry, source: "personal" };
835
- }).filter((e) => e !== null).slice(0, input.limit);
836
+ }).filter((e) => e !== null);
836
837
  if (input.sort_by === "importance") {
837
838
  const scored = entries.map((e) => {
838
839
  const { score } = db.calculateImportance(e.id);
@@ -841,13 +842,9 @@ function getSearchTools(context) {
841
842
  scored.sort(
842
843
  (a, b) => (b.importanceScore ?? 0) - (a.importanceScore ?? 0)
843
844
  );
844
- return {
845
- success: true,
846
- entries: scored,
847
- count: scored.length,
848
- searchMode: isAuto ? "semantic (auto)" : "semantic"
849
- };
845
+ entries = scored;
850
846
  }
847
+ entries = entries.slice(0, input.limit);
851
848
  return {
852
849
  success: true,
853
850
  entries,
@@ -5143,6 +5140,55 @@ var TeamCollaborationMatrixOutputSchema = z.object({
5143
5140
  ).optional(),
5144
5141
  error: z.string().optional()
5145
5142
  }).extend(ErrorFieldsMixin.shape);
5143
+ var DEFAULT_FLAG_VOCABULARY = [
5144
+ "blocker",
5145
+ "needs_review",
5146
+ "help_requested",
5147
+ "fyi"
5148
+ ];
5149
+ var PassTeamFlagSchema = z.object({
5150
+ flag_type: z.string().min(1).describe("Flag type from vocabulary (e.g., blocker, needs_review)"),
5151
+ message: z.string().min(1).max(5e4).describe("Flag message describing the issue or request"),
5152
+ target_user: z.string().optional().describe("Target user to flag (e.g., @sarah)"),
5153
+ link: z.string().optional().describe("Related file path, URL, or reference"),
5154
+ project_number: z.number().optional(),
5155
+ issue_number: z.number().optional(),
5156
+ author: z.string().optional()
5157
+ });
5158
+ var PassTeamFlagSchemaMcp = z.object({
5159
+ flag_type: z.string().optional(),
5160
+ message: z.string().optional(),
5161
+ target_user: z.string().optional(),
5162
+ link: z.string().optional(),
5163
+ project_number: relaxedNumber().optional(),
5164
+ issue_number: relaxedNumber().optional(),
5165
+ author: z.string().optional()
5166
+ });
5167
+ var ResolveTeamFlagSchema = z.object({
5168
+ flag_id: z.number().describe("Entry ID of the flag to resolve"),
5169
+ resolution: z.string().optional().describe("Optional resolution comment")
5170
+ });
5171
+ var ResolveTeamFlagSchemaMcp = z.object({
5172
+ flag_id: relaxedNumber().optional(),
5173
+ resolution: z.string().optional()
5174
+ });
5175
+ var FlagOutputSchema = z.object({
5176
+ success: z.boolean().optional(),
5177
+ entry: TeamEntryOutputSchema.optional(),
5178
+ flag_type: z.string().optional(),
5179
+ target_user: z.string().nullable().optional(),
5180
+ resolved: z.boolean().optional(),
5181
+ author: z.string().optional(),
5182
+ error: z.string().optional()
5183
+ }).extend(ErrorFieldsMixin.shape);
5184
+ var ResolveFlagOutputSchema = z.object({
5185
+ success: z.boolean().optional(),
5186
+ entry: TeamEntryOutputSchema.optional(),
5187
+ flag_type: z.string().optional(),
5188
+ resolved: z.boolean().optional(),
5189
+ resolution: z.string().nullable().optional(),
5190
+ error: z.string().optional()
5191
+ }).extend(ErrorFieldsMixin.shape);
5146
5192
 
5147
5193
  // src/handlers/tools/team/core-tools.ts
5148
5194
  function getTeamCoreTools(context) {
@@ -5313,7 +5359,7 @@ function getTeamSearchTools(context) {
5313
5359
  return { ...TEAM_DB_ERROR_RESPONSE };
5314
5360
  }
5315
5361
  const { query, tags, limit, sort_by } = TeamSearchSchema.parse(params);
5316
- const searchLimit = tags && tags.length > 0 ? Math.min(Math.max(limit * 5, 50), 1e3) : limit;
5362
+ const searchLimit = tags && tags.length > 0 ? Math.min(Math.max(limit * 5, 50), MAX_QUERY_LIMIT) : limit;
5317
5363
  let entries;
5318
5364
  if (query) {
5319
5365
  entries = teamDb.searchEntries(query, {
@@ -5728,11 +5774,11 @@ function getTeamAnalyticsTools(context) {
5728
5774
  return { ...TEAM_DB_ERROR_RESPONSE };
5729
5775
  }
5730
5776
  const { period, limit } = TeamCollaborationMatrixSchema.parse(params);
5731
- const dateFormat = period === "week" ? "%Y-W%W" : period === "quarter" ? "%Y-Q" : "%Y-%m";
5777
+ const dateExpression = period === "week" ? `strftime('%Y-W%W', timestamp)` : period === "quarter" ? `strftime('%Y-Q', timestamp) || cast(((cast(strftime('%m', timestamp) as integer) + 2) / 3) as integer)` : `strftime('%Y-%m', timestamp)`;
5732
5778
  const activityResult = teamDb.executeRawQuery(
5733
5779
  `SELECT
5734
5780
  COALESCE(author, 'unknown') AS author,
5735
- strftime('${dateFormat}', timestamp) AS period,
5781
+ ${dateExpression} AS period,
5736
5782
  COUNT(*) AS entry_count
5737
5783
  FROM memory_journal
5738
5784
  WHERE deleted_at IS NULL
@@ -6543,6 +6589,191 @@ function getTeamVectorTools(context) {
6543
6589
  ];
6544
6590
  }
6545
6591
 
6592
+ // src/handlers/tools/team/flag-tools.ts
6593
+ function getVocabulary(context) {
6594
+ const custom = context.config?.flagVocabulary;
6595
+ return custom && custom.length > 0 ? custom : DEFAULT_FLAG_VOCABULARY;
6596
+ }
6597
+ function parseFlagContext(autoContext) {
6598
+ if (!autoContext) return void 0;
6599
+ try {
6600
+ const parsed = JSON.parse(autoContext);
6601
+ if (typeof parsed === "object" && parsed !== null && "flag_type" in parsed && "resolved" in parsed) {
6602
+ return parsed;
6603
+ }
6604
+ return void 0;
6605
+ } catch {
6606
+ return void 0;
6607
+ }
6608
+ }
6609
+ function getTeamFlagTools(context) {
6610
+ const { teamDb } = context;
6611
+ return [
6612
+ {
6613
+ name: "team_pass_flag",
6614
+ title: "Pass Team Flag",
6615
+ description: "Create a machine-actionable flag in the team database. Flags replace communication noise with structured, searchable signals. Vocabulary: blocker, needs_review, help_requested, fyi (configurable via FLAG_VOCABULARY).",
6616
+ group: "team",
6617
+ inputSchema: PassTeamFlagSchemaMcp,
6618
+ outputSchema: FlagOutputSchema,
6619
+ annotations: {
6620
+ readOnlyHint: false,
6621
+ destructiveHint: false,
6622
+ idempotentHint: false,
6623
+ openWorldHint: false
6624
+ },
6625
+ handler: (params) => {
6626
+ try {
6627
+ if (!teamDb) {
6628
+ return { ...TEAM_DB_ERROR_RESPONSE };
6629
+ }
6630
+ const input = PassTeamFlagSchema.parse(params);
6631
+ const vocabulary = getVocabulary(context);
6632
+ if (!vocabulary.includes(input.flag_type)) {
6633
+ return {
6634
+ success: false,
6635
+ error: `Invalid flag type: "${input.flag_type}". Valid types: ${vocabulary.join(", ")}`,
6636
+ code: "VALIDATION_ERROR",
6637
+ category: "validation",
6638
+ suggestion: `Use one of: ${vocabulary.join(", ")}`,
6639
+ recoverable: true
6640
+ };
6641
+ }
6642
+ const author = input.author ?? resolveAuthor();
6643
+ const targetUser = input.target_user?.replace(/^@/, "") ?? null;
6644
+ const flagContext = {
6645
+ flag_type: input.flag_type,
6646
+ target_user: targetUser,
6647
+ link: input.link ?? null,
6648
+ resolved: false,
6649
+ resolved_at: null,
6650
+ resolution: null,
6651
+ author
6652
+ };
6653
+ const contentPrefix = `flag:${input.flag_type}`;
6654
+ const targetSuffix = targetUser ? ` \u2014 @${targetUser}` : "";
6655
+ const content = `${contentPrefix}${targetSuffix}: ${input.message}`;
6656
+ const tags = [`flag:${input.flag_type}`];
6657
+ if (targetUser) {
6658
+ tags.push(`@${targetUser}`);
6659
+ }
6660
+ const entry = teamDb.createEntry({
6661
+ content,
6662
+ entryType: "flag",
6663
+ tags,
6664
+ isPersonal: false,
6665
+ autoContext: JSON.stringify(flagContext),
6666
+ projectNumber: input.project_number,
6667
+ issueNumber: input.issue_number
6668
+ });
6669
+ teamDb.executeRawQuery("UPDATE memory_journal SET author = ? WHERE id = ?", [
6670
+ author,
6671
+ entry.id
6672
+ ]);
6673
+ teamDb.flushSave();
6674
+ return {
6675
+ success: true,
6676
+ entry: { ...entry, author },
6677
+ flag_type: input.flag_type,
6678
+ target_user: targetUser,
6679
+ resolved: false,
6680
+ author
6681
+ };
6682
+ } catch (err) {
6683
+ return formatHandlerError(err);
6684
+ }
6685
+ }
6686
+ },
6687
+ {
6688
+ name: "team_resolve_flag",
6689
+ title: "Resolve Team Flag",
6690
+ description: "Mark a team flag as resolved with an optional resolution comment. Idempotent \u2014 resolving an already-resolved flag returns success with the existing state.",
6691
+ group: "team",
6692
+ inputSchema: ResolveTeamFlagSchemaMcp,
6693
+ outputSchema: ResolveFlagOutputSchema,
6694
+ annotations: {
6695
+ readOnlyHint: false,
6696
+ destructiveHint: false,
6697
+ idempotentHint: true,
6698
+ openWorldHint: false
6699
+ },
6700
+ handler: (params) => {
6701
+ try {
6702
+ if (!teamDb) {
6703
+ return { ...TEAM_DB_ERROR_RESPONSE };
6704
+ }
6705
+ const input = ResolveTeamFlagSchema.parse(params);
6706
+ const entry = teamDb.getEntryById(input.flag_id);
6707
+ if (!entry) {
6708
+ return {
6709
+ success: false,
6710
+ error: `Flag entry ${String(input.flag_id)} not found`,
6711
+ code: "RESOURCE_NOT_FOUND",
6712
+ category: "resource",
6713
+ suggestion: "Verify the flag entry ID and try again",
6714
+ recoverable: true
6715
+ };
6716
+ }
6717
+ if (entry.entryType !== "flag") {
6718
+ return {
6719
+ success: false,
6720
+ error: `Entry ${String(input.flag_id)} is not a flag (type: ${entry.entryType})`,
6721
+ code: "VALIDATION_ERROR",
6722
+ category: "validation",
6723
+ suggestion: "Use team_resolve_flag only on entries created by team_pass_flag",
6724
+ recoverable: true
6725
+ };
6726
+ }
6727
+ const flagCtx = parseFlagContext(entry.autoContext);
6728
+ if (!flagCtx) {
6729
+ return {
6730
+ success: false,
6731
+ error: `Flag entry ${String(input.flag_id)} has invalid auto_context`,
6732
+ code: "INTERNAL_ERROR",
6733
+ category: "internal",
6734
+ recoverable: false
6735
+ };
6736
+ }
6737
+ if (flagCtx.resolved) {
6738
+ const author2 = fetchAuthor(teamDb, input.flag_id);
6739
+ return {
6740
+ success: true,
6741
+ entry: { ...entry, author: author2 },
6742
+ flag_type: flagCtx.flag_type,
6743
+ resolved: true,
6744
+ resolution: flagCtx.resolution
6745
+ };
6746
+ }
6747
+ const updatedContext = {
6748
+ ...flagCtx,
6749
+ resolved: true,
6750
+ resolved_at: (/* @__PURE__ */ new Date()).toISOString(),
6751
+ resolution: input.resolution ?? null
6752
+ };
6753
+ const resolutionSuffix = input.resolution ? ` [RESOLVED: ${input.resolution}]` : " [RESOLVED]";
6754
+ const updatedContent = entry.content + resolutionSuffix;
6755
+ teamDb.executeRawQuery(
6756
+ "UPDATE memory_journal SET auto_context = ?, content = ? WHERE id = ?",
6757
+ [JSON.stringify(updatedContext), updatedContent, input.flag_id]
6758
+ );
6759
+ teamDb.flushSave();
6760
+ const updatedEntry = teamDb.getEntryById(input.flag_id);
6761
+ const author = fetchAuthor(teamDb, input.flag_id);
6762
+ return {
6763
+ success: true,
6764
+ entry: updatedEntry ? { ...updatedEntry, author } : void 0,
6765
+ flag_type: flagCtx.flag_type,
6766
+ resolved: true,
6767
+ resolution: input.resolution ?? null
6768
+ };
6769
+ } catch (err) {
6770
+ return formatHandlerError(err);
6771
+ }
6772
+ }
6773
+ }
6774
+ ];
6775
+ }
6776
+
6546
6777
  // src/handlers/tools/team/index.ts
6547
6778
  function getTeamTools(context) {
6548
6779
  return [
@@ -6554,7 +6785,8 @@ function getTeamTools(context) {
6554
6785
  ...getTeamExportTools(context),
6555
6786
  ...getTeamIoTools(context),
6556
6787
  ...getTeamBackupTools(context),
6557
- ...getTeamVectorTools(context)
6788
+ ...getTeamVectorTools(context),
6789
+ ...getTeamFlagTools(context)
6558
6790
  ];
6559
6791
  }
6560
6792
 
@@ -6639,7 +6871,11 @@ var METHOD_ALIASES = {
6639
6871
  vectorStats: "teamGetVectorIndexStats",
6640
6872
  rebuildIndex: "teamRebuildVectorIndex",
6641
6873
  addToIndex: "teamAddToVectorIndex",
6642
- insights: "teamGetCrossProjectInsights"
6874
+ insights: "teamGetCrossProjectInsights",
6875
+ passTeamFlag: "teamPassFlag",
6876
+ resolveTeamFlag: "teamResolveFlag",
6877
+ passFlag: "teamPassFlag",
6878
+ resolveFlag: "teamResolveFlag"
6643
6879
  }
6644
6880
  };
6645
6881
  var GROUP_EXAMPLES = {
@@ -6698,7 +6934,9 @@ var GROUP_EXAMPLES = {
6698
6934
  'mj.team.teamExportEntries({ format: "json" })',
6699
6935
  "mj.team.teamBackup()",
6700
6936
  'mj.team.teamSemanticSearch({ query: "deployment" })',
6701
- "mj.team.teamGetCrossProjectInsights()"
6937
+ "mj.team.teamGetCrossProjectInsights()",
6938
+ 'mj.team.passTeamFlag({ flag_type: "blocker", message: "FK constraint issue" })',
6939
+ "mj.team.resolveTeamFlag({ flag_id: 42 })"
6702
6940
  ]
6703
6941
  };
6704
6942
  var POSITIONAL_PARAM_MAP = {
@@ -6752,7 +6990,11 @@ var POSITIONAL_PARAM_MAP = {
6752
6990
  teamVisualizeRelationships: "entry_id",
6753
6991
  teamExportEntries: "format",
6754
6992
  teamSemanticSearch: "query",
6755
- teamAddToVectorIndex: "entry_id"
6993
+ teamAddToVectorIndex: "entry_id",
6994
+ teamPassFlag: "flag_type",
6995
+ teamResolveFlag: "flag_id",
6996
+ passTeamFlag: "flag_type",
6997
+ resolveTeamFlag: "flag_id"
6756
6998
  };
6757
6999
  var GROUP_PREFIX_MAP = {
6758
7000
  core: "",
@@ -7973,7 +8215,9 @@ var TOOL_GROUPS = {
7973
8215
  "team_rebuild_vector_index",
7974
8216
  "team_add_to_vector_index",
7975
8217
  "team_get_cross_project_insights",
7976
- "team_get_collaboration_matrix"
8218
+ "team_get_collaboration_matrix",
8219
+ "team_pass_flag",
8220
+ "team_resolve_flag"
7977
8221
  ],
7978
8222
  codemode: ["mj_execute_code"]
7979
8223
  };
@@ -8564,4 +8808,4 @@ function getAllToolDefinitions(context) {
8564
8808
  ];
8565
8809
  }
8566
8810
 
8567
- export { ASSISTANT_FOCUSED, BASE_SCOPES, DEFAULT_AUDIT_LOG_MAX_SIZE_BYTES, DEFAULT_BRIEFING_CONFIG, HIGH_PRIORITY, LOW_PRIORITY, MEDIUM_PRIORITY, META_GROUPS, SUPPORTED_SCOPES, TOOL_GROUPS, calculateTokenSavings, callTool, execQuery, filterTools, getAllToolNames, getAuditResourceDef, getEnabledGroups, getFilterSummary, getGlobalAuditLogger, getRequiredScope, getToolFilterFromEnv, getToolGroup, getTools, globalMetrics, hasScope, initializeAuditLogger, isResourceError, isToolEnabled, milestoneCompletionPct, parseScopes, parseToolFilter, resolveGitHubRepo, sendProgress, setDefaultSandboxMode, transformEntryRow, withPriority, withSessionInit };
8811
+ export { ASSISTANT_FOCUSED, BASE_SCOPES, DEFAULT_AUDIT_LOG_MAX_SIZE_BYTES, DEFAULT_BRIEFING_CONFIG, DEFAULT_FLAG_VOCABULARY, HIGH_PRIORITY, LOW_PRIORITY, MEDIUM_PRIORITY, META_GROUPS, SUPPORTED_SCOPES, TOOL_GROUPS, calculateTokenSavings, callTool, execQuery, filterTools, getAllToolNames, getAuditResourceDef, getEnabledGroups, getFilterSummary, getGlobalAuditLogger, getRequiredScope, getToolFilterFromEnv, getToolGroup, getTools, globalMetrics, hasScope, initializeAuditLogger, isResourceError, isToolEnabled, milestoneCompletionPct, parseScopes, parseToolFilter, resolveGitHubRepo, sendProgress, setDefaultSandboxMode, transformEntryRow, withPriority, withSessionInit };