create-theokit 1.23.4 → 1.23.6

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-theokit",
3
- "version": "1.23.4",
3
+ "version": "1.23.6",
4
4
  "type": "module",
5
5
  "description": "Scaffold a new TheoKit project",
6
6
  "license": "Apache-2.0",
@@ -0,0 +1,83 @@
1
+ # Cross-platform desktop release — builds {{name}} for macOS (Apple Silicon + Intel),
2
+ # Linux (x64 + arm64) and Windows, then drafts a GitHub release with the installers.
3
+ #
4
+ # WHY a matrix of native runners: Tauri does NOT support cross-compiling between operating
5
+ # systems (macOS/Linux bundles REQUIRE their own host; only Windows-NSIS-from-Linux is a
6
+ # last-resort exception). Each target therefore builds on its own runner — the documented
7
+ # best practice: https://v2.tauri.app/distribute/pipelines/github/
8
+ #
9
+ # ⚠️ PREREQUISITE — the sidecar must be a real binary, not the dev shim.
10
+ # `tauri build` runs `scripts/build-sidecar.mjs`, which in DEV writes a POSIX shell shim
11
+ # that execs this repo's local `tsx` (absolute build-time paths, requires Node on the user's
12
+ # machine). That shim is NOT portable to end users, and `build-sidecar.mjs` intentionally
13
+ # FAILS on Windows (Tauri needs a `.exe`). Before this workflow can ship a working app you
14
+ # MUST compile `sidecar/sidecar.ts` to a self-contained per-platform binary at
15
+ # `src-tauri/binaries/theo-sidecar-<target-triple>[.exe]`. See README-surface.md § Packaging.
16
+ #
17
+ # Trigger: push to the `release` branch, or run manually (Actions → Run workflow).
18
+ name: release-desktop
19
+
20
+ on:
21
+ workflow_dispatch:
22
+ push:
23
+ branches: [release]
24
+
25
+ jobs:
26
+ build:
27
+ permissions:
28
+ contents: write
29
+ strategy:
30
+ fail-fast: false
31
+ matrix:
32
+ include:
33
+ - platform: macos-latest # Apple Silicon → .app / .dmg
34
+ args: --target aarch64-apple-darwin
35
+ - platform: macos-latest # Intel → .app / .dmg
36
+ args: --target x86_64-apple-darwin
37
+ - platform: ubuntu-22.04 # Linux x64 → .deb / .AppImage / .rpm
38
+ args: ''
39
+ - platform: ubuntu-22.04-arm # Linux arm64
40
+ args: ''
41
+ - platform: windows-latest # Windows → .exe (NSIS) / .msi
42
+ args: ''
43
+
44
+ runs-on: ${{ matrix.platform }}
45
+ steps:
46
+ - uses: actions/checkout@v4
47
+
48
+ - name: Install Linux system dependencies
49
+ if: startsWith(matrix.platform, 'ubuntu')
50
+ run: |
51
+ sudo apt-get update
52
+ sudo apt-get install -y libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf xdg-utils
53
+
54
+ - name: Setup Node
55
+ uses: actions/setup-node@v4
56
+ with:
57
+ node-version: lts/*
58
+ cache: npm
59
+
60
+ - name: Install Rust (stable)
61
+ uses: dtolnay/rust-toolchain@stable
62
+ with:
63
+ targets: ${{ matrix.platform == 'macos-latest' && 'aarch64-apple-darwin,x86_64-apple-darwin' || '' }}
64
+
65
+ - name: Rust cache
66
+ uses: swatinem/rust-cache@v2
67
+ with:
68
+ workspaces: ./src-tauri -> target
69
+
70
+ - name: Install frontend dependencies
71
+ run: npm install
72
+
73
+ - name: Build + release with Tauri
74
+ uses: tauri-apps/tauri-action@v0
75
+ env:
76
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
77
+ with:
78
+ tagName: {{name}}-v__VERSION__
79
+ releaseName: '{{name}} v__VERSION__'
80
+ releaseBody: 'See the assets below to download and install this version.'
81
+ releaseDraft: true
82
+ prerelease: false
83
+ args: ${{ matrix.args }}
@@ -53,3 +53,17 @@ externalBin that a shell shim cannot satisfy (`build:sidecar` fails loud on win3
53
53
  before building. Options: **Node SEA** (single-executable app — runs under Node, where the stream works),
54
54
  or `bun build --compile`/`pkg` (verify the ai-sdk token stream survives your bundler first). Replace the
55
55
  `build:sidecar` script with your compile command and keep the same output path.
56
+
57
+ ### Cross-platform release (macOS · Linux · Windows)
58
+
59
+ Tauri does **not** cross-compile between operating systems — macOS/Linux bundles must be built on their own
60
+ host, and only Windows-NSIS-from-Linux is a fragile last resort ([docs](https://v2.tauri.app/distribute/pipelines/github/)).
61
+ The best practice is a **matrix of native CI runners**, so this surface ships
62
+ `.github/workflows/release.yml`: on push to a `release` branch (or a manual run) it builds `{{name}}` on
63
+ `macos-latest` (Apple Silicon **and** Intel), `ubuntu-22.04` (x64 + arm64) and `windows-latest`, then drafts
64
+ a GitHub release with the installers (`.dmg`/`.app`, `.deb`/`.AppImage`/`.rpm`, `.msi`/NSIS `.exe`).
65
+
66
+ Before that workflow can ship a **working** app, resolve the sidecar gap above (the CI `tauri build` runs the
67
+ same `build:sidecar`, which fails on the Windows runner and produces a non-portable shim on macOS/Linux). For
68
+ public distribution you also need **code signing** — macOS notarization (Apple Developer ID) and a Windows
69
+ signing certificate; see [Tauri › Distribute](https://v2.tauri.app/distribute/).
@@ -13,7 +13,7 @@ import {
13
13
  } from '@theokit/ui'
14
14
  import { Button } from '@usetheo/ui'
15
15
  import { createTauriChannelSource, type TauriCore } from '@theokit/tauri'
16
- import { Bot, Plus, Sparkles } from 'lucide-react'
16
+ import { Bot, Minus, Plus, Sparkles, Square, X } from 'lucide-react'
17
17
  import { ChannelTransport, useAgent } from 'theokit/client'
18
18
 
19
19
  import { AGENT } from '../../shared/agent'
@@ -40,6 +40,25 @@ if (tauri === undefined) {
40
40
  }
41
41
  const transport = new ChannelTransport({ source: createTauriChannelSource(tauri.core) })
42
42
 
43
+ // The window is frameless (`decorations: false` in tauri.conf.json) so the OS title bar can't clash with
44
+ // the app background — the app owns its top bar. These drive the native window from our custom controls.
45
+ const appWindow = (
46
+ globalThis as {
47
+ __TAURI__?: {
48
+ window?: {
49
+ getCurrentWindow: () => {
50
+ minimize: () => Promise<void>
51
+ toggleMaximize: () => Promise<void>
52
+ close: () => Promise<void>
53
+ }
54
+ }
55
+ }
56
+ }
57
+ ).__TAURI__?.window
58
+ const minimizeWindow = (): void => void appWindow?.getCurrentWindow().minimize()
59
+ const maximizeWindow = (): void => void appWindow?.getCurrentWindow().toggleMaximize()
60
+ const closeWindow = (): void => void appWindow?.getCurrentWindow().close()
61
+
43
62
  /** The agent's opening line (from `shared/agent.ts`) — so the conversation starts warm instead of empty. */
