dev-recall 0.2.2__tar.gz → 0.2.3__tar.gz

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 (47) hide show
  1. {dev_recall-0.2.2 → dev_recall-0.2.3}/PKG-INFO +1 -1
  2. {dev_recall-0.2.2 → dev_recall-0.2.3}/dev_recall.egg-info/PKG-INFO +1 -1
  3. {dev_recall-0.2.2 → dev_recall-0.2.3}/dev_recall.egg-info/SOURCES.txt +3 -0
  4. {dev_recall-0.2.2 → dev_recall-0.2.3}/pyproject.toml +8 -1
  5. {dev_recall-0.2.2 → dev_recall-0.2.3}/recall/cli.py +3 -3
  6. dev_recall-0.2.3/recall/vscode-extension/package.json +42 -0
  7. dev_recall-0.2.3/recall/vscode-extension/src/extension.ts +238 -0
  8. dev_recall-0.2.3/recall/vscode-extension/tsconfig.json +14 -0
  9. {dev_recall-0.2.2 → dev_recall-0.2.3}/README.md +0 -0
  10. {dev_recall-0.2.2 → dev_recall-0.2.3}/dev_recall.egg-info/dependency_links.txt +0 -0
  11. {dev_recall-0.2.2 → dev_recall-0.2.3}/dev_recall.egg-info/entry_points.txt +0 -0
  12. {dev_recall-0.2.2 → dev_recall-0.2.3}/dev_recall.egg-info/requires.txt +0 -0
  13. {dev_recall-0.2.2 → dev_recall-0.2.3}/dev_recall.egg-info/top_level.txt +0 -0
  14. {dev_recall-0.2.2 → dev_recall-0.2.3}/recall/__init__.py +0 -0
  15. {dev_recall-0.2.2 → dev_recall-0.2.3}/recall/_hooks.py +0 -0
  16. {dev_recall-0.2.2 → dev_recall-0.2.3}/recall/collectors/__init__.py +0 -0
  17. {dev_recall-0.2.2 → dev_recall-0.2.3}/recall/collectors/ai_chat.py +0 -0
  18. {dev_recall-0.2.2 → dev_recall-0.2.3}/recall/collectors/containers.py +0 -0
  19. {dev_recall-0.2.2 → dev_recall-0.2.3}/recall/collectors/git.py +0 -0
  20. {dev_recall-0.2.2 → dev_recall-0.2.3}/recall/collectors/linux_process.py +0 -0
  21. {dev_recall-0.2.2 → dev_recall-0.2.3}/recall/collectors/linux_session.py +0 -0
  22. {dev_recall-0.2.2 → dev_recall-0.2.3}/recall/collectors/linux_window.py +0 -0
  23. {dev_recall-0.2.2 → dev_recall-0.2.3}/recall/collectors/shell.py +0 -0
  24. {dev_recall-0.2.2 → dev_recall-0.2.3}/recall/collectors/vscode.py +0 -0
  25. {dev_recall-0.2.2 → dev_recall-0.2.3}/recall/config.py +0 -0
  26. {dev_recall-0.2.2 → dev_recall-0.2.3}/recall/daemon.py +0 -0
  27. {dev_recall-0.2.2 → dev_recall-0.2.3}/recall/daemon_main.py +0 -0
  28. {dev_recall-0.2.2 → dev_recall-0.2.3}/recall/mcp_server.py +0 -0
  29. {dev_recall-0.2.2 → dev_recall-0.2.3}/recall/models.py +0 -0
  30. {dev_recall-0.2.2 → dev_recall-0.2.3}/recall/processor/__init__.py +0 -0
  31. {dev_recall-0.2.2 → dev_recall-0.2.3}/recall/processor/embedder.py +0 -0
  32. {dev_recall-0.2.2 → dev_recall-0.2.3}/recall/processor/enricher.py +0 -0
  33. {dev_recall-0.2.2 → dev_recall-0.2.3}/recall/processor/session.py +0 -0
  34. {dev_recall-0.2.2 → dev_recall-0.2.3}/recall/query/__init__.py +0 -0
  35. {dev_recall-0.2.2 → dev_recall-0.2.3}/recall/query/context.py +0 -0
  36. {dev_recall-0.2.2 → dev_recall-0.2.3}/recall/query/llm.py +0 -0
  37. {dev_recall-0.2.2 → dev_recall-0.2.3}/recall/query/retriever.py +0 -0
  38. {dev_recall-0.2.2 → dev_recall-0.2.3}/recall/query/timeparser.py +0 -0
  39. {dev_recall-0.2.2 → dev_recall-0.2.3}/recall/storage/__init__.py +0 -0
  40. {dev_recall-0.2.2 → dev_recall-0.2.3}/recall/storage/db.py +0 -0
  41. {dev_recall-0.2.2 → dev_recall-0.2.3}/recall/storage/vectors.py +0 -0
  42. {dev_recall-0.2.2 → dev_recall-0.2.3}/setup.cfg +0 -0
  43. {dev_recall-0.2.2 → dev_recall-0.2.3}/tests/test_collectors.py +0 -0
  44. {dev_recall-0.2.2 → dev_recall-0.2.3}/tests/test_enricher.py +0 -0
  45. {dev_recall-0.2.2 → dev_recall-0.2.3}/tests/test_query.py +0 -0
  46. {dev_recall-0.2.2 → dev_recall-0.2.3}/tests/test_session.py +0 -0
  47. {dev_recall-0.2.2 → dev_recall-0.2.3}/tests/test_storage.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dev-recall
