@interopio/iocd-cli 1.0.2 → 1.1.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.
Files changed (48) hide show
  1. package/README.md +28 -2
  2. package/changelog.md +16 -0
  3. package/dist/cli.js +2 -0
  4. package/dist/cli.js.map +1 -1
  5. package/dist/commands/apps.command.js +83 -0
  6. package/dist/commands/apps.command.js.map +1 -1
  7. package/dist/commands/index.js +3 -1
  8. package/dist/commands/index.js.map +1 -1
  9. package/dist/commands/skills.command.js +56 -0
  10. package/dist/commands/skills.command.js.map +1 -0
  11. package/dist/services/dev.service.js +5 -1
  12. package/dist/services/dev.service.js.map +1 -1
  13. package/dist/services/skills.service.js +178 -0
  14. package/dist/services/skills.service.js.map +1 -0
  15. package/dist/services/template.service.js +141 -9
  16. package/dist/services/template.service.js.map +1 -1
  17. package/dist/services/test-infrastructure.service.js +7 -17
  18. package/dist/services/test-infrastructure.service.js.map +1 -1
  19. package/dist/services/test.service.js +21 -8
  20. package/dist/services/test.service.js.map +1 -1
  21. package/dist/templates/ioconnect-desktop/README.md +28 -2
  22. package/dist/templates/launchpad/apps/launchpad/.gitignore.template +23 -1
  23. package/dist/templates/launchpad/apps/launchpad/.prettierignore +3 -0
  24. package/dist/templates/launchpad/apps/launchpad/.prettierrc +6 -0
  25. package/dist/templates/launchpad/apps/launchpad/README.md +220 -0
  26. package/dist/templates/launchpad/apps/launchpad/config/iocd.app.def.dev.json +1 -1
  27. package/dist/templates/launchpad/apps/launchpad/index.html +13 -14
  28. package/dist/templates/launchpad/apps/launchpad/package.json +17 -9
  29. package/dist/templates/launchpad/apps/launchpad/src/app/app.tsx +31 -37
  30. package/dist/templates/launchpad/apps/launchpad/src/components/launchpad.tsx +37 -0
  31. package/dist/templates/launchpad/apps/launchpad/src/{app → constants}/constants.ts +2 -1
  32. package/dist/templates/launchpad/apps/launchpad/src/main.tsx +1 -3
  33. package/dist/templates/launchpad/apps/launchpad/src/styles.css +2 -17
  34. package/dist/templates/launchpad/apps/launchpad/tsconfig.json +10 -8
  35. package/dist/templates/launchpad/apps/launchpad/vite-env.d.ts +1 -0
  36. package/dist/templates/launchpad/apps/launchpad/vite.config.ts +8 -3
  37. package/dist/templates/tests/.agents/skills/iocd-wdio-testing/references/configuration.md +3 -2
  38. package/dist/templates/tests/.agents/skills/iocd-wdio-testing/references/models.md +1 -1
  39. package/dist/templates/tests/.agents/skills/iocd-wdio-testing/references/troubleshooting.md +8 -9
  40. package/dist/templates/tests/tests/package.json +1 -1
  41. package/dist/utils/template-update.js +6 -0
  42. package/dist/utils/template-update.js.map +1 -0
  43. package/package.json +3 -1
  44. package/dist/templates/launchpad/apps/launchpad/package-lock.json +0 -2778
  45. package/dist/templates/launchpad/apps/launchpad/src/components/logo.tsx +0 -11
  46. package/dist/templates/launchpad/apps/launchpad/src/components/main-context-menu.tsx +0 -212
  47. package/dist/templates/launchpad/apps/launchpad/src/components/notifications-button.tsx +0 -51
  48. package/dist/templates/tests/tests/package-lock.json +0 -8441
