gitmem-mcp 1.4.3 → 1.4.4

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,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [1.4.4] - 2026-03-31
11
+
12
+ ### Fixed
13
+ - **Project drift on session resume eliminated**: When resuming an existing session (same hostname+PID), the stored project now overrides whatever the agent passes. Previously, context compaction could cause agents to send the wrong project (e.g., `orchestra_dev` instead of `weekend_warrior`), creating a session under the wrong project with wrong threads and decisions. The active-sessions registry already stored the correct project — it just wasn't used on resume.
14
+ - **`closing_reflection` array coercion**: Values passed as arrays in `closing_reflection` are now coerced to strings, preventing schema validation errors on session close.
15
+ - **`create_thread` no longer triggers false enforcement warnings**: Removed from `CONSEQUENTIAL_TOOLS` list — creating threads is lightweight and shouldn't require prior recall.
16
+
10
17
  ## [1.4.3] - 2026-02-24
11
18
 
12
19
  ### Fixed
package/bin/gitmem.js CHANGED
@@ -154,9 +154,10 @@ async function cmdInit() {
154
154
  // Merge: skip scars that already exist by id
155
155
  const existingIds = new Set(existing.map((s) => s.id));
156
156
  let added = 0;
157
+ const now = new Date().toISOString();
157
158
  for (const scar of starterScars) {
158
159
  if (!existingIds.has(scar.id)) {
159
- existing.push(scar);
160
+ existing.push({ ...scar, created_at: now, source_date: now.slice(0, 10) });
160
161
  added++;
161
162
  console.log(` + ${scar.title}`);
162
163
  } else {
@@ -13,11 +13,11 @@ export declare const ClosingReflectionSchema: z.ZodObject<{
13
13
  wrong_assumption: z.ZodString;
14
14
  scars_applied: z.ZodUnion<[z.ZodString, z.ZodArray<z.ZodString, "many">]>;
15
15
  /** Q7: What from this session should be captured as institutional memory? */
16
- institutional_memory_items: z.ZodOptional<z.ZodString>;
16
+ institutional_memory_items: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodEffects<z.ZodArray<z.ZodString, "many">, string, string[]>]>>;
17
17
  /** Q8: How did the human prefer to work this session? */
18
- collaborative_dynamic: z.ZodOptional<z.ZodString>;
18
+ collaborative_dynamic: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodEffects<z.ZodArray<z.ZodString, "many">, string, string[]>]>>;
19
19
  /** Q9: What collaborative dynamic worked or didn't work? */
20
- rapport_notes: z.ZodOptional<z.ZodString>;
20
+ rapport_notes: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodEffects<z.ZodArray<z.ZodString, "many">, string, string[]>]>>;
21
21
  }, "strip", z.ZodTypeAny, {
22
22
  what_broke: string;
23
23
  what_took_longer: string;
@@ -35,9 +35,9 @@ export declare const ClosingReflectionSchema: z.ZodObject<{
35
35
  what_worked: string;
36
36
  wrong_assumption: string;
37
37
  scars_applied: string | string[];
38
- institutional_memory_items?: string | undefined;
39
- collaborative_dynamic?: string | undefined;
40
- rapport_notes?: string | undefined;
38
+ institutional_memory_items?: string | string[] | undefined;
39
+ collaborative_dynamic?: string | string[] | undefined;
40
+ rapport_notes?: string | string[] | undefined;
41
41
  }>;
42
42
  export type ClosingReflection = z.infer<typeof ClosingReflectionSchema>;
43
43
  /**
@@ -154,11 +154,11 @@ export declare const SessionCloseParamsSchema: z.ZodObject<{
154
154
  wrong_assumption: z.ZodString;
155
155
  scars_applied: z.ZodUnion<[z.ZodString, z.ZodArray<z.ZodString, "many">]>;
156
156
  /** Q7: What from this session should be captured as institutional memory? */
157
- institutional_memory_items: z.ZodOptional<z.ZodString>;
157
+ institutional_memory_items: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodEffects<z.ZodArray<z.ZodString, "many">, string, string[]>]>>;
158
158
  /** Q8: How did the human prefer to work this session? */
159
- collaborative_dynamic: z.ZodOptional<z.ZodString>;
159
+ collaborative_dynamic: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodEffects<z.ZodArray<z.ZodString, "many">, string, string[]>]>>;
160
160
  /** Q9: What collaborative dynamic worked or didn't work? */
