dev-recall 0.2.1__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.1 → dev_recall-0.2.3}/PKG-INFO +3 -2
  2. {dev_recall-0.2.1 → dev_recall-0.2.3}/README.md +2 -1
  3. {dev_recall-0.2.1 → dev_recall-0.2.3}/dev_recall.egg-info/PKG-INFO +3 -2
  4. {dev_recall-0.2.1 → dev_recall-0.2.3}/dev_recall.egg-info/SOURCES.txt +3 -0
  5. {dev_recall-0.2.1 → dev_recall-0.2.3}/pyproject.toml +8 -1
  6. {dev_recall-0.2.1 → dev_recall-0.2.3}/recall/cli.py +97 -2
  7. dev_recall-0.2.3/recall/vscode-extension/package.json +42 -0
  8. dev_recall-0.2.3/recall/vscode-extension/src/extension.ts +238 -0
  9. dev_recall-0.2.3/recall/vscode-extension/tsconfig.json +14 -0
  10. {dev_recall-0.2.1 → dev_recall-0.2.3}/dev_recall.egg-info/dependency_links.txt +0 -0
  11. {dev_recall-0.2.1 → dev_recall-0.2.3}/dev_recall.egg-info/entry_points.txt +0 -0
  12. {dev_recall-0.2.1 → dev_recall-0.2.3}/dev_recall.egg-info/requires.txt +0 -0
  13. {dev_recall-0.2.1 → dev_recall-0.2.3}/dev_recall.egg-info/top_level.txt +0 -0
  14. {dev_recall-0.2.1 → dev_recall-0.2.3}/recall/__init__.py +0 -0
  15. {dev_recall-0.2.1 → dev_recall-0.2.3}/recall/_hooks.py +0 -0
  16. {dev_recall-0.2.1 → dev_recall-0.2.3}/recall/collectors/__init__.py +0 -0
  17. {dev_recall-0.2.1 → dev_recall-0.2.3}/recall/collectors/ai_chat.py +0 -0
  18. {dev_recall-0.2.1 → dev_recall-0.2.3}/recall/collectors/containers.py +0 -0
  19. {dev_recall-0.2.1 → dev_recall-0.2.3}/recall/collectors/git.py +0 -0
  20. {dev_recall-0.2.1 → dev_recall-0.2.3}/recall/collectors/linux_process.py +0 -0
  21. {dev_recall-0.2.1 → dev_recall-0.2.3}/recall/collectors/linux_session.py +0 -0
  22. {dev_recall-0.2.1 → dev_recall-0.2.3}/recall/collectors/linux_window.py +0 -0
  23. {dev_recall-0.2.1 → dev_recall-0.2.3}/recall/collectors/shell.py +0 -0
  24. {dev_recall-0.2.1 → dev_recall-0.2.3}/recall/collectors/vscode.py +0 -0
  25. {dev_recall-0.2.1 → dev_recall-0.2.3}/recall/config.py +0 -0
  26. {dev_recall-0.2.1 → dev_recall-0.2.3}/recall/daemon.py +0 -0
  27. {dev_recall-0.2.1 → dev_recall-0.2.3}/recall/daemon_main.py +0 -0
  28. {dev_recall-0.2.1 → dev_recall-0.2.3}/recall/mcp_server.py +0 -0
  29. {dev_recall-0.2.1 → dev_recall-0.2.3}/recall/models.py +0 -0
  30. {dev_recall-0.2.1 → dev_recall-0.2.3}/recall/processor/__init__.py +0 -0
  31. {dev_recall-0.2.1 → dev_recall-0.2.3}/recall/processor/embedder.py +0 -0
  32. {dev_recall-0.2.1 → dev_recall-0.2.3}/recall/processor/enricher.py +0 -0
  33. {dev_recall-0.2.1 → dev_recall-0.2.3}/recall/processor/session.py +0 -0
  34. {dev_recall-0.2.1 → dev_recall-0.2.3}/recall/query/__init__.py +0 -0
  35. {dev_recall-0.2.1 → dev_recall-0.2.3}/recall/query/context.py +0 -0
  36. {dev_recall-0.2.1 → dev_recall-0.2.3}/recall/query/llm.py +0 -0
  37. {dev_recall-0.2.1 → dev_recall-0.2.3}/recall/query/retriever.py +0 -0
  38. {dev_recall-0.2.1 → dev_recall-0.2.3}/recall/query/timeparser.py +0 -0
  39. {dev_recall-0.2.1 → dev_recall-0.2.3}/recall/storage/__init__.py +0 -0
  40. {dev_recall-0.2.1 → dev_recall-0.2.3}/recall/storage/db.py +0 -0
  41. {dev_recall-0.2.1 → dev_recall-0.2.3}/recall/storage/vectors.py +0 -0
  42. {dev_recall-0.2.1 → dev_recall-0.2.3}/setup.cfg +0 -0
  43. {dev_recall-0.2.1 → dev_recall-0.2.3}/tests/test_collectors.py +0 -0
  44. {dev_recall-0.2.1 → dev_recall-0.2.3}/tests/test_enricher.py +0 -0
  45. {dev_recall-0.2.1 → dev_recall-0.2.3}/tests/test_query.py +0 -0
  46. {dev_recall-0.2.1 → dev_recall-0.2.3}/tests/test_session.py +0 -0
  47. {dev_recall-0.2.1 → 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.1
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
@@ -76,6 +76,7 @@ source .zshrc # or .bashrc
76
76
  | `recall privacy ignore --cmd "pattern"` | Add a privacy filter |
77
77
  | `recall daemon start/stop/status/logs` | Manage the background daemon |
78
78
  | `recall mcp-serve` | Start MCP server (for Claude Code / Copilot) |
79
+ | `recall vscode install` | Build and install VS Code extension |
79
80
 
80
81
  ---
81
82
 
@@ -109,7 +110,7 @@ source ~/.config/dev-recall/hook.zsh
109
110
  ### VS Code activity
110
111
  Install the extension:
111
112
  ```bash
112
- code --install-extension recall.recall-vscode
113
+ recall vscode install
113
114
  ```
114
115
 
115
116
  ### AI chat sessions
@@ -47,6 +47,7 @@ source .zshrc # or .bashrc
47
47
  | `recall privacy ignore --cmd "pattern"` | Add a privacy filter |
48
48
  | `recall daemon start/stop/status/logs` | Manage the background daemon |
49
49
  | `recall mcp-serve` | Start MCP server (for Claude Code / Copilot) |
50
+ | `recall vscode install` | Build and install VS Code extension |
50
51
 
51
52
  ---
52
53
 
@@ -80,7 +81,7 @@ source ~/.config/dev-recall/hook.zsh
80
81
  ### VS Code activity
81
82
  Install the extension:
82
83
  ```bash
83
- code --install-extension recall.recall-vscode
84
+ recall vscode install
84
85
  ```
85
86
 
86
87
  ### AI chat sessions
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dev-recall
3
- Version: 0.2.1
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
@@ -76,6 +76,7 @@ source .zshrc # or .bashrc
76
76
  | `recall privacy ignore --cmd "pattern"` | Add a privacy filter |
77
77
  | `recall daemon start/stop/status/logs` | Manage the background daemon |
78
78
  | `recall mcp-serve` | Start MCP server (for Claude Code / Copilot) |
79
+ | `recall vscode install` | Build and install VS Code extension |
79
80
 
80
81
  ---
81
82
 
@@ -109,7 +110,7 @@ source ~/.config/dev-recall/hook.zsh
109
110
  ### VS Code activity
110
111
  Install the extension:
111
112
  ```bash
112
- code --install-extension recall.recall-vscode
113
+ recall vscode install
113
114
  ```
114
115
 
115
116
  ### AI chat sessions
@@ -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.1"
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
@@ -126,7 +127,12 @@ def init(yes: bool):
126
127
 
127
128
  # Step 6: VS Code extension hint
128
129
  _print_step(6, steps[5])
129
- console.print(" → Run: [cyan]code --install-extension recall.recall-vscode[/cyan] (optional)")
130
+ if yes or click.confirm(" → Would you like to build and install the VS Code extension now?", default=False):
131
+ # We can call the function directly or via a new command
132
+ ctx = click.get_current_context()
133
+ ctx.invoke(vscode_install)
134
+ else:
135
+ console.print(" → Skip. Run manually later: [cyan]recall vscode install[/cyan]")
130
136
 
131
137
  console.print()
132
138
  console.print("[bold green]Done. Recall is running.[/bold green]")
@@ -985,6 +991,95 @@ def mcp_serve():
985
991
  run_mcp_server()
986
992
 
987
993
 
994
+ # ---------------------------------------------------------------------------
995
+ # vscode
996
+ # ---------------------------------------------------------------------------
997
+
998
+
999
+ @cli.group()
1000
+ def vscode():
1001
+ """Manage the Recall VS Code extension."""
1002
+ pass
1003
+
1004
+
1005
+ @vscode.command("install")
1006
+ def vscode_install():
1007
+ """Build and install the Recall VS Code extension."""
1008
+ import shutil
1009
+
1010
+ ext_dir = pkg_resources.files("recall") / "vscode-extension" # vsce produces name-version.vsix
1011
+ vsix_pattern = "recall-vscode-*.vsix"
1012
+
1013
+ # Check for npm and code
1014
+ if not shutil.which("npm"):
1015
+ console.print("[red]npm not found. Install Node.js to build the VS Code extension.[/red]")
1016
+ return
1017
+ if not shutil.which("code"):
1018
+ console.print("[red]'code' command not found. Make sure VS Code is in your PATH.[/red]")
1019
+ return
1020
+
1021
+ # Install dependencies and build
1022
+ console.print("[dim]Installing extension dependencies...[/dim]")
1023
+ result = subprocess.run(
1024
+ ["npm", "install"],
1025
+ cwd=ext_dir,
1026
+ capture_output=True,
1027
+ text=True,
1028
+ )
1029
+ if result.returncode != 0:
1030
+ console.print(f"[red]npm install failed:[/red] {result.stderr}")
1031
+ return
1032
+
1033
+ console.print("[dim]Compiling TypeScript...[/dim]")
1034
+ result = subprocess.run(
1035
+ ["npm", "run", "compile"],
1036
+ cwd=ext_dir,
1037
+ capture_output=True,
1038
+ text=True,
1039
+ )
1040
+ if result.returncode != 0:
1041
+ console.print(f"[red]TypeScript compilation failed:[/red] {result.stderr}")
1042
+ return
1043
+
1044
+ console.print("[dim]Packaging extension...[/dim]")
1045
+ # Remove old vsix files first to avoid ambiguity
1046
+ for old_vsix in ext_dir.glob("*.vsix"):
1047
+ old_vsix.unlink()
1048
+
1049
+ result = subprocess.run(
1050
+ ["npx", "@vscode/vsce", "package"],
1051
+ cwd=ext_dir,
1052
+ capture_output=True,
1053
+ text=True,
1054
+ )
1055
+ if result.returncode != 0:
1056
+ console.print(f"[red]vsce package failed:[/red] {result.stderr}")
1057
+ return
1058
+
1059
+ # Find the generated .vsix file
1060
+ vsix_files = list(ext_dir.glob(vsix_pattern))
1061
+ if not vsix_files:
1062
+ console.print("[red]No .vsix file generated (looked for recall-vscode-*.vsix).[/red]")
1063
+ return
1064
+
1065
+ vsix_path = vsix_files[0]
1066
+ console.print(f" → [green]✓[/green] Generated {vsix_path.name}")
1067
+
1068
+ # Install the extension
1069
+ console.print(f"[dim]Installing extension via 'code --install-extension'...[/dim]")
1070
+ result = subprocess.run(
1071
+ ["code", "--install-extension", str(vsix_path)],
1072
+ capture_output=True,
1073
+ text=True,
1074
+ )
1075
+ if result.returncode != 0:
1076
+ console.print(f"[red]Extension installation failed:[/red] {result.stderr}")
1077
+ return
1078
+
1079
+ console.print("[green]✓ VS Code extension installed successfully.[/green]")
1080
+ console.print(" → Restart VS Code (or run 'Developer: Reload Window') to activate.")
1081
+
1082
+
988
1083
  # ---------------------------------------------------------------------------
989
1084
  # Helpers
990
1085
  # ---------------------------------------------------------------------------
@@ -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