everything-dev 0.3.3 → 1.3.3

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 (313) hide show
  1. package/README.md +64 -0
  2. package/cli.js +10 -0
  3. package/dist/_virtual/_rolldown/runtime.cjs +29 -0
  4. package/dist/api-contract.cjs +172 -0
  5. package/dist/api-contract.cjs.map +1 -0
  6. package/dist/api-contract.mjs +171 -0
  7. package/dist/api-contract.mjs.map +1 -0
  8. package/dist/api.cjs +124 -0
  9. package/dist/api.cjs.map +1 -0
  10. package/dist/api.d.cts +36 -0
  11. package/dist/api.d.cts.map +1 -0
  12. package/dist/api.d.mts +36 -0
  13. package/dist/api.d.mts.map +1 -0
  14. package/dist/api.mjs +119 -0
  15. package/dist/api.mjs.map +1 -0
  16. package/dist/app.cjs +156 -0
  17. package/dist/app.cjs.map +1 -0
  18. package/dist/app.mjs +153 -0
  19. package/dist/app.mjs.map +1 -0
  20. package/dist/cli/catalog.cjs +30 -0
  21. package/dist/cli/catalog.cjs.map +1 -0
  22. package/dist/cli/catalog.mjs +29 -0
  23. package/dist/cli/catalog.mjs.map +1 -0
  24. package/dist/cli/help.cjs +16 -0
  25. package/dist/cli/help.cjs.map +1 -0
  26. package/dist/cli/help.mjs +16 -0
  27. package/dist/cli/help.mjs.map +1 -0
  28. package/dist/cli/init.cjs +287 -0
  29. package/dist/cli/init.cjs.map +1 -0
  30. package/dist/cli/init.d.cts +36 -0
  31. package/dist/cli/init.d.cts.map +1 -0
  32. package/dist/cli/init.d.mts +36 -0
  33. package/dist/cli/init.d.mts.map +1 -0
  34. package/dist/cli/init.mjs +279 -0
  35. package/dist/cli/init.mjs.map +1 -0
  36. package/dist/cli/parse.cjs +96 -0
  37. package/dist/cli/parse.cjs.map +1 -0
  38. package/dist/cli/parse.mjs +95 -0
  39. package/dist/cli/parse.mjs.map +1 -0
  40. package/dist/cli/prompts.cjs +42 -0
  41. package/dist/cli/prompts.cjs.map +1 -0
  42. package/dist/cli/prompts.mjs +41 -0
  43. package/dist/cli/prompts.mjs.map +1 -0
  44. package/dist/cli.cjs +167 -0
  45. package/dist/cli.cjs.map +1 -0
  46. package/dist/cli.d.cts +1 -0
  47. package/dist/cli.d.mts +1 -0
  48. package/dist/cli.mjs +166 -0
  49. package/dist/cli.mjs.map +1 -0
  50. package/dist/components/dev-view.cjs +307 -0
  51. package/dist/components/dev-view.cjs.map +1 -0
  52. package/dist/components/dev-view.mjs +306 -0
  53. package/dist/components/dev-view.mjs.map +1 -0
  54. package/dist/components/streaming-view.cjs +146 -0
  55. package/dist/components/streaming-view.cjs.map +1 -0
  56. package/dist/components/streaming-view.mjs +144 -0
  57. package/dist/components/streaming-view.mjs.map +1 -0
  58. package/dist/config.cjs +280 -0
  59. package/dist/config.cjs.map +1 -0
  60. package/dist/config.d.cts +35 -0
  61. package/dist/config.d.cts.map +1 -0
  62. package/dist/config.d.mts +35 -0
  63. package/dist/config.d.mts.map +1 -0
  64. package/dist/config.mjs +266 -0
  65. package/dist/config.mjs.map +1 -0
  66. package/dist/contract.cjs +209 -0
  67. package/dist/contract.cjs.map +1 -0
  68. package/dist/contract.d.cts +490 -0
  69. package/dist/contract.d.cts.map +1 -0
  70. package/dist/contract.d.mts +490 -0
  71. package/dist/contract.d.mts.map +1 -0
  72. package/dist/contract.meta.cjs +104 -0
  73. package/dist/contract.meta.cjs.map +1 -0
  74. package/dist/contract.meta.d.cts +141 -0
  75. package/dist/contract.meta.d.cts.map +1 -0
  76. package/dist/contract.meta.d.mts +141 -0
  77. package/dist/contract.meta.d.mts.map +1 -0
  78. package/dist/contract.meta.mjs +102 -0
  79. package/dist/contract.meta.mjs.map +1 -0
  80. package/dist/contract.mjs +186 -0
  81. package/dist/contract.mjs.map +1 -0
  82. package/dist/dev-logs.cjs +53 -0
  83. package/dist/dev-logs.cjs.map +1 -0
  84. package/dist/dev-logs.mjs +51 -0
  85. package/dist/dev-logs.mjs.map +1 -0
  86. package/dist/dev-session.cjs +195 -0
  87. package/dist/dev-session.cjs.map +1 -0
  88. package/dist/dev-session.mjs +194 -0
  89. package/dist/dev-session.mjs.map +1 -0
  90. package/dist/fastkv.cjs +89 -0
  91. package/dist/fastkv.cjs.map +1 -0
  92. package/dist/fastkv.d.cts +11 -0
  93. package/dist/fastkv.d.cts.map +1 -0
  94. package/dist/fastkv.d.mts +11 -0
  95. package/dist/fastkv.d.mts.map +1 -0
  96. package/dist/fastkv.mjs +82 -0
  97. package/dist/fastkv.mjs.map +1 -0
  98. package/dist/federation.server.cjs +27 -0
  99. package/dist/federation.server.cjs.map +1 -0
  100. package/dist/federation.server.mjs +27 -0
  101. package/dist/federation.server.mjs.map +1 -0
  102. package/dist/host.cjs +367 -0
  103. package/dist/host.cjs.map +1 -0
  104. package/dist/host.d.cts +22 -0
  105. package/dist/host.d.cts.map +1 -0
  106. package/dist/host.d.mts +22 -0
  107. package/dist/host.d.mts.map +1 -0
  108. package/dist/host.mjs +364 -0
  109. package/dist/host.mjs.map +1 -0
  110. package/dist/index.cjs +122 -0
  111. package/dist/index.d.cts +7 -0
  112. package/dist/index.d.mts +7 -0
  113. package/dist/index.mjs +9 -0
  114. package/dist/integrity.cjs +39 -0
  115. package/dist/integrity.cjs.map +1 -0
  116. package/dist/integrity.d.cts +7 -0
  117. package/dist/integrity.d.cts.map +1 -0
  118. package/dist/integrity.d.mts +7 -0
  119. package/dist/integrity.d.mts.map +1 -0
  120. package/dist/integrity.mjs +35 -0
  121. package/dist/integrity.mjs.map +1 -0
  122. package/dist/internal/manifest-normalizer.cjs +140 -0
  123. package/dist/internal/manifest-normalizer.cjs.map +1 -0
  124. package/dist/internal/manifest-normalizer.mjs +138 -0
  125. package/dist/internal/manifest-normalizer.mjs.map +1 -0
  126. package/dist/mf.cjs +77 -0
  127. package/dist/mf.cjs.map +1 -0
  128. package/dist/mf.d.cts +19 -0
  129. package/dist/mf.d.cts.map +1 -0
  130. package/dist/mf.d.mts +19 -0
  131. package/dist/mf.d.mts.map +1 -0
  132. package/dist/mf.mjs +71 -0
  133. package/dist/mf.mjs.map +1 -0
  134. package/dist/near-cli.cjs +196 -0
  135. package/dist/near-cli.cjs.map +1 -0
  136. package/dist/near-cli.mjs +193 -0
  137. package/dist/near-cli.mjs.map +1 -0
  138. package/dist/network.cjs +9 -0
  139. package/dist/network.cjs.map +1 -0
  140. package/dist/network.mjs +8 -0
  141. package/dist/network.mjs.map +1 -0
  142. package/dist/orchestrator.cjs +441 -0
  143. package/dist/orchestrator.cjs.map +1 -0
  144. package/dist/orchestrator.d.cts +40 -0
  145. package/dist/orchestrator.d.cts.map +1 -0
  146. package/dist/orchestrator.d.mts +40 -0
  147. package/dist/orchestrator.d.mts.map +1 -0
  148. package/dist/orchestrator.mjs +436 -0
  149. package/dist/orchestrator.mjs.map +1 -0
  150. package/dist/plugin.cjs +830 -0
  151. package/dist/plugin.cjs.map +1 -0
  152. package/dist/plugin.d.cts +347 -0
  153. package/dist/plugin.d.cts.map +1 -0
  154. package/dist/plugin.d.mts +348 -0
  155. package/dist/plugin.d.mts.map +1 -0
  156. package/dist/plugin.mjs +827 -0
  157. package/dist/plugin.mjs.map +1 -0
  158. package/dist/process-registry.cjs +120 -0
  159. package/dist/process-registry.cjs.map +1 -0
  160. package/dist/process-registry.d.cts +25 -0
  161. package/dist/process-registry.d.cts.map +1 -0
  162. package/dist/process-registry.d.mts +25 -0
  163. package/dist/process-registry.d.mts.map +1 -0
  164. package/dist/process-registry.mjs +119 -0
  165. package/dist/process-registry.mjs.map +1 -0
  166. package/dist/sdk.cjs +61 -0
  167. package/dist/sdk.d.cts +5 -0
  168. package/dist/sdk.d.mts +5 -0
  169. package/dist/sdk.mjs +6 -0
  170. package/dist/shared.cjs +143 -0
  171. package/dist/shared.cjs.map +1 -0
  172. package/dist/shared.d.cts +33 -0
  173. package/dist/shared.d.cts.map +1 -0
  174. package/dist/shared.d.mts +33 -0
  175. package/dist/shared.d.mts.map +1 -0
  176. package/dist/shared.mjs +140 -0
  177. package/dist/shared.mjs.map +1 -0
  178. package/dist/types.cjs +160 -0
  179. package/dist/types.cjs.map +1 -0
  180. package/dist/types.d.cts +269 -0
  181. package/dist/types.d.cts.map +1 -0
  182. package/dist/types.d.mts +269 -0
  183. package/dist/types.d.mts.map +1 -0
  184. package/dist/types.mjs +144 -0
  185. package/dist/types.mjs.map +1 -0
  186. package/dist/ui/head.cjs +67 -0
  187. package/dist/ui/head.cjs.map +1 -0
  188. package/dist/ui/head.d.cts +19 -0
  189. package/dist/ui/head.d.cts.map +1 -0
  190. package/dist/ui/head.d.mts +19 -0
  191. package/dist/ui/head.d.mts.map +1 -0
  192. package/dist/ui/head.mjs +61 -0
  193. package/dist/ui/head.mjs.map +1 -0
  194. package/dist/ui/index.cjs +32 -0
  195. package/dist/ui/index.d.cts +7 -0
  196. package/dist/ui/index.d.mts +7 -0
  197. package/dist/ui/index.mjs +6 -0
  198. package/dist/ui/metadata.cjs +106 -0
  199. package/dist/ui/metadata.cjs.map +1 -0
  200. package/dist/ui/metadata.d.cts +35 -0
  201. package/dist/ui/metadata.d.cts.map +1 -0
  202. package/dist/ui/metadata.d.mts +35 -0
  203. package/dist/ui/metadata.d.mts.map +1 -0
  204. package/dist/ui/metadata.mjs +100 -0
  205. package/dist/ui/metadata.mjs.map +1 -0
  206. package/dist/ui/router.cjs +56 -0
  207. package/dist/ui/router.cjs.map +1 -0
  208. package/dist/ui/router.d.cts +11 -0
  209. package/dist/ui/router.d.cts.map +1 -0
  210. package/dist/ui/router.d.mts +11 -0
  211. package/dist/ui/router.d.mts.map +1 -0
  212. package/dist/ui/router.mjs +51 -0
  213. package/dist/ui/router.mjs.map +1 -0
  214. package/dist/ui/runtime.cjs +65 -0
  215. package/dist/ui/runtime.cjs.map +1 -0
  216. package/dist/ui/runtime.d.cts +29 -0
  217. package/dist/ui/runtime.d.cts.map +1 -0
  218. package/dist/ui/runtime.d.mts +29 -0
  219. package/dist/ui/runtime.d.mts.map +1 -0
  220. package/dist/ui/runtime.mjs +53 -0
  221. package/dist/ui/runtime.mjs.map +1 -0
  222. package/dist/ui/types.cjs +0 -0
  223. package/dist/ui/types.d.cts +52 -0
  224. package/dist/ui/types.d.cts.map +1 -0
  225. package/dist/ui/types.d.mts +52 -0
  226. package/dist/ui/types.d.mts.map +1 -0
  227. package/dist/ui/types.mjs +1 -0
  228. package/dist/utils/banner.cjs +24 -0
  229. package/dist/utils/banner.cjs.map +1 -0
  230. package/dist/utils/banner.mjs +23 -0
  231. package/dist/utils/banner.mjs.map +1 -0
  232. package/dist/utils/linkify.cjs +15 -0
  233. package/dist/utils/linkify.cjs.map +1 -0
  234. package/dist/utils/linkify.mjs +14 -0
  235. package/dist/utils/linkify.mjs.map +1 -0
  236. package/dist/utils/run.cjs +40 -0
  237. package/dist/utils/run.cjs.map +1 -0
  238. package/dist/utils/run.mjs +39 -0
  239. package/dist/utils/run.mjs.map +1 -0
  240. package/dist/utils/theme.cjs +44 -0
  241. package/dist/utils/theme.cjs.map +1 -0
  242. package/dist/utils/theme.mjs +37 -0
  243. package/dist/utils/theme.mjs.map +1 -0
  244. package/package.json +269 -80
  245. package/src/api-contract.ts +309 -0
  246. package/src/api.ts +181 -0
  247. package/src/app.ts +346 -0
  248. package/src/cli/catalog.ts +49 -0
  249. package/src/cli/help.ts +13 -0
  250. package/src/cli/init.ts +386 -0
  251. package/src/cli/parse.ts +130 -0
  252. package/src/cli/prompts.ts +64 -0
  253. package/src/cli.ts +203 -1507
  254. package/src/components/dev-view.tsx +307 -255
  255. package/src/components/streaming-view.ts +164 -128
  256. package/src/config.ts +462 -532
  257. package/src/contract.meta.ts +96 -0
  258. package/src/contract.ts +164 -561
  259. package/src/dev-logs.ts +85 -0
  260. package/src/dev-session.ts +318 -0
  261. package/src/fastkv.ts +153 -0
  262. package/src/federation.server.ts +43 -0
  263. package/src/host.ts +526 -0
  264. package/src/index.ts +6 -3
  265. package/src/integrity.ts +54 -0
  266. package/src/internal/manifest-normalizer.ts +251 -0
  267. package/src/mf.ts +105 -0
  268. package/src/near-cli.ts +284 -0
  269. package/src/network.ts +3 -0
  270. package/src/orchestrator.ts +648 -0
  271. package/src/plugin.ts +1130 -2311
  272. package/src/process-registry.ts +154 -0
  273. package/src/scripts/sync-api-contract.ts +24 -0
  274. package/src/sdk.ts +14 -0
  275. package/src/shared.ts +206 -0
  276. package/src/types.ts +152 -206
  277. package/src/ui/head.ts +34 -27
  278. package/src/ui/index.ts +3 -3
  279. package/src/ui/metadata.ts +95 -0
  280. package/src/ui/router.ts +22 -6
  281. package/src/ui/runtime.ts +55 -6
  282. package/src/ui/types.ts +24 -11
  283. package/src/utils/banner.ts +10 -6
  284. package/src/utils/run.ts +26 -27
  285. package/src/utils/theme.ts +3 -66
  286. package/src/components/monitor-view.tsx +0 -475
  287. package/src/components/status-view.tsx +0 -173
  288. package/src/lib/env.ts +0 -109
  289. package/src/lib/near-cli.ts +0 -289
  290. package/src/lib/nova.ts +0 -266
  291. package/src/lib/orchestrator.ts +0 -276
  292. package/src/lib/process-registry.ts +0 -166
  293. package/src/lib/process.ts +0 -550
  294. package/src/lib/resource-monitor/assertions.ts +0 -234
  295. package/src/lib/resource-monitor/command.ts +0 -283
  296. package/src/lib/resource-monitor/diff.ts +0 -157
  297. package/src/lib/resource-monitor/errors.ts +0 -127
  298. package/src/lib/resource-monitor/index.ts +0 -305
  299. package/src/lib/resource-monitor/platform/darwin.ts +0 -306
  300. package/src/lib/resource-monitor/platform/index.ts +0 -35
  301. package/src/lib/resource-monitor/platform/linux.ts +0 -332
  302. package/src/lib/resource-monitor/platform/windows.ts +0 -298
  303. package/src/lib/resource-monitor/snapshot.ts +0 -217
  304. package/src/lib/resource-monitor/types.ts +0 -74
  305. package/src/lib/session-recorder/errors.ts +0 -102
  306. package/src/lib/session-recorder/flows/login.ts +0 -210
  307. package/src/lib/session-recorder/index.ts +0 -361
  308. package/src/lib/session-recorder/playwright.ts +0 -257
  309. package/src/lib/session-recorder/report.ts +0 -353
  310. package/src/lib/session-recorder/server.ts +0 -268
  311. package/src/lib/session-recorder/types.ts +0 -115
  312. package/src/lib/sync.ts +0 -1
  313. package/src/ui/files.ts +0 -134
