everything-dev 1.26.0 → 1.27.0

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 (121) hide show
  1. package/dist/api-contract.cjs.map +1 -1
  2. package/dist/api-contract.mjs.map +1 -1
  3. package/dist/cli/catalog.cjs.map +1 -1
  4. package/dist/cli/catalog.mjs.map +1 -1
  5. package/dist/cli/framework-version.cjs.map +1 -1
  6. package/dist/cli/framework-version.mjs.map +1 -1
  7. package/dist/cli/infra.cjs.map +1 -1
  8. package/dist/cli/infra.mjs.map +1 -1
  9. package/dist/cli/init.cjs +127 -114
  10. package/dist/cli/init.cjs.map +1 -1
  11. package/dist/cli/init.d.cts +7 -6
  12. package/dist/cli/init.d.cts.map +1 -1
  13. package/dist/cli/init.d.mts +7 -6
  14. package/dist/cli/init.d.mts.map +1 -1
  15. package/dist/cli/init.mjs +124 -114
  16. package/dist/cli/init.mjs.map +1 -1
  17. package/dist/cli/parse.cjs.map +1 -1
  18. package/dist/cli/parse.mjs.map +1 -1
  19. package/dist/cli/prompts.cjs +3 -3
  20. package/dist/cli/prompts.cjs.map +1 -1
  21. package/dist/cli/prompts.mjs +2 -2
  22. package/dist/cli/prompts.mjs.map +1 -1
  23. package/dist/cli/status.cjs.map +1 -1
  24. package/dist/cli/status.mjs.map +1 -1
  25. package/dist/cli/sync.cjs +42 -92
  26. package/dist/cli/sync.cjs.map +1 -1
  27. package/dist/cli/sync.mjs +45 -95
  28. package/dist/cli/sync.mjs.map +1 -1
  29. package/dist/cli/timing.cjs.map +1 -1
  30. package/dist/cli/timing.mjs.map +1 -1
  31. package/dist/cli/upgrade.cjs +43 -22
  32. package/dist/cli/upgrade.cjs.map +1 -1
  33. package/dist/cli/upgrade.mjs +44 -23
  34. package/dist/cli/upgrade.mjs.map +1 -1
  35. package/dist/cli.cjs +1 -1
  36. package/dist/cli.cjs.map +1 -1
  37. package/dist/cli.mjs +1 -1
  38. package/dist/cli.mjs.map +1 -1
  39. package/dist/components/dev-view.cjs.map +1 -1
  40. package/dist/components/dev-view.mjs.map +1 -1
  41. package/dist/components/streaming-view.cjs.map +1 -1
  42. package/dist/components/streaming-view.mjs.map +1 -1
  43. package/dist/config.cjs.map +1 -1
  44. package/dist/config.mjs.map +1 -1
  45. package/dist/contract.cjs +174 -173
  46. package/dist/contract.cjs.map +1 -1
  47. package/dist/contract.d.cts +3 -3
  48. package/dist/contract.d.cts.map +1 -1
  49. package/dist/contract.d.mts +3 -3
  50. package/dist/contract.d.mts.map +1 -1
  51. package/dist/contract.meta.cjs +1 -1
  52. package/dist/contract.meta.cjs.map +1 -1
  53. package/dist/contract.meta.d.cts +1 -1
  54. package/dist/contract.meta.d.mts +1 -1
  55. package/dist/contract.meta.mjs +1 -1
  56. package/dist/contract.meta.mjs.map +1 -1
  57. package/dist/contract.mjs +2 -1
  58. package/dist/contract.mjs.map +1 -1
  59. package/dist/dev-logs.cjs.map +1 -1
  60. package/dist/dev-logs.mjs.map +1 -1
  61. package/dist/fastkv.cjs.map +1 -1
  62. package/dist/fastkv.mjs.map +1 -1
  63. package/dist/index.cjs +3 -3
  64. package/dist/index.d.cts +1 -1
  65. package/dist/index.d.mts +1 -1
  66. package/dist/index.mjs +1 -1
  67. package/dist/integrity.cjs.map +1 -1
  68. package/dist/integrity.mjs.map +1 -1
  69. package/dist/internal/manifest-normalizer.cjs.map +1 -1
  70. package/dist/internal/manifest-normalizer.mjs.map +1 -1
  71. package/dist/merge.cjs.map +1 -1
  72. package/dist/merge.mjs.map +1 -1
  73. package/dist/near-cli.cjs.map +1 -1
  74. package/dist/near-cli.mjs.map +1 -1
  75. package/dist/orchestrator.cjs.map +1 -1
  76. package/dist/orchestrator.mjs.map +1 -1
  77. package/dist/plugin.cjs +72 -50
  78. package/dist/plugin.cjs.map +1 -1
  79. package/dist/plugin.d.cts +2 -2
  80. package/dist/plugin.d.cts.map +1 -1
  81. package/dist/plugin.d.mts +2 -2
  82. package/dist/plugin.d.mts.map +1 -1
  83. package/dist/plugin.mjs +53 -32
  84. package/dist/plugin.mjs.map +1 -1
  85. package/dist/sdk.cjs +2 -2
  86. package/dist/sdk.d.cts +1 -1
  87. package/dist/sdk.d.mts +1 -1
  88. package/dist/sdk.mjs +1 -1
  89. package/dist/shared.cjs.map +1 -1
  90. package/dist/shared.mjs.map +1 -1
  91. package/dist/types.cjs +184 -184
  92. package/dist/types.cjs.map +1 -1
  93. package/dist/types.d.cts +3 -3
  94. package/dist/types.d.mts +3 -3
  95. package/dist/types.mjs +1 -1
  96. package/dist/types.mjs.map +1 -1
  97. package/dist/ui/types.d.cts +1 -0
  98. package/dist/ui/types.d.cts.map +1 -1
  99. package/dist/ui/types.d.mts +1 -0
  100. package/dist/ui/types.d.mts.map +1 -1
  101. package/dist/utils/banner.cjs.map +1 -1
  102. package/dist/utils/banner.mjs.map +1 -1
  103. package/dist/utils/run.cjs.map +1 -1
  104. package/dist/utils/run.mjs.map +1 -1
  105. package/package.json +2 -2
  106. package/skills/init-upgrade/SKILL.md +22 -16
  107. package/skills/publish-sync/SKILL.md +7 -18
  108. package/src/cli/init.ts +149 -195
  109. package/src/cli/prompts.ts +1 -1
  110. package/src/cli/sync.ts +48 -137
  111. package/src/cli/upgrade.ts +66 -25
  112. package/src/contract.meta.ts +1 -1
  113. package/src/contract.ts +2 -1
  114. package/src/plugin.ts +69 -34
  115. package/src/sdk.ts +1 -1
  116. package/src/types.ts +1 -1
  117. package/src/ui/types.ts +1 -0
  118. package/dist/utils/path-match.cjs +0 -18
  119. package/dist/utils/path-match.cjs.map +0 -1
  120. package/dist/utils/path-match.mjs +0 -17
  121. package/dist/utils/path-match.mjs.map +0 -1
package/dist/cli/sync.mjs CHANGED
@@ -1,30 +1,35 @@
1
1
  import { isPlainObject, mergeBosConfigWithTemplate, resolveExtendsRef } from "../merge.mjs";
2
2
  import { loadConfig } from "../config.mjs";
3
3
  import { writeGeneratedInfra } from "./infra.mjs";
