auto-memory 0.1.0__py3-none-any.whl

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.
Files changed (48) hide show
  1. auto_memory-0.1.0.dist-info/METADATA +285 -0
  2. auto_memory-0.1.0.dist-info/RECORD +48 -0
  3. auto_memory-0.1.0.dist-info/WHEEL +5 -0
  4. auto_memory-0.1.0.dist-info/entry_points.txt +2 -0
  5. auto_memory-0.1.0.dist-info/licenses/LICENSE +21 -0
  6. auto_memory-0.1.0.dist-info/top_level.txt +1 -0
  7. session_recall/__init__.py +0 -0
  8. session_recall/__main__.py +117 -0
  9. session_recall/commands/__init__.py +0 -0
  10. session_recall/commands/checkpoints.py +42 -0
  11. session_recall/commands/files.py +42 -0
  12. session_recall/commands/health.py +38 -0
  13. session_recall/commands/list_sessions.py +81 -0
  14. session_recall/commands/schema_check_cmd.py +23 -0
  15. session_recall/commands/search.py +103 -0
  16. session_recall/commands/show_session.py +73 -0
  17. session_recall/config.py +18 -0
  18. session_recall/db/__init__.py +0 -0
  19. session_recall/db/connect.py +35 -0
  20. session_recall/db/schema_check.py +24 -0
  21. session_recall/health/__init__.py +0 -0
  22. session_recall/health/dim_concurrency.py +33 -0
  23. session_recall/health/dim_corpus.py +19 -0
  24. session_recall/health/dim_disclosure.py +154 -0
  25. session_recall/health/dim_e2e.py +30 -0
  26. session_recall/health/dim_freshness.py +19 -0
  27. session_recall/health/dim_latency.py +26 -0
  28. session_recall/health/dim_repo_coverage.py +27 -0
  29. session_recall/health/dim_schema.py +25 -0
  30. session_recall/health/dim_summary_coverage.py +35 -0
  31. session_recall/health/scoring.py +34 -0
  32. session_recall/tests/__init__.py +0 -0
  33. session_recall/tests/test_connect.py +44 -0
  34. session_recall/tests/test_days_filter.py +225 -0
  35. session_recall/tests/test_dim_disclosure.py +90 -0
  36. session_recall/tests/test_health_scoring.py +60 -0
  37. session_recall/tests/test_list_sessions.py +98 -0
  38. session_recall/tests/test_parser.py +15 -0
  39. session_recall/tests/test_sanitize_terminal.py +45 -0
  40. session_recall/tests/test_schema_check.py +75 -0
  41. session_recall/tests/test_search_sanitize.py +51 -0
  42. session_recall/tests/test_show_session.py +154 -0
  43. session_recall/tests/test_telemetry.py +67 -0
  44. session_recall/types.py +21 -0
  45. session_recall/util/__init__.py +0 -0
  46. session_recall/util/detect_repo.py +25 -0
  47. session_recall/util/format_output.py +51 -0
  48. session_recall/util/telemetry.py +52 -0
