Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
4f4e110
fix(memory): capture end-topic turns that carry more than the end com…
Anson-Se Sep 26, 2026
dabe01c
fix(documents): support continued reading of long documents
Orsted290 Sep 23, 2026
8114ccc
fix(agent): keep read_file line counts aligned with apply_patch
Orsted290 Sep 24, 2026
c639753
chore(documents): drop debug scripts and investigation notes
Orsted290 Sep 28, 2026
7ff1188
fix(memory): stop sending CLI arguments as analytics command actions
Anson-Se Sep 29, 2026
29ef072
fix(memory): wake the worker after every session close
Anson-Se Sep 29, 2026
1aa0614
Merge pull request #568 from MemTensor/main
syzsunshine219 Sep 29, 2026
32c3437
fix: refresh installed agent hooks when the bundled revision changes
Orsted290 Sep 30, 2026
478ae78
fix: deprioritize startup summary repairs
Sep 30, 2026
b5b9174
Merge upstream/v1.2.1 into fix-hook-auto-update
Orsted290 Sep 30, 2026
fb65ef0
fix(dsh): use the current recall message source and assistant event
Wang-Daoji Sep 30, 2026
8bb6d0d
fix(dsh): give the memory plugin a package version
Wang-Daoji Sep 30, 2026
7e9ec79
fix(dsh): align standalone adapter with supported lifecycle
hijzy Oct 8, 2026
7580c48
fix(dsh): align client manifest with supported tags
hijzy Oct 8, 2026
dcdecf6
Merge pull request #579 from hijzy/main
hijzy Oct 8, 2026
ceb5fa3
fix: remove legacy memory embedding config
hijzy Oct 8, 2026
fcf55fd
Merge pull request #581 from hijzy/main
hijzy Oct 8, 2026
9da8ea8
fix: retry a hook install whose revision was written before the files
Orsted290 Oct 8, 2026
fdb3617
fix(analytics): report each newly stored memory once
Oct 8, 2026
3c549a2
Merge pull request #574 from Orsted290/fix-hook-auto-update
origami-chen Oct 8, 2026
d424259
Merge pull request #582 from antalike/fix/tracking
syzsunshine219 Oct 8, 2026
cc09607
Merge pull request #559 from Orsted290/fix-long-document-reading
Wang-Daoji Oct 9, 2026
9cae0f4
Merge pull request #567 from Orsted290/fix-memory-patch-line-count
Wang-Daoji Oct 9, 2026
023430e
chore: merge v1.2.1 updates
Oct 9, 2026
fa12bd0
Merge pull request #577 from jia030928/fix-placeholder-summary-repair…
origami-chen Oct 9, 2026
98819bf
fix: support LM Studio JSON responses
Oct 9, 2026
4ad0fda
Merge pull request #565 from Anson-Se/fix-session-close-wake-worker
origami-chen Oct 9, 2026
d8c1b21
Merge remote-tracking branch 'upstream/v1.2.2' into fix-end-topic-l1-…
Anson-Se Oct 9, 2026
0aa4be2
test: give the end-topic capture decision stub a non-empty l1 title
Anson-Se Oct 9, 2026
0e60325
Merge pull request #566 from Anson-Se/fix-cli-analytics-command-action
origami-chen Oct 9, 2026
d396f16
Merge pull request #548 from Anson-Se/fix-end-topic-l1-capture
origami-chen Oct 9, 2026
b46be20
Merge pull request #598 from MemTensor/main
syzsunshine219 Oct 10, 2026
62a371f
Merge pull request #587 from jia030928/fix-lmstudio-response-format
origami-chen Oct 10, 2026
ac94d8d
fix(memory): replace stale runtimes by build identity
hijzy Oct 10, 2026
f6c9338
Merge pull request #601 from hijzy/agent/fix-memory-runtime-upgrade-v…
hijzy Oct 10, 2026
f482d8f
fix: bound memory initialization and queue turn capture off the model…
Orsted290 Oct 10, 2026
52f0cc8
fix: align memory degradation diagnostics with background capture
Orsted290 Oct 10, 2026
2069443
Merge pull request #603 from Orsted290/fix-memory-hook-deadline
origami-chen Oct 10, 2026
3d9df14
chore(release): prepare Memmy v1.2.2
Oct 12, 2026
18fa667
test(analytics): cover boolean desktop event params
Oct 12, 2026
4e44217
test(analytics): align boolean event assertions
Oct 12, 2026
9da4641
test(memory): align project version assertion
Oct 12, 2026
229dc5e
test(windows): allow slower runtime upgrade fixtures
Oct 12, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions .github/release-notes/v1.2.2.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Memmy v1.2.2

