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
@@ -0,0 +1,154 @@
1
+ import { existsSync } from "node:fs";
2
+ import { mkdir, readFile, writeFile } from "node:fs/promises";
3
+ import { dirname, join } from "node:path";
4
+ import { Effect, Ref } from "effect";
5
+ import { getBosDir } from "./dev-logs";
6
+
7
+ export interface TrackedProcess {
8
+ pid: number;
9
+ name: string;
10
+ port: number;
11
+ startedAt: number;
12
+ command: string;
13
+ }
14
+
15
+ export interface ProcessRegistry {
16
+ readonly tracked: Ref.Ref<Map<number, TrackedProcess>>;
17
+ track: (proc: TrackedProcess) => Effect.Effect<void>;
18
+ untrack: (pid: number) => Effect.Effect<void>;
19
+ getAll: () => Effect.Effect<TrackedProcess[]>;
20
+ killAll: (force?: boolean) => Effect.Effect<{ killed: number[]; failed: number[] }>;
21
+ persist: () => Effect.Effect<void>;
22
+ restore: () => Effect.Effect<void>;
23
+ }
24
+
25
+ export function getPidFilePath(configDir: string): string {
26
+ return join(getBosDir(configDir), "pids.json");
27
+ }
28
+
29
+ const isProcessAlive = (pid: number): boolean => {
30
+ try {
31
+ process.kill(pid, 0);
32
+ return true;
33
+ } catch {
34
+ return false;
35
+ }
36
+ };
37
+
38
+ const killProcess = (pid: number, signal: NodeJS.Signals): boolean => {
39
+ try {
40
+ // Try process group first (covers spawned child trees)
41
+ try {
42
+ process.kill(-pid, signal);
43
+ } catch {}
44
+ process.kill(pid, signal);
45
+ return true;
46
+ } catch {
47
+ return false;
48
+ }
49
+ };
50
+
51
+ export const makeProcessRegistry = (configDir: string) =>
52
+ Effect.gen(function* () {
53
+ const tracked = yield* Ref.make(new Map<number, TrackedProcess>());
54
+ const pidFile = getPidFilePath(configDir);
55
+
56
+ const getAll: ProcessRegistry["getAll"] = () =>
57
+ Ref.get(tracked).pipe(Effect.map((m) => Array.from(m.values())));
58
+
59
+ const persist: ProcessRegistry["persist"] = () =>
60
+ Effect.gen(function* () {
61
+ const procs = yield* getAll();
62
+ const dir = dirname(pidFile);
63
+ yield* Effect.tryPromise({
64
+ try: async () => {
65
+ if (!existsSync(dir)) {
66
+ await mkdir(dir, { recursive: true });
67
+ }
68
+ await writeFile(pidFile, JSON.stringify(procs, null, 2));
69
+ },
70
+ catch: () => new Error("Failed to persist PIDs"),
71
+ }).pipe(Effect.catchAll(() => Effect.void));
72
+ });
73
+
74
+ const track: ProcessRegistry["track"] = (proc) =>
75
+ Effect.gen(function* () {
76
+ yield* Ref.update(tracked, (m) => new Map(m).set(proc.pid, proc));
77
+ yield* persist();
78
+ });
79
+
80
+ const untrack: ProcessRegistry["untrack"] = (pid) =>
81
+ Effect.gen(function* () {
82
+ yield* Ref.update(tracked, (m) => {
83
+ const copy = new Map(m);
84
+ copy.delete(pid);
85
+ return copy;
86
+ });
87
+ yield* persist();
88
+ });
89
+
90
+ const restore: ProcessRegistry["restore"] = () =>
91
+ Effect.gen(function* () {
92
+ if (!existsSync(pidFile)) return;
93
+
94
+ const content = yield* Effect.tryPromise({
95
+ try: () => readFile(pidFile, "utf8"),
96
+ catch: () => new Error("Failed to read PID file"),
97
+ }).pipe(Effect.catchAll(() => Effect.succeed("")));
98
+
99
+ if (!content) return;
100
+
101
+ let procs: TrackedProcess[];
102
+ try {
103
+ procs = JSON.parse(content) as TrackedProcess[];
104
+ } catch {
105
+ return;
106
+ }
107
+
108
+ const alive = procs.filter((p) => isProcessAlive(p.pid));
109
+ yield* Ref.set(tracked, new Map(alive.map((p) => [p.pid, p])));
110
+ });
111
+
112
+ yield* restore();
113
+
114
+ const killAll: ProcessRegistry["killAll"] = (force = false) =>
115
+ Effect.gen(function* () {
116
+ const procs = yield* getAll();
117
+ const killed: number[] = [];
118
+ const failed: number[] = [];
119
+
120
+ for (const proc of procs) {
121
+ if (!isProcessAlive(proc.pid)) {
122
+ yield* untrack(proc.pid);
123
+ continue;
124
+ }
125
+
126
+ const signal = force ? "SIGKILL" : "SIGTERM";
127
+ if (killProcess(proc.pid, signal)) {
128
+ killed.push(proc.pid);
129
+ yield* untrack(proc.pid);
130
+ } else {
131
+ failed.push(proc.pid);
132
+ }
133
+ }
134
+
135
+ if (!force && failed.length > 0) {
136
+ yield* Effect.sleep("500 millis");
137
+ for (const pid of [...failed]) {
138
+ if (killProcess(pid, "SIGKILL")) {
139
+ const idx = failed.indexOf(pid);
140
+ if (idx !== -1) {
141
+ failed.splice(idx, 1);
142
+ killed.push(pid);
143
+ }
144
+ yield* untrack(pid);
145
+ }
146
+ }
147
+ }
148
+
149
+ yield* persist();
150
+ return { killed, failed };
151
+ });
152
+
153
+ return { tracked, track, untrack, getAll, killAll, persist, restore };
154
+ });
@@ -0,0 +1,24 @@
1
+ #!/usr/bin/env bun
2
+
3
+ import { dirname } from "node:path";
4
+ import { syncApiContractBridge } from "../api-contract";
5
+ import { loadConfig } from "../config";
6
+
7
+ async function main() {
8
+ const result = await loadConfig({ cwd: process.cwd(), env: "development" });
9
+ if (!result) {
10
+ throw new Error("No bos.config.json found");
11
+ }
12
+
13
+ const configDir = dirname(result.source.path);
14
+ await syncApiContractBridge({
15
+ configDir,
16
+ runtimeConfig: result.runtime,
17
+ apiBaseUrl: result.runtime.api.url,
18
+ });
19
+ }
20
+
21
+ main().catch((error) => {
22
+ console.error("[sync-api-contract]", error instanceof Error ? error.message : String(error));
23
+ process.exit(1);
24
+ });
package/src/sdk.ts ADDED
@@ -0,0 +1,14 @@
1
+ export {
2
+ createPlugin,
3
+ createPluginRuntime,
4
+ type LoadedPluginWithBinding,
5
+ type Plugin,
6
+ PluginRuntime,
7
+ } from "every-plugin";
8
+ export { Context, Effect, Layer, Scope } from "every-plugin/effect";
9
+ export {
10
+ type AnyContractRouter,
11
+ type AnySchema,
12
+ oc,
13
+ } from "every-plugin/orpc";
14
+ export { z } from "every-plugin/zod";
package/src/shared.ts ADDED
@@ -0,0 +1,206 @@
1
+ import { createHash } from "node:crypto";
2
+ import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
3
+ import { dirname, join } from "node:path";
4
+ import type { BosConfig, SharedDepConfig } from "./types";
5
+
6
+ export interface SharedUiResolvedDep {
7
+ name: string;
8
+ version: string;
9
+ requiredVersion: string;
10
+ shareScope: string;
11
+ singleton: boolean;
12
+ eager: boolean;
13
+ strictVersion: boolean;
14
+ }
15
+
16
+ export interface SharedUiResolved {
17
+ deps: Record<string, SharedUiResolvedDep>;
18
+ fingerprintSha256: string;
19
+ }
20
+
21
+ export interface SharedSyncResult {
22
+ mode: "catalog->bos" | "bos->catalog";
23
+ hostMode: "local" | "remote";
24
+ bosConfigChanged: boolean;
25
+ catalogChanged: boolean;
26
+ generatedChanged: boolean;
27
+ resolved: SharedUiResolved;
28
+ }
29
+
30
+ function sha256(input: string): string {
31
+ return createHash("sha256").update(input).digest("hex");
32
+ }
33
+
34
+ function extractSemverExact(input: unknown): string | null {
35
+ if (typeof input !== "string") return null;
36
+ const match = input.match(/\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?/);
37
+ return match ? match[0] : null;
38
+ }
39
+
40
+ function caretRange(version: string): string {
41
+ return `^${version}`;
42
+ }
43
+
44
+ function stableDepsObject(
45
+ deps: Record<string, SharedUiResolvedDep>,
46
+ ): Record<string, SharedUiResolvedDep> {
47
+ const keys = Object.keys(deps).sort((a, b) => a.localeCompare(b));
48
+ const out: Record<string, SharedUiResolvedDep> = {};
49
+ for (const k of keys) out[k] = deps[k]!;
50
+ return out;
51
+ }
52
+
53
+ function writeFileIfChanged(filePath: string, nextContent: string): boolean {
54
+ try {
55
+ const current = readFileSync(filePath, "utf-8");
56
+ if (current === nextContent) return false;
57
+ } catch {
58
+ // ignore
59
+ }
60
+
61
+ writeFileSync(filePath, nextContent);
62
+ return true;
63
+ }
64
+
65
+ function fingerprintResolved(deps: Record<string, SharedUiResolvedDep>): string {
66
+ const stable = stableDepsObject(deps);
67
+ return sha256(JSON.stringify(stable));
68
+ }
69
+
70
+ function getSharedUiDeps(bosConfig: BosConfig): Record<string, SharedDepConfig> {
71
+ const shared = bosConfig.shared ?? {};
72
+ const ui = shared.ui ?? {};
73
+ return ui;
74
+ }
75
+
76
+ export async function syncAndGenerateSharedUi(opts: {
77
+ configDir: string;
78
+ hostMode: "local" | "remote";
79
+ bosConfig?: BosConfig;
80
+ }): Promise<SharedSyncResult> {
81
+ const bosConfigPath = join(opts.configDir, "bos.config.json");
82
+ const packageJsonPath = join(opts.configDir, "package.json");
83
+ const generatedPath = join(opts.configDir, ".bos", "generated", "shared-ui.json");
84
+
85
+ const bosConfig: BosConfig = opts.bosConfig ?? JSON.parse(readFileSync(bosConfigPath, "utf-8"));
86
+ let pkgJson: any = {};
87
+ try {
88
+ pkgJson = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
89
+ } catch {
90
+ // package.json might not exist
91
+ }
92
+
93
+ const originalBos = JSON.stringify(bosConfig);
94
+ const originalPkg = JSON.stringify(pkgJson);
95
+
96
+ const catalog = pkgJson?.workspaces?.catalog ?? {};
97
+ const sharedUi = getSharedUiDeps(bosConfig);
98
+
99
+ const mode = opts.hostMode === "local" ? "catalog->bos" : "bos->catalog";
100
+
101
+ if (mode === "catalog->bos") {
102
+ for (const [name, cfg] of Object.entries(sharedUi)) {
103
+ const dep = cfg as SharedDepConfig;
104
+ const version =
105
+ catalog[name] ?? extractSemverExact(dep.version) ?? extractSemverExact(dep.requiredVersion);
106
+ if (!version) continue;
107
+ dep.version = version;
108
+ dep.requiredVersion = caretRange(version);
109
+ dep.shareScope = dep.shareScope ?? "default";
110
+ }
111
+ } else {
112
+ for (const [name, cfg] of Object.entries(sharedUi)) {
113
+ const dep = cfg as SharedDepConfig;
114
+ const version = extractSemverExact(dep.version) ?? extractSemverExact(dep.requiredVersion);
115
+ if (!version) continue;
116
+ dep.version = version;
117
+ dep.requiredVersion = caretRange(version);
118
+ dep.shareScope = dep.shareScope ?? "default";
119
+ if (catalog[name] !== version) {
120
+ catalog[name] = version;
121
+ }
122
+ }
123
+ if (!pkgJson.workspaces) pkgJson.workspaces = { packages: [], catalog: {} };
124
+ pkgJson.workspaces.catalog = catalog;
125
+ }
126
+
127
+ const nextBos = JSON.stringify(bosConfig);
128
+ const nextPkg = JSON.stringify(pkgJson);
129
+ const bosConfigChanged = nextBos !== originalBos;
130
+ const catalogChanged = nextPkg !== originalPkg;
131
+
132
+ if (bosConfigChanged) {
133
+ writeFileIfChanged(bosConfigPath, `${JSON.stringify(bosConfig, null, 2)}\n`);
134
+ }
135
+ if (catalogChanged) {
136
+ writeFileIfChanged(packageJsonPath, `${JSON.stringify(pkgJson, null, 2)}\n`);
137
+ }
138
+
139
+ const resolvedDeps: Record<string, SharedUiResolvedDep> = {};
140
+ for (const [name, cfg] of Object.entries(getSharedUiDeps(bosConfig))) {
141
+ const version =
142
+ catalog[name] ?? extractSemverExact(cfg.version) ?? extractSemverExact(cfg.requiredVersion);
143
+ if (!version) continue;
144
+ resolvedDeps[name] = {
145
+ name,
146
+ version,
147
+ requiredVersion: caretRange(version),
148
+ shareScope: cfg.shareScope ?? "default",
149
+ singleton: cfg.singleton ?? false,
150
+ eager: cfg.eager ?? false,
151
+ strictVersion: cfg.strictVersion ?? false,
152
+ };
153
+ }
154
+
155
+ const stableResolvedDeps = stableDepsObject(resolvedDeps);
156
+ const resolved: SharedUiResolved = {
157
+ deps: stableResolvedDeps,
158
+ fingerprintSha256: fingerprintResolved(stableResolvedDeps),
159
+ };
160
+
161
+ const nextGenerated = {
162
+ schemaVersion: 1,
163
+ kind: "everything-dev/shared-ui",
164
+ generatedAt: new Date().toISOString(),
165
+ ui: {
166
+ deps: stableResolvedDeps,
167
+ fingerprintSha256: resolved.fingerprintSha256,
168
+ },
169
+ inputs: {
170
+ mode,
171
+ hostMode: opts.hostMode,
172
+ },
173
+ };
174
+
175
+ let prevFingerprint: string | null = null;
176
+ try {
177
+ const prev = JSON.parse(readFileSync(generatedPath, "utf-8"));
178
+ prevFingerprint = prev?.ui?.fingerprintSha256 ?? null;
179
+ } catch {
180
+ // ignore
181
+ }
182
+
183
+ mkdirSync(dirname(generatedPath), { recursive: true });
184
+ writeFileIfChanged(generatedPath, `${JSON.stringify(nextGenerated, null, 2)}\n`);
185
+
186
+ const generatedChanged = prevFingerprint !== nextGenerated.ui.fingerprintSha256;
187
+
188
+ return {
189
+ mode,
190
+ hostMode: opts.hostMode,
191
+ bosConfigChanged,
192
+ catalogChanged,
193
+ generatedChanged,
194
+ resolved,
195
+ };
196
+ }
197
+
198
+ export function loadGeneratedSharedUi(configDir: string): SharedUiResolved | null {
199
+ const generatedPath = join(configDir, ".bos", "generated", "shared-ui.json");
200
+ try {
201
+ const content = JSON.parse(readFileSync(generatedPath, "utf-8"));
202
+ return content?.ui ?? null;
203
+ } catch {
204
+ return null;
205
+ }
206
+ }