memoir-cli 3.16.3 → 3.16.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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "memoir-cli",
|
|
3
|
-
"version": "3.16.
|
|
3
|
+
"version": "3.16.4",
|
|
4
4
|
"mcpName": "io.github.camgitt/memoir",
|
|
5
5
|
"description": "Portable, project-scoped memory and session handoffs for coding agents. Readable files, MCP recall, and optional user-passphrase encrypted backups.",
|
|
6
6
|
"main": "src/index.js",
|
package/src/adapters/index.js
CHANGED
|
@@ -8,6 +8,7 @@ import os from 'os';
|
|
|
8
8
|
import chalk from 'chalk';
|
|
9
9
|
import { shouldIgnoreProject } from '../context/capture.js';
|
|
10
10
|
import { vscodeUserDir, vscodeGlobalStorage, xdgConfigDir } from '../utils/platform.js';
|
|
11
|
+
import { isSideCarDir } from '../context/transcripts.js';
|
|
11
12
|
|
|
12
13
|
const home = os.homedir();
|
|
13
14
|
|
|
@@ -57,8 +58,8 @@ export const adapters = [
|
|
|
57
58
|
// Allow directory traversal but skip dirs that only contain session data
|
|
58
59
|
try {
|
|
59
60
|
if (nodeFs.statSync(src).isDirectory()) {
|
|
60
|
-
// Skip
|
|
61
|
-
if (basename
|
|
61
|
+
// Skip agent side-car and UUID-named session dirs (contain large .jsonl files, no .md)
|
|
62
|
+
if (isSideCarDir(basename)) return false;
|
|
62
63
|
// UUID pattern: 8-4-4-4-12 hex chars
|
|
63
64
|
if (/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/.test(basename)) return false;
|
|
64
65
|
return true;
|
package/src/commands/snapshot.js
CHANGED
|
@@ -8,6 +8,7 @@ import gradient from 'gradient-string';
|
|
|
8
8
|
import { getConfig, getGeminiApiKey } from '../config.js';
|
|
9
9
|
import { syncToLocal, syncToGit } from '../providers/index.js';
|
|
10
10
|
import { saveHandoff } from '../context/handoffs.js';
|
|
11
|
+
import { isSideCarDir, isUserTranscript } from '../context/transcripts.js';
|
|
11
12
|
|
|
12
13
|
const home = os.homedir();
|
|
13
14
|
|
|
@@ -22,8 +23,12 @@ function findClaudeSessions() {
|
|
|
22
23
|
for (const entry of entries) {
|
|
23
24
|
const full = path.join(dir, entry.name);
|
|
24
25
|
if (entry.isDirectory()) {
|
|
26
|
+
// Same side-car directories capture.js refuses. Without this, every
|
|
27
|
+
// agent-<id>.jsonl under subagents/ is collected and its orchestrator
|
|
28
|
+
// prompt is sent to the summariser as "what they asked for".
|
|
29
|
+
if (isSideCarDir(entry.name)) continue;
|
|
25
30
|
scanDir(full);
|
|
26
|
-
} else if (
|
|
31
|
+
} else if (isUserTranscript(entry.name)) {
|
|
27
32
|
const stat = fs.statSync(full);
|
|
28
33
|
sessions.push({ path: full, mtime: stat.mtimeMs, size: stat.size });
|
|
29
34
|
}
|
package/src/context/capture.js
CHANGED
|
@@ -3,6 +3,7 @@ import path from 'path';
|
|
|
3
3
|
import os from 'os';
|
|
4
4
|
import { execFileSync } from 'child_process';
|
|
5
5
|
import { scanForSecrets, redactSecrets } from '../security/scanner.js';
|
|
6
|
+
import { isSideCarDir, isUserTranscript } from './transcripts.js';
|
|
6
7
|
|
|
7
8
|
const home = os.homedir();
|
|
8
9
|
|
|
@@ -47,9 +48,9 @@ export function findClaudeSessions() {
|
|
|
47
48
|
// agent-<id>.jsonl, not *subagent*), so USER_NOTE_RE minted
|
|
48
49
|
// decisions out of system prompts. Live proof: three of the
|
|
49
50
|
// author's own pinned decisions were subagent-prompt fragments.
|
|
50
|
-
if (entry.name
|
|
51
|
+
if (isSideCarDir(entry.name)) continue;
|
|
51
52
|
scanDir(full);
|
|
52
|
-
} else if (
|
|
53
|
+
} else if (isUserTranscript(entry.name)) {
|
|
53
54
|
try {
|
|
54
55
|
const stat = fs.statSync(full);
|
|
55
56
|
// Skip files older than 7 days for performance
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// One definition of "this .jsonl is an agent transcript, not the user talking."
|
|
2
|
+
//
|
|
3
|
+
// Claude Code writes subagent transcripts as `agent-<id>.jsonl` inside a
|
|
4
|
+
// `subagents/` directory. The FIRST user message in one of those files is the
|
|
5
|
+
// orchestrator's prompt ("You are a software architect. Note that ..."), not
|
|
6
|
+
// anything a person typed. Treating them as user speech has already produced
|
|
7
|
+
// two distinct failures in this codebase:
|
|
8
|
+
//
|
|
9
|
+
// 1. src/context/capture.js minted pinned "decisions" out of system prompts —
|
|
10
|
+
// three of the author's own were subagent-prompt fragments.
|
|
11
|
+
// 2. src/commands/snapshot.js collected them into a handoff summary whose
|
|
12
|
+
// prompt is labelled "User messages (what they asked for)" and POSTed to
|
|
13
|
+
// generativelanguage.googleapis.com, so orchestrator prompts left the
|
|
14
|
+
// machine entirely.
|
|
15
|
+
//
|
|
16
|
+
// Both were written as `!name.includes('subagent')`, which never matches
|
|
17
|
+
// `agent-<id>.jsonl` — the substring is "agent-", not "subagent". capture.js
|
|
18
|
+
// was fixed in place; snapshot.js kept the defeated test for three more weeks
|
|
19
|
+
// because the predicate was spelled four different ways across three files.
|
|
20
|
+
// It is spelled once here now.
|
|
21
|
+
|
|
22
|
+
/** Per-session side directories that never contain user speech. */
|
|
23
|
+
const SIDE_CAR_DIRS = new Set(['subagents', 'workflows', 'tool-results']);
|
|
24
|
+
|
|
25
|
+
/** True for a directory that holds agent-generated transcripts, not user turns. */
|
|
26
|
+
export function isSideCarDir(name) {
|
|
27
|
+
return SIDE_CAR_DIRS.has(name);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* True for a .jsonl file that is an agent transcript rather than a user
|
|
32
|
+
* session. Covers both the real filename (`agent-<id>.jsonl`) and the older
|
|
33
|
+
* `*subagent*` spelling, so a directory walk that reaches one anyway is safe.
|
|
34
|
+
*/
|
|
35
|
+
export function isAgentTranscript(name) {
|
|
36
|
+
return name.startsWith('agent-') || name.includes('subagent');
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** True for a .jsonl file safe to read as a record of what the user asked for. */
|
|
40
|
+
export function isUserTranscript(name) {
|
|
41
|
+
return name.endsWith('.jsonl') && !isAgentTranscript(name);
|
|
42
|
+
}
|