claude-flow 3.6.30 → 3.7.0-alpha.1
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/.claude/settings.local.json +1 -0
- package/package.json +1 -1
- package/v3/@claude-flow/cli/dist/src/mcp-tools/types.d.ts +4 -33
- package/v3/@claude-flow/cli/dist/src/mcp-tools/types.js +4 -14
- package/v3/@claude-flow/cli/dist/src/mcp-tools/validate-input.d.ts +5 -57
- package/v3/@claude-flow/cli/dist/src/mcp-tools/validate-input.js +5 -233
- package/v3/@claude-flow/cli/dist/src/output.d.ts +6 -130
- package/v3/@claude-flow/cli/dist/src/output.js +6 -511
- package/v3/@claude-flow/cli/dist/src/types.d.ts +10 -195
- package/v3/@claude-flow/cli/dist/src/types.js +10 -35
- package/v3/@claude-flow/cli/package.json +2 -1
- package/.claude/scheduled_tasks.lock +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-flow",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.7.0-alpha.1",
|
|
4
4
|
"description": "Ruflo - Enterprise AI agent orchestration for Claude Code. Deploy 60+ specialized agents in coordinated swarms with self-learning, fault-tolerant consensus, vector memory, and MCP integration",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -1,37 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* MCP Tool Types
|
|
2
|
+
* MCP Tool Types — re-export shim (ADR-100, alpha.5).
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* Authoritative source: @claude-flow/cli-core/mcp-tools/types. Was a 46-line
|
|
5
|
+
* byte-identical copy. Re-exports MCPTool, MCPToolInputSchema, MCPToolResult.
|
|
5
6
|
*/
|
|
6
|
-
export
|
|
7
|
-
type: 'object';
|
|
8
|
-
properties: Record<string, unknown>;
|
|
9
|
-
required?: string[];
|
|
10
|
-
}
|
|
11
|
-
export interface MCPToolResult {
|
|
12
|
-
content: Array<{
|
|
13
|
-
type: 'text' | 'image' | 'resource';
|
|
14
|
-
text?: string;
|
|
15
|
-
data?: string;
|
|
16
|
-
mimeType?: string;
|
|
17
|
-
}>;
|
|
18
|
-
isError?: boolean;
|
|
19
|
-
}
|
|
20
|
-
/**
|
|
21
|
-
* Returns the effective project working directory.
|
|
22
|
-
* Prefers CLAUDE_FLOW_CWD (set by the install script for global/MCP installs
|
|
23
|
-
* where process.cwd() may resolve to '/') over the real process.cwd().
|
|
24
|
-
*/
|
|
25
|
-
export declare function getProjectCwd(): string;
|
|
26
|
-
export interface MCPTool {
|
|
27
|
-
name: string;
|
|
28
|
-
description: string;
|
|
29
|
-
inputSchema: MCPToolInputSchema;
|
|
30
|
-
category?: string;
|
|
31
|
-
tags?: string[];
|
|
32
|
-
version?: string;
|
|
33
|
-
cacheable?: boolean;
|
|
34
|
-
cacheTTL?: number;
|
|
35
|
-
handler: (input: Record<string, unknown>, context?: Record<string, unknown>) => Promise<MCPToolResult | unknown>;
|
|
36
|
-
}
|
|
7
|
+
export * from '@claude-flow/cli-core/mcp-tools/types';
|
|
37
8
|
//# sourceMappingURL=types.d.ts.map
|
|
@@ -1,18 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* MCP Tool Types
|
|
2
|
+
* MCP Tool Types — re-export shim (ADR-100, alpha.5).
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* Authoritative source: @claude-flow/cli-core/mcp-tools/types. Was a 46-line
|
|
5
|
+
* byte-identical copy. Re-exports MCPTool, MCPToolInputSchema, MCPToolResult.
|
|
5
6
|
*/
|
|
6
|
-
|
|
7
|
-
* Returns the effective project working directory.
|
|
8
|
-
* Prefers CLAUDE_FLOW_CWD (set by the install script for global/MCP installs
|
|
9
|
-
* where process.cwd() may resolve to '/') over the real process.cwd().
|
|
10
|
-
*/
|
|
11
|
-
export function getProjectCwd() {
|
|
12
|
-
const envCwd = process.env.CLAUDE_FLOW_CWD;
|
|
13
|
-
if (envCwd && envCwd !== '/' && envCwd !== process.env.HOME) {
|
|
14
|
-
return envCwd;
|
|
15
|
-
}
|
|
16
|
-
return process.cwd();
|
|
17
|
-
}
|
|
7
|
+
export * from '@claude-flow/cli-core/mcp-tools/types';
|
|
18
8
|
//# sourceMappingURL=types.js.map
|
|
@@ -1,61 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Input Validation for MCP Tools
|
|
2
|
+
* Input Validation for MCP Tools — re-export shim (ADR-100, alpha.5).
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* Addresses #1425: security validators were implemented but never wired to runtime.
|
|
8
|
-
*/
|
|
9
|
-
export interface ValidationResult {
|
|
10
|
-
valid: boolean;
|
|
11
|
-
sanitized: string;
|
|
12
|
-
error?: string;
|
|
13
|
-
}
|
|
14
|
-
/**
|
|
15
|
-
* Validate an identifier (agent ID, agent type, namespace, key, etc.)
|
|
16
|
-
* Rejects shell metacharacters and path traversal.
|
|
17
|
-
*/
|
|
18
|
-
export declare function validateIdentifier(value: unknown, label: string): ValidationResult;
|
|
19
|
-
/**
|
|
20
|
-
* Validate a git ref (HEAD~1, main..feature, commit hashes, etc.).
|
|
21
|
-
* Allows ~, ^, and / which are standard git revision selectors.
|
|
22
|
-
*/
|
|
23
|
-
export declare function validateGitRef(value: unknown, label: string): ValidationResult;
|
|
24
|
-
/**
|
|
25
|
-
* Validate an npm package name (allows @scope/name format).
|
|
26
|
-
*/
|
|
27
|
-
export declare function validatePackageName(value: unknown, label: string): ValidationResult;
|
|
28
|
-
/**
|
|
29
|
-
* Validate a file path (prevents traversal and shell injection).
|
|
30
|
-
*/
|
|
31
|
-
export declare function validatePath(value: unknown, label: string): ValidationResult;
|
|
32
|
-
/**
|
|
33
|
-
* Validate a free-text string (description, value, etc.)
|
|
34
|
-
* Allows most characters but rejects shell metacharacters that could cause injection.
|
|
35
|
-
*/
|
|
36
|
-
export declare function validateText(value: unknown, label: string, maxLen?: number): ValidationResult;
|
|
37
|
-
export interface EnvValidationResult {
|
|
38
|
-
valid: boolean;
|
|
39
|
-
sanitized: Record<string, string>;
|
|
40
|
-
error?: string;
|
|
41
|
-
}
|
|
42
|
-
/**
|
|
43
|
-
* Validate a Record<string,string> of environment variables: enforce POSIX
|
|
44
|
-
* names, reject hijack-prone names (LD_PRELOAD, NODE_OPTIONS, …), forbid null
|
|
45
|
-
* bytes in values, and cap value length so a malicious caller can't bloat the
|
|
46
|
-
* stored session past reasonable bounds.
|
|
47
|
-
*/
|
|
48
|
-
export declare function validateEnv(value: unknown, label?: string): EnvValidationResult;
|
|
49
|
-
/**
|
|
50
|
-
* Assert validation or throw with a structured error.
|
|
51
|
-
*/
|
|
52
|
-
export declare function assertValid(result: ValidationResult): string;
|
|
53
|
-
/**
|
|
54
|
-
* Enhanced validation using @claude-flow/security Zod schemas when available.
|
|
55
|
-
* Falls back to inline regex validation otherwise.
|
|
4
|
+
* Authoritative source: @claude-flow/cli-core/mcp-tools/validate-input.
|
|
5
|
+
* Was a 256-line byte-identical copy. Loads @claude-flow/security validators
|
|
6
|
+
* when available, with lightweight fallback otherwise.
|
|
56
7
|
*/
|
|
57
|
-
export
|
|
58
|
-
valid: boolean;
|
|
59
|
-
errors: string[];
|
|
60
|
-
}>;
|
|
8
|
+
export * from '@claude-flow/cli-core/mcp-tools/validate-input';
|
|
61
9
|
//# sourceMappingURL=validate-input.d.ts.map
|
|
@@ -1,237 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Input Validation for MCP Tools
|
|
2
|
+
* Input Validation for MCP Tools — re-export shim (ADR-100, alpha.5).
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* Addresses #1425: security validators were implemented but never wired to runtime.
|
|
8
|
-
*/
|
|
9
|
-
// Patterns for input sanitization (inline — no external dependency required)
|
|
10
|
-
const SHELL_META = /[;&|`$(){}[\]<>!#\\]/;
|
|
11
|
-
const PATH_TRAVERSAL = /\.\.[/\\]/;
|
|
12
|
-
const IDENTIFIER_RE = /^[a-zA-Z0-9_][a-zA-Z0-9_\-.:]{0,127}$/;
|
|
13
|
-
const GIT_REF_RE = /^[a-zA-Z0-9_][a-zA-Z0-9_\-.:~^/]{0,255}$/;
|
|
14
|
-
const NPM_PACKAGE_RE = /^(@[a-zA-Z0-9_\-]+\/)?[a-zA-Z0-9_\-][a-zA-Z0-9_\-.]{0,213}$/;
|
|
15
|
-
/**
|
|
16
|
-
* Validate an identifier (agent ID, agent type, namespace, key, etc.)
|
|
17
|
-
* Rejects shell metacharacters and path traversal.
|
|
18
|
-
*/
|
|
19
|
-
export function validateIdentifier(value, label) {
|
|
20
|
-
if (typeof value !== 'string' || value.length === 0) {
|
|
21
|
-
return { valid: false, sanitized: '', error: `${label} must be a non-empty string` };
|
|
22
|
-
}
|
|
23
|
-
if (value.length > 128) {
|
|
24
|
-
return { valid: false, sanitized: '', error: `${label} exceeds 128 characters` };
|
|
25
|
-
}
|
|
26
|
-
if (SHELL_META.test(value)) {
|
|
27
|
-
return { valid: false, sanitized: '', error: `${label} contains disallowed characters` };
|
|
28
|
-
}
|
|
29
|
-
if (PATH_TRAVERSAL.test(value)) {
|
|
30
|
-
return { valid: false, sanitized: '', error: `${label} contains path traversal` };
|
|
31
|
-
}
|
|
32
|
-
if (!IDENTIFIER_RE.test(value)) {
|
|
33
|
-
return { valid: false, sanitized: '', error: `${label} contains invalid characters (allowed: alphanumeric, _, -, ., :)` };
|
|
34
|
-
}
|
|
35
|
-
return { valid: true, sanitized: value };
|
|
36
|
-
}
|
|
37
|
-
/**
|
|
38
|
-
* Validate a git ref (HEAD~1, main..feature, commit hashes, etc.).
|
|
39
|
-
* Allows ~, ^, and / which are standard git revision selectors.
|
|
40
|
-
*/
|
|
41
|
-
export function validateGitRef(value, label) {
|
|
42
|
-
if (typeof value !== 'string' || value.length === 0) {
|
|
43
|
-
return { valid: false, sanitized: '', error: `${label} must be a non-empty string` };
|
|
44
|
-
}
|
|
45
|
-
if (value.length > 256) {
|
|
46
|
-
return { valid: false, sanitized: '', error: `${label} exceeds 256 characters` };
|
|
47
|
-
}
|
|
48
|
-
if (SHELL_META.test(value)) {
|
|
49
|
-
return { valid: false, sanitized: '', error: `${label} contains disallowed characters` };
|
|
50
|
-
}
|
|
51
|
-
if (!GIT_REF_RE.test(value)) {
|
|
52
|
-
return { valid: false, sanitized: '', error: `${label} contains invalid characters (allowed: alphanumeric, _, -, ., :, ~, ^, /)` };
|
|
53
|
-
}
|
|
54
|
-
return { valid: true, sanitized: value };
|
|
55
|
-
}
|
|
56
|
-
/**
|
|
57
|
-
* Validate an npm package name (allows @scope/name format).
|
|
58
|
-
*/
|
|
59
|
-
export function validatePackageName(value, label) {
|
|
60
|
-
if (typeof value !== 'string' || value.length === 0) {
|
|
61
|
-
return { valid: false, sanitized: '', error: `${label} must be a non-empty string` };
|
|
62
|
-
}
|
|
63
|
-
if (value.length > 214) {
|
|
64
|
-
return { valid: false, sanitized: '', error: `${label} exceeds 214 characters` };
|
|
65
|
-
}
|
|
66
|
-
if (SHELL_META.test(value)) {
|
|
67
|
-
return { valid: false, sanitized: '', error: `${label} contains disallowed characters` };
|
|
68
|
-
}
|
|
69
|
-
if (!NPM_PACKAGE_RE.test(value)) {
|
|
70
|
-
return { valid: false, sanitized: '', error: `${label} contains invalid characters (expected npm package name, e.g. @scope/name)` };
|
|
71
|
-
}
|
|
72
|
-
return { valid: true, sanitized: value };
|
|
73
|
-
}
|
|
74
|
-
/**
|
|
75
|
-
* Validate a file path (prevents traversal and shell injection).
|
|
76
|
-
*/
|
|
77
|
-
export function validatePath(value, label) {
|
|
78
|
-
if (typeof value !== 'string' || value.length === 0) {
|
|
79
|
-
return { valid: false, sanitized: '', error: `${label} must be a non-empty string` };
|
|
80
|
-
}
|
|
81
|
-
if (value.length > 4096) {
|
|
82
|
-
return { valid: false, sanitized: '', error: `${label} exceeds 4096 characters` };
|
|
83
|
-
}
|
|
84
|
-
if (PATH_TRAVERSAL.test(value)) {
|
|
85
|
-
return { valid: false, sanitized: '', error: `${label} contains path traversal (..)` };
|
|
86
|
-
}
|
|
87
|
-
if (SHELL_META.test(value)) {
|
|
88
|
-
return { valid: false, sanitized: '', error: `${label} contains shell metacharacters` };
|
|
89
|
-
}
|
|
90
|
-
return { valid: true, sanitized: value };
|
|
91
|
-
}
|
|
92
|
-
/**
|
|
93
|
-
* Validate a free-text string (description, value, etc.)
|
|
94
|
-
* Allows most characters but rejects shell metacharacters that could cause injection.
|
|
95
|
-
*/
|
|
96
|
-
export function validateText(value, label, maxLen = 10_000) {
|
|
97
|
-
if (typeof value !== 'string') {
|
|
98
|
-
return { valid: false, sanitized: '', error: `${label} must be a string` };
|
|
99
|
-
}
|
|
100
|
-
if (value.length > maxLen) {
|
|
101
|
-
return { valid: false, sanitized: '', error: `${label} exceeds ${maxLen} characters` };
|
|
102
|
-
}
|
|
103
|
-
// Strip null bytes
|
|
104
|
-
const sanitized = value.replace(/\0/g, '');
|
|
105
|
-
return { valid: true, sanitized };
|
|
106
|
-
}
|
|
107
|
-
/**
|
|
108
|
-
* Names that let an attacker pivot a child process before any user code runs:
|
|
109
|
-
* shared-library injection on Linux/macOS, Node hooks, and command resolution.
|
|
110
|
-
*
|
|
111
|
-
* audit_1776853149979: terminal_create previously merged caller-supplied env
|
|
112
|
-
* straight into execSync's environment for every subsequent command in the
|
|
113
|
-
* session. Setting LD_PRELOAD or NODE_OPTIONS via that path is functionally
|
|
114
|
-
* equivalent to remote code execution, so the env input needs an allowlist
|
|
115
|
-
* shape and a denylist on these specific names.
|
|
116
|
-
*/
|
|
117
|
-
const DENYLISTED_ENV_NAMES = new Set([
|
|
118
|
-
'LD_PRELOAD',
|
|
119
|
-
'LD_LIBRARY_PATH',
|
|
120
|
-
'LD_AUDIT',
|
|
121
|
-
'DYLD_INSERT_LIBRARIES',
|
|
122
|
-
'DYLD_LIBRARY_PATH',
|
|
123
|
-
'DYLD_FALLBACK_LIBRARY_PATH',
|
|
124
|
-
'DYLD_FORCE_FLAT_NAMESPACE',
|
|
125
|
-
'NODE_OPTIONS',
|
|
126
|
-
'NODE_PATH',
|
|
127
|
-
]);
|
|
128
|
-
const ENV_NAME_RE = /^[A-Za-z_][A-Za-z0-9_]{0,127}$/;
|
|
129
|
-
/**
|
|
130
|
-
* Validate a Record<string,string> of environment variables: enforce POSIX
|
|
131
|
-
* names, reject hijack-prone names (LD_PRELOAD, NODE_OPTIONS, …), forbid null
|
|
132
|
-
* bytes in values, and cap value length so a malicious caller can't bloat the
|
|
133
|
-
* stored session past reasonable bounds.
|
|
134
|
-
*/
|
|
135
|
-
export function validateEnv(value, label = 'env') {
|
|
136
|
-
if (value === undefined || value === null) {
|
|
137
|
-
return { valid: true, sanitized: {} };
|
|
138
|
-
}
|
|
139
|
-
if (typeof value !== 'object' || Array.isArray(value)) {
|
|
140
|
-
return { valid: false, sanitized: {}, error: `${label} must be an object of string→string` };
|
|
141
|
-
}
|
|
142
|
-
const out = {};
|
|
143
|
-
for (const [name, rawVal] of Object.entries(value)) {
|
|
144
|
-
if (!ENV_NAME_RE.test(name)) {
|
|
145
|
-
return { valid: false, sanitized: {}, error: `${label} key "${name}" is not a valid POSIX env name` };
|
|
146
|
-
}
|
|
147
|
-
if (DENYLISTED_ENV_NAMES.has(name)) {
|
|
148
|
-
return { valid: false, sanitized: {}, error: `${label} key "${name}" is denylisted (loader/runtime hijack)` };
|
|
149
|
-
}
|
|
150
|
-
if (typeof rawVal !== 'string') {
|
|
151
|
-
return { valid: false, sanitized: {}, error: `${label}["${name}"] must be a string` };
|
|
152
|
-
}
|
|
153
|
-
if (rawVal.length > 32_768) {
|
|
154
|
-
return { valid: false, sanitized: {}, error: `${label}["${name}"] exceeds 32768 characters` };
|
|
155
|
-
}
|
|
156
|
-
if (rawVal.includes('\0')) {
|
|
157
|
-
return { valid: false, sanitized: {}, error: `${label}["${name}"] contains a null byte` };
|
|
158
|
-
}
|
|
159
|
-
out[name] = rawVal;
|
|
160
|
-
}
|
|
161
|
-
return { valid: true, sanitized: out };
|
|
162
|
-
}
|
|
163
|
-
/**
|
|
164
|
-
* Assert validation or throw with a structured error.
|
|
165
|
-
*/
|
|
166
|
-
export function assertValid(result) {
|
|
167
|
-
if (!result.valid) {
|
|
168
|
-
throw new Error(`Validation failed: ${result.error}`);
|
|
169
|
-
}
|
|
170
|
-
return result.sanitized;
|
|
171
|
-
}
|
|
172
|
-
// Try to load the full @claude-flow/security module for enhanced validation
|
|
173
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
174
|
-
let _securityModule = null;
|
|
175
|
-
let _securityLoaded = false;
|
|
176
|
-
async function getSecurityModule() {
|
|
177
|
-
if (_securityLoaded)
|
|
178
|
-
return _securityModule;
|
|
179
|
-
_securityLoaded = true;
|
|
180
|
-
try {
|
|
181
|
-
// Dynamic import — @claude-flow/security is an optional dependency
|
|
182
|
-
_securityModule = await Function('return import("@claude-flow/security")')();
|
|
183
|
-
}
|
|
184
|
-
catch {
|
|
185
|
-
// @claude-flow/security is optional — fallback to inline validation above
|
|
186
|
-
}
|
|
187
|
-
return _securityModule;
|
|
188
|
-
}
|
|
189
|
-
/**
|
|
190
|
-
* Enhanced validation using @claude-flow/security Zod schemas when available.
|
|
191
|
-
* Falls back to inline regex validation otherwise.
|
|
4
|
+
* Authoritative source: @claude-flow/cli-core/mcp-tools/validate-input.
|
|
5
|
+
* Was a 256-line byte-identical copy. Loads @claude-flow/security validators
|
|
6
|
+
* when available, with lightweight fallback otherwise.
|
|
192
7
|
*/
|
|
193
|
-
export
|
|
194
|
-
const errors = [];
|
|
195
|
-
// Always run inline validation
|
|
196
|
-
if (input.agentType) {
|
|
197
|
-
const r = validateIdentifier(input.agentType, 'agentType');
|
|
198
|
-
if (!r.valid)
|
|
199
|
-
errors.push(r.error);
|
|
200
|
-
}
|
|
201
|
-
if (input.agentId) {
|
|
202
|
-
const r = validateIdentifier(input.agentId, 'agentId');
|
|
203
|
-
if (!r.valid)
|
|
204
|
-
errors.push(r.error);
|
|
205
|
-
}
|
|
206
|
-
if (input.domain) {
|
|
207
|
-
const r = validateIdentifier(input.domain, 'domain');
|
|
208
|
-
if (!r.valid)
|
|
209
|
-
errors.push(r.error);
|
|
210
|
-
}
|
|
211
|
-
// Try enhanced Zod validation if available.
|
|
212
|
-
// Fix for #1567: @claude-flow/security's SpawnAgentSchema expects `type` and
|
|
213
|
-
// `id` (not `agentType`/`name`), so the previous call always failed with
|
|
214
|
-
// "type: Required". Also swallow `invalid_enum_value` errors because the
|
|
215
|
-
// schema enumerates only 15 built-in agent types — we support custom types
|
|
216
|
-
// (the inline validator already checked the identifier is safe).
|
|
217
|
-
const sec = await getSecurityModule();
|
|
218
|
-
if (sec?.SpawnAgentSchema) {
|
|
219
|
-
try {
|
|
220
|
-
sec.SpawnAgentSchema.parse({
|
|
221
|
-
type: input.agentType,
|
|
222
|
-
id: input.agentId,
|
|
223
|
-
});
|
|
224
|
-
}
|
|
225
|
-
catch (zodErr) {
|
|
226
|
-
if (zodErr.issues) {
|
|
227
|
-
for (const issue of zodErr.issues) {
|
|
228
|
-
if (issue.code === 'invalid_enum_value')
|
|
229
|
-
continue;
|
|
230
|
-
errors.push(`${issue.path.join('.')}: ${issue.message}`);
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
return { valid: errors.length === 0, errors };
|
|
236
|
-
}
|
|
8
|
+
export * from '@claude-flow/cli-core/mcp-tools/validate-input';
|
|
237
9
|
//# sourceMappingURL=validate-input.js.map
|
|
@@ -1,133 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* V3 CLI Output Formatter
|
|
3
|
-
*
|
|
2
|
+
* V3 CLI Output Formatter — re-export shim (ADR-100, alpha.5).
|
|
3
|
+
*
|
|
4
|
+
* Authoritative source: @claude-flow/cli-core/output. Was a byte-identical
|
|
5
|
+
* 640-line copy. The OutputFormatter class and `output` instance plus all
|
|
6
|
+
* helper exports flow through unchanged. Edit cli-core for behavior changes.
|
|
4
7
|
*/
|
|
5
|
-
|
|
6
|
-
declare const COLORS: {
|
|
7
|
-
readonly reset: "\u001B[0m";
|
|
8
|
-
readonly bold: "\u001B[1m";
|
|
9
|
-
readonly dim: "\u001B[2m";
|
|
10
|
-
readonly italic: "\u001B[3m";
|
|
11
|
-
readonly underline: "\u001B[4m";
|
|
12
|
-
readonly black: "\u001B[30m";
|
|
13
|
-
readonly red: "\u001B[31m";
|
|
14
|
-
readonly green: "\u001B[32m";
|
|
15
|
-
readonly yellow: "\u001B[33m";
|
|
16
|
-
readonly blue: "\u001B[34m";
|
|
17
|
-
readonly magenta: "\u001B[35m";
|
|
18
|
-
readonly cyan: "\u001B[36m";
|
|
19
|
-
readonly white: "\u001B[37m";
|
|
20
|
-
readonly gray: "\u001B[90m";
|
|
21
|
-
readonly brightRed: "\u001B[91m";
|
|
22
|
-
readonly brightGreen: "\u001B[92m";
|
|
23
|
-
readonly brightYellow: "\u001B[93m";
|
|
24
|
-
readonly brightBlue: "\u001B[94m";
|
|
25
|
-
readonly brightMagenta: "\u001B[95m";
|
|
26
|
-
readonly brightCyan: "\u001B[96m";
|
|
27
|
-
readonly brightWhite: "\u001B[97m";
|
|
28
|
-
readonly bgBlack: "\u001B[40m";
|
|
29
|
-
readonly bgRed: "\u001B[41m";
|
|
30
|
-
readonly bgGreen: "\u001B[42m";
|
|
31
|
-
readonly bgYellow: "\u001B[43m";
|
|
32
|
-
readonly bgBlue: "\u001B[44m";
|
|
33
|
-
readonly bgMagenta: "\u001B[45m";
|
|
34
|
-
readonly bgCyan: "\u001B[46m";
|
|
35
|
-
readonly bgWhite: "\u001B[47m";
|
|
36
|
-
};
|
|
37
|
-
type ColorName = keyof typeof COLORS;
|
|
38
|
-
export type VerbosityLevel = 'quiet' | 'normal' | 'verbose' | 'debug';
|
|
39
|
-
export declare class OutputFormatter {
|
|
40
|
-
private colorEnabled;
|
|
41
|
-
private outputStream;
|
|
42
|
-
private errorStream;
|
|
43
|
-
private verbosity;
|
|
44
|
-
constructor(options?: {
|
|
45
|
-
color?: boolean;
|
|
46
|
-
verbosity?: VerbosityLevel;
|
|
47
|
-
});
|
|
48
|
-
/**
|
|
49
|
-
* Set verbosity level
|
|
50
|
-
* - quiet: Only errors and direct results
|
|
51
|
-
* - normal: Errors, warnings, info, and results
|
|
52
|
-
* - verbose: All of normal + debug messages
|
|
53
|
-
* - debug: All output including trace
|
|
54
|
-
*/
|
|
55
|
-
setVerbosity(level: VerbosityLevel): void;
|
|
56
|
-
getVerbosity(): VerbosityLevel;
|
|
57
|
-
isQuiet(): boolean;
|
|
58
|
-
isVerbose(): boolean;
|
|
59
|
-
isDebug(): boolean;
|
|
60
|
-
private supportsColor;
|
|
61
|
-
color(text: string, ...colors: ColorName[]): string;
|
|
62
|
-
bold(text: string): string;
|
|
63
|
-
dim(text: string): string;
|
|
64
|
-
success(text: string): string;
|
|
65
|
-
error(text: string): string;
|
|
66
|
-
warning(text: string): string;
|
|
67
|
-
info(text: string): string;
|
|
68
|
-
highlight(text: string): string;
|
|
69
|
-
write(text: string): void;
|
|
70
|
-
writeln(text?: string): void;
|
|
71
|
-
writeError(text: string): void;
|
|
72
|
-
writeErrorln(text?: string): void;
|
|
73
|
-
printSuccess(message: string): void;
|
|
74
|
-
printError(message: string, details?: string): void;
|
|
75
|
-
printWarning(message: string): void;
|
|
76
|
-
printInfo(message: string): void;
|
|
77
|
-
printDebug(message: string): void;
|
|
78
|
-
printTrace(message: string): void;
|
|
79
|
-
table(options: TableOptions): string;
|
|
80
|
-
printTable(options: TableOptions): void;
|
|
81
|
-
private calculateColumnWidths;
|
|
82
|
-
private createBorderLine;
|
|
83
|
-
private alignText;
|
|
84
|
-
private truncate;
|
|
85
|
-
private stripAnsi;
|
|
86
|
-
createProgress(options: ProgressOptions): Progress;
|
|
87
|
-
progressBar(current: number, total: number, width?: number): string;
|
|
88
|
-
createSpinner(options: SpinnerOptions): Spinner;
|
|
89
|
-
json(data: unknown, pretty?: boolean): string;
|
|
90
|
-
printJson(data: unknown, pretty?: boolean): void;
|
|
91
|
-
list(items: string[], bullet?: string): string;
|
|
92
|
-
printList(items: string[], bullet?: string): void;
|
|
93
|
-
numberedList(items: string[]): string;
|
|
94
|
-
printNumberedList(items: string[]): void;
|
|
95
|
-
box(content: string, title?: string): string;
|
|
96
|
-
printBox(content: string, title?: string): void;
|
|
97
|
-
setColorEnabled(enabled: boolean): void;
|
|
98
|
-
isColorEnabled(): boolean;
|
|
99
|
-
}
|
|
100
|
-
export declare class Progress {
|
|
101
|
-
private current;
|
|
102
|
-
private total;
|
|
103
|
-
private width;
|
|
104
|
-
private startTime;
|
|
105
|
-
private formatter;
|
|
106
|
-
private showPercentage;
|
|
107
|
-
private showETA;
|
|
108
|
-
private lastRender;
|
|
109
|
-
constructor(formatter: OutputFormatter, options: ProgressOptions);
|
|
110
|
-
update(current: number): void;
|
|
111
|
-
increment(amount?: number): void;
|
|
112
|
-
render(): void;
|
|
113
|
-
finish(): void;
|
|
114
|
-
private formatTime;
|
|
115
|
-
}
|
|
116
|
-
export declare class Spinner {
|
|
117
|
-
private formatter;
|
|
118
|
-
private text;
|
|
119
|
-
private frames;
|
|
120
|
-
private interval;
|
|
121
|
-
private frameIndex;
|
|
122
|
-
private static readonly SPINNERS;
|
|
123
|
-
constructor(formatter: OutputFormatter, options: SpinnerOptions);
|
|
124
|
-
start(): void;
|
|
125
|
-
stop(message?: string): void;
|
|
126
|
-
succeed(message?: string): void;
|
|
127
|
-
fail(message?: string): void;
|
|
128
|
-
private render;
|
|
129
|
-
setText(text: string): void;
|
|
130
|
-
}
|
|
131
|
-
export declare const output: OutputFormatter;
|
|
132
|
-
export {};
|
|
8
|
+
export * from '@claude-flow/cli-core/output';
|
|
133
9
|
//# sourceMappingURL=output.d.ts.map
|
|
@@ -1,514 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* V3 CLI Output Formatter
|
|
3
|
-
*
|
|
2
|
+
* V3 CLI Output Formatter — re-export shim (ADR-100, alpha.5).
|
|
3
|
+
*
|
|
4
|
+
* Authoritative source: @claude-flow/cli-core/output. Was a byte-identical
|
|
5
|
+
* 640-line copy. The OutputFormatter class and `output` instance plus all
|
|
6
|
+
* helper exports flow through unchanged. Edit cli-core for behavior changes.
|
|
4
7
|
*/
|
|
5
|
-
|
|
6
|
-
// Color Support
|
|
7
|
-
// ============================================
|
|
8
|
-
const COLORS = {
|
|
9
|
-
// Standard colors
|
|
10
|
-
reset: '\x1b[0m',
|
|
11
|
-
bold: '\x1b[1m',
|
|
12
|
-
dim: '\x1b[2m',
|
|
13
|
-
italic: '\x1b[3m',
|
|
14
|
-
underline: '\x1b[4m',
|
|
15
|
-
// Foreground colors
|
|
16
|
-
black: '\x1b[30m',
|
|
17
|
-
red: '\x1b[31m',
|
|
18
|
-
green: '\x1b[32m',
|
|
19
|
-
yellow: '\x1b[33m',
|
|
20
|
-
blue: '\x1b[34m',
|
|
21
|
-
magenta: '\x1b[35m',
|
|
22
|
-
cyan: '\x1b[36m',
|
|
23
|
-
white: '\x1b[37m',
|
|
24
|
-
gray: '\x1b[90m',
|
|
25
|
-
// Bright foreground colors
|
|
26
|
-
brightRed: '\x1b[91m',
|
|
27
|
-
brightGreen: '\x1b[92m',
|
|
28
|
-
brightYellow: '\x1b[93m',
|
|
29
|
-
brightBlue: '\x1b[94m',
|
|
30
|
-
brightMagenta: '\x1b[95m',
|
|
31
|
-
brightCyan: '\x1b[96m',
|
|
32
|
-
brightWhite: '\x1b[97m',
|
|
33
|
-
// Background colors
|
|
34
|
-
bgBlack: '\x1b[40m',
|
|
35
|
-
bgRed: '\x1b[41m',
|
|
36
|
-
bgGreen: '\x1b[42m',
|
|
37
|
-
bgYellow: '\x1b[43m',
|
|
38
|
-
bgBlue: '\x1b[44m',
|
|
39
|
-
bgMagenta: '\x1b[45m',
|
|
40
|
-
bgCyan: '\x1b[46m',
|
|
41
|
-
bgWhite: '\x1b[47m'
|
|
42
|
-
};
|
|
43
|
-
export class OutputFormatter {
|
|
44
|
-
colorEnabled;
|
|
45
|
-
outputStream;
|
|
46
|
-
errorStream;
|
|
47
|
-
verbosity;
|
|
48
|
-
constructor(options = {}) {
|
|
49
|
-
this.colorEnabled = options.color ?? this.supportsColor();
|
|
50
|
-
this.outputStream = process.stdout;
|
|
51
|
-
this.errorStream = process.stderr;
|
|
52
|
-
this.verbosity = options.verbosity ?? 'normal';
|
|
53
|
-
}
|
|
54
|
-
/**
|
|
55
|
-
* Set verbosity level
|
|
56
|
-
* - quiet: Only errors and direct results
|
|
57
|
-
* - normal: Errors, warnings, info, and results
|
|
58
|
-
* - verbose: All of normal + debug messages
|
|
59
|
-
* - debug: All output including trace
|
|
60
|
-
*/
|
|
61
|
-
setVerbosity(level) {
|
|
62
|
-
this.verbosity = level;
|
|
63
|
-
}
|
|
64
|
-
getVerbosity() {
|
|
65
|
-
return this.verbosity;
|
|
66
|
-
}
|
|
67
|
-
isQuiet() {
|
|
68
|
-
return this.verbosity === 'quiet';
|
|
69
|
-
}
|
|
70
|
-
isVerbose() {
|
|
71
|
-
return this.verbosity === 'verbose' || this.verbosity === 'debug';
|
|
72
|
-
}
|
|
73
|
-
isDebug() {
|
|
74
|
-
return this.verbosity === 'debug';
|
|
75
|
-
}
|
|
76
|
-
supportsColor() {
|
|
77
|
-
// Check for NO_COLOR environment variable
|
|
78
|
-
if (process.env.NO_COLOR !== undefined)
|
|
79
|
-
return false;
|
|
80
|
-
// Check for FORCE_COLOR environment variable
|
|
81
|
-
if (process.env.FORCE_COLOR !== undefined)
|
|
82
|
-
return true;
|
|
83
|
-
// Check if stdout is a TTY
|
|
84
|
-
return process.stdout.isTTY ?? false;
|
|
85
|
-
}
|
|
86
|
-
// ============================================
|
|
87
|
-
// Color Methods
|
|
88
|
-
// ============================================
|
|
89
|
-
color(text, ...colors) {
|
|
90
|
-
if (!this.colorEnabled)
|
|
91
|
-
return text;
|
|
92
|
-
const codes = colors.map(c => COLORS[c]).join('');
|
|
93
|
-
return `${codes}${text}${COLORS.reset}`;
|
|
94
|
-
}
|
|
95
|
-
bold(text) {
|
|
96
|
-
return this.color(text, 'bold');
|
|
97
|
-
}
|
|
98
|
-
dim(text) {
|
|
99
|
-
return this.color(text, 'dim');
|
|
100
|
-
}
|
|
101
|
-
success(text) {
|
|
102
|
-
return this.color(text, 'green');
|
|
103
|
-
}
|
|
104
|
-
error(text) {
|
|
105
|
-
return this.color(text, 'red');
|
|
106
|
-
}
|
|
107
|
-
warning(text) {
|
|
108
|
-
return this.color(text, 'yellow');
|
|
109
|
-
}
|
|
110
|
-
info(text) {
|
|
111
|
-
return this.color(text, 'blue');
|
|
112
|
-
}
|
|
113
|
-
highlight(text) {
|
|
114
|
-
return this.color(text, 'cyan', 'bold');
|
|
115
|
-
}
|
|
116
|
-
// ============================================
|
|
117
|
-
// Output Methods
|
|
118
|
-
// ============================================
|
|
119
|
-
write(text) {
|
|
120
|
-
this.outputStream.write(text);
|
|
121
|
-
}
|
|
122
|
-
writeln(text = '') {
|
|
123
|
-
this.outputStream.write(text + '\n');
|
|
124
|
-
}
|
|
125
|
-
writeError(text) {
|
|
126
|
-
this.errorStream.write(text);
|
|
127
|
-
}
|
|
128
|
-
writeErrorln(text = '') {
|
|
129
|
-
this.errorStream.write(text + '\n');
|
|
130
|
-
}
|
|
131
|
-
// ============================================
|
|
132
|
-
// Formatted Output Methods
|
|
133
|
-
// ============================================
|
|
134
|
-
printSuccess(message) {
|
|
135
|
-
// Success always shows (result output)
|
|
136
|
-
const icon = this.color('[OK]', 'green', 'bold');
|
|
137
|
-
this.writeln(`${icon} ${message}`);
|
|
138
|
-
}
|
|
139
|
-
printError(message, details) {
|
|
140
|
-
// Errors always show
|
|
141
|
-
const icon = this.color('[ERROR]', 'red', 'bold');
|
|
142
|
-
this.writeErrorln(`${icon} ${message}`);
|
|
143
|
-
if (details) {
|
|
144
|
-
this.writeErrorln(this.dim(` ${details}`));
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
printWarning(message) {
|
|
148
|
-
// Warnings suppressed in quiet mode
|
|
149
|
-
if (this.verbosity === 'quiet')
|
|
150
|
-
return;
|
|
151
|
-
const icon = this.color('[WARN]', 'yellow', 'bold');
|
|
152
|
-
this.writeln(`${icon} ${message}`);
|
|
153
|
-
}
|
|
154
|
-
printInfo(message) {
|
|
155
|
-
// Info suppressed in quiet mode
|
|
156
|
-
if (this.verbosity === 'quiet')
|
|
157
|
-
return;
|
|
158
|
-
const icon = this.color('[INFO]', 'blue', 'bold');
|
|
159
|
-
this.writeln(`${icon} ${message}`);
|
|
160
|
-
}
|
|
161
|
-
printDebug(message) {
|
|
162
|
-
// Debug only shows in verbose/debug mode
|
|
163
|
-
if (this.verbosity !== 'verbose' && this.verbosity !== 'debug')
|
|
164
|
-
return;
|
|
165
|
-
const icon = this.color('[DEBUG]', 'gray');
|
|
166
|
-
this.writeln(`${icon} ${this.dim(message)}`);
|
|
167
|
-
}
|
|
168
|
-
printTrace(message) {
|
|
169
|
-
// Trace only shows in debug mode
|
|
170
|
-
if (this.verbosity !== 'debug')
|
|
171
|
-
return;
|
|
172
|
-
const icon = this.color('[TRACE]', 'gray', 'dim');
|
|
173
|
-
this.writeln(`${icon} ${this.dim(message)}`);
|
|
174
|
-
}
|
|
175
|
-
// ============================================
|
|
176
|
-
// Table Formatting
|
|
177
|
-
// ============================================
|
|
178
|
-
table(options) {
|
|
179
|
-
const { columns, data, border = true, header = true, padding = 1, maxWidth } = options;
|
|
180
|
-
// Calculate column widths
|
|
181
|
-
const widths = this.calculateColumnWidths(columns, data, maxWidth);
|
|
182
|
-
const lines = [];
|
|
183
|
-
const pad = ' '.repeat(padding);
|
|
184
|
-
// Border characters
|
|
185
|
-
const borderChars = border ? {
|
|
186
|
-
topLeft: '+', topRight: '+', bottomLeft: '+', bottomRight: '+',
|
|
187
|
-
horizontal: '-', vertical: '|',
|
|
188
|
-
leftT: '+', rightT: '+', topT: '+', bottomT: '+', cross: '+'
|
|
189
|
-
} : {
|
|
190
|
-
topLeft: '', topRight: '', bottomLeft: '', bottomRight: '',
|
|
191
|
-
horizontal: '', vertical: ' ',
|
|
192
|
-
leftT: '', rightT: '', topT: '', bottomT: '', cross: ''
|
|
193
|
-
};
|
|
194
|
-
// Top border
|
|
195
|
-
if (border) {
|
|
196
|
-
lines.push(this.createBorderLine(widths, borderChars, 'top', padding));
|
|
197
|
-
}
|
|
198
|
-
// Header row
|
|
199
|
-
if (header) {
|
|
200
|
-
const headerRow = columns.map((col, i) => {
|
|
201
|
-
const text = this.truncate(col.header, widths[i]);
|
|
202
|
-
return pad + this.alignText(this.bold(text), widths[i], col.align) + pad;
|
|
203
|
-
}).join(borderChars.vertical);
|
|
204
|
-
lines.push(`${borderChars.vertical}${headerRow}${borderChars.vertical}`);
|
|
205
|
-
// Header separator
|
|
206
|
-
if (border) {
|
|
207
|
-
lines.push(this.createBorderLine(widths, borderChars, 'middle', padding));
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
// Data rows
|
|
211
|
-
for (const row of data) {
|
|
212
|
-
const rowCells = columns.map((col, i) => {
|
|
213
|
-
let value = row[col.key];
|
|
214
|
-
// Apply formatter if provided
|
|
215
|
-
if (col.format) {
|
|
216
|
-
value = col.format(value);
|
|
217
|
-
}
|
|
218
|
-
else {
|
|
219
|
-
value = String(value ?? '');
|
|
220
|
-
}
|
|
221
|
-
const text = this.truncate(String(value), widths[i]);
|
|
222
|
-
return pad + this.alignText(text, widths[i], col.align) + pad;
|
|
223
|
-
}).join(borderChars.vertical);
|
|
224
|
-
lines.push(`${borderChars.vertical}${rowCells}${borderChars.vertical}`);
|
|
225
|
-
}
|
|
226
|
-
// Bottom border
|
|
227
|
-
if (border) {
|
|
228
|
-
lines.push(this.createBorderLine(widths, borderChars, 'bottom', padding));
|
|
229
|
-
}
|
|
230
|
-
return lines.join('\n');
|
|
231
|
-
}
|
|
232
|
-
printTable(options) {
|
|
233
|
-
this.writeln(this.table(options));
|
|
234
|
-
}
|
|
235
|
-
calculateColumnWidths(columns, data, maxWidth) {
|
|
236
|
-
const widths = columns.map((col, i) => {
|
|
237
|
-
// Start with header width
|
|
238
|
-
let width = col.header.length;
|
|
239
|
-
// Check all data values
|
|
240
|
-
for (const row of data) {
|
|
241
|
-
let value = row[col.key];
|
|
242
|
-
if (col.format) {
|
|
243
|
-
value = col.format(value);
|
|
244
|
-
}
|
|
245
|
-
const len = this.stripAnsi(String(value ?? '')).length;
|
|
246
|
-
width = Math.max(width, len);
|
|
247
|
-
}
|
|
248
|
-
// Apply column-specific width limit
|
|
249
|
-
if (col.width) {
|
|
250
|
-
width = Math.min(width, col.width);
|
|
251
|
-
}
|
|
252
|
-
return width;
|
|
253
|
-
});
|
|
254
|
-
// Apply max width constraint
|
|
255
|
-
if (maxWidth) {
|
|
256
|
-
const totalWidth = widths.reduce((a, b) => a + b, 0) + (columns.length * 3) + 1;
|
|
257
|
-
if (totalWidth > maxWidth) {
|
|
258
|
-
const reduction = (totalWidth - maxWidth) / columns.length;
|
|
259
|
-
return widths.map(w => Math.max(3, Math.floor(w - reduction)));
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
return widths;
|
|
263
|
-
}
|
|
264
|
-
createBorderLine(widths, chars, position, padding) {
|
|
265
|
-
const cellWidth = (w) => chars.horizontal.repeat(w + (padding * 2));
|
|
266
|
-
const cells = widths.map(cellWidth).join(position === 'top' ? chars.topT :
|
|
267
|
-
position === 'bottom' ? chars.bottomT :
|
|
268
|
-
chars.cross);
|
|
269
|
-
const left = position === 'top' ? chars.topLeft : position === 'bottom' ? chars.bottomLeft : chars.leftT;
|
|
270
|
-
const right = position === 'top' ? chars.topRight : position === 'bottom' ? chars.bottomRight : chars.rightT;
|
|
271
|
-
return `${left}${cells}${right}`;
|
|
272
|
-
}
|
|
273
|
-
alignText(text, width, align = 'left') {
|
|
274
|
-
const len = this.stripAnsi(text).length;
|
|
275
|
-
const padding = width - len;
|
|
276
|
-
if (padding <= 0)
|
|
277
|
-
return text;
|
|
278
|
-
switch (align) {
|
|
279
|
-
case 'right':
|
|
280
|
-
return ' '.repeat(padding) + text;
|
|
281
|
-
case 'center':
|
|
282
|
-
const left = Math.floor(padding / 2);
|
|
283
|
-
const right = padding - left;
|
|
284
|
-
return ' '.repeat(left) + text + ' '.repeat(right);
|
|
285
|
-
default:
|
|
286
|
-
return text + ' '.repeat(padding);
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
truncate(text, maxLength) {
|
|
290
|
-
const stripped = this.stripAnsi(text);
|
|
291
|
-
if (stripped.length <= maxLength)
|
|
292
|
-
return text;
|
|
293
|
-
return stripped.slice(0, maxLength - 3) + '...';
|
|
294
|
-
}
|
|
295
|
-
stripAnsi(text) {
|
|
296
|
-
return text.replace(/\x1b\[[0-9;]*m/g, '');
|
|
297
|
-
}
|
|
298
|
-
// ============================================
|
|
299
|
-
// Progress Bar
|
|
300
|
-
// ============================================
|
|
301
|
-
createProgress(options) {
|
|
302
|
-
return new Progress(this, options);
|
|
303
|
-
}
|
|
304
|
-
progressBar(current, total, width = 40) {
|
|
305
|
-
const percent = Math.min(100, Math.max(0, (current / total) * 100));
|
|
306
|
-
const filled = Math.round((width * percent) / 100);
|
|
307
|
-
const empty = width - filled;
|
|
308
|
-
const bar = this.color('#'.repeat(filled), 'green') +
|
|
309
|
-
this.dim('-'.repeat(empty));
|
|
310
|
-
return `[${bar}] ${percent.toFixed(1)}%`;
|
|
311
|
-
}
|
|
312
|
-
// ============================================
|
|
313
|
-
// Spinner
|
|
314
|
-
// ============================================
|
|
315
|
-
createSpinner(options) {
|
|
316
|
-
return new Spinner(this, options);
|
|
317
|
-
}
|
|
318
|
-
// ============================================
|
|
319
|
-
// JSON Output
|
|
320
|
-
// ============================================
|
|
321
|
-
json(data, pretty = true) {
|
|
322
|
-
return pretty ? JSON.stringify(data, null, 2) : JSON.stringify(data);
|
|
323
|
-
}
|
|
324
|
-
printJson(data, pretty = true) {
|
|
325
|
-
this.writeln(this.json(data, pretty));
|
|
326
|
-
}
|
|
327
|
-
// ============================================
|
|
328
|
-
// List Output
|
|
329
|
-
// ============================================
|
|
330
|
-
list(items, bullet = '-') {
|
|
331
|
-
return items.map(item => ` ${bullet} ${item}`).join('\n');
|
|
332
|
-
}
|
|
333
|
-
printList(items, bullet = '-') {
|
|
334
|
-
this.writeln(this.list(items, bullet));
|
|
335
|
-
}
|
|
336
|
-
numberedList(items) {
|
|
337
|
-
return items.map((item, i) => ` ${i + 1}. ${item}`).join('\n');
|
|
338
|
-
}
|
|
339
|
-
printNumberedList(items) {
|
|
340
|
-
this.writeln(this.numberedList(items));
|
|
341
|
-
}
|
|
342
|
-
// ============================================
|
|
343
|
-
// Box Output
|
|
344
|
-
// ============================================
|
|
345
|
-
box(content, title) {
|
|
346
|
-
const lines = content.split('\n');
|
|
347
|
-
const maxLen = Math.max(...lines.map(l => this.stripAnsi(l).length), title?.length ?? 0);
|
|
348
|
-
const width = maxLen + 4;
|
|
349
|
-
const border = {
|
|
350
|
-
topLeft: '+', topRight: '+',
|
|
351
|
-
bottomLeft: '+', bottomRight: '+',
|
|
352
|
-
horizontal: '-', vertical: '|'
|
|
353
|
-
};
|
|
354
|
-
const result = [];
|
|
355
|
-
// Top border with optional title
|
|
356
|
-
if (title) {
|
|
357
|
-
const titleText = ` ${title} `;
|
|
358
|
-
const leftPad = Math.floor((width - titleText.length - 2) / 2);
|
|
359
|
-
const rightPad = width - titleText.length - leftPad - 2;
|
|
360
|
-
result.push(border.topLeft +
|
|
361
|
-
border.horizontal.repeat(leftPad) +
|
|
362
|
-
this.bold(titleText) +
|
|
363
|
-
border.horizontal.repeat(rightPad) +
|
|
364
|
-
border.topRight);
|
|
365
|
-
}
|
|
366
|
-
else {
|
|
367
|
-
result.push(border.topLeft + border.horizontal.repeat(width - 2) + border.topRight);
|
|
368
|
-
}
|
|
369
|
-
// Content lines
|
|
370
|
-
for (const line of lines) {
|
|
371
|
-
const stripped = this.stripAnsi(line);
|
|
372
|
-
const padding = maxLen - stripped.length;
|
|
373
|
-
result.push(`${border.vertical} ${line}${' '.repeat(padding)} ${border.vertical}`);
|
|
374
|
-
}
|
|
375
|
-
// Bottom border
|
|
376
|
-
result.push(border.bottomLeft + border.horizontal.repeat(width - 2) + border.bottomRight);
|
|
377
|
-
return result.join('\n');
|
|
378
|
-
}
|
|
379
|
-
printBox(content, title) {
|
|
380
|
-
this.writeln(this.box(content, title));
|
|
381
|
-
}
|
|
382
|
-
setColorEnabled(enabled) {
|
|
383
|
-
this.colorEnabled = enabled;
|
|
384
|
-
}
|
|
385
|
-
isColorEnabled() {
|
|
386
|
-
return this.colorEnabled;
|
|
387
|
-
}
|
|
388
|
-
}
|
|
389
|
-
// ============================================
|
|
390
|
-
// Progress Class
|
|
391
|
-
// ============================================
|
|
392
|
-
export class Progress {
|
|
393
|
-
current;
|
|
394
|
-
total;
|
|
395
|
-
width;
|
|
396
|
-
startTime;
|
|
397
|
-
formatter;
|
|
398
|
-
showPercentage;
|
|
399
|
-
showETA;
|
|
400
|
-
lastRender = '';
|
|
401
|
-
constructor(formatter, options) {
|
|
402
|
-
this.formatter = formatter;
|
|
403
|
-
this.current = options.current ?? 0;
|
|
404
|
-
this.total = options.total;
|
|
405
|
-
this.width = options.width ?? 40;
|
|
406
|
-
this.showPercentage = options.showPercentage ?? true;
|
|
407
|
-
this.showETA = options.showETA ?? true;
|
|
408
|
-
this.startTime = Date.now();
|
|
409
|
-
}
|
|
410
|
-
update(current) {
|
|
411
|
-
this.current = current;
|
|
412
|
-
this.render();
|
|
413
|
-
}
|
|
414
|
-
increment(amount = 1) {
|
|
415
|
-
this.update(this.current + amount);
|
|
416
|
-
}
|
|
417
|
-
render() {
|
|
418
|
-
const bar = this.formatter.progressBar(this.current, this.total, this.width);
|
|
419
|
-
let output = bar;
|
|
420
|
-
if (this.showETA && this.current > 0) {
|
|
421
|
-
const elapsed = Date.now() - this.startTime;
|
|
422
|
-
const rate = this.current / elapsed;
|
|
423
|
-
const remaining = this.total - this.current;
|
|
424
|
-
const eta = remaining / rate;
|
|
425
|
-
if (isFinite(eta)) {
|
|
426
|
-
output += ` ETA: ${this.formatTime(eta)}`;
|
|
427
|
-
}
|
|
428
|
-
}
|
|
429
|
-
// Clear previous line and write new
|
|
430
|
-
if (this.lastRender) {
|
|
431
|
-
process.stdout.write('\r' + ' '.repeat(this.lastRender.length) + '\r');
|
|
432
|
-
}
|
|
433
|
-
process.stdout.write(output);
|
|
434
|
-
this.lastRender = output;
|
|
435
|
-
}
|
|
436
|
-
finish() {
|
|
437
|
-
this.current = this.total;
|
|
438
|
-
this.render();
|
|
439
|
-
process.stdout.write('\n');
|
|
440
|
-
}
|
|
441
|
-
formatTime(ms) {
|
|
442
|
-
const seconds = Math.floor(ms / 1000);
|
|
443
|
-
const minutes = Math.floor(seconds / 60);
|
|
444
|
-
const hours = Math.floor(minutes / 60);
|
|
445
|
-
if (hours > 0) {
|
|
446
|
-
return `${hours}h ${minutes % 60}m`;
|
|
447
|
-
}
|
|
448
|
-
else if (minutes > 0) {
|
|
449
|
-
return `${minutes}m ${seconds % 60}s`;
|
|
450
|
-
}
|
|
451
|
-
else {
|
|
452
|
-
return `${seconds}s`;
|
|
453
|
-
}
|
|
454
|
-
}
|
|
455
|
-
}
|
|
456
|
-
// ============================================
|
|
457
|
-
// Spinner Class
|
|
458
|
-
// ============================================
|
|
459
|
-
export class Spinner {
|
|
460
|
-
formatter;
|
|
461
|
-
text;
|
|
462
|
-
frames;
|
|
463
|
-
interval = null;
|
|
464
|
-
frameIndex = 0;
|
|
465
|
-
static SPINNERS = {
|
|
466
|
-
dots: ['...', '..:', '.::', ':::', '::.', ':..',],
|
|
467
|
-
line: ['-', '\\', '|', '/'],
|
|
468
|
-
arc: ['◜', '◠', '◝', '◞', '◡', '◟'],
|
|
469
|
-
circle: ['◐', '◓', '◑', '◒'],
|
|
470
|
-
arrows: ['←', '↖', '↑', '↗', '→', '↘', '↓', '↙']
|
|
471
|
-
};
|
|
472
|
-
constructor(formatter, options) {
|
|
473
|
-
this.formatter = formatter;
|
|
474
|
-
this.text = options.text;
|
|
475
|
-
this.frames = Spinner.SPINNERS[options.spinner ?? 'dots'];
|
|
476
|
-
}
|
|
477
|
-
start() {
|
|
478
|
-
if (this.interval)
|
|
479
|
-
return;
|
|
480
|
-
this.interval = setInterval(() => {
|
|
481
|
-
this.render();
|
|
482
|
-
this.frameIndex = (this.frameIndex + 1) % this.frames.length;
|
|
483
|
-
}, 100);
|
|
484
|
-
this.interval.unref();
|
|
485
|
-
this.render();
|
|
486
|
-
}
|
|
487
|
-
stop(message) {
|
|
488
|
-
if (this.interval) {
|
|
489
|
-
clearInterval(this.interval);
|
|
490
|
-
this.interval = null;
|
|
491
|
-
}
|
|
492
|
-
// Clear the line
|
|
493
|
-
process.stdout.write('\r' + ' '.repeat(this.text.length + 10) + '\r');
|
|
494
|
-
if (message) {
|
|
495
|
-
this.formatter.writeln(message);
|
|
496
|
-
}
|
|
497
|
-
}
|
|
498
|
-
succeed(message) {
|
|
499
|
-
this.stop(this.formatter.success(message ?? this.text));
|
|
500
|
-
}
|
|
501
|
-
fail(message) {
|
|
502
|
-
this.stop(this.formatter.error(message ?? this.text));
|
|
503
|
-
}
|
|
504
|
-
render() {
|
|
505
|
-
const frame = this.formatter.info(this.frames[this.frameIndex]);
|
|
506
|
-
process.stdout.write(`\r${frame} ${this.text}`);
|
|
507
|
-
}
|
|
508
|
-
setText(text) {
|
|
509
|
-
this.text = text;
|
|
510
|
-
}
|
|
511
|
-
}
|
|
512
|
-
// Export singleton instance
|
|
513
|
-
export const output = new OutputFormatter();
|
|
8
|
+
export * from '@claude-flow/cli-core/output';
|
|
514
9
|
//# sourceMappingURL=output.js.map
|
|
@@ -1,198 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* V3 CLI Type Definitions
|
|
3
|
-
*
|
|
2
|
+
* V3 CLI Type Definitions — re-export shim (ADR-100, alpha.5).
|
|
3
|
+
*
|
|
4
|
+
* Authoritative source: @claude-flow/cli-core/types. Was a byte-identical
|
|
5
|
+
* 287-line copy until alpha.5 published the cli-core subpath. The 60+
|
|
6
|
+
* `import './types.js'` call sites inside cli keep working unchanged
|
|
7
|
+
* because the file path is preserved.
|
|
8
|
+
*
|
|
9
|
+
* To extend the type system, edit v3/@claude-flow/cli-core/src/types.ts
|
|
10
|
+
* — changes flow through here automatically.
|
|
4
11
|
*/
|
|
5
|
-
export
|
|
6
|
-
args: string[];
|
|
7
|
-
flags: ParsedFlags;
|
|
8
|
-
config?: V3Config;
|
|
9
|
-
cwd: string;
|
|
10
|
-
interactive: boolean;
|
|
11
|
-
}
|
|
12
|
-
export interface ParsedFlags {
|
|
13
|
-
[key: string]: string | boolean | number | string[];
|
|
14
|
-
_: string[];
|
|
15
|
-
}
|
|
16
|
-
export interface Command {
|
|
17
|
-
name: string;
|
|
18
|
-
description: string;
|
|
19
|
-
aliases?: string[];
|
|
20
|
-
subcommands?: Command[];
|
|
21
|
-
options?: CommandOption[];
|
|
22
|
-
examples?: CommandExample[];
|
|
23
|
-
action?: CommandAction;
|
|
24
|
-
hidden?: boolean;
|
|
25
|
-
}
|
|
26
|
-
export interface CommandOption {
|
|
27
|
-
name: string;
|
|
28
|
-
short?: string;
|
|
29
|
-
description: string;
|
|
30
|
-
type: 'string' | 'boolean' | 'number' | 'array';
|
|
31
|
-
default?: unknown;
|
|
32
|
-
required?: boolean;
|
|
33
|
-
choices?: string[];
|
|
34
|
-
validate?: (value: unknown) => boolean | string;
|
|
35
|
-
}
|
|
36
|
-
export interface CommandExample {
|
|
37
|
-
command: string;
|
|
38
|
-
description: string;
|
|
39
|
-
}
|
|
40
|
-
export type CommandAction = (ctx: CommandContext) => Promise<CommandResult | void>;
|
|
41
|
-
export interface CommandResult {
|
|
42
|
-
success: boolean;
|
|
43
|
-
message?: string;
|
|
44
|
-
data?: unknown;
|
|
45
|
-
exitCode?: number;
|
|
46
|
-
}
|
|
47
|
-
export interface V3Config {
|
|
48
|
-
version: string;
|
|
49
|
-
projectRoot: string;
|
|
50
|
-
agents: AgentConfig;
|
|
51
|
-
swarm: SwarmConfig;
|
|
52
|
-
memory: MemoryConfig;
|
|
53
|
-
mcp: MCPConfig;
|
|
54
|
-
cli: CLIPreferences;
|
|
55
|
-
hooks: HooksConfig;
|
|
56
|
-
}
|
|
57
|
-
export interface AgentConfig {
|
|
58
|
-
defaultType: string;
|
|
59
|
-
autoSpawn: boolean;
|
|
60
|
-
maxConcurrent: number;
|
|
61
|
-
timeout: number;
|
|
62
|
-
providers: ProviderConfig[];
|
|
63
|
-
}
|
|
64
|
-
export interface ProviderConfig {
|
|
65
|
-
name: string;
|
|
66
|
-
apiKey?: string;
|
|
67
|
-
baseUrl?: string;
|
|
68
|
-
model?: string;
|
|
69
|
-
priority: number;
|
|
70
|
-
enabled: boolean;
|
|
71
|
-
}
|
|
72
|
-
export interface SwarmConfig {
|
|
73
|
-
topology: 'hierarchical' | 'mesh' | 'ring' | 'star' | 'hybrid' | 'hierarchical-mesh';
|
|
74
|
-
maxAgents: number;
|
|
75
|
-
autoScale: boolean;
|
|
76
|
-
coordinationStrategy: 'consensus' | 'leader' | 'distributed';
|
|
77
|
-
healthCheckInterval: number;
|
|
78
|
-
}
|
|
79
|
-
export interface MemoryConfig {
|
|
80
|
-
backend: 'agentdb' | 'sqlite' | 'memory' | 'hybrid';
|
|
81
|
-
persistPath: string;
|
|
82
|
-
cacheSize: number;
|
|
83
|
-
enableHNSW: boolean;
|
|
84
|
-
vectorDimension: number;
|
|
85
|
-
}
|
|
86
|
-
export interface MCPConfig {
|
|
87
|
-
serverHost: string;
|
|
88
|
-
serverPort: number;
|
|
89
|
-
autoStart: boolean;
|
|
90
|
-
transportType: 'stdio' | 'http' | 'websocket';
|
|
91
|
-
tools: string[];
|
|
92
|
-
}
|
|
93
|
-
export interface CLIPreferences {
|
|
94
|
-
colorOutput: boolean;
|
|
95
|
-
interactive: boolean;
|
|
96
|
-
verbosity: 'quiet' | 'normal' | 'verbose' | 'debug';
|
|
97
|
-
outputFormat: 'text' | 'json' | 'table';
|
|
98
|
-
progressStyle: 'bar' | 'spinner' | 'dots' | 'none';
|
|
99
|
-
}
|
|
100
|
-
export interface HooksConfig {
|
|
101
|
-
enabled: boolean;
|
|
102
|
-
autoExecute: boolean;
|
|
103
|
-
hooks: HookDefinition[];
|
|
104
|
-
}
|
|
105
|
-
export interface HookDefinition {
|
|
106
|
-
name: string;
|
|
107
|
-
event: string;
|
|
108
|
-
handler: string;
|
|
109
|
-
priority: number;
|
|
110
|
-
enabled: boolean;
|
|
111
|
-
}
|
|
112
|
-
export interface TableColumn {
|
|
113
|
-
key: string;
|
|
114
|
-
header: string;
|
|
115
|
-
width?: number;
|
|
116
|
-
align?: 'left' | 'center' | 'right';
|
|
117
|
-
format?: (value: unknown) => string;
|
|
118
|
-
}
|
|
119
|
-
export interface TableOptions {
|
|
120
|
-
columns: TableColumn[];
|
|
121
|
-
data: Record<string, unknown>[];
|
|
122
|
-
border?: boolean;
|
|
123
|
-
header?: boolean;
|
|
124
|
-
padding?: number;
|
|
125
|
-
maxWidth?: number;
|
|
126
|
-
}
|
|
127
|
-
export interface ProgressOptions {
|
|
128
|
-
total: number;
|
|
129
|
-
current?: number;
|
|
130
|
-
width?: number;
|
|
131
|
-
format?: string;
|
|
132
|
-
showPercentage?: boolean;
|
|
133
|
-
showETA?: boolean;
|
|
134
|
-
showSpeed?: boolean;
|
|
135
|
-
}
|
|
136
|
-
export interface SpinnerOptions {
|
|
137
|
-
text: string;
|
|
138
|
-
spinner?: 'dots' | 'line' | 'arc' | 'circle' | 'arrows';
|
|
139
|
-
color?: string;
|
|
140
|
-
}
|
|
141
|
-
export interface SelectOption<T = string> {
|
|
142
|
-
value: T;
|
|
143
|
-
label: string;
|
|
144
|
-
hint?: string;
|
|
145
|
-
disabled?: boolean;
|
|
146
|
-
/** For multiselect: whether this option is selected by default */
|
|
147
|
-
selected?: boolean;
|
|
148
|
-
}
|
|
149
|
-
export interface SelectPromptOptions<T = string> {
|
|
150
|
-
message: string;
|
|
151
|
-
options: SelectOption<T>[];
|
|
152
|
-
default?: T;
|
|
153
|
-
searchable?: boolean;
|
|
154
|
-
pageSize?: number;
|
|
155
|
-
}
|
|
156
|
-
export interface ConfirmPromptOptions {
|
|
157
|
-
message: string;
|
|
158
|
-
default?: boolean;
|
|
159
|
-
active?: string;
|
|
160
|
-
inactive?: string;
|
|
161
|
-
}
|
|
162
|
-
export interface InputPromptOptions {
|
|
163
|
-
message: string;
|
|
164
|
-
default?: string;
|
|
165
|
-
placeholder?: string;
|
|
166
|
-
validate?: (value: string) => boolean | string;
|
|
167
|
-
mask?: boolean;
|
|
168
|
-
}
|
|
169
|
-
export interface MultiSelectPromptOptions<T = string> {
|
|
170
|
-
message: string;
|
|
171
|
-
options: SelectOption<T>[];
|
|
172
|
-
default?: T[];
|
|
173
|
-
required?: boolean;
|
|
174
|
-
min?: number;
|
|
175
|
-
max?: number;
|
|
176
|
-
}
|
|
177
|
-
export type CLIEventType = 'command:start' | 'command:end' | 'command:error' | 'prompt:start' | 'prompt:complete' | 'output:write' | 'progress:update' | 'spinner:start' | 'spinner:stop';
|
|
178
|
-
export interface CLIEvent {
|
|
179
|
-
type: CLIEventType;
|
|
180
|
-
timestamp: number;
|
|
181
|
-
data?: unknown;
|
|
182
|
-
}
|
|
183
|
-
export declare class CLIError extends Error {
|
|
184
|
-
code: string;
|
|
185
|
-
exitCode: number;
|
|
186
|
-
details?: unknown | undefined;
|
|
187
|
-
constructor(message: string, code: string, exitCode?: number, details?: unknown | undefined);
|
|
188
|
-
}
|
|
189
|
-
export declare class ValidationError extends CLIError {
|
|
190
|
-
constructor(message: string, details?: unknown);
|
|
191
|
-
}
|
|
192
|
-
export declare class ConfigError extends CLIError {
|
|
193
|
-
constructor(message: string, details?: unknown);
|
|
194
|
-
}
|
|
195
|
-
export declare class CommandNotFoundError extends CLIError {
|
|
196
|
-
constructor(commandName: string);
|
|
197
|
-
}
|
|
12
|
+
export * from '@claude-flow/cli-core/types';
|
|
198
13
|
//# sourceMappingURL=types.d.ts.map
|
|
@@ -1,38 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* V3 CLI Type Definitions
|
|
3
|
-
*
|
|
2
|
+
* V3 CLI Type Definitions — re-export shim (ADR-100, alpha.5).
|
|
3
|
+
*
|
|
4
|
+
* Authoritative source: @claude-flow/cli-core/types. Was a byte-identical
|
|
5
|
+
* 287-line copy until alpha.5 published the cli-core subpath. The 60+
|
|
6
|
+
* `import './types.js'` call sites inside cli keep working unchanged
|
|
7
|
+
* because the file path is preserved.
|
|
8
|
+
*
|
|
9
|
+
* To extend the type system, edit v3/@claude-flow/cli-core/src/types.ts
|
|
10
|
+
* — changes flow through here automatically.
|
|
4
11
|
*/
|
|
5
|
-
|
|
6
|
-
// Error Types
|
|
7
|
-
// ============================================
|
|
8
|
-
export class CLIError extends Error {
|
|
9
|
-
code;
|
|
10
|
-
exitCode;
|
|
11
|
-
details;
|
|
12
|
-
constructor(message, code, exitCode = 1, details) {
|
|
13
|
-
super(message);
|
|
14
|
-
this.code = code;
|
|
15
|
-
this.exitCode = exitCode;
|
|
16
|
-
this.details = details;
|
|
17
|
-
this.name = 'CLIError';
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
export class ValidationError extends CLIError {
|
|
21
|
-
constructor(message, details) {
|
|
22
|
-
super(message, 'VALIDATION_ERROR', 1, details);
|
|
23
|
-
this.name = 'ValidationError';
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
export class ConfigError extends CLIError {
|
|
27
|
-
constructor(message, details) {
|
|
28
|
-
super(message, 'CONFIG_ERROR', 1, details);
|
|
29
|
-
this.name = 'ConfigError';
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
export class CommandNotFoundError extends CLIError {
|
|
33
|
-
constructor(commandName) {
|
|
34
|
-
super(`Unknown command: ${commandName}`, 'COMMAND_NOT_FOUND', 127);
|
|
35
|
-
this.name = 'CommandNotFoundError';
|
|
36
|
-
}
|
|
37
|
-
}
|
|
12
|
+
export * from '@claude-flow/cli-core/types';
|
|
38
13
|
//# sourceMappingURL=types.js.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@claude-flow/cli",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.7.0-alpha.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Ruflo CLI - Enterprise AI agent orchestration with 60+ specialized agents, swarm coordination, MCP server, self-learning hooks, and vector memory for Claude Code",
|
|
6
6
|
"main": "dist/src/index.js",
|
|
@@ -95,6 +95,7 @@
|
|
|
95
95
|
"vitest": "^4.0.16"
|
|
96
96
|
},
|
|
97
97
|
"dependencies": {
|
|
98
|
+
"@claude-flow/cli-core": "^3.7.0-alpha.5",
|
|
98
99
|
"@claude-flow/mcp": "^3.0.0-alpha.8",
|
|
99
100
|
"@claude-flow/shared": "^3.0.0-alpha.7",
|
|
100
101
|
"@noble/ed25519": "^2.1.0",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"sessionId":"1dba3b8c-1f1f-4718-bab4-9ffba5f49578","pid":20633,"procStart":"Mon May 4 17:00:40 2026","acquiredAt":1777938041240}
|