@@ -0,0 +1,220 @@
1
+ # Launchpad App for io.Connect Desktop
2
+
3
+ Template for creating a custom desktop Launchpad app for **io.Connect Desktop**, built on top of the
4
+ `IOLaunchpadDesktop` feature exported by [`@interopio/components-react`](https://www.npmjs.com/package/@interopio/components-react). Clone
5
+ this app and customize only the pieces you need — everything else keeps working out of the box.
6
+
7
+ ## Prerequisites
8
+
9
+ **io.Connect Desktop** is required, since this app only configures the `desktop` factory (see
10
+ [src/constants/constants.ts](src/constants/constants.ts)).
11
+
12
+ ## Setup
13
+
14
+ - Run `npm install` to install all dependencies.
15
+ - Run `npm run start` to start the app (dev server runs on `http://localhost:4242` by default, see
16
+ [vite.config.ts](vite.config.ts)).
17
+ - Point your io.Connect Desktop configuration's Launchpad/System application entry to this app's URL, then start
18
+ io.Connect Desktop to see your customized Launchpad. Refer to your io.Connect Desktop version's documentation for
19
+ the exact application-definition file and property to update.
20
+ - Run `npm run build` to produce a production build in `dist/`.
21
+ - Start **io.Connect Desktop** to start using and modifying your Launchpad App.
22
+
23
+ ## How it's wired
24
+
25
+ `src/components/launchpad.tsx` wires up the required providers around a single `<Launchpad />` component. You
26
+ don't need to pass a `components` prop at all - `<Launchpad />` already renders a fully working default header
27
+ (`DragHandle` + `LogoButton` before search, `ExtendedArea` + `NotificationsButton` + `MainContextMenu` after
28
+ search) out of the box:
29
+
30
+ ```tsx
31
+ import {
32
+ ThemeProvider,
33
+ PlatformPrefsProvider,
34
+ IOActivePanelRenderer,
35
+ IODownloadManager,
36
+ IOLaunchpadDesktop,
37
+ IONotifications,
38
+ } from "@interopio/components-react";
39
+
40
+ const { LaunchpadProvider, LaunchpadBodyPopupProvider, PanelPopupProvider, Launchpad } = IOLaunchpadDesktop;
41
+ const { NotificationsProvider } = IONotifications;
42
+ const { DownloadManagerProvider } = IODownloadManager;
43
+ const { PanelManagerProvider } = IOActivePanelRenderer;
44
+
45
+ function LaunchpadWrapper() {
46
+ return (
47
+ <ThemeProvider>
48
+ <PlatformPrefsProvider>
49
+ <NotificationsProvider>
50
+ <DownloadManagerProvider>
51
+ <PanelManagerProvider>
52
+ <LaunchpadProvider>
53
+ <LaunchpadBodyPopupProvider>
54
+ <PanelPopupProvider>
55
+ <Launchpad />
56
+ </PanelPopupProvider>
57
+ </LaunchpadBodyPopupProvider>
58
+ </LaunchpadProvider>
59
+ </PanelManagerProvider>
60
+ </DownloadManagerProvider>
61
+ </NotificationsProvider>
62
+ </PlatformPrefsProvider>
63
+ </ThemeProvider>
64
+ );
65
+ }
66
+ ```
67
+
68
+ All customization happens through the `components` prop of `<Launchpad />` - you shouldn't need to touch the
69
+ provider chain above.
70
+
71
+ ## Customization
72
+
73
+ ### 1. Replacing the default io.Connect Desktop Launchpad with a custom implementation
74
+
75
+ For details on how io.Connect Desktop discovers and loads a custom Launchpad app, see the
76
+ [Launchpad documentation](https://docs.interop.io/desktop/capabilities/launcher/index.html#launchpad).
77
+
78
+
79
+ ### 2. The `components` prop
80
+
81
+ `<Launchpad components={{ ... }} />` forwards straight to the native `IOLaunchpad.ContentsContainer`, so it only
82
+ accepts `header` (`BeforeSearch` / `AfterSearch`) and `sections` - there's no per-piece override system.
83
+ `DragHandle`, `LogoButton`, `NotificationsButton`, `MainContextMenu`, `ExtendedArea` are exported standalone so you
84
+ compose them yourself into `header.BeforeSearch` / `AfterSearch`, as shown above.
85
+
86
+ > **Tip:** define `BeforeSearch` / `AfterSearch` (and the `components` object) **outside** your component's render
87
+ > function (module scope), or memoize them. Passing a brand-new inline function on every render forces
88
+ > `<Launchpad />` to remount that zone on every render - wasteful in general, and it can also break in-flight
89
+ > async work started by a piece inside it (e.g. opening the docked search popup).
90
+
91
+ ### 3. Default `BeforeSearch` / `AfterSearch`
92
+
93
+ `<Launchpad />` fills in `header.BeforeSearch` / `AfterSearch` with its own defaults whenever you don't specify
94
+ them, so there are 3 possible outcomes per zone:
95
+
96
+ 1. **Omitted** (key not present, or `undefined`) - the library default renders (`DragHandle` + `LogoButton` for
97
+ `BeforeSearch`; `ExtendedArea` + `NotificationsButton` + `MainContextMenu` for `AfterSearch`).
98
+ 2. **Explicitly empty** (e.g. `BeforeSearch: () => null`) - the default is overridden and nothing renders in that
99
+ zone.
100
+ 3. **A real custom component** - that component renders in place of the default.
101
+
102
+ ```tsx
103
+ // 1. Omitted - renders the library defaults
104
+ <Launchpad />;
105
+
106
+ // 2. Explicitly empty - hides the zone entirely
107
+ <Launchpad components={{ header: { AfterSearch: () => null } }} />;
108
+
109
+ // 3. Custom component - fully replaces the zone
110
+ function CustomBeforeSearch() {
111
+ return <MyCustomLogo />;
112
+ }
113
+
114
+ <Launchpad components={{ header: { BeforeSearch: CustomBeforeSearch } }} />;
115
+ ```
116
+
117
+ ### 4. Removing a piece
118
+
119
+ Since `header.BeforeSearch` / `AfterSearch` **fully replace** the zone, just omit a piece from your composition to
120
+ hide it - e.g. hide the notifications bell:
121
+
122
+ ```tsx
123
+ function AfterSearch() {
124
+ return (
125
+ <>
126
+ <ExtendedArea />
127
+ <MainContextMenu />
128
+ </>
129
+ );
130
+ }
131
+ ```
132
+
133
+ ### 5. Passing your own component
134
+
135
+ Compose your own implementation alongside (or instead of) the default pieces:
136
+
137
+ ```tsx
138
+ function MyMainContextMenu() {
139
+ return <button onClick={() => console.log("clicked!")}>⋮</button>;
140
+ }
141
+
142
+ function AfterSearch() {
143
+ return (
144
+ <>
145
+ <ExtendedArea />
146
+ <NotificationsButton />
147
+ <MyMainContextMenu />
148
+ </>
149
+ );
150
+ }
151
+ ```
152
+
153
+ ### 6. Overriding `BeforeSearch` / `AfterSearch`
154
+
155
+ Pass `components.header` to fully replace either zone with something entirely custom:
156
+
157
+ ```tsx
158
+ function CustomBeforeSearch() {
159
+ return <MyCustomLogo />;
160
+ }
161
+
162
+ function CustomAfterSearch() {
163
+ return <MyCustomButton />;
164
+ }
165
+
166
+ const launchpadComponents = { header: { BeforeSearch: CustomBeforeSearch, AfterSearch: CustomAfterSearch } };
167
+
168
+ <Launchpad components={launchpadComponents} />;
169
+ ```
170
+
171
+ Since `header.BeforeSearch` / `AfterSearch` **fully replace** the zone, if you just want to add something
172
+ alongside the defaults, import the default pieces (they're also exported standalone) and compose them yourself:
173
+
174
+ ```tsx
175
+ import { IOLaunchpadDesktop } from "@interopio/components-react";
176
+
177
+ const { DragHandle, LogoButton } = IOLaunchpadDesktop;
178
+
179
+ function CustomBeforeSearch() {
180
+ return (
181
+ <>
182
+ <DragHandle />
183
+ <LogoButton />
184
+ <MyExtraBadge />
185
+ </>
186
+ );
187
+ }
188
+
189
+ const launchpadComponents = { header: { BeforeSearch: CustomBeforeSearch } };
190
+ ```
191
+
192
+ ### 7. Customizing the `LogoButton`
193
+
194
+ `LogoButton` itself accepts `icon`, `iconSrc`, and `onClick` props, so you don't need to replace it entirely just
195
+ to change the logo or its click behavior:
196
+
197
+ ```tsx
198
+ import { IOLaunchpadDesktop } from "@interopio/components-react";
199
+
200
+ const { DragHandle, LogoButton } = IOLaunchpadDesktop;
201
+
202
+ function BeforeSearch() {
203
+ return (
204
+ <>
205
+ <DragHandle />
206
+ <LogoButton iconSrc="/my-logo.png" onClick={() => console.log("logo clicked")} />
207
+ </>
208
+ );
209
+ }
210
+ ```
211
+
212
+ - `icon` — an icon variant name (ignored if `iconSrc` is set); defaults to `"logo"`.
213
+ - `iconSrc` — a custom image URL/data-URI to render instead of `icon`.
214
+ - `onClick` — replaces the default collapse/popup-toggle behavior; drag-to-move still works either way.
215
+
216
+ ### 7. `ExtendedArea` visibility
217
+
218
+ `ExtendedArea` self-guards: it renders `null` unless the Launchpad is both docked and the
219
+ `LAUNCHPAD_SHOW_EXTENDED_AREA` platform pref is enabled, so it's safe to always include it in `AfterSearch` - it
220
+ simply won't render anything otherwise.
@@ -9,7 +9,7 @@
9
9
  "autoInjectAPI": {
10
10
  "enabled": true
11
11
  },
12
- "url": "http://localhost:5178/",
12
+ "url": "http://localhost:4242/",
13
13
  "mode": "frameless",
14
14
  "showInTaskbar": true,
15
15
  "hasSizeAreas": true,
@@ -1,16 +1,15 @@
1
- <!DOCTYPE html>
1
+ <!doctype html>
2
2
  <html lang="en" class="dark">
3
- <head>
4
- <meta charset="utf-8" />
5
- <title>Launchpad</title>
6
- <base href="./" />
7
-
8
- <meta name="viewport" content="width=device-width, initial-scale=1" />
9
- <link rel="icon" type="image/x-icon" href="/favicon.ico" />
10
- <link rel="stylesheet" href="/src/styles.css" />
11
- </head>
12
- <body>
13
- <div id="root"></div>
14
- <script type="module" src="/src/main.tsx"></script>
15
- </body>
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <title>Launchpad</title>
6
+ <base href="./" />
7
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
8
+ <link rel="icon" type="image/x-icon" href="/favicon.ico" />
9
+ <link rel="stylesheet" href="/src/styles.css" />
10
+ </head>
11
+ <body>
12
+ <div id="root"></div>
13
+ <script type="module" src="/src/main.tsx"></script>
14
+ </body>
16
15
  </html>
@@ -1,6 +1,6 @@
1
1
  {
2
- "name": "dev-launchpad",
3
- "version": "1.0.5",
2
+ "name": "io-connect-desktop-launchpad",
3
+ "version": "4.6.0",
4
4
  "homepage": "./",
5
5
  "private": true,
6
6
  "scripts": {
@@ -8,14 +8,22 @@
8
8
  "build": "vite build"
9
9
  },
10
10
  "dependencies": {
11
- "@interopio/components-react": "^0.8.0",
12
- "@interopio/home-ui-react": "^2.1.1",
13
- "@interopio/react-hooks": "^4.1.1",
14
- "@interopio/workspaces-ui-react": "^4.1.1"
11
+ "@interopio/components-react": "~4.6.0",
12
+ "@interopio/desktop": "~6.16.0",
13
+ "@interopio/react-hooks": "~4.6.0",
14
+ "@interopio/workspaces-ui-react": "~4.6.0",
15
+ "@interopio/modals-api": "~4.6.0",
16
+ "@interopio/search-api": "^3.3.0",
17
+ "@interopio/theme": "~4.6.0",
18
+ "react": "~18.2.0",
19
+ "react-dom": "~18.2.0"
15
20
  },
16
21
  "devDependencies": {
17
- "@vitejs/plugin-react": "^5.0.2",
18
- "vite": "^7.1.5",
19
- "vite-plugin-environment": "^1.1.3"
22
+ "@types/node": "~20.12.7",
23
+ "@types/react": "~18.2.79",
24
+ "@types/react-dom": "~18.2.25",
25
+ "@vitejs/plugin-react": "~3.0.0",
26
+ "typescript": "~5.8.2",
27
+ "vite": "~4.0.1"
20
28
  }
21
29
  }
@@ -1,45 +1,39 @@
1
- import { IOConnectProvider } from "@interopio/react-hooks";
2
- import {
3
- LaunchpadBody,
4
- LaunchpadHeader,
5
- LaunchpadContentsContainer,
6
- PlatformPrefsProvider,
7
- } from "@interopio/home-ui-react";
8
- import { ioConfig } from "./constants";
9
- import { ThemeProvider, IONotifications } from "@interopio/components-react";
10
- import Logo from "../components/logo";
11
- import NotificationsButton from "../components/notifications-button";
12
- import MainContextMenu from "../components/main-context-menu";
1
+ import { lazy, Suspense, useContext, useEffect } from "react";
2
+ import { IOConnectContext, IOConnectProvider } from "@interopio/react-hooks";
3
+ import { ioConfig } from "../constants/constants";
13
4
  import "@interopio/workspaces-ui-react/dist/styles/workspaces.css";
14
- import "@interopio/home-ui-react/index.css";
5
+ import "@interopio/components-react/dist/styles/components/ui/dropdown-menu.css";
6
+ import "@interopio/components-react/dist/styles/components/ui/overlay-scrollbars-container.css";
7
+ import "@interopio/components-react/dist/styles/features/active-panel-renderer/styles.css";
8
+ import "@interopio/components-react/dist/styles/features/notifications/styles.css";
9
+ import "@interopio/components-react/dist/styles/features/preferences/styles.css";
10
+ import "@interopio/components-react/dist/styles/features/profile/styles.css";
11
+ import "@interopio/components-react/dist/styles/features/launchpad/styles.css";
12
+ import "@interopio/components-react/dist/styles/features/launchpad-desktop/styles.css";
15
13
 
16
- export function App() {
17
- const { NotificationsProvider } = IONotifications;
14
+ const Launchpad = lazy(() => import("../components/launchpad"));
15
+
16
+ // IOConnectProvider owns the only io.Connect initialization - read the resulting instance from context instead of initializing again.
17
+ function GlobalIOBinder() {
18
+ const io = useContext(IOConnectContext);
19
+
20
+ useEffect(() => {
21
+ if (io) {
22
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
23
+ (globalThis as any).io = io;
24
+ }
25
+ }, [io]);
18
26
 
27
+ return null;
28
+ }
29
+
30
+ export function App() {
19
31
  return (
20
32
  <IOConnectProvider settings={ioConfig}>
21
- <PlatformPrefsProvider>
22
- <ThemeProvider>
23
- <NotificationsProvider>
24
- <LaunchpadContentsContainer
25
- components={{
26
- header: {
27
- BeforeSearch: () => <Logo />,
28
- AfterSearch: () => (
29
- <>
30
- <NotificationsButton />
31
- <MainContextMenu />
32
- </>
33
- ),
34
- },
35
- }}
36
- >
37
- <LaunchpadHeader />
38
- <LaunchpadBody />
39
- </LaunchpadContentsContainer>
40
- </NotificationsProvider>
41
- </ThemeProvider>
42
- </PlatformPrefsProvider>
33
+ <GlobalIOBinder />
34
+ <Suspense fallback={null}>
35
+ <Launchpad />
36
+ </Suspense>
43
37
  </IOConnectProvider>
44
38
  );
45
39
  }
@@ -0,0 +1,37 @@
1
+ import {
2
+ ThemeProvider,
3
+ PlatformPrefsProvider,
4
+ IOActivePanelRenderer,
5
+ IODownloadManager,
6
+ IOLaunchpadDesktop,
7
+ IONotifications,
8
+ } from "@interopio/components-react";
9
+
10
+ const { PanelManagerProvider } = IOActivePanelRenderer;
11
+ const { DownloadManagerProvider } = IODownloadManager;
12
+ const { LaunchpadProvider, LaunchpadBodyPopupProvider, PanelPopupProvider, Launchpad } = IOLaunchpadDesktop;
13
+ const { NotificationsProvider } = IONotifications;
14
+
15
+ function LaunchpadWrapper() {
16
+ return (
17
+ <ThemeProvider>
18
+ <PlatformPrefsProvider>
19
+ <NotificationsProvider>
20
+ <DownloadManagerProvider>
21
+ <PanelManagerProvider>
22
+ <LaunchpadProvider>
23
+ <LaunchpadBodyPopupProvider>
24
+ <PanelPopupProvider>
25
+ <Launchpad />
26
+ </PanelPopupProvider>
27
+ </LaunchpadBodyPopupProvider>
28
+ </LaunchpadProvider>
29
+ </PanelManagerProvider>
30
+ </DownloadManagerProvider>
31
+ </NotificationsProvider>
32
+ </PlatformPrefsProvider>
33
+ </ThemeProvider>
34
+ );
35
+ }
36
+
37
+ export default LaunchpadWrapper;
@@ -1,6 +1,7 @@
1
1
  import IODesktop from "@interopio/desktop";
2
2
  import IOSearch from "@interopio/search-api";
3
3
  import IOWorkspaces from "@interopio/workspaces-api";
4
+ import IOModalsAPI from "@interopio/modals-api";
4
5
  import { IOConnectInitSettings } from "@interopio/react-hooks";
5
6
 
6
7
  export const ioConfig = {
@@ -12,7 +13,7 @@ export const ioConfig = {
12
13
  level: "warn",
13
14
  },
14
15
  },
15
- libraries: [IOWorkspaces, IOSearch],
16
+ libraries: [IOWorkspaces, IOSearch, IOModalsAPI],
16
17
  appManager: "full",
17
18
  layouts: "full",
18
19
  activities: "trackAll",
@@ -1,8 +1,6 @@
1
1
  import * as ReactDOM from "react-dom/client";
2
2
  import App from "./app/app";
3
3
 
4
- const root = ReactDOM.createRoot(
5
- document.getElementById("root") as HTMLElement
6
- );
4
+ const root = ReactDOM.createRoot(document.getElementById("root") as HTMLElement);
7
5
 
8
6
  root.render(<App />);
@@ -1,17 +1,2 @@
1
- /* You can add global styles to this file, and also import other style files */
2
- .launchpad-header-notifications-button {
3
- position: relative;
4
- }
5
-
6
- .launchpad-header-notifications-button .io-badge {
7
- position: absolute;
8
- top: 7px;
9
- right: -2px;
10
- display: flex;
11
- align-items: center;
12
- justify-content: center;
13
- min-width: var(--spacing-16);
14
- height: var(--spacing-16);
15
- margin: calc(var(--spacing-10) * -1) auto 0 calc(var(--spacing-4) * -1);
16
- font-size: var(--spacing-10);
17
- }
1
+ /* App-specific overrides go here. Launchpad desktop styling now ships with
2
+ @interopio/components-react/dist/styles/features/launchpad-desktop/styles.css */
@@ -1,10 +1,12 @@
1
1
  {
2
- "compilerOptions": {
3
- "jsx": "react-jsx",
4
- "esModuleInterop": true,
5
- "resolveJsonModule": true,
6
- "allowJs": false,
7
- "allowSyntheticDefaultImports": true,
8
- "strict": true
9
- }
2
+ "compilerOptions": {
3
+ "module": "esnext",
4
+ "moduleResolution": "bundler",
5
+ "jsx": "react-jsx",
6
+ "esModuleInterop": true,
7
+ "resolveJsonModule": true,
8
+ "allowJs": false,
9
+ "allowSyntheticDefaultImports": true,
10
+ "strict": true
11
+ }
10
12
  }
@@ -0,0 +1 @@
1
+ /// <reference types="vite/client" />
@@ -2,10 +2,15 @@ import { defineConfig } from "vite";
2
2
  import react from "@vitejs/plugin-react";
3
3
 
4
4
  export default defineConfig({
5
+ plugins: [react()],
6
+ base: "./",
5
7
  server: {
6
- port: 5178,
8
+ port: 4242,
7
9
  host: "localhost",
8
10
  },
9
- base: "./",
10
- plugins: [react()],
11
+ build: {
12
+ commonjsOptions: {
13
+ include: [/@interopio\/components-react/, /node_modules/],
14
+ },
15
+ },
11
16
  });
@@ -17,11 +17,12 @@ The config the platform runs with is three layers, each deep-merged over the pre
17
17
  | Layer | Owner | Where |
18
18
  |-------|-------|-------|
19
19
  | Default `system.json` | io.Connect Desktop | inside the installed `iocd` component |
20
- | Seed modifications | the seed | `modifications/**/iocd/config/system.json.merge` — dev *and* packed build |
20
+ | Seed modifications | the seed | `modifications/base/` plus `modifications/dev/` for tests; packed builds use `modifications/build/` |
21
21
  | Test overrides | the test package | `config/system.json`, merged on top for the test process only |
22
22
 
23
23
  **Keep the test layer minimal.** Whatever the seed configures is already in effect during a test
24
- run — don't restate it. Override only what makes the run isolated and reproducible: the fixture app
24
+ run because `iocd test` prepares the component in dev mode — don't restate it. Override only what
25
+ makes the run isolated and reproducible: the fixture app
25
26
  store, `folders.userData`, log/crash output locations, and similar plumbing. Changing platform
26
27
  behavior here (window mode, Channels, gateway, auth, themes) means the tests no longer exercise the
27
28
  platform the seed ships — you'd be testing something else. Behavior changes belong in
@@ -11,7 +11,7 @@ over copying internal IOCD selectors into a spec.
11
11
 
12
12
  ## Current Generated Version
13
13
 
14
- The generated test package currently pins `@interopio/wdio-iocd-service@1.0.0-next.3`. Its
14
+ The generated test package currently pins `@interopio/wdio-iocd-service@1.0.0-next.4`. Its
15
15
  `@interopio/wdio-iocd-service/models` subpath exports:
16
16
 
17
17
  | Area | Models and types |
@@ -2,18 +2,17 @@
2
2
 
3
3
  ## Missing platform executable
4
4
 
5
- Ensure the configured `iocd` component is installed: run `npm run setup`, or start the seed once with
6
- `npm run dev` and close it before `npm test` (the service starts its own instance).
7
-
8
- If `iocd test` searches for an executable named after the seed's `productName`, but the installed
9
- component still has its default `io.Connect Desktop` name, run `npm run dev` once. Development
10
- preparation applies the seed branding and creates the executable path that the test command expects;
11
- close that development instance before rerunning the tests.
5
+ Ensure the configured `iocd` component is installed by running `npm run setup`. `iocd test`
6
+ automatically performs the same bundle preparation as `iocd dev`: it generates application-owned
7
+ base modifications, applies the seed's base and dev modifications, copies the configured output
8
+ license when enabled, and signs the macOS bundle before resolving the executable. It does not launch
9
+ a separate development instance.
12
10
 
13
11
  ## License prompt or failure
14
12
 
15
- Run from the seed root through `npm test` so the CLI can use `config/iocd.license.key`. In CI, supply
16
- the license via secrets. Never hard-code a license in a spec or fixture.
13
+ Run from the seed root through `npm test` so the CLI can read `config/iocd.license.key` and forward it
14
+ to the test platform as `IOCD_LICENSE_KEY`. In CI, supply the license via secrets. Never hard-code a
15
+ license in a spec or fixture.
17
16
 
18
17
  ## Startup timeout
19
18
 
@@ -10,7 +10,7 @@
10
10
  },
11
11
  "devDependencies": {
12
12
  "@interopio/desktop": "^6.21.0",
13
- "@interopio/wdio-iocd-service": "1.0.0-next.3",
13
+ "@interopio/wdio-iocd-service": "next",
14
14
  "@interopio/workspaces-api": "^4.5.0",
15
15
  "@types/chai": "^5.2.3",
16
16
  "@types/mocha": "^10.0.10",
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getTemplateUpdateWarning = void 0;
4
+ const getTemplateUpdateWarning = (appNames) => `Updating ${appNames.join(", ")} will permanently delete the existing template application files and replace them with the current CLI templates. Any customizations in those app directories will be lost. Commit or copy your work before continuing.`;
5
+ exports.getTemplateUpdateWarning = getTemplateUpdateWarning;
6
+ //# sourceMappingURL=template-update.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"template-update.js","sourceRoot":"","sources":["../../src/utils/template-update.ts"],"names":[],"mappings":";;;AAAO,MAAM,wBAAwB,GAAG,CAAC,QAAkB,EAAU,EAAE,CACrE,YAAY,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,yNAAyN,CAAC;AAD9O,QAAA,wBAAwB,4BACsN"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@interopio/iocd-cli",
3
- "version": "1.0.2",
3
+ "version": "1.1.0",
4
4
  "description": "CLI tool for setting up, building and packaging io.Connect Desktop platforms",
5
5
  "engines": {
6
6
  "node": ">=22.0.0",
@@ -60,6 +60,7 @@
60
60
  "jsonwebtoken": "^9.0.2",
61
61
  "log4js": "^6.9.1",
62
62
  "plist": "^3.1.0",
63
+ "proper-lockfile": "^4.1.2",
63
64
  "undici": "^7.16.0"
64
65
  },
65
66
  "devDependencies": {
@@ -73,6 +74,7 @@
73
74
  "@types/jsonwebtoken": "^9.0.10",
74
75
  "@types/log4js": "^0.0.33",
75
76
  "@types/node": "^22.19.17",
77
+ "@types/proper-lockfile": "^4.1.4",
76
78
  "@typescript-eslint/eslint-plugin": "^8.47.0",
77
79
  "@typescript-eslint/parser": "^8.47.0",
78
80
  "cross-env": "^10.1.0",