@owdproject/core 3.3.1 → 3.4.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.
- package/CHANGELOG.md +98 -0
- package/DESKTOP_KERNEL.md +232 -0
- package/MIGRATION_3.3.2.md +23 -0
- package/MIGRATION_3.4.md +126 -0
- package/PLAYGROUND.md +91 -0
- package/README.md +13 -80
- package/dist/module.d.mts +2 -2
- package/dist/module.json +3 -3
- package/dist/module.mjs +74 -88
- package/index.ts +6 -3
- package/kit/authoring.ts +340 -0
- package/kit/defineDesktopApp.ts +56 -0
- package/module.ts +64 -84
- package/package.json +70 -41
- package/runtime/components/{Desktop/Application/DesktopApplicationRender.vue → Application/DesktopCoreApplicationRender.vue} +2 -2
- package/runtime/components/{Desktop/Application/DesktopApplicationWindowsRender.vue → Application/DesktopCoreApplicationWindowsRender.vue} +1 -1
- package/runtime/components/core/DesktopCore.vue +43 -0
- package/runtime/components/{Desktop/Window/DesktopWindow.vue → window/DesktopCoreWindow.vue} +17 -6
- package/runtime/components/window/DesktopCoreWindowSnapHintsBase.vue +74 -0
- package/runtime/components/workspace/DesktopCoreWorkspaceEdgeHintsBase.vue +84 -0
- package/runtime/composables/useBlockNonInputContextMenu.ts +30 -0
- package/runtime/composables/useDesktopConfig.ts +8 -0
- package/runtime/composables/useDesktopDialogs.ts +16 -0
- package/runtime/composables/useDesktopExtension.ts +8 -0
- package/runtime/composables/useDesktopManager.ts +2 -0
- package/runtime/composables/useDesktopManifest.ts +17 -0
- package/runtime/composables/useDesktopSession.ts +27 -0
- package/runtime/composables/useDesktopShellIdentity.ts +99 -0
- package/runtime/composables/useDesktopShellOptions.ts +36 -0
- package/runtime/composables/useDesktopShellReady.ts +7 -0
- package/runtime/composables/useDesktopWorkArea.ts +93 -0
- package/runtime/composables/useTerminalManager.ts +102 -9
- package/runtime/composables/useToggleWindowMaximize.ts +35 -0
- package/runtime/composables/useWindowDragHandlers.ts +47 -0
- package/runtime/composables/useWindowSnapDrop.ts +112 -0
- package/runtime/composables/useWorkspaceEdgeDrop.ts +176 -0
- package/runtime/composables/useWorkspaceManager.ts +26 -0
- package/runtime/composables/useWorkspaceOverviewCapture.ts +92 -0
- package/runtime/composables/useWorkspaceOverviewLiveScale.ts +151 -0
- package/runtime/constants/desktopShellKeys.ts +12 -0
- package/runtime/constants/shellLayout.ts +5 -0
- package/runtime/dialogs/desktopDialogProvider.ts +73 -0
- package/runtime/internal/controllers/ApplicationController.ts +8 -2
- package/runtime/internal/controllers/WindowController.ts +93 -8
- package/runtime/plugins/01.desktop-shell-init.client.ts +28 -0
- package/runtime/plugins/02.desktop-register-desktop-apps.client.ts +2 -6
- package/runtime/stores/storeApplicationMeta.ts +2 -1
- package/runtime/stores/storeApplicationWindows.ts +2 -1
- package/runtime/stores/storeDesktop.ts +17 -57
- package/runtime/stores/storeDesktopDefaultApps.ts +2 -1
- package/runtime/stores/storeDesktopVolume.ts +2 -1
- package/runtime/stores/storeDesktopWindow.ts +20 -2
- package/runtime/stores/storeDesktopWorkspace.ts +31 -1
- package/runtime/stores/storeIds.ts +35 -0
- package/runtime/types/desktopMenu.ts +10 -0
- package/runtime/utils/initDesktopShell.ts +80 -0
- package/runtime/utils/migratePersistedStoreIds.ts +57 -0
- package/runtime/utils/utilApp.ts +0 -12
- package/runtime/utils/{captureElementToCanvas.ts → utilCaptureElementToCanvas.ts} +1 -1
- package/runtime/utils/utilDetectSnapZone.ts +57 -0
- package/runtime/utils/utilWindowLayout.ts +82 -0
- package/runtime/utils/utilWindowMaximizeLayout.ts +44 -0
- package/runtime/utils/utilWorkspaceWindows.ts +33 -0
- package/types/index.d.ts +125 -14
- package/bin/cli.js +0 -395
- package/bin/desktop.js +0 -5
- package/bin/lib/catalog.js +0 -293
- package/bin/lib/config.js +0 -109
- package/bin/lib/desktopConfig.js +0 -56
- package/bin/lib/generateTemplate.js +0 -389
- package/bin/lib/install.js +0 -408
- package/bin/lib/migrateModulePlayground.config.mjs +0 -164
- package/bin/lib/migrateModulePlayground.mjs +0 -313
- package/bin/lib/npmVersions.js +0 -124
- package/bin/lib/playgroundContext.js +0 -188
- package/bin/lib/scaffold.js +0 -197
- package/bin/lib/status.js +0 -289
- package/bin/lib/validateModule.js +0 -697
- package/bin/lib/workspace.js +0 -182
- package/bin/owd.js +0 -5
- package/bin/tui.js +0 -1379
- package/runtime/components/Desktop/Core/DesktopCore.vue +0 -90
- package/runtime/utils/explorerEntryPath.ts +0 -10
- package/runtime/utils/resolveDesktopConfigPath.ts +0 -52
- package/runtime/utils/splitDesktopUserConfig.ts +0 -85
- package/runtime/utils/utilDesktop.ts +0 -35
- package/runtime/utils/validateDesktopUserConfig.ts +0 -44
- /package/runtime/components/{Desktop/Background/DesktopBackground.vue → background/DesktopCoreBackground.vue} +0 -0
- /package/runtime/components/{Desktop/Time/DesktopTime.vue → time/DesktopCoreTime.vue} +0 -0
- /package/runtime/components/{Desktop/Window/DesktopWindowContent.vue → window/DesktopCoreWindowContent.vue} +0 -0
- /package/runtime/components/{Desktop/Window/DesktopWindowNav.vue → window/DesktopCoreWindowNav.vue} +0 -0
- /package/runtime/utils/{utilWindow.ts → utilWindowControllerAdapter.ts} +0 -0
package/types/index.d.ts
CHANGED
|
@@ -1,16 +1,14 @@
|
|
|
1
1
|
import type { Nuxt } from '@nuxt/schema'
|
|
2
2
|
import type { ShallowRef } from 'vue'
|
|
3
|
-
import { useApplicationManager } from '../runtime/composables/useApplicationManager'
|
|
4
3
|
|
|
5
4
|
declare module 'nuxt/schema' {
|
|
6
5
|
interface PublicRuntimeConfig {
|
|
7
|
-
|
|
8
|
-
tailwindPaths: []
|
|
9
|
-
}
|
|
6
|
+
desktop: DesktopConfig
|
|
10
7
|
}
|
|
11
8
|
}
|
|
12
9
|
|
|
13
|
-
|
|
10
|
+
declare global {
|
|
11
|
+
interface IApplicationManager {
|
|
14
12
|
apps: Map<string, IApplicationController>
|
|
15
13
|
|
|
16
14
|
get appsEntries(): Reactive<ApplicationEntry[]>
|
|
@@ -61,6 +59,7 @@ interface ApplicationConfig {
|
|
|
61
59
|
windows?: { [key: string]: WindowConfig }
|
|
62
60
|
entries: { [key: string]: ApplicationEntry }
|
|
63
61
|
commands?: { [key: string]: ApplicationCommand }
|
|
62
|
+
terminal?: { [commandName: string]: Omit<TerminalCommand, 'name' | 'applicationId'> }
|
|
64
63
|
|
|
65
64
|
onReady?(app: IApplicationController): void | Promise<void>
|
|
66
65
|
|
|
@@ -73,7 +72,8 @@ interface ApplicationConfig {
|
|
|
73
72
|
|
|
74
73
|
interface ApplicationConfigProvide {
|
|
75
74
|
name: string
|
|
76
|
-
|
|
75
|
+
entry: string
|
|
76
|
+
command?: string
|
|
77
77
|
}
|
|
78
78
|
|
|
79
79
|
type IApplicationMeta = { [key: string]: any }
|
|
@@ -131,6 +131,8 @@ export interface IWindowController {
|
|
|
131
131
|
// common
|
|
132
132
|
get title(): string
|
|
133
133
|
|
|
134
|
+
get windowTitle(): string
|
|
135
|
+
|
|
134
136
|
get icon(): string | undefined
|
|
135
137
|
|
|
136
138
|
// sizes
|
|
@@ -173,6 +175,11 @@ export interface IWindowController {
|
|
|
173
175
|
maximize(): boolean
|
|
174
176
|
unmaximize(): boolean
|
|
175
177
|
|
|
178
|
+
// layout (snap / tiled zones)
|
|
179
|
+
setLayout(layout: WindowLayout): boolean
|
|
180
|
+
clearLayout(): boolean
|
|
181
|
+
saveBoundsBeforeLayout(): void
|
|
182
|
+
|
|
176
183
|
// destroy
|
|
177
184
|
destroy(): boolean
|
|
178
185
|
|
|
@@ -182,13 +189,15 @@ export interface IWindowController {
|
|
|
182
189
|
// override
|
|
183
190
|
setTitleOverride(title: string | undefined): void
|
|
184
191
|
resetTitleOverride(): void
|
|
192
|
+
setWindowTitleOverride(title: string | undefined): void
|
|
193
|
+
resetWindowTitleOverride(): void
|
|
185
194
|
}
|
|
186
195
|
|
|
187
196
|
/** Payload restored with window state (e.g. explorer cwd in `path`). */
|
|
188
197
|
get meta(): { path?: string } & Record<string, unknown>
|
|
189
198
|
|
|
190
|
-
/** Chrome menu model (
|
|
191
|
-
menu:
|
|
199
|
+
/** Chrome menu model ({@link DesktopMenuItem}[]; Menubar-compatible). */
|
|
200
|
+
menu: import('../runtime/types/desktopMenu').DesktopMenuItem[]
|
|
192
201
|
|
|
193
202
|
setMenu(menu: unknown[]): void
|
|
194
203
|
|
|
@@ -254,6 +263,7 @@ interface WindowStoredState {
|
|
|
254
263
|
|
|
255
264
|
interface WindowOverride {
|
|
256
265
|
title?: undefined | string
|
|
266
|
+
windowTitle?: undefined | string
|
|
257
267
|
icon?: undefined | string
|
|
258
268
|
}
|
|
259
269
|
|
|
@@ -289,6 +299,37 @@ interface WindowState {
|
|
|
289
299
|
|
|
290
300
|
// draggable
|
|
291
301
|
resizable?: boolean
|
|
302
|
+
|
|
303
|
+
/** Snap zone layout; `normal` is unset or explicit restore. */
|
|
304
|
+
layout?: WindowLayout
|
|
305
|
+
|
|
306
|
+
/** Bounds saved before first snap so restore can revert geometry. */
|
|
307
|
+
boundsBeforeLayout?: WindowBounds
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
export type WindowLayout =
|
|
311
|
+
| 'normal'
|
|
312
|
+
| 'maximize'
|
|
313
|
+
| 'bottom-half'
|
|
314
|
+
| 'left-half'
|
|
315
|
+
| 'right-half'
|
|
316
|
+
| 'top-left'
|
|
317
|
+
| 'top-right'
|
|
318
|
+
| 'bottom-left'
|
|
319
|
+
| 'bottom-right'
|
|
320
|
+
|
|
321
|
+
export interface WindowBounds {
|
|
322
|
+
x: number
|
|
323
|
+
y: number
|
|
324
|
+
width: number
|
|
325
|
+
height: number
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
export interface DesktopWorkAreaRect {
|
|
329
|
+
x: number
|
|
330
|
+
y: number
|
|
331
|
+
width: number
|
|
332
|
+
height: number
|
|
292
333
|
}
|
|
293
334
|
|
|
294
335
|
interface WindowSize {
|
|
@@ -351,6 +392,7 @@ interface DocsModuleConfig {
|
|
|
351
392
|
}
|
|
352
393
|
|
|
353
394
|
interface DesktopConfig {
|
|
395
|
+
coreVersion?: string
|
|
354
396
|
theme?: string
|
|
355
397
|
modules?: string[]
|
|
356
398
|
apps?: string[]
|
|
@@ -364,6 +406,7 @@ interface DesktopConfig {
|
|
|
364
406
|
systemBar?: DesktopSystemBarConfig
|
|
365
407
|
dockBar?: DesktopDockBarConfig
|
|
366
408
|
workspaces?: DesktopWorkspacesConfig
|
|
409
|
+
windows?: DesktopWindowsConfig
|
|
367
410
|
}
|
|
368
411
|
|
|
369
412
|
interface DesktopWindowsConfig {
|
|
@@ -387,13 +430,36 @@ interface DesktopWorkspacesConfig {
|
|
|
387
430
|
|
|
388
431
|
// TERMINAL
|
|
389
432
|
|
|
433
|
+
type TerminalCommandArg = {
|
|
434
|
+
name: string
|
|
435
|
+
description?: string
|
|
436
|
+
required?: boolean
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
type TerminalCommandOption = {
|
|
440
|
+
flag: string
|
|
441
|
+
description?: string
|
|
442
|
+
}
|
|
443
|
+
|
|
390
444
|
type TerminalCommand = {
|
|
391
445
|
name: string
|
|
392
446
|
applicationId: string
|
|
447
|
+
description?: string
|
|
448
|
+
usage?: string
|
|
449
|
+
args?: TerminalCommandArg[]
|
|
450
|
+
options?: TerminalCommandOption[]
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
interface ITerminalManager {
|
|
454
|
+
addCommand(command: TerminalCommand): void
|
|
455
|
+
listCommands(): string[]
|
|
456
|
+
getCommand(name: string): TerminalCommand | undefined
|
|
457
|
+
getAllCommands(): TerminalCommand[]
|
|
458
|
+
execCommand(input: string): Promise<CommandOutput | void>
|
|
393
459
|
}
|
|
394
460
|
|
|
395
461
|
interface CommandOutput {
|
|
396
|
-
|
|
462
|
+
message: string
|
|
397
463
|
isError?: boolean
|
|
398
464
|
}
|
|
399
465
|
|
|
@@ -407,14 +473,59 @@ interface DefaultAppsConfig {
|
|
|
407
473
|
[key: string]: DefaultAppConfig
|
|
408
474
|
}
|
|
409
475
|
|
|
410
|
-
/** Stored default for a feature: which app and which entry key to use. */
|
|
411
|
-
interface DefaultAppConfig {
|
|
412
|
-
|
|
413
|
-
|
|
476
|
+
/** Stored default for a feature: which app and which entry key to use. */
|
|
477
|
+
interface DefaultAppConfig {
|
|
478
|
+
applicationId: string
|
|
479
|
+
entry: string
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
module '*.vue' {
|
|
483
|
+
import type { DefineComponent } from 'vue'
|
|
484
|
+
const component: DefineComponent<{}, {}, any>
|
|
485
|
+
export default component
|
|
486
|
+
}
|
|
414
487
|
}
|
|
415
488
|
|
|
416
489
|
export function defineDesktopApp(config: ApplicationConfig)
|
|
417
490
|
export function defineDesktopConfig(config: DesktopConfig)
|
|
418
|
-
export function
|
|
491
|
+
export function defineDesktopModule(
|
|
492
|
+
definition: import('@nuxt/kit').NuxtModule<
|
|
493
|
+
Record<string, unknown>,
|
|
494
|
+
Record<string, unknown>,
|
|
495
|
+
false
|
|
496
|
+
> & { meta: { name: string; configKey: string } },
|
|
497
|
+
): ReturnType<typeof import('@nuxt/kit').defineNuxtModule>
|
|
498
|
+
|
|
499
|
+
export function defineDesktopTheme(
|
|
500
|
+
definition: import('@nuxt/kit').NuxtModule<
|
|
501
|
+
Record<string, unknown>,
|
|
502
|
+
Record<string, unknown>,
|
|
503
|
+
false
|
|
504
|
+
>,
|
|
505
|
+
): ReturnType<typeof import('@nuxt/kit').defineNuxtModule>
|
|
506
|
+
|
|
507
|
+
export function setDesktopExtensionConfig(
|
|
508
|
+
nuxt: Nuxt,
|
|
509
|
+
configKey: string,
|
|
510
|
+
resolved: Record<string, unknown>,
|
|
511
|
+
): void
|
|
512
|
+
|
|
513
|
+
export function mergeDesktopExtensionConfig(
|
|
514
|
+
nuxt: Nuxt,
|
|
515
|
+
configKey: string,
|
|
516
|
+
partial: Record<string, unknown>,
|
|
517
|
+
): void
|
|
518
|
+
|
|
519
|
+
export function useDesktopConfig(): import('vue').ComputedRef<DesktopConfig>
|
|
520
|
+
export function useDesktopExtension<K extends string>(
|
|
521
|
+
key: K,
|
|
522
|
+
): import('vue').ComputedRef<unknown>
|
|
523
|
+
export function hasDesktopModule(
|
|
524
|
+
pkg: string,
|
|
525
|
+
): import('vue').ComputedRef<boolean>
|
|
526
|
+
export function hasDesktopApp(pkg: string): import('vue').ComputedRef<boolean>
|
|
527
|
+
export function hasDesktopExtension(
|
|
528
|
+
key: string,
|
|
529
|
+
): import('vue').ComputedRef<boolean>
|
|
419
530
|
|
|
420
531
|
export {}
|
package/bin/cli.js
DELETED
|
@@ -1,395 +0,0 @@
|
|
|
1
|
-
import { spawn } from 'node:child_process'
|
|
2
|
-
import { runDevForeground } from './lib/status.js'
|
|
3
|
-
import { existsSync } from 'node:fs'
|
|
4
|
-
import { join } from 'node:path'
|
|
5
|
-
import getopts from 'getopts'
|
|
6
|
-
import {
|
|
7
|
-
resolveSource,
|
|
8
|
-
printPlan,
|
|
9
|
-
printNextSteps,
|
|
10
|
-
runWorkspaceInstall,
|
|
11
|
-
runNpmInstall,
|
|
12
|
-
} from './lib/install.js'
|
|
13
|
-
import { findWorkspaceRoot, inferKind } from './lib/workspace.js'
|
|
14
|
-
import { resolveDevTarget } from './lib/playgroundContext.js'
|
|
15
|
-
import { scaffoldProject } from './lib/scaffold.js'
|
|
16
|
-
|
|
17
|
-
const SCOPE = '@owdproject/'
|
|
18
|
-
|
|
19
|
-
/** @type {Record<string, { configKey: string, workspaceDir: string, nx: string, label: string }>} */
|
|
20
|
-
const KINDS = {
|
|
21
|
-
app: {
|
|
22
|
-
label: 'app',
|
|
23
|
-
configKey: 'apps',
|
|
24
|
-
workspaceDir: 'apps',
|
|
25
|
-
nx: 'desktop:install-app',
|
|
26
|
-
},
|
|
27
|
-
module: {
|
|
28
|
-
label: 'module',
|
|
29
|
-
configKey: 'modules',
|
|
30
|
-
workspaceDir: 'packages',
|
|
31
|
-
nx: 'desktop:install-module',
|
|
32
|
-
},
|
|
33
|
-
theme: {
|
|
34
|
-
label: 'theme',
|
|
35
|
-
configKey: 'theme',
|
|
36
|
-
workspaceDir: 'themes',
|
|
37
|
-
nx: 'desktop:install-theme',
|
|
38
|
-
},
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
const LEGACY_COMMANDS = {
|
|
42
|
-
'install-app': 'app',
|
|
43
|
-
'install-module': 'module',
|
|
44
|
-
'install-theme': 'theme',
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/** @type {string} */
|
|
48
|
-
let commandName = 'desktop'
|
|
49
|
-
|
|
50
|
-
function buildHelp(name) {
|
|
51
|
-
return `
|
|
52
|
-
${name} — add apps, modules, and themes to your Open Web Desktop
|
|
53
|
-
|
|
54
|
-
USAGE
|
|
55
|
-
${name} Open the control panel (interactive TUI)
|
|
56
|
-
${name} dev [--playground] Start dev server (auto-detects module playground)
|
|
57
|
-
|
|
58
|
-
CONTROL PANEL (TUI)
|
|
59
|
-
m Open command menu (all actions)
|
|
60
|
-
s Start the Nuxt dev server
|
|
61
|
-
x Stop the Nuxt dev server
|
|
62
|
-
R Reboot the Nuxt dev server (stop + start)
|
|
63
|
-
w Save catalog/theme changes to desktop.config.ts
|
|
64
|
-
i Open in-app docs (when module-docs is installed)
|
|
65
|
-
d Toggle User (npm) / Dev (git clone) install mode
|
|
66
|
-
g Settings (GitHub username for fork clones)
|
|
67
|
-
r Refresh package list from GitHub
|
|
68
|
-
b Run pnpm run generate
|
|
69
|
-
q / Esc Quit
|
|
70
|
-
${name} init [dir] Create a new OWD project (then opens the control panel)
|
|
71
|
-
${name} add <package> [options]
|
|
72
|
-
${name} add <kind> <name> [options]
|
|
73
|
-
${name} validate [path...] Check Nuxt module + playground layout
|
|
74
|
-
${name} template [--dry-run] [--check] Regenerate client/template/ (maintainers)
|
|
75
|
-
|
|
76
|
-
TEMPLATE (monorepo maintainers)
|
|
77
|
-
${name} template Write template/ from blueprint + desktop/ + latest npm versions
|
|
78
|
-
${name} template --dry-run Show planned @owdproject/* and starter versions
|
|
79
|
-
${name} template --check Fail if committed template/ differs (CI)
|
|
80
|
-
|
|
81
|
-
VALIDATE
|
|
82
|
-
${name} validate Validate cwd package, or all apps/themes/modules at repo root
|
|
83
|
-
${name} validate . Validate explicit package directory
|
|
84
|
-
${name} validate apps Validate every @owdproject/* module under apps/
|
|
85
|
-
--json Machine-readable output
|
|
86
|
-
--strict Treat warnings as failures
|
|
87
|
-
--smoke Run dev:prepare + nuxt build playground (slow, CI)
|
|
88
|
-
|
|
89
|
-
INSTALL MODES
|
|
90
|
-
User (default) npm registry — for end users and generated projects
|
|
91
|
-
Dev clone into apps/, packages/, or themes/ in the monorepo
|
|
92
|
-
|
|
93
|
-
EXAMPLES
|
|
94
|
-
pnpm ${name} # control panel
|
|
95
|
-
pnpm ${name} dev # monorepo desktop (from repo root)
|
|
96
|
-
cd apps/app-about && pnpm ${name} dev # app-about playground
|
|
97
|
-
pnpm ${name} dev --playground # force playground when cwd is in a module
|
|
98
|
-
${name} init my-desktop # scaffold + pnpm install + control panel
|
|
99
|
-
${name} add app-todo --npm
|
|
100
|
-
${name} add app-todo --dev
|
|
101
|
-
${name} add module-persistence --from dxlliv
|
|
102
|
-
|
|
103
|
-
KINDS (optional — inferred from the package name)
|
|
104
|
-
app app-* → apps/
|
|
105
|
-
module module-* → packages/ (kit-* and *-template are not listed in the control panel)
|
|
106
|
-
theme theme-* → themes/
|
|
107
|
-
|
|
108
|
-
OPTIONS
|
|
109
|
-
--playground Start the module playground dev server (when cwd is inside an @owdproject/* package with playground/)
|
|
110
|
-
--from <source> Git source (user, user/repo, or URL)
|
|
111
|
-
--branch <name> Git branch to clone
|
|
112
|
-
--npm Install from npm (default when --from is omitted)
|
|
113
|
-
--dev, --workspace Clone from github.com/owdproject/<package>
|
|
114
|
-
--dry-run Print the plan without changing anything
|
|
115
|
-
-h, --help Show this help
|
|
116
|
-
|
|
117
|
-
--from <source>
|
|
118
|
-
(omit) npm registry (default)
|
|
119
|
-
npm npm registry
|
|
120
|
-
owdproject Clone official repo (monorepo only)
|
|
121
|
-
<github-user> Clone github.com/<user>/<package> (your fork)
|
|
122
|
-
<user>/<repo> Explicit GitHub repo
|
|
123
|
-
<git-url> Full clone URL
|
|
124
|
-
|
|
125
|
-
LEGACY (still supported)
|
|
126
|
-
${name} install-app @owdproject/app-todo
|
|
127
|
-
→ prefer: ${name} add app-todo
|
|
128
|
-
`
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
async function openControlPanel(name) {
|
|
132
|
-
const { runTui } = await import('./tui.js')
|
|
133
|
-
await runTui(name)
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
function fail(message, hint) {
|
|
137
|
-
console.error(`\n✗ ${message}`)
|
|
138
|
-
if (hint) console.error(` ${hint}`)
|
|
139
|
-
console.error(`\nRun \`${commandName} --help\` for usage.\n`)
|
|
140
|
-
process.exit(1)
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
function warn(message) {
|
|
144
|
-
console.warn(`\n⚠ ${message}\n`)
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
/**
|
|
148
|
-
* @param {string} input
|
|
149
|
-
* @param {string | undefined} explicitKind
|
|
150
|
-
*/
|
|
151
|
-
function normalizePackage(input, explicitKind) {
|
|
152
|
-
let raw = input.trim()
|
|
153
|
-
if (raw.startsWith(SCOPE)) raw = raw.slice(SCOPE.length)
|
|
154
|
-
|
|
155
|
-
if (!raw) {
|
|
156
|
-
fail('Package name is required.', `Example: ${commandName} add app-todo`)
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
const kind = explicitKind ?? inferKind(raw)
|
|
160
|
-
|
|
161
|
-
if (explicitKind) {
|
|
162
|
-
const prefixes = {
|
|
163
|
-
app: 'app-',
|
|
164
|
-
theme: 'theme-',
|
|
165
|
-
module: ['module-', 'kit-'],
|
|
166
|
-
}
|
|
167
|
-
const expected = prefixes[explicitKind]
|
|
168
|
-
const list = Array.isArray(expected) ? expected : [expected]
|
|
169
|
-
if (!list.some((p) => raw.startsWith(p))) {
|
|
170
|
-
raw = `${list[0]}${raw}`
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
return { pkgName: `${SCOPE}${raw}`, shortName: raw, kind }
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
function mapLegacyFlags(parsed) {
|
|
178
|
-
const { dev, workspace, fork, repo, branch, from, npm } = parsed
|
|
179
|
-
let mappedFrom = from
|
|
180
|
-
let mappedNpm = npm
|
|
181
|
-
const forceDev = dev || workspace
|
|
182
|
-
|
|
183
|
-
if (fork || repo) {
|
|
184
|
-
warn('`--fork` and `--repo` are deprecated — use `--from` instead.')
|
|
185
|
-
mappedFrom = repo || fork
|
|
186
|
-
}
|
|
187
|
-
if (forceDev && !mappedFrom && !mappedNpm) {
|
|
188
|
-
mappedFrom = 'owdproject'
|
|
189
|
-
}
|
|
190
|
-
if (mappedNpm) mappedFrom = 'npm'
|
|
191
|
-
|
|
192
|
-
return { from: mappedFrom, branch, npm: mappedNpm, dev: forceDev }
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
function parseAddArgs(positionals) {
|
|
196
|
-
const kindNames = Object.keys(KINDS)
|
|
197
|
-
if (positionals.length === 0) {
|
|
198
|
-
fail('Missing package name.', `Example: ${commandName} add app-todo`)
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
if (kindNames.includes(positionals[0])) {
|
|
202
|
-
const kind = positionals[0]
|
|
203
|
-
const name = positionals[1]
|
|
204
|
-
if (!name) {
|
|
205
|
-
fail(`Missing name for kind "${kind}".`, `Example: ${commandName} add ${kind} todo`)
|
|
206
|
-
}
|
|
207
|
-
return normalizePackage(name, kind)
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
return normalizePackage(positionals[0])
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
function parseLegacyInstall(cmd, positionals) {
|
|
214
|
-
const kind = LEGACY_COMMANDS[cmd]
|
|
215
|
-
const raw = positionals[0]
|
|
216
|
-
if (!raw) {
|
|
217
|
-
fail('Missing package name.', `Example: ${commandName} ${cmd} ${SCOPE}app-todo`)
|
|
218
|
-
}
|
|
219
|
-
warn(`\`${cmd}\` is deprecated — use \`${commandName} add …\` instead.`)
|
|
220
|
-
return normalizePackage(raw, kind)
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
/**
|
|
224
|
-
* @param {string} name CLI binary name (`desktop` or deprecated `owd`)
|
|
225
|
-
* @param {string[]} argv Arguments (without node and script path)
|
|
226
|
-
* @param {{ deprecated?: boolean }} [options]
|
|
227
|
-
*/
|
|
228
|
-
export async function runCli(name, argv, options = {}) {
|
|
229
|
-
commandName = name
|
|
230
|
-
|
|
231
|
-
if (options.deprecated) {
|
|
232
|
-
warn('The `owd` command is deprecated. Use `desktop` instead.')
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
const parsed = getopts(argv, {
|
|
236
|
-
alias: { h: 'help', b: 'branch' },
|
|
237
|
-
boolean: ['help', 'npm', 'dry-run', 'dev', 'workspace', 'playground', 'json', 'strict', 'smoke', 'check'],
|
|
238
|
-
string: ['from', 'branch', 'fork', 'repo'],
|
|
239
|
-
})
|
|
240
|
-
|
|
241
|
-
const { _, help, npm: npmFlag } = parsed
|
|
242
|
-
const dryRun = parsed['dry-run'] === true
|
|
243
|
-
const { from, branch, npm: npmFromLegacy, dev: devFlag } = mapLegacyFlags(parsed)
|
|
244
|
-
const useNpm = npmFlag || npmFromLegacy || (!from && !devFlag)
|
|
245
|
-
|
|
246
|
-
if (help || _[0] === 'help') {
|
|
247
|
-
console.log(buildHelp(name))
|
|
248
|
-
process.exit(0)
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
const cmd = _[0]
|
|
252
|
-
|
|
253
|
-
if (cmd === 'init') {
|
|
254
|
-
const projectDir = (_[1] || 'owd-client').trim()
|
|
255
|
-
const cwd = process.cwd()
|
|
256
|
-
|
|
257
|
-
if (findWorkspaceRoot(cwd)) {
|
|
258
|
-
fail(
|
|
259
|
-
'Already inside an OWD workspace.',
|
|
260
|
-
`Use \`${name}\` to manage this project, or run init from a parent directory.`,
|
|
261
|
-
)
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
try {
|
|
265
|
-
await scaffoldProject({ dir: projectDir, cwd, commandName: name })
|
|
266
|
-
} catch (error) {
|
|
267
|
-
fail(error.message ?? String(error))
|
|
268
|
-
}
|
|
269
|
-
return
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
const workspaceRoot = findWorkspaceRoot()
|
|
273
|
-
|
|
274
|
-
if (cmd === 'dev') {
|
|
275
|
-
if (!workspaceRoot) {
|
|
276
|
-
fail(
|
|
277
|
-
'Not inside an OWD workspace.',
|
|
278
|
-
'Run from the client repo, or try: desktop · desktop add <package>',
|
|
279
|
-
)
|
|
280
|
-
}
|
|
281
|
-
const forcePlayground = parsed.playground === true
|
|
282
|
-
const devTarget = resolveDevTarget(process.cwd(), workspaceRoot, { forcePlayground })
|
|
283
|
-
if (forcePlayground && !devTarget) {
|
|
284
|
-
fail(
|
|
285
|
-
'No @owdproject module with playground/desktop.config.ts found from this directory.',
|
|
286
|
-
'Run from an app/theme/module package (e.g. apps/app-about), or omit --playground for the monorepo desktop.',
|
|
287
|
-
)
|
|
288
|
-
}
|
|
289
|
-
runDevForeground(devTarget)
|
|
290
|
-
return
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
if (cmd === 'validate') {
|
|
294
|
-
const { runValidateCli, formatValidationReport } = await import('./lib/validateModule.js')
|
|
295
|
-
const strict = parsed.strict === true
|
|
296
|
-
const json = parsed.json === true
|
|
297
|
-
const smoke = parsed.smoke === true
|
|
298
|
-
const paths = _.slice(1).map(String)
|
|
299
|
-
const { exitCode, results } = runValidateCli(paths, {
|
|
300
|
-
workspaceRoot,
|
|
301
|
-
json,
|
|
302
|
-
strict,
|
|
303
|
-
smoke,
|
|
304
|
-
})
|
|
305
|
-
for (const result of results) {
|
|
306
|
-
console.log(formatValidationReport(result, { json }))
|
|
307
|
-
if (!json) console.log('')
|
|
308
|
-
}
|
|
309
|
-
process.exit(exitCode)
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
if (cmd === 'template') {
|
|
313
|
-
if (!workspaceRoot) {
|
|
314
|
-
fail(
|
|
315
|
-
'Not inside an OWD workspace.',
|
|
316
|
-
`Run from the client monorepo root to regenerate template/.`,
|
|
317
|
-
)
|
|
318
|
-
}
|
|
319
|
-
const { runGenerateTemplateCli } = await import('./lib/generateTemplate.js')
|
|
320
|
-
await runGenerateTemplateCli({
|
|
321
|
-
workspaceRoot,
|
|
322
|
-
dryRun: parsed['dry-run'] === true,
|
|
323
|
-
check: parsed.check === true,
|
|
324
|
-
})
|
|
325
|
-
return
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
if (!cmd) {
|
|
329
|
-
if (!workspaceRoot) {
|
|
330
|
-
fail(
|
|
331
|
-
'Not inside an OWD workspace.',
|
|
332
|
-
'Run from the client repo, or try: desktop · desktop add <package>',
|
|
333
|
-
)
|
|
334
|
-
}
|
|
335
|
-
await openControlPanel(name)
|
|
336
|
-
return
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
if (cmd === 'ui') {
|
|
340
|
-
fail('The `ui` subcommand was removed.', `Use \`${name}\` to open the control panel.`)
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
if (!workspaceRoot) {
|
|
344
|
-
fail(
|
|
345
|
-
'Not inside an OWD workspace.',
|
|
346
|
-
'Run from the client repo (needs pnpm-workspace.yaml + nx.json), or use a generated project with the same layout.',
|
|
347
|
-
)
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
let pkgInfo
|
|
351
|
-
|
|
352
|
-
if (cmd === 'add') {
|
|
353
|
-
pkgInfo = parseAddArgs(_.slice(1))
|
|
354
|
-
} else if (LEGACY_COMMANDS[cmd]) {
|
|
355
|
-
pkgInfo = parseLegacyInstall(cmd, _.slice(1))
|
|
356
|
-
} else {
|
|
357
|
-
fail(`Unknown command: ${cmd}`, `Use \`${name}\`, \`${name} dev\`, or \`${name} add <package>\`.`)
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
const { pkgName, shortName, kind } = pkgInfo
|
|
361
|
-
const inMonorepo = Boolean(workspaceRoot)
|
|
362
|
-
const source = resolveSource(useNpm ? 'npm' : from, shortName, inMonorepo, {
|
|
363
|
-
npm: useNpm,
|
|
364
|
-
dev: devFlag,
|
|
365
|
-
})
|
|
366
|
-
|
|
367
|
-
if (source.mode === 'npm') {
|
|
368
|
-
if (dryRun) {
|
|
369
|
-
printPlan({
|
|
370
|
-
pkgName,
|
|
371
|
-
kind,
|
|
372
|
-
targetDir: '(npm → node_modules)',
|
|
373
|
-
source,
|
|
374
|
-
branch: null,
|
|
375
|
-
dryRun: true,
|
|
376
|
-
})
|
|
377
|
-
process.exit(0)
|
|
378
|
-
}
|
|
379
|
-
runNpmInstall(kind, pkgName, workspaceRoot)
|
|
380
|
-
} else {
|
|
381
|
-
try {
|
|
382
|
-
await runWorkspaceInstall({
|
|
383
|
-
pkgName,
|
|
384
|
-
shortName,
|
|
385
|
-
kind,
|
|
386
|
-
workspaceRoot,
|
|
387
|
-
source,
|
|
388
|
-
branch,
|
|
389
|
-
dryRun,
|
|
390
|
-
})
|
|
391
|
-
} catch (error) {
|
|
392
|
-
fail(error.message ?? String(error))
|
|
393
|
-
}
|
|
394
|
-
}
|
|
395
|
-
}
|