pi-automem-bridge 0.2.0 → 0.2.2
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/README.md +75 -29
- package/examples/config.advanced.json +61 -59
- package/package.json +61 -58
- package/src/config.ts +262 -251
- package/src/mcp-client.ts +401 -361
- package/src/project-detect.ts +96 -94
- package/src/recall.ts +283 -254
- package/src/tools/memory-tools.ts +307 -307
- package/src/tools/relationship-tools.ts +121 -114
- package/src/write-policy.ts +148 -142
package/src/project-detect.ts
CHANGED
|
@@ -1,94 +1,96 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* project-detect.ts - Infer the current project from cwd, git remote, and prompt text.
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { existsSync, readFileSync } from "node:fs";
|
|
6
|
-
import { resolve } from "node:path";
|
|
7
|
-
import type { AutoMemConfig } from "./config";
|
|
8
|
-
|
|
9
|
-
export interface ProjectDetection {
|
|
10
|
-
projectTag: string | null;
|
|
11
|
-
projectLabel: string | null;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
function detectFromGit(cwd: string, gitRepoToTag: Record<string, string>): ProjectDetection {
|
|
15
|
-
// Walk up the directory tree to handle running from a subdirectory of a repo
|
|
16
|
-
let dir = cwd;
|
|
17
|
-
while (true) {
|
|
18
|
-
const gitConfigPath = resolve(dir, ".git", "config");
|
|
19
|
-
if (existsSync(gitConfigPath)) {
|
|
20
|
-
try {
|
|
21
|
-
const gitConfig = readFileSync(gitConfigPath, "utf8");
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
1
|
+
/**
|
|
2
|
+
* project-detect.ts - Infer the current project from cwd, git remote, and prompt text.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
6
|
+
import { resolve } from "node:path";
|
|
7
|
+
import type { AutoMemConfig } from "./config";
|
|
8
|
+
|
|
9
|
+
export interface ProjectDetection {
|
|
10
|
+
projectTag: string | null;
|
|
11
|
+
projectLabel: string | null;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function detectFromGit(cwd: string, gitRepoToTag: Record<string, string>): ProjectDetection {
|
|
15
|
+
// Walk up the directory tree to handle running from a subdirectory of a repo
|
|
16
|
+
let dir = cwd;
|
|
17
|
+
while (true) {
|
|
18
|
+
const gitConfigPath = resolve(dir, ".git", "config");
|
|
19
|
+
if (existsSync(gitConfigPath)) {
|
|
20
|
+
try {
|
|
21
|
+
const gitConfig = readFileSync(gitConfigPath, "utf8");
|
|
22
|
+
// Examine every remote url, not just the first — a repo's configured
|
|
23
|
+
// tag may match a non-first remote (e.g. `upstream`).
|
|
24
|
+
const remoteUrls = Array.from(gitConfig.matchAll(/^\s*url\s*=\s*(.+)$/gim))
|
|
25
|
+
.map(function(m) { return m[1].trim().toLowerCase(); });
|
|
26
|
+
const keys = Object.keys(gitRepoToTag);
|
|
27
|
+
for (let u = 0; u < remoteUrls.length; u++) {
|
|
28
|
+
for (let i = 0; i < keys.length; i++) {
|
|
29
|
+
const substring = keys[i].toLowerCase();
|
|
30
|
+
if (remoteUrls[u].indexOf(substring) !== -1) {
|
|
31
|
+
const tag = gitRepoToTag[keys[i]];
|
|
32
|
+
return { projectTag: tag, projectLabel: tag.replace(/^[^:]+:/, "") };
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
} catch (_e) {
|
|
37
|
+
// ignore unreadable config
|
|
38
|
+
}
|
|
39
|
+
// Found .git but no matching remote — stop traversing
|
|
40
|
+
break;
|
|
41
|
+
}
|
|
42
|
+
const parent = resolve(dir, "..");
|
|
43
|
+
if (parent === dir) break; // reached filesystem root
|
|
44
|
+
dir = parent;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return { projectTag: null, projectLabel: null };
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function detectFromFolder(cwd: string, folderTags: Record<string, string[]>): ProjectDetection {
|
|
51
|
+
const normalizedFolderTags: Record<string, string[]> = {};
|
|
52
|
+
const keys = Object.keys(folderTags);
|
|
53
|
+
for (let i = 0; i < keys.length; i++) {
|
|
54
|
+
normalizedFolderTags[keys[i].toLowerCase()] = folderTags[keys[i]];
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const parts = cwd.split(/[\\/]/);
|
|
58
|
+
for (let i = 0; i < parts.length; i++) {
|
|
59
|
+
const lower = parts[i].toLowerCase();
|
|
60
|
+
if (normalizedFolderTags[lower] && normalizedFolderTags[lower].length > 0) {
|
|
61
|
+
const tag = normalizedFolderTags[lower][0];
|
|
62
|
+
return { projectTag: tag, projectLabel: lower };
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return { projectTag: null, projectLabel: null };
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function detectFromPrompt(prompt: string, gitRepoToTag: Record<string, string>): ProjectDetection {
|
|
69
|
+
const lower = prompt.toLowerCase();
|
|
70
|
+
const keys = Object.keys(gitRepoToTag);
|
|
71
|
+
for (let i = 0; i < keys.length; i++) {
|
|
72
|
+
if (lower.indexOf(keys[i].toLowerCase()) !== -1) {
|
|
73
|
+
const tag = gitRepoToTag[keys[i]];
|
|
74
|
+
return { projectTag: tag, projectLabel: tag.replace(/^[^:]+:/, "") };
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return { projectTag: null, projectLabel: null };
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export function detectProject(
|
|
81
|
+
cwd: string,
|
|
82
|
+
prompt: string,
|
|
83
|
+
config: AutoMemConfig,
|
|
84
|
+
): ProjectDetection {
|
|
85
|
+
if (!config.projectDetection.enabled) {
|
|
86
|
+
return { projectTag: null, projectLabel: null };
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const gitResult = detectFromGit(cwd, config.projectDetection.gitRepoToTag);
|
|
90
|
+
if (gitResult.projectTag) return gitResult;
|
|
91
|
+
|
|
92
|
+
const folderResult = detectFromFolder(cwd, config.projectDetection.folderTags);
|
|
93
|
+
if (folderResult.projectTag) return folderResult;
|
|
94
|
+
|
|
95
|
+
return detectFromPrompt(prompt, config.projectDetection.gitRepoToTag);
|
|
96
|
+
}
|