vault-go 0.29.0 → 0.29.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 +2 -0
- package/dist/crystal-memory-mirror.js +9 -1
- package/dist/hooks.js +24 -6
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -150,6 +150,8 @@ Capture and recall: `vault_go_event`, `vault_go_remember`, `vault_go_forget`, `v
|
|
|
150
150
|
|
|
151
151
|
Projects are matched by path first and then by repository: vault-go reads the checkout's `origin` remote, normalizes it to `host/owner/repo` and records it as the project's `repoKey`. A clone on another machine or user joins the oldest project with the same `repoKey` instead of creating a new one, and projects created before this are backfilled the first time a capture matches them by path.
|
|
152
152
|
|
|
153
|
+
A folder without git joins the nearest existing project above it instead of becoming a project of its own; a git checkout always keeps its own project.
|
|
154
|
+
|
|
153
155
|
Read tools (`vault_go_search`, `vault_go_search_index`, `vault_go_feed`, `vault_go_retrieve` and query-anchored `vault_go_timeline`) are scoped to the project of the MCP server's working directory when no `projectId` is given; a git worktree maps to its main checkout. Pass `scope: "account"` to search every project of the account. Outside a known project they fall back to the account, and no project is created. Memories marked private stay out of search and feed results unless `includePrivate: true` is set.
|
|
154
156
|
|
|
155
157
|
`vault_go_retrieve` lets the central memory engine choose a bounded retrieval path while every explicit retrieval tool remains available. `vault_go_decision_status` reports sanitized rollout/circuit state. Jev and its credential remain in the engine; a healthy deployment does not by itself prove provider availability or decision quality. `vault_go_decide` sends a caller-authored state plus up to 8 typed questions (`noul`, `choice`, `score`) to the central Jev and returns probabilities; it runs only in `full` rollout, one call at a time, refuses secrets, e-mails, identifiers, URLs and absolute local paths before anything leaves Vault, and persists nothing. The caller still owns the decision.
|
|
@@ -23,7 +23,15 @@ export async function resolveCrystalProjectFolder(cloud, projectId) {
|
|
|
23
23
|
if (!Array.isArray(projects))
|
|
24
24
|
return null;
|
|
25
25
|
const found = projects.find((item) => item && typeof item === 'object' && item.id === projectId);
|
|
26
|
-
|
|
26
|
+
const folder = crystalProjectFolder(found);
|
|
27
|
+
if (!folder)
|
|
28
|
+
return null;
|
|
29
|
+
// Why: same-named projects used to share one Crystal folder and mix their
|
|
30
|
+
// memories. The oldest keeps the plain name (existing folders stay put); newer
|
|
31
|
+
// namesakes get a stable suffix from their id. Projects arrive newest first.
|
|
32
|
+
const namesakes = projects.filter((item) => crystalProjectFolder(item)?.toLowerCase() === folder.toLowerCase());
|
|
33
|
+
const oldest = namesakes.at(-1);
|
|
34
|
+
return oldest?.id === projectId ? folder : `${folder}-${projectId.slice(0, 8)}`;
|
|
27
35
|
}
|
|
28
36
|
export async function mirrorCrystalMemory(input) {
|
|
29
37
|
if (!shouldMirrorCrystalMemory(input.job))
|
package/dist/hooks.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { redact } from './capture-privacy.js';
|
|
2
2
|
export { redact } from './capture-privacy.js';
|
|
3
3
|
import { createHash, randomUUID } from "node:crypto";
|
|
4
|
-
import { basename, dirname, isAbsolute, relative, resolve } from "node:path";
|
|
4
|
+
import { basename, dirname, isAbsolute, relative, resolve, sep } from "node:path";
|
|
5
5
|
import { existsSync, readFileSync, realpathSync, statSync } from "node:fs";
|
|
6
6
|
import { applyCustomModeContext } from './custom-modes.js';
|
|
7
7
|
import { VaultCloudClient } from "./cloud.js";
|
|
@@ -67,7 +67,7 @@ function projectRoots(workspace) {
|
|
|
67
67
|
return fallback;
|
|
68
68
|
}
|
|
69
69
|
}
|
|
70
|
-
function matchWorkspaceProject(projects, roots, key) {
|
|
70
|
+
function matchWorkspaceProject(projects, roots, key, inGit = true) {
|
|
71
71
|
if (!Array.isArray(projects))
|
|
72
72
|
throw new Error("Resposta de projetos inválida");
|
|
73
73
|
const byPath = roots.map((cwd) => projects.find((item) => item &&
|
|
@@ -75,16 +75,34 @@ function matchWorkspaceProject(projects, roots, key) {
|
|
|
75
75
|
typeof item.rootPath === "string" &&
|
|
76
76
|
Boolean(String(item.rootPath).trim()) &&
|
|
77
77
|
resolvedPath(String(item.rootPath)) === cwd)).find(Boolean);
|
|
78
|
-
if (byPath
|
|
78
|
+
if (byPath)
|
|
79
79
|
return byPath;
|
|
80
80
|
// Why: a clone on another machine or user shares the repository, not the path.
|
|
81
81
|
// Projects arrive newest first; the oldest one with this key is the canonical one.
|
|
82
|
-
|
|
82
|
+
const byRepo = key
|
|
83
|
+
? projects.filter((item) => item && typeof item === "object" && item.repoKey === key).at(-1)
|
|
84
|
+
: undefined;
|
|
85
|
+
if (byRepo || inGit)
|
|
86
|
+
return byRepo;
|
|
87
|
+
// Why: a folder without git used to become its own project, splitting memories
|
|
88
|
+
// between an umbrella folder and its subfolders. Prefer the nearest existing ancestor.
|
|
89
|
+
const cwd = roots[0];
|
|
90
|
+
return projects
|
|
91
|
+
.filter((item) => {
|
|
92
|
+
if (!item || typeof item !== "object" || typeof item.rootPath !== "string")
|
|
93
|
+
return false;
|
|
94
|
+
const path = String(item.rootPath).trim();
|
|
95
|
+
if (!path)
|
|
96
|
+
return false;
|
|
97
|
+
const ancestor = relative(resolvedPath(path), cwd);
|
|
98
|
+
return Boolean(ancestor) && ancestor !== ".." && !ancestor.startsWith(`..${sep}`) && !isAbsolute(ancestor);
|
|
99
|
+
})
|
|
100
|
+
.sort((a, b) => resolvedPath(String(b.rootPath)).length - resolvedPath(String(a.rootPath)).length)[0];
|
|
83
101
|
}
|
|
84
102
|
/** The existing project for a working directory (worktrees map to their main checkout); never creates one. */
|
|
85
103
|
export async function findWorkspaceProject(cloud, cwd) {
|
|
86
104
|
const workspace = root(cwd);
|
|
87
|
-
return matchWorkspaceProject(await cloud.projects(), projectRoots(workspace), repoKey(workspace));
|
|
105
|
+
return matchWorkspaceProject(await cloud.projects(), projectRoots(workspace), repoKey(workspace), existsSync(resolve(workspace, ".git")));
|
|
88
106
|
}
|
|
89
107
|
function canonicalFile(file, workspace, project) {
|
|
90
108
|
const absolute = resolve(workspace, file);
|
|
@@ -194,7 +212,7 @@ export async function executeHook(adapter, event, value, cloud = new VaultCloudC
|
|
|
194
212
|
if (!Array.isArray(projects))
|
|
195
213
|
throw new Error("Resposta de projetos inválida");
|
|
196
214
|
const key = repoKey(workspace);
|
|
197
|
-
let project = matchWorkspaceProject(projects, roots, key);
|
|
215
|
+
let project = matchWorkspaceProject(projects, roots, key, existsSync(resolve(workspace, ".git")));
|
|
198
216
|
const cwd = project ? resolvedPath(String(project.rootPath)) : roots[0];
|
|
199
217
|
if (!project && reading)
|
|
200
218
|
return hookOutput(event, "", adapter);
|