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/src/cli/sync.ts CHANGED
@@ -1,14 +1,6 @@
1
1
  import { createHash } from "node:crypto";
2
- import {
3
- copyFileSync,
4
- existsSync,
5
- lstatSync,
6
- mkdirSync,
7
- readFileSync,
8
- writeFileSync,
9
- } from "node:fs";
2
+ import { copyFileSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
10
3
  import { dirname, join } from "node:path";
11
- import { glob } from "glob";
12
4
  import { loadConfig } from "../config";
13
5
  import type { SyncOptions, SyncResult } from "../contract";
14
6
  import {
@@ -16,32 +8,38 @@ import {
16
8
  mergeBosConfigWithTemplate,
17
9
  resolveExtendsRef,
18
10
  } from "../merge";
19
- import { isPathExcluded } from "../utils/path-match";
20
11
  import { writeGeneratedInfra } from "./infra";
21
12
  import {
22
13
  personalizeConfig,
23
- readTemplatekeep,
24
14
  resolveSourceDir,
25
15
  runBunInstall,
26
16
  runTypesGen,
17
+ sourcePathToDestinationPath,
27
18
  } from "./init";
28
- import { readSnapshot, writeSnapshot } from "./snapshot";
19
+ import { writeSnapshot } from "./snapshot";
29
20
 
30
21
  const FRAMEWORK_OWNED_SYNC_FILES = new Set([
31
22
  ".env.example",
32
23
  ".gitignore",
24
+ "AGENTS.md",
33
25
  "biome.json",
34
26
  "bos.config.json",
27
+ "bunfig.toml",
28
+ "CONTRIBUTING.md",
35
29
  "package.json",
30
+ ".changeset/config.json",
31
+ ".changeset/README.md",
36
32
  "docker-compose.yml",
37
33
  ".github/renovate.json",
38
34
  ".github/workflows/ci.yml",
39
35
  ".github/workflows/release-sync.yml",
36
+ ".opencode/skills/everything-dev/SKILL.md",
40
37
  "ui/package.json",
41
38
  "ui/postcss.config.mjs",
42
39
  "ui/rsbuild.config.ts",
43
40
  "ui/tsconfig.json",
44
41
  "ui/src/app.ts",
42
+ "ui/src/globals.d.ts",
45
43
  "ui/src/hydrate.tsx",
46
44
  "ui/src/lib/api.ts",
47
45
  "ui/src/lib/auth.ts",
@@ -62,23 +60,6 @@ export function isFrameworkOwnedSyncFile(filePath: string): boolean {
62
60
  return FRAMEWORK_OWNED_SYNC_FILES.has(filePath);
63
61
  }
64
62
 
65
- function readExcludeFile(filePath: string): string[] {
66
- if (!existsSync(filePath)) return [];
67
- const content = readFileSync(filePath, "utf-8");
68
- return content
69
- .split("\n")
70
- .map((line) => line.trim())
71
- .filter((line) => line.length > 0 && !line.startsWith("#"));
72
- }
73
-
74
- export async function readTemplatesyncExclude(sourceDir: string): Promise<string[]> {
75
- return readExcludeFile(join(sourceDir, ".templatesync-exclude"));
76
- }
77
-
78
- export function readLocalSyncExcludes(projectDir: string): string[] {
79
- return readExcludeFile(join(projectDir, ".bos", "sync-local-exclude"));
80
- }
81
-
82
63
  function computeLocalHash(projectDir: string, filePath: string): string | null {
83
64
  const fullPath = join(projectDir, filePath);
84
65
  if (!existsSync(fullPath)) return null;
@@ -232,9 +213,23 @@ export function mergePackageJson(
232
213
  }
233
214
 
234
215
  function toDestPath(filePath: string): string {
235
- return filePath.startsWith(".github/templates/")
236
- ? filePath.replace(/^\.github\/templates\//, ".github/")
237
- : filePath;
216
+ return sourcePathToDestinationPath(filePath);
217
+ }
218
+
219
+ function toSourcePath(sourceDir: string, destPath: string): string | null {
220
+ const directPath = join(sourceDir, destPath);
221
+ if (existsSync(directPath)) {
222
+ return destPath;
223
+ }
224
+
225
+ if (destPath.startsWith(".github/")) {
226
+ const templatePath = destPath.replace(/^\.github\//, ".github/templates/");
227
+ if (existsSync(join(sourceDir, templatePath))) {
228
+ return templatePath;
229
+ }
230
+ }
231
+
232
+ return null;
238
233
  }
239
234
 
240
235
  function writeSyncedFile(sourceDir: string, projectDir: string, filePath: string): void {
@@ -319,90 +314,31 @@ export async function syncTemplate(projectDir: string, options: SyncOptions): Pr
319
314
  });
320
315
 
321
316
  try {
322
- const patterns = await readTemplatekeep(sourceDir);
323
- if (patterns.length === 0) {
324
- return {
325
- status: "error",
326
- updated: [],
327
- skipped: [],
328
- added: [],
329
- error: "No .templatekeep found in template source",
330
- };
331
- }
332
-
333
- const parentExcludes = await readTemplatesyncExclude(sourceDir);
334
- const localExcludes = readLocalSyncExcludes(projectDir);
335
- const excludePatterns = [...parentExcludes, ...localExcludes];
336
-
337
- const allTemplateFiles = new Set<string>();
338
- for (const pattern of patterns) {
339
- const matches = await glob(pattern, {
340
- cwd: sourceDir,
341
- nodir: true,
342
- dot: true,
343
- absolute: false,
344
- });
345
- for (const match of matches) {
346
- allTemplateFiles.add(match);
347
- }
348
- }
349
-
350
317
  const childPlugins =
351
318
  localConfig.plugins && typeof localConfig.plugins === "object"
352
319
  ? Object.keys(localConfig.plugins as Record<string, unknown>)
353
320
  : [];
354
-
355
- const pluginRoutes: Record<string, string[]> = {};
356
- const parentRuntime = await loadConfig({ cwd: sourceDir });
357
- for (const [key, plugin] of Object.entries(parentRuntime?.runtime.plugins ?? {})) {
358
- if (plugin.routes && plugin.routes.length > 0) {
359
- pluginRoutes[key] = plugin.routes;
360
- }
361
- }
362
-
363
- const excludedRoutePatterns: string[] = [];
364
- for (const [pluginKey, routePatterns] of Object.entries(pluginRoutes)) {
365
- if (!childPlugins.includes(pluginKey)) {
366
- excludedRoutePatterns.push(...routePatterns);
367
- }
368
- }
321
+ const withUi = existsSync(join(projectDir, "ui", "package.json"));
322
+ const withApi = existsSync(join(projectDir, "api", "package.json"));
323
+ const withHost = existsSync(join(projectDir, "host", "package.json"));
369
324
 
370
325
  const filteredFiles = new Set<string>();
371
- for (const filePath of allTemplateFiles) {
372
- const pluginMatch = filePath.match(/^plugins\/([^/]+)/);
373
- if (pluginMatch && !childPlugins.includes(pluginMatch[1])) continue;
374
- if (isPathExcluded(filePath, excludedRoutePatterns)) continue;
375
- filteredFiles.add(filePath);
376
- }
377
-
378
- for (const [pluginKey, routePatterns] of Object.entries(pluginRoutes)) {
379
- if (!childPlugins.includes(pluginKey)) continue;
380
- for (const rp of routePatterns) {
381
- const matches = await glob(rp, {
382
- cwd: sourceDir,
383
- nodir: true,
384
- dot: true,
385
- absolute: false,
386
- });
387
- for (const match of matches) {
388
- if (!isPathExcluded(match, excludedRoutePatterns)) {
389
- filteredFiles.add(match);
390
- }
391
- }
392
- }
326
+ const destToSource = new Map<string, string>();
327
+ for (const destPath of FRAMEWORK_OWNED_SYNC_FILES) {
328
+ if (destPath.startsWith("ui/") && !withUi) continue;
329
+ if (destPath.startsWith("api/") && !withApi) continue;
330
+ if (destPath.startsWith("host/") && !withHost) continue;
331
+ const sourcePath = toSourcePath(sourceDir, destPath);
332
+ if (!sourcePath) continue;
333
+ filteredFiles.add(sourcePath);
334
+ destToSource.set(destPath, sourcePath);
393
335
  }
394
336
 
395
- const snapshot = await readSnapshot(projectDir);
396
-
397
337
  const updated: string[] = [];
398
338
  const skipped: string[] = [];
399
339
  const added: string[] = [];
400
340
 
401
- for (const filePath of filteredFiles) {
402
- const destPath = toDestPath(filePath);
403
- const frameworkOwned = isFrameworkOwnedSyncFile(destPath);
404
- if (isPathExcluded(destPath, excludePatterns) && !frameworkOwned) continue;
405
-
341
+ for (const [destPath, filePath] of destToSource.entries()) {
406
342
  const localHash = computeLocalHash(projectDir, destPath);
407
343
  const sourceContent = readFileSync(join(sourceDir, filePath));
408
344
  const sourceHash = createHash("sha256").update(sourceContent).digest("hex").substring(0, 16);
@@ -412,28 +348,8 @@ export async function syncTemplate(projectDir: string, options: SyncOptions): Pr
412
348
  continue;
413
349
  }
414
350
 
415
- if (localHash === sourceHash) continue;
416
-
417
- if (frameworkOwned) {
351
+ if (localHash !== sourceHash) {
418
352
  updated.push(destPath);
419
- continue;
420
- }
421
-
422
- const snapshotHash = snapshot?.files[destPath];
423
-
424
- if (snapshotHash === undefined) {
425
- updated.push(destPath);
426
- continue;
427
- }
428
-
429
- if (localHash === snapshotHash) {
430
- updated.push(destPath);
431
- } else {
432
- if (options.force) {
433
- updated.push(destPath);
434
- } else {
435
- skipped.push(destPath);
436
- }
437
353
  }
438
354
  }
439
355
 
@@ -446,14 +362,7 @@ export async function syncTemplate(projectDir: string, options: SyncOptions): Pr
446
362
  };
447
363
  }
448
364
 
449
- const filesToWrite = [...updated, ...added].filter(
450
- (f) => isFrameworkOwnedSyncFile(f) || !isPathExcluded(f, excludePatterns),
451
- );
452
-
453
- const destToSource = new Map<string, string>();
454
- for (const filePath of filteredFiles) {
455
- destToSource.set(toDestPath(filePath), filePath);
456
- }
365
+ const filesToWrite = [...updated, ...added];
457
366
 
458
367
  if (filesToWrite.length > 0) {
459
368
  backupFiles(projectDir, filesToWrite);
@@ -467,8 +376,6 @@ export async function syncTemplate(projectDir: string, options: SyncOptions): Pr
467
376
  const newSnapshotFiles: Record<string, string> = {};
468
377
  for (const filePath of filteredFiles) {
469
378
  const src = join(sourceDir, filePath);
470
- const stat = lstatSync(src);
471
- if (!stat.isFile()) continue;
472
379
  const content = readFileSync(src);
473
380
  newSnapshotFiles[toDestPath(filePath)] = createHash("sha256")
474
381
  .update(content)
@@ -483,15 +390,19 @@ export async function syncTemplate(projectDir: string, options: SyncOptions): Pr
483
390
 
484
391
  const account = (localConfig.account as string) || extendsAccount;
485
392
  const domain = (localConfig.domain as string) || extendsGateway;
393
+ const overrides: Array<"ui" | "api" | "host" | "plugins"> = [];
394
+ if (withUi) overrides.push("ui");
395
+ if (withApi) overrides.push("api");
396
+ if (withHost) overrides.push("host");
397
+ if (childPlugins.length > 0) overrides.push("plugins");
486
398
 
487
399
  await personalizeConfig(projectDir, {
488
400
  extendsAccount,
489
401
  extendsGateway,
490
402
  account,
491
403
  domain,
404
+ overrides,
492
405
  plugins: childPlugins,
493
- pluginRoutes,
494
- overrides: ["ui", "api", "host", "plugins"],
495
406
  workspaceOpts: { sourceDir },
496
407
  mode: "sync",
497
408
  });
@@ -4,10 +4,10 @@ import process from "node:process";
4
4
  import * as p from "@clack/prompts";
5
5
  import { glob } from "glob";
6
6
  import type { PhaseTiming, UpgradeOptions, UpgradeResult } from "../contract";
7
- import { resolveExtendsRef } from "../merge";
7
+ import { isPlainObject as isPlainObjectFromMerge, resolveExtendsRef } from "../merge";
8
8
  import { saveBosConfig } from "../utils/save-config";
9
9
  import { readInstalledFrameworkVersion } from "./framework-version";
10
- import { fetchParentConfig, runBunInstallForUpgrade, runTypesGen } from "./init";
10
+ import { fetchParentConfig, resolveSourceDir, runBunInstallForUpgrade, runTypesGen } from "./init";
11
11
  import { syncTemplate } from "./sync";
12
12
  import { timePhase } from "./timing";
13
13
 
@@ -25,6 +25,14 @@ const CATALOG_TOOL_PACKAGES = [
25
25
  "@module-federation/sdk",
26
26
  "@module-federation/dts-plugin",
27
27
  ] as const;
28
+ const PINNED_CATALOG_TOOL_VERSIONS: Partial<
29
+ Record<(typeof CATALOG_TOOL_PACKAGES)[number], string>
30
+ > = {
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
+ };
28
36
  const LEGACY_UI_IMPORT_REWRITES = [
29
37
  ['from "@/auth"', 'from "@/app"'],
30
38
  ["from '@/auth'", "from '@/app'"],
@@ -46,10 +54,53 @@ const OBSOLETE_FILES = [
46
54
  ".github/dependabot.yml",
47
55
  ".github/templates/dependabot.yml",
48
56
  "packages/everything-dev/cli.js",
57
+ ".templatekeep",
58
+ ".templatesync-exclude",
49
59
  ];
50
60
 
51
- interface NpmPackageInfo {
52
- version: string;
61
+ function extractVersion(value: string | undefined): string | null {
62
+ if (!value) return null;
63
+ const match = value.match(/\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?/);
64
+ return match?.[0] ?? null;
65
+ }
66
+
67
+ async function readExtendedRootCatalog(projectDir: string): Promise<Record<string, string>> {
68
+ const configPath = join(projectDir, "bos.config.json");
69
+ if (!existsSync(configPath)) {
70
+ return {};
71
+ }
72
+
73
+ const localConfig = JSON.parse(readFileSync(configPath, "utf-8")) as Record<string, unknown>;
74
+ let extendsRef: string | undefined;
75
+ if (typeof localConfig.extends === "string") {
76
+ extendsRef = localConfig.extends;
77
+ } else if (isPlainObjectFromMerge(localConfig.extends)) {
78
+ extendsRef = resolveExtendsRef(localConfig.extends as Record<string, string>, "production");
79
+ }
80
+
81
+ const parsed = extendsRef ? parseBosRef(extendsRef) : null;
82
+ if (!parsed) {
83
+ return {};
84
+ }
85
+
86
+ const { sourceDir, cleanup } = await resolveSourceDir({
87
+ extendsAccount: parsed.account,
88
+ extendsGateway: parsed.gateway,
89
+ });
90
+
91
+ try {
92
+ const sourcePkgPath = join(sourceDir, "package.json");
93
+ if (!existsSync(sourcePkgPath)) {
94
+ return {};
95
+ }
96
+
97
+ const sourcePkg = JSON.parse(readFileSync(sourcePkgPath, "utf-8")) as {
98
+ workspaces?: { catalog?: Record<string, string> };
99
+ };
100
+ return { ...(sourcePkg.workspaces?.catalog ?? {}) };
101
+ } finally {
102
+ await cleanup();
103
+ }
53
104
  }
54
105
 
55
106
  function getExtendsRef(config: Record<string, unknown>): string | undefined {
@@ -468,20 +519,6 @@ async function addSelectedParentPlugins(projectDir: string): Promise<string[]> {
468
519
  return selected;
469
520
  }
470
521
 
471
- async function fetchLatestNpmVersion(packageName: string): Promise<string | null> {
472
- try {
473
- const response = await fetch(`https://registry.npmjs.org/${packageName}/latest`, {
474
- headers: { Accept: "application/json" },
475
- signal: AbortSignal.timeout(10_000),
476
- });
477
- if (!response.ok) return null;
478
- const data = (await response.json()) as NpmPackageInfo;
479
- return data.version;
480
- } catch {
481
- return null;
482
- }
483
- }
484
-
485
522
  function readInstalledVersion(projectDir: string, packageName: string): string | undefined {
486
523
  return readInstalledFrameworkVersion(projectDir, packageName);
487
524
  }
@@ -537,7 +574,7 @@ function updateRootPackageVersion(
537
574
  modified = true;
538
575
  }
539
576
 
540
- const nextVersion = `^${newVersion}`;
577
+ const nextVersion = newVersion;
541
578
  if (workspaces.catalog[packageName] !== nextVersion) {
542
579
  workspaces.catalog[packageName] = nextVersion;
543
580
  modified = true;
@@ -566,7 +603,7 @@ function updateRootCatalogVersion(
566
603
  workspaces.catalog = {};
567
604
  }
568
605
 
569
- const nextVersion = `^${newVersion}`;
606
+ const nextVersion = newVersion;
570
607
  if (workspaces.catalog[packageName] === nextVersion) return false;
571
608
 
572
609
  workspaces.catalog[packageName] = nextVersion;
@@ -662,6 +699,8 @@ export async function upgradeTemplate(
662
699
  };
663
700
  }
664
701
 
702
+ const sourceRootCatalog = await readExtendedRootCatalog(projectDir);
703
+
665
704
  const { packages, catalogVersionUpdates } = await timePhase(
666
705
  timings,
667
706
  "check package versions",
@@ -670,7 +709,7 @@ export async function upgradeTemplate(
670
709
 
671
710
  for (const name of FRAMEWORK_PACKAGES) {
672
711
  const installed = readInstalledVersion(projectDir, name);
673
- const latest = await fetchLatestNpmVersion(name);
712
+ const latest = extractVersion(sourceRootCatalog[name]);
674
713
 
675
714
  if (!latest) {
676
715
  nextPackages.push({ name, from: installed, to: installed ?? "unknown" });
@@ -688,10 +727,12 @@ export async function upgradeTemplate(
688
727
  for (const name of CATALOG_TOOL_PACKAGES) {
689
728
  const installed = readInstalledVersion(projectDir, name);
690
729
  if (!installed) continue;
691
- const latest = await fetchLatestNpmVersion(name);
692
- if (!latest) continue;
693
- if (installed === latest) continue;
694
- nextCatalogVersionUpdates.push({ name, from: installed, to: latest });
730
+ const targetVersion =
731
+ PINNED_CATALOG_TOOL_VERSIONS[name] ??
732
+ extractVersion(sourceRootCatalog[name]) ??
733
+ installed;
734
+ if (installed === targetVersion) continue;
735
+ nextCatalogVersionUpdates.push({ name, from: installed, to: targetVersion });
695
736
  }
696
737
 
697
738
  return { packages: nextPackages, catalogVersionUpdates: nextCatalogVersionUpdates };
@@ -96,7 +96,7 @@ export const cliCommandMeta = {
96
96
  description: "Comma-separated plugin keys to include (requires --overrides=plugins)",
97
97
  },
98
98
  overrides: {
99
- description: "Comma-separated sections to override locally: ui,api,host,plugins",
99
+ description: "Comma-separated sections to customize locally: ui,api,host,plugins",
100
100
  },
101
101
  noInteractive: { description: "Skip prompts, use flags only" },
102
102
  noInstall: { description: "Skip bun install" },
package/src/contract.ts CHANGED
@@ -1,4 +1,5 @@
1
- import { oc, z } from "./sdk";
1
+ import * as z from "zod";
2
+ import { oc } from "./sdk";
2
3
  import { BosConfigSchema, SourceModeSchema } from "./types";
3
4
 
4
5
  export const DevOptionsSchema = z.object({
package/src/plugin.ts CHANGED
@@ -1,17 +1,19 @@
1
1
  import { existsSync, readFileSync, writeFileSync } from "node:fs";
2
2
  import { basename, dirname, join, resolve } from "node:path";
3
+ import process from "node:process";
3
4
  import * as p from "@clack/prompts";
4
5
  import { Effect } from "effect";
5
6
  import { syncApiContractBridge } from "./api-contract";
6
7
  import { buildRuntimeConfig, detectLocalPackages, prepareDevelopmentRuntimeConfig } from "./app";
7
8
  import { ensureEnvFile, writeGeneratedInfra } from "./cli/infra";
8
9
  import {
10
+ buildInitPatterns,
9
11
  copyFilteredFiles,
10
12
  detectGitRemoteUrl,
11
13
  fetchParentConfig,
12
14
  generateDatabaseMigrations,
13
15
  personalizeConfig,
14
- readTemplatekeep,
16
+ removeInitLockfile,
15
17
  resolveSourceDir,
16
18
  runBunInstall,
17
19
  runDockerComposeUp,
@@ -1235,6 +1237,8 @@ export default createPlugin({
1235
1237
 
1236
1238
  if (!input.noInteractive) {
1237
1239
  s.stop("Config fetched");
1240
+ const initialExtendsAccount = extendsAccount;
1241
+ const initialExtendsGateway = extendsGateway;
1238
1242
  const prompted = await promptInitOptions({
1239
1243
  extends: `bos://${extendsAccount}/${extendsGateway}`,
1240
1244
  directory,
@@ -1251,6 +1255,58 @@ export default createPlugin({
1251
1255
  domain = prompted.domain;
1252
1256
  plugins = prompted.plugins;
1253
1257
  overrides = prompted.overrides;
1258
+
1259
+ if (
1260
+ !parentConfig ||
1261
+ prompted.extendsAccount !== initialExtendsAccount ||
1262
+ prompted.extendsGateway !== initialExtendsGateway
1263
+ ) {
1264
+ try {
1265
+ parentConfig = await timePhase(
1266
+ timings,
1267
+ "parent config",
1268
+ () => fetchParentConfig(prompted.extendsAccount, prompted.extendsGateway),
1269
+ s,
1270
+ );
1271
+ if (parentConfig?.plugins && typeof parentConfig.plugins === "object") {
1272
+ parentPluginKeys = Object.keys(parentConfig.plugins);
1273
+ } else {
1274
+ parentPluginKeys = [];
1275
+ }
1276
+ } catch {
1277
+ return {
1278
+ status: "error" as const,
1279
+ directory,
1280
+ extendsRef: `bos://${prompted.extendsAccount}/${prompted.extendsGateway}`,
1281
+ account,
1282
+ domain,
1283
+ extends: `bos://${prompted.extendsAccount}/${prompted.extendsGateway}`,
1284
+ plugins,
1285
+ overrides,
1286
+ filesCopied: 0,
1287
+ timings,
1288
+ error: `No config found at bos://${prompted.extendsAccount}/${prompted.extendsGateway} — are you sure this is the right parent?`,
1289
+ };
1290
+ }
1291
+ s.stop("Config fetched");
1292
+ }
1293
+
1294
+ if (
1295
+ typeof parentConfig?.title === "string" &&
1296
+ parentConfig.title.trim() &&
1297
+ typeof parentConfig.description === "string" &&
1298
+ parentConfig.description.trim()
1299
+ ) {
1300
+ const shouldContinue = await p.confirm({
1301
+ message: `You will be extending ${parentConfig.title} - ${parentConfig.description}. Continue?`,
1302
+ initialValue: true,
1303
+ });
1304
+
1305
+ if (p.isCancel(shouldContinue) || !shouldContinue) {
1306
+ process.exit(0);
1307
+ }
1308
+ }
1309
+
1254
1310
  s.start("Setting up project");
1255
1311
  }
1256
1312
 
@@ -1334,6 +1390,8 @@ export default createPlugin({
1334
1390
  plugins,
1335
1391
  overrides,
1336
1392
  repository,
1393
+ title: parentConfig?.title,
1394
+ description: parentConfig?.description,
1337
1395
  }),
1338
1396
  s,
1339
1397
  );
@@ -1351,40 +1409,15 @@ export default createPlugin({
1351
1409
  overrides,
1352
1410
  mode: "init",
1353
1411
  repository,
1412
+ title: parentConfig?.title,
1413
+ description: parentConfig?.description,
1414
+ testnet: parentConfig?.testnet,
1415
+ staging: parentConfig?.staging,
1354
1416
  }),
1355
1417
  s,
1356
1418
  );
1357
1419
  } else {
1358
- const patterns = await readTemplatekeep(sourceDir);
1359
- if (patterns.length === 0) {
1360
- s.stop("Failed");
1361
- return {
1362
- status: "error" as const,
1363
- directory,
1364
- extendsRef,
1365
- account,
1366
- domain,
1367
- extends: extendsRef,
1368
- plugins,
1369
- overrides,
1370
- filesCopied: 0,
1371
- error: "No .templatekeep found in template source",
1372
- };
1373
- }
1374
-
1375
- const pluginRoutes: Record<string, string[]> = {};
1376
- if (overrides.includes("plugins")) {
1377
- const parentRuntimePlugins = await buildRuntimePluginsForConfig(
1378
- parentConfig as BosConfig,
1379
- sourceDir,
1380
- "production",
1381
- );
1382
- for (const [key, plugin] of Object.entries(parentRuntimePlugins ?? {})) {
1383
- if (plugin.routes && plugin.routes.length > 0) {
1384
- pluginRoutes[key] = plugin.routes;
1385
- }
1386
- }
1387
- }
1420
+ const patterns = buildInitPatterns(overrides, plugins);
1388
1421
 
1389
1422
  filesCopied = await timePhase(
1390
1423
  timings,
@@ -1393,7 +1426,6 @@ export default createPlugin({
1393
1426
  copyFilteredFiles(sourceDir, targetDir, patterns, {
1394
1427
  overrides,
1395
1428
  plugins,
1396
- pluginRoutes,
1397
1429
  }),
1398
1430
  s,
1399
1431
  );
@@ -1409,9 +1441,12 @@ export default createPlugin({
1409
1441
  domain: domain || extendsGateway,
1410
1442
  plugins,
1411
1443
  overrides,
1412
- pluginRoutes,
1413
1444
  workspaceOpts: { sourceDir },
1414
1445
  repository,
1446
+ title: parentConfig?.title,
1447
+ description: parentConfig?.description,
1448
+ testnet: parentConfig?.testnet,
1449
+ staging: parentConfig?.staging,
1415
1450
  }),
1416
1451
  s,
1417
1452
  );
@@ -1423,7 +1458,6 @@ export default createPlugin({
1423
1458
  writeInitSnapshot(targetDir, extendsAccount, extendsGateway, sourceDir, patterns, {
1424
1459
  overrides,
1425
1460
  plugins,
1426
- pluginRoutes,
1427
1461
  }),
1428
1462
  s,
1429
1463
  );
@@ -1432,6 +1466,7 @@ export default createPlugin({
1432
1466
  const lockfilePath = join(targetDir, "bun.lock");
1433
1467
  const allowedWorkspaces = computeAllowedWorkspaces(overrides, plugins);
1434
1468
  stripOrphanedWorkspacesFromLockfile(lockfilePath, allowedWorkspaces);
1469
+ removeInitLockfile(lockfilePath);
1435
1470
 
1436
1471
  const initConfig = await timePhase(
1437
1472
  timings,
package/src/sdk.ts CHANGED
@@ -11,4 +11,4 @@ export {
11
11
  type AnySchema,
12
12
  oc,
13
13
  } from "every-plugin/orpc";
14
- export { z } from "every-plugin/zod";
14
+ export { z } from "zod";
package/src/types.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { z } from "./sdk";
1
+ import * as z from "zod";
2
2
 
3
3
  export const ExtendsSchema = z.union([
4
4
  z.string(),
package/src/ui/types.ts CHANGED
@@ -40,6 +40,7 @@ export interface RenderOptions<TSession = unknown> {
40
40
  export interface RenderOptionsWithApi<TApiClient = unknown, TSession = unknown>
41
41
  extends RenderOptions<TSession> {
42
42
  apiClient: TApiClient;
43
+ authClient?: unknown;
43
44
  }
44
45
 
45
46
  export interface RenderResult {
@@ -1,18 +0,0 @@
1
-
2
- //#region src/utils/path-match.ts
3
- function isPathExcluded(filePath, excludePatterns) {
4
- if (excludePatterns.length === 0) return false;
5
- for (const pattern of excludePatterns) if (pattern.endsWith("/**")) {
6
- const prefix = pattern.slice(0, -3);
7
- if (filePath.startsWith(`${prefix}/`) || filePath === prefix) return true;
8
- } else if (pattern.endsWith("/*")) {
9
- const prefix = pattern.slice(0, -2);
10
- const slashIdx = filePath.indexOf("/", prefix.length + 1);
11
- if (filePath.startsWith(`${prefix}/`) && slashIdx === -1) return true;
12
- } else if (filePath === pattern || filePath.startsWith(`${pattern}/`)) return true;
13
- return false;
14
- }
15
-
16
- //#endregion
17
- exports.isPathExcluded = isPathExcluded;
18
- //# sourceMappingURL=path-match.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"path-match.cjs","names":[],"sources":["../../src/utils/path-match.ts"],"sourcesContent":["export function isPathExcluded(filePath: string, excludePatterns: string[]): boolean {\n if (excludePatterns.length === 0) return false;\n for (const pattern of excludePatterns) {\n if (pattern.endsWith(\"/**\")) {\n const prefix = pattern.slice(0, -3);\n if (filePath.startsWith(`${prefix}/`) || filePath === prefix) return true;\n } else if (pattern.endsWith(\"/*\")) {\n const prefix = pattern.slice(0, -2);\n const slashIdx = filePath.indexOf(\"/\", prefix.length + 1);\n if (filePath.startsWith(`${prefix}/`) && slashIdx === -1) return true;\n } else if (filePath === pattern || filePath.startsWith(`${pattern}/`)) {\n return true;\n }\n }\n return false;\n}\n"],"mappings":";;AAAA,SAAgB,eAAe,UAAkB,iBAAoC;AACnF,KAAI,gBAAgB,WAAW,EAAG,QAAO;AACzC,MAAK,MAAM,WAAW,gBACpB,KAAI,QAAQ,SAAS,MAAM,EAAE;EAC3B,MAAM,SAAS,QAAQ,MAAM,GAAG,GAAG;AACnC,MAAI,SAAS,WAAW,GAAG,OAAO,GAAG,IAAI,aAAa,OAAQ,QAAO;YAC5D,QAAQ,SAAS,KAAK,EAAE;EACjC,MAAM,SAAS,QAAQ,MAAM,GAAG,GAAG;EACnC,MAAM,WAAW,SAAS,QAAQ,KAAK,OAAO,SAAS,EAAE;AACzD,MAAI,SAAS,WAAW,GAAG,OAAO,GAAG,IAAI,aAAa,GAAI,QAAO;YACxD,aAAa,WAAW,SAAS,WAAW,GAAG,QAAQ,GAAG,CACnE,QAAO;AAGX,QAAO"}