opencode-add-dir 1.0.3 → 1.1.0

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.
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAyMlD,QAAA,MAAM,YAAY,EAAE,MA6DnB,CAAC;AAEF,eAAe,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAgHlD,QAAA,MAAM,YAAY,EAAE,MAgDnB,CAAC;AAEF,eAAe,YAAY,CAAC"}
package/dist/index.js CHANGED
@@ -1,195 +1,126 @@
1
1
  import { tool } from '@opencode-ai/plugin/tool';
2
2
  import fs from 'fs';
3
3
  import path from 'path';
4
- const IGNORED_DIRECTORIES = new Set([
5
- 'node_modules',
6
- '.git',
7
- 'dist',
8
- 'build',
9
- '.next',
10
- '__pycache__',
11
- '.venv',
12
- 'venv',
13
- 'env',
14
- '.env',
15
- 'coverage',
16
- '.nuxt',
17
- '.output',
18
- 'tmp',
19
- 'temp',
20
- '.turbo'
21
- ]);
22
- const BINARY_EXTENSIONS = new Set([
23
- '.png', '.jpg', '.jpeg', '.gif', '.bmp', '.ico', '.svg', '.webp',
24
- '.pdf', '.doc', '.docx', '.xls', '.xlsx', '.ppt', '.pptx',
25
- '.zip', '.tar', '.gz', '.rar', '.7z',
26
- '.mp3', '.mp4', '.avi', '.mov', '.wav',
27
- '.exe', '.dll', '.so', '.dylib', '.bin',
28
- '.class', '.jar', '.war',
29
- '.pyc', '.pyo',
30
- '.db', '.sqlite', '.sqlite3',
31
- '.lock', '.log'
32
- ]);
33
- const MAX_FILE_SIZE_BYTES = 100 * 1024;
34
- const MAX_FILES = 500;
35
- const ADDED_DIRS_FILE = path.join(__dirname, '.added-dirs.json');
36
- function getAddedDirectories() {
4
+ import { validateDirectory, countFiles } from './utils.js';
5
+ const SESSIONS_FILE = path.join(__dirname, '.sessions.json');
6
+ const MAX_SESSIONS = 50;
7
+ const SESSION_AGE_DAYS = 30;
8
+ const CLEANUP_INTERVAL_MS = 3600000;
9
+ const LAST_ACCESS_UPDATE_MS = 3600000;
10
+ let lastCleaned = 0;
11
+ function readSessions() {
37
12
  try {
38
- if (fs.existsSync(ADDED_DIRS_FILE)) {
39
- const content = fs.readFileSync(ADDED_DIRS_FILE, 'utf-8');
40
- const data = JSON.parse(content);
41
- return new Set(data.directories);
13
+ if (fs.existsSync(SESSIONS_FILE)) {
14
+ return JSON.parse(fs.readFileSync(SESSIONS_FILE, 'utf-8'));
42
15
  }
43
16
  }
44
17
  catch (error) {
45
- console.error('Failed to read added directories:', error);
18
+ console.error('Failed to read sessions:', error);
46
19
  }
47
- return new Set();
20
+ return {};
48
21
  }
49
- function saveAddedDirectory(dirPath) {
50
- const added = getAddedDirectories();
51
- const normalizedPath = path.resolve(dirPath);
52
- if (!added.has(normalizedPath)) {
53
- added.add(normalizedPath);
54
- const data = { directories: Array.from(added) };
55
- fs.writeFileSync(ADDED_DIRS_FILE, JSON.stringify(data, null, 2));
56
- }
22
+ function writeSessions(sessions) {
23
+ fs.writeFileSync(SESSIONS_FILE, JSON.stringify(sessions, null, 2));
57
24
  }
58
- function isPathInAddedDirectories(requestedPath) {
59
- const addedDirs = getAddedDirectories();
60
- const normalizedPath = path.resolve(requestedPath);
61
- for (const dir of addedDirs) {
62
- const relative = path.relative(dir, normalizedPath);
63
- if (!relative.startsWith('..') && !path.isAbsolute(relative)) {
64
- return true;
25
+ function getSessionDirs(sessionId) {
26
+ const sessions = readSessions();
27
+ const session = sessions[sessionId];
28
+ if (session) {
29
+ const now = Date.now();
30
+ if (now - session.lastAccessed > LAST_ACCESS_UPDATE_MS) {
31
+ session.lastAccessed = now;
32
+ writeSessions(sessions);
65
33
  }
34
+ return session.dirs;
66
35
  }
67
- return false;
36
+ return [];
68
37
  }
69
- function isBinaryFile(filePath) {
70
- const ext = path.extname(filePath).toLowerCase();
71
- return BINARY_EXTENSIONS.has(ext);
72
- }
73
- function shouldIgnoreDirectory(dirName) {
74
- return IGNORED_DIRECTORIES.has(dirName);
38
+ function addSessionDir(sessionId, dirPath) {
39
+ const sessions = readSessions();
40
+ const normalized = path.resolve(dirPath);
41
+ if (!sessions[sessionId]) {
42
+ sessions[sessionId] = { dirs: [], lastAccessed: Date.now() };
43
+ }
44
+ if (!sessions[sessionId].dirs.includes(normalized)) {
45
+ sessions[sessionId].dirs.push(normalized);
46
+ sessions[sessionId].lastAccessed = Date.now();
47
+ writeSessions(sessions);
48
+ }
75
49
  }
76
- function scanDirectory(dirPath, baseDir, files = [], tree = [], depth = 0, fileCount = 0) {
77
- if (fileCount >= MAX_FILES) {
78
- return { files, tree, fileCount, skipped: 0 };
50
+ function cleanOldSessions() {
51
+ const sessions = readSessions();
52
+ const now = Date.now();
53
+ const maxAge = SESSION_AGE_DAYS * 24 * 60 * 60 * 1000;
54
+ const entries = Object.entries(sessions);
55
+ const recentSessions = entries.filter(([, data]) => now - data.lastAccessed < maxAge);
56
+ if (recentSessions.length <= MAX_SESSIONS) {
57
+ if (recentSessions.length === entries.length) {
58
+ return;
59
+ }
60
+ }
61
+ else {
62
+ recentSessions.sort(([, a], [, b]) => b.lastAccessed - a.lastAccessed);
63
+ recentSessions.splice(MAX_SESSIONS);
79
64
  }
80
- let skipped = 0;
81
- const entries = fs.readdirSync(dirPath, { withFileTypes: true });
82
- const sortedEntries = entries.sort((a, b) => {
83
- if (a.isDirectory() && !b.isDirectory())
84
- return -1;
85
- if (!a.isDirectory() && b.isDirectory())
86
- return 1;
87
- return a.name.localeCompare(b.name);
65
+ const cleanedSessions = {};
66
+ recentSessions.forEach(([id, data]) => {
67
+ cleanedSessions[id] = data;
88
68
  });
89
- for (const entry of sortedEntries) {
90
- if (fileCount >= MAX_FILES) {
91
- break;
92
- }
93
- const fullPath = path.join(dirPath, entry.name);
94
- const relativePath = path.relative(baseDir, fullPath);
95
- const indent = ' '.repeat(depth);
96
- if (entry.isDirectory()) {
97
- if (shouldIgnoreDirectory(entry.name)) {
98
- skipped++;
99
- continue;
100
- }
101
- tree.push(`${indent}${entry.name}/`);
102
- const result = scanDirectory(fullPath, baseDir, files, tree, depth + 1, fileCount);
103
- files = result.files;
104
- tree = result.tree;
105
- fileCount = result.fileCount;
106
- skipped += result.skipped;
107
- }
108
- else if (entry.isFile()) {
109
- if (isBinaryFile(entry.name)) {
110
- skipped++;
111
- continue;
112
- }
113
- const stats = fs.statSync(fullPath);
114
- if (stats.size > MAX_FILE_SIZE_BYTES) {
115
- skipped++;
116
- continue;
117
- }
118
- tree.push(`${indent}${entry.name}`);
119
- let content;
120
- let isTruncated = false;
121
- try {
122
- content = fs.readFileSync(fullPath, 'utf-8');
123
- if (content.length > MAX_FILE_SIZE_BYTES) {
124
- content = content.slice(0, MAX_FILE_SIZE_BYTES);
125
- isTruncated = true;
126
- }
127
- }
128
- catch (error) {
129
- content = undefined;
130
- }
131
- files.push({
132
- path: relativePath,
133
- size: stats.size,
134
- content,
135
- isTruncated
136
- });
137
- fileCount++;
69
+ writeSessions(cleanedSessions);
70
+ }
71
+ function isInSessionDirs(filePath, dirs) {
72
+ const normalizedFilePath = path.resolve(filePath);
73
+ for (const dir of dirs) {
74
+ const normalizedDir = path.resolve(dir);
75
+ const relative = path.relative(normalizedDir, normalizedFilePath);
76
+ const isInside = !relative.startsWith('..') && !path.isAbsolute(relative);
77
+ if (isInside) {
78
+ return true;
138
79
  }
139
80
  }
140
- return { files, tree, fileCount, skipped };
81
+ return false;
141
82
  }
142
83
  const addDirPlugin = async () => {
143
84
  return {
144
85
  tool: {
145
86
  add_dir: tool({
146
- description: 'Add an external directory to the session context by reading all its files',
87
+ description: 'Add a directory to the workspace. Access is auto-approved for files in added directories.',
147
88
  args: {
148
- directory: tool.schema.string().describe('Path to the directory to add')
89
+ directory: tool.schema.string().describe('Absolute path to the directory')
149
90
  },
150
- execute: async ({ directory }) => {
91
+ execute: async ({ directory }, context) => {
92
+ const sessionId = context.sessionID;
151
93
  const resolvedPath = path.resolve(directory);
152
- if (!fs.existsSync(resolvedPath)) {
153
- throw new Error(`Directory does not exist: ${resolvedPath}`);
154
- }
155
- if (!fs.statSync(resolvedPath).isDirectory()) {
156
- throw new Error(`Path is not a directory: ${resolvedPath}`);
157
- }
158
- try {
159
- fs.accessSync(resolvedPath, fs.constants.R_OK);
160
- }
161
- catch (error) {
162
- throw new Error(`Permission denied: Cannot read directory ${resolvedPath}`);
163
- }
164
- const scanResult = scanDirectory(resolvedPath, resolvedPath);
165
- const totalFound = scanResult.fileCount + scanResult.skipped;
166
- const filesTooLarge = scanResult.skipped;
167
- const output = {
168
- directory: resolvedPath,
169
- totalFilesFound: totalFound,
170
- filesProcessed: scanResult.fileCount,
171
- filesSkipped: scanResult.skipped - filesTooLarge,
172
- filesTooLarge,
173
- tree: scanResult.tree,
174
- files: scanResult.files
175
- };
176
- saveAddedDirectory(resolvedPath);
94
+ validateDirectory(resolvedPath);
95
+ addSessionDir(sessionId, resolvedPath);
96
+ const fileCount = countFiles(resolvedPath);
177
97
  return JSON.stringify({
178
- ...output,
179
- message: 'Directory added to context. Future access to this directory will not require permission prompts.'
98
+ directory: resolvedPath,
99
+ status: 'added',
100
+ message: 'Directory added to workspace',
101
+ fileCount
180
102
  }, null, 2);
181
103
  }
182
104
  })
183
105
  },
106
+ 'chat.message': async (context) => {
107
+ getSessionDirs(context.sessionID);
108
+ const now = Date.now();
109
+ if (now - lastCleaned > CLEANUP_INTERVAL_MS) {
110
+ cleanOldSessions();
111
+ lastCleaned = now;
112
+ }
113
+ },
184
114
  'permission.ask': async (input, output) => {
185
- if (input.pattern) {
186
- const patterns = Array.isArray(input.pattern) ? input.pattern : [input.pattern];
187
- for (const pattern of patterns) {
188
- if (typeof pattern === 'string' && isPathInAddedDirectories(pattern)) {
189
- output.status = 'allow';
190
- return;
191
- }
192
- }
115
+ const dirs = getSessionDirs(input.sessionID);
116
+ const check = (value) => typeof value === 'string' && isInSessionDirs(value, dirs);
117
+ const approved = [
118
+ check(input.title),
119
+ (input.pattern ? (Array.isArray(input.pattern) ? input.pattern : [input.pattern]) : []).some(check),
120
+ Object.values(input.metadata || {}).flat().some(check)
121
+ ].some(Boolean);
122
+ if (approved) {
123
+ output.status = 'allow';
193
124
  }
194
125
  }
195
126
  };
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,0BAA0B,CAAC;AAGhD,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,iBAAiB,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE3D,MAAM,aAAa,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,gBAAgB,CAAC,CAAC;AAC7D,MAAM,YAAY,GAAG,EAAE,CAAC;AACxB,MAAM,gBAAgB,GAAG,EAAE,CAAC;AAC5B,MAAM,mBAAmB,GAAG,OAAO,CAAC;AACpC,MAAM,qBAAqB,GAAG,OAAO,CAAC;AAWtC,IAAI,WAAW,GAAG,CAAC,CAAC;AAEpB,SAAS,YAAY;IACnB,IAAI,CAAC;QACH,IAAI,EAAE,CAAC,UAAU,CAAC,aAAa,CAAC,EAAE,CAAC;YACjC,OAAO,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,aAAa,EAAE,OAAO,CAAC,CAAa,CAAC;QACzE,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,0BAA0B,EAAE,KAAK,CAAC,CAAC;IACnD,CAAC;IACD,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,SAAS,aAAa,CAAC,QAAkB;IACvC,EAAE,CAAC,aAAa,CAAC,aAAa,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;AACrE,CAAC;AAED,SAAS,cAAc,CAAC,SAAiB;IACvC,MAAM,QAAQ,GAAG,YAAY,EAAE,CAAC;IAChC,MAAM,OAAO,GAAG,QAAQ,CAAC,SAAS,CAAC,CAAC;IAEpC,IAAI,OAAO,EAAE,CAAC;QACZ,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,IAAI,GAAG,GAAG,OAAO,CAAC,YAAY,GAAG,qBAAqB,EAAE,CAAC;YACvD,OAAO,CAAC,YAAY,GAAG,GAAG,CAAC;YAC3B,aAAa,CAAC,QAAQ,CAAC,CAAC;QAC1B,CAAC;QACD,OAAO,OAAO,CAAC,IAAI,CAAC;IACtB,CAAC;IAED,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,SAAS,aAAa,CAAC,SAAiB,EAAE,OAAe;IACvD,MAAM,QAAQ,GAAG,YAAY,EAAE,CAAC;IAChC,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IAEzC,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;QACzB,QAAQ,CAAC,SAAS,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,EAAE,YAAY,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;IAC/D,CAAC;IAED,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;QACnD,QAAQ,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC1C,QAAQ,CAAC,SAAS,CAAC,CAAC,YAAY,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC9C,aAAa,CAAC,QAAQ,CAAC,CAAC;IAC1B,CAAC;AACH,CAAC;AAED,SAAS,gBAAgB;IACvB,MAAM,QAAQ,GAAG,YAAY,EAAE,CAAC;IAChC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACvB,MAAM,MAAM,GAAG,gBAAgB,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;IAEtD,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IACzC,MAAM,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,EAAE,CACjD,GAAG,GAAG,IAAI,CAAC,YAAY,GAAG,MAAM,CACjC,CAAC;IAEF,IAAI,cAAc,CAAC,MAAM,IAAI,YAAY,EAAE,CAAC;QAC1C,IAAI,cAAc,CAAC,MAAM,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC;YAC7C,OAAO;QACT,CAAC;IACH,CAAC;SAAM,CAAC;QACN,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,YAAY,GAAG,CAAC,CAAC,YAAY,CAAC,CAAC;QACvE,cAAc,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;IACtC,CAAC;IAED,MAAM,eAAe,GAAa,EAAE,CAAC;IACrC,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE;QACpC,eAAe,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC;IAC7B,CAAC,CAAC,CAAC;IAEH,aAAa,CAAC,eAAe,CAAC,CAAC;AACjC,CAAC;AAED,SAAS,eAAe,CAAC,QAAgB,EAAE,IAAc;IACvD,MAAM,kBAAkB,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IAElD,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,MAAM,aAAa,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACxC,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,aAAa,EAAE,kBAAkB,CAAC,CAAC;QAClE,MAAM,QAAQ,GAAG,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;QAE1E,IAAI,QAAQ,EAAE,CAAC;YACb,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,YAAY,GAAW,KAAK,IAAI,EAAE;IACtC,OAAO;QACL,IAAI,EAAE;YACJ,OAAO,EAAE,IAAI,CAAC;gBACZ,WAAW,EAAE,2FAA2F;gBACxG,IAAI,EAAE;oBACJ,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,gCAAgC,CAAC;iBAC3E;gBACD,OAAO,EAAE,KAAK,EAAE,EAAE,SAAS,EAAE,EAAE,OAAO,EAAE,EAAE;oBACxC,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC;oBACpC,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;oBAC7C,iBAAiB,CAAC,YAAY,CAAC,CAAC;oBAChC,aAAa,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC;oBACvC,MAAM,SAAS,GAAG,UAAU,CAAC,YAAY,CAAC,CAAC;oBAE3C,OAAO,IAAI,CAAC,SAAS,CAAC;wBACpB,SAAS,EAAE,YAAY;wBACvB,MAAM,EAAE,OAAO;wBACf,OAAO,EAAE,8BAA8B;wBACvC,SAAS;qBACV,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;gBACd,CAAC;aACF,CAAC;SACH;QACD,cAAc,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;YAChC,cAAc,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;YAClC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YAEvB,IAAI,GAAG,GAAG,WAAW,GAAG,mBAAmB,EAAE,CAAC;gBAC5C,gBAAgB,EAAE,CAAC;gBACnB,WAAW,GAAG,GAAG,CAAC;YACpB,CAAC;QACH,CAAC;QACD,gBAAgB,EAAE,KAAK,EAAE,KAAiB,EAAE,MAA4C,EAAE,EAAE;YAC1F,MAAM,IAAI,GAAG,cAAc,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;YAC7C,MAAM,KAAK,GAAG,CAAC,KAAc,EAAE,EAAE,CAAC,OAAO,KAAK,KAAK,QAAQ,IAAI,eAAe,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;YAE5F,MAAM,QAAQ,GAAG;gBACf,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC;gBAClB,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC;gBACnG,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC;aACvD,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAEhB,IAAI,QAAQ,EAAE,CAAC;gBACb,MAAM,CAAC,MAAM,GAAG,OAAO,CAAC;YAC1B,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC,CAAC;AAEF,eAAe,YAAY,CAAC"}
@@ -0,0 +1,15 @@
1
+ export interface AddedDirectory {
2
+ directory: string;
3
+ addedAt: number;
4
+ }
5
+ export interface SessionDirectories {
6
+ sessionId: string;
7
+ directories: AddedDirectory[];
8
+ }
9
+ export interface AddDirResult {
10
+ directory: string;
11
+ status: 'added' | 'error';
12
+ message: string;
13
+ fileCount?: number;
14
+ }
15
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,cAAc,EAAE,CAAC;CAC/B;AAED,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,OAAO,GAAG,OAAO,CAAC;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,4 @@
1
+ export declare function isIgnoredDirectory(dirName: string): boolean;
2
+ export declare function countFiles(directory: string): number;
3
+ export declare function validateDirectory(dirPath: string): void;
4
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAsBA,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAE3D;AAED,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CA+BpD;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAgBvD"}
package/dist/utils.js ADDED
@@ -0,0 +1,67 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ const IGNORED_DIRECTORIES = new Set([
4
+ 'node_modules',
5
+ '.git',
6
+ 'dist',
7
+ 'build',
8
+ '.next',
9
+ '__pycache__',
10
+ '.venv',
11
+ 'venv',
12
+ 'env',
13
+ '.env',
14
+ 'coverage',
15
+ '.nuxt',
16
+ '.output',
17
+ 'tmp',
18
+ 'temp',
19
+ '.turbo'
20
+ ]);
21
+ export function isIgnoredDirectory(dirName) {
22
+ return IGNORED_DIRECTORIES.has(dirName);
23
+ }
24
+ export function countFiles(directory) {
25
+ let fileCount = 0;
26
+ function scanDir(dir) {
27
+ try {
28
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
29
+ for (const entry of entries) {
30
+ if (isIgnoredDirectory(entry.name)) {
31
+ continue;
32
+ }
33
+ if (entry.isSymbolicLink()) {
34
+ continue;
35
+ }
36
+ const fullPath = path.join(dir, entry.name);
37
+ if (entry.isDirectory()) {
38
+ scanDir(fullPath);
39
+ }
40
+ else if (entry.isFile()) {
41
+ fileCount++;
42
+ }
43
+ }
44
+ }
45
+ catch (error) {
46
+ console.error(`Error scanning ${dir}:`, error);
47
+ }
48
+ }
49
+ scanDir(directory);
50
+ return fileCount;
51
+ }
52
+ export function validateDirectory(dirPath) {
53
+ if (!fs.existsSync(dirPath)) {
54
+ throw new Error(`Directory does not exist: ${dirPath}`);
55
+ }
56
+ const stats = fs.statSync(dirPath);
57
+ if (!stats.isDirectory()) {
58
+ throw new Error(`Path is not a directory: ${dirPath}`);
59
+ }
60
+ try {
61
+ fs.accessSync(dirPath, fs.constants.R_OK);
62
+ }
63
+ catch (error) {
64
+ throw new Error(`Permission denied: Cannot read directory ${dirPath}`);
65
+ }
66
+ }
67
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB,MAAM,mBAAmB,GAAG,IAAI,GAAG,CAAC;IAClC,cAAc;IACd,MAAM;IACN,MAAM;IACN,OAAO;IACP,OAAO;IACP,aAAa;IACb,OAAO;IACP,MAAM;IACN,KAAK;IACL,MAAM;IACN,UAAU;IACV,OAAO;IACP,SAAS;IACT,KAAK;IACL,MAAM;IACN,QAAQ;CACT,CAAC,CAAC;AAEH,MAAM,UAAU,kBAAkB,CAAC,OAAe;IAChD,OAAO,mBAAmB,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;AAC1C,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,SAAiB;IAC1C,IAAI,SAAS,GAAG,CAAC,CAAC;IAElB,SAAS,OAAO,CAAC,GAAW;QAC1B,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,EAAE,CAAC,WAAW,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;YAE7D,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;gBAC5B,IAAI,kBAAkB,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;oBACnC,SAAS;gBACX,CAAC;gBAED,IAAI,KAAK,CAAC,cAAc,EAAE,EAAE,CAAC;oBAC3B,SAAS;gBACX,CAAC;gBAED,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;gBAE5C,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;oBACxB,OAAO,CAAC,QAAQ,CAAC,CAAC;gBACpB,CAAC;qBAAM,IAAI,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC;oBAC1B,SAAS,EAAE,CAAC;gBACd,CAAC;YACH,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,kBAAkB,GAAG,GAAG,EAAE,KAAK,CAAC,CAAC;QACjD,CAAC;IACH,CAAC;IAED,OAAO,CAAC,SAAS,CAAC,CAAC;IACnB,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,OAAe;IAC/C,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QAC5B,MAAM,IAAI,KAAK,CAAC,6BAA6B,OAAO,EAAE,CAAC,CAAC;IAC1D,CAAC;IAED,MAAM,KAAK,GAAG,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;IAEnC,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CAAC,4BAA4B,OAAO,EAAE,CAAC,CAAC;IACzD,CAAC;IAED,IAAI,CAAC;QACH,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IAC5C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,4CAA4C,OAAO,EAAE,CAAC,CAAC;IACzE,CAAC;AACH,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-add-dir",
3
- "version": "1.0.3",
3
+ "version": "1.1.0",
4
4
  "description": "OpenCode plugin to add external directories to session context",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -32,6 +32,6 @@
32
32
  "add-directory",
33
33
  "context"
34
34
  ],
35
- "author": "",
35
+ "author": "Cristian Fonseca <cfonsecacomas@gmail.com>",
36
36
  "license": "MIT"
37
37
  }