pi-vault-mind 0.12.10 → 0.13.0
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/CHANGELOG.md +21 -0
- package/dist/src/server.d.ts +1 -1
- package/dist/src/server.js +58 -8
- package/dist/src/tools/marksman.d.ts +93 -0
- package/dist/src/tools/marksman.js +534 -0
- package/dist/src/tools.js +2 -0
- package/dist/src/types.d.ts +8 -0
- package/dist/src/watcher.d.ts +18 -0
- package/dist/src/watcher.js +102 -30
- package/dist/test/dispatch.test.js +155 -0
- package/dist/test/marksman-tools.test.js +171 -0
- package/package.json +1 -1
- package/skills/vault-mind/SKILL.md +11 -0
- package/skills/vault-mind-broadcaster/SKILL.md +2 -0
- package/skills/vault-mind-heavy-lifter/SKILL.md +1 -0
- package/skills/vault-mind-manager/SKILL.md +1 -0
- package/skills/vault-mind-miner/SKILL.md +1 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,26 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
|
|
4
|
+
## 0.13.0 / 0.5.0 — 2026-06-28
|
|
5
|
+
|
|
6
|
+
### Added
|
|
7
|
+
|
|
8
|
+
- **Arrow.js chat UI refactor** — reactive composer (`chat/arrow/`), model chip in the input bar, mentionable badges with preview popup, per-assistant-message action row (copy/info/rewind), keyboard-navigable session popover, and Arrow-based permission modals.
|
|
9
|
+
- **`@agent` dispatch command** — Obsidian palette command that picks a vault-mind role, prompts for an instruction, and calls `POST /vault-mind/dispatch`; also adds `VaultMindClient.scan()` for immediate tag-based scanning.
|
|
10
|
+
- **Marksman LSP tool wrappers** — `vm_backlinks`, `vm_broken_links`, `vm_related` with graceful degradation when `marksman` is unavailable.
|
|
11
|
+
- **Setup model-router picker** — vault init now lets users choose the primary chat model and fallback model sequence, writing choices directly into `.pi/model-router.json`.
|
|
12
|
+
- **`op://` 1Password resolution** — Modal setup resolves `op://` references via the 1Password CLI and stores the actual token in the Obsidian keychain; test-connection now sends the bearer token and reports detailed errors.
|
|
13
|
+
|
|
14
|
+
### Changed
|
|
15
|
+
|
|
16
|
+
- `docs/ROADMAP.md` is now the single source of truth for project direction; `docs/NEXT_STEPS.md` is deprecated.
|
|
17
|
+
- `packages/obsidian/package.json` version now tracks the plugin manifest version.
|
|
18
|
+
|
|
19
|
+
### Fixed
|
|
20
|
+
|
|
21
|
+
- PVM_API_TOKEN injection into the `pi` subprocess via `resolveToken()` in `ChatTab.mount()`.
|
|
22
|
+
- Modal test connection failing silently because it did not send an `Authorization` header.
|
|
23
|
+
|
|
3
24
|
## 0.8.0 - 2026-06-24
|
|
4
25
|
|
|
5
26
|
### Added
|
package/dist/src/server.d.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Endpoints:
|
|
5
5
|
* GET /vault-mind/status → { running, dispatches, vaults, uptime }
|
|
6
6
|
* POST /vault-mind/scan → scan a file for @agent markers { file }
|
|
7
|
-
* POST /vault-mind/dispatch → fire a manual dispatch
|
|
7
|
+
* POST /vault-mind/dispatch → fire a manual dispatch { role, instruction, file?, vault? }
|
|
8
8
|
* POST /vault-mind/context → push active editor context from Obsidian { filePath, selection, cursor }
|
|
9
9
|
* GET /vault-mind/context → latest editor context (file, cursor, selection) for pi agents
|
|
10
10
|
*
|
package/dist/src/server.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Endpoints:
|
|
5
5
|
* GET /vault-mind/status → { running, dispatches, vaults, uptime }
|
|
6
6
|
* POST /vault-mind/scan → scan a file for @agent markers { file }
|
|
7
|
-
* POST /vault-mind/dispatch → fire a manual dispatch
|
|
7
|
+
* POST /vault-mind/dispatch → fire a manual dispatch { role, instruction, file?, vault? }
|
|
8
8
|
* POST /vault-mind/context → push active editor context from Obsidian { filePath, selection, cursor }
|
|
9
9
|
* GET /vault-mind/context → latest editor context (file, cursor, selection) for pi agents
|
|
10
10
|
*
|
|
@@ -33,7 +33,7 @@ import { queryGraph } from "./graph.js";
|
|
|
33
33
|
import { searchFts, searchHybrid, upsertEntry } from "./lance.js";
|
|
34
34
|
import { DEFAULT_CONFIG } from "./types.js";
|
|
35
35
|
import { ensureDir, expandHome, findConfig, loadConfig, resolveInitCollectionName, shrinkHome, } from "./utils.js";
|
|
36
|
-
import { processQueue, scanFile, startWatcher, stopWatcher } from "./watcher.js";
|
|
36
|
+
import { createManualDispatch, processQueue, scanFile, startWatcher, stopWatcher, } from "./watcher.js";
|
|
37
37
|
export function createServerState(port = 11435) {
|
|
38
38
|
return { server: null, wss: null, port, startTime: 0 };
|
|
39
39
|
}
|
|
@@ -85,7 +85,7 @@ export function startServer(pi, serverState, watcherState) {
|
|
|
85
85
|
}
|
|
86
86
|
}
|
|
87
87
|
serverState.vaultPath = vaultPath;
|
|
88
|
-
serverState.server = http.createServer((req, res) => {
|
|
88
|
+
serverState.server = http.createServer(async (req, res) => {
|
|
89
89
|
// CORS for localhost-only access
|
|
90
90
|
res.setHeader("Access-Control-Allow-Origin", `http://localhost:${serverState.port}`);
|
|
91
91
|
res.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
|
|
@@ -116,7 +116,7 @@ export function startServer(pi, serverState, watcherState) {
|
|
|
116
116
|
res.end(JSON.stringify({ error: "Method not allowed" }));
|
|
117
117
|
return;
|
|
118
118
|
}
|
|
119
|
-
handleDispatch(req, res, pi, watcherState);
|
|
119
|
+
await handleDispatch(req, res, pi, watcherState, serverState);
|
|
120
120
|
break;
|
|
121
121
|
case "/vault-mind/context":
|
|
122
122
|
if (req.method === "POST") {
|
|
@@ -427,11 +427,61 @@ function handleScan(req, res, pi, watcherState) {
|
|
|
427
427
|
}
|
|
428
428
|
});
|
|
429
429
|
}
|
|
430
|
-
function handleDispatch(req, res,
|
|
430
|
+
async function handleDispatch(req, res, pi, watcherState, serverState) {
|
|
431
|
+
let body;
|
|
432
|
+
try {
|
|
433
|
+
body = await readJsonBody(req);
|
|
434
|
+
}
|
|
435
|
+
catch {
|
|
436
|
+
res.writeHead(400);
|
|
437
|
+
res.end(JSON.stringify({ error: "Invalid JSON body" }));
|
|
438
|
+
return;
|
|
439
|
+
}
|
|
440
|
+
if (!body || typeof body !== "object") {
|
|
441
|
+
res.writeHead(400);
|
|
442
|
+
res.end(JSON.stringify({ error: "Expected a JSON object body" }));
|
|
443
|
+
return;
|
|
444
|
+
}
|
|
445
|
+
if (!("role" in body) || typeof body.role !== "string" || body.role.trim() === "") {
|
|
446
|
+
res.writeHead(400);
|
|
447
|
+
res.end(JSON.stringify({ error: "Missing or invalid 'role' field" }));
|
|
448
|
+
return;
|
|
449
|
+
}
|
|
450
|
+
if (!("instruction" in body) ||
|
|
451
|
+
typeof body.instruction !== "string" ||
|
|
452
|
+
body.instruction.trim() === "") {
|
|
453
|
+
res.writeHead(400);
|
|
454
|
+
res.end(JSON.stringify({ error: "Missing or invalid 'instruction' field" }));
|
|
455
|
+
return;
|
|
456
|
+
}
|
|
457
|
+
if ("file" in body && body.file !== undefined && typeof body.file !== "string") {
|
|
458
|
+
res.writeHead(400);
|
|
459
|
+
res.end(JSON.stringify({ error: "'file' must be a string when provided" }));
|
|
460
|
+
return;
|
|
461
|
+
}
|
|
462
|
+
if ("vault" in body && body.vault !== undefined && typeof body.vault !== "string") {
|
|
463
|
+
res.writeHead(400);
|
|
464
|
+
res.end(JSON.stringify({ error: "'vault' must be a string when provided" }));
|
|
465
|
+
return;
|
|
466
|
+
}
|
|
467
|
+
const role = body.role.trim();
|
|
468
|
+
const instruction = body.instruction.trim();
|
|
469
|
+
const file = "file" in body && typeof body.file === "string" ? body.file : undefined;
|
|
470
|
+
const vault = "vault" in body && typeof body.vault === "string" ? body.vault : undefined;
|
|
471
|
+
const vaultPath = vault || serverState.vaultPath || process.cwd();
|
|
472
|
+
const result = createManualDispatch(pi, watcherState, {
|
|
473
|
+
role,
|
|
474
|
+
instruction,
|
|
475
|
+
filePath: file,
|
|
476
|
+
vaultPath,
|
|
477
|
+
});
|
|
478
|
+
if ("error" in result) {
|
|
479
|
+
res.writeHead(500);
|
|
480
|
+
res.end(JSON.stringify({ error: result.error }));
|
|
481
|
+
return;
|
|
482
|
+
}
|
|
431
483
|
res.writeHead(200);
|
|
432
|
-
res.end(JSON.stringify({
|
|
433
|
-
message: "Manual dispatch not yet implemented. Use /vm watcher status for state.",
|
|
434
|
-
}));
|
|
484
|
+
res.end(JSON.stringify({ ok: true, jobId: result.jobId, message: result.message }));
|
|
435
485
|
}
|
|
436
486
|
async function handleVaultMindContextUpdate(req, res, serverState) {
|
|
437
487
|
const body = (await readJsonBody(req));
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { type ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
import { Type } from "typebox";
|
|
3
|
+
export declare const isMarksmanAvailable: () => Promise<boolean>;
|
|
4
|
+
export type LspPosition = {
|
|
5
|
+
line: number;
|
|
6
|
+
character: number;
|
|
7
|
+
};
|
|
8
|
+
export type LspRange = {
|
|
9
|
+
start: LspPosition;
|
|
10
|
+
end: LspPosition;
|
|
11
|
+
};
|
|
12
|
+
export type LspLocation = {
|
|
13
|
+
uri: string;
|
|
14
|
+
range: LspRange;
|
|
15
|
+
};
|
|
16
|
+
export type LspDocumentLink = {
|
|
17
|
+
range: LspRange;
|
|
18
|
+
target?: string;
|
|
19
|
+
tooltip?: string;
|
|
20
|
+
};
|
|
21
|
+
export type LspDiagnostic = {
|
|
22
|
+
range: LspRange;
|
|
23
|
+
severity?: number;
|
|
24
|
+
code?: string | number;
|
|
25
|
+
source?: string;
|
|
26
|
+
message: string;
|
|
27
|
+
};
|
|
28
|
+
export type WorkspaceDiagnosticItem = {
|
|
29
|
+
uri: string;
|
|
30
|
+
kind?: number;
|
|
31
|
+
items: LspDiagnostic[];
|
|
32
|
+
};
|
|
33
|
+
export interface IMarksmanClient {
|
|
34
|
+
initialize(): Promise<void>;
|
|
35
|
+
openDocument(uri: string, text?: string): Promise<void>;
|
|
36
|
+
closeDocument(uri: string): Promise<void>;
|
|
37
|
+
documentLinks(uri: string): Promise<LspDocumentLink[]>;
|
|
38
|
+
documentSymbols(uri: string): Promise<unknown[]>;
|
|
39
|
+
references(uri: string, position: LspPosition): Promise<LspLocation[]>;
|
|
40
|
+
workspaceDiagnostics(): Promise<WorkspaceDiagnosticItem[]>;
|
|
41
|
+
shutdown(): Promise<void>;
|
|
42
|
+
}
|
|
43
|
+
export declare class MarksmanClient implements IMarksmanClient {
|
|
44
|
+
#private;
|
|
45
|
+
constructor(vaultPath: string);
|
|
46
|
+
initialize(): Promise<void>;
|
|
47
|
+
openDocument(uri: string, text?: string): Promise<void>;
|
|
48
|
+
closeDocument(uri: string): Promise<void>;
|
|
49
|
+
documentLinks(uri: string): Promise<LspDocumentLink[]>;
|
|
50
|
+
documentSymbols(uri: string): Promise<unknown[]>;
|
|
51
|
+
references(uri: string, position: LspPosition): Promise<LspLocation[]>;
|
|
52
|
+
workspaceDiagnostics(): Promise<WorkspaceDiagnosticItem[]>;
|
|
53
|
+
shutdown(): Promise<void>;
|
|
54
|
+
}
|
|
55
|
+
type Backlink = {
|
|
56
|
+
file: string;
|
|
57
|
+
target?: string;
|
|
58
|
+
range?: LspRange;
|
|
59
|
+
};
|
|
60
|
+
export declare const backlinksForNote: (client: IMarksmanClient, vaultPath: string, note: string) => Promise<{
|
|
61
|
+
note: string;
|
|
62
|
+
backlinks: Backlink[];
|
|
63
|
+
}>;
|
|
64
|
+
type BrokenLink = {
|
|
65
|
+
file: string;
|
|
66
|
+
message: string;
|
|
67
|
+
range?: LspRange;
|
|
68
|
+
};
|
|
69
|
+
export declare const brokenLinks: (client: IMarksmanClient, vaultPath: string) => Promise<{
|
|
70
|
+
broken: BrokenLink[];
|
|
71
|
+
}>;
|
|
72
|
+
type Edge = {
|
|
73
|
+
from: string;
|
|
74
|
+
to: string;
|
|
75
|
+
type: "backlink" | "forward";
|
|
76
|
+
};
|
|
77
|
+
export declare const relatedNotes: (client: IMarksmanClient, vaultPath: string, entity: string, depth?: number) => Promise<{
|
|
78
|
+
entity: string;
|
|
79
|
+
depth: number;
|
|
80
|
+
nodes: string[];
|
|
81
|
+
edges: Edge[];
|
|
82
|
+
titles: Record<string, string>;
|
|
83
|
+
}>;
|
|
84
|
+
export declare const vmBacklinksTool: import("@earendil-works/pi-coding-agent").ToolDefinition<Type.TObject<{
|
|
85
|
+
note: Type.TString;
|
|
86
|
+
}>, Record<string, unknown>, any> & import("@earendil-works/pi-coding-agent").ToolDefinition<any, any, any>;
|
|
87
|
+
export declare const vmBrokenLinksTool: import("@earendil-works/pi-coding-agent").ToolDefinition<Type.TObject<{}>, Record<string, unknown>, any> & import("@earendil-works/pi-coding-agent").ToolDefinition<any, any, any>;
|
|
88
|
+
export declare const vmRelatedTool: import("@earendil-works/pi-coding-agent").ToolDefinition<Type.TObject<{
|
|
89
|
+
entity: Type.TString;
|
|
90
|
+
depth: Type.TOptional<Type.TNumber>;
|
|
91
|
+
}>, Record<string, unknown>, any> & import("@earendil-works/pi-coding-agent").ToolDefinition<any, any, any>;
|
|
92
|
+
export declare const registerMarksmanTools: (pi: ExtensionAPI) => void;
|
|
93
|
+
export {};
|