pi-vault-mind 0.14.2 → 0.16.3

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 (164) hide show
  1. package/CHANGELOG.md +293 -0
  2. package/README.md +5 -5
  3. package/agents/broadcaster.agent.md +2 -2
  4. package/agents/heavy-lifter.agent.md +1 -1
  5. package/agents/main.agent.md +29 -0
  6. package/agents/manager.agent.md +1 -1
  7. package/agents/miner.agent.md +1 -1
  8. package/dist/packages/obsidian/src/client.js +331 -0
  9. package/dist/packages/obsidian/src/types.js +1 -0
  10. package/dist/src/activity.d.ts +49 -0
  11. package/dist/src/activity.js +175 -0
  12. package/dist/src/agent-bus/Agent.d.ts +9 -1
  13. package/dist/src/agent-bus/Agent.js +18 -2
  14. package/dist/src/agent-bus/index.d.ts +5 -5
  15. package/dist/src/agent-bus/index.js +1 -1
  16. package/dist/src/agent-queue.js +12 -3
  17. package/dist/src/agents/BroadcasterAgent.d.ts +1 -1
  18. package/dist/src/agents/BroadcasterAgent.js +2 -2
  19. package/dist/src/agents/HeavyLifterAgent.d.ts +1 -1
  20. package/dist/src/agents/HeavyLifterAgent.js +2 -2
  21. package/dist/src/agents/ManagerAgent.js +1 -1
  22. package/dist/src/agents/MinerAgent.d.ts +1 -1
  23. package/dist/src/agents/MinerAgent.js +2 -2
  24. package/dist/src/agents/index.d.ts +2 -2
  25. package/dist/src/agents/index.js +2 -2
  26. package/dist/src/auth.d.ts +17 -15
  27. package/dist/src/auth.js +26 -37
  28. package/dist/src/autosync.js +2 -2
  29. package/dist/src/commands.d.ts +2 -19
  30. package/dist/src/commands.js +301 -231
  31. package/dist/src/config-keys.d.ts +16 -0
  32. package/dist/src/config-keys.js +45 -0
  33. package/dist/src/discover-schema.js +4 -4
  34. package/dist/src/edits.d.ts +21 -0
  35. package/dist/src/edits.js +75 -0
  36. package/dist/src/embedding-probe.d.ts +34 -0
  37. package/dist/src/embedding-probe.js +142 -0
  38. package/dist/src/embedding-providers.d.ts +133 -0
  39. package/dist/src/embedding-providers.js +173 -0
  40. package/dist/src/embedding-secrets.d.ts +38 -0
  41. package/dist/src/embedding-secrets.js +291 -0
  42. package/dist/src/engine.d.ts +6 -0
  43. package/dist/src/engine.js +78 -6
  44. package/dist/src/events.js +7 -10
  45. package/dist/src/extension-packages.d.ts +9 -0
  46. package/dist/src/extension-packages.js +14 -0
  47. package/dist/src/git.d.ts +19 -0
  48. package/dist/src/git.js +78 -0
  49. package/dist/src/graph.d.ts +2 -1
  50. package/dist/src/graph.js +47 -13
  51. package/dist/src/identities-config.d.ts +6 -0
  52. package/dist/src/identities-config.js +39 -0
  53. package/dist/src/identity-injector.js +1 -1
  54. package/dist/src/index.js +9 -26
  55. package/dist/src/lance.d.ts +9 -0
  56. package/dist/src/lance.js +143 -203
  57. package/dist/src/modal-client.d.ts +16 -0
  58. package/dist/src/modal-client.js +16 -0
  59. package/dist/src/modal-config.d.ts +37 -14
  60. package/dist/src/modal-config.js +59 -32
  61. package/dist/src/model-router.d.ts +27 -0
  62. package/dist/src/model-router.js +67 -0
  63. package/dist/src/models.d.ts +42 -0
  64. package/dist/src/models.js +78 -0
  65. package/dist/src/personalize.js +17 -3
  66. package/dist/src/scaffold.d.ts +48 -0
  67. package/dist/src/scaffold.js +246 -0
  68. package/dist/src/server.d.ts +47 -4
  69. package/dist/src/server.js +988 -221
  70. package/dist/src/session-search.d.ts +63 -0
  71. package/dist/src/session-search.js +379 -0
  72. package/dist/src/settings-ui.d.ts +2 -2
  73. package/dist/src/settings-ui.js +76 -135
  74. package/dist/src/sync.d.ts +3 -3
  75. package/dist/src/sync.js +19 -15
  76. package/dist/src/tool-catalog.d.ts +18 -0
  77. package/dist/src/tool-catalog.js +232 -0
  78. package/dist/src/tools/marksman.js +1 -1
  79. package/dist/src/tools.js +111 -65
  80. package/dist/src/types.d.ts +127 -71
  81. package/dist/src/utils.d.ts +57 -6
  82. package/dist/src/utils.js +114 -28
  83. package/dist/src/vault-tools.d.ts +34 -0
  84. package/dist/src/vault-tools.js +99 -0
  85. package/dist/src/vault-writer.js +4 -1
  86. package/dist/src/vm-handlers.js +140 -43
  87. package/dist/src/watcher.js +9 -9
  88. package/dist/test/activity-tool.test.js +54 -0
  89. package/dist/test/agent-bus/Agent.test.js +174 -0
  90. package/dist/test/agent-bus/AgentLoader.test.js +180 -0
  91. package/dist/test/agent-bus/AgentRegistry.test.js +86 -0
  92. package/dist/test/agent-bus/LLMProvider.test.js +162 -0
  93. package/dist/test/agent-bus/TaskQueue.test.js +256 -0
  94. package/dist/test/agent-dispatch-context.test.js +73 -0
  95. package/dist/test/agent-queue.test.js +1 -1
  96. package/dist/test/agents/Agents.test.js +282 -0
  97. package/dist/test/auth.test.js +57 -56
  98. package/dist/test/bridge-identity.test.js +34 -3
  99. package/dist/test/classify-search-mode.test.js +51 -0
  100. package/dist/test/commands.test.js +410 -0
  101. package/dist/test/config-merge.test.js +98 -0
  102. package/dist/test/context-capture.test.js +56 -0
  103. package/dist/test/discover-schema.test.js +8 -5
  104. package/dist/test/dispatch.test.js +45 -91
  105. package/dist/test/edits.test.js +144 -0
  106. package/dist/test/embedding-probe.test.js +424 -0
  107. package/dist/test/embedding-providers.test.js +157 -0
  108. package/dist/test/embedding-secrets.test.js +210 -0
  109. package/dist/test/engine-identity.test.js +1 -1
  110. package/dist/test/events.test.js +675 -0
  111. package/dist/test/git-bridge.test.js +160 -0
  112. package/dist/test/graph.test.js +464 -0
  113. package/dist/test/helpers/server.js +81 -0
  114. package/dist/test/identity-injector.test.js +197 -0
  115. package/dist/test/index.test.js +5 -7
  116. package/dist/test/lance-modal.test.js +67 -2
  117. package/dist/test/lance.test.js +429 -0
  118. package/dist/test/modal-client.test.js +1 -1
  119. package/dist/test/modal-config.test.js +92 -79
  120. package/dist/test/model-readiness.test.js +122 -0
  121. package/dist/test/model-router.test.js +99 -0
  122. package/dist/test/obsidian-client.test.js +42 -0
  123. package/dist/test/personalize.test.js +1 -1
  124. package/dist/test/rest-models.test.js +153 -0
  125. package/dist/test/rest-queue.test.js +135 -87
  126. package/dist/test/rest-setup.test.js +625 -115
  127. package/dist/test/rest-vm.test.js +355 -94
  128. package/dist/test/server-cors.test.js +48 -0
  129. package/dist/test/server-ws.test.js +61 -34
  130. package/dist/test/session-crud.test.js +323 -0
  131. package/dist/test/session-search.test.js +139 -0
  132. package/dist/test/settings-ui.test.js +113 -4
  133. package/dist/test/sync.test.js +12 -12
  134. package/dist/test/tombstone.test.js +8 -10
  135. package/dist/test/tool-catalog.test.js +86 -0
  136. package/dist/test/utils.test.js +588 -0
  137. package/dist/test/vault-tools.test.js +103 -12
  138. package/dist/test/vault-writer.test.js +371 -0
  139. package/dist/test/vm-handlers.test.js +620 -0
  140. package/extension-packages.json +9 -0
  141. package/package.json +107 -90
  142. package/pi-vault-mind.config.example.json +24 -2
  143. package/scripts/check-deps.sh +35 -32
  144. package/scripts/cli-e2e.mjs +215 -0
  145. package/scripts/configuration-e2e.mjs +783 -0
  146. package/scripts/e2e-commands.mjs +391 -0
  147. package/scripts/e2e-ws.mjs +3 -2
  148. package/scripts/fetch-modal-token.sh +4 -3
  149. package/scripts/generate-config-keys-json.mjs +45 -0
  150. package/scripts/generate-extension-packages-json.mjs +55 -0
  151. package/scripts/pi-session-query +0 -0
  152. package/scripts/publish-obsidian-plugin.sh +0 -0
  153. package/scripts/reset-test-vault.sh +2 -2
  154. package/scripts/setup-test-config.sh +0 -0
  155. package/scripts/setup-vault-pi.sh +48 -9
  156. package/scripts/test-slash-commands.mjs +2 -2
  157. package/scripts/vault-pi.sh +12 -3
  158. package/skills/github-release-notes-file/SKILL.md +42 -0
  159. package/skills/obsidian-guided-test-session/SKILL.md +110 -0
  160. package/skills/obsidian-interactive-test/SKILL.md +88 -0
  161. package/skills/obsidian-plugin-publish/SKILL.md +58 -0
  162. package/skills/pi-vault-mind-release/SKILL.md +141 -0
  163. package/skills/pre-test-release/SKILL.md +116 -0
  164. package/dist/test/auto-indexer.test.js +0 -2