44
63
  const GREETING: UIMessage = {
45
64
  id: 'greeting',
@@ -55,24 +74,30 @@ const STARTERS: QuickAction[] = [
55
74
  ]
56
75
 
57
76
  // App-level layout in inline styles (the desktop bundle has no Tailwind). Colors read the theme CSS vars
58
- // `@theokit/ui` sets, so light/dark + the theme switcher cascade exactly like the web surface.
77
+ // `@theokit/ui` sets and those vars are `oklch()` colors, so wrap them in `color-mix(in oklch, …)` for
78
+ // alpha (NOT `hsl(var(--x) / a)`, which is invalid CSS and silently renders transparent).
59
79
  const styles = {
60
80
  page: {
61
81
  display: 'flex',
62
82
  flexDirection: 'column',
63
83
  height: '100vh',
64
- background: 'hsl(var(--background))',
65
- color: 'hsl(var(--foreground))',
84
+ background: 'var(--background)',
85
+ color: 'var(--foreground)',
66
86
  },
67
87
  header: {
68
88
  display: 'flex',
69
89
  alignItems: 'center',
70
90
  justifyContent: 'space-between',
71
- borderBottom: '1px solid hsl(var(--border) / 0.6)',
72
- padding: '8px 16px',
91
+ // The frameless title bar is its own DISTINCT band: the `--muted` surface reads clearly apart
92
+ // from the content background (adapts to light/dark), with a border to seal the strip.
93
+ background: 'var(--muted)',
94
+ borderBottom: '1px solid var(--border)',
95
+ // Slim title bar — thin vertical padding keeps the strip compact.
96
+ padding: '3px 12px',
73
97
  },
74
98
  brand: { display: 'inline-flex', alignItems: 'center', gap: 8 },
75
- brandName: { fontWeight: 600, fontSize: 13, letterSpacing: '-0.01em' },
99
+ brandName: { fontWeight: 600, fontSize: 12, letterSpacing: '-0.01em' },
100
+ headerRight: { display: 'inline-flex', alignItems: 'center', gap: 2 },
76
101
  scroll: { flex: 1, overflowY: 'auto', minHeight: 0 },
77
102
  column: {
78
103
  margin: '0 auto',
@@ -84,8 +109,8 @@ const styles = {
84
109
  padding: 24,
85
110
  },
86
111
  composerBar: {
87
- borderTop: '1px solid hsl(var(--border) / 0.6)',
88
- background: 'hsl(var(--background) / 0.5)',
112
+ borderTop: '1px solid color-mix(in oklch, var(--border) 60%, transparent)',
113
+ background: 'color-mix(in oklch, var(--background) 50%, transparent)',
89
114
  },
90
115
  composerInner: { margin: '0 auto', width: '100%', maxWidth: 768, padding: '16px 24px' },
91
116
  } satisfies Record<string, CSSProperties>
@@ -115,13 +140,57 @@ export function App(): ReactElement {
115
140
 
116
141
  return (
117
142
  <TheoUIProvider>
143
+ {/* Window controls need :hover feedback — inline styles can't do pseudo-classes, so the button
144
+ appearance (incl. hover, and the classic red close) lives in this small stylesheet. */}
145
+ <style>{`
146
+ .tk-winbtn {
147
+ display: inline-flex; align-items: center; justify-content: center;
148
+ width: 20px; height: 20px; border: none; border-radius: 6px;
149
+ background: transparent; color: var(--muted-foreground); cursor: pointer;
150
+ transition: background 0.12s ease, color 0.12s ease;
151
+ }
152
+ .tk-winbtn:hover { background: color-mix(in oklch, var(--foreground) 12%, transparent); color: var(--foreground); }
153
+ .tk-winbtn--close:hover { background: #e5484d; color: #fff; }
154
+ `}</style>
118
155
  <div style={styles.page}>
119
- <header style={styles.header}>
156
+ {/* Frameless title bar: `data-tauri-drag-region` makes the whole strip drag the window; the
157
+ background is the `--muted` band, so the bar reads as a distinct strip. Interactive
158
+ children (theme switcher, window buttons) still receive clicks. */}
159
+ <header style={styles.header} data-tauri-drag-region>
120
160
  <span style={styles.brand}>
121
- <Bot size={18} style={{ color: 'hsl(var(--primary))' }} aria-hidden />
122
- <span style={styles.brandName}>{{name}} — TheoKit agent</span>
161
+ <Bot size={18} style={{ color: 'var(--primary)' }} aria-hidden />
162
+ <span style={styles.brandName}>{{name}}</span>
163
+ </span>
164
+ <span style={styles.headerRight}>
165
+ <ThemeSwitcher />
166
+ <button
167
+ type="button"
168
+ className="tk-winbtn"
169
+ onClick={minimizeWindow}
170
+ aria-label="Minimize"
171
+ title="Minimize"
172
+ >
173
+ <Minus size={15} />
174
+ </button>
175
+ <button
176
+ type="button"
177
+ className="tk-winbtn"
178
+ onClick={maximizeWindow}
179
+ aria-label="Maximize"
180
+ title="Maximize"
181
+ >
182
+ <Square size={12} />
183
+ </button>
184
+ <button
185
+ type="button"
186
+ className="tk-winbtn tk-winbtn--close"
187
+ onClick={closeWindow}
188
+ aria-label="Close"
189
+ title="Close"
190
+ >
191
+ <X size={15} />
192
+ </button>
123
193
  </span>
124
- <ThemeSwitcher />
125
194
  </header>
126
195
 
127
196
  <div style={styles.scroll}>
@@ -1,10 +1,16 @@
1
1
  {
2
2
  "$schema": "../gen/schemas/desktop-schema.json",
3
3
  "identifier": "default",
4
- "description": "Allow the webview to run the agent turn + settle HITL via the sidecar.",
4
+ "description": "Allow the webview to run the agent turn + settle HITL via the sidecar, and drive the frameless window (drag + minimize/maximize/close).",
5
5
  "windows": ["main"],
6
6
  "permissions": [
7
7
  "core:default",
8
+ "core:window:allow-start-dragging",
9
+ "core:window:allow-minimize",
10
+ "core:window:allow-maximize",
11
+ "core:window:allow-unmaximize",
12
+ "core:window:allow-toggle-maximize",
13
+ "core:window:allow-close",
8
14
  "shell:allow-spawn",
9
15
  {
10
16
  "identifier": "shell:allow-execute",
@@ -16,7 +16,8 @@
16
16
  "label": "main",
17
17
  "title": "{{name}} — TheoKit desktop",
18
18
  "width": 900,
19
- "height": 680
19
+ "height": 680,
20
+ "decorations": false
20
21
  }
21
22
  ],
22
23
  "security": {