3
- Version: 0.2.2
3
+ Version: 0.2.3
4
4
  Summary: Local-first developer memory layer
5
5
  License: MIT
6
6
  Keywords: developer-tools,memory,productivity,cli
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dev-recall
3
- Version: 0.2.2
3
+ Version: 0.2.3
4
4
  Summary: Local-first developer memory layer
5
5
  License: MIT
6
6
  Keywords: developer-tools,memory,productivity,cli
@@ -35,6 +35,9 @@ recall/query/timeparser.py
35
35
  recall/storage/__init__.py
36
36
  recall/storage/db.py
37
37
  recall/storage/vectors.py
38
+ recall/vscode-extension/package.json
39
+ recall/vscode-extension/tsconfig.json
40
+ recall/vscode-extension/src/extension.ts
38
41
  tests/test_collectors.py
39
42
  tests/test_enricher.py
40
43
  tests/test_query.py
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "dev-recall"
7
- version = "0.2.2"
7
+ version = "0.2.3"
8
8
  description = "Local-first developer memory layer"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -42,6 +42,13 @@ linux = [
42
42
  where = ["."]
43
43
  include = ["recall*"]
44
44
 
45
+ [tool.setuptools.package-data]
46
+ recall = ["vscode-extension/**"]
47
+
48
+ # ensures non-.py files are included
49
+ [tool.setuptools]
50
+ include-package-data = true
51
+
45
52
  [tool.ruff]
46
53
  line-length = 100
47
54
  target-version = "py310"
@@ -12,6 +12,7 @@ import time
12
12
  from datetime import datetime, timezone
13
13
  from pathlib import Path
14
14
  from typing import Optional
15
+ import importlib.resources as pkg_resources
15
16
 
16
17
  import click
17
18
  from rich.console import Console
@@ -66,7 +67,7 @@ _TYPE_STYLES = {
66
67
 
67
68
 
68
69
  @click.group()
69
- @click.version_option()
70
+ @click.version_option(package_name="dev-recall")
70
71
  def cli():
71
72
  """Recall — local-first developer memory layer."""
72
73
  pass
@@ -1006,8 +1007,7 @@ def vscode_install():
1006
1007
  """Build and install the Recall VS Code extension."""
1007
1008
  import shutil
1008
1009
 
1009
- ext_dir = Path(__file__).parent.parent / "vscode-extension"
1010
- # vsce produces name-version.vsix
1010
+ ext_dir = pkg_resources.files("recall") / "vscode-extension" # vsce produces name-version.vsix
1011
1011
  vsix_pattern = "recall-vscode-*.vsix"
1012
1012
 
1013
1013
  # Check for npm and code
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "recall-vscode",
3
+ "displayName": "Recall",
4
+ "description": "Developer memory layer — captures workspace activity for dev-recall",
5
+ "version": "0.1.0",
6
+ "publisher": "dev-recall",
7
+ "engines": {
8
+ "vscode": "^1.85.0"
9
+ },
10
+ "categories": ["Other"],
11
+ "activationEvents": ["onStartupFinished"],
12
+ "main": "./out/extension.js",
13
+ "contributes": {
14
+ "configuration": {
15
+ "title": "Recall",
16
+ "properties": {
17
+ "recall.port": {
18
+ "type": "number",
19
+ "default": 27182,
20
+ "description": "Port for the Recall daemon HTTP server"
21
+ },
22
+ "recall.enabled": {
23
+ "type": "boolean",
24
+ "default": true,
25
+ "description": "Enable/disable the Recall VS Code extension"
26
+ }
27
+ }
28
+ }
29
+ },
30
+ "scripts": {
31
+ "vscode:prepublish": "npm run compile",
32
+ "compile": "tsc -p ./",
33
+ "watch": "tsc -watch -p ./",
34
+ "package": "npm run compile && vsce package"
35
+ },
36
+ "devDependencies": {
37
+ "@types/vscode": "^1.85.0",
38
+ "@types/node": "^20.0.0",
39
+ "typescript": "^5.0.0",
40
+ "@vscode/vsce": "^3.25.0"
41
+ }
42
+ }
@@ -0,0 +1,238 @@
1
+ import * as vscode from 'vscode';
2
+ import * as path from 'path';
3
+ import * as fs from 'fs';
4
+
5
+ // ---------------------------------------------------------------------------
6
+ // Configuration
7
+ // ---------------------------------------------------------------------------
8
+
9
+ function getPort(): number {
10
+ // Try reading from config file first, then VS Code setting
11
+ const home = process.env.HOME || process.env.USERPROFILE || '';
12
+ // Cross-platform config path
13
+ let cfgFile: string;
14
+ if (process.platform === 'darwin') {
15
+ cfgFile = path.join(home, 'Library', 'Application Support', 'dev-recall', 'config.json');
16
+ } else if (process.platform === 'win32') {
17
+ cfgFile = path.join(process.env.APPDATA || '', 'dev-recall', 'config.json');
18
+ } else {
19
+ cfgFile = path.join(home, '.config', 'dev-recall', 'config.json');
20
+ }
21
+ try {
22
+ const raw = fs.readFileSync(cfgFile, 'utf-8');
23
+ const cfg = JSON.parse(raw);
24
+ if (cfg.daemon_port) { return cfg.daemon_port; }
25
+ } catch { /* ignore */ }
26
+
27
+ const vsCfg = vscode.workspace.getConfiguration('recall');
28
+ return vsCfg.get<number>('port', 27182);
29
+ }
30
+
31
+ function isEnabled(): boolean {
32
+ return vscode.workspace.getConfiguration('recall').get<boolean>('enabled', true);
33
+ }
34
+
35
+ // ---------------------------------------------------------------------------
36
+ // HTTP fire-and-forget
37
+ // ---------------------------------------------------------------------------
38
+
39
+ async function sendEvent(type: string, data: Record<string, unknown>): Promise<void> {
40
+ if (!isEnabled()) { return; }
41
+ const port = getPort();
42
+ const body = JSON.stringify({ type, ts: new Date().toISOString(), ...data });
43
+ try {
44
+ await fetch(`http://127.0.0.1:${port}/event`, {
45
+ method: 'POST',
46
+ headers: { 'Content-Type': 'application/json' },
47
+ body,
48
+ signal: AbortSignal.timeout(500),
49
+ });
50
+ } catch {
51
+ // Daemon may not be running — silently ignore
52
+ }
53
+ }
54
+
55
+ // ---------------------------------------------------------------------------
56
+ // Active time tracking
57
+ // ---------------------------------------------------------------------------
58
+
59
+ let lastActivityAt: number = Date.now();
60
+ let activeTimeInterval: ReturnType<typeof setInterval> | undefined;
61
+
62
+ function recordActivity(): void {
63
+ lastActivityAt = Date.now();
64
+ }
65
+
66
+ // ---------------------------------------------------------------------------
67
+ // Extension activation
68
+ // ---------------------------------------------------------------------------
69
+
70
+ export function activate(context: vscode.ExtensionContext): void {
71
+ // Report workspace open for each workspace folder
72
+ const folders = vscode.workspace.workspaceFolders;
73
+ if (folders) {
74
+ for (const folder of folders) {
75
+ sendEvent('workspace_open', { workspace: folder.uri.fsPath });
76
+ }
77
+ }
78
+
79
+ // Workspace folders changed
80
+ context.subscriptions.push(
81
+ vscode.workspace.onDidChangeWorkspaceFolders(e => {
82
+ for (const added of e.added) {
83
+ sendEvent('workspace_open', { workspace: added.uri.fsPath });
84
+ }
85
+ })
86
+ );
87
+
88
+ // File save
89
+ context.subscriptions.push(
90
+ vscode.workspace.onDidSaveTextDocument(doc => {
91
+ recordActivity();
92
+ const workspaceFolder = vscode.workspace.getWorkspaceFolder(doc.uri);
93
+ sendEvent('file_save', {
94
+ file: doc.uri.fsPath,
95
+ language: doc.languageId,
96
+ workspace: workspaceFolder?.uri.fsPath ?? '',
97
+ });
98
+ })
99
+ );
100
+
101
+ // Track activity for active_time reporting
102
+ context.subscriptions.push(
103
+ vscode.window.onDidChangeActiveTextEditor(recordActivity),
104
+ vscode.workspace.onDidChangeTextDocument(recordActivity),
105
+ );
106
+
107
+ // File lifecycle events
108
+ context.subscriptions.push(
109
+ vscode.workspace.onDidCreateFiles(e => {
110
+ recordActivity();
111
+ for (const uri of e.files) {
112
+ const workspaceFolder = vscode.workspace.getWorkspaceFolder(uri);
113
+ sendEvent('file_create', {
114
+ file: uri.fsPath,
115
+ filename: uri.fsPath.split('/').pop() ?? '',
116
+ workspace: workspaceFolder?.uri.fsPath ?? '',
117
+ });
118
+ }
119
+ }),
120
+ vscode.workspace.onDidDeleteFiles(e => {
121
+ recordActivity();
122
+ for (const uri of e.files) {
123
+ const workspaceFolder = vscode.workspace.getWorkspaceFolder(uri);
124
+ sendEvent('file_delete', {
125
+ file: uri.fsPath,
126
+ filename: uri.fsPath.split('/').pop() ?? '',
127
+ workspace: workspaceFolder?.uri.fsPath ?? '',
128
+ });
129
+ }
130
+ }),
131
+ vscode.workspace.onDidRenameFiles(e => {
132
+ recordActivity();
133
+ for (const { oldUri, newUri } of e.files) {
134
+ const workspaceFolder = vscode.workspace.getWorkspaceFolder(newUri);
135
+ sendEvent('file_rename', {
136
+ old_file: oldUri.fsPath,
137
+ new_file: newUri.fsPath,
138
+ old_filename: oldUri.fsPath.split('/').pop() ?? '',
139
+ new_filename: newUri.fsPath.split('/').pop() ?? '',
140
+ workspace: workspaceFolder?.uri.fsPath ?? '',
141
+ });
142
+ }
143
+ }),
144
+ );
145
+
146
+ // Debug session events
147
+ context.subscriptions.push(
148
+ vscode.debug.onDidStartDebugSession(session => {
149
+ const workspace = session.workspaceFolder?.uri.fsPath ?? '';
150
+ sendEvent('debug_session_start', {
151
+ name: session.name,
152
+ debug_type: session.type,
153
+ workspace,
154
+ });
155
+ }),
156
+ vscode.debug.onDidTerminateDebugSession(session => {
157
+ const workspace = session.workspaceFolder?.uri.fsPath ?? '';
158
+ sendEvent('debug_session_end', {
159
+ name: session.name,
160
+ debug_type: session.type,
161
+ workspace,
162
+ });
163
+ }),
164
+ );
165
+
166
+ // Test task events (tasks in the Test group)
167
+ context.subscriptions.push(
168
+ vscode.tasks.onDidStartTask(e => {
169
+ if (e.execution.task.group === vscode.TaskGroup.Test) {
170
+ const scope = e.execution.task.scope;
171
+ const workspace = (scope && typeof scope !== 'number')
172
+ ? (scope as vscode.WorkspaceFolder).uri.fsPath : '';
173
+ sendEvent('test_run_start', {
174
+ name: e.execution.task.name,
175
+ workspace,
176
+ });
177
+ }
178
+ }),
179
+ vscode.tasks.onDidEndTaskProcess(e => {
180
+ if (e.execution.task.group === vscode.TaskGroup.Test) {
181
+ const scope = e.execution.task.scope;
182
+ const workspace = (scope && typeof scope !== 'number')
183
+ ? (scope as vscode.WorkspaceFolder).uri.fsPath : '';
184
+ sendEvent('test_run_finish', {
185
+ name: e.execution.task.name,
186
+ exit_code: e.exitCode ?? 0,
187
+ workspace,
188
+ });
189
+ }
190
+ }),
191
+ );
192
+
193
+ // Report active time every 5 minutes
194
+ activeTimeInterval = setInterval(() => {
195
+ const secondsSinceActivity = (Date.now() - lastActivityAt) / 1000;
196
+ // Only report if user was active in the last 5 minutes
197
+ if (secondsSinceActivity < 300) {
198
+ const workspace = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath ?? '';
199
+ sendEvent('active_time', {
200
+ workspace,
201
+ seconds_active: 300 - secondsSinceActivity,
202
+ });
203
+ }
204
+ }, 5 * 60 * 1000);
205
+ }
206
+
207
+ // ---------------------------------------------------------------------------
208
+ // Extension deactivation
209
+ // ---------------------------------------------------------------------------
210
+
211
+ export function deactivate(): void {
212
+ if (activeTimeInterval) {
213
+ clearInterval(activeTimeInterval);
214
+ }
215
+ const folders = vscode.workspace.workspaceFolders;
216
+ if (folders) {
217
+ for (const folder of folders) {
218
+ // Fire-and-forget — deactivation is synchronous, best effort
219
+ const port = getPort();
220
+ const body = JSON.stringify({
221
+ type: 'workspace_close',
222
+ ts: new Date().toISOString(),
223
+ workspace: folder.uri.fsPath,
224
+ });
225
+ try {
226
+ // Synchronous best-effort using Node.js http module
227
+ const http = require('http');
228
+ const req = http.request({
229
+ hostname: '127.0.0.1', port, path: '/event', method: 'POST',
230
+ headers: { 'Content-Type': 'application/json' },
231
+ timeout: 200,
232
+ });
233
+ req.write(body);
234
+ req.end();
235
+ } catch { /* ignore */ }
236
+ }
237
+ }
238
+ }
@@ -0,0 +1,14 @@
1
+ {
2
+ "compilerOptions": {
3
+ "module": "commonjs",
4
+ "target": "ES2020",
5
+ "outDir": "./out",
6
+ "lib": ["ES2020"],
7
+ "sourceMap": true,
8
+ "rootDir": "./src",
9
+ "strict": true,
10
+ "esModuleInterop": true,
11
+ "skipLibCheck": true
12
+ },
13
+ "exclude": ["node_modules", ".vscode-test"]
14
+ }
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes