@kywk/open-slide-core 0.0.0-stage → 2.3.1
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/LICENSE +21 -0
- package/README.md +107 -2
- package/bin.js +2 -0
- package/dist/build-CZ6Qtrng.js +19 -0
- package/dist/cli/bin.d.ts +1 -0
- package/dist/cli/bin.js +473 -0
- package/dist/config-B5LArqpp.js +3597 -0
- package/dist/config-CpmGqpQi.d.ts +24 -0
- package/dist/design-CoZ0cWDN.js +45 -0
- package/dist/dev-CCgdakbZ.js +118 -0
- package/dist/index.d.ts +133 -0
- package/dist/index.js +933 -0
- package/dist/locale/index.d.ts +21 -0
- package/dist/locale/index.js +13 -0
- package/dist/preview-AwAqvG17.js +24 -0
- package/dist/types-CvAqFqsY.d.ts +565 -0
- package/dist/update-C_RlnKu4.js +938 -0
- package/dist/vite/index.d.ts +11 -0
- package/dist/vite/index.js +2 -0
- package/dist/zh-tw-B7_Oqv2q.js +2606 -0
- package/env.d.ts +65 -0
- package/package.json +111 -3
- package/skills/apply-comments/SKILL.md +128 -0
- package/skills/create-slide/SKILL.md +103 -0
- package/skills/create-theme/SKILL.md +253 -0
- package/skills/current-slide/SKILL.md +111 -0
- package/skills/slide-authoring/SKILL.md +412 -0
- package/skills/slide-authoring/references/assets.md +72 -0
- package/skills/slide-authoring/references/design-system.md +48 -0
- package/skills/slide-authoring/references/diagrams.md +182 -0
- package/skills/slide-authoring/references/mermaid.md +191 -0
- package/skills/slide-authoring/references/morph.md +67 -0
- package/skills/slide-authoring/references/page-numbers.md +16 -0
- package/skills/slide-authoring/references/steps.md +43 -0
- package/skills/slide-authoring/references/transitions.md +176 -0
- package/skills/slide-authoring/references/webfonts.md +39 -0
- package/src/app/app.tsx +52 -0
- package/src/app/assets/open-slide.svg +39 -0
- package/src/app/components/asset-view.tsx +2120 -0
- package/src/app/components/command/command-menu.tsx +229 -0
- package/src/app/components/command/command.tsx +144 -0
- package/src/app/components/command/home-command-menu.tsx +96 -0
- package/src/app/components/command/slide-command-menu.tsx +181 -0
- package/src/app/components/export-progress-toast.tsx +80 -0
- package/src/app/components/history-provider.tsx +162 -0
- package/src/app/components/icon-switcher-indicator.tsx +10 -0
- package/src/app/components/icon-tooltip.tsx +43 -0
- package/src/app/components/image-placeholder.tsx +235 -0
- package/src/app/components/inline-svg.tsx +190 -0
- package/src/app/components/inspector/arrange-panel.tsx +449 -0
- package/src/app/components/inspector/asset-picker-dialog.tsx +188 -0
- package/src/app/components/inspector/comment-layer.tsx +992 -0
- package/src/app/components/inspector/image-crop-dialog.tsx +215 -0
- package/src/app/components/inspector/inline-text-editor.tsx +684 -0
- package/src/app/components/inspector/inspect-overlay.tsx +647 -0
- package/src/app/components/inspector/inspector-panel.tsx +1022 -0
- package/src/app/components/inspector/inspector-provider.tsx +1690 -0
- package/src/app/components/inspector/save-bar.tsx +84 -0
- package/src/app/components/language-toggle.tsx +45 -0
- package/src/app/components/mermaid.tsx +436 -0
- package/src/app/components/morph-element.tsx +43 -0
- package/src/app/components/note-markdown.test.tsx +42 -0
- package/src/app/components/note-markdown.tsx +85 -0
- package/src/app/components/notes-drawer.tsx +117 -0
- package/src/app/components/overview-grid.tsx +372 -0
- package/src/app/components/panel/editor-sidebar.tsx +50 -0
- package/src/app/components/panel/panel-fields.tsx +248 -0
- package/src/app/components/panel/panel-shell.tsx +63 -0
- package/src/app/components/panel/save-card.tsx +155 -0
- package/src/app/components/player.tsx +471 -0
- package/src/app/components/present/blackout-overlay.tsx +31 -0
- package/src/app/components/present/control-bar.tsx +326 -0
- package/src/app/components/present/help-overlay.tsx +57 -0
- package/src/app/components/present/jump-input.tsx +96 -0
- package/src/app/components/present/laser-pointer.tsx +62 -0
- package/src/app/components/present/progress-bar.tsx +26 -0
- package/src/app/components/present/use-idle.ts +46 -0
- package/src/app/components/present/use-pointer-near-bottom.ts +34 -0
- package/src/app/components/present/use-presenter-channel.ts +66 -0
- package/src/app/components/present/use-touch-swipe.ts +73 -0
- package/src/app/components/preview-step-host.tsx +16 -0
- package/src/app/components/sidebar/folder-item.tsx +296 -0
- package/src/app/components/sidebar/icon-picker.tsx +61 -0
- package/src/app/components/sidebar/sidebar-footer.tsx +152 -0
- package/src/app/components/sidebar/sidebar.tsx +329 -0
- package/src/app/components/slide-canvas.tsx +98 -0
- package/src/app/components/slide-preload-layer.tsx +185 -0
- package/src/app/components/slide-transition-layer.tsx +827 -0
- package/src/app/components/style-panel/design-provider.tsx +135 -0
- package/src/app/components/style-panel/style-panel.tsx +293 -0
- package/src/app/components/style-panel/use-design.ts +85 -0
- package/src/app/components/theme-toggle.tsx +65 -0
- package/src/app/components/themes/theme-detail.tsx +308 -0
- package/src/app/components/themes/themes-gallery.tsx +154 -0
- package/src/app/components/thumbnail-rail-scroll.test.ts +60 -0
- package/src/app/components/thumbnail-rail-scroll.ts +33 -0
- package/src/app/components/thumbnail-rail.tsx +1048 -0
- package/src/app/components/ui/badge.tsx +48 -0
- package/src/app/components/ui/button.tsx +93 -0
- package/src/app/components/ui/card.tsx +92 -0
- package/src/app/components/ui/context-menu.tsx +247 -0
- package/src/app/components/ui/dialog.tsx +155 -0
- package/src/app/components/ui/dropdown-menu.tsx +267 -0
- package/src/app/components/ui/input.tsx +25 -0
- package/src/app/components/ui/label.tsx +21 -0
- package/src/app/components/ui/popover.tsx +82 -0
- package/src/app/components/ui/progress.tsx +33 -0
- package/src/app/components/ui/scroll-area.tsx +53 -0
- package/src/app/components/ui/select.tsx +195 -0
- package/src/app/components/ui/separator.tsx +26 -0
- package/src/app/components/ui/slider.tsx +68 -0
- package/src/app/components/ui/sonner.tsx +48 -0
- package/src/app/components/ui/tabs.tsx +79 -0
- package/src/app/components/ui/textarea.tsx +22 -0
- package/src/app/components/ui/toggle-group.tsx +84 -0
- package/src/app/components/ui/toggle.tsx +45 -0
- package/src/app/components/ui/tooltip.tsx +75 -0
- package/src/app/favicon.ico +0 -0
- package/src/app/favicon.svg +39 -0
- package/src/app/index.html +35 -0
- package/src/app/lib/asset-filter.test.ts +176 -0
- package/src/app/lib/asset-filter.ts +80 -0
- package/src/app/lib/assets.ts +289 -0
- package/src/app/lib/design-presets.ts +94 -0
- package/src/app/lib/design.ts +69 -0
- package/src/app/lib/dom.ts +42 -0
- package/src/app/lib/export-html.ts +367 -0
- package/src/app/lib/export-pdf.ts +281 -0
- package/src/app/lib/export-pptx.ts +183 -0
- package/src/app/lib/folders.ts +244 -0
- package/src/app/lib/inspector/fiber.test.ts +154 -0
- package/src/app/lib/inspector/fiber.ts +85 -0
- package/src/app/lib/inspector/freeze-motion.ts +61 -0
- package/src/app/lib/inspector/geometry.test.ts +324 -0
- package/src/app/lib/inspector/geometry.ts +207 -0
- package/src/app/lib/inspector/inline-text.ts +31 -0
- package/src/app/lib/inspector/pick-target.ts +38 -0
- package/src/app/lib/inspector/text-edit-timeline.test.ts +121 -0
- package/src/app/lib/inspector/text-edit-timeline.ts +12 -0
- package/src/app/lib/inspector/text-selection.ts +117 -0
- package/src/app/lib/inspector/use-comments.ts +103 -0
- package/src/app/lib/inspector/use-editor.ts +73 -0
- package/src/app/lib/inspector/use-notes.ts +134 -0
- package/src/app/lib/inspector/use-visual-editor.ts +429 -0
- package/src/app/lib/inspector/visual-dom.ts +255 -0
- package/src/app/lib/keys.ts +30 -0
- package/src/app/lib/last-home-location.ts +18 -0
- package/src/app/lib/locale-store.ts +72 -0
- package/src/app/lib/note-markdown.test.ts +147 -0
- package/src/app/lib/note-markdown.ts +116 -0
- package/src/app/lib/page-context.tsx +38 -0
- package/src/app/lib/pptx/color.ts +49 -0
- package/src/app/lib/pptx/css.test.ts +205 -0
- package/src/app/lib/pptx/css.ts +462 -0
- package/src/app/lib/pptx/fonts.ts +145 -0
- package/src/app/lib/pptx/images.ts +116 -0
- package/src/app/lib/pptx/measure.ts +1281 -0
- package/src/app/lib/pptx/ooxml.test.ts +199 -0
- package/src/app/lib/pptx/ooxml.ts +470 -0
- package/src/app/lib/pptx/raster.ts +189 -0
- package/src/app/lib/pptx/render.ts +102 -0
- package/src/app/lib/pptx/scene.ts +116 -0
- package/src/app/lib/pptx/text-lines.test.ts +82 -0
- package/src/app/lib/pptx/text-lines.ts +109 -0
- package/src/app/lib/pptx/units.ts +22 -0
- package/src/app/lib/print-ready.test.ts +55 -0
- package/src/app/lib/print-ready.ts +52 -0
- package/src/app/lib/sdk.test.ts +13 -0
- package/src/app/lib/sdk.ts +37 -0
- package/src/app/lib/slides.ts +29 -0
- package/src/app/lib/step-context.tsx +269 -0
- package/src/app/lib/text-diff.ts +19 -0
- package/src/app/lib/themes.ts +22 -0
- package/src/app/lib/transition.test.ts +31 -0
- package/src/app/lib/transition.ts +43 -0
- package/src/app/lib/use-agent-socket.ts +18 -0
- package/src/app/lib/use-click-page-navigation.ts +56 -0
- package/src/app/lib/use-document-title.test.ts +14 -0
- package/src/app/lib/use-document-title.ts +16 -0
- package/src/app/lib/use-is-mobile.ts +9 -0
- package/src/app/lib/use-locale.ts +8 -0
- package/src/app/lib/use-media-query.ts +20 -0
- package/src/app/lib/use-prefers-reduced-motion.ts +11 -0
- package/src/app/lib/use-restart-server.ts +78 -0
- package/src/app/lib/use-slide-module.ts +48 -0
- package/src/app/lib/use-slide-titles.ts +29 -0
- package/src/app/lib/use-wheel-page-navigation.ts +99 -0
- package/src/app/lib/utils.test.ts +49 -0
- package/src/app/lib/utils.ts +14 -0
- package/src/app/main.tsx +14 -0
- package/src/app/routes/assets.tsx +9 -0
- package/src/app/routes/home-shell.tsx +261 -0
- package/src/app/routes/home.tsx +856 -0
- package/src/app/routes/presenter.tsx +692 -0
- package/src/app/routes/preview.tsx +169 -0
- package/src/app/routes/slide.tsx +1311 -0
- package/src/app/routes/themes.tsx +33 -0
- package/src/app/styles.css +385 -0
- package/src/app/virtual.d.ts +51 -0
- package/src/locale/en.ts +543 -0
- package/src/locale/es.ts +550 -0
- package/src/locale/format.ts +12 -0
- package/src/locale/index.ts +7 -0
- package/src/locale/ja.ts +550 -0
- package/src/locale/types.ts +578 -0
- package/src/locale/zh-cn.ts +540 -0
- package/src/locale/zh-tw.ts +540 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Yiwei Ho
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,108 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @kywk/open-slide-core
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Runtime and CLI for [open-slide](https://github.com/open-slide/open-slide) — a React-based slide framework where you write slides and the framework handles the Vite/React stack, layout, navigation, hot reload, and fullscreen play mode.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pnpm add @kywk/open-slide-core
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Most users get this installed automatically by running `npx @kywk/open-slide-cli init`. Use this package directly only if you're wiring up an existing workspace by hand.
|
|
12
|
+
|
|
13
|
+
## What's inside
|
|
14
|
+
|
|
15
|
+
- **Runtime** — home page, slide viewer, thumbnail rail, keyboard navigation, and fullscreen presenter mode. Every slide renders into a fixed **1920×1080** canvas; the framework scales it.
|
|
16
|
+
- **Vite plugin** — discovers `slides/<id>/index.{tsx,jsx,ts,js}`, exposes them via virtual modules, and reloads when slides are added or removed.
|
|
17
|
+
- **CLI** — `open-slide dev | build | preview` so workspaces never need to touch Vite, React, or tsconfig directly.
|
|
18
|
+
|
|
19
|
+
## CLI
|
|
20
|
+
|
|
21
|
+
Once installed, the `open-slide` bin is available in the workspace:
|
|
22
|
+
|
|
23
|
+
| Command | Description |
|
|
24
|
+
| --- | --- |
|
|
25
|
+
| `open-slide dev` | Start the dev server. Flags: `-p, --port <port>`, `--host [host]`, `--open`. |
|
|
26
|
+
| `open-slide build` | Build a static site. Flags: `--out-dir <dir>` (defaults to `dist`). |
|
|
27
|
+
| `open-slide preview` | Preview the production build. Flags: `-p, --port <port>`, `--host [host]`, `--open`. |
|
|
28
|
+
|
|
29
|
+
## Config
|
|
30
|
+
|
|
31
|
+
Create `open-slide.config.ts` in the workspace root (all fields optional):
|
|
32
|
+
|
|
33
|
+
```ts
|
|
34
|
+
import type { OpenSlideConfig } from '@kywk/open-slide-core';
|
|
35
|
+
|
|
36
|
+
const openSlideConfig: OpenSlideConfig = {
|
|
37
|
+
slidesDir: 'slides',
|
|
38
|
+
port: 5173,
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export default openSlideConfig;
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Hosting under a subpath
|
|
45
|
+
|
|
46
|
+
Set `base` to deploy the built site under a sub-directory (intranet folders, GitHub Pages project sites, reverse proxies). Use a leading and trailing slash:
|
|
47
|
+
|
|
48
|
+
```ts
|
|
49
|
+
const openSlideConfig: OpenSlideConfig = {
|
|
50
|
+
base: '/my-slides/',
|
|
51
|
+
};
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
The value is passed straight to Vite's `base` and to React Router's `basename`, so client-side navigation matches the deployed path.
|
|
55
|
+
|
|
56
|
+
## Authoring slides
|
|
57
|
+
|
|
58
|
+
Slides live under `slides/<kebab-case-id>/index.tsx` and default-export an array of `Page` components:
|
|
59
|
+
|
|
60
|
+
```tsx
|
|
61
|
+
import type { Page } from '@kywk/open-slide-core';
|
|
62
|
+
|
|
63
|
+
const Cover: Page = () => (
|
|
64
|
+
<div className="flex h-full w-full items-center justify-center">
|
|
65
|
+
<h1 className="text-[120px] font-bold">Hello, open-slide</h1>
|
|
66
|
+
</div>
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
const pages: Page[] = [Cover];
|
|
70
|
+
export default pages;
|
|
71
|
+
|
|
72
|
+
export const meta = { title: 'Hello' };
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Exports
|
|
76
|
+
|
|
77
|
+
```ts
|
|
78
|
+
import {
|
|
79
|
+
CANVAS_WIDTH, // 1920
|
|
80
|
+
CANVAS_HEIGHT, // 1080
|
|
81
|
+
Mermaid, // render flow, sequence, state, and other Mermaid diagrams
|
|
82
|
+
MorphElement, // match or fade objects across pages for morph transitions
|
|
83
|
+
type Page,
|
|
84
|
+
type SlideMeta,
|
|
85
|
+
type SlideModule,
|
|
86
|
+
type SlideTransition,
|
|
87
|
+
type OpenSlideConfig,
|
|
88
|
+
} from '@kywk/open-slide-core';
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Render relational or sequential information directly in a TSX page:
|
|
92
|
+
|
|
93
|
+
```tsx
|
|
94
|
+
<Mermaid chart={`flowchart LR
|
|
95
|
+
Source --> Transform --> Result`} style={{ width: 1200, height: 650 }} />
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Lightbox is enabled by default — click any diagram to expand it near-fullscreen. Pass `lightbox={false}` to disable.
|
|
99
|
+
|
|
100
|
+
The Vite plugin is exposed under a subpath for advanced setups:
|
|
101
|
+
|
|
102
|
+
```ts
|
|
103
|
+
import { createViteConfig } from '@kywk/open-slide-core/vite';
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## License
|
|
107
|
+
|
|
108
|
+
MIT
|
package/bin.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { r as printHeader, t as createCliLogger } from "./cli/bin.js";
|
|
2
|
+
import { t as createViteConfig } from "./config-B5LArqpp.js";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { build as build$1, mergeConfig } from "vite";
|
|
5
|
+
//#region src/cli/build.ts
|
|
6
|
+
async function build(opts = {}) {
|
|
7
|
+
printHeader("building for production");
|
|
8
|
+
const base = await createViteConfig({
|
|
9
|
+
userCwd: process.cwd(),
|
|
10
|
+
mode: "build"
|
|
11
|
+
});
|
|
12
|
+
const config = mergeConfig(base, {
|
|
13
|
+
customLogger: createCliLogger(),
|
|
14
|
+
build: { ...opts.outDir !== void 0 ? { outDir: path.resolve(process.cwd(), opts.outDir) } : {} }
|
|
15
|
+
});
|
|
16
|
+
await build$1(config);
|
|
17
|
+
}
|
|
18
|
+
//#endregion
|
|
19
|
+
export { build };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {}
|
package/dist/cli/bin.js
ADDED
|
@@ -0,0 +1,473 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { A as ownPackage, j as ownPackageName, t as detectPackageManager } from "../update-C_RlnKu4.js";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import * as readline from "node:readline/promises";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
import chalk from "chalk";
|
|
7
|
+
import { Command, Option } from "commander";
|
|
8
|
+
import { existsSync, readFileSync, realpathSync } from "node:fs";
|
|
9
|
+
import { cp, lstat, mkdir, readFile, readdir, readlink, rm, symlink } from "node:fs/promises";
|
|
10
|
+
import { createHash } from "node:crypto";
|
|
11
|
+
import * as readline$1 from "node:readline";
|
|
12
|
+
import { stripVTControlCharacters } from "node:util";
|
|
13
|
+
//#region src/cli/preflight.ts
|
|
14
|
+
const MIGRATION_URL = "https://open-slide.dev/docs/migrate-to-v2";
|
|
15
|
+
const VITE_CONSUMERS = ["@vitejs/plugin-react", "@tailwindcss/vite"];
|
|
16
|
+
const DEPENDENCY_FIELDS = [
|
|
17
|
+
"dependencies",
|
|
18
|
+
"devDependencies",
|
|
19
|
+
"optionalDependencies",
|
|
20
|
+
"peerDependencies"
|
|
21
|
+
];
|
|
22
|
+
const PROJECT_ROOT_MARKERS = [
|
|
23
|
+
"pnpm-workspace.yaml",
|
|
24
|
+
"pnpm-lock.yaml",
|
|
25
|
+
"yarn.lock",
|
|
26
|
+
"bun.lock",
|
|
27
|
+
"bun.lockb",
|
|
28
|
+
"package-lock.json",
|
|
29
|
+
".git"
|
|
30
|
+
];
|
|
31
|
+
function locatePackage(name, fromDir) {
|
|
32
|
+
let dir = fromDir;
|
|
33
|
+
while (true) {
|
|
34
|
+
const candidate = path.join(dir, "node_modules", name);
|
|
35
|
+
const pkgPath = path.join(candidate, "package.json");
|
|
36
|
+
if (existsSync(pkgPath)) {
|
|
37
|
+
let version = "unknown";
|
|
38
|
+
try {
|
|
39
|
+
version = JSON.parse(readFileSync(pkgPath, "utf8")).version ?? version;
|
|
40
|
+
} catch {}
|
|
41
|
+
return {
|
|
42
|
+
dir: realpathSync(candidate),
|
|
43
|
+
root: dir,
|
|
44
|
+
version
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
const parent = path.dirname(dir);
|
|
48
|
+
if (parent === dir) return null;
|
|
49
|
+
dir = parent;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
function findViteMismatch(coreDir) {
|
|
53
|
+
const coreVite = locatePackage("vite", coreDir);
|
|
54
|
+
if (!coreVite) return null;
|
|
55
|
+
for (const consumer of VITE_CONSUMERS) {
|
|
56
|
+
const consumerPkg = locatePackage(consumer, coreDir);
|
|
57
|
+
if (!consumerPkg) continue;
|
|
58
|
+
const consumerVite = locatePackage("vite", consumerPkg.dir);
|
|
59
|
+
if (!consumerVite || consumerVite.version === coreVite.version) continue;
|
|
60
|
+
return {
|
|
61
|
+
consumer,
|
|
62
|
+
coreVite,
|
|
63
|
+
consumerVite
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
function declarationIn(dir) {
|
|
69
|
+
const file = path.join(dir, "package.json");
|
|
70
|
+
if (!existsSync(file)) return null;
|
|
71
|
+
try {
|
|
72
|
+
const pkg = JSON.parse(readFileSync(file, "utf8"));
|
|
73
|
+
for (const field of DEPENDENCY_FIELDS) {
|
|
74
|
+
const deps = pkg[field];
|
|
75
|
+
if (deps && Object.hasOwn(deps, "vite")) return {
|
|
76
|
+
file,
|
|
77
|
+
field
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
} catch {}
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
function isProjectRoot(dir) {
|
|
84
|
+
return PROJECT_ROOT_MARKERS.some((marker) => existsSync(path.join(dir, marker)));
|
|
85
|
+
}
|
|
86
|
+
function isAncestorOrSelf(ancestor, dir) {
|
|
87
|
+
const rel = path.relative(ancestor, dir);
|
|
88
|
+
return !rel.startsWith("..") && !path.isAbsolute(rel);
|
|
89
|
+
}
|
|
90
|
+
function findViteDeclaration(cwd, installRoot) {
|
|
91
|
+
if (installRoot && (isAncestorOrSelf(installRoot, cwd) || isAncestorOrSelf(cwd, installRoot))) {
|
|
92
|
+
const owner = declarationIn(installRoot);
|
|
93
|
+
if (owner) return owner;
|
|
94
|
+
}
|
|
95
|
+
const stopAt = installRoot && isAncestorOrSelf(installRoot, cwd) ? installRoot : null;
|
|
96
|
+
let dir = cwd;
|
|
97
|
+
while (dir !== stopAt) {
|
|
98
|
+
const found = declarationIn(dir);
|
|
99
|
+
if (found) return found;
|
|
100
|
+
const parent = path.dirname(dir);
|
|
101
|
+
if (parent === dir || !stopAt && isProjectRoot(dir)) return null;
|
|
102
|
+
dir = parent;
|
|
103
|
+
}
|
|
104
|
+
return null;
|
|
105
|
+
}
|
|
106
|
+
function removeCommand(pm) {
|
|
107
|
+
return pm === "npm" ? "npm uninstall vite" : `${pm} remove vite`;
|
|
108
|
+
}
|
|
109
|
+
function formatViteMismatch(mismatch, { cwd = process.cwd(), packageManager = "npm", declaration = null } = {}) {
|
|
110
|
+
const rel = (p) => path.relative(cwd, p) || p;
|
|
111
|
+
const want = chalk.bold(`vite@${mismatch.coreVite.version}`);
|
|
112
|
+
const got = chalk.bold(`vite@${mismatch.consumerVite.version}`);
|
|
113
|
+
const from = chalk.dim(rel(mismatch.consumerVite.dir));
|
|
114
|
+
const command = (cmd) => [
|
|
115
|
+
"",
|
|
116
|
+
` ${chalk.dim("$")} ${chalk.cyan(cmd)}`,
|
|
117
|
+
""
|
|
118
|
+
];
|
|
119
|
+
const footer = `${chalk.dim("Migration guide")} ${chalk.cyan.underline(MIGRATION_URL)}`;
|
|
120
|
+
if (!declaration) return [
|
|
121
|
+
chalk.bold("Conflicting vite versions in node_modules"),
|
|
122
|
+
"",
|
|
123
|
+
`open-slide ships ${want}, but ${mismatch.consumer} is loading ${got}`,
|
|
124
|
+
`from ${from}. Make sure no package.json lists vite, then reinstall:`,
|
|
125
|
+
...command(`${packageManager} install`),
|
|
126
|
+
footer
|
|
127
|
+
].join("\n");
|
|
128
|
+
const dir = path.dirname(declaration.file);
|
|
129
|
+
const cd = path.resolve(dir) === path.resolve(cwd) ? "" : `cd ${rel(dir)} && `;
|
|
130
|
+
return [
|
|
131
|
+
chalk.bold(`Remove ${chalk.yellow("vite")} from your package.json`),
|
|
132
|
+
"",
|
|
133
|
+
`${chalk.bold(declaration.field)} in ${chalk.dim(rel(declaration.file))} still lists vite, a leftover from v1.`,
|
|
134
|
+
`It shadows the ${want} bundled with open-slide: ${mismatch.consumer}`,
|
|
135
|
+
`is loading ${got} from ${from} instead.`,
|
|
136
|
+
...command(cd + removeCommand(packageManager)),
|
|
137
|
+
footer
|
|
138
|
+
].join("\n");
|
|
139
|
+
}
|
|
140
|
+
async function assertViteResolvesToCore(cwd = process.cwd()) {
|
|
141
|
+
const mismatch = findViteMismatch(realpathSync(path.dirname(fileURLToPath(import.meta.url))));
|
|
142
|
+
if (!mismatch) return;
|
|
143
|
+
const declaration = findViteDeclaration(cwd, mismatch.consumerVite.root);
|
|
144
|
+
const packageManager = await detectPackageManager(declaration ? path.dirname(declaration.file) : cwd);
|
|
145
|
+
throw new Error(formatViteMismatch(mismatch, {
|
|
146
|
+
cwd,
|
|
147
|
+
packageManager,
|
|
148
|
+
declaration
|
|
149
|
+
}));
|
|
150
|
+
}
|
|
151
|
+
//#endregion
|
|
152
|
+
//#region src/cli/sync.ts
|
|
153
|
+
async function detectSkillsDrift(skillsDir) {
|
|
154
|
+
if (!existsSync(skillsDir)) return [];
|
|
155
|
+
const cwd = process.cwd();
|
|
156
|
+
const agentsSkillsDir = path.join(cwd, ".agents", "skills");
|
|
157
|
+
const skillNames = (await readdir(skillsDir, { withFileTypes: true })).filter((e) => e.isDirectory()).map((e) => e.name).sort();
|
|
158
|
+
const results = [];
|
|
159
|
+
for (const name of skillNames) {
|
|
160
|
+
const src = path.join(skillsDir, name);
|
|
161
|
+
const dst = path.join(agentsSkillsDir, name);
|
|
162
|
+
const srcHash = await hashDir(src);
|
|
163
|
+
const dstHash = existsSync(dst) ? await hashDir(dst) : null;
|
|
164
|
+
let status;
|
|
165
|
+
if (dstHash === null) status = "added";
|
|
166
|
+
else if (dstHash !== srcHash) status = "updated";
|
|
167
|
+
else status = "unchanged";
|
|
168
|
+
results.push({
|
|
169
|
+
name,
|
|
170
|
+
status
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
return results;
|
|
174
|
+
}
|
|
175
|
+
async function syncSkills(skillsDir, opts = {}) {
|
|
176
|
+
const { dryRun = false } = opts;
|
|
177
|
+
if (!existsSync(skillsDir)) throw new Error(`Built-in skills directory missing at ${skillsDir}. The ${ownPackageName()} package may be corrupt — try reinstalling.`);
|
|
178
|
+
const cwd = process.cwd();
|
|
179
|
+
const agentsSkillsDir = path.join(cwd, ".agents", "skills");
|
|
180
|
+
const claudeSkillsDir = path.join(cwd, ".claude", "skills");
|
|
181
|
+
const results = await detectSkillsDrift(skillsDir);
|
|
182
|
+
if (results.length === 0) {
|
|
183
|
+
process.stdout.write(chalk.yellow("No skills found to sync.\n"));
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
for (const { name, status } of results) {
|
|
187
|
+
const src = path.join(skillsDir, name);
|
|
188
|
+
const dst = path.join(agentsSkillsDir, name);
|
|
189
|
+
if (dryRun) continue;
|
|
190
|
+
if (status === "unchanged") {
|
|
191
|
+
await ensureClaudeSymlink(claudeSkillsDir, name);
|
|
192
|
+
continue;
|
|
193
|
+
}
|
|
194
|
+
await mkdir(path.dirname(dst), { recursive: true });
|
|
195
|
+
if (existsSync(dst)) await rm(dst, {
|
|
196
|
+
recursive: true,
|
|
197
|
+
force: true
|
|
198
|
+
});
|
|
199
|
+
await cp(src, dst, { recursive: true });
|
|
200
|
+
await ensureClaudeSymlink(claudeSkillsDir, name);
|
|
201
|
+
}
|
|
202
|
+
printSummary(results, dryRun);
|
|
203
|
+
}
|
|
204
|
+
async function ensureClaudeSymlink(claudeSkillsDir, name) {
|
|
205
|
+
await mkdir(claudeSkillsDir, { recursive: true });
|
|
206
|
+
const linkPath = path.join(claudeSkillsDir, name);
|
|
207
|
+
const target = path.join("..", "..", ".agents", "skills", name);
|
|
208
|
+
if (existsSync(linkPath)) try {
|
|
209
|
+
if ((await lstat(linkPath)).isSymbolicLink()) {
|
|
210
|
+
if (await readlink(linkPath) === target) return;
|
|
211
|
+
}
|
|
212
|
+
await rm(linkPath, {
|
|
213
|
+
recursive: true,
|
|
214
|
+
force: true
|
|
215
|
+
});
|
|
216
|
+
} catch {
|
|
217
|
+
await rm(linkPath, {
|
|
218
|
+
recursive: true,
|
|
219
|
+
force: true
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
try {
|
|
223
|
+
await symlink(target, linkPath, "dir");
|
|
224
|
+
} catch (err) {
|
|
225
|
+
const code = err.code;
|
|
226
|
+
if (code === "EPERM" || code === "EEXIST") {
|
|
227
|
+
const absoluteTarget = path.resolve(claudeSkillsDir, target);
|
|
228
|
+
await cp(absoluteTarget, linkPath, { recursive: true });
|
|
229
|
+
} else throw err;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
async function hashDir(dir) {
|
|
233
|
+
const hash = createHash("sha256");
|
|
234
|
+
const files = await collectFiles(dir);
|
|
235
|
+
files.sort();
|
|
236
|
+
for (const rel of files) {
|
|
237
|
+
const abs = path.join(dir, rel);
|
|
238
|
+
const data = await readFile(abs);
|
|
239
|
+
hash.update(rel);
|
|
240
|
+
hash.update("\0");
|
|
241
|
+
hash.update(data);
|
|
242
|
+
hash.update("\0");
|
|
243
|
+
}
|
|
244
|
+
return hash.digest("hex");
|
|
245
|
+
}
|
|
246
|
+
async function collectFiles(dir, prefix = "") {
|
|
247
|
+
const out = [];
|
|
248
|
+
const entries = await readdir(dir, { withFileTypes: true });
|
|
249
|
+
for (const entry of entries) {
|
|
250
|
+
const rel = prefix ? path.join(prefix, entry.name) : entry.name;
|
|
251
|
+
if (entry.isDirectory()) out.push(...await collectFiles(path.join(dir, entry.name), rel));
|
|
252
|
+
else if (entry.isFile()) out.push(rel);
|
|
253
|
+
}
|
|
254
|
+
return out;
|
|
255
|
+
}
|
|
256
|
+
function printSummary(results, dryRun) {
|
|
257
|
+
const symbols = {
|
|
258
|
+
added: chalk.green("+"),
|
|
259
|
+
updated: chalk.yellow("~"),
|
|
260
|
+
unchanged: chalk.dim("=")
|
|
261
|
+
};
|
|
262
|
+
const labels = {
|
|
263
|
+
added: chalk.green("added"),
|
|
264
|
+
updated: chalk.yellow("updated"),
|
|
265
|
+
unchanged: chalk.dim("unchanged")
|
|
266
|
+
};
|
|
267
|
+
const header = dryRun ? chalk.bold("Dry run — no files written:") : chalk.bold("Synced built-in skills:");
|
|
268
|
+
process.stdout.write(`${header}\n`);
|
|
269
|
+
for (const { name, status } of results) process.stdout.write(` ${symbols[status]} ${name} ${chalk.dim(`(${labels[status]})`)}\n`);
|
|
270
|
+
const counts = results.reduce((acc, { status }) => {
|
|
271
|
+
acc[status] += 1;
|
|
272
|
+
return acc;
|
|
273
|
+
}, {
|
|
274
|
+
added: 0,
|
|
275
|
+
updated: 0,
|
|
276
|
+
unchanged: 0
|
|
277
|
+
});
|
|
278
|
+
process.stdout.write(chalk.dim(`\n${counts.added} added, ${counts.updated} updated, ${counts.unchanged} unchanged.\n`));
|
|
279
|
+
}
|
|
280
|
+
//#endregion
|
|
281
|
+
//#region src/cli/ui.ts
|
|
282
|
+
const UNICODE = process.platform !== "win32" || Boolean(process.env.WT_SESSION) || process.env.TERM_PROGRAM === "vscode";
|
|
283
|
+
const glyph = {
|
|
284
|
+
bar: UNICODE ? "┃" : "|",
|
|
285
|
+
warn: UNICODE ? "▲" : "!",
|
|
286
|
+
cross: UNICODE ? "✖" : "x"
|
|
287
|
+
};
|
|
288
|
+
function readVersion() {
|
|
289
|
+
return ownPackage().version;
|
|
290
|
+
}
|
|
291
|
+
function brand() {
|
|
292
|
+
return chalk.inverse.bold(" open-slide ");
|
|
293
|
+
}
|
|
294
|
+
function printHeader(status) {
|
|
295
|
+
const parts = [brand(), chalk.dim(`v${readVersion()}`)];
|
|
296
|
+
if (status) parts.push(chalk.dim(status));
|
|
297
|
+
process.stdout.write(`\n ${parts.join(" ")}\n\n`);
|
|
298
|
+
}
|
|
299
|
+
function startupDuration() {
|
|
300
|
+
return `ready in ${Math.round(process.uptime() * 1e3)} ms`;
|
|
301
|
+
}
|
|
302
|
+
function printUrls(urls, host) {
|
|
303
|
+
if (!urls) return;
|
|
304
|
+
const rows = [];
|
|
305
|
+
for (const url of urls.local) rows.push(urlRow("Local", chalk.cyan(url)));
|
|
306
|
+
urls.network.forEach((url, index) => {
|
|
307
|
+
const iface = urls.networkInterfaceNames?.[index];
|
|
308
|
+
rows.push(urlRow("Network", chalk.cyan(url) + (iface ? ` ${chalk.dim(iface)}` : "")));
|
|
309
|
+
});
|
|
310
|
+
if (urls.network.length === 0 && host === void 0) rows.push(urlRow("Network", chalk.dim("use --host to expose")));
|
|
311
|
+
process.stdout.write(`${rows.join("\n")}\n`);
|
|
312
|
+
}
|
|
313
|
+
function urlRow(label, value) {
|
|
314
|
+
return ` ${chalk.dim(glyph.bar)} ${chalk.bold(label.padEnd(8))} ${value}`;
|
|
315
|
+
}
|
|
316
|
+
function shortcutsEnabled() {
|
|
317
|
+
return Boolean(process.stdin.isTTY) && !process.env.CI;
|
|
318
|
+
}
|
|
319
|
+
function printShortcutsHint() {
|
|
320
|
+
process.stdout.write(`\n ${chalk.dim("press")} ${chalk.bold("h + enter")} ${chalk.dim("for shortcuts")}\n`);
|
|
321
|
+
}
|
|
322
|
+
function formatError(message) {
|
|
323
|
+
const [first, ...rest] = message.split("\n");
|
|
324
|
+
const body = rest.map((line) => line ? `\n ${line}` : "\n").join("");
|
|
325
|
+
return `\n ${chalk.red(glyph.cross)} ${first}${body}\n\n`;
|
|
326
|
+
}
|
|
327
|
+
const DROPPED = [/^vite v\d+\.\d+\.\d+ building /];
|
|
328
|
+
const REWRITES = [
|
|
329
|
+
[/hmr update /, "updated "],
|
|
330
|
+
[/hmr invalidate /, "invalidated "],
|
|
331
|
+
[/trigger page reload /, "full reload "],
|
|
332
|
+
[/page reload/, "full reload"],
|
|
333
|
+
[/server restarted\./, "server restarted"],
|
|
334
|
+
[/optimized dependencies changed\. reloading/, "dependencies changed, reloading"],
|
|
335
|
+
[/Re-optimizing dependencies because vite config has changed/, "config changed, re-bundling"],
|
|
336
|
+
[/Re-optimizing dependencies because lockfile has changed/, "lockfile changed, re-bundling"],
|
|
337
|
+
[/Forced re-optimization of dependencies/, "re-bundling dependencies"],
|
|
338
|
+
[/\[plugin builtin:vite-[a-z-]+\] ?\n?/, ""],
|
|
339
|
+
[/\[vite\] ?/g, ""]
|
|
340
|
+
];
|
|
341
|
+
function rewriteViteMessage(msg) {
|
|
342
|
+
const plain = stripVTControlCharacters(msg);
|
|
343
|
+
if (DROPPED.some((re) => re.test(plain))) return null;
|
|
344
|
+
let out = msg;
|
|
345
|
+
for (const [re, replacement] of REWRITES) out = out.replace(re, replacement);
|
|
346
|
+
return out;
|
|
347
|
+
}
|
|
348
|
+
function timestamp() {
|
|
349
|
+
return (/* @__PURE__ */ new Date()).toLocaleTimeString([], { hourCycle: "h23" });
|
|
350
|
+
}
|
|
351
|
+
function formatLine(type, text, opts) {
|
|
352
|
+
if (!opts?.timestamp) return text;
|
|
353
|
+
const mark = type === "warn" ? `${chalk.yellow(glyph.warn)} ` : type === "error" ? `${chalk.red(glyph.cross)} ` : "";
|
|
354
|
+
return ` ${chalk.dim(timestamp())} ${mark}${text}`;
|
|
355
|
+
}
|
|
356
|
+
function clearTerminal() {
|
|
357
|
+
if (!process.stdout.isTTY || process.env.CI) return;
|
|
358
|
+
const blank = "\n".repeat(Math.max(process.stdout.rows - 2, 0));
|
|
359
|
+
console.log(blank);
|
|
360
|
+
readline$1.cursorTo(process.stdout, 0, 0);
|
|
361
|
+
readline$1.clearScreenDown(process.stdout);
|
|
362
|
+
}
|
|
363
|
+
function createCliLogger() {
|
|
364
|
+
const loggedErrors = /* @__PURE__ */ new WeakSet();
|
|
365
|
+
const warnedOnce = /* @__PURE__ */ new Set();
|
|
366
|
+
const write = (type, msg, opts) => {
|
|
367
|
+
const text = rewriteViteMessage(msg);
|
|
368
|
+
if (text === null) return;
|
|
369
|
+
console[type === "info" ? "log" : type](formatLine(type, text, opts));
|
|
370
|
+
};
|
|
371
|
+
const logger = {
|
|
372
|
+
hasWarned: false,
|
|
373
|
+
info(msg, opts) {
|
|
374
|
+
write("info", msg, opts);
|
|
375
|
+
},
|
|
376
|
+
warn(msg, opts) {
|
|
377
|
+
logger.hasWarned = true;
|
|
378
|
+
write("warn", msg, opts);
|
|
379
|
+
},
|
|
380
|
+
warnOnce(msg, opts) {
|
|
381
|
+
if (warnedOnce.has(msg)) return;
|
|
382
|
+
warnedOnce.add(msg);
|
|
383
|
+
logger.warn(msg, opts);
|
|
384
|
+
},
|
|
385
|
+
error(msg, opts) {
|
|
386
|
+
logger.hasWarned = true;
|
|
387
|
+
if (opts?.error) loggedErrors.add(opts.error);
|
|
388
|
+
write("error", msg, opts);
|
|
389
|
+
},
|
|
390
|
+
clearScreen() {
|
|
391
|
+
clearTerminal();
|
|
392
|
+
},
|
|
393
|
+
hasErrorLogged(error) {
|
|
394
|
+
return loggedErrors.has(error);
|
|
395
|
+
}
|
|
396
|
+
};
|
|
397
|
+
return logger;
|
|
398
|
+
}
|
|
399
|
+
//#endregion
|
|
400
|
+
//#region src/cli/run.ts
|
|
401
|
+
function parsePort(value) {
|
|
402
|
+
const n = Number(value);
|
|
403
|
+
if (!Number.isInteger(n) || n < 0 || n > 65535) throw new Error(`Invalid port: ${value}`);
|
|
404
|
+
return n;
|
|
405
|
+
}
|
|
406
|
+
async function runSkillsDriftCheck(skillsDir) {
|
|
407
|
+
if (process.env.OPEN_SLIDE_SKIP_SKILLS_CHECK === "1") return;
|
|
408
|
+
let drift;
|
|
409
|
+
try {
|
|
410
|
+
drift = await detectSkillsDrift(skillsDir);
|
|
411
|
+
} catch {
|
|
412
|
+
return;
|
|
413
|
+
}
|
|
414
|
+
const stale = drift.filter((d) => d.status !== "unchanged");
|
|
415
|
+
if (stale.length === 0) return;
|
|
416
|
+
const names = stale.map((d) => d.name).join(", ");
|
|
417
|
+
const interactive = Boolean(process.stdin.isTTY && process.stdout.isTTY);
|
|
418
|
+
const notice = `${chalk.yellow(glyph.warn)} Built-in skills are out of date: ${chalk.bold(names)}`;
|
|
419
|
+
if (!interactive) {
|
|
420
|
+
process.stderr.write(`\n ${notice}\n ${chalk.dim("Run `open-slide sync:skills` to update.")}\n`);
|
|
421
|
+
return;
|
|
422
|
+
}
|
|
423
|
+
const rl = readline.createInterface({
|
|
424
|
+
input: process.stdin,
|
|
425
|
+
output: process.stdout
|
|
426
|
+
});
|
|
427
|
+
try {
|
|
428
|
+
const answer = (await rl.question(`\n ${notice}\n Sync now? ${chalk.dim("(Y/n)")} `)).trim().toLowerCase();
|
|
429
|
+
if (answer === "" || answer === "y" || answer === "yes") {
|
|
430
|
+
process.stdout.write("\n");
|
|
431
|
+
await syncSkills(skillsDir);
|
|
432
|
+
} else process.stdout.write(chalk.dim(" Skipped. Run `open-slide sync:skills` later to update.\n"));
|
|
433
|
+
} finally {
|
|
434
|
+
rl.close();
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
function resolveBuiltinSkillsDir() {
|
|
438
|
+
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
439
|
+
return path.resolve(here, "..", "..", "skills");
|
|
440
|
+
}
|
|
441
|
+
async function run(argv) {
|
|
442
|
+
const program = new Command();
|
|
443
|
+
program.name("open-slide").description("Author slides in React — open-slide runs the rest.").version(readVersion(), "-v, --version", "print version").helpOption("-h, --help", "show help").showHelpAfterError(chalk.dim("(run `open-slide --help` for usage)"));
|
|
444
|
+
program.command("dev").description("Start the dev server").addOption(new Option("-p, --port <port>", "port to listen on").argParser(parsePort)).addOption(new Option("--host [host]", "expose on the network (optional host)")).option("--open", "open the browser on start").option("--no-skills-check", "skip the built-in skills drift check").action(async (flags) => {
|
|
445
|
+
if (flags.skillsCheck !== false) await runSkillsDriftCheck(resolveBuiltinSkillsDir());
|
|
446
|
+
await assertViteResolvesToCore();
|
|
447
|
+
const { dev } = await import("../dev-CCgdakbZ.js");
|
|
448
|
+
await dev(flags);
|
|
449
|
+
});
|
|
450
|
+
program.command("build").description("Build a static site").option("--out-dir <dir>", "output directory (defaults to `dist`)").action(async (flags) => {
|
|
451
|
+
await assertViteResolvesToCore();
|
|
452
|
+
const { build } = await import("../build-CZ6Qtrng.js");
|
|
453
|
+
await build(flags);
|
|
454
|
+
});
|
|
455
|
+
program.command("preview").description("Preview the production build").addOption(new Option("-p, --port <port>", "port to listen on").argParser(parsePort)).addOption(new Option("--host [host]", "expose on the network (optional host)")).option("--open", "open the browser on start").action(async (flags) => {
|
|
456
|
+
await assertViteResolvesToCore();
|
|
457
|
+
const { preview } = await import("../preview-AwAqvG17.js");
|
|
458
|
+
await preview(flags);
|
|
459
|
+
});
|
|
460
|
+
program.command("sync:skills").description(`Sync built-in skills from ${ownPackageName()} into this workspace`).option("--dry-run", "show what would change without writing").action(async (flags) => {
|
|
461
|
+
await syncSkills(resolveBuiltinSkillsDir(), flags);
|
|
462
|
+
});
|
|
463
|
+
await program.parseAsync(argv, { from: "user" });
|
|
464
|
+
}
|
|
465
|
+
//#endregion
|
|
466
|
+
//#region src/cli/bin.ts
|
|
467
|
+
run(process.argv.slice(2)).catch((err) => {
|
|
468
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
469
|
+
process.stderr.write(formatError(message));
|
|
470
|
+
process.exit(1);
|
|
471
|
+
});
|
|
472
|
+
//#endregion
|
|
473
|
+
export { printUrls as a, printShortcutsHint as i, formatError as n, shortcutsEnabled as o, printHeader as r, startupDuration as s, createCliLogger as t };
|