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
|
-
|
|
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.
|