gitmem-mcp 1.1.3 → 1.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.
package/CHANGELOG.md CHANGED
@@ -7,10 +7,51 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [1.2.0] - 2026-02-20
11
+
12
+ ### Added
13
+ - **Telemetry CLI**: `npx gitmem-mcp telemetry` command for viewing scar effectiveness metrics and recall statistics.
14
+ - **Confirm-scars prefix matching**: `confirm_scars` now accepts 8-character ID prefixes instead of requiring full UUIDs — faster agent workflows.
15
+ - **Session-close timing**: `session_close` now tracks and reports ceremony duration for performance visibility.
16
+
17
+ ### Fixed
18
+ - **Test assertion alignment**: Updated smoke and E2E test assertions to match current CLI output format (branded `((●))` display, lowercase identifiers).
19
+ - **No-console-log allowlist**: CLI commands correctly excluded from console.log lint rule.
20
+
21
+ ## [1.1.4] - 2026-02-20
22
+
23
+ ### Changed
24
+ - **Recall default switched to c-review**: Production nudge header changed from "INSTITUTIONAL MEMORY ACTIVATED" to "N scars to review". Nudge-bench testing (54 runs × 3 models) showed 89% scar reference rate vs 44% — a 2x improvement across Opus, Sonnet, and Haiku.
25
+
26
+ ### Fixed
27
+ - **Thread display cleanup**: Removed internal thread IDs from `list_threads` output. Threads now show `# | Thread | Active` — IDs were implementation detail with no user value.
28
+
10
29
  ## [1.1.3] - 2026-02-19
11
30
 
31
+ ### Added
32
+ - **Multi-client init wizard**: `npx gitmem-mcp init` now supports VS Code, Windsurf, and generic MCP clients in addition to Claude Code and Cursor.
33
+ - **Server-side enforcement layer**: Universal compliance enforcement that works across all MCP clients — recall before consequential actions, scar confirmation gates.
34
+ - **Scar framing guidance**: `create_learning` tool now guides agents to frame scars as "what we now know" (factual discovery) rather than "what I did wrong" (self-criticism).
35
+ - **Auto-detect agent and session**: Scar usage tracking automatically detects the current agent identity and session context.
36
+ - **Closing payload schema**: Session close payload schema now ships with `init` and `session_start` for client reference.
37
+ - **npm discoverability keywords**: Added `mcp-server`, `claude-code`, `ai-memory`, `ai-agent` keywords for npm search.
38
+ - **Documentation site**:
39
+ - Restored Fumadocs source for gitmem.ai/docs with emerald theme.
40
+ - Redesigned docs landing page with improved messaging and branding.
41
+ - Added FAQ page with 11 questions.
42
+ - Added MCP one-liner explainer for new users.
43
+ - Added 3 docs examples (scar stories): credential leak, phantom deploy, and first scar.
44
+ - Inline mailing list signup form in docs pages.
45
+ - Rich installation page with multi-client instructions.
46
+
12
47
  ### Fixed
13
48
  - **Thread display output**: `list_threads` and `cleanup_threads` replaced ASCII box-drawing tables with markdown tables. Thread text truncation increased from 40-48 to 60 characters. Output now renders cleanly in all MCP clients instead of clipping on narrow terminals.
49
+ - **Version reporting**: Server now reads version from `package.json` instead of hardcoded `1.0.3`.
50
+ - **Log header clarity**: `gitmem log` header now says "most recent learnings" instead of ambiguous label.
51
+ - **Analyze output**: Relabeled misleading "Open Threads" to "Threads Referenced" in analyze output.
52
+ - **Stale thread cleanup**: Drop stale local-only threads on `session_start` when Supabase is authoritative source.
53
+ - **Package name in docs**: Corrected to `npx gitmem-mcp init` (was `npx gitmem init`).
54
+ - **Docs fixes**: Removed duplicate h1 headers, fixed sidebar nav duplicate entry, corrected GitHub URLs after org migration.
14
55
 
15
56
  ## [1.1.2] - 2026-02-17
16
57
 
