context-vault 3.1.6 → 3.1.8
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/bin/cli.js +1369 -1774
- package/dist/archive.d.ts +23 -0
- package/dist/archive.d.ts.map +1 -0
- package/dist/archive.js +197 -0
- package/dist/archive.js.map +1 -0
- package/dist/consolidation.d.ts +14 -0
- package/dist/consolidation.d.ts.map +1 -0
- package/dist/consolidation.js +59 -0
- package/dist/consolidation.js.map +1 -0
- package/dist/error-log.d.ts +4 -0
- package/dist/error-log.d.ts.map +1 -0
- package/dist/error-log.js +33 -0
- package/dist/error-log.js.map +1 -0
- package/dist/helpers.d.ts +10 -0
- package/dist/helpers.d.ts.map +1 -0
- package/dist/helpers.js +42 -0
- package/dist/helpers.js.map +1 -0
- package/dist/linking.d.ts +13 -0
- package/dist/linking.d.ts.map +1 -0
- package/dist/linking.js +86 -0
- package/dist/linking.js.map +1 -0
- package/dist/migrate-dirs.d.ts +16 -0
- package/dist/migrate-dirs.d.ts.map +1 -0
- package/dist/migrate-dirs.js +127 -0
- package/dist/migrate-dirs.js.map +1 -0
- package/dist/register-tools.d.ts +3 -0
- package/dist/register-tools.d.ts.map +1 -0
- package/dist/register-tools.js +161 -0
- package/dist/register-tools.js.map +1 -0
- package/dist/server.d.ts +3 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +241 -0
- package/dist/server.js.map +1 -0
- package/dist/status.d.ts +18 -0
- package/dist/status.d.ts.map +1 -0
- package/dist/status.js +265 -0
- package/dist/status.js.map +1 -0
- package/dist/telemetry.d.ts +6 -0
- package/dist/telemetry.d.ts.map +1 -0
- package/dist/telemetry.js +74 -0
- package/dist/telemetry.js.map +1 -0
- package/dist/temporal.d.ts +9 -0
- package/dist/temporal.d.ts.map +1 -0
- package/dist/temporal.js +76 -0
- package/dist/temporal.js.map +1 -0
- package/dist/tools/clear-context.d.ts +11 -0
- package/dist/tools/clear-context.d.ts.map +1 -0
- package/dist/tools/clear-context.js +28 -0
- package/dist/tools/clear-context.js.map +1 -0
- package/dist/tools/context-status.d.ts +6 -0
- package/dist/tools/context-status.d.ts.map +1 -0
- package/dist/tools/context-status.js +160 -0
- package/dist/tools/context-status.js.map +1 -0
- package/dist/tools/create-snapshot.d.ts +13 -0
- package/dist/tools/create-snapshot.d.ts.map +1 -0
- package/dist/tools/create-snapshot.js +161 -0
- package/dist/tools/create-snapshot.js.map +1 -0
- package/dist/tools/delete-context.d.ts +9 -0
- package/dist/tools/delete-context.d.ts.map +1 -0
- package/dist/tools/delete-context.js +45 -0
- package/dist/tools/delete-context.js.map +1 -0
- package/dist/tools/get-context.d.ts +85 -0
- package/dist/tools/get-context.d.ts.map +1 -0
- package/dist/tools/get-context.js +576 -0
- package/dist/tools/get-context.js.map +1 -0
- package/dist/tools/ingest-project.d.ts +11 -0
- package/dist/tools/ingest-project.d.ts.map +1 -0
- package/dist/tools/ingest-project.js +226 -0
- package/dist/tools/ingest-project.js.map +1 -0
- package/dist/tools/ingest-url.d.ts +11 -0
- package/dist/tools/ingest-url.d.ts.map +1 -0
- package/dist/tools/ingest-url.js +62 -0
- package/dist/tools/ingest-url.js.map +1 -0
- package/dist/tools/list-buckets.d.ts +9 -0
- package/dist/tools/list-buckets.d.ts.map +1 -0
- package/dist/tools/list-buckets.js +76 -0
- package/dist/tools/list-buckets.js.map +1 -0
- package/dist/tools/list-context.d.ts +19 -0
- package/dist/tools/list-context.d.ts.map +1 -0
- package/dist/tools/list-context.js +110 -0
- package/dist/tools/list-context.js.map +1 -0
- package/dist/tools/save-context.d.ts +36 -0
- package/dist/tools/save-context.d.ts.map +1 -0
- package/dist/tools/save-context.js +458 -0
- package/dist/tools/save-context.js.map +1 -0
- package/dist/tools/session-start.d.ts +11 -0
- package/dist/tools/session-start.d.ts.map +1 -0
- package/dist/tools/session-start.js +224 -0
- package/dist/tools/session-start.js.map +1 -0
- package/dist/types.d.ts +37 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/node_modules/@context-vault/core/dist/capture.d.ts +1 -1
- package/node_modules/@context-vault/core/dist/capture.d.ts.map +1 -1
- package/node_modules/@context-vault/core/dist/capture.js +34 -47
- package/node_modules/@context-vault/core/dist/capture.js.map +1 -1
- package/node_modules/@context-vault/core/dist/categories.js +30 -30
- package/node_modules/@context-vault/core/dist/config.d.ts +1 -1
- package/node_modules/@context-vault/core/dist/config.d.ts.map +1 -1
- package/node_modules/@context-vault/core/dist/config.js +37 -43
- package/node_modules/@context-vault/core/dist/config.js.map +1 -1
- package/node_modules/@context-vault/core/dist/constants.d.ts +1 -1
- package/node_modules/@context-vault/core/dist/constants.d.ts.map +1 -1
- package/node_modules/@context-vault/core/dist/constants.js +4 -4
- package/node_modules/@context-vault/core/dist/constants.js.map +1 -1
- package/node_modules/@context-vault/core/dist/db.d.ts +2 -2
- package/node_modules/@context-vault/core/dist/db.d.ts.map +1 -1
- package/node_modules/@context-vault/core/dist/db.js +21 -20
- package/node_modules/@context-vault/core/dist/db.js.map +1 -1
- package/node_modules/@context-vault/core/dist/embed.d.ts.map +1 -1
- package/node_modules/@context-vault/core/dist/embed.js +11 -11
- package/node_modules/@context-vault/core/dist/embed.js.map +1 -1
- package/node_modules/@context-vault/core/dist/files.d.ts.map +1 -1
- package/node_modules/@context-vault/core/dist/files.js +12 -13
- package/node_modules/@context-vault/core/dist/files.js.map +1 -1
- package/node_modules/@context-vault/core/dist/formatters.js +5 -5
- package/node_modules/@context-vault/core/dist/frontmatter.d.ts.map +1 -1
- package/node_modules/@context-vault/core/dist/frontmatter.js +23 -23
- package/node_modules/@context-vault/core/dist/frontmatter.js.map +1 -1
- package/node_modules/@context-vault/core/dist/index.d.ts +1 -1
- package/node_modules/@context-vault/core/dist/index.d.ts.map +1 -1
- package/node_modules/@context-vault/core/dist/index.js +58 -46
- package/node_modules/@context-vault/core/dist/index.js.map +1 -1
- package/node_modules/@context-vault/core/dist/ingest-url.d.ts.map +1 -1
- package/node_modules/@context-vault/core/dist/ingest-url.js +30 -33
- package/node_modules/@context-vault/core/dist/ingest-url.js.map +1 -1
- package/node_modules/@context-vault/core/dist/main.d.ts +13 -13
- package/node_modules/@context-vault/core/dist/main.d.ts.map +1 -1
- package/node_modules/@context-vault/core/dist/main.js +12 -12
- package/node_modules/@context-vault/core/dist/main.js.map +1 -1
- package/node_modules/@context-vault/core/dist/search.d.ts +1 -1
- package/node_modules/@context-vault/core/dist/search.d.ts.map +1 -1
- package/node_modules/@context-vault/core/dist/search.js +20 -22
- package/node_modules/@context-vault/core/dist/search.js.map +1 -1
- package/node_modules/@context-vault/core/dist/types.d.ts +1 -1
- package/node_modules/@context-vault/core/package.json +1 -1
- package/node_modules/@context-vault/core/src/capture.ts +44 -81
- package/node_modules/@context-vault/core/src/categories.ts +30 -30
- package/node_modules/@context-vault/core/src/config.ts +45 -60
- package/node_modules/@context-vault/core/src/constants.ts +8 -10
- package/node_modules/@context-vault/core/src/db.ts +37 -56
- package/node_modules/@context-vault/core/src/embed.ts +15 -26
- package/node_modules/@context-vault/core/src/files.ts +13 -16
- package/node_modules/@context-vault/core/src/formatters.ts +5 -5
- package/node_modules/@context-vault/core/src/frontmatter.ts +26 -30
- package/node_modules/@context-vault/core/src/index.ts +94 -100
- package/node_modules/@context-vault/core/src/ingest-url.ts +56 -93
- package/node_modules/@context-vault/core/src/main.ts +13 -18
- package/node_modules/@context-vault/core/src/search.ts +34 -56
- package/node_modules/@context-vault/core/src/types.ts +1 -1
- package/package.json +10 -4
- package/scripts/postinstall.js +18 -25
- package/scripts/prepack.js +13 -19
- package/src/archive.ts +244 -0
- package/src/consolidation.ts +78 -0
- package/src/{error-log.js → error-log.ts} +10 -10
- package/src/helpers.ts +61 -0
- package/src/{linking.js → linking.ts} +22 -20
- package/src/migrate-dirs.ts +152 -0
- package/src/register-tools.ts +183 -0
- package/src/{server.js → server.ts} +89 -109
- package/src/{status.js → status.ts} +94 -108
- package/src/telemetry.ts +80 -0
- package/src/{temporal.js → temporal.ts} +29 -33
- package/src/tools/clear-context.ts +41 -0
- package/src/tools/{context-status.js → context-status.ts} +43 -66
- package/src/tools/{create-snapshot.js → create-snapshot.ts} +54 -65
- package/src/tools/delete-context.ts +53 -0
- package/src/tools/{get-context.js → get-context.ts} +142 -205
- package/src/tools/ingest-project.ts +260 -0
- package/src/tools/ingest-url.ts +74 -0
- package/src/tools/{list-buckets.js → list-buckets.ts} +27 -37
- package/src/tools/{list-context.js → list-context.ts} +46 -71
- package/src/tools/{save-context.js → save-context.ts} +148 -204
- package/src/tools/{session-start.js → session-start.ts} +72 -79
- package/src/types.ts +29 -0
- package/src/helpers.js +0 -57
- package/src/register-tools.js +0 -175
- package/src/telemetry.js +0 -80
- package/src/tools/clear-context.js +0 -47
- package/src/tools/delete-context.js +0 -54
- package/src/tools/ingest-project.js +0 -272
- package/src/tools/ingest-url.js +0 -87
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
import { ok } from "../helpers.js";
|
|
3
|
-
|
|
4
|
-
export const name = "clear_context";
|
|
5
|
-
|
|
6
|
-
export const description =
|
|
7
|
-
"Reset active in-memory session context without deleting vault entries. Call this when switching projects or topics mid-session. With `scope`, all subsequent get_context calls should filter to that tag/project. Vault data is never modified.";
|
|
8
|
-
|
|
9
|
-
export const inputSchema = {
|
|
10
|
-
scope: z
|
|
11
|
-
.string()
|
|
12
|
-
.optional()
|
|
13
|
-
.describe(
|
|
14
|
-
"Optional tag or project name to focus on going forward. When provided, treat subsequent get_context calls as if filtered to this tag.",
|
|
15
|
-
),
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* @param {object} args
|
|
20
|
-
* @param {import('../types.js').BaseCtx & Partial<import('../types.js').HostedCtxExtensions>} _ctx
|
|
21
|
-
*/
|
|
22
|
-
export function handler({ scope } = {}) {
|
|
23
|
-
const lines = [
|
|
24
|
-
"## Context Reset",
|
|
25
|
-
"",
|
|
26
|
-
"Active session context has been cleared. All previous context from this session should be disregarded.",
|
|
27
|
-
"",
|
|
28
|
-
"Vault entries are unchanged — no data was deleted.",
|
|
29
|
-
];
|
|
30
|
-
|
|
31
|
-
if (scope?.trim()) {
|
|
32
|
-
const trimmed = scope.trim();
|
|
33
|
-
lines.push(
|
|
34
|
-
"",
|
|
35
|
-
`### Active Scope: \`${trimmed}\``,
|
|
36
|
-
"",
|
|
37
|
-
`Going forward, treat \`get_context\` calls as scoped to the tag or project **"${trimmed}"** unless the user explicitly requests a different scope or passes their own tag filters.`,
|
|
38
|
-
);
|
|
39
|
-
} else {
|
|
40
|
-
lines.push(
|
|
41
|
-
"",
|
|
42
|
-
"No scope set. Use `get_context` normally — all vault entries are accessible.",
|
|
43
|
-
);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
return ok(lines.join("\n"));
|
|
47
|
-
}
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
import { unlinkSync } from "node:fs";
|
|
3
|
-
import { ok, err } from "../helpers.js";
|
|
4
|
-
|
|
5
|
-
export const name = "delete_context";
|
|
6
|
-
|
|
7
|
-
export const description =
|
|
8
|
-
"Delete an entry from your vault by its ULID id. Removes the file from disk and cleans up the search index.";
|
|
9
|
-
|
|
10
|
-
export const inputSchema = {
|
|
11
|
-
id: z.string().describe("The entry ULID to delete"),
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* @param {object} args
|
|
16
|
-
* @param {import('../types.js').BaseCtx & Partial<import('../types.js').HostedCtxExtensions>} ctx
|
|
17
|
-
* @param {import('../types.js').ToolShared} shared
|
|
18
|
-
*/
|
|
19
|
-
export async function handler({ id }, ctx, { ensureIndexed }) {
|
|
20
|
-
if (!id?.trim())
|
|
21
|
-
return err("Required: id (non-empty string)", "INVALID_INPUT");
|
|
22
|
-
await ensureIndexed();
|
|
23
|
-
|
|
24
|
-
const entry = ctx.stmts.getEntryById.get(id);
|
|
25
|
-
if (!entry) return err(`Entry not found: ${id}`, "NOT_FOUND");
|
|
26
|
-
|
|
27
|
-
try {
|
|
28
|
-
// Delete DB record first — if this fails, the file stays and no orphan is created
|
|
29
|
-
const rowidResult = ctx.stmts.getRowid.get(id);
|
|
30
|
-
if (rowidResult?.rowid) {
|
|
31
|
-
try {
|
|
32
|
-
ctx.deleteVec(Number(rowidResult.rowid));
|
|
33
|
-
} catch {}
|
|
34
|
-
}
|
|
35
|
-
ctx.stmts.deleteEntry.run(id);
|
|
36
|
-
|
|
37
|
-
// Delete file from disk after successful DB delete
|
|
38
|
-
let fileWarning = null;
|
|
39
|
-
if (entry.file_path) {
|
|
40
|
-
try {
|
|
41
|
-
unlinkSync(entry.file_path);
|
|
42
|
-
} catch (e) {
|
|
43
|
-
if (e.code !== "ENOENT") {
|
|
44
|
-
fileWarning = `file could not be removed from disk (${e.code}): ${entry.file_path}`;
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
const msg = `Deleted ${entry.kind}: ${entry.title || "(untitled)"} [${id}]`;
|
|
50
|
-
return ok(fileWarning ? `${msg}\nWarning: ${fileWarning}` : msg);
|
|
51
|
-
} catch (e) {
|
|
52
|
-
return err(e.message, "DELETE_FAILED");
|
|
53
|
-
}
|
|
54
|
-
}
|
|
@@ -1,272 +0,0 @@
|
|
|
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
|
-
|
|
8
|
-
export const name = "ingest_project";
|
|
9
|
-
|
|
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.";
|
|
12
|
-
|
|
13
|
-
export const inputSchema = {
|
|
14
|
-
path: z.string().describe("Absolute path to the project directory to ingest"),
|
|
15
|
-
tags: z
|
|
16
|
-
.array(z.string())
|
|
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"),
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
function safeRead(filePath) {
|
|
26
|
-
try {
|
|
27
|
-
return readFileSync(filePath, "utf-8");
|
|
28
|
-
} catch {
|
|
29
|
-
return null;
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
function safeExec(cmd, cwd) {
|
|
34
|
-
try {
|
|
35
|
-
return execSync(cmd, {
|
|
36
|
-
cwd,
|
|
37
|
-
encoding: "utf-8",
|
|
38
|
-
stdio: ["pipe", "pipe", "pipe"],
|
|
39
|
-
}).trim();
|
|
40
|
-
} catch {
|
|
41
|
-
return null;
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
function detectTechStack(projectPath, pkgJson) {
|
|
46
|
-
const stack = [];
|
|
47
|
-
|
|
48
|
-
if (
|
|
49
|
-
existsSync(join(projectPath, "pyproject.toml")) ||
|
|
50
|
-
existsSync(join(projectPath, "setup.py"))
|
|
51
|
-
) {
|
|
52
|
-
stack.push("python");
|
|
53
|
-
}
|
|
54
|
-
if (existsSync(join(projectPath, "Cargo.toml"))) {
|
|
55
|
-
stack.push("rust");
|
|
56
|
-
}
|
|
57
|
-
if (existsSync(join(projectPath, "go.mod"))) {
|
|
58
|
-
stack.push("go");
|
|
59
|
-
}
|
|
60
|
-
if (pkgJson) {
|
|
61
|
-
stack.push("javascript");
|
|
62
|
-
const allDeps = {
|
|
63
|
-
...(pkgJson.dependencies || {}),
|
|
64
|
-
...(pkgJson.devDependencies || {}),
|
|
65
|
-
};
|
|
66
|
-
if (allDeps.typescript || existsSync(join(projectPath, "tsconfig.json"))) {
|
|
67
|
-
stack.push("typescript");
|
|
68
|
-
}
|
|
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");
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
return [...new Set(stack)];
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
function extractReadmeDescription(projectPath) {
|
|
85
|
-
const raw =
|
|
86
|
-
safeRead(join(projectPath, "README.md")) ||
|
|
87
|
-
safeRead(join(projectPath, "readme.md"));
|
|
88
|
-
if (!raw) return null;
|
|
89
|
-
for (const line of raw.split("\n")) {
|
|
90
|
-
const trimmed = line.trim();
|
|
91
|
-
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
92
|
-
return trimmed.slice(0, 200);
|
|
93
|
-
}
|
|
94
|
-
return null;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
function buildProjectBody({
|
|
98
|
-
projectName,
|
|
99
|
-
description,
|
|
100
|
-
techStack,
|
|
101
|
-
repoUrl,
|
|
102
|
-
lastCommit,
|
|
103
|
-
projectPath,
|
|
104
|
-
hasClaudeMd,
|
|
105
|
-
}) {
|
|
106
|
-
const lines = [];
|
|
107
|
-
lines.push(`## ${projectName}`);
|
|
108
|
-
if (description) lines.push("", description);
|
|
109
|
-
lines.push("", "### Metadata");
|
|
110
|
-
lines.push(`- **Path**: \`${projectPath}\``);
|
|
111
|
-
if (repoUrl) lines.push(`- **Repo**: ${repoUrl}`);
|
|
112
|
-
if (techStack.length) lines.push(`- **Stack**: ${techStack.join(", ")}`);
|
|
113
|
-
if (lastCommit) lines.push(`- **Last commit**: ${lastCommit}`);
|
|
114
|
-
lines.push(`- **CLAUDE.md**: ${hasClaudeMd ? "yes" : "no"}`);
|
|
115
|
-
return lines.join("\n");
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
/**
|
|
119
|
-
* @param {object} args
|
|
120
|
-
* @param {import('../types.js').BaseCtx & Partial<import('../types.js').HostedCtxExtensions>} ctx
|
|
121
|
-
* @param {import('../types.js').ToolShared} shared
|
|
122
|
-
*/
|
|
123
|
-
export async function handler(
|
|
124
|
-
{ path: projectPath, tags, pillar },
|
|
125
|
-
ctx,
|
|
126
|
-
{ ensureIndexed },
|
|
127
|
-
) {
|
|
128
|
-
const { config } = ctx;
|
|
129
|
-
|
|
130
|
-
const vaultErr = ensureVaultExists(config);
|
|
131
|
-
if (vaultErr) return vaultErr;
|
|
132
|
-
|
|
133
|
-
if (!projectPath?.trim()) {
|
|
134
|
-
return err(
|
|
135
|
-
"Required: path (absolute path to project directory)",
|
|
136
|
-
"INVALID_INPUT",
|
|
137
|
-
);
|
|
138
|
-
}
|
|
139
|
-
if (!existsSync(projectPath)) {
|
|
140
|
-
return err(`Directory not found: ${projectPath}`, "INVALID_INPUT");
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
await ensureIndexed();
|
|
144
|
-
|
|
145
|
-
// Read package.json if present
|
|
146
|
-
let pkgJson = null;
|
|
147
|
-
const pkgPath = join(projectPath, "package.json");
|
|
148
|
-
if (existsSync(pkgPath)) {
|
|
149
|
-
try {
|
|
150
|
-
pkgJson = JSON.parse(readFileSync(pkgPath, "utf-8"));
|
|
151
|
-
} catch {
|
|
152
|
-
pkgJson = null;
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
// Derive project name
|
|
157
|
-
let projectName = basename(projectPath);
|
|
158
|
-
if (pkgJson?.name) {
|
|
159
|
-
projectName = pkgJson.name.replace(/^@[^/]+\//, "");
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
// Slug-safe identity_key
|
|
163
|
-
const identityKey = projectName
|
|
164
|
-
.toLowerCase()
|
|
165
|
-
.replace(/[^a-z0-9-]/g, "-")
|
|
166
|
-
.replace(/-+/g, "-")
|
|
167
|
-
.replace(/^-|-$/g, "");
|
|
168
|
-
|
|
169
|
-
// Description: package.json > README
|
|
170
|
-
const description =
|
|
171
|
-
pkgJson?.description || extractReadmeDescription(projectPath) || null;
|
|
172
|
-
|
|
173
|
-
// Tech stack detection
|
|
174
|
-
const techStack = detectTechStack(projectPath, pkgJson);
|
|
175
|
-
|
|
176
|
-
// 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;
|
|
184
|
-
|
|
185
|
-
// CLAUDE.md presence
|
|
186
|
-
const hasClaudeMd = existsSync(join(projectPath, "CLAUDE.md"));
|
|
187
|
-
|
|
188
|
-
// Build tags
|
|
189
|
-
const bucketTag = `bucket:${identityKey}`;
|
|
190
|
-
const autoTags = [bucketTag];
|
|
191
|
-
if (pillar) autoTags.push(`bucket:${pillar}`);
|
|
192
|
-
const allTags = [...new Set([...autoTags, ...(tags || [])])];
|
|
193
|
-
|
|
194
|
-
// Build body
|
|
195
|
-
const body = buildProjectBody({
|
|
196
|
-
projectName,
|
|
197
|
-
description,
|
|
198
|
-
techStack,
|
|
199
|
-
repoUrl,
|
|
200
|
-
lastCommit,
|
|
201
|
-
projectPath,
|
|
202
|
-
hasClaudeMd,
|
|
203
|
-
});
|
|
204
|
-
|
|
205
|
-
// Build meta
|
|
206
|
-
const meta = {
|
|
207
|
-
path: projectPath,
|
|
208
|
-
...(repoUrl ? { repo_url: repoUrl } : {}),
|
|
209
|
-
...(techStack.length ? { tech_stack: techStack } : {}),
|
|
210
|
-
has_claude_md: hasClaudeMd,
|
|
211
|
-
};
|
|
212
|
-
|
|
213
|
-
// Save project entity
|
|
214
|
-
const projectEntry = await captureAndIndex(ctx, {
|
|
215
|
-
kind: "project",
|
|
216
|
-
title: projectName,
|
|
217
|
-
body,
|
|
218
|
-
tags: allTags,
|
|
219
|
-
identity_key: identityKey,
|
|
220
|
-
meta,
|
|
221
|
-
});
|
|
222
|
-
|
|
223
|
-
// Save bucket entity if it doesn't already exist
|
|
224
|
-
const bucketUserClause = "";
|
|
225
|
-
const bucketParams = false ? [bucketTag] : [bucketTag];
|
|
226
|
-
const bucketExists = ctx.db
|
|
227
|
-
.prepare(
|
|
228
|
-
`SELECT 1 FROM vault WHERE kind = 'bucket' AND identity_key = ? ${bucketUserClause} LIMIT 1`,
|
|
229
|
-
)
|
|
230
|
-
.get(...bucketParams);
|
|
231
|
-
|
|
232
|
-
let bucketEntry = null;
|
|
233
|
-
if (!bucketExists) {
|
|
234
|
-
bucketEntry = await captureAndIndex(ctx, {
|
|
235
|
-
kind: "bucket",
|
|
236
|
-
title: projectName,
|
|
237
|
-
body: `Bucket for project: ${projectName}`,
|
|
238
|
-
tags: allTags,
|
|
239
|
-
identity_key: bucketTag,
|
|
240
|
-
meta: { project_path: projectPath },
|
|
241
|
-
});
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
const relPath = projectEntry.filePath
|
|
245
|
-
? projectEntry.filePath.replace(config.vaultDir + "/", "")
|
|
246
|
-
: projectEntry.filePath;
|
|
247
|
-
|
|
248
|
-
const parts = [
|
|
249
|
-
`✓ Ingested project → ${relPath}`,
|
|
250
|
-
` id: ${projectEntry.id}`,
|
|
251
|
-
` title: ${projectEntry.title}`,
|
|
252
|
-
` tags: ${allTags.join(", ")}`,
|
|
253
|
-
...(techStack.length ? [` stack: ${techStack.join(", ")}`] : []),
|
|
254
|
-
...(repoUrl ? [` repo: ${repoUrl}`] : []),
|
|
255
|
-
];
|
|
256
|
-
|
|
257
|
-
if (bucketEntry) {
|
|
258
|
-
const bucketRelPath = bucketEntry.filePath
|
|
259
|
-
? bucketEntry.filePath.replace(config.vaultDir + "/", "")
|
|
260
|
-
: bucketEntry.filePath;
|
|
261
|
-
parts.push(``, `✓ Created bucket → ${bucketRelPath}`);
|
|
262
|
-
parts.push(` id: ${bucketEntry.id}`);
|
|
263
|
-
} else {
|
|
264
|
-
parts.push(``, ` (bucket '${bucketTag}' already exists — skipped)`);
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
parts.push(
|
|
268
|
-
"",
|
|
269
|
-
"_Use get_context with bucket tag to retrieve project-scoped entries._",
|
|
270
|
-
);
|
|
271
|
-
return ok(parts.join("\n"));
|
|
272
|
-
}
|
package/src/tools/ingest-url.js
DELETED
|
@@ -1,87 +0,0 @@
|
|
|
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";
|
|
9
|
-
|
|
10
|
-
const MAX_URL_LENGTH = 2048;
|
|
11
|
-
|
|
12
|
-
export const name = "ingest_url";
|
|
13
|
-
|
|
14
|
-
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.";
|
|
16
|
-
|
|
17
|
-
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"),
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* @param {object} args
|
|
25
|
-
* @param {import('../types.js').BaseCtx & Partial<import('../types.js').HostedCtxExtensions>} ctx
|
|
26
|
-
* @param {import('../types.js').ToolShared} shared
|
|
27
|
-
*/
|
|
28
|
-
export async function handler(
|
|
29
|
-
{ url: targetUrl, kind, tags },
|
|
30
|
-
ctx,
|
|
31
|
-
{ ensureIndexed },
|
|
32
|
-
) {
|
|
33
|
-
const { config } = ctx;
|
|
34
|
-
|
|
35
|
-
const vaultErr = ensureVaultExists(config);
|
|
36
|
-
if (vaultErr) return vaultErr;
|
|
37
|
-
|
|
38
|
-
if (!targetUrl?.trim())
|
|
39
|
-
return err("Required: url (non-empty string)", "INVALID_INPUT");
|
|
40
|
-
if (targetUrl.length > MAX_URL_LENGTH)
|
|
41
|
-
return err(`url must be under ${MAX_URL_LENGTH} chars`, "INVALID_INPUT");
|
|
42
|
-
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
|
-
);
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
if (tags !== undefined && tags !== null) {
|
|
51
|
-
if (!Array.isArray(tags))
|
|
52
|
-
return err("tags must be an array of strings", "INVALID_INPUT");
|
|
53
|
-
if (tags.length > MAX_TAGS_COUNT)
|
|
54
|
-
return err(`tags: max ${MAX_TAGS_COUNT} tags allowed`, "INVALID_INPUT");
|
|
55
|
-
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
|
-
);
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
await ensureIndexed();
|
|
66
|
-
|
|
67
|
-
try {
|
|
68
|
-
const { ingestUrl } = await import("../../capture/ingest-url.js");
|
|
69
|
-
const entryData = await ingestUrl(targetUrl, { kind, tags });
|
|
70
|
-
const entry = await captureAndIndex(ctx, { ...entryData });
|
|
71
|
-
const relPath = entry.filePath
|
|
72
|
-
? entry.filePath.replace(config.vaultDir + "/", "")
|
|
73
|
-
: entry.filePath;
|
|
74
|
-
const parts = [
|
|
75
|
-
`✓ Ingested URL → ${relPath}`,
|
|
76
|
-
` id: ${entry.id}`,
|
|
77
|
-
` title: ${entry.title || "(untitled)"}`,
|
|
78
|
-
` source: ${entry.source || targetUrl}`,
|
|
79
|
-
];
|
|
80
|
-
if (entry.tags?.length) parts.push(` tags: ${entry.tags.join(", ")}`);
|
|
81
|
-
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"));
|
|
84
|
-
} catch (e) {
|
|
85
|
-
return err(`Failed to ingest URL: ${e.message}`, "INGEST_FAILED");
|
|
86
|
-
}
|
|
87
|
-
}
|