everything-dev 0.3.2 → 1.3.2

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 (308) 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 +317 -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 +309 -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/mf.cjs +77 -0
  123. package/dist/mf.cjs.map +1 -0
  124. package/dist/mf.d.cts +19 -0
  125. package/dist/mf.d.cts.map +1 -0
  126. package/dist/mf.d.mts +19 -0
  127. package/dist/mf.d.mts.map +1 -0
  128. package/dist/mf.mjs +71 -0
  129. package/dist/mf.mjs.map +1 -0
  130. package/dist/near-cli.cjs +196 -0
  131. package/dist/near-cli.cjs.map +1 -0
  132. package/dist/near-cli.mjs +193 -0
  133. package/dist/near-cli.mjs.map +1 -0
  134. package/dist/network.cjs +9 -0
  135. package/dist/network.cjs.map +1 -0
  136. package/dist/network.mjs +8 -0
  137. package/dist/network.mjs.map +1 -0
  138. package/dist/orchestrator.cjs +441 -0
  139. package/dist/orchestrator.cjs.map +1 -0
  140. package/dist/orchestrator.d.cts +40 -0
  141. package/dist/orchestrator.d.cts.map +1 -0
  142. package/dist/orchestrator.d.mts +40 -0
  143. package/dist/orchestrator.d.mts.map +1 -0
  144. package/dist/orchestrator.mjs +436 -0
  145. package/dist/orchestrator.mjs.map +1 -0
  146. package/dist/plugin.cjs +825 -0
  147. package/dist/plugin.cjs.map +1 -0
  148. package/dist/plugin.d.cts +347 -0
  149. package/dist/plugin.d.cts.map +1 -0
  150. package/dist/plugin.d.mts +348 -0
  151. package/dist/plugin.d.mts.map +1 -0
  152. package/dist/plugin.mjs +822 -0
  153. package/dist/plugin.mjs.map +1 -0
  154. package/dist/process-registry.cjs +120 -0
  155. package/dist/process-registry.cjs.map +1 -0
  156. package/dist/process-registry.d.cts +25 -0
  157. package/dist/process-registry.d.cts.map +1 -0
  158. package/dist/process-registry.d.mts +25 -0
  159. package/dist/process-registry.d.mts.map +1 -0
  160. package/dist/process-registry.mjs +119 -0
  161. package/dist/process-registry.mjs.map +1 -0
  162. package/dist/sdk.cjs +61 -0
  163. package/dist/sdk.d.cts +5 -0
  164. package/dist/sdk.d.mts +5 -0
  165. package/dist/sdk.mjs +6 -0
  166. package/dist/shared.cjs +143 -0
  167. package/dist/shared.cjs.map +1 -0
  168. package/dist/shared.d.cts +33 -0
  169. package/dist/shared.d.cts.map +1 -0
  170. package/dist/shared.d.mts +33 -0
  171. package/dist/shared.d.mts.map +1 -0
  172. package/dist/shared.mjs +140 -0
  173. package/dist/shared.mjs.map +1 -0
  174. package/dist/types.cjs +160 -0
  175. package/dist/types.cjs.map +1 -0
  176. package/dist/types.d.cts +269 -0
  177. package/dist/types.d.cts.map +1 -0
  178. package/dist/types.d.mts +269 -0
  179. package/dist/types.d.mts.map +1 -0
  180. package/dist/types.mjs +144 -0
  181. package/dist/types.mjs.map +1 -0
  182. package/dist/ui/head.cjs +67 -0
  183. package/dist/ui/head.cjs.map +1 -0
  184. package/dist/ui/head.d.cts +19 -0
  185. package/dist/ui/head.d.cts.map +1 -0
  186. package/dist/ui/head.d.mts +19 -0
  187. package/dist/ui/head.d.mts.map +1 -0
  188. package/dist/ui/head.mjs +61 -0
  189. package/dist/ui/head.mjs.map +1 -0
  190. package/dist/ui/index.cjs +32 -0
  191. package/dist/ui/index.d.cts +7 -0
  192. package/dist/ui/index.d.mts +7 -0
  193. package/dist/ui/index.mjs +6 -0
  194. package/dist/ui/metadata.cjs +106 -0
  195. package/dist/ui/metadata.cjs.map +1 -0
  196. package/dist/ui/metadata.d.cts +35 -0
  197. package/dist/ui/metadata.d.cts.map +1 -0
  198. package/dist/ui/metadata.d.mts +35 -0
  199. package/dist/ui/metadata.d.mts.map +1 -0
  200. package/dist/ui/metadata.mjs +100 -0
  201. package/dist/ui/metadata.mjs.map +1 -0
  202. package/dist/ui/router.cjs +56 -0
  203. package/dist/ui/router.cjs.map +1 -0
  204. package/dist/ui/router.d.cts +11 -0
  205. package/dist/ui/router.d.cts.map +1 -0
  206. package/dist/ui/router.d.mts +11 -0
  207. package/dist/ui/router.d.mts.map +1 -0
  208. package/dist/ui/router.mjs +51 -0
  209. package/dist/ui/router.mjs.map +1 -0
  210. package/dist/ui/runtime.cjs +65 -0
  211. package/dist/ui/runtime.cjs.map +1 -0
  212. package/dist/ui/runtime.d.cts +29 -0
  213. package/dist/ui/runtime.d.cts.map +1 -0
  214. package/dist/ui/runtime.d.mts +29 -0
  215. package/dist/ui/runtime.d.mts.map +1 -0
  216. package/dist/ui/runtime.mjs +53 -0
  217. package/dist/ui/runtime.mjs.map +1 -0
  218. package/dist/ui/types.cjs +0 -0
  219. package/dist/ui/types.d.cts +52 -0
  220. package/dist/ui/types.d.cts.map +1 -0
  221. package/dist/ui/types.d.mts +52 -0
  222. package/dist/ui/types.d.mts.map +1 -0
  223. package/dist/ui/types.mjs +1 -0
  224. package/dist/utils/banner.cjs +24 -0
  225. package/dist/utils/banner.cjs.map +1 -0
  226. package/dist/utils/banner.mjs +23 -0
  227. package/dist/utils/banner.mjs.map +1 -0
  228. package/dist/utils/linkify.cjs +15 -0
  229. package/dist/utils/linkify.cjs.map +1 -0
  230. package/dist/utils/linkify.mjs +14 -0
  231. package/dist/utils/linkify.mjs.map +1 -0
  232. package/dist/utils/run.cjs +40 -0
  233. package/dist/utils/run.cjs.map +1 -0
  234. package/dist/utils/run.mjs +39 -0
  235. package/dist/utils/run.mjs.map +1 -0
  236. package/dist/utils/theme.cjs +44 -0
  237. package/dist/utils/theme.cjs.map +1 -0
  238. package/dist/utils/theme.mjs +37 -0
  239. package/dist/utils/theme.mjs.map +1 -0
  240. package/package.json +269 -80
  241. package/src/api-contract.ts +309 -0
  242. package/src/api.ts +181 -0
  243. package/src/app.ts +346 -0
  244. package/src/cli/catalog.ts +49 -0
  245. package/src/cli/help.ts +13 -0
  246. package/src/cli/init.ts +415 -0
  247. package/src/cli/parse.ts +130 -0
  248. package/src/cli/prompts.ts +64 -0
  249. package/src/cli.ts +203 -1507
  250. package/src/components/dev-view.tsx +104 -41
  251. package/src/components/streaming-view.ts +89 -22
  252. package/src/config.ts +462 -532
  253. package/src/contract.meta.ts +96 -0
  254. package/src/contract.ts +164 -561
  255. package/src/dev-logs.ts +85 -0
  256. package/src/dev-session.ts +318 -0
  257. package/src/fastkv.ts +153 -0
  258. package/src/federation.server.ts +43 -0
  259. package/src/host.ts +526 -0
  260. package/src/index.ts +6 -3
  261. package/src/integrity.ts +54 -0
  262. package/src/mf.ts +105 -0
  263. package/src/near-cli.ts +284 -0
  264. package/src/network.ts +3 -0
  265. package/src/orchestrator.ts +648 -0
  266. package/src/plugin.ts +1116 -2303
  267. package/src/process-registry.ts +154 -0
  268. package/src/scripts/sync-api-contract.ts +24 -0
  269. package/src/sdk.ts +14 -0
  270. package/src/shared.ts +206 -0
  271. package/src/types.ts +152 -206
  272. package/src/ui/head.ts +34 -27
  273. package/src/ui/index.ts +3 -3
  274. package/src/ui/metadata.ts +95 -0
  275. package/src/ui/router.ts +22 -6
  276. package/src/ui/runtime.ts +55 -6
  277. package/src/ui/types.ts +24 -11
  278. package/src/utils/banner.ts +10 -6
  279. package/src/utils/run.ts +26 -27
  280. package/src/utils/theme.ts +3 -66
  281. package/src/components/monitor-view.tsx +0 -475
  282. package/src/components/status-view.tsx +0 -173
  283. package/src/lib/env.ts +0 -109
  284. package/src/lib/near-cli.ts +0 -289
  285. package/src/lib/nova.ts +0 -266
  286. package/src/lib/orchestrator.ts +0 -276
  287. package/src/lib/process-registry.ts +0 -166
  288. package/src/lib/process.ts +0 -549
  289. package/src/lib/resource-monitor/assertions.ts +0 -234
  290. package/src/lib/resource-monitor/command.ts +0 -283
  291. package/src/lib/resource-monitor/diff.ts +0 -157
  292. package/src/lib/resource-monitor/errors.ts +0 -127
  293. package/src/lib/resource-monitor/index.ts +0 -305
  294. package/src/lib/resource-monitor/platform/darwin.ts +0 -306
  295. package/src/lib/resource-monitor/platform/index.ts +0 -35
  296. package/src/lib/resource-monitor/platform/linux.ts +0 -332
  297. package/src/lib/resource-monitor/platform/windows.ts +0 -298
  298. package/src/lib/resource-monitor/snapshot.ts +0 -217
  299. package/src/lib/resource-monitor/types.ts +0 -74
  300. package/src/lib/session-recorder/errors.ts +0 -102
  301. package/src/lib/session-recorder/flows/login.ts +0 -210
  302. package/src/lib/session-recorder/index.ts +0 -361
  303. package/src/lib/session-recorder/playwright.ts +0 -257
  304. package/src/lib/session-recorder/report.ts +0 -353
  305. package/src/lib/session-recorder/server.ts +0 -267
  306. package/src/lib/session-recorder/types.ts +0 -115
  307. package/src/lib/sync.ts +0 -1
  308. 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
+ }