@@ -0,0 +1,285 @@
1
+ Metadata-Version: 2.4
2
+ Name: auto-memory
3
+ Version: 0.1.0
4
+ Summary: Your AI coding agent never forgets — progressive session recall for GitHub Copilot CLI
5
+ Author-email: Desi Villanueva <217994822+dezgit2025@users.noreply.github.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/dezgit2025/auto-memory
8
+ Project-URL: Repository, https://github.com/dezgit2025/auto-memory
9
+ Project-URL: Issues, https://github.com/dezgit2025/auto-memory/issues
10
+ Keywords: session,recall,context,memory,cli,copilot
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Environment :: Console
15
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
16
+ Requires-Python: >=3.10
17
+ Description-Content-Type: text/markdown
18
+ License-File: LICENSE
19
+ Provides-Extra: dev
20
+ Requires-Dist: pytest>=8; extra == "dev"
21
+ Requires-Dist: ruff>=0.6; extra == "dev"
22
+ Dynamic: license-file
23
+
24
+ # auto-memory
25
+
26
+ ## Your AI coding agent has amnesia. Here's the fix.
27
+
28
+ *~1,900 lines of Python. Zero dependencies. Saves you an hour a day.*
29
+
30
+ > Built by [Desi Villanueva](https://github.com/dezgit2025)
31
+
32
+ [![CI](https://github.com/dezgit2025/auto-memory/actions/workflows/test.yml/badge.svg)](https://github.com/dezgit2025/auto-memory/actions/workflows/test.yml)
33
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
34
+ [![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org)
35
+ [![Zero Dependencies](https://img.shields.io/badge/dependencies-0-brightgreen)](pyproject.toml)
36
+ [![Tests](https://img.shields.io/badge/tests-90%20passed-brightgreen)]()
37
+
38
+ **Zero-dependency CLI that turns Copilot CLI's local SQLite into instant recall — no MCP server, no hooks, read-only, schema-checked. ~50 tokens per prompt.**
39
+
40
+ **Works with:** GitHub Copilot CLI
41
+ **Coming soon:** Claude Code Ā· Cursor Ā· Codex
42
+
43
+ ---
44
+
45
+ ### Quickstart
46
+
47
+ ```bash
48
+ git clone https://github.com/dezgit2025/auto-memory.git
49
+ cd auto-memory && ./install.sh
50
+ session-recall health # verify it works
51
+ ```
52
+
53
+ Point your agent at [`deploy/install.md`](deploy/install.md) and let it cook. šŸ³
54
+
55
+ ---
56
+
57
+ ## The Problem
58
+
59
+ Every AI coding agent ships with a big number on the box. 200K tokens. Sounds massive. Here's what actually happens:
60
+
61
+ ```
62
+ 200,000 tokens — context window (theoretical max)
63
+ 120,000 tokens — effective limit before context rot kicks in (~60%)
64
+ -65,000 tokens — MCP tools
65
+ -25,000 tokens — instruction files
66
+ =========
67
+ ~30,000 tokens — what you ACTUALLY have before quality degrades
68
+ ```
69
+
70
+ LLMs don't degrade gracefully — once you cross roughly **60% of the context window**, the model starts losing coherence. The industry calls it "lost in the middle": attention goes to the beginning (instructions) and the end (recent turns), but your actual working context in the middle gets progressively fuzzier.
71
+
72
+ I timed it over a week: **68 minutes per day** lost to re-orientation after compactions and new sessions.
73
+
74
+ > It's a **death spiral of diminishing context** — each compaction leaves the agent slightly dumber, which burns more tokens explaining things, which triggers the next compaction sooner.
75
+
76
+ ### The Compaction Tax
77
+
78
+ Every 20–30 turns, the context warning hits and you get two bad choices: ignore it and watch the agent hallucinate, or run `/compact` and watch it lobotomize itself into a tidy two-paragraph summary of a 30-minute investigation. Either way you lose five minutes re-narrating your own project back to the agent like it's a new hire. That's not a workflow — that's a hamster wheel.
79
+
80
+ ## The 200x ROI
81
+
82
+ Here's the cost comparison that made me build this:
83
+
84
+ | Operation | Tokens | What you get |
85
+ |-----------|--------|-------------|
86
+ | `grep -r "auth" src/` | ~5,000-10,000 | 500 results, mostly irrelevant |
87
+ | `find . -name "*.py"` | ~2,000 | Every Python file, no context |
88
+ | Agent re-orientation | ~2,000 | You re-explaining yesterday |
89
+ | **`auto-memory files --json --limit 10`** | **~50** | **Exactly the 10 files you touched yesterday** |
90
+
91
+ **50 tokens vs 10,000 — a 200x improvement.**
92
+
93
+ ## Before & After
94
+
95
+ **Before auto-memory** — new session on a project:
96
+
97
+ ```
98
+ You: Fix the failing test in the auth module
99
+
100
+ Agent: Let me explore the project structure...
101
+ $ find . -name "*.py" | head -50 ← 2K tokens
102
+ $ grep -r "test.*auth" tests/ ← 5K tokens
103
+ $ cat tests/test_auth.py ← 3K tokens
104
+ $ cat src/auth/handler.py ← 2K tokens
105
+ I see several test files. Which test is failing?
106
+
107
+ You: The one we were working on yesterday, the token refresh edge case
108
+
109
+ Agent: Let me search for that...
110
+ $ grep -r "refresh" tests/ ← 4K tokens
111
+ ...
112
+ ```
113
+
114
+ Total: ~16K tokens burned, 8 minutes elapsed, agent still isn't oriented.
115
+
116
+ **After auto-memory** — same scenario:
117
+
118
+ ```
119
+ You: Fix the failing test in the auth module
120
+
121
+ Agent: [auto-recall: auto-memory files --json --limit 10]
122
+ → src/auth/refresh.py, tests/test_refresh_edge_cases.py,
123
+ src/auth/token_store.py (last touched 14h ago)
124
+
125
+ [auto-recall: auto-memory list --json --limit 3]
126
+ → Yesterday: "Fixed token refresh race condition, one edge case
127
+ test still failing on expired token + network timeout combo"
128
+
129
+ I can see from your last session that test_refresh_edge_cases.py
130
+ has a failing test for the expired token + network timeout case.
131
+ Let me look at that specific test...
132
+ $ cat tests/test_refresh_edge_cases.py ← 1K tokens (targeted)
133
+ ```
134
+
135
+ Total: ~1.1K tokens, 30 seconds, agent is immediately productive.
136
+
137
+ ## How it compares
138
+
139
+ | Approach | Dependencies | Writes to DB | Setup | Agent-native |
140
+ |----------|-------------|-------------|-------|-------------|
141
+ | **auto-memory** | None (stdlib) | āŒ Read-only | `pip install` | āœ… Instruction-file |
142
+ | MCP server | Node.js runtime | Varies | Server config | āŒ Protocol layer |
143
+ | Custom hooks | Varies | Often yes | Hook scripts | āŒ Event-driven |
144
+ | Manual grep | None | āŒ | None | āŒ Manual |
145
+
146
+ ## Mental Model: RAM vs Disk
147
+
148
+ - **Context window = RAM.** Fast, limited, clears on restart.
149
+ - **session-store.db = Disk.** Persistent, searchable, grows forever.
150
+
151
+ auto-memory is the **page fault handler** — it pulls exact facts from disk in ~50 tokens when the agent needs them.
152
+
153
+ **It's not unlimited context. It's unlimited context *recall*.** In practice, same thing.
154
+
155
+ ## Design
156
+
157
+ ```
158
+ ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”
159
+ │ copilot-instructions.md │
160
+ │ "Run auto-memory FIRST on every prompt" │
161
+ ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¬ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜
162
+ │ agent reads instruction
163
+ ā–¼
164
+ ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”
165
+ │ auto-memory CLI │
166
+ │ (pure Python, zero deps, read-only) │
167
+ ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¬ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜
168
+ │ SELECT ... FROM sessions
169
+ ā–¼
170
+ ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”
171
+ │ ~/.copilot/session-store.db │
172
+ │ (SQLite + FTS5, owned by Copilot CLI binary) │
173
+ ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜
174
+ ```
175
+
176
+ - **Zero dependencies** — stdlib only (sqlite3, json, argparse)
177
+ - **Read-only** — never writes to `~/.copilot/session-store.db`
178
+ - **WAL-safe** — exponential backoff retry on SQLITE_BUSY (50→150→450ms)
179
+ - **Schema-aware** — validates expected schema on every call, fails fast on drift
180
+ - **Telemetry** — ring buffer of last 100 invocations for concurrency monitoring
181
+
182
+ ## Usage
183
+
184
+ ### Try these prompts with your agent
185
+
186
+ Once wired into your agent's instruction file, session-recall runs on every prompt — giving the agent your recent files and sessions as context before it does anything else.
187
+
188
+
189
+ ```
190
+ "Search recent sessions about fixing the db connection bug"
191
+ "Check past 5 days sessions for latest plans?"
192
+ "Pick up where we left off on the API refactor"
193
+ "search recent sessions for last 10 files we modified"
194
+ "search sessions for the db migration bug"
195
+ ```
196
+
197
+ No special syntax. The agent reads your session history and gets oriented in seconds instead of minutes.
198
+
199
+ ### How it works under the hood
200
+
201
+ Progressive disclosure — most prompts never get past Tier 1.
202
+
203
+ **Tier 1 — Cheap scan (~50 tokens).** Usually enough.
204
+
205
+ ```bash
206
+ session-recall files --json --limit 10
207
+ session-recall list --json --limit 5
208
+ ```
209
+
210
+ **Tier 2 — Focused recall (~200 tokens).** When Tier 1 isn't enough.
211
+
212
+ ```bash
213
+ session-recall search "specific term" --json
214
+ ```
215
+
216
+ **Tier 3 — Full session detail (~500 tokens).** Only when investigating something specific.
217
+
218
+ ```bash
219
+ session-recall show <session-id> --json
220
+ ```
221
+
222
+ **Operational commands:**
223
+
224
+ ```bash
225
+ session-recall health # 9-dimension health dashboard
226
+ session-recall schema-check # validate DB schema after Copilot CLI upgrades
227
+ ```
228
+
229
+ ## Health Check
230
+
231
+ ```
232
+ Dim Name Zone Score Detail
233
+ ----------------------------------------------------------------------
234
+ 1 DB Freshness 🟢 GREEN 8.0 15.8h old
235
+ 2 Schema Integrity 🟢 GREEN 10.0 All tables/columns OK
236
+ 3 Query Latency 🟢 GREEN 10.0 1ms
237
+ 4 Corpus Size 🟢 GREEN 10.0 399 sessions
238
+ 5 Summary Coverage 🟢 GREEN 7.4 92% (367/399)
239
+ 6 Repo Coverage 🟢 GREEN 10.0 8 sessions for owner/repo
240
+ 7 Concurrency 🟢 GREEN 10.0 busy=0.0%, p95=48ms
241
+ 8 E2E Probe 🟢 GREEN 10.0 list→show OK
242
+ 9 Progressive Disclosure ⚪ CALIBRATING — Collecting baseline (n=42/200)
243
+ ```
244
+
245
+ ## Agent Integration
246
+
247
+ auto-memory works with **any agent that supports instruction files** — GitHub Copilot CLI, Claude Code, Cursor, Aider, Windsurf, and more. Installation wires session-recall into your agent's instruction file so it runs context recall automatically.
248
+
249
+ See [`deploy/install.md`](deploy/install.md) for setup and [`copilot-instructions-template.md`](copilot-instructions-template.md) for integration patterns.
250
+
251
+ See [`UPGRADE-COPILOT-CLI.md`](UPGRADE-COPILOT-CLI.md) for schema validation after Copilot CLI upgrades.
252
+
253
+ ## What This Isn't
254
+
255
+ - **Not a vector database** — no embeddings, SQLite FTS5 only.
256
+ - **Not cross-machine sync** — local only.
257
+ - **Not a replacement for project documentation** — recalls *what you did*, not *how the system works*.
258
+
259
+ ## FAQ
260
+
261
+ **Is it safe? Does it modify my session data?**
262
+ No. auto-memory is strictly read-only. It never writes to `~/.copilot/session-store.db`.
263
+
264
+ **What happens when Copilot CLI updates its schema?**
265
+ Run `session-recall schema-check` to validate. The tool fails fast on schema drift rather than returning bad data. See [UPGRADE-COPILOT-CLI.md](UPGRADE-COPILOT-CLI.md).
266
+
267
+ ## Roadmap
268
+
269
+ See [ROADMAP.md](ROADMAP.md).
270
+
271
+ ## Contributing
272
+
273
+ See [CONTRIBUTING.md](CONTRIBUTING.md) for setup and guidelines. Issues, PRs, and docs improvements are welcome.
274
+
275
+ ⭐ **If auto-memory saved you time, [star the repo](https://github.com/dezgit2025/auto-memory)** — it's the best way to help others find it.
276
+
277
+ šŸ”— **Share it:** *"Zero-dependency CLI that gives your AI coding agent session memory. Read-only, schema-checked, ~50 tokens per prompt."* → [github.com/dezgit2025/auto-memory](https://github.com/dezgit2025/auto-memory)
278
+
279
+ ## Disclaimer
280
+
281
+ This is an independent open-source project. It is **not** affiliated with, endorsed by, or supported by Microsoft, GitHub, or any other company. There is no official support — use at your own risk. Contributions and issues are welcome on GitHub.
282
+
283
+ ## License
284
+
285
+ MIT
@@ -0,0 +1,48 @@
1
+ auto_memory-0.1.0.dist-info/licenses/LICENSE,sha256=xUWsqT_KBHFgGHazfzrn0HZF3m3cFmQohZb03j9XA5g,1081
2
+ session_recall/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
+ session_recall/__main__.py,sha256=i_QWXoFOpQSWPh5SrHjZVYbpdf0BvkqwsjwLuXwGaYg,4633
4
+ session_recall/config.py,sha256=QPYZsvpb1k_IH-U2Wa6tw0NIFj8UL9QVmpNHdenVPdY,440
5
+ session_recall/types.py,sha256=AILEMG4TLt318KmKQcbjM7xZvpBncGMhksgn7TytBrQ,696
6
+ session_recall/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
+ session_recall/commands/checkpoints.py,sha256=PSvSXRNgtjh-H5JkAfrlNYurWcKDo-cQarDs8CFgfZ8,1805
8
+ session_recall/commands/files.py,sha256=CJJV2QTWCOMv0lzF4aLUPACFnU0M3dE1C4cbBpoLUb8,1724
9
+ session_recall/commands/health.py,sha256=CHqKnbPGIuNboMedBU7yRc5zwczpEkXt-JWuZbWaLYw,1561
10
+ session_recall/commands/list_sessions.py,sha256=ySkrZsu_XMruXUIn3KyOQ-Lw5V-5Ojq72V0vnk01-Fc,3261
11
+ session_recall/commands/schema_check_cmd.py,sha256=u8wGqjlg27usWMsFH18aOMXtr-58U3lStZjiQSV6mFM,851
12
+ session_recall/commands/search.py,sha256=TmRkXcP6ttWIB2jbSDmVm66GJSShu_bZwsCMr8Nonns,4306
13
+ session_recall/commands/show_session.py,sha256=2wev-aV0OKeXXdOEgnuWvot9Q0A5uARen4XHQ2Ycv44,2839
14
+ session_recall/db/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
15
+ session_recall/db/connect.py,sha256=XDBDLsajL16EaVOvsWB_KF9PDB7TPR8p728Sf2ChWNY,1232
16
+ session_recall/db/schema_check.py,sha256=7NgDsf-sD0tYJAOh8Z1Qkw_S9--QgMAD_EvWDjhkDHE,1166
17
+ session_recall/health/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
18
+ session_recall/health/dim_concurrency.py,sha256=t6_PxMRuseEXWOshUm_9vb7tlC8J-b_WdGl9c589edY,1560
19
+ session_recall/health/dim_corpus.py,sha256=ef7036raknEdh3zjNAlUDQiQSre9vtlRVSULnp6S3gM,681
20
+ session_recall/health/dim_disclosure.py,sha256=iIFg5P2oSAzh5IxogmvmBwmDvWErT2ZfDRGOOnZKXgY,6355
21
+ session_recall/health/dim_e2e.py,sha256=EPTZOaIRlKit2SNuhHRV6veJAPj331KkMxkHQ2qI01Q,1177
22
+ session_recall/health/dim_freshness.py,sha256=7nN93Myfo5CdZna3R2-VLJ0XPzkTJNfUHw_BNYKcfS8,698
23
+ session_recall/health/dim_latency.py,sha256=Z6igJ4GR4F7nC-aC_oxxYn65zAc8NWGHVvMeiBVKuns,1067
24
+ session_recall/health/dim_repo_coverage.py,sha256=SEv2_OPzbo61W4AEayu9BsLwviRohyaAgBTXYo5AbQY,1051
25
+ session_recall/health/dim_schema.py,sha256=HLo5UGFW9IiEL37SjpNRAqykd9Lsb22VOe1q0wWlJMo,1029
26
+ session_recall/health/dim_summary_coverage.py,sha256=-R2dO8EiXvUuXcB69GLh7y-EXrkhLJwRYbxqKjE5xT8,1453
27
+ session_recall/health/scoring.py,sha256=i_Z5g5u3Vq_cNF5YxgUDBRVlQRBpGeZaonjA2oXKC5s,1657
28
+ session_recall/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
29
+ session_recall/tests/test_connect.py,sha256=HJeJiGwxaegYM1mg3mcpJ04JUWqgaF72m_J4gSU5zco,1308
30
+ session_recall/tests/test_days_filter.py,sha256=_hjs6y50jsJHszOuBW3tpyzQKabOUl3_4d7ZrcITxXw,9101
31
+ session_recall/tests/test_dim_disclosure.py,sha256=UcK_e0zXMRvgCr4dvf2qbnRlb-XivHDBpzzNv2LdE5Q,3481
32
+ session_recall/tests/test_health_scoring.py,sha256=JAhOgPT-Na677HcGvmxFYHWaemuVRiNzTaREx59B6f0,1865
33
+ session_recall/tests/test_list_sessions.py,sha256=a2fx_KkFkToR3tsWwIimPTSTLAXct5MgPADxn_XOQOA,4383
34
+ session_recall/tests/test_parser.py,sha256=F3Fq4w7D_rGMbOGtINi-mpscL5rnG-SJMXGJT1CDnvc,690
35
+ session_recall/tests/test_sanitize_terminal.py,sha256=zLSKIA8GdEVWdsSBrsHGZwlq45rbv6K149Oy_jmE1Do,1474
36
+ session_recall/tests/test_schema_check.py,sha256=o2BsEqamMyTjVLbRbVUjAqJW8ovox60Z0cm5ho1zUMI,2435
37
+ session_recall/tests/test_search_sanitize.py,sha256=ceLP5ndVkF-3a-ACs0sZAgFYE4MJA6oG-SM2CZRsvRM,1746
38
+ session_recall/tests/test_show_session.py,sha256=mysfTd_U5Rn97En756k1wgS7qjZK1gcD446y0NSm5r8,5886
39
+ session_recall/tests/test_telemetry.py,sha256=5PoeVk8hyPmYNrOJnVcDjpv8dcTV2B3X9YJAXhKJWxM,2337
40
+ session_recall/util/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
41
+ session_recall/util/detect_repo.py,sha256=bLOIsenTnhmygZr_zYYhJk3-VmsGwvu4gJgXIORJPHQ,777
42
+ session_recall/util/format_output.py,sha256=zmcJq7v0nrRwDS7mixOPZjvLNdj5cEQzxVxTWeLLYQQ,1934
43
+ session_recall/util/telemetry.py,sha256=GaNqmA4UJkmt30JAn0M1Sl6FK_HKhtfAZokGDFahzWw,2401
44
+ auto_memory-0.1.0.dist-info/METADATA,sha256=KpqcNvxMwH5d-6GcfaDLP02PWxZ27OCdSm-aKNHYIZA,12263
45
+ auto_memory-0.1.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
46
+ auto_memory-0.1.0.dist-info/entry_points.txt,sha256=BHVjZhFujSpgxlyRqqIu4V1jOdv_xKD-19zmKqQYPEE,64
47
+ auto_memory-0.1.0.dist-info/top_level.txt,sha256=xKR1tZQmXXPwvC0rXmDS8tr9LZo_wZOIfMps2OqtFGo,15
48
+ auto_memory-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (82.0.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ session-recall = session_recall.__main__:main
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 auto-memory contributors
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.
@@ -0,0 +1 @@
1
+ session_recall
File without changes
@@ -0,0 +1,117 @@
1
+ """auto-memory CLI — progressive session disclosure for Copilot CLI."""
2
+ import argparse
3
+ import sys
4
+ import time
5
+
6
+ from .config import TELEMETRY_PATH
7
+ from .util import telemetry
8
+
9
+
10
+ def _non_negative_int(v):
11
+ """Argparse type: non-negative integer."""
12
+ i = int(v)
13
+ if i < 0:
14
+ raise argparse.ArgumentTypeError(f"must be >= 0, got {v}")
15
+ return i
16
+
17
+
18
+ TIER_MAP = {
19
+ "list": 1, "files": 1, "checkpoints": 1, # Tier 1 — cheap scan
20
+ "search": 2, # Tier 2 — focused search
21
+ "show": 3, # Tier 3 — deep dive
22
+ "health": 0, "schema-check": 0, # Tier 0 — meta/ops
23
+ "calibrate": 0, # Tier 0 — meta (Phase 4)
24
+ }
25
+
26
+
27
+ def main() -> None:
28
+ telemetry.init(TELEMETRY_PATH)
29
+ t0 = time.monotonic()
30
+ parser = argparse.ArgumentParser(prog="auto-memory", description="Query Copilot CLI session history")
31
+ sub = parser.add_subparsers(dest="command")
32
+
33
+ p_list = sub.add_parser("list", help="Recent sessions")
34
+ p_list.add_argument("--repo", default=None)
35
+ p_list.add_argument("--limit", type=int, default=None)
36
+ p_list.add_argument("--days", type=int, default=None, help="Only include sessions from last N days (default 30)")
37
+ p_list.add_argument("--json", action="store_true")
38
+
39
+ p_schema = sub.add_parser("schema-check", help="Validate DB schema")
40
+ p_schema.add_argument("--json", action="store_true")
41
+
42
+ p_files = sub.add_parser("files", help="Recently touched files")
43
+ p_files.add_argument("--json", action="store_true")
44
+ p_files.add_argument("--repo", default=None)
45
+ p_files.add_argument("--limit", type=int, default=None)
46
+ p_files.add_argument("--days", type=int, default=None, help="Only include files from last N days")
47
+
48
+ p_cp = sub.add_parser("checkpoints", help="Recent checkpoints")
49
+ p_cp.add_argument("--json", action="store_true")
50
+ p_cp.add_argument("--repo", default=None)
51
+ p_cp.add_argument("--limit", type=int, default=None)
52
+ p_cp.add_argument("--days", type=int, default=None, help="Only include checkpoints from last N days")
53
+
54
+ p_show = sub.add_parser("show", help="Show session details")
55
+ p_show.add_argument("session_id")
56
+ p_show.add_argument("--json", action="store_true")
57
+ p_show.add_argument("--turns", type=_non_negative_int, default=None)
58
+ p_show.add_argument("--full", action="store_true")
59
+
60
+ p_search = sub.add_parser("search", help="Full-text search")
61
+ p_search.add_argument("query")
62
+ p_search.add_argument("--json", action="store_true")
63
+ p_search.add_argument("--repo", default=None)
64
+ p_search.add_argument("--limit", type=int, default=None)
65
+ p_search.add_argument("--days", type=int, default=None, help="Only include sessions from last N days")
66
+
67
+ p_health = sub.add_parser("health", help="Health check (9 dimensions)")
68
+ p_health.add_argument("--json", action="store_true")
69
+
70
+ args = parser.parse_args()
71
+ if not args.command:
72
+ parser.print_help()
73
+ sys.exit(1)
74
+
75
+ exit_code = 1
76
+ if args.command == "list":
77
+ from .commands.list_sessions import run
78
+ exit_code = run(args)
79
+ elif args.command == "schema-check":
80
+ from .commands.schema_check_cmd import run
81
+ exit_code = run(args)
82
+ elif args.command == "files":
83
+ from .commands.files import run
84
+ exit_code = run(args)
85
+ elif args.command == "checkpoints":
86
+ from .commands.checkpoints import run
87
+ exit_code = run(args)
88
+ elif args.command == "show":
89
+ from .commands.show_session import run
90
+ exit_code = run(args)
91
+ elif args.command == "search":
92
+ from .commands.search import run
93
+ exit_code = run(args)
94
+ elif args.command == "health":
95
+ from .commands.health import run
96
+ exit_code = run(args)
97
+ else:
98
+ print(f"'{args.command}' not yet implemented. Coming in Phase 2.", file=sys.stderr)
99
+
100
+ duration_ms = int((time.monotonic() - t0) * 1000)
101
+ tier = TIER_MAP.get(args.command) # None if command unknown
102
+ qhash = None
103
+ sid_prefix = None
104
+ wtier = None # Phase 4 will populate this
105
+ if args.command == "search":
106
+ qhash = telemetry.query_hash(getattr(args, "query", "") or "")
107
+ elif args.command == "show":
108
+ sid = getattr(args, "session_id", "") or ""
109
+ sid_prefix = sid[:8] if sid else None
110
+ telemetry.record(cmd=args.command, duration_ms=duration_ms, exit_code=exit_code,
111
+ tier=tier, query_hash=qhash, session_id_prefix=sid_prefix,
112
+ window_tier=wtier)
113
+ sys.exit(exit_code)
114
+
115
+
116
+ if __name__ == "__main__":
117
+ main()
File without changes
@@ -0,0 +1,42 @@
1
+ """List recent checkpoints with session context."""
2
+ import sys
3
+ from ..db.connect import connect_ro
4
+ from ..db.schema_check import schema_check
5
+ from ..config import DB_PATH
6
+ from ..util.detect_repo import detect_repo
7
+ from ..util.format_output import output
8
+
9
+ _BASE = """SELECT c.checkpoint_number, c.title, c.overview, c.created_at,
10
+ c.session_id, s.summary as session_summary FROM checkpoints c
11
+ JOIN sessions s ON s.id = c.session_id"""
12
+
13
+
14
+ def run(args) -> int:
15
+ conn = connect_ro(DB_PATH)
16
+ problems = schema_check(conn)
17
+ if problems:
18
+ for p in problems:
19
+ print(f" - {p}", file=sys.stderr)
20
+ conn.close()
21
+ return 2
22
+ repo = getattr(args, 'repo', None) or detect_repo()
23
+ limit = getattr(args, 'limit', None) or 5
24
+ days = getattr(args, 'days', None)
25
+ date_filter = " AND c.created_at >= datetime('now', ?)" if days else ""
26
+ date_param = (f"-{days} days",) if days else ()
27
+ if repo and repo != "all":
28
+ sql = _BASE + f" WHERE s.repository = ?{date_filter} ORDER BY c.created_at DESC LIMIT ?"
29
+ rows = conn.execute(sql, (repo, *date_param, limit)).fetchall()
30
+ else:
31
+ where = f" WHERE 1=1{date_filter}" if days else ""
32
+ sql = _BASE + where + " ORDER BY c.created_at DESC LIMIT ?"
33
+ rows = conn.execute(sql, (*date_param, limit)).fetchall()
34
+ checkpoints = [{
35
+ "checkpoint_number": r["checkpoint_number"], "title": r["title"],
36
+ "overview": (r["overview"] or "")[:300], "date": (r["created_at"] or "")[:10],
37
+ "session_id": r["session_id"][:8], "session_summary": r["session_summary"],
38
+ } for r in rows]
39
+ output({"repo": repo or "all", "count": len(checkpoints), "checkpoints": checkpoints},
40
+ json_mode=getattr(args, 'json', False))
41
+ conn.close()
42
+ return 0
@@ -0,0 +1,42 @@
1
+ """List recently touched files with session attribution."""
2
+ import sys
3
+ from ..db.connect import connect_ro
4
+ from ..db.schema_check import schema_check
5
+ from ..config import DB_PATH
6
+ from ..util.detect_repo import detect_repo
7
+ from ..util.format_output import output
8
+
9
+ _BASE = """SELECT sf.file_path, sf.tool_name, sf.first_seen_at,
10
+ sf.session_id, s.summary FROM session_files sf
11
+ JOIN sessions s ON s.id = sf.session_id"""
12
+
13
+
14
+ def run(args) -> int:
15
+ conn = connect_ro(DB_PATH)
16
+ problems = schema_check(conn)
17
+ if problems:
18
+ for p in problems:
19
+ print(f" - {p}", file=sys.stderr)
20
+ conn.close()
21
+ return 2
22
+ repo = getattr(args, 'repo', None) or detect_repo()
23
+ limit = getattr(args, 'limit', None) or 10
24
+ days = getattr(args, 'days', None)
25
+ date_filter = " AND sf.first_seen_at >= datetime('now', ?)" if days else ""
26
+ date_param = (f"-{days} days",) if days else ()
27
+ if repo and repo != "all":
28
+ sql = _BASE + f" WHERE s.repository = ?{date_filter} ORDER BY sf.first_seen_at DESC LIMIT ?"
29
+ rows = conn.execute(sql, (repo, *date_param, limit)).fetchall()
30
+ else:
31
+ where = f" WHERE 1=1{date_filter}" if days else ""
32
+ sql = _BASE + where + " ORDER BY sf.first_seen_at DESC LIMIT ?"
33
+ rows = conn.execute(sql, (*date_param, limit)).fetchall()
34
+ files = [{
35
+ "file_path": r["file_path"], "tool_name": r["tool_name"],
36
+ "date": (r["first_seen_at"] or "")[:10],
37
+ "session_id": r["session_id"][:8], "session_summary": r["summary"],
38
+ } for r in rows]
39
+ output({"repo": repo or "all", "count": len(files), "files": files},
40
+ json_mode=getattr(args, 'json', False))
41
+ conn.close()
42
+ return 0
@@ -0,0 +1,38 @@
1
+ """Health check orchestrator — run all 9 dimensions and report."""
2
+ import sys
3
+ from ..health.scoring import overall_score
4
+ from ..health import (dim_freshness, dim_schema, dim_latency, dim_corpus,
5
+ dim_summary_coverage, dim_repo_coverage, dim_concurrency,
6
+ dim_e2e, dim_disclosure)
7
+ from ..util.format_output import fmt_json
8
+
9
+ DIMS = [dim_freshness, dim_schema, dim_latency, dim_corpus,
10
+ dim_summary_coverage, dim_repo_coverage, dim_concurrency, dim_e2e,
11
+ dim_disclosure]
12
+
13
+ ZONE_ICON = {"GREEN": "🟢", "AMBER": "🟔", "RED": "šŸ”“"}
14
+ ZONE_ICON["CALIBRATING"] = "⚪"
15
+
16
+
17
+ def run(args) -> int:
18
+ results = [d.check() for d in DIMS]
19
+ score = overall_score(results)
20
+ hints = [r["hint"] for r in results if r["zone"] != "GREEN" and r.get("hint")]
21
+
22
+ if getattr(args, "json", False):
23
+ print(fmt_json({"overall_score": score, "dims": results, "top_hints": hints[:3]}))
24
+ else:
25
+ print(f"\n{'Dim':<3s} {'Name':<22s} {'Zone':<8s} {'Score':>5s} Detail")
26
+ print("-" * 70)
27
+ for i, r in enumerate(results, 1):
28
+ icon = ZONE_ICON.get(r["zone"], "?")
29
+ score_str = f"{r['score']:5.1f}" if r.get("score") is not None else " - "
30
+ print(f" {i:<2d} {r['name']:<22s} {icon} {r['zone']:<5s} {score_str} {r['detail']}")
31
+ print("-" * 70)
32
+ print(f" {'Overall':<22s} {score:5.1f}")
33
+ if hints:
34
+ print(f"\nšŸ’” Hints:")
35
+ for h in hints[:3]:
36
+ print(f" • {h}")
37
+ print()
38
+ return 0