@prmichaelsen/acp-mcp 0.5.1 → 0.7.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/CHANGELOG.md +66 -0
- package/README.md +15 -6
- package/agent/design/local.progress-streaming.md +940 -0
- package/agent/milestones/milestone-4-progress-streaming-server.md +84 -0
- package/agent/milestones/milestone-5-progress-streaming-wrapper.md +71 -0
- package/agent/milestones/milestone-6-progress-streaming-client.md +79 -0
- package/agent/progress.yaml +145 -16
- package/agent/tasks/milestone-4-progress-streaming-server/task-6-add-ssh-stream-execution.md +149 -0
- package/agent/tasks/milestone-4-progress-streaming-server/task-7-implement-progress-streaming.md +191 -0
- package/agent/tasks/milestone-4-progress-streaming-server/task-8-update-server-handlers.md +109 -0
- package/agent/tasks/milestone-4-progress-streaming-server/task-9-testing-documentation.md +192 -0
- package/agent/tasks/task-5-fix-incomplete-directory-listings.md +170 -0
- package/dist/server-factory.js +299 -28
- package/dist/server-factory.js.map +4 -4
- package/dist/server.js +299 -28
- package/dist/server.js.map +4 -4
- package/dist/tools/acp-remote-execute-command.d.ts +4 -1
- package/dist/types/file-entry.d.ts +88 -0
- package/dist/utils/ssh-connection.d.ts +26 -5
- package/package.json +1 -1
- package/src/server-factory.ts +3 -2
- package/src/server.ts +3 -2
- package/src/tools/acp-remote-execute-command.ts +116 -7
- package/src/tools/acp-remote-list-files.ts +27 -21
- package/src/types/file-entry.ts +123 -0
- package/src/utils/ssh-connection.ts +189 -5
package/agent/tasks/milestone-4-progress-streaming-server/task-7-implement-progress-streaming.md
ADDED
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
# Task 7: Implement Progress Streaming in Execute Command
|
|
2
|
+
|
|
3
|
+
**Milestone**: M4 - Progress Streaming - Server Implementation
|
|
4
|
+
**Estimated Time**: 4-5 hours
|
|
5
|
+
**Dependencies**: Task 6 (SSH stream execution)
|
|
6
|
+
**Status**: Not Started
|
|
7
|
+
**Priority**: High
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Objective
|
|
12
|
+
|
|
13
|
+
Update `acp_remote_execute_command` tool to support progress streaming when client provides a `progressToken`. Implement graceful fallback to timeout mode when no progress token is provided.
|
|
14
|
+
|
|
15
|
+
## Context
|
|
16
|
+
|
|
17
|
+
**Design Reference**: [`agent/design/local.progress-streaming.md`](../../design/local.progress-streaming.md)
|
|
18
|
+
|
|
19
|
+
**Current State**: Tool uses `execWithTimeout()` and returns all output at once
|
|
20
|
+
|
|
21
|
+
**Desired State**: Tool detects `progressToken`, streams output with progress notifications, maintains backward compatibility
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Steps
|
|
26
|
+
|
|
27
|
+
### 1. Update Handler Signature
|
|
28
|
+
|
|
29
|
+
**File**: `src/tools/acp-remote-execute-command.ts`
|
|
30
|
+
|
|
31
|
+
**Actions**:
|
|
32
|
+
- Add `extra?: { progressToken?: string | number }` parameter
|
|
33
|
+
- Import server instance for sending notifications
|
|
34
|
+
- Add type definitions for progress params
|
|
35
|
+
|
|
36
|
+
### 2. Add Progress Detection Logic
|
|
37
|
+
|
|
38
|
+
**Actions**:
|
|
39
|
+
- Check if `extra?.progressToken` exists
|
|
40
|
+
- If yes: call `executeWithProgress()`
|
|
41
|
+
- If no: use existing `execWithTimeout()` (fallback)
|
|
42
|
+
|
|
43
|
+
### 3. Implement executeWithProgress() Function
|
|
44
|
+
|
|
45
|
+
**Actions**:
|
|
46
|
+
- Call `sshConnection.execStream()`
|
|
47
|
+
- Set up stdout data handler
|
|
48
|
+
- Send progress notification for each chunk
|
|
49
|
+
- Collect full output for final result
|
|
50
|
+
- Handle stderr separately (no progress)
|
|
51
|
+
- Wait for exit code
|
|
52
|
+
- Return structured result
|
|
53
|
+
|
|
54
|
+
**Code Pattern**:
|
|
55
|
+
```typescript
|
|
56
|
+
async function executeWithProgress(
|
|
57
|
+
command: string,
|
|
58
|
+
cwd: string | undefined,
|
|
59
|
+
sshConnection: SSHConnectionManager,
|
|
60
|
+
progressToken: string | number
|
|
61
|
+
): Promise<{ content: Array<{ type: string; text: string }> }> {
|
|
62
|
+
const { stream, stderr: stderrStream, exitCode } = await sshConnection.execStream(command, cwd);
|
|
63
|
+
|
|
64
|
+
let stdout = '';
|
|
65
|
+
let stderr = '';
|
|
66
|
+
let bytesReceived = 0;
|
|
67
|
+
|
|
68
|
+
stream.on('data', (chunk: Buffer) => {
|
|
69
|
+
const text = chunk.toString();
|
|
70
|
+
stdout += text;
|
|
71
|
+
bytesReceived += chunk.length;
|
|
72
|
+
|
|
73
|
+
// Send progress notification
|
|
74
|
+
server.notification({
|
|
75
|
+
method: 'notifications/progress',
|
|
76
|
+
params: {
|
|
77
|
+
progressToken,
|
|
78
|
+
progress: bytesReceived,
|
|
79
|
+
total: undefined,
|
|
80
|
+
message: text,
|
|
81
|
+
},
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
stderrStream.on('data', (chunk: Buffer) => {
|
|
86
|
+
stderr += chunk.toString();
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
const finalExitCode = await exitCode;
|
|
90
|
+
|
|
91
|
+
return {
|
|
92
|
+
content: [{
|
|
93
|
+
type: 'text',
|
|
94
|
+
text: JSON.stringify({
|
|
95
|
+
stdout,
|
|
96
|
+
stderr,
|
|
97
|
+
exitCode: finalExitCode,
|
|
98
|
+
timedOut: false,
|
|
99
|
+
streamed: true,
|
|
100
|
+
}, null, 2),
|
|
101
|
+
}],
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### 4. Add Rate Limiting
|
|
107
|
+
|
|
108
|
+
**Actions**:
|
|
109
|
+
- Limit progress notifications to max 10/second
|
|
110
|
+
- Batch small chunks
|
|
111
|
+
- Track last notification time
|
|
112
|
+
- Only send if enough time elapsed
|
|
113
|
+
|
|
114
|
+
**Code Pattern**:
|
|
115
|
+
```typescript
|
|
116
|
+
let lastProgressTime = 0;
|
|
117
|
+
const MIN_PROGRESS_INTERVAL = 100; // 100ms
|
|
118
|
+
|
|
119
|
+
stream.on('data', (chunk: Buffer) => {
|
|
120
|
+
stdout += chunk.toString();
|
|
121
|
+
bytesReceived += chunk.length;
|
|
122
|
+
|
|
123
|
+
const now = Date.now();
|
|
124
|
+
if (now - lastProgressTime >= MIN_PROGRESS_INTERVAL) {
|
|
125
|
+
server.notification({ /* ... */ });
|
|
126
|
+
lastProgressTime = now;
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### 5. Add Error Handling
|
|
132
|
+
|
|
133
|
+
**Actions**:
|
|
134
|
+
- Handle stream errors
|
|
135
|
+
- Handle connection loss
|
|
136
|
+
- Send error via progress notification
|
|
137
|
+
- Return error in final result
|
|
138
|
+
|
|
139
|
+
### 6. Update Tool Schema
|
|
140
|
+
|
|
141
|
+
**Actions**:
|
|
142
|
+
- Update description to mention progress support
|
|
143
|
+
- Note that timeout is ignored when streaming
|
|
144
|
+
- Add examples of progress usage
|
|
145
|
+
|
|
146
|
+
### 7. Test Implementation
|
|
147
|
+
|
|
148
|
+
**Actions**:
|
|
149
|
+
- Build project
|
|
150
|
+
- Test with progressToken (streaming mode)
|
|
151
|
+
- Test without progressToken (fallback mode)
|
|
152
|
+
- Test with long-running command
|
|
153
|
+
- Test with command that fails
|
|
154
|
+
- Test error scenarios
|
|
155
|
+
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
## Verification
|
|
159
|
+
|
|
160
|
+
- [ ] Handler accepts `extra` parameter
|
|
161
|
+
- [ ] Detects `progressToken` correctly
|
|
162
|
+
- [ ] Calls `executeWithProgress()` when token provided
|
|
163
|
+
- [ ] Falls back to `execWithTimeout()` when no token
|
|
164
|
+
- [ ] Sends progress notifications for stdout chunks
|
|
165
|
+
- [ ] Rate limiting prevents notification spam
|
|
166
|
+
- [ ] Collects full output for final result
|
|
167
|
+
- [ ] Handles errors gracefully
|
|
168
|
+
- [ ] TypeScript compiles without errors
|
|
169
|
+
- [ ] Build completes successfully
|
|
170
|
+
- [ ] Both modes tested and working
|
|
171
|
+
|
|
172
|
+
---
|
|
173
|
+
|
|
174
|
+
## Expected Output
|
|
175
|
+
|
|
176
|
+
### Files Modified
|
|
177
|
+
- `src/tools/acp-remote-execute-command.ts` - Progress streaming implementation
|
|
178
|
+
|
|
179
|
+
### New Function
|
|
180
|
+
```typescript
|
|
181
|
+
async function executeWithProgress(
|
|
182
|
+
command: string,
|
|
183
|
+
cwd: string | undefined,
|
|
184
|
+
sshConnection: SSHConnectionManager,
|
|
185
|
+
progressToken: string | number
|
|
186
|
+
): Promise<{ content: Array<{ type: string; text: string }> }>
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
---
|
|
190
|
+
|
|
191
|
+
**Next Task**: [Task 8: Update Server Request Handlers](task-8-update-server-handlers.md)
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# Task 8: Update Server Request Handlers
|
|
2
|
+
|
|
3
|
+
**Milestone**: M4 - Progress Streaming - Server Implementation
|
|
4
|
+
**Estimated Time**: 1-2 hours
|
|
5
|
+
**Dependencies**: Task 7 (Progress streaming implementation)
|
|
6
|
+
**Status**: Not Started
|
|
7
|
+
**Priority**: Medium
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Objective
|
|
12
|
+
|
|
13
|
+
Update server request handlers in both `server.ts` and `server-factory.ts` to pass the `extra` parameter (containing `progressToken`) to tool handlers.
|
|
14
|
+
|
|
15
|
+
## Context
|
|
16
|
+
|
|
17
|
+
**Design Reference**: [`agent/design/local.progress-streaming.md`](../../design/local.progress-streaming.md)
|
|
18
|
+
|
|
19
|
+
**Current State**: Handlers don't pass `extra` parameter to tools
|
|
20
|
+
|
|
21
|
+
**Desired State**: Handlers pass `extra` to `acp_remote_execute_command` handler
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Steps
|
|
26
|
+
|
|
27
|
+
### 1. Update server.ts Handler
|
|
28
|
+
|
|
29
|
+
**File**: `src/server.ts`
|
|
30
|
+
|
|
31
|
+
**Actions**:
|
|
32
|
+
- Modify `CallToolRequestSchema` handler signature to accept `extra` parameter
|
|
33
|
+
- Pass `extra` to `handleAcpRemoteExecuteCommand()`
|
|
34
|
+
- Keep other tool handlers unchanged (they don't need progress)
|
|
35
|
+
|
|
36
|
+
**Code Pattern**:
|
|
37
|
+
```typescript
|
|
38
|
+
server.setRequestHandler(CallToolRequestSchema, async (request, extra) => {
|
|
39
|
+
const startTime = Date.now();
|
|
40
|
+
logger.toolInvoked(request.params.name, request.params.arguments);
|
|
41
|
+
|
|
42
|
+
try {
|
|
43
|
+
let result;
|
|
44
|
+
|
|
45
|
+
if (request.params.name === 'acp_remote_execute_command') {
|
|
46
|
+
result = await handleAcpRemoteExecuteCommand(
|
|
47
|
+
request.params.arguments,
|
|
48
|
+
sshConnection,
|
|
49
|
+
extra // Pass extra with progressToken
|
|
50
|
+
);
|
|
51
|
+
} else if (request.params.name === 'acp_remote_list_files') {
|
|
52
|
+
result = await handleAcpRemoteListFiles(request.params.arguments, sshConnection);
|
|
53
|
+
}
|
|
54
|
+
// ... other tools
|
|
55
|
+
|
|
56
|
+
return result;
|
|
57
|
+
} catch (error) {
|
|
58
|
+
logger.toolFailed(request.params.name, error as Error, request.params.arguments);
|
|
59
|
+
throw error;
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### 2. Update server-factory.ts Handler
|
|
65
|
+
|
|
66
|
+
**File**: `src/server-factory.ts`
|
|
67
|
+
|
|
68
|
+
**Actions**:
|
|
69
|
+
- Same changes as server.ts
|
|
70
|
+
- Ensure consistency between both files
|
|
71
|
+
|
|
72
|
+
### 3. Verify No Breaking Changes
|
|
73
|
+
|
|
74
|
+
**Actions**:
|
|
75
|
+
- Confirm other tools still work
|
|
76
|
+
- Verify `extra` parameter is optional
|
|
77
|
+
- Test that undefined `extra` doesn't break anything
|
|
78
|
+
|
|
79
|
+
### 4. Test Both Server Modes
|
|
80
|
+
|
|
81
|
+
**Actions**:
|
|
82
|
+
- Build project
|
|
83
|
+
- Test standalone server (server.ts)
|
|
84
|
+
- Test factory server (server-factory.ts)
|
|
85
|
+
- Verify both pass `extra` correctly
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## Verification
|
|
90
|
+
|
|
91
|
+
- [ ] server.ts handler updated
|
|
92
|
+
- [ ] server-factory.ts handler updated
|
|
93
|
+
- [ ] `extra` parameter passed to execute_command handler
|
|
94
|
+
- [ ] Other tools unaffected
|
|
95
|
+
- [ ] TypeScript compiles without errors
|
|
96
|
+
- [ ] Build completes successfully
|
|
97
|
+
- [ ] Both server modes tested
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
## Expected Output
|
|
102
|
+
|
|
103
|
+
### Files Modified
|
|
104
|
+
- `src/server.ts` - Pass `extra` to handler
|
|
105
|
+
- `src/server-factory.ts` - Pass `extra` to handler
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
**Next Task**: [Task 9: Testing and Documentation](task-9-testing-documentation.md)
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
# Task 9: Testing and Documentation
|
|
2
|
+
|
|
3
|
+
**Milestone**: M4 - Progress Streaming - Server Implementation
|
|
4
|
+
**Estimated Time**: 3-4 hours
|
|
5
|
+
**Dependencies**: Tasks 6, 7, 8 (All implementation complete)
|
|
6
|
+
**Status**: Not Started
|
|
7
|
+
**Priority**: High
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Objective
|
|
12
|
+
|
|
13
|
+
Add comprehensive tests for progress streaming functionality and update all documentation for v0.7.0 release.
|
|
14
|
+
|
|
15
|
+
## Context
|
|
16
|
+
|
|
17
|
+
**Design Reference**: [`agent/design/local.progress-streaming.md`](../../design/local.progress-streaming.md)
|
|
18
|
+
|
|
19
|
+
**Current State**: Implementation complete, needs testing and documentation
|
|
20
|
+
|
|
21
|
+
**Desired State**: Full test coverage, updated documentation, ready for v0.7.0 release
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Steps
|
|
26
|
+
|
|
27
|
+
### 1. Write Unit Tests
|
|
28
|
+
|
|
29
|
+
**File**: Create `src/utils/ssh-connection.test.ts` (if doesn't exist)
|
|
30
|
+
|
|
31
|
+
**Actions**:
|
|
32
|
+
- Test `execStream()` returns correct types
|
|
33
|
+
- Test stream emits data events
|
|
34
|
+
- Test exit code promise resolves
|
|
35
|
+
- Test error handling
|
|
36
|
+
- Mock SSH client for tests
|
|
37
|
+
|
|
38
|
+
### 2. Write Integration Tests
|
|
39
|
+
|
|
40
|
+
**File**: Create `src/tools/acp-remote-execute-command.test.ts`
|
|
41
|
+
|
|
42
|
+
**Actions**:
|
|
43
|
+
- Test with `progressToken` (streaming mode)
|
|
44
|
+
- Test without `progressToken` (fallback mode)
|
|
45
|
+
- Test progress notifications are sent
|
|
46
|
+
- Test rate limiting works
|
|
47
|
+
- Test error scenarios
|
|
48
|
+
- Use real SSH connection (or mock)
|
|
49
|
+
|
|
50
|
+
### 3. Manual Testing
|
|
51
|
+
|
|
52
|
+
**Actions**:
|
|
53
|
+
- Test with simple command: `echo "test"`
|
|
54
|
+
- Test with long command: `for i in 1 2 3 4 5; do echo "Line $i"; sleep 0.5; done`
|
|
55
|
+
- Test with failing command
|
|
56
|
+
- Test with very long output
|
|
57
|
+
- Test connection loss scenario
|
|
58
|
+
|
|
59
|
+
### 4. Update README.md
|
|
60
|
+
|
|
61
|
+
**File**: `README.md`
|
|
62
|
+
|
|
63
|
+
**Actions**:
|
|
64
|
+
- Add section on progress streaming support
|
|
65
|
+
- Document that progress requires MCP SDK v1.26.0+
|
|
66
|
+
- Add examples of progress usage
|
|
67
|
+
- Note client requirements
|
|
68
|
+
- Update tool description for `acp_remote_execute_command`
|
|
69
|
+
|
|
70
|
+
**Example Addition**:
|
|
71
|
+
```markdown
|
|
72
|
+
### Progress Streaming (v0.7.0+)
|
|
73
|
+
|
|
74
|
+
`acp_remote_execute_command` supports real-time progress streaming for long-running commands. When a client provides a `progressToken`, the tool will send progress notifications with live output.
|
|
75
|
+
|
|
76
|
+
**Requirements**:
|
|
77
|
+
- MCP SDK v1.26.0+ (server and client)
|
|
78
|
+
- Client must provide `progressToken` in request
|
|
79
|
+
- Client must handle `onprogress` callback
|
|
80
|
+
|
|
81
|
+
**Example** (client-side):
|
|
82
|
+
\`\`\`typescript
|
|
83
|
+
const result = await client.request({
|
|
84
|
+
method: 'tools/call',
|
|
85
|
+
params: {
|
|
86
|
+
name: 'acp_remote_execute_command',
|
|
87
|
+
arguments: { command: 'npm run build' }
|
|
88
|
+
}
|
|
89
|
+
}, {
|
|
90
|
+
progressToken: 'build-123',
|
|
91
|
+
onprogress: (progress) => {
|
|
92
|
+
console.log(progress.message); // Live output
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
\`\`\`
|
|
96
|
+
|
|
97
|
+
**Fallback**: If no `progressToken` provided, uses timeout-based execution (backward compatible).
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### 5. Update CHANGELOG.md
|
|
101
|
+
|
|
102
|
+
**File**: `CHANGELOG.md`
|
|
103
|
+
|
|
104
|
+
**Actions**:
|
|
105
|
+
- Add v0.7.0 section
|
|
106
|
+
- Document progress streaming feature
|
|
107
|
+
- Note backward compatibility
|
|
108
|
+
- List all changes
|
|
109
|
+
|
|
110
|
+
**Example Entry**:
|
|
111
|
+
```markdown
|
|
112
|
+
## [0.7.0] - 2026-02-24
|
|
113
|
+
|
|
114
|
+
### Added
|
|
115
|
+
- **Progress Streaming** for `acp_remote_execute_command` tool
|
|
116
|
+
- Real-time output streaming for long-running commands
|
|
117
|
+
- Uses MCP SDK's native progress notification system
|
|
118
|
+
- Graceful fallback to timeout mode for clients without progress support
|
|
119
|
+
- Rate limiting prevents notification spam (max 10/second)
|
|
120
|
+
- Supports commands like `npm run build`, `npm run dev`, `npm test`
|
|
121
|
+
|
|
122
|
+
### Changed
|
|
123
|
+
- `acp_remote_execute_command` now accepts optional `progressToken` parameter
|
|
124
|
+
- Added `execStream()` method to SSHConnectionManager
|
|
125
|
+
- Server handlers now pass `extra` parameter to tool handlers
|
|
126
|
+
|
|
127
|
+
### Technical Details
|
|
128
|
+
- Requires MCP SDK v1.26.0+ for progress support
|
|
129
|
+
- Progress notifications sent via `notifications/progress` method
|
|
130
|
+
- Backward compatible - existing clients unaffected
|
|
131
|
+
- No breaking changes to API
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### 6. Update package.json
|
|
135
|
+
|
|
136
|
+
**File**: `package.json`
|
|
137
|
+
|
|
138
|
+
**Actions**:
|
|
139
|
+
- Bump version to 0.7.0
|
|
140
|
+
- Verify dependencies are correct
|
|
141
|
+
|
|
142
|
+
### 7. Build and Verify
|
|
143
|
+
|
|
144
|
+
**Actions**:
|
|
145
|
+
- Run `npm run build`
|
|
146
|
+
- Verify TypeScript compiles
|
|
147
|
+
- Run tests: `npm test`
|
|
148
|
+
- Verify all tests pass
|
|
149
|
+
- Check for any warnings
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
## Verification
|
|
154
|
+
|
|
155
|
+
- [ ] Unit tests written and passing
|
|
156
|
+
- [ ] Integration tests written and passing
|
|
157
|
+
- [ ] Manual testing completed successfully
|
|
158
|
+
- [ ] README.md updated with progress documentation
|
|
159
|
+
- [ ] CHANGELOG.md updated for v0.7.0
|
|
160
|
+
- [ ] package.json version bumped to 0.7.0
|
|
161
|
+
- [ ] TypeScript compiles without errors
|
|
162
|
+
- [ ] Build completes successfully
|
|
163
|
+
- [ ] All tests pass
|
|
164
|
+
- [ ] No warnings or errors
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
|
|
168
|
+
## Expected Output
|
|
169
|
+
|
|
170
|
+
### Files Created
|
|
171
|
+
- `src/utils/ssh-connection.test.ts` - Unit tests (if doesn't exist)
|
|
172
|
+
- `src/tools/acp-remote-execute-command.test.ts` - Integration tests (if doesn't exist)
|
|
173
|
+
|
|
174
|
+
### Files Modified
|
|
175
|
+
- `README.md` - Progress streaming documentation
|
|
176
|
+
- `CHANGELOG.md` - v0.7.0 entry
|
|
177
|
+
- `package.json` - Version bump to 0.7.0
|
|
178
|
+
|
|
179
|
+
### Test Results
|
|
180
|
+
```
|
|
181
|
+
✓ SSH stream execution tests (5 passed)
|
|
182
|
+
✓ Progress streaming tests (8 passed)
|
|
183
|
+
✓ Fallback mode tests (3 passed)
|
|
184
|
+
✓ Error handling tests (4 passed)
|
|
185
|
+
|
|
186
|
+
Total: 20 tests passed
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
---
|
|
190
|
+
|
|
191
|
+
**Next Milestone**: M5 - Progress Streaming - Wrapper Integration (mcp-auth)
|
|
192
|
+
**Related Design**: [`agent/design/local.progress-streaming.md`](../../design/local.progress-streaming.md)
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
# Task 5: Fix Incomplete Directory Listings (GitHub Issue #2)
|
|
2
|
+
|
|
3
|
+
**Milestone**: M3 - Bug Fixes and Enhancements
|
|
4
|
+
**Estimated Time**: 3-4 hours
|
|
5
|
+
**Dependencies**: None
|
|
6
|
+
**Status**: In Progress
|
|
7
|
+
**Priority**: 🚨 CRITICAL
|
|
8
|
+
**GitHub Issue**: [#2](https://github.com/prmichaelsen/acp-mcp/issues/2)
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Objective
|
|
13
|
+
|
|
14
|
+
Fix the critical bug where `acp_remote_list_files` returns incomplete directory listings, missing hidden files and directories. Implement comprehensive file listing with full metadata (permissions, timestamps, size, etc.) using a hybrid approach.
|
|
15
|
+
|
|
16
|
+
## Context
|
|
17
|
+
|
|
18
|
+
**Problem**: SFTP `readdir()` filters out hidden files (starting with `.`) by default, causing incomplete listings.
|
|
19
|
+
|
|
20
|
+
**Root Cause**: SFTP protocol behavior, not a library bug. SFTP `readdir()` excludes hidden files per protocol specification.
|
|
21
|
+
|
|
22
|
+
**Solution**: Use shell `ls` command to get ALL filenames (including hidden), then SFTP `stat()` to get rich metadata for each file.
|
|
23
|
+
|
|
24
|
+
**Design Reference**: See [`agent/reports/github-issue-2-incomplete-directory-listings.md`](../reports/github-issue-2-incomplete-directory-listings.md)
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## Steps
|
|
29
|
+
|
|
30
|
+
### 1. Update FileEntry Interface
|
|
31
|
+
|
|
32
|
+
Create comprehensive interface for file metadata.
|
|
33
|
+
|
|
34
|
+
**File**: `src/types/file-entry.ts` (create new)
|
|
35
|
+
|
|
36
|
+
**Actions**:
|
|
37
|
+
- Define `FileEntry` interface with all metadata fields
|
|
38
|
+
- Include permissions, timestamps, size, ownership
|
|
39
|
+
- Export helper functions for permission conversion
|
|
40
|
+
|
|
41
|
+
### 2. Update SSHConnectionManager.listFiles()
|
|
42
|
+
|
|
43
|
+
Implement hybrid approach: shell + SFTP.
|
|
44
|
+
|
|
45
|
+
**File**: `src/utils/ssh-connection.ts`
|
|
46
|
+
|
|
47
|
+
**Actions**:
|
|
48
|
+
- Add `includeHidden` parameter (default: `true`)
|
|
49
|
+
- Use shell `ls -A` to get all filenames
|
|
50
|
+
- Use SFTP `stat()` to get metadata for each file
|
|
51
|
+
- Return comprehensive `FileEntry[]` with all metadata
|
|
52
|
+
- Add fallback to SFTP `readdir()` if shell fails
|
|
53
|
+
- Add comprehensive logging
|
|
54
|
+
|
|
55
|
+
### 3. Update Tool Schema
|
|
56
|
+
|
|
57
|
+
Add `includeHidden` parameter to tool.
|
|
58
|
+
|
|
59
|
+
**File**: `src/tools/acp-remote-list-files.ts`
|
|
60
|
+
|
|
61
|
+
**Actions**:
|
|
62
|
+
- Add `includeHidden` to input schema
|
|
63
|
+
- Update tool description
|
|
64
|
+
- Pass parameter to `listFiles()`
|
|
65
|
+
- Update recursive listing to use parameter
|
|
66
|
+
|
|
67
|
+
### 4. Update Tool Output Format
|
|
68
|
+
|
|
69
|
+
Return structured JSON with metadata.
|
|
70
|
+
|
|
71
|
+
**File**: `src/tools/acp-remote-list-files.ts`
|
|
72
|
+
|
|
73
|
+
**Actions**:
|
|
74
|
+
- Change output from simple text to structured JSON
|
|
75
|
+
- Include all file metadata in response
|
|
76
|
+
- Format for easy parsing by agents
|
|
77
|
+
|
|
78
|
+
### 5. Update Documentation
|
|
79
|
+
|
|
80
|
+
Document new functionality and parameters.
|
|
81
|
+
|
|
82
|
+
**Files**: `README.md`, `CHANGELOG.md`
|
|
83
|
+
|
|
84
|
+
**Actions**:
|
|
85
|
+
- Document `includeHidden` parameter
|
|
86
|
+
- Document new output format with metadata
|
|
87
|
+
- Add examples of usage
|
|
88
|
+
- Update CHANGELOG for v0.6.0
|
|
89
|
+
|
|
90
|
+
### 6. Test Implementation
|
|
91
|
+
|
|
92
|
+
Verify fix works correctly.
|
|
93
|
+
|
|
94
|
+
**Actions**:
|
|
95
|
+
- Build project: `npm run build`
|
|
96
|
+
- Test with hidden files directory
|
|
97
|
+
- Verify all files returned
|
|
98
|
+
- Verify metadata is correct
|
|
99
|
+
- Test recursive listing
|
|
100
|
+
- Test with `includeHidden=false`
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
## Verification
|
|
105
|
+
|
|
106
|
+
- [ ] `FileEntry` interface created with all fields
|
|
107
|
+
- [ ] `SSHConnectionManager.listFiles()` updated with hybrid approach
|
|
108
|
+
- [ ] `includeHidden` parameter added to tool schema
|
|
109
|
+
- [ ] Tool returns structured JSON with metadata
|
|
110
|
+
- [ ] README.md updated with new parameter
|
|
111
|
+
- [ ] CHANGELOG.md updated for v0.6.0
|
|
112
|
+
- [ ] TypeScript compiles without errors
|
|
113
|
+
- [ ] Build completes successfully
|
|
114
|
+
- [ ] Manual testing shows all files including hidden
|
|
115
|
+
- [ ] Metadata fields populated correctly
|
|
116
|
+
- [ ] Recursive listing works with hidden files
|
|
117
|
+
- [ ] Fallback to SFTP works if shell fails
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
## Expected Output
|
|
122
|
+
|
|
123
|
+
### Files Created
|
|
124
|
+
- `src/types/file-entry.ts` - FileEntry interface and helpers
|
|
125
|
+
|
|
126
|
+
### Files Modified
|
|
127
|
+
- `src/utils/ssh-connection.ts` - Hybrid listing implementation
|
|
128
|
+
- `src/tools/acp-remote-list-files.ts` - Updated schema and output
|
|
129
|
+
- `README.md` - Documentation updates
|
|
130
|
+
- `CHANGELOG.md` - v0.6.0 entry
|
|
131
|
+
- `package.json` - Version bump to 0.6.0
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## Implementation Details
|
|
136
|
+
|
|
137
|
+
### FileEntry Interface
|
|
138
|
+
```typescript
|
|
139
|
+
export interface FileEntry {
|
|
140
|
+
name: string;
|
|
141
|
+
path: string;
|
|
142
|
+
type: 'file' | 'directory' | 'symlink' | 'other';
|
|
143
|
+
size: number;
|
|
144
|
+
permissions: {
|
|
145
|
+
mode: number;
|
|
146
|
+
string: string;
|
|
147
|
+
owner: { read: boolean; write: boolean; execute: boolean };
|
|
148
|
+
group: { read: boolean; write: boolean; execute: boolean };
|
|
149
|
+
others: { read: boolean; write: boolean; execute: boolean };
|
|
150
|
+
};
|
|
151
|
+
owner: {
|
|
152
|
+
uid: number;
|
|
153
|
+
gid: number;
|
|
154
|
+
};
|
|
155
|
+
timestamps: {
|
|
156
|
+
accessed: string;
|
|
157
|
+
modified: string;
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### Hybrid Approach
|
|
163
|
+
1. Execute `ls -A -1` to get all filenames (including hidden)
|
|
164
|
+
2. For each filename, call SFTP `stat()` to get metadata
|
|
165
|
+
3. Construct `FileEntry` objects with complete information
|
|
166
|
+
4. Return structured array
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
**Next Task**: Task 6 - Deploy v0.6.0 to npm
|