@deimoscloud/coreai 0.1.9 → 0.1.10
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/cli/index.js +1 -1
- package/dist/cli/index.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +6 -1
- package/.prettierrc +0 -9
- package/AGENT_SPEC.md +0 -347
- package/ARCHITECTURE.md +0 -547
- package/DRAFT_PRD.md +0 -1440
- package/IMPLEMENTATION_PLAN.md +0 -256
- package/PRODUCT.md +0 -473
- package/WORKFLOWS.md +0 -295
- package/commands/core/check-inbox.md +0 -34
- package/commands/core/delegate.md +0 -30
- package/commands/core/git-commit.md +0 -144
- package/commands/core/pr-create.md +0 -193
- package/commands/core/review.md +0 -56
- package/commands/core/sprint-status.md +0 -65
- package/commands/optional/docs-update.md +0 -200
- package/commands/optional/jira-create.md +0 -200
- package/commands/optional/jira-transition.md +0 -184
- package/commands/optional/worktree-cleanup.md +0 -167
- package/commands/optional/worktree-setup.md +0 -110
- package/eslint.config.js +0 -29
- package/jest.config.js +0 -22
- package/knowledge-library/README.md +0 -118
- package/knowledge-library/android-engineer/context/current.txt +0 -42
- package/knowledge-library/android-engineer/control/decisions.txt +0 -9
- package/knowledge-library/android-engineer/control/dependencies.txt +0 -19
- package/knowledge-library/android-engineer/control/objectives.txt +0 -26
- package/knowledge-library/android-engineer/history/.gitkeep +0 -0
- package/knowledge-library/android-engineer/inbox/processed/.gitkeep +0 -0
- package/knowledge-library/android-engineer/outbox/.gitkeep +0 -0
- package/knowledge-library/android-engineer/tech/.gitkeep +0 -0
- package/knowledge-library/architecture.txt +0 -61
- package/knowledge-library/backend-engineer/context/current.txt +0 -42
- package/knowledge-library/backend-engineer/control/decisions.txt +0 -9
- package/knowledge-library/backend-engineer/control/dependencies.txt +0 -19
- package/knowledge-library/backend-engineer/control/objectives.txt +0 -26
- package/knowledge-library/backend-engineer/history/.gitkeep +0 -0
- package/knowledge-library/backend-engineer/inbox/processed/.gitkeep +0 -0
- package/knowledge-library/backend-engineer/outbox/.gitkeep +0 -0
- package/knowledge-library/backend-engineer/tech/.gitkeep +0 -0
- package/knowledge-library/context.txt +0 -52
- package/knowledge-library/devops-engineer/context/current.txt +0 -42
- package/knowledge-library/devops-engineer/control/decisions.txt +0 -9
- package/knowledge-library/devops-engineer/control/dependencies.txt +0 -19
- package/knowledge-library/devops-engineer/control/objectives.txt +0 -26
- package/knowledge-library/devops-engineer/history/.gitkeep +0 -0
- package/knowledge-library/devops-engineer/inbox/processed/.gitkeep +0 -0
- package/knowledge-library/devops-engineer/outbox/.gitkeep +0 -0
- package/knowledge-library/devops-engineer/tech/.gitkeep +0 -0
- package/knowledge-library/engineering-manager/context/current.txt +0 -40
- package/knowledge-library/engineering-manager/control/decisions.txt +0 -9
- package/knowledge-library/engineering-manager/control/objectives.txt +0 -27
- package/knowledge-library/engineering-manager/history/.gitkeep +0 -0
- package/knowledge-library/engineering-manager/inbox/processed/.gitkeep +0 -0
- package/knowledge-library/engineering-manager/outbox/.gitkeep +0 -0
- package/knowledge-library/engineering-manager/tech/.gitkeep +0 -0
- package/knowledge-library/prd.txt +0 -81
- package/knowledge-library/product-manager/context/current.txt +0 -42
- package/knowledge-library/product-manager/control/decisions.txt +0 -9
- package/knowledge-library/product-manager/control/dependencies.txt +0 -19
- package/knowledge-library/product-manager/control/objectives.txt +0 -26
- package/knowledge-library/product-manager/history/.gitkeep +0 -0
- package/knowledge-library/product-manager/inbox/processed/.gitkeep +0 -0
- package/knowledge-library/product-manager/outbox/.gitkeep +0 -0
- package/knowledge-library/product-manager/tech/.gitkeep +0 -0
- package/knowledge-library/qa-engineer/context/current.txt +0 -42
- package/knowledge-library/qa-engineer/control/decisions.txt +0 -9
- package/knowledge-library/qa-engineer/control/dependencies.txt +0 -19
- package/knowledge-library/qa-engineer/control/objectives.txt +0 -26
- package/knowledge-library/qa-engineer/history/.gitkeep +0 -0
- package/knowledge-library/qa-engineer/inbox/processed/.gitkeep +0 -0
- package/knowledge-library/qa-engineer/outbox/.gitkeep +0 -0
- package/knowledge-library/qa-engineer/tech/.gitkeep +0 -0
- package/knowledge-library/security-engineer/context/current.txt +0 -42
- package/knowledge-library/security-engineer/control/decisions.txt +0 -9
- package/knowledge-library/security-engineer/control/dependencies.txt +0 -19
- package/knowledge-library/security-engineer/control/objectives.txt +0 -26
- package/knowledge-library/security-engineer/history/.gitkeep +0 -0
- package/knowledge-library/security-engineer/inbox/processed/.gitkeep +0 -0
- package/knowledge-library/security-engineer/outbox/.gitkeep +0 -0
- package/knowledge-library/security-engineer/tech/.gitkeep +0 -0
- package/knowledge-library/solutions-architect/context/current.txt +0 -42
- package/knowledge-library/solutions-architect/control/decisions.txt +0 -9
- package/knowledge-library/solutions-architect/control/dependencies.txt +0 -19
- package/knowledge-library/solutions-architect/control/objectives.txt +0 -26
- package/knowledge-library/solutions-architect/history/.gitkeep +0 -0
- package/knowledge-library/solutions-architect/inbox/processed/.gitkeep +0 -0
- package/knowledge-library/solutions-architect/outbox/.gitkeep +0 -0
- package/knowledge-library/solutions-architect/tech/.gitkeep +0 -0
- package/knowledge-library/wearos-engineer/context/current.txt +0 -42
- package/knowledge-library/wearos-engineer/control/decisions.txt +0 -9
- package/knowledge-library/wearos-engineer/control/dependencies.txt +0 -19
- package/knowledge-library/wearos-engineer/control/objectives.txt +0 -26
- package/knowledge-library/wearos-engineer/history/.gitkeep +0 -0
- package/knowledge-library/wearos-engineer/inbox/processed/.gitkeep +0 -0
- package/knowledge-library/wearos-engineer/outbox/.gitkeep +0 -0
- package/knowledge-library/wearos-engineer/tech/.gitkeep +0 -0
- package/scripts/add-agent.sh +0 -323
- package/scripts/install.sh +0 -354
- package/src/adapters/factory.test.ts +0 -386
- package/src/adapters/factory.ts +0 -305
- package/src/adapters/index.ts +0 -113
- package/src/adapters/interfaces.ts +0 -268
- package/src/adapters/mcp/client.test.ts +0 -130
- package/src/adapters/mcp/client.ts +0 -451
- package/src/adapters/mcp/discovery.test.ts +0 -315
- package/src/adapters/mcp/discovery.ts +0 -340
- package/src/adapters/mcp/index.ts +0 -66
- package/src/adapters/mcp/mapper.test.ts +0 -218
- package/src/adapters/mcp/mapper.ts +0 -536
- package/src/adapters/mcp/registry.test.ts +0 -433
- package/src/adapters/mcp/registry.ts +0 -550
- package/src/adapters/mcp/types.ts +0 -258
- package/src/adapters/native/filesystem.test.ts +0 -350
- package/src/adapters/native/filesystem.ts +0 -393
- package/src/adapters/native/github.test.ts +0 -173
- package/src/adapters/native/github.ts +0 -627
- package/src/adapters/native/index.ts +0 -22
- package/src/adapters/native/selector.test.ts +0 -224
- package/src/adapters/native/selector.ts +0 -150
- package/src/adapters/types.ts +0 -270
- package/src/agents/compiler.test.ts +0 -410
- package/src/agents/compiler.ts +0 -424
- package/src/agents/index.ts +0 -37
- package/src/agents/loader.test.ts +0 -319
- package/src/agents/loader.ts +0 -143
- package/src/agents/resolver.test.ts +0 -282
- package/src/agents/resolver.ts +0 -262
- package/src/agents/types.ts +0 -97
- package/src/cache/index.ts +0 -38
- package/src/cache/interfaces.ts +0 -283
- package/src/cache/manager.test.ts +0 -266
- package/src/cache/manager.ts +0 -388
- package/src/cache/provider.test.ts +0 -485
- package/src/cache/provider.ts +0 -745
- package/src/cache/types.test.ts +0 -192
- package/src/cache/types.ts +0 -313
- package/src/cli/commands/build.test.ts +0 -248
- package/src/cli/commands/build.ts +0 -284
- package/src/cli/commands/cache.test.ts +0 -221
- package/src/cli/commands/cache.ts +0 -229
- package/src/cli/commands/index.ts +0 -63
- package/src/cli/commands/init.test.ts +0 -173
- package/src/cli/commands/init.ts +0 -296
- package/src/cli/commands/skills.test.ts +0 -272
- package/src/cli/commands/skills.ts +0 -348
- package/src/cli/commands/status.test.ts +0 -392
- package/src/cli/commands/status.ts +0 -332
- package/src/cli/commands/sync.test.ts +0 -213
- package/src/cli/commands/sync.ts +0 -251
- package/src/cli/commands/validate.test.ts +0 -216
- package/src/cli/commands/validate.ts +0 -340
- package/src/cli/index.test.ts +0 -190
- package/src/cli/index.ts +0 -493
- package/src/commands/context.test.ts +0 -163
- package/src/commands/context.ts +0 -111
- package/src/commands/index.ts +0 -56
- package/src/commands/loader.test.ts +0 -273
- package/src/commands/loader.ts +0 -355
- package/src/commands/registry.test.ts +0 -384
- package/src/commands/registry.ts +0 -248
- package/src/commands/runner.test.ts +0 -297
- package/src/commands/runner.ts +0 -222
- package/src/commands/types.ts +0 -361
- package/src/config/index.ts +0 -19
- package/src/config/loader.test.ts +0 -262
- package/src/config/loader.ts +0 -188
- package/src/config/types.ts +0 -154
- package/src/context/index.ts +0 -14
- package/src/context/loader.test.ts +0 -334
- package/src/context/loader.ts +0 -357
- package/src/index.test.ts +0 -13
- package/src/index.ts +0 -268
- package/src/knowledge-library/index.ts +0 -44
- package/src/knowledge-library/manager.test.ts +0 -536
- package/src/knowledge-library/manager.ts +0 -804
- package/src/knowledge-library/types.ts +0 -432
- package/src/skills/generator.test.ts +0 -602
- package/src/skills/generator.ts +0 -491
- package/src/skills/index.ts +0 -27
- package/src/skills/templates.ts +0 -520
- package/src/skills/types.ts +0 -251
- package/templates/completion-report.md +0 -72
- package/templates/feedback.md +0 -56
- package/templates/project-files/CLAUDE.md.template +0 -109
- package/templates/project-files/coreai.json.example +0 -47
- package/templates/project-files/mcp.json.template +0 -20
- package/templates/review-complete.md +0 -64
- package/templates/review-request.md +0 -67
- package/templates/task-assignment.md +0 -51
- package/tsconfig.build.json +0 -4
- package/tsconfig.json +0 -26
- package/tsup.config.ts +0 -23
|
@@ -1,258 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* MCP Integration Types
|
|
3
|
-
*
|
|
4
|
-
* Types for MCP server configuration and integration.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Transport type for MCP servers
|
|
9
|
-
*/
|
|
10
|
-
export type McpTransportType = 'stdio' | 'http' | 'sse';
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Configuration for a stdio-based MCP server
|
|
14
|
-
*/
|
|
15
|
-
export interface StdioServerConfig {
|
|
16
|
-
transport: 'stdio';
|
|
17
|
-
command: string;
|
|
18
|
-
args?: string[];
|
|
19
|
-
env?: Record<string, string>;
|
|
20
|
-
cwd?: string;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Configuration for an HTTP-based MCP server
|
|
25
|
-
*/
|
|
26
|
-
export interface HttpServerConfig {
|
|
27
|
-
transport: 'http' | 'sse';
|
|
28
|
-
url: string;
|
|
29
|
-
headers?: Record<string, string>;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Union type for all MCP server configurations
|
|
34
|
-
*/
|
|
35
|
-
export type McpServerConfig = StdioServerConfig | HttpServerConfig;
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* MCP server definition from config
|
|
39
|
-
*/
|
|
40
|
-
export interface McpServerDefinition {
|
|
41
|
-
/**
|
|
42
|
-
* Unique name for this server
|
|
43
|
-
*/
|
|
44
|
-
name: string;
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Server configuration
|
|
48
|
-
*/
|
|
49
|
-
config: McpServerConfig;
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* Whether this server is enabled
|
|
53
|
-
*/
|
|
54
|
-
enabled?: boolean;
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* Description of what this server provides
|
|
58
|
-
*/
|
|
59
|
-
description?: string;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* MCP config file structure (e.g., mcp.json)
|
|
64
|
-
*/
|
|
65
|
-
export interface McpConfigFile {
|
|
66
|
-
/**
|
|
67
|
-
* MCP servers to connect to
|
|
68
|
-
*/
|
|
69
|
-
mcpServers?: Record<string, McpServerConfig>;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* Information about a connected MCP server
|
|
74
|
-
*/
|
|
75
|
-
export interface McpServerInfo {
|
|
76
|
-
/**
|
|
77
|
-
* Server name
|
|
78
|
-
*/
|
|
79
|
-
name: string;
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* Server version (if available)
|
|
83
|
-
*/
|
|
84
|
-
version?: string;
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* Protocol version
|
|
88
|
-
*/
|
|
89
|
-
protocolVersion?: string;
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* Server capabilities
|
|
93
|
-
*/
|
|
94
|
-
capabilities?: McpCapabilities;
|
|
95
|
-
|
|
96
|
-
/**
|
|
97
|
-
* Server instructions (if any)
|
|
98
|
-
*/
|
|
99
|
-
instructions?: string;
|
|
100
|
-
|
|
101
|
-
/**
|
|
102
|
-
* Whether the server is connected
|
|
103
|
-
*/
|
|
104
|
-
connected: boolean;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
/**
|
|
108
|
-
* MCP server capabilities
|
|
109
|
-
*/
|
|
110
|
-
export interface McpCapabilities {
|
|
111
|
-
tools?: boolean;
|
|
112
|
-
resources?: boolean;
|
|
113
|
-
prompts?: boolean;
|
|
114
|
-
logging?: boolean;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
/**
|
|
118
|
-
* MCP tool definition
|
|
119
|
-
*/
|
|
120
|
-
export interface McpTool {
|
|
121
|
-
/**
|
|
122
|
-
* Tool name
|
|
123
|
-
*/
|
|
124
|
-
name: string;
|
|
125
|
-
|
|
126
|
-
/**
|
|
127
|
-
* Tool description
|
|
128
|
-
*/
|
|
129
|
-
description?: string;
|
|
130
|
-
|
|
131
|
-
/**
|
|
132
|
-
* Input schema for the tool
|
|
133
|
-
*/
|
|
134
|
-
inputSchema: {
|
|
135
|
-
type: 'object';
|
|
136
|
-
properties?: Record<string, unknown>;
|
|
137
|
-
required?: string[];
|
|
138
|
-
};
|
|
139
|
-
|
|
140
|
-
/**
|
|
141
|
-
* Tool annotations
|
|
142
|
-
*/
|
|
143
|
-
annotations?: {
|
|
144
|
-
title?: string;
|
|
145
|
-
readOnlyHint?: boolean;
|
|
146
|
-
destructiveHint?: boolean;
|
|
147
|
-
idempotentHint?: boolean;
|
|
148
|
-
};
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
/**
|
|
152
|
-
* MCP resource definition
|
|
153
|
-
*/
|
|
154
|
-
export interface McpResource {
|
|
155
|
-
/**
|
|
156
|
-
* Resource URI
|
|
157
|
-
*/
|
|
158
|
-
uri: string;
|
|
159
|
-
|
|
160
|
-
/**
|
|
161
|
-
* Resource name
|
|
162
|
-
*/
|
|
163
|
-
name: string;
|
|
164
|
-
|
|
165
|
-
/**
|
|
166
|
-
* Resource description
|
|
167
|
-
*/
|
|
168
|
-
description?: string;
|
|
169
|
-
|
|
170
|
-
/**
|
|
171
|
-
* MIME type
|
|
172
|
-
*/
|
|
173
|
-
mimeType?: string;
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
/**
|
|
177
|
-
* Result of calling an MCP tool
|
|
178
|
-
*/
|
|
179
|
-
export interface McpToolResult {
|
|
180
|
-
/**
|
|
181
|
-
* Tool output content
|
|
182
|
-
*/
|
|
183
|
-
content: McpContent[];
|
|
184
|
-
|
|
185
|
-
/**
|
|
186
|
-
* Whether the tool call resulted in an error
|
|
187
|
-
*/
|
|
188
|
-
isError?: boolean;
|
|
189
|
-
|
|
190
|
-
/**
|
|
191
|
-
* Structured content (if tool has outputSchema)
|
|
192
|
-
*/
|
|
193
|
-
structuredContent?: Record<string, unknown>;
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
/**
|
|
197
|
-
* Content returned by MCP tools and resources
|
|
198
|
-
*/
|
|
199
|
-
export type McpContent = McpTextContent | McpImageContent | McpResourceContent;
|
|
200
|
-
|
|
201
|
-
/**
|
|
202
|
-
* Text content
|
|
203
|
-
*/
|
|
204
|
-
export interface McpTextContent {
|
|
205
|
-
type: 'text';
|
|
206
|
-
text: string;
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
/**
|
|
210
|
-
* Image content
|
|
211
|
-
*/
|
|
212
|
-
export interface McpImageContent {
|
|
213
|
-
type: 'image';
|
|
214
|
-
data: string;
|
|
215
|
-
mimeType: string;
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
/**
|
|
219
|
-
* Embedded resource content
|
|
220
|
-
*/
|
|
221
|
-
export interface McpResourceContent {
|
|
222
|
-
type: 'resource';
|
|
223
|
-
resource: {
|
|
224
|
-
uri: string;
|
|
225
|
-
text?: string;
|
|
226
|
-
blob?: string;
|
|
227
|
-
mimeType?: string;
|
|
228
|
-
};
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
/**
|
|
232
|
-
* Error from MCP operations
|
|
233
|
-
*/
|
|
234
|
-
export class McpError extends Error {
|
|
235
|
-
constructor(
|
|
236
|
-
message: string,
|
|
237
|
-
public readonly code: McpErrorCode,
|
|
238
|
-
public readonly server?: string,
|
|
239
|
-
cause?: Error
|
|
240
|
-
) {
|
|
241
|
-
super(message, { cause });
|
|
242
|
-
this.name = 'McpError';
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
/**
|
|
247
|
-
* MCP error codes
|
|
248
|
-
*/
|
|
249
|
-
export type McpErrorCode =
|
|
250
|
-
| 'connection_failed'
|
|
251
|
-
| 'connection_closed'
|
|
252
|
-
| 'server_not_found'
|
|
253
|
-
| 'tool_not_found'
|
|
254
|
-
| 'resource_not_found'
|
|
255
|
-
| 'invalid_config'
|
|
256
|
-
| 'transport_error'
|
|
257
|
-
| 'protocol_error'
|
|
258
|
-
| 'timeout';
|
|
@@ -1,350 +0,0 @@
|
|
|
1
|
-
import { mkdtempSync, rmSync, writeFileSync, mkdirSync, readFileSync } from 'fs';
|
|
2
|
-
import { join } from 'path';
|
|
3
|
-
import { tmpdir } from 'os';
|
|
4
|
-
import { FilesystemAdapter, createFilesystemAdapter } from './filesystem.js';
|
|
5
|
-
import { AdapterError } from '../types.js';
|
|
6
|
-
|
|
7
|
-
describe('FilesystemAdapter', () => {
|
|
8
|
-
let tempDir: string;
|
|
9
|
-
let adapter: FilesystemAdapter;
|
|
10
|
-
|
|
11
|
-
beforeEach(() => {
|
|
12
|
-
tempDir = mkdtempSync(join(tmpdir(), 'filesystem-adapter-test-'));
|
|
13
|
-
adapter = createFilesystemAdapter({ basePath: tempDir });
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
afterEach(() => {
|
|
17
|
-
rmSync(tempDir, { recursive: true, force: true });
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
describe('constructor', () => {
|
|
21
|
-
it('should create adapter with base path', () => {
|
|
22
|
-
const info = adapter.getInfo();
|
|
23
|
-
expect(info.type).toBe('state');
|
|
24
|
-
expect(info.provider).toBe('filesystem');
|
|
25
|
-
expect(info.implementation).toBe('native');
|
|
26
|
-
expect(info.connected).toBe(false);
|
|
27
|
-
});
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
describe('connect', () => {
|
|
31
|
-
it('should connect when base path exists', async () => {
|
|
32
|
-
await adapter.connect();
|
|
33
|
-
expect(adapter.isConnected()).toBe(true);
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
it('should create base path if it does not exist', async () => {
|
|
37
|
-
const newPath = join(tempDir, 'new-dir');
|
|
38
|
-
const newAdapter = createFilesystemAdapter({ basePath: newPath });
|
|
39
|
-
|
|
40
|
-
await newAdapter.connect();
|
|
41
|
-
expect(newAdapter.isConnected()).toBe(true);
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
it('should throw if base path is a file', async () => {
|
|
45
|
-
const filePath = join(tempDir, 'file.txt');
|
|
46
|
-
writeFileSync(filePath, 'content');
|
|
47
|
-
|
|
48
|
-
const fileAdapter = createFilesystemAdapter({ basePath: filePath });
|
|
49
|
-
await expect(fileAdapter.connect()).rejects.toThrow(AdapterError);
|
|
50
|
-
});
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
describe('disconnect', () => {
|
|
54
|
-
it('should disconnect', async () => {
|
|
55
|
-
await adapter.connect();
|
|
56
|
-
await adapter.disconnect();
|
|
57
|
-
expect(adapter.isConnected()).toBe(false);
|
|
58
|
-
});
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
describe('read', () => {
|
|
62
|
-
beforeEach(async () => {
|
|
63
|
-
await adapter.connect();
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
it('should read file content', async () => {
|
|
67
|
-
writeFileSync(join(tempDir, 'test.txt'), 'hello world');
|
|
68
|
-
|
|
69
|
-
const content = await adapter.read('test.txt');
|
|
70
|
-
expect(content).toBe('hello world');
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
it('should read file from subdirectory', async () => {
|
|
74
|
-
mkdirSync(join(tempDir, 'subdir'));
|
|
75
|
-
writeFileSync(join(tempDir, 'subdir', 'file.txt'), 'nested content');
|
|
76
|
-
|
|
77
|
-
const content = await adapter.read('subdir/file.txt');
|
|
78
|
-
expect(content).toBe('nested content');
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
it('should throw for non-existent file', async () => {
|
|
82
|
-
await expect(adapter.read('nonexistent.txt')).rejects.toThrow(AdapterError);
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
it('should throw if not connected', async () => {
|
|
86
|
-
await adapter.disconnect();
|
|
87
|
-
await expect(adapter.read('test.txt')).rejects.toThrow(AdapterError);
|
|
88
|
-
});
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
describe('write', () => {
|
|
92
|
-
beforeEach(async () => {
|
|
93
|
-
await adapter.connect();
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
it('should write file content', async () => {
|
|
97
|
-
await adapter.write('output.txt', 'new content');
|
|
98
|
-
|
|
99
|
-
const content = readFileSync(join(tempDir, 'output.txt'), 'utf-8');
|
|
100
|
-
expect(content).toBe('new content');
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
it('should overwrite existing file', async () => {
|
|
104
|
-
writeFileSync(join(tempDir, 'existing.txt'), 'old content');
|
|
105
|
-
|
|
106
|
-
await adapter.write('existing.txt', 'new content');
|
|
107
|
-
|
|
108
|
-
const content = readFileSync(join(tempDir, 'existing.txt'), 'utf-8');
|
|
109
|
-
expect(content).toBe('new content');
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
it('should create parent directories with recursive option', async () => {
|
|
113
|
-
await adapter.write('deep/nested/file.txt', 'content', { recursive: true });
|
|
114
|
-
|
|
115
|
-
const content = readFileSync(join(tempDir, 'deep/nested/file.txt'), 'utf-8');
|
|
116
|
-
expect(content).toBe('content');
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
it('should throw for non-existent parent without recursive', async () => {
|
|
120
|
-
await expect(adapter.write('nonexistent/file.txt', 'content')).rejects.toThrow(AdapterError);
|
|
121
|
-
});
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
describe('exists', () => {
|
|
125
|
-
beforeEach(async () => {
|
|
126
|
-
await adapter.connect();
|
|
127
|
-
});
|
|
128
|
-
|
|
129
|
-
it('should return true for existing file', async () => {
|
|
130
|
-
writeFileSync(join(tempDir, 'exists.txt'), 'content');
|
|
131
|
-
|
|
132
|
-
const exists = await adapter.exists('exists.txt');
|
|
133
|
-
expect(exists).toBe(true);
|
|
134
|
-
});
|
|
135
|
-
|
|
136
|
-
it('should return true for existing directory', async () => {
|
|
137
|
-
mkdirSync(join(tempDir, 'subdir'));
|
|
138
|
-
|
|
139
|
-
const exists = await adapter.exists('subdir');
|
|
140
|
-
expect(exists).toBe(true);
|
|
141
|
-
});
|
|
142
|
-
|
|
143
|
-
it('should return false for non-existent path', async () => {
|
|
144
|
-
const exists = await adapter.exists('nonexistent');
|
|
145
|
-
expect(exists).toBe(false);
|
|
146
|
-
});
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
describe('list', () => {
|
|
150
|
-
beforeEach(async () => {
|
|
151
|
-
await adapter.connect();
|
|
152
|
-
});
|
|
153
|
-
|
|
154
|
-
it('should list directory contents', async () => {
|
|
155
|
-
writeFileSync(join(tempDir, 'file1.txt'), 'content1');
|
|
156
|
-
writeFileSync(join(tempDir, 'file2.txt'), 'content2');
|
|
157
|
-
mkdirSync(join(tempDir, 'subdir'));
|
|
158
|
-
|
|
159
|
-
const entries = await adapter.list('.');
|
|
160
|
-
expect(entries.length).toBe(3);
|
|
161
|
-
|
|
162
|
-
const names = entries.map((e) => e.name).sort();
|
|
163
|
-
expect(names).toEqual(['file1.txt', 'file2.txt', 'subdir']);
|
|
164
|
-
|
|
165
|
-
const file1 = entries.find((e) => e.name === 'file1.txt');
|
|
166
|
-
expect(file1?.type).toBe('file');
|
|
167
|
-
expect(file1?.size).toBeDefined();
|
|
168
|
-
|
|
169
|
-
const subdir = entries.find((e) => e.name === 'subdir');
|
|
170
|
-
expect(subdir?.type).toBe('directory');
|
|
171
|
-
});
|
|
172
|
-
|
|
173
|
-
it('should throw for non-existent directory', async () => {
|
|
174
|
-
await expect(adapter.list('nonexistent')).rejects.toThrow(AdapterError);
|
|
175
|
-
});
|
|
176
|
-
|
|
177
|
-
it('should throw if path is a file', async () => {
|
|
178
|
-
writeFileSync(join(tempDir, 'file.txt'), 'content');
|
|
179
|
-
await expect(adapter.list('file.txt')).rejects.toThrow(AdapterError);
|
|
180
|
-
});
|
|
181
|
-
});
|
|
182
|
-
|
|
183
|
-
describe('delete', () => {
|
|
184
|
-
beforeEach(async () => {
|
|
185
|
-
await adapter.connect();
|
|
186
|
-
});
|
|
187
|
-
|
|
188
|
-
it('should delete a file', async () => {
|
|
189
|
-
writeFileSync(join(tempDir, 'to-delete.txt'), 'content');
|
|
190
|
-
|
|
191
|
-
await adapter.delete('to-delete.txt');
|
|
192
|
-
|
|
193
|
-
const exists = await adapter.exists('to-delete.txt');
|
|
194
|
-
expect(exists).toBe(false);
|
|
195
|
-
});
|
|
196
|
-
|
|
197
|
-
it('should delete empty directory', async () => {
|
|
198
|
-
mkdirSync(join(tempDir, 'empty-dir'));
|
|
199
|
-
|
|
200
|
-
await adapter.delete('empty-dir');
|
|
201
|
-
|
|
202
|
-
const exists = await adapter.exists('empty-dir');
|
|
203
|
-
expect(exists).toBe(false);
|
|
204
|
-
});
|
|
205
|
-
|
|
206
|
-
it('should delete non-empty directory with recursive', async () => {
|
|
207
|
-
mkdirSync(join(tempDir, 'non-empty'));
|
|
208
|
-
writeFileSync(join(tempDir, 'non-empty', 'file.txt'), 'content');
|
|
209
|
-
|
|
210
|
-
await adapter.delete('non-empty', { recursive: true });
|
|
211
|
-
|
|
212
|
-
const exists = await adapter.exists('non-empty');
|
|
213
|
-
expect(exists).toBe(false);
|
|
214
|
-
});
|
|
215
|
-
|
|
216
|
-
it('should throw for non-empty directory without recursive', async () => {
|
|
217
|
-
mkdirSync(join(tempDir, 'non-empty'));
|
|
218
|
-
writeFileSync(join(tempDir, 'non-empty', 'file.txt'), 'content');
|
|
219
|
-
|
|
220
|
-
await expect(adapter.delete('non-empty')).rejects.toThrow(AdapterError);
|
|
221
|
-
});
|
|
222
|
-
|
|
223
|
-
it('should not throw for non-existent path', async () => {
|
|
224
|
-
await expect(adapter.delete('nonexistent')).resolves.toBeUndefined();
|
|
225
|
-
});
|
|
226
|
-
});
|
|
227
|
-
|
|
228
|
-
describe('mkdir', () => {
|
|
229
|
-
beforeEach(async () => {
|
|
230
|
-
await adapter.connect();
|
|
231
|
-
});
|
|
232
|
-
|
|
233
|
-
it('should create directory', async () => {
|
|
234
|
-
await adapter.mkdir('new-dir');
|
|
235
|
-
|
|
236
|
-
const exists = await adapter.exists('new-dir');
|
|
237
|
-
expect(exists).toBe(true);
|
|
238
|
-
});
|
|
239
|
-
|
|
240
|
-
it('should create nested directories with recursive', async () => {
|
|
241
|
-
await adapter.mkdir('a/b/c', { recursive: true });
|
|
242
|
-
|
|
243
|
-
const exists = await adapter.exists('a/b/c');
|
|
244
|
-
expect(exists).toBe(true);
|
|
245
|
-
});
|
|
246
|
-
|
|
247
|
-
it('should not throw if directory already exists', async () => {
|
|
248
|
-
mkdirSync(join(tempDir, 'existing-dir'));
|
|
249
|
-
|
|
250
|
-
await expect(adapter.mkdir('existing-dir')).resolves.toBeUndefined();
|
|
251
|
-
});
|
|
252
|
-
|
|
253
|
-
it('should throw for nested path without recursive', async () => {
|
|
254
|
-
await expect(adapter.mkdir('a/b/c')).rejects.toThrow(AdapterError);
|
|
255
|
-
});
|
|
256
|
-
});
|
|
257
|
-
|
|
258
|
-
describe('move', () => {
|
|
259
|
-
beforeEach(async () => {
|
|
260
|
-
await adapter.connect();
|
|
261
|
-
});
|
|
262
|
-
|
|
263
|
-
it('should move/rename a file', async () => {
|
|
264
|
-
writeFileSync(join(tempDir, 'source.txt'), 'content');
|
|
265
|
-
|
|
266
|
-
await adapter.move('source.txt', 'dest.txt');
|
|
267
|
-
|
|
268
|
-
expect(await adapter.exists('source.txt')).toBe(false);
|
|
269
|
-
expect(await adapter.exists('dest.txt')).toBe(true);
|
|
270
|
-
|
|
271
|
-
const content = await adapter.read('dest.txt');
|
|
272
|
-
expect(content).toBe('content');
|
|
273
|
-
});
|
|
274
|
-
|
|
275
|
-
it('should move/rename a directory', async () => {
|
|
276
|
-
mkdirSync(join(tempDir, 'source-dir'));
|
|
277
|
-
writeFileSync(join(tempDir, 'source-dir', 'file.txt'), 'content');
|
|
278
|
-
|
|
279
|
-
await adapter.move('source-dir', 'dest-dir');
|
|
280
|
-
|
|
281
|
-
expect(await adapter.exists('source-dir')).toBe(false);
|
|
282
|
-
expect(await adapter.exists('dest-dir')).toBe(true);
|
|
283
|
-
expect(await adapter.exists('dest-dir/file.txt')).toBe(true);
|
|
284
|
-
});
|
|
285
|
-
|
|
286
|
-
it('should throw for non-existent source', async () => {
|
|
287
|
-
await expect(adapter.move('nonexistent', 'dest')).rejects.toThrow(AdapterError);
|
|
288
|
-
});
|
|
289
|
-
});
|
|
290
|
-
|
|
291
|
-
describe('copy', () => {
|
|
292
|
-
beforeEach(async () => {
|
|
293
|
-
await adapter.connect();
|
|
294
|
-
});
|
|
295
|
-
|
|
296
|
-
it('should copy a file', async () => {
|
|
297
|
-
writeFileSync(join(tempDir, 'source.txt'), 'content');
|
|
298
|
-
|
|
299
|
-
await adapter.copy('source.txt', 'copy.txt');
|
|
300
|
-
|
|
301
|
-
expect(await adapter.exists('source.txt')).toBe(true);
|
|
302
|
-
expect(await adapter.exists('copy.txt')).toBe(true);
|
|
303
|
-
|
|
304
|
-
const content = await adapter.read('copy.txt');
|
|
305
|
-
expect(content).toBe('content');
|
|
306
|
-
});
|
|
307
|
-
|
|
308
|
-
it('should copy a directory recursively', async () => {
|
|
309
|
-
mkdirSync(join(tempDir, 'source-dir'));
|
|
310
|
-
mkdirSync(join(tempDir, 'source-dir', 'nested'));
|
|
311
|
-
writeFileSync(join(tempDir, 'source-dir', 'file.txt'), 'content');
|
|
312
|
-
writeFileSync(join(tempDir, 'source-dir', 'nested', 'nested.txt'), 'nested');
|
|
313
|
-
|
|
314
|
-
await adapter.copy('source-dir', 'copy-dir');
|
|
315
|
-
|
|
316
|
-
expect(await adapter.exists('source-dir')).toBe(true);
|
|
317
|
-
expect(await adapter.exists('copy-dir')).toBe(true);
|
|
318
|
-
expect(await adapter.exists('copy-dir/file.txt')).toBe(true);
|
|
319
|
-
expect(await adapter.exists('copy-dir/nested/nested.txt')).toBe(true);
|
|
320
|
-
|
|
321
|
-
const content = await adapter.read('copy-dir/nested/nested.txt');
|
|
322
|
-
expect(content).toBe('nested');
|
|
323
|
-
});
|
|
324
|
-
|
|
325
|
-
it('should throw for non-existent source', async () => {
|
|
326
|
-
await expect(adapter.copy('nonexistent', 'dest')).rejects.toThrow(AdapterError);
|
|
327
|
-
});
|
|
328
|
-
});
|
|
329
|
-
|
|
330
|
-
describe('path traversal protection', () => {
|
|
331
|
-
beforeEach(async () => {
|
|
332
|
-
await adapter.connect();
|
|
333
|
-
});
|
|
334
|
-
|
|
335
|
-
it('should prevent path traversal with ..', async () => {
|
|
336
|
-
await expect(adapter.read('../outside.txt')).rejects.toThrow(AdapterError);
|
|
337
|
-
});
|
|
338
|
-
|
|
339
|
-
it('should prevent path traversal with absolute paths', async () => {
|
|
340
|
-
await expect(adapter.read('/etc/passwd')).rejects.toThrow(AdapterError);
|
|
341
|
-
});
|
|
342
|
-
});
|
|
343
|
-
});
|
|
344
|
-
|
|
345
|
-
describe('createFilesystemAdapter', () => {
|
|
346
|
-
it('should create a filesystem adapter', () => {
|
|
347
|
-
const adapter = createFilesystemAdapter({ basePath: '/tmp' });
|
|
348
|
-
expect(adapter).toBeInstanceOf(FilesystemAdapter);
|
|
349
|
-
});
|
|
350
|
-
});
|