@lossless-claude/lcm 0.2.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 +31 -0
- package/.claude-plugin/commands/lcm-curate.md +31 -0
- package/.claude-plugin/commands/lcm-diagnose.md +29 -0
- package/.claude-plugin/commands/lcm-doctor.md +23 -0
- package/.claude-plugin/commands/lcm-dogfood.md +101 -0
- package/.claude-plugin/commands/lcm-import.md +48 -0
- package/.claude-plugin/commands/lcm-promote.md +29 -0
- package/.claude-plugin/commands/lcm-sensitive.md +55 -0
- package/.claude-plugin/commands/lcm-stats.md +19 -0
- package/.claude-plugin/commands/lcm-status.md +27 -0
- package/.claude-plugin/hooks/README.md +47 -0
- package/.claude-plugin/marketplace.json +20 -0
- package/.claude-plugin/mcp.mjs +12 -0
- package/.claude-plugin/plugin.json +46 -0
- package/.claude-plugin/skills/lcm-context/SKILL.md +107 -0
- package/.claude-plugin/skills/lcm-dogfood/SKILL.md +102 -0
- package/.claude-plugin/skills/lcm-dogfood/references/checks.md +239 -0
- package/.claude-plugin/skills/lcm-dogfood/references/known-issues.md +11 -0
- package/.claude-plugin/skills/lcm-dogfood/scripts/db-integrity.js +40 -0
- package/.claude-plugin/skills/lcm-dogfood/scripts/prompt-search-test.js +35 -0
- package/.claude-plugin/skills/lcm-e2e/SKILL.md +61 -0
- package/.claude-plugin/skills/lcm-e2e/checklist.md +367 -0
- package/.claude-plugin/skills/lossless-claude-upgrade/SKILL.md +47 -0
- package/LICENSE +21 -0
- package/README.md +231 -0
- package/dist/bin/lcm.d.ts +2 -0
- package/dist/bin/lcm.js +461 -0
- package/dist/bin/lcm.js.map +1 -0
- package/dist/installer/dry-run-deps.d.ts +23 -0
- package/dist/installer/dry-run-deps.js +66 -0
- package/dist/installer/dry-run-deps.js.map +1 -0
- package/dist/installer/install.d.ts +39 -0
- package/dist/installer/install.js +236 -0
- package/dist/installer/install.js.map +1 -0
- package/dist/installer/uninstall.d.ts +11 -0
- package/dist/installer/uninstall.js +80 -0
- package/dist/installer/uninstall.js.map +1 -0
- package/dist/src/batch-compact.d.ts +16 -0
- package/dist/src/batch-compact.js +121 -0
- package/dist/src/batch-compact.js.map +1 -0
- package/dist/src/compaction.d.ts +198 -0
- package/dist/src/compaction.js +964 -0
- package/dist/src/compaction.js.map +1 -0
- package/dist/src/connectors/constants.d.ts +5 -0
- package/dist/src/connectors/constants.js +6 -0
- package/dist/src/connectors/constants.js.map +1 -0
- package/dist/src/connectors/installer.d.ts +16 -0
- package/dist/src/connectors/installer.js +200 -0
- package/dist/src/connectors/installer.js.map +1 -0
- package/dist/src/connectors/registry.d.ts +4 -0
- package/dist/src/connectors/registry.js +264 -0
- package/dist/src/connectors/registry.js.map +1 -0
- package/dist/src/connectors/template-service.d.ts +5 -0
- package/dist/src/connectors/template-service.js +54 -0
- package/dist/src/connectors/template-service.js.map +1 -0
- package/dist/src/connectors/templates/base.md +1 -0
- package/dist/src/connectors/templates/mcp-base.md +1 -0
- package/dist/src/connectors/templates/sections/command-reference.md +15 -0
- package/dist/src/connectors/templates/sections/mcp-workflow.md +18 -0
- package/dist/src/connectors/templates/sections/workflow.md +29 -0
- package/dist/src/connectors/templates/skill/SKILL.md +74 -0
- package/dist/src/connectors/types.d.ts +19 -0
- package/dist/src/connectors/types.js +10 -0
- package/dist/src/connectors/types.js.map +1 -0
- package/dist/src/daemon/client.d.ts +9 -0
- package/dist/src/daemon/client.js +28 -0
- package/dist/src/daemon/client.js.map +1 -0
- package/dist/src/daemon/config.d.ts +48 -0
- package/dist/src/daemon/config.js +67 -0
- package/dist/src/daemon/config.js.map +1 -0
- package/dist/src/daemon/lifecycle.d.ts +19 -0
- package/dist/src/daemon/lifecycle.js +102 -0
- package/dist/src/daemon/lifecycle.js.map +1 -0
- package/dist/src/daemon/orientation.d.ts +1 -0
- package/dist/src/daemon/orientation.js +9 -0
- package/dist/src/daemon/orientation.js.map +1 -0
- package/dist/src/daemon/project-queue.d.ts +1 -0
- package/dist/src/daemon/project-queue.js +17 -0
- package/dist/src/daemon/project-queue.js.map +1 -0
- package/dist/src/daemon/project.d.ts +7 -0
- package/dist/src/daemon/project.js +25 -0
- package/dist/src/daemon/project.js.map +1 -0
- package/dist/src/daemon/proxy-manager.d.ts +21 -0
- package/dist/src/daemon/proxy-manager.js +205 -0
- package/dist/src/daemon/proxy-manager.js.map +1 -0
- package/dist/src/daemon/routes/compact.d.ts +13 -0
- package/dist/src/daemon/routes/compact.js +195 -0
- package/dist/src/daemon/routes/compact.js.map +1 -0
- package/dist/src/daemon/routes/describe.d.ts +3 -0
- package/dist/src/daemon/routes/describe.js +39 -0
- package/dist/src/daemon/routes/describe.js.map +1 -0
- package/dist/src/daemon/routes/expand.d.ts +3 -0
- package/dist/src/daemon/routes/expand.js +41 -0
- package/dist/src/daemon/routes/expand.js.map +1 -0
- package/dist/src/daemon/routes/grep.d.ts +3 -0
- package/dist/src/daemon/routes/grep.js +43 -0
- package/dist/src/daemon/routes/grep.js.map +1 -0
- package/dist/src/daemon/routes/ingest.d.ts +3 -0
- package/dist/src/daemon/routes/ingest.js +101 -0
- package/dist/src/daemon/routes/ingest.js.map +1 -0
- package/dist/src/daemon/routes/promote.d.ts +4 -0
- package/dist/src/daemon/routes/promote.js +104 -0
- package/dist/src/daemon/routes/promote.js.map +1 -0
- package/dist/src/daemon/routes/prompt-search.d.ts +3 -0
- package/dist/src/daemon/routes/prompt-search.js +65 -0
- package/dist/src/daemon/routes/prompt-search.js.map +1 -0
- package/dist/src/daemon/routes/recent.d.ts +3 -0
- package/dist/src/daemon/routes/recent.js +37 -0
- package/dist/src/daemon/routes/recent.js.map +1 -0
- package/dist/src/daemon/routes/restore.d.ts +3 -0
- package/dist/src/daemon/routes/restore.js +120 -0
- package/dist/src/daemon/routes/restore.js.map +1 -0
- package/dist/src/daemon/routes/search.d.ts +2 -0
- package/dist/src/daemon/routes/search.js +66 -0
- package/dist/src/daemon/routes/search.js.map +1 -0
- package/dist/src/daemon/routes/status.d.ts +3 -0
- package/dist/src/daemon/routes/status.js +80 -0
- package/dist/src/daemon/routes/status.js.map +1 -0
- package/dist/src/daemon/routes/store.d.ts +2 -0
- package/dist/src/daemon/routes/store.js +46 -0
- package/dist/src/daemon/routes/store.js.map +1 -0
- package/dist/src/daemon/server.d.ts +19 -0
- package/dist/src/daemon/server.js +183 -0
- package/dist/src/daemon/server.js.map +1 -0
- package/dist/src/daemon/summarizer.d.ts +11 -0
- package/dist/src/daemon/summarizer.js +51 -0
- package/dist/src/daemon/summarizer.js.map +1 -0
- package/dist/src/db/config.d.ts +31 -0
- package/dist/src/db/config.js +83 -0
- package/dist/src/db/config.js.map +1 -0
- package/dist/src/db/connection.d.ts +3 -0
- package/dist/src/db/connection.js +62 -0
- package/dist/src/db/connection.js.map +1 -0
- package/dist/src/db/features.d.ts +11 -0
- package/dist/src/db/features.js +36 -0
- package/dist/src/db/features.js.map +1 -0
- package/dist/src/db/migration.d.ts +4 -0
- package/dist/src/db/migration.js +499 -0
- package/dist/src/db/migration.js.map +1 -0
- package/dist/src/db/promoted.d.ts +47 -0
- package/dist/src/db/promoted.js +96 -0
- package/dist/src/db/promoted.js.map +1 -0
- package/dist/src/db/redaction-stats.d.ts +6 -0
- package/dist/src/db/redaction-stats.js +16 -0
- package/dist/src/db/redaction-stats.js.map +1 -0
- package/dist/src/diagnose.d.ts +39 -0
- package/dist/src/diagnose.js +432 -0
- package/dist/src/diagnose.js.map +1 -0
- package/dist/src/doctor/doctor.d.ts +4 -0
- package/dist/src/doctor/doctor.js +378 -0
- package/dist/src/doctor/doctor.js.map +1 -0
- package/dist/src/doctor/types.d.ts +24 -0
- package/dist/src/doctor/types.js +2 -0
- package/dist/src/doctor/types.js.map +1 -0
- package/dist/src/expansion.d.ts +100 -0
- package/dist/src/expansion.js +268 -0
- package/dist/src/expansion.js.map +1 -0
- package/dist/src/hooks/auto-heal.d.ts +12 -0
- package/dist/src/hooks/auto-heal.js +49 -0
- package/dist/src/hooks/auto-heal.js.map +1 -0
- package/dist/src/hooks/compact.d.ts +5 -0
- package/dist/src/hooks/compact.js +22 -0
- package/dist/src/hooks/compact.js.map +1 -0
- package/dist/src/hooks/dispatch.d.ts +7 -0
- package/dist/src/hooks/dispatch.js +36 -0
- package/dist/src/hooks/dispatch.js.map +1 -0
- package/dist/src/hooks/probe-precompact.d.ts +2 -0
- package/dist/src/hooks/probe-precompact.js +17 -0
- package/dist/src/hooks/probe-precompact.js.map +1 -0
- package/dist/src/hooks/probe-sessionstart.d.ts +2 -0
- package/dist/src/hooks/probe-sessionstart.js +18 -0
- package/dist/src/hooks/probe-sessionstart.js.map +1 -0
- package/dist/src/hooks/restore.d.ts +5 -0
- package/dist/src/hooks/restore.js +19 -0
- package/dist/src/hooks/restore.js.map +1 -0
- package/dist/src/hooks/session-end.d.ts +16 -0
- package/dist/src/hooks/session-end.js +73 -0
- package/dist/src/hooks/session-end.js.map +1 -0
- package/dist/src/hooks/user-prompt.d.ts +5 -0
- package/dist/src/hooks/user-prompt.js +31 -0
- package/dist/src/hooks/user-prompt.js.map +1 -0
- package/dist/src/import.d.ts +24 -0
- package/dist/src/import.js +119 -0
- package/dist/src/import.js.map +1 -0
- package/dist/src/large-files.d.ts +28 -0
- package/dist/src/large-files.js +413 -0
- package/dist/src/large-files.js.map +1 -0
- package/dist/src/llm/anthropic.d.ts +9 -0
- package/dist/src/llm/anthropic.js +54 -0
- package/dist/src/llm/anthropic.js.map +1 -0
- package/dist/src/llm/claude-process.d.ts +2 -0
- package/dist/src/llm/claude-process.js +55 -0
- package/dist/src/llm/claude-process.js.map +1 -0
- package/dist/src/llm/codex-process.d.ts +15 -0
- package/dist/src/llm/codex-process.js +142 -0
- package/dist/src/llm/codex-process.js.map +1 -0
- package/dist/src/llm/mock-summarizer.d.ts +9 -0
- package/dist/src/llm/mock-summarizer.js +17 -0
- package/dist/src/llm/mock-summarizer.js.map +1 -0
- package/dist/src/llm/openai.d.ts +10 -0
- package/dist/src/llm/openai.js +52 -0
- package/dist/src/llm/openai.js.map +1 -0
- package/dist/src/llm/types.d.ts +6 -0
- package/dist/src/llm/types.js +2 -0
- package/dist/src/llm/types.js.map +1 -0
- package/dist/src/mcp/server.d.ts +9 -0
- package/dist/src/mcp/server.js +128 -0
- package/dist/src/mcp/server.js.map +1 -0
- package/dist/src/mcp/tools/lcm-describe.d.ts +14 -0
- package/dist/src/mcp/tools/lcm-describe.js +12 -0
- package/dist/src/mcp/tools/lcm-describe.js.map +1 -0
- package/dist/src/mcp/tools/lcm-doctor.d.ts +8 -0
- package/dist/src/mcp/tools/lcm-doctor.js +9 -0
- package/dist/src/mcp/tools/lcm-doctor.js.map +1 -0
- package/dist/src/mcp/tools/lcm-expand.d.ts +18 -0
- package/dist/src/mcp/tools/lcm-expand.js +13 -0
- package/dist/src/mcp/tools/lcm-expand.js.map +1 -0
- package/dist/src/mcp/tools/lcm-grep.d.ts +27 -0
- package/dist/src/mcp/tools/lcm-grep.js +15 -0
- package/dist/src/mcp/tools/lcm-grep.js.map +1 -0
- package/dist/src/mcp/tools/lcm-search.d.ts +33 -0
- package/dist/src/mcp/tools/lcm-search.js +15 -0
- package/dist/src/mcp/tools/lcm-search.js.map +1 -0
- package/dist/src/mcp/tools/lcm-stats.d.ts +14 -0
- package/dist/src/mcp/tools/lcm-stats.js +11 -0
- package/dist/src/mcp/tools/lcm-stats.js.map +1 -0
- package/dist/src/mcp/tools/lcm-store.d.ts +26 -0
- package/dist/src/mcp/tools/lcm-store.js +22 -0
- package/dist/src/mcp/tools/lcm-store.js.map +1 -0
- package/dist/src/memory/index.d.ts +22 -0
- package/dist/src/memory/index.js +21 -0
- package/dist/src/memory/index.js.map +1 -0
- package/dist/src/promotion/dedup.d.ts +19 -0
- package/dist/src/promotion/dedup.js +42 -0
- package/dist/src/promotion/dedup.js.map +1 -0
- package/dist/src/promotion/detector.d.ts +15 -0
- package/dist/src/promotion/detector.js +31 -0
- package/dist/src/promotion/detector.js.map +1 -0
- package/dist/src/prompts/condensed-d1.yaml +38 -0
- package/dist/src/prompts/condensed-d2.yaml +32 -0
- package/dist/src/prompts/condensed-d3plus.yaml +32 -0
- package/dist/src/prompts/leaf-aggressive.yaml +34 -0
- package/dist/src/prompts/leaf-normal.yaml +34 -0
- package/dist/src/prompts/loader.d.ts +9 -0
- package/dist/src/prompts/loader.js +37 -0
- package/dist/src/prompts/loader.js.map +1 -0
- package/dist/src/prompts/promoted-merge.yaml +18 -0
- package/dist/src/prompts/system.yaml +5 -0
- package/dist/src/retrieval.d.ts +122 -0
- package/dist/src/retrieval.js +214 -0
- package/dist/src/retrieval.js.map +1 -0
- package/dist/src/scrub.d.ts +46 -0
- package/dist/src/scrub.js +184 -0
- package/dist/src/scrub.js.map +1 -0
- package/dist/src/sensitive.d.ts +4 -0
- package/dist/src/sensitive.js +258 -0
- package/dist/src/sensitive.js.map +1 -0
- package/dist/src/stats.d.ts +34 -0
- package/dist/src/stats.js +260 -0
- package/dist/src/stats.js.map +1 -0
- package/dist/src/store/conversation-store.d.ts +115 -0
- package/dist/src/store/conversation-store.js +447 -0
- package/dist/src/store/conversation-store.js.map +1 -0
- package/dist/src/store/fts5-sanitize.d.ts +23 -0
- package/dist/src/store/fts5-sanitize.js +30 -0
- package/dist/src/store/fts5-sanitize.js.map +1 -0
- package/dist/src/store/full-text-fallback.d.ts +16 -0
- package/dist/src/store/full-text-fallback.js +60 -0
- package/dist/src/store/full-text-fallback.js.map +1 -0
- package/dist/src/store/index.d.ts +4 -0
- package/dist/src/store/index.js +3 -0
- package/dist/src/store/index.js.map +1 -0
- package/dist/src/store/summary-store.d.ts +118 -0
- package/dist/src/store/summary-store.js +570 -0
- package/dist/src/store/summary-store.js.map +1 -0
- package/dist/src/summarize.d.ts +59 -0
- package/dist/src/summarize.js +619 -0
- package/dist/src/summarize.js.map +1 -0
- package/dist/src/transcript.d.ts +7 -0
- package/dist/src/transcript.js +51 -0
- package/dist/src/transcript.js.map +1 -0
- package/dist/src/types.d.ts +116 -0
- package/dist/src/types.js +8 -0
- package/dist/src/types.js.map +1 -0
- package/docs/agent-tools.md +187 -0
- package/docs/architecture.md +224 -0
- package/docs/configuration.md +168 -0
- package/docs/fts5.md +161 -0
- package/docs/hook-protocol.md +41 -0
- package/docs/privacy.md +101 -0
- package/mcp.mjs +17 -0
- package/package.json +79 -0
|
@@ -0,0 +1,367 @@
|
|
|
1
|
+
# lcm E2E Validation Checklist
|
|
2
|
+
|
|
3
|
+
> **Note:** Some flows reference planned CLI flags (e.g., `--cwd`, `hook` subcommand) and MCP tools not yet implemented. These serve as a roadmap for future coverage.
|
|
4
|
+
|
|
5
|
+
All flows run against an isolated temp directory. No user project data is touched.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Setup
|
|
10
|
+
|
|
11
|
+
Before any flow, create the temp working directory:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
LCME2E_DIR=$(mktemp -d /tmp/lcm-e2e-test-XXXXXX)
|
|
15
|
+
echo "Test dir: $LCME2E_DIR"
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
All subsequent commands are run with `--cwd $LCME2E_DIR` or `cd $LCME2E_DIR &&` as appropriate.
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Flow 1 — Environment
|
|
23
|
+
|
|
24
|
+
**Goal:** Verify lcm binary is installed and daemon is reachable.
|
|
25
|
+
|
|
26
|
+
| Step | Command | Expected |
|
|
27
|
+
|------|---------|----------|
|
|
28
|
+
| 1.1 | `lcm --version` | Prints version string (e.g. `lcm 0.x.y`) |
|
|
29
|
+
| 1.2 | `lcm status --json` | JSON with `daemon: "running"` or attempt start |
|
|
30
|
+
| 1.3 | `lcm daemon start --detach` (if 1.2 failed) | Daemon starts, PID file created |
|
|
31
|
+
| 1.4 | `lcm status --json` | JSON with `daemon: "running"` |
|
|
32
|
+
|
|
33
|
+
**Pass criteria:** lcm binary found, daemon running after step 1.4.
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## Flow 2 — Import
|
|
38
|
+
|
|
39
|
+
**Goal:** Ingest a synthetic transcript into the isolated project.
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
cat > $LCME2E_DIR/e2e-session.jsonl << 'FIXTURE'
|
|
43
|
+
{"type":"human","message":{"role":"user","content":[{"type":"text","text":"What database should we use for the project?"}]},"timestamp":"2024-01-01T00:00:00Z"}
|
|
44
|
+
{"type":"assistant","message":{"role":"assistant","content":[{"type":"text","text":"We decided to use SQLite instead of PostgreSQL because it requires zero infrastructure. The ConversationStore class in src/store/conversation-store.ts handles all CRUD operations."}]},"timestamp":"2024-01-01T00:01:00Z"}
|
|
45
|
+
{"type":"human","message":{"role":"user","content":[{"type":"text","text":"What should the API authentication strategy be?"}]},"timestamp":"2024-01-01T00:02:00Z"}
|
|
46
|
+
{"type":"assistant","message":{"role":"assistant","content":[{"type":"text","text":"We agreed on JWT tokens with 24-hour expiry. The AuthMiddleware in src/middleware/auth.ts validates every request. API keys are stored hashed with bcrypt, never in plaintext."}]},"timestamp":"2024-01-01T00:03:00Z"}
|
|
47
|
+
{"type":"human","message":{"role":"user","content":[{"type":"text","text":"How should we handle errors globally?"}]},"timestamp":"2024-01-01T00:04:00Z"}
|
|
48
|
+
{"type":"assistant","message":{"role":"assistant","content":[{"type":"text","text":"All unhandled errors go through the ErrorHandler class in src/middleware/error-handler.ts. It logs to stderr and returns a structured JSON response with code, message, and request ID."}]},"timestamp":"2024-01-01T00:05:00Z"}
|
|
49
|
+
{"type":"human","message":{"role":"user","content":[{"type":"text","text":"What test framework are we using?"}]},"timestamp":"2024-01-01T00:06:00Z"}
|
|
50
|
+
{"type":"assistant","message":{"role":"assistant","content":[{"type":"text","text":"We chose Vitest over Jest because it's faster with native ESM support. Test files live in src/__tests__/ with .test.ts suffix. Coverage threshold is 80%."}]},"timestamp":"2024-01-01T00:07:00Z"}
|
|
51
|
+
{"type":"human","message":{"role":"user","content":[{"type":"text","text":"How do we deploy?"}]},"timestamp":"2024-01-01T00:08:00Z"}
|
|
52
|
+
{"type":"assistant","message":{"role":"assistant","content":[{"type":"text","text":"Docker containers pushed to ECR, deployed via ECS Fargate. The Dockerfile uses multi-stage builds: builder stage compiles TypeScript, runtime stage copies dist/ only. No Node dev dependencies in production image."}]},"timestamp":"2024-01-01T00:09:00Z"}
|
|
53
|
+
{"type":"human","message":{"role":"user","content":[{"type":"text","text":"What's the branching strategy?"}]},"timestamp":"2024-01-01T00:10:00Z"}
|
|
54
|
+
{"type":"assistant","message":{"role":"assistant","content":[{"type":"text","text":"Trunk-based development: main is always deployable. Feature branches merge via PR. We use conventional commits (feat:, fix:, chore:) enforced by commitlint. Semantic-release handles versioning automatically."}]},"timestamp":"2024-01-01T00:11:00Z"}
|
|
55
|
+
FIXTURE
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
| Step | Command | Expected |
|
|
59
|
+
|------|---------|----------|
|
|
60
|
+
| 2.1 | Create fixture file (above) | File `$LCME2E_DIR/e2e-session.jsonl` exists |
|
|
61
|
+
| 2.2 | `lcm import $LCME2E_DIR/e2e-session.jsonl --cwd $LCME2E_DIR` | Exit 0, prints imported message count |
|
|
62
|
+
| 2.3 | `lcm status --json --cwd $LCME2E_DIR` | JSON contains `conversations` count ≥ 1 |
|
|
63
|
+
|
|
64
|
+
**Pass criteria:** Import exits 0, at least 1 conversation recorded.
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## Flow 3 — Idempotent Re-import
|
|
69
|
+
|
|
70
|
+
**Goal:** Re-running import on the same file produces no duplicate records.
|
|
71
|
+
|
|
72
|
+
| Step | Command | Expected |
|
|
73
|
+
|------|---------|----------|
|
|
74
|
+
| 3.1 | `lcm status --json --cwd $LCME2E_DIR` (capture baseline count) | Record baseline `conversations` value |
|
|
75
|
+
| 3.2 | `lcm import $LCME2E_DIR/e2e-session.jsonl --cwd $LCME2E_DIR` | Exit 0, prints "0 new" or "already imported" |
|
|
76
|
+
| 3.3 | `lcm status --json --cwd $LCME2E_DIR` | `conversations` count unchanged from 3.1 |
|
|
77
|
+
|
|
78
|
+
**Pass criteria:** Count after re-import equals count before re-import.
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## Flow 4 — Subagent Import
|
|
83
|
+
|
|
84
|
+
**Goal:** Ingest a subagent transcript and verify it is stored separately.
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
cat > $LCME2E_DIR/e2e-subagent.jsonl << 'FIXTURE'
|
|
88
|
+
{"type":"human","message":{"role":"user","content":[{"type":"text","text":"Subagent task: analyze the database schema"}]},"timestamp":"2024-01-02T00:00:00Z","subagent":true}
|
|
89
|
+
{"type":"assistant","message":{"role":"assistant","content":[{"type":"text","text":"Schema analysis complete. Found 3 tables: users, sessions, memories. The memories table has a full-text search index on the content column. Foreign key from sessions to users is indexed."}]},"timestamp":"2024-01-02T00:01:00Z","subagent":true}
|
|
90
|
+
FIXTURE
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
| Step | Command | Expected |
|
|
94
|
+
|------|---------|----------|
|
|
95
|
+
| 4.1 | Create subagent fixture (above) | File exists |
|
|
96
|
+
| 4.2 | `lcm import $LCME2E_DIR/e2e-subagent.jsonl --cwd $LCME2E_DIR` | Exit 0 |
|
|
97
|
+
| 4.3 | `lcm status --json --cwd $LCME2E_DIR` | `conversations` count increased by 1 |
|
|
98
|
+
|
|
99
|
+
**Pass criteria:** Subagent data ingested, total count incremented.
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## Flow 5 — Compact
|
|
104
|
+
|
|
105
|
+
**Goal:** Run compaction and verify DAG memory nodes are created.
|
|
106
|
+
|
|
107
|
+
| Step | Command | Expected |
|
|
108
|
+
|------|---------|----------|
|
|
109
|
+
| 5.1 | `lcm compact --all --cwd $LCME2E_DIR` | Exit 0, prints nodes created count |
|
|
110
|
+
| 5.2 | `lcm status --json --cwd $LCME2E_DIR` | JSON contains `memories` or `nodes` count ≥ 1 |
|
|
111
|
+
|
|
112
|
+
**Pass criteria:** Compact exits 0, at least 1 memory node exists.
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## Flow 6 — Promote
|
|
117
|
+
|
|
118
|
+
**Goal:** Run promotion and verify promoted memories exist.
|
|
119
|
+
|
|
120
|
+
| Step | Command | Expected |
|
|
121
|
+
|------|---------|----------|
|
|
122
|
+
| 6.1 | `lcm promote --cwd $LCME2E_DIR` | Exit 0, prints promoted count |
|
|
123
|
+
| 6.2 | `lcm status --json --cwd $LCME2E_DIR` | JSON contains `promoted` count ≥ 1 |
|
|
124
|
+
|
|
125
|
+
**Pass criteria:** Promote exits 0, at least 1 promoted memory.
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
## Flow 7 — Curate (Full Pipeline)
|
|
130
|
+
|
|
131
|
+
**Goal:** Verify the full import → compact → promote pipeline works end-to-end.
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
cat > $LCME2E_DIR/e2e-curate.jsonl << 'FIXTURE'
|
|
135
|
+
{"type":"human","message":{"role":"user","content":[{"type":"text","text":"What logging library should we use?"}]},"timestamp":"2024-01-03T00:00:00Z"}
|
|
136
|
+
{"type":"assistant","message":{"role":"assistant","content":[{"type":"text","text":"We chose pino over winston for structured logging. It outputs JSON by default and is 5x faster. The LoggerService in src/services/logger.ts wraps pino and adds request-id correlation."}]},"timestamp":"2024-01-03T00:01:00Z"}
|
|
137
|
+
FIXTURE
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
| Step | Command | Expected |
|
|
141
|
+
|------|---------|----------|
|
|
142
|
+
| 7.1 | Create curate fixture (above) | File exists |
|
|
143
|
+
| 7.2 | `lcm import $LCME2E_DIR/e2e-curate.jsonl --cwd $LCME2E_DIR` | Exit 0 |
|
|
144
|
+
| 7.3 | `lcm compact --all --cwd $LCME2E_DIR` | Exit 0 |
|
|
145
|
+
| 7.4 | `lcm promote --cwd $LCME2E_DIR` | Exit 0 |
|
|
146
|
+
| 7.5 | `lcm status --json --cwd $LCME2E_DIR` | `promoted` count ≥ previous flow value |
|
|
147
|
+
|
|
148
|
+
**Pass criteria:** All three stages exit 0, promoted count non-decreasing.
|
|
149
|
+
|
|
150
|
+
---
|
|
151
|
+
|
|
152
|
+
## Flow 8 — Retrieval
|
|
153
|
+
|
|
154
|
+
**Goal:** Verify search, grep, expand, and describe operations return relevant results.
|
|
155
|
+
|
|
156
|
+
| Step | Command | Expected |
|
|
157
|
+
|------|---------|----------|
|
|
158
|
+
| 8.1 | `lcm search "SQLite database" --cwd $LCME2E_DIR` | Returns ≥ 1 result mentioning SQLite |
|
|
159
|
+
| 8.2 | `lcm search "JWT authentication" --cwd $LCME2E_DIR` | Returns ≥ 1 result mentioning JWT |
|
|
160
|
+
| 8.3 | `lcm search "nonexistent-xyzzy-term" --cwd $LCME2E_DIR` | Returns 0 results or empty (no crash) |
|
|
161
|
+
| 8.4 | `lcm search "SQLite" --format json --cwd $LCME2E_DIR` | Valid JSON array output |
|
|
162
|
+
|
|
163
|
+
**Pass criteria:** Steps 8.1 and 8.2 return results; 8.3 does not crash; 8.4 produces valid JSON.
|
|
164
|
+
|
|
165
|
+
---
|
|
166
|
+
|
|
167
|
+
## Flow 9 — Restore (SessionStart Hook)
|
|
168
|
+
|
|
169
|
+
**Goal:** Verify the SessionStart hook returns context for a new session.
|
|
170
|
+
|
|
171
|
+
| Step | Command | Expected |
|
|
172
|
+
|------|---------|----------|
|
|
173
|
+
| 9.1 | `lcm hook session-start --cwd $LCME2E_DIR` | Exit 0, returns context JSON or markdown block |
|
|
174
|
+
| 9.2 | Output contains memory content | Response references at least one stored memory |
|
|
175
|
+
|
|
176
|
+
**Pass criteria:** Hook exits 0, returns non-empty context referencing prior conversations.
|
|
177
|
+
|
|
178
|
+
---
|
|
179
|
+
|
|
180
|
+
## Flow 10 — UserPromptSubmit Hook
|
|
181
|
+
|
|
182
|
+
**Goal:** Verify the UserPromptSubmit hook returns memory hints for a relevant prompt.
|
|
183
|
+
|
|
184
|
+
| Step | Command | Expected |
|
|
185
|
+
|------|---------|----------|
|
|
186
|
+
| 10.1 | `lcm hook user-prompt-submit --prompt "What database are we using?" --cwd $LCME2E_DIR` | Exit 0, returns hint about SQLite |
|
|
187
|
+
| 10.2 | `lcm hook user-prompt-submit --prompt "xyzzy irrelevant" --cwd $LCME2E_DIR` | Exit 0, returns empty or minimal hint (no crash) |
|
|
188
|
+
|
|
189
|
+
**Pass criteria:** Both commands exit 0; 10.1 returns relevant hint.
|
|
190
|
+
|
|
191
|
+
---
|
|
192
|
+
|
|
193
|
+
## Flow 11 — MCP Transport
|
|
194
|
+
|
|
195
|
+
**Goal:** Verify all 7 MCP tools respond without error.
|
|
196
|
+
|
|
197
|
+
| Step | Command | Expected |
|
|
198
|
+
|------|---------|----------|
|
|
199
|
+
| 11.1 | `lcm mcp ping` | Exit 0, returns `pong` or health OK |
|
|
200
|
+
| 11.2 | `lcm mcp list-tools` | Lists ≥ 7 tool names |
|
|
201
|
+
| 11.3 | `lcm mcp call lcm_search '{"query":"SQLite"}' --cwd $LCME2E_DIR` | Returns result JSON |
|
|
202
|
+
| 11.4 | `lcm mcp call lcm_status '{}' --cwd $LCME2E_DIR` | Returns status JSON |
|
|
203
|
+
| 11.5 | `lcm mcp call lcm_compact '{}' --cwd $LCME2E_DIR` | Exit 0 |
|
|
204
|
+
| 11.6 | `lcm mcp call lcm_promote '{}' --cwd $LCME2E_DIR` | Exit 0 |
|
|
205
|
+
| 11.7 | `lcm mcp call lcm_doctor '{}' --cwd $LCME2E_DIR` | Returns health report |
|
|
206
|
+
|
|
207
|
+
**Pass criteria:** All 7 MCP calls exit 0 and return non-empty output.
|
|
208
|
+
|
|
209
|
+
---
|
|
210
|
+
|
|
211
|
+
## Flow 12 — Doctor
|
|
212
|
+
|
|
213
|
+
**Goal:** `lcm doctor` reports all checks healthy.
|
|
214
|
+
|
|
215
|
+
| Step | Command | Expected |
|
|
216
|
+
|------|---------|----------|
|
|
217
|
+
| 12.1 | `lcm doctor` | Exit 0 |
|
|
218
|
+
| 12.2 | Output contains no FAIL or ERROR lines | Zero failures in report |
|
|
219
|
+
| 12.3 | Daemon check | Shows daemon as running |
|
|
220
|
+
| 12.4 | Hooks check | Shows hooks as registered |
|
|
221
|
+
| 12.5 | MCP check | Shows MCP server as reachable |
|
|
222
|
+
|
|
223
|
+
**Pass criteria:** Exit 0, no FAIL/ERROR in output, all subsystems healthy.
|
|
224
|
+
|
|
225
|
+
---
|
|
226
|
+
|
|
227
|
+
## Flow 13 — Teardown
|
|
228
|
+
|
|
229
|
+
**Goal:** Remove temp directory and associated project data. Always runs at end of full suite.
|
|
230
|
+
|
|
231
|
+
| Step | Command | Expected |
|
|
232
|
+
|------|---------|----------|
|
|
233
|
+
| 13.1 | `PROJECT_HASH=$(lcm status --json --cwd $LCME2E_DIR \| jq -r '.projectHash // empty')` | Hash extracted or empty |
|
|
234
|
+
| 13.2 | `rm -rf $LCME2E_DIR` | Temp dir removed |
|
|
235
|
+
| 13.3 | `[ -n "$PROJECT_HASH" ] && rm -rf ~/.lossless-claude/projects/$PROJECT_HASH` | Project data removed (if hash known) |
|
|
236
|
+
| 13.4 | `ls /tmp/lcm-e2e-test-* 2>/dev/null` | No lcm-e2e-test dirs remain |
|
|
237
|
+
|
|
238
|
+
**Pass criteria:** Temp dir gone, project data cleaned up.
|
|
239
|
+
|
|
240
|
+
---
|
|
241
|
+
|
|
242
|
+
## Flow 14 — SessionEnd Hook
|
|
243
|
+
|
|
244
|
+
**Goal:** Verify the SessionEnd hook ingests session data via hook trigger.
|
|
245
|
+
|
|
246
|
+
| Step | Command | Expected |
|
|
247
|
+
|------|---------|----------|
|
|
248
|
+
| 14.1 | Create a fresh temp dir: `HOOK_DIR=$(mktemp -d /tmp/lcm-e2e-test-XXXXXX)` | Dir created |
|
|
249
|
+
| 14.2 | `lcm hook session-end --transcript '{"messages":[{"role":"user","content":"hook test"},{"role":"assistant","content":"hook response stored"}]}' --cwd $HOOK_DIR` | Exit 0 |
|
|
250
|
+
| 14.3 | `lcm status --json --cwd $HOOK_DIR` | `conversations` count ≥ 1 |
|
|
251
|
+
| 14.4 | `rm -rf $HOOK_DIR` | Cleanup |
|
|
252
|
+
|
|
253
|
+
**Pass criteria:** Hook exits 0, conversation recorded in isolated project.
|
|
254
|
+
|
|
255
|
+
---
|
|
256
|
+
|
|
257
|
+
## Flow 15 — PreCompact Hook
|
|
258
|
+
|
|
259
|
+
**Goal:** Verify the PreCompact hook returns exit code 2 to signal Claude to proceed.
|
|
260
|
+
|
|
261
|
+
| Step | Command | Expected |
|
|
262
|
+
|------|---------|----------|
|
|
263
|
+
| 15.1 | `lcm hook pre-compact --cwd $LCME2E_DIR` | Exit code 2 (not 0 or 1) |
|
|
264
|
+
| 15.2 | Output contains memory summary or context | Non-empty stdout |
|
|
265
|
+
|
|
266
|
+
**Pass criteria:** Exit code is exactly 2, stdout is non-empty.
|
|
267
|
+
|
|
268
|
+
---
|
|
269
|
+
|
|
270
|
+
## Flow 16 — Auto-heal (Read-only in Live Mode)
|
|
271
|
+
|
|
272
|
+
**Goal:** Verify hooks are registered in Claude Code config. READ-ONLY — does not modify hooks.
|
|
273
|
+
|
|
274
|
+
| Step | Command | Expected |
|
|
275
|
+
|------|---------|----------|
|
|
276
|
+
| 16.1 | `lcm hooks list` | Lists registered hooks |
|
|
277
|
+
| 16.2 | Output contains `session-start` | SessionStart hook present |
|
|
278
|
+
| 16.3 | Output contains `session-end` | SessionEnd hook present |
|
|
279
|
+
| 16.4 | Output contains `pre-compact` | PreCompact hook present |
|
|
280
|
+
| 16.5 | Output contains `user-prompt-submit` | UserPromptSubmit hook present |
|
|
281
|
+
|
|
282
|
+
**Pass criteria:** All 4 hook types are registered. No modifications made.
|
|
283
|
+
|
|
284
|
+
---
|
|
285
|
+
|
|
286
|
+
## Flow 17 — Scrubbing
|
|
287
|
+
|
|
288
|
+
**Goal:** Verify sensitive patterns are redacted before storage.
|
|
289
|
+
|
|
290
|
+
```bash
|
|
291
|
+
cat > $LCME2E_DIR/e2e-sensitive.jsonl << 'FIXTURE'
|
|
292
|
+
{"type":"human","message":{"role":"user","content":[{"type":"text","text":"The API key is sk-1234567890abcdef and the password is hunter2. Connect via postgres://admin:secret@localhost/db"}]},"timestamp":"2024-01-04T00:00:00Z"}
|
|
293
|
+
{"type":"assistant","message":{"role":"assistant","content":[{"type":"text","text":"I'll help you configure the connection. I've noted the credentials."}]},"timestamp":"2024-01-04T00:01:00Z"}
|
|
294
|
+
FIXTURE
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
| Step | Command | Expected |
|
|
298
|
+
|------|---------|----------|
|
|
299
|
+
| 17.1 | Create sensitive fixture (above) | File created |
|
|
300
|
+
| 17.2 | `lcm import $LCME2E_DIR/e2e-sensitive.jsonl --cwd $LCME2E_DIR` | Exit 0 |
|
|
301
|
+
| 17.3 | `lcm search "sk-1234" --cwd $LCME2E_DIR` | Returns 0 results (key redacted) |
|
|
302
|
+
| 17.4 | `lcm search "hunter2" --cwd $LCME2E_DIR` | Returns 0 results (password redacted) |
|
|
303
|
+
| 17.5 | `lcm search "postgres://admin" --cwd $LCME2E_DIR` | Returns 0 results (connection string redacted) |
|
|
304
|
+
|
|
305
|
+
**Pass criteria:** None of the 3 sensitive patterns are findable via search.
|
|
306
|
+
|
|
307
|
+
---
|
|
308
|
+
|
|
309
|
+
## Flow 18 — Daemon-down Resilience
|
|
310
|
+
|
|
311
|
+
**Goal:** Hooks fail gracefully when daemon is not running.
|
|
312
|
+
|
|
313
|
+
| Step | Command | Expected |
|
|
314
|
+
|------|---------|----------|
|
|
315
|
+
| 18.1 | `lcm daemon stop` | Daemon stops (or already stopped) |
|
|
316
|
+
| 18.2 | `lcm hook session-start --cwd $LCME2E_DIR` | Exits non-zero OR exits 0 with empty/fallback context (no crash/hang) |
|
|
317
|
+
| 18.3 | `lcm hook user-prompt-submit --prompt "test" --cwd $LCME2E_DIR` | Exits non-zero OR exits 0 with empty hint (no crash/hang) |
|
|
318
|
+
| 18.4 | `lcm daemon start --detach` | Daemon restarts successfully |
|
|
319
|
+
| 18.5 | `lcm status --json` | Daemon running again |
|
|
320
|
+
|
|
321
|
+
**Pass criteria:** Hooks do not crash or hang when daemon is down; daemon restarts cleanly.
|
|
322
|
+
|
|
323
|
+
---
|
|
324
|
+
|
|
325
|
+
## Flow 19 — Status
|
|
326
|
+
|
|
327
|
+
**Goal:** `lcm status` returns correct state fields.
|
|
328
|
+
|
|
329
|
+
| Step | Command | Expected |
|
|
330
|
+
|------|---------|----------|
|
|
331
|
+
| 19.1 | `lcm status` | Exit 0, human-readable output |
|
|
332
|
+
| 19.2 | `lcm status --json` | Exit 0, valid JSON |
|
|
333
|
+
| 19.3 | JSON contains `daemon` field | `daemon` is `"running"` |
|
|
334
|
+
| 19.4 | JSON contains `version` field | Non-empty version string |
|
|
335
|
+
| 19.5 | JSON contains `projects` or `projectCount` field | Numeric value ≥ 0 |
|
|
336
|
+
|
|
337
|
+
**Pass criteria:** Both plain and JSON output succeed, all expected fields present.
|
|
338
|
+
|
|
339
|
+
---
|
|
340
|
+
|
|
341
|
+
## Summary Table
|
|
342
|
+
|
|
343
|
+
Fill in ✓ (pass) or ✗ (fail) after running each flow. Add notes for any failures.
|
|
344
|
+
|
|
345
|
+
| Flow | Status | Notes |
|
|
346
|
+
|------|--------|-------|
|
|
347
|
+
| 1 — Environment | ✓ / ✗ | |
|
|
348
|
+
| 2 — Import | ✓ / ✗ | |
|
|
349
|
+
| 3 — Idempotent re-import | ✓ / ✗ | |
|
|
350
|
+
| 4 — Subagent import | ✓ / ✗ | |
|
|
351
|
+
| 5 — Compact | ✓ / ✗ | |
|
|
352
|
+
| 6 — Promote | ✓ / ✗ | |
|
|
353
|
+
| 7 — Curate | ✓ / ✗ | |
|
|
354
|
+
| 8 — Retrieval | ✓ / ✗ | |
|
|
355
|
+
| 9 — Restore (SessionStart) | ✓ / ✗ | |
|
|
356
|
+
| 10 — UserPromptSubmit | ✓ / ✗ | |
|
|
357
|
+
| 11 — MCP transport | ✓ / ✗ | |
|
|
358
|
+
| 12 — Doctor | ✓ / ✗ | |
|
|
359
|
+
| 13 — Teardown | ✓ / ✗ | |
|
|
360
|
+
| 14 — SessionEnd hook | ✓ / ✗ | |
|
|
361
|
+
| 15 — PreCompact hook | ✓ / ✗ | |
|
|
362
|
+
| 16 — Auto-heal | ✓ / ✗ | |
|
|
363
|
+
| 17 — Scrubbing | ✓ / ✗ | |
|
|
364
|
+
| 18 — Daemon-down resilience | ✓ / ✗ | |
|
|
365
|
+
| 19 — Status | ✓ / ✗ | |
|
|
366
|
+
|
|
367
|
+
**Result:** _N/19 flows passed_
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: lossless-claude-upgrade
|
|
3
|
+
description: |
|
|
4
|
+
Rebuild, reinstall, and restart lossless-claude from source.
|
|
5
|
+
Fixes hooks, restarts daemon, runs diagnostics.
|
|
6
|
+
Trigger: /lossless-claude:upgrade
|
|
7
|
+
user-invocable: true
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# lossless-claude Upgrade (lcm)
|
|
11
|
+
|
|
12
|
+
Rebuild from source, restart daemon, and verify installation.
|
|
13
|
+
|
|
14
|
+
## Instructions
|
|
15
|
+
|
|
16
|
+
1. Derive the **repo root** from this skill's base directory (go up 3 levels — remove `/skills/lossless-claude-upgrade` from the path, then remove `.claude-plugin`).
|
|
17
|
+
2. Run with Bash:
|
|
18
|
+
```
|
|
19
|
+
cd <REPO_ROOT> && npm run build && npm link
|
|
20
|
+
```
|
|
21
|
+
3. Restart daemon with Bash:
|
|
22
|
+
```
|
|
23
|
+
PID_FILE="$HOME/.lossless-claude/daemon.pid"
|
|
24
|
+
if [ -f "$PID_FILE" ]; then
|
|
25
|
+
PID=$(cat "$PID_FILE")
|
|
26
|
+
if ps -p "$PID" -o args= 2>/dev/null | grep -q 'lcm.*daemon'; then
|
|
27
|
+
kill "$PID" 2>/dev/null
|
|
28
|
+
fi
|
|
29
|
+
rm -f "$PID_FILE"
|
|
30
|
+
fi
|
|
31
|
+
lcm daemon start --detach
|
|
32
|
+
```
|
|
33
|
+
4. Run doctor with Bash:
|
|
34
|
+
```
|
|
35
|
+
lcm doctor
|
|
36
|
+
```
|
|
37
|
+
5. **IMPORTANT**: After all Bash commands complete, re-display key results as markdown text directly in the conversation. Format as:
|
|
38
|
+
```
|
|
39
|
+
## lossless-claude upgrade
|
|
40
|
+
- [x] Built from source
|
|
41
|
+
- [x] npm linked globally
|
|
42
|
+
- [x] Daemon restarted (PID XXXX)
|
|
43
|
+
- [x] Hooks configured
|
|
44
|
+
- [x] Doctor: all checks PASS
|
|
45
|
+
```
|
|
46
|
+
Use `[x]` for success, `[ ]` for failure. Show actual version and any warnings.
|
|
47
|
+
Tell the user to **restart their Claude Code session** to pick up the new version.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Josh Lehman / Martian Engineering
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<strong>lossless-claude</strong><br>
|
|
3
|
+
Shared memory infrastructure for Claude Code
|
|
4
|
+
</p>
|
|
5
|
+
|
|
6
|
+
<p align="center">
|
|
7
|
+
DAG-based summarization, SQLite-backed message persistence, promoted long-term memory, MCP retrieval tools
|
|
8
|
+
</p>
|
|
9
|
+
|
|
10
|
+
<p align="center">
|
|
11
|
+
<a href="https://www.npmjs.com/package/@lossless-claude/lcm"><img src="https://img.shields.io/npm/v/@lossless-claude/lcm" alt="npm"></a>
|
|
12
|
+
<a href="LICENSE"><img src="https://img.shields.io/github/license/lossless-claude/lcm" alt="License: MIT"></a>
|
|
13
|
+
<a href="package.json"><img src="https://img.shields.io/node/v/@lossless-claude/lcm" alt="Node"></a>
|
|
14
|
+
<a href="https://github.com/anthropics/claude-code"><img src="https://img.shields.io/badge/Claude_Code-hooks%20%2B%20MCP-7c3aed" alt="Claude Code"></a>
|
|
15
|
+
</p>
|
|
16
|
+
|
|
17
|
+
<p align="center">
|
|
18
|
+
<a href="https://lossless-claude.com">Website</a> •
|
|
19
|
+
<a href="#runtime-model">Runtime Model</a> •
|
|
20
|
+
<a href="#installation">Installation</a> •
|
|
21
|
+
<a href="#mcp-tools">MCP Tools</a> •
|
|
22
|
+
<a href="#development">Development</a>
|
|
23
|
+
</p>
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
`lossless-claude` replaces sliding-window forgetfulness with a persistent memory runtime for both humans and agents.
|
|
28
|
+
|
|
29
|
+
- Every message is stored in a project SQLite database.
|
|
30
|
+
- Older context is compacted into a DAG of summaries instead of being dropped.
|
|
31
|
+
- Durable decisions and findings are promoted into cross-session memory.
|
|
32
|
+
- Claude Code reads and writes project memory across sessions.
|
|
33
|
+
|
|
34
|
+
Humans and agents use the same backend. The integration surface differs by client, but the memory model is shared.
|
|
35
|
+
|
|
36
|
+
This repo started as a fork of [lossless-claw](https://github.com/Martian-Engineering/lossless-claude) by [Martian Engineering](https://martian.engineering), adapted for Claude Code. The LCM model and DAG architecture originate from the [Voltropy paper](https://papers.voltropy.com/LCM).
|
|
37
|
+
|
|
38
|
+
## Runtime Model
|
|
39
|
+
|
|
40
|
+
```mermaid
|
|
41
|
+
flowchart LR
|
|
42
|
+
subgraph Clients["Clients"]
|
|
43
|
+
CC["Claude Code<br/>hooks + MCP"]
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
CC --> D["lossless-claude daemon"]
|
|
47
|
+
|
|
48
|
+
D --> DB[("project SQLite DAG")]
|
|
49
|
+
D --> PM[("promoted memory FTS5")]
|
|
50
|
+
D --> TOOLS["MCP tools<br/>search / grep / expand / describe / store / stats / doctor"]
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### Capabilities by integration path
|
|
54
|
+
|
|
55
|
+
| Path | Restore | Prompt hints | Turn writeback | Automatic compaction | Notes |
|
|
56
|
+
|---|---|---|---|---|---|
|
|
57
|
+
| Claude Code | Yes | Yes | Yes, via transcript/hooks | Yes | Primary hook-based integration |
|
|
58
|
+
|
|
59
|
+
## LCM Model
|
|
60
|
+
|
|
61
|
+
| Phase | What happens |
|
|
62
|
+
|---|---|
|
|
63
|
+
| Persist | Raw messages are stored in SQLite per conversation |
|
|
64
|
+
| Summarize | Older messages are grouped into leaf summaries |
|
|
65
|
+
| Condense | Summaries roll up into higher-level DAG nodes |
|
|
66
|
+
| Promote | Durable insights are copied into cross-session memory |
|
|
67
|
+
| Restore | New sessions recover context from summaries and promoted memory |
|
|
68
|
+
| Recall | Agents query, expand, and inspect memory on demand |
|
|
69
|
+
|
|
70
|
+
Nothing is dropped. Raw messages remain in the database. Summaries point back to their sources. Promoted memory remains searchable across sessions.
|
|
71
|
+
|
|
72
|
+
```mermaid
|
|
73
|
+
flowchart TD
|
|
74
|
+
A["conversation / tool output"] --> B["persist raw messages"]
|
|
75
|
+
B --> C["compact into leaf summaries"]
|
|
76
|
+
C --> D["condense into deeper DAG nodes"]
|
|
77
|
+
C --> E["promote durable insights"]
|
|
78
|
+
D --> F["restore future context"]
|
|
79
|
+
E --> F
|
|
80
|
+
F --> G["search / grep / describe / expand / store"]
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Installation
|
|
84
|
+
|
|
85
|
+
### Prerequisites
|
|
86
|
+
|
|
87
|
+
- Node.js 22+
|
|
88
|
+
- Claude Code for hook-based Claude integration
|
|
89
|
+
|
|
90
|
+
### Claude Code
|
|
91
|
+
|
|
92
|
+
Install the `lcm` binary first:
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
npm install -g @lossless-claude/lcm # provides the `lcm` command
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
claude plugin add github:lossless-claude/lcm
|
|
100
|
+
lcm install
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
`lcm install` writes config, registers hooks, installs slash commands, registers MCP, and verifies the daemon.
|
|
104
|
+
|
|
105
|
+
## Hooks
|
|
106
|
+
|
|
107
|
+
Claude Code uses four hooks. All hooks auto-heal: each validates that all required entries remain registered and repairs missing entries before continuing.
|
|
108
|
+
|
|
109
|
+
| Hook | Command | Purpose |
|
|
110
|
+
|---|---|---|
|
|
111
|
+
| `PreCompact` | `lcm compact` | Intercepts compaction and writes DAG summaries |
|
|
112
|
+
| `SessionStart` | `lcm restore` | Restores project context, recent summaries, and promoted memory |
|
|
113
|
+
| `SessionEnd` | `lcm session-end` | Ingests the completed Claude transcript |
|
|
114
|
+
| `UserPromptSubmit` | `lcm user-prompt` | Searches memory and injects prompt-time hints |
|
|
115
|
+
|
|
116
|
+
```mermaid
|
|
117
|
+
flowchart LR
|
|
118
|
+
SS["SessionStart"] --> CONV["Conversation"]
|
|
119
|
+
CONV --> UP["UserPromptSubmit<br/>(each prompt)"]
|
|
120
|
+
UP --> CONV
|
|
121
|
+
CONV --> PC["PreCompact<br/>(if context fills)"]
|
|
122
|
+
PC --> CONV
|
|
123
|
+
CONV --> SE["SessionEnd"]
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## MCP Tools
|
|
127
|
+
|
|
128
|
+
| Tool | Purpose |
|
|
129
|
+
|---|---|
|
|
130
|
+
| `lcm_search` | Search episodic and promoted knowledge |
|
|
131
|
+
| `lcm_grep` | Regex or full-text search across stored history |
|
|
132
|
+
| `lcm_expand` | Recover deeper detail from compacted history |
|
|
133
|
+
| `lcm_describe` | Inspect a stored summary or file by id |
|
|
134
|
+
| `lcm_store` | Persist durable memory manually |
|
|
135
|
+
| `lcm_stats` | Inspect memory coverage, DAG depth, and compression |
|
|
136
|
+
| `lcm_doctor` | Diagnose daemon, hooks, MCP registration, and summarizer setup |
|
|
137
|
+
|
|
138
|
+
## CLI
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
lcm install # setup wizard
|
|
142
|
+
lcm doctor # diagnostics
|
|
143
|
+
lcm stats # memory and compression overview
|
|
144
|
+
lcm stats -v # per-conversation breakdown
|
|
145
|
+
lcm status # daemon + summarizer mode
|
|
146
|
+
lcm daemon start --detach # start daemon in background
|
|
147
|
+
lcm compact # PreCompact hook handler
|
|
148
|
+
lcm restore # SessionStart hook handler
|
|
149
|
+
lcm session-end # SessionEnd hook handler
|
|
150
|
+
lcm user-prompt # UserPromptSubmit hook handler
|
|
151
|
+
lcm mcp # MCP server
|
|
152
|
+
lcm -v # version
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
## Configuration
|
|
156
|
+
|
|
157
|
+
All environment variables are optional. The default summarizer mode is `auto`.
|
|
158
|
+
|
|
159
|
+
| Variable | Default | Description |
|
|
160
|
+
|---|---|---|
|
|
161
|
+
| `LCM_SUMMARY_PROVIDER` | `auto` | `auto`, `claude-process`, `codex-process`, `anthropic`, `openai`, or `disabled` |
|
|
162
|
+
| `LCM_SUMMARY_MODEL` | unset | Optional model override for the selected summarizer provider |
|
|
163
|
+
| `LCM_CONTEXT_THRESHOLD` | `0.75` | Context fill ratio that triggers compaction |
|
|
164
|
+
| `LCM_FRESH_TAIL_COUNT` | `32` | Most recent raw messages protected from compaction |
|
|
165
|
+
| `LCM_LEAF_MIN_FANOUT` | `8` | Minimum raw messages per leaf summary |
|
|
166
|
+
| `LCM_CONDENSED_MIN_FANOUT` | `4` | Minimum summaries per condensed node |
|
|
167
|
+
| `LCM_INCREMENTAL_MAX_DEPTH` | `0` | Automatic condensation depth |
|
|
168
|
+
| `LCM_LEAF_CHUNK_TOKENS` | `20000` | Maximum source tokens per leaf compaction pass |
|
|
169
|
+
| `LCM_LEAF_TARGET_TOKENS` | `1200` | Target size for leaf summaries |
|
|
170
|
+
| `LCM_CONDENSED_TARGET_TOKENS` | `2000` | Target size for condensed summaries |
|
|
171
|
+
|
|
172
|
+
`auto` resolves per caller:
|
|
173
|
+
|
|
174
|
+
- `lcm` -> `claude-process`
|
|
175
|
+
- explicit config or `LCM_SUMMARY_PROVIDER` override always takes precedence
|
|
176
|
+
|
|
177
|
+
See [`docs/configuration.md`](docs/configuration.md) for tuning notes and deeper operational guidance.
|
|
178
|
+
|
|
179
|
+
## Development
|
|
180
|
+
|
|
181
|
+
```bash
|
|
182
|
+
npm install
|
|
183
|
+
npm run build
|
|
184
|
+
npx vitest
|
|
185
|
+
npx tsc --noEmit
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
### Repository layout
|
|
189
|
+
|
|
190
|
+
```text
|
|
191
|
+
bin/
|
|
192
|
+
lcm.ts CLI entry point (binary: lcm)
|
|
193
|
+
src/
|
|
194
|
+
compaction.ts DAG compaction engine
|
|
195
|
+
connectors/ client integration adapters
|
|
196
|
+
daemon/ HTTP daemon, lifecycle, config, routes
|
|
197
|
+
db/ SQLite schema + promoted memory
|
|
198
|
+
hooks/ Claude hook handlers + auto-heal
|
|
199
|
+
llm/ summarizer backends
|
|
200
|
+
mcp/ MCP server + tool definitions
|
|
201
|
+
store/ conversation and summary persistence
|
|
202
|
+
installer/
|
|
203
|
+
install.ts setup wizard
|
|
204
|
+
uninstall.ts cleanup
|
|
205
|
+
test/
|
|
206
|
+
... Vitest suites
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
## Privacy
|
|
210
|
+
|
|
211
|
+
All conversation data is stored locally in `~/.lossless-claude/`. Nothing is sent to any lossless-claude server.
|
|
212
|
+
|
|
213
|
+
If you configure an external summarizer (`claude-process`, `anthropic`, `openai`, etc.), messages are sent to that provider for summarization — after built-in secret redaction. lossless-claude scrubs common secret patterns (API keys, tokens, passwords) from message content before writing to SQLite and before sending to the summarizer.
|
|
214
|
+
|
|
215
|
+
Add project-specific patterns with `lcm sensitive add "MY_PATTERN"`. See [docs/privacy.md](docs/privacy.md) for full details.
|
|
216
|
+
|
|
217
|
+
## Technical Notes
|
|
218
|
+
|
|
219
|
+
- Claude Code integration is hook-first.
|
|
220
|
+
- The daemon is shared; the memory backend is client-agnostic.
|
|
221
|
+
- The repo carries the original lossless-claw lineage; the current runtime is Claude Code oriented.
|
|
222
|
+
|
|
223
|
+
## Acknowledgments
|
|
224
|
+
|
|
225
|
+
`lossless-claude` stands on the shoulders of [lossless-claw](https://github.com/Martian-Engineering/lossless-claude), the original implementation by [Martian Engineering](https://martian.engineering). The DAG-based compaction architecture, the LCM memory model, and the foundational design decisions all originate there.
|
|
226
|
+
|
|
227
|
+
The underlying theory comes from the [LCM paper](https://papers.voltropy.com/LCM) by [Voltropy](https://x.com/Voltropy).
|
|
228
|
+
|
|
229
|
+
## License
|
|
230
|
+
|
|
231
|
+
MIT
|