gitmem-mcp 1.0.9 → 1.0.11
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,6 +7,24 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [1.0.11] - 2026-02-16
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
- **CI pipeline cleanup**: `build` script is now just `tsc` (was `tsc && npm run test:unit`). Tests ran 8x per CI run due to `build`, `test`, and `prepublishOnly` all triggering the same 764-test suite. Now each step does one thing: typecheck, compile, test, smoke, publish.
|
|
14
|
+
|
|
15
|
+
## [1.0.10] - 2026-02-16
|
|
16
|
+
|
|
17
|
+
### Fixed
|
|
18
|
+
- **CI smoke test**: `session_close` test looked for `active-sessions.json` at `process.cwd()` instead of `GITMEM_DIR`, failing in CI where they differ.
|
|
19
|
+
- **CI peer dependencies**: Added `--legacy-peer-deps` to `npm ci` for `zod@4` conflict with `claude-agent-sdk`.
|
|
20
|
+
- **CI unit test**: `quick-retrieve.test.ts` now sets `GITMEM_DIR` so disk cache tests resolve correctly in CI.
|
|
21
|
+
|
|
22
|
+
## [1.0.9] - 2026-02-16
|
|
23
|
+
|
|
24
|
+
### Fixed
|
|
25
|
+
- **Closing payload field name mismatch**: `CLAUDE.md.template` documented wrong field names (`institutional_memory` instead of `institutional_memory_items`, bogus `started_at`/`completed_at` in task_completion) causing agents to write payloads that `session_close` couldn't parse. Fixed template and added `institutional_memory` as normalizer alias.
|
|
26
|
+
- **Missing Q8/Q9 in closing template**: Added `collaborative_dynamic` and `rapport_notes` fields to payload example.
|
|
27
|
+
|
|
10
28
|
## [1.0.6] - 2026-02-16
|
|
11
29
|
|
|
12
30
|
### Fixed
|
package/CLAUDE.md.template
CHANGED
|
@@ -47,17 +47,17 @@ On "closing", "done for now", or "wrapping up":
|
|
|
47
47
|
"do_differently": "...",
|
|
48
48
|
"what_worked": "...",
|
|
49
49
|
"wrong_assumption": "...",
|
|
50
|
-
"scars_applied": "
|
|
51
|
-
"
|
|
50
|
+
"scars_applied": ["scar title 1", "scar title 2"],
|
|
51
|
+
"institutional_memory_items": "...",
|
|
52
|
+
"collaborative_dynamic": "Q8: How human preferred to work",
|
|
53
|
+
"rapport_notes": "Q9: What collaborative dynamic worked"
|
|
52
54
|
},
|
|
53
55
|
"task_completion": {
|
|
54
|
-
"started_at": "ISO timestamp",
|
|
55
|
-
"completed_at": "ISO timestamp",
|
|
56
56
|
"questions_displayed_at": "ISO timestamp",
|
|
57
57
|
"reflection_completed_at": "ISO timestamp",
|
|
58
58
|
"human_asked_at": "ISO timestamp",
|
|
59
59
|
"human_response_at": "ISO timestamp",
|
|
60
|
-
"human_response": "human's correction text or
|
|
60
|
+
"human_response": "human's correction text or 'Looks good'"
|
|
61
61
|
},
|
|
62
62
|
"human_corrections": "",
|
|
63
63
|
"scars_to_record": [],
|
|
@@ -137,6 +137,7 @@ const REFLECTION_ALIASES = {
|
|
|
137
137
|
capture: "institutional_memory_items",
|
|
138
138
|
capture_as_memory: "institutional_memory_items",
|
|
139
139
|
memory_items: "institutional_memory_items",
|
|
140
|
+
institutional_memory: "institutional_memory_items",
|
|
140
141
|
// Q8-Q9 (rapport, not in CLOSING_QUESTIONS but used)
|
|
141
142
|
q8_human_style: "human_work_style",
|
|
142
143
|
q9_dynamic: "collaborative_dynamic",
|
package/dist/index.js
CHANGED
|
File without changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gitmem-mcp",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.11",
|
|
4
4
|
"description": "Institutional memory for AI coding agents. Memory that compounds.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"gitmem-mcp": "bin/gitmem.js"
|
|
11
11
|
},
|
|
12
12
|
"scripts": {
|
|
13
|
-
"build": "tsc
|
|
13
|
+
"build": "tsc",
|
|
14
14
|
"dev": "tsc --watch",
|
|
15
15
|
"start": "node dist/index.js",
|
|
16
16
|
"test": "vitest run",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"test:all": "npm run test:unit && npm run test:smoke && npm run test:integration && npm run test:perf && npm run test:e2e",
|
|
25
25
|
"test:watch": "vitest",
|
|
26
26
|
"typecheck": "tsc --noEmit",
|
|
27
|
-
"prepublishOnly": "
|
|
27
|
+
"prepublishOnly": "tsc"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
30
|
"@huggingface/transformers": "^3.0.0",
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* create_linear_issue Tool (OD-611)
|
|
3
|
-
*
|
|
4
|
-
* Proxy Linear issue creation via GraphQL API.
|
|
5
|
-
* Returns slim response (~50 tokens) instead of Linear MCP's ~1400 tokens.
|
|
6
|
-
*
|
|
7
|
-
* Pattern: File-based payload handoff (same as session_close).
|
|
8
|
-
* Agent writes description to .gitmem/issue-payload.json, then calls this
|
|
9
|
-
* tool with title + teamId inline. Tool reads, merges, calls Linear, deletes file.
|
|
10
|
-
*
|
|
11
|
-
* Performance target: <2000ms (one network call)
|
|
12
|
-
*/
|
|
13
|
-
import type { CreateLinearIssueParams, CreateLinearIssueResult } from "../types/index.js";
|
|
14
|
-
/**
|
|
15
|
-
* Create a Linear issue via GraphQL API with slim response.
|
|
16
|
-
*/
|
|
17
|
-
export declare function createLinearIssue(params: CreateLinearIssueParams): Promise<CreateLinearIssueResult>;
|
|
18
|
-
//# sourceMappingURL=create-linear-issue.d.ts.map
|
|
@@ -1,197 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* create_linear_issue Tool (OD-611)
|
|
3
|
-
*
|
|
4
|
-
* Proxy Linear issue creation via GraphQL API.
|
|
5
|
-
* Returns slim response (~50 tokens) instead of Linear MCP's ~1400 tokens.
|
|
6
|
-
*
|
|
7
|
-
* Pattern: File-based payload handoff (same as session_close).
|
|
8
|
-
* Agent writes description to .gitmem/issue-payload.json, then calls this
|
|
9
|
-
* tool with title + teamId inline. Tool reads, merges, calls Linear, deletes file.
|
|
10
|
-
*
|
|
11
|
-
* Performance target: <2000ms (one network call)
|
|
12
|
-
*/
|
|
13
|
-
import * as fs from "fs";
|
|
14
|
-
import { v4 as uuidv4 } from "uuid";
|
|
15
|
-
import { getGitmemPath } from "../services/gitmem-dir.js";
|
|
16
|
-
import { Timer, buildPerformanceData, recordMetrics, } from "../services/metrics.js";
|
|
17
|
-
import { getEffectTracker } from "../services/effect-tracker.js";
|
|
18
|
-
const LINEAR_API_URL = "https://api.linear.app/graphql";
|
|
19
|
-
/** GraphQL mutation — request only the fields needed for the slim response */
|
|
20
|
-
const ISSUE_CREATE_MUTATION = `
|
|
21
|
-
mutation IssueCreate($input: IssueCreateInput!) {
|
|
22
|
-
issueCreate(input: $input) {
|
|
23
|
-
success
|
|
24
|
-
issue {
|
|
25
|
-
id
|
|
26
|
-
identifier
|
|
27
|
-
url
|
|
28
|
-
state {
|
|
29
|
-
name
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
`;
|
|
35
|
-
/**
|
|
36
|
-
* Create a Linear issue via GraphQL API with slim response.
|
|
37
|
-
*/
|
|
38
|
-
export async function createLinearIssue(params) {
|
|
39
|
-
const timer = new Timer();
|
|
40
|
-
const metricsId = uuidv4();
|
|
41
|
-
// 1. Check LINEAR_API_KEY
|
|
42
|
-
const apiKey = process.env.LINEAR_API_KEY;
|
|
43
|
-
if (!apiKey) {
|
|
44
|
-
const latencyMs = timer.stop();
|
|
45
|
-
return {
|
|
46
|
-
success: false,
|
|
47
|
-
error: "LINEAR_API_KEY environment variable is not set. Add it to your MCP server configuration.",
|
|
48
|
-
performance: buildPerformanceData("create_linear_issue", latencyMs, 0),
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
|
-
// 2. Load file-based payload (same pattern as session_close)
|
|
52
|
-
const payloadPath = params.payload_path || getGitmemPath("issue-payload.json");
|
|
53
|
-
let filePayload = {};
|
|
54
|
-
try {
|
|
55
|
-
if (fs.existsSync(payloadPath)) {
|
|
56
|
-
filePayload = JSON.parse(fs.readFileSync(payloadPath, "utf-8"));
|
|
57
|
-
console.error(`[create_linear_issue] Loaded payload from ${payloadPath}`);
|
|
58
|
-
// Clean up payload file after reading
|
|
59
|
-
try {
|
|
60
|
-
fs.unlinkSync(payloadPath);
|
|
61
|
-
}
|
|
62
|
-
catch {
|
|
63
|
-
/* ignore cleanup errors */
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
catch (error) {
|
|
68
|
-
console.error("[create_linear_issue] Failed to read issue-payload.json:", error);
|
|
69
|
-
}
|
|
70
|
-
// 3. Merge: inline params override file payload
|
|
71
|
-
const teamId = params.teamId || filePayload.teamId;
|
|
72
|
-
const title = params.title || filePayload.title;
|
|
73
|
-
if (!teamId || !title) {
|
|
74
|
-
const latencyMs = timer.stop();
|
|
75
|
-
return {
|
|
76
|
-
success: false,
|
|
77
|
-
error: "teamId and title are required. Provide inline or in .gitmem/issue-payload.json.",
|
|
78
|
-
performance: buildPerformanceData("create_linear_issue", latencyMs, 0),
|
|
79
|
-
};
|
|
80
|
-
}
|
|
81
|
-
// 4. Build IssueCreateInput for GraphQL
|
|
82
|
-
const input = {
|
|
83
|
-
teamId,
|
|
84
|
-
title,
|
|
85
|
-
};
|
|
86
|
-
// Description only comes from file payload (the large field)
|
|
87
|
-
if (filePayload.description) {
|
|
88
|
-
input.description = filePayload.description;
|
|
89
|
-
}
|
|
90
|
-
// Merge optional fields — inline overrides file
|
|
91
|
-
if (params.priority !== undefined || filePayload.priority !== undefined) {
|
|
92
|
-
input.priority = params.priority ?? filePayload.priority;
|
|
93
|
-
}
|
|
94
|
-
if (params.labelIds?.length || filePayload.labelIds?.length) {
|
|
95
|
-
input.labelIds = params.labelIds || filePayload.labelIds;
|
|
96
|
-
}
|
|
97
|
-
if (params.projectId || filePayload.projectId) {
|
|
98
|
-
input.projectId = params.projectId || filePayload.projectId;
|
|
99
|
-
}
|
|
100
|
-
if (params.assigneeId || filePayload.assigneeId) {
|
|
101
|
-
input.assigneeId = params.assigneeId || filePayload.assigneeId;
|
|
102
|
-
}
|
|
103
|
-
if (params.parentId || filePayload.parentId) {
|
|
104
|
-
input.parentId = params.parentId || filePayload.parentId;
|
|
105
|
-
}
|
|
106
|
-
if (params.stateId || filePayload.stateId) {
|
|
107
|
-
input.stateId = params.stateId || filePayload.stateId;
|
|
108
|
-
}
|
|
109
|
-
if (params.estimate !== undefined || filePayload.estimate !== undefined) {
|
|
110
|
-
input.estimate = params.estimate ?? filePayload.estimate;
|
|
111
|
-
}
|
|
112
|
-
// 5. Call Linear GraphQL API
|
|
113
|
-
try {
|
|
114
|
-
const response = await fetch(LINEAR_API_URL, {
|
|
115
|
-
method: "POST",
|
|
116
|
-
headers: {
|
|
117
|
-
"Content-Type": "application/json",
|
|
118
|
-
Authorization: apiKey,
|
|
119
|
-
},
|
|
120
|
-
body: JSON.stringify({
|
|
121
|
-
query: ISSUE_CREATE_MUTATION,
|
|
122
|
-
variables: { input },
|
|
123
|
-
}),
|
|
124
|
-
});
|
|
125
|
-
if (!response.ok) {
|
|
126
|
-
const text = await response.text();
|
|
127
|
-
const latencyMs = timer.stop();
|
|
128
|
-
return {
|
|
129
|
-
success: false,
|
|
130
|
-
error: `Linear API HTTP ${response.status}: ${text.slice(0, 200)}`,
|
|
131
|
-
performance: buildPerformanceData("create_linear_issue", latencyMs, 0),
|
|
132
|
-
};
|
|
133
|
-
}
|
|
134
|
-
const data = (await response.json());
|
|
135
|
-
// Handle GraphQL errors
|
|
136
|
-
if (data.errors?.length) {
|
|
137
|
-
const latencyMs = timer.stop();
|
|
138
|
-
return {
|
|
139
|
-
success: false,
|
|
140
|
-
error: `Linear GraphQL error: ${data.errors.map((e) => e.message).join("; ")}`,
|
|
141
|
-
performance: buildPerformanceData("create_linear_issue", latencyMs, 0),
|
|
142
|
-
};
|
|
143
|
-
}
|
|
144
|
-
const issueCreate = data.data?.issueCreate;
|
|
145
|
-
if (!issueCreate?.success || !issueCreate.issue) {
|
|
146
|
-
const latencyMs = timer.stop();
|
|
147
|
-
return {
|
|
148
|
-
success: false,
|
|
149
|
-
error: "Linear API returned unsuccessful issueCreate",
|
|
150
|
-
performance: buildPerformanceData("create_linear_issue", latencyMs, 0),
|
|
151
|
-
};
|
|
152
|
-
}
|
|
153
|
-
const issue = issueCreate.issue;
|
|
154
|
-
const latencyMs = timer.stop();
|
|
155
|
-
// 6. Fire-and-forget metrics recording
|
|
156
|
-
getEffectTracker().track("metrics", "create_linear_issue", () => recordMetrics({
|
|
157
|
-
id: metricsId,
|
|
158
|
-
tool_name: "create_linear_issue",
|
|
159
|
-
latency_ms: latencyMs,
|
|
160
|
-
result_count: 1,
|
|
161
|
-
metadata: {
|
|
162
|
-
identifier: issue.identifier,
|
|
163
|
-
teamId,
|
|
164
|
-
has_description: !!filePayload.description,
|
|
165
|
-
},
|
|
166
|
-
}));
|
|
167
|
-
// 7. Return slim response (~50 tokens vs ~1400)
|
|
168
|
-
return {
|
|
169
|
-
success: true,
|
|
170
|
-
identifier: issue.identifier,
|
|
171
|
-
url: issue.url,
|
|
172
|
-
id: issue.id,
|
|
173
|
-
state: issue.state?.name,
|
|
174
|
-
performance: buildPerformanceData("create_linear_issue", latencyMs, 1, {
|
|
175
|
-
breakdown: {
|
|
176
|
-
upsert: {
|
|
177
|
-
latency_ms: latencyMs,
|
|
178
|
-
source: "supabase",
|
|
179
|
-
cache_status: "not_applicable",
|
|
180
|
-
network_call: true,
|
|
181
|
-
},
|
|
182
|
-
},
|
|
183
|
-
}),
|
|
184
|
-
};
|
|
185
|
-
}
|
|
186
|
-
catch (error) {
|
|
187
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
188
|
-
console.error("[create_linear_issue] Failed:", error);
|
|
189
|
-
const latencyMs = timer.stop();
|
|
190
|
-
return {
|
|
191
|
-
success: false,
|
|
192
|
-
error: `Linear API call failed: ${errorMessage}`,
|
|
193
|
-
performance: buildPerformanceData("create_linear_issue", latencyMs, 0),
|
|
194
|
-
};
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
//# sourceMappingURL=create-linear-issue.js.map
|