context-vault 3.1.6 → 3.1.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.
Files changed (82) hide show
  1. package/bin/cli.js +1369 -1774
  2. package/node_modules/@context-vault/core/dist/capture.d.ts +1 -1
  3. package/node_modules/@context-vault/core/dist/capture.d.ts.map +1 -1
  4. package/node_modules/@context-vault/core/dist/capture.js +34 -47
  5. package/node_modules/@context-vault/core/dist/capture.js.map +1 -1
  6. package/node_modules/@context-vault/core/dist/categories.js +30 -30
  7. package/node_modules/@context-vault/core/dist/config.d.ts +1 -1
  8. package/node_modules/@context-vault/core/dist/config.d.ts.map +1 -1
  9. package/node_modules/@context-vault/core/dist/config.js +37 -43
  10. package/node_modules/@context-vault/core/dist/config.js.map +1 -1
  11. package/node_modules/@context-vault/core/dist/constants.d.ts.map +1 -1
  12. package/node_modules/@context-vault/core/dist/constants.js +4 -4
  13. package/node_modules/@context-vault/core/dist/constants.js.map +1 -1
  14. package/node_modules/@context-vault/core/dist/db.d.ts +2 -2
  15. package/node_modules/@context-vault/core/dist/db.d.ts.map +1 -1
  16. package/node_modules/@context-vault/core/dist/db.js +21 -20
  17. package/node_modules/@context-vault/core/dist/db.js.map +1 -1
  18. package/node_modules/@context-vault/core/dist/embed.d.ts.map +1 -1
  19. package/node_modules/@context-vault/core/dist/embed.js +11 -11
  20. package/node_modules/@context-vault/core/dist/embed.js.map +1 -1
  21. package/node_modules/@context-vault/core/dist/files.d.ts.map +1 -1
  22. package/node_modules/@context-vault/core/dist/files.js +12 -13
  23. package/node_modules/@context-vault/core/dist/files.js.map +1 -1
  24. package/node_modules/@context-vault/core/dist/formatters.js +5 -5
  25. package/node_modules/@context-vault/core/dist/frontmatter.d.ts.map +1 -1
  26. package/node_modules/@context-vault/core/dist/frontmatter.js +23 -23
  27. package/node_modules/@context-vault/core/dist/frontmatter.js.map +1 -1
  28. package/node_modules/@context-vault/core/dist/index.d.ts +1 -1
  29. package/node_modules/@context-vault/core/dist/index.d.ts.map +1 -1
  30. package/node_modules/@context-vault/core/dist/index.js +58 -46
  31. package/node_modules/@context-vault/core/dist/index.js.map +1 -1
  32. package/node_modules/@context-vault/core/dist/ingest-url.d.ts.map +1 -1
  33. package/node_modules/@context-vault/core/dist/ingest-url.js +30 -33
  34. package/node_modules/@context-vault/core/dist/ingest-url.js.map +1 -1
  35. package/node_modules/@context-vault/core/dist/main.d.ts +13 -13
  36. package/node_modules/@context-vault/core/dist/main.d.ts.map +1 -1
  37. package/node_modules/@context-vault/core/dist/main.js +12 -12
  38. package/node_modules/@context-vault/core/dist/main.js.map +1 -1
  39. package/node_modules/@context-vault/core/dist/search.d.ts +1 -1
  40. package/node_modules/@context-vault/core/dist/search.d.ts.map +1 -1
  41. package/node_modules/@context-vault/core/dist/search.js +20 -22
  42. package/node_modules/@context-vault/core/dist/search.js.map +1 -1
  43. package/node_modules/@context-vault/core/dist/types.d.ts +1 -1
  44. package/node_modules/@context-vault/core/package.json +1 -1
  45. package/node_modules/@context-vault/core/src/capture.ts +44 -81
  46. package/node_modules/@context-vault/core/src/categories.ts +30 -30
  47. package/node_modules/@context-vault/core/src/config.ts +45 -60
  48. package/node_modules/@context-vault/core/src/constants.ts +8 -10
  49. package/node_modules/@context-vault/core/src/db.ts +37 -56
  50. package/node_modules/@context-vault/core/src/embed.ts +15 -26
  51. package/node_modules/@context-vault/core/src/files.ts +13 -16
  52. package/node_modules/@context-vault/core/src/formatters.ts +5 -5
  53. package/node_modules/@context-vault/core/src/frontmatter.ts +26 -30
  54. package/node_modules/@context-vault/core/src/index.ts +94 -100
  55. package/node_modules/@context-vault/core/src/ingest-url.ts +56 -93
  56. package/node_modules/@context-vault/core/src/main.ts +13 -18
  57. package/node_modules/@context-vault/core/src/search.ts +34 -56
  58. package/node_modules/@context-vault/core/src/types.ts +1 -1
  59. package/package.json +2 -2
  60. package/scripts/postinstall.js +18 -25
  61. package/scripts/prepack.js +13 -19
  62. package/src/archive.js +211 -0
  63. package/src/error-log.js +7 -7
  64. package/src/helpers.js +11 -13
  65. package/src/linking.js +8 -11
  66. package/src/migrate-dirs.js +139 -0
  67. package/src/register-tools.js +46 -48
  68. package/src/server.js +73 -99
  69. package/src/status.js +35 -71
  70. package/src/telemetry.js +18 -22
  71. package/src/temporal.js +19 -30
  72. package/src/tools/clear-context.js +15 -18
  73. package/src/tools/context-status.js +37 -57
  74. package/src/tools/create-snapshot.js +45 -57
  75. package/src/tools/delete-context.js +11 -12
  76. package/src/tools/get-context.js +112 -160
  77. package/src/tools/ingest-project.js +66 -86
  78. package/src/tools/ingest-url.js +25 -41
  79. package/src/tools/list-buckets.js +19 -25
  80. package/src/tools/list-context.js +35 -58
  81. package/src/tools/save-context.js +126 -182
  82. package/src/tools/session-start.js +46 -62