@@ -12,6 +12,7 @@
12
12
  */
13
13
  import * as fs from "node:fs";
14
14
  import * as path from "node:path";
15
+ import { loadConfig, resolveVaultFile } from "./utils.js";
15
16
  const queueSubscribers = new Set();
16
17
  /** Subscribe to queue events. Returns an unsubscribe function. */
17
18
  export const subscribeQueue = (cb) => {
@@ -35,8 +36,16 @@ const eventTypeFor = (status, prev) => {
35
36
  return "job-completed";
36
37
  return "job-updated";
37
38
  };
38
- const queueFileName = ".vault-mind/agent-queue.jsonl";
39
- const queuePath = (vaultPath) => path.join(vaultPath, queueFileName);
39
+ /** Per-vault queue path, resolved from config once and memoized. */
40
+ const queuePathCache = new Map();
41
+ const queuePath = (vaultPath) => {
42
+ const cached = queuePathCache.get(vaultPath);
43
+ if (cached)
44
+ return cached;
45
+ const resolved = path.join(vaultPath, resolveVaultFile(loadConfig(vaultPath).vaultMind, "queue"));
46
+ queuePathCache.set(vaultPath, resolved);
47
+ return resolved;
48
+ };
40
49
  const ensureQueueDir = (vaultPath) => {
41
50
  const dir = path.dirname(queuePath(vaultPath));
42
51
  if (!fs.existsSync(dir)) {
@@ -125,7 +134,7 @@ export const markJobRunning = (vaultPath, id) => {
125
134
  /** Mark a pending job as cancelled. */
126
135
  export const cancelJob = (vaultPath, id) => {
127
136
  const current = getJob(vaultPath, id);
128
- if (!current || current.status !== "pending")
137
+ if (current?.status !== "pending")
129
138
  return undefined;
130
139
  return updateJob(vaultPath, id, "cancelled");
131
140
  };
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * BroadcasterAgent — content distribution agent.
3
3
  *
4
- * Allowed tools: read, write, edit, vm_search, vm_fts_search
4
+ * Allowed tools: read, write, edit, vm_search
5
5
  * Cannot write to durable store or publish.
6
6
  * Writes output only under Agent/Presentations/.
7
7
  */
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * BroadcasterAgent — content distribution agent.
3
3
  *
4
- * Allowed tools: read, write, edit, vm_search, vm_fts_search
4
+ * Allowed tools: read, write, edit, vm_search
5
5
  * Cannot write to durable store or publish.
6
6
  * Writes output only under Agent/Presentations/.
7
7
  */
@@ -25,7 +25,7 @@ export class BroadcasterAgent extends Agent {
25
25
  if (!this.taskQueue.claim(taskId, this.config.id))
26
26
  return;
27
27
  try {
28
- await this.executeJob(job);
28
+ await this.withDispatchContext(job.dispatchId, () => this.executeJob(job));
29
29
  this.taskQueue.complete(taskId, this.config.id, { dispatchId: job.dispatchId });
30
30
  await this.broadcast("JOB_COMPLETED", {
31
31
  dispatchId: job.dispatchId,
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * HeavyLifterAgent — external CLI execution agent.
3
3
  *
4
- * Allowed tools: read, write, edit, grep, find, ls, bash, vm_search, vm_fts_search
4
+ * Allowed tools: read, write, edit, grep, find, ls, bash, vm_search
5
5
  * Cannot write to durable store or publish.
6
6
  * Runs bash in isolated worktree.
7
7
  */
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * HeavyLifterAgent — external CLI execution agent.
3
3
  *
4
- * Allowed tools: read, write, edit, grep, find, ls, bash, vm_search, vm_fts_search
4
+ * Allowed tools: read, write, edit, grep, find, ls, bash, vm_search
5
5
  * Cannot write to durable store or publish.
6
6
  * Runs bash in isolated worktree.
7
7
  */
@@ -25,7 +25,7 @@ export class HeavyLifterAgent extends Agent {
25
25
  if (!this.taskQueue.claim(taskId, this.config.id))
26
26
  return;
27
27
  try {
28
- await this.executeJob(job);
28
+ await this.withDispatchContext(job.dispatchId, () => this.executeJob(job));
29
29
  this.taskQueue.complete(taskId, this.config.id, { dispatchId: job.dispatchId });
30
30
  await this.broadcast("JOB_COMPLETED", {
31
31
  dispatchId: job.dispatchId,
@@ -26,7 +26,7 @@ export class ManagerAgent extends Agent {
26
26
  if (!this.taskQueue.claim(taskId, this.config.id))
27
27
  return;
28
28
  try {
29
- await this.executeJob(job);
29
+ await this.withDispatchContext(job.dispatchId, () => this.executeJob(job));
30
30
  this.taskQueue.complete(taskId, this.config.id, { dispatchId: job.dispatchId });
31
31
  await this.broadcast("JOB_COMPLETED", {
32
32
  dispatchId: job.dispatchId,
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * MinerAgent — knowledge extraction and storage agent.
3
3
  *
4
- * Allowed tools: read, write, edit, grep, find, ls, vm_search, vm_fts_search, vm_append
4
+ * Allowed tools: read, write, edit, grep, find, ls, vm_search, vm_append
5
5
  * Write collections: main, research
6
6
  * Cannot publish (vm_sync disabled).
7
7
  */
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * MinerAgent — knowledge extraction and storage agent.
3
3
  *
4
- * Allowed tools: read, write, edit, grep, find, ls, vm_search, vm_fts_search, vm_append
4
+ * Allowed tools: read, write, edit, grep, find, ls, vm_search, vm_append
5
5
  * Write collections: main, research
6
6
  * Cannot publish (vm_sync disabled).
7
7
  */
@@ -25,7 +25,7 @@ export class MinerAgent extends Agent {
25
25
  if (!this.taskQueue.claim(taskId, this.config.id))
26
26
  return;
27
27
  try {
28
- await this.executeJob(job);
28
+ await this.withDispatchContext(job.dispatchId, () => this.executeJob(job));
29
29
  this.taskQueue.complete(taskId, this.config.id, { dispatchId: job.dispatchId });
30
30
  await this.broadcast("JOB_COMPLETED", {
31
31
  dispatchId: job.dispatchId,
@@ -1,4 +1,4 @@
1
- export { HeavyLifterAgent, type DispatchJob } from "./HeavyLifterAgent.js";
2
- export { MinerAgent } from "./MinerAgent.js";
3
1
  export { BroadcasterAgent } from "./BroadcasterAgent.js";
2
+ export { type DispatchJob, HeavyLifterAgent } from "./HeavyLifterAgent.js";
4
3
  export { ManagerAgent } from "./ManagerAgent.js";
4
+ export { MinerAgent } from "./MinerAgent.js";
@@ -1,4 +1,4 @@
1
- export { HeavyLifterAgent } from "./HeavyLifterAgent.js";
2
- export { MinerAgent } from "./MinerAgent.js";
3
1
  export { BroadcasterAgent } from "./BroadcasterAgent.js";
2
+ export { HeavyLifterAgent } from "./HeavyLifterAgent.js";
4
3
  export { ManagerAgent } from "./ManagerAgent.js";
4
+ export { MinerAgent } from "./MinerAgent.js";
@@ -3,18 +3,20 @@
3
3
  *
4
4
  * Token resolution order:
5
5
  * 1. `process.env.PVM_API_TOKEN`
6
- * 2. `<homedir>/.pi/agent/vault-mind.env` (key=value, # comments)
7
- * 3. `vaultMind.embedding.modal.apiToken` in the loaded config
6
+ * 2. `<vault>/.vault-mind/vault-mind.env` (key=value, # comments)
8
7
  *
9
8
  * Returns `null` if no token is configured (auth is off until set).
10
9
  *
11
- * Cross-platform: `os.homedir()` (never `~/`); `chmod 600` on the
12
- * dotenv file is the caller's responsibility and is a no-op on
13
- * win32 (the file system doesn't honor POSIX modes there).
10
+ * The token env path is resolved from the vault cwd via `getTokenEnvPath`;
11
+ * `chmod 600` on the dotenv file is best-effort and a no-op on win32 (the file
12
+ * system doesn't honor POSIX modes there).
13
+ *
14
+ * Provider credentials (PVM_REMOTE_EMBEDDING_API_KEY, PVM_MODAL_*_TOKEN,
15
+ * PVM_LOCAL_EMBEDDING_API_KEY) are intentionally never consulted for bridge
16
+ * authentication — see `src/embedding-secrets.ts` for provider secrets.
14
17
  */
15
- import type { UniversalConfig } from "./types.js";
16
- /** Resolve the bearer token. `cfg` is optional; pass the loaded config to fall back to it. */
17
- export declare const resolveAuthToken: (cfg?: UniversalConfig) => string | null;
18
+ /** Resolve the bearer token from env or dotenv only. */
19
+ export declare const resolveAuthToken: () => string | null;
18
20
  /** Resolved identity for a per-role bearer token. */
19
21
  export interface TokenIdentity {
20
22
  token: string;
@@ -49,7 +51,7 @@ export interface AuthResult {
49
51
  * 2. Legacy `PVM_API_TOKEN` — returns `ok: true` with no identity (full access).
50
52
  * 3. No token configured → `ok: true` (auth is off).
51
53
  */
52
- export declare const authoriseRequest: (req: IncomingLike, cfg?: UniversalConfig) => AuthResult;
54
+ export declare const authoriseRequest: (req: IncomingLike) => AuthResult;
53
55
  /** Test-only: forget the cached token so tests get a fresh resolve on each call. */
54
56
  export declare const _resetAuthCache: () => void;
55
57
  /** Set an in-memory token override for the current process. Invalidates any cached value. */
@@ -58,16 +60,16 @@ export declare const setToken: (value: string) => void;
58
60
  export declare const clearToken: () => void;
59
61
  /**
60
62
  * Revoke a role-specific bearer token by removing `PVM_TOKEN_<IDENTITY>`
61
- * from `~/.pi/agent/vault-mind.env`. Preserves all other lines and comments.
62
- * Returns `true` if the variable was found and removed.
63
+ * from `<vault>/.vault-mind/vault-mind.env`. Preserves all other lines and
64
+ * comments. Returns `true` if the variable was found and removed.
63
65
  */
64
66
  export declare const revokeToken: (identity: string) => boolean;
65
67
  /**
66
68
  * Generate a fresh 32-byte base64url token, persist it to
67
- * `<os.homedir()>/.pi/agent/vault-mind.env` (replacing any existing
68
- * `PVM_API_TOKEN` line while preserving all other lines and comments), create
69
- * the directory + file if missing, apply `chmod 600` (best-effort; no-op on
70
- * win32), update the in-process cache, and return the new token.
69
+ * `<vault>/.vault-mind/vault-mind.env` (replacing any existing `PVM_API_TOKEN`
70
+ * line while preserving all other lines and comments), create the directory +
71
+ * file if missing, apply `chmod 600` (best-effort; no-op on win32), update the
72
+ * in-process cache, and return the new token.
71
73
  *
72
74
  * **Env-var precedence note:** if `PVM_API_TOKEN` is exported as an environment
73
75
  * variable it takes precedence over the dotenv file at resolution time, so the
package/dist/src/auth.js CHANGED
@@ -3,28 +3,27 @@
3
3
  *
4
4
  * Token resolution order:
5
5
  * 1. `process.env.PVM_API_TOKEN`
6
- * 2. `<homedir>/.pi/agent/vault-mind.env` (key=value, # comments)
7
- * 3. `vaultMind.embedding.modal.apiToken` in the loaded config
6
+ * 2. `<vault>/.vault-mind/vault-mind.env` (key=value, # comments)
8
7
  *
9
8
  * Returns `null` if no token is configured (auth is off until set).
10
9
  *
11
- * Cross-platform: `os.homedir()` (never `~/`); `chmod 600` on the
12
- * dotenv file is the caller's responsibility and is a no-op on
13
- * win32 (the file system doesn't honor POSIX modes there).
10
+ * The token env path is resolved from the vault cwd via `getTokenEnvPath`;
11
+ * `chmod 600` on the dotenv file is best-effort and a no-op on win32 (the file
12
+ * system doesn't honor POSIX modes there).
13
+ *
14
+ * Provider credentials (PVM_REMOTE_EMBEDDING_API_KEY, PVM_MODAL_*_TOKEN,
15
+ * PVM_LOCAL_EMBEDDING_API_KEY) are intentionally never consulted for bridge
16
+ * authentication — see `src/embedding-secrets.ts` for provider secrets.
14
17
  */
15
18
  import * as crypto from "node:crypto";
16
19
  import * as fs from "node:fs";
17
- import * as os from "node:os";
18
20
  import * as path from "node:path";
21
+ import { getTokenEnvPath } from "./utils.js";
19
22
  const ENV_VAR = "PVM_API_TOKEN";
20
- const DOTENV_REL = path.join(".pi", "agent", "vault-mind.env");
21
23
  /** Cached token resolution. The cache is invalidated by `setToken` / `clearToken`. */
22
24
  let cached = null;
23
25
  const readDotenvToken = () => {
24
- const home = os.homedir();
25
- if (!home)
26
- return null;
27
- const p = path.join(home, DOTENV_REL);
26
+ const p = getTokenEnvPath(process.cwd());
28
27
  try {
29
28
  const text = fs.readFileSync(p, "utf-8");
30
29
  for (const line of text.split(/\r?\n/)) {
@@ -41,11 +40,8 @@ const readDotenvToken = () => {
41
40
  }
42
41
  return null;
43
42
  };
44
- const readConfigToken = (cfg) => {
45
- return cfg?.vaultMind?.embedding?.modal?.apiToken;
46
- };
47
- /** Resolve the bearer token. `cfg` is optional; pass the loaded config to fall back to it. */
48
- export const resolveAuthToken = (cfg) => {
43
+ /** Resolve the bearer token from env or dotenv only. */
44
+ export const resolveAuthToken = () => {
49
45
  if (process.env[ENV_VAR])
50
46
  return process.env[ENV_VAR] ?? null;
51
47
  if (cached && cached.value !== null)
@@ -55,11 +51,6 @@ export const resolveAuthToken = (cfg) => {
55
51
  cached = { value: fromFile };
56
52
  return fromFile;
57
53
  }
58
- const fromCfg = readConfigToken(cfg);
59
- if (fromCfg) {
60
- cached = { value: fromCfg };
61
- return fromCfg;
62
- }
63
54
  return null;
64
55
  };
65
56
  /**
@@ -106,16 +97,14 @@ const safeEqual = (a, b) => {
106
97
  * 2. Legacy `PVM_API_TOKEN` — returns `ok: true` with no identity (full access).
107
98
  * 3. No token configured → `ok: true` (auth is off).
108
99
  */
109
- export const authoriseRequest = (req, cfg) => {
100
+ export const authoriseRequest = (req) => {
110
101
  const raw = req.headers.authorization;
111
102
  const header = Array.isArray(raw) ? raw[0] : raw;
112
103
  // Auth off: no tokens configured at all → allow everything
113
- const hasPerRole = resolveTokenIdentity("") !== undefined || true; // check env vars
114
- const hasLegacy = resolveAuthToken(cfg) !== null;
104
+ const hasLegacy = resolveAuthToken() !== null;
115
105
  if (!hasLegacy && !hasAnyPerRoleToken()) {
116
- // No tokens configured — auth is off, allow all requests
117
- if (!header)
118
- return { ok: true };
106
+ // No tokens configured — auth is off, allow all requests regardless of header
107
+ return { ok: true };
119
108
  }
120
109
  if (!header)
121
110
  return { ok: false, reason: "missing" };
@@ -128,9 +117,9 @@ export const authoriseRequest = (req, cfg) => {
128
117
  if (identity)
129
118
  return { ok: true, identity };
130
119
  // 2. Legacy single-token fallback
131
- const expected = resolveAuthToken(cfg);
120
+ const expected = resolveAuthToken();
132
121
  if (!expected)
133
- return { ok: true }; // auth off — no tokens configured
122
+ return { ok: false, reason: "mismatch" }; // tokens are configured but none matched
134
123
  if (!safeEqual(token, expected))
135
124
  return { ok: false, reason: "mismatch" };
136
125
  return { ok: true };
@@ -149,12 +138,12 @@ export const clearToken = () => {
149
138
  };
150
139
  /**
151
140
  * Revoke a role-specific bearer token by removing `PVM_TOKEN_<IDENTITY>`
152
- * from `~/.pi/agent/vault-mind.env`. Preserves all other lines and comments.
153
- * Returns `true` if the variable was found and removed.
141
+ * from `<vault>/.vault-mind/vault-mind.env`. Preserves all other lines and
142
+ * comments. Returns `true` if the variable was found and removed.
154
143
  */
155
144
  export const revokeToken = (identity) => {
156
145
  const varName = `PVM_TOKEN_${identity.toUpperCase()}`;
157
- const dotenvPath = path.join(os.homedir(), DOTENV_REL);
146
+ const dotenvPath = getTokenEnvPath(process.cwd());
158
147
  let lines = [];
159
148
  try {
160
149
  lines = fs.readFileSync(dotenvPath, "utf-8").split(/\r?\n/);
@@ -183,10 +172,10 @@ export const revokeToken = (identity) => {
183
172
  };
184
173
  /**
185
174
  * Generate a fresh 32-byte base64url token, persist it to
186
- * `<os.homedir()>/.pi/agent/vault-mind.env` (replacing any existing
187
- * `PVM_API_TOKEN` line while preserving all other lines and comments), create
188
- * the directory + file if missing, apply `chmod 600` (best-effort; no-op on
189
- * win32), update the in-process cache, and return the new token.
175
+ * `<vault>/.vault-mind/vault-mind.env` (replacing any existing `PVM_API_TOKEN`
176
+ * line while preserving all other lines and comments), create the directory +
177
+ * file if missing, apply `chmod 600` (best-effort; no-op on win32), update the
178
+ * in-process cache, and return the new token.
190
179
  *
191
180
  * **Env-var precedence note:** if `PVM_API_TOKEN` is exported as an environment
192
181
  * variable it takes precedence over the dotenv file at resolution time, so the
@@ -195,7 +184,7 @@ export const revokeToken = (identity) => {
195
184
  */
196
185
  export const rotateToken = () => {
197
186
  const newToken = crypto.randomBytes(32).toString("base64url");
198
- const dotenvPath = path.join(os.homedir(), DOTENV_REL);
187
+ const dotenvPath = getTokenEnvPath(process.cwd());
199
188
  const dir = path.dirname(dotenvPath);
200
189
  if (!fs.existsSync(dir))
201
190
  fs.mkdirSync(dir, { recursive: true });
@@ -20,14 +20,14 @@ export const startAutoSync = (intervalMs = 300_000) => {
20
20
  const tick = async () => {
21
21
  try {
22
22
  const cfg = loadConfig(process.cwd());
23
- const sync = cfg.vaultMind.embedding.modal?.sync;
23
+ const sync = cfg.vaultMind.embedding.sync;
24
24
  if (!sync?.autoSync)
25
25
  return; // off by default
26
26
  if (!isModalConfigured(cfg.vaultMind))
27
27
  return; // nothing to sync
28
28
  const ms = sync.autoSyncIntervalMs ?? intervalMs;
29
29
  void ms; // cadence is fixed at start; tick honors config toggle
30
- await syncAll(cfg);
30
+ await syncAll(cfg, process.cwd());
31
31
  console.log("[pi-vault-mind] auto-sync tick complete");
32
32
  }
33
33
  catch (err) {
@@ -1,27 +1,10 @@
1
1
  import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
2
- import type { ServerState } from "./server.js";
2
+ import { type ServerState } from "./server.js";
3
3
  export declare const auditConfig: (ctx: ExtensionContext) => Promise<void>;
4
4
  export declare const selectActiveCollection: (ctx: ExtensionContext) => Promise<void>;
5
- /**
6
- * Vault-root `.gitignore` entries that keep pi-vault-mind compatible with
7
- * `obsidian-git` (and, transitively, Obsidian Sync setups that also back up via
8
- * git): the LanceDB index is a large, per-device, rebuildable binary and must
9
- * never be committed; Obsidian's workspace UI state churns constantly. See
10
- * docs/OBSIDIAN_SETUP.md §6.
11
- */
12
- export declare const GITIGNORE_ENTRIES: string[];
13
- /**
14
- * Decide what to do with the vault `.gitignore`, given its current contents
15
- * (`null` if absent). Pure — does no I/O — so it is unit-testable. Creates the
16
- * file when missing, appends only the entries that aren't already present
17
- * (line-exact match, trimmed), and skips when everything is covered.
18
- */
19
- export declare const planGitignore: (existing: string | null) => {
20
- action: "create" | "append" | "skip";
21
- content: string;
22
- };
23
5
  export declare const watcherState: import("./watcher.js").WatcherState;
24
6
  /** Module-level server state, referenced by the /vm server command.
25
7
  * Port is set when the server starts in index.ts. */
26
8
  export declare const serverState: ServerState;
9
+ export declare const writeTokenEnv: (token: string, cwd: string, varName?: string) => void;
27
10
  export declare const registerCommands: (pi: ExtensionAPI) => void;