161
- rapport_notes: z.ZodOptional<z.ZodString>;
161
+ rapport_notes: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodEffects<z.ZodArray<z.ZodString, "many">, string, string[]>]>>;
162
162
  }, "strip", z.ZodTypeAny, {
163
163
  what_broke: string;
164
164
  what_took_longer: string;
@@ -176,9 +176,9 @@ export declare const SessionCloseParamsSchema: z.ZodObject<{
176
176
  what_worked: string;
177
177
  wrong_assumption: string;
178
178
  scars_applied: string | string[];
179
- institutional_memory_items?: string | undefined;
180
- collaborative_dynamic?: string | undefined;
181
- rapport_notes?: string | undefined;
179
+ institutional_memory_items?: string | string[] | undefined;
180
+ collaborative_dynamic?: string | string[] | undefined;
181
+ rapport_notes?: string | string[] | undefined;
182
182
  }>>;
183
183
  human_corrections: z.ZodOptional<z.ZodString>;
184
184
  decisions: z.ZodOptional<z.ZodArray<z.ZodObject<{
@@ -343,9 +343,9 @@ export declare const SessionCloseParamsSchema: z.ZodObject<{
343
343
  what_worked: string;
344
344
  wrong_assumption: string;
345
345
  scars_applied: string | string[];
346
- institutional_memory_items?: string | undefined;
347
- collaborative_dynamic?: string | undefined;
348
- rapport_notes?: string | undefined;
346
+ institutional_memory_items?: string | string[] | undefined;
347
+ collaborative_dynamic?: string | string[] | undefined;
348
+ rapport_notes?: string | string[] | undefined;
349
349
  } | undefined;
350
350
  human_corrections?: string | undefined;
351
351
  scars_to_record?: {
@@ -15,11 +15,11 @@ export const ClosingReflectionSchema = z.object({
15
15
  wrong_assumption: z.string(),
16
16
  scars_applied: z.union([z.string(), z.array(z.string())]),
17
17
  /** Q7: What from this session should be captured as institutional memory? */
18
- institutional_memory_items: z.string().optional(),
18
+ institutional_memory_items: z.union([z.string(), z.array(z.string()).transform((arr) => arr.join(". "))]).optional(),
19
19
  /** Q8: How did the human prefer to work this session? */
20
- collaborative_dynamic: z.string().optional(),
20
+ collaborative_dynamic: z.union([z.string(), z.array(z.string()).transform((arr) => arr.join(". "))]).optional(),
21
21
  /** Q9: What collaborative dynamic worked or didn't work? */
22
- rapport_notes: z.string().optional(),
22
+ rapport_notes: z.union([z.string(), z.array(z.string()).transform((arr) => arr.join(". "))]).optional(),
23
23
  });
24
24
  /**
25
25
  * Task completion proof schema
@@ -37,7 +37,6 @@ const SESSION_REQUIRED_TOOLS = new Set([
37
37
  const CONSEQUENTIAL_TOOLS = new Set([
38
38
  "create_learning", "gitmem-cl", "gm-scar",
39
39
  "create_decision", "gitmem-cd",
40
- "create_thread", "gitmem-ct", "gm-thread-new",
41
40
  "session_close", "gitmem-sc", "gm-close",
42
41
  ]);
43
42
  /**
@@ -503,6 +503,7 @@ function restoreSessionState(existing, fallbackAgent) {
503
503
  agent: existing.agent || fallbackAgent,
504
504
  linearIssue: existing.linear_issue,
505
505
  startedAt,
506
+ project: existing.project,
506
507
  };
507
508
  }
508
509
  /**
@@ -743,10 +744,20 @@ export async function sessionStart(params) {
743
744
  // 1. Detect agent (or use provided)
744
745
  const env = detectAgent();
745
746
  const agent = params.agent_identity || env.agent;
746
- const project = params.project || getConfigProject() || "default";
747
+ let project = params.project || getConfigProject() || "default";
747
748
  // Check for existing active session — reuse session_id but still load full context
748
749
  const existingSession = checkExistingSession(agent, params.force);
749
750
  const isResuming = existingSession !== null;
751
+ // When resuming, prefer the stored project from the existing session.
752
+ // This prevents project drift after context compaction — the agent may pass
753
+ // the wrong project (e.g., from CLAUDE.md defaults) but the stored session
754
+ // knows the real project.
755
+ if (isResuming && existingSession?.project) {
756
+ if (existingSession.project !== project) {
757
+ console.error(`[session_start] Project override on resume: ${project} → ${existingSession.project} (from stored session)`);
758
+ }
759
+ project = existingSession.project;
760
+ }
750
761
  // t-f7c2fa01: When force:true kills an existing session, carry forward its startedAt
751
762
  // so session_close duration reflects the full conversation, not just the new session.
752
763
  // Also carry forward activity counts (recalls, observations) so standard close isn't rejected.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gitmem-mcp",
3
- "version": "1.4.3",
3
+ "version": "1.4.4",
4
4
  "mcpName": "io.github.gitmem-dev/gitmem",
5
5
  "description": "Persistent learning memory for AI coding agents. Memory that compounds.",
6
6
  "type": "module",