@@ -1,30 +1,27 @@
1
- import { z } from "zod";
2
- import { readFileSync, existsSync } from "node:fs";
3
- import { execSync } from "node:child_process";
4
- import { join, basename } from "node:path";
5
- import { captureAndIndex } from "@context-vault/core/capture";
6
- import { ok, err, ensureVaultExists } from "../helpers.js";
1
+ import { z } from 'zod';
2
+ import { readFileSync, existsSync } from 'node:fs';
3
+ import { execSync } from 'node:child_process';
4
+ import { join, basename } from 'node:path';
5
+ import { captureAndIndex } from '@context-vault/core/capture';
6
+ import { ok, err, ensureVaultExists } from '../helpers.js';
7
7
 
8
- export const name = "ingest_project";
8
+ export const name = 'ingest_project';
9
9
 
10
10
  export const description =
11
- "Scan a local project directory and register it as a project entity in the vault. Extracts metadata from package.json, git history, and README. Also creates a bucket entity for project-scoped tagging.";
11
+ 'Scan a local project directory and register it as a project entity in the vault. Extracts metadata from package.json, git history, and README. Also creates a bucket entity for project-scoped tagging.';
12
12
 
13
13
  export const inputSchema = {
14
- path: z.string().describe("Absolute path to the project directory to ingest"),
14
+ path: z.string().describe('Absolute path to the project directory to ingest'),
15
15
  tags: z
16
16
  .array(z.string())
17
17
  .optional()
18
- .describe("Additional tags to apply (bucket tags are auto-generated)"),
19
- pillar: z
20
- .string()
21
- .optional()
22
- .describe("Parent pillar/domain name — creates a bucket:pillar tag"),
18
+ .describe('Additional tags to apply (bucket tags are auto-generated)'),
19
+ pillar: z.string().optional().describe('Parent pillar/domain name — creates a bucket:pillar tag'),
23
20
  };
24
21
 
