@koffeekat/diana 0.0.0-stage → 0.1.0-beta.2
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/.claude-plugin/marketplace.json +13 -0
- package/.claude-plugin/plugin.json +9 -0
- package/LICENSE.md +21 -0
- package/README.md +165 -2
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +75 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/index.d.ts +4 -0
- package/dist/commands/index.js +19 -0
- package/dist/commands/index.js.map +1 -0
- package/dist/commands/init.d.ts +4 -0
- package/dist/commands/init.js +36 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/read.d.ts +13 -0
- package/dist/commands/read.js +74 -0
- package/dist/commands/read.js.map +1 -0
- package/dist/commands/search.d.ts +13 -0
- package/dist/commands/search.js +52 -0
- package/dist/commands/search.js.map +1 -0
- package/dist/indexer.d.ts +16 -0
- package/dist/indexer.js +258 -0
- package/dist/indexer.js.map +1 -0
- package/dist/sources.d.ts +11 -0
- package/dist/sources.js +85 -0
- package/dist/sources.js.map +1 -0
- package/dist/templates/config.template.d.ts +2 -0
- package/dist/templates/config.template.js +5 -0
- package/dist/templates/config.template.js.map +1 -0
- package/dist/templates/gitignore.template.d.ts +1 -0
- package/dist/templates/gitignore.template.js +5 -0
- package/dist/templates/gitignore.template.js.map +1 -0
- package/dist/types/source.types.d.ts +4 -0
- package/dist/types/source.types.js +2 -0
- package/dist/types/source.types.js.map +1 -0
- package/dist/types/workspace.types.d.ts +27 -0
- package/dist/types/workspace.types.js +12 -0
- package/dist/types/workspace.types.js.map +1 -0
- package/dist/utils/forbiddenDirs.d.ts +1 -0
- package/dist/utils/forbiddenDirs.js +2 -0
- package/dist/utils/forbiddenDirs.js.map +1 -0
- package/dist/utils/hasErrorCode.d.ts +1 -0
- package/dist/utils/hasErrorCode.js +4 -0
- package/dist/utils/hasErrorCode.js.map +1 -0
- package/dist/utils/pathExists.d.ts +1 -0
- package/dist/utils/pathExists.js +15 -0
- package/dist/utils/pathExists.js.map +1 -0
- package/dist/workspace.d.ts +14 -0
- package/dist/workspace.js +70 -0
- package/dist/workspace.js.map +1 -0
- package/docs/security.md +32 -0
- package/img/diana-banner.webp +0 -0
- package/package.json +65 -4
- package/skills/diana/SKILL.md +23 -0
package/dist/indexer.js
ADDED
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { readdir, readFile, stat } from "node:fs/promises";
|
|
3
|
+
import { basename, posix, relative, sep } from "node:path";
|
|
4
|
+
import { DatabaseSync } from "node:sqlite";
|
|
5
|
+
const PROTECTED_DIRECTORY_NAMES = new Set([".diana", ".git"]);
|
|
6
|
+
const SCHEMA_VERSION = 1;
|
|
7
|
+
const MAX_INDEX_FILE_BYTES = 1024 * 1024;
|
|
8
|
+
export const INDEX_ERRORS = {
|
|
9
|
+
invalidTextError: (filePath) => `Source file is not valid UTF-8: ${filePath}.`,
|
|
10
|
+
fileTooLargeError: (filePath) => `Source file exceeds the ${MAX_INDEX_FILE_BYTES}-byte index limit: ${filePath}.`,
|
|
11
|
+
schemaRebuildError: "Index schema changed. Run diana index to rebuild it.",
|
|
12
|
+
};
|
|
13
|
+
export async function updateIndex(databasePath, sources, mode = "all") {
|
|
14
|
+
const database = new DatabaseSync(databasePath);
|
|
15
|
+
try {
|
|
16
|
+
database.exec("BEGIN IMMEDIATE");
|
|
17
|
+
try {
|
|
18
|
+
prepareSchema(database, mode);
|
|
19
|
+
await removeUnconfiguredSources(database, sources);
|
|
20
|
+
for (const source of sources) {
|
|
21
|
+
if (mode === "all" || source.autoReindex === true) {
|
|
22
|
+
await indexSource(database, source);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
database.exec("COMMIT");
|
|
26
|
+
}
|
|
27
|
+
catch (error) {
|
|
28
|
+
database.exec("ROLLBACK");
|
|
29
|
+
throw error;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
finally {
|
|
33
|
+
database.close();
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
export async function findMarkdownFiles(source) {
|
|
37
|
+
const markdownFiles = [];
|
|
38
|
+
await visitDirectory(source.sourceRoot, source, markdownFiles);
|
|
39
|
+
return markdownFiles;
|
|
40
|
+
}
|
|
41
|
+
export function extractMarkdownSection(markdown, requestedAnchor) {
|
|
42
|
+
const lines = markdown.replace(/\r\n?/g, "\n").split("\n");
|
|
43
|
+
const anchorCounts = new Map();
|
|
44
|
+
let sectionStart;
|
|
45
|
+
let sectionAnchor;
|
|
46
|
+
for (const [lineIndex, line] of lines.entries()) {
|
|
47
|
+
const heading = parseHeading(line);
|
|
48
|
+
if (heading === undefined) {
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
if (sectionAnchor === requestedAnchor && sectionStart !== undefined) {
|
|
52
|
+
return lines.slice(sectionStart, lineIndex).join("\n");
|
|
53
|
+
}
|
|
54
|
+
sectionStart = lineIndex;
|
|
55
|
+
sectionAnchor = createAnchor(heading, anchorCounts);
|
|
56
|
+
}
|
|
57
|
+
if (sectionAnchor === requestedAnchor && sectionStart !== undefined) {
|
|
58
|
+
return lines.slice(sectionStart).join("\n");
|
|
59
|
+
}
|
|
60
|
+
return undefined;
|
|
61
|
+
}
|
|
62
|
+
export function splitMarkdownIntoSections(markdown, filePath) {
|
|
63
|
+
const title = findTitle(markdown, filePath);
|
|
64
|
+
const lines = markdown.replace(/\r\n?/g, "\n").split("\n");
|
|
65
|
+
const sections = [];
|
|
66
|
+
const anchorCounts = new Map();
|
|
67
|
+
let currentHeading;
|
|
68
|
+
let currentAnchor;
|
|
69
|
+
let currentBody = [];
|
|
70
|
+
for (const line of lines) {
|
|
71
|
+
const heading = parseHeading(line);
|
|
72
|
+
if (heading === undefined) {
|
|
73
|
+
currentBody.push(line);
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
if (currentHeading === undefined || currentAnchor === undefined) {
|
|
77
|
+
currentHeading = heading;
|
|
78
|
+
currentAnchor = createAnchor(heading, anchorCounts);
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
addSection(sections, title, currentHeading, currentAnchor, currentBody);
|
|
82
|
+
currentHeading = heading;
|
|
83
|
+
currentAnchor = createAnchor(heading, anchorCounts);
|
|
84
|
+
currentBody = [];
|
|
85
|
+
}
|
|
86
|
+
if (currentHeading === undefined || currentAnchor === undefined) {
|
|
87
|
+
addSection(sections, title, title, createAnchor(title, anchorCounts), currentBody);
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
addSection(sections, title, currentHeading, currentAnchor, currentBody);
|
|
91
|
+
}
|
|
92
|
+
return sections;
|
|
93
|
+
}
|
|
94
|
+
function prepareSchema(database, mode) {
|
|
95
|
+
const version = database.prepare("PRAGMA user_version").get();
|
|
96
|
+
if (mode === "auto") {
|
|
97
|
+
if (version.user_version !== SCHEMA_VERSION) {
|
|
98
|
+
throw new Error(INDEX_ERRORS.schemaRebuildError);
|
|
99
|
+
}
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
if (version.user_version !== SCHEMA_VERSION) {
|
|
103
|
+
database.exec("DROP TABLE IF EXISTS sections; DROP TABLE IF EXISTS documents;");
|
|
104
|
+
}
|
|
105
|
+
database.exec(`
|
|
106
|
+
CREATE TABLE IF NOT EXISTS documents (
|
|
107
|
+
source_root TEXT NOT NULL,
|
|
108
|
+
path TEXT NOT NULL,
|
|
109
|
+
sha256 TEXT NOT NULL,
|
|
110
|
+
PRIMARY KEY (source_root, path)
|
|
111
|
+
) STRICT;
|
|
112
|
+
|
|
113
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS sections USING fts5(
|
|
114
|
+
source_root UNINDEXED,
|
|
115
|
+
path UNINDEXED,
|
|
116
|
+
title,
|
|
117
|
+
heading,
|
|
118
|
+
anchor UNINDEXED,
|
|
119
|
+
body,
|
|
120
|
+
tokenize = 'unicode61'
|
|
121
|
+
);
|
|
122
|
+
PRAGMA user_version = ${SCHEMA_VERSION};
|
|
123
|
+
`);
|
|
124
|
+
}
|
|
125
|
+
async function readMarkdownFile(filePath) {
|
|
126
|
+
const fileStats = await stat(filePath);
|
|
127
|
+
if (fileStats.size > MAX_INDEX_FILE_BYTES) {
|
|
128
|
+
throw new Error(INDEX_ERRORS.fileTooLargeError(filePath));
|
|
129
|
+
}
|
|
130
|
+
const content = await readFile(filePath);
|
|
131
|
+
try {
|
|
132
|
+
return new TextDecoder("utf-8", { fatal: true }).decode(content);
|
|
133
|
+
}
|
|
134
|
+
catch {
|
|
135
|
+
throw new Error(INDEX_ERRORS.invalidTextError(filePath));
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
async function indexSource(database, source) {
|
|
139
|
+
const markdownFiles = await findMarkdownFiles(source);
|
|
140
|
+
const currentPaths = new Set();
|
|
141
|
+
for (const filePath of markdownFiles) {
|
|
142
|
+
const documentPath = toDocumentPath(source.sourceRoot, filePath);
|
|
143
|
+
currentPaths.add(documentPath);
|
|
144
|
+
const markdown = await readMarkdownFile(filePath);
|
|
145
|
+
const sha256 = createHash("sha256").update(markdown).digest("hex");
|
|
146
|
+
const existingDocument = database
|
|
147
|
+
.prepare("SELECT sha256 FROM documents WHERE source_root = ? AND path = ?")
|
|
148
|
+
.get(source.sourceRoot, documentPath);
|
|
149
|
+
if (existingDocument?.sha256 === sha256) {
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
deleteDocument(database, source.sourceRoot, documentPath);
|
|
153
|
+
database
|
|
154
|
+
.prepare("INSERT INTO documents (source_root, path, sha256) VALUES (?, ?, ?)")
|
|
155
|
+
.run(source.sourceRoot, documentPath, sha256);
|
|
156
|
+
const insertSection = database.prepare(`
|
|
157
|
+
INSERT INTO sections (source_root, path, title, heading, anchor, body)
|
|
158
|
+
VALUES (?, ?, ?, ?, ?, ?)
|
|
159
|
+
`);
|
|
160
|
+
for (const section of splitMarkdownIntoSections(markdown, documentPath)) {
|
|
161
|
+
insertSection.run(source.sourceRoot, documentPath, section.title, section.heading, section.anchor, section.body);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
const indexedDocuments = database
|
|
165
|
+
.prepare("SELECT path FROM documents WHERE source_root = ?")
|
|
166
|
+
.all(source.sourceRoot);
|
|
167
|
+
for (const document of indexedDocuments) {
|
|
168
|
+
if (!currentPaths.has(document.path)) {
|
|
169
|
+
deleteDocument(database, source.sourceRoot, document.path);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
async function removeUnconfiguredSources(database, sources) {
|
|
174
|
+
const activeSourceRoots = new Set(sources.map((source) => source.sourceRoot));
|
|
175
|
+
const indexedSources = database
|
|
176
|
+
.prepare("SELECT DISTINCT source_root FROM documents")
|
|
177
|
+
.all();
|
|
178
|
+
for (const indexedSource of indexedSources) {
|
|
179
|
+
if (activeSourceRoots.has(indexedSource.source_root)) {
|
|
180
|
+
continue;
|
|
181
|
+
}
|
|
182
|
+
database
|
|
183
|
+
.prepare("DELETE FROM sections WHERE source_root = ?")
|
|
184
|
+
.run(indexedSource.source_root);
|
|
185
|
+
database
|
|
186
|
+
.prepare("DELETE FROM documents WHERE source_root = ?")
|
|
187
|
+
.run(indexedSource.source_root);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
function deleteDocument(database, sourceRoot, documentPath) {
|
|
191
|
+
database
|
|
192
|
+
.prepare("DELETE FROM sections WHERE source_root = ? AND path = ?")
|
|
193
|
+
.run(sourceRoot, documentPath);
|
|
194
|
+
database
|
|
195
|
+
.prepare("DELETE FROM documents WHERE source_root = ? AND path = ?")
|
|
196
|
+
.run(sourceRoot, documentPath);
|
|
197
|
+
}
|
|
198
|
+
async function visitDirectory(directoryPath, source, markdownFiles) {
|
|
199
|
+
const entries = await readdir(directoryPath, { withFileTypes: true });
|
|
200
|
+
entries.sort((left, right) => left.name.localeCompare(right.name));
|
|
201
|
+
for (const entry of entries) {
|
|
202
|
+
if (entry.isSymbolicLink() || isProtectedOrHidden(entry.name)) {
|
|
203
|
+
continue;
|
|
204
|
+
}
|
|
205
|
+
const entryPath = `${directoryPath}${sep}${entry.name}`;
|
|
206
|
+
if (entry.isDirectory()) {
|
|
207
|
+
await visitDirectory(entryPath, source, markdownFiles);
|
|
208
|
+
}
|
|
209
|
+
else if (entry.isFile() &&
|
|
210
|
+
entry.name.endsWith(".md") &&
|
|
211
|
+
matchesSourcePatterns(toDocumentPath(source.sourceRoot, entryPath), source)) {
|
|
212
|
+
markdownFiles.push(entryPath);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
function matchesSourcePatterns(documentPath, source) {
|
|
217
|
+
return (source.include.some((pattern) => posix.matchesGlob(documentPath, pattern)) &&
|
|
218
|
+
!source.exclude.some((pattern) => posix.matchesGlob(documentPath, pattern)));
|
|
219
|
+
}
|
|
220
|
+
function isProtectedOrHidden(name) {
|
|
221
|
+
return name.startsWith(".") || PROTECTED_DIRECTORY_NAMES.has(name);
|
|
222
|
+
}
|
|
223
|
+
function toDocumentPath(sourceRoot, filePath) {
|
|
224
|
+
return relative(sourceRoot, filePath).split(sep).join("/");
|
|
225
|
+
}
|
|
226
|
+
function findTitle(markdown, filePath) {
|
|
227
|
+
for (const line of markdown.split(/\r?\n/)) {
|
|
228
|
+
const heading = parseHeading(line);
|
|
229
|
+
if (heading !== undefined) {
|
|
230
|
+
return heading;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
return basename(filePath, ".md");
|
|
234
|
+
}
|
|
235
|
+
function parseHeading(line) {
|
|
236
|
+
const match = /^(#{1,6})\s+(.+?)\s*#*\s*$/.exec(line);
|
|
237
|
+
return match?.[2];
|
|
238
|
+
}
|
|
239
|
+
function createAnchor(heading, anchorCounts) {
|
|
240
|
+
const baseAnchor = heading
|
|
241
|
+
.toLowerCase()
|
|
242
|
+
.normalize("NFKD")
|
|
243
|
+
.replace(/[\u0300-\u036f]/g, "")
|
|
244
|
+
.replace(/[^\p{L}\p{N}\s-]/gu, "")
|
|
245
|
+
.trim()
|
|
246
|
+
.replace(/[\s-]+/g, "-");
|
|
247
|
+
const count = anchorCounts.get(baseAnchor) ?? 0;
|
|
248
|
+
anchorCounts.set(baseAnchor, count + 1);
|
|
249
|
+
return count === 0 ? baseAnchor : `${baseAnchor}-${count}`;
|
|
250
|
+
}
|
|
251
|
+
function addSection(sections, title, heading, anchor, lines) {
|
|
252
|
+
const body = lines.join("\n").trim();
|
|
253
|
+
if (body === "" && sections.length > 0) {
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
sections.push({ anchor, body, heading, title });
|
|
257
|
+
}
|
|
258
|
+
//# sourceMappingURL=indexer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"indexer.js","sourceRoot":"","sources":["../src/indexer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Workspace } from "./types/workspace.types.js";
|
|
2
|
+
import type { ResolvedSource } from "./types/source.types.js";
|
|
3
|
+
export declare const SOURCE_ERRORS: {
|
|
4
|
+
readonly sourceDoesNotExistError: (configuredPath: string) => string;
|
|
5
|
+
readonly sourceMustBeDirError: (sourceRoot: string) => string;
|
|
6
|
+
readonly sharedSourceOutsideWorkspaceError: (sourceRoot: string) => string;
|
|
7
|
+
readonly protectedSourceRootError: (sourceRoot: string) => string;
|
|
8
|
+
readonly overlappingSourceRootsError: (firstRoot: string, secondRoot: string) => string;
|
|
9
|
+
readonly invalidGlobPatternError: (pattern: string) => string;
|
|
10
|
+
};
|
|
11
|
+
export declare function resolveSources(workspace: Workspace): Promise<ResolvedSource[]>;
|
package/dist/sources.js
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { realpath, stat } from "node:fs/promises";
|
|
2
|
+
import { basename, isAbsolute, posix, relative, resolve, sep } from "node:path";
|
|
3
|
+
import { hasErrorCode } from "./utils/hasErrorCode.js";
|
|
4
|
+
export const SOURCE_ERRORS = {
|
|
5
|
+
sourceDoesNotExistError: (configuredPath) => `Source does not exist: ${configuredPath}.`,
|
|
6
|
+
sourceMustBeDirError: (sourceRoot) => `Source must be a directory: ${sourceRoot}.`,
|
|
7
|
+
sharedSourceOutsideWorkspaceError: (sourceRoot) => `Shared source must be inside the workspace: ${sourceRoot}.`,
|
|
8
|
+
protectedSourceRootError: (sourceRoot) => `Source root cannot be .git or .diana: ${sourceRoot}.`,
|
|
9
|
+
overlappingSourceRootsError: (firstRoot, secondRoot) => `Source roots overlap: ${firstRoot} and ${secondRoot}.`,
|
|
10
|
+
invalidGlobPatternError: (pattern) => `Invalid source glob pattern: ${pattern}.`,
|
|
11
|
+
};
|
|
12
|
+
const { sourceDoesNotExistError, sourceMustBeDirError, sharedSourceOutsideWorkspaceError, protectedSourceRootError, overlappingSourceRootsError, invalidGlobPatternError, } = SOURCE_ERRORS;
|
|
13
|
+
export async function resolveSources(workspace) {
|
|
14
|
+
const sourcePromises = [];
|
|
15
|
+
const workspaceRoot = await realpath(workspace.root);
|
|
16
|
+
workspace.sources.forEach((source) => {
|
|
17
|
+
validatePatterns(source.include);
|
|
18
|
+
validatePatterns(source.exclude);
|
|
19
|
+
sourcePromises.push(resolveSource(workspaceRoot, source));
|
|
20
|
+
});
|
|
21
|
+
const resolvedSources = await Promise.all(sourcePromises);
|
|
22
|
+
const sourceRoots = new Set();
|
|
23
|
+
const uniqueSources = [];
|
|
24
|
+
resolvedSources.forEach((source) => {
|
|
25
|
+
if (sourceRoots.has(source.sourceRoot)) {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
const overlappingSource = uniqueSources.find((existingSource) => isPathInside(existingSource.sourceRoot, source.sourceRoot) ||
|
|
29
|
+
isPathInside(source.sourceRoot, existingSource.sourceRoot));
|
|
30
|
+
if (overlappingSource !== undefined) {
|
|
31
|
+
throw new Error(overlappingSourceRootsError(overlappingSource.sourceRoot, source.sourceRoot));
|
|
32
|
+
}
|
|
33
|
+
sourceRoots.add(source.sourceRoot);
|
|
34
|
+
uniqueSources.push(source);
|
|
35
|
+
});
|
|
36
|
+
return uniqueSources;
|
|
37
|
+
}
|
|
38
|
+
async function resolveSource(workspaceRoot, source) {
|
|
39
|
+
const configuredPath = resolve(workspaceRoot, source.path);
|
|
40
|
+
let sourceRoot;
|
|
41
|
+
try {
|
|
42
|
+
sourceRoot = await realpath(configuredPath);
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
if (hasErrorCode(error, "ENOENT")) {
|
|
46
|
+
throw new Error(sourceDoesNotExistError(configuredPath));
|
|
47
|
+
}
|
|
48
|
+
throw error;
|
|
49
|
+
}
|
|
50
|
+
const sourceStats = await stat(sourceRoot);
|
|
51
|
+
if (!sourceStats.isDirectory()) {
|
|
52
|
+
throw new Error(sourceMustBeDirError(sourceRoot));
|
|
53
|
+
}
|
|
54
|
+
if ([".diana", ".git"].includes(basename(sourceRoot))) {
|
|
55
|
+
throw new Error(protectedSourceRootError(sourceRoot));
|
|
56
|
+
}
|
|
57
|
+
if (source.origin === "shared" && !isPathInside(workspaceRoot, sourceRoot)) {
|
|
58
|
+
throw new Error(sharedSourceOutsideWorkspaceError(sourceRoot));
|
|
59
|
+
}
|
|
60
|
+
return {
|
|
61
|
+
...source,
|
|
62
|
+
sourceRoot,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
function validatePatterns(patterns) {
|
|
66
|
+
for (const pattern of patterns) {
|
|
67
|
+
if (pattern.includes("\0")) {
|
|
68
|
+
throw new Error(invalidGlobPatternError(pattern));
|
|
69
|
+
}
|
|
70
|
+
try {
|
|
71
|
+
posix.matchesGlob("", pattern);
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
throw new Error(invalidGlobPatternError(pattern));
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
function isPathInside(parentPath, childPath) {
|
|
79
|
+
const relativePath = relative(parentPath, childPath);
|
|
80
|
+
return (relativePath === "" ||
|
|
81
|
+
(relativePath !== ".." &&
|
|
82
|
+
!relativePath.startsWith(`..${sep}`) &&
|
|
83
|
+
!isAbsolute(relativePath)));
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=sources.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sources.js","sourceRoot":"","sources":["../src/sources.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.template.js","sourceRoot":"","sources":["../../src/templates/config.template.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,cAAc,GAAgB;IACzC,OAAO,EAAE,CAAC;IACV,OAAO,EAAE,EAAE;CACZ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const gitIgnoreTemplate = "index.sqlite\n*\n!.gitignore\n";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gitignore.template.js","sourceRoot":"","sources":["../../src/templates/gitignore.template.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,iBAAiB,GAAG;;;CAGhC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"source.types.js","sourceRoot":"","sources":["../../src/types/source.types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export declare const sourceSchema: z.ZodObject<{
|
|
3
|
+
path: z.ZodString;
|
|
4
|
+
include: z.ZodArray<z.ZodString>;
|
|
5
|
+
exclude: z.ZodArray<z.ZodString>;
|
|
6
|
+
autoReindex: z.ZodOptional<z.ZodBoolean>;
|
|
7
|
+
}, z.core.$strip>;
|
|
8
|
+
export declare const configSchema: z.ZodObject<{
|
|
9
|
+
version: z.ZodLiteral<1>;
|
|
10
|
+
sources: z.ZodArray<z.ZodObject<{
|
|
11
|
+
path: z.ZodString;
|
|
12
|
+
include: z.ZodArray<z.ZodString>;
|
|
13
|
+
exclude: z.ZodArray<z.ZodString>;
|
|
14
|
+
autoReindex: z.ZodOptional<z.ZodBoolean>;
|
|
15
|
+
}, z.core.$strip>>;
|
|
16
|
+
}, z.core.$strip>;
|
|
17
|
+
export type DianaSource = z.infer<typeof sourceSchema>;
|
|
18
|
+
export type DianaConfig = z.infer<typeof configSchema>;
|
|
19
|
+
export type SourceOrigin = "shared" | "local";
|
|
20
|
+
export type ConfiguredSource = DianaSource & {
|
|
21
|
+
origin: SourceOrigin;
|
|
22
|
+
};
|
|
23
|
+
export type Workspace = {
|
|
24
|
+
root: string;
|
|
25
|
+
configPath: string;
|
|
26
|
+
sources: ConfiguredSource[];
|
|
27
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export const sourceSchema = z.object({
|
|
3
|
+
path: z.string().min(1),
|
|
4
|
+
include: z.array(z.string()),
|
|
5
|
+
exclude: z.array(z.string()),
|
|
6
|
+
autoReindex: z.boolean().optional(),
|
|
7
|
+
});
|
|
8
|
+
export const configSchema = z.object({
|
|
9
|
+
version: z.literal(1),
|
|
10
|
+
sources: z.array(sourceSchema),
|
|
11
|
+
});
|
|
12
|
+
//# sourceMappingURL=workspace.types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workspace.types.js","sourceRoot":"","sources":["../../src/types/workspace.types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,CAAC,MAAM,CAAC;IACnC,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACvB,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;IAC5B,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;IAC5B,WAAW,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;CACpC,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,CAAC,MAAM,CAAC;IACnC,OAAO,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;IACrB,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,YAAY,CAAC;CAC/B,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const FORBIDDEN_DIRS: Set<string>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"forbiddenDirs.js","sourceRoot":"","sources":["../../src/utils/forbiddenDirs.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,cAAc,GAAG,IAAI,GAAG,CAAC,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function hasErrorCode(error: unknown, code: string): boolean;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hasErrorCode.js","sourceRoot":"","sources":["../../src/utils/hasErrorCode.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,YAAY,CAAC,KAAc,EAAE,IAAY;IACvD,OAAO,KAAK,YAAY,KAAK,IAAI,MAAM,IAAI,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC;AAC1E,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function pathExists(path: string): Promise<boolean>;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { lstat } from "node:fs/promises";
|
|
2
|
+
import { hasErrorCode } from "./hasErrorCode.js";
|
|
3
|
+
export async function pathExists(path) {
|
|
4
|
+
try {
|
|
5
|
+
await lstat(path);
|
|
6
|
+
return true;
|
|
7
|
+
}
|
|
8
|
+
catch (e) {
|
|
9
|
+
if (hasErrorCode(e, "ENOENT")) {
|
|
10
|
+
return false;
|
|
11
|
+
}
|
|
12
|
+
throw e;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=pathExists.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pathExists.js","sourceRoot":"","sources":["../../src/utils/pathExists.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEjD,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,IAAY;IAC3C,IAAI,CAAC;QACH,MAAM,KAAK,CAAC,IAAI,CAAC,CAAC;QAClB,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,OAAO,CAAU,EAAE,CAAC;QACpB,IAAI,YAAY,CAAC,CAAC,EAAE,QAAQ,CAAC,EAAE,CAAC;YAC9B,OAAO,KAAK,CAAC;QACf,CAAC;QAED,MAAM,CAAC,CAAC;IACV,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Workspace } from "./types/workspace.types.js";
|
|
2
|
+
export declare const WORKSPACE_CONSTANTS: {
|
|
3
|
+
readonly configFileName: "diana.config.json";
|
|
4
|
+
readonly internalDirName: ".diana";
|
|
5
|
+
readonly localConfigFileName: "local.config.json";
|
|
6
|
+
readonly internalGitIgnoreName: ".gitignore";
|
|
7
|
+
readonly databaseFileName: "index.sqlite";
|
|
8
|
+
};
|
|
9
|
+
export declare const WORKSPACE_ERRORS: {
|
|
10
|
+
readonly noConfigFileError: (directory: string) => string;
|
|
11
|
+
readonly invalidJsonError: (configPath: string) => string;
|
|
12
|
+
readonly invalidConfigError: (configPath: string) => string;
|
|
13
|
+
};
|
|
14
|
+
export declare function loadWorkspace(startDirectory: string): Promise<Workspace>;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import { join, resolve } from "node:path";
|
|
3
|
+
import { configSchema } from "./types/workspace.types.js";
|
|
4
|
+
import { hasErrorCode } from "./utils/hasErrorCode.js";
|
|
5
|
+
export const WORKSPACE_CONSTANTS = {
|
|
6
|
+
configFileName: "diana.config.json",
|
|
7
|
+
internalDirName: ".diana",
|
|
8
|
+
localConfigFileName: "local.config.json",
|
|
9
|
+
internalGitIgnoreName: ".gitignore",
|
|
10
|
+
databaseFileName: "index.sqlite",
|
|
11
|
+
};
|
|
12
|
+
const { configFileName, internalDirName, localConfigFileName } = WORKSPACE_CONSTANTS;
|
|
13
|
+
export const WORKSPACE_ERRORS = {
|
|
14
|
+
noConfigFileError: (directory) => `No configuration file found at ${directory}. Run "diana init" to create ${configFileName}.`,
|
|
15
|
+
invalidJsonError: (configPath) => `Invalid Diana configuration at ${configPath}: invalid JSON.`,
|
|
16
|
+
invalidConfigError: (configPath) => `Invalid Diana configuration at ${configPath}`,
|
|
17
|
+
};
|
|
18
|
+
const { noConfigFileError, invalidJsonError, invalidConfigError } = WORKSPACE_ERRORS;
|
|
19
|
+
export async function loadWorkspace(startDirectory) {
|
|
20
|
+
const directory = resolve(startDirectory);
|
|
21
|
+
const configPath = join(directory, configFileName);
|
|
22
|
+
const config = await readConfig(configPath);
|
|
23
|
+
if (config === undefined) {
|
|
24
|
+
throw new Error(noConfigFileError(directory));
|
|
25
|
+
}
|
|
26
|
+
const localConfigPath = join(directory, internalDirName, localConfigFileName);
|
|
27
|
+
const localConfig = await readConfig(localConfigPath);
|
|
28
|
+
const configuredSharedSources = config.sources.map((source) => ({
|
|
29
|
+
...source,
|
|
30
|
+
origin: "shared",
|
|
31
|
+
}));
|
|
32
|
+
const configuredLocalSources = localConfig?.sources.map((source) => ({
|
|
33
|
+
...source,
|
|
34
|
+
origin: "local",
|
|
35
|
+
})) ?? [];
|
|
36
|
+
return {
|
|
37
|
+
root: directory,
|
|
38
|
+
configPath,
|
|
39
|
+
sources: [...configuredSharedSources, ...configuredLocalSources],
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
async function readConfig(configPath) {
|
|
43
|
+
let contents;
|
|
44
|
+
try {
|
|
45
|
+
contents = await readFile(configPath, "utf-8");
|
|
46
|
+
}
|
|
47
|
+
catch (e) {
|
|
48
|
+
const checkResult = hasErrorCode(e, "ENOENT");
|
|
49
|
+
if (checkResult) {
|
|
50
|
+
return undefined;
|
|
51
|
+
}
|
|
52
|
+
throw e;
|
|
53
|
+
}
|
|
54
|
+
return parseConfig(contents, configPath);
|
|
55
|
+
}
|
|
56
|
+
function parseConfig(contents, configPath) {
|
|
57
|
+
let value;
|
|
58
|
+
try {
|
|
59
|
+
value = JSON.parse(contents);
|
|
60
|
+
}
|
|
61
|
+
catch (e) {
|
|
62
|
+
throw new Error(invalidJsonError(configPath));
|
|
63
|
+
}
|
|
64
|
+
const parsedConfig = configSchema.safeParse(value);
|
|
65
|
+
if (!parsedConfig.success || parsedConfig.data.version !== 1) {
|
|
66
|
+
throw new Error(invalidConfigError(configPath));
|
|
67
|
+
}
|
|
68
|
+
return parsedConfig.data;
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=workspace.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workspace.js","sourceRoot":"","sources":["../src/workspace.ts"],"names":[],"mappings":"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"}
|
package/docs/security.md
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Security and privacy
|
|
2
|
+
|
|
3
|
+
Diana never edits your notes, but **local doesn't automatically mean private**. Review both configs before using it in an unfamiliar project.
|
|
4
|
+
|
|
5
|
+
## Choose what Diana can read
|
|
6
|
+
|
|
7
|
+
- **Project config (`diana.config.json`):** source directories must stay inside the project, even when linked elsewhere through a symlink.
|
|
8
|
+
- **Local config (`.diana/local.config.json`):** can include directories outside the project. It's ignored by Git by default, but someone can still force-add or replace it. Check its contents rather than assuming it's trusted.
|
|
9
|
+
|
|
10
|
+
Diana applies source boundaries and include/exclude patterns to reads. Indexing skips hidden entries and symlinks; reads may follow symlinks to allowed files. `.git` and `.diana` cannot themselves be source roots.
|
|
11
|
+
|
|
12
|
+
**Diana isn't a sandbox.** It uses your filesystem permissions and doesn't protect against another process maliciously changing files during an operation. Exclusions don't prevent other tools from reading those files.
|
|
13
|
+
|
|
14
|
+
## Treat the index like your notes
|
|
15
|
+
|
|
16
|
+
`.diana/index.sqlite` contains **unencrypted note text and absolute paths**. Keep the generated `.diana/.gitignore`, and avoid sharing the cache through commits, backups, or build artifacts when your notes are private.
|
|
17
|
+
|
|
18
|
+
Search validates all source roots, then refreshes only sources with `autoReindex: true` (default: `false`). Other sources' contents and patterns remain cached until `diana index`. Successful searches also remove cached results for unconfigured sources. If refresh fails, search fails rather than returning stale results. Reads check the current config and source file independently.
|
|
19
|
+
|
|
20
|
+
To discard the cache, stop Diana commands and delete only `.diana/index.sqlite`—keep your local config. Deletion isn't secure erasure: backups and snapshots may retain copies.
|
|
21
|
+
|
|
22
|
+
## Keep agents in mind
|
|
23
|
+
|
|
24
|
+
- Diana searches locally, but your harness may send results to a model provider or save them in logs.
|
|
25
|
+
- Retrieved notes are reference material, not instructions. Embedded commands have no authority; shell-quote paths and other result values rather than executing them.
|
|
26
|
+
- Skills guide agents to search first, read narrowly, and ask before explicit indexing or configuration changes. Automatic cache refresh is part of search when you opt in. Skills can't enforce these rules or restrict the agent's other tools.
|
|
27
|
+
|
|
28
|
+
## Writes and limits
|
|
29
|
+
|
|
30
|
+
`init` creates configuration and ignore rules; `index` and `search` may update the cache. None edits source notes. A missing or outdated index requires explicit `diana index` to build all sources; search won't silently build a partial index.
|
|
31
|
+
|
|
32
|
+
Files over 1 MiB are rejected, and read output is limited. `truncated: true` means the result is incomplete. These limits reduce resource use—they don't sanitize content or make it safe to trust.
|
|
Binary file
|