wizards 0.4.7 → 0.5.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/README.md +45 -42
- package/apps/runtime/dist/agents/studio-assistant.js +8 -8
- package/apps/runtime/dist/app.js +7 -4
- package/apps/runtime/dist/assistant/primer.js +1 -1
- package/apps/runtime/dist/auth/index.js +2 -2
- package/apps/runtime/dist/authoring/guide.js +8 -8
- package/apps/runtime/dist/cli/account.js +31 -28
- package/apps/runtime/dist/cli/autostart.js +5 -3
- package/apps/runtime/dist/cli/clients.js +1 -1
- package/apps/runtime/dist/cli/connect.js +24 -24
- package/apps/runtime/dist/cli/features.js +6 -6
- package/apps/runtime/dist/cli/main.js +51 -39
- package/apps/runtime/dist/cli/mcp.js +5 -4
- package/apps/runtime/dist/cli/menu.js +32 -30
- package/apps/runtime/dist/cli/report.js +7 -9
- package/apps/runtime/dist/cli/setup.js +42 -38
- package/apps/runtime/dist/cli/start.js +16 -15
- package/apps/runtime/dist/cli/status.js +20 -20
- package/apps/runtime/dist/cli/ui.js +9 -2
- package/apps/runtime/dist/cli/update.js +6 -6
- package/apps/runtime/dist/cli/validate.js +1 -1
- package/apps/runtime/dist/connectors/external.js +3 -2
- package/apps/runtime/dist/connectors/index.js +5 -5
- package/apps/runtime/dist/connectors/plugin-connections.js +2 -2
- package/apps/runtime/dist/connectors/via-account.js +5 -5
- package/apps/runtime/dist/db/control-schema.js +14 -0
- package/apps/runtime/dist/db/migrations/control/0009_plugin_claim.sql +9 -0
- package/apps/runtime/dist/db/migrations/control/meta/0009_snapshot.json +561 -0
- package/apps/runtime/dist/db/migrations/control/meta/_journal.json +7 -0
- package/apps/runtime/dist/db/schema.js +9 -9
- package/apps/runtime/dist/docs/dev/index.md +16 -14
- package/apps/runtime/dist/docs/dev/plugins/connections.md +27 -24
- package/apps/runtime/dist/docs/dev/plugins/events.md +19 -17
- package/apps/runtime/dist/docs/dev/plugins/examples.md +13 -12
- package/apps/runtime/dist/docs/dev/plugins/index.md +29 -24
- package/apps/runtime/dist/docs/dev/plugins/layout.md +20 -19
- package/apps/runtime/dist/docs/dev/plugins/quick-start.md +16 -15
- package/apps/runtime/dist/docs/dev/plugins/reference.md +52 -40
- package/apps/runtime/dist/docs/dev/plugins/reloading.md +24 -23
- package/apps/runtime/dist/docs/dev/plugins/routes.md +26 -22
- package/apps/runtime/dist/docs/dev/plugins/runners.md +49 -44
- package/apps/runtime/dist/docs/dev/plugins/server.md +95 -43
- package/apps/runtime/dist/docs/dev/plugins/shipping.md +19 -16
- package/apps/runtime/dist/docs/dev/plugins/space.md +75 -69
- package/apps/runtime/dist/docs/dev/plugins/starters.md +22 -17
- package/apps/runtime/dist/docs/dev/plugins/studio.md +80 -37
- package/apps/runtime/dist/docs/dev/plugins/styling.md +44 -41
- package/apps/runtime/dist/docs/dev/plugins/tables.md +11 -11
- package/apps/runtime/dist/docs/dev/plugins/tools.md +26 -25
- package/apps/runtime/dist/docs/dev/wizard-format.md +35 -23
- package/apps/runtime/dist/docs/user/ai-apps.md +46 -43
- package/apps/runtime/dist/docs/user/assistant.md +41 -36
- package/apps/runtime/dist/docs/user/build-a-wizard.md +64 -39
- package/apps/runtime/dist/docs/user/command-line.md +47 -44
- package/apps/runtime/dist/docs/user/connectors.md +40 -35
- package/apps/runtime/dist/docs/user/create-account.md +27 -22
- package/apps/runtime/dist/docs/user/data.md +29 -29
- package/apps/runtime/dist/docs/user/first-start.md +26 -28
- package/apps/runtime/dist/docs/user/index.md +16 -17
- package/apps/runtime/dist/docs/user/install.md +28 -27
- package/apps/runtime/dist/docs/user/local-only.md +21 -17
- package/apps/runtime/dist/docs/user/models.md +92 -84
- package/apps/runtime/dist/docs/user/plugins.md +28 -23
- package/apps/runtime/dist/docs/user/run.md +51 -50
- package/apps/runtime/dist/docs/user/server.md +9 -9
- package/apps/runtime/dist/docs/user/space.md +87 -65
- package/apps/runtime/dist/docs/user/steps.md +73 -69
- package/apps/runtime/dist/docs/user/test-and-share.md +127 -105
- package/apps/runtime/dist/docs/user/troubleshooting.md +40 -38
- package/apps/runtime/dist/docs/user/wordpress.md +62 -54
- package/apps/runtime/dist/documents/parse.js +2 -2
- package/apps/runtime/dist/engenty/shims/web-ingest.js +17 -1
- package/apps/runtime/dist/engine/input.js +4 -4
- package/apps/runtime/dist/engine/push.js +2 -2
- package/apps/runtime/dist/engine/runner.js +8 -8
- package/apps/runtime/dist/engine/steps.js +4 -4
- package/apps/runtime/dist/engine/surface.js +1 -1
- package/apps/runtime/dist/film/step.js +3 -3
- package/apps/runtime/dist/harness/claude.js +1 -1
- package/apps/runtime/dist/harness/codex.js +1 -1
- package/apps/runtime/dist/harness/model.js +2 -2
- package/apps/runtime/dist/harness/terminal.js +3 -3
- package/apps/runtime/dist/mcp/handler.js +2 -2
- package/apps/runtime/dist/mcp/tools.js +9 -9
- package/apps/runtime/dist/models.js +15 -15
- package/apps/runtime/dist/plugins/claims.js +56 -0
- package/apps/runtime/dist/plugins/loader.js +2 -0
- package/apps/runtime/dist/plugins/public.js +2 -3
- package/apps/runtime/dist/plugins/runs.js +13 -8
- package/apps/runtime/dist/render/chromium.js +24 -11
- package/apps/runtime/dist/routes/api.js +16 -10
- package/apps/runtime/dist/routes/debug.js +1 -1
- package/apps/runtime/dist/routes/delivery.js +46 -0
- package/apps/runtime/dist/routes/lang.js +7 -0
- package/apps/runtime/dist/routes/marketplace.js +2 -1
- package/apps/runtime/dist/routes/plugin-public.js +2 -1
- package/apps/runtime/dist/routes/plugins.js +13 -14
- package/apps/runtime/dist/routes/runs.js +59 -49
- package/apps/runtime/dist/routes/studio.js +58 -28
- package/apps/runtime/dist/services/access.js +3 -3
- package/apps/runtime/dist/services/assistant-chats.js +1 -1
- package/apps/runtime/dist/services/brand.js +2 -2
- package/apps/runtime/dist/services/cloud.js +5 -4
- package/apps/runtime/dist/services/errors.js +2 -1
- package/apps/runtime/dist/services/knowledge-model.js +10 -10
- package/apps/runtime/dist/services/knowledge.js +19 -19
- package/apps/runtime/dist/services/marketplace.js +2 -2
- package/apps/runtime/dist/services/package-file.js +12 -9
- package/apps/runtime/dist/services/package.js +3 -3
- package/apps/runtime/dist/services/project-files.js +15 -17
- package/apps/runtime/dist/services/project-index.js +10 -10
- package/apps/runtime/dist/services/projects.js +13 -8
- package/apps/runtime/dist/services/relevance.js +3 -3
- package/apps/runtime/dist/services/runners.js +4 -3
- package/apps/runtime/dist/services/runs.js +3 -3
- package/apps/runtime/dist/services/site.js +10 -10
- package/apps/runtime/dist/services/space-categories.js +22 -22
- package/apps/runtime/dist/services/space-data.js +16 -16
- package/apps/runtime/dist/services/space-origin.js +4 -4
- package/apps/runtime/dist/services/spaces.js +10 -10
- package/apps/runtime/dist/services/wizards.js +5 -5
- package/apps/runtime/dist/tools/index.js +1 -1
- package/apps/runtime/dist/tools/net-guard.js +135 -24
- package/apps/runtime/dist/tools/pages.js +4 -4
- package/apps/runtime/dist/tools/plugin.js +1 -1
- package/apps/runtime/dist/tools/project.js +10 -10
- package/apps/runtime/dist/tools/store.js +1 -1
- package/apps/runtime/dist/widgets/step.js +1 -1
- package/apps/web/dist/assets/AboutDialog-DaYwk84X.js +1 -0
- package/apps/web/dist/assets/{ChangelogDialog-Cm25slr3.js → ChangelogDialog-CsYbEayb.js} +1 -1
- package/apps/web/dist/assets/{ChatView-BXtXWnqK.js → ChatView-BRD3fKZU.js} +1 -1
- package/apps/web/dist/assets/EditorPage-ocPlZD3E.js +3 -0
- package/apps/web/dist/assets/{FlowPreview-BsfjDVv8.js → FlowPreview-Bm7sv746.js} +1 -1
- package/apps/web/dist/assets/{Harness-B0hD5Pp7.js → Harness-DKE-YNA5.js} +1 -1
- package/apps/web/dist/assets/{NewWizardChannels-DMDp9Ao5.js → NewWizardChannels-CnWckqjO.js} +1 -1
- package/apps/web/dist/assets/{NewWizardPage-aOisxyk2.js → NewWizardPage-BXTpbHVM.js} +1 -1
- package/apps/web/dist/assets/{OnboardingPage-Czb0pOyy.js → OnboardingPage-3Rz5uOsa.js} +1 -1
- package/apps/web/dist/assets/{ProjectPage-DPCtb42K.js → ProjectPage-QdSJwm3k.js} +1 -1
- package/apps/web/dist/assets/{PublicRunner-CvyA-gkf.js → PublicRunner-DEpBer5g.js} +1 -1
- package/apps/web/dist/assets/ReadOnly-rr_RJD-a.js +1 -0
- package/apps/web/dist/assets/{RunDrawer-BCiPEz9g.js → RunDrawer-BsZt0tL9.js} +1 -1
- package/apps/web/dist/assets/{RunnerView-4z6DMzE6.js → RunnerView-BbRukEdE.js} +1 -1
- package/apps/web/dist/assets/SettingsPage-qkWsQIMN.js +1 -0
- package/apps/web/dist/assets/{SetupPage-YFoU_nXK.js → SetupPage-PzvPPLfM.js} +1 -1
- package/apps/web/dist/assets/{SharePage-BBHiJ34e.js → SharePage-7vdDWG1n.js} +1 -1
- package/apps/web/dist/assets/changelog-BFdAYD28.js +1 -0
- package/apps/web/dist/assets/{esm-hSq-jeOG.js → esm-g0kaGp8t.js} +1 -1
- package/apps/web/dist/assets/{index-CSeBGwy0.css → index-Bi2x2g7n.css} +1 -1
- package/apps/web/dist/assets/{index-DB_iwB35.js → index-BzPid1oQ.js} +4 -4
- package/apps/web/dist/assets/lock-BK9RYIft.js +1 -0
- package/apps/web/dist/assets/oss-credits-BJrR7BR1.js +1 -0
- package/apps/web/dist/assets/{phone-CeqyvwK-.js → phone-DtkY0NfU.js} +1 -1
- package/apps/web/dist/assets/{settings-menu-BK8WpcGv.js → settings-menu-7EJQRFOi.js} +1 -1
- package/apps/web/dist/assets/{ui-BbIh6SOJ.js → ui-B6S5hYPd.js} +3 -3
- package/apps/web/dist/assets/{upload-BQrAlHIG.js → upload-rYCAy7ox.js} +1 -1
- package/apps/web/dist/index.html +3 -3
- package/apps/web/dist/mcp/flow.html +4 -4
- package/bin/wizards.mjs +1 -1
- package/node_modules/@engenty-wizards/plugin-sdk/dist/index.d.ts +33 -14
- package/node_modules/@engenty-wizards/plugin-sdk/dist/studio.d.ts +3 -3
- package/node_modules/@engenty-wizards/shared/dist/definition.d.ts +690 -690
- package/node_modules/@engenty-wizards/shared/dist/definition.js +1 -1
- package/node_modules/@engenty-wizards/shared/dist/engenty/data-tables/columns.d.ts +76 -76
- package/node_modules/@engenty-wizards/shared/dist/feature-flags.d.ts +3 -3
- package/node_modules/@engenty-wizards/shared/dist/feature-flags.js +3 -3
- package/node_modules/@engenty-wizards/shared/dist/knowledge.d.ts +13 -13
- package/node_modules/@engenty-wizards/shared/dist/knowledge.js +4 -4
- package/node_modules/@engenty-wizards/shared/dist/marketplace.d.ts +4 -4
- package/node_modules/@engenty-wizards/shared/dist/projects.js +1 -1
- package/node_modules/@engenty-wizards/shared/dist/run.d.ts +48 -48
- package/node_modules/@engenty-wizards/shared/dist/run.js +48 -48
- package/node_modules/@engenty-wizards/shared/dist/space-data.d.ts +2 -2
- package/node_modules/@engenty-wizards/shared/dist/surface.d.ts +20 -20
- package/node_modules/@engenty-wizards/shared/dist/wizard-package.js +1 -1
- package/package.json +5 -4
- package/apps/web/dist/assets/AboutDialog-BtAuA44m.js +0 -1
- package/apps/web/dist/assets/EditorPage-B4jX_Ckc.js +0 -3
- package/apps/web/dist/assets/ReadOnly-DFysMEMF.js +0 -1
- package/apps/web/dist/assets/SettingsPage-BKkOfz6P.js +0 -1
- package/apps/web/dist/assets/changelog-D8WjOq7d.js +0 -1
- package/apps/web/dist/assets/circle-alert-BVj6idzu.js +0 -1
- package/apps/web/dist/assets/lock-BoWS-JhN.js +0 -1
- package/apps/web/dist/assets/oss-credits-BQQX0kvk.js +0 -1
package/README.md
CHANGED
|
@@ -10,32 +10,28 @@
|
|
|
10
10
|
Let AI do the work.
|
|
11
11
|
</p>
|
|
12
12
|
|
|
13
|
-
<p align="center">
|
|
14
|
-
<img src="docs/assets/setup.png" alt="The first start of engenty wizards: choose the engine it thinks with — Codex, Claude Code, Gemini CLI, Cursor Agent or your own keys">
|
|
15
|
-
</p>
|
|
16
|
-
|
|
17
13
|
## What it does
|
|
18
14
|
|
|
19
|
-
- **Describe it, get a wizard.** Say in plain words what you do again and again
|
|
20
|
-
an image, a research briefing, an invoice, a quote, a damage report
|
|
15
|
+
- **Describe it, get a wizard.** Say in plain words what you do again and again – a post with
|
|
16
|
+
an image, a research briefing, an invoice, a quote, a damage report – and engenty builds a
|
|
21
17
|
wizard for it: pages that ask what it needs, AI steps that do the work.
|
|
22
18
|
- **AI steps do the work.** They research the web, write, draw images, render video, read PDFs,
|
|
23
|
-
scans and
|
|
19
|
+
scans and emails, build documents and dashboards, and write into other services over MCP, HTTP
|
|
24
20
|
or a browser. Anything that changes an account asks first.
|
|
25
21
|
- **Share it with a link.** Anyone can run a wizard in the browser, on a phone too: camera,
|
|
26
22
|
code scan, voice notes, location and a drawn signature included. Results download as PDF,
|
|
27
|
-
Word, HTML, Markdown, PNG, MP4, CSV, Excel or JSON, or go out as a link.
|
|
28
|
-
- **Runs on your machine, on your subscription.** It
|
|
23
|
+
Word, HTML, Markdown, PNG, MP4, MP3, CSV, Excel or JSON, or go out as a link.
|
|
24
|
+
- **Runs on your machine, on your subscription.** It uses Codex, Claude Code, Gemini CLI
|
|
29
25
|
or Cursor Agent when one is installed and signed in, so no API key is needed. Or bring a key
|
|
30
26
|
(Vercel AI Gateway, OpenAI, Anthropic), or a local model through Ollama. Your wizards and
|
|
31
27
|
results stay in a folder on your machine.
|
|
32
28
|
|
|
33
29
|
## How it looks
|
|
34
30
|
|
|
35
|
-
The studio: a wizard
|
|
31
|
+
The studio: a wizard’s steps as a flow with its branches, next to the conversation that changes them.
|
|
36
32
|
|
|
37
33
|
<p align="center">
|
|
38
|
-
<img src="docs/assets/studio.png" alt="The studio of engenty wizards: the flow of a wizard that collects a month's receipts for bookkeeping
|
|
34
|
+
<img src="docs/assets/studio.png" alt="The studio of engenty wizards: the flow of a wizard that collects a month's receipts for bookkeeping – two pages of questions, AI steps that branch to the inbox and to customer portals, a review and the result – with the conversation beside it">
|
|
39
35
|
</p>
|
|
40
36
|
|
|
41
37
|
A wizard in use: it asks on one page, then on the next, and ends with the result to download or share.
|
|
@@ -46,14 +42,14 @@ A wizard in use: it asks on one page, then on the next, and ends with the result
|
|
|
46
42
|
|
|
47
43
|
## Get started
|
|
48
44
|
|
|
49
|
-
Create an account at [engenty.ai](https://engenty.ai): it is in a closed beta, so
|
|
50
|
-
takes your
|
|
45
|
+
Create an account at [engenty.ai](https://engenty.ai): it is in a closed beta, so “Get started”
|
|
46
|
+
takes your email for an invitation, or your invitation code. Signed in, the studio asks who
|
|
51
47
|
your team is, reads your website into your space, takes first documents, and you build your
|
|
52
|
-
first wizard in the browser. Links run day and night on the team
|
|
48
|
+
first wizard in the browser. Links run day and night on the team’s credits.
|
|
53
49
|
|
|
54
50
|
## Install it on your computer
|
|
55
51
|
|
|
56
|
-
The same account on your own machine: it
|
|
52
|
+
The same account on your own machine: it runs on your Claude, ChatGPT, Gemini or Cursor
|
|
57
53
|
subscription, reads your local files and browses for you, and what you publish keeps running in
|
|
58
54
|
the cloud behind the same links. On macOS or Linux, in a terminal:
|
|
59
55
|
|
|
@@ -65,19 +61,23 @@ It needs nothing but `curl` and `tar` and asks for no password. It brings its ow
|
|
|
65
61
|
Node you already have is left alone), installs engenty wizards into `~/.engenty/wizards` and
|
|
66
62
|
then walks you through the rest:
|
|
67
63
|
|
|
68
|
-
- **Your engenty account.**
|
|
69
|
-
|
|
64
|
+
- **Your engenty account.** “Sign in now?”: a code and the browser for the sign-in; what you
|
|
65
|
+
publish on this computer then runs in the cloud too. Say no, and `wizards account sign-in`
|
|
66
|
+
does it any time.
|
|
70
67
|
`--local` leaves the account out: nothing leaves the computer, links answer on it only
|
|
71
68
|
([local only](https://engenty.ai/docs/user/local-only)).
|
|
72
|
-
- **
|
|
73
|
-
offers to install
|
|
69
|
+
- **An AI client.** It looks for Codex, Claude Code, Gemini CLI and Cursor Agent and
|
|
70
|
+
offers to install the missing ones – first the one whose app (Claude, ChatGPT, Cursor) is
|
|
74
71
|
on your Mac, as its subscription is most likely yours already. The first page of the studio
|
|
75
|
-
installs them too. Or use your account
|
|
76
|
-
|
|
77
|
-
|
|
72
|
+
installs them too. Or use your account’s credits, an API key, [Ollama](https://ollama.com) or,
|
|
73
|
+
on a Mac with Apple silicon and macOS 26, Apple Intelligence.
|
|
74
|
+
- **A browser and ffmpeg** (optional): Chrome, Edge or Chromium (on a Mac also Brave) for PDF
|
|
75
|
+
and PNG exports and for steps that use a browser, ffmpeg for MP4 videos of animated widgets.
|
|
78
76
|
- **Start at login** (optional): engenty wizards starts in the background when you log in (a
|
|
79
77
|
LaunchAgent on a Mac, a systemd user service on Linux). Links and AI clients then always
|
|
80
78
|
reach it. `wizards autostart on` or `off` switches it later.
|
|
79
|
+
- **Your AI apps** (optional): adds your wizards to the AI apps it finds, such as Claude
|
|
80
|
+
Desktop, Cursor or Codex. `wizards connect` and `wizards disconnect` do it later.
|
|
81
81
|
|
|
82
82
|
It starts nothing. Afterwards:
|
|
83
83
|
|
|
@@ -86,6 +86,7 @@ wizards start
|
|
|
86
86
|
```
|
|
87
87
|
|
|
88
88
|
starts it and opens the studio; it runs while that terminal is open, Ctrl-C stops it.
|
|
89
|
+
`wizards start -s` starts it in the background instead.
|
|
89
90
|
`wizards` opens a menu with all of it, `wizards status` says what is installed and what runs,
|
|
90
91
|
`wizards setup` runs the guided setup again, and `wizards --help` lists the rest.
|
|
91
92
|
|
|
@@ -99,29 +100,30 @@ You need Node.js 24.11 or newer and pnpm 10 (`corepack enable`).
|
|
|
99
100
|
|
|
100
101
|
```bash
|
|
101
102
|
git clone https://github.com/engenty/wizards.git
|
|
102
|
-
cd
|
|
103
|
+
cd wizards
|
|
103
104
|
pnpm install
|
|
104
105
|
pnpm build
|
|
105
106
|
pnpm wizards
|
|
106
107
|
```
|
|
107
108
|
|
|
108
|
-
pnpm may list
|
|
109
|
+
pnpm may list “Ignored build scripts” – that’s expected, nothing to do.
|
|
109
110
|
|
|
110
111
|
Code steps (shell, Node, Python) run in a sandbox when Docker and the sandbox image are on the
|
|
111
112
|
machine; a checkout brings its own sandbox, the installed version has none yet.
|
|
112
113
|
|
|
113
114
|
## First start
|
|
114
115
|
|
|
115
|
-
The setup shows your account at the top and asks
|
|
116
|
-
client that is installed on your computer
|
|
117
|
-
it in for you in a terminal right on the page
|
|
116
|
+
The setup shows your account at the top and asks how the AI should run. Pick an AI
|
|
117
|
+
client that is installed on your computer – engenty uses your existing subscription and signs
|
|
118
|
+
it in for you in a terminal right on the page – your account’s credits, Apple Intelligence on a
|
|
119
|
+
Mac that has it, or your own keys.
|
|
118
120
|
It stays until a test call works, then the studio opens.
|
|
119
121
|
|
|
120
|
-
Change it later under Settings.
|
|
122
|
+
Change it later under Settings → Models.
|
|
121
123
|
|
|
122
124
|
## Using it
|
|
123
125
|
|
|
124
|
-
- **Make a wizard:** describe it in the studio
|
|
126
|
+
- **Make a wizard:** describe it in the studio’s chat, or start from one of the templates.
|
|
125
127
|
You see the steps as a diagram and can change any of them.
|
|
126
128
|
- **Run and share:** try it yourself, then share the link. Shared results are kept for 7 days
|
|
127
129
|
for people without an account.
|
|
@@ -129,8 +131,9 @@ Change it later under Settings.
|
|
|
129
131
|
GitHub, HubSpot and S3 are built in; any other service can be added from its API description
|
|
130
132
|
or MCP server through the [integrations.sh](https://integrations.sh) registry. Services that
|
|
131
133
|
sign in with OAuth need a few settings first: [Connectors](docs/development.md#connectors).
|
|
132
|
-
- **Build from Claude Code or Codex:** Settings →
|
|
133
|
-
|
|
134
|
+
- **Build from Claude Code or Codex:** Settings → Integrate adds engenty wizards to your AI
|
|
135
|
+
apps (Claude Desktop, Claude Code, Codex, Cursor and others), or `wizards connect` from a
|
|
136
|
+
terminal.
|
|
134
137
|
|
|
135
138
|
Your machine only answers on `localhost`. To let others open shared wizards, run it on a server.
|
|
136
139
|
|
|
@@ -149,12 +152,12 @@ Back up the folder; delete it to start over. Settings go into `~/.engenty/wizard
|
|
|
149
152
|
wizards update
|
|
150
153
|
```
|
|
151
154
|
|
|
152
|
-
This runs the installer again without its questions. The studio says
|
|
153
|
-
out and can run the same update from its
|
|
155
|
+
This runs the installer again without its questions. The studio says in a banner at the top
|
|
156
|
+
when a newer release is out and can run the same update from there or from its About dialog.
|
|
154
157
|
From source: `git pull`, `pnpm install`, `pnpm build`. Your data is brought up to date at the
|
|
155
158
|
next start.
|
|
156
159
|
|
|
157
|
-
To remove engenty wizards, run `wizards autostart off`, then delete `~/.engenty/wizards` (your data is in its `data` folder) and
|
|
160
|
+
To remove engenty wizards, run `wizards stop`, `wizards autostart off` and `wizards disconnect`, then delete `~/.engenty/wizards` (your data is in its `data` folder) and
|
|
158
161
|
`~/.local/bin/wizards`.
|
|
159
162
|
|
|
160
163
|
## Run it on a server
|
|
@@ -163,24 +166,24 @@ With Docker, behind an https proxy (Caddy, Traefik, Coolify):
|
|
|
163
166
|
|
|
164
167
|
```bash
|
|
165
168
|
git clone https://github.com/engenty/wizards.git
|
|
166
|
-
cd
|
|
169
|
+
cd wizards
|
|
167
170
|
cp .env.example .env # set APP_URL to your https address and add a model key
|
|
168
171
|
docker compose up -d --build
|
|
169
172
|
docker compose logs # shows the link to open once
|
|
170
173
|
```
|
|
171
174
|
|
|
172
|
-
Point the proxy at port 8891. On a server, engenty
|
|
173
|
-
AI clients
|
|
175
|
+
Point the proxy at port 8891. On a server, engenty uses your keys or Ollama; the
|
|
176
|
+
AI clients’ subscriptions live on your own computer. The code sandbox is off in this image.
|
|
174
177
|
|
|
175
178
|
## Troubleshooting
|
|
176
179
|
|
|
177
180
|
| | |
|
|
178
181
|
|---|---|
|
|
179
|
-
|
|
|
182
|
+
| “This link is no longer valid” | The link works once. `wizards open` gives this browser a new one. |
|
|
180
183
|
| `wizards`: command not found | Open a new terminal, or run `~/.local/bin/wizards`. |
|
|
181
184
|
| You open it under another address | Set `APP_URL` in `~/.engenty/wizards/.env` to the address you open. |
|
|
182
|
-
| An AI client shows as not signed in | Sign it in on the setup page, or in your own terminal (e.g. `claude`, `codex login`), then
|
|
183
|
-
| PDF or PNG export fails | Install
|
|
185
|
+
| An AI client shows as not signed in | Sign it in on the setup page, or in your own terminal (e.g. `claude`, `codex login`), then “Check again”. |
|
|
186
|
+
| PDF or PNG export fails | Install Chrome, Edge or Chromium (on a Mac also Brave), or set `CHROME_PATH` to one. |
|
|
184
187
|
| Port 24368 is taken | The next free port is used. To fix one, set `API_PORT` in `~/.engenty/wizards/.env`. |
|
|
185
188
|
| Something else | `wizards doctor` checks the install. |
|
|
186
189
|
|
|
@@ -194,12 +197,12 @@ Development server, checks, how it is built, the managed mode:
|
|
|
194
197
|
Plugins add tools for steps, routes with their own tables and pages in the studio, without
|
|
195
198
|
changing the runtime: [docs/content/dev/plugins](docs/content/dev/plugins/index.md).
|
|
196
199
|
|
|
197
|
-
The documentation
|
|
200
|
+
The documentation – a user guide and the developer docs – is in [docs/content](docs/content)
|
|
198
201
|
and is a site of its own: `pnpm dev:docs`.
|
|
199
202
|
|
|
200
203
|
## License
|
|
201
204
|
|
|
202
|
-
[FSL-1.1-MIT](LICENSE): use it for yourself and your company, run it, change it
|
|
205
|
+
[FSL-1.1-MIT](LICENSE): use it for yourself and your company, run it, change it – just don’t
|
|
203
206
|
offer it to others as a competing product or service. Each release becomes MIT two years
|
|
204
207
|
after it is published. [COPYRIGHTS.md](COPYRIGHTS.md) names the owner, the marks, what is not ours and the
|
|
205
208
|
third-party software with its licences.
|
|
@@ -24,7 +24,7 @@ export function signalText(taken) {
|
|
|
24
24
|
const MAX_STEPS = 24;
|
|
25
25
|
const SYSTEM = `You are Goose, the assistant of the engenty wizards studio. You stand on every page of the studio except the wizard editor, which has a chat of its own: the space's pages, the settings, the plugins' pages. You help the person who works here understand the app, set it up and find their way.
|
|
26
26
|
|
|
27
|
-
You talk to the person. Answer in their language, briefly and warmly: a few sentences, a short list where it helps. Never mention JSON, ids, keys or tool names. Call it a space
|
|
27
|
+
You talk to the person. Answer in their language, briefly and warmly: a few sentences, a short list where it helps. Never mention JSON, ids, keys or tool names. Call it a space, never a project: the tools say project, the app says space. Name the studio's parts and pages as the studio shows them in the person's language.
|
|
28
28
|
|
|
29
29
|
${PRIMER}
|
|
30
30
|
|
|
@@ -42,9 +42,9 @@ THE PAGE
|
|
|
42
42
|
- fill_field never saves: say that the person checks and saves. You never press buttons for the person.
|
|
43
43
|
|
|
44
44
|
THE SPACE
|
|
45
|
-
- Where a space's tools are there, you also fill the space in: what every wizard of the space draws on — who they are (title, about), the brand (logos, colours), assets (images, graphics, videos), documents, and facts (label → value: address, VAT
|
|
46
|
-
- A website: read_website it first. You get the page's text, colours from its stylesheet, logo candidates and the links to imprint / contact / about. Read those pages too (at most four more) for address, VAT
|
|
47
|
-
- Facts: one fact per thing, a short label in the person's language ("Adresse", "
|
|
45
|
+
- Where a space's tools are there, you also fill the space in: what every wizard of the space draws on — who they are (title, about), the brand (logos, colours), assets (images, graphics, videos), documents, and facts (label → value: address, VAT ID, phone, opening hours — anything). The space as it is now comes with every message then; you change it ONLY through tools.
|
|
46
|
+
- A website: read_website it first. You get the page's text, colours from its stylesheet, logo candidates and the links to imprint / contact / about. Read those pages too (at most four more) for address, VAT ID, register number, phone, email, bank details, who runs it.
|
|
47
|
+
- Facts: one fact per thing, a short label in the person's language ("Adresse", "USt-IdNr.", "Telefon"), the value on one line where it fits. Only what a source or the person states — never guess, never invent. Keep the facts that are there; a fact with a known label is updated.
|
|
48
48
|
- About: two to five sentences — what they do, for whom, what sets them apart, the tone they write in. Rewrite it only when you learned something new or the person asks.
|
|
49
49
|
- Colours: two to six, the main one first, each with a name that says what it is for ("Primär", "Hintergrund", "Text"). Take them from the stylesheet's variables or its most used colours, never from photos. set_colors replaces the list: pass all colours that should remain. Colours in no section are the standard ones; the first of them is the accent. Colour sections are optional like logo sections: only for a further palette a brand guide or the person names for its own use ("Illustration – drawings and charts"), never for the standard colours. A brand's gradients (set_gradients, as CSS) only where a brand guide or the site's stylesheet has them; patterns and background fills are pictures the person uploads.
|
|
50
50
|
- Logos: save the best candidate (an SVG or a large PNG rather than a favicon); a second one only if it truly differs (for dark ground, a signet). A few images that show the business (header, team, products) may be saved as assets — a handful, never everything.
|
|
@@ -52,7 +52,7 @@ THE SPACE
|
|
|
52
52
|
- Typography: the brand's fonts (set_typography), each with what it is for ("Headings", "Body text") and the weights it uses — from the website's stylesheet (read_website lists its fonts) or a brand guide; system and generic faces are no brand fonts. A font's licence and what it may be used for (web, documents, print, images, video) only where a brand guide, the font's own page or the person says so; the wizards keep to it. A type scale (text styles: name, size, weight, line height, letter spacing) only when a brand guide gives one.
|
|
53
53
|
- Asset sections are optional too: tabs of one kind each ("Icons", "Background images"), made with set_asset_sections only when the space holds enough assets of clearly different kinds or the person asks; a handful of pictures stay in the general tab.
|
|
54
54
|
- Files the person attached are stored already; the message names them. look_at_file shows you a picture or a document's text. Give a file a description with describe_file when it has none or the person says what it is. Take facts from a document when asked.
|
|
55
|
-
-
|
|
55
|
+
- Knowledge is what the wizards' steps look things up in: pages, tables and files, kept apart by typed categories. Documents the person attaches are read into Knowledge by themselves: say so; do not copy their text into facts unless asked. A website, a sitemap or a folder whose entries should go into Knowledge is a source: where a tool proposes sources, use it (the person takes the proposal on its card); where there is none, say that sources need the Sources plugin.
|
|
56
56
|
- Talking from another page than Info & brand, change title, about, logos, colours and facts only when the person asks.
|
|
57
57
|
- A space that is read-only (synced from a local install, or a team that builds elsewhere) has no tools: say where it is changed.
|
|
58
58
|
|
|
@@ -113,9 +113,9 @@ async function projectState(userId, projectId) {
|
|
|
113
113
|
const files = await projectFiles(projectId);
|
|
114
114
|
const categories = await categoryRows(projectId);
|
|
115
115
|
return {
|
|
116
|
-
|
|
116
|
+
knowledge: {
|
|
117
117
|
...(await knowledgeCounts(projectId)),
|
|
118
|
-
|
|
118
|
+
categories: categories.map((c) => `${c.name} (${c.type}${c.proposed ? ", proposed" : ""})`),
|
|
119
119
|
},
|
|
120
120
|
title: p.brand.name ?? "",
|
|
121
121
|
about: p.brand.about ?? "",
|
|
@@ -799,7 +799,7 @@ export async function runStudioAssistant(input) {
|
|
|
799
799
|
? `The space "${project.name}" is read-only here: nothing of it can be changed in this studio.`
|
|
800
800
|
: "No space is open.",
|
|
801
801
|
part === "knowledge"
|
|
802
|
-
? "The person talks to you from
|
|
802
|
+
? "The person talks to you from Knowledge: they want the wizards to know something."
|
|
803
803
|
: "",
|
|
804
804
|
space && !(brandOn.brandSections && brandOn.brandRules && brandOn.typography)
|
|
805
805
|
? `Not in this studio (no tools for it; never offer it): ${[
|
package/apps/runtime/dist/app.js
CHANGED
|
@@ -23,7 +23,7 @@ import { PLUGIN_NAME, pluginArchive, pluginMarketplace } from "./plugin.js";
|
|
|
23
23
|
import { apiRoutes } from "./routes/api.js";
|
|
24
24
|
import { browserReport, localDebugRoutes } from "./routes/debug.js";
|
|
25
25
|
import { internalRoutes } from "./routes/internal.js";
|
|
26
|
-
import { inLang, requestLang } from "./routes/lang.js";
|
|
26
|
+
import { inLang, notFoundAnswer, requestLang } from "./routes/lang.js";
|
|
27
27
|
import { marketplaceStudio } from "./routes/marketplace.js";
|
|
28
28
|
import { publicPluginRoutes } from "./routes/plugin-public.js";
|
|
29
29
|
import { pluginRoutes } from "./routes/plugins.js";
|
|
@@ -67,7 +67,7 @@ const ticketedRun = /^\/api\/runs\/([^/]+)(\/|$)/;
|
|
|
67
67
|
app.use("*", async (c, next) => {
|
|
68
68
|
if (!managed && !hostAllowed(c.req.header("host") ?? new URL(c.req.url).host)) {
|
|
69
69
|
// Says where it does answer: the studio opened under another name shows the way there.
|
|
70
|
-
return c.json({ error: "
|
|
70
|
+
return c.json({ error: "This address isn’t allowed.", code: "host", appUrl: env.appUrl }, 403);
|
|
71
71
|
}
|
|
72
72
|
const origin = c.req.header("origin");
|
|
73
73
|
const path = c.req.path.startsWith(`${basePath}/`)
|
|
@@ -201,7 +201,10 @@ if (serves.studio) {
|
|
|
201
201
|
app.use("/api/studio/*", async (c, next) => {
|
|
202
202
|
const user = await principalOf(c);
|
|
203
203
|
if (!user) {
|
|
204
|
-
return c.json({
|
|
204
|
+
return c.json({
|
|
205
|
+
error: inLang(c, "Du bist nicht angemeldet.", "You’re not signed in."),
|
|
206
|
+
code: "unauthorized",
|
|
207
|
+
}, 401);
|
|
205
208
|
}
|
|
206
209
|
if ((await tenantStatus(user.tenantId)) === "suspended") {
|
|
207
210
|
return c.json({
|
|
@@ -257,7 +260,7 @@ if (serves.studio) {
|
|
|
257
260
|
return c.body(new Uint8Array(zip), 200, { "content-type": "application/zip" });
|
|
258
261
|
});
|
|
259
262
|
}
|
|
260
|
-
app.all("/api/*", (c) => c.json(
|
|
263
|
+
app.all("/api/*", (c) => c.json(notFoundAnswer(c), 404));
|
|
261
264
|
/**
|
|
262
265
|
* `/w/<token>/<runner>`: a plugin's page runner, where the tenant has it and the wizard offers
|
|
263
266
|
* it; otherwise the next handler (the app's page, which knows `steps`, `chat` and run ids).
|
|
@@ -10,7 +10,7 @@ Words
|
|
|
10
10
|
- Studio: where wizards are built. Home lists the space's wizards; the editor (/edit/<id>) shows a wizard's flow as a diagram with its own chat (the architect) that builds and changes it.
|
|
11
11
|
- Wizard: a flow of steps a person walks through on a link. Step kinds: a page (fields to fill in), an AI step (an agent with tools: web search, reading files, writing documents, images, video, pages, other services), a review, and the result.
|
|
12
12
|
- Run: one person going through a wizard once. Results lists every run that reached its result.
|
|
13
|
-
- Space: what all wizards of a team know. Its page has four parts: Info & brand (title, about, logos, colours, assets, facts),
|
|
13
|
+
- Space: what all wizards of a team know. Its page has four parts: Info & brand (title, about, logos, colours, assets, facts), Knowledge (pages, tables and files the AI steps look things up in, kept apart by typed categories), Data (tables and pages the wizards keep) and Results (finished runs).
|
|
14
14
|
- Model class: the kind of model a step needs (Classifier, Standard, High, Highest for text; Image, Video, Speech, Audio). Which model serves a class is a setting (Settings › Models), not part of the wizard.
|
|
15
15
|
|
|
16
16
|
Thinking: an installed AI client on the person's subscription (Claude Code, Codex, Gemini CLI, Cursor Agent), own API keys (OpenAI, Anthropic, Google, fal.ai, ElevenLabs, Replicate, Vercel AI Gateway), a local model (Ollama), or engenty credits from an account. Settings › Models shows which way serves each class and what is missing.
|
|
@@ -184,7 +184,7 @@ export const authRoutes = new Hono()
|
|
|
184
184
|
usedTickets.set(ticket, expires);
|
|
185
185
|
}
|
|
186
186
|
else if (managed || !accessKey || !sameValue(given, accessKey)) {
|
|
187
|
-
return c.text("This link is no longer valid.
|
|
187
|
+
return c.text("This link is no longer valid. Run wizards open to get a new one.", 403);
|
|
188
188
|
}
|
|
189
189
|
else {
|
|
190
190
|
accessKey = null;
|
|
@@ -285,7 +285,7 @@ export const authRoutes = new Hono()
|
|
|
285
285
|
}
|
|
286
286
|
catch (err) {
|
|
287
287
|
console.error("[account]", err);
|
|
288
|
-
return c.html(closePage("The sign-in
|
|
288
|
+
return c.html(closePage("The sign-in didn’t work. Try again."), 400);
|
|
289
289
|
}
|
|
290
290
|
}
|
|
291
291
|
const state = unseal(getCookie(c, STATE_COOKIE) ?? "");
|
|
@@ -24,7 +24,7 @@ type List = {
|
|
|
24
24
|
key?: columnId // rows are matched on this column: saving a row with a known key updates that row
|
|
25
25
|
shared?: true // ONE list for every run (leads, sign-ups, bookings, a log) instead of one per person.
|
|
26
26
|
// The person running the wizard never sees it: no list field, review or deliverable of it;
|
|
27
|
-
// the admin sees and edits it in the studio under Space →
|
|
27
|
+
// the admin sees and edits it in the studio under Space → Data
|
|
28
28
|
check?: { file?: columnId, status?: columnId }
|
|
29
29
|
// a review that shows the list lets the person go through it ROW BY ROW on a split screen:
|
|
30
30
|
// "file" = a text column holding the path of a kept file (PDF, photo), previewed beside the row;
|
|
@@ -151,10 +151,10 @@ type AgentStep = {
|
|
|
151
151
|
// Every agent step also has, without listing them: list_read / list_write (the wizard's lists), files_list,
|
|
152
152
|
// read_document (PDF, scans and photos, Word, Excel, CSV, saved mails) and scan_documents (invoice / receipt fields, many at once)
|
|
153
153
|
// — on an installed client only where there is something to read: tools or connections, uploads, lists or kept files;
|
|
154
|
-
// and where the space has
|
|
155
|
-
// project_list (by
|
|
154
|
+
// and where the space has Knowledge: project_search (a question, "where" on its typed categories, hits checked for relevance),
|
|
155
|
+
// project_list (by categories), page_read / table_read / project_document (an item whole, by its path).
|
|
156
156
|
// "pages" brings: page_read / page_write — Markdown pages of the space the wizard keeps for every run (notes, a log
|
|
157
|
-
// that grows with append), shown to the admin under Space →
|
|
157
|
+
// that grows with append), shown to the admin under Space → Data; page_read also reads Knowledge by path.
|
|
158
158
|
// "browser" brings: browser_open/read/click/type/select/scroll/press/back/wait, browser_screenshot (the model looks at the page),
|
|
159
159
|
// browser_run_fast (a decision model clicks through a page's mechanical part, where one is reached),
|
|
160
160
|
// browser_request_credentials (the PERSON types a login into the page — the model never sees it; sign-ins can be remembered),
|
|
@@ -243,9 +243,9 @@ type ResultStep = { type: "result", message?: string, deliverables: { from: step
|
|
|
243
243
|
|
|
244
244
|
Templates (in instructions/prompt): {{fieldId}} · {{steps.stepId}} (whole output) · {{steps.stepId.key}} (json key)
|
|
245
245
|
· {{itemsField}} (line items as a table WITH computed net/VAT/total) · {{itemsField.net|vat|gross}} · {{today}}
|
|
246
|
-
· the project (its settings): {{brand.name}} {{brand.about}} {{brand.colors}} · {{facts.key}} (one fact: address, VAT
|
|
247
|
-
— every AI step already knows them, name one only where the text must carry it; agent steps also search the space's
|
|
248
|
-
and are told its
|
|
246
|
+
· the project (its settings): {{brand.name}} {{brand.about}} {{brand.colors}} · {{facts.key}} (one fact: address, VAT ID, …) · {{facts}} (all facts)
|
|
247
|
+
— every AI step already knows them, name one only where the text must carry it; agent steps also search the space's Knowledge
|
|
248
|
+
and are told its categories: say in a step's instructions which category to filter by when the task names one
|
|
249
249
|
· {{lists.listId}} (the stored list as a table, as it is when the step starts) · {{fileField}} (the names of the uploads, for read_document)
|
|
250
250
|
· {{locationField}} {{locationField.lat|lng|accuracy|label|map}} · {{audioField}} (the transcript) · {{signatureField}} (asset://ID)
|
|
251
251
|
A template may only use fields asked and steps run EARLIER.`;
|
|
@@ -261,7 +261,7 @@ How good wizards look:
|
|
|
261
261
|
- Writing into other systems (CRM, database, spreadsheet, website): an agent step with the matching mcp server, http, or browser tool, preceded by a review step.
|
|
262
262
|
${sandboxGuideLine()}
|
|
263
263
|
- Remembering between runs ("merke dir", "führe eine Liste"): declare a list and let an agent step save into it with list_write; a later run reads it as {{lists.id}} or list_read. Give it a key column so known rows are updated, not duplicated. Never make the person re-upload last time's result.
|
|
264
|
-
- Collecting from everyone who runs the wizard (requests, leads, sign-ups, feedback): a list with "shared": true, saved with list_write. It is the admin's, under Space →
|
|
264
|
+
- Collecting from everyone who runs the wizard (requests, leads, sign-ups, feedback): a list with "shared": true, saved with list_write. It is the admin's, under Space → Data; never show one person's rows to another. Longer text for every run (a running summary, a log): the "pages" tool.
|
|
265
265
|
- The person's mail: one connection of kind "mail", a page field of kind "connection" early in the wizard, and the agent step lists it in "connections". Do not ask for the provider or the address in other fields — the connect field does that.
|
|
266
266
|
- Working in a service for the person (read their Notion, create an issue, look up a customer): import the service as a connector, declare a connection with "connector", put a page field of kind "connection" before the step, and list the connection in the step's "connections". Prefer a connector over the browser whenever the service has one.
|
|
267
267
|
- Logins on websites: never ask for passwords in page fields. An agent step with the browser tool asks the person at the moment it meets the login (browser_request_credentials); write that into its instructions, and that it must go on without the site when the person skips.
|
|
@@ -4,9 +4,9 @@ import { DeviceSignInError, requestDeviceCode, waitForDeviceSignIn } from "../au
|
|
|
4
4
|
import { migrateControlDb } from "../db/client.js";
|
|
5
5
|
import { env } from "../env.js";
|
|
6
6
|
import { featuresFile, fileFeatures, writeFeature } from "../features.js";
|
|
7
|
-
import {
|
|
7
|
+
import { readInstallNote, writeInstallNote } from "./home.js";
|
|
8
8
|
import { openBrowser, runningRuntime, settings } from "./start.js";
|
|
9
|
-
import { bold, busy, cyan, dim, tilde } from "./ui.js";
|
|
9
|
+
import { bold, busy, cmd, cyan, dim, tilde } from "./ui.js";
|
|
10
10
|
/**
|
|
11
11
|
* The account of this install, from the terminal. `wizards account` says where it stands,
|
|
12
12
|
* `sign-in` runs the device flow (auth/device.ts), `sign-out` ends the link the way the
|
|
@@ -73,7 +73,7 @@ export function described(account, team, credits = true) {
|
|
|
73
73
|
export function describeAccount(state) {
|
|
74
74
|
switch (state.kind) {
|
|
75
75
|
case "local":
|
|
76
|
-
return "
|
|
76
|
+
return "only on this computer, no account";
|
|
77
77
|
case "none":
|
|
78
78
|
return "not signed in";
|
|
79
79
|
default:
|
|
@@ -86,16 +86,18 @@ const host = () => new URL(env.local.accountUrl).host.replace(/^account\./, "");
|
|
|
86
86
|
async function status() {
|
|
87
87
|
const state = await accountState();
|
|
88
88
|
if (state.kind === "local") {
|
|
89
|
-
console.log(`
|
|
89
|
+
console.log(`Only on this computer, no account. ${dim(`To connect one: ${cmd("account sign-in")}`)}`);
|
|
90
90
|
return 0;
|
|
91
91
|
}
|
|
92
92
|
if (state.kind === "none") {
|
|
93
|
-
console.log(`Not signed in. ${dim(
|
|
93
|
+
console.log(`Not signed in. ${dim(`To sign in: ${cmd("account sign-in")}`)}`);
|
|
94
94
|
return 0;
|
|
95
95
|
}
|
|
96
96
|
const overview = await accountOverview();
|
|
97
97
|
const team = overview?.tenant ?? state.team;
|
|
98
|
-
console.log(`Signed in as ${described(state.account, team)} · ${host()}${overview
|
|
98
|
+
console.log(`Signed in as ${described(state.account, team)} · ${host()}${overview
|
|
99
|
+
? ""
|
|
100
|
+
: dim(` (${host()} didn’t respond${team ? ", so this is from last time" : ""})`)}`);
|
|
99
101
|
return 0;
|
|
100
102
|
}
|
|
101
103
|
/**
|
|
@@ -112,21 +114,21 @@ async function deviceSignIn() {
|
|
|
112
114
|
return null;
|
|
113
115
|
}
|
|
114
116
|
const link = code.verificationUriComplete ?? code.verificationUri;
|
|
115
|
-
p.log.message(`Open ${cyan(link)} and
|
|
117
|
+
p.log.message(`Open ${cyan(link)} and enter the code ${bold(code.userCode)}.`);
|
|
116
118
|
if (openBrowser(link)) {
|
|
117
119
|
p.log.message(dim("The page opens in your browser."));
|
|
118
120
|
}
|
|
119
|
-
const spinner = busy("Waiting for you to
|
|
121
|
+
const spinner = busy("Waiting for you to confirm in the browser…");
|
|
120
122
|
try {
|
|
121
123
|
const account = await waitForDeviceSignIn(code);
|
|
122
124
|
const overview = await accountOverview();
|
|
123
|
-
spinner.stop(`Signed in as ${described(account, overview?.tenant ?? null)}
|
|
125
|
+
spinner.stop(`Signed in as ${described(account, overview?.tenant ?? null)}.`);
|
|
124
126
|
return account;
|
|
125
127
|
}
|
|
126
128
|
catch (err) {
|
|
127
129
|
spinner.fail(err instanceof DeviceSignInError
|
|
128
130
|
? err.message
|
|
129
|
-
: `The sign-in
|
|
131
|
+
: `The sign-in didn’t work. ${err.message}`);
|
|
130
132
|
return null;
|
|
131
133
|
}
|
|
132
134
|
}
|
|
@@ -139,29 +141,28 @@ async function pickUp(paths, interactive, why) {
|
|
|
139
141
|
if (!(await runningRuntime(settings(paths).dataDir))) {
|
|
140
142
|
return;
|
|
141
143
|
}
|
|
142
|
-
const how = `${command()} restart`;
|
|
143
144
|
if (!interactive) {
|
|
144
|
-
p.log.info(`
|
|
145
|
+
p.log.info(`Run ${cmd("restart")} so ${why}.`);
|
|
145
146
|
return;
|
|
146
147
|
}
|
|
147
148
|
const answer = await p.confirm({
|
|
148
|
-
message: `Restart
|
|
149
|
+
message: `Restart engenty wizards now, so ${why}?`,
|
|
149
150
|
initialValue: true,
|
|
150
151
|
});
|
|
151
152
|
if (p.isCancel(answer) || !answer) {
|
|
152
|
-
p.log.info(dim(`
|
|
153
|
+
p.log.info(dim(`To do it later: ${cmd("restart")}`));
|
|
153
154
|
return;
|
|
154
155
|
}
|
|
155
156
|
// status.ts shows the account; loaded here when needed, so neither module waits on the other.
|
|
156
157
|
const { restart } = await import("./status.js");
|
|
157
158
|
await restart(paths);
|
|
158
159
|
}
|
|
159
|
-
const SIGNED_IN = "
|
|
160
|
+
const SIGNED_IN = "your plan’s Pro modules load and your published wizards arrive in the cloud";
|
|
160
161
|
async function signIn(paths, interactive) {
|
|
161
162
|
await ready();
|
|
162
163
|
const linked = await linkedAccount();
|
|
163
164
|
if (linked) {
|
|
164
|
-
p.log.info(`Already signed in as ${described(linked, await knownTeam(), false)}. ${dim(`To switch
|
|
165
|
+
p.log.info(`Already signed in as ${described(linked, await knownTeam(), false)}. ${dim(`To switch accounts, run ${cmd("account sign-out")} first.`)}`);
|
|
165
166
|
return 0;
|
|
166
167
|
}
|
|
167
168
|
const account = await deviceSignIn();
|
|
@@ -176,10 +177,12 @@ async function signIn(paths, interactive) {
|
|
|
176
177
|
async function signOut(paths, interactive) {
|
|
177
178
|
const state = await accountState();
|
|
178
179
|
if (state.kind !== "linked") {
|
|
179
|
-
console.log(state.kind === "local"
|
|
180
|
+
console.log(state.kind === "local"
|
|
181
|
+
? "No account is connected, so there’s nothing to sign out of."
|
|
182
|
+
: "Not signed in.");
|
|
180
183
|
return 0;
|
|
181
184
|
}
|
|
182
|
-
const spinner = busy(`Signing out ${state.account.name || state.account.email}
|
|
185
|
+
const spinner = busy(`Signing out ${state.account.name || state.account.email}…`);
|
|
183
186
|
await unlink();
|
|
184
187
|
// The same as the studio's sign-out (DELETE /api/studio/account): what was sent to the cloud
|
|
185
188
|
// is forgotten, the entitlement goes with the account's plan, and models that ran on its
|
|
@@ -197,7 +200,7 @@ async function signOut(paths, interactive) {
|
|
|
197
200
|
await models.saveLocalModels({ source: "own" });
|
|
198
201
|
}
|
|
199
202
|
spinner.stop("Signed out. Your wizards and results stay on this computer.");
|
|
200
|
-
await pickUp(paths, interactive, "
|
|
203
|
+
await pickUp(paths, interactive, "it disconnects from the account");
|
|
201
204
|
return 0;
|
|
202
205
|
}
|
|
203
206
|
/** `wizards account [sign-in|sign-out]`. */
|
|
@@ -215,7 +218,7 @@ export async function accountCommand(paths, value, options) {
|
|
|
215
218
|
case "logout":
|
|
216
219
|
return signOut(paths, interactive);
|
|
217
220
|
default:
|
|
218
|
-
console.error(
|
|
221
|
+
console.error(`Usage: ${cmd("account [sign-in|sign-out]")}`);
|
|
219
222
|
return 2;
|
|
220
223
|
}
|
|
221
224
|
}
|
|
@@ -250,37 +253,37 @@ export async function accountMenu(paths) {
|
|
|
250
253
|
export async function accountStep(paths, options, interactive) {
|
|
251
254
|
if (options.local) {
|
|
252
255
|
localOnly(paths);
|
|
253
|
-
p.log.warn(`
|
|
254
|
-
p.log.message(dim(`
|
|
256
|
+
p.log.warn(`No account: nothing leaves this computer. Your wizards, your space and results stay in ${tilde(settings(paths).dataDir)}. Links work only on this computer.`);
|
|
257
|
+
p.log.message(dim(`To connect an account any time: ${cmd("account sign-in")}`));
|
|
255
258
|
return;
|
|
256
259
|
}
|
|
257
260
|
const state = await accountState();
|
|
258
261
|
if (state.kind === "local") {
|
|
259
|
-
p.log.info(`
|
|
262
|
+
p.log.info(`Only on this computer, no account. ${dim(`To connect one: ${cmd("account sign-in")}`)}`);
|
|
260
263
|
return;
|
|
261
264
|
}
|
|
262
265
|
if (state.kind === "linked") {
|
|
263
266
|
const overview = await accountOverview();
|
|
264
|
-
p.log.success(`Signed in as ${described(state.account, overview?.tenant ?? state.team)}
|
|
267
|
+
p.log.success(`Signed in as ${described(state.account, overview?.tenant ?? state.team)}.`);
|
|
265
268
|
return;
|
|
266
269
|
}
|
|
267
270
|
p.note(INTRO, "Your engenty account");
|
|
268
271
|
if (!interactive) {
|
|
269
|
-
p.log.info(dim(`
|
|
272
|
+
p.log.info(dim(`To sign in later: ${cmd("account sign-in")}`));
|
|
270
273
|
return;
|
|
271
274
|
}
|
|
272
275
|
const answer = await p.confirm({ message: "Sign in now?", initialValue: true });
|
|
273
276
|
if (p.isCancel(answer)) {
|
|
274
|
-
p.cancel(`Setup stopped.
|
|
277
|
+
p.cancel(`Setup stopped. To run it again: ${cmd("setup")}`);
|
|
275
278
|
return "cancelled";
|
|
276
279
|
}
|
|
277
280
|
if (!answer) {
|
|
278
|
-
p.log.info(dim(`
|
|
281
|
+
p.log.info(dim(`To sign in later: ${cmd("account sign-in")}`));
|
|
279
282
|
return;
|
|
280
283
|
}
|
|
281
284
|
const account = await deviceSignIn();
|
|
282
285
|
if (!account) {
|
|
283
|
-
p.log.info(dim(`
|
|
286
|
+
p.log.info(dim(`To sign in later: ${cmd("account sign-in")}`));
|
|
284
287
|
return;
|
|
285
288
|
}
|
|
286
289
|
joinedAccount(paths);
|
|
@@ -82,16 +82,18 @@ async function systemdHere() {
|
|
|
82
82
|
}
|
|
83
83
|
export async function autostartState(paths) {
|
|
84
84
|
if (process.platform !== "darwin" && process.platform !== "linux") {
|
|
85
|
-
return {
|
|
85
|
+
return {
|
|
86
|
+
unavailable: process.platform === "win32" ? "not on Windows" : `not on ${process.platform}`,
|
|
87
|
+
};
|
|
86
88
|
}
|
|
87
89
|
if (!installedByScript(paths)) {
|
|
88
|
-
return { unavailable: "only for
|
|
90
|
+
return { unavailable: "only for installs made with the install script" };
|
|
89
91
|
}
|
|
90
92
|
if (process.platform === "darwin") {
|
|
91
93
|
return { on: existsSync(LOGIN_ITEM), how: MAC_HOW };
|
|
92
94
|
}
|
|
93
95
|
if (!(await systemdHere())) {
|
|
94
|
-
return { unavailable: "this
|
|
96
|
+
return { unavailable: "this system has no systemd user session" };
|
|
95
97
|
}
|
|
96
98
|
try {
|
|
97
99
|
await run("systemctl", ["--user", "is-enabled", "--quiet", UNIT], { timeout: 10_000 });
|
|
@@ -28,7 +28,7 @@ export function installClient(client, paths, onLine) {
|
|
|
28
28
|
}
|
|
29
29
|
const npm = findOnPath("npm", [dirname(process.execPath), process.env.PATH ?? ""].join(delimiter));
|
|
30
30
|
if (!npm) {
|
|
31
|
-
return Promise.resolve({ code: 127, tail: "npm
|
|
31
|
+
return Promise.resolve({ code: 127, tail: "npm wasn’t found next to this Node.js." });
|
|
32
32
|
}
|
|
33
33
|
mkdirSync(paths.clients, { recursive: true });
|
|
34
34
|
return runLogged(npm, [
|