local-serverless-stack 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/CHANGELOG.md +104 -0
  2. package/LICENSE +21 -0
  3. package/README.md +653 -0
  4. package/bin/cli.js +204 -0
  5. package/dist/server/dev/dynamo-proxy.d.ts +3 -0
  6. package/dist/server/dev/dynamo-proxy.d.ts.map +1 -0
  7. package/dist/server/dev/dynamo-proxy.js +35 -0
  8. package/dist/server/dev/dynamo-proxy.js.map +1 -0
  9. package/dist/server/index.d.ts +2 -0
  10. package/dist/server/index.d.ts.map +1 -0
  11. package/dist/server/index.js +67 -0
  12. package/dist/server/index.js.map +1 -0
  13. package/dist/server/routes/resources.d.ts +3 -0
  14. package/dist/server/routes/resources.d.ts.map +1 -0
  15. package/dist/server/routes/resources.js +16 -0
  16. package/dist/server/routes/resources.js.map +1 -0
  17. package/dist/server/routes/services.d.ts +5 -0
  18. package/dist/server/routes/services.d.ts.map +1 -0
  19. package/dist/server/routes/services.js +217 -0
  20. package/dist/server/routes/services.js.map +1 -0
  21. package/dist/server/services/cache-manager.d.ts +21 -0
  22. package/dist/server/services/cache-manager.d.ts.map +1 -0
  23. package/dist/server/services/cache-manager.js +70 -0
  24. package/dist/server/services/cache-manager.js.map +1 -0
  25. package/dist/server/services/cloudformation-parser.d.ts +88 -0
  26. package/dist/server/services/cloudformation-parser.d.ts.map +1 -0
  27. package/dist/server/services/cloudformation-parser.js +112 -0
  28. package/dist/server/services/cloudformation-parser.js.map +1 -0
  29. package/dist/server/services/localstack-manager.d.ts +23 -0
  30. package/dist/server/services/localstack-manager.d.ts.map +1 -0
  31. package/dist/server/services/localstack-manager.js +142 -0
  32. package/dist/server/services/localstack-manager.js.map +1 -0
  33. package/dist/server/services/process-manager.d.ts +41 -0
  34. package/dist/server/services/process-manager.d.ts.map +1 -0
  35. package/dist/server/services/process-manager.js +119 -0
  36. package/dist/server/services/process-manager.js.map +1 -0
  37. package/dist/server/services/resource-provisioner.d.ts +37 -0
  38. package/dist/server/services/resource-provisioner.d.ts.map +1 -0
  39. package/dist/server/services/resource-provisioner.js +539 -0
  40. package/dist/server/services/resource-provisioner.js.map +1 -0
  41. package/dist/ui/assets/index-7WT0rkfU.css +1 -0
  42. package/dist/ui/assets/index-M0lXeUj-.js +19 -0
  43. package/dist/ui/index.html +16 -0
  44. package/package.json +89 -0
  45. package/packages/serverless-plugin/README.md +95 -0
  46. package/packages/serverless-plugin/dist/index.d.ts +2 -0
  47. package/packages/serverless-plugin/dist/index.d.ts.map +1 -0
  48. package/packages/serverless-plugin/dist/index.js +88 -0
  49. package/packages/serverless-plugin/dist/index.js.map +1 -0
