@orkify/cli 1.0.0-beta.5

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 (203) hide show
  1. package/LICENSE +191 -0
  2. package/README.md +1701 -0
  3. package/bin/orkify +3 -0
  4. package/boot/systemd/orkify@.service +30 -0
  5. package/dist/agent-name.d.ts +4 -0
  6. package/dist/agent-name.js +42 -0
  7. package/dist/alerts/AlertEvaluator.d.ts +14 -0
  8. package/dist/alerts/AlertEvaluator.js +135 -0
  9. package/dist/cli/commands/autostart.d.ts +3 -0
  10. package/dist/cli/commands/autostart.js +11 -0
  11. package/dist/cli/commands/crash-test.d.ts +3 -0
  12. package/dist/cli/commands/crash-test.js +17 -0
  13. package/dist/cli/commands/daemon-reload.d.ts +3 -0
  14. package/dist/cli/commands/daemon-reload.js +72 -0
  15. package/dist/cli/commands/delete.d.ts +3 -0
  16. package/dist/cli/commands/delete.js +37 -0
  17. package/dist/cli/commands/deploy.d.ts +6 -0
  18. package/dist/cli/commands/deploy.js +266 -0
  19. package/dist/cli/commands/down.d.ts +3 -0
  20. package/dist/cli/commands/down.js +36 -0
  21. package/dist/cli/commands/flush.d.ts +3 -0
  22. package/dist/cli/commands/flush.js +28 -0
  23. package/dist/cli/commands/kill.d.ts +3 -0
  24. package/dist/cli/commands/kill.js +35 -0
  25. package/dist/cli/commands/list.d.ts +14 -0
  26. package/dist/cli/commands/list.js +361 -0
  27. package/dist/cli/commands/logs.d.ts +3 -0
  28. package/dist/cli/commands/logs.js +107 -0
  29. package/dist/cli/commands/mcp.d.ts +3 -0
  30. package/dist/cli/commands/mcp.js +151 -0
  31. package/dist/cli/commands/reload.d.ts +3 -0
  32. package/dist/cli/commands/reload.js +54 -0
  33. package/dist/cli/commands/restart.d.ts +3 -0
  34. package/dist/cli/commands/restart.js +43 -0
  35. package/dist/cli/commands/restore.d.ts +3 -0
  36. package/dist/cli/commands/restore.js +88 -0
  37. package/dist/cli/commands/run.d.ts +8 -0
  38. package/dist/cli/commands/run.js +212 -0
  39. package/dist/cli/commands/snap.d.ts +3 -0
  40. package/dist/cli/commands/snap.js +30 -0
  41. package/dist/cli/commands/up.d.ts +3 -0
  42. package/dist/cli/commands/up.js +125 -0
  43. package/dist/cli/crash-recovery.d.ts +2 -0
  44. package/dist/cli/crash-recovery.js +67 -0
  45. package/dist/cli/index.d.ts +3 -0
  46. package/dist/cli/index.js +46 -0
  47. package/dist/cli/parse.d.ts +28 -0
  48. package/dist/cli/parse.js +97 -0
  49. package/dist/cluster/ClusterWrapper.d.ts +18 -0
  50. package/dist/cluster/ClusterWrapper.js +602 -0
  51. package/dist/config/ConfigStore.d.ts +11 -0
  52. package/dist/config/ConfigStore.js +21 -0
  53. package/dist/config/schema.d.ts +103 -0
  54. package/dist/config/schema.js +49 -0
  55. package/dist/constants.d.ts +83 -0
  56. package/dist/constants.js +289 -0
  57. package/dist/cron/CronScheduler.d.ts +25 -0
  58. package/dist/cron/CronScheduler.js +149 -0
  59. package/dist/daemon/GracefulManager.d.ts +8 -0
  60. package/dist/daemon/GracefulManager.js +29 -0
  61. package/dist/daemon/ManagedProcess.d.ts +71 -0
  62. package/dist/daemon/ManagedProcess.js +1020 -0
  63. package/dist/daemon/Orchestrator.d.ts +51 -0
  64. package/dist/daemon/Orchestrator.js +416 -0
  65. package/dist/daemon/RotatingWriter.d.ts +27 -0
  66. package/dist/daemon/RotatingWriter.js +264 -0
  67. package/dist/daemon/index.d.ts +2 -0
  68. package/dist/daemon/index.js +106 -0
  69. package/dist/daemon/startDaemon.d.ts +30 -0
  70. package/dist/daemon/startDaemon.js +693 -0
  71. package/dist/deploy/CommandPoller.d.ts +13 -0
  72. package/dist/deploy/CommandPoller.js +53 -0
  73. package/dist/deploy/DeployExecutor.d.ts +33 -0
  74. package/dist/deploy/DeployExecutor.js +340 -0
  75. package/dist/deploy/config.d.ts +20 -0
  76. package/dist/deploy/config.js +161 -0
  77. package/dist/deploy/env.d.ts +2 -0
  78. package/dist/deploy/env.js +17 -0
  79. package/dist/deploy/tarball.d.ts +32 -0
  80. package/dist/deploy/tarball.js +243 -0
  81. package/dist/detect/framework.d.ts +2 -0
  82. package/dist/detect/framework.js +24 -0
  83. package/dist/ipc/DaemonClient.d.ts +31 -0
  84. package/dist/ipc/DaemonClient.js +248 -0
  85. package/dist/ipc/DaemonServer.d.ts +28 -0
  86. package/dist/ipc/DaemonServer.js +166 -0
  87. package/dist/ipc/MultiUserClient.d.ts +27 -0
  88. package/dist/ipc/MultiUserClient.js +203 -0
  89. package/dist/ipc/protocol.d.ts +7 -0
  90. package/dist/ipc/protocol.js +53 -0
  91. package/dist/ipc/restoreDaemon.d.ts +8 -0
  92. package/dist/ipc/restoreDaemon.js +19 -0
  93. package/dist/machine-id.d.ts +11 -0
  94. package/dist/machine-id.js +51 -0
  95. package/dist/mcp/auth.d.ts +118 -0
  96. package/dist/mcp/auth.js +245 -0
  97. package/dist/mcp/http.d.ts +20 -0
  98. package/dist/mcp/http.js +229 -0
  99. package/dist/mcp/index.d.ts +3 -0
  100. package/dist/mcp/index.js +8 -0
  101. package/dist/mcp/server.d.ts +37 -0
  102. package/dist/mcp/server.js +413 -0
  103. package/dist/probe/compute-fingerprint.d.ts +27 -0
  104. package/dist/probe/compute-fingerprint.js +65 -0
  105. package/dist/probe/parse-frames.d.ts +21 -0
  106. package/dist/probe/parse-frames.js +57 -0
  107. package/dist/probe/resolve-sourcemaps.d.ts +25 -0
  108. package/dist/probe/resolve-sourcemaps.js +281 -0
  109. package/dist/state/StateStore.d.ts +11 -0
  110. package/dist/state/StateStore.js +78 -0
  111. package/dist/telemetry/TelemetryReporter.d.ts +49 -0
  112. package/dist/telemetry/TelemetryReporter.js +451 -0
  113. package/dist/types/index.d.ts +373 -0
  114. package/dist/types/index.js +2 -0
  115. package/package.json +148 -0
  116. package/packages/cache/README.md +114 -0
  117. package/packages/cache/dist/CacheClient.d.ts +26 -0
  118. package/packages/cache/dist/CacheClient.d.ts.map +1 -0
  119. package/packages/cache/dist/CacheClient.js +174 -0
  120. package/packages/cache/dist/CacheClient.js.map +1 -0
  121. package/packages/cache/dist/CacheFileStore.d.ts +45 -0
  122. package/packages/cache/dist/CacheFileStore.d.ts.map +1 -0
  123. package/packages/cache/dist/CacheFileStore.js +446 -0
  124. package/packages/cache/dist/CacheFileStore.js.map +1 -0
  125. package/packages/cache/dist/CachePersistence.d.ts +9 -0
  126. package/packages/cache/dist/CachePersistence.d.ts.map +1 -0
  127. package/packages/cache/dist/CachePersistence.js +67 -0
  128. package/packages/cache/dist/CachePersistence.js.map +1 -0
  129. package/packages/cache/dist/CachePrimary.d.ts +25 -0
  130. package/packages/cache/dist/CachePrimary.d.ts.map +1 -0
  131. package/packages/cache/dist/CachePrimary.js +155 -0
  132. package/packages/cache/dist/CachePrimary.js.map +1 -0
  133. package/packages/cache/dist/CacheStore.d.ts +50 -0
  134. package/packages/cache/dist/CacheStore.d.ts.map +1 -0
  135. package/packages/cache/dist/CacheStore.js +271 -0
  136. package/packages/cache/dist/CacheStore.js.map +1 -0
  137. package/packages/cache/dist/constants.d.ts +6 -0
  138. package/packages/cache/dist/constants.d.ts.map +1 -0
  139. package/packages/cache/dist/constants.js +9 -0
  140. package/packages/cache/dist/constants.js.map +1 -0
  141. package/packages/cache/dist/index.d.ts +16 -0
  142. package/packages/cache/dist/index.d.ts.map +1 -0
  143. package/packages/cache/dist/index.js +86 -0
  144. package/packages/cache/dist/index.js.map +1 -0
  145. package/packages/cache/dist/serialize.d.ts +9 -0
  146. package/packages/cache/dist/serialize.d.ts.map +1 -0
  147. package/packages/cache/dist/serialize.js +40 -0
  148. package/packages/cache/dist/serialize.js.map +1 -0
  149. package/packages/cache/dist/types.d.ts +123 -0
  150. package/packages/cache/dist/types.d.ts.map +1 -0
  151. package/packages/cache/dist/types.js +2 -0
  152. package/packages/cache/dist/types.js.map +1 -0
  153. package/packages/cache/package.json +27 -0
  154. package/packages/cache/src/CacheClient.ts +227 -0
  155. package/packages/cache/src/CacheFileStore.ts +528 -0
  156. package/packages/cache/src/CachePersistence.ts +89 -0
  157. package/packages/cache/src/CachePrimary.ts +172 -0
  158. package/packages/cache/src/CacheStore.ts +308 -0
  159. package/packages/cache/src/constants.ts +10 -0
  160. package/packages/cache/src/index.ts +100 -0
  161. package/packages/cache/src/serialize.ts +49 -0
  162. package/packages/cache/src/types.ts +156 -0
  163. package/packages/cache/tsconfig.json +18 -0
  164. package/packages/cache/tsconfig.tsbuildinfo +1 -0
  165. package/packages/next/README.md +166 -0
  166. package/packages/next/dist/error-capture.d.ts +34 -0
  167. package/packages/next/dist/error-capture.d.ts.map +1 -0
  168. package/packages/next/dist/error-capture.js +130 -0
  169. package/packages/next/dist/error-capture.js.map +1 -0
  170. package/packages/next/dist/error-handler.d.ts +10 -0
  171. package/packages/next/dist/error-handler.d.ts.map +1 -0
  172. package/packages/next/dist/error-handler.js +186 -0
  173. package/packages/next/dist/error-handler.js.map +1 -0
  174. package/packages/next/dist/isr-cache.d.ts +9 -0
  175. package/packages/next/dist/isr-cache.d.ts.map +1 -0
  176. package/packages/next/dist/isr-cache.js +86 -0
  177. package/packages/next/dist/isr-cache.js.map +1 -0
  178. package/packages/next/dist/stream.d.ts +5 -0
  179. package/packages/next/dist/stream.d.ts.map +1 -0
  180. package/packages/next/dist/stream.js +22 -0
  181. package/packages/next/dist/stream.js.map +1 -0
  182. package/packages/next/dist/types.d.ts +33 -0
  183. package/packages/next/dist/types.d.ts.map +1 -0
  184. package/packages/next/dist/types.js +6 -0
  185. package/packages/next/dist/types.js.map +1 -0
  186. package/packages/next/dist/use-cache.d.ts +4 -0
  187. package/packages/next/dist/use-cache.d.ts.map +1 -0
  188. package/packages/next/dist/use-cache.js +86 -0
  189. package/packages/next/dist/use-cache.js.map +1 -0
  190. package/packages/next/dist/utils.d.ts +32 -0
  191. package/packages/next/dist/utils.d.ts.map +1 -0
  192. package/packages/next/dist/utils.js +88 -0
  193. package/packages/next/dist/utils.js.map +1 -0
  194. package/packages/next/package.json +52 -0
  195. package/packages/next/src/error-capture.ts +177 -0
  196. package/packages/next/src/error-handler.ts +221 -0
  197. package/packages/next/src/isr-cache.ts +100 -0
  198. package/packages/next/src/stream.ts +23 -0
  199. package/packages/next/src/types.ts +33 -0
  200. package/packages/next/src/use-cache.ts +99 -0
  201. package/packages/next/src/utils.ts +102 -0
  202. package/packages/next/tsconfig.json +19 -0
  203. package/packages/next/tsconfig.tsbuildinfo +1 -0
