@owdproject/core 3.3.1 → 4.0.0-alpha.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (93) hide show
  1. package/README.md +91 -59
  2. package/dist/dom/index.d.mts +65 -0
  3. package/dist/dom/index.d.ts +65 -0
  4. package/dist/dom/index.mjs +224 -0
  5. package/dist/events/index.d.mts +70 -0
  6. package/dist/events/index.d.ts +70 -0
  7. package/dist/events/index.mjs +3 -0
  8. package/dist/index.d.mts +73 -0
  9. package/dist/index.d.ts +73 -0
  10. package/dist/index.mjs +115 -0
  11. package/dist/layout/index.d.mts +41 -0
  12. package/dist/layout/index.d.ts +41 -0
  13. package/dist/layout/index.mjs +64 -0
  14. package/dist/machines/index.d.mts +31 -0
  15. package/dist/machines/index.d.ts +31 -0
  16. package/dist/machines/index.mjs +2 -0
  17. package/dist/managers/index.d.mts +117 -0
  18. package/dist/managers/index.d.ts +117 -0
  19. package/dist/managers/index.mjs +6 -0
  20. package/dist/session/index.d.mts +57 -0
  21. package/dist/session/index.d.ts +57 -0
  22. package/dist/session/index.mjs +65 -0
  23. package/dist/shared/core.B0B0KfVK.mjs +865 -0
  24. package/dist/shared/core.B1XxB289.mjs +239 -0
  25. package/dist/shared/core.B3mp7ztE.mjs +237 -0
  26. package/dist/shared/core.BOvFdEVQ.d.ts +114 -0
  27. package/dist/shared/core.CsDFgGnX.mjs +40 -0
  28. package/dist/shared/core.Di1eFcr_.d.mts +114 -0
  29. package/dist/shared/core.Pd_Ogt4g.mjs +101 -0
  30. package/dist/shared/core.b3Xldzyu.mjs +29 -0
  31. package/dist/types/index.d.mts +266 -0
  32. package/dist/types/index.d.ts +266 -0
  33. package/dist/types/index.mjs +1 -0
  34. package/package.json +60 -87
  35. package/bin/cli.js +0 -395
  36. package/bin/desktop.js +0 -5
  37. package/bin/lib/catalog.js +0 -293
  38. package/bin/lib/config.js +0 -109
  39. package/bin/lib/desktopConfig.js +0 -56
  40. package/bin/lib/generateTemplate.js +0 -389
  41. package/bin/lib/install.js +0 -408
  42. package/bin/lib/migrateModulePlayground.config.mjs +0 -164
  43. package/bin/lib/migrateModulePlayground.mjs +0 -313
  44. package/bin/lib/npmVersions.js +0 -124
  45. package/bin/lib/playgroundContext.js +0 -188
  46. package/bin/lib/scaffold.js +0 -197
  47. package/bin/lib/status.js +0 -289
  48. package/bin/lib/validateModule.js +0 -697
  49. package/bin/lib/workspace.js +0 -182
  50. package/bin/owd.js +0 -5
  51. package/bin/tui.js +0 -1379
  52. package/dist/module.d.mts +0 -13
  53. package/dist/module.json +0 -9
  54. package/dist/module.mjs +0 -268
  55. package/dist/types.d.mts +0 -7
  56. package/index.ts +0 -5
  57. package/module.ts +0 -223
  58. package/runtime/components/Desktop/Application/DesktopApplicationRender.vue +0 -20
  59. package/runtime/components/Desktop/Application/DesktopApplicationWindowsRender.vue +0 -38
  60. package/runtime/components/Desktop/Background/DesktopBackground.vue +0 -16
  61. package/runtime/components/Desktop/Core/DesktopCore.vue +0 -90
  62. package/runtime/components/Desktop/Time/DesktopTime.vue +0 -56
  63. package/runtime/components/Desktop/Window/DesktopWindow.vue +0 -204
  64. package/runtime/components/Desktop/Window/DesktopWindowContent.vue +0 -28
  65. package/runtime/components/Desktop/Window/DesktopWindowNav.vue +0 -66
  66. package/runtime/composables/useApplicationEntries.ts +0 -51
  67. package/runtime/composables/useApplicationManager.ts +0 -285
  68. package/runtime/composables/useDesktopManager.ts +0 -49
  69. package/runtime/composables/useTerminalManager.ts +0 -66
  70. package/runtime/composables/useWorkspaceManager.ts +0 -41
  71. package/runtime/internal/controllers/ApplicationController.ts +0 -345
  72. package/runtime/internal/controllers/WindowController.ts +0 -462
  73. package/runtime/plugins/02.desktop-register-desktop-apps.client.ts +0 -17
  74. package/runtime/plugins/resize.client.ts +0 -6
  75. package/runtime/stores/storeApplicationMeta.ts +0 -59
  76. package/runtime/stores/storeApplicationWindows.ts +0 -20
  77. package/runtime/stores/storeDesktop.ts +0 -111
  78. package/runtime/stores/storeDesktopDefaultApps.ts +0 -53
  79. package/runtime/stores/storeDesktopVolume.ts +0 -18
  80. package/runtime/stores/storeDesktopWindow.ts +0 -20
  81. package/runtime/stores/storeDesktopWorkspace.ts +0 -75
  82. package/runtime/utils/captureElementToCanvas.ts +0 -21
  83. package/runtime/utils/explorerEntryPath.ts +0 -10
  84. package/runtime/utils/resolveDesktopConfigPath.ts +0 -52
  85. package/runtime/utils/splitDesktopUserConfig.ts +0 -85
  86. package/runtime/utils/utilApp.ts +0 -37
  87. package/runtime/utils/utilCommon.ts +0 -26
  88. package/runtime/utils/utilDebug.ts +0 -30
  89. package/runtime/utils/utilDesktop.ts +0 -35
  90. package/runtime/utils/utilTerminal.ts +0 -6
  91. package/runtime/utils/utilWindow.ts +0 -15
  92. package/runtime/utils/validateDesktopUserConfig.ts +0 -44
  93. package/types/index.d.ts +0 -420