@@ -51,18 +51,19 @@ A PreToolUse hook blocks consequential actions until all recalled scars are conf
51
51
 
52
52
  On "closing", "done for now", or "wrapping up":
53
53
 
54
- 1. **Answer these reflection questions** and display to the human:
55
- - What broke that you didn't expect?
56
- - What took longer than it should have?
57
- - What would you do differently next time?
58
- - What pattern or approach worked well?
59
- - What assumption was wrong?
60
- - Which scars did you apply?
61
- - What should be captured as institutional memory?
62
-
63
- 2. **Ask the human**: "Any corrections or additions?" Wait for their response.
64
-
65
- 3. **Write payload** to `.gitmem/closing-payload.json`:
54
+ 1. **Write reflection directly to payload** do NOT display the full Q&A to the human.
55
+ Internally answer these 9 questions and write them straight to `.gitmem/closing-payload.json`:
56
+ - Q1: What broke that you didn't expect?
57
+ - Q2: What took longer than it should have?
58
+ - Q3: What would you do differently next time?
59
+ - Q4: What pattern or approach worked well?
60
+ - Q5: What assumption was wrong?
61
+ - Q6: Which scars did you apply?
62
+ - Q7: What should be captured as institutional memory?
63
+ - Q8: How did the human prefer to work this session?
64
+ - Q9: What collaborative dynamic worked or didn't?
65
+
66
+ Payload schema (`.gitmem/closing-payload.json`):
66
67
  ```json
67
68
  {
68
69
  "closing_reflection": {
@@ -73,15 +74,15 @@ On "closing", "done for now", or "wrapping up":
73
74
  "wrong_assumption": "...",
74
75
  "scars_applied": ["scar title 1", "scar title 2"],
75
76
  "institutional_memory_items": "...",
76
- "collaborative_dynamic": "Q8: How human preferred to work",
77
- "rapport_notes": "Q9: What collaborative dynamic worked"
77
+ "collaborative_dynamic": "...",
78
+ "rapport_notes": "..."
78
79
  },
79
80
  "task_completion": {
80
- "questions_displayed_at": "ISO timestamp",
81
- "reflection_completed_at": "ISO timestamp",
82
- "human_asked_at": "ISO timestamp",
83
- "human_response_at": "ISO timestamp",
84
- "human_response": "human's correction text or 'Looks good'"
81
+ "questions_displayed_at": "ISO timestamp (when reflection started)",
82
+ "reflection_completed_at": "ISO timestamp (when payload written)",
83
+ "human_asked_at": "ISO timestamp (when 'Corrections?' shown)",
84
+ "human_response_at": "ISO timestamp (when human replied)",
85
+ "human_response": "user's correction text or 'none'"
85
86
  },
86
87
  "human_corrections": "",
87
88
  "scars_to_record": [],
@@ -91,7 +92,15 @@ On "closing", "done for now", or "wrapping up":
91
92
  }
92
93
  ```
93
94
 
94
- 4. **Call `session_close`** with `session_id` and `close_type: "standard"`
95
+ 2. **Show compact summary** (3-4 lines max):
96
+ ```
97
+ Session close: [N] learnings captured, [M] scars applied, [K] threads open
98
+ Key lesson: [one-sentence from Q7]
99
+ ```
100
+
101
+ 3. **Ask**: "Corrections?" — wait for response, then call `session_close`.
102
+
103
+ 4. **Call `session_close`** with `session_id` and `close_type: "standard"`.
95
104
 
96
105
  For short exploratory sessions (< 30 min, no real work), use `close_type: "quick"` — no questions needed.
97
106
  <!-- gitmem:end -->
package/README.md CHANGED
@@ -3,11 +3,11 @@
3
3
  </p>
4
4
 
5
5
  <p align="center">
