@shepai/cli 1.20.1 → 1.21.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/dist/src/application/ports/output/services/index.d.ts +1 -0
- package/dist/src/application/ports/output/services/index.d.ts.map +1 -1
- package/dist/src/application/ports/output/services/tool-installer.service.d.ts +35 -0
- package/dist/src/application/ports/output/services/tool-installer.service.d.ts.map +1 -0
- package/dist/src/application/ports/output/services/tool-installer.service.js +7 -0
- package/dist/src/application/use-cases/tools/install-tool.use-case.d.ts +21 -0
- package/dist/src/application/use-cases/tools/install-tool.use-case.d.ts.map +1 -0
- package/dist/src/application/use-cases/tools/install-tool.use-case.js +41 -0
- package/dist/src/application/use-cases/tools/validate-tool-availability.use-case.d.ts +20 -0
- package/dist/src/application/use-cases/tools/validate-tool-availability.use-case.d.ts.map +1 -0
- package/dist/src/application/use-cases/tools/validate-tool-availability.use-case.js +40 -0
- package/dist/src/domain/generated/output.d.ts +97 -0
- package/dist/src/domain/generated/output.d.ts.map +1 -1
- package/dist/src/domain/generated/output.js +10 -0
- package/dist/src/domain/value-objects/index.d.ts +2 -0
- package/dist/src/domain/value-objects/index.d.ts.map +1 -1
- package/dist/src/domain/value-objects/index.js +1 -0
- package/dist/src/domain/value-objects/tool-installation-status.d.ts +70 -0
- package/dist/src/domain/value-objects/tool-installation-status.d.ts.map +1 -0
- package/dist/src/domain/value-objects/tool-installation-status.js +111 -0
- package/dist/src/infrastructure/di/container.d.ts.map +1 -1
- package/dist/src/infrastructure/di/container.js +6 -0
- package/dist/src/infrastructure/services/tool-installer/tool-installer.service.d.ts +36 -0
- package/dist/src/infrastructure/services/tool-installer/tool-installer.service.d.ts.map +1 -0
- package/dist/src/infrastructure/services/tool-installer/tool-installer.service.js +179 -0
- package/dist/src/infrastructure/services/tool-installer/tool-metadata.d.ts +37 -0
- package/dist/src/infrastructure/services/tool-installer/tool-metadata.d.ts.map +1 -0
- package/dist/src/infrastructure/services/tool-installer/tool-metadata.js +52 -0
- package/dist/src/infrastructure/services/tool-installer/tools/antigravity.json +20 -0
- package/dist/src/infrastructure/services/tool-installer/tools/claude-code.json +16 -0
- package/dist/src/infrastructure/services/tool-installer/tools/cursor-cli.json +16 -0
- package/dist/src/infrastructure/services/tool-installer/tools/cursor.json +17 -0
- package/dist/src/infrastructure/services/tool-installer/tools/vscode.json +17 -0
- package/dist/src/infrastructure/services/tool-installer/tools/windsurf.json +17 -0
- package/dist/src/infrastructure/services/tool-installer/tools/zed.json +17 -0
- package/dist/src/presentation/cli/commands/install.command.d.ts +14 -0
- package/dist/src/presentation/cli/commands/install.command.d.ts.map +1 -0
- package/dist/src/presentation/cli/commands/install.command.js +134 -0
- package/dist/src/presentation/cli/index.js +2 -0
- package/dist/src/presentation/cli/ui/index.d.ts +1 -0
- package/dist/src/presentation/cli/ui/index.d.ts.map +1 -1
- package/dist/src/presentation/cli/ui/index.js +1 -0
- package/dist/src/presentation/cli/ui/install-messages.d.ts +23 -0
- package/dist/src/presentation/cli/ui/install-messages.d.ts.map +1 -0
- package/dist/src/presentation/cli/ui/install-messages.js +36 -0
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +2 -2
- package/web/.next/BUILD_ID +1 -1
- package/web/.next/build-manifest.json +2 -2
- package/web/.next/cache/.previewinfo +1 -1
- package/web/.next/cache/.rscinfo +1 -1
- package/web/.next/cache/config.json +3 -3
- package/web/.next/fallback-build-manifest.json +2 -2
- package/web/.next/prerender-manifest.json +3 -3
- package/web/.next/required-server-files.js +1 -1
- package/web/.next/required-server-files.json +1 -1
- package/web/.next/server/app/_global-error.html +2 -2
- package/web/.next/server/app/_global-error.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/web/.next/server/app/_not-found.html +2 -2
- package/web/.next/server/app/_not-found.rsc +1 -1
- package/web/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- package/web/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/web/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
- package/web/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/web/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/web/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/web/.next/server/app/index.html +2 -2
- package/web/.next/server/app/index.rsc +1 -1
- package/web/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
- package/web/.next/server/app/index.segments/_full.segment.rsc +1 -1
- package/web/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/web/.next/server/app/index.segments/_index.segment.rsc +1 -1
- package/web/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/web/.next/server/app/version.html +2 -2
- package/web/.next/server/app/version.rsc +1 -1
- package/web/.next/server/app/version.segments/_full.segment.rsc +1 -1
- package/web/.next/server/app/version.segments/_head.segment.rsc +1 -1
- package/web/.next/server/app/version.segments/_index.segment.rsc +1 -1
- package/web/.next/server/app/version.segments/_tree.segment.rsc +1 -1
- package/web/.next/server/app/version.segments/version/__PAGE__.segment.rsc +1 -1
- package/web/.next/server/app/version.segments/version.segment.rsc +1 -1
- package/web/.next/server/chunks/ssr/_19be0743._.js +1 -1
- package/web/.next/server/pages/404.html +2 -2
- package/web/.next/server/pages/500.html +2 -2
- package/web/.next/server/server-reference-manifest.js +1 -1
- package/web/.next/server/server-reference-manifest.json +1 -1
- package/web/.next/trace +1 -1
- package/web/.next/trace-build +1 -1
- /package/web/.next/static/{xKJulVMYO_ZRGoqa6eM7G → 64iQn2RbdM-TFYWmABhXw}/_buildManifest.js +0 -0
- /package/web/.next/static/{xKJulVMYO_ZRGoqa6eM7G → 64iQn2RbdM-TFYWmABhXw}/_clientMiddlewareManifest.json +0 -0
- /package/web/.next/static/{xKJulVMYO_ZRGoqa6eM7G → 64iQn2RbdM-TFYWmABhXw}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool Installer Service Implementation
|
|
3
|
+
*
|
|
4
|
+
* Provides tool availability checking, installation command resolution,
|
|
5
|
+
* and installation execution with streaming output and timeout handling.
|
|
6
|
+
*
|
|
7
|
+
* Features:
|
|
8
|
+
* - Check binary availability using 'which' command
|
|
9
|
+
* - Retrieve platform-specific installation commands
|
|
10
|
+
* - Execute installations with real-time output streaming
|
|
11
|
+
* - Automatic timeout handling with process termination
|
|
12
|
+
* - Immutable status objects via value object factory functions
|
|
13
|
+
*/
|
|
14
|
+
import type { IToolInstallerService } from '../../../application/ports/output/services/tool-installer.service.js';
|
|
15
|
+
import type { ToolInstallationStatus, ToolInstallCommand } from '../../../domain/generated/output.js';
|
|
16
|
+
export declare class ToolInstallerServiceImpl implements IToolInstallerService {
|
|
17
|
+
/**
|
|
18
|
+
* Check if a tool binary is available on the system (PATH check)
|
|
19
|
+
*/
|
|
20
|
+
checkAvailability(toolName: string): Promise<ToolInstallationStatus>;
|
|
21
|
+
/**
|
|
22
|
+
* Get the install command metadata for a tool on the current platform.
|
|
23
|
+
* Returns null if tool is unknown or not supported on current platform.
|
|
24
|
+
*/
|
|
25
|
+
getInstallCommand(toolName: string): ToolInstallCommand | null;
|
|
26
|
+
/**
|
|
27
|
+
* Execute installation of a tool with live output streaming.
|
|
28
|
+
* Streams stdout/stderr to optional callback and handles timeout automatically.
|
|
29
|
+
*/
|
|
30
|
+
executeInstall(toolName: string, onOutput?: (data: string) => void): Promise<ToolInstallationStatus>;
|
|
31
|
+
/**
|
|
32
|
+
* Create installation suggestions for a tool based on its metadata
|
|
33
|
+
*/
|
|
34
|
+
private createInstallationSuggestions;
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=tool-installer.service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-installer.service.d.ts","sourceRoot":"","sources":["../../../../../src/infrastructure/services/tool-installer/tool-installer.service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAKH,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,sEAAsE,CAAC;AAClH,OAAO,KAAK,EACV,sBAAsB,EACtB,kBAAkB,EAEnB,MAAM,qCAAqC,CAAC;AA6B7C,qBACa,wBAAyB,YAAW,qBAAqB;IACpE;;OAEG;IACG,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,sBAAsB,CAAC;IA8B1E;;;OAGG;IACH,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,kBAAkB,GAAG,IAAI;IAqB9D;;;OAGG;IACG,cAAc,CAClB,QAAQ,EAAE,MAAM,EAChB,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,GAChC,OAAO,CAAC,sBAAsB,CAAC;IAyDlC;;OAEG;IACH,OAAO,CAAC,6BAA6B;CA4BtC"}
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool Installer Service Implementation
|
|
3
|
+
*
|
|
4
|
+
* Provides tool availability checking, installation command resolution,
|
|
5
|
+
* and installation execution with streaming output and timeout handling.
|
|
6
|
+
*
|
|
7
|
+
* Features:
|
|
8
|
+
* - Check binary availability using 'which' command
|
|
9
|
+
* - Retrieve platform-specific installation commands
|
|
10
|
+
* - Execute installations with real-time output streaming
|
|
11
|
+
* - Automatic timeout handling with process termination
|
|
12
|
+
* - Immutable status objects via value object factory functions
|
|
13
|
+
*/
|
|
14
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
15
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
16
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
17
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
18
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
19
|
+
};
|
|
20
|
+
import { injectable } from 'tsyringe';
|
|
21
|
+
import { execFile, spawn } from 'node:child_process';
|
|
22
|
+
import { platform } from 'node:os';
|
|
23
|
+
import { createAvailableStatus, createMissingStatus, createErrorStatus, } from '../../../domain/value-objects/tool-installation-status.js';
|
|
24
|
+
import { TOOL_METADATA } from './tool-metadata.js';
|
|
25
|
+
/**
|
|
26
|
+
* Resolve binary name for the current platform.
|
|
27
|
+
* Supports both simple string binaries and per-platform maps.
|
|
28
|
+
*/
|
|
29
|
+
function resolveBinary(metadata) {
|
|
30
|
+
if (typeof metadata.binary === 'string')
|
|
31
|
+
return metadata.binary;
|
|
32
|
+
return metadata.binary[platform()] ?? Object.values(metadata.binary)[0];
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Check if a binary exists in the system PATH using 'which' command.
|
|
36
|
+
* Returns both availability status and any error for detailed reporting.
|
|
37
|
+
*/
|
|
38
|
+
const checkBinaryExists = (binary) => {
|
|
39
|
+
return new Promise((resolve) => {
|
|
40
|
+
execFile('which', [binary], (err) => {
|
|
41
|
+
resolve(err ? { found: false, error: err } : { found: true });
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
};
|
|
45
|
+
let ToolInstallerServiceImpl = class ToolInstallerServiceImpl {
|
|
46
|
+
/**
|
|
47
|
+
* Check if a tool binary is available on the system (PATH check)
|
|
48
|
+
*/
|
|
49
|
+
async checkAvailability(toolName) {
|
|
50
|
+
const metadata = TOOL_METADATA[toolName];
|
|
51
|
+
if (!metadata) {
|
|
52
|
+
return createErrorStatus(toolName, `Unknown tool: ${toolName}`);
|
|
53
|
+
}
|
|
54
|
+
try {
|
|
55
|
+
const result = await checkBinaryExists(resolveBinary(metadata));
|
|
56
|
+
if (result.found) {
|
|
57
|
+
return createAvailableStatus(toolName);
|
|
58
|
+
}
|
|
59
|
+
// Check if it's just "not found" or another error
|
|
60
|
+
if (result.error?.message.includes('not found')) {
|
|
61
|
+
// Binary doesn't exist in PATH - create suggestions for installation
|
|
62
|
+
const suggestions = this.createInstallationSuggestions(metadata);
|
|
63
|
+
return createMissingStatus(toolName, suggestions);
|
|
64
|
+
}
|
|
65
|
+
// Some other error occurred
|
|
66
|
+
const errorMessage = result.error?.message ?? 'Unknown error checking availability';
|
|
67
|
+
return createErrorStatus(toolName, `Failed to check availability: ${errorMessage}`);
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
71
|
+
return createErrorStatus(toolName, `Failed to check availability: ${errorMessage}`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Get the install command metadata for a tool on the current platform.
|
|
76
|
+
* Returns null if tool is unknown or not supported on current platform.
|
|
77
|
+
*/
|
|
78
|
+
getInstallCommand(toolName) {
|
|
79
|
+
const metadata = TOOL_METADATA[toolName];
|
|
80
|
+
if (!metadata) {
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
const currentPlatform = platform();
|
|
84
|
+
const command = metadata.commands[currentPlatform];
|
|
85
|
+
if (!command) {
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
return {
|
|
89
|
+
command,
|
|
90
|
+
platform: currentPlatform,
|
|
91
|
+
timeout: metadata.timeout,
|
|
92
|
+
toolName,
|
|
93
|
+
packageManager: metadata.packageManager,
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Execute installation of a tool with live output streaming.
|
|
98
|
+
* Streams stdout/stderr to optional callback and handles timeout automatically.
|
|
99
|
+
*/
|
|
100
|
+
async executeInstall(toolName, onOutput) {
|
|
101
|
+
const installCommand = this.getInstallCommand(toolName);
|
|
102
|
+
if (!installCommand) {
|
|
103
|
+
return createErrorStatus(toolName, `No installation command available for ${toolName}`);
|
|
104
|
+
}
|
|
105
|
+
return new Promise((resolve) => {
|
|
106
|
+
let output = '';
|
|
107
|
+
const child = spawn('sh', ['-c', installCommand.command], {
|
|
108
|
+
shell: false,
|
|
109
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
110
|
+
});
|
|
111
|
+
// Stream output from stdout and stderr
|
|
112
|
+
const pipeOutput = (stream) => {
|
|
113
|
+
if (!stream)
|
|
114
|
+
return;
|
|
115
|
+
stream.on('data', (data) => {
|
|
116
|
+
const text = data.toString();
|
|
117
|
+
output += text;
|
|
118
|
+
if (onOutput) {
|
|
119
|
+
onOutput(text);
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
};
|
|
123
|
+
pipeOutput(child.stdout);
|
|
124
|
+
pipeOutput(child.stderr);
|
|
125
|
+
// Set up timeout to kill process if it takes too long
|
|
126
|
+
const timeoutId = setTimeout(() => {
|
|
127
|
+
child.kill();
|
|
128
|
+
}, installCommand.timeout);
|
|
129
|
+
// Handle process completion or error
|
|
130
|
+
const cleanup = (errorMessage) => {
|
|
131
|
+
clearTimeout(timeoutId);
|
|
132
|
+
const returnStatus = errorMessage
|
|
133
|
+
? createErrorStatus(toolName, errorMessage)
|
|
134
|
+
: createAvailableStatus(toolName);
|
|
135
|
+
resolve(returnStatus);
|
|
136
|
+
};
|
|
137
|
+
child.on('close', (code) => {
|
|
138
|
+
if (code === 0) {
|
|
139
|
+
cleanup();
|
|
140
|
+
}
|
|
141
|
+
else {
|
|
142
|
+
cleanup(`Installation failed with exit code ${code}. Output: ${output.slice(0, 200)}`);
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
child.on('error', (err) => {
|
|
146
|
+
cleanup(`Installation error: ${err.message}`);
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Create installation suggestions for a tool based on its metadata
|
|
152
|
+
*/
|
|
153
|
+
createInstallationSuggestions(metadata) {
|
|
154
|
+
const suggestions = [];
|
|
155
|
+
// Add suggestion for current platform if available
|
|
156
|
+
const currentPlatform = platform();
|
|
157
|
+
const command = metadata.commands[currentPlatform];
|
|
158
|
+
if (command) {
|
|
159
|
+
suggestions.push({
|
|
160
|
+
packageManager: metadata.packageManager,
|
|
161
|
+
command,
|
|
162
|
+
documentationUrl: metadata.documentationUrl,
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
// Add generic suggestion
|
|
166
|
+
if (!suggestions.length) {
|
|
167
|
+
suggestions.push({
|
|
168
|
+
packageManager: metadata.packageManager,
|
|
169
|
+
command: 'Visit official documentation',
|
|
170
|
+
documentationUrl: metadata.documentationUrl,
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
return suggestions;
|
|
174
|
+
}
|
|
175
|
+
};
|
|
176
|
+
ToolInstallerServiceImpl = __decorate([
|
|
177
|
+
injectable()
|
|
178
|
+
], ToolInstallerServiceImpl);
|
|
179
|
+
export { ToolInstallerServiceImpl };
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool Installation Metadata
|
|
3
|
+
*
|
|
4
|
+
* Dynamically loads tool definitions from individual JSON files in the tools/ directory.
|
|
5
|
+
* Each JSON file defines installation commands and metadata for a single development tool.
|
|
6
|
+
*
|
|
7
|
+
* To add a new tool, create a JSON file in tools/ matching the ToolMetadata schema:
|
|
8
|
+
* tools/<tool-name>.json
|
|
9
|
+
*/
|
|
10
|
+
export interface ToolMetadata {
|
|
11
|
+
/** Human-readable display name */
|
|
12
|
+
name: string;
|
|
13
|
+
/** Short one-line summary */
|
|
14
|
+
summary: string;
|
|
15
|
+
/** Detailed description */
|
|
16
|
+
description: string;
|
|
17
|
+
/** Tool category for grouping in listings */
|
|
18
|
+
category: 'ide' | 'cli-agent';
|
|
19
|
+
/** Binary name to check with 'which' command (string or per-platform map) */
|
|
20
|
+
binary: string | Record<string, string>;
|
|
21
|
+
/** Package manager or installation method */
|
|
22
|
+
packageManager: string;
|
|
23
|
+
/** Platform-specific installation commands as shell strings (keyed by os.platform()) */
|
|
24
|
+
commands: Record<string, string>;
|
|
25
|
+
/** Installation timeout in milliseconds */
|
|
26
|
+
timeout: number;
|
|
27
|
+
/** Official documentation URL */
|
|
28
|
+
documentationUrl: string;
|
|
29
|
+
/** Command to verify installation (e.g., "code --version") */
|
|
30
|
+
verifyCommand: string;
|
|
31
|
+
/** Whether the tool supports automated installation (default: true) */
|
|
32
|
+
autoInstall?: boolean;
|
|
33
|
+
/** Command to open a directory in this tool (e.g., "code .") */
|
|
34
|
+
openDirectory?: string;
|
|
35
|
+
}
|
|
36
|
+
export declare const TOOL_METADATA: Record<string, ToolMetadata>;
|
|
37
|
+
//# sourceMappingURL=tool-metadata.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-metadata.d.ts","sourceRoot":"","sources":["../../../../../src/infrastructure/services/tool-installer/tool-metadata.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAMH,MAAM,WAAW,YAAY;IAC3B,kCAAkC;IAClC,IAAI,EAAE,MAAM,CAAC;IAEb,6BAA6B;IAC7B,OAAO,EAAE,MAAM,CAAC;IAEhB,2BAA2B;IAC3B,WAAW,EAAE,MAAM,CAAC;IAEpB,6CAA6C;IAC7C,QAAQ,EAAE,KAAK,GAAG,WAAW,CAAC;IAE9B,6EAA6E;IAC7E,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAExC,6CAA6C;IAC7C,cAAc,EAAE,MAAM,CAAC;IAEvB,wFAAwF;IACxF,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAEjC,2CAA2C;IAC3C,OAAO,EAAE,MAAM,CAAC;IAEhB,iCAAiC;IACjC,gBAAgB,EAAE,MAAM,CAAC;IAEzB,8DAA8D;IAC9D,aAAa,EAAE,MAAM,CAAC;IAEtB,uEAAuE;IACvE,WAAW,CAAC,EAAE,OAAO,CAAC;IAEtB,gEAAgE;IAChE,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AA8CD,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAsB,CAAC"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool Installation Metadata
|
|
3
|
+
*
|
|
4
|
+
* Dynamically loads tool definitions from individual JSON files in the tools/ directory.
|
|
5
|
+
* Each JSON file defines installation commands and metadata for a single development tool.
|
|
6
|
+
*
|
|
7
|
+
* To add a new tool, create a JSON file in tools/ matching the ToolMetadata schema:
|
|
8
|
+
* tools/<tool-name>.json
|
|
9
|
+
*/
|
|
10
|
+
import { readdirSync, readFileSync } from 'node:fs';
|
|
11
|
+
import { join, basename } from 'node:path';
|
|
12
|
+
import { fileURLToPath } from 'node:url';
|
|
13
|
+
const REQUIRED_FIELDS = [
|
|
14
|
+
'name',
|
|
15
|
+
'summary',
|
|
16
|
+
'description',
|
|
17
|
+
'category',
|
|
18
|
+
'binary',
|
|
19
|
+
'packageManager',
|
|
20
|
+
'commands',
|
|
21
|
+
'timeout',
|
|
22
|
+
'documentationUrl',
|
|
23
|
+
'verifyCommand',
|
|
24
|
+
];
|
|
25
|
+
function loadToolMetadata() {
|
|
26
|
+
const toolsDir = join(fileURLToPath(import.meta.url), '..', 'tools');
|
|
27
|
+
const metadata = {};
|
|
28
|
+
let files;
|
|
29
|
+
try {
|
|
30
|
+
files = readdirSync(toolsDir).filter((f) => f.endsWith('.json'));
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
return metadata;
|
|
34
|
+
}
|
|
35
|
+
for (const file of files) {
|
|
36
|
+
const toolName = basename(file, '.json');
|
|
37
|
+
try {
|
|
38
|
+
const raw = readFileSync(join(toolsDir, file), 'utf-8');
|
|
39
|
+
const parsed = JSON.parse(raw);
|
|
40
|
+
const missing = REQUIRED_FIELDS.filter((field) => !(field in parsed));
|
|
41
|
+
if (missing.length > 0) {
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
metadata[toolName] = parsed;
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
// Skip malformed JSON files
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return metadata;
|
|
51
|
+
}
|
|
52
|
+
export const TOOL_METADATA = loadToolMetadata();
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "Google Antigravity",
|
|
3
|
+
"summary": "AI-powered agentic development platform",
|
|
4
|
+
"description": "Google Antigravity is an AI-powered platform that enables agentic development workflows, helping developers build intelligent applications with autonomous agents.",
|
|
5
|
+
"category": "ide",
|
|
6
|
+
"binary": {
|
|
7
|
+
"linux": "antigravity",
|
|
8
|
+
"darwin": "agy"
|
|
9
|
+
},
|
|
10
|
+
"packageManager": "download",
|
|
11
|
+
"commands": {
|
|
12
|
+
"linux": "echo \"Download from https://antigravity.google/download\"",
|
|
13
|
+
"darwin": "echo \"Download from https://antigravity.google/download\""
|
|
14
|
+
},
|
|
15
|
+
"timeout": 300000,
|
|
16
|
+
"documentationUrl": "https://codelabs.developers.google.com/getting-started-google-antigravity",
|
|
17
|
+
"verifyCommand": "agy --version",
|
|
18
|
+
"autoInstall": false,
|
|
19
|
+
"openDirectory": "agy ."
|
|
20
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "Claude Code",
|
|
3
|
+
"summary": "AI-powered code assistant from Anthropic",
|
|
4
|
+
"description": "Claude Code is an AI-powered code assistant from Anthropic that helps you write, understand, and debug code with advanced AI capabilities.",
|
|
5
|
+
"category": "cli-agent",
|
|
6
|
+
"binary": "claude",
|
|
7
|
+
"packageManager": "curl",
|
|
8
|
+
"commands": {
|
|
9
|
+
"linux": "curl -fsSL https://claude.ai/install.sh | bash",
|
|
10
|
+
"darwin": "curl -fsSL https://claude.ai/install.sh | bash"
|
|
11
|
+
},
|
|
12
|
+
"timeout": 300000,
|
|
13
|
+
"documentationUrl": "https://code.claude.com/docs/en/overview",
|
|
14
|
+
"verifyCommand": "claude --version",
|
|
15
|
+
"autoInstall": true
|
|
16
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "Cursor CLI",
|
|
3
|
+
"summary": "AI-powered code editor command-line interface",
|
|
4
|
+
"description": "Cursor CLI provides command-line access to Cursor, an AI-powered code editor designed for efficient AI-assisted development.",
|
|
5
|
+
"category": "cli-agent",
|
|
6
|
+
"binary": "cursor",
|
|
7
|
+
"packageManager": "curl",
|
|
8
|
+
"commands": {
|
|
9
|
+
"linux": "curl https://cursor.com/install -fsS | bash",
|
|
10
|
+
"darwin": "curl https://cursor.com/install -fsS | bash"
|
|
11
|
+
},
|
|
12
|
+
"timeout": 300000,
|
|
13
|
+
"documentationUrl": "https://cursor.com",
|
|
14
|
+
"verifyCommand": "cursor --version",
|
|
15
|
+
"autoInstall": true
|
|
16
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "Cursor",
|
|
3
|
+
"summary": "AI-powered code editor for efficient development",
|
|
4
|
+
"description": "Cursor is an AI-powered code editor built on VS Code, designed to streamline development workflows with advanced AI-assisted coding capabilities.",
|
|
5
|
+
"category": "ide",
|
|
6
|
+
"binary": "cursor",
|
|
7
|
+
"packageManager": "curl",
|
|
8
|
+
"commands": {
|
|
9
|
+
"linux": "curl -fsSL https://www.cursor.com/linux/install.sh | sh",
|
|
10
|
+
"darwin": "curl -fsSL https://www.cursor.com/mac/install.sh | sh"
|
|
11
|
+
},
|
|
12
|
+
"timeout": 600000,
|
|
13
|
+
"documentationUrl": "https://www.cursor.com/docs",
|
|
14
|
+
"verifyCommand": "cursor --version",
|
|
15
|
+
"autoInstall": true,
|
|
16
|
+
"openDirectory": "cursor ."
|
|
17
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "Visual Studio Code",
|
|
3
|
+
"summary": "Lightweight but powerful source code editor",
|
|
4
|
+
"description": "Microsoft Visual Studio Code is a free, open-source code editor with built-in support for debugging, version control, and extensions for enhanced development workflows.",
|
|
5
|
+
"category": "ide",
|
|
6
|
+
"binary": "code",
|
|
7
|
+
"packageManager": "apt",
|
|
8
|
+
"commands": {
|
|
9
|
+
"linux": "sudo apt update && sudo apt install -y code",
|
|
10
|
+
"darwin": "brew install visual-studio-code"
|
|
11
|
+
},
|
|
12
|
+
"timeout": 300000,
|
|
13
|
+
"documentationUrl": "https://code.visualstudio.com/docs/setup/linux",
|
|
14
|
+
"verifyCommand": "code --version",
|
|
15
|
+
"autoInstall": true,
|
|
16
|
+
"openDirectory": "code ."
|
|
17
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "Windsurf",
|
|
3
|
+
"summary": "AI-powered code editor by Codeium",
|
|
4
|
+
"description": "Windsurf is an AI-powered code editor by Codeium that provides intelligent code assistance and automation features for modern development.",
|
|
5
|
+
"category": "ide",
|
|
6
|
+
"binary": "windsurf",
|
|
7
|
+
"packageManager": "apt",
|
|
8
|
+
"commands": {
|
|
9
|
+
"linux": "curl -fsSL \"https://windsurf-stable.codeiumdata.com/wVxQEIWkwPUEAGf3/windsurf.gpg\" | sudo gpg --dearmor -o /usr/share/keyrings/windsurf-stable-archive-keyring.gpg && echo \"deb [signed-by=/usr/share/keyrings/windsurf-stable-archive-keyring.gpg arch=amd64] https://windsurf-stable.codeiumdata.com/wVxQEIWkwPUEAGf3/apt stable main\" | sudo tee /etc/apt/sources.list.d/windsurf.list > /dev/null && sudo apt-get update && sudo apt-get install -y windsurf",
|
|
10
|
+
"darwin": "brew install --cask windsurf"
|
|
11
|
+
},
|
|
12
|
+
"timeout": 300000,
|
|
13
|
+
"documentationUrl": "https://docs.windsurf.com/windsurf/getting-started",
|
|
14
|
+
"verifyCommand": "windsurf --version",
|
|
15
|
+
"autoInstall": true,
|
|
16
|
+
"openDirectory": "windsurf ."
|
|
17
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "Zed",
|
|
3
|
+
"summary": "High-performance code editor written in Rust",
|
|
4
|
+
"description": "Zed is a high-performance code editor written in Rust, designed for speed and collaboration with modern developer workflows.",
|
|
5
|
+
"category": "ide",
|
|
6
|
+
"binary": "zed",
|
|
7
|
+
"packageManager": "curl",
|
|
8
|
+
"commands": {
|
|
9
|
+
"linux": "curl -f https://zed.dev/install.sh | sh",
|
|
10
|
+
"darwin": "curl -f https://zed.dev/install.sh | sh"
|
|
11
|
+
},
|
|
12
|
+
"timeout": 300000,
|
|
13
|
+
"documentationUrl": "https://zed.dev/docs/installation",
|
|
14
|
+
"verifyCommand": "zed --version",
|
|
15
|
+
"autoInstall": true,
|
|
16
|
+
"openDirectory": "zed ."
|
|
17
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Install Command
|
|
3
|
+
*
|
|
4
|
+
* Installs a development tool (IDE or CLI agent) on the system.
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* shep install <tool> Install a tool
|
|
8
|
+
* shep install <tool> --how Show installation instructions without executing
|
|
9
|
+
*
|
|
10
|
+
* Available tools are loaded dynamically from JSON files in the tools/ directory.
|
|
11
|
+
*/
|
|
12
|
+
import { Command } from 'commander';
|
|
13
|
+
export declare function createInstallCommand(): Command;
|
|
14
|
+
//# sourceMappingURL=install.command.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install.command.d.ts","sourceRoot":"","sources":["../../../../../src/presentation/cli/commands/install.command.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA6BpC,wBAAgB,oBAAoB,IAAI,OAAO,CAuE9C"}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Install Command
|
|
3
|
+
*
|
|
4
|
+
* Installs a development tool (IDE or CLI agent) on the system.
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* shep install <tool> Install a tool
|
|
8
|
+
* shep install <tool> --how Show installation instructions without executing
|
|
9
|
+
*
|
|
10
|
+
* Available tools are loaded dynamically from JSON files in the tools/ directory.
|
|
11
|
+
*/
|
|
12
|
+
import { Command } from 'commander';
|
|
13
|
+
import { container } from '../../../infrastructure/di/container.js';
|
|
14
|
+
import { ValidateToolAvailabilityUseCase } from '../../../application/use-cases/tools/validate-tool-availability.use-case.js';
|
|
15
|
+
import { InstallToolUseCase } from '../../../application/use-cases/tools/install-tool.use-case.js';
|
|
16
|
+
import { TOOL_METADATA } from '../../../infrastructure/services/tool-installer/tool-metadata.js';
|
|
17
|
+
import { messages, fmt, colors } from '../ui/index.js';
|
|
18
|
+
function printToolsList() {
|
|
19
|
+
const tools = Object.entries(TOOL_METADATA);
|
|
20
|
+
const ides = tools.filter(([, meta]) => meta.category === 'ide');
|
|
21
|
+
const cliAgents = tools.filter(([, meta]) => meta.category === 'cli-agent');
|
|
22
|
+
console.log(fmt.heading('IDEs:'));
|
|
23
|
+
for (const [key, meta] of ides) {
|
|
24
|
+
console.log(` ${colors.accent(key.padEnd(16))}${meta.name} - ${colors.muted(meta.summary)}`);
|
|
25
|
+
}
|
|
26
|
+
console.log();
|
|
27
|
+
console.log(fmt.heading('CLI Agents:'));
|
|
28
|
+
for (const [key, meta] of cliAgents) {
|
|
29
|
+
console.log(` ${colors.accent(key.padEnd(16))}${meta.name} - ${colors.muted(meta.summary)}`);
|
|
30
|
+
}
|
|
31
|
+
console.log();
|
|
32
|
+
}
|
|
33
|
+
export function createInstallCommand() {
|
|
34
|
+
return new Command('install')
|
|
35
|
+
.description('Install a development tool (IDE or CLI agent)')
|
|
36
|
+
.argument('[tool]', 'Tool to install (vscode, cursor, windsurf, zed, antigravity, cursor-cli, claude-code)')
|
|
37
|
+
.option('--how', 'Show installation instructions without executing')
|
|
38
|
+
.action(async (tool, options) => {
|
|
39
|
+
try {
|
|
40
|
+
// No tool specified — show available tools
|
|
41
|
+
if (!tool) {
|
|
42
|
+
console.log();
|
|
43
|
+
console.log(`Run ${fmt.code('shep install <tool>')} with one of these options:`);
|
|
44
|
+
console.log();
|
|
45
|
+
printToolsList();
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
// Validate tool name
|
|
49
|
+
const metadata = TOOL_METADATA[tool];
|
|
50
|
+
if (!metadata) {
|
|
51
|
+
console.log();
|
|
52
|
+
console.log(`Hmm, I don't recognize '${tool}'. Did you mean one of these?`);
|
|
53
|
+
console.log();
|
|
54
|
+
printToolsList();
|
|
55
|
+
process.exitCode = 1;
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
if (options.how) {
|
|
59
|
+
// Print installation instructions without executing
|
|
60
|
+
printInstallInstructions(metadata);
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
// Check availability first
|
|
64
|
+
const validateUseCase = container.resolve(ValidateToolAvailabilityUseCase);
|
|
65
|
+
const status = await validateUseCase.execute(tool);
|
|
66
|
+
if (status.status === 'available') {
|
|
67
|
+
messages.success(`${tool} is already installed`);
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
// Tools that don't support auto-install — show instructions instead
|
|
71
|
+
if (metadata.autoInstall === false) {
|
|
72
|
+
messages.warning(`${tool} does not support automated installation`);
|
|
73
|
+
printInstallInstructions(metadata);
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
// Install
|
|
77
|
+
const installUseCase = container.resolve(InstallToolUseCase);
|
|
78
|
+
const result = await installUseCase.execute(tool, (data) => process.stdout.write(data));
|
|
79
|
+
if (result.status === 'available') {
|
|
80
|
+
messages.success(`${tool} installed successfully`);
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
messages.error(`Failed to install ${tool}: ${result.errorMessage ?? 'Unknown error'}`, new Error(result.errorMessage ?? 'Installation failed'));
|
|
84
|
+
process.exitCode = 1;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
catch (error) {
|
|
88
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
89
|
+
messages.error(`Failed to install ${tool}`, err);
|
|
90
|
+
process.exitCode = 1;
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Print installation instructions for a tool
|
|
96
|
+
*/
|
|
97
|
+
function printInstallInstructions(metadata) {
|
|
98
|
+
console.log();
|
|
99
|
+
console.log(fmt.heading(`Installation Instructions for ${metadata.name}`));
|
|
100
|
+
console.log();
|
|
101
|
+
console.log(`${fmt.label('Name:')} ${metadata.name}`);
|
|
102
|
+
console.log(`${fmt.label('Summary:')} ${metadata.summary}`);
|
|
103
|
+
console.log(`${fmt.label('Description:')} ${metadata.description}`);
|
|
104
|
+
console.log(`${fmt.label('Category:')} ${metadata.category}`);
|
|
105
|
+
console.log();
|
|
106
|
+
const binaryDisplay = typeof metadata.binary === 'string'
|
|
107
|
+
? metadata.binary
|
|
108
|
+
: Object.entries(metadata.binary)
|
|
109
|
+
.map(([platform, bin]) => `${bin} (${platform})`)
|
|
110
|
+
.join(', ');
|
|
111
|
+
console.log(`${fmt.label('Binary:')} ${binaryDisplay}`);
|
|
112
|
+
console.log(`${fmt.label('Package Manager:')} ${metadata.packageManager}`);
|
|
113
|
+
console.log();
|
|
114
|
+
// Print platform-specific commands
|
|
115
|
+
console.log(fmt.heading('Installation Commands'));
|
|
116
|
+
for (const [platform, command] of Object.entries(metadata.commands)) {
|
|
117
|
+
console.log(`${colors.muted(`[${platform}]`)} ${command}`);
|
|
118
|
+
}
|
|
119
|
+
console.log();
|
|
120
|
+
// Print verify command
|
|
121
|
+
console.log(fmt.heading('Verify Installation'));
|
|
122
|
+
console.log(`${colors.muted('$')} ${metadata.verifyCommand}`);
|
|
123
|
+
console.log();
|
|
124
|
+
// Print open directory command if available
|
|
125
|
+
if (metadata.openDirectory) {
|
|
126
|
+
console.log(fmt.heading('Open Directory'));
|
|
127
|
+
console.log(`${colors.muted('$')} ${metadata.openDirectory}`);
|
|
128
|
+
console.log();
|
|
129
|
+
}
|
|
130
|
+
// Print documentation link
|
|
131
|
+
console.log(fmt.heading('Documentation'));
|
|
132
|
+
console.log(`${colors.muted('→')} ${metadata.documentationUrl}`);
|
|
133
|
+
console.log();
|
|
134
|
+
}
|
|
@@ -31,6 +31,7 @@ import { createRunCommand } from './commands/run.command.js';
|
|
|
31
31
|
import { createAgentCommand } from './commands/agent/index.js';
|
|
32
32
|
import { createFeatCommand } from './commands/feat/index.js';
|
|
33
33
|
import { createIdeOpenCommand } from './commands/ide-open.command.js';
|
|
34
|
+
import { createInstallCommand } from './commands/install.command.js';
|
|
34
35
|
import { messages } from './ui/index.js';
|
|
35
36
|
// DI container and settings
|
|
36
37
|
import { initializeContainer, container } from '../../infrastructure/di/container.js';
|
|
@@ -80,6 +81,7 @@ async function bootstrap() {
|
|
|
80
81
|
program.addCommand(createAgentCommand());
|
|
81
82
|
program.addCommand(createFeatCommand());
|
|
82
83
|
program.addCommand(createIdeOpenCommand());
|
|
84
|
+
program.addCommand(createInstallCommand());
|
|
83
85
|
// Parse arguments (parseAsync needed for async command actions like init)
|
|
84
86
|
await program.parseAsync();
|
|
85
87
|
}
|
|
@@ -15,6 +15,7 @@ export { colors, type Colors } from './colors.js';
|
|
|
15
15
|
export { symbols, type Symbols } from './symbols.js';
|
|
16
16
|
export { fmt, type Formatters } from './formatters.js';
|
|
17
17
|
export { messages, type Messages } from './messages.js';
|
|
18
|
+
export { installMessages } from './install-messages.js';
|
|
18
19
|
export { TableFormatter, type DatabaseMeta } from './tables.js';
|
|
19
20
|
export { OutputFormatter, type OutputFormat } from './output.js';
|
|
20
21
|
export { renderDetailView, type DetailViewConfig, type DetailSection, type DetailField, type DetailTextBlock, } from './detail-view.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/presentation/cli/ui/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,MAAM,EAAE,KAAK,MAAM,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,OAAO,EAAE,KAAK,OAAO,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,EAAE,GAAG,EAAE,KAAK,UAAU,EAAE,MAAM,iBAAiB,CAAC;AACvD,OAAO,EAAE,QAAQ,EAAE,KAAK,QAAQ,EAAE,MAAM,eAAe,CAAC;AACxD,OAAO,EAAE,cAAc,EAAE,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC;AAChE,OAAO,EAAE,eAAe,EAAE,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC;AACjE,OAAO,EACL,gBAAgB,EAChB,KAAK,gBAAgB,EACrB,KAAK,aAAa,EAClB,KAAK,WAAW,EAChB,KAAK,eAAe,GACrB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,cAAc,EAAE,KAAK,cAAc,EAAE,KAAK,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACtF,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/presentation/cli/ui/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,MAAM,EAAE,KAAK,MAAM,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,OAAO,EAAE,KAAK,OAAO,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,EAAE,GAAG,EAAE,KAAK,UAAU,EAAE,MAAM,iBAAiB,CAAC;AACvD,OAAO,EAAE,QAAQ,EAAE,KAAK,QAAQ,EAAE,MAAM,eAAe,CAAC;AACxD,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,cAAc,EAAE,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC;AAChE,OAAO,EAAE,eAAe,EAAE,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC;AACjE,OAAO,EACL,gBAAgB,EAChB,KAAK,gBAAgB,EACrB,KAAK,aAAa,EAClB,KAAK,WAAW,EAChB,KAAK,eAAe,GACrB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,cAAc,EAAE,KAAK,cAAc,EAAE,KAAK,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACtF,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC"}
|
|
@@ -15,6 +15,7 @@ export { colors } from './colors.js';
|
|
|
15
15
|
export { symbols } from './symbols.js';
|
|
16
16
|
export { fmt } from './formatters.js';
|
|
17
17
|
export { messages } from './messages.js';
|
|
18
|
+
export { installMessages } from './install-messages.js';
|
|
18
19
|
export { TableFormatter } from './tables.js';
|
|
19
20
|
export { OutputFormatter } from './output.js';
|
|
20
21
|
export { renderDetailView, } from './detail-view.js';
|