boxsafe 1.0.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/.directory +2 -0
- package/.env.example +3 -0
- package/AUDIT_LANG.md +45 -0
- package/BOXSAFE_VERSION_NOTES.md +14 -0
- package/README.md +4 -0
- package/TODO.md +130 -0
- package/adapters/index.ts +27 -0
- package/adapters/primary/cli-adapter.ts +56 -0
- package/adapters/secondary/filesystem/node-filesystem.ts +307 -0
- package/adapters/secondary/system/configuration.ts +147 -0
- package/ai/caller.ts +42 -0
- package/ai/label.ts +33 -0
- package/ai/modelConfig.ts +236 -0
- package/ai/provider.ts +111 -0
- package/boxsafe.config.json +68 -0
- package/core/auth/dasktop/cred/CRED.md +112 -0
- package/core/auth/dasktop/cred/credLinux.ts +82 -0
- package/core/auth/dasktop/cred/credWin.ts +2 -0
- package/core/config/defaults/boxsafeDefaults.ts +67 -0
- package/core/config/defaults/index.ts +1 -0
- package/core/config/loadConfig.ts +133 -0
- package/core/loop/about.md +13 -0
- package/core/loop/boxConfig.ts +20 -0
- package/core/loop/buildExecCommand.ts +76 -0
- package/core/loop/cmd/execode.ts +121 -0
- package/core/loop/cmd/test.js +3 -0
- package/core/loop/execLoop.ts +341 -0
- package/core/loop/git/VERSIONING.md +17 -0
- package/core/loop/git/commands.ts +11 -0
- package/core/loop/git/gitClient.ts +78 -0
- package/core/loop/git/index.ts +99 -0
- package/core/loop/git/runVersionControlRunner.ts +33 -0
- package/core/loop/initNavigator.ts +44 -0
- package/core/loop/initTasksManager.ts +35 -0
- package/core/loop/runValidation.ts +25 -0
- package/core/loop/tasks/AGENT-TASKS.md +36 -0
- package/core/loop/tasks/index.ts +96 -0
- package/core/loop/toolCalls.ts +168 -0
- package/core/loop/toolDispatcher.ts +146 -0
- package/core/loop/traceLogger.ts +106 -0
- package/core/loop/types.ts +26 -0
- package/core/loop/versionControlAdapter.ts +36 -0
- package/core/loop/waterfall.ts +404 -0
- package/core/loop/writeArtifactAtomically.ts +13 -0
- package/core/navigate/NAVIGATE.md +186 -0
- package/core/navigate/about.md +128 -0
- package/core/navigate/examples.ts +367 -0
- package/core/navigate/handler.ts +148 -0
- package/core/navigate/index.ts +32 -0
- package/core/navigate/navigate.test.ts +372 -0
- package/core/navigate/navigator.ts +437 -0
- package/core/navigate/types.ts +132 -0
- package/core/navigate/utils.ts +146 -0
- package/core/paths/paths.ts +33 -0
- package/core/ports/index.ts +271 -0
- package/core/segments/CONVENTIONS.md +30 -0
- package/core/segments/loop/index.ts +18 -0
- package/core/segments/map.ts +56 -0
- package/core/segments/navigate/index.ts +20 -0
- package/core/segments/versionControl/index.ts +18 -0
- package/core/util/logger.ts +128 -0
- package/docs/AGENT-TASKS.md +36 -0
- package/docs/ARQUITETURA_CORRECAO.md +121 -0
- package/docs/CONVENTIONS.md +30 -0
- package/docs/CRED.md +112 -0
- package/docs/L_RAG.md +567 -0
- package/docs/NAVIGATE.md +186 -0
- package/docs/PRIMARY_ACTORS.md +78 -0
- package/docs/SECONDARY_ACTORS.md +174 -0
- package/docs/VERSIONING.md +17 -0
- package/docs/boxsafe.config.md +472 -0
- package/eslint.config.mts +15 -0
- package/main.ts +53 -0
- package/memo/generated/codelog.md +13 -0
- package/memo/state/tasks/state.json +6 -0
- package/memo/state/tasks/tasks/task_001.md +2 -0
- package/memo/states-logs/logs.txt +7 -0
- package/memo/states-logs/trace-mljvrxvi-9g0k4q.jsonl +11 -0
- package/memo/states-logs/trace-mljvvc9j-pe9ekj.jsonl +11 -0
- package/memo/states-logs/trace-mljvvm1c-wbnqzp.jsonl +11 -0
- package/memo/states-logs/trace-mljxecwn-9xh3nw.jsonl +11 -0
- package/memo/states-logs/trace-mljxqkfm-ipijik.jsonl +11 -0
- package/memo/states-logs/trace-mljxwtrw-3fanky.jsonl +11 -0
- package/memo/states-logs/trace-mljxzen3-m8iinh.jsonl +11 -0
- package/memo/states-logs/trace-mljyucef-td6odn.jsonl +11 -0
- package/memo/states-logs/trace-mljyuprw-b1a6f4.jsonl +11 -0
- package/memo/states-logs/trace-mljyvefl-b6yoce.jsonl +11 -0
- package/memo/states-logs/trace-mljyxjo4-n7ibj2.jsonl +13 -0
- package/memo/states-logs/trace-mljziez5-8drqtn.jsonl +13 -0
- package/memo/states-logs/trace-mljziulp-dtd03z.jsonl +13 -0
- package/memo/states-logs/trace-mljzjwrq-1p2krb.jsonl +13 -0
- package/memo/states-logs/trace-mljzl0i7-b1cqa6.jsonl +13 -0
- package/memo/states-logs/trace-mljzmlk6-7kdyls.jsonl +13 -0
- package/memo/states-logs/trace-mlk0oj25-xa3dcu.jsonl +13 -0
- package/memo/states-logs/trace-mlk1x59q-713huj.jsonl +14 -0
- package/memo/states-logs/trace-mlk22dz8-7fd6hq.jsonl +14 -0
- package/memo/states-logs/trace-mlk241uy-wmx907.jsonl +14 -0
- package/memo/states-logs/trace-mlk2bf5r-yoh1vg.jsonl +15 -0
- package/package.json +44 -0
- package/pnpm-workspace.yaml +4 -0
- package/prompt_improvement_example.md +55 -0
- package/remove.txt +1 -0
- package/tests/adapters.test.ts +128 -0
- package/tests/extractCode.test.ts +26 -0
- package/tests/integration.test.ts +83 -0
- package/tests/loadConfig.test.ts +25 -0
- package/tests/navigatorBoundary.test.ts +17 -0
- package/tests/ports.test.ts +84 -0
- package/tests/runAllTests.ts +49 -0
- package/tests/toolCalls.test.ts +149 -0
- package/tests/waterfall.test.ts +52 -0
- package/tsconfig.json +32 -0
- package/tsup.config.ts +17 -0
- package/types.d.ts +96 -0
- package/util/ANSI.ts +29 -0
- package/util/extractCode.ts +217 -0
- package/util/extractToolCalls.ts +80 -0
- package/util/logger.ts +125 -0
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# Navigate Module
|
|
2
|
+
|
|
3
|
+
File system navigation system with safety boundaries for LLM-driven operations.
|
|
4
|
+
|
|
5
|
+
## Purpose
|
|
6
|
+
|
|
7
|
+
Provides a robust, type-safe interface for an LLM to:
|
|
8
|
+
- List directory contents
|
|
9
|
+
- Read file contents
|
|
10
|
+
- Write/create files
|
|
11
|
+
- Create directories
|
|
12
|
+
- Delete files and directories
|
|
13
|
+
- Get file/directory metadata
|
|
14
|
+
|
|
15
|
+
All operations are confined to a workspace boundary and validated.
|
|
16
|
+
|
|
17
|
+
## Architecture
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
navigator.ts (main class)
|
|
21
|
+
├─ listDirectory()
|
|
22
|
+
├─ readFile()
|
|
23
|
+
├─ writeFile()
|
|
24
|
+
├─ createDirectory()
|
|
25
|
+
├─ delete()
|
|
26
|
+
└─ getMetadata()
|
|
27
|
+
|
|
28
|
+
handler.ts (sgmnt integration)
|
|
29
|
+
└─ NavigatorHandler.execute(params)
|
|
30
|
+
|
|
31
|
+
utils.ts (security & validation)
|
|
32
|
+
├─ isWithinWorkspace()
|
|
33
|
+
├─ resolvePath()
|
|
34
|
+
├─ checkFileSize()
|
|
35
|
+
└─ isReadable/isWritable()
|
|
36
|
+
|
|
37
|
+
types.ts (exported interfaces)
|
|
38
|
+
├─ NavigatorConfig
|
|
39
|
+
├─ NavigatorResult
|
|
40
|
+
└─ FileSystemEntry
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Quick Start
|
|
44
|
+
|
|
45
|
+
```typescript
|
|
46
|
+
import { createNavigator } from '@core/navigate';
|
|
47
|
+
|
|
48
|
+
const nav = createNavigator({ workspace: '/app' });
|
|
49
|
+
|
|
50
|
+
// List files
|
|
51
|
+
const dir = await nav.listDirectory('src');
|
|
52
|
+
if (dir.ok) {
|
|
53
|
+
console.log(dir.entries);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Read file
|
|
57
|
+
const file = await nav.readFile('src/main.ts');
|
|
58
|
+
if (file.ok) {
|
|
59
|
+
console.log(file.content);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Write file
|
|
63
|
+
const write = await nav.writeFile('src/out.ts', 'export const x = 1;', {
|
|
64
|
+
createDirs: true,
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
// Create directory
|
|
68
|
+
const mkdir = await nav.createDirectory('src/utils');
|
|
69
|
+
|
|
70
|
+
// Get metadata
|
|
71
|
+
const stat = await nav.getMetadata('src/main.ts');
|
|
72
|
+
|
|
73
|
+
// Delete
|
|
74
|
+
const del = await nav.delete('src/temp', { recursive: true });
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Integration with sgmnt
|
|
78
|
+
|
|
79
|
+
Can be integrated into the segmentation map for unified command routing:
|
|
80
|
+
|
|
81
|
+
```typescript
|
|
82
|
+
const handler = createNavigatorHandler(workspace);
|
|
83
|
+
|
|
84
|
+
await handler.execute({
|
|
85
|
+
op: 'write',
|
|
86
|
+
path: 'src/file.ts',
|
|
87
|
+
content: '...',
|
|
88
|
+
writeOptions: { createDirs: true }
|
|
89
|
+
});
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## Safety Features
|
|
93
|
+
|
|
94
|
+
1. **Workspace Boundary** - All paths validated to stay within workspace
|
|
95
|
+
2. **Size Limits** - File reads limited to 10MB default (configurable)
|
|
96
|
+
3. **Permission Checks** - Validates read/write permissions before operations
|
|
97
|
+
4. **Path Validation** - Prevents directory traversal attacks
|
|
98
|
+
5. **Structured Errors** - Clear, machine-readable error results
|
|
99
|
+
|
|
100
|
+
## Error Handling
|
|
101
|
+
|
|
102
|
+
All operations return `NavigatorResult` - either success or error:
|
|
103
|
+
|
|
104
|
+
```typescript
|
|
105
|
+
type NavigatorResult =
|
|
106
|
+
| DirectoryListing
|
|
107
|
+
| FileReadResult
|
|
108
|
+
| FileWriteResult
|
|
109
|
+
| DirectoryCreateResult
|
|
110
|
+
| DeleteResult
|
|
111
|
+
| MetadataResult
|
|
112
|
+
| OperationError;
|
|
113
|
+
|
|
114
|
+
if (result.ok) {
|
|
115
|
+
// Success - type is narrowed to specific result type
|
|
116
|
+
} else {
|
|
117
|
+
// Error
|
|
118
|
+
console.error(result.error);
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## Performance Notes
|
|
123
|
+
|
|
124
|
+
- No blocking operations
|
|
125
|
+
- Async/await throughout
|
|
126
|
+
- Efficient directory sorting (dirs first, then alphabetical)
|
|
127
|
+
- Metadata included with directory listings for smart filtering
|
|
128
|
+
- File read limited by configurable size limit
|
|
@@ -0,0 +1,367 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview
|
|
3
|
+
* Practical examples of using the Navigator module.
|
|
4
|
+
* These examples show common use cases for LLM-driven file operations.
|
|
5
|
+
*
|
|
6
|
+
* @module core/navigate/examples
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { createNavigator, createNavigatorHandler } from '@core/navigate';
|
|
10
|
+
import type { DirectoryListing, FileReadResult, FileWriteResult, MetadataResult } from '@core/navigate';
|
|
11
|
+
import { Logger } from '@core/util/logger';
|
|
12
|
+
|
|
13
|
+
// Type guards for proper narrowing
|
|
14
|
+
const isDirectory = (result: any): result is DirectoryListing => result.ok && 'entries' in result;
|
|
15
|
+
const isFileRead = (result: any): result is FileReadResult => result.ok && 'content' in result;
|
|
16
|
+
const isFileWrite = (result: any): result is FileWriteResult => result.ok && 'created' in result;
|
|
17
|
+
const isMetadata = (result: any): result is MetadataResult => result.ok && 'stat' in result;
|
|
18
|
+
const isError = (result: any): result is { ok: false; error: string } => !result.ok;
|
|
19
|
+
|
|
20
|
+
const logger = Logger.createModuleLogger('NavigateExamples');
|
|
21
|
+
|
|
22
|
+
// Example 1: Basic Setup and Directory Listing
|
|
23
|
+
|
|
24
|
+
async function example1_BasicListingAndExploration() {
|
|
25
|
+
const nav = createNavigator({
|
|
26
|
+
workspace: '/home/inky/Development/boxsafe',
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
// List root workspace
|
|
30
|
+
const root = await nav.listDirectory('.');
|
|
31
|
+
if (isDirectory(root)) {
|
|
32
|
+
logger.info(`Workspace has ${root.total} items:`);
|
|
33
|
+
root.entries.forEach((entry) => {
|
|
34
|
+
const icon = entry.type === 'directory' ? '📁' : '📄';
|
|
35
|
+
const size = entry.size ? ` (${entry.size} bytes)` : '';
|
|
36
|
+
logger.info(` ${icon} ${entry.name}${size}`);
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Navigate to specific directory
|
|
41
|
+
const srcDir = await nav.listDirectory('src');
|
|
42
|
+
if (isDirectory(srcDir)) {
|
|
43
|
+
logger.info(`Found ${srcDir.total} items in src/`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// ============================================================================
|
|
48
|
+
// Example 2: Reading Multiple Files for Analysis
|
|
49
|
+
// ============================================================================
|
|
50
|
+
|
|
51
|
+
async function example2_ReadMultipleFilesForLLMAnalysis() {
|
|
52
|
+
const nav = createNavigator({
|
|
53
|
+
workspace: '/home/inky/Development/boxsafe',
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
// Read several related files
|
|
57
|
+
const files = ['main.ts', 'types.d.ts', 'package.json'];
|
|
58
|
+
const contents: Record<string, string> = {};
|
|
59
|
+
|
|
60
|
+
for (const file of files) {
|
|
61
|
+
const result = await nav.readFile(file);
|
|
62
|
+
if (isFileRead(result)) {
|
|
63
|
+
contents[file] = result.content;
|
|
64
|
+
logger.info(`Loaded ${file} (${result.size} bytes)`);
|
|
65
|
+
} else if (!result.ok) {
|
|
66
|
+
logger.error(`Failed to read ${file}: ${result.error}`);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Now LLM can analyze all files together
|
|
71
|
+
logger.info(`All files loaded for analysis`);
|
|
72
|
+
return contents;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// ============================================================================
|
|
76
|
+
// Example 3: Creating Project Structure
|
|
77
|
+
// ============================================================================
|
|
78
|
+
|
|
79
|
+
async function example3_CreateProjectStructure() {
|
|
80
|
+
const nav = createNavigator({
|
|
81
|
+
workspace: '/home/inky/Development/boxsafe',
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
// Create directory structure
|
|
85
|
+
const dirs = [
|
|
86
|
+
'output',
|
|
87
|
+
'output/generated',
|
|
88
|
+
'output/reports',
|
|
89
|
+
'output/logs',
|
|
90
|
+
];
|
|
91
|
+
|
|
92
|
+
for (const dir of dirs) {
|
|
93
|
+
const result = await nav.createDirectory(dir, { recursive: true });
|
|
94
|
+
if (isError(result)) {
|
|
95
|
+
logger.error(`Failed: ${result.error}`);
|
|
96
|
+
} else {
|
|
97
|
+
logger.info(`Created: ${result.path}`);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// ============================================================================
|
|
103
|
+
// Example 4: Generate Multiple Code Files
|
|
104
|
+
// ============================================================================
|
|
105
|
+
|
|
106
|
+
async function example4_GenerateCodeFiles() {
|
|
107
|
+
const nav = createNavigator({
|
|
108
|
+
workspace: '/home/inky/Development/boxsafe',
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
const files = [
|
|
112
|
+
{
|
|
113
|
+
path: 'generated/types.ts',
|
|
114
|
+
content: `export interface User { id: string; name: string; }`,
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
path: 'generated/utils.ts',
|
|
118
|
+
content: `export function formatName(name: string): string { return name.trim(); }`,
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
path: 'generated/index.ts',
|
|
122
|
+
content: `export * from './types';\nexport * from './utils';`,
|
|
123
|
+
},
|
|
124
|
+
];
|
|
125
|
+
|
|
126
|
+
for (const file of files) {
|
|
127
|
+
const result = await nav.writeFile(file.path, file.content, {
|
|
128
|
+
createDirs: true,
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
if (isError(result)) {
|
|
132
|
+
logger.error(`✗ Failed: ${result.error}`);
|
|
133
|
+
} else {
|
|
134
|
+
logger.info(`✓ Created ${result.path}`);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// ============================================================================
|
|
140
|
+
// Example 5: Iterate and Update Files
|
|
141
|
+
// ============================================================================
|
|
142
|
+
|
|
143
|
+
async function example5_IterativeFileUpdates() {
|
|
144
|
+
const nav = createNavigator({
|
|
145
|
+
workspace: '/home/inky/Development/boxsafe',
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
// Read existing file
|
|
149
|
+
const result = await nav.readFile('src/main.ts');
|
|
150
|
+
if (!isFileRead(result)) {
|
|
151
|
+
logger.error(`Cannot read: ${isError(result) ? result.error : 'unknown'}`);
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
let content = result.content;
|
|
155
|
+
const hasExport = content.includes('export');
|
|
156
|
+
if (!hasExport) {
|
|
157
|
+
// Add export if missing
|
|
158
|
+
content = `export ${content}`;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Write back with updated content
|
|
162
|
+
const writeResult = await nav.writeFile('src/main.ts', content);
|
|
163
|
+
if (isFileWrite(writeResult)) {
|
|
164
|
+
logger.info(`Updated ${writeResult.path} (${writeResult.size} bytes)`);
|
|
165
|
+
} else if (isError(writeResult)) {
|
|
166
|
+
logger.error(`Write failed: ${writeResult.error}`);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// ============================================================================
|
|
171
|
+
// Example 6: Check File Metadata Before Operations
|
|
172
|
+
// ============================================================================
|
|
173
|
+
|
|
174
|
+
async function example6_ValidateBeforeOperation() {
|
|
175
|
+
const nav = createNavigator({
|
|
176
|
+
workspace: '/home/inky/Development/boxsafe',
|
|
177
|
+
maxFileSize: 5 * 1024 * 1024, // 5MB limit
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
const filePath = 'src/large.json';
|
|
181
|
+
|
|
182
|
+
// Check metadata first
|
|
183
|
+
const stat = await nav.getMetadata(filePath);
|
|
184
|
+
if (!isMetadata(stat)) {
|
|
185
|
+
logger.error(`File not found: ${isError(stat) ? stat.error : 'unknown'}`);
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
if (stat.stat.size > 1024 * 1024) {
|
|
189
|
+
logger.warn(`File is ${stat.stat.size} bytes - may be too large`);
|
|
190
|
+
}
|
|
191
|
+
if (!stat.stat.isReadable) {
|
|
192
|
+
logger.error(`File is not readable`);
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// Now safe to read
|
|
197
|
+
const content = await nav.readFile(filePath);
|
|
198
|
+
if (isFileRead(content)) {
|
|
199
|
+
logger.info(`File content loaded: ${content.content.slice(0, 100)}`);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// ============================================================================
|
|
204
|
+
// Example 7: LLM-Friendly Handler Integration
|
|
205
|
+
// ============================================================================
|
|
206
|
+
|
|
207
|
+
async function example7_HandlerIntegration() {
|
|
208
|
+
const handler = createNavigatorHandler('/home/inky/Development/boxsafe');
|
|
209
|
+
|
|
210
|
+
// Simple operations through handler
|
|
211
|
+
const list = await handler.execute({
|
|
212
|
+
op: 'list',
|
|
213
|
+
path: 'src',
|
|
214
|
+
});
|
|
215
|
+
logger.info(`Directory listing result:`);
|
|
216
|
+
logger.debug(JSON.stringify(list, null, 2));
|
|
217
|
+
|
|
218
|
+
// Write with structured params
|
|
219
|
+
const write = await handler.execute({
|
|
220
|
+
op: 'write',
|
|
221
|
+
path: 'output/result.ts',
|
|
222
|
+
content: 'export const result = "success";',
|
|
223
|
+
writeOptions: { createDirs: true },
|
|
224
|
+
});
|
|
225
|
+
logger.info(`Write result:`);
|
|
226
|
+
logger.debug(JSON.stringify(write, null, 2));
|
|
227
|
+
|
|
228
|
+
// Read with error handling
|
|
229
|
+
const read = await handler.execute({
|
|
230
|
+
op: 'read',
|
|
231
|
+
path: 'output/result.ts',
|
|
232
|
+
});
|
|
233
|
+
if (isError(read)) {
|
|
234
|
+
logger.error(`Read error: ${read.error}`);
|
|
235
|
+
} else if (isFileRead(read)) {
|
|
236
|
+
logger.info(`Content: ${read.content}`);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// Delete operation
|
|
240
|
+
const del = await handler.execute({
|
|
241
|
+
op: 'delete',
|
|
242
|
+
path: 'output/temp',
|
|
243
|
+
deleteOptions: { recursive: true },
|
|
244
|
+
});
|
|
245
|
+
logger.info(`Delete result:`);
|
|
246
|
+
logger.debug(JSON.stringify(del, null, 2));
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// ============================================================================
|
|
250
|
+
// Example 8: Batch Operations with Error Recovery
|
|
251
|
+
// ============================================================================
|
|
252
|
+
|
|
253
|
+
async function example8_BatchOperationsWithRecovery() {
|
|
254
|
+
const nav = createNavigator({
|
|
255
|
+
workspace: '/home/inky/Development/boxsafe',
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
const operations = [
|
|
259
|
+
{ type: 'mkdir' as const, path: 'batch/level1' },
|
|
260
|
+
{ type: 'mkdir' as const, path: 'batch/level1/level2' },
|
|
261
|
+
{ type: 'write' as const, path: 'batch/file1.txt', content: 'content1' },
|
|
262
|
+
{ type: 'write' as const, path: 'batch/level1/file2.txt', content: 'content2' },
|
|
263
|
+
];
|
|
264
|
+
|
|
265
|
+
const results = [];
|
|
266
|
+
for (const op of operations) {
|
|
267
|
+
try {
|
|
268
|
+
let result;
|
|
269
|
+
if (op.type === 'mkdir') {
|
|
270
|
+
result = await nav.createDirectory(op.path, { recursive: true });
|
|
271
|
+
} else if (op.type === 'write') {
|
|
272
|
+
result = await nav.writeFile(op.path, op.content, { createDirs: true });
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
if (result?.ok) {
|
|
276
|
+
results.push({ status: 'ok', op, result });
|
|
277
|
+
} else if (isError(result)) {
|
|
278
|
+
results.push({ status: 'error', op, error: result });
|
|
279
|
+
}
|
|
280
|
+
} catch (err) {
|
|
281
|
+
results.push({ status: 'exception', op, error: err });
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
logger.info(`Batch results:`);
|
|
286
|
+
logger.debug(JSON.stringify(results, null, 2));
|
|
287
|
+
return results;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
// ============================================================================
|
|
291
|
+
// Example 9: Explore Directory Tree
|
|
292
|
+
// ============================================================================
|
|
293
|
+
|
|
294
|
+
async function example9_ExploreDirectoryTree() {
|
|
295
|
+
const nav = createNavigator({
|
|
296
|
+
workspace: '/home/inky/Development/boxsafe',
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
async function exploreTree(dirPath: string, depth: number = 0): Promise<void> {
|
|
300
|
+
const indent = ' '.repeat(depth);
|
|
301
|
+
|
|
302
|
+
const listing = await nav.listDirectory(dirPath);
|
|
303
|
+
if (!isDirectory(listing)) {
|
|
304
|
+
logger.error(`${indent}ERROR: ${isError(listing) ? listing.error : 'unknown'}`);
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
for (const entry of listing.entries) {
|
|
309
|
+
if (entry.type === 'directory') {
|
|
310
|
+
logger.info(`${indent}📁 ${entry.name}/`);
|
|
311
|
+
if (depth < 2) await exploreTree(entry.path, depth + 1);
|
|
312
|
+
} else {
|
|
313
|
+
logger.info(`${indent}📄 ${entry.name} (${entry.size ?? 0} bytes)`);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
await exploreTree('.');
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
// ============================================================================
|
|
322
|
+
// Example 10: Validate Workspace Before Starting
|
|
323
|
+
// ============================================================================
|
|
324
|
+
|
|
325
|
+
async function example10_ValidateWorkspace() {
|
|
326
|
+
const nav = createNavigator({
|
|
327
|
+
workspace: '/home/inky/Development/boxsafe',
|
|
328
|
+
});
|
|
329
|
+
|
|
330
|
+
const requiredFiles = [
|
|
331
|
+
'package.json',
|
|
332
|
+
'tsconfig.json',
|
|
333
|
+
'types.d.ts',
|
|
334
|
+
];
|
|
335
|
+
|
|
336
|
+
const required = [];
|
|
337
|
+
for (const file of requiredFiles) {
|
|
338
|
+
const stat = await nav.getMetadata(file);
|
|
339
|
+
const exists = isMetadata(stat);
|
|
340
|
+
const writable = exists ? stat.stat.isWritable : false;
|
|
341
|
+
|
|
342
|
+
required.push({ file, exists, writable });
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
logger.info(`Workspace validation:`);
|
|
346
|
+
logger.debug(JSON.stringify(required, null, 2));
|
|
347
|
+
const allReady = required.every((r) => r.exists && r.writable);
|
|
348
|
+
logger.info(`Workspace ready: ${allReady}`);
|
|
349
|
+
return allReady;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
// ============================================================================
|
|
353
|
+
// Export all examples for testing
|
|
354
|
+
// ============================================================================
|
|
355
|
+
|
|
356
|
+
export const examples = {
|
|
357
|
+
basicListing: example1_BasicListingAndExploration,
|
|
358
|
+
readMultiple: example2_ReadMultipleFilesForLLMAnalysis,
|
|
359
|
+
createStructure: example3_CreateProjectStructure,
|
|
360
|
+
generateFiles: example4_GenerateCodeFiles,
|
|
361
|
+
iterateUpdate: example5_IterativeFileUpdates,
|
|
362
|
+
validateMetadata: example6_ValidateBeforeOperation,
|
|
363
|
+
handlerIntegration: example7_HandlerIntegration,
|
|
364
|
+
batchOperations: example8_BatchOperationsWithRecovery,
|
|
365
|
+
exploreTree: example9_ExploreDirectoryTree,
|
|
366
|
+
validateWorkspace: example10_ValidateWorkspace,
|
|
367
|
+
};
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview
|
|
3
|
+
* Handler for file system navigation operations.
|
|
4
|
+
* Integrates with the sgmnt (segmentation) system for unified LLM command routing.
|
|
5
|
+
*
|
|
6
|
+
* @module core/navigate/handler
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { NavigatorResult } from '@core/navigate/types';
|
|
10
|
+
import { createNavigator, Navigator } from '@core/navigate/navigator';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Parameters for navigator operations.
|
|
14
|
+
*/
|
|
15
|
+
export interface NavigatorOperationParams {
|
|
16
|
+
/** Operation type: 'list', 'read', 'write', 'mkdir', 'delete', 'stat' */
|
|
17
|
+
op: 'list' | 'read' | 'write' | 'mkdir' | 'delete' | 'stat';
|
|
18
|
+
|
|
19
|
+
/** File or directory path (required for all except 'list' with default) */
|
|
20
|
+
path?: string;
|
|
21
|
+
|
|
22
|
+
/** Content to write (required for 'write') */
|
|
23
|
+
content?: string;
|
|
24
|
+
|
|
25
|
+
/** Write options */
|
|
26
|
+
writeOptions?: {
|
|
27
|
+
append?: boolean;
|
|
28
|
+
createDirs?: boolean;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
/** Directory creation options */
|
|
32
|
+
mkdirOptions?: {
|
|
33
|
+
recursive?: boolean;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
/** Delete options */
|
|
37
|
+
deleteOptions?: {
|
|
38
|
+
recursive?: boolean;
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Handler for all navigation operations.
|
|
44
|
+
* Provides a unified interface for LLM-driven file system access.
|
|
45
|
+
*/
|
|
46
|
+
export class NavigatorHandler {
|
|
47
|
+
private navigator: Navigator;
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Creates a handler instance.
|
|
51
|
+
*
|
|
52
|
+
* @param workspace - Workspace root path for all operations
|
|
53
|
+
*/
|
|
54
|
+
constructor(workspace: string) {
|
|
55
|
+
this.navigator = createNavigator({
|
|
56
|
+
workspace,
|
|
57
|
+
followSymlinks: false,
|
|
58
|
+
maxFileSize: 10 * 1024 * 1024, // 10MB default
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Executes a navigation operation.
|
|
64
|
+
*
|
|
65
|
+
* @param params - Operation parameters
|
|
66
|
+
* @returns Promise resolving to operation result
|
|
67
|
+
*/
|
|
68
|
+
async execute(params: NavigatorOperationParams): Promise<NavigatorResult> {
|
|
69
|
+
switch (params.op) {
|
|
70
|
+
case 'list':
|
|
71
|
+
return this.navigator.listDirectory(params.path || '.');
|
|
72
|
+
|
|
73
|
+
case 'read':
|
|
74
|
+
if (!params.path) {
|
|
75
|
+
return {
|
|
76
|
+
ok: false,
|
|
77
|
+
operation: 'read',
|
|
78
|
+
error: 'path is required for read operation',
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
return this.navigator.readFile(params.path);
|
|
82
|
+
|
|
83
|
+
case 'write':
|
|
84
|
+
if (!params.path) {
|
|
85
|
+
return {
|
|
86
|
+
ok: false,
|
|
87
|
+
operation: 'write',
|
|
88
|
+
error: 'path is required for write operation',
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
if (params.content === undefined) {
|
|
92
|
+
return {
|
|
93
|
+
ok: false,
|
|
94
|
+
operation: 'write',
|
|
95
|
+
error: 'content is required for write operation',
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
return this.navigator.writeFile(params.path, params.content, params.writeOptions);
|
|
99
|
+
|
|
100
|
+
case 'mkdir':
|
|
101
|
+
if (!params.path) {
|
|
102
|
+
return {
|
|
103
|
+
ok: false,
|
|
104
|
+
operation: 'mkdir',
|
|
105
|
+
error: 'path is required for mkdir operation',
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
return this.navigator.createDirectory(params.path, params.mkdirOptions);
|
|
109
|
+
|
|
110
|
+
case 'delete':
|
|
111
|
+
if (!params.path) {
|
|
112
|
+
return {
|
|
113
|
+
ok: false,
|
|
114
|
+
operation: 'delete',
|
|
115
|
+
error: 'path is required for delete operation',
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
return this.navigator.delete(params.path, params.deleteOptions);
|
|
119
|
+
|
|
120
|
+
case 'stat':
|
|
121
|
+
if (!params.path) {
|
|
122
|
+
return {
|
|
123
|
+
ok: false,
|
|
124
|
+
operation: 'stat',
|
|
125
|
+
error: 'path is required for stat operation',
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
return this.navigator.getMetadata(params.path);
|
|
129
|
+
|
|
130
|
+
default:
|
|
131
|
+
return {
|
|
132
|
+
ok: false,
|
|
133
|
+
operation: 'unknown',
|
|
134
|
+
error: `unknown operation: ${(params as any).op}`,
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Creates a handler instance bound to a workspace.
|
|
142
|
+
*
|
|
143
|
+
* @param workspace - Workspace root path
|
|
144
|
+
* @returns NavigatorHandler instance
|
|
145
|
+
*/
|
|
146
|
+
export function createNavigatorHandler(workspace: string): NavigatorHandler {
|
|
147
|
+
return new NavigatorHandler(workspace);
|
|
148
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview
|
|
3
|
+
* File system navigation module - public API exports.
|
|
4
|
+
*
|
|
5
|
+
* Provides LLM-safe file and directory operations with workspace boundary enforcement.
|
|
6
|
+
*
|
|
7
|
+
* @module core/navigate
|
|
8
|
+
* @example
|
|
9
|
+
* ```typescript
|
|
10
|
+
* import { createNavigator } from '@core/navigate';
|
|
11
|
+
*
|
|
12
|
+
* const nav = createNavigator({ workspace: '/app' });
|
|
13
|
+
* const result = await nav.listDirectory('src');
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
export { Navigator, createNavigator } from '@core/navigate/navigator';
|
|
18
|
+
export { NavigatorHandler, createNavigatorHandler } from '@core/navigate/handler';
|
|
19
|
+
export type {
|
|
20
|
+
NavigatorConfig,
|
|
21
|
+
NavigatorResult,
|
|
22
|
+
OperationResult,
|
|
23
|
+
OperationError,
|
|
24
|
+
DirectoryListing,
|
|
25
|
+
FileReadResult,
|
|
26
|
+
FileWriteResult,
|
|
27
|
+
DirectoryCreateResult,
|
|
28
|
+
DeleteResult,
|
|
29
|
+
MetadataResult,
|
|
30
|
+
FileSystemEntry,
|
|
31
|
+
} from '@core/navigate/types';
|
|
32
|
+
export type { NavigatorOperationParams } from '@core/navigate/handler';
|