4
- import { isPathExcluded } from "../utils/path-match.mjs";
5
- import { readSnapshot, writeSnapshot } from "./snapshot.mjs";
6
- import { personalizeConfig, readTemplatekeep, resolveSourceDir, runBunInstall, runTypesGen } from "./init.mjs";
7
- import { copyFileSync, existsSync, lstatSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
4
+ import { writeSnapshot } from "./snapshot.mjs";
5
+ import { personalizeConfig, resolveSourceDir, runBunInstall, runTypesGen, sourcePathToDestinationPath } from "./init.mjs";
6
+ import { copyFileSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
8
7
  import { dirname, join } from "node:path";
9
8
  import { createHash } from "node:crypto";
10
- import { glob } from "glob";
11
9
 
12
10
  //#region src/cli/sync.ts
13
11
  const FRAMEWORK_OWNED_SYNC_FILES = new Set([
14
12
  ".env.example",
15
13
  ".gitignore",
14
+ "AGENTS.md",
16
15
  "biome.json",
17
16
  "bos.config.json",
17
+ "bunfig.toml",
18
+ "CONTRIBUTING.md",
18
19
  "package.json",
20
+ ".changeset/config.json",
21
+ ".changeset/README.md",
19
22
  "docker-compose.yml",
20
23
  ".github/renovate.json",
21
24
  ".github/workflows/ci.yml",
22
25
  ".github/workflows/release-sync.yml",
26
+ ".opencode/skills/everything-dev/SKILL.md",
23
27
  "ui/package.json",
24
28
  "ui/postcss.config.mjs",
25
29
  "ui/rsbuild.config.ts",
26
30
  "ui/tsconfig.json",
27
31
  "ui/src/app.ts",
32
+ "ui/src/globals.d.ts",
28
33
  "ui/src/hydrate.tsx",
29
34
  "ui/src/lib/api.ts",
30
35
  "ui/src/lib/auth.ts",
@@ -38,19 +43,6 @@ const FRAMEWORK_OWNED_SYNC_FILES = new Set([
38
43
  "api/tsconfig.json",
39
44
  "api/src/lib/auth.ts"
40
45
  ]);
41
- function isFrameworkOwnedSyncFile(filePath) {
42
- return FRAMEWORK_OWNED_SYNC_FILES.has(filePath);
43
- }
44
- function readExcludeFile(filePath) {
45
- if (!existsSync(filePath)) return [];
46
- return readFileSync(filePath, "utf-8").split("\n").map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#"));
47
- }
48
- async function readTemplatesyncExclude(sourceDir) {
49
- return readExcludeFile(join(sourceDir, ".templatesync-exclude"));
50
- }
51
- function readLocalSyncExcludes(projectDir) {
52
- return readExcludeFile(join(projectDir, ".bos", "sync-local-exclude"));
53
- }
54
46
  function computeLocalHash(projectDir, filePath) {
55
47
  const fullPath = join(projectDir, filePath);
56
48
  if (!existsSync(fullPath)) return null;
@@ -136,7 +128,15 @@ function mergePackageJson(filePath, local, template) {
136
128
  return merged;
137
129
  }
138
130
  function toDestPath(filePath) {
139
- return filePath.startsWith(".github/templates/") ? filePath.replace(/^\.github\/templates\//, ".github/") : filePath;
131
+ return sourcePathToDestinationPath(filePath);
132
+ }
133
+ function toSourcePath(sourceDir, destPath) {
134
+ if (existsSync(join(sourceDir, destPath))) return destPath;
135
+ if (destPath.startsWith(".github/")) {
136
+ const templatePath = destPath.replace(/^\.github\//, ".github/templates/");
137
+ if (existsSync(join(sourceDir, templatePath))) return templatePath;
138
+ }
139
+ return null;
140
140
  }
141
141
  function writeSyncedFile(sourceDir, projectDir, filePath) {
142
142
  const src = join(sourceDir, filePath);
@@ -190,60 +190,25 @@ async function syncTemplate(projectDir, options) {
190
190
  extendsGateway
191
191
  });
192
192
  try {
193
- const patterns = await readTemplatekeep(sourceDir);
194
- if (patterns.length === 0) return {
195
- status: "error",
196
- updated: [],
197
- skipped: [],
198
- added: [],
199
- error: "No .templatekeep found in template source"
200
- };
201
- const parentExcludes = await readTemplatesyncExclude(sourceDir);
202
- const localExcludes = readLocalSyncExcludes(projectDir);
203
- const excludePatterns = [...parentExcludes, ...localExcludes];
204
- const allTemplateFiles = /* @__PURE__ */ new Set();
205
- for (const pattern of patterns) {
206
- const matches = await glob(pattern, {
207
- cwd: sourceDir,
208
- nodir: true,
209
- dot: true,
210
- absolute: false
211
- });
212
- for (const match of matches) allTemplateFiles.add(match);
213
- }
214
193
  const childPlugins = localConfig.plugins && typeof localConfig.plugins === "object" ? Object.keys(localConfig.plugins) : [];
215
- const pluginRoutes = {};
216
- const parentRuntime = await loadConfig({ cwd: sourceDir });
217
- for (const [key, plugin] of Object.entries(parentRuntime?.runtime.plugins ?? {})) if (plugin.routes && plugin.routes.length > 0) pluginRoutes[key] = plugin.routes;
218
- const excludedRoutePatterns = [];
219
- for (const [pluginKey, routePatterns] of Object.entries(pluginRoutes)) if (!childPlugins.includes(pluginKey)) excludedRoutePatterns.push(...routePatterns);
194
+ const withUi = existsSync(join(projectDir, "ui", "package.json"));
195
+ const withApi = existsSync(join(projectDir, "api", "package.json"));
196
+ const withHost = existsSync(join(projectDir, "host", "package.json"));
220
197
  const filteredFiles = /* @__PURE__ */ new Set();
221
- for (const filePath of allTemplateFiles) {
222
- const pluginMatch = filePath.match(/^plugins\/([^/]+)/);
223
- if (pluginMatch && !childPlugins.includes(pluginMatch[1])) continue;
224
- if (isPathExcluded(filePath, excludedRoutePatterns)) continue;
225
- filteredFiles.add(filePath);
226
- }
227
- for (const [pluginKey, routePatterns] of Object.entries(pluginRoutes)) {
228
- if (!childPlugins.includes(pluginKey)) continue;
229
- for (const rp of routePatterns) {
230
- const matches = await glob(rp, {
231
- cwd: sourceDir,
232
- nodir: true,
233
- dot: true,
234
- absolute: false
235
- });
236
- for (const match of matches) if (!isPathExcluded(match, excludedRoutePatterns)) filteredFiles.add(match);
237
- }
198
+ const destToSource = /* @__PURE__ */ new Map();
199
+ for (const destPath of FRAMEWORK_OWNED_SYNC_FILES) {
200
+ if (destPath.startsWith("ui/") && !withUi) continue;
201
+ if (destPath.startsWith("api/") && !withApi) continue;
202
+ if (destPath.startsWith("host/") && !withHost) continue;
203
+ const sourcePath = toSourcePath(sourceDir, destPath);
204
+ if (!sourcePath) continue;
205
+ filteredFiles.add(sourcePath);
206
+ destToSource.set(destPath, sourcePath);
238
207
  }
239
- const snapshot = await readSnapshot(projectDir);
240
208
  const updated = [];
241
209
  const skipped = [];
242
210
  const added = [];
243
- for (const filePath of filteredFiles) {
244
- const destPath = toDestPath(filePath);
245
- const frameworkOwned = isFrameworkOwnedSyncFile(destPath);
246
- if (isPathExcluded(destPath, excludePatterns) && !frameworkOwned) continue;
211
+ for (const [destPath, filePath] of destToSource.entries()) {
247
212
  const localHash = computeLocalHash(projectDir, destPath);
248
213
  const sourceContent = readFileSync(join(sourceDir, filePath));
249
214
  const sourceHash = createHash("sha256").update(sourceContent).digest("hex").substring(0, 16);
@@ -251,19 +216,7 @@ async function syncTemplate(projectDir, options) {
251
216
  added.push(destPath);
252
217
  continue;
253
218
  }
254
- if (localHash === sourceHash) continue;
255
- if (frameworkOwned) {
256
- updated.push(destPath);
257
- continue;
258
- }
259
- const snapshotHash = snapshot?.files[destPath];
260
- if (snapshotHash === void 0) {
261
- updated.push(destPath);
262
- continue;
263
- }
264
- if (localHash === snapshotHash) updated.push(destPath);
265
- else if (options.force) updated.push(destPath);
266
- else skipped.push(destPath);
219
+ if (localHash !== sourceHash) updated.push(destPath);
267
220
  }
268
221
  if (options.dryRun) return {
269
222
  status: "dry-run",
@@ -271,37 +224,34 @@ async function syncTemplate(projectDir, options) {
271
224
  skipped,
272
225
  added
273
226
  };
274
- const filesToWrite = [...updated, ...added].filter((f) => isFrameworkOwnedSyncFile(f) || !isPathExcluded(f, excludePatterns));
275
- const destToSource = /* @__PURE__ */ new Map();
276
- for (const filePath of filteredFiles) destToSource.set(toDestPath(filePath), filePath);
227
+ const filesToWrite = [...updated, ...added];
277
228
  if (filesToWrite.length > 0) {
278
229
  backupFiles(projectDir, filesToWrite);
279
230
  for (const destPath of filesToWrite) writeSyncedFile(sourceDir, projectDir, destToSource.get(destPath) ?? destPath);
280
231
  }
281
232
  const newSnapshotFiles = {};
282
233
  for (const filePath of filteredFiles) {
283
- const src = join(sourceDir, filePath);
284
- if (!lstatSync(src).isFile()) continue;
285
- const content = readFileSync(src);
234
+ const content = readFileSync(join(sourceDir, filePath));
286
235
  newSnapshotFiles[toDestPath(filePath)] = createHash("sha256").update(content).digest("hex").substring(0, 16);
287
236
  }
288
237
  await writeSnapshot(projectDir, {
289
238
  parentRef: `bos://${extendsAccount}/${extendsGateway}`,
290
239
  files: newSnapshotFiles
291
240
  });
241
+ const account = localConfig.account || extendsAccount;
242
+ const domain = localConfig.domain || extendsGateway;
243
+ const overrides = [];
244
+ if (withUi) overrides.push("ui");
245
+ if (withApi) overrides.push("api");
246
+ if (withHost) overrides.push("host");
247
+ if (childPlugins.length > 0) overrides.push("plugins");
292
248
  await personalizeConfig(projectDir, {
293
249
  extendsAccount,
294
250
  extendsGateway,
295
- account: localConfig.account || extendsAccount,
296
- domain: localConfig.domain || extendsGateway,
251
+ account,
252
+ domain,
253
+ overrides,
297
254
  plugins: childPlugins,
298
- pluginRoutes,
299
- overrides: [
300
- "ui",
301
- "api",
302
- "host",
303
- "plugins"
304
- ],
305
255
  workspaceOpts: { sourceDir },
306
256
  mode: "sync"
307
257
  });
@@ -1 +1 @@
1
- {"version":3,"file":"sync.mjs","names":["isPlainObjectFromMerge"],"sources":["../../src/cli/sync.ts"],"sourcesContent":["import { createHash } from \"node:crypto\";\nimport {\n copyFileSync,\n existsSync,\n lstatSync,\n mkdirSync,\n readFileSync,\n writeFileSync,\n} from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { glob } from \"glob\";\nimport { loadConfig } from \"../config\";\nimport type { SyncOptions, SyncResult } from \"../contract\";\nimport {\n isPlainObject as isPlainObjectFromMerge,\n mergeBosConfigWithTemplate,\n resolveExtendsRef,\n} from \"../merge\";\nimport { isPathExcluded } from \"../utils/path-match\";\nimport { writeGeneratedInfra } from \"./infra\";\nimport {\n personalizeConfig,\n readTemplatekeep,\n resolveSourceDir,\n runBunInstall,\n runTypesGen,\n} from \"./init\";\nimport { readSnapshot, writeSnapshot } from \"./snapshot\";\n\nconst FRAMEWORK_OWNED_SYNC_FILES = new Set([\n \".env.example\",\n \".gitignore\",\n \"biome.json\",\n \"bos.config.json\",\n \"package.json\",\n \"docker-compose.yml\",\n \".github/renovate.json\",\n \".github/workflows/ci.yml\",\n \".github/workflows/release-sync.yml\",\n \"ui/package.json\",\n \"ui/postcss.config.mjs\",\n \"ui/rsbuild.config.ts\",\n \"ui/tsconfig.json\",\n \"ui/src/app.ts\",\n \"ui/src/hydrate.tsx\",\n \"ui/src/lib/api.ts\",\n \"ui/src/lib/auth.ts\",\n \"ui/src/router.server.tsx\",\n \"ui/src/router.tsx\",\n \"ui/src/routes/__root.tsx\",\n \"api/package.json\",\n \"api/plugin.dev.ts\",\n \"api/rspack.config.js\",\n \"api/tsconfig.contract.json\",\n \"api/tsconfig.json\",\n \"api/src/lib/auth.ts\",\n]);\n\ntype PackageJson = Record<string, unknown>;\n\nexport function isFrameworkOwnedSyncFile(filePath: string): boolean {\n return FRAMEWORK_OWNED_SYNC_FILES.has(filePath);\n}\n\nfunction readExcludeFile(filePath: string): string[] {\n if (!existsSync(filePath)) return [];\n const content = readFileSync(filePath, \"utf-8\");\n return content\n .split(\"\\n\")\n .map((line) => line.trim())\n .filter((line) => line.length > 0 && !line.startsWith(\"#\"));\n}\n\nexport async function readTemplatesyncExclude(sourceDir: string): Promise<string[]> {\n return readExcludeFile(join(sourceDir, \".templatesync-exclude\"));\n}\n\nexport function readLocalSyncExcludes(projectDir: string): string[] {\n return readExcludeFile(join(projectDir, \".bos\", \"sync-local-exclude\"));\n}\n\nfunction computeLocalHash(projectDir: string, filePath: string): string | null {\n const fullPath = join(projectDir, filePath);\n if (!existsSync(fullPath)) return null;\n try {\n const content = readFileSync(fullPath);\n return createHash(\"sha256\").update(content).digest(\"hex\").substring(0, 16);\n } catch {\n return null;\n }\n}\n\nfunction backupFiles(projectDir: string, filePaths: string[]): string | null {\n const filesToBackup = filePaths.filter((f) => existsSync(join(projectDir, f)));\n if (filesToBackup.length === 0) return null;\n\n const timestamp = new Date().toISOString().replace(/[:.]/g, \"-\");\n const backupDir = join(projectDir, \".bos\", \"sync-backup\", timestamp);\n\n for (const filePath of filesToBackup) {\n const src = join(projectDir, filePath);\n const dest = join(backupDir, filePath);\n mkdirSync(dirname(dest), { recursive: true });\n copyFileSync(src, dest);\n }\n\n return backupDir;\n}\n\nfunction mergeStringMaps(\n local: Record<string, string> | undefined,\n template: Record<string, string> | undefined,\n): Record<string, string> | undefined {\n if (!local && !template) return undefined;\n\n const merged: Record<string, string> = { ...(local ?? {}) };\n for (const [name, value] of Object.entries(template ?? {})) {\n merged[name] = value;\n }\n\n return Object.keys(merged).length > 0 ? merged : undefined;\n}\n\nfunction mergeWorkspacePackages(local: unknown, template: unknown): string[] | undefined {\n const localPackages = Array.isArray(local) ? local : [];\n const templatePackages = Array.isArray(template) ? template : [];\n if (localPackages.length === 0 && templatePackages.length === 0) return undefined;\n\n const ordered = new Set<string>();\n for (const entry of templatePackages) {\n if (typeof entry === \"string\" && entry.length > 0) ordered.add(entry);\n }\n for (const entry of localPackages) {\n if (typeof entry === \"string\" && entry.length > 0) ordered.add(entry);\n }\n\n return ordered.size > 0 ? [...ordered] : undefined;\n}\n\nexport function mergePackageJson(\n filePath: string,\n local: PackageJson,\n template: PackageJson,\n): PackageJson {\n const merged: PackageJson = { ...local, ...template };\n\n if (filePath === \"package.json\") {\n for (const key of [\"name\", \"private\", \"version\"] as const) {\n if (key in local) {\n merged[key] = local[key];\n }\n }\n } else if (\"version\" in local) {\n merged.version = local.version;\n }\n\n for (const depField of [\n \"dependencies\",\n \"devDependencies\",\n \"peerDependencies\",\n \"overrides\",\n ] as const) {\n const localDeps = local[depField] as Record<string, string> | undefined;\n const templateDeps = template[depField] as Record<string, string> | undefined;\n\n const mergedDeps = mergeStringMaps(localDeps, templateDeps);\n if (mergedDeps) {\n merged[depField] = mergedDeps;\n } else {\n delete merged[depField];\n }\n }\n\n if (\n (local.scripts && typeof local.scripts === \"object\") ||\n (template.scripts && typeof template.scripts === \"object\")\n ) {\n const mergedScripts = mergeStringMaps(\n local.scripts as Record<string, string> | undefined,\n template.scripts as Record<string, string> | undefined,\n );\n if (mergedScripts) {\n merged.scripts = mergedScripts;\n } else {\n delete merged.scripts;\n }\n }\n\n if (\n (local.workspaces && typeof local.workspaces === \"object\") ||\n (template.workspaces && typeof template.workspaces === \"object\")\n ) {\n const localWorkspaces = (local.workspaces ?? {}) as {\n packages?: string[];\n catalog?: Record<string, string>;\n };\n const templateWorkspaces = (template.workspaces ?? {}) as {\n packages?: string[];\n catalog?: Record<string, string>;\n };\n\n const mergedWorkspaces: { packages?: string[]; catalog?: Record<string, string> } = {\n ...localWorkspaces,\n ...templateWorkspaces,\n };\n\n const mergedPackages = mergeWorkspacePackages(\n localWorkspaces.packages,\n templateWorkspaces.packages,\n );\n if (mergedPackages) {\n mergedWorkspaces.packages = mergedPackages;\n } else {\n delete mergedWorkspaces.packages;\n }\n\n const mergedCatalog = mergeStringMaps(localWorkspaces.catalog, templateWorkspaces.catalog);\n if (mergedCatalog) {\n mergedWorkspaces.catalog = mergedCatalog;\n } else {\n delete mergedWorkspaces.catalog;\n }\n\n if (Object.keys(mergedWorkspaces).length > 0) {\n merged.workspaces = mergedWorkspaces;\n } else {\n delete merged.workspaces;\n }\n }\n\n return merged;\n}\n\nfunction toDestPath(filePath: string): string {\n return filePath.startsWith(\".github/templates/\")\n ? filePath.replace(/^\\.github\\/templates\\//, \".github/\")\n : filePath;\n}\n\nfunction writeSyncedFile(sourceDir: string, projectDir: string, filePath: string): void {\n const src = join(sourceDir, filePath);\n const destPath = filePath.startsWith(\".github/templates/\")\n ? filePath.replace(/^\\.github\\/templates\\//, \".github/\")\n : filePath;\n const dest = join(projectDir, destPath);\n mkdirSync(dirname(dest), { recursive: true });\n\n if (filePath.endsWith(\"bos.config.json\")) {\n const localContent = existsSync(dest) ? readFileSync(dest, \"utf-8\") : null;\n const templateContent = readFileSync(src, \"utf-8\");\n\n if (localContent) {\n const local = JSON.parse(localContent) as Record<string, unknown>;\n const template = JSON.parse(templateContent) as Record<string, unknown>;\n const merged = mergeBosConfigWithTemplate(local, template);\n writeFileSync(dest, `${JSON.stringify(merged, null, 2)}\\n`);\n return;\n }\n }\n\n if (filePath.endsWith(\"package.json\")) {\n const localContent = existsSync(dest) ? readFileSync(dest, \"utf-8\") : null;\n const templateContent = readFileSync(src, \"utf-8\");\n\n if (localContent) {\n const local = JSON.parse(localContent) as Record<string, unknown>;\n const template = JSON.parse(templateContent) as Record<string, unknown>;\n const merged = mergePackageJson(destPath, local, template);\n writeFileSync(dest, `${JSON.stringify(merged, null, 2)}\\n`);\n return;\n }\n }\n\n writeFileSync(dest, readFileSync(src));\n}\n\nexport async function syncTemplate(projectDir: string, options: SyncOptions): Promise<SyncResult> {\n // Sync reads the raw bos.config.json (not the resolved config) because it needs\n // the user's explicit local settings: their extends ref, selected plugins, etc.\n // The resolved config is the merged result and would include inherited parent\n // values that the user didn't explicitly choose, which would break sync filtering.\n const localConfig = JSON.parse(\n readFileSync(join(projectDir, \"bos.config.json\"), \"utf-8\"),\n ) as Record<string, unknown>;\n\n let extendsRef: string | undefined;\n if (typeof localConfig.extends === \"string\") {\n extendsRef = localConfig.extends;\n } else if (isPlainObjectFromMerge(localConfig.extends)) {\n extendsRef = resolveExtendsRef(localConfig.extends as Record<string, string>, \"production\");\n }\n if (!extendsRef?.startsWith(\"bos://\")) {\n return {\n status: \"error\",\n updated: [],\n skipped: [],\n added: [],\n error: \"No extends field found in bos.config.json — cannot determine parent\",\n };\n }\n\n const extendsMatch = extendsRef.match(/^bos:\\/\\/([^/]+)\\/(.+)$/);\n if (!extendsMatch) {\n return {\n status: \"error\",\n updated: [],\n skipped: [],\n added: [],\n error: `Invalid extends reference: ${extendsRef}`,\n };\n }\n\n const extendsAccount = extendsMatch[1];\n const extendsGateway = extendsMatch[2];\n\n const { sourceDir, cleanup } = await resolveSourceDir({\n extendsAccount,\n extendsGateway,\n });\n\n try {\n const patterns = await readTemplatekeep(sourceDir);\n if (patterns.length === 0) {\n return {\n status: \"error\",\n updated: [],\n skipped: [],\n added: [],\n error: \"No .templatekeep found in template source\",\n };\n }\n\n const parentExcludes = await readTemplatesyncExclude(sourceDir);\n const localExcludes = readLocalSyncExcludes(projectDir);\n const excludePatterns = [...parentExcludes, ...localExcludes];\n\n const allTemplateFiles = new Set<string>();\n for (const pattern of patterns) {\n const matches = await glob(pattern, {\n cwd: sourceDir,\n nodir: true,\n dot: true,\n absolute: false,\n });\n for (const match of matches) {\n allTemplateFiles.add(match);\n }\n }\n\n const childPlugins =\n localConfig.plugins && typeof localConfig.plugins === \"object\"\n ? Object.keys(localConfig.plugins as Record<string, unknown>)\n : [];\n\n const pluginRoutes: Record<string, string[]> = {};\n const parentRuntime = await loadConfig({ cwd: sourceDir });\n for (const [key, plugin] of Object.entries(parentRuntime?.runtime.plugins ?? {})) {\n if (plugin.routes && plugin.routes.length > 0) {\n pluginRoutes[key] = plugin.routes;\n }\n }\n\n const excludedRoutePatterns: string[] = [];\n for (const [pluginKey, routePatterns] of Object.entries(pluginRoutes)) {\n if (!childPlugins.includes(pluginKey)) {\n excludedRoutePatterns.push(...routePatterns);\n }\n }\n\n const filteredFiles = new Set<string>();\n for (const filePath of allTemplateFiles) {\n const pluginMatch = filePath.match(/^plugins\\/([^/]+)/);\n if (pluginMatch && !childPlugins.includes(pluginMatch[1])) continue;\n if (isPathExcluded(filePath, excludedRoutePatterns)) continue;\n filteredFiles.add(filePath);\n }\n\n for (const [pluginKey, routePatterns] of Object.entries(pluginRoutes)) {\n if (!childPlugins.includes(pluginKey)) continue;\n for (const rp of routePatterns) {\n const matches = await glob(rp, {\n cwd: sourceDir,\n nodir: true,\n dot: true,\n absolute: false,\n });\n for (const match of matches) {\n if (!isPathExcluded(match, excludedRoutePatterns)) {\n filteredFiles.add(match);\n }\n }\n }\n }\n\n const snapshot = await readSnapshot(projectDir);\n\n const updated: string[] = [];\n const skipped: string[] = [];\n const added: string[] = [];\n\n for (const filePath of filteredFiles) {\n const destPath = toDestPath(filePath);\n const frameworkOwned = isFrameworkOwnedSyncFile(destPath);\n if (isPathExcluded(destPath, excludePatterns) && !frameworkOwned) continue;\n\n const localHash = computeLocalHash(projectDir, destPath);\n const sourceContent = readFileSync(join(sourceDir, filePath));\n const sourceHash = createHash(\"sha256\").update(sourceContent).digest(\"hex\").substring(0, 16);\n\n if (localHash === null) {\n added.push(destPath);\n continue;\n }\n\n if (localHash === sourceHash) continue;\n\n if (frameworkOwned) {\n updated.push(destPath);\n continue;\n }\n\n const snapshotHash = snapshot?.files[destPath];\n\n if (snapshotHash === undefined) {\n updated.push(destPath);\n continue;\n }\n\n if (localHash === snapshotHash) {\n updated.push(destPath);\n } else {\n if (options.force) {\n updated.push(destPath);\n } else {\n skipped.push(destPath);\n }\n }\n }\n\n if (options.dryRun) {\n return {\n status: \"dry-run\",\n updated,\n skipped,\n added,\n };\n }\n\n const filesToWrite = [...updated, ...added].filter(\n (f) => isFrameworkOwnedSyncFile(f) || !isPathExcluded(f, excludePatterns),\n );\n\n const destToSource = new Map<string, string>();\n for (const filePath of filteredFiles) {\n destToSource.set(toDestPath(filePath), filePath);\n }\n\n if (filesToWrite.length > 0) {\n backupFiles(projectDir, filesToWrite);\n\n for (const destPath of filesToWrite) {\n const sourcePath = destToSource.get(destPath) ?? destPath;\n writeSyncedFile(sourceDir, projectDir, sourcePath);\n }\n }\n\n const newSnapshotFiles: Record<string, string> = {};\n for (const filePath of filteredFiles) {\n const src = join(sourceDir, filePath);\n const stat = lstatSync(src);\n if (!stat.isFile()) continue;\n const content = readFileSync(src);\n newSnapshotFiles[toDestPath(filePath)] = createHash(\"sha256\")\n .update(content)\n .digest(\"hex\")\n .substring(0, 16);\n }\n\n await writeSnapshot(projectDir, {\n parentRef: `bos://${extendsAccount}/${extendsGateway}`,\n files: newSnapshotFiles,\n });\n\n const account = (localConfig.account as string) || extendsAccount;\n const domain = (localConfig.domain as string) || extendsGateway;\n\n await personalizeConfig(projectDir, {\n extendsAccount,\n extendsGateway,\n account,\n domain,\n plugins: childPlugins,\n pluginRoutes,\n overrides: [\"ui\", \"api\", \"host\", \"plugins\"],\n workspaceOpts: { sourceDir },\n mode: \"sync\",\n });\n\n const syncedConfig = await loadConfig({ cwd: projectDir });\n if (syncedConfig?.runtime) {\n writeGeneratedInfra(projectDir, syncedConfig.runtime);\n }\n\n if (!options.noInstall) {\n await runBunInstall(projectDir);\n await runTypesGen(projectDir);\n }\n\n return {\n status: \"synced\",\n updated,\n skipped,\n added,\n };\n } finally {\n await cleanup();\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"sync.mjs","names":["isPlainObjectFromMerge"],"sources":["../../src/cli/sync.ts"],"sourcesContent":["import { createHash } from \"node:crypto\";\nimport { copyFileSync, existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { loadConfig } from \"../config\";\nimport type { SyncOptions, SyncResult } from \"../contract\";\nimport {\n isPlainObject as isPlainObjectFromMerge,\n mergeBosConfigWithTemplate,\n resolveExtendsRef,\n} from \"../merge\";\nimport { writeGeneratedInfra } from \"./infra\";\nimport {\n personalizeConfig,\n resolveSourceDir,\n runBunInstall,\n runTypesGen,\n sourcePathToDestinationPath,\n} from \"./init\";\nimport { writeSnapshot } from \"./snapshot\";\n\nconst FRAMEWORK_OWNED_SYNC_FILES = new Set([\n \".env.example\",\n \".gitignore\",\n \"AGENTS.md\",\n \"biome.json\",\n \"bos.config.json\",\n \"bunfig.toml\",\n \"CONTRIBUTING.md\",\n \"package.json\",\n \".changeset/config.json\",\n \".changeset/README.md\",\n \"docker-compose.yml\",\n \".github/renovate.json\",\n \".github/workflows/ci.yml\",\n \".github/workflows/release-sync.yml\",\n \".opencode/skills/everything-dev/SKILL.md\",\n \"ui/package.json\",\n \"ui/postcss.config.mjs\",\n \"ui/rsbuild.config.ts\",\n \"ui/tsconfig.json\",\n \"ui/src/app.ts\",\n \"ui/src/globals.d.ts\",\n \"ui/src/hydrate.tsx\",\n \"ui/src/lib/api.ts\",\n \"ui/src/lib/auth.ts\",\n \"ui/src/router.server.tsx\",\n \"ui/src/router.tsx\",\n \"ui/src/routes/__root.tsx\",\n \"api/package.json\",\n \"api/plugin.dev.ts\",\n \"api/rspack.config.js\",\n \"api/tsconfig.contract.json\",\n \"api/tsconfig.json\",\n \"api/src/lib/auth.ts\",\n]);\n\ntype PackageJson = Record<string, unknown>;\n\nexport function isFrameworkOwnedSyncFile(filePath: string): boolean {\n return FRAMEWORK_OWNED_SYNC_FILES.has(filePath);\n}\n\nfunction computeLocalHash(projectDir: string, filePath: string): string | null {\n const fullPath = join(projectDir, filePath);\n if (!existsSync(fullPath)) return null;\n try {\n const content = readFileSync(fullPath);\n return createHash(\"sha256\").update(content).digest(\"hex\").substring(0, 16);\n } catch {\n return null;\n }\n}\n\nfunction backupFiles(projectDir: string, filePaths: string[]): string | null {\n const filesToBackup = filePaths.filter((f) => existsSync(join(projectDir, f)));\n if (filesToBackup.length === 0) return null;\n\n const timestamp = new Date().toISOString().replace(/[:.]/g, \"-\");\n const backupDir = join(projectDir, \".bos\", \"sync-backup\", timestamp);\n\n for (const filePath of filesToBackup) {\n const src = join(projectDir, filePath);\n const dest = join(backupDir, filePath);\n mkdirSync(dirname(dest), { recursive: true });\n copyFileSync(src, dest);\n }\n\n return backupDir;\n}\n\nfunction mergeStringMaps(\n local: Record<string, string> | undefined,\n template: Record<string, string> | undefined,\n): Record<string, string> | undefined {\n if (!local && !template) return undefined;\n\n const merged: Record<string, string> = { ...(local ?? {}) };\n for (const [name, value] of Object.entries(template ?? {})) {\n merged[name] = value;\n }\n\n return Object.keys(merged).length > 0 ? merged : undefined;\n}\n\nfunction mergeWorkspacePackages(local: unknown, template: unknown): string[] | undefined {\n const localPackages = Array.isArray(local) ? local : [];\n const templatePackages = Array.isArray(template) ? template : [];\n if (localPackages.length === 0 && templatePackages.length === 0) return undefined;\n\n const ordered = new Set<string>();\n for (const entry of templatePackages) {\n if (typeof entry === \"string\" && entry.length > 0) ordered.add(entry);\n }\n for (const entry of localPackages) {\n if (typeof entry === \"string\" && entry.length > 0) ordered.add(entry);\n }\n\n return ordered.size > 0 ? [...ordered] : undefined;\n}\n\nexport function mergePackageJson(\n filePath: string,\n local: PackageJson,\n template: PackageJson,\n): PackageJson {\n const merged: PackageJson = { ...local, ...template };\n\n if (filePath === \"package.json\") {\n for (const key of [\"name\", \"private\", \"version\"] as const) {\n if (key in local) {\n merged[key] = local[key];\n }\n }\n } else if (\"version\" in local) {\n merged.version = local.version;\n }\n\n for (const depField of [\n \"dependencies\",\n \"devDependencies\",\n \"peerDependencies\",\n \"overrides\",\n ] as const) {\n const localDeps = local[depField] as Record<string, string> | undefined;\n const templateDeps = template[depField] as Record<string, string> | undefined;\n\n const mergedDeps = mergeStringMaps(localDeps, templateDeps);\n if (mergedDeps) {\n merged[depField] = mergedDeps;\n } else {\n delete merged[depField];\n }\n }\n\n if (\n (local.scripts && typeof local.scripts === \"object\") ||\n (template.scripts && typeof template.scripts === \"object\")\n ) {\n const mergedScripts = mergeStringMaps(\n local.scripts as Record<string, string> | undefined,\n template.scripts as Record<string, string> | undefined,\n );\n if (mergedScripts) {\n merged.scripts = mergedScripts;\n } else {\n delete merged.scripts;\n }\n }\n\n if (\n (local.workspaces && typeof local.workspaces === \"object\") ||\n (template.workspaces && typeof template.workspaces === \"object\")\n ) {\n const localWorkspaces = (local.workspaces ?? {}) as {\n packages?: string[];\n catalog?: Record<string, string>;\n };\n const templateWorkspaces = (template.workspaces ?? {}) as {\n packages?: string[];\n catalog?: Record<string, string>;\n };\n\n const mergedWorkspaces: { packages?: string[]; catalog?: Record<string, string> } = {\n ...localWorkspaces,\n ...templateWorkspaces,\n };\n\n const mergedPackages = mergeWorkspacePackages(\n localWorkspaces.packages,\n templateWorkspaces.packages,\n );\n if (mergedPackages) {\n mergedWorkspaces.packages = mergedPackages;\n } else {\n delete mergedWorkspaces.packages;\n }\n\n const mergedCatalog = mergeStringMaps(localWorkspaces.catalog, templateWorkspaces.catalog);\n if (mergedCatalog) {\n mergedWorkspaces.catalog = mergedCatalog;\n } else {\n delete mergedWorkspaces.catalog;\n }\n\n if (Object.keys(mergedWorkspaces).length > 0) {\n merged.workspaces = mergedWorkspaces;\n } else {\n delete merged.workspaces;\n }\n }\n\n return merged;\n}\n\nfunction toDestPath(filePath: string): string {\n return sourcePathToDestinationPath(filePath);\n}\n\nfunction toSourcePath(sourceDir: string, destPath: string): string | null {\n const directPath = join(sourceDir, destPath);\n if (existsSync(directPath)) {\n return destPath;\n }\n\n if (destPath.startsWith(\".github/\")) {\n const templatePath = destPath.replace(/^\\.github\\//, \".github/templates/\");\n if (existsSync(join(sourceDir, templatePath))) {\n return templatePath;\n }\n }\n\n return null;\n}\n\nfunction writeSyncedFile(sourceDir: string, projectDir: string, filePath: string): void {\n const src = join(sourceDir, filePath);\n const destPath = filePath.startsWith(\".github/templates/\")\n ? filePath.replace(/^\\.github\\/templates\\//, \".github/\")\n : filePath;\n const dest = join(projectDir, destPath);\n mkdirSync(dirname(dest), { recursive: true });\n\n if (filePath.endsWith(\"bos.config.json\")) {\n const localContent = existsSync(dest) ? readFileSync(dest, \"utf-8\") : null;\n const templateContent = readFileSync(src, \"utf-8\");\n\n if (localContent) {\n const local = JSON.parse(localContent) as Record<string, unknown>;\n const template = JSON.parse(templateContent) as Record<string, unknown>;\n const merged = mergeBosConfigWithTemplate(local, template);\n writeFileSync(dest, `${JSON.stringify(merged, null, 2)}\\n`);\n return;\n }\n }\n\n if (filePath.endsWith(\"package.json\")) {\n const localContent = existsSync(dest) ? readFileSync(dest, \"utf-8\") : null;\n const templateContent = readFileSync(src, \"utf-8\");\n\n if (localContent) {\n const local = JSON.parse(localContent) as Record<string, unknown>;\n const template = JSON.parse(templateContent) as Record<string, unknown>;\n const merged = mergePackageJson(destPath, local, template);\n writeFileSync(dest, `${JSON.stringify(merged, null, 2)}\\n`);\n return;\n }\n }\n\n writeFileSync(dest, readFileSync(src));\n}\n\nexport async function syncTemplate(projectDir: string, options: SyncOptions): Promise<SyncResult> {\n // Sync reads the raw bos.config.json (not the resolved config) because it needs\n // the user's explicit local settings: their extends ref, selected plugins, etc.\n // The resolved config is the merged result and would include inherited parent\n // values that the user didn't explicitly choose, which would break sync filtering.\n const localConfig = JSON.parse(\n readFileSync(join(projectDir, \"bos.config.json\"), \"utf-8\"),\n ) as Record<string, unknown>;\n\n let extendsRef: string | undefined;\n if (typeof localConfig.extends === \"string\") {\n extendsRef = localConfig.extends;\n } else if (isPlainObjectFromMerge(localConfig.extends)) {\n extendsRef = resolveExtendsRef(localConfig.extends as Record<string, string>, \"production\");\n }\n if (!extendsRef?.startsWith(\"bos://\")) {\n return {\n status: \"error\",\n updated: [],\n skipped: [],\n added: [],\n error: \"No extends field found in bos.config.json — cannot determine parent\",\n };\n }\n\n const extendsMatch = extendsRef.match(/^bos:\\/\\/([^/]+)\\/(.+)$/);\n if (!extendsMatch) {\n return {\n status: \"error\",\n updated: [],\n skipped: [],\n added: [],\n error: `Invalid extends reference: ${extendsRef}`,\n };\n }\n\n const extendsAccount = extendsMatch[1];\n const extendsGateway = extendsMatch[2];\n\n const { sourceDir, cleanup } = await resolveSourceDir({\n extendsAccount,\n extendsGateway,\n });\n\n try {\n const childPlugins =\n localConfig.plugins && typeof localConfig.plugins === \"object\"\n ? Object.keys(localConfig.plugins as Record<string, unknown>)\n : [];\n const withUi = existsSync(join(projectDir, \"ui\", \"package.json\"));\n const withApi = existsSync(join(projectDir, \"api\", \"package.json\"));\n const withHost = existsSync(join(projectDir, \"host\", \"package.json\"));\n\n const filteredFiles = new Set<string>();\n const destToSource = new Map<string, string>();\n for (const destPath of FRAMEWORK_OWNED_SYNC_FILES) {\n if (destPath.startsWith(\"ui/\") && !withUi) continue;\n if (destPath.startsWith(\"api/\") && !withApi) continue;\n if (destPath.startsWith(\"host/\") && !withHost) continue;\n const sourcePath = toSourcePath(sourceDir, destPath);\n if (!sourcePath) continue;\n filteredFiles.add(sourcePath);\n destToSource.set(destPath, sourcePath);\n }\n\n const updated: string[] = [];\n const skipped: string[] = [];\n const added: string[] = [];\n\n for (const [destPath, filePath] of destToSource.entries()) {\n const localHash = computeLocalHash(projectDir, destPath);\n const sourceContent = readFileSync(join(sourceDir, filePath));\n const sourceHash = createHash(\"sha256\").update(sourceContent).digest(\"hex\").substring(0, 16);\n\n if (localHash === null) {\n added.push(destPath);\n continue;\n }\n\n if (localHash !== sourceHash) {\n updated.push(destPath);\n }\n }\n\n if (options.dryRun) {\n return {\n status: \"dry-run\",\n updated,\n skipped,\n added,\n };\n }\n\n const filesToWrite = [...updated, ...added];\n\n if (filesToWrite.length > 0) {\n backupFiles(projectDir, filesToWrite);\n\n for (const destPath of filesToWrite) {\n const sourcePath = destToSource.get(destPath) ?? destPath;\n writeSyncedFile(sourceDir, projectDir, sourcePath);\n }\n }\n\n const newSnapshotFiles: Record<string, string> = {};\n for (const filePath of filteredFiles) {\n const src = join(sourceDir, filePath);\n const content = readFileSync(src);\n newSnapshotFiles[toDestPath(filePath)] = createHash(\"sha256\")\n .update(content)\n .digest(\"hex\")\n .substring(0, 16);\n }\n\n await writeSnapshot(projectDir, {\n parentRef: `bos://${extendsAccount}/${extendsGateway}`,\n files: newSnapshotFiles,\n });\n\n const account = (localConfig.account as string) || extendsAccount;\n const domain = (localConfig.domain as string) || extendsGateway;\n const overrides: Array<\"ui\" | \"api\" | \"host\" | \"plugins\"> = [];\n if (withUi) overrides.push(\"ui\");\n if (withApi) overrides.push(\"api\");\n if (withHost) overrides.push(\"host\");\n if (childPlugins.length > 0) overrides.push(\"plugins\");\n\n await personalizeConfig(projectDir, {\n extendsAccount,\n extendsGateway,\n account,\n domain,\n overrides,\n plugins: childPlugins,\n workspaceOpts: { sourceDir },\n mode: \"sync\",\n });\n\n const syncedConfig = await loadConfig({ cwd: projectDir });\n if (syncedConfig?.runtime) {\n writeGeneratedInfra(projectDir, syncedConfig.runtime);\n }\n\n if (!options.noInstall) {\n await runBunInstall(projectDir);\n await runTypesGen(projectDir);\n }\n\n return {\n status: \"synced\",\n updated,\n skipped,\n added,\n };\n } finally {\n await cleanup();\n }\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"timing.cjs","names":[],"sources":["../../src/cli/timing.ts"],"sourcesContent":["import type { spinner as clackSpinner } from \"@clack/prompts\";\n\ntype Spinner = ReturnType<typeof clackSpinner>;\n\nexport interface PhaseTiming {\n name: string;\n durationMs: number;\n}\n\nconst PHASE_LABELS: Record<string, string> = {\n \"parent config\": \"Fetching parent config...\",\n \"template source\": \"Resolving template source...\",\n \"scaffold project\": \"Creating project scaffold...\",\n \"copy files\": \"Copying template files...\",\n \"personalize config\": \"Personalizing config...\",\n \"write snapshot\": \"Writing snapshot...\",\n \"resolve config\": \"Resolving config...\",\n \"generate env/docker\": \"Generating environment config...\",\n \"create env file\": \"Creating .env file...\",\n \"install dependencies\": \"Installing dependencies...\",\n \"generate types\": \"Generating types...\",\n \"generate migrations\": \"Generating database migrations...\",\n \"generate code artifacts\": \"Generating code artifacts...\",\n \"docker compose up\": \"Starting Docker services...\",\n};\n\nfunction phaseLabel(name: string): string {\n return PHASE_LABELS[name] ?? name;\n}\n\nexport async function timePhase<T>(\n timings: PhaseTiming[],\n name: string,\n fn: () => Promise<T>,\n spinner?: Spinner,\n): Promise<T> {\n spinner?.message(phaseLabel(name));\n const startedAt = Date.now();\n try {\n return await fn();\n } finally {\n timings.push({ name, durationMs: Date.now() - startedAt });\n }\n}\n\nexport function sumPhaseDurations(timings: PhaseTiming[]): number {\n return timings.reduce((total, timing) => total + timing.durationMs, 0);\n}\n\nexport function formatDuration(durationMs: number): string {\n if (durationMs < 1000) {\n return `${durationMs}ms`;\n }\n\n if (durationMs < 60_000) {\n const seconds = durationMs / 1000;\n return `${seconds.toFixed(seconds >= 10 ? 0 : 1)}s`;\n }\n\n const minutes = Math.floor(durationMs / 60_000);\n const seconds = Math.round((durationMs % 60_000) / 1000);\n return `${minutes}m ${seconds}s`;\n}\n"],"mappings":";;AASA,MAAM,eAAuC;CAC3C,iBAAiB;CACjB,mBAAmB;CACnB,oBAAoB;CACpB,cAAc;CACd,sBAAsB;CACtB,kBAAkB;CAClB,kBAAkB;CAClB,uBAAuB;CACvB,mBAAmB;CACnB,wBAAwB;CACxB,kBAAkB;CAClB,uBAAuB;CACvB,2BAA2B;CAC3B,qBAAqB;CACtB;AAED,SAAS,WAAW,MAAsB;AACxC,QAAO,aAAa,SAAS;;AAG/B,eAAsB,UACpB,SACA,MACA,IACA,SACY;AACZ,UAAS,QAAQ,WAAW,KAAK,CAAC;CAClC,MAAM,YAAY,KAAK,KAAK;AAC5B,KAAI;AACF,SAAO,MAAM,IAAI;WACT;AACR,UAAQ,KAAK;GAAE;GAAM,YAAY,KAAK,KAAK,GAAG;GAAW,CAAC;;;AAI9D,SAAgB,kBAAkB,SAAgC;AAChE,QAAO,QAAQ,QAAQ,OAAO,WAAW,QAAQ,OAAO,YAAY,EAAE;;AAGxE,SAAgB,eAAe,YAA4B;AACzD,KAAI,aAAa,IACf,QAAO,GAAG,WAAW;AAGvB,KAAI,aAAa,KAAQ;EACvB,MAAM,UAAU,aAAa;AAC7B,SAAO,GAAG,QAAQ,QAAQ,WAAW,KAAK,IAAI,EAAE,CAAC;;AAKnD,QAAO,GAFS,KAAK,MAAM,aAAa,IAAO,CAE7B,IADF,KAAK,MAAO,aAAa,MAAU,IAAK,CAC1B"}
1
+ {"version":3,"file":"timing.cjs","names":[],"sources":["../../src/cli/timing.ts"],"sourcesContent":["import type { spinner as clackSpinner } from \"@clack/prompts\";\n\ntype Spinner = ReturnType<typeof clackSpinner>;\n\nexport interface PhaseTiming {\n name: string;\n durationMs: number;\n}\n\nconst PHASE_LABELS: Record<string, string> = {\n \"parent config\": \"Fetching parent config...\",\n \"template source\": \"Resolving template source...\",\n \"scaffold project\": \"Creating project scaffold...\",\n \"copy files\": \"Copying template files...\",\n \"personalize config\": \"Personalizing config...\",\n \"write snapshot\": \"Writing snapshot...\",\n \"resolve config\": \"Resolving config...\",\n \"generate env/docker\": \"Generating environment config...\",\n \"create env file\": \"Creating .env file...\",\n \"install dependencies\": \"Installing dependencies...\",\n \"generate types\": \"Generating types...\",\n \"generate migrations\": \"Generating database migrations...\",\n \"generate code artifacts\": \"Generating code artifacts...\",\n \"docker compose up\": \"Starting Docker services...\",\n};\n\nfunction phaseLabel(name: string): string {\n return PHASE_LABELS[name] ?? name;\n}\n\nexport async function timePhase<T>(\n timings: PhaseTiming[],\n name: string,\n fn: () => Promise<T>,\n spinner?: Spinner,\n): Promise<T> {\n spinner?.message(phaseLabel(name));\n const startedAt = Date.now();\n try {\n return await fn();\n } finally {\n timings.push({ name, durationMs: Date.now() - startedAt });\n }\n}\n\nexport function sumPhaseDurations(timings: PhaseTiming[]): number {\n return timings.reduce((total, timing) => total + timing.durationMs, 0);\n}\n\nexport function formatDuration(durationMs: number): string {\n if (durationMs < 1000) {\n return `${durationMs}ms`;\n }\n\n if (durationMs < 60_000) {\n const seconds = durationMs / 1000;\n return `${seconds.toFixed(seconds >= 10 ? 0 : 1)}s`;\n }\n\n const minutes = Math.floor(durationMs / 60_000);\n const seconds = Math.round((durationMs % 60_000) / 1000);\n return `${minutes}m ${seconds}s`;\n}\n"],"mappings":";;AASA,MAAM,eAAuC;CAC3C,iBAAiB;CACjB,mBAAmB;CACnB,oBAAoB;CACpB,cAAc;CACd,sBAAsB;CACtB,kBAAkB;CAClB,kBAAkB;CAClB,uBAAuB;CACvB,mBAAmB;CACnB,wBAAwB;CACxB,kBAAkB;CAClB,uBAAuB;CACvB,2BAA2B;CAC3B,qBAAqB;CACtB;AAED,SAAS,WAAW,MAAsB;AACxC,QAAO,aAAa,SAAS;;AAG/B,eAAsB,UACpB,SACA,MACA,IACA,SACY;AACZ,UAAS,QAAQ,WAAW,KAAK,CAAC;CAClC,MAAM,YAAY,KAAK,KAAK;AAC5B,KAAI;AACF,SAAO,MAAM,IAAI;WACT;AACR,UAAQ,KAAK;GAAE;GAAM,YAAY,KAAK,KAAK,GAAG;GAAW,CAAC;;;AAI9D,SAAgB,kBAAkB,SAAgC;AAChE,QAAO,QAAQ,QAAQ,OAAO,WAAW,QAAQ,OAAO,YAAY,EAAE;;AAGxE,SAAgB,eAAe,YAA4B;AACzD,KAAI,aAAa,IACf,QAAO,GAAG,WAAW;AAGvB,KAAI,aAAa,KAAQ;EACvB,MAAM,UAAU,aAAa;AAC7B,SAAO,GAAG,QAAQ,QAAQ,WAAW,KAAK,IAAI,EAAE,CAAC;;AAKnD,QAAO,GAFS,KAAK,MAAM,aAAa,IAEvB,CAAC,IADF,KAAK,MAAO,aAAa,MAAU,IACtB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"timing.mjs","names":[],"sources":["../../src/cli/timing.ts"],"sourcesContent":["import type { spinner as clackSpinner } from \"@clack/prompts\";\n\ntype Spinner = ReturnType<typeof clackSpinner>;\n\nexport interface PhaseTiming {\n name: string;\n durationMs: number;\n}\n\nconst PHASE_LABELS: Record<string, string> = {\n \"parent config\": \"Fetching parent config...\",\n \"template source\": \"Resolving template source...\",\n \"scaffold project\": \"Creating project scaffold...\",\n \"copy files\": \"Copying template files...\",\n \"personalize config\": \"Personalizing config...\",\n \"write snapshot\": \"Writing snapshot...\",\n \"resolve config\": \"Resolving config...\",\n \"generate env/docker\": \"Generating environment config...\",\n \"create env file\": \"Creating .env file...\",\n \"install dependencies\": \"Installing dependencies...\",\n \"generate types\": \"Generating types...\",\n \"generate migrations\": \"Generating database migrations...\",\n \"generate code artifacts\": \"Generating code artifacts...\",\n \"docker compose up\": \"Starting Docker services...\",\n};\n\nfunction phaseLabel(name: string): string {\n return PHASE_LABELS[name] ?? name;\n}\n\nexport async function timePhase<T>(\n timings: PhaseTiming[],\n name: string,\n fn: () => Promise<T>,\n spinner?: Spinner,\n): Promise<T> {\n spinner?.message(phaseLabel(name));\n const startedAt = Date.now();\n try {\n return await fn();\n } finally {\n timings.push({ name, durationMs: Date.now() - startedAt });\n }\n}\n\nexport function sumPhaseDurations(timings: PhaseTiming[]): number {\n return timings.reduce((total, timing) => total + timing.durationMs, 0);\n}\n\nexport function formatDuration(durationMs: number): string {\n if (durationMs < 1000) {\n return `${durationMs}ms`;\n }\n\n if (durationMs < 60_000) {\n const seconds = durationMs / 1000;\n return `${seconds.toFixed(seconds >= 10 ? 0 : 1)}s`;\n }\n\n const minutes = Math.floor(durationMs / 60_000);\n const seconds = Math.round((durationMs % 60_000) / 1000);\n return `${minutes}m ${seconds}s`;\n}\n"],"mappings":";AASA,MAAM,eAAuC;CAC3C,iBAAiB;CACjB,mBAAmB;CACnB,oBAAoB;CACpB,cAAc;CACd,sBAAsB;CACtB,kBAAkB;CAClB,kBAAkB;CAClB,uBAAuB;CACvB,mBAAmB;CACnB,wBAAwB;CACxB,kBAAkB;CAClB,uBAAuB;CACvB,2BAA2B;CAC3B,qBAAqB;CACtB;AAED,SAAS,WAAW,MAAsB;AACxC,QAAO,aAAa,SAAS;;AAG/B,eAAsB,UACpB,SACA,MACA,IACA,SACY;AACZ,UAAS,QAAQ,WAAW,KAAK,CAAC;CAClC,MAAM,YAAY,KAAK,KAAK;AAC5B,KAAI;AACF,SAAO,MAAM,IAAI;WACT;AACR,UAAQ,KAAK;GAAE;GAAM,YAAY,KAAK,KAAK,GAAG;GAAW,CAAC;;;AAI9D,SAAgB,kBAAkB,SAAgC;AAChE,QAAO,QAAQ,QAAQ,OAAO,WAAW,QAAQ,OAAO,YAAY,EAAE;;AAGxE,SAAgB,eAAe,YAA4B;AACzD,KAAI,aAAa,IACf,QAAO,GAAG,WAAW;AAGvB,KAAI,aAAa,KAAQ;EACvB,MAAM,UAAU,aAAa;AAC7B,SAAO,GAAG,QAAQ,QAAQ,WAAW,KAAK,IAAI,EAAE,CAAC;;AAKnD,QAAO,GAFS,KAAK,MAAM,aAAa,IAAO,CAE7B,IADF,KAAK,MAAO,aAAa,MAAU,IAAK,CAC1B"}
1
+ {"version":3,"file":"timing.mjs","names":[],"sources":["../../src/cli/timing.ts"],"sourcesContent":["import type { spinner as clackSpinner } from \"@clack/prompts\";\n\ntype Spinner = ReturnType<typeof clackSpinner>;\n\nexport interface PhaseTiming {\n name: string;\n durationMs: number;\n}\n\nconst PHASE_LABELS: Record<string, string> = {\n \"parent config\": \"Fetching parent config...\",\n \"template source\": \"Resolving template source...\",\n \"scaffold project\": \"Creating project scaffold...\",\n \"copy files\": \"Copying template files...\",\n \"personalize config\": \"Personalizing config...\",\n \"write snapshot\": \"Writing snapshot...\",\n \"resolve config\": \"Resolving config...\",\n \"generate env/docker\": \"Generating environment config...\",\n \"create env file\": \"Creating .env file...\",\n \"install dependencies\": \"Installing dependencies...\",\n \"generate types\": \"Generating types...\",\n \"generate migrations\": \"Generating database migrations...\",\n \"generate code artifacts\": \"Generating code artifacts...\",\n \"docker compose up\": \"Starting Docker services...\",\n};\n\nfunction phaseLabel(name: string): string {\n return PHASE_LABELS[name] ?? name;\n}\n\nexport async function timePhase<T>(\n timings: PhaseTiming[],\n name: string,\n fn: () => Promise<T>,\n spinner?: Spinner,\n): Promise<T> {\n spinner?.message(phaseLabel(name));\n const startedAt = Date.now();\n try {\n return await fn();\n } finally {\n timings.push({ name, durationMs: Date.now() - startedAt });\n }\n}\n\nexport function sumPhaseDurations(timings: PhaseTiming[]): number {\n return timings.reduce((total, timing) => total + timing.durationMs, 0);\n}\n\nexport function formatDuration(durationMs: number): string {\n if (durationMs < 1000) {\n return `${durationMs}ms`;\n }\n\n if (durationMs < 60_000) {\n const seconds = durationMs / 1000;\n return `${seconds.toFixed(seconds >= 10 ? 0 : 1)}s`;\n }\n\n const minutes = Math.floor(durationMs / 60_000);\n const seconds = Math.round((durationMs % 60_000) / 1000);\n return `${minutes}m ${seconds}s`;\n}\n"],"mappings":";AASA,MAAM,eAAuC;CAC3C,iBAAiB;CACjB,mBAAmB;CACnB,oBAAoB;CACpB,cAAc;CACd,sBAAsB;CACtB,kBAAkB;CAClB,kBAAkB;CAClB,uBAAuB;CACvB,mBAAmB;CACnB,wBAAwB;CACxB,kBAAkB;CAClB,uBAAuB;CACvB,2BAA2B;CAC3B,qBAAqB;CACtB;AAED,SAAS,WAAW,MAAsB;AACxC,QAAO,aAAa,SAAS;;AAG/B,eAAsB,UACpB,SACA,MACA,IACA,SACY;AACZ,UAAS,QAAQ,WAAW,KAAK,CAAC;CAClC,MAAM,YAAY,KAAK,KAAK;AAC5B,KAAI;AACF,SAAO,MAAM,IAAI;WACT;AACR,UAAQ,KAAK;GAAE;GAAM,YAAY,KAAK,KAAK,GAAG;GAAW,CAAC;;;AAI9D,SAAgB,kBAAkB,SAAgC;AAChE,QAAO,QAAQ,QAAQ,OAAO,WAAW,QAAQ,OAAO,YAAY,EAAE;;AAGxE,SAAgB,eAAe,YAA4B;AACzD,KAAI,aAAa,IACf,QAAO,GAAG,WAAW;AAGvB,KAAI,aAAa,KAAQ;EACvB,MAAM,UAAU,aAAa;AAC7B,SAAO,GAAG,QAAQ,QAAQ,WAAW,KAAK,IAAI,EAAE,CAAC;;AAKnD,QAAO,GAFS,KAAK,MAAM,aAAa,IAEvB,CAAC,IADF,KAAK,MAAO,aAAa,MAAU,IACtB,CAAC"}
@@ -7,11 +7,11 @@ const require_sync = require('./sync.cjs');
7
7
  const require_timing = require('./timing.cjs');
8
8
  let node_fs = require("node:fs");
9
9
  let node_path = require("node:path");
10
+ let node_process = require("node:process");
11
+ node_process = require_runtime.__toESM(node_process, 1);
10
12
  let _clack_prompts = require("@clack/prompts");
11
13
  _clack_prompts = require_runtime.__toESM(_clack_prompts, 1);
12
14
  let glob = require("glob");
13
- let node_process = require("node:process");
14
- node_process = require_runtime.__toESM(node_process, 1);
15
15
 
16
16
  //#region src/cli/upgrade.ts
17
17
  const FRAMEWORK_PACKAGES = ["everything-dev", "every-plugin"];
@@ -27,6 +27,12 @@ const CATALOG_TOOL_PACKAGES = [
27
27
  "@module-federation/sdk",
28
28
  "@module-federation/dts-plugin"
29
29
  ];
30
+ const PINNED_CATALOG_TOOL_VERSIONS = {
31
+ "@rspack/core": "1.7.11",
32
+ "@rspack/cli": "1.7.11",
33
+ "@rsbuild/core": "1.7.5",
34
+ "@rsbuild/plugin-react": "1.4.6"
35
+ };
30
36
  const LEGACY_UI_IMPORT_REWRITES = [
31
37
  ["from \"@/auth\"", "from \"@/app\""],
32
38
  ["from '@/auth'", "from '@/app'"],
@@ -47,8 +53,35 @@ const OBSOLETE_FILES = [
47
53
  "ui/scripts/generate-metadata.ts",
48
54
  ".github/dependabot.yml",
49
55
  ".github/templates/dependabot.yml",
50
- "packages/everything-dev/cli.js"
56
+ "packages/everything-dev/cli.js",
57
+ ".templatekeep",
58
+ ".templatesync-exclude"
51
59
  ];
60
+ function extractVersion(value) {
61
+ if (!value) return null;
62
+ return value.match(/\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?/)?.[0] ?? null;
63
+ }
64
+ async function readExtendedRootCatalog(projectDir) {
65
+ const configPath = (0, node_path.join)(projectDir, "bos.config.json");
66
+ if (!(0, node_fs.existsSync)(configPath)) return {};
67
+ const localConfig = JSON.parse((0, node_fs.readFileSync)(configPath, "utf-8"));
68
+ let extendsRef;
69
+ if (typeof localConfig.extends === "string") extendsRef = localConfig.extends;
70
+ else if (require_merge.isPlainObject(localConfig.extends)) extendsRef = require_merge.resolveExtendsRef(localConfig.extends, "production");
71
+ const parsed = extendsRef ? parseBosRef(extendsRef) : null;
72
+ if (!parsed) return {};
73
+ const { sourceDir, cleanup } = await require_cli_init.resolveSourceDir({
74
+ extendsAccount: parsed.account,
75
+ extendsGateway: parsed.gateway
76
+ });
77
+ try {
78
+ const sourcePkgPath = (0, node_path.join)(sourceDir, "package.json");
79
+ if (!(0, node_fs.existsSync)(sourcePkgPath)) return {};
80
+ return { ...JSON.parse((0, node_fs.readFileSync)(sourcePkgPath, "utf-8")).workspaces?.catalog ?? {} };
81
+ } finally {
82
+ await cleanup();
83
+ }
84
+ }
52
85
  function getExtendsRef(config) {
53
86
  if (typeof config.extends === "string") return config.extends;
54
87
  if (config.extends && typeof config.extends === "object") return require_merge.resolveExtendsRef(config.extends, "production");
@@ -315,18 +348,6 @@ async function addSelectedParentPlugins(projectDir) {
315
348
  await require_save_config.saveBosConfig(projectDir, pluginOptions.localConfig);
316
349
  return selected;
317
350
  }
318
- async function fetchLatestNpmVersion(packageName) {
319
- try {
320
- const response = await fetch(`https://registry.npmjs.org/${packageName}/latest`, {
321
- headers: { Accept: "application/json" },
322
- signal: AbortSignal.timeout(1e4)
323
- });
324
- if (!response.ok) return null;
325
- return (await response.json()).version;
326
- } catch {
327
- return null;
328
- }
329
- }
330
351
  function readInstalledVersion(projectDir, packageName) {
331
352
  return require_framework_version.readInstalledFrameworkVersion(projectDir, packageName);
332
353
  }
@@ -374,7 +395,7 @@ function updateRootPackageVersion(projectDir, packageName, newVersion) {
374
395
  workspaces.catalog = {};
375
396
  modified = true;
376
397
  }
377
- const nextVersion = `^${newVersion}`;
398
+ const nextVersion = newVersion;
378
399
  if (workspaces.catalog[packageName] !== nextVersion) {
379
400
  workspaces.catalog[packageName] = nextVersion;
380
401
  modified = true;
@@ -391,7 +412,7 @@ function updateRootCatalogVersion(projectDir, packageName, newVersion) {
391
412
  };
392
413
  const workspaces = pkg.workspaces;
393
414
  if (!workspaces.catalog || typeof workspaces.catalog !== "object") workspaces.catalog = {};
394
- const nextVersion = `^${newVersion}`;
415
+ const nextVersion = newVersion;
395
416
  if (workspaces.catalog[packageName] === nextVersion) return false;
396
417
  workspaces.catalog[packageName] = nextVersion;
397
418
  (0, node_fs.writeFileSync)(pkgPath, `${JSON.stringify(pkg, null, 2)}\n`);
@@ -456,11 +477,12 @@ async function upgradeTemplate(projectDir, options) {
456
477
  timings,
457
478
  error: "No package.json found in current directory"
458
479
  };
480
+ const sourceRootCatalog = await readExtendedRootCatalog(projectDir);
459
481
  const { packages, catalogVersionUpdates } = await require_timing.timePhase(timings, "check package versions", async () => {
460
482
  const nextPackages = [];
461
483
  for (const name of FRAMEWORK_PACKAGES) {
462
484
  const installed = readInstalledVersion(projectDir, name);
463
- const latest = await fetchLatestNpmVersion(name);
485
+ const latest = extractVersion(sourceRootCatalog[name]);
464
486
  if (!latest) {
465
487
  nextPackages.push({
466
488
  name,
@@ -479,13 +501,12 @@ async function upgradeTemplate(projectDir, options) {
479
501
  for (const name of CATALOG_TOOL_PACKAGES) {
480
502
  const installed = readInstalledVersion(projectDir, name);
481
503
  if (!installed) continue;
482
- const latest = await fetchLatestNpmVersion(name);
483
- if (!latest) continue;
484
- if (installed === latest) continue;
504
+ const targetVersion = PINNED_CATALOG_TOOL_VERSIONS[name] ?? extractVersion(sourceRootCatalog[name]) ?? installed;
505
+ if (installed === targetVersion) continue;
485
506
  nextCatalogVersionUpdates.push({
486
507
  name,
487
508
  from: installed,
488
- to: latest
509
+ to: targetVersion
489
510
  });
490
511
  }
491
512
  return {