@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
@@ -1,313 +0,0 @@
1
- #!/usr/bin/env node
2
- import {
3
- copyFileSync,
4
- existsSync,
5
- mkdirSync,
6
- readFileSync,
7
- renameSync,
8
- writeFileSync,
9
- } from 'node:fs'
10
- import { dirname, join } from 'node:path'
11
- import { fileURLToPath } from 'node:url'
12
- import { configs } from './migrateModulePlayground.config.mjs'
13
-
14
- const ROOT = join(dirname(fileURLToPath(import.meta.url)), '../../../../')
15
-
16
- function fixAppPlugin(pluginPath, registerName) {
17
- const raw = readFileSync(pluginPath, 'utf8')
18
- const configVar = raw.match(/import (config\w+) from/)?.[1] || 'configApp'
19
- writeFileSync(
20
- pluginPath,
21
- `import { defineNuxtPlugin } from 'nuxt/app'
22
- import { defineDesktopApp } from '@owdproject/core/runtime/utils/utilDesktop'
23
- import ${configVar} from './app.config'
24
-
25
- export default defineNuxtPlugin({
26
- name: '${registerName}',
27
- async setup() {
28
- if (import.meta.server) return
29
- await defineDesktopApp(${configVar})
30
- },
31
- })
32
- `,
33
- )
34
- }
35
-
36
- function buildLaunchPlugin(cfg) {
37
- const l = cfg.launch
38
- if (l.fsDemo) {
39
- return `import { nextTick } from 'vue'
40
- import { defineNuxtPlugin } from 'nuxt/app'
41
- import { useApplicationManager } from '@owdproject/core/runtime/composables/useApplicationManager'
42
- import { openVfsFile } from '@owdproject/module-fs/runtime/utils/utilFsOpenFile'
43
-
44
- const APP_ID = '${l.appId}'
45
-
46
- export default defineNuxtPlugin({
47
- name: '${l.pluginName}',
48
- dependsOn: ['${l.dependsOn}'],
49
- async setup(nuxtApp) {
50
- if (!import.meta.dev) return
51
-
52
- const applicationManager = useApplicationManager()
53
-
54
- async function runDemo() {
55
- if (!applicationManager.isAppDefined('org.owdproject.explorer')) return false
56
- await applicationManager.execAppCommand('org.owdproject.explorer', 'explorer /mnt/test')
57
- const opened = await openVfsFile('/mnt/test/demo.mp3')
58
- if (!opened && applicationManager.isAppDefined(APP_ID)) {
59
- await applicationManager.execAppCommand(APP_ID, ${JSON.stringify(l.command)})
60
- }
61
- return true
62
- }
63
-
64
- nuxtApp.hook('app:mounted', async () => {
65
- await nextTick()
66
- for (let i = 0; i < 80; i++) {
67
- if (await runDemo()) return
68
- await new Promise((r) => setTimeout(r, 50))
69
- }
70
- })
71
- },
72
- })
73
- `
74
- }
75
-
76
- return `import { nextTick } from 'vue'
77
- import { defineNuxtPlugin } from 'nuxt/app'
78
- import { useApplicationManager } from '@owdproject/core/runtime/composables/useApplicationManager'
79
-
80
- const APP_ID = '${l.appId}'
81
- const WINDOW_MODEL = 'main'
82
-
83
- export default defineNuxtPlugin({
84
- name: '${l.pluginName}',
85
- dependsOn: ['${l.dependsOn}'],
86
- async setup(nuxtApp) {
87
- if (!import.meta.dev) return
88
-
89
- const applicationManager = useApplicationManager()
90
-
91
- async function surfaceWindow() {
92
- if (!applicationManager.isAppDefined(APP_ID)) return false
93
- const app = applicationManager.getAppById(APP_ID)!
94
- if (app.storeWindows.$persistedState) {
95
- await app.storeWindows.$persistedState.isReady()
96
- }
97
- app.closeAllWindows()
98
- app.storeWindows.windows = {}
99
- await applicationManager.execAppCommand(APP_ID, ${JSON.stringify(l.command)})
100
- const window = app.getFirstWindowByModel(WINDOW_MODEL)
101
- if (window) {
102
- window.actions.setActive(true)
103
- window.actions.bringToFront()
104
- }
105
- return Boolean(window)
106
- }
107
-
108
- nuxtApp.hook('app:mounted', async () => {
109
- await nextTick()
110
- await surfaceWindow()
111
- })
112
-
113
- for (let attempt = 0; attempt < 80; attempt++) {
114
- if (await surfaceWindow()) return
115
- await new Promise((resolve) => setTimeout(resolve, 50))
116
- }
117
- },
118
- })
119
- `
120
- }
121
-
122
- function buildPackageJson(cfg, old) {
123
- const slug = cfg.slug
124
- const deps = { '@nuxt/kit': '^4.3.0', ...(cfg.dependencies || {}) }
125
- const devDeps = {
126
- '@nuxt/module-builder': '^1.0.2',
127
- '@nuxt/schema': '^4.3.0',
128
- '@owdproject/core': 'workspace:*',
129
- '@owdproject/theme-nova': '0.0.1',
130
- nuxt: '^4.3.0',
131
- typescript: '~5.9.3',
132
- ...(cfg.devDependencies || {}),
133
- ...(cfg.playgroundExtraDevDeps || {}),
134
- }
135
-
136
- const pkg = {
137
- name: cfg.name,
138
- version: old.version || cfg.version,
139
- description: old.description,
140
- keywords: old.keywords || cfg.keywords,
141
- license: old.license || 'MIT',
142
- homepage: old.homepage || `https://github.com/owdproject/${slug}`,
143
- author: old.author,
144
- type: 'module',
145
- exports: { '.': { types: './dist/types.d.mts', import: './dist/module.mjs' } },
146
- main: './dist/module.mjs',
147
- typesVersions: { '*': { '.': ['./dist/types.d.mts'] } },
148
- files: ['dist'],
149
- nx: { name: slug },
150
- scripts: {
151
- prepack: 'nuxt-module-build build',
152
- dev: 'pnpm run dev:prepare && cd playground && pnpm exec nuxt dev',
153
- 'dev:build': 'nuxt build playground',
154
- 'dev:generate': `NUXT_APP_BASE_URL=\${NUXT_APP_BASE_URL:-/${slug}/} nuxt generate playground`,
155
- 'dev:prepare':
156
- 'nuxt-module-build build --stub && nuxt-module-build prepare && cd playground && pnpm exec nuxt prepare',
157
- validate: 'desktop validate .',
158
- },
159
- dependencies: deps,
160
- devDependencies: devDeps,
161
- peerDependencies: old.peerDependencies || { '@owdproject/core': '^3.2.0' },
162
- }
163
- if (cfg.private || old.private) pkg.private = true
164
- if (old.peerDependenciesMeta) pkg.peerDependenciesMeta = old.peerDependenciesMeta
165
- return pkg
166
- }
167
-
168
- function buildPlaygroundPkg(cfg) {
169
- const deps = {
170
- '@owdproject/core': 'workspace:*',
171
- [cfg.name]: 'workspace:*',
172
- nuxt: '^4.4.4',
173
- ...(cfg.playgroundExtraDevDeps || {}),
174
- }
175
- if (!cfg.playgroundTheme) deps['@owdproject/theme-nova'] = '0.0.1'
176
- if (cfg.playgroundTheme) deps[cfg.playgroundTheme] = 'workspace:*'
177
- return {
178
- name: `${cfg.name}-playground`,
179
- private: true,
180
- type: 'module',
181
- scripts: { dev: 'nuxt dev', build: 'nuxt build', generate: 'nuxt generate' },
182
- dependencies: deps,
183
- }
184
- }
185
-
186
- function buildDesktopConfig(cfg) {
187
- const theme = cfg.playgroundTheme || '@owdproject/theme-nova'
188
- const apps = cfg.playgroundApps || [cfg.name]
189
- const modules = cfg.playgroundModules || []
190
- let s = `import { defineDesktopConfig } from '@owdproject/core'\n\nexport default defineDesktopConfig({\n theme: '${theme}',\n`
191
- if (apps.length) s += ` apps: [${apps.map((a) => `'${a}'`).join(', ')}],\n`
192
- if (modules.length) s += ` modules: [${modules.map((m) => `'${m}'`).join(', ')}],\n`
193
- s += ' systemBar: { enabled: true, startButton: true },\n'
194
- if (cfg.fsMounts) {
195
- s += ' fs: {\n mounts: {\n'
196
- for (const [k, v] of Object.entries(cfg.fsMounts)) s += ` '${k}': '${v}',\n`
197
- s += ' },\n },\n'
198
- }
199
- s += '})\n'
200
- return s
201
- }
202
-
203
- const NUXT = `export default defineNuxtConfig({
204
- modules: ['@owdproject/core'],
205
- app: { baseURL: process.env.NUXT_APP_BASE_URL || '/' },
206
- i18n: { strategy: 'no_prefix' },
207
- devtools: { enabled: true },
208
- compatibilityDate: 'latest',
209
- ssr: false,
210
- })
211
- `
212
-
213
- function pagesYml(slug) {
214
- return `name: Deploy playground to GitHub Pages
215
- on:
216
- push:
217
- branches: [main]
218
- workflow_dispatch:
219
- permissions:
220
- contents: read
221
- pages: write
222
- id-token: write
223
- concurrency:
224
- group: pages
225
- cancel-in-progress: true
226
- jobs:
227
- build:
228
- runs-on: ubuntu-latest
229
- steps:
230
- - uses: actions/checkout@v6
231
- - uses: actions/setup-node@v6
232
- with:
233
- node-version: 22
234
- - run: npm i -g --force corepack@latest && corepack enable
235
- - run: npx nypm@latest i
236
- - run: npm run dev:prepare
237
- - run: npm run dev:generate
238
- env:
239
- NUXT_APP_BASE_URL: /${slug}/
240
- - uses: actions/upload-pages-artifact@v3
241
- with:
242
- path: playground/.output/public
243
- deploy:
244
- needs: build
245
- runs-on: ubuntu-latest
246
- environment:
247
- name: github-pages
248
- url: \${{ steps.deployment.outputs.page_url }}
249
- steps:
250
- - uses: actions/deploy-pages@v4
251
- `
252
- }
253
-
254
- function migrate(cfg) {
255
- const dir = join(ROOT, cfg.path)
256
- const src = join(dir, 'src')
257
- mkdirSync(src, { recursive: true })
258
- if (existsSync(join(dir, 'module.ts'))) renameSync(join(dir, 'module.ts'), join(src, 'module.ts'))
259
- if (existsSync(join(dir, 'runtime'))) renameSync(join(dir, 'runtime'), join(src, 'runtime'))
260
-
261
- const registerName = `${cfg.moduleName}-register`
262
- const pluginPath = join(src, 'runtime/plugin.ts')
263
- if (existsSync(pluginPath)) fixAppPlugin(pluginPath, registerName)
264
-
265
- const old = JSON.parse(readFileSync(join(dir, 'package.json'), 'utf8'))
266
- writeFileSync(join(dir, 'package.json'), JSON.stringify(buildPackageJson(cfg, old), null, 2) + '\n')
267
-
268
- writeFileSync(
269
- join(dir, 'tsconfig.json'),
270
- JSON.stringify(
271
- {
272
- extends: '../../tsconfig.base.json',
273
- include: ['src/runtime', 'src/module.ts', '../../packages/core/types/index.d.ts'],
274
- exclude: ['dist', 'node_modules', 'playground'],
275
- compilerOptions: { outDir: 'dist' },
276
- },
277
- null,
278
- 2,
279
- ) + '\n',
280
- )
281
-
282
- writeFileSync(
283
- join(dir, '.gitignore'),
284
- 'node_modules\n.nuxt\ndist\n.output\nplayground/.nuxt\nplayground/node_modules\n._*\n',
285
- )
286
-
287
- const pg = join(dir, 'playground')
288
- mkdirSync(join(pg, 'app/plugins'), { recursive: true })
289
- writeFileSync(join(pg, 'nuxt.config.ts'), NUXT)
290
- writeFileSync(join(pg, 'tsconfig.json'), '{ "extends": "./.nuxt/tsconfig.json" }\n')
291
- writeFileSync(join(pg, 'package.json'), JSON.stringify(buildPlaygroundPkg(cfg), null, 2) + '\n')
292
- writeFileSync(join(pg, 'desktop.config.ts'), buildDesktopConfig(cfg))
293
- writeFileSync(join(pg, 'app/app.vue'), '<template>\n <Desktop />\n</template>\n')
294
- if (cfg.launch) {
295
- writeFileSync(join(pg, 'app/plugins', cfg.launch.file), buildLaunchPlugin(cfg))
296
- }
297
-
298
- if (cfg.copyTestZip) {
299
- mkdirSync(join(pg, 'public'), { recursive: true })
300
- const srcZip = join(ROOT, 'desktop/public/test.zip')
301
- if (existsSync(srcZip)) copyFileSync(srcZip, join(pg, 'public/test.zip'))
302
- }
303
-
304
- if (cfg.pagesYml) {
305
- const wf = join(dir, '.github/workflows')
306
- mkdirSync(wf, { recursive: true })
307
- writeFileSync(join(wf, 'pages.yml'), pagesYml(cfg.slug))
308
- }
309
-
310
- console.log('OK', cfg.name)
311
- }
312
-
313
- for (const cfg of configs) migrate(cfg)
@@ -1,124 +0,0 @@
1
- import { execSync } from 'node:child_process'
2
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'
3
- import { join } from 'node:path'
4
- import { desktopMetaDir } from './workspace.js'
5
-
6
- const CACHE_TTL_MS = 60 * 60 * 1000
7
- const SCOPE = '@owdproject/'
8
-
9
- /**
10
- * @param {string} version
11
- */
12
- export function formatCaretVersion(version) {
13
- const trimmed = String(version).trim()
14
- if (!trimmed) throw new Error('Invalid npm version (empty)')
15
- if (trimmed.startsWith('^') || trimmed.startsWith('~') || trimmed.startsWith('>=')) {
16
- return trimmed
17
- }
18
- return `^${trimmed}`
19
- }
20
-
21
- /**
22
- * @param {unknown} error
23
- */
24
- function isNpmLookupSkippableError(error) {
25
- const msg = error?.stderr?.toString?.() || error?.message || String(error)
26
- return (
27
- /E404|404 Not Found/.test(msg) ||
28
- /EAI_AGAIN|ENOTFOUND|ETIMEDOUT|ECONNREFUSED|network/i.test(msg)
29
- )
30
- }
31
-
32
- /**
33
- * @param {string} pkgName
34
- * @param {{ optional?: boolean }} [options]
35
- * @returns {string | null}
36
- */
37
- export function fetchLatestVersion(pkgName, options = {}) {
38
- let out
39
- try {
40
- out = execSync(`npm view ${JSON.stringify(pkgName)} version`, {
41
- encoding: 'utf8',
42
- stdio: ['pipe', 'pipe', 'pipe'],
43
- }).trim()
44
- } catch (error) {
45
- if (options.optional || isNpmLookupSkippableError(error)) return null
46
- const msg = error.stderr?.toString?.() || error.message || String(error)
47
- throw new Error(`npm view failed for ${pkgName}: ${msg}`)
48
- }
49
- return formatCaretVersion(out)
50
- }
51
-
52
- /**
53
- * @param {string[]} pkgNames
54
- * @returns {Record<string, string>}
55
- */
56
- export function fetchLatestVersions(pkgNames, options = {}) {
57
- const unique = [...new Set(pkgNames.filter(Boolean))]
58
- if (unique.length === 0) return {}
59
-
60
- /** @type {Record<string, string>} */
61
- const result = {}
62
- for (const name of unique) {
63
- const version = fetchLatestVersion(name, options)
64
- if (version) result[name] = version
65
- }
66
- return result
67
- }
68
-
69
- function cachePath(workspaceRoot) {
70
- return join(desktopMetaDir(workspaceRoot), 'template-versions.json')
71
- }
72
-
73
- /**
74
- * @param {string} workspaceRoot
75
- * @param {string[]} pkgNames
76
- * @param {{ useCache?: boolean }} [options]
77
- */
78
- export function resolveLatestVersions(workspaceRoot, pkgNames, options = {}) {
79
- const useCache = options.useCache !== false
80
- const unique = [...new Set(pkgNames.filter(Boolean))]
81
- const path = cachePath(workspaceRoot)
82
-
83
- if (useCache && existsSync(path)) {
84
- try {
85
- const data = JSON.parse(readFileSync(path, 'utf8'))
86
- if (Date.now() - data.fetchedAt < CACHE_TTL_MS && data.versions) {
87
- const cached = data.versions
88
- const missing = unique.filter((name) => !cached[name])
89
- if (missing.length === 0) {
90
- return Object.fromEntries(unique.map((name) => [name, cached[name]]))
91
- }
92
- const fresh = fetchLatestVersions(missing)
93
- const merged = { ...cached, ...fresh }
94
- writeVersionCache(workspaceRoot, merged)
95
- return Object.fromEntries(unique.map((name) => [name, merged[name]]))
96
- }
97
- } catch {
98
- /* ignore corrupt cache */
99
- }
100
- }
101
-
102
- const versions = fetchLatestVersions(unique)
103
- if (useCache) writeVersionCache(workspaceRoot, versions)
104
- return versions
105
- }
106
-
107
- /**
108
- * @param {string} workspaceRoot
109
- * @param {Record<string, string>} versions
110
- */
111
- export function writeVersionCache(workspaceRoot, versions) {
112
- mkdirSync(desktopMetaDir(workspaceRoot), { recursive: true })
113
- writeFileSync(
114
- cachePath(workspaceRoot),
115
- JSON.stringify({ fetchedAt: Date.now(), versions }, null, 2) + '\n',
116
- )
117
- }
118
-
119
- /**
120
- * @param {string} pkgName
121
- */
122
- export function isOwdScopedPackage(pkgName) {
123
- return pkgName.startsWith(SCOPE)
124
- }
@@ -1,188 +0,0 @@
1
- import { existsSync, readFileSync } from 'node:fs'
2
- import { dirname, join, resolve, sep } from 'node:path'
3
- import { SCOPE } from './workspace.js'
4
-
5
- const PLAYGROUND_CONFIG = join('playground', 'desktop.config.ts')
6
-
7
- /**
8
- * @param {string} dir
9
- * @returns {boolean}
10
- */
11
- export function hasPlaygroundDesktopConfig(dir) {
12
- return (
13
- existsSync(join(dir, 'playground')) &&
14
- existsSync(join(dir, PLAYGROUND_CONFIG))
15
- )
16
- }
17
-
18
- /**
19
- * @param {string} pkgPath
20
- * @returns {{ name: string } | null}
21
- */
22
- function readOwdPackageJson(pkgPath) {
23
- if (!existsSync(pkgPath)) return null
24
- try {
25
- const pkg = JSON.parse(readFileSync(pkgPath, 'utf8'))
26
- if (typeof pkg.name === 'string' && pkg.name.startsWith(SCOPE)) {
27
- return { name: pkg.name }
28
- }
29
- } catch {
30
- /* ignore */
31
- }
32
- return null
33
- }
34
-
35
- /**
36
- * Walk up from cwd until a package.json with @owdproject/* name and a playground
37
- * with desktop.config.ts is found.
38
- *
39
- * @param {string} [startDir]
40
- * @returns {string | null} Absolute package directory
41
- */
42
- export function findOwdModulePackageRoot(startDir = process.cwd()) {
43
- let dir = resolve(startDir)
44
- for (;;) {
45
- const meta = readOwdPackageJson(join(dir, 'package.json'))
46
- if (meta && hasPlaygroundDesktopConfig(dir)) {
47
- return dir
48
- }
49
- const parent = dirname(dir)
50
- if (parent === dir) return null
51
- dir = parent
52
- }
53
- }
54
-
55
- /**
56
- * @param {string} path
57
- * @param {string} root
58
- */
59
- function isPathInside(path, root) {
60
- const normalized = resolve(path)
61
- const base = resolve(root)
62
- return normalized === base || normalized.startsWith(base + sep)
63
- }
64
-
65
- /**
66
- * @typedef {'workspace' | 'playground'} DevTargetMode
67
- */
68
-
69
- /**
70
- * @typedef {object} DevTarget
71
- * @property {DevTargetMode} mode
72
- * @property {string} workspaceRoot
73
- * @property {string} packageDir Directory where `pnpm run dev` runs
74
- * @property {string | null} packageName Set when mode is playground
75
- * @property {string | null} playgroundDir Absolute path to playground/
76
- */
77
-
78
- /**
79
- * @param {string} packageDir
80
- * @param {string} workspaceRoot
81
- * @param {string} packageName
82
- * @returns {DevTarget}
83
- */
84
- function playgroundTarget(packageDir, workspaceRoot, packageName) {
85
- return {
86
- mode: 'playground',
87
- workspaceRoot,
88
- packageDir: resolve(packageDir),
89
- packageName,
90
- playgroundDir: join(resolve(packageDir), 'playground'),
91
- }
92
- }
93
-
94
- /**
95
- * @param {string} workspaceRoot
96
- * @returns {DevTarget}
97
- */
98
- function workspaceTarget(workspaceRoot) {
99
- return {
100
- mode: 'workspace',
101
- workspaceRoot: resolve(workspaceRoot),
102
- packageDir: resolve(workspaceRoot),
103
- packageName: null,
104
- playgroundDir: null,
105
- }
106
- }
107
-
108
- /**
109
- * Resolve whether the CLI/TUI should start the monorepo desktop shell or a
110
- * module package playground dev server.
111
- *
112
- * @param {string} [cwd]
113
- * @param {string | null} workspaceRoot
114
- * @param {{ forcePlayground?: boolean }} [options]
115
- * @returns {DevTarget | null} null when workspaceRoot is missing
116
- */
117
- export function resolveDevTarget(cwd, workspaceRoot, options = {}) {
118
- if (!workspaceRoot) return null
119
-
120
- const normalizedCwd = resolve(cwd ?? process.cwd())
121
- const root = resolve(workspaceRoot)
122
- const desktopDir = join(root, 'desktop')
123
- const packageRoot = findOwdModulePackageRoot(normalizedCwd)
124
- const forcePlayground = options.forcePlayground === true
125
-
126
- if (packageRoot) {
127
- const meta = readOwdPackageJson(join(packageRoot, 'package.json'))
128
- const packageName = meta?.name ?? null
129
-
130
- if (forcePlayground) {
131
- return playgroundTarget(packageRoot, root, packageName)
132
- }
133
-
134
- const atWorkspaceRoot = normalizedCwd === root
135
- const underDesktopOnly =
136
- isPathInside(normalizedCwd, desktopDir) && !isPathInside(normalizedCwd, packageRoot)
137
-
138
- if (!atWorkspaceRoot && !underDesktopOnly && isPathInside(normalizedCwd, packageRoot)) {
139
- return playgroundTarget(packageRoot, root, packageName)
140
- }
141
- }
142
-
143
- if (forcePlayground) {
144
- return null
145
- }
146
-
147
- return workspaceTarget(root)
148
- }
149
-
150
- /**
151
- * @param {DevTarget | string | null | undefined} target
152
- * @param {string} [workspaceRoot]
153
- * @returns {DevTarget | null}
154
- */
155
- export function normalizeDevTarget(target, workspaceRoot) {
156
- if (!target) return workspaceRoot ? workspaceTarget(workspaceRoot) : null
157
- if (typeof target === 'string') return workspaceTarget(target)
158
- if (target.mode && target.workspaceRoot) return target
159
- if (workspaceRoot) {
160
- return {
161
- ...workspaceTarget(workspaceRoot),
162
- ...target,
163
- workspaceRoot: resolve(workspaceRoot),
164
- }
165
- }
166
- return null
167
- }
168
-
169
- /**
170
- * @param {DevTarget | string} target
171
- * @returns {string}
172
- */
173
- export function devSpawnCwd(target) {
174
- const resolved = typeof target === 'string' ? workspaceTarget(target) : target
175
- return resolved.packageDir
176
- }
177
-
178
- /**
179
- * @param {DevTarget | string} target
180
- * @returns {string}
181
- */
182
- export function devTargetLogLabel(target) {
183
- const resolved = typeof target === 'string' ? workspaceTarget(target) : target
184
- if (resolved.mode === 'playground' && resolved.packageName) {
185
- return `playground ${resolved.packageName}`
186
- }
187
- return 'workspace desktop'
188
- }