25
22
  function safeRead(filePath) {
26
23
  try {
27
- return readFileSync(filePath, "utf-8");
24
+ return readFileSync(filePath, 'utf-8');
28
25
  } catch {
29
26
  return null;
30
27
  }
@@ -34,8 +31,8 @@ function safeExec(cmd, cwd) {
34
31
  try {
35
32
  return execSync(cmd, {
36
33
  cwd,
37
- encoding: "utf-8",
38
- stdio: ["pipe", "pipe", "pipe"],
34
+ encoding: 'utf-8',
35
+ stdio: ['pipe', 'pipe', 'pipe'],
39
36
  }).trim();
40
37
  } catch {
41
38
  return null;
@@ -46,49 +43,47 @@ function detectTechStack(projectPath, pkgJson) {
46
43
  const stack = [];
47
44
 
48
45
  if (
49
- existsSync(join(projectPath, "pyproject.toml")) ||
50
- existsSync(join(projectPath, "setup.py"))
46
+ existsSync(join(projectPath, 'pyproject.toml')) ||
47
+ existsSync(join(projectPath, 'setup.py'))
51
48
  ) {
52
- stack.push("python");
49
+ stack.push('python');
53
50
  }
54
- if (existsSync(join(projectPath, "Cargo.toml"))) {
55
- stack.push("rust");
51
+ if (existsSync(join(projectPath, 'Cargo.toml'))) {
52
+ stack.push('rust');
56
53
  }
57
- if (existsSync(join(projectPath, "go.mod"))) {
58
- stack.push("go");
54
+ if (existsSync(join(projectPath, 'go.mod'))) {
55
+ stack.push('go');
59
56
  }
60
57
  if (pkgJson) {
61
- stack.push("javascript");
58
+ stack.push('javascript');
62
59
  const allDeps = {
63
60
  ...(pkgJson.dependencies || {}),
64
61
  ...(pkgJson.devDependencies || {}),
65
62
  };
66
- if (allDeps.typescript || existsSync(join(projectPath, "tsconfig.json"))) {
67
- stack.push("typescript");
63
+ if (allDeps.typescript || existsSync(join(projectPath, 'tsconfig.json'))) {
64
+ stack.push('typescript');
68
65
  }
69
- if (allDeps.react || allDeps["react-dom"]) stack.push("react");
70
- if (allDeps.next || allDeps["next"]) stack.push("nextjs");
71
- if (allDeps.vue) stack.push("vue");
72
- if (allDeps.svelte) stack.push("svelte");
73
- if (allDeps.express) stack.push("express");
74
- if (allDeps.fastify) stack.push("fastify");
75
- if (allDeps.hono) stack.push("hono");
76
- if (allDeps.vite) stack.push("vite");
77
- if (allDeps.electron) stack.push("electron");
78
- if (allDeps.tauri || allDeps["@tauri-apps/api"]) stack.push("tauri");
66
+ if (allDeps.react || allDeps['react-dom']) stack.push('react');
67
+ if (allDeps.next || allDeps['next']) stack.push('nextjs');
68
+ if (allDeps.vue) stack.push('vue');
69
+ if (allDeps.svelte) stack.push('svelte');
70
+ if (allDeps.express) stack.push('express');
71
+ if (allDeps.fastify) stack.push('fastify');
72
+ if (allDeps.hono) stack.push('hono');
73
+ if (allDeps.vite) stack.push('vite');
74
+ if (allDeps.electron) stack.push('electron');
75
+ if (allDeps.tauri || allDeps['@tauri-apps/api']) stack.push('tauri');
79
76
  }
80
77
 
81
78
  return [...new Set(stack)];
82
79
  }
83
80
 
84
81
  function extractReadmeDescription(projectPath) {
85
- const raw =
86
- safeRead(join(projectPath, "README.md")) ||
87
- safeRead(join(projectPath, "readme.md"));
82
+ const raw = safeRead(join(projectPath, 'README.md')) || safeRead(join(projectPath, 'readme.md'));
88
83
  if (!raw) return null;
89
- for (const line of raw.split("\n")) {
84
+ for (const line of raw.split('\n')) {
90
85
  const trimmed = line.trim();
91
- if (!trimmed || trimmed.startsWith("#")) continue;
86
+ if (!trimmed || trimmed.startsWith('#')) continue;
92
87
  return trimmed.slice(0, 200);
93
88
  }
94
89
  return null;
@@ -105,14 +100,14 @@ function buildProjectBody({
105
100
  }) {
106
101
  const lines = [];
107
102
  lines.push(`## ${projectName}`);
108
- if (description) lines.push("", description);
109
- lines.push("", "### Metadata");
103
+ if (description) lines.push('', description);
104
+ lines.push('', '### Metadata');
110
105
  lines.push(`- **Path**: \`${projectPath}\``);
111
106
  if (repoUrl) lines.push(`- **Repo**: ${repoUrl}`);
112
- if (techStack.length) lines.push(`- **Stack**: ${techStack.join(", ")}`);
107
+ if (techStack.length) lines.push(`- **Stack**: ${techStack.join(', ')}`);
113
108
  if (lastCommit) lines.push(`- **Last commit**: ${lastCommit}`);
114
- lines.push(`- **CLAUDE.md**: ${hasClaudeMd ? "yes" : "no"}`);
115
- return lines.join("\n");
109
+ lines.push(`- **CLAUDE.md**: ${hasClaudeMd ? 'yes' : 'no'}`);
110
+ return lines.join('\n');
116
111
  }
117
112
 
118
113
  /**
@@ -120,34 +115,27 @@ function buildProjectBody({
120
115
  * @param {import('../types.js').BaseCtx & Partial<import('../types.js').HostedCtxExtensions>} ctx
121
116
  * @param {import('../types.js').ToolShared} shared
122
117
  */
123
- export async function handler(
124
- { path: projectPath, tags, pillar },
125
- ctx,
126
- { ensureIndexed },
127
- ) {
118
+ export async function handler({ path: projectPath, tags, pillar }, ctx, { ensureIndexed }) {
128
119
  const { config } = ctx;
129
120
 
130
121
  const vaultErr = ensureVaultExists(config);
131
122
  if (vaultErr) return vaultErr;
132
123
 
133
124
  if (!projectPath?.trim()) {
134
- return err(
135
- "Required: path (absolute path to project directory)",
136
- "INVALID_INPUT",
137
- );
125
+ return err('Required: path (absolute path to project directory)', 'INVALID_INPUT');
138
126
  }
139
127
  if (!existsSync(projectPath)) {
140
- return err(`Directory not found: ${projectPath}`, "INVALID_INPUT");
128
+ return err(`Directory not found: ${projectPath}`, 'INVALID_INPUT');
141
129
  }
142
130
 
143
131
  await ensureIndexed();
144
132
 
145
133
  // Read package.json if present
146
134
  let pkgJson = null;
147
- const pkgPath = join(projectPath, "package.json");
135
+ const pkgPath = join(projectPath, 'package.json');
148
136
  if (existsSync(pkgPath)) {
149
137
  try {
150
- pkgJson = JSON.parse(readFileSync(pkgPath, "utf-8"));
138
+ pkgJson = JSON.parse(readFileSync(pkgPath, 'utf-8'));
151
139
  } catch {
152
140
  pkgJson = null;
153
141
  }
@@ -156,34 +144,29 @@ export async function handler(
156
144
  // Derive project name
157
145
  let projectName = basename(projectPath);
158
146
  if (pkgJson?.name) {
159
- projectName = pkgJson.name.replace(/^@[^/]+\//, "");
147
+ projectName = pkgJson.name.replace(/^@[^/]+\//, '');
160
148
  }
161
149
 
162
150
  // Slug-safe identity_key
163
151
  const identityKey = projectName
164
152
  .toLowerCase()
165
- .replace(/[^a-z0-9-]/g, "-")
166
- .replace(/-+/g, "-")
167
- .replace(/^-|-$/g, "");
153
+ .replace(/[^a-z0-9-]/g, '-')
154
+ .replace(/-+/g, '-')
155
+ .replace(/^-|-$/g, '');
168
156
 
169
157
  // Description: package.json > README
170
- const description =
171
- pkgJson?.description || extractReadmeDescription(projectPath) || null;
158
+ const description = pkgJson?.description || extractReadmeDescription(projectPath) || null;
172
159
 
173
160
  // Tech stack detection
174
161
  const techStack = detectTechStack(projectPath, pkgJson);
175
162
 
176
163
  // Git metadata
177
- const isGitRepo = existsSync(join(projectPath, ".git"));
178
- const repoUrl = isGitRepo
179
- ? safeExec("git remote get-url origin", projectPath)
180
- : null;
181
- const lastCommit = isGitRepo
182
- ? safeExec("git log -1 --format=%ci", projectPath)
183
- : null;
164
+ const isGitRepo = existsSync(join(projectPath, '.git'));
165
+ const repoUrl = isGitRepo ? safeExec('git remote get-url origin', projectPath) : null;
166
+ const lastCommit = isGitRepo ? safeExec('git log -1 --format=%ci', projectPath) : null;
184
167
 
185
168
  // CLAUDE.md presence
186
- const hasClaudeMd = existsSync(join(projectPath, "CLAUDE.md"));
169
+ const hasClaudeMd = existsSync(join(projectPath, 'CLAUDE.md'));
187
170
 
188
171
  // Build tags
189
172
  const bucketTag = `bucket:${identityKey}`;
@@ -212,7 +195,7 @@ export async function handler(
212
195
 
213
196
  // Save project entity
214
197
  const projectEntry = await captureAndIndex(ctx, {
215
- kind: "project",
198
+ kind: 'project',
216
199
  title: projectName,
217
200
  body,
218
201
  tags: allTags,
@@ -221,18 +204,18 @@ export async function handler(
221
204
  });
222
205
 
223
206
  // Save bucket entity if it doesn't already exist
224
- const bucketUserClause = "";
207
+ const bucketUserClause = '';
225
208
  const bucketParams = false ? [bucketTag] : [bucketTag];
226
209
  const bucketExists = ctx.db
227
210
  .prepare(
228
- `SELECT 1 FROM vault WHERE kind = 'bucket' AND identity_key = ? ${bucketUserClause} LIMIT 1`,
211
+ `SELECT 1 FROM vault WHERE kind = 'bucket' AND identity_key = ? ${bucketUserClause} LIMIT 1`
229
212
  )
230
213
  .get(...bucketParams);
231
214
 
232
215
  let bucketEntry = null;
233
216
  if (!bucketExists) {
234
217
  bucketEntry = await captureAndIndex(ctx, {
235
- kind: "bucket",
218
+ kind: 'bucket',
236
219
  title: projectName,
237
220
  body: `Bucket for project: ${projectName}`,
238
221
  tags: allTags,
@@ -242,21 +225,21 @@ export async function handler(
242
225
  }
243
226
 
244
227
  const relPath = projectEntry.filePath
245
- ? projectEntry.filePath.replace(config.vaultDir + "/", "")
228
+ ? projectEntry.filePath.replace(config.vaultDir + '/', '')
246
229
  : projectEntry.filePath;
247
230
 
248
231
  const parts = [
249
232
  `✓ Ingested project → ${relPath}`,
250
233
  ` id: ${projectEntry.id}`,
251
234
  ` title: ${projectEntry.title}`,
252
- ` tags: ${allTags.join(", ")}`,
253
- ...(techStack.length ? [` stack: ${techStack.join(", ")}`] : []),
235
+ ` tags: ${allTags.join(', ')}`,
236
+ ...(techStack.length ? [` stack: ${techStack.join(', ')}`] : []),
254
237
  ...(repoUrl ? [` repo: ${repoUrl}`] : []),
255
238
  ];
256
239
 
257
240
  if (bucketEntry) {
258
241
  const bucketRelPath = bucketEntry.filePath
259
- ? bucketEntry.filePath.replace(config.vaultDir + "/", "")
242
+ ? bucketEntry.filePath.replace(config.vaultDir + '/', '')
260
243
  : bucketEntry.filePath;
261
244
  parts.push(``, `✓ Created bucket → ${bucketRelPath}`);
262
245
  parts.push(` id: ${bucketEntry.id}`);
@@ -264,9 +247,6 @@ export async function handler(
264
247
  parts.push(``, ` (bucket '${bucketTag}' already exists — skipped)`);
265
248
  }
266
249
 
267
- parts.push(
268
- "",
269
- "_Use get_context with bucket tag to retrieve project-scoped entries._",
270
- );
271
- return ok(parts.join("\n"));
250
+ parts.push('', '_Use get_context with bucket tag to retrieve project-scoped entries._');
251
+ return ok(parts.join('\n'));
272
252
  }
@@ -1,23 +1,19 @@
1
- import { z } from "zod";
2
- import { captureAndIndex } from "@context-vault/core/capture";
3
- import { ok, err, ensureVaultExists } from "../helpers.js";
4
- import {
5
- MAX_KIND_LENGTH,
6
- MAX_TAG_LENGTH,
7
- MAX_TAGS_COUNT,
8
- } from "@context-vault/core/constants";
1
+ import { z } from 'zod';
2
+ import { captureAndIndex } from '@context-vault/core/capture';
3
+ import { ok, err, ensureVaultExists } from '../helpers.js';
4
+ import { MAX_KIND_LENGTH, MAX_TAG_LENGTH, MAX_TAGS_COUNT } from '@context-vault/core/constants';
9
5
 
10
6
  const MAX_URL_LENGTH = 2048;
11
7
 
12
- export const name = "ingest_url";
8
+ export const name = 'ingest_url';
13
9
 
14
10
  export const description =
15
- "Fetch a URL, extract its readable content, and save it as a vault entry. Useful for saving articles, documentation, or web pages to your knowledge vault.";
11
+ 'Fetch a URL, extract its readable content, and save it as a vault entry. Useful for saving articles, documentation, or web pages to your knowledge vault.';
16
12
 
17
13
  export const inputSchema = {
18
- url: z.string().describe("The URL to fetch and save"),
19
- kind: z.string().optional().describe("Entry kind (default: reference)"),
20
- tags: z.array(z.string()).optional().describe("Tags for the entry"),
14
+ url: z.string().describe('The URL to fetch and save'),
15
+ kind: z.string().optional().describe('Entry kind (default: reference)'),
16
+ tags: z.array(z.string()).optional().describe('Tags for the entry'),
21
17
  };
22
18
 
23
19
  /**
@@ -25,39 +21,27 @@ export const inputSchema = {
25
21
  * @param {import('../types.js').BaseCtx & Partial<import('../types.js').HostedCtxExtensions>} ctx
26
22
  * @param {import('../types.js').ToolShared} shared
27
23
  */
28
- export async function handler(
29
- { url: targetUrl, kind, tags },
30
- ctx,
31
- { ensureIndexed },
32
- ) {
24
+ export async function handler({ url: targetUrl, kind, tags }, ctx, { ensureIndexed }) {
33
25
  const { config } = ctx;
34
26
 
35
27
  const vaultErr = ensureVaultExists(config);
36
28
  if (vaultErr) return vaultErr;
37
29
 
38
- if (!targetUrl?.trim())
39
- return err("Required: url (non-empty string)", "INVALID_INPUT");
30
+ if (!targetUrl?.trim()) return err('Required: url (non-empty string)', 'INVALID_INPUT');
40
31
  if (targetUrl.length > MAX_URL_LENGTH)
41
- return err(`url must be under ${MAX_URL_LENGTH} chars`, "INVALID_INPUT");
32
+ return err(`url must be under ${MAX_URL_LENGTH} chars`, 'INVALID_INPUT');
42
33
  if (kind !== undefined && kind !== null) {
43
- if (typeof kind !== "string" || kind.length > MAX_KIND_LENGTH) {
44
- return err(
45
- `kind must be a string, max ${MAX_KIND_LENGTH} chars`,
46
- "INVALID_INPUT",
47
- );
34
+ if (typeof kind !== 'string' || kind.length > MAX_KIND_LENGTH) {
35
+ return err(`kind must be a string, max ${MAX_KIND_LENGTH} chars`, 'INVALID_INPUT');
48
36
  }
49
37
  }
50
38
  if (tags !== undefined && tags !== null) {
51
- if (!Array.isArray(tags))
52
- return err("tags must be an array of strings", "INVALID_INPUT");
39
+ if (!Array.isArray(tags)) return err('tags must be an array of strings', 'INVALID_INPUT');
53
40
  if (tags.length > MAX_TAGS_COUNT)
54
- return err(`tags: max ${MAX_TAGS_COUNT} tags allowed`, "INVALID_INPUT");
41
+ return err(`tags: max ${MAX_TAGS_COUNT} tags allowed`, 'INVALID_INPUT');
55
42
  for (const tag of tags) {
56
- if (typeof tag !== "string" || tag.length > MAX_TAG_LENGTH) {
57
- return err(
58
- `each tag must be a string, max ${MAX_TAG_LENGTH} chars`,
59
- "INVALID_INPUT",
60
- );
43
+ if (typeof tag !== 'string' || tag.length > MAX_TAG_LENGTH) {
44
+ return err(`each tag must be a string, max ${MAX_TAG_LENGTH} chars`, 'INVALID_INPUT');
61
45
  }
62
46
  }
63
47
  }
@@ -65,23 +49,23 @@ export async function handler(
65
49
  await ensureIndexed();
66
50
 
67
51
  try {
68
- const { ingestUrl } = await import("../../capture/ingest-url.js");
52
+ const { ingestUrl } = await import('../../capture/ingest-url.js');
69
53
  const entryData = await ingestUrl(targetUrl, { kind, tags });
70
54
  const entry = await captureAndIndex(ctx, { ...entryData });
71
55
  const relPath = entry.filePath
72
- ? entry.filePath.replace(config.vaultDir + "/", "")
56
+ ? entry.filePath.replace(config.vaultDir + '/', '')
73
57
  : entry.filePath;
74
58
  const parts = [
75
59
  `✓ Ingested URL → ${relPath}`,
76
60
  ` id: ${entry.id}`,
77
- ` title: ${entry.title || "(untitled)"}`,
61
+ ` title: ${entry.title || '(untitled)'}`,
78
62
  ` source: ${entry.source || targetUrl}`,
79
63
  ];
80
- if (entry.tags?.length) parts.push(` tags: ${entry.tags.join(", ")}`);
64
+ if (entry.tags?.length) parts.push(` tags: ${entry.tags.join(', ')}`);
81
65
  parts.push(` body: ${entry.body?.length || 0} chars`);
82
- parts.push("", "_Use this id to update or delete later._");
83
- return ok(parts.join("\n"));
66
+ parts.push('', '_Use this id to update or delete later._');
67
+ return ok(parts.join('\n'));
84
68
  } catch (e) {
85
- return err(`Failed to ingest URL: ${e.message}`, "INGEST_FAILED");
69
+ return err(`Failed to ingest URL: ${e.message}`, 'INGEST_FAILED');
86
70
  }
87
71
  }
@@ -1,7 +1,7 @@
1
- import { z } from "zod";
2
- import { ok } from "../helpers.js";
1
+ import { z } from 'zod';
2
+ import { ok } from '../helpers.js';
3
3
 
4
- export const name = "list_buckets";
4
+ export const name = 'list_buckets';
5
5
 
6
6
  export const description =
7
7
  "List all registered bucket entities in the vault. Buckets are named scopes used to group entries via 'bucket:' prefixed tags. Returns each bucket's name, description, parent, and optional entry count.";
@@ -11,7 +11,7 @@ export const inputSchema = {
11
11
  .boolean()
12
12
  .optional()
13
13
  .describe(
14
- "Include count of entries tagged with each bucket (default true). Set false to skip the count queries for faster response.",
14
+ 'Include count of entries tagged with each bucket (default true). Set false to skip the count queries for faster response.'
15
15
  ),
16
16
  };
17
17
 
@@ -20,14 +20,10 @@ export const inputSchema = {
20
20
  * @param {import('../types.js').BaseCtx & Partial<import('../types.js').HostedCtxExtensions>} ctx
21
21
  * @param {import('../types.js').ToolShared} shared
22
22
  */
23
- export async function handler(
24
- { include_counts = true },
25
- ctx,
26
- { ensureIndexed, reindexFailed },
27
- ) {
23
+ export async function handler({ include_counts = true }, ctx, { ensureIndexed, reindexFailed }) {
28
24
  await ensureIndexed();
29
25
 
30
- const userClause = "";
26
+ const userClause = '';
31
27
  const userParams = [];
32
28
 
33
29
  const buckets = ctx.db
@@ -38,20 +34,20 @@ export async function handler(
38
34
  AND (expires_at IS NULL OR expires_at > datetime('now'))
39
35
  AND superseded_by IS NULL
40
36
  ${userClause}
41
- ORDER BY title ASC`,
37
+ ORDER BY title ASC`
42
38
  )
43
39
  .all(...userParams);
44
40
 
45
41
  if (!buckets.length) {
46
42
  return ok(
47
- 'No buckets registered.\n\nCreate one with `save_context(kind: "bucket", identity_key: "bucket:myproject", title: "My Project", body: "...")` to register a bucket.',
43
+ 'No buckets registered.\n\nCreate one with `save_context(kind: "bucket", identity_key: "bucket:myproject", title: "My Project", body: "...")` to register a bucket.'
48
44
  );
49
45
  }
50
46
 
51
47
  const lines = [];
52
48
  if (reindexFailed) {
53
49
  lines.push(
54
- `> **Warning:** Auto-reindex failed. Results may be stale. Run \`context-vault reindex\` to fix.\n`,
50
+ `> **Warning:** Auto-reindex failed. Results may be stale. Run \`context-vault reindex\` to fix.\n`
55
51
  );
56
52
  }
57
53
  lines.push(`## Registered Buckets (${buckets.length})\n`);
@@ -60,21 +56,19 @@ export async function handler(
60
56
  let meta = {};
61
57
  if (b.meta) {
62
58
  try {
63
- meta = typeof b.meta === "string" ? JSON.parse(b.meta) : b.meta;
59
+ meta = typeof b.meta === 'string' ? JSON.parse(b.meta) : b.meta;
64
60
  } catch {
65
61
  meta = {};
66
62
  }
67
63
  }
68
64
 
69
65
  const bucketTags = b.tags ? JSON.parse(b.tags) : [];
70
- const name = b.identity_key
71
- ? b.identity_key.replace(/^bucket:/, "")
72
- : b.title || b.id;
66
+ const name = b.identity_key ? b.identity_key.replace(/^bucket:/, '') : b.title || b.id;
73
67
  const parent = meta.parent || null;
74
68
 
75
69
  let entryCount = null;
76
70
  if (include_counts && b.identity_key) {
77
- const countUserClause = "";
71
+ const countUserClause = '';
78
72
  const countParams = [];
79
73
  const row = ctx.db
80
74
  .prepare(
@@ -83,7 +77,7 @@ export async function handler(
83
77
  AND kind != 'bucket'
84
78
  AND (expires_at IS NULL OR expires_at > datetime('now'))
85
79
  AND superseded_by IS NULL
86
- ${countUserClause}`,
80
+ ${countUserClause}`
87
81
  )
88
82
  .get(`%"${b.identity_key}"%`, ...countParams);
89
83
  entryCount = row ? row.c : 0;
@@ -94,20 +88,20 @@ export async function handler(
94
88
  if (b.identity_key) headerParts.push(`\`${b.identity_key}\``);
95
89
  if (parent) headerParts.push(`parent: ${parent}`);
96
90
  if (entryCount !== null) headerParts.push(`${entryCount} entries`);
97
- lines.push(`- ${headerParts.join("")}`);
91
+ lines.push(`- ${headerParts.join('')}`);
98
92
 
99
93
  if (b.body) {
100
- const preview = b.body.replace(/\n+/g, " ").trim().slice(0, 120);
101
- lines.push(` ${preview}${b.body.length > 120 ? "" : ""}`);
94
+ const preview = b.body.replace(/\n+/g, ' ').trim().slice(0, 120);
95
+ lines.push(` ${preview}${b.body.length > 120 ? '' : ''}`);
102
96
  }
103
97
  if (bucketTags.length) {
104
- lines.push(` tags: ${bucketTags.join(", ")}`);
98
+ lines.push(` tags: ${bucketTags.join(', ')}`);
105
99
  }
106
100
  }
107
101
 
108
102
  lines.push(
109
- '\n_Register a new bucket with `save_context(kind: "bucket", identity_key: "bucket:<name>", title: "...", body: "...")`_',
103
+ '\n_Register a new bucket with `save_context(kind: "bucket", identity_key: "bucket:<name>", title: "...", body: "...")`_'
110
104
  );
111
105
 
112
- return ok(lines.join("\n"));
106
+ return ok(lines.join('\n'));
113
107
  }