@dotdotgod/context 0.6.2 → 0.6.4
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/README.md +1 -1
- package/package.json +2 -2
- package/src/directory-ingestion.mjs +1 -12
- package/src/index.d.ts +1 -1
- package/src/paths.mjs +2 -9
package/README.md
CHANGED
|
@@ -79,7 +79,7 @@ This bounded retrieval keeps indexed runtime material separate from maintained p
|
|
|
79
79
|
|
|
80
80
|
## Structural Ingestion
|
|
81
81
|
|
|
82
|
-
Local `index` accepts one
|
|
82
|
+
Local `index` accepts one regular text file or explicitly requested directory, including external paths. Project roots are defaults, not access boundaries. A file is limited to **25 MiB**. Directory defaults allow at most depth 16, 10,000 visited entries, 1,000 indexed files, 25 MiB per file, and 100 MiB in aggregate; callers may configure the traversal limits explicitly.
|
|
83
83
|
|
|
84
84
|
Directory ingestion:
|
|
85
85
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dotdotgod/context",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.4",
|
|
4
4
|
"description": "Local-first MCP execution, indexing, and retrieval runtime for dotdotgod adapters.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "Elastic-2.0",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"dependencies": {
|
|
29
29
|
"@modelcontextprotocol/sdk": "^1.25.2",
|
|
30
30
|
"zod": "^3.25.76",
|
|
31
|
-
"@dotdotgod/cli": "0.6.
|
|
31
|
+
"@dotdotgod/cli": "0.6.4"
|
|
32
32
|
},
|
|
33
33
|
"engines": {
|
|
34
34
|
"node": ">=22.5.0"
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { closeSync, constants, fstatSync, lstatSync, openSync, readFileSync, readdirSync, realpathSync, statSync } from 'node:fs';
|
|
2
|
-
import {
|
|
2
|
+
import { relative, resolve, sep } from 'node:path';
|
|
3
3
|
|
|
4
4
|
const DEFAULT_LIMITS = Object.freeze({
|
|
5
5
|
maxDepth: 16,
|
|
@@ -9,11 +9,6 @@ const DEFAULT_LIMITS = Object.freeze({
|
|
|
9
9
|
maxAggregateBytes: 100 * 1024 * 1024,
|
|
10
10
|
});
|
|
11
11
|
|
|
12
|
-
function inside(base, target) {
|
|
13
|
-
const rel = relative(base, target);
|
|
14
|
-
return rel !== '..' && !rel.startsWith(`..${sep}`) && !isAbsolute(rel);
|
|
15
|
-
}
|
|
16
|
-
|
|
17
12
|
function relativePath(base, target) {
|
|
18
13
|
return relative(base, target).split(sep).join('/');
|
|
19
14
|
}
|
|
@@ -72,10 +67,7 @@ function snapshot(path, target, stat, symlink) {
|
|
|
72
67
|
export function walkDirectoryManifest(options = {}) {
|
|
73
68
|
const root = realpathSync(resolve(options.root || process.cwd()));
|
|
74
69
|
const requested = resolve(root, options.path ?? '.');
|
|
75
|
-
if (!inside(root, requested)) throw new Error(`Directory escapes project root: ${options.path}`);
|
|
76
|
-
if (lstatSync(requested).isSymbolicLink()) throw new Error(`Directory symlinks are not followed: ${options.path ?? '.'}`);
|
|
77
70
|
const directory = realpathSync(requested);
|
|
78
|
-
if (!inside(root, directory)) throw new Error(`Directory escapes project root: ${options.path}`);
|
|
79
71
|
if (!statSync(directory).isDirectory()) throw new Error(`Not a directory: ${options.path ?? '.'}`);
|
|
80
72
|
|
|
81
73
|
const policy = normalizeOptions(options);
|
|
@@ -113,7 +105,6 @@ export function walkDirectoryManifest(options = {}) {
|
|
|
113
105
|
let targetStat;
|
|
114
106
|
try {
|
|
115
107
|
target = realpathSync(absolutePath);
|
|
116
|
-
if (!inside(root, target)) { skip(path, 'symlink-outside-root'); continue; }
|
|
117
108
|
targetStat = statSync(target);
|
|
118
109
|
} catch { skip(path, 'symlink-unresolvable'); continue; }
|
|
119
110
|
if (targetStat.isDirectory()) { skip(path, 'directory-symlink'); continue; }
|
|
@@ -152,9 +143,7 @@ function matchesIdentity(stat, identity) {
|
|
|
152
143
|
}
|
|
153
144
|
|
|
154
145
|
export function verifyManifestFile(entry, root) {
|
|
155
|
-
const base = realpathSync(resolve(root));
|
|
156
146
|
const target = realpathSync(entry.absolutePath);
|
|
157
|
-
if (!inside(base, target)) throw new Error(`Manifest file escapes project root: ${entry.path}`);
|
|
158
147
|
const stat = statSync(target);
|
|
159
148
|
if (!stat.isFile()) throw new Error(`Manifest entry is not a regular file: ${entry.path}`);
|
|
160
149
|
if (!matchesIdentity(stat, entry.identity ?? {})) throw new Error(`Manifest file changed before indexing: ${entry.path}`);
|
package/src/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export function formatToolMarkdown(name: string, value: unknown): string;
|
|
2
2
|
export type ContextScope = 'transient' | 'session' | 'project';
|
|
3
|
-
export type DirectoryReason = 'excluded-path' | 'extension-filter' | 'file-byte-limit' | 'file-count-limit' | 'aggregate-byte-limit' | 'visited-entry-limit' | 'depth-limit' | 'file-symlink' | 'directory-symlink' | 'symlink-
|
|
3
|
+
export type DirectoryReason = 'excluded-path' | 'extension-filter' | 'file-byte-limit' | 'file-count-limit' | 'aggregate-byte-limit' | 'visited-entry-limit' | 'depth-limit' | 'file-symlink' | 'directory-symlink' | 'symlink-unresolvable' | 'special-file' | 'directory-read-failed' | 'entry-stat-failed' | 'index-failed';
|
|
4
4
|
export interface EnvironmentPolicy { mode: 'inherit-filtered-v1' | 'allowlist-v1'; platform: 'win32' | 'darwin' | 'posix'; allowedNames?: string[]; filteredNames: string[] }
|
|
5
5
|
export interface DirectoryManifestEntry { path: string; absolutePath: string; size: number; identity: { dev: number; ino: number; size: number; mtimeMs: number }; symlink: boolean }
|
|
6
6
|
export interface DirectoryManifest { root: string; directory: string; files: DirectoryManifestEntry[]; skipped: Array<{ path: string; reason: DirectoryReason }>; failed: Array<{ path: string; reason: DirectoryReason; error?: string }>; aborted: boolean; truncated: boolean; visitedEntries: number; aggregateBytes: number }
|
package/src/paths.mjs
CHANGED
|
@@ -1,23 +1,16 @@
|
|
|
1
1
|
import { realpathSync } from 'node:fs';
|
|
2
|
-
import {
|
|
2
|
+
import { resolve } from 'node:path';
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
const rel = relative(base, target);
|
|
6
|
-
if (rel === '..' || rel.startsWith(`..${process.platform === 'win32' ? '\\' : '/'}`) || isAbsolute(rel)) {
|
|
7
|
-
throw new Error(`Path escapes project root: ${candidate}`);
|
|
8
|
-
}
|
|
9
|
-
}
|
|
4
|
+
// Legacy export names: root is a relative-path default, not an access boundary.
|
|
10
5
|
|
|
11
6
|
export function resolveWithinRoot(root, candidate = '.') {
|
|
12
7
|
const base = resolve(root || process.cwd());
|
|
13
8
|
const target = resolve(base, candidate);
|
|
14
|
-
assertWithinRoot(base, target, candidate);
|
|
15
9
|
return target;
|
|
16
10
|
}
|
|
17
11
|
|
|
18
12
|
export function resolveExistingWithinRoot(root, candidate = '.') {
|
|
19
13
|
const base = realpathSync(resolve(root || process.cwd()));
|
|
20
14
|
const target = realpathSync(resolveWithinRoot(base, candidate));
|
|
21
|
-
assertWithinRoot(base, target, candidate);
|
|
22
15
|
return target;
|
|
23
16
|
}
|