@lossless-claude/lcm 0.5.0 → 0.7.0
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/.claude-plugin/commands/lcm-compact.md +10 -0
- package/.claude-plugin/commands/lcm-curate.md +16 -6
- package/.claude-plugin/commands/lcm-diagnose.md +10 -0
- package/.claude-plugin/commands/lcm-doctor.md +1 -1
- package/.claude-plugin/commands/lcm-dogfood.md +1 -1
- package/.claude-plugin/commands/lcm-import.md +10 -0
- package/.claude-plugin/commands/lcm-promote.md +10 -0
- package/.claude-plugin/commands/lcm-sensitive.md +10 -0
- package/.claude-plugin/commands/lcm-stats.md +1 -1
- package/.claude-plugin/commands/lcm-status.md +10 -0
- package/.claude-plugin/hooks/README.md +1 -1
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +14 -2
- package/.claude-plugin/skills/lcm-context/SKILL.md +10 -0
- package/.claude-plugin/skills/lcm-dogfood/SKILL.md +1 -1
- package/.claude-plugin/skills/lcm-dogfood/references/checks.md +1 -1
- package/README.md +2 -2
- package/dist/bin/lcm.js +828 -474
- package/dist/bin/lcm.js.map +1 -1
- package/dist/installer/install.d.ts +6 -5
- package/dist/installer/install.js +116 -108
- package/dist/installer/install.js.map +1 -1
- package/dist/src/batch-compact.d.ts +7 -1
- package/dist/src/batch-compact.js +80 -6
- package/dist/src/batch-compact.js.map +1 -1
- package/dist/src/bootstrap.d.ts +24 -0
- package/dist/src/bootstrap.js +76 -0
- package/dist/src/bootstrap.js.map +1 -0
- package/dist/src/cli/pipeline-runner.d.ts +47 -0
- package/dist/src/cli/pipeline-runner.js +106 -0
- package/dist/src/cli/pipeline-runner.js.map +1 -0
- package/dist/src/cli/pipeline-step.d.ts +20 -0
- package/dist/src/cli/pipeline-step.js +6 -0
- package/dist/src/cli/pipeline-step.js.map +1 -0
- package/dist/src/cli/progress-state.d.ts +61 -0
- package/dist/src/cli/progress-state.js +16 -0
- package/dist/src/cli/progress-state.js.map +1 -0
- package/dist/src/cli/render-frame.d.ts +26 -0
- package/dist/src/cli/render-frame.js +153 -0
- package/dist/src/cli/render-frame.js.map +1 -0
- package/dist/src/cli/render-summary.d.ts +8 -0
- package/dist/src/cli/render-summary.js +79 -0
- package/dist/src/cli/render-summary.js.map +1 -0
- package/dist/src/cli-help.js +15 -9
- package/dist/src/cli-help.js.map +1 -1
- package/dist/src/codex-transcript.d.ts +50 -0
- package/dist/src/codex-transcript.js +207 -0
- package/dist/src/codex-transcript.js.map +1 -0
- package/dist/src/daemon/auth.d.ts +2 -0
- package/dist/src/daemon/auth.js +40 -0
- package/dist/src/daemon/auth.js.map +1 -0
- package/dist/src/daemon/client.d.ts +5 -1
- package/dist/src/daemon/client.js +21 -2
- package/dist/src/daemon/client.js.map +1 -1
- package/dist/src/daemon/config.d.ts +15 -0
- package/dist/src/daemon/config.js +33 -8
- package/dist/src/daemon/config.js.map +1 -1
- package/dist/src/daemon/content-fence.d.ts +7 -0
- package/dist/src/daemon/content-fence.js +14 -0
- package/dist/src/daemon/content-fence.js.map +1 -0
- package/dist/src/daemon/lifecycle.js +5 -0
- package/dist/src/daemon/lifecycle.js.map +1 -1
- package/dist/src/daemon/orientation.d.ts +1 -0
- package/dist/src/daemon/orientation.js +35 -6
- package/dist/src/daemon/orientation.js.map +1 -1
- package/dist/src/daemon/project.d.ts +1 -0
- package/dist/src/daemon/project.js +95 -3
- package/dist/src/daemon/project.js.map +1 -1
- package/dist/src/daemon/routes/compact.js +41 -10
- package/dist/src/daemon/routes/compact.js.map +1 -1
- package/dist/src/daemon/routes/describe.js +12 -1
- package/dist/src/daemon/routes/describe.js.map +1 -1
- package/dist/src/daemon/routes/expand.js +12 -1
- package/dist/src/daemon/routes/expand.js.map +1 -1
- package/dist/src/daemon/routes/grep.js +11 -2
- package/dist/src/daemon/routes/grep.js.map +1 -1
- package/dist/src/daemon/routes/ingest.js +36 -8
- package/dist/src/daemon/routes/ingest.js.map +1 -1
- package/dist/src/daemon/routes/promote-events.d.ts +3 -0
- package/dist/src/daemon/routes/promote-events.js +180 -0
- package/dist/src/daemon/routes/promote-events.js.map +1 -0
- package/dist/src/daemon/routes/promote.js +18 -3
- package/dist/src/daemon/routes/promote.js.map +1 -1
- package/dist/src/daemon/routes/prompt-search.js +11 -2
- package/dist/src/daemon/routes/prompt-search.js.map +1 -1
- package/dist/src/daemon/routes/recent.js +11 -2
- package/dist/src/daemon/routes/recent.js.map +1 -1
- package/dist/src/daemon/routes/restore.js +117 -69
- package/dist/src/daemon/routes/restore.js.map +1 -1
- package/dist/src/daemon/routes/search.js +12 -1
- package/dist/src/daemon/routes/search.js.map +1 -1
- package/dist/src/daemon/routes/session-complete.d.ts +2 -0
- package/dist/src/daemon/routes/session-complete.js +36 -0
- package/dist/src/daemon/routes/session-complete.js.map +1 -0
- package/dist/src/daemon/routes/status.js +77 -64
- package/dist/src/daemon/routes/status.js.map +1 -1
- package/dist/src/daemon/routes/store.d.ts +2 -1
- package/dist/src/daemon/routes/store.js +42 -8
- package/dist/src/daemon/routes/store.js.map +1 -1
- package/dist/src/daemon/safe-error.d.ts +5 -0
- package/dist/src/daemon/safe-error.js +15 -0
- package/dist/src/daemon/safe-error.js.map +1 -0
- package/dist/src/daemon/server.d.ts +3 -1
- package/dist/src/daemon/server.js +37 -17
- package/dist/src/daemon/server.js.map +1 -1
- package/dist/src/daemon/validate-cwd.d.ts +5 -0
- package/dist/src/daemon/validate-cwd.js +38 -0
- package/dist/src/daemon/validate-cwd.js.map +1 -0
- package/dist/src/daemon/version.d.ts +10 -0
- package/dist/src/daemon/version.js +31 -0
- package/dist/src/daemon/version.js.map +1 -0
- package/dist/src/db/events-path.d.ts +2 -0
- package/dist/src/db/events-path.js +11 -0
- package/dist/src/db/events-path.js.map +1 -0
- package/dist/src/db/events-stats.d.ts +29 -0
- package/dist/src/db/events-stats.js +107 -0
- package/dist/src/db/events-stats.js.map +1 -0
- package/dist/src/db/migration.js +8 -0
- package/dist/src/db/migration.js.map +1 -1
- package/dist/src/diagnose.js +14 -1
- package/dist/src/diagnose.js.map +1 -1
- package/dist/src/doctor/doctor.d.ts +1 -1
- package/dist/src/doctor/doctor.js +184 -15
- package/dist/src/doctor/doctor.js.map +1 -1
- package/dist/src/hooks/auto-heal.js +24 -1
- package/dist/src/hooks/auto-heal.js.map +1 -1
- package/dist/src/hooks/compact.js +7 -0
- package/dist/src/hooks/compact.js.map +1 -1
- package/dist/src/hooks/dispatch.d.ts +1 -1
- package/dist/src/hooks/dispatch.js +19 -1
- package/dist/src/hooks/dispatch.js.map +1 -1
- package/dist/src/hooks/events-db.d.ts +41 -0
- package/dist/src/hooks/events-db.js +190 -0
- package/dist/src/hooks/events-db.js.map +1 -0
- package/dist/src/hooks/extractors.d.ts +17 -0
- package/dist/src/hooks/extractors.js +198 -0
- package/dist/src/hooks/extractors.js.map +1 -0
- package/dist/src/hooks/hook-errors.d.ts +14 -0
- package/dist/src/hooks/hook-errors.js +56 -0
- package/dist/src/hooks/hook-errors.js.map +1 -0
- package/dist/src/hooks/post-tool.d.ts +4 -0
- package/dist/src/hooks/post-tool.js +43 -0
- package/dist/src/hooks/post-tool.js.map +1 -0
- package/dist/src/hooks/restore.js +31 -1
- package/dist/src/hooks/restore.js.map +1 -1
- package/dist/src/hooks/session-end.d.ts +3 -0
- package/dist/src/hooks/session-end.js +68 -5
- package/dist/src/hooks/session-end.js.map +1 -1
- package/dist/src/hooks/session-snapshot.d.ts +12 -0
- package/dist/src/hooks/session-snapshot.js +100 -0
- package/dist/src/hooks/session-snapshot.js.map +1 -0
- package/dist/src/hooks/user-prompt.js +44 -5
- package/dist/src/hooks/user-prompt.js.map +1 -1
- package/dist/src/import-summary.d.ts +4 -0
- package/dist/src/import-summary.js +34 -0
- package/dist/src/import-summary.js.map +1 -0
- package/dist/src/import.d.ts +11 -1
- package/dist/src/import.js +218 -88
- package/dist/src/import.js.map +1 -1
- package/dist/src/installer/settings.d.ts +5 -0
- package/dist/src/installer/settings.js +74 -0
- package/dist/src/installer/settings.js.map +1 -0
- package/dist/src/mcp/server.d.ts +15 -0
- package/dist/src/mcp/server.js +83 -6
- package/dist/src/mcp/server.js.map +1 -1
- package/dist/src/promotion/detector.js +19 -5
- package/dist/src/promotion/detector.js.map +1 -1
- package/dist/src/scrub.js +26 -0
- package/dist/src/scrub.js.map +1 -1
- package/dist/src/stats.d.ts +4 -0
- package/dist/src/stats.js +23 -0
- package/dist/src/stats.js.map +1 -1
- package/dist/src/store/conversation-store.js +2 -1
- package/dist/src/store/conversation-store.js.map +1 -1
- package/dist/src/store/regex-safety.d.ts +1 -0
- package/dist/src/store/regex-safety.js +22 -0
- package/dist/src/store/regex-safety.js.map +1 -0
- package/dist/src/store/summary-store.js +2 -1
- package/dist/src/store/summary-store.js.map +1 -1
- package/docs/passive-learning.md +138 -0
- package/lcm.mjs +20 -1
- package/package.json +5 -2
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
# Passive Learning
|
|
2
|
+
|
|
3
|
+
Passive learning captures insights from your Claude Code sessions automatically — no manual `lcm_store()` calls needed. It observes tool usage patterns, user decisions, and session events, then promotes high-signal observations into cross-session memory.
|
|
4
|
+
|
|
5
|
+
## How It Works
|
|
6
|
+
|
|
7
|
+
### Event Capture
|
|
8
|
+
|
|
9
|
+
Two hooks capture events during your session:
|
|
10
|
+
|
|
11
|
+
- **PostToolUse** — fires after every tool call. Extracts structured metadata (tool name, command, file path) from tool inputs. Never captures raw tool output.
|
|
12
|
+
- **UserPromptSubmit** — fires on each user prompt. Detects decisions ("always use X"), role statements ("I'm a data scientist"), and intent patterns.
|
|
13
|
+
|
|
14
|
+
Events are written to a **sidecar SQLite database** (`~/.lossless-claude/events/<project-hash>.db`) at <10ms cost. This is separate from the main LCM database — if the daemon is unavailable, events are safely queued.
|
|
15
|
+
|
|
16
|
+
### What Gets Captured
|
|
17
|
+
|
|
18
|
+
| Category | Examples | Priority |
|
|
19
|
+
|----------|----------|----------|
|
|
20
|
+
| Decisions | User answers to AskUserQuestion, "always use TypeScript" | 1 (immediate) |
|
|
21
|
+
| Plan approvals | EnterPlanMode / ExitPlanMode events | 1 (immediate) |
|
|
22
|
+
| Errors | Bash commands that fail (isError: true) | 1 (immediate) |
|
|
23
|
+
| Git operations | Commits, merges, branch switches | 2 (batch) |
|
|
24
|
+
| Environment | `npm install`, `pip install`, `brew install` | 2 (batch) |
|
|
25
|
+
| File access | Read/Edit/Write/Glob/Grep with file paths | 3 (pattern-only) |
|
|
26
|
+
| MCP tools | Which MCP tools are used (tool name only) | 3 (pattern-only) |
|
|
27
|
+
| Skills | Which skills are invoked | 3 (pattern-only) |
|
|
28
|
+
|
|
29
|
+
### What Is NOT Captured
|
|
30
|
+
|
|
31
|
+
- Raw tool payload contents such as file contents and command stdout/stderr (only tool metadata and brief user answers are stored)
|
|
32
|
+
- Sensitive file paths (`.env`, `.ssh/`, `credentials`, `.npmrc`)
|
|
33
|
+
- LCM's own `lcm_store` calls (prevents feedback loops)
|
|
34
|
+
|
|
35
|
+
### Three-Tier Promotion
|
|
36
|
+
|
|
37
|
+
Events are promoted to cross-session memory at session boundaries (session-end, pre-compact, or next session start):
|
|
38
|
+
|
|
39
|
+
**Tier 1 — Immediate promotion** (priority 1): Decisions, plan approvals, and error→fix pairs are promoted directly with high confidence (0.4–0.7).
|
|
40
|
+
|
|
41
|
+
**Tier 2 — Batch promotion** (priority 2): Git and environment events are promoted with moderate confidence (0.3).
|
|
42
|
+
|
|
43
|
+
**Tier 3 — Pattern reinforcement** (priority 3): File access and tool usage events are only promoted if they match an existing entry in the promoted store. This prevents low-signal noise from flooding memory.
|
|
44
|
+
|
|
45
|
+
### Error→Fix Correlation
|
|
46
|
+
|
|
47
|
+
When a tool error is followed by a successful command with a matching prefix (within 20 events), the system correlates them as an error→fix pair. These are tagged `category:solution` and promoted with higher priority.
|
|
48
|
+
|
|
49
|
+
### Learned Insights
|
|
50
|
+
|
|
51
|
+
On SessionStart, recently promoted passive insights are surfaced in a `<learned-insights>` block. This closes the feedback loop — the system learns from your sessions and applies those learnings in future ones.
|
|
52
|
+
|
|
53
|
+
## Configuration
|
|
54
|
+
|
|
55
|
+
All thresholds are configurable in `~/.lossless-claude/config.json` under `compaction.promotionThresholds`:
|
|
56
|
+
|
|
57
|
+
```json
|
|
58
|
+
{
|
|
59
|
+
"compaction": {
|
|
60
|
+
"promotionThresholds": {
|
|
61
|
+
"eventConfidence": {
|
|
62
|
+
"decision": 0.5,
|
|
63
|
+
"plan": 0.7,
|
|
64
|
+
"errorFix": 0.4,
|
|
65
|
+
"batch": 0.3,
|
|
66
|
+
"pattern": 0.2
|
|
67
|
+
},
|
|
68
|
+
"reinforcementBoost": 0.3,
|
|
69
|
+
"maxConfidence": 1.0,
|
|
70
|
+
"insightsMaxAgeDays": 90
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Data Storage
|
|
77
|
+
|
|
78
|
+
- **Sidecar DB**: `~/.lossless-claude/events/<sha256-of-project-path>.db`
|
|
79
|
+
- Per-project SQLite database in WAL mode
|
|
80
|
+
- Processed events pruned after 7 days
|
|
81
|
+
- Unprocessed events capped at 10,000 rows (oldest pruned first)
|
|
82
|
+
- Schema versioned for future migrations (currently v2)
|
|
83
|
+
|
|
84
|
+
- **Error log**: `error_log` table in each sidecar DB
|
|
85
|
+
- Records hook errors with timestamp and session ID
|
|
86
|
+
- Pruned after 30 days on SessionStart
|
|
87
|
+
- Queryable by `lcm doctor` for health diagnostics
|
|
88
|
+
|
|
89
|
+
- **Promoted store**: Events promoted via `deduplicateAndInsert()` into the main LCM database
|
|
90
|
+
- Tagged with `source:passive-capture` and `hook:<PostToolUse|UserPromptSubmit>`
|
|
91
|
+
- Searchable via `lcm search` and `lcm grep`
|
|
92
|
+
- Deduplicated via BM25 matching
|
|
93
|
+
|
|
94
|
+
## Negative-Match Guards
|
|
95
|
+
|
|
96
|
+
The UserPromptSubmit extractor includes guards against false-positive decisions. Phrases like "don't worry", "never mind", "not sure", "doesn't matter", and "up to you" suppress decision extraction to prevent noise.
|
|
97
|
+
|
|
98
|
+
## Recovery
|
|
99
|
+
|
|
100
|
+
| Scenario | Behavior |
|
|
101
|
+
|----------|----------|
|
|
102
|
+
| Clean session end | Events promoted via `/promote-events` |
|
|
103
|
+
| Ctrl+C (SIGINT) | Stop hook triggers best-effort promotion |
|
|
104
|
+
| Pre-compact | Events promoted before context is compacted |
|
|
105
|
+
| Daemon unavailable | Events queued in sidecar, promoted next session |
|
|
106
|
+
| Hard kill (SIGKILL) | Events survive in sidecar, scavenged on next SessionStart |
|
|
107
|
+
| Unprocessed cap exceeded | Oldest events pruned when > 10,000 rows or > 30 days |
|
|
108
|
+
| Error log pruning | Entries older than 30 days removed on SessionStart |
|
|
109
|
+
|
|
110
|
+
## Observability
|
|
111
|
+
|
|
112
|
+
### `lcm doctor`
|
|
113
|
+
|
|
114
|
+
When passive learning hooks are installed, `lcm doctor` includes a "Passive Learning" category with three checks:
|
|
115
|
+
|
|
116
|
+
| Check | What it monitors |
|
|
117
|
+
|-------|-----------------|
|
|
118
|
+
| `events-capture` | Total events captured, unprocessed count |
|
|
119
|
+
| `events-errors` | Hook error count (last 30 days) |
|
|
120
|
+
| `events-staleness` | Time since last event capture |
|
|
121
|
+
|
|
122
|
+
Run `lcm doctor` to see the per-project breakdown and recent error details.
|
|
123
|
+
|
|
124
|
+
### `lcm stats`
|
|
125
|
+
|
|
126
|
+
A single line is added to the Memory section when events have been captured:
|
|
127
|
+
|
|
128
|
+
```
|
|
129
|
+
Events 1,234 captured (42 unprocessed, 3 errors (30d))
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### Error Handling
|
|
133
|
+
|
|
134
|
+
All hooks use a three-layer error fence (`safeLogError`):
|
|
135
|
+
|
|
136
|
+
1. **Layer 1**: Write to sidecar DB `error_log` table (queryable by doctor/stats)
|
|
137
|
+
2. **Layer 2**: Append to `~/.lossless-claude/logs/events.log` (flat file fallback)
|
|
138
|
+
3. **Layer 3**: Swallow silently — hooks must never crash or interfere with Claude Code
|
package/lcm.mjs
CHANGED
|
@@ -15,10 +15,29 @@ if (!existsSync(join(__dirname, "node_modules"))) {
|
|
|
15
15
|
} catch {}
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
// Auto-build: compile TypeScript if dist/ is missing (fresh GitHub install)
|
|
18
|
+
// Auto-build: compile TypeScript if dist/ is missing (fresh GitHub/marketplace install)
|
|
19
19
|
if (!existsSync(join(__dirname, "dist"))) {
|
|
20
20
|
try {
|
|
21
21
|
execSync("npm run build --silent", { cwd: __dirname, stdio: "pipe", timeout: 120000 });
|
|
22
|
+
// Register as a global binary so `lcm` is available in PATH.
|
|
23
|
+
// Gated behind LCM_BOOTSTRAP_INSTALL=1 (opt-in) to avoid unexpected npm install -g
|
|
24
|
+
// side effects in environments where the user manages their own global packages.
|
|
25
|
+
if (process.env.LCM_BOOTSTRAP_INSTALL === "1") {
|
|
26
|
+
try {
|
|
27
|
+
execSync("npm install -g . --silent", { cwd: __dirname, stdio: "pipe", timeout: 60000 });
|
|
28
|
+
} catch (error) {
|
|
29
|
+
const message =
|
|
30
|
+
error instanceof Error && typeof error.message === "string"
|
|
31
|
+
? error.message
|
|
32
|
+
: String(error);
|
|
33
|
+
console.error(
|
|
34
|
+
"[lcm] Warning: Failed to globally install the lcm CLI. " +
|
|
35
|
+
"The `lcm` binary may not be available in your PATH. " +
|
|
36
|
+
"You can manually run `npm install -g .` in the plugin directory if desired.\n" +
|
|
37
|
+
`Underlying error: ${message}`,
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
22
41
|
} catch {}
|
|
23
42
|
}
|
|
24
43
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lossless-claude/lcm",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "Never lose context again. lossless-claude compresses Claude Code sessions into searchable memory — every message preserved, every insight remembered.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/src/memory/index.js",
|
|
@@ -43,13 +43,16 @@
|
|
|
43
43
|
"dependencies": {
|
|
44
44
|
"@modelcontextprotocol/sdk": "^1.12.0",
|
|
45
45
|
"@sinclair/typebox": "0.34.48",
|
|
46
|
-
"
|
|
46
|
+
"commander": "^14.0.3",
|
|
47
|
+
"js-yaml": "^4.1.1",
|
|
48
|
+
"safe-regex": "^2.1.1"
|
|
47
49
|
},
|
|
48
50
|
"devDependencies": {
|
|
49
51
|
"@anthropic-ai/sdk": "^0.39.0",
|
|
50
52
|
"@changesets/cli": "^2.30.0",
|
|
51
53
|
"@types/js-yaml": "^4.0.9",
|
|
52
54
|
"@types/node": ">=22",
|
|
55
|
+
"@types/safe-regex": "^1.1.6",
|
|
53
56
|
"openai": "^6.32.0",
|
|
54
57
|
"typescript": "^5.7.0",
|
|
55
58
|
"vitest": "^3.0.0"
|