@@ -1,234 +0,0 @@
1
- import { Effect } from "effect";
2
- import {
3
- MemoryLimitExceeded,
4
- MemoryPercentExceeded,
5
- OrphanedProcesses,
6
- PortStillBound,
7
- ProcessesStillAlive,
8
- ResourceLeaks,
9
- } from "./errors";
10
- import { PlatformService, withPlatform } from "./platform";
11
- import { isProcessAlive } from "./snapshot";
12
- import type { Snapshot, SnapshotDiff } from "./types";
13
-
14
- export const assertAllPortsFree = (
15
- ports: number[]
16
- ): Effect.Effect<void, PortStillBound, PlatformService> =>
17
- Effect.gen(function* () {
18
- yield* Effect.logInfo(`Asserting ${ports.length} ports are free`);
19
-
20
- const platform = yield* PlatformService;
21
- const portInfo = yield* platform.getPortInfo(ports);
22
-
23
- const bound: Array<{
24
- port: number;
25
- pid: number | null;
26
- command: string | null;
27
- }> = [];
28
-
29
- for (const [portStr, info] of Object.entries(portInfo)) {
30
- if (info.state !== "FREE") {
31
- bound.push({
32
- port: parseInt(portStr, 10),
33
- pid: info.pid,
34
- command: info.command,
35
- });
36
- }
37
- }
38
-
39
- if (bound.length > 0) {
40
- yield* Effect.logError(`${bound.length} ports still bound:`);
41
- for (const p of bound) {
42
- yield* Effect.logError(` :${p.port} ← PID ${p.pid} (${p.command})`);
43
- }
44
- return yield* Effect.fail(new PortStillBound({ ports: bound }));
45
- }
46
-
47
- yield* Effect.logInfo(`All ${ports.length} ports are free ✓`);
48
- });
49
-
50
- export const assertAllPortsFreeWithPlatform = (
51
- ports: number[]
52
- ): Effect.Effect<void, PortStillBound> =>
53
- withPlatform(assertAllPortsFree(ports));
54
-
55
- export const assertNoOrphanProcesses = (
56
- runningSnapshot: Snapshot,
57
- afterSnapshot: Snapshot
58
- ): Effect.Effect<void, OrphanedProcesses> =>
59
- Effect.gen(function* () {
60
- yield* Effect.logInfo("Checking for orphaned processes");
61
-
62
- const runningPids = new Set(runningSnapshot.processes.map((p) => p.pid));
63
-
64
- const orphans: Array<{ pid: number; command: string; rss: number }> = [];
65
-
66
- for (const proc of runningSnapshot.processes) {
67
- if (!runningPids.has(proc.pid)) continue;
68
-
69
- const stillInAfter = afterSnapshot.processes.some(
70
- (p) => p.pid === proc.pid
71
- );
72
- if (stillInAfter) continue;
73
-
74
- const alive = yield* isProcessAlive(proc.pid);
75
- if (alive) {
76
- orphans.push({
77
- pid: proc.pid,
78
- command: proc.command,
79
- rss: proc.rss,
80
- });
81
- }
82
- }
83
-
84
- if (orphans.length > 0) {
85
- yield* Effect.logError(`${orphans.length} orphaned processes found:`);
86
- for (const p of orphans) {
87
- yield* Effect.logError(
88
- ` PID ${p.pid}: ${p.command} (${(p.rss / 1024 / 1024).toFixed(1)}MB)`
89
- );
90
- }
91
- return yield* Effect.fail(new OrphanedProcesses({ processes: orphans }));
92
- }
93
-
94
- yield* Effect.logInfo("No orphaned processes ✓");
95
- });
96
-
97
- export const assertMemoryDelta = (
98
- baseline: Snapshot,
99
- after: Snapshot,
100
- options: { maxDeltaMB?: number; maxDeltaPercent?: number }
101
- ): Effect.Effect<void, MemoryLimitExceeded | MemoryPercentExceeded> =>
102
- Effect.gen(function* () {
103
- yield* Effect.logInfo("Checking memory delta");
104
-
105
- const deltaMB =
106
- (after.memory.processRss - baseline.memory.processRss) / 1024 / 1024;
107
-
108
- yield* Effect.logDebug(
109
- `Memory delta: ${deltaMB >= 0 ? "+" : ""}${deltaMB.toFixed(1)}MB`
110
- );
111
-
112
- if (options.maxDeltaMB !== undefined && deltaMB > options.maxDeltaMB) {
113
- yield* Effect.logError(
114
- `Memory delta ${deltaMB.toFixed(1)}MB exceeds max ${options.maxDeltaMB}MB`
115
- );
116
- return yield* Effect.fail(
117
- new MemoryLimitExceeded({
118
- deltaMB,
119
- limitMB: options.maxDeltaMB,
120
- baselineRss: baseline.memory.processRss,
121
- afterRss: after.memory.processRss,
122
- })
123
- );
124
- }
125
-
126
- if (options.maxDeltaPercent !== undefined && baseline.memory.processRss > 0) {
127
- const deltaPercent =
128
- ((after.memory.processRss - baseline.memory.processRss) /
129
- baseline.memory.processRss) *
130
- 100;
131
-
132
- yield* Effect.logDebug(
133
- `Memory delta: ${deltaPercent >= 0 ? "+" : ""}${deltaPercent.toFixed(1)}%`
134
- );
135
-
136
- if (deltaPercent > options.maxDeltaPercent) {
137
- yield* Effect.logError(
138
- `Memory delta ${deltaPercent.toFixed(1)}% exceeds max ${options.maxDeltaPercent}%`
139
- );
140
- return yield* Effect.fail(
141
- new MemoryPercentExceeded({
142
- deltaPercent,
143
- limitPercent: options.maxDeltaPercent,
144
- baselineRss: baseline.memory.processRss,
145
- afterRss: after.memory.processRss,
146
- })
147
- );
148
- }
149
- }
150
-
151
- yield* Effect.logInfo("Memory delta within limits ✓");
152
- });
153
-
154
- export const assertProcessesDead = (
155
- pids: number[]
156
- ): Effect.Effect<void, ProcessesStillAlive> =>
157
- Effect.gen(function* () {
158
- yield* Effect.logInfo(`Asserting ${pids.length} processes are dead`);
159
-
160
- const stillAlive: number[] = [];
161
-
162
- for (const pid of pids) {
163
- const alive = yield* isProcessAlive(pid);
164
- if (alive) {
165
- stillAlive.push(pid);
166
- }
167
- }
168
-
169
- if (stillAlive.length > 0) {
170
- yield* Effect.logError(
171
- `${stillAlive.length} processes still alive: ${stillAlive.join(", ")}`
172
- );
173
- return yield* Effect.fail(new ProcessesStillAlive({ pids: stillAlive }));
174
- }
175
-
176
- yield* Effect.logInfo(`All ${pids.length} processes are dead ✓`);
177
- });
178
-
179
- export const assertNoLeaks = (
180
- diff: SnapshotDiff
181
- ): Effect.Effect<void, ResourceLeaks> =>
182
- Effect.gen(function* () {
183
- yield* Effect.logInfo("Checking for resource leaks");
184
-
185
- if (
186
- diff.orphanedProcesses.length > 0 ||
187
- diff.stillBoundPorts.length > 0
188
- ) {
189
- yield* Effect.logError("Resource leaks detected:");
190
-
191
- for (const proc of diff.orphanedProcesses) {
192
- yield* Effect.logError(
193
- ` Orphaned PID ${proc.pid}: ${proc.command} (${(proc.rss / 1024 / 1024).toFixed(1)}MB)`
194
- );
195
- }
196
-
197
- for (const port of diff.stillBoundPorts) {
198
- yield* Effect.logError(
199
- ` Port :${port.port} still bound to PID ${port.pid} (${port.command})`
200
- );
201
- }
202
-
203
- return yield* Effect.fail(
204
- new ResourceLeaks({
205
- orphanedProcesses: diff.orphanedProcesses,
206
- stillBoundPorts: diff.stillBoundPorts,
207
- })
208
- );
209
- }
210
-
211
- yield* Effect.logInfo("No resource leaks detected ✓");
212
- });
213
-
214
- export const assertCleanState = (
215
- baseline: Snapshot
216
- ): Effect.Effect<void, PortStillBound | ProcessesStillAlive, PlatformService> =>
217
- Effect.gen(function* () {
218
- yield* Effect.logInfo("Asserting clean state");
219
-
220
- const ports = Object.keys(baseline.ports).map((p) => parseInt(p, 10));
221
- yield* assertAllPortsFree(ports);
222
-
223
- const pids = baseline.processes.map((p) => p.pid);
224
- if (pids.length > 0) {
225
- yield* assertProcessesDead(pids);
226
- }
227
-
228
- yield* Effect.logInfo("Clean state verified ✓");
229
- });
230
-
231
- export const assertCleanStateWithPlatform = (
232
- baseline: Snapshot
233
- ): Effect.Effect<void, PortStillBound | ProcessesStillAlive> =>
234
- withPlatform(assertCleanState(baseline));
@@ -1,283 +0,0 @@
1
- import { Effect, Schedule } from "effect";
2
- import { execa } from "execa";
3
- import { CommandFailed, CommandTimeout } from "./errors";
4
-
5
- export interface ExecOptions {
6
- cwd?: string;
7
- timeout?: number;
8
- retries?: number;
9
- silent?: boolean;
10
- }
11
-
12
- const DEFAULT_TIMEOUT = 10000;
13
- const DEFAULT_RETRIES = 1;
14
-
15
- export const execCommand = (
16
- cmd: string,
17
- args: string[],
18
- options?: ExecOptions
19
- ): Effect.Effect<string, CommandFailed | CommandTimeout> =>
20
- Effect.gen(function* () {
21
- const timeout = options?.timeout ?? DEFAULT_TIMEOUT;
22
- const silent = options?.silent ?? false;
23
-
24
- if (!silent) {
25
- yield* Effect.logDebug(`Executing: ${cmd} ${args.join(" ")}`);
26
- }
27
-
28
- const result = yield* Effect.tryPromise({
29
- try: async () => {
30
- const proc = await execa(cmd, args, {
31
- cwd: options?.cwd,
32
- timeout,
33
- reject: false,
34
- shell: true,
35
- });
36
- return {
37
- stdout: proc.stdout?.trim() ?? "",
38
- stderr: proc.stderr?.trim() ?? "",
39
- exitCode: proc.exitCode,
40
- timedOut: proc.timedOut,
41
- };
42
- },
43
- catch: (error) => {
44
- const err = error as { timedOut?: boolean; message?: string };
45
- if (err.timedOut) {
46
- return new CommandTimeout({ command: cmd, timeoutMs: timeout });
47
- }
48
- return new CommandFailed({
49
- command: cmd,
50
- args,
51
- exitCode: -1,
52
- stderr: String(error),
53
- });
54
- },
55
- });
56
-
57
- if (result.timedOut) {
58
- return yield* Effect.fail(
59
- new CommandTimeout({ command: cmd, timeoutMs: timeout })
60
- );
61
- }
62
-
63
- if (result.exitCode !== 0) {
64
- if (!silent) {
65
- yield* Effect.logWarning(
66
- `Command failed: ${cmd} (exit ${result.exitCode})`
67
- );
68
- }
69
- return yield* Effect.fail(
70
- new CommandFailed({
71
- command: cmd,
72
- args,
73
- exitCode: result.exitCode ?? 1,
74
- stderr: result.stderr,
75
- })
76
- );
77
- }
78
-
79
- if (!silent) {
80
- yield* Effect.logDebug(`Command succeeded: ${cmd}`);
81
- }
82
-
83
- return result.stdout;
84
- }).pipe(
85
- Effect.retry(
86
- Schedule.recurs(options?.retries ?? DEFAULT_RETRIES).pipe(
87
- Schedule.addDelay(() => "100 millis")
88
- )
89
- ),
90
- Effect.catchAll((error) => Effect.fail(error))
91
- );
92
-
93
- export const execCommandSafe = (
94
- cmd: string,
95
- args: string[],
96
- options?: ExecOptions
97
- ): Effect.Effect<string, never> =>
98
- execCommand(cmd, args, options).pipe(
99
- Effect.catchAll((error) =>
100
- Effect.gen(function* () {
101
- yield* Effect.logWarning(`Command failed (graceful): ${error.message}`);
102
- return "";
103
- })
104
- )
105
- );
106
-
107
- export const execShell = (
108
- script: string,
109
- options?: ExecOptions
110
- ): Effect.Effect<string, CommandFailed | CommandTimeout> =>
111
- Effect.gen(function* () {
112
- const timeout = options?.timeout ?? DEFAULT_TIMEOUT;
113
- const silent = options?.silent ?? false;
114
-
115
- if (!silent) {
116
- yield* Effect.logDebug(`Executing shell: ${script.slice(0, 50)}...`);
117
- }
118
-
119
- const result = yield* Effect.tryPromise({
120
- try: async () => {
121
- const proc = await execa(script, {
122
- cwd: options?.cwd,
123
- timeout,
124
- reject: false,
125
- shell: true,
126
- });
127
- return {
128
- stdout: proc.stdout?.trim() ?? "",
129
- stderr: proc.stderr?.trim() ?? "",
130
- exitCode: proc.exitCode,
131
- timedOut: proc.timedOut,
132
- };
133
- },
134
- catch: (error) => {
135
- const err = error as { timedOut?: boolean; message?: string };
136
- if (err.timedOut) {
137
- return new CommandTimeout({ command: script, timeoutMs: timeout });
138
- }
139
- return new CommandFailed({
140
- command: script,
141
- args: [],
142
- exitCode: -1,
143
- stderr: String(error),
144
- });
145
- },
146
- });
147
-
148
- if (result.timedOut) {
149
- return yield* Effect.fail(
150
- new CommandTimeout({ command: script, timeoutMs: timeout })
151
- );
152
- }
153
-
154
- if (result.exitCode !== 0) {
155
- if (!silent) {
156
- yield* Effect.logWarning(
157
- `Shell command failed (exit ${result.exitCode})`
158
- );
159
- }
160
- return yield* Effect.fail(
161
- new CommandFailed({
162
- command: script,
163
- args: [],
164
- exitCode: result.exitCode ?? 1,
165
- stderr: result.stderr,
166
- })
167
- );
168
- }
169
-
170
- return result.stdout;
171
- }).pipe(
172
- Effect.retry(
173
- Schedule.recurs(options?.retries ?? DEFAULT_RETRIES).pipe(
174
- Schedule.addDelay(() => "100 millis")
175
- )
176
- ),
177
- Effect.catchAll((error) => Effect.fail(error))
178
- );
179
-
180
- export const execShellSafe = (
181
- script: string,
182
- options?: ExecOptions
183
- ): Effect.Effect<string, never> =>
184
- execShell(script, options).pipe(
185
- Effect.catchAll((error) =>
186
- Effect.gen(function* () {
187
- yield* Effect.logWarning(
188
- `Shell command failed (graceful): ${error.message}`
189
- );
190
- return "";
191
- })
192
- )
193
- );
194
-
195
- export const powershell = (
196
- script: string,
197
- options?: ExecOptions
198
- ): Effect.Effect<string, CommandFailed | CommandTimeout> =>
199
- Effect.gen(function* () {
200
- const timeout = options?.timeout ?? DEFAULT_TIMEOUT;
201
- const silent = options?.silent ?? false;
202
-
203
- if (!silent) {
204
- yield* Effect.logDebug(`Executing PowerShell: ${script.slice(0, 50)}...`);
205
- }
206
-
207
- const result = yield* Effect.tryPromise({
208
- try: async () => {
209
- const proc = await execa("powershell", ["-NoProfile", "-Command", script], {
210
- cwd: options?.cwd,
211
- timeout,
212
- reject: false,
213
- });
214
- return {
215
- stdout: proc.stdout?.trim() ?? "",
216
- stderr: proc.stderr?.trim() ?? "",
217
- exitCode: proc.exitCode,
218
- timedOut: proc.timedOut,
219
- };
220
- },
221
- catch: (error) => {
222
- const err = error as { timedOut?: boolean; message?: string };
223
- if (err.timedOut) {
224
- return new CommandTimeout({
225
- command: "powershell",
226
- timeoutMs: timeout,
227
- });
228
- }
229
- return new CommandFailed({
230
- command: "powershell",
231
- args: [script],
232
- exitCode: -1,
233
- stderr: String(error),
234
- });
235
- },
236
- });
237
-
238
- if (result.timedOut) {
239
- return yield* Effect.fail(
240
- new CommandTimeout({ command: "powershell", timeoutMs: timeout })
241
- );
242
- }
243
-
244
- if (result.exitCode !== 0) {
245
- if (!silent) {
246
- yield* Effect.logWarning(
247
- `PowerShell command failed (exit ${result.exitCode})`
248
- );
249
- }
250
- return yield* Effect.fail(
251
- new CommandFailed({
252
- command: "powershell",
253
- args: [script],
254
- exitCode: result.exitCode ?? 1,
255
- stderr: result.stderr,
256
- })
257
- );
258
- }
259
-
260
- return result.stdout;
261
- }).pipe(
262
- Effect.retry(
263
- Schedule.recurs(options?.retries ?? DEFAULT_RETRIES).pipe(
264
- Schedule.addDelay(() => "100 millis")
265
- )
266
- ),
267
- Effect.catchAll((error) => Effect.fail(error))
268
- );
269
-
270
- export const powershellSafe = (
271
- script: string,
272
- options?: ExecOptions
273
- ): Effect.Effect<string, never> =>
274
- powershell(script, options).pipe(
275
- Effect.catchAll((error) =>
276
- Effect.gen(function* () {
277
- yield* Effect.logWarning(
278
- `PowerShell command failed (graceful): ${error.message}`
279
- );
280
- return "";
281
- })
282
- )
283
- );
@@ -1,157 +0,0 @@
1
- import type { PortInfo, ProcessInfo, Snapshot, SnapshotDiff } from "./types";
2
-
3
- export const diffSnapshots = (from: Snapshot, to: Snapshot): SnapshotDiff => {
4
- const fromPids = new Set(from.processes.map((p) => p.pid));
5
- const toPids = new Set(to.processes.map((p) => p.pid));
6
-
7
- const stillBoundPorts: PortInfo[] = [];
8
- const freedPorts: number[] = [];
9
-
10
- for (const [portStr, fromPort] of Object.entries(from.ports)) {
11
- const port = parseInt(portStr, 10);
12
- const toPort = to.ports[port];
13
-
14
- if (fromPort.state === "LISTEN") {
15
- if (toPort?.state === "LISTEN") {
16
- stillBoundPorts.push(toPort);
17
- } else {
18
- freedPorts.push(port);
19
- }
20
- }
21
- }
22
-
23
- const orphanedProcesses = findOrphanedProcesses(from, to, fromPids, toPids);
24
-
25
- const newProcesses = to.processes.filter((p) => !fromPids.has(p.pid));
26
- const killedProcesses = from.processes.filter((p) => !toPids.has(p.pid));
27
-
28
- const memoryDeltaBytes = to.memory.processRss - from.memory.processRss;
29
-
30
- return {
31
- from,
32
- to,
33
- orphanedProcesses,
34
- stillBoundPorts,
35
- freedPorts,
36
- memoryDeltaBytes,
37
- newProcesses,
38
- killedProcesses,
39
- };
40
- };
41
-
42
- const findOrphanedProcesses = (
43
- from: Snapshot,
44
- to: Snapshot,
45
- fromPids: Set<number>,
46
- toPids: Set<number>
47
- ): ProcessInfo[] => {
48
- const orphaned: ProcessInfo[] = [];
49
-
50
- for (const toProc of to.processes) {
51
- const parentPid = toProc.ppid;
52
-
53
- if (parentPid <= 1) continue;
54
-
55
- const parentWasTracked = fromPids.has(parentPid);
56
- const parentIsGone = !toPids.has(parentPid);
57
- const childStillAlive = toPids.has(toProc.pid);
58
-
59
- if (parentWasTracked && parentIsGone && childStillAlive) {
60
- orphaned.push(toProc);
61
- }
62
- }
63
-
64
- return orphaned;
65
- };
66
-
67
- export const hasLeaks = (diff: SnapshotDiff): boolean => {
68
- return diff.orphanedProcesses.length > 0 || diff.stillBoundPorts.length > 0;
69
- };
70
-
71
- export const formatDiff = (diff: SnapshotDiff): string => {
72
- const lines: string[] = [];
73
- const elapsed = diff.to.timestamp - diff.from.timestamp;
74
-
75
- lines.push(`Snapshot Diff (${elapsed}ms elapsed)`);
76
- lines.push("─".repeat(50));
77
-
78
- if (diff.stillBoundPorts.length > 0) {
79
- lines.push("");
80
- lines.push("⚠️ STILL BOUND PORTS:");
81
- for (const port of diff.stillBoundPorts) {
82
- lines.push(` :${port.port} ← PID ${port.pid} (${port.command})`);
83
- }
84
- }
85
-
86
- if (diff.orphanedProcesses.length > 0) {
87
- lines.push("");
88
- lines.push("⚠️ ORPHANED PROCESSES:");
89
- for (const proc of diff.orphanedProcesses) {
90
- const mb = (proc.rss / 1024 / 1024).toFixed(1);
91
- lines.push(` PID ${proc.pid}: ${proc.command} (${mb} MB)`);
92
- }
93
- }
94
-
95
- if (diff.freedPorts.length > 0) {
96
- lines.push("");
97
- lines.push("✓ FREED PORTS:");
98
- lines.push(` ${diff.freedPorts.join(", ")}`);
99
- }
100
-
101
- if (diff.killedProcesses.length > 0) {
102
- lines.push("");
103
- lines.push("✓ KILLED PROCESSES:");
104
- for (const proc of diff.killedProcesses) {
105
- lines.push(` PID ${proc.pid}: ${proc.command}`);
106
- }
107
- }
108
-
109
- lines.push("");
110
- const memDeltaMb = (diff.memoryDeltaBytes / 1024 / 1024).toFixed(1);
111
- const sign = diff.memoryDeltaBytes >= 0 ? "+" : "";
112
- lines.push(`Memory Delta: ${sign}${memDeltaMb} MB`);
113
-
114
- if (!hasLeaks(diff)) {
115
- lines.push("");
116
- lines.push("✅ No resource leaks detected");
117
- }
118
-
119
- return lines.join("\n");
120
- };
121
-
122
- export const formatSnapshotSummary = (snapshot: Snapshot): string => {
123
- const lines: string[] = [];
124
-
125
- lines.push(`Snapshot at ${new Date(snapshot.timestamp).toISOString()}`);
126
- lines.push(`Platform: ${snapshot.platform}`);
127
- if (snapshot.configPath) {
128
- lines.push(`Config: ${snapshot.configPath}`);
129
- }
130
- lines.push("");
131
-
132
- lines.push("PORTS:");
133
- for (const [port, info] of Object.entries(snapshot.ports)) {
134
- if (info.state === "FREE") {
135
- lines.push(` :${port} ○ free`);
136
- } else {
137
- lines.push(` :${port} ● PID ${info.pid} (${info.command})`);
138
- }
139
- }
140
-
141
- if (snapshot.processes.length > 0) {
142
- lines.push("");
143
- lines.push("PROCESS TREE:");
144
- for (const proc of snapshot.processes) {
145
- const mb = (proc.rss / 1024 / 1024).toFixed(1);
146
- const childCount = proc.children.length;
147
- const childText = childCount > 0 ? ` [${childCount} children]` : "";
148
- lines.push(` ${proc.pid} ${proc.command} (${mb} MB)${childText}`);
149
- }
150
- }
151
-
152
- lines.push("");
153
- const totalMb = (snapshot.memory.processRss / 1024 / 1024).toFixed(1);
154
- lines.push(`Total Process RSS: ${totalMb} MB`);
155
-
156
- return lines.join("\n");
157
- };