deja-cli 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.
deja/llm/factory.py ADDED
@@ -0,0 +1,90 @@
1
+ from __future__ import annotations
2
+
3
+ import sys
4
+ from typing import Literal, Optional
5
+
6
+ import httpx
7
+
8
+ from deja.config import Config, LLMProviderConfig
9
+ from deja.llm.base import LLMAdapter
10
+ from deja.llm.embedding import EmbeddingAdapter, OllamaEmbeddingAdapter
11
+ from deja.llm.providers.anthropic import AnthropicAdapter
12
+ from deja.llm.providers.ollama import OllamaAdapter
13
+
14
+
15
+ async def _ollama_available(base_url: str) -> bool:
16
+ try:
17
+ async with httpx.AsyncClient(timeout=2.0) as client:
18
+ response = await client.get(f"{base_url.rstrip('/')}/api/tags")
19
+ return response.status_code == 200
20
+ except Exception:
21
+ return False
22
+
23
+
24
+ def _build_adapter(provider_cfg: LLMProviderConfig) -> LLMAdapter:
25
+ if provider_cfg.provider == "ollama":
26
+ return OllamaAdapter(
27
+ model=provider_cfg.model,
28
+ base_url=provider_cfg.base_url,
29
+ )
30
+ elif provider_cfg.provider == "anthropic":
31
+ return AnthropicAdapter(
32
+ model=provider_cfg.model,
33
+ api_key=provider_cfg.api_key,
34
+ )
35
+ else:
36
+ raise ValueError(f"Unknown provider: {provider_cfg.provider}")
37
+
38
+
39
+ async def create_adapter(
40
+ config: Config,
41
+ task: Literal["extraction", "reflection"] = "extraction",
42
+ ) -> Optional[LLMAdapter]:
43
+ """Create an LLM adapter for the given task.
44
+
45
+ Returns None when provider is 'none' — the agent handles extraction itself
46
+ via deja save, or the watcher falls back to saving raw content.
47
+ """
48
+ provider_cfg = (
49
+ config.llm.extraction if task == "extraction" else config.llm.reflection
50
+ )
51
+
52
+ if provider_cfg.provider == "none":
53
+ return None
54
+
55
+ if provider_cfg.provider == "ollama":
56
+ if await _ollama_available(provider_cfg.base_url):
57
+ return _build_adapter(provider_cfg)
58
+ else:
59
+ print(
60
+ f"[deja] Ollama unavailable at {provider_cfg.base_url}, "
61
+ f"falling back to {config.llm.fallback.provider}",
62
+ file=sys.stderr,
63
+ )
64
+ return _build_adapter(config.llm.fallback)
65
+
66
+ return _build_adapter(provider_cfg)
67
+
68
+
69
+ async def create_embedding_adapter(config: Config) -> Optional[EmbeddingAdapter]:
70
+ """Create an embedding adapter for semantic search.
71
+
72
+ Returns None when provider is 'none' — search falls back to BM25 (FTS5) only.
73
+ """
74
+ if config.embedding.provider == "none":
75
+ return None
76
+
77
+ if config.embedding.provider == "ollama":
78
+ if await _ollama_available(config.embedding.base_url):
79
+ return OllamaEmbeddingAdapter(
80
+ model=config.embedding.model,
81
+ base_url=config.embedding.base_url,
82
+ )
83
+ print(
84
+ f"[deja] Ollama unavailable at {config.embedding.base_url} — embedding search disabled",
85
+ file=sys.stderr,
86
+ )
87
+ return None
88
+
89
+ print(f"[deja] Unknown embedding provider: {config.embedding.provider}", file=sys.stderr)
90
+ return None
File without changes
@@ -0,0 +1,21 @@
1
+ from __future__ import annotations
2
+
3
+ import anthropic
4
+
5
+ from deja.llm.base import LLMAdapter, LLMResponse
6
+
7
+
8
+ class AnthropicAdapter(LLMAdapter):
9
+ def __init__(self, model: str, api_key: str | None = None) -> None:
10
+ self.model = model
11
+ self._client = anthropic.AsyncAnthropic(api_key=api_key)
12
+
13
+ async def complete(self, system: str, user: str, **kwargs) -> LLMResponse:
14
+ message = await self._client.messages.create(
15
+ model=self.model,
16
+ max_tokens=4096,
17
+ system=system,
18
+ messages=[{"role": "user", "content": user}],
19
+ )
20
+ content = message.content[0].text
21
+ return LLMResponse(content=content, raw=message)
@@ -0,0 +1,30 @@
1
+ from __future__ import annotations
2
+
3
+ import httpx
4
+
5
+ from deja.llm.base import LLMAdapter, LLMResponse
6
+
7
+
8
+ class OllamaAdapter(LLMAdapter):
9
+ def __init__(self, model: str, base_url: str = "http://localhost:11434") -> None:
10
+ self.model = model
11
+ self.base_url = base_url.rstrip("/")
12
+
13
+ async def complete(self, system: str, user: str, **kwargs) -> LLMResponse:
14
+ payload = {
15
+ "model": self.model,
16
+ "messages": [
17
+ {"role": "system", "content": system},
18
+ {"role": "user", "content": user},
19
+ ],
20
+ "stream": False,
21
+ }
22
+ async with httpx.AsyncClient(timeout=120.0) as client:
23
+ response = await client.post(
24
+ f"{self.base_url}/api/chat",
25
+ json=payload,
26
+ )
27
+ response.raise_for_status()
28
+ data = response.json()
29
+ content = data["message"]["content"]
30
+ return LLMResponse(content=content, raw=data)
deja/main.py ADDED
@@ -0,0 +1,4 @@
1
+ from deja.interfaces.cli import app
2
+
3
+ if __name__ == "__main__":
4
+ app()
@@ -0,0 +1,100 @@
1
+ Metadata-Version: 2.4
2
+ Name: deja-cli
3
+ Version: 0.1.0
4
+ Summary: Local-first persistent memory CLI for coding agents
5
+ Author-email: Mike <mike@bigtreeproduction.com>
6
+ License: MIT
7
+ License-File: LICENSE
8
+ Keywords: agent,claude,cli,developer-tools,llm,memory
9
+ Classifier: Development Status :: 4 - Beta
10
+ Classifier: Environment :: Console
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
16
+ Classifier: Topic :: Utilities
17
+ Requires-Python: >=3.12
18
+ Requires-Dist: aiosqlite>=0.20
19
+ Requires-Dist: anthropic>=0.34
20
+ Requires-Dist: apscheduler<4.0,>=3.10
21
+ Requires-Dist: fastapi>=0.115
22
+ Requires-Dist: httpx>=0.27
23
+ Requires-Dist: mcp>=1.26.0
24
+ Requires-Dist: pydantic-settings>=2.4
25
+ Requires-Dist: pydantic>=2.0
26
+ Requires-Dist: python-ulid>=2.0
27
+ Requires-Dist: pyyaml>=6.0
28
+ Requires-Dist: typer>=0.12
29
+ Requires-Dist: uvicorn[standard]>=0.30
30
+ Requires-Dist: watchdog>=4.0
31
+ Description-Content-Type: text/markdown
32
+
33
+ # deja
34
+
35
+ Local-first persistent memory CLI for coding agents. Memories accumulate across sessions, deduplicate automatically, and stay on your machine.
36
+
37
+ ## Install
38
+
39
+ ```bash
40
+ uv tool install deja-cli
41
+ ```
42
+
43
+ ## Quick Start
44
+
45
+ ```bash
46
+ deja init # first-time setup
47
+ deja setup claude-code # inject memory instructions into Claude Code
48
+ ```
49
+
50
+ ## Core Commands
51
+
52
+ **Save a memory:**
53
+ ```bash
54
+ deja save "Always use explicit error handling over try/catch" --type preference
55
+ deja save "Auth tokens stored in localStorage, not cookies" --type decision --project myapp
56
+ deja save "Prisma migrations fail silently if DB_URL has wrong port" --type gotcha --project myapp
57
+ ```
58
+
59
+ **Load at session start:**
60
+ ```bash
61
+ deja load --project myapp --context "what you're working on"
62
+ ```
63
+
64
+ **Search mid-session:**
65
+ ```bash
66
+ deja search "authentication" --project myapp
67
+ ```
68
+
69
+ **Extract memories from a session:**
70
+ ```bash
71
+ deja save-session --project myapp
72
+ ```
73
+
74
+ ## Memory Types
75
+
76
+ | Type | When to use |
77
+ |---|---|
78
+ | `preference` | How you like to code — style, tools, habits |
79
+ | `pattern` | Reusable solution that applies across contexts |
80
+ | `decision` | Non-obvious architectural choice with reasoning |
81
+ | `gotcha` | Bug, trap, or non-obvious issue to avoid |
82
+ | `progress` | Current state of in-progress work |
83
+ | `procedure` | Ordered steps for a recurring task |
84
+
85
+ ## Setup for Coding Agents
86
+
87
+ ```bash
88
+ deja setup claude-code # Claude Code — global config + recall hooks
89
+ deja setup gemini-cli # Gemini CLI
90
+ deja setup codex # Codex CLI
91
+ deja setup cursor # Cursor
92
+ ```
93
+
94
+ ## MCP Server
95
+
96
+ ```bash
97
+ claude mcp add --scope user deja -- ~/.local/bin/deja-mcp
98
+ ```
99
+
100
+ Registers `memory_load`, `memory_save`, and `memory_search` as native tools in every Claude Code session.
@@ -0,0 +1,31 @@
1
+ deja/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ deja/config.py,sha256=0QVDDA4xKNz6PbefZ2rIq4kH0VDmf09F4eqJd14erKw,3874
3
+ deja/main.py,sha256=nni8Tguta7JFkjcCbjy-fDZIn02dCzkEbUw9wnbOoWs,74
4
+ deja/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
+ deja/core/extractor.py,sha256=p40C6NJaSmwTw5dZN05R7n298E_6kBrPp2JOYxOR05s,4742
6
+ deja/core/reflection.py,sha256=IUgzaSZsgxRRnqJ2cFvxiG91HlpIWtFk8Kl3C5fbmc0,15721
7
+ deja/core/scheduler.py,sha256=uTFKZaCv4HWp_thYr4DMK4QoO535l6In_prfPcch9xk,1835
8
+ deja/core/store.py,sha256=2uMhX63BPFfRCV7RDjkNAXR5vJ0W2l32NL5nbadi03A,57378
9
+ deja/ingest/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
+ deja/ingest/watchers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
+ deja/ingest/watchers/base.py,sha256=0EnjNf96fHE-_YGZHzJuc4EkQFKNYQoxxA020_fhY3E,4950
12
+ deja/ingest/watchers/claude_code.py,sha256=lo_MpQf3F_dvSSjyhKFfaUXvyUXqNwUpkXCh5FRWBmY,2674
13
+ deja/ingest/watchers/codex_cli.py,sha256=Btj9FBA69nyHvpi5iDXHdfBIYbe9HMtZRMCq3yqUIIM,3458
14
+ deja/ingest/watchers/gemini_cli.py,sha256=bIEvPTWjniofdFxanN7cY44U1GFqLU74UzX-PA44C6g,3350
15
+ deja/interfaces/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
16
+ deja/interfaces/cli.py,sha256=oiafmZOHoSD6MDxkmoM7HfptVGfuP__anvk-oJd8wRA,76808
17
+ deja/interfaces/mcp_server.py,sha256=zo0Q1aHEmfM82jk6P-FacxYsPuhSSyH32YAgJq2OfuA,3198
18
+ deja/interfaces/web.py,sha256=2emjKBVTXhrIaxhw59RI5X1c8mV14sVJ4IIXERcbPwo,3136
19
+ deja/interfaces/web_ui/index.html,sha256=TE3JKlfqcli-dLfEcwR5eN5eNyMZd0YtmJYbdf_Ptis,17817
20
+ deja/llm/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
21
+ deja/llm/base.py,sha256=bkkN-ylKfTJNOt756Y7YQO45RIbm23ttT7aS8g2UxhA,1062
22
+ deja/llm/embedding.py,sha256=gsZzU8hQFnfmk0i4yea9eRFzfGwG6QX9oSpR0wCh4OQ,1407
23
+ deja/llm/factory.py,sha256=Kmd4oRLqTPFFwAE1Wo5p9GBSN7HfdALgrmHU7b3H6_s,2972
24
+ deja/llm/providers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
25
+ deja/llm/providers/anthropic.py,sha256=Gmb6vjGN23vbLUBUdRTsFbcV9ndhaV3CcTgF6DICRkQ,693
26
+ deja/llm/providers/ollama.py,sha256=b0v8MJcOL7fV_zd5r1LKHXpRHBnpjMia-B2PNWVoYUs,988
27
+ deja_cli-0.1.0.dist-info/METADATA,sha256=Y1BIgPw1hyv2cy4tjvZPca4FVRnPX034VbGAU2vqaCY,2880
28
+ deja_cli-0.1.0.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
29
+ deja_cli-0.1.0.dist-info/entry_points.txt,sha256=1DFYa8oXV00iBZk-Yc4ZKOMhTmQGhI1qHtGfdOXA1dY,82
30
+ deja_cli-0.1.0.dist-info/licenses/LICENSE,sha256=bnwiEGciwVH_xm0PryA1FV7KGtkZMfVnnGdziRwI3u8,1061
31
+ deja_cli-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.29.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,3 @@
1
+ [console_scripts]
2
+ deja = deja.main:app
3
+ deja-mcp = deja.interfaces.mcp_server:main
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Mike
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.