Repository navigation
Releases: rasyidmmz/dsh-ai-memory
Release list
v1.3.0 — native DSH capture with safe legacy compatibility
Adds native DSH capture identity support for ai-memory 3.2.0 and later. Finalization uses each stored session's actual dsh or claude-code identity, never the server version. Explicit agentKind still wins; unavailable stores fall back to legacy capture. Sweeper excludes unrelated harnesses and preserves row identity. No hook/profile rewrites or database relabeling. Includes migration guidance and 27 passing checks (16 smoke, 11 SQLite regressions). Source contract checked at upstream 3.2.0/3.2.1; not a live 3.2.1 consolidation test. Full changelog: https://github.com/rasyidmmz/dsh-ai-memory/blob/v1.3.0/CHANGELOG.md
v1.2.1 — declare dsh.engines for marketplace compatibility gating
Metadata only; behaviour unchanged from 1.2.0.
Added
dsh.enginesinpackage.json:dsh: ">=0.1.7-rc.2 <0.3.0"andnode: ">=22.5.0". dsh-market reads an ownengines.dshrange as the authoritative compatibility declaration, so an incompatible host is refused at install instead of failing at runtime. The DSH floor is wherectx.shell.execute()replacedrun(); the ceiling is the 0.2.x line this release was verified on. Node's floor is wherenode:sqlite(the sweeper's read-only store access) became available.
Changed
- Repository description now states what the plugin does and that it ships the capture-hook template.
v1.2.0 — startup diagnosis for a marketplace install
The plugin can be installed from a marketplace in one row, but it cannot install ai-memory or wire DSH's capture hooks. Until now that looked like 'loaded, idle'. It now says which piece is missing, once, with the next step.
- Checks the configured ai-memory binary, its data directory (
config.toml), and whether the running DSH profile wires@deepseek-ai/dsh-hooks-claude-code. - Each miss prints a concrete step: the upstream install link,
ai-memory init, or the absolute path to the shippeddocs/hooks-dsh.json. - 'server did not answer' now says how to start one.
npm test= 16 checks, including a clean profile producing no output at all.
No change to the finalize path: same events, same CLI arguments, same sweeper.
v1.1.2 — re-verified on DSH 0.2.1-rc.2 and ai-memory 3.1.1
Compatibility re-verification; no behaviour change.
- DSH 0.2.1-rc.2 (installed app.asar): agent/created, agent/disposed, session/disposed still emitted; ctx.sessions.get().header still carries cwd/origin/delegationDepth; ctx.shell still execute()-only.
- ai-memory 3.1.1: finalize-session keeps --agent/--workspace/--project/--session-id/--reopen/--json; output lines unchanged (Finalized … / No open … sessions matched …); session ids still uuid5(NAMESPACE_OID, native id).
- Store upgrade: a 2.6-era store opens under 3.1.1, migrates to schema V83, sweeper query returns the same rows.
- docs/hooks-dsh.json now matches the running configuration (PreToolUse included with its measured cost, Stop->hook-drain chain explained, insert-form profile row, Windows 0xC0000142 sandbox note).
- New: test/smoke.mjs — 11 in-process checks via
npm test.
v1.1.1
Fixed
-
The
identitysupport added in 1.1.0 never ran in the common case. The
candidate that resolves a marker'sidentityto the project that owns it was
placed inside the branch that runs only when the session's folder sits BELOW
the marker root. But a marker that declares onlyidentityis the root it
sits in, so the session's own folder is that root — precisely the case the
branch excludes. On any folder whose name differs from the identity's project,
the plugin looked the session up under the folder name instead, got
No open ... sessions matched, and left it to the sweeper.Found by running the installed plugin against a real identity with a real
shell, not by the unit test: that test put the session in a subfolder, so it
exercised the harder case and walked straight past the common one. There is a
test for both shapes now, and the old code fails the new one.Behaviour for markers without
identityis unchanged.
Verified
- Feature suite 9/9 on the published source, 7/7 on the local variant (two
assertions skipped there, with the reason printed). Against 1.1.0 the same
suite scores 8/9 — the new assertion is the one that fails. - Behaviour suite 19/19; parity SEPADAN (18 units).
v1.1.0
Built against ai-memory 2.5.2. Two changes, both driven by that release.
Added
-
A marker's
identityis honoured. ai-memory 2.5.0 gave every project an
identitythat is deliberately not its folder name (#708) and routes captures
by it;identityin.ai-memory.tomloutranksproject, and a marker that
declares onlyidentityis valid.The plugin does not try to reproduce the naming rule — which name owns an
identity is the SERVER's decision on first sighting, and guessing it is what
caused the 1.0.4 bug. It reads the answer back out ofprojects.identity
(migration V70) with one indexed lookup, and falls back to the folder name
when there is no answer. Read-only; any failure is silent. -
A session that continued after a finalize can be re-finalized. ai-memory
2.5.0 addedfinalize-session --reopen(#836). This matters for one concrete
failure the plugin could otherwise cause and not repair: the sweeper
closing a session it wrongly judged abandoned. Its page was then built from
the first half, and because the session had ended, no later finalize could
ever update it — everything the agent did afterwards was lost.--reopenis now used for exactly that case: once per session, only for a
session this process already finalized, and only after a plain finalize
answersNo open ... sessions matched. Re-running with nothing new is a
documented no-op, so the case where another harness ended the session is
harmless.
Changed
-
"Already finalized" is now a question about time, not a flag. The guard
that stops two events describing one session end from finalizing twice
(Bug 1) was a set, which cannot tell "the second event of one end" from "a
genuinely new end hours later". It is a timestamped map with a 60-second
window, and only a finalize outside that window is allowed to reopen.Stated plainly: a session that ends twice inside those 60 seconds gets only
the first finalize. The window is far wider than the millisecond race the
guard exists for, and can be overridden withAI_MEMORY_DEDUP_WINDOW_MS.
Verified
- New suite
uji-fitur-1.1.0.mjs: 6/6 on the published source, 5/5 on
the local variant (one assertion is skipped there, with the reason printed —
that variant reads a fixed database path and cannot take an injected one).
Against 1.0.5 the same suite scores 2/6, which is how the new behaviour is
shown to be what makes it pass. - Existing behaviour suite 19/19; parity between the variants SEPADAN
(18 compared units).
v1.0.5
Fixed
-
The startup log no longer reports a stale version.
VERSIONwas a
hand-edited constant, and it fell behindpackage.jsontwice — first
active v1.0.0whilepackage.jsonsaid 1.0.2, thenactive v1.0.3while
package.jsonsaid 1.0.4. Both times the only visible symptom was a log line
that lied, which is exactly the question that line exists to answer: which
build is actually loaded?The version is now read from the
package.jsonshipped beside the module, so
there is no number left that can go stale. If it cannot be read, the log says
active v?rather than guessing.Version 1.0.4 is functionally correct but announces itself as
v1.0.3. If
you are on 1.0.4 and the log bothers you, this is the release that fixes it;
there is no behavioural difference between the two.
Verified
uji-label-versi.mjs— the guard that caught this — now passes for the
published repo. It imports the plugin, runsapply()against a mock context
and compares the captured log line withpackage.json, so a computed version
is checked for real rather than pattern-matched.- Behaviour suite 19/19, parity SEPADAN (17 units).
v1.0.4
Fixed
-
A session opened in a subfolder is now finalized into its project's root.
ai-memory derives a session's project from its working directory, and a
.ai-memory.tomlmarker pins the name only for the folder that HOLDS it —
measured withai-memory doctor: run fromC:\Code\Dsh\arsip-dumpit answers
projectarsip-dump, notdsh, while the workspace is still inherited from
the ancestor marker.So a session started in
<project>\subwas looked up under a project named
sub, the CLI answeredNo open ... sessions matched, and the session was
left to the sweeper instead of being summarized on the spot. The plugin now
walks up from the session's directory to the nearest marker and tries that
project FIRST, so the fast path succeeds the same way it does for a session
opened at the root.The walk stops at a
.gitboundary, so a nested repository such as
ai-memory/plugin-publikkeeps its own project instead of being folded into
its parent. A session whose folder is not inside a marker root behaves exactly
as before — the previous behaviour is still in the candidate chain, so a
session captured before this change (project = folder basename) finalizes too
rather than being retried on every sweep.Nothing else changed: no new configuration, no new dependency, and the
resolution is bounded and silent (any failure falls back to the old path).
Verified
- Behaviour suite 19/19, against the installed copy, the published source and
the local variant. Three of those assertions are new and cover this case: with
the previous code they fail (17/19), which is how the fix was confirmed to be
the thing that makes them pass. - Parity between the local and published variants: SEPADAN (17 compared
units — the two new scope helpers included, so the rule cannot drift between
them).
v1.0.1
Do not use this version on DSH 0.1.7-rc.2. It contains both bug fixes below
but still callsctx.shell.run(), which no longer exists there. It installed
cleanly and finalized nothing. See 1.0.2.
Fixed
Two real bugs, both found in the field rather than by reading code.
-
A session was finalized twice.
agent/disposedcarries the id
session-<uuid>, whilesession/disposedcarries the bare stored UUID. The
same session therefore entered the queue twice within milliseconds, through two
different id shapes. Both were checked againstfinalizedRecentlyat
enqueue time — when the first finalize has not finished and the set is still
empty, so both passed.pump()did not re-check, so the CLI ran twice: ~2.2 s
and oneai-memory.exeprocess wasted, the second call answering
No open claude-code sessions matched.Observed in the log before the fix:
04:41:18.237 finalizing session session- 04:41:20.482 session -> page created 04:41:20.482 finalizing session c37c3911 (SAME session, second call) 04:41:22.665 session c37c3911 -> no open session matchedFixed by de-duplicating in
pump()on the normalised UUID, so a duplicate is
caught regardless of which event enqueued it. -
Session labels in logs were the useless constant
"session-".
id.slice(0, 8)applied to a rawsession-<uuid>id yields"session-", so
every session logged identically and the line told you nothing. Labels now come
fromshortLabel(), which strips the prefix first and therefore always shows
the real UUID's first 8 characters.
Verification
- A functional test drives the plugin with a stub ctx and sends two events for one
session. Before the fix it made 3finalize-sessioncalls; after, 1. - Unit tests cover
shortLabelfor a raw id, a bare UUID, and an empty string
(4/4).
Note for the record
The first attempt at the duplicate-finalize fix was itself wrong: it guarded on
!hinted, but the fast path records a sweepProjects hint and enqueues, so the
duplicate always arrives as a hinted item and the check caught nothing. The
functional test caught that — not code review.
v1.0.0
Added
- Initial release, published as
dsh-ai-memory-bridgeand renamed to
dsh-ai-memorythe same evening. Closes ai-memory's consolidation loop for
DSH: on session end, callsai-memory finalize-sessionso captured
observations become searchable wiki pages. - Skips subagents (only main sessions are finalized).
- Queues concurrent session ends instead of dropping them.
- Sweeps sessions abandoned by a forced restart.
- Handles both id shapes:
session-<uuid>fromagent/disposedand the bare
stored UUID fromsession/disposed. docs/ships in the npm package so the README's hook example link resolves.