## Highlights

- Improved memory initialization and turn capture by moving bounded work off the model path and exposing clearer background-capture diagnostics.
- Improved bundled Memory runtime upgrades by selecting runtimes by build identity and validating the installed runtime across macOS and Windows.
- Added long-document reading with bounded chunks and continuation offsets for PDF and Office files.
- Improved agent-source ingestion, auto-injection, and skill distribution with broader regression coverage and clearer lifecycle handling.
- Fixed LM Studio and OpenAI-compatible JSON response-format incompatibilities by retrying with text mode when needed.

## Agent and Desktop improvements

- Refreshed installed Claude Code, Codex, and Cursor hooks when their bundled revision or on-disk files are stale, and record the revision only after a successful install.
- Kept queued memory processing moving after session close and retained end-topic turns that contain feedback or instructions for L1 capture.
- Improved filesystem and document tools with consistent line numbering, continued long-document reads, and expanded agent-runtime regression coverage.
- Tightened analytics boundaries by avoiding raw search queries, memory text, and identifiers in CLI command actions while reporting stored-memory and source-layer events consistently.

## Upgrade notes

- Memmy Desktop and Agent are version `1.2.2`.
- The bundled Memory service, viewer, and CLI remain independently versioned.
- Memory protocol version remains `1`.
6 changes: 4 additions & 2 deletions .github/workflows/memory-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ on:
version:
description: Memory version (X.Y.Z)
required: true
default: 2.1.3
default: 2.1.4
push:
tags:
- "memory-v*"
Expand All @@ -26,7 +26,9 @@ jobs:
- run: npm ci
- run: npm run typecheck -w @memmy/memory
- run: npm test -w @memmy/memory
- run: npx vitest run App/shell/desktop/tests/packaged-runtime-boundary.test.ts App/shell/desktop/tests/runtime-services.test.ts
- run: npm run build -w @memmy/migrations
- run: npm run build -w @memmy/local-api-contracts
- run: npx vitest run App/shell/desktop/tests/packaged-runtime-boundary.test.ts App/shell/desktop/tests/runtime-services.test.ts App/shell/desktop/tests/runtime-memory-upgrade.test.ts tests/packaged-runtime-config.test.mjs