package/bin/lib/config.js DELETED
@@ -1,109 +0,0 @@
1
- import { readFileSync, existsSync, copyFileSync } from 'node:fs'
2
- import { createRequire } from 'node:module'
3
- import { join } from 'node:path'
4
- import { SCOPE } from './workspace.js'
5
- import { LEGACY_CONFIG_DEPRECATION } from './desktopConfig.js'
6
-
7
- const require = createRequire(import.meta.url)
8
-
9
- function loadTsMorph(workspaceRoot) {
10
- const utilPath = join(
11
- workspaceRoot,
12
- 'node_modules/@owdproject/nx/dist/utils/utilConfig.js',
13
- )
14
- if (!existsSync(utilPath)) {
15
- throw new Error('Missing @owdproject/nx — run pnpm install at the repo root.')
16
- }
17
- const { Project, SyntaxKind } = require('ts-morph')
18
- return { Project, SyntaxKind }
19
- }
20
-
21
- function getConfigObject(sourceFile, SyntaxKind) {
22
- const exportDefault = sourceFile.getExportAssignmentOrThrow((exp) => !exp.isExportEquals())
23
- const callExpr = exportDefault.getExpressionIfKindOrThrow(SyntaxKind.CallExpression)
24
- const args = callExpr.getArguments()
25
- if (args.length === 0) throw new Error('defineDesktopConfig({}) is empty')
26
- return args[0].asKindOrThrow(SyntaxKind.ObjectLiteralExpression)
27
- }
28
-
29
- function readArrayProperty(configObj, key, SyntaxKind) {
30
- const prop = configObj.getProperty(key)?.asKind(SyntaxKind.PropertyAssignment)
31
- if (!prop) return []
32
- const init = prop.getInitializerIfKind(SyntaxKind.ArrayLiteralExpression)
33
- if (!init) return []
34
- return init
35
- .getElements()
36
- .map((el) => el.getText().trim().replace(/['"`]/g, ''))
37
- .filter(Boolean)
38
- }
39
-
40
- function readTheme(configObj, SyntaxKind) {
41
- const prop = configObj.getProperty('theme')?.asKind(SyntaxKind.PropertyAssignment)
42
- if (!prop) return null
43
- return prop.getInitializer()?.getText().trim().replace(/['"`]/g, '') ?? null
44
- }
45
-
46
- function setArrayProperty(configObj, key, values, SyntaxKind) {
47
- const quoted = values.map((v) => `'${v}'`).join(', ')
48
- const initializer = `[ ${quoted} ]`
49
- const existing = configObj.getProperty(key)?.asKind(SyntaxKind.PropertyAssignment)
50
- if (existing) {
51
- existing.setInitializer(initializer)
52
- } else {
53
- configObj.addPropertyAssignment({ name: key, initializer })
54
- }
55
- }
56
-
57
- export function readDesktopConfig(configPath, workspaceRoot) {
58
- const { Project, SyntaxKind } = loadTsMorph(workspaceRoot)
59
- const project = new Project()
60
- const sourceFile = project.addSourceFileAtPath(configPath)
61
- const configObj = getConfigObject(sourceFile, SyntaxKind)
62
-
63
- return {
64
- theme: readTheme(configObj, SyntaxKind),
65
- apps: readArrayProperty(configObj, 'apps', SyntaxKind),
66
- modules: readArrayProperty(configObj, 'modules', SyntaxKind),
67
- }
68
- }
69
-
70
- /**
71
- * When saving from the TUI, always target desktop.config.ts (migrate from legacy on first save).
72
- *
73
- * @param {{ config: string, configWrite: string }} paths
74
- */
75
- export function resolveConfigPathForWrite(paths) {
76
- if (paths.config === paths.configWrite) {
77
- return paths.configWrite
78
- }
79
- if (!existsSync(paths.configWrite) && existsSync(paths.config)) {
80
- copyFileSync(paths.config, paths.configWrite)
81
- console.warn(LEGACY_CONFIG_DEPRECATION)
82
- }
83
- return paths.configWrite
84
- }
85
-
86
- export function writeDesktopConfig(configPath, workspaceRoot, state) {
87
- const { Project, SyntaxKind } = loadTsMorph(workspaceRoot)
88
- const project = new Project()
89
- const sourceFile = project.addSourceFileAtPath(configPath)
90
- const configObj = getConfigObject(sourceFile, SyntaxKind)
91
-
92
- if (state.theme) {
93
- const themeProp = configObj.getProperty('theme')?.asKind(SyntaxKind.PropertyAssignment)
94
- if (themeProp) themeProp.setInitializer(`'${state.theme}'`)
95
- else configObj.addPropertyAssignment({ name: 'theme', initializer: `'${state.theme}'` })
96
- }
97
-
98
- if (state.apps) setArrayProperty(configObj, 'apps', state.apps, SyntaxKind)
99
- if (state.modules) setArrayProperty(configObj, 'modules', state.modules, SyntaxKind)
100
-
101
- sourceFile.saveSync()
102
- }
103
-
104
- export function readDesktopDependencies(packageJsonPath) {
105
- if (!existsSync(packageJsonPath)) return []
106
- const pkg = JSON.parse(readFileSync(packageJsonPath, 'utf8'))
107
- const deps = { ...pkg.dependencies, ...pkg.devDependencies }
108
- return Object.keys(deps).filter((name) => name.startsWith(SCOPE))
109
- }
@@ -1,56 +0,0 @@
1
- import { existsSync } from 'node:fs'
2
- import { join } from 'node:path'
3
-
4
- export const DESKTOP_CONFIG_FILENAME = 'desktop.config.ts'
5
- export const LEGACY_DESKTOP_CONFIG_FILENAME = 'owd.config.ts'
6
-
7
- export const LEGACY_CONFIG_DEPRECATION =
8
- '[@owdproject/core] owd.config.ts is deprecated and kept only for backward compatibility; rename to desktop.config.ts (required from @owdproject/core 3.2).'
9
-
10
- /**
11
- * Resolve the desktop config file under a Nuxt project root (or desktop/ folder).
12
- *
13
- * @param {string} rootDir
14
- * @returns {{ path: string, file: string, legacy: boolean } | null}
15
- */
16
- export function resolveDesktopConfigPath(rootDir) {
17
- const desktopPath = join(rootDir, DESKTOP_CONFIG_FILENAME)
18
- const legacyPath = join(rootDir, LEGACY_DESKTOP_CONFIG_FILENAME)
19
- const hasDesktop = existsSync(desktopPath)
20
- const hasLegacy = existsSync(legacyPath)
21
-
22
- if (hasDesktop && hasLegacy) {
23
- console.warn(
24
- '[@owdproject/core] Both desktop.config.ts and owd.config.ts exist; using desktop.config.ts. Remove owd.config.ts.',
25
- )
26
- return { path: desktopPath, file: DESKTOP_CONFIG_FILENAME, legacy: false }
27
- }
28
-
29
- if (hasDesktop) {
30
- return { path: desktopPath, file: DESKTOP_CONFIG_FILENAME, legacy: false }
31
- }
32
-
33
- if (hasLegacy) {
34
- return { path: legacyPath, file: LEGACY_DESKTOP_CONFIG_FILENAME, legacy: true }
35
- }
36
-
37
- return null
38
- }
39
-
40
- /**
41
- * @param {{ legacy?: boolean, file?: string } | null | undefined} resolved
42
- */
43
- export function warnLegacyDesktopConfig(resolved) {
44
- if (resolved?.legacy) {
45
- console.warn(LEGACY_CONFIG_DEPRECATION)
46
- }
47
- }
48
-
49
- /**
50
- * Path used when creating or updating config from the CLI (always the new filename).
51
- *
52
- * @param {string} desktopDir
53
- */
54
- export function desktopConfigWritePath(desktopDir) {
55
- return join(desktopDir, DESKTOP_CONFIG_FILENAME)
56
- }
@@ -1,389 +0,0 @@
1
- import { execSync } from 'node:child_process'
2
- import {
3
- cpSync,
4
- existsSync,
5
- mkdtempSync,
6
- mkdirSync,
7
- readFileSync,
8
- readdirSync,
9
- rmSync,
10
- statSync,
11
- writeFileSync,
12
- } from 'node:fs'
13
- import { tmpdir } from 'node:os'
14
- import { basename, dirname, join, relative, resolve } from 'node:path'
15
- import { fileURLToPath } from 'node:url'
16
- import {
17
- fetchLatestVersions,
18
- isOwdScopedPackage,
19
- resolveLatestVersions,
20
- } from './npmVersions.js'
21
-
22
- const __dirname = dirname(fileURLToPath(import.meta.url))
23
- const BLUEPRINT_ROOT = resolve(__dirname, '../../template-blueprint')
24
-
25
- export const STARTER_DESKTOP_DEPS = [
26
- '@owdproject/core',
27
- '@owdproject/theme-nova',
28
- '@owdproject/app-about',
29
- 'h3',
30
- ]
31
-
32
- /** Used when a starter package is not on npm yet (before first publish). */
33
- export const TEMPLATE_NPM_FALLBACK_VERSIONS = {
34
- '@owdproject/theme-nova': '0.0.1',
35
- }
36
-
37
- const DESKTOP_COPY_FILES = [
38
- 'tsconfig.json',
39
- 'tsconfig.app.json',
40
- 'tsconfig.spec.json',
41
- '.npmrc',
42
- ]
43
-
44
- const ROOT_COPY_FROM_MONOREPO = [
45
- 'nx.json',
46
- 'tsconfig.base.json',
47
- 'tsconfig.json',
48
- '.editorconfig',
49
- '.npmrc',
50
- '.prettierrc',
51
- '.prettierignore',
52
- ]
53
-
54
- const DESKTOP_SKIP_NAMES = new Set([
55
- 'node_modules',
56
- '.nuxt',
57
- '.output',
58
- 'dist',
59
- '.env',
60
- '.data',
61
- 'vitest.config.ts',
62
- 'tsconfig.tsbuildinfo',
63
- 'package.json',
64
- 'desktop.config.ts',
65
- 'nuxt.config.ts',
66
- 'app',
67
- ])
68
-
69
- const BLUEPRINT_SKIP_NAMES = new Set(['root-package.json'])
70
-
71
- /**
72
- * @param {string} blueprintRoot
73
- */
74
- export function resolveBlueprintRoot(blueprintRoot = BLUEPRINT_ROOT) {
75
- if (!existsSync(join(blueprintRoot, 'pnpm-workspace.yaml'))) {
76
- throw new Error(`Template blueprint not found at ${blueprintRoot}`)
77
- }
78
- return blueprintRoot
79
- }
80
-
81
- /**
82
- * @param {string} src
83
- * @param {string} dest
84
- * @param {Set<string>} [skipNames]
85
- */
86
- function copyTree(src, dest, skipNames = new Set()) {
87
- if (!existsSync(src)) return
88
- const stat = statSync(src)
89
- if (stat.isFile()) {
90
- mkdirSync(dirname(dest), { recursive: true })
91
- cpSync(src, dest)
92
- return
93
- }
94
-
95
- mkdirSync(dest, { recursive: true })
96
- for (const name of readdirSync(src)) {
97
- if (skipNames.has(name)) continue
98
- copyTree(join(src, name), join(dest, name), skipNames)
99
- }
100
- }
101
-
102
- /**
103
- * @param {string} workspaceRoot
104
- */
105
- function readMonorepoPackageJson(workspaceRoot) {
106
- const path = join(workspaceRoot, 'package.json')
107
- return JSON.parse(readFileSync(path, 'utf8'))
108
- }
109
-
110
- /**
111
- * @param {string} workspaceRoot
112
- * @param {{ useCache?: boolean }} [options]
113
- */
114
- export async function resolveTemplateVersions(workspaceRoot, options = {}) {
115
- const monorepo = readMonorepoPackageJson(workspaceRoot)
116
- const monorepoDevDeps = monorepo.devDependencies ?? {}
117
-
118
- const owdPackages = [
119
- ...new Set([
120
- ...STARTER_DESKTOP_DEPS,
121
- ...Object.keys(monorepoDevDeps).filter(isOwdScopedPackage),
122
- ]),
123
- ]
124
-
125
- const npmLatest = await resolveLatestVersions(workspaceRoot, owdPackages, options)
126
-
127
- /** @type {Record<string, string>} */
128
- const versions = { ...monorepoDevDeps, ...npmLatest }
129
- for (const name of STARTER_DESKTOP_DEPS) {
130
- versions[name] =
131
- npmLatest[name] ?? TEMPLATE_NPM_FALLBACK_VERSIONS[name] ?? monorepoDevDeps[name]
132
- if (!versions[name]) {
133
- throw new Error(`Could not resolve version for ${name}`)
134
- }
135
- }
136
-
137
- return versions
138
- }
139
-
140
- /**
141
- * @param {Record<string, string>} versions
142
- */
143
- function buildTemplateRootPackageJson(versions) {
144
- const base = JSON.parse(readFileSync(join(BLUEPRINT_ROOT, 'root-package.json'), 'utf8'))
145
- /** @type {Record<string, string>} */
146
- const devDependencies = {}
147
- for (const [name, range] of Object.entries(versions)) {
148
- if (name === 'h3') continue
149
- devDependencies[name] = range
150
- }
151
- base.devDependencies = Object.fromEntries(
152
- Object.entries(devDependencies).sort(([a], [b]) => a.localeCompare(b)),
153
- )
154
- return `${JSON.stringify(base, null, 2)}\n`
155
- }
156
-
157
- /**
158
- * @param {Record<string, string>} versions
159
- */
160
- function buildTemplateDesktopPackageJson(versions) {
161
- /** @type {Record<string, string>} */
162
- const dependencies = {}
163
- for (const name of STARTER_DESKTOP_DEPS) {
164
- dependencies[name] = versions[name]
165
- }
166
-
167
- const pkg = {
168
- name: '@owdproject/client',
169
- private: true,
170
- nx: { name: 'desktop' },
171
- scripts: {
172
- build: 'nuxt generate',
173
- dev: 'nuxt dev --host',
174
- generate: 'nuxt generate --dev',
175
- postinstall: 'nuxt prepare',
176
- preview: 'nuxt preview',
177
- },
178
- dependencies: Object.fromEntries(
179
- Object.entries(dependencies).sort(([a], [b]) => a.localeCompare(b)),
180
- ),
181
- }
182
-
183
- return `${JSON.stringify(pkg, null, 2)}\n`
184
- }
185
-
186
- /**
187
- * @param {string} srcPath
188
- */
189
- function readProjectJson(srcPath) {
190
- const raw = readFileSync(srcPath, 'utf8')
191
- const data = JSON.parse(raw)
192
- if (data.name === 'desktopx') data.name = 'desktop'
193
- return `${JSON.stringify(data, null, 2)}\n`
194
- }
195
-
196
- /**
197
- * @param {string} workspaceRoot
198
- * @param {string} outputRoot
199
- * @param {{ versions: Record<string, string> }} ctx
200
- */
201
- function writeGeneratedFiles(workspaceRoot, outputRoot, ctx) {
202
- const { versions } = ctx
203
- const desktopSrc = join(workspaceRoot, 'desktop')
204
- const desktopOut = join(outputRoot, 'desktop')
205
- const blueprint = resolveBlueprintRoot()
206
-
207
- mkdirSync(outputRoot, { recursive: true })
208
-
209
- copyTree(blueprint, outputRoot, BLUEPRINT_SKIP_NAMES)
210
-
211
- writeFileSync(join(outputRoot, 'package.json'), buildTemplateRootPackageJson(versions))
212
-
213
- mkdirSync(desktopOut, { recursive: true })
214
- for (const file of DESKTOP_COPY_FILES) {
215
- const src = join(desktopSrc, file)
216
- if (existsSync(src)) {
217
- cpSync(src, join(desktopOut, file))
218
- }
219
- }
220
-
221
- const i18nBlueprint = join(blueprint, 'desktop/i18n')
222
- if (existsSync(i18nBlueprint)) {
223
- copyTree(i18nBlueprint, join(desktopOut, 'i18n'))
224
- }
225
-
226
- const projectJsonSrc = join(desktopSrc, 'project.json')
227
- if (existsSync(projectJsonSrc)) {
228
- writeFileSync(join(desktopOut, 'project.json'), readProjectJson(projectJsonSrc))
229
- }
230
-
231
- for (const file of ROOT_COPY_FROM_MONOREPO) {
232
- const src = join(workspaceRoot, file)
233
- if (existsSync(src)) {
234
- cpSync(src, join(outputRoot, file))
235
- }
236
- }
237
-
238
- writeFileSync(join(desktopOut, 'package.json'), buildTemplateDesktopPackageJson(versions))
239
- }
240
-
241
- /**
242
- * @param {string} dir
243
- * @returns {string[]}
244
- */
245
- function listFilesRecursive(dir) {
246
- if (!existsSync(dir)) return []
247
- /** @type {string[]} */
248
- const files = []
249
- for (const name of readdirSync(dir)) {
250
- const path = join(dir, name)
251
- const stat = statSync(path)
252
- if (stat.isDirectory()) {
253
- if (name === 'node_modules' || name === '.git') continue
254
- files.push(...listFilesRecursive(path))
255
- } else {
256
- files.push(path)
257
- }
258
- }
259
- return files
260
- }
261
-
262
- /**
263
- * @param {string} aRoot
264
- * @param {string} bRoot
265
- */
266
- export function diffTemplateTrees(aRoot, bRoot) {
267
- const aFiles = new Set(listFilesRecursive(aRoot).map((p) => relative(aRoot, p)))
268
- const bFiles = new Set(listFilesRecursive(bRoot).map((p) => relative(bRoot, p)))
269
- /** @type {{ path: string, type: 'missing' | 'extra' | 'changed' }[]} */
270
- const diffs = []
271
-
272
- for (const rel of aFiles) {
273
- if (!bFiles.has(rel)) {
274
- diffs.push({ path: rel, type: 'missing' })
275
- continue
276
- }
277
- const a = readFileSync(join(aRoot, rel))
278
- const b = readFileSync(join(bRoot, rel))
279
- if (!a.equals(b)) diffs.push({ path: rel, type: 'changed' })
280
- }
281
-
282
- for (const rel of bFiles) {
283
- if (!aFiles.has(rel)) diffs.push({ path: rel, type: 'extra' })
284
- }
285
-
286
- return diffs.sort((x, y) => x.path.localeCompare(y.path))
287
- }
288
-
289
- /**
290
- * @param {string} workspaceRoot
291
- * @param {{ dryRun?: boolean, check?: boolean, useCache?: boolean }} [options]
292
- */
293
- export async function generateTemplate(workspaceRoot, options = {}) {
294
- const { dryRun = false, check = false, useCache = true } = options
295
- const templateOut = join(workspaceRoot, 'template')
296
- const desktopPath = join(workspaceRoot, 'desktop')
297
-
298
- if (!existsSync(desktopPath)) {
299
- throw new Error(`Monorepo desktop/ not found at ${desktopPath}`)
300
- }
301
- resolveBlueprintRoot()
302
-
303
- const versions = await resolveTemplateVersions(workspaceRoot, { useCache })
304
-
305
- if (dryRun) {
306
- console.log('\nTemplate generation plan (dry run)\n')
307
- console.log('Output:', templateOut)
308
- console.log('\nStarter desktop dependencies:')
309
- for (const name of STARTER_DESKTOP_DEPS) {
310
- console.log(` ${name} ${versions[name]}`)
311
- }
312
- console.log('\nRoot devDependencies (@owdproject/* from npm):')
313
- for (const [name, range] of Object.entries(versions).sort(([a], [b]) => a.localeCompare(b))) {
314
- if (isOwdScopedPackage(name)) console.log(` ${name} ${range}`)
315
- }
316
- console.log('\nSources:')
317
- console.log(` blueprint ${BLUEPRINT_ROOT}`)
318
- console.log(` desktop/ ${desktopPath}`)
319
- console.log(` monorepo ${workspaceRoot}`)
320
- console.log('')
321
- return { versions, outputRoot: templateOut }
322
- }
323
-
324
- const outputRoot = check ? mkdtempSync(join(tmpdir(), 'owd-template-check-')) : templateOut
325
-
326
- try {
327
- if (!check && existsSync(templateOut)) {
328
- rmSync(templateOut, { recursive: true, force: true })
329
- }
330
-
331
- writeGeneratedFiles(workspaceRoot, outputRoot, { versions })
332
-
333
- if (check) {
334
- const diffs = diffTemplateTrees(templateOut, outputRoot)
335
- if (diffs.length === 0) {
336
- console.log('\n✓ template/ is up to date\n')
337
- return { ok: true, versions }
338
- }
339
-
340
- console.error('\n✗ template/ is out of date\n')
341
- for (const d of diffs.slice(0, 40)) {
342
- const label =
343
- d.type === 'missing'
344
- ? 'only in committed template'
345
- : d.type === 'extra'
346
- ? 'missing from committed template'
347
- : 'changed'
348
- console.error(` ${label}: ${d.path}`)
349
- }
350
- if (diffs.length > 40) {
351
- console.error(` … and ${diffs.length - 40} more`)
352
- }
353
- console.error('\nRun: pnpm desktop template\n')
354
- return { ok: false, versions, diffs }
355
- }
356
-
357
- console.log('\n✓ Generated template/\n')
358
- console.log('Starter packages:')
359
- for (const name of STARTER_DESKTOP_DEPS) {
360
- console.log(` ${name} ${versions[name]}`)
361
- }
362
- console.log('\nCommit template/ when ready.\n')
363
- return { ok: true, versions, outputRoot }
364
- } finally {
365
- if (check && existsSync(outputRoot)) {
366
- rmSync(outputRoot, { recursive: true, force: true })
367
- }
368
- }
369
- }
370
-
371
- /**
372
- * @param {{ workspaceRoot: string, dryRun?: boolean, check?: boolean }} options
373
- */
374
- export async function runGenerateTemplateCli(options) {
375
- const { workspaceRoot, dryRun = false, check = false } = options
376
-
377
- if (!workspaceRoot) {
378
- console.error('\n✗ Not inside an OWD workspace.\n')
379
- process.exit(1)
380
- }
381
-
382
- try {
383
- const result = await generateTemplate(workspaceRoot, { dryRun, check })
384
- if (check && result.ok === false) process.exit(1)
385
- } catch (error) {
386
- console.error(`\n✗ ${error.message ?? String(error)}\n`)
387
- process.exit(1)
388
- }
389
- }