@enactprotocol/shared 1.2.11 → 2.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/README.md +44 -0
- package/package.json +16 -58
- package/src/config.ts +476 -0
- package/src/constants.ts +36 -0
- package/src/execution/command.ts +314 -0
- package/src/execution/index.ts +73 -0
- package/src/execution/runtime.ts +308 -0
- package/src/execution/types.ts +379 -0
- package/src/execution/validation.ts +508 -0
- package/src/index.ts +237 -30
- package/src/manifest/index.ts +36 -0
- package/src/manifest/loader.ts +187 -0
- package/src/manifest/parser.ts +173 -0
- package/src/manifest/validator.ts +309 -0
- package/src/paths.ts +108 -0
- package/src/registry.ts +219 -0
- package/src/resolver.ts +345 -0
- package/src/types/index.ts +30 -0
- package/src/types/manifest.ts +255 -0
- package/src/types.ts +5 -188
- package/src/utils/fs.ts +281 -0
- package/src/utils/logger.ts +270 -59
- package/src/utils/version.ts +304 -36
- package/tests/config.test.ts +515 -0
- package/tests/execution/command.test.ts +317 -0
- package/tests/execution/validation.test.ts +384 -0
- package/tests/fixtures/invalid-tool.yaml +4 -0
- package/tests/fixtures/valid-tool.md +62 -0
- package/tests/fixtures/valid-tool.yaml +40 -0
- package/tests/index.test.ts +8 -0
- package/tests/manifest/loader.test.ts +291 -0
- package/tests/manifest/parser.test.ts +345 -0
- package/tests/manifest/validator.test.ts +394 -0
- package/tests/manifest-types.test.ts +358 -0
- package/tests/paths.test.ts +153 -0
- package/tests/registry.test.ts +231 -0
- package/tests/resolver.test.ts +272 -0
- package/tests/utils/fs.test.ts +388 -0
- package/tests/utils/logger.test.ts +480 -0
- package/tests/utils/version.test.ts +390 -0
- package/tsconfig.json +12 -0
- package/tsconfig.tsbuildinfo +1 -0
- package/dist/LocalToolResolver.d.ts +0 -84
- package/dist/LocalToolResolver.js +0 -353
- package/dist/api/enact-api.d.ts +0 -130
- package/dist/api/enact-api.js +0 -428
- package/dist/api/index.d.ts +0 -2
- package/dist/api/index.js +0 -2
- package/dist/api/types.d.ts +0 -103
- package/dist/api/types.js +0 -1
- package/dist/constants.d.ts +0 -7
- package/dist/constants.js +0 -10
- package/dist/core/DaggerExecutionProvider.d.ts +0 -169
- package/dist/core/DaggerExecutionProvider.js +0 -1029
- package/dist/core/DirectExecutionProvider.d.ts +0 -23
- package/dist/core/DirectExecutionProvider.js +0 -406
- package/dist/core/EnactCore.d.ts +0 -162
- package/dist/core/EnactCore.js +0 -597
- package/dist/core/NativeExecutionProvider.d.ts +0 -9
- package/dist/core/NativeExecutionProvider.js +0 -16
- package/dist/core/index.d.ts +0 -3
- package/dist/core/index.js +0 -3
- package/dist/exec/index.d.ts +0 -3
- package/dist/exec/index.js +0 -3
- package/dist/exec/logger.d.ts +0 -11
- package/dist/exec/logger.js +0 -57
- package/dist/exec/validate.d.ts +0 -5
- package/dist/exec/validate.js +0 -167
- package/dist/index.d.ts +0 -21
- package/dist/index.js +0 -25
- package/dist/lib/enact-direct.d.ts +0 -150
- package/dist/lib/enact-direct.js +0 -159
- package/dist/lib/index.d.ts +0 -1
- package/dist/lib/index.js +0 -1
- package/dist/security/index.d.ts +0 -3
- package/dist/security/index.js +0 -3
- package/dist/security/security.d.ts +0 -23
- package/dist/security/security.js +0 -137
- package/dist/security/sign.d.ts +0 -103
- package/dist/security/sign.js +0 -666
- package/dist/security/verification-enforcer.d.ts +0 -53
- package/dist/security/verification-enforcer.js +0 -204
- package/dist/services/McpCoreService.d.ts +0 -98
- package/dist/services/McpCoreService.js +0 -124
- package/dist/services/index.d.ts +0 -1
- package/dist/services/index.js +0 -1
- package/dist/types.d.ts +0 -132
- package/dist/types.js +0 -3
- package/dist/utils/config.d.ts +0 -111
- package/dist/utils/config.js +0 -342
- package/dist/utils/env-loader.d.ts +0 -54
- package/dist/utils/env-loader.js +0 -270
- package/dist/utils/help.d.ts +0 -36
- package/dist/utils/help.js +0 -248
- package/dist/utils/index.d.ts +0 -7
- package/dist/utils/index.js +0 -7
- package/dist/utils/logger.d.ts +0 -35
- package/dist/utils/logger.js +0 -75
- package/dist/utils/silent-monitor.d.ts +0 -67
- package/dist/utils/silent-monitor.js +0 -242
- package/dist/utils/timeout.d.ts +0 -5
- package/dist/utils/timeout.js +0 -23
- package/dist/utils/version.d.ts +0 -4
- package/dist/utils/version.js +0 -35
- package/dist/web/env-manager-server.d.ts +0 -29
- package/dist/web/env-manager-server.js +0 -367
- package/dist/web/index.d.ts +0 -1
- package/dist/web/index.js +0 -1
- package/src/LocalToolResolver.ts +0 -424
- package/src/api/enact-api.ts +0 -604
- package/src/api/index.ts +0 -2
- package/src/api/types.ts +0 -114
- package/src/core/DaggerExecutionProvider.ts +0 -1357
- package/src/core/DirectExecutionProvider.ts +0 -484
- package/src/core/EnactCore.ts +0 -847
- package/src/core/index.ts +0 -3
- package/src/exec/index.ts +0 -3
- package/src/exec/logger.ts +0 -63
- package/src/exec/validate.ts +0 -238
- package/src/lib/enact-direct.ts +0 -254
- package/src/lib/index.ts +0 -1
- package/src/services/McpCoreService.ts +0 -201
- package/src/services/index.ts +0 -1
- package/src/utils/config.ts +0 -438
- package/src/utils/env-loader.ts +0 -370
- package/src/utils/help.ts +0 -257
- package/src/utils/index.ts +0 -7
- package/src/utils/silent-monitor.ts +0 -328
- package/src/utils/timeout.ts +0 -26
- package/src/web/env-manager-server.ts +0 -465
- package/src/web/index.ts +0 -1
- package/src/web/static/app.js +0 -663
- package/src/web/static/index.html +0 -117
- package/src/web/static/style.css +0 -291
package/src/types.ts
CHANGED
|
@@ -1,189 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
name: string; // Tool identifier with hierarchical path
|
|
5
|
-
description: string; // Human-readable description
|
|
6
|
-
command: string; // Shell command to execute with version pins
|
|
1
|
+
/**
|
|
2
|
+
* Type definitions for shared utilities
|
|
3
|
+
*/
|
|
7
4
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
timeout?: string; // Go duration format: "30s", "5m", "1h" (default: "30s")
|
|
11
|
-
tags?: string[]; // Tags for search and categorization
|
|
12
|
-
license?: string; // SPDX License identifier (e.g., "MIT", "Apache-2.0")
|
|
13
|
-
outputSchema?: JSONSchemaDefinition; // Output structure as JSON Schema (strongly recommended)
|
|
14
|
-
|
|
15
|
-
// OPTIONAL FIELDS
|
|
16
|
-
enact?: string; // Protocol version (e.g., "1.0.0")
|
|
17
|
-
version?: string; // Tool definition version for tracking changes
|
|
18
|
-
namespace?: string; // Environment variable namespace (deprecated, use name hierarchy)
|
|
19
|
-
|
|
20
|
-
// Resource requirements
|
|
21
|
-
resources?: {
|
|
22
|
-
memory?: string; // System memory needed (e.g., "16Gi", "32Gi")
|
|
23
|
-
gpu?: string; // GPU memory needed (e.g., "24Gi", "48Gi")
|
|
24
|
-
disk?: string; // Disk space needed (e.g., "100Gi", "500Gi")
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
// Environment variables
|
|
28
|
-
env?: Record<
|
|
29
|
-
string,
|
|
30
|
-
{
|
|
31
|
-
description: string; // What this variable is for (required)
|
|
32
|
-
source: string; // Where to get this value (required)
|
|
33
|
-
required: boolean; // Whether this is required (required)
|
|
34
|
-
default?: string; // Default value if not set (optional)
|
|
35
|
-
}
|
|
36
|
-
>;
|
|
37
|
-
|
|
38
|
-
// Input/Output JSON Schemas
|
|
39
|
-
inputSchema?: JSONSchemaDefinition;
|
|
40
|
-
|
|
41
|
-
// Documentation and Testing
|
|
42
|
-
doc?: string; // Markdown documentation
|
|
43
|
-
authors?: Array<{
|
|
44
|
-
name: string; // Author name (required)
|
|
45
|
-
email?: string; // Author email (optional)
|
|
46
|
-
url?: string; // Author website (optional)
|
|
47
|
-
}>;
|
|
48
|
-
|
|
49
|
-
examples?: Array<{
|
|
50
|
-
input: Record<string, any>; // Input parameters
|
|
51
|
-
output?: any; // Expected output
|
|
52
|
-
description?: string; // Test description
|
|
53
|
-
}>;
|
|
54
|
-
|
|
55
|
-
// Behavior Annotations (MCP-aligned, all default to false)
|
|
56
|
-
annotations?: {
|
|
57
|
-
title?: string; // Human-readable display name
|
|
58
|
-
readOnlyHint?: boolean; // No environment modifications
|
|
59
|
-
destructiveHint?: boolean; // May make irreversible changes
|
|
60
|
-
idempotentHint?: boolean; // Multiple calls = single call
|
|
61
|
-
openWorldHint?: boolean; // Interacts with external systems
|
|
62
|
-
};
|
|
63
|
-
|
|
64
|
-
// Security
|
|
65
|
-
signature?: {
|
|
66
|
-
algorithm: string; // Hash algorithm: "sha256"
|
|
67
|
-
type: string; // Signature type: "ecdsa-p256"
|
|
68
|
-
signer: string; // Signer identifier
|
|
69
|
-
created: string; // ISO timestamp
|
|
70
|
-
value: string; // Base64 encoded signature
|
|
71
|
-
role?: string; // Optional description of the signer
|
|
72
|
-
};
|
|
73
|
-
|
|
74
|
-
// Multi-signature support (array format)
|
|
75
|
-
signatures?: {
|
|
76
|
-
signer: string; // Signer identifier (UUID or human-readable name)
|
|
77
|
-
algorithm: string; // Hash algorithm: "sha256"
|
|
78
|
-
type: string; // Signature type: "ecdsa-p256"
|
|
79
|
-
value: string; // Base64 encoded signature
|
|
80
|
-
created: string; // ISO timestamp
|
|
81
|
-
role?: string; // Optional description of the signer (e.g., "author", "reviewer", "approver")
|
|
82
|
-
}[];
|
|
83
|
-
|
|
84
|
-
// Extensions pattern (x-prefixed fields)
|
|
85
|
-
[key: string]: any; // Allow x- prefixed extension fields
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
// JSON Schema type definitions
|
|
89
|
-
export interface JSONSchemaDefinition {
|
|
90
|
-
type?: string | string[]; // JSON Schema type(s)
|
|
91
|
-
description?: string; // Human-readable description
|
|
92
|
-
format?: string; // Format specifier (e.g., "email", "date-time")
|
|
93
|
-
default?: any; // Default value
|
|
94
|
-
enum?: any[]; // Enumeration of possible values
|
|
95
|
-
const?: any; // Constant value
|
|
96
|
-
|
|
97
|
-
// String validations
|
|
98
|
-
pattern?: string; // Regular expression pattern
|
|
99
|
-
minLength?: number; // Minimum string length
|
|
100
|
-
maxLength?: number; // Maximum string length
|
|
101
|
-
|
|
102
|
-
// Number validations
|
|
103
|
-
minimum?: number; // Minimum value
|
|
104
|
-
maximum?: number; // Maximum value
|
|
105
|
-
exclusiveMinimum?: number; // Exclusive minimum
|
|
106
|
-
exclusiveMaximum?: number; // Exclusive maximum
|
|
107
|
-
multipleOf?: number; // Multiple of
|
|
108
|
-
|
|
109
|
-
// Array validations
|
|
110
|
-
items?: JSONSchemaDefinition | JSONSchemaDefinition[]; // Items schema
|
|
111
|
-
minItems?: number; // Minimum items
|
|
112
|
-
maxItems?: number; // Maximum items
|
|
113
|
-
uniqueItems?: boolean; // Items must be unique
|
|
114
|
-
|
|
115
|
-
// Object validations
|
|
116
|
-
properties?: Record<string, JSONSchemaDefinition>; // Properties
|
|
117
|
-
required?: string[]; // Required properties
|
|
118
|
-
additionalProperties?: JSONSchemaDefinition | boolean; // Additional properties
|
|
119
|
-
|
|
120
|
-
// Combiners
|
|
121
|
-
allOf?: JSONSchemaDefinition[]; // All of these schemas
|
|
122
|
-
anyOf?: JSONSchemaDefinition[]; // Any of these schemas
|
|
123
|
-
oneOf?: JSONSchemaDefinition[]; // Exactly one of these schemas
|
|
124
|
-
not?: JSONSchemaDefinition; // Not this schema
|
|
125
|
-
|
|
126
|
-
// Other
|
|
127
|
-
definitions?: Record<string, JSONSchemaDefinition>; // Definitions
|
|
128
|
-
$ref?: string; // JSON Schema reference
|
|
129
|
-
$id?: string; // Schema ID
|
|
130
|
-
$schema?: string; // Schema version
|
|
131
|
-
|
|
132
|
-
// Custom extensions
|
|
133
|
-
[key: string]: any; // Additional properties
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
export interface ExecutionResult {
|
|
137
|
-
success: boolean;
|
|
138
|
-
output?: any; // Command output/result
|
|
139
|
-
error?: {
|
|
140
|
-
message: string;
|
|
141
|
-
code?: string;
|
|
142
|
-
details?: any;
|
|
143
|
-
};
|
|
144
|
-
metadata: {
|
|
145
|
-
executionId: string;
|
|
146
|
-
toolName: string; // Changed from toolId
|
|
147
|
-
version?: string;
|
|
148
|
-
executedAt: string;
|
|
149
|
-
environment: string;
|
|
150
|
-
timeout?: string;
|
|
151
|
-
command?: string; // The actual command that was executed
|
|
152
|
-
};
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
// Execution environment interface
|
|
156
|
-
export interface ExecutionEnvironment {
|
|
157
|
-
vars: Record<string, any>; // Environment variables
|
|
158
|
-
resources?: {
|
|
159
|
-
memory?: string;
|
|
160
|
-
gpu?: string;
|
|
161
|
-
disk?: string;
|
|
162
|
-
timeout?: string;
|
|
163
|
-
};
|
|
164
|
-
namespace?: string; // Environment variable namespace
|
|
165
|
-
mount?: string; // Mount local directory to container (format: "localPath" or "localPath:containerPath")
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
// Updated execution provider interface
|
|
169
|
-
export abstract class ExecutionProvider {
|
|
170
|
-
abstract setup(tool: EnactTool): Promise<boolean>;
|
|
171
|
-
abstract execute(
|
|
172
|
-
tool: EnactTool,
|
|
173
|
-
inputs: Record<string, any>,
|
|
174
|
-
environment: ExecutionEnvironment,
|
|
175
|
-
): Promise<ExecutionResult>;
|
|
176
|
-
abstract cleanup(): Promise<boolean>;
|
|
177
|
-
abstract resolveEnvironmentVariables(
|
|
178
|
-
envConfig: Record<string, any>,
|
|
179
|
-
namespace?: string,
|
|
180
|
-
): Promise<Record<string, any>>;
|
|
181
|
-
|
|
182
|
-
// New method for command execution
|
|
183
|
-
abstract executeCommand(
|
|
184
|
-
command: string,
|
|
185
|
-
inputs: Record<string, any>,
|
|
186
|
-
environment: ExecutionEnvironment,
|
|
187
|
-
timeout?: string,
|
|
188
|
-
): Promise<{ stdout: string; stderr: string; exitCode: number }>;
|
|
189
|
-
}
|
|
5
|
+
// Placeholder for Phase 3 implementation
|
|
6
|
+
export type EnactManifest = Record<string, unknown>;
|
package/src/utils/fs.ts
ADDED
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @enactprotocol/shared - File system helpers
|
|
3
|
+
*
|
|
4
|
+
* Provides utilities for common filesystem operations.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
copyFileSync,
|
|
9
|
+
existsSync,
|
|
10
|
+
mkdirSync,
|
|
11
|
+
readFileSync,
|
|
12
|
+
readdirSync,
|
|
13
|
+
rmSync,
|
|
14
|
+
statSync,
|
|
15
|
+
writeFileSync,
|
|
16
|
+
} from "node:fs";
|
|
17
|
+
import { dirname, join } from "node:path";
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Ensure a directory exists, creating it if necessary
|
|
21
|
+
*/
|
|
22
|
+
export function ensureDir(dirPath: string): void {
|
|
23
|
+
if (!existsSync(dirPath)) {
|
|
24
|
+
mkdirSync(dirPath, { recursive: true });
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Ensure the parent directory of a file exists
|
|
30
|
+
*/
|
|
31
|
+
export function ensureParentDir(filePath: string): void {
|
|
32
|
+
const parentDir = dirname(filePath);
|
|
33
|
+
ensureDir(parentDir);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Check if a path exists
|
|
38
|
+
*/
|
|
39
|
+
export function pathExists(path: string): boolean {
|
|
40
|
+
return existsSync(path);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Check if a path is a directory
|
|
45
|
+
*/
|
|
46
|
+
export function isDirectory(path: string): boolean {
|
|
47
|
+
try {
|
|
48
|
+
return existsSync(path) && statSync(path).isDirectory();
|
|
49
|
+
} catch {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Check if a path is a file
|
|
56
|
+
*/
|
|
57
|
+
export function isFile(path: string): boolean {
|
|
58
|
+
try {
|
|
59
|
+
return existsSync(path) && statSync(path).isFile();
|
|
60
|
+
} catch {
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Read and parse a JSON file
|
|
67
|
+
* @throws Error if file doesn't exist or isn't valid JSON
|
|
68
|
+
*/
|
|
69
|
+
export function readJsonFile<T = unknown>(filePath: string): T {
|
|
70
|
+
const content = readFileSync(filePath, "utf-8");
|
|
71
|
+
return JSON.parse(content) as T;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Try to read and parse a JSON file
|
|
76
|
+
* @returns The parsed JSON or null if file doesn't exist or is invalid
|
|
77
|
+
*/
|
|
78
|
+
export function tryReadJsonFile<T = unknown>(filePath: string): T | null {
|
|
79
|
+
try {
|
|
80
|
+
return readJsonFile<T>(filePath);
|
|
81
|
+
} catch {
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Write data to a JSON file with formatting
|
|
88
|
+
*/
|
|
89
|
+
export function writeJsonFile(
|
|
90
|
+
filePath: string,
|
|
91
|
+
data: unknown,
|
|
92
|
+
options?: { indent?: number | undefined }
|
|
93
|
+
): void {
|
|
94
|
+
const indent = options?.indent ?? 2;
|
|
95
|
+
ensureParentDir(filePath);
|
|
96
|
+
writeFileSync(filePath, `${JSON.stringify(data, null, indent)}\n`, "utf-8");
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Read a text file
|
|
101
|
+
*/
|
|
102
|
+
export function readTextFile(filePath: string): string {
|
|
103
|
+
return readFileSync(filePath, "utf-8");
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Try to read a text file
|
|
108
|
+
* @returns The file content or null if file doesn't exist
|
|
109
|
+
*/
|
|
110
|
+
export function tryReadTextFile(filePath: string): string | null {
|
|
111
|
+
try {
|
|
112
|
+
return readTextFile(filePath);
|
|
113
|
+
} catch {
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Write content to a text file
|
|
120
|
+
*/
|
|
121
|
+
export function writeTextFile(filePath: string, content: string): void {
|
|
122
|
+
ensureParentDir(filePath);
|
|
123
|
+
writeFileSync(filePath, content, "utf-8");
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Copy a file
|
|
128
|
+
*/
|
|
129
|
+
export function copyFile(src: string, dest: string): void {
|
|
130
|
+
ensureParentDir(dest);
|
|
131
|
+
copyFileSync(src, dest);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Copy a directory recursively
|
|
136
|
+
*/
|
|
137
|
+
export function copyDir(src: string, dest: string): void {
|
|
138
|
+
ensureDir(dest);
|
|
139
|
+
|
|
140
|
+
const entries = readdirSync(src, { withFileTypes: true });
|
|
141
|
+
|
|
142
|
+
for (const entry of entries) {
|
|
143
|
+
const srcPath = join(src, entry.name);
|
|
144
|
+
const destPath = join(dest, entry.name);
|
|
145
|
+
|
|
146
|
+
if (entry.isDirectory()) {
|
|
147
|
+
copyDir(srcPath, destPath);
|
|
148
|
+
} else {
|
|
149
|
+
copyFile(srcPath, destPath);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Remove a file or directory
|
|
156
|
+
*/
|
|
157
|
+
export function remove(path: string): void {
|
|
158
|
+
if (existsSync(path)) {
|
|
159
|
+
rmSync(path, { recursive: true, force: true });
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* List directory contents
|
|
165
|
+
*/
|
|
166
|
+
export function listDir(dirPath: string): string[] {
|
|
167
|
+
if (!existsSync(dirPath)) {
|
|
168
|
+
return [];
|
|
169
|
+
}
|
|
170
|
+
return readdirSync(dirPath);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* List directory entries with types
|
|
175
|
+
*/
|
|
176
|
+
export function listDirEntries(dirPath: string): Array<{
|
|
177
|
+
name: string;
|
|
178
|
+
type: "file" | "directory" | "unknown";
|
|
179
|
+
path: string;
|
|
180
|
+
}> {
|
|
181
|
+
if (!existsSync(dirPath)) {
|
|
182
|
+
return [];
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
const entries = readdirSync(dirPath, { withFileTypes: true });
|
|
186
|
+
return entries.map((entry) => ({
|
|
187
|
+
name: entry.name,
|
|
188
|
+
type: entry.isDirectory() ? "directory" : entry.isFile() ? "file" : "unknown",
|
|
189
|
+
path: join(dirPath, entry.name),
|
|
190
|
+
}));
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Find files matching a pattern in a directory (non-recursive)
|
|
195
|
+
*/
|
|
196
|
+
export function findFiles(dirPath: string, pattern: RegExp | string): string[] {
|
|
197
|
+
const entries = listDir(dirPath);
|
|
198
|
+
const regex = typeof pattern === "string" ? new RegExp(pattern) : pattern;
|
|
199
|
+
|
|
200
|
+
return entries
|
|
201
|
+
.filter((name) => regex.test(name) && isFile(join(dirPath, name)))
|
|
202
|
+
.map((name) => join(dirPath, name));
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Find files recursively
|
|
207
|
+
*/
|
|
208
|
+
export function findFilesRecursive(dirPath: string, pattern?: RegExp | string): string[] {
|
|
209
|
+
const results: string[] = [];
|
|
210
|
+
|
|
211
|
+
if (!existsSync(dirPath)) {
|
|
212
|
+
return results;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
const regex =
|
|
216
|
+
pattern !== undefined ? (typeof pattern === "string" ? new RegExp(pattern) : pattern) : null;
|
|
217
|
+
|
|
218
|
+
function walk(dir: string) {
|
|
219
|
+
const entries = readdirSync(dir, { withFileTypes: true });
|
|
220
|
+
|
|
221
|
+
for (const entry of entries) {
|
|
222
|
+
const fullPath = join(dir, entry.name);
|
|
223
|
+
|
|
224
|
+
if (entry.isDirectory()) {
|
|
225
|
+
walk(fullPath);
|
|
226
|
+
} else if (entry.isFile()) {
|
|
227
|
+
if (!regex || regex.test(entry.name)) {
|
|
228
|
+
results.push(fullPath);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
walk(dirPath);
|
|
235
|
+
return results;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Get file stats
|
|
240
|
+
*/
|
|
241
|
+
export function getStats(path: string): {
|
|
242
|
+
size: number;
|
|
243
|
+
isFile: boolean;
|
|
244
|
+
isDirectory: boolean;
|
|
245
|
+
created: Date;
|
|
246
|
+
modified: Date;
|
|
247
|
+
} | null {
|
|
248
|
+
try {
|
|
249
|
+
const stats = statSync(path);
|
|
250
|
+
return {
|
|
251
|
+
size: stats.size,
|
|
252
|
+
isFile: stats.isFile(),
|
|
253
|
+
isDirectory: stats.isDirectory(),
|
|
254
|
+
created: stats.birthtime,
|
|
255
|
+
modified: stats.mtime,
|
|
256
|
+
};
|
|
257
|
+
} catch {
|
|
258
|
+
return null;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Get file size in bytes
|
|
264
|
+
*/
|
|
265
|
+
export function getFileSize(filePath: string): number | null {
|
|
266
|
+
const stats = getStats(filePath);
|
|
267
|
+
return stats?.isFile ? stats.size : null;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Touch a file (create if not exists, update mtime if exists)
|
|
272
|
+
*/
|
|
273
|
+
export function touchFile(filePath: string): void {
|
|
274
|
+
ensureParentDir(filePath);
|
|
275
|
+
if (existsSync(filePath)) {
|
|
276
|
+
// Update access and modification time by rewriting the file
|
|
277
|
+
writeFileSync(filePath, readFileSync(filePath));
|
|
278
|
+
} else {
|
|
279
|
+
writeFileSync(filePath, "", "utf-8");
|
|
280
|
+
}
|
|
281
|
+
}
|