@@ -0,0 +1,51 @@
1
+ import { EventEmitter } from 'node:events';
2
+ import type { McpStartPayload, ProcessConfig, ProcessInfo, ReconcileResult, UpPayload } from '../types/index.js';
3
+ import { ManagedProcess } from './ManagedProcess.js';
4
+ export declare class Orchestrator extends EventEmitter {
5
+ private processes;
6
+ private nameToId;
7
+ private nextProcessId;
8
+ private gracefulManager;
9
+ private stateStore;
10
+ private startedAt;
11
+ constructor();
12
+ up(payload: UpPayload): Promise<ProcessInfo>;
13
+ down(target: 'all' | number | string): Promise<ProcessInfo[]>;
14
+ restart(target: 'all' | number | string): Promise<ProcessInfo[]>;
15
+ reload(target: 'all' | number | string): Promise<ProcessInfo[]>;
16
+ delete(target: 'all' | number | string): Promise<ProcessInfo[]>;
17
+ flushLogs(target: 'all' | number | string): Promise<void>;
18
+ list(): ProcessInfo[];
19
+ getRunningConfigs(): ProcessConfig[];
20
+ snap(options?: {
21
+ noEnv?: boolean;
22
+ file?: string;
23
+ mcpOptions?: McpStartPayload;
24
+ }): Promise<void>;
25
+ restoreFromMemory(configs: ProcessConfig[]): Promise<ProcessInfo[]>;
26
+ restoreFromSnapshot(file?: string): Promise<{
27
+ processes: ProcessInfo[];
28
+ configs: ProcessConfig[];
29
+ mcpState?: McpStartPayload;
30
+ }>;
31
+ shutdown(opts?: {
32
+ persistCache?: boolean;
33
+ }): Promise<void>;
34
+ /**
35
+ * Immediately SIGKILL all child processes without waiting for graceful shutdown.
36
+ */
37
+ forceShutdown(): void;
38
+ reconcile(configs: ProcessConfig[], env?: Record<string, string>): Promise<ReconcileResult>;
39
+ private configChanged;
40
+ private resolveTarget;
41
+ getProcess(target: number | string): ManagedProcess | undefined;
42
+ getCronSecret(name: string): string | undefined;
43
+ getProcessByName(name: string): ManagedProcess | undefined;
44
+ getDaemonStatus(): {
45
+ pid: number;
46
+ uptime: number;
47
+ processCount: number;
48
+ workerCount: number;
49
+ };
50
+ }
51
+ //# sourceMappingURL=Orchestrator.d.ts.map
@@ -0,0 +1,416 @@
1
+ import { randomBytes } from 'node:crypto';
2
+ import { EventEmitter } from 'node:events';
3
+ import { existsSync } from 'node:fs';
4
+ import { cpus } from 'node:os';
5
+ import { basename, resolve } from 'node:path';
6
+ import { DEFAULT_LOG_MAX_AGE, DEFAULT_LOG_MAX_FILES, DEFAULT_LOG_MAX_SIZE, DEFAULT_MAX_RESTARTS, DEFAULT_MIN_UPTIME, DEFAULT_RELOAD_RETRIES, DEFAULT_RESTART_DELAY, DEFAULT_WORKERS, ExecMode, KILL_TIMEOUT, } from '../constants.js';
7
+ import { detectFramework } from '../detect/framework.js';
8
+ import { StateStore } from '../state/StateStore.js';
9
+ import { GracefulManager } from './GracefulManager.js';
10
+ import { ManagedProcess } from './ManagedProcess.js';
11
+ export class Orchestrator extends EventEmitter {
12
+ processes = new Map();
13
+ nameToId = new Map();
14
+ nextProcessId = 0;
15
+ gracefulManager;
16
+ stateStore;
17
+ startedAt;
18
+ constructor() {
19
+ super();
20
+ this.gracefulManager = new GracefulManager();
21
+ this.stateStore = new StateStore();
22
+ this.startedAt = Date.now();
23
+ }
24
+ async up(payload) {
25
+ const script = resolve(payload.cwd || process.cwd(), payload.script);
26
+ if (!existsSync(script)) {
27
+ throw new Error(`Script not found: ${script}`);
28
+ }
29
+ const name = payload.name || basename(script, '.js');
30
+ // Check if process with same name exists
31
+ if (this.nameToId.has(name)) {
32
+ // Safe: .has() guard above guarantees a defined value
33
+ const existingId = this.nameToId.get(name);
34
+ const existing = this.processes.get(existingId);
35
+ // Allow re-using the name if the existing process is stopped
36
+ if (existing && !existing.isRunning()) {
37
+ this.processes.delete(existingId);
38
+ this.nameToId.delete(name);
39
+ }
40
+ else {
41
+ throw new Error(`Process "${name}" already exists`);
42
+ }
43
+ }
44
+ const rawWorkers = payload.workers ?? DEFAULT_WORKERS;
45
+ const workerCount = rawWorkers === 0 ? cpus().length : rawWorkers;
46
+ const execMode = workerCount > 1 ? ExecMode.CLUSTER : ExecMode.FORK;
47
+ const cwd = payload.cwd || process.cwd();
48
+ const config = {
49
+ name,
50
+ script,
51
+ cwd,
52
+ workerCount,
53
+ execMode,
54
+ watch: payload.watch || false,
55
+ watchPaths: payload.watchPaths,
56
+ env: payload.env || {},
57
+ nodeArgs: payload.nodeArgs || [],
58
+ args: payload.args || [],
59
+ killTimeout: payload.killTimeout || KILL_TIMEOUT,
60
+ maxRestarts: payload.maxRestarts ?? DEFAULT_MAX_RESTARTS,
61
+ minUptime: payload.minUptime ?? DEFAULT_MIN_UPTIME,
62
+ restartDelay: payload.restartDelay ?? DEFAULT_RESTART_DELAY,
63
+ sticky: payload.sticky || false,
64
+ port: payload.port,
65
+ reloadRetries: payload.reloadRetries ?? DEFAULT_RELOAD_RETRIES,
66
+ healthCheck: payload.healthCheck,
67
+ logMaxSize: payload.logMaxSize ?? DEFAULT_LOG_MAX_SIZE,
68
+ logMaxFiles: payload.logMaxFiles ?? DEFAULT_LOG_MAX_FILES,
69
+ logMaxAge: payload.logMaxAge ?? DEFAULT_LOG_MAX_AGE,
70
+ restartOnMemory: payload.restartOnMemory,
71
+ cron: payload.cron,
72
+ framework: payload.framework ?? detectFramework(cwd),
73
+ };
74
+ // Auto-generate a stable encryption key for Next.js Server Actions
75
+ if (config.framework === 'nextjs' && !config.env.NEXT_SERVER_ACTIONS_ENCRYPTION_KEY) {
76
+ config.env.NEXT_SERVER_ACTIONS_ENCRYPTION_KEY = randomBytes(32).toString('hex');
77
+ }
78
+ const processId = this.nextProcessId++;
79
+ const container = new ManagedProcess(processId, config);
80
+ // Set up event forwarding
81
+ container.on('log', (data) => {
82
+ this.emit('log', { processName: name, ...data });
83
+ });
84
+ container.on('worker:ready', (workerId) => {
85
+ this.emit('worker:ready', { processName: name, workerId });
86
+ });
87
+ container.on('worker:exit', (data) => {
88
+ this.emit('worker:exit', { processName: name, ...data });
89
+ });
90
+ container.on('worker:maxRestarts', (workerId) => {
91
+ this.emit('worker:maxRestarts', { processName: name, workerId });
92
+ });
93
+ container.on('worker:memoryRestart', (data) => {
94
+ this.emit('worker:memoryRestart', { processName: name, ...data });
95
+ });
96
+ container.on('worker:error:captured', (data) => {
97
+ this.emit('worker:error:captured', { processName: name, ...data });
98
+ });
99
+ container.on('watch:reload', () => {
100
+ this.reload(name).catch((err) => {
101
+ console.error(`Watch reload failed for ${name}:`, err.message);
102
+ });
103
+ });
104
+ this.processes.set(processId, container);
105
+ this.nameToId.set(name, processId);
106
+ try {
107
+ await container.start();
108
+ }
109
+ catch (err) {
110
+ this.processes.delete(processId);
111
+ this.nameToId.delete(name);
112
+ throw err;
113
+ }
114
+ this.emit('process:start', { processName: name, processId });
115
+ return container.getInfo();
116
+ }
117
+ async down(target) {
118
+ const containers = this.resolveTarget(target);
119
+ const results = [];
120
+ for (const container of containers) {
121
+ try {
122
+ await container.stop();
123
+ this.emit('process:stop', { processName: container.config.name, processId: container.id });
124
+ results.push(container.getInfo());
125
+ }
126
+ catch (err) {
127
+ console.error(`Failed to stop process "${container.config.name}":`, err.message);
128
+ }
129
+ }
130
+ return results;
131
+ }
132
+ async restart(target) {
133
+ const containers = this.resolveTarget(target);
134
+ const results = [];
135
+ for (const container of containers) {
136
+ try {
137
+ await container.restart();
138
+ results.push(container.getInfo());
139
+ }
140
+ catch (err) {
141
+ console.error(`Failed to restart process "${container.config.name}":`, err.message);
142
+ }
143
+ }
144
+ return results;
145
+ }
146
+ async reload(target) {
147
+ const containers = this.resolveTarget(target);
148
+ const results = [];
149
+ for (const container of containers) {
150
+ try {
151
+ this.emit('reload:start', { processName: container.config.name, processId: container.id });
152
+ await this.gracefulManager.reload(container);
153
+ this.emit('reload:complete', {
154
+ processName: container.config.name,
155
+ processId: container.id,
156
+ });
157
+ results.push(container.getInfo());
158
+ }
159
+ catch (err) {
160
+ console.error(`Failed to reload process "${container.config.name}":`, err.message);
161
+ }
162
+ }
163
+ return results;
164
+ }
165
+ async delete(target) {
166
+ const containers = this.resolveTarget(target);
167
+ const results = [];
168
+ for (const container of containers) {
169
+ try {
170
+ await container.stop();
171
+ }
172
+ catch (err) {
173
+ console.error(`Failed to stop process "${container.config.name}" during delete:`, err.message);
174
+ }
175
+ results.push(container.getInfo());
176
+ this.processes.delete(container.id);
177
+ this.nameToId.delete(container.config.name);
178
+ }
179
+ return results;
180
+ }
181
+ async flushLogs(target) {
182
+ const containers = this.resolveTarget(target);
183
+ await Promise.all(containers.map((c) => c.flushLogs()));
184
+ }
185
+ list() {
186
+ return Array.from(this.processes.values()).map((p) => p.getInfo());
187
+ }
188
+ getRunningConfigs() {
189
+ return Array.from(this.processes.values())
190
+ .filter((p) => p.isRunning())
191
+ .map((p) => p.config);
192
+ }
193
+ async snap(options) {
194
+ let configs = this.getRunningConfigs();
195
+ if (options?.noEnv) {
196
+ configs = configs.map((c) => ({ ...c, env: {} }));
197
+ }
198
+ const store = options?.file ? new StateStore(options.file) : this.stateStore;
199
+ await store.save(configs, options?.mcpOptions);
200
+ }
201
+ async restoreFromMemory(configs) {
202
+ const results = [];
203
+ for (const config of configs) {
204
+ if (this.nameToId.has(config.name)) {
205
+ continue;
206
+ }
207
+ try {
208
+ const info = await this.up({
209
+ script: config.script,
210
+ name: config.name,
211
+ workers: config.workerCount,
212
+ watch: config.watch,
213
+ watchPaths: config.watchPaths,
214
+ cwd: config.cwd,
215
+ env: config.env,
216
+ nodeArgs: config.nodeArgs,
217
+ args: config.args,
218
+ killTimeout: config.killTimeout,
219
+ maxRestarts: config.maxRestarts,
220
+ minUptime: config.minUptime,
221
+ restartDelay: config.restartDelay,
222
+ sticky: config.sticky,
223
+ port: config.port,
224
+ reloadRetries: config.reloadRetries,
225
+ healthCheck: config.healthCheck,
226
+ logMaxSize: config.logMaxSize,
227
+ logMaxFiles: config.logMaxFiles,
228
+ logMaxAge: config.logMaxAge,
229
+ restartOnMemory: config.restartOnMemory,
230
+ cron: config.cron,
231
+ framework: config.framework,
232
+ });
233
+ results.push(info);
234
+ }
235
+ catch (err) {
236
+ console.error(`Failed to restore process "${config.name}":`, err.message);
237
+ }
238
+ }
239
+ return results;
240
+ }
241
+ async restoreFromSnapshot(file) {
242
+ const store = file ? new StateStore(file) : this.stateStore;
243
+ const state = await store.loadFull();
244
+ const processes = await this.restoreFromMemory(state.processes);
245
+ return { processes, configs: state.processes, mcpState: state.mcp };
246
+ }
247
+ async shutdown(opts) {
248
+ // Stop all processes in parallel for faster shutdown
249
+ await Promise.all(Array.from(this.processes.values()).map((container) => container.stop({ persistCache: opts?.persistCache }).catch((err) => {
250
+ console.error(`Failed to stop process "${container.config.name}" during shutdown:`, err.message);
251
+ })));
252
+ this.processes.clear();
253
+ this.nameToId.clear();
254
+ }
255
+ /**
256
+ * Immediately SIGKILL all child processes without waiting for graceful shutdown.
257
+ */
258
+ forceShutdown() {
259
+ for (const container of this.processes.values()) {
260
+ container.forceKill();
261
+ }
262
+ this.processes.clear();
263
+ this.nameToId.clear();
264
+ }
265
+ async reconcile(configs, env) {
266
+ const result = { started: [], reloaded: [], deleted: [] };
267
+ // Build name→config maps
268
+ const targetByName = new Map();
269
+ for (const config of configs) {
270
+ targetByName.set(config.name, config);
271
+ }
272
+ const runningNames = new Set(this.nameToId.keys());
273
+ // Delete processes not in target configs
274
+ for (const name of runningNames) {
275
+ if (!targetByName.has(name)) {
276
+ await this.delete(name);
277
+ result.deleted.push(name);
278
+ }
279
+ }
280
+ // Start new, reload unchanged, replace changed
281
+ for (const config of configs) {
282
+ const mergedEnv = { ...config.env, ...env };
283
+ const payload = {
284
+ script: config.script,
285
+ name: config.name,
286
+ workers: config.workerCount,
287
+ watch: config.watch,
288
+ watchPaths: config.watchPaths,
289
+ cwd: config.cwd,
290
+ env: mergedEnv,
291
+ nodeArgs: config.nodeArgs,
292
+ args: config.args,
293
+ killTimeout: config.killTimeout,
294
+ maxRestarts: config.maxRestarts,
295
+ minUptime: config.minUptime,
296
+ restartDelay: config.restartDelay,
297
+ sticky: config.sticky,
298
+ port: config.port,
299
+ reloadRetries: config.reloadRetries,
300
+ healthCheck: config.healthCheck,
301
+ logMaxSize: config.logMaxSize,
302
+ logMaxFiles: config.logMaxFiles,
303
+ logMaxAge: config.logMaxAge,
304
+ restartOnMemory: config.restartOnMemory,
305
+ cron: config.cron,
306
+ framework: config.framework,
307
+ };
308
+ if (!runningNames.has(config.name)) {
309
+ // New process
310
+ await this.up(payload);
311
+ result.started.push(config.name);
312
+ }
313
+ else {
314
+ const existing = this.getProcessByName(config.name);
315
+ if (existing && this.configChanged(existing.config, config)) {
316
+ // Config changed — full restart
317
+ await this.delete(config.name);
318
+ await this.up(payload);
319
+ result.started.push(config.name);
320
+ }
321
+ else {
322
+ // Config unchanged — zero-downtime reload
323
+ await this.reload(config.name);
324
+ result.reloaded.push(config.name);
325
+ }
326
+ }
327
+ }
328
+ return result;
329
+ }
330
+ configChanged(running, target) {
331
+ // Compare config fields that matter (ignore env and cwd which vary between deploys)
332
+ const keys = [
333
+ 'script',
334
+ 'workerCount',
335
+ 'nodeArgs',
336
+ 'args',
337
+ 'sticky',
338
+ 'port',
339
+ 'healthCheck',
340
+ 'reloadRetries',
341
+ 'watch',
342
+ 'watchPaths',
343
+ 'killTimeout',
344
+ 'maxRestarts',
345
+ 'minUptime',
346
+ 'restartDelay',
347
+ 'restartOnMemory',
348
+ ];
349
+ for (const key of keys) {
350
+ const a = running[key];
351
+ const b = target[key];
352
+ if (Array.isArray(a) && Array.isArray(b)) {
353
+ if (a.length !== b.length || a.some((v, i) => v !== b[i]))
354
+ return true;
355
+ }
356
+ else if (a !== b) {
357
+ return true;
358
+ }
359
+ }
360
+ // Deep-compare cron (array of objects, not simple primitives)
361
+ if (JSON.stringify(running.cron ?? []) !== JSON.stringify(target.cron ?? []))
362
+ return true;
363
+ return false;
364
+ }
365
+ resolveTarget(target) {
366
+ if (target === 'all') {
367
+ return Array.from(this.processes.values());
368
+ }
369
+ if (typeof target === 'number') {
370
+ const container = this.processes.get(target);
371
+ if (!container) {
372
+ throw new Error(`Process with id ${target} not found`);
373
+ }
374
+ return [container];
375
+ }
376
+ // Try by name first
377
+ const id = this.nameToId.get(target);
378
+ if (id !== undefined) {
379
+ const container = this.processes.get(id);
380
+ if (container) {
381
+ return [container];
382
+ }
383
+ }
384
+ // Try parsing as number
385
+ const numId = parseInt(target, 10);
386
+ if (!isNaN(numId)) {
387
+ const container = this.processes.get(numId);
388
+ if (container) {
389
+ return [container];
390
+ }
391
+ }
392
+ throw new Error(`Process "${target}" not found`);
393
+ }
394
+ getProcess(target) {
395
+ const containers = this.resolveTarget(target);
396
+ return containers[0];
397
+ }
398
+ getCronSecret(name) {
399
+ return this.getProcessByName(name)?.cronSecret;
400
+ }
401
+ getProcessByName(name) {
402
+ const id = this.nameToId.get(name);
403
+ if (id === undefined)
404
+ return undefined;
405
+ return this.processes.get(id);
406
+ }
407
+ getDaemonStatus() {
408
+ return {
409
+ pid: process.pid,
410
+ uptime: Date.now() - this.startedAt,
411
+ processCount: this.processes.size,
412
+ workerCount: Array.from(this.processes.values()).reduce((sum, p) => sum + p.getWorkerCount(), 0),
413
+ };
414
+ }
415
+ }
416
+ //# sourceMappingURL=Orchestrator.js.map
@@ -0,0 +1,27 @@
1
+ export declare class RotatingWriter {
2
+ private fd;
3
+ private bytesWritten;
4
+ private lastRotationDate;
5
+ private rotating;
6
+ private compressionChain;
7
+ readonly filePath: string;
8
+ private readonly maxSize;
9
+ private readonly maxFiles;
10
+ private readonly maxAge;
11
+ private cachedDateString;
12
+ private cachedDateAt;
13
+ constructor(filePath: string, maxSize: number, maxFiles: number, maxAge?: number);
14
+ write(data: string): void;
15
+ private rotate;
16
+ private compressAndPrune;
17
+ flush(): Promise<void>;
18
+ end(): void;
19
+ /** Wait for all pending compressions to complete. */
20
+ drain(): Promise<void>;
21
+ private todayString;
22
+ private computeDateString;
23
+ /** Parse epoch ms from archive filename like `app.stdout.log-20260217T143052.123.gz` */
24
+ private parseArchiveTimestamp;
25
+ private formatTimestamp;
26
+ }
27
+ //# sourceMappingURL=RotatingWriter.d.ts.map