@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.
Files changed (96) hide show
  1. package/dist/src/application/ports/output/services/index.d.ts +1 -0
  2. package/dist/src/application/ports/output/services/index.d.ts.map +1 -1
  3. package/dist/src/application/ports/output/services/tool-installer.service.d.ts +35 -0
  4. package/dist/src/application/ports/output/services/tool-installer.service.d.ts.map +1 -0
  5. package/dist/src/application/ports/output/services/tool-installer.service.js +7 -0
  6. package/dist/src/application/use-cases/tools/install-tool.use-case.d.ts +21 -0
  7. package/dist/src/application/use-cases/tools/install-tool.use-case.d.ts.map +1 -0
  8. package/dist/src/application/use-cases/tools/install-tool.use-case.js +41 -0
  9. package/dist/src/application/use-cases/tools/validate-tool-availability.use-case.d.ts +20 -0
  10. package/dist/src/application/use-cases/tools/validate-tool-availability.use-case.d.ts.map +1 -0
  11. package/dist/src/application/use-cases/tools/validate-tool-availability.use-case.js +40 -0
  12. package/dist/src/domain/generated/output.d.ts +97 -0
  13. package/dist/src/domain/generated/output.d.ts.map +1 -1
  14. package/dist/src/domain/generated/output.js +10 -0
  15. package/dist/src/domain/value-objects/index.d.ts +2 -0
  16. package/dist/src/domain/value-objects/index.d.ts.map +1 -1
  17. package/dist/src/domain/value-objects/index.js +1 -0
  18. package/dist/src/domain/value-objects/tool-installation-status.d.ts +70 -0
  19. package/dist/src/domain/value-objects/tool-installation-status.d.ts.map +1 -0
  20. package/dist/src/domain/value-objects/tool-installation-status.js +111 -0
  21. package/dist/src/infrastructure/di/container.d.ts.map +1 -1
  22. package/dist/src/infrastructure/di/container.js +6 -0
  23. package/dist/src/infrastructure/services/tool-installer/tool-installer.service.d.ts +36 -0
  24. package/dist/src/infrastructure/services/tool-installer/tool-installer.service.d.ts.map +1 -0
  25. package/dist/src/infrastructure/services/tool-installer/tool-installer.service.js +179 -0
  26. package/dist/src/infrastructure/services/tool-installer/tool-metadata.d.ts +37 -0
  27. package/dist/src/infrastructure/services/tool-installer/tool-metadata.d.ts.map +1 -0
  28. package/dist/src/infrastructure/services/tool-installer/tool-metadata.js +52 -0
  29. package/dist/src/infrastructure/services/tool-installer/tools/antigravity.json +20 -0
  30. package/dist/src/infrastructure/services/tool-installer/tools/claude-code.json +16 -0
  31. package/dist/src/infrastructure/services/tool-installer/tools/cursor-cli.json +16 -0
  32. package/dist/src/infrastructure/services/tool-installer/tools/cursor.json +17 -0
  33. package/dist/src/infrastructure/services/tool-installer/tools/vscode.json +17 -0
  34. package/dist/src/infrastructure/services/tool-installer/tools/windsurf.json +17 -0
  35. package/dist/src/infrastructure/services/tool-installer/tools/zed.json +17 -0
  36. package/dist/src/presentation/cli/commands/install.command.d.ts +14 -0
  37. package/dist/src/presentation/cli/commands/install.command.d.ts.map +1 -0
  38. package/dist/src/presentation/cli/commands/install.command.js +134 -0
  39. package/dist/src/presentation/cli/index.js +2 -0
  40. package/dist/src/presentation/cli/ui/index.d.ts +1 -0
  41. package/dist/src/presentation/cli/ui/index.d.ts.map +1 -1
  42. package/dist/src/presentation/cli/ui/index.js +1 -0
  43. package/dist/src/presentation/cli/ui/install-messages.d.ts +23 -0
  44. package/dist/src/presentation/cli/ui/install-messages.d.ts.map +1 -0
  45. package/dist/src/presentation/cli/ui/install-messages.js +36 -0
  46. package/dist/tsconfig.build.tsbuildinfo +1 -1
  47. package/package.json +2 -2
  48. package/web/.next/BUILD_ID +1 -1
  49. package/web/.next/build-manifest.json +2 -2
  50. package/web/.next/cache/.previewinfo +1 -1
  51. package/web/.next/cache/.rscinfo +1 -1
  52. package/web/.next/cache/config.json +3 -3
  53. package/web/.next/fallback-build-manifest.json +2 -2
  54. package/web/.next/prerender-manifest.json +3 -3
  55. package/web/.next/required-server-files.js +1 -1
  56. package/web/.next/required-server-files.json +1 -1
  57. package/web/.next/server/app/_global-error.html +2 -2
  58. package/web/.next/server/app/_global-error.rsc +1 -1
  59. package/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  60. package/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  61. package/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  62. package/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  63. package/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  64. package/web/.next/server/app/_not-found.html +2 -2
  65. package/web/.next/server/app/_not-found.rsc +1 -1
  66. package/web/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  67. package/web/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  68. package/web/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  69. package/web/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  70. package/web/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  71. package/web/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  72. package/web/.next/server/app/index.html +2 -2
  73. package/web/.next/server/app/index.rsc +1 -1
  74. package/web/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  75. package/web/.next/server/app/index.segments/_full.segment.rsc +1 -1
  76. package/web/.next/server/app/index.segments/_head.segment.rsc +1 -1
  77. package/web/.next/server/app/index.segments/_index.segment.rsc +1 -1
  78. package/web/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  79. package/web/.next/server/app/version.html +2 -2
  80. package/web/.next/server/app/version.rsc +1 -1
  81. package/web/.next/server/app/version.segments/_full.segment.rsc +1 -1
  82. package/web/.next/server/app/version.segments/_head.segment.rsc +1 -1
  83. package/web/.next/server/app/version.segments/_index.segment.rsc +1 -1
  84. package/web/.next/server/app/version.segments/_tree.segment.rsc +1 -1
  85. package/web/.next/server/app/version.segments/version/__PAGE__.segment.rsc +1 -1
  86. package/web/.next/server/app/version.segments/version.segment.rsc +1 -1
  87. package/web/.next/server/chunks/ssr/_19be0743._.js +1 -1
  88. package/web/.next/server/pages/404.html +2 -2
  89. package/web/.next/server/pages/500.html +2 -2
  90. package/web/.next/server/server-reference-manifest.js +1 -1
  91. package/web/.next/server/server-reference-manifest.json +1 -1
  92. package/web/.next/trace +1 -1
  93. package/web/.next/trace-build +1 -1
  94. /package/web/.next/static/{xKJulVMYO_ZRGoqa6eM7G → 64iQn2RbdM-TFYWmABhXw}/_buildManifest.js +0 -0
  95. /package/web/.next/static/{xKJulVMYO_ZRGoqa6eM7G → 64iQn2RbdM-TFYWmABhXw}/_clientMiddlewareManifest.json +0 -0
  96. /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';