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.
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +91 -160
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +15 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/utils.d.ts +4 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +67 -0
- package/dist/utils.js.map +1 -0
- package/package.json +2 -2
package/dist/index.d.ts.map
CHANGED
|
@@ -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;
|
|
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
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
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(
|
|
39
|
-
|
|
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
|
|
18
|
+
console.error('Failed to read sessions:', error);
|
|
46
19
|
}
|
|
47
|
-
return
|
|
20
|
+
return {};
|
|
48
21
|
}
|
|
49
|
-
function
|
|
50
|
-
|
|
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
|
|
59
|
-
const
|
|
60
|
-
const
|
|
61
|
-
|
|
62
|
-
const
|
|
63
|
-
if (
|
|
64
|
-
|
|
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
|
|
36
|
+
return [];
|
|
68
37
|
}
|
|
69
|
-
function
|
|
70
|
-
const
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
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
|
|
77
|
-
|
|
78
|
-
|
|
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
|
-
|
|
81
|
-
|
|
82
|
-
|
|
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
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
const
|
|
95
|
-
const
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
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
|
|
81
|
+
return false;
|
|
141
82
|
}
|
|
142
83
|
const addDirPlugin = async () => {
|
|
143
84
|
return {
|
|
144
85
|
tool: {
|
|
145
86
|
add_dir: tool({
|
|
146
|
-
description: 'Add
|
|
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('
|
|
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
|
-
|
|
153
|
-
|
|
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
|
-
|
|
179
|
-
|
|
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
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
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":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,0BAA0B,CAAC;AAGhD,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -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 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
package/dist/utils.d.ts
ADDED
|
@@ -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
|
+
"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
|
}
|