@wonderwhy-er/desktop-commander 0.2.2 → 0.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +27 -4
- package/dist/config-manager.d.ts +10 -0
- package/dist/config-manager.js +7 -1
- package/dist/handlers/edit-search-handlers.js +25 -6
- package/dist/handlers/filesystem-handlers.js +2 -4
- package/dist/handlers/terminal-handlers.d.ts +8 -4
- package/dist/handlers/terminal-handlers.js +16 -10
- package/dist/index-dxt.d.ts +2 -0
- package/dist/index-dxt.js +76 -0
- package/dist/index-with-startup-detection.d.ts +5 -0
- package/dist/index-with-startup-detection.js +180 -0
- package/dist/server.d.ts +5 -0
- package/dist/server.js +381 -65
- package/dist/terminal-manager.d.ts +7 -0
- package/dist/terminal-manager.js +93 -18
- package/dist/tools/client.d.ts +10 -0
- package/dist/tools/client.js +13 -0
- package/dist/tools/config.d.ts +1 -1
- package/dist/tools/config.js +21 -3
- package/dist/tools/edit.js +4 -3
- package/dist/tools/environment.d.ts +55 -0
- package/dist/tools/environment.js +65 -0
- package/dist/tools/feedback.d.ts +8 -0
- package/dist/tools/feedback.js +132 -0
- package/dist/tools/filesystem.d.ts +10 -0
- package/dist/tools/filesystem.js +410 -60
- package/dist/tools/improved-process-tools.d.ts +24 -0
- package/dist/tools/improved-process-tools.js +453 -0
- package/dist/tools/schemas.d.ts +20 -2
- package/dist/tools/schemas.js +20 -3
- package/dist/tools/usage.d.ts +5 -0
- package/dist/tools/usage.js +24 -0
- package/dist/utils/capture.d.ts +2 -0
- package/dist/utils/capture.js +40 -9
- package/dist/utils/early-logger.d.ts +4 -0
- package/dist/utils/early-logger.js +35 -0
- package/dist/utils/mcp-logger.d.ts +30 -0
- package/dist/utils/mcp-logger.js +59 -0
- package/dist/utils/process-detection.d.ts +23 -0
- package/dist/utils/process-detection.js +150 -0
- package/dist/utils/smithery-detector.d.ts +94 -0
- package/dist/utils/smithery-detector.js +292 -0
- package/dist/utils/startup-detector.d.ts +65 -0
- package/dist/utils/startup-detector.js +390 -0
- package/dist/utils/system-info.d.ts +30 -0
- package/dist/utils/system-info.js +146 -0
- package/dist/utils/usageTracker.d.ts +85 -0
- package/dist/utils/usageTracker.js +280 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +4 -1
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Production-Ready Startup Detection Module
|
|
3
|
+
*
|
|
4
|
+
* This module provides a lightweight, production-ready way to detect
|
|
5
|
+
* how a Node.js application was started. Perfect for logging, analytics,
|
|
6
|
+
* or conditional behavior based on startup method.
|
|
7
|
+
*/
|
|
8
|
+
export interface StartupInfo {
|
|
9
|
+
method: 'npm-run' | 'npx' | 'docker' | 'node-direct' | 'ci-cd' | 'smithery' | 'unknown';
|
|
10
|
+
confidence: number;
|
|
11
|
+
details: {
|
|
12
|
+
npmScript?: string;
|
|
13
|
+
ciPlatform?: string;
|
|
14
|
+
dockerContainer?: boolean;
|
|
15
|
+
smitheryClient?: string;
|
|
16
|
+
smitheryConnection?: string;
|
|
17
|
+
smitherySession?: string;
|
|
18
|
+
evidence: string[];
|
|
19
|
+
};
|
|
20
|
+
environment: 'development' | 'production' | 'ci' | 'container' | 'smithery' | 'unknown';
|
|
21
|
+
}
|
|
22
|
+
export declare class StartupDetector {
|
|
23
|
+
private static instance;
|
|
24
|
+
private _startupInfo;
|
|
25
|
+
private constructor();
|
|
26
|
+
static getInstance(): StartupDetector;
|
|
27
|
+
/**
|
|
28
|
+
* Get startup information (cached after first call)
|
|
29
|
+
*/
|
|
30
|
+
getStartupInfo(): StartupInfo;
|
|
31
|
+
/**
|
|
32
|
+
* Force re-detection (useful for testing)
|
|
33
|
+
*/
|
|
34
|
+
forceRedetect(): StartupInfo;
|
|
35
|
+
private detectStartupMethod;
|
|
36
|
+
private detectNpmRun;
|
|
37
|
+
private detectNpx;
|
|
38
|
+
private detectDocker;
|
|
39
|
+
private detectCiCd;
|
|
40
|
+
private detectDirectNode;
|
|
41
|
+
private detectSmithery;
|
|
42
|
+
private detectEnvironment;
|
|
43
|
+
/**
|
|
44
|
+
* Get a simple string representation of how the app was started
|
|
45
|
+
*/
|
|
46
|
+
getStartupMethodString(): string;
|
|
47
|
+
/**
|
|
48
|
+
* Check if running in a specific environment
|
|
49
|
+
*/
|
|
50
|
+
isEnvironment(env: StartupInfo['environment']): boolean;
|
|
51
|
+
/**
|
|
52
|
+
* Check if running via a specific method
|
|
53
|
+
*/
|
|
54
|
+
isMethod(method: StartupInfo['method']): boolean;
|
|
55
|
+
}
|
|
56
|
+
export declare const startupDetector: StartupDetector;
|
|
57
|
+
export declare const getStartupInfo: () => StartupInfo;
|
|
58
|
+
export declare const getStartupMethod: () => string;
|
|
59
|
+
export declare const isProduction: () => boolean;
|
|
60
|
+
export declare const isDevelopment: () => boolean;
|
|
61
|
+
export declare const isDocker: () => boolean;
|
|
62
|
+
export declare const isCi: () => boolean;
|
|
63
|
+
export declare const isSmithery: () => boolean;
|
|
64
|
+
export declare const getSmitheryClient: () => string | undefined;
|
|
65
|
+
export declare const getSmitheryConnection: () => string | undefined;
|
|
@@ -0,0 +1,390 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Production-Ready Startup Detection Module
|
|
3
|
+
*
|
|
4
|
+
* This module provides a lightweight, production-ready way to detect
|
|
5
|
+
* how a Node.js application was started. Perfect for logging, analytics,
|
|
6
|
+
* or conditional behavior based on startup method.
|
|
7
|
+
*/
|
|
8
|
+
import { readFileSync } from 'fs';
|
|
9
|
+
import { platform } from 'os';
|
|
10
|
+
export class StartupDetector {
|
|
11
|
+
constructor() {
|
|
12
|
+
this._startupInfo = null;
|
|
13
|
+
}
|
|
14
|
+
static getInstance() {
|
|
15
|
+
if (!StartupDetector.instance) {
|
|
16
|
+
StartupDetector.instance = new StartupDetector();
|
|
17
|
+
}
|
|
18
|
+
return StartupDetector.instance;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Get startup information (cached after first call)
|
|
22
|
+
*/
|
|
23
|
+
getStartupInfo() {
|
|
24
|
+
if (!this._startupInfo) {
|
|
25
|
+
this._startupInfo = this.detectStartupMethod();
|
|
26
|
+
}
|
|
27
|
+
return this._startupInfo;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Force re-detection (useful for testing)
|
|
31
|
+
*/
|
|
32
|
+
forceRedetect() {
|
|
33
|
+
this._startupInfo = this.detectStartupMethod();
|
|
34
|
+
return this._startupInfo;
|
|
35
|
+
}
|
|
36
|
+
detectStartupMethod() {
|
|
37
|
+
const detectors = [
|
|
38
|
+
this.detectSmithery.bind(this),
|
|
39
|
+
this.detectNpmRun.bind(this),
|
|
40
|
+
this.detectNpx.bind(this),
|
|
41
|
+
this.detectDocker.bind(this),
|
|
42
|
+
this.detectCiCd.bind(this),
|
|
43
|
+
this.detectDirectNode.bind(this)
|
|
44
|
+
];
|
|
45
|
+
const results = detectors.map(detector => detector()).filter(result => result !== null);
|
|
46
|
+
// Sort by confidence, highest first
|
|
47
|
+
results.sort((a, b) => b.confidence - a.confidence);
|
|
48
|
+
if (results.length === 0) {
|
|
49
|
+
return {
|
|
50
|
+
method: 'unknown',
|
|
51
|
+
confidence: 0,
|
|
52
|
+
details: { evidence: ['No detection method succeeded'] },
|
|
53
|
+
environment: 'unknown'
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
const topResult = results[0];
|
|
57
|
+
topResult.environment = this.detectEnvironment(topResult);
|
|
58
|
+
return topResult;
|
|
59
|
+
}
|
|
60
|
+
detectNpmRun() {
|
|
61
|
+
const evidence = [];
|
|
62
|
+
let confidence = 0;
|
|
63
|
+
// Primary indicator - npm_lifecycle_event is only set during npm run
|
|
64
|
+
if (process.env.npm_lifecycle_event) {
|
|
65
|
+
confidence += 50;
|
|
66
|
+
evidence.push(`npm script: ${process.env.npm_lifecycle_event}`);
|
|
67
|
+
// Additional confidence for npm script context
|
|
68
|
+
if (process.env.npm_lifecycle_script) {
|
|
69
|
+
confidence += 20;
|
|
70
|
+
}
|
|
71
|
+
return {
|
|
72
|
+
method: 'npm-run',
|
|
73
|
+
confidence,
|
|
74
|
+
details: {
|
|
75
|
+
npmScript: process.env.npm_lifecycle_event,
|
|
76
|
+
evidence
|
|
77
|
+
},
|
|
78
|
+
environment: 'unknown' // Will be set later
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
detectNpx() {
|
|
84
|
+
const evidence = [];
|
|
85
|
+
let confidence = 0;
|
|
86
|
+
// Check user agent for npx
|
|
87
|
+
const userAgent = process.env.npm_config_user_agent;
|
|
88
|
+
if (userAgent?.includes('npx')) {
|
|
89
|
+
confidence += 40;
|
|
90
|
+
evidence.push(`User agent indicates npx: ${userAgent}`);
|
|
91
|
+
}
|
|
92
|
+
// NPX specific environment variables
|
|
93
|
+
if (process.env.NPM_CLI_JS?.includes('npx')) {
|
|
94
|
+
confidence += 30;
|
|
95
|
+
evidence.push('NPM_CLI_JS indicates npx execution');
|
|
96
|
+
}
|
|
97
|
+
if (confidence > 0) {
|
|
98
|
+
return {
|
|
99
|
+
method: 'npx',
|
|
100
|
+
confidence,
|
|
101
|
+
details: { evidence },
|
|
102
|
+
environment: 'unknown'
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
detectDocker() {
|
|
108
|
+
const evidence = [];
|
|
109
|
+
let confidence = 0;
|
|
110
|
+
// Most reliable: Check for .dockerenv file
|
|
111
|
+
try {
|
|
112
|
+
readFileSync('/.dockerenv');
|
|
113
|
+
confidence += 70;
|
|
114
|
+
evidence.push('/.dockerenv file exists');
|
|
115
|
+
}
|
|
116
|
+
catch {
|
|
117
|
+
// Not in Docker
|
|
118
|
+
}
|
|
119
|
+
// Check container environment variable
|
|
120
|
+
if (process.env.container === 'docker' || process.env.container === 'podman') {
|
|
121
|
+
confidence += 50;
|
|
122
|
+
evidence.push(`Container type: ${process.env.container}`);
|
|
123
|
+
}
|
|
124
|
+
// Check for Docker-like hostname pattern
|
|
125
|
+
const hostname = process.env.HOSTNAME;
|
|
126
|
+
if (hostname && hostname.length === 12 && /^[a-f0-9]{12}$/.test(hostname)) {
|
|
127
|
+
confidence += 25;
|
|
128
|
+
evidence.push('Docker-style hostname detected');
|
|
129
|
+
}
|
|
130
|
+
// Linux-specific: Check cgroup
|
|
131
|
+
if (platform() === 'linux') {
|
|
132
|
+
try {
|
|
133
|
+
const cgroup = readFileSync('/proc/1/cgroup', 'utf8');
|
|
134
|
+
if (cgroup.includes('docker') || cgroup.includes('containerd')) {
|
|
135
|
+
confidence += 60;
|
|
136
|
+
evidence.push('Docker detected in cgroup');
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
catch {
|
|
140
|
+
// Ignore errors
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
if (confidence > 0) {
|
|
144
|
+
return {
|
|
145
|
+
method: 'docker',
|
|
146
|
+
confidence,
|
|
147
|
+
details: {
|
|
148
|
+
dockerContainer: true,
|
|
149
|
+
evidence
|
|
150
|
+
},
|
|
151
|
+
environment: 'unknown'
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
return null;
|
|
155
|
+
}
|
|
156
|
+
detectCiCd() {
|
|
157
|
+
const evidence = [];
|
|
158
|
+
let confidence = 0;
|
|
159
|
+
let ciPlatform;
|
|
160
|
+
const ciDetectors = {
|
|
161
|
+
'GitHub Actions': () => process.env.GITHUB_ACTIONS === 'true',
|
|
162
|
+
'GitLab CI': () => process.env.GITLAB_CI === 'true',
|
|
163
|
+
'Jenkins': () => !!process.env.JENKINS_URL,
|
|
164
|
+
'CircleCI': () => process.env.CIRCLECI === 'true',
|
|
165
|
+
'Travis CI': () => process.env.TRAVIS === 'true',
|
|
166
|
+
'Azure DevOps': () => process.env.TF_BUILD === 'True',
|
|
167
|
+
'Bamboo': () => !!process.env.bamboo_buildKey,
|
|
168
|
+
'TeamCity': () => !!process.env.TEAMCITY_VERSION
|
|
169
|
+
};
|
|
170
|
+
for (const [platform, detector] of Object.entries(ciDetectors)) {
|
|
171
|
+
if (detector()) {
|
|
172
|
+
ciPlatform = platform;
|
|
173
|
+
confidence += 60;
|
|
174
|
+
evidence.push(`${platform} environment detected`);
|
|
175
|
+
break;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
// Generic CI detection
|
|
179
|
+
if (!ciPlatform && (process.env.CI === 'true' || process.env.CI === '1')) {
|
|
180
|
+
confidence += 40;
|
|
181
|
+
evidence.push('Generic CI environment');
|
|
182
|
+
ciPlatform = 'Generic CI';
|
|
183
|
+
}
|
|
184
|
+
if (confidence > 0) {
|
|
185
|
+
return {
|
|
186
|
+
method: 'ci-cd',
|
|
187
|
+
confidence,
|
|
188
|
+
details: {
|
|
189
|
+
ciPlatform,
|
|
190
|
+
evidence
|
|
191
|
+
},
|
|
192
|
+
environment: 'unknown'
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
return null;
|
|
196
|
+
}
|
|
197
|
+
detectDirectNode() {
|
|
198
|
+
const evidence = [];
|
|
199
|
+
let confidence = 0;
|
|
200
|
+
// If no npm/npx indicators are present, likely direct node
|
|
201
|
+
if (!process.env.npm_lifecycle_event &&
|
|
202
|
+
!process.env.npm_config_user_agent &&
|
|
203
|
+
!process.env.npm_execpath) {
|
|
204
|
+
confidence += 30;
|
|
205
|
+
evidence.push('No package manager environment variables');
|
|
206
|
+
}
|
|
207
|
+
// This is more of a fallback, so lower confidence
|
|
208
|
+
if (confidence > 0) {
|
|
209
|
+
return {
|
|
210
|
+
method: 'node-direct',
|
|
211
|
+
confidence,
|
|
212
|
+
details: { evidence },
|
|
213
|
+
environment: 'unknown'
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
return null;
|
|
217
|
+
}
|
|
218
|
+
detectSmithery() {
|
|
219
|
+
const evidence = [];
|
|
220
|
+
let confidence = 0;
|
|
221
|
+
let smitheryClient;
|
|
222
|
+
let smitheryConnection;
|
|
223
|
+
let smitherySession;
|
|
224
|
+
// Check for Smithery-specific environment variables
|
|
225
|
+
const smitheryEnvVars = [
|
|
226
|
+
'SMITHERY_SESSION_ID',
|
|
227
|
+
'SMITHERY_CLIENT',
|
|
228
|
+
'SMITHERY_PROFILE',
|
|
229
|
+
'SMITHERY_ANALYTICS',
|
|
230
|
+
'SMITHERY_CONNECTION_TYPE',
|
|
231
|
+
'SMITHERY_QUALIFIED_NAME'
|
|
232
|
+
];
|
|
233
|
+
for (const envVar of smitheryEnvVars) {
|
|
234
|
+
if (process.env[envVar]) {
|
|
235
|
+
confidence += 40;
|
|
236
|
+
evidence.push(`Smithery environment variable: ${envVar}`);
|
|
237
|
+
// Extract specific details
|
|
238
|
+
switch (envVar) {
|
|
239
|
+
case 'SMITHERY_SESSION_ID':
|
|
240
|
+
smitherySession = process.env[envVar];
|
|
241
|
+
break;
|
|
242
|
+
case 'SMITHERY_CLIENT':
|
|
243
|
+
smitheryClient = process.env[envVar];
|
|
244
|
+
break;
|
|
245
|
+
case 'SMITHERY_CONNECTION_TYPE':
|
|
246
|
+
smitheryConnection = process.env[envVar];
|
|
247
|
+
break;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
// Check for Smithery endpoints
|
|
252
|
+
if (process.env.REGISTRY_ENDPOINT?.includes('smithery')) {
|
|
253
|
+
confidence += 30;
|
|
254
|
+
evidence.push('Smithery registry endpoint detected');
|
|
255
|
+
}
|
|
256
|
+
if (process.env.ANALYTICS_ENDPOINT?.includes('smithery')) {
|
|
257
|
+
confidence += 25;
|
|
258
|
+
evidence.push('Smithery analytics endpoint detected');
|
|
259
|
+
}
|
|
260
|
+
// Check process arguments for Smithery patterns
|
|
261
|
+
const args = process.argv.join(' ');
|
|
262
|
+
const smitheryPatterns = [
|
|
263
|
+
/smithery[\s\/\\]cli/i,
|
|
264
|
+
/@smithery[\s\/\\]cli/i,
|
|
265
|
+
/npx.*@smithery/i,
|
|
266
|
+
/smithery.*run/i
|
|
267
|
+
];
|
|
268
|
+
for (const pattern of smitheryPatterns) {
|
|
269
|
+
if (pattern.test(args)) {
|
|
270
|
+
confidence += 35;
|
|
271
|
+
evidence.push('Smithery CLI pattern in arguments');
|
|
272
|
+
break;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
// Check for UUID v7 session pattern (Smithery uses uuidv7)
|
|
276
|
+
const envVars = Object.keys(process.env);
|
|
277
|
+
for (const key of envVars) {
|
|
278
|
+
const value = process.env[key] || '';
|
|
279
|
+
if (/^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(value)) {
|
|
280
|
+
confidence += 25;
|
|
281
|
+
evidence.push('UUID v7 session ID pattern detected');
|
|
282
|
+
if (!smitherySession)
|
|
283
|
+
smitherySession = value;
|
|
284
|
+
break;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
if (confidence > 0) {
|
|
288
|
+
return {
|
|
289
|
+
method: 'smithery',
|
|
290
|
+
confidence,
|
|
291
|
+
details: {
|
|
292
|
+
smitheryClient,
|
|
293
|
+
smitheryConnection,
|
|
294
|
+
smitherySession,
|
|
295
|
+
evidence
|
|
296
|
+
},
|
|
297
|
+
environment: 'unknown'
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
return null;
|
|
301
|
+
}
|
|
302
|
+
detectEnvironment(startupInfo) {
|
|
303
|
+
// Smithery is always considered smithery environment
|
|
304
|
+
if (startupInfo.method === 'smithery') {
|
|
305
|
+
return 'smithery';
|
|
306
|
+
}
|
|
307
|
+
// Docker containers are usually production or CI
|
|
308
|
+
if (startupInfo.method === 'docker') {
|
|
309
|
+
// Check if it's also CI
|
|
310
|
+
if (process.env.CI === 'true' || process.env.CI === '1') {
|
|
311
|
+
return 'ci';
|
|
312
|
+
}
|
|
313
|
+
return 'container';
|
|
314
|
+
}
|
|
315
|
+
// Check NODE_ENV
|
|
316
|
+
const nodeEnv = process.env.NODE_ENV?.toLowerCase();
|
|
317
|
+
if (nodeEnv === 'production')
|
|
318
|
+
return 'production';
|
|
319
|
+
if (nodeEnv === 'development')
|
|
320
|
+
return 'development';
|
|
321
|
+
// NPM scripts often indicate development
|
|
322
|
+
if (startupInfo.method === 'npm-run') {
|
|
323
|
+
const script = startupInfo.details.npmScript;
|
|
324
|
+
if (script?.includes('dev') || script?.includes('start')) {
|
|
325
|
+
return 'development';
|
|
326
|
+
}
|
|
327
|
+
if (script?.includes('prod') || script?.includes('build')) {
|
|
328
|
+
return 'production';
|
|
329
|
+
}
|
|
330
|
+
return 'development'; // Default for npm scripts
|
|
331
|
+
}
|
|
332
|
+
// NPX is often used for one-off tools in development
|
|
333
|
+
if (startupInfo.method === 'npx') {
|
|
334
|
+
return 'development';
|
|
335
|
+
}
|
|
336
|
+
return 'unknown';
|
|
337
|
+
}
|
|
338
|
+
/**
|
|
339
|
+
* Get a simple string representation of how the app was started
|
|
340
|
+
*/
|
|
341
|
+
getStartupMethodString() {
|
|
342
|
+
const info = this.getStartupInfo();
|
|
343
|
+
switch (info.method) {
|
|
344
|
+
case 'npm-run':
|
|
345
|
+
return `npm run ${info.details.npmScript || 'script'}`;
|
|
346
|
+
case 'npx':
|
|
347
|
+
return 'npx';
|
|
348
|
+
case 'docker':
|
|
349
|
+
return 'Docker container';
|
|
350
|
+
case 'ci-cd':
|
|
351
|
+
return info.details.ciPlatform || 'CI/CD';
|
|
352
|
+
case 'smithery':
|
|
353
|
+
return `Smithery CLI${info.details.smitheryClient ? ` (${info.details.smitheryClient})` : ''}`;
|
|
354
|
+
case 'node-direct':
|
|
355
|
+
return 'node (direct)';
|
|
356
|
+
default:
|
|
357
|
+
return 'unknown';
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
/**
|
|
361
|
+
* Check if running in a specific environment
|
|
362
|
+
*/
|
|
363
|
+
isEnvironment(env) {
|
|
364
|
+
return this.getStartupInfo().environment === env;
|
|
365
|
+
}
|
|
366
|
+
/**
|
|
367
|
+
* Check if running via a specific method
|
|
368
|
+
*/
|
|
369
|
+
isMethod(method) {
|
|
370
|
+
return this.getStartupInfo().method === method;
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
// Singleton instance
|
|
374
|
+
export const startupDetector = StartupDetector.getInstance();
|
|
375
|
+
// Convenience functions
|
|
376
|
+
export const getStartupInfo = () => startupDetector.getStartupInfo();
|
|
377
|
+
export const getStartupMethod = () => startupDetector.getStartupMethodString();
|
|
378
|
+
export const isProduction = () => startupDetector.isEnvironment('production');
|
|
379
|
+
export const isDevelopment = () => startupDetector.isEnvironment('development');
|
|
380
|
+
export const isDocker = () => startupDetector.isMethod('docker');
|
|
381
|
+
export const isCi = () => startupDetector.isEnvironment('ci');
|
|
382
|
+
export const isSmithery = () => startupDetector.isMethod('smithery');
|
|
383
|
+
export const getSmitheryClient = () => {
|
|
384
|
+
const info = startupDetector.getStartupInfo();
|
|
385
|
+
return info.method === 'smithery' ? info.details.smitheryClient : undefined;
|
|
386
|
+
};
|
|
387
|
+
export const getSmitheryConnection = () => {
|
|
388
|
+
const info = startupDetector.getStartupInfo();
|
|
389
|
+
return info.method === 'smithery' ? info.details.smitheryConnection : undefined;
|
|
390
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export interface SystemInfo {
|
|
2
|
+
platform: string;
|
|
3
|
+
platformName: string;
|
|
4
|
+
defaultShell: string;
|
|
5
|
+
pathSeparator: string;
|
|
6
|
+
isWindows: boolean;
|
|
7
|
+
isMacOS: boolean;
|
|
8
|
+
isLinux: boolean;
|
|
9
|
+
examplePaths: {
|
|
10
|
+
home: string;
|
|
11
|
+
temp: string;
|
|
12
|
+
absolute: string;
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Get comprehensive system information for tool prompts
|
|
17
|
+
*/
|
|
18
|
+
export declare function getSystemInfo(): SystemInfo;
|
|
19
|
+
/**
|
|
20
|
+
* Generate OS-specific guidance for tool prompts
|
|
21
|
+
*/
|
|
22
|
+
export declare function getOSSpecificGuidance(systemInfo: SystemInfo): string;
|
|
23
|
+
/**
|
|
24
|
+
* Get common development tool guidance based on OS
|
|
25
|
+
*/
|
|
26
|
+
export declare function getDevelopmentToolGuidance(systemInfo: SystemInfo): string;
|
|
27
|
+
/**
|
|
28
|
+
* Get path guidance (simplified since paths are normalized)
|
|
29
|
+
*/
|
|
30
|
+
export declare function getPathGuidance(systemInfo: SystemInfo): string;
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import os from 'os';
|
|
2
|
+
/**
|
|
3
|
+
* Get comprehensive system information for tool prompts
|
|
4
|
+
*/
|
|
5
|
+
export function getSystemInfo() {
|
|
6
|
+
const platform = os.platform();
|
|
7
|
+
const isWindows = platform === 'win32';
|
|
8
|
+
const isMacOS = platform === 'darwin';
|
|
9
|
+
const isLinux = platform === 'linux';
|
|
10
|
+
let platformName;
|
|
11
|
+
let defaultShell;
|
|
12
|
+
let pathSeparator;
|
|
13
|
+
let examplePaths;
|
|
14
|
+
if (isWindows) {
|
|
15
|
+
platformName = 'Windows';
|
|
16
|
+
defaultShell = 'powershell.exe';
|
|
17
|
+
pathSeparator = '\\';
|
|
18
|
+
examplePaths = {
|
|
19
|
+
home: 'C:\\Users\\username',
|
|
20
|
+
temp: 'C:\\Temp',
|
|
21
|
+
absolute: 'C:\\path\\to\\file.txt'
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
else if (isMacOS) {
|
|
25
|
+
platformName = 'macOS';
|
|
26
|
+
defaultShell = 'zsh';
|
|
27
|
+
pathSeparator = '/';
|
|
28
|
+
examplePaths = {
|
|
29
|
+
home: '/Users/username',
|
|
30
|
+
temp: '/tmp',
|
|
31
|
+
absolute: '/path/to/file.txt'
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
else if (isLinux) {
|
|
35
|
+
platformName = 'Linux';
|
|
36
|
+
defaultShell = 'bash';
|
|
37
|
+
pathSeparator = '/';
|
|
38
|
+
examplePaths = {
|
|
39
|
+
home: '/home/username',
|
|
40
|
+
temp: '/tmp',
|
|
41
|
+
absolute: '/path/to/file.txt'
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
// Fallback for other Unix-like systems
|
|
46
|
+
platformName = 'Unix';
|
|
47
|
+
defaultShell = 'bash';
|
|
48
|
+
pathSeparator = '/';
|
|
49
|
+
examplePaths = {
|
|
50
|
+
home: '/home/username',
|
|
51
|
+
temp: '/tmp',
|
|
52
|
+
absolute: '/path/to/file.txt'
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
return {
|
|
56
|
+
platform,
|
|
57
|
+
platformName,
|
|
58
|
+
defaultShell,
|
|
59
|
+
pathSeparator,
|
|
60
|
+
isWindows,
|
|
61
|
+
isMacOS,
|
|
62
|
+
isLinux,
|
|
63
|
+
examplePaths
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Generate OS-specific guidance for tool prompts
|
|
68
|
+
*/
|
|
69
|
+
export function getOSSpecificGuidance(systemInfo) {
|
|
70
|
+
const { platformName, defaultShell, isWindows } = systemInfo;
|
|
71
|
+
let guidance = `Running on ${platformName}. Default shell: ${defaultShell}.`;
|
|
72
|
+
if (isWindows) {
|
|
73
|
+
guidance += `
|
|
74
|
+
|
|
75
|
+
WINDOWS-SPECIFIC TROUBLESHOOTING:
|
|
76
|
+
- If Node.js/Python commands fail with "not recognized" errors:
|
|
77
|
+
* Try different shells: specify shell parameter as "cmd" or "powershell.exe"
|
|
78
|
+
* PowerShell may have execution policy restrictions for some tools
|
|
79
|
+
* CMD typically has better compatibility with development tools
|
|
80
|
+
* Use set_config_value to change defaultShell if needed
|
|
81
|
+
- Windows services and processes use different commands (Get-Process vs ps)
|
|
82
|
+
- Package managers: choco, winget, scoop instead of apt/brew
|
|
83
|
+
- Environment variables: $env:VAR instead of $VAR
|
|
84
|
+
- File permissions work differently than Unix systems`;
|
|
85
|
+
}
|
|
86
|
+
else if (systemInfo.isMacOS) {
|
|
87
|
+
guidance += `
|
|
88
|
+
|
|
89
|
+
MACOS-SPECIFIC NOTES:
|
|
90
|
+
- Package manager: brew (Homebrew) is commonly used
|
|
91
|
+
- Python 3 might be 'python3' command, not 'python'
|
|
92
|
+
- Some GNU tools have different names (e.g., gsed instead of sed)
|
|
93
|
+
- System Integrity Protection (SIP) may block certain operations
|
|
94
|
+
- Use 'open' command to open files/applications from terminal`;
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
guidance += `
|
|
98
|
+
|
|
99
|
+
LINUX-SPECIFIC NOTES:
|
|
100
|
+
- Package managers vary by distro: apt, yum, dnf, pacman, zypper
|
|
101
|
+
- Python 3 might be 'python3' command, not 'python'
|
|
102
|
+
- Standard Unix shell tools available (grep, awk, sed, etc.)
|
|
103
|
+
- File permissions and ownership important for many operations
|
|
104
|
+
- Systemd services common on modern distributions`;
|
|
105
|
+
}
|
|
106
|
+
return guidance;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Get common development tool guidance based on OS
|
|
110
|
+
*/
|
|
111
|
+
export function getDevelopmentToolGuidance(systemInfo) {
|
|
112
|
+
const { isWindows, isMacOS, isLinux, platformName } = systemInfo;
|
|
113
|
+
if (isWindows) {
|
|
114
|
+
return `
|
|
115
|
+
COMMON WINDOWS DEVELOPMENT TOOLS:
|
|
116
|
+
- Node.js: Usually installed globally, accessible from any shell
|
|
117
|
+
- Python: May be 'python' or 'py' command, check both
|
|
118
|
+
- Git: Git Bash provides Unix-like environment
|
|
119
|
+
- WSL: Windows Subsystem for Linux available for Unix tools
|
|
120
|
+
- Visual Studio tools: cl, msbuild for C++ compilation`;
|
|
121
|
+
}
|
|
122
|
+
else if (isMacOS) {
|
|
123
|
+
return `
|
|
124
|
+
COMMON MACOS DEVELOPMENT TOOLS:
|
|
125
|
+
- Xcode Command Line Tools: Required for many development tools
|
|
126
|
+
- Homebrew: Primary package manager for development tools
|
|
127
|
+
- Python: Usually python3, check if python points to Python 2
|
|
128
|
+
- Node.js: Available via brew or direct installer
|
|
129
|
+
- Ruby: System Ruby available, rbenv/rvm for version management`;
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
132
|
+
return `
|
|
133
|
+
COMMON LINUX DEVELOPMENT TOOLS:
|
|
134
|
+
- Package managers: Install tools via distribution package manager
|
|
135
|
+
- Python: Usually python3, python may point to Python 2
|
|
136
|
+
- Node.js: Available via package manager or NodeSource repository
|
|
137
|
+
- Build tools: gcc, make typically available or easily installed
|
|
138
|
+
- Container tools: docker, podman common for development`;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Get path guidance (simplified since paths are normalized)
|
|
143
|
+
*/
|
|
144
|
+
export function getPathGuidance(systemInfo) {
|
|
145
|
+
return `Always use absolute paths for reliability. Paths are automatically normalized regardless of slash direction.`;
|
|
146
|
+
}
|