@openparachute/vault 0.7.6 → 0.7.7
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 +16 -16
- package/core/src/attachment/policy.test.ts +7 -0
- package/core/src/attachment/policy.ts +9 -0
- package/core/src/attachment-tickets-tool.test.ts +15 -0
- package/core/src/conformance.test.ts +78 -0
- package/core/src/conformance.ts +34 -5
- package/core/src/connection-pragmas.test.ts +27 -1
- package/core/src/core.test.ts +88 -3
- package/core/src/cursor.ts +2 -0
- package/core/src/do-param-cap.test.ts +167 -0
- package/core/src/lede.test.ts +60 -0
- package/core/src/mcp-manifest.ts +15 -1
- package/core/src/mcp.ts +37 -5
- package/core/src/notes.ts +120 -48
- package/core/src/query-operators.ts +87 -5
- package/core/src/query-warnings.ts +11 -3
- package/core/src/schema.ts +32 -0
- package/core/src/seed-packs.ts +74 -5
- package/core/src/sql-in.ts +32 -2
- package/core/src/store.ts +16 -49
- package/core/src/test-preload.ts +48 -3
- package/core/src/types.ts +13 -1
- package/core/src/wikilinks.test.ts +57 -0
- package/core/src/wikilinks.ts +63 -29
- package/package.json +1 -1
- package/src/attachment-tickets.test.ts +62 -0
- package/src/attachment-tickets.ts +2 -2
- package/src/cli.ts +36 -8
- package/src/config.ts +34 -1
- package/src/contract-honest-queries.test.ts +33 -1
- package/src/contract-search.test.ts +47 -0
- package/src/embedding/select.ts +16 -3
- package/src/live-match.test.ts +8 -0
- package/src/live-match.ts +15 -0
- package/src/mcp-http.test.ts +12 -0
- package/src/mcp-http.ts +1 -0
- package/src/mcp-tools.ts +51 -17
- package/src/mirror-routes.test.ts +22 -31
- package/src/onboarding-seed.test.ts +68 -0
- package/src/routes.ts +88 -25
- package/src/routing.test.ts +24 -0
- package/src/routing.ts +2 -0
- package/src/subscriptions.ts +18 -2
- package/src/tag-scope-note-tags.test.ts +476 -0
- package/src/tag-scope.ts +73 -5
- package/src/test-home-isolation.test.ts +137 -0
- package/src/test-support/spawn.ts +12 -0
- package/src/transcription/download.test.ts +187 -1
- package/src/transcription/download.ts +149 -2
- package/src/transcription/install-python.test.ts +23 -2
- package/src/transcription/install-python.ts +13 -4
- package/src/vault.test.ts +39 -4
- package/src/version.test.ts +8 -0
- package/src/ws-server.ts +12 -2
package/src/vault.test.ts
CHANGED
|
@@ -238,6 +238,14 @@ describe("BunStore", async () => {
|
|
|
238
238
|
expect(results.map((n) => n.path)).toContain("Projects/Parachute/README");
|
|
239
239
|
expect(results.map((n) => n.path)).toContain("Projects/Parachute/Notes");
|
|
240
240
|
});
|
|
241
|
+
|
|
242
|
+
test("queryNotes excludePathPrefix drops matching paths (vault#628)", async () => {
|
|
243
|
+
await store.createNote("user", { path: "Projects/a" });
|
|
244
|
+
await store.createNote("sys", { path: ".parachute/notes/settings" });
|
|
245
|
+
await store.createNote("bare");
|
|
246
|
+
const results = await store.queryNotes({ excludePathPrefix: [".parachute/"] });
|
|
247
|
+
expect(results.map((n) => n.content).sort()).toEqual(["bare", "user"]);
|
|
248
|
+
});
|
|
241
249
|
});
|
|
242
250
|
|
|
243
251
|
describe("metadata", async () => {
|
|
@@ -1877,11 +1885,16 @@ describe("scoped MCP wrapper", async () => {
|
|
|
1877
1885
|
// note, so it's not a schema-shape indicator.)
|
|
1878
1886
|
const serialized = JSON.stringify(result);
|
|
1879
1887
|
expect(serialized).not.toContain("fizzbuzz");
|
|
1880
|
-
// The tag NAME must be gone from validation_status specifically.
|
|
1881
|
-
//
|
|
1882
|
-
//
|
|
1883
|
-
//
|
|
1888
|
+
// The tag NAME must be gone from validation_status specifically.
|
|
1889
|
+
// (Historical note: this assertion used to be narrowed to
|
|
1890
|
+
// `validation_status` because the name STILL appeared in the note's
|
|
1891
|
+
// `.tags` array — pre-existing scoped-read behavior, filed as vault#568
|
|
1892
|
+
// and out of scope for fix 3. #568 has since scrubbed `.tags` too, so
|
|
1893
|
+
// the name is now absent from the whole response; the narrow assertion
|
|
1894
|
+
// is kept as-is because it pins THIS fix's field specifically.
|
|
1895
|
+
// `tag-scope-note-tags.test.ts` owns the `.tags` coverage.)
|
|
1884
1896
|
expect(JSON.stringify(result.validation_status)).not.toContain("project-manhattan");
|
|
1897
|
+
expect(result.tags).toEqual(["work"]);
|
|
1885
1898
|
|
|
1886
1899
|
// The in-scope tag's own warning DOES survive.
|
|
1887
1900
|
const vs = result.validation_status;
|
|
@@ -2496,6 +2509,20 @@ describe("HTTP /notes", async () => {
|
|
|
2496
2509
|
expect(body.preview).toBe("hello");
|
|
2497
2510
|
});
|
|
2498
2511
|
|
|
2512
|
+
test("GET /notes?exclude_path_prefix=.parachute/ drops system-space (vault#628)", async () => {
|
|
2513
|
+
await store.createNote("user", { path: "Projects/a" });
|
|
2514
|
+
await store.createNote("sys", { path: ".parachute/notes/settings" });
|
|
2515
|
+
await store.createNote("bare");
|
|
2516
|
+
const res = await handleNotes(
|
|
2517
|
+
mkReq("GET", "/notes?exclude_path_prefix=.parachute/&include_content=true"),
|
|
2518
|
+
store,
|
|
2519
|
+
"",
|
|
2520
|
+
);
|
|
2521
|
+
expect(res.status).toBe(200);
|
|
2522
|
+
const body = await res.json() as any[];
|
|
2523
|
+
expect(body.map((n) => n.content).sort()).toEqual(["bare", "user"]);
|
|
2524
|
+
});
|
|
2525
|
+
|
|
2499
2526
|
test("GET /notes?include_metadata=false strips metadata from list", async () => {
|
|
2500
2527
|
await store.createNote("a", { tags: ["m"], metadata: { summary: "hello", status: "ok" } });
|
|
2501
2528
|
await store.createNote("b", { tags: ["m"], metadata: { summary: "world" } });
|
|
@@ -2530,6 +2557,14 @@ describe("HTTP /notes", async () => {
|
|
|
2530
2557
|
expect(body.metadata).toEqual({ summary: "s" });
|
|
2531
2558
|
});
|
|
2532
2559
|
|
|
2560
|
+
test("GET /notes?include_metadata=nonexistent keeps metadata: {} (vault#600)", async () => {
|
|
2561
|
+
await store.createNote("a", { tags: ["m600"], metadata: { summary: "hello" } });
|
|
2562
|
+
const res = await handleNotes(mkReq("GET", "/notes?tag=m600&include_metadata=nonexistent"), store, "");
|
|
2563
|
+
const body = await res.json() as any[];
|
|
2564
|
+
expect(body).toHaveLength(1);
|
|
2565
|
+
expect(body[0]).toHaveProperty("metadata", {});
|
|
2566
|
+
});
|
|
2567
|
+
|
|
2533
2568
|
test("GET /notes/:id?expand_links=true inlines wikilink content", async () => {
|
|
2534
2569
|
await store.createNote("target body", { path: "Target" });
|
|
2535
2570
|
await store.createNote("see [[Target]]", { id: "src", path: "Src" });
|
package/src/version.test.ts
CHANGED
|
@@ -21,6 +21,14 @@ function runCli(args: string[]): {
|
|
|
21
21
|
cmd: ["bun", CLI, ...args],
|
|
22
22
|
stdout: "pipe",
|
|
23
23
|
stderr: "pipe",
|
|
24
|
+
// `env` is NOT optional here. Bun hands a child the environ the parent
|
|
25
|
+
// process *started* with, not the live `process.env` — so runtime
|
|
26
|
+
// assignments never reach it, including the temp PARACHUTE_HOME that
|
|
27
|
+
// `core/src/test-preload.ts` sets for the suite. Spawn without this and
|
|
28
|
+
// the child resolves its parachute home to the developer's real
|
|
29
|
+
// `~/.parachute`. Nothing here writes, but the next copy of this helper
|
|
30
|
+
// might; spreading `process.env` is the shape every CLI test should use.
|
|
31
|
+
env: { ...process.env } as Record<string, string>,
|
|
24
32
|
});
|
|
25
33
|
return {
|
|
26
34
|
exitCode: proc.exitCode ?? -1,
|
package/src/ws-server.ts
CHANGED
|
@@ -37,7 +37,7 @@ import { readVaultConfig } from "./config.ts";
|
|
|
37
37
|
import { getVaultStore } from "./vault-store.ts";
|
|
38
38
|
import { authenticateVaultRequest, type AuthResult } from "./auth.ts";
|
|
39
39
|
import { hasScopeForVault } from "./scopes.ts";
|
|
40
|
-
import { expandTokenTagScope, filterNotesByTagScope } from "./tag-scope.ts";
|
|
40
|
+
import { expandTokenTagScope, filterNotesByTagScope, scrubNotesTagsByScope } from "./tag-scope.ts";
|
|
41
41
|
import { buildLiveMatcher } from "./live-match.ts";
|
|
42
42
|
import {
|
|
43
43
|
subscriptionManager,
|
|
@@ -254,7 +254,17 @@ export function createSubscribeWsBinding(deps: SubscribeWsDeps = {}): {
|
|
|
254
254
|
// Project AFTER the tag-scope filter (which reads note.tags). `toNoteIndex`
|
|
255
255
|
// is the SAME lean shape the REST list route returns, so a client that
|
|
256
256
|
// renders REST lists renders these snapshot frames unchanged.
|
|
257
|
-
|
|
257
|
+
//
|
|
258
|
+
// Then scrub each surviving note's `.tags` down to the in-scope subset
|
|
259
|
+
// (vault#568) — a snapshot is a read, and it must not disclose the NAMES
|
|
260
|
+
// of a visible note's out-of-scope co-tags any more than `GET /api/notes`
|
|
261
|
+
// does. Scrubbing AFTER the projection keeps the filter reading the full
|
|
262
|
+
// tag set. No-op for an unscoped subscription.
|
|
263
|
+
const frames = buildSnapshotFrames(
|
|
264
|
+
lean
|
|
265
|
+
? scrubNotesTagsByScope(snapshotNotes.map(toNoteIndex), tagScopeAllowed, auth.scoped_tags)
|
|
266
|
+
: scrubNotesTagsByScope(snapshotNotes, tagScopeAllowed, auth.scoped_tags),
|
|
267
|
+
);
|
|
258
268
|
|
|
259
269
|
// --- SYNCHRONOUS from here (no await) so no write interleaves between
|
|
260
270
|
// register and the snapshot flush.
|