runtime:
needs: verify
Expand Down
12 changes: 12 additions & 0 deletions .github/workflows/windows-memory-validation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@ on:
- "Memory/**"
- "AgentSourceCore/**"
- "App/shell/desktop/build/**"
- "App/shell/desktop/src/main/runtime-services.ts"
- "App/shell/desktop/tests/runtime-memory-upgrade.test.ts"
- "App/shell/desktop/tests/windows-standard-upgrade-check.test.ts"
- "scripts/internal/shared/memory-runtime-build-identity.mjs"
- "scripts/internal/win/create-memory-runtime-manifest.mjs"
- "package.json"
- "package-lock.json"
workflow_dispatch:
Expand Down Expand Up @@ -57,11 +61,19 @@ jobs:
run: npm ci
- name: Build shared Agent source contracts
run: npm run build -w @memmy/agent-source-core
- name: Build desktop startup dependencies
run: |
npm run build -w @memmy/migrations
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
npm run build -w @memmy/local-api-contracts
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
- name: Test Windows Memory contracts and temporary upgrade layouts
run: >-
node node_modules/vitest/vitest.mjs run
tests/windows-memory-workflow.test.ts
Memory/tests/runtime-installer-windows.test.ts
Memory/tests/runtime-installer.test.ts
App/shell/desktop/tests/runtime-memory-upgrade.test.ts
App/shell/desktop/tests/windows-standard-upgrade-check.test.ts
--reporter=default --reporter=json --outputFile=windows-memory-unit-results.json
- name: Test the native temporary Memory task
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1039,6 +1039,9 @@ function createFakeAgentSourceService(): AgentSourceService {
async uninstallPlugin() {
return undefined;
},
async isInstalledHookCurrent() {
return true;
},
async detectMemoryPluginConflicts() {
return [];
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { mkdir, readFile, rename, rm, stat, writeFile } from "node:fs/promises";
import { homedir } from "node:os";
import { basename, dirname, join } from "node:path";
import { createNodeHookCommand } from "../hook-command.js";
import { isInstalledMemmyHookCurrent, memmyHookRevisionField } from "../hook-revision.js";
import { readMemmyMemoryServiceConfig } from "../memmy-runtime-config.js";
import { removeMemmySkillDirectory, replaceMemmySkillDirectory } from "../skill-directory.js";
import { renderMemmyPluginSkillManifest } from "../templates/memmy-plugin.js";
Expand Down Expand Up @@ -85,6 +86,19 @@ export function createClaudeCodeSkillTarget(deps: CreateClaudeCodeSkillTargetDep
return (await readTextFile(join(root, TARGET_FILE_NAME))).includes(START_MARKER);
},

async isInstalledHookCurrent() {
const root = await this.resolveRootDirectory();
if (!root) return false;
const hookDirectory = join(root, HOOK_DIRECTORY_NAME);
return isInstalledMemmyHookCurrent({
source: CLAUDE_CODE_TARGET_ID,
mode: "claude-code",
hookScriptPath: join(hookDirectory, HOOK_SCRIPT_FILE_NAME),
bridgePath: join(hookDirectory, WORKSPACE_BRIDGE_FILE_NAME),
configPath: join(hookDirectory, HOOK_CONFIG_FILE_NAME)
});
},

async installPlugin(_targetId) {
const root = await this.resolveRootDirectory();
if (!root) {
Expand All @@ -93,11 +107,13 @@ export function createClaudeCodeSkillTarget(deps: CreateClaudeCodeSkillTargetDep

const hookDirectory = join(root, HOOK_DIRECTORY_NAME);
const hookScriptPath = join(hookDirectory, HOOK_SCRIPT_FILE_NAME);
const hookConfigPath = join(hookDirectory, HOOK_CONFIG_FILE_NAME);
const hookConfig = {
memmy_config_path: memmyConfigPath,
...(await readMemmyMemoryServiceConfig(memmyConfigPath))
};
await mkdir(hookDirectory, { recursive: true });
await writeFileAtomically(
join(hookDirectory, HOOK_CONFIG_FILE_NAME),
`${JSON.stringify({ memmy_config_path: memmyConfigPath, ...(await readMemmyMemoryServiceConfig(memmyConfigPath)) }, null, 2)}\n`
);
await writeFileAtomically(hookConfigPath, `${JSON.stringify(hookConfig, null, 2)}\n`);
await writeFileAtomically(
hookScriptPath,
renderMemmyResumeHookScript({ source: CLAUDE_CODE_TARGET_ID, mode: "claude-code" })
Expand All @@ -118,6 +134,10 @@ export function createClaudeCodeSkillTarget(deps: CreateClaudeCodeSkillTargetDep
upsertMarkerBlock(await readTextFile(filePath), renderMemmySkillBootstrapManifest(manifest))
);
await replaceMemmySkillDirectory(root, manifest);
await writeFileAtomically(
hookConfigPath,
`${JSON.stringify({ ...hookConfig, ...(await memmyHookRevisionField(CLAUDE_CODE_TARGET_ID, "claude-code")) }, null, 2)}\n`
);
},

async uninstallPlugin(_targetId) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,30 @@ describe("claude code skill target", () => {
}
});

it("marks a hook without a stored revision as outdated and refreshes it in place", async () => {
const { rootDirectory, memmyConfigPath } = createFixture();
const target = createClaudeCodeSkillTarget({ rootDirectory, memmyConfigPath });
const configPath = join(rootDirectory, "hooks", "memmy-memory-config.json");

await target.installPlugin?.("claude_code");
const installed = JSON.parse(readFileSync(configPath, "utf8")) as { hook_revision?: string };
expect(installed.hook_revision).toEqual(expect.stringMatching(/^[a-f0-9]{64}$/));
await expect(target.isInstalledHookCurrent?.()).resolves.toBe(true);

writeFileSync(configPath, `${JSON.stringify({ ...installed, hook_revision: "stale" }, null, 2)}\n`, "utf8");
await expect(target.isInstalledHookCurrent?.()).resolves.toBe(false);

writeFileSync(join(rootDirectory, "hooks", "memmy-resume-hook.mjs"), "old hook\n", "utf8");
writeFileSync(configPath, `${JSON.stringify(installed, null, 2)}\n`, "utf8");
await expect(target.isInstalledHookCurrent?.()).resolves.toBe(false);
rmSync(join(rootDirectory, "hooks", "memmy-resume-hook.mjs"));
writeFileSync(configPath, `${JSON.stringify(installed, null, 2)}\n`, "utf8");
await expect(target.isInstalledHookCurrent?.()).resolves.toBe(false);

await target.installPlugin?.("claude_code");
await expect(target.isInstalledHookCurrent?.()).resolves.toBe(true);
});

it("installs a UserPromptSubmit hook that blocks resume commands with top L1 candidates", async () => {
const { rootDirectory, memmyConfigPath } = createFixture();
let requestBody: Record<string, unknown> | undefined;
Expand Down
28 changes: 24 additions & 4 deletions App/backend/src/adapters/outbound/skill-writer/codex/target.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { homedir } from "node:os";
import { basename, dirname, join } from "node:path";
import { resolveCodexHomeDirectory } from "../../agent-paths.js";
import { createNodeHookCommand } from "../hook-command.js";
import { isInstalledMemmyHookCurrent, memmyHookRevisionField } from "../hook-revision.js";
import { readMemmyMemoryServiceConfig } from "../memmy-runtime-config.js";
import {
removeMemmyResumeSkillDirectory,
Expand Down Expand Up @@ -91,6 +92,19 @@ export function createCodexSkillTarget(deps: CreateCodexSkillTargetDeps = {}): S
return (await readTextFile(join(root, TARGET_FILE_NAME))).includes(START_MARKER);
},

async isInstalledHookCurrent() {
const root = await this.resolveRootDirectory();
if (!root) return false;
const hookDirectory = join(root, HOOK_DIRECTORY_NAME);
return isInstalledMemmyHookCurrent({
source: CODEX_TARGET_ID,
mode: "codex",
hookScriptPath: join(hookDirectory, HOOK_SCRIPT_FILE_NAME),
bridgePath: join(hookDirectory, WORKSPACE_BRIDGE_FILE_NAME),
configPath: join(hookDirectory, HOOK_CONFIG_FILE_NAME)
});
},

async installPlugin(_targetId) {
const root = await this.resolveRootDirectory();
if (!root) {
Expand All @@ -99,11 +113,13 @@ export function createCodexSkillTarget(deps: CreateCodexSkillTargetDeps = {}): S

const hookDirectory = join(root, HOOK_DIRECTORY_NAME);
const hookScriptPath = join(hookDirectory, HOOK_SCRIPT_FILE_NAME);
const hookConfigPath = join(hookDirectory, HOOK_CONFIG_FILE_NAME);
const hookConfig = {
memmy_config_path: memmyConfigPath,
...(await readMemmyMemoryServiceConfig(memmyConfigPath))
};
await mkdir(hookDirectory, { recursive: true });
await writeFileAtomically(
join(hookDirectory, HOOK_CONFIG_FILE_NAME),
`${JSON.stringify({ memmy_config_path: memmyConfigPath, ...(await readMemmyMemoryServiceConfig(memmyConfigPath)) }, null, 2)}\n`
);
await writeFileAtomically(hookConfigPath, `${JSON.stringify(hookConfig, null, 2)}\n`);
await writeFileAtomically(hookScriptPath, renderMemmyResumeHookScript({ source: CODEX_TARGET_ID, mode: "codex" }));
await writeFileAtomically(
join(hookDirectory, WORKSPACE_BRIDGE_FILE_NAME),
Expand All @@ -127,6 +143,10 @@ export function createCodexSkillTarget(deps: CreateCodexSkillTargetDeps = {}): S
hooksFilePath,
hookCommand
});
await writeFileAtomically(
hookConfigPath,
`${JSON.stringify({ ...hookConfig, ...(await memmyHookRevisionField(CODEX_TARGET_ID, "codex")) }, null, 2)}\n`
);
},

async uninstallPlugin(_targetId) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,27 @@ describe("codex skill target", () => {
}
});

it("marks a hook without a stored revision as outdated and refreshes it in place", async () => {
const { rootDirectory, memmyConfigPath } = createFixture();
const target = createCodexSkillTarget({ rootDirectory, memmyConfigPath, trustHooks: noOpTrustHooks });
const configPath = join(rootDirectory, "hooks", "memmy-memory-config.json");

await target.installPlugin?.("codex");
const installed = JSON.parse(readFileSync(configPath, "utf8")) as { hook_revision?: string };
expect(installed.hook_revision).toEqual(expect.stringMatching(/^[a-f0-9]{64}$/));
await expect(target.isInstalledHookCurrent?.()).resolves.toBe(true);

writeFileSync(configPath, `${JSON.stringify({ ...installed, hook_revision: "stale" }, null, 2)}\n`, "utf8");
await expect(target.isInstalledHookCurrent?.()).resolves.toBe(false);

writeFileSync(join(rootDirectory, "hooks", "memmy-resume-hook.mjs"), "old hook\n", "utf8");
writeFileSync(configPath, `${JSON.stringify(installed, null, 2)}\n`, "utf8");
await expect(target.isInstalledHookCurrent?.()).resolves.toBe(false);

await target.installPlugin?.("codex");
await expect(target.isInstalledHookCurrent?.()).resolves.toBe(true);
});

it("persists trust for the installed user-level hooks before installation completes", async () => {
const { rootDirectory, memmyConfigPath } = createFixture();
let trustOptions: TrustMemmyCodexHooksOptions | undefined;
Expand Down
26 changes: 22 additions & 4 deletions App/backend/src/adapters/outbound/skill-writer/cursor/target.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { mkdir, readFile, rename, rm, writeFile } from "node:fs/promises";
import { homedir } from "node:os";
import { basename, dirname, join } from "node:path";
import { createNodeHookCommand } from "../hook-command.js";
import { isInstalledMemmyHookCurrent, memmyHookRevisionField } from "../hook-revision.js";
import { readMemmyMemoryServiceConfig } from "../memmy-runtime-config.js";
import {
removeMemmyResumeSkillDirectory,
Expand Down Expand Up @@ -59,16 +60,29 @@ export function createCursorSkillTarget(deps: CreateCursorSkillTargetDeps = {}):
return (await readTextFile(join(cursorRootDirectory, "skills", "memmy-memory", "SKILL.md"))).includes("name: memmy-memory");
},

async isInstalledHookCurrent() {
const hookDirectory = join(cursorRootDirectory, HOOK_DIRECTORY_NAME);
return isInstalledMemmyHookCurrent({
source: CURSOR_TARGET_ID,
mode: "cursor",
hookScriptPath: join(hookDirectory, HOOK_SCRIPT_FILE_NAME),
bridgePath: join(hookDirectory, WORKSPACE_BRIDGE_FILE_NAME),
configPath: join(hookDirectory, HOOK_CONFIG_FILE_NAME)
});
},

async installPlugin(_targetId) {
await mkdir(cursorRootDirectory, { recursive: true });

const hookDirectory = join(cursorRootDirectory, HOOK_DIRECTORY_NAME);
const hookScriptPath = join(hookDirectory, HOOK_SCRIPT_FILE_NAME);
const hookConfigPath = join(hookDirectory, HOOK_CONFIG_FILE_NAME);
const hookConfig = {
memmy_config_path: memmyConfigPath,
...(await readMemmyMemoryServiceConfig(memmyConfigPath))
};
await mkdir(hookDirectory, { recursive: true });
await writeFileAtomically(
join(hookDirectory, HOOK_CONFIG_FILE_NAME),
`${JSON.stringify({ memmy_config_path: memmyConfigPath, ...(await readMemmyMemoryServiceConfig(memmyConfigPath)) }, null, 2)}\n`
);
await writeFileAtomically(hookConfigPath, `${JSON.stringify(hookConfig, null, 2)}\n`);
await writeFileAtomically(
hookScriptPath,
renderMemmyResumeHookScript({ source: CURSOR_TARGET_ID, mode: "cursor" })
Expand All @@ -83,6 +97,10 @@ export function createCursorSkillTarget(deps: CreateCursorSkillTargetDeps = {}):
const manifest = renderMemmyPluginSkillManifest(_targetId);
await replaceMemmySkillDirectory(cursorRootDirectory, manifest);
await replaceMemmyResumeSkillDirectory(cursorRootDirectory, CURSOR_TARGET_ID);
await writeFileAtomically(
hookConfigPath,
`${JSON.stringify({ ...hookConfig, ...(await memmyHookRevisionField(CURSOR_TARGET_ID, "cursor")) }, null, 2)}\n`
);
},

async uninstallPlugin(_targetId) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,31 @@ describe("cursor skill target", () => {
}
});

it("marks a hook without a stored revision as outdated and refreshes it in place", async () => {
const { rootDirectory, memmyConfigPath } = createFixture();
const target = createCursorSkillTarget({ rootDirectory, memmyConfigPath });
const configPath = join(rootDirectory, "hooks", "memmy-memory-config.json");

await target.installPlugin?.("cursor");
const installed = JSON.parse(readFileSync(configPath, "utf8")) as { hook_revision?: string };
expect(installed.hook_revision).toEqual(expect.stringMatching(/^[a-f0-9]{64}$/));
await expect(target.isInstalledHookCurrent?.()).resolves.toBe(true);

writeFileSync(configPath, `${JSON.stringify({ ...installed, hook_revision: "stale" }, null, 2)}\n`, "utf8");
await expect(target.isInstalledHookCurrent?.()).resolves.toBe(false);

writeFileSync(join(rootDirectory, "hooks", "memmy-resume-hook.mjs"), "old hook\n", "utf8");
writeFileSync(configPath, `${JSON.stringify(installed, null, 2)}\n`, "utf8");
await expect(target.isInstalledHookCurrent?.()).resolves.toBe(false);

delete installed.hook_revision;
writeFileSync(configPath, `${JSON.stringify(installed, null, 2)}\n`, "utf8");
await expect(target.isInstalledHookCurrent?.()).resolves.toBe(false);

await target.installPlugin?.("cursor");
await expect(target.isInstalledHookCurrent?.()).resolves.toBe(true);
});

it("installs a resume Skill and reads the current memmyMemory storage instead of legacy storage", async () => {
const { rootDirectory, memmyConfigPath } = createFixture();
let requestBody: Record<string, unknown> | undefined;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/** Hook revision tests. */
import { mkdtempSync, rmSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { afterEach, describe, expect, it } from "vitest";
import { currentMemmyHookRevision, hookRevision, isInstalledMemmyHookCurrent } from "./hook-revision.js";

let tempDir: string | undefined;

afterEach(() => {
if (tempDir) {
rmSync(tempDir, { recursive: true, force: true });
tempDir = undefined;
}
});

describe("hook revision", () => {
it("changes when the hook script or workspace bridge changes", () => {
const current = hookRevision("hook script", "workspace bridge");

expect(hookRevision("hook script", "workspace bridge")).toBe(current);
expect(hookRevision("updated hook script", "workspace bridge")).not.toBe(current);
expect(hookRevision("hook script", "updated workspace bridge")).not.toBe(current);
});

it("treats a current fingerprint with leftover hook files as outdated", async () => {
tempDir = mkdtempSync(join(tmpdir(), "memmy-hook-revision-"));
const revision = await currentMemmyHookRevision("cursor", "cursor");
const hookScriptPath = join(tempDir, "memmy-resume-hook.mjs");
const bridgePath = join(tempDir, "memmy-workspace-bridge.mjs");
const configPath = join(tempDir, "memmy-memory-config.json");
writeFileSync(hookScriptPath, "old hook\n", "utf8");
writeFileSync(bridgePath, "old bridge\n", "utf8");
writeFileSync(configPath, `${JSON.stringify({ hook_revision: revision }, null, 2)}\n`, "utf8");

await expect(isInstalledMemmyHookCurrent({
source: "cursor",
mode: "cursor",
hookScriptPath,
bridgePath,
configPath
})).resolves.toBe(false);
});
});
Loading
Loading