@@ -0,0 +1,70 @@
1
+ import fs from 'fs/promises';
2
+ import path from 'path';
3
+ import os from 'os';
4
+ export class CacheManager {
5
+ cacheDir;
6
+ constructor() {
7
+ this.cacheDir = path.join(os.homedir(), '.lss', 'orchestrator', 'cache');
8
+ }
9
+ async init() {
10
+ await fs.mkdir(this.cacheDir, { recursive: true });
11
+ }
12
+ async saveTemplate(serviceName, template, metadata) {
13
+ const serviceDir = path.join(this.cacheDir, serviceName);
14
+ await fs.mkdir(serviceDir, { recursive: true });
15
+ // Save template
16
+ await fs.writeFile(path.join(serviceDir, 'cloudformation-template.json'), JSON.stringify(template, null, 2));
17
+ // Save metadata
18
+ await fs.writeFile(path.join(serviceDir, 'metadata.json'), JSON.stringify({ name: serviceName, ...metadata }, null, 2));
19
+ }
20
+ async getTemplate(serviceName) {
21
+ try {
22
+ const templatePath = path.join(this.cacheDir, serviceName, 'cloudformation-template.json');
23
+ const content = await fs.readFile(templatePath, 'utf-8');
24
+ return JSON.parse(content);
25
+ }
26
+ catch {
27
+ return null;
28
+ }
29
+ }
30
+ async getMetadata(serviceName) {
31
+ try {
32
+ const metadataPath = path.join(this.cacheDir, serviceName, 'metadata.json');
33
+ const content = await fs.readFile(metadataPath, 'utf-8');
34
+ return JSON.parse(content);
35
+ }
36
+ catch {
37
+ return null;
38
+ }
39
+ }
40
+ async updateMetadata(serviceName, updates) {
41
+ const metadata = await this.getMetadata(serviceName);
42
+ if (!metadata) {
43
+ throw new Error(`Service ${serviceName} not found in cache`);
44
+ }
45
+ await fs.writeFile(path.join(this.cacheDir, serviceName, 'metadata.json'), JSON.stringify({ ...metadata, ...updates }, null, 2));
46
+ }
47
+ async listServices() {
48
+ try {
49
+ const entries = await fs.readdir(this.cacheDir, { withFileTypes: true });
50
+ const services = [];
51
+ for (const entry of entries) {
52
+ if (entry.isDirectory()) {
53
+ const metadata = await this.getMetadata(entry.name);
54
+ if (metadata) {
55
+ services.push(metadata);
56
+ }
57
+ }
58
+ }
59
+ return services;
60
+ }
61
+ catch {
62
+ return [];
63
+ }
64
+ }
65
+ async deleteService(serviceName) {
66
+ const serviceDir = path.join(this.cacheDir, serviceName);
67
+ await fs.rm(serviceDir, { recursive: true, force: true });
68
+ }
69
+ }
70
+ //# sourceMappingURL=cache-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache-manager.js","sourceRoot":"","sources":["../../../src/server/services/cache-manager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,88 @@
1
+ interface CloudFormationTemplate {
2
+ Resources: Record<string, CloudFormationResource>;
3
+ [key: string]: unknown;
4
+ }
5
+ interface CloudFormationResource {
6
+ Type: string;
7
+ Properties?: Record<string, unknown>;
8
+ [key: string]: unknown;
9
+ }
10
+ export interface LambdaResource {
11
+ type: 'lambda';
12
+ name: string;
13
+ handler: string;
14
+ runtime: string;
15
+ environment: Record<string, string>;
16
+ memorySize: number;
17
+ timeout: number;
18
+ }
19
+ export interface DynamoDBResource {
20
+ type: 'dynamodb';
21
+ name: string;
22
+ keySchema: Array<{
23
+ AttributeName: string;
24
+ KeyType: string;
25
+ }>;
26
+ attributeDefinitions: Array<{
27
+ AttributeName: string;
28
+ AttributeType: string;
29
+ }>;
30
+ billingMode?: string;
31
+ streamEnabled?: boolean;
32
+ globalSecondaryIndexes?: Array<{
33
+ IndexName: string;
34
+ KeySchema: Array<{
35
+ AttributeName: string;
36
+ KeyType: string;
37
+ }>;
38
+ Projection: {
39
+ ProjectionType: string;
40
+ };
41
+ [key: string]: unknown;
42
+ }>;
43
+ localSecondaryIndexes?: Array<{
44
+ IndexName: string;
45
+ KeySchema: Array<{
46
+ AttributeName: string;
47
+ KeyType: string;
48
+ }>;
49
+ Projection: {
50
+ ProjectionType: string;
51
+ };
52
+ [key: string]: unknown;
53
+ }>;
54
+ }
55
+ export interface SQSResource {
56
+ type: 'sqs';
57
+ name: string;
58
+ visibilityTimeout?: number;
59
+ messageRetentionPeriod?: number;
60
+ fifoQueue?: boolean;
61
+ contentBasedDeduplication?: boolean;
62
+ }
63
+ export interface SNSResource {
64
+ type: 'sns';
65
+ name: string;
66
+ }
67
+ export interface EventSourceMapping {
68
+ type: 'event-source';
69
+ functionName: string;
70
+ eventSourceArn: string;
71
+ batchSize?: number;
72
+ enabled: boolean;
73
+ }
74
+ export type Resource = LambdaResource | DynamoDBResource | SQSResource | SNSResource | EventSourceMapping;
75
+ export declare class CloudFormationParser {
76
+ parse(template: CloudFormationTemplate): Resource[];
77
+ private parseResource;
78
+ private parseLambda;
79
+ private parseDynamoDB;
80
+ private parseSQS;
81
+ private parseSNS;
82
+ private parseEventSource;
83
+ private extractFunctionName;
84
+ private extractArn;
85
+ calculateHash(template: CloudFormationTemplate): string;
86
+ }
87
+ export {};
88
+ //# sourceMappingURL=cloudformation-parser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cloudformation-parser.d.ts","sourceRoot":"","sources":["../../../src/server/services/cloudformation-parser.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,112 @@
1
+ import crypto from 'crypto';
2
+ export class CloudFormationParser {
3
+ parse(template) {
4
+ const resources = [];
5
+ if (!template.Resources) {
6
+ return resources;
7
+ }
8
+ for (const [key, resource] of Object.entries(template.Resources)) {
9
+ const parsed = this.parseResource(key, resource);
10
+ if (parsed) {
11
+ resources.push(parsed);
12
+ }
13
+ }
14
+ return resources;
15
+ }
16
+ parseResource(key, resource) {
17
+ switch (resource.Type) {
18
+ case 'AWS::Lambda::Function':
19
+ return this.parseLambda(key, resource);
20
+ case 'AWS::DynamoDB::Table':
21
+ return this.parseDynamoDB(key, resource);
22
+ case 'AWS::SQS::Queue':
23
+ return this.parseSQS(key, resource);
24
+ case 'AWS::SNS::Topic':
25
+ return this.parseSNS(key, resource);
26
+ case 'AWS::Lambda::EventSourceMapping':
27
+ return this.parseEventSource(key, resource);
28
+ default:
29
+ return null;
30
+ }
31
+ }
32
+ parseLambda(key, resource) {
33
+ const props = (resource.Properties || {});
34
+ return {
35
+ type: 'lambda',
36
+ name: props.FunctionName || key,
37
+ handler: props.Handler || '',
38
+ runtime: props.Runtime || 'nodejs20.x',
39
+ environment: (props.Environment?.Variables) || {},
40
+ memorySize: props.MemorySize || 128,
41
+ timeout: props.Timeout || 30,
42
+ };
43
+ }
44
+ parseDynamoDB(key, resource) {
45
+ const props = (resource.Properties || {});
46
+ return {
47
+ type: 'dynamodb',
48
+ name: props.TableName || key,
49
+ keySchema: props.KeySchema || [],
50
+ attributeDefinitions: props.AttributeDefinitions || [],
51
+ billingMode: props.BillingMode,
52
+ streamEnabled: (props.StreamSpecification?.StreamEnabled) || false,
53
+ globalSecondaryIndexes: props.GlobalSecondaryIndexes,
54
+ localSecondaryIndexes: props.LocalSecondaryIndexes,
55
+ };
56
+ }
57
+ parseSQS(key, resource) {
58
+ const props = (resource.Properties || {});
59
+ return {
60
+ type: 'sqs',
61
+ name: props.QueueName || key,
62
+ visibilityTimeout: props.VisibilityTimeout,
63
+ messageRetentionPeriod: props.MessageRetentionPeriod,
64
+ fifoQueue: props.FifoQueue,
65
+ contentBasedDeduplication: props.ContentBasedDeduplication,
66
+ };
67
+ }
68
+ parseSNS(key, resource) {
69
+ const props = (resource.Properties || {});
70
+ return {
71
+ type: 'sns',
72
+ name: props.TopicName || key,
73
+ };
74
+ }
75
+ parseEventSource(_key, resource) {
76
+ const props = (resource.Properties || {});
77
+ return {
78
+ type: 'event-source',
79
+ functionName: this.extractFunctionName(props.FunctionName),
80
+ eventSourceArn: this.extractArn(props.EventSourceArn),
81
+ batchSize: props.BatchSize,
82
+ enabled: props.Enabled !== false,
83
+ };
84
+ }
85
+ extractFunctionName(ref) {
86
+ if (typeof ref === 'string')
87
+ return ref;
88
+ if (ref && typeof ref === 'object') {
89
+ const obj = ref;
90
+ if ('Ref' in obj)
91
+ return obj.Ref;
92
+ if ('Fn::GetAtt' in obj)
93
+ return obj['Fn::GetAtt'][0];
94
+ }
95
+ return '';
96
+ }
97
+ extractArn(ref) {
98
+ if (typeof ref === 'string')
99
+ return ref;
100
+ if (ref && typeof ref === 'object') {
101
+ const obj = ref;
102
+ if ('Fn::GetAtt' in obj)
103
+ return obj['Fn::GetAtt'].join('::');
104
+ }
105
+ return '';
106
+ }
107
+ calculateHash(template) {
108
+ const content = JSON.stringify(template);
109
+ return crypto.createHash('sha256').update(content).digest('hex');
110
+ }
111
+ }
112
+ //# sourceMappingURL=cloudformation-parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cloudformation-parser.js","sourceRoot":"","sources":["../../../src/server/services/cloudformation-parser.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ export declare class LocalStackManager {
2
+ private static instance;
3
+ private process;
4
+ private _isRunning;
5
+ private endpoint;
6
+ private readonly containerName;
7
+ private constructor();
8
+ static getInstance(): LocalStackManager;
9
+ start(): Promise<void>;
10
+ stop(): Promise<void>;
11
+ private waitForReady;
12
+ isRunning(): boolean;
13
+ getEndpoint(): string;
14
+ getConfig(): {
15
+ endpoint: string;
16
+ region: string;
17
+ credentials: {
18
+ accessKeyId: string;
19
+ secretAccessKey: string;
20
+ };
21
+ };
22
+ }
23
+ //# sourceMappingURL=localstack-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"localstack-manager.d.ts","sourceRoot":"","sources":["../../../src/server/services/localstack-manager.ts"],"names":[],"mappings":"AAKA,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAoB;IAC3C,OAAO,CAAC,OAAO,CAA6B;IAC5C,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,QAAQ,CAA2B;IAC3C,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAoB;IAElD,OAAO;IAEP,MAAM,CAAC,WAAW,IAAI,iBAAiB;IAOjC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAgFtB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;YAkBb,YAAY;IAmB1B,SAAS,IAAI,OAAO;IAIpB,WAAW,IAAI,MAAM;IAIrB,SAAS;;;;;;;;CAUV"}
@@ -0,0 +1,142 @@
1
+ import { spawn, exec } from 'child_process';
2
+ import { promisify } from 'util';
3
+ const execAsync = promisify(exec);
4
+ export class LocalStackManager {
5
+ static instance;
6
+ process = null;
7
+ _isRunning = false;
8
+ endpoint = 'http://localhost:4566';
9
+ containerName = 'lss-localstack';
10
+ constructor() { }
11
+ static getInstance() {
12
+ if (!LocalStackManager.instance) {
13
+ LocalStackManager.instance = new LocalStackManager();
14
+ }
15
+ return LocalStackManager.instance;
16
+ }
17
+ async start() {
18
+ if (this._isRunning) {
19
+ console.log('⚠️ LocalStack already running');
20
+ return;
21
+ }
22
+ try {
23
+ // Check if docker is available
24
+ await execAsync('docker ps -q', { timeout: 5000 });
25
+ }
26
+ catch {
27
+ throw new Error('Docker is not available or not running. Please start Docker first.');
28
+ }
29
+ return new Promise((resolve, reject) => {
30
+ console.log('🔄 Starting LocalStack...');
31
+ // Start LocalStack via Docker
32
+ this.process = spawn('docker', [
33
+ 'run',
34
+ '--rm',
35
+ '-p',
36
+ '4566:4566',
37
+ '-p',
38
+ '4571:4571',
39
+ '-v',
40
+ 'lss-localstack-data:/var/lib/localstack',
41
+ '-v',
42
+ '/var/run/docker.sock:/var/run/docker.sock',
43
+ '--name',
44
+ this.containerName,
45
+ '-e',
46
+ 'SERVICES=dynamodb,sqs,sns,lambda',
47
+ '-e',
48
+ 'LAMBDA_EXECUTOR=local',
49
+ '-e',
50
+ 'PERSISTENCE=1',
51
+ '-e',
52
+ 'DEBUG=0',
53
+ 'localstack/localstack:latest',
54
+ ]);
55
+ let stderr = '';
56
+ let stdout = '';
57
+ this.process.stderr?.on('data', data => {
58
+ stderr += data.toString();
59
+ console.log(`[LocalStack stderr] ${data.toString().trim()}`);
60
+ });
61
+ this.process.stdout?.on('data', data => {
62
+ stdout += data.toString();
63
+ console.log(`[LocalStack stdout] ${data.toString().trim()}`);
64
+ });
65
+ this.process.on('error', error => {
66
+ console.error('❌ Failed to start LocalStack process:', error);
67
+ reject(error);
68
+ });
69
+ this.process.on('close', code => {
70
+ if (code !== 0) {
71
+ console.error(`Container exited with code ${code}`);
72
+ console.error('stderr:', stderr);
73
+ console.error('stdout:', stdout);
74
+ }
75
+ });
76
+ // Wait for LocalStack to be ready
77
+ this.waitForReady()
78
+ .then(() => {
79
+ this._isRunning = true;
80
+ console.log('✅ LocalStack ready');
81
+ resolve();
82
+ })
83
+ .catch(err => {
84
+ console.error('LocalStack startup error:', err.message);
85
+ this.process?.kill();
86
+ reject(err);
87
+ });
88
+ });
89
+ }
90
+ async stop() {
91
+ if (!this._isRunning) {
92
+ return;
93
+ }
94
+ console.log('🛑 Stopping LocalStack...');
95
+ try {
96
+ await execAsync(`docker stop ${this.containerName}`, { timeout: 10000 });
97
+ this._isRunning = false;
98
+ this.process = null;
99
+ console.log('✅ LocalStack stopped');
100
+ }
101
+ catch (error) {
102
+ console.error('⚠️ Error stopping LocalStack:', error instanceof Error ? error.message : 'Unknown error');
103
+ this._isRunning = false;
104
+ }
105
+ }
106
+ async waitForReady(maxAttempts = 120) {
107
+ for (let i = 0; i < maxAttempts; i++) {
108
+ try {
109
+ const response = await fetch(`${this.endpoint}/_localstack/health`);
110
+ if (response.ok) {
111
+ console.log(`✓ LocalStack is responsive (attempt ${i + 1}/${maxAttempts})`);
112
+ return;
113
+ }
114
+ }
115
+ catch {
116
+ // Ignore fetch errors during startup
117
+ if (i % 20 === 0) {
118
+ console.log(`⏳ Waiting for LocalStack... (attempt ${i + 1}/${maxAttempts})`);
119
+ }
120
+ }
121
+ await new Promise(resolve => setTimeout(resolve, 1000));
122
+ }
123
+ throw new Error('LocalStack failed to start in time (120s timeout). Check Docker and container logs.');
124
+ }
125
+ isRunning() {
126
+ return this._isRunning;
127
+ }
128
+ getEndpoint() {
129
+ return this.endpoint;
130
+ }
131
+ getConfig() {
132
+ return {
133
+ endpoint: this.endpoint,
134
+ region: process.env.AWS_REGION || 'us-east-1',
135
+ credentials: {
136
+ accessKeyId: process.env.LOCALSTACK_ACCESS_KEY_ID || 'test',
137
+ secretAccessKey: process.env.LOCALSTACK_SECRET_ACCESS_KEY || 'test',
138
+ },
139
+ };
140
+ }
141
+ }
142
+ //# sourceMappingURL=localstack-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"localstack-manager.js","sourceRoot":"","sources":["../../../src/server/services/localstack-manager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ export type ProcessStatus = 'running' | 'stopped' | 'failed';
2
+ interface RunOptions {
3
+ cwd: string;
4
+ command?: string;
5
+ args?: string[];
6
+ env?: Record<string, string>;
7
+ }
8
+ export declare class ProcessManager {
9
+ private processes;
10
+ private killProcessTree;
11
+ start(serviceName: string, options: RunOptions): {
12
+ pid: number | undefined;
13
+ status: ProcessStatus;
14
+ };
15
+ stop(serviceName: string): {
16
+ stopped: boolean;
17
+ };
18
+ getStatus(serviceName: string): {
19
+ pid: number | undefined;
20
+ status: ProcessStatus;
21
+ exitCode: number | null | undefined;
22
+ startedAt: number;
23
+ } | null;
24
+ getLogs(serviceName: string): {
25
+ logs: never[];
26
+ status: ProcessStatus;
27
+ pid?: undefined;
28
+ exitCode?: undefined;
29
+ startedAt?: undefined;
30
+ } | {
31
+ logs: string[];
32
+ status: ProcessStatus;
33
+ pid: number | undefined;
34
+ exitCode: number | null | undefined;
35
+ startedAt: number;
36
+ };
37
+ stopAll(): void;
38
+ cleanup(): Promise<void>;
39
+ }
40
+ export {};
41
+ //# sourceMappingURL=process-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"process-manager.d.ts","sourceRoot":"","sources":["../../../src/server/services/process-manager.ts"],"names":[],"mappings":"AAMA,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG,SAAS,GAAG,QAAQ,CAAC;AAE7D,UAAU,UAAU;IAClB,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC9B;AAYD,qBAAa,cAAc;IACzB,OAAO,CAAC,SAAS,CAAqC;YAExC,eAAe;IAsB7B,KAAK,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU;;;;IAoD9C,IAAI,CAAC,WAAW,EAAE,MAAM;;;IAWxB,SAAS,CAAC,WAAW,EAAE,MAAM;;;;;;IAY7B,OAAO,CAAC,WAAW,EAAE,MAAM;;gBAE6B,aAAa;;;;;;;;;;;IAWrE,OAAO;IAMD,OAAO;CASd"}
@@ -0,0 +1,119 @@
1
+ import { spawn } from 'child_process';
2
+ import { exec } from 'child_process';
3
+ import { promisify } from 'util';
4
+ const execAsync = promisify(exec);
5
+ const LOG_LIMIT = 500;
6
+ export class ProcessManager {
7
+ processes = new Map();
8
+ async killProcessTree(pid) {
9
+ if (!pid)
10
+ return;
11
+ try {
12
+ // Try to kill the process tree using pkill (works on Unix/Linux)
13
+ await execAsync(`pkill -P ${pid}`);
14
+ }
15
+ catch {
16
+ // Ignore errors, pkill might not be available
17
+ }
18
+ try {
19
+ // Kill the main process
20
+ process.kill(pid, 'SIGTERM');
21
+ // Wait a bit and then SIGKILL if still alive
22
+ await new Promise(r => setTimeout(r, 500));
23
+ process.kill(pid, 'SIGKILL');
24
+ }
25
+ catch {
26
+ // Process might already be dead
27
+ }
28
+ }
29
+ start(serviceName, options) {
30
+ const existing = this.processes.get(serviceName);
31
+ if (existing && existing.status === 'running') {
32
+ throw new Error(`Service ${serviceName} is already running`);
33
+ }
34
+ const command = options.command || 'npm';
35
+ const args = options.args && options.args.length > 0 ? options.args : ['run', 'start'];
36
+ const proc = spawn(command, args, {
37
+ cwd: options.cwd,
38
+ env: { ...process.env, ...options.env },
39
+ stdio: ['ignore', 'pipe', 'pipe'],
40
+ });
41
+ const managed = {
42
+ proc,
43
+ logs: [],
44
+ status: 'running',
45
+ startedAt: Date.now(),
46
+ };
47
+ const appendLog = (prefix, chunk) => {
48
+ const lines = chunk.toString().split(/\r?\n/).filter(Boolean);
49
+ for (const line of lines) {
50
+ managed.logs.push(`${prefix} ${line}`);
51
+ }
52
+ if (managed.logs.length > LOG_LIMIT) {
53
+ managed.logs.splice(0, managed.logs.length - LOG_LIMIT);
54
+ }
55
+ };
56
+ proc.stdout?.on('data', data => appendLog('stdout:', data));
57
+ proc.stderr?.on('data', data => appendLog('stderr:', data));
58
+ proc.on('close', code => {
59
+ managed.status = code === 0 ? 'stopped' : 'failed';
60
+ managed.exitCode = code;
61
+ this.processes.set(serviceName, managed);
62
+ });
63
+ proc.on('error', err => {
64
+ appendLog('error:', Buffer.from(String(err)));
65
+ managed.status = 'failed';
66
+ this.processes.set(serviceName, managed);
67
+ });
68
+ this.processes.set(serviceName, managed);
69
+ return { pid: proc.pid, status: managed.status };
70
+ }
71
+ stop(serviceName) {
72
+ const managed = this.processes.get(serviceName);
73
+ if (!managed)
74
+ return { stopped: false };
75
+ // Kill the process tree aggressively
76
+ this.killProcessTree(managed.proc.pid);
77
+ managed.status = 'stopped';
78
+ this.processes.set(serviceName, managed);
79
+ return { stopped: true };
80
+ }
81
+ getStatus(serviceName) {
82
+ const managed = this.processes.get(serviceName);
83
+ if (!managed)
84
+ return null;
85
+ return {
86
+ pid: managed.proc.pid,
87
+ status: managed.status,
88
+ exitCode: managed.exitCode,
89
+ startedAt: managed.startedAt,
90
+ };
91
+ }
92
+ getLogs(serviceName) {
93
+ const managed = this.processes.get(serviceName);
94
+ if (!managed)
95
+ return { logs: [], status: 'stopped' };
96
+ return {
97
+ logs: managed.logs,
98
+ status: managed.status,
99
+ pid: managed.proc.pid,
100
+ exitCode: managed.exitCode,
101
+ startedAt: managed.startedAt,
102
+ };
103
+ }
104
+ stopAll() {
105
+ for (const name of this.processes.keys()) {
106
+ this.stop(name);
107
+ }
108
+ }
109
+ async cleanup() {
110
+ // Give processes time to exit gracefully, then force kill any remaining
111
+ await new Promise(r => setTimeout(r, 1000));
112
+ for (const managed of this.processes.values()) {
113
+ if (managed.status === 'running') {
114
+ await this.killProcessTree(managed.proc.pid);
115
+ }
116
+ }
117
+ }
118
+ }
119
+ //# sourceMappingURL=process-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"process-manager.js","sourceRoot":"","sources":["../../../src/server/services/process-manager.ts"],"names":[],"mappings":"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"}