@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,281 @@
1
+ import { extractContext } from '@orkify/next/utils';
2
+ import { closeSync, existsSync, openSync, readFileSync, readSync, statSync } from 'node:fs';
3
+ import { dirname, isAbsolute, join } from 'node:path';
4
+ import { SourceMapConsumer } from 'source-map-js';
5
+ const SOURCEMAP_URL_RE = /\/[/*]#\s*sourceMappingURL=(\S+)\s*(?:\*\/)?$/;
6
+ /** Protocol prefixes used by bundlers in source map `sources` entries. */
7
+ const SOURCE_PROTOCOL_RE = /^(?:webpack:\/\/\/|webpack-internal:\/\/\/|webpack:\/\/[^/]*\/|vite-[\w-]+:\/\/)/;
8
+ /** Max bytes to read from the tail of a file to find sourceMappingURL. */
9
+ const TAIL_BYTES = 512;
10
+ /**
11
+ * Parse a base64-encoded inline source map from a data: URL.
12
+ * Returns the parsed JSON object, or null if parsing fails.
13
+ */
14
+ function parseInlineSourceMap(dataUrl) {
15
+ try {
16
+ const base64Idx = dataUrl.indexOf('base64,');
17
+ if (base64Idx === -1)
18
+ return null;
19
+ const raw = Buffer.from(dataUrl.slice(base64Idx + 7), 'base64').toString('utf8');
20
+ return JSON.parse(raw);
21
+ }
22
+ catch {
23
+ return null;
24
+ }
25
+ }
26
+ /**
27
+ * Scan lines (newest-first) for a sourceMappingURL comment.
28
+ * Returns the URL string or null.
29
+ */
30
+ function scanForSourceMapUrl(content) {
31
+ const lines = content.split('\n');
32
+ for (let i = lines.length - 1; i >= 0; i--) {
33
+ const match = lines[i].match(SOURCEMAP_URL_RE);
34
+ if (match)
35
+ return match[1];
36
+ }
37
+ return null;
38
+ }
39
+ function findSourceMap(filePath) {
40
+ try {
41
+ const stat = statSync(filePath);
42
+ const size = stat.size;
43
+ if (size === 0)
44
+ return null;
45
+ // Read only the tail of the file first (sourceMappingURL is always at the end).
46
+ // This is enough for external .map references (~40 chars).
47
+ const readSize = Math.min(size, TAIL_BYTES);
48
+ const buf = Buffer.alloc(readSize);
49
+ const fd = openSync(filePath, 'r');
50
+ try {
51
+ readSync(fd, buf, 0, readSize, size - readSize);
52
+ }
53
+ finally {
54
+ closeSync(fd);
55
+ }
56
+ const tail = buf.toString('utf8');
57
+ let url = scanForSourceMapUrl(tail);
58
+ // If no match in the tail but we didn't read the whole file, the comment
59
+ // might be a long inline data: URL whose "//# sourceMappingURL=" prefix
60
+ // falls outside our 512-byte window. Fall back to full read.
61
+ if (!url && readSize < size) {
62
+ const full = readFileSync(filePath, 'utf8');
63
+ url = scanForSourceMapUrl(full);
64
+ }
65
+ if (!url)
66
+ return null;
67
+ if (url.startsWith('data:')) {
68
+ const data = parseInlineSourceMap(url);
69
+ return data ? { type: 'inline', data } : null;
70
+ }
71
+ // External .map file
72
+ const resolvedPath = isAbsolute(url) ? url : join(dirname(filePath), url);
73
+ return { type: 'file', path: resolvedPath };
74
+ }
75
+ catch {
76
+ return null;
77
+ }
78
+ }
79
+ /**
80
+ * Strip bundler protocol prefixes from source paths.
81
+ * e.g. "webpack:///src/app.ts" → "src/app.ts"
82
+ * "webpack-internal:///./src/app.ts" → "./src/app.ts"
83
+ * "vite-node:///src/app.ts" → "src/app.ts"
84
+ */
85
+ function stripSourceProtocol(source) {
86
+ return source.replace(SOURCE_PROTOCOL_RE, '');
87
+ }
88
+ /**
89
+ * Resolve a source file path for display.
90
+ *
91
+ * For standalone bundler output (webpack/vite), `join(mapDir, source)` typically
92
+ * points to the real file. For Next.js, the source is relative to the project
93
+ * root (e.g. "src/app/page.tsx") but the .map lives deep inside .next/, so the
94
+ * naive join produces a wrong path. We walk up from the map directory looking
95
+ * for a package.json (project root marker) and resolve relative to that.
96
+ */
97
+ function resolveDisplayPath(cleanSource, mapDir) {
98
+ if (isAbsolute(cleanSource))
99
+ return cleanSource;
100
+ // Fast path: source exists relative to the map directory (standalone bundles)
101
+ const naiveJoin = join(mapDir, cleanSource);
102
+ if (existsSync(naiveJoin))
103
+ return naiveJoin;
104
+ // Walk up to find the project root (package.json), then resolve relative to it
105
+ let dir = mapDir;
106
+ const root = dirname(dir) === dir ? dir : '/'; // filesystem root
107
+ while (dir !== root) {
108
+ if (existsSync(join(dir, 'package.json'))) {
109
+ const candidate = join(dir, cleanSource);
110
+ if (existsSync(candidate))
111
+ return candidate;
112
+ }
113
+ dir = dirname(dir);
114
+ }
115
+ // Fallback: return the clean relative source as-is (still readable)
116
+ return cleanSource;
117
+ }
118
+ /**
119
+ * Try to resolve a single frame using its source map.
120
+ * Returns the resolved frame or null if resolution fails.
121
+ */
122
+ function resolveFrame(frame, consumerCache) {
123
+ // Find the source map (external file or inline data: URL)
124
+ const sourceMap = findSourceMap(frame.file);
125
+ let consumer;
126
+ let mapDir = dirname(frame.file);
127
+ if (sourceMap) {
128
+ if (sourceMap.type === 'inline') {
129
+ // Inline source map — create consumer directly from parsed data
130
+ try {
131
+ consumer = new SourceMapConsumer(sourceMap.data);
132
+ }
133
+ catch {
134
+ consumer = null;
135
+ }
136
+ }
137
+ else {
138
+ // External .map file — use cache
139
+ mapDir = dirname(sourceMap.path);
140
+ consumer = consumerCache.get(sourceMap.path);
141
+ if (consumer === undefined) {
142
+ try {
143
+ const raw = readFileSync(sourceMap.path, 'utf8');
144
+ consumer = new SourceMapConsumer(JSON.parse(raw));
145
+ consumerCache.set(sourceMap.path, consumer);
146
+ }
147
+ catch {
148
+ consumerCache.set(sourceMap.path, null);
149
+ return null;
150
+ }
151
+ }
152
+ }
153
+ }
154
+ else {
155
+ // Fallback: try <file>.map
156
+ const fallback = frame.file + '.map';
157
+ if (existsSync(fallback)) {
158
+ mapDir = dirname(fallback);
159
+ consumer = consumerCache.get(fallback);
160
+ if (consumer === undefined) {
161
+ try {
162
+ const raw = readFileSync(fallback, 'utf8');
163
+ consumer = new SourceMapConsumer(JSON.parse(raw));
164
+ consumerCache.set(fallback, consumer);
165
+ }
166
+ catch {
167
+ consumerCache.set(fallback, null);
168
+ return null;
169
+ }
170
+ }
171
+ }
172
+ else {
173
+ return null;
174
+ }
175
+ }
176
+ if (!consumer)
177
+ return null;
178
+ // Resolve the original position
179
+ const pos = consumer.originalPositionFor({
180
+ line: frame.line,
181
+ column: Math.max(0, (frame.column || 1) - 1),
182
+ });
183
+ if (!pos.source || !pos.line)
184
+ return null;
185
+ // Strip bundler protocol prefixes (webpack:///, vite-node://, etc.)
186
+ const cleanSource = stripSourceProtocol(pos.source);
187
+ // Get source content — prefer sourcesContent from the map, fall back to disk
188
+ let sourceContent = null;
189
+ try {
190
+ sourceContent = consumer.sourceContentFor(pos.source);
191
+ }
192
+ catch {
193
+ // Not available in sourcesContent
194
+ }
195
+ if (!sourceContent) {
196
+ // Try reading from disk using the cleaned source path
197
+ const displayPath = resolveDisplayPath(cleanSource, mapDir);
198
+ try {
199
+ sourceContent = readFileSync(displayPath, 'utf8');
200
+ }
201
+ catch {
202
+ return null;
203
+ }
204
+ }
205
+ const context = extractContext(sourceContent, pos.line);
206
+ if (!context)
207
+ return null;
208
+ // Resolve the display file path from the cleaned source
209
+ const file = resolveDisplayPath(cleanSource, mapDir);
210
+ return {
211
+ frame: {
212
+ file,
213
+ line: pos.line,
214
+ column: (pos.column ?? 0) + 1,
215
+ pre: context.pre,
216
+ target: context.target,
217
+ post: context.post,
218
+ },
219
+ functionName: pos.name || null,
220
+ };
221
+ }
222
+ /**
223
+ * Resolve source maps for all frames in an error's source context.
224
+ *
225
+ * For each frame, attempts to find and parse the corresponding .map file,
226
+ * then replaces the minified location with the original source location.
227
+ * Frames that can't be resolved are kept as-is.
228
+ *
229
+ * Returns the resolved function name from the source map (if available)
230
+ * so the caller can use it for fingerprinting.
231
+ */
232
+ export function resolveSourceMaps(sourceContext, topFrame) {
233
+ if (!sourceContext || sourceContext.length === 0) {
234
+ return { sourceContext, topFrame, resolvedFunctionName: null, resolved: false };
235
+ }
236
+ try {
237
+ const consumerCache = new Map();
238
+ const resolvedFrames = [];
239
+ let anyResolved = false;
240
+ let resolvedTopFrame = null;
241
+ let resolvedFunctionName = null;
242
+ for (const frame of sourceContext) {
243
+ try {
244
+ const result = resolveFrame(frame, consumerCache);
245
+ if (result) {
246
+ resolvedFrames.push(result.frame);
247
+ anyResolved = true;
248
+ if (!resolvedTopFrame) {
249
+ resolvedTopFrame = {
250
+ file: result.frame.file,
251
+ line: result.frame.line,
252
+ column: result.frame.column,
253
+ };
254
+ resolvedFunctionName = result.functionName;
255
+ }
256
+ }
257
+ else {
258
+ resolvedFrames.push(frame);
259
+ }
260
+ }
261
+ catch {
262
+ // Per-frame try/catch: one bad frame doesn't block others
263
+ resolvedFrames.push(frame);
264
+ }
265
+ }
266
+ if (!anyResolved) {
267
+ return { sourceContext, topFrame, resolvedFunctionName: null, resolved: false };
268
+ }
269
+ return {
270
+ sourceContext: resolvedFrames,
271
+ topFrame: resolvedTopFrame ?? topFrame,
272
+ resolvedFunctionName,
273
+ resolved: true,
274
+ };
275
+ }
276
+ catch {
277
+ // Never crash the daemon — return original data
278
+ return { sourceContext, topFrame, resolvedFunctionName: null, resolved: false };
279
+ }
280
+ }
281
+ //# sourceMappingURL=resolve-sourcemaps.js.map
@@ -0,0 +1,11 @@
1
+ import type { McpStartPayload, ProcessConfig, SavedState } from '../types/index.js';
2
+ export declare class StateStore {
3
+ private filePath;
4
+ constructor(filePath?: string);
5
+ save(processes: ProcessConfig[], mcp?: McpStartPayload): Promise<void>;
6
+ load(): Promise<ProcessConfig[]>;
7
+ loadFull(): Promise<SavedState>;
8
+ clear(): Promise<void>;
9
+ exists(): Promise<boolean>;
10
+ }
11
+ //# sourceMappingURL=StateStore.d.ts.map
@@ -0,0 +1,78 @@
1
+ import { existsSync } from 'node:fs';
2
+ import { mkdir, readFile, rename, writeFile } from 'node:fs/promises';
3
+ import { dirname } from 'node:path';
4
+ import { parse, stringify } from 'yaml';
5
+ import { validateMcpState } from '../config/schema.js';
6
+ import { SNAPSHOT_FILE } from '../constants.js';
7
+ const STATE_VERSION = 1;
8
+ export class StateStore {
9
+ filePath;
10
+ constructor(filePath = SNAPSHOT_FILE) {
11
+ this.filePath = filePath;
12
+ }
13
+ async save(processes, mcp) {
14
+ const state = {
15
+ version: STATE_VERSION,
16
+ processes,
17
+ ...(mcp ? { mcp } : {}),
18
+ };
19
+ // Ensure directory exists
20
+ const dir = dirname(this.filePath);
21
+ if (!existsSync(dir)) {
22
+ await mkdir(dir, { recursive: true });
23
+ }
24
+ // Atomic write: write to temp file then rename to prevent corruption
25
+ // if the process crashes mid-write
26
+ const tmpPath = this.filePath + '.tmp';
27
+ await writeFile(tmpPath, stringify(state, { defaultStringType: 'QUOTE_DOUBLE' }), 'utf-8');
28
+ await rename(tmpPath, this.filePath);
29
+ }
30
+ async load() {
31
+ const state = await this.loadFull();
32
+ return state.processes;
33
+ }
34
+ async loadFull() {
35
+ if (!existsSync(this.filePath)) {
36
+ return { processes: [] };
37
+ }
38
+ try {
39
+ const content = await readFile(this.filePath, 'utf-8');
40
+ const state = parse(content);
41
+ const version = state?.version ?? 1;
42
+ if (version !== STATE_VERSION) {
43
+ console.warn(`Snapshot file version mismatch: expected ${STATE_VERSION}, got ${version}`);
44
+ }
45
+ const processes = state?.processes || [];
46
+ // Coerce env values to strings — YAML parses unquoted values like
47
+ // `PORT: 3000` as numbers and `VERBOSE: yes` as booleans. Environment
48
+ // variables must always be strings.
49
+ for (const proc of processes) {
50
+ if (proc.env && typeof proc.env === 'object') {
51
+ for (const [key, value] of Object.entries(proc.env)) {
52
+ if (typeof value !== 'string') {
53
+ proc.env[key] = value === null || value === undefined ? '' : String(value);
54
+ }
55
+ }
56
+ }
57
+ }
58
+ const mcp = validateMcpState(state?.mcp) ? state.mcp : undefined;
59
+ if (state?.mcp && !mcp) {
60
+ console.warn('Snapshot contains invalid mcp section — ignoring');
61
+ }
62
+ return { ...state, processes, mcp };
63
+ }
64
+ catch (err) {
65
+ console.error('Failed to load snapshot:', err);
66
+ return { processes: [] };
67
+ }
68
+ }
69
+ async clear() {
70
+ if (existsSync(this.filePath)) {
71
+ await writeFile(this.filePath, stringify({ version: STATE_VERSION, processes: [] }, { defaultStringType: 'QUOTE_DOUBLE' }), 'utf-8');
72
+ }
73
+ }
74
+ async exists() {
75
+ return existsSync(this.filePath);
76
+ }
77
+ }
78
+ //# sourceMappingURL=StateStore.js.map
@@ -0,0 +1,49 @@
1
+ import { EventEmitter } from 'node:events';
2
+ import type { AlertEvaluator } from '../alerts/AlertEvaluator.js';
3
+ import type { ConfigStore } from '../config/ConfigStore.js';
4
+ import type { Orchestrator } from '../daemon/Orchestrator.js';
5
+ import type { DeployStatus, TelemetryConfig, TelemetryEventType } from '../types/index.js';
6
+ export declare class TelemetryReporter extends EventEmitter {
7
+ private config;
8
+ private orchestrator;
9
+ private events;
10
+ private metrics;
11
+ private errors;
12
+ private logRings;
13
+ private logFlushBuffer;
14
+ private logFlushDropped;
15
+ private timer;
16
+ private hostName;
17
+ private agentName;
18
+ private machineId;
19
+ private hostInfo;
20
+ private _deployStatus;
21
+ private configStore;
22
+ private alertEvaluator;
23
+ private mcpCapable;
24
+ /** Previous cumulative cache counters per worker — keyed by "processName:workerId" */
25
+ private prevCacheCounters;
26
+ constructor(config: TelemetryConfig, orchestrator: Orchestrator, configStore?: ConfigStore | null, alertEvaluator?: AlertEvaluator | null);
27
+ start(): void;
28
+ shutdown(): Promise<void>;
29
+ private bindEvents;
30
+ /**
31
+ * Get logs for a specific worker. In cluster mode, worker stdout/stderr flows
32
+ * through the primary process (workerId -1), so if the worker-specific ring
33
+ * is empty we fall back to the primary's ring.
34
+ */
35
+ private getWorkerLogs;
36
+ private clearWorkerLogs;
37
+ private pushEvent;
38
+ emitEvent(type: TelemetryEventType, processName: string, fields?: Record<string, unknown>): void;
39
+ setDeployStatus(status: DeployStatus | null): void;
40
+ setMcpCapable(v: boolean): void;
41
+ private collectAndFlush;
42
+ /**
43
+ * Drain the log flush buffer, capping at TELEMETRY_LOG_FLUSH_MAX_LINES per
44
+ * worker. When lines are dropped, prepend a truncation marker.
45
+ */
46
+ private drainLogFlushBuffer;
47
+ private restoreBuffers;
48
+ }
49
+ //# sourceMappingURL=TelemetryReporter.d.ts.map