6
- <a href="https://www.npmjs.com/package/gitmem-mcp"><img src="https://img.shields.io/npm/v/gitmem-mcp?style=flat-square&color=ed1e25&label=npm" alt="npm version" /></a>
6
+ <a href="https://www.npmjs.com/package/gitmem-mcp"><img src="https://img.shields.io/npm/v/gitmem-mcp?style=flat-square&color=c41920&label=npm" alt="npm version" /></a>
7
7
  <a href="https://www.npmjs.com/package/gitmem-mcp"><img src="https://img.shields.io/npm/dm/gitmem-mcp?style=flat-square&color=333333&label=downloads" alt="npm downloads" /></a>
8
- <a href="https://github.com/gitmem-dev/gitmem/blob/main/LICENSE"><img src="https://img.shields.io/github/license/gitmem-dev/gitmem?style=flat-square&color=ed1e25" alt="MIT License" /></a>
8
+ <a href="https://github.com/gitmem-dev/gitmem/blob/main/LICENSE"><img src="https://img.shields.io/github/license/gitmem-dev/gitmem?style=flat-square&color=c41920" alt="MIT License" /></a>
9
9
  <a href="https://github.com/gitmem-dev/gitmem/actions/workflows/ci.yml"><img src="https://img.shields.io/github/actions/workflow/status/gitmem-dev/gitmem/ci.yml?style=flat-square&color=333333&label=build" alt="Build" /></a>
10
- <img src="https://img.shields.io/badge/node-%3E%3D22-ed1e25?style=flat-square" alt="Node.js >= 22" />
10
+ <img src="https://img.shields.io/badge/node-%3E%3D18-c41920?style=flat-square" alt="Node.js >= 18" />
11
11
  </p>
12
12
 
13
13
  <p align="center">
@@ -136,7 +136,7 @@ Add this to your MCP client's config file:
136
136
  | **Session analytics** | Spot patterns in what keeps going wrong |
137
137
  | **Sub-agent briefing** | Hand institutional context to sub-agents automatically |
138
138
  | **Cloud persistence** | Memory survives machine changes, shareable across team |
139
- | **A/B testing** | Optimize scar phrasing based on what actually changes behavior |
139
+ | **A/B testing analytics** | Measure which scar phrasings actually change agent behavior (free tier includes `GITMEM_NUDGE_VARIANT` for manual testing) |
140
140
 
141
141
  The free tier gives you everything for solo projects. Pro makes recall smarter and memory portable.
142
142
 
package/bin/gitmem.js CHANGED
@@ -51,6 +51,9 @@ Other commands:
51
51
  npx gitmem-mcp check --full Full diagnostic with benchmarks
52
52
  npx gitmem-mcp install-hooks Install hooks (standalone)
53
53
  npx gitmem-mcp uninstall-hooks Remove hooks (standalone)
54
+ npx gitmem-mcp telemetry status Check telemetry settings
55
+ npx gitmem-mcp telemetry enable Enable anonymous usage tracking (opt-in)
56
+ npx gitmem-mcp telemetry disable Disable usage tracking
54
57
  npx gitmem-mcp server Start MCP server (default)
55
58
  npx gitmem-mcp help Show this help message
56
59
 
@@ -200,6 +203,10 @@ async function cmdInit() {
200
203
  console.log("Add .gitmem/ to your .gitignore:");
201
204
  console.log(" echo '.gitmem/' >> .gitignore");
202
205
  console.log("");
206
+
207
+ // Prompt for telemetry (optional, non-blocking)
208
+ promptTelemetryOptIn();
209
+
203
210
  console.log("To upgrade to Pro tier (semantic search + Supabase persistence):");
204
211
  console.log(" Set SUPABASE_URL and SUPABASE_SERVICE_ROLE_KEY, then run init again.");
205
212
  return;
@@ -686,6 +693,29 @@ function cmdInstallHooks() {
686
693
  console.log(" npx gitmem-mcp install-hooks --force");
687
694
  }
688
695
 
696
+ /**
697
+ * Prompt user to opt-in to telemetry (non-blocking, async)
698
+ */
699
+ function promptTelemetryOptIn() {
700
+ console.log("─────────────────────────────────────────────");
701
+ console.log("");
702
+ console.log("Help improve GitMem? (Optional)");
703
+ console.log("");
704
+ console.log("Send anonymous usage data to help us understand:");
705
+ console.log(" • Which features are most useful");
706
+ console.log(" • Where errors occur");
707
+ console.log(" • Performance patterns");
708
+ console.log("");
709
+ console.log("✓ No queries, scars, or project content");
710
+ console.log("✓ Randomized ID (not linked to you)");
711
+ console.log("✓ View all data before it's sent");
712
+ console.log("✓ Disable anytime");
713
+ console.log("");
714
+ console.log("To enable: npx gitmem-mcp telemetry enable");
715
+ console.log("Privacy policy: https://gitmem.ai/privacy");
716
+ console.log("");
717
+ }
718
+
689
719
  /**
690
720
  * Uninstall gitmem hooks.
691
721
  *
@@ -858,6 +888,9 @@ switch (command) {
858
888
  case "check":
859
889
  import("../dist/commands/check.js").then((m) => m.main(process.argv.slice(3)));
860
890
  break;
891
+ case "telemetry":
892
+ import("../dist/commands/telemetry.js").then((m) => m.main(process.argv.slice(3)));
893
+ break;
861
894
  case "install-hooks":
862
895
  cmdInstallHooks();
863
896
  break;
@@ -46,18 +46,19 @@ Safe alternatives: `env | grep -c VARNAME` (count only), `[ -n "$VARNAME" ] && e
46
46
 
47
47
  **End:** On "closing", "done for now", or "wrapping up":
48
48
 
49
- 1. **Answer these reflection questions** and display to the human:
50
- - What broke that you didn't expect?
51
- - What took longer than it should have?
52
- - What would you do differently next time?
53
- - What pattern or approach worked well?
54
- - What assumption was wrong?
55
- - Which scars did you apply?
56
- - What should be captured as institutional memory?
57
-
58
- 2. **Ask the human**: "Any corrections or additions?" Wait for their response.
59
-
60
- 3. **Write payload** to `.gitmem/closing-payload.json`:
49
+ 1. **Write reflection directly to payload** do NOT display the full Q&A to the human.
50
+ Internally answer these 9 questions and write them straight to `.gitmem/closing-payload.json`:
51
+ - Q1: What broke that you didn't expect?
52
+ - Q2: What took longer than it should have?
53
+ - Q3: What would you do differently next time?
54
+ - Q4: What pattern or approach worked well?
55
+ - Q5: What assumption was wrong?
56
+ - Q6: Which scars did you apply?
57
+ - Q7: What should be captured as institutional memory?
58
+ - Q8: How did the human prefer to work this session?
59
+ - Q9: What collaborative dynamic worked or didn't?
60
+
61
+ Payload schema (`.gitmem/closing-payload.json`):
61
62
  ```json
62
63
  {
63
64
  "closing_reflection": {
@@ -67,16 +68,34 @@ Safe alternatives: `env | grep -c VARNAME` (count only), `[ -n "$VARNAME" ] && e
67
68
  "what_worked": "...",
68
69
  "wrong_assumption": "...",
69
70
  "scars_applied": ["scar title 1", "scar title 2"],
70
- "institutional_memory_items": "..."
71
+ "institutional_memory_items": "...",
72
+ "collaborative_dynamic": "...",
73
+ "rapport_notes": "..."
74
+ },
75
+ "task_completion": {
76
+ "questions_displayed_at": "ISO timestamp (when reflection started)",
77
+ "reflection_completed_at": "ISO timestamp (when payload written)",
78
+ "human_asked_at": "ISO timestamp (when 'Corrections?' shown)",
79
+ "human_response_at": "ISO timestamp (when human replied)",
80
+ "human_response": "user's correction text or 'none'"
71
81
  },
72
82
  "human_corrections": "",
73
83
  "scars_to_record": [],
84
+ "learnings_created": [],
74
85
  "open_threads": [],
75
86
  "decisions": []
76
87
  }
77
88
  ```
78
89
 
79
- 4. **Call `session_close`** with `session_id` and `close_type: "standard"`
90
+ 2. **Show compact summary** (3-4 lines max):
91
+ ```
92
+ Session close: [N] learnings captured, [M] scars applied, [K] threads open
93
+ Key lesson: [one-sentence from Q7]
94
+ ```
95
+
96
+ 3. **Ask**: "Corrections?" — wait for response, then call `session_close`.
97
+
98
+ 4. **Call `session_close`** with `session_id` and `close_type: "standard"`.
80
99
 
81
100
  For short exploratory sessions (< 30 min, no real work), use `close_type: "quick"` — no questions needed.
82
101
  <!-- gitmem:end -->
@@ -46,18 +46,19 @@ Safe alternatives: `env | grep -c VARNAME` (count only), `[ -n "$VARNAME" ] && e
46
46
 
47
47
  On "closing", "done for now", or "wrapping up":
48
48
 
49
- 1. **Answer these reflection questions** and display to the human:
50
- - What broke that you didn't expect?
51
- - What took longer than it should have?
52
- - What would you do differently next time?
53
- - What pattern or approach worked well?
54
- - What assumption was wrong?
55
- - Which scars did you apply?
56
- - What should be captured as institutional memory?
57
-
58
- 2. **Ask the human**: "Any corrections or additions?" Wait for their response.
59
-
60
- 3. **Write payload** to `.gitmem/closing-payload.json`:
49
+ 1. **Write reflection directly to payload** do NOT display the full Q&A to the human.
50
+ Internally answer these 9 questions and write them straight to `.gitmem/closing-payload.json`:
51
+ - Q1: What broke that you didn't expect?
52
+ - Q2: What took longer than it should have?
53
+ - Q3: What would you do differently next time?
54
+ - Q4: What pattern or approach worked well?
55
+ - Q5: What assumption was wrong?
56
+ - Q6: Which scars did you apply?
57
+ - Q7: What should be captured as institutional memory?
58
+ - Q8: How did the human prefer to work this session?
59
+ - Q9: What collaborative dynamic worked or didn't?
60
+
61
+ Payload schema (`.gitmem/closing-payload.json`):
61
62
  ```json
62
63
  {
63
64
  "closing_reflection": {
@@ -68,15 +69,15 @@ On "closing", "done for now", or "wrapping up":
68
69
  "wrong_assumption": "...",
69
70
  "scars_applied": ["scar title 1", "scar title 2"],
70
71
  "institutional_memory_items": "...",
71
- "collaborative_dynamic": "Q8: How human preferred to work",
72
- "rapport_notes": "Q9: What collaborative dynamic worked"
72
+ "collaborative_dynamic": "...",
73
+ "rapport_notes": "..."
73
74
  },
74
75
  "task_completion": {
75
- "questions_displayed_at": "ISO timestamp",
76
- "reflection_completed_at": "ISO timestamp",
77
- "human_asked_at": "ISO timestamp",
78
- "human_response_at": "ISO timestamp",
79
- "human_response": "human's correction text or 'Looks good'"
76
+ "questions_displayed_at": "ISO timestamp (when reflection started)",
77
+ "reflection_completed_at": "ISO timestamp (when payload written)",
78
+ "human_asked_at": "ISO timestamp (when 'Corrections?' shown)",
79
+ "human_response_at": "ISO timestamp (when human replied)",
80
+ "human_response": "user's correction text or 'none'"
80
81
  },
81
82
  "human_corrections": "",
82
83
  "scars_to_record": [],
@@ -86,7 +87,15 @@ On "closing", "done for now", or "wrapping up":
86
87
  }
87
88
  ```
88
89
 
89
- 4. **Call `session_close`** with `session_id` and `close_type: "standard"`
90
+ 2. **Show compact summary** (3-4 lines max):
91
+ ```
92
+ Session close: [N] learnings captured, [M] scars applied, [K] threads open
93
+ Key lesson: [one-sentence from Q7]
94
+ ```
95
+
96
+ 3. **Ask**: "Corrections?" — wait for response, then call `session_close`.
97
+
98
+ 4. **Call `session_close`** with `session_id` and `close_type: "standard"`.
90
99
 
91
100
  For short exploratory sessions (< 30 min, no real work), use `close_type: "quick"` — no questions needed.
92
101
  # --- gitmem:end ---
@@ -0,0 +1,11 @@
1
+ /**
2
+ * CLI commands for telemetry control
3
+ *
4
+ * gitmem telemetry status
5
+ * gitmem telemetry enable
6
+ * gitmem telemetry disable
7
+ * gitmem telemetry show [--limit N]
8
+ * gitmem telemetry clear
9
+ */
10
+ export declare function main(args: string[]): void;
11
+ //# sourceMappingURL=telemetry.d.ts.map
@@ -0,0 +1,207 @@
1
+ /**
2
+ * CLI commands for telemetry control
3
+ *
4
+ * gitmem telemetry status
5
+ * gitmem telemetry enable
6
+ * gitmem telemetry disable
7
+ * gitmem telemetry show [--limit N]
8
+ * gitmem telemetry clear
9
+ */
10
+ import { getTelemetry, Telemetry } from "../lib/telemetry.js";
11
+ import { join } from "path";
12
+ import { readFileSync } from "fs";
13
+ const VERSION = getPackageVersion();
14
+ function getPackageVersion() {
15
+ try {
16
+ const pkg = JSON.parse(readFileSync(join(process.cwd(), "package.json"), "utf-8"));
17
+ return pkg.version || "0.0.0";
18
+ }
19
+ catch {
20
+ return "0.0.0";
21
+ }
22
+ }
23
+ function getGitmemDir() {
24
+ return join(process.cwd(), ".gitmem");
25
+ }
26
+ export function main(args) {
27
+ const subcommand = args[0];
28
+ const gitmemDir = getGitmemDir();
29
+ const telemetry = getTelemetry(gitmemDir, VERSION);
30
+ switch (subcommand) {
31
+ case "status":
32
+ cmdStatus(telemetry);
33
+ break;
34
+ case "enable":
35
+ cmdEnable(telemetry);
36
+ break;
37
+ case "disable":
38
+ cmdDisable(telemetry);
39
+ break;
40
+ case "show":
41
+ cmdShow(telemetry, args);
42
+ break;
43
+ case "clear":
44
+ cmdClear(telemetry);
45
+ break;
46
+ default:
47
+ printUsage();
48
+ process.exit(1);
49
+ }
50
+ }
51
+ function cmdStatus(telemetry) {
52
+ const status = telemetry.getStatus();
53
+ console.log("GitMem Telemetry — Status");
54
+ console.log("========================\n");
55
+ if (status.enabled) {
56
+ console.log("Status: \x1b[32mEnabled\x1b[0m");
57
+ console.log(`Session ID: ${status.session_id} (random, not persistent)`);
58
+ console.log(`Events logged: ${status.event_count} (local)`);
59
+ if (status.consented_at) {
60
+ const date = new Date(status.consented_at).toLocaleDateString();
61
+ console.log(`Consented: ${date}`);
62
+ }
63
+ console.log("");
64
+ console.log("What's collected:");
65
+ console.log(" • Tool names (recall, session_close, etc.)");
66
+ console.log(" • Success/failure status");
67
+ console.log(" • Execution duration");
68
+ console.log(" • Result counts (not content)");
69
+ console.log(" • Platform (darwin, linux, win32)");
70
+ console.log(" • Version number");
71
+ console.log("");
72
+ console.log("What's NOT collected:");
73
+ console.log(" ✗ Queries or search terms");
74
+ console.log(" ✗ Scar/learning content");
75
+ console.log(" ✗ Project names or file paths");
76
+ console.log(" ✗ IP addresses or identifiers");
77
+ console.log("");
78
+ console.log("Commands:");
79
+ console.log(" gitmem telemetry show View pending events");
80
+ console.log(" gitmem telemetry disable Turn off telemetry");
81
+ console.log("");
82
+ console.log("Privacy policy: https://gitmem.ai/privacy");
83
+ }
84
+ else {
85
+ console.log("Status: \x1b[33mDisabled\x1b[0m");
86
+ console.log("");
87
+ console.log("No data is being sent.");
88
+ console.log("");
89
+ console.log("To help improve GitMem:");
90
+ console.log(" gitmem telemetry enable");
91
+ console.log("");
92
+ console.log("Privacy policy: https://gitmem.ai/privacy");
93
+ }
94
+ }
95
+ function cmdEnable(telemetry) {
96
+ console.log("GitMem Telemetry — Enable");
97
+ console.log("=========================\n");
98
+ console.log("Help improve GitMem by sending anonymous usage data.\n");
99
+ console.log("What we collect:");
100
+ console.log(" ✓ Tool usage patterns (which tools are most useful)");
101
+ console.log(" ✓ Error rates (to prioritize fixes)");
102
+ console.log(" ✓ Performance metrics (duration, platform)");
103
+ console.log("");
104
+ console.log("What we DON'T collect:");
105
+ console.log(" ✗ Your queries or content");
106
+ console.log(" ✗ Scar/learning text");
107
+ console.log(" ✗ Project names or file paths");
108
+ console.log(" ✗ IP addresses or persistent IDs");
109
+ console.log("");
110
+ console.log("Transparency:");
111
+ console.log(" • All events logged to .gitmem/telemetry.log");
112
+ console.log(" • View before sending: gitmem telemetry show");
113
+ console.log(" • Disable anytime: gitmem telemetry disable");
114
+ console.log("");
115
+ console.log("Full privacy policy: https://gitmem.ai/privacy");
116
+ console.log("");
117
+ // Prompt for confirmation (skip if --yes flag)
118
+ if (!process.argv.includes("--yes") && !process.argv.includes("-y")) {
119
+ const readline = require("readline");
120
+ const rl = readline.createInterface({
121
+ input: process.stdin,
122
+ output: process.stdout,
123
+ });
124
+ rl.question("Enable telemetry? [y/N] ", (answer) => {
125
+ rl.close();
126
+ if (answer.toLowerCase() === "y" || answer.toLowerCase() === "yes") {
127
+ telemetry.enable();
128
+ console.log("");
129
+ console.log("\x1b[32m✓\x1b[0m Telemetry enabled");
130
+ console.log(" Data logged to: .gitmem/telemetry.log");
131
+ console.log(" Review anytime: gitmem telemetry show");
132
+ console.log(" Disable anytime: gitmem telemetry disable");
133
+ }
134
+ else {
135
+ console.log("");
136
+ console.log("Telemetry not enabled.");
137
+ }
138
+ });
139
+ }
140
+ else {
141
+ telemetry.enable();
142
+ console.log("\x1b[32m✓\x1b[0m Telemetry enabled (--yes flag)");
143
+ }
144
+ }
145
+ function cmdDisable(telemetry) {
146
+ telemetry.disable();
147
+ console.log("GitMem Telemetry — Disable");
148
+ console.log("==========================\n");
149
+ console.log("\x1b[32m✓\x1b[0m Telemetry disabled");
150
+ console.log(" Pending events: will not be sent");
151
+ console.log(" Local logs: preserved at .gitmem/telemetry.log");
152
+ console.log("");
153
+ console.log("To re-enable: gitmem telemetry enable");
154
+ }
155
+ function cmdShow(telemetry, args) {
156
+ const limitIdx = args.indexOf("--limit");
157
+ const limit = limitIdx !== -1 ? parseInt(args[limitIdx + 1], 10) : 100;
158
+ const events = telemetry.getRecentEvents(limit);
159
+ console.log(`GitMem Telemetry — Recent Events (last ${Math.min(limit, events.length)})`);
160
+ console.log("=".repeat(60));
161
+ console.log("");
162
+ if (events.length === 0) {
163
+ console.log("No events logged yet.");
164
+ console.log("");
165
+ console.log("Events are logged automatically as you use gitmem tools.");
166
+ return;
167
+ }
168
+ for (const eventJson of events) {
169
+ console.log(Telemetry.formatEvent(eventJson));
170
+ }
171
+ console.log("");
172
+ console.log(`Total events: ${events.length}`);
173
+ console.log(`Status: ${telemetry.isEnabled() ? "\x1b[32mEnabled\x1b[0m (will be sent)" : "\x1b[33mDisabled\x1b[0m (logged only)"}`);
174
+ }
175
+ function cmdClear(telemetry) {
176
+ const status = telemetry.getStatus();
177
+ const count = status.event_count;
178
+ telemetry.clearLog();
179
+ console.log("GitMem Telemetry — Clear");
180
+ console.log("========================\n");
181
+ console.log("\x1b[32m✓\x1b[0m Cleared all local telemetry logs");
182
+ console.log(` Events removed: ${count}`);
183
+ console.log("");
184
+ console.log("Note: Remote data (already sent) cannot be deleted.");
185
+ console.log(" It's already anonymous and not linked to you.");
186
+ }
187
+ function printUsage() {
188
+ console.log(`
189
+ GitMem Telemetry — Control
190
+
191
+ Usage:
192
+ gitmem telemetry status Show current status
193
+ gitmem telemetry enable Enable anonymous usage tracking
194
+ gitmem telemetry disable Disable usage tracking
195
+ gitmem telemetry show [--limit N] View recent events (default: 100)
196
+ gitmem telemetry clear Clear local event log
197
+
198
+ Privacy:
199
+ • Opt-in only (disabled by default)
200
+ • No PII (queries, scars, project names, IPs)
201
+ • Transparent (local logs before sending)
202
+ • Anonymous (random session IDs, not persistent)
203
+
204
+ Full policy: https://gitmem.ai/privacy
205
+ `);
206
+ }
207
+ //# sourceMappingURL=telemetry.js.map
@@ -23,6 +23,7 @@ export interface FormattableScar {
23
23
  action_protocol?: string[];
24
24
  self_check_criteria?: string[];
25
25
  }
26
+ /** Text severity indicators — no emoji (column width is unpredictable across terminals) */
26
27
  export declare const SEVERITY_EMOJI: Record<string, string>;
27
28
  export declare const SEVERITY_LABEL: Record<string, string>;
28
29
  export declare const SEVERITY_ORDER: Record<string, number>;
@@ -6,11 +6,12 @@
6
6
  * - quick-retrieve.ts (hook-invoked retrieval for auto-inject)
7
7
  */
8
8
  // --- Severity Constants ---
9
+ /** Text severity indicators — no emoji (column width is unpredictable across terminals) */
9
10
  export const SEVERITY_EMOJI = {
10
- critical: "\uD83D\uDD34",
11
- high: "\uD83D\uDFE0",
12
- medium: "\uD83D\uDFE1",
13
- low: "\uD83D\uDFE2",
11
+ critical: "[!!]",
12
+ high: "[!]",
13
+ medium: "[~]",
14
+ low: "[-]",
14
15
  };
15
16
  export const SEVERITY_LABEL = {
16
17
  critical: "CRITICAL",
@@ -44,7 +45,7 @@ export function formatCompact(scars, plan, maxTokens) {
44
45
  const lines = [header];
45
46
  let included = 0;
46
47
  for (const scar of sorted) {
47
- const emoji = SEVERITY_EMOJI[scar.severity] || "\u26AA";
48
+ const emoji = SEVERITY_EMOJI[scar.severity] || "[?]";
48
49
  const label = SEVERITY_LABEL[scar.severity] || "UNKNOWN";
49
50
  const firstSentence = scar.description.split(/\.\s/)[0].slice(0, 120);
50
51
  const line = `${emoji} ${label}: ${scar.title} \u2014 ${firstSentence}`;
@@ -76,7 +77,7 @@ export function formatGate(scars) {
76
77
  ];
77
78
  for (const scar of blockingScars) {
78
79
  const rv = scar.required_verification;
79
- lines.push(`\uD83D\uDEA8 BLOCK: ${rv.when}`);
80
+ lines.push(`[!!] BLOCK: ${rv.when}`);
80
81
  if (rv.queries && rv.queries.length > 0) {
81
82
  for (const query of rv.queries) {
82
83
  lines.push(` RUN: ${query}`);