@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 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 project-contained regular text file or directory. 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.
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.2",
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.2"
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 { isAbsolute, relative, resolve, sep } from 'node:path';
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-outside-root' | 'symlink-unresolvable' | 'special-file' | 'directory-read-failed' | 'entry-stat-failed' | 'index-failed';
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 { isAbsolute, relative, resolve } from 'node:path';
2
+ import { resolve } from 'node:path';
3
3
 
4
- function assertWithinRoot(base, target, candidate) {
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
  }