wizards 0.5.0 → 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 +3 -3
- package/apps/runtime/dist/app.js +7 -4
- package/apps/runtime/dist/auth/index.js +2 -2
- package/apps/runtime/dist/authoring/guide.js +1 -1
- 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/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 +2 -2
- 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 +15 -9
- 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 +53 -23
- 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 +2 -2
- 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 +2 -2
- package/apps/runtime/dist/services/project-files.js +10 -12
- package/apps/runtime/dist/services/projects.js +13 -8
- 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 +2 -2
- package/apps/runtime/dist/services/space-categories.js +4 -4
- package/apps/runtime/dist/services/space-data.js +13 -13
- package/apps/runtime/dist/services/space-origin.js +1 -1
- package/apps/runtime/dist/services/spaces.js +7 -7
- package/apps/runtime/dist/services/wizards.js +5 -5
- package/apps/runtime/dist/tools/net-guard.js +135 -24
- package/apps/runtime/dist/tools/plugin.js +1 -1
- 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-BXpkgatF.js → ChangelogDialog-CsYbEayb.js} +1 -1
- package/apps/web/dist/assets/{ChatView-t7z44uFN.js → ChatView-BRD3fKZU.js} +1 -1
- package/apps/web/dist/assets/{EditorPage-4qxNJgKr.js → EditorPage-ocPlZD3E.js} +3 -3
- package/apps/web/dist/assets/{FlowPreview-WpS8DCPl.js → FlowPreview-Bm7sv746.js} +1 -1
- package/apps/web/dist/assets/{Harness-DL7Bse40.js → Harness-DKE-YNA5.js} +1 -1
- package/apps/web/dist/assets/{NewWizardChannels-Crt6PzH2.js → NewWizardChannels-CnWckqjO.js} +1 -1
- package/apps/web/dist/assets/{NewWizardPage-COiVmNsl.js → NewWizardPage-BXTpbHVM.js} +1 -1
- package/apps/web/dist/assets/{OnboardingPage-BwluEqXq.js → OnboardingPage-3Rz5uOsa.js} +1 -1
- package/apps/web/dist/assets/{ProjectPage-BIRU_AlN.js → ProjectPage-QdSJwm3k.js} +1 -1
- package/apps/web/dist/assets/{PublicRunner-BxMb4gEt.js → PublicRunner-DEpBer5g.js} +1 -1
- package/apps/web/dist/assets/{ReadOnly-D9r5ze5S.js → ReadOnly-rr_RJD-a.js} +1 -1
- package/apps/web/dist/assets/{RunDrawer-DmJl2QOJ.js → RunDrawer-BsZt0tL9.js} +1 -1
- package/apps/web/dist/assets/{RunnerView-CF_1rC-7.js → RunnerView-BbRukEdE.js} +1 -1
- package/apps/web/dist/assets/SettingsPage-qkWsQIMN.js +1 -0
- package/apps/web/dist/assets/{SetupPage-BGKtbS7j.js → SetupPage-PzvPPLfM.js} +1 -1
- package/apps/web/dist/assets/{SharePage-C4MqXKDA.js → SharePage-7vdDWG1n.js} +1 -1
- package/apps/web/dist/assets/changelog-BFdAYD28.js +1 -0
- package/apps/web/dist/assets/{esm-CsY8TkyE.js → esm-g0kaGp8t.js} +1 -1
- package/apps/web/dist/assets/{index-BjQvGQp_.js → index-BzPid1oQ.js} +4 -4
- package/apps/web/dist/assets/{lock-CI6TpWL-.js → lock-BK9RYIft.js} +1 -1
- package/apps/web/dist/assets/oss-credits-BJrR7BR1.js +1 -0
- package/apps/web/dist/assets/{phone-BrtQz-fG.js → phone-DtkY0NfU.js} +1 -1
- package/apps/web/dist/assets/{settings-menu-BtEKL72n.js → settings-menu-7EJQRFOi.js} +1 -1
- package/apps/web/dist/assets/{ui-4IaTD7LB.js → ui-B6S5hYPd.js} +3 -3
- package/apps/web/dist/assets/{upload-CWJAtPRo.js → upload-rYCAy7ox.js} +1 -1
- package/apps/web/dist/index.html +2 -2
- package/apps/web/dist/mcp/flow.html +3 -3
- package/bin/wizards.mjs +1 -1
- package/node_modules/@engenty-wizards/plugin-sdk/dist/index.d.ts +21 -2
- 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/package.json +5 -4
- package/apps/web/dist/assets/AboutDialog-A_ILyeue.js +0 -1
- package/apps/web/dist/assets/SettingsPage-3xSInE-A.js +0 -1
- package/apps/web/dist/assets/changelog-CM_GdIVI.js +0 -1
- package/apps/web/dist/assets/oss-credits-BQQX0kvk.js +0 -1
|
@@ -10,12 +10,12 @@ import { runLogged } from "./exec.js";
|
|
|
10
10
|
import { command, installedByScript, isCheckout, packageVersion, readInstallNote, writeInstallNote, } from "./home.js";
|
|
11
11
|
import { CLIENTS, detectClients, findChrome, findFfmpeg, findOnPath, suggestedClient, vendorApp, } from "./machine.js";
|
|
12
12
|
import { runningRuntime, settings } from "./start.js";
|
|
13
|
-
import { badge, busy, cyan, dim, tilde } from "./ui.js";
|
|
13
|
+
import { badge, busy, cmd, cyan, dim, tilde } from "./ui.js";
|
|
14
14
|
/** The studio as an app of its own: Chrome (or Edge) installs it from the page. */
|
|
15
|
-
const CHROME_APP = "Tip: in Chrome or Edge the studio
|
|
15
|
+
const CHROME_APP = "Tip: in Chrome or Edge you can install the studio as an app, with its own window and icon. Use the offer at the top of the studio, or the install icon in the address bar.";
|
|
16
16
|
function cancelled(value) {
|
|
17
17
|
if (p.isCancel(value)) {
|
|
18
|
-
p.cancel(`Setup stopped.
|
|
18
|
+
p.cancel(`Setup stopped. To run it again: ${cmd("setup")}`);
|
|
19
19
|
return true;
|
|
20
20
|
}
|
|
21
21
|
return false;
|
|
@@ -29,19 +29,19 @@ async function install(client, paths) {
|
|
|
29
29
|
task.success(`${client.name} ${installed.version ?? ""} installed`.trim());
|
|
30
30
|
return true;
|
|
31
31
|
}
|
|
32
|
-
task.error(`${client.name}
|
|
32
|
+
task.error(`${client.name} didn’t install${code === 0 ? ": its command isn’t on the PATH" : ""}. ${tail.split("\n").pop() ?? ""}`);
|
|
33
33
|
return false;
|
|
34
34
|
}
|
|
35
35
|
async function clientsStep(paths, options, interactive) {
|
|
36
|
-
const spinner = busy("Looking for AI clients on this
|
|
36
|
+
const spinner = busy("Looking for AI clients on this computer…");
|
|
37
37
|
const found = await detectClients(paths);
|
|
38
38
|
const installed = found.filter((state) => state.path);
|
|
39
39
|
const missing = found.filter((state) => !state.path);
|
|
40
40
|
spinner.stop(installed.length
|
|
41
|
-
? `
|
|
42
|
-
: "No AI client on this
|
|
41
|
+
? `Found AI clients: ${installed.map((s) => `${s.client.name} ${s.version}`).join(", ")}.`
|
|
42
|
+
: "No AI client on this computer yet.");
|
|
43
43
|
if (!installed.length) {
|
|
44
|
-
p.log.message(dim("engenty wizards
|
|
44
|
+
p.log.message(dim("engenty wizards uses an AI client to think, on a subscription you already have."));
|
|
45
45
|
}
|
|
46
46
|
let wanted = missing.filter((s) => options.clients.includes(s.client.id));
|
|
47
47
|
if (interactive && missing.length && !wanted.length) {
|
|
@@ -50,8 +50,8 @@ async function clientsStep(paths, options, interactive) {
|
|
|
50
50
|
const offered = [...missing].sort((a, b) => Number(!vendorApp(a.client)) - Number(!vendorApp(b.client)));
|
|
51
51
|
const answer = await p.multiselect({
|
|
52
52
|
message: installed.length
|
|
53
|
-
? "Install another AI client? (space to
|
|
54
|
-
: "Which
|
|
53
|
+
? "Install another AI client? (space to choose, enter to continue)"
|
|
54
|
+
: "Which AI client should be installed?",
|
|
55
55
|
options: offered.map(({ client }) => {
|
|
56
56
|
const app = vendorApp(client);
|
|
57
57
|
return {
|
|
@@ -79,10 +79,10 @@ async function clientsStep(paths, options, interactive) {
|
|
|
79
79
|
any = (await install(client, paths)) || any;
|
|
80
80
|
}
|
|
81
81
|
if (any) {
|
|
82
|
-
p.log.info("
|
|
82
|
+
p.log.info("Sign in to the AI client on the first page of the studio.");
|
|
83
83
|
}
|
|
84
84
|
else {
|
|
85
|
-
p.log.warn(`No AI client yet
|
|
85
|
+
p.log.warn(`No AI client yet. The first page of the studio can install one, or you can use an API key (Vercel AI Gateway, OpenAI, Anthropic) or a local model (Ollama).\n${dim(`To install ${CLIENTS.map((c) => c.name).join(", ")} here later: ${cmd("setup")}`)}`);
|
|
86
86
|
}
|
|
87
87
|
return any;
|
|
88
88
|
}
|
|
@@ -92,7 +92,7 @@ async function toolsStep(interactive) {
|
|
|
92
92
|
p.log.success(`Browser for PDF and PNG: ${dim(tilde(chrome))}`);
|
|
93
93
|
}
|
|
94
94
|
else {
|
|
95
|
-
p.log.warn("No Chrome, Edge or Chromium
|
|
95
|
+
p.log.warn("No Chrome, Edge or Chromium found. PDF and PNG exports and browser steps need one.\nhttps://www.google.com/chrome");
|
|
96
96
|
}
|
|
97
97
|
const ffmpeg = await findFfmpeg();
|
|
98
98
|
if (ffmpeg.path) {
|
|
@@ -101,7 +101,7 @@ async function toolsStep(interactive) {
|
|
|
101
101
|
}
|
|
102
102
|
const brew = findOnPath("brew", process.env.PATH ?? "");
|
|
103
103
|
if (!interactive || !brew) {
|
|
104
|
-
p.log.warn(`No ffmpeg
|
|
104
|
+
p.log.warn(`No ffmpeg found. MP4 videos of animated widgets need it.${brew ? `\n${dim(`To install it: ${cyan("brew install ffmpeg")}`)}` : ""}`);
|
|
105
105
|
return;
|
|
106
106
|
}
|
|
107
107
|
const answer = await p.confirm({
|
|
@@ -120,7 +120,7 @@ async function toolsStep(interactive) {
|
|
|
120
120
|
task.success("ffmpeg installed");
|
|
121
121
|
}
|
|
122
122
|
else {
|
|
123
|
-
task.error(`ffmpeg
|
|
123
|
+
task.error(`ffmpeg didn’t install. ${tail.split("\n").pop() ?? ""}`);
|
|
124
124
|
}
|
|
125
125
|
}
|
|
126
126
|
}
|
|
@@ -138,18 +138,18 @@ async function autostartStep(paths, interactive) {
|
|
|
138
138
|
return;
|
|
139
139
|
}
|
|
140
140
|
if (!interactive) {
|
|
141
|
-
p.log.info(dim(`To start it
|
|
141
|
+
p.log.info(dim(`To start it when you log in: ${cmd("autostart on")}`));
|
|
142
142
|
return;
|
|
143
143
|
}
|
|
144
144
|
const answer = await p.confirm({
|
|
145
|
-
message: "Start engenty wizards when you log in? It keeps running in the background, so links and AI
|
|
145
|
+
message: "Start engenty wizards when you log in? It keeps running in the background, so links and your AI apps can always reach it.",
|
|
146
146
|
initialValue: true,
|
|
147
147
|
});
|
|
148
148
|
if (cancelled(answer)) {
|
|
149
149
|
return "cancelled";
|
|
150
150
|
}
|
|
151
151
|
if (!answer) {
|
|
152
|
-
p.log.info(dim(`
|
|
152
|
+
p.log.info(dim(`To do it later: ${cmd("autostart on")}`));
|
|
153
153
|
return;
|
|
154
154
|
}
|
|
155
155
|
try {
|
|
@@ -158,11 +158,11 @@ async function autostartStep(paths, interactive) {
|
|
|
158
158
|
p.log.success(`Starts at login: ${dim(after.how)}`);
|
|
159
159
|
}
|
|
160
160
|
else {
|
|
161
|
-
p.log.warn("
|
|
161
|
+
p.log.warn("Couldn’t turn on start at login.");
|
|
162
162
|
}
|
|
163
163
|
}
|
|
164
164
|
catch (error) {
|
|
165
|
-
p.log.warn(`
|
|
165
|
+
p.log.warn(`Couldn’t turn on start at login. ${error.message}`);
|
|
166
166
|
}
|
|
167
167
|
}
|
|
168
168
|
/**
|
|
@@ -180,15 +180,15 @@ async function appsStep(paths, interactive) {
|
|
|
180
180
|
return;
|
|
181
181
|
}
|
|
182
182
|
if (!interactive) {
|
|
183
|
-
p.log.info(dim(`To use your wizards in ${offered.map((s) => s.name).join(", ")}:
|
|
183
|
+
p.log.info(dim(`To use your wizards in ${offered.map((s) => s.name).join(", ")}: ${cmd("connect")}`));
|
|
184
184
|
return;
|
|
185
185
|
}
|
|
186
186
|
const answer = await p.multiselect({
|
|
187
|
-
message: "Use your wizards in these AI apps? (space to
|
|
187
|
+
message: "Use your wizards in these AI apps? (space to choose, enter to continue)",
|
|
188
188
|
options: offered.map((s) => ({
|
|
189
189
|
value: s.id,
|
|
190
190
|
label: s.name,
|
|
191
|
-
hint: s.widgets ? "shows runs as a widget" : "as text",
|
|
191
|
+
hint: s.widgets ? "shows runs as a widget" : "shows runs as text",
|
|
192
192
|
})),
|
|
193
193
|
initialValues: offered.map((s) => s.id),
|
|
194
194
|
required: false,
|
|
@@ -197,12 +197,12 @@ async function appsStep(paths, interactive) {
|
|
|
197
197
|
return "cancelled";
|
|
198
198
|
}
|
|
199
199
|
if (!answer.length) {
|
|
200
|
-
p.log.info(dim(`
|
|
200
|
+
p.log.info(dim(`To do it later: ${cmd("connect")}`));
|
|
201
201
|
return;
|
|
202
202
|
}
|
|
203
203
|
for (const { app, outcome } of await connectApps(paths, answer)) {
|
|
204
204
|
if (outcome.ok) {
|
|
205
|
-
p.log.success(`${app.name}: ${dim(
|
|
205
|
+
p.log.success(`${app.name}: ${dim(outcome.message)}`);
|
|
206
206
|
}
|
|
207
207
|
else {
|
|
208
208
|
p.log.warn(`${app.name}: ${outcome.message}${outcome.snippet ? `\n${outcome.snippet}` : ""}`);
|
|
@@ -234,16 +234,16 @@ async function pathStep(interactive) {
|
|
|
234
234
|
}
|
|
235
235
|
const { file, line } = pathLine();
|
|
236
236
|
if (existsSync(file) && readFileSync(file, "utf8").includes(".local/bin")) {
|
|
237
|
-
p.log.info(`Open a new terminal to use the
|
|
237
|
+
p.log.info(`Open a new terminal to use the ${cyan("wizards")} command.`);
|
|
238
238
|
return;
|
|
239
239
|
}
|
|
240
|
-
const hint = `Until then
|
|
240
|
+
const hint = `Until then, use ${cyan(tilde(join(local, "wizards")))}`;
|
|
241
241
|
if (!interactive) {
|
|
242
|
-
p.log.warn(`~/.local/bin
|
|
242
|
+
p.log.warn(`~/.local/bin isn’t on your PATH. Add this to ${tilde(file)}:\n${line}\n${dim(hint)}`);
|
|
243
243
|
return;
|
|
244
244
|
}
|
|
245
245
|
const answer = await p.confirm({
|
|
246
|
-
message: `The
|
|
246
|
+
message: `The wizards command is in ~/.local/bin, which isn’t on your PATH. Add it in ${tilde(file)}?`,
|
|
247
247
|
initialValue: true,
|
|
248
248
|
});
|
|
249
249
|
if (cancelled(answer)) {
|
|
@@ -251,7 +251,7 @@ async function pathStep(interactive) {
|
|
|
251
251
|
}
|
|
252
252
|
if (answer) {
|
|
253
253
|
appendFileSync(file, `\n# engenty wizards\n${line}\n`);
|
|
254
|
-
p.log.success(`Added to ${tilde(file)}.
|
|
254
|
+
p.log.success(`Added to ${tilde(file)}. Open a new terminal to use it.\n${dim(hint)}`);
|
|
255
255
|
}
|
|
256
256
|
else {
|
|
257
257
|
p.log.info(hint);
|
|
@@ -266,8 +266,12 @@ async function howToUse(paths) {
|
|
|
266
266
|
const wizards = command();
|
|
267
267
|
const row = (what, cmd, note = "") => `${what.padEnd(9)}${cyan(cmd.padEnd(wizards.length + 12))}${note ? dim(note) : ""}`;
|
|
268
268
|
p.log.message([
|
|
269
|
-
running
|
|
270
|
-
|
|
269
|
+
running
|
|
270
|
+
? `engenty wizards is running: ${cyan(running.url)}`
|
|
271
|
+
: "engenty wizards isn’t running yet.",
|
|
272
|
+
"unavailable" in atLogin || !atLogin.on
|
|
273
|
+
? ""
|
|
274
|
+
: dim("It starts automatically when you log in."),
|
|
271
275
|
]
|
|
272
276
|
.filter(Boolean)
|
|
273
277
|
.join("\n"));
|
|
@@ -275,15 +279,15 @@ async function howToUse(paths) {
|
|
|
275
279
|
"From now on, in a terminal:",
|
|
276
280
|
"",
|
|
277
281
|
row("Start", `${wizards} start`, "runs in this terminal; Ctrl-C stops it"),
|
|
278
|
-
row("", `${wizards} start -s`, "runs
|
|
279
|
-
row("Studio", `${wizards} studio`, "opens the studio
|
|
282
|
+
row("", `${wizards} start -s`, "runs in the background; the terminal stays free"),
|
|
283
|
+
row("Studio", `${wizards} studio`, "opens the studio, starting it first if needed"),
|
|
280
284
|
row("Stop", `${wizards} stop`, "your data is kept"),
|
|
281
|
-
row("Check", `${wizards} status`, "what
|
|
285
|
+
row("Check", `${wizards} status`, "shows what’s running and where"),
|
|
282
286
|
row("Restart", `${wizards} restart`),
|
|
283
|
-
row("
|
|
287
|
+
row("Menu", wizards, "everything in one menu"),
|
|
284
288
|
"",
|
|
285
|
-
dim("
|
|
286
|
-
|
|
289
|
+
dim("It’s installed, so there’s no need to run the installer again. To update: ") +
|
|
290
|
+
cmd("update"),
|
|
287
291
|
].join("\n"));
|
|
288
292
|
}
|
|
289
293
|
/**
|
|
@@ -3,13 +3,13 @@ import { randomBytes } from "node:crypto";
|
|
|
3
3
|
import { existsSync, mkdirSync, openSync, readFileSync } from "node:fs";
|
|
4
4
|
import { createServer } from "node:net";
|
|
5
5
|
import { join, resolve } from "node:path";
|
|
6
|
-
import { styleText } from "node:util";
|
|
7
6
|
import { mintLocalTicket } from "../auth/local-ticket.js";
|
|
8
7
|
import { readRunning } from "../running.js";
|
|
9
8
|
import { RESTART_EXIT } from "../update.js";
|
|
10
9
|
import { runtimeEnv } from "./environment.js";
|
|
11
|
-
import {
|
|
10
|
+
import { packageRoot, readEnvFile } from "./home.js";
|
|
12
11
|
import { findOnPath } from "./machine.js";
|
|
12
|
+
import { cmd, cyan, dim, live, tilde } from "./ui.js";
|
|
13
13
|
const DEFAULT_PORT = 24368;
|
|
14
14
|
const START_TIMEOUT_MS = 60_000;
|
|
15
15
|
/** The settings this install starts with: its `.env`, overridden by the terminal's variables. */
|
|
@@ -87,13 +87,13 @@ export function openBrowser(url) {
|
|
|
87
87
|
function show(url, entry, open) {
|
|
88
88
|
const opened = open && openBrowser(entry);
|
|
89
89
|
console.log("");
|
|
90
|
-
console.log(` ${
|
|
90
|
+
console.log(` ${live} engenty wizards is running: ${cyan(url)}`);
|
|
91
91
|
if (opened) {
|
|
92
|
-
console.log(
|
|
92
|
+
console.log(dim(" The studio opens in your browser."));
|
|
93
93
|
}
|
|
94
94
|
else {
|
|
95
|
-
console.log(` Open the studio: ${entry}`);
|
|
96
|
-
console.log(
|
|
95
|
+
console.log(` Open the studio: ${cyan(entry)}`);
|
|
96
|
+
console.log(dim(" The link signs in one browser and works only once."));
|
|
97
97
|
}
|
|
98
98
|
}
|
|
99
99
|
/** The command of this install, as it is on disk now: `wizards <args>`. */
|
|
@@ -146,22 +146,23 @@ export async function start(paths, options) {
|
|
|
146
146
|
const running = await runningRuntime(dataDir);
|
|
147
147
|
if (running) {
|
|
148
148
|
show(running.url, entryUrl(running, dataDir), options.open);
|
|
149
|
-
console.log(
|
|
149
|
+
console.log(dim(` It was already running. To stop it: ${cmd("stop")}`));
|
|
150
150
|
return 0;
|
|
151
151
|
}
|
|
152
152
|
if (options.background) {
|
|
153
153
|
const started = await startInBackground(paths);
|
|
154
154
|
if (!started) {
|
|
155
|
-
console.error(`engenty wizards
|
|
155
|
+
console.error(`engenty wizards didn’t start. Its log is in ${tilde(join(paths.logs, "runtime.log"))}.`);
|
|
156
156
|
return 1;
|
|
157
157
|
}
|
|
158
158
|
show(started.url, entryUrl(started, dataDir), options.open);
|
|
159
|
-
console.log(
|
|
159
|
+
console.log(dim(` It’s running in the background. To stop it: ${cmd("stop")}`));
|
|
160
|
+
console.log(dim(` Its log is in ${tilde(join(paths.logs, "runtime.log"))}.`));
|
|
160
161
|
return 0;
|
|
161
162
|
}
|
|
162
163
|
const port = wanted ?? (await freePort());
|
|
163
164
|
if (!wanted && port !== DEFAULT_PORT) {
|
|
164
|
-
console.log(
|
|
165
|
+
console.log(dim(` Port ${DEFAULT_PORT} is taken, so it uses ${port}.`));
|
|
165
166
|
}
|
|
166
167
|
const accessKey = randomBytes(24).toString("hex");
|
|
167
168
|
const url = appUrl || `http://localhost:${port}`;
|
|
@@ -178,7 +179,7 @@ export async function start(paths, options) {
|
|
|
178
179
|
let exited = null;
|
|
179
180
|
const ended = new Promise((done) => {
|
|
180
181
|
child.on("error", (error) => {
|
|
181
|
-
console.error(`
|
|
182
|
+
console.error(`engenty wizards didn’t start: ${error.message}`);
|
|
182
183
|
exited = 1;
|
|
183
184
|
done(1);
|
|
184
185
|
});
|
|
@@ -194,7 +195,7 @@ export async function start(paths, options) {
|
|
|
194
195
|
while (exited === null && !(await healthy(port))) {
|
|
195
196
|
if (Date.now() - began > START_TIMEOUT_MS) {
|
|
196
197
|
child.kill("SIGTERM");
|
|
197
|
-
console.error("
|
|
198
|
+
console.error("engenty wizards didn’t respond within 60 seconds.");
|
|
198
199
|
return 1;
|
|
199
200
|
}
|
|
200
201
|
await new Promise((wait) => setTimeout(wait, 150));
|
|
@@ -203,7 +204,7 @@ export async function start(paths, options) {
|
|
|
203
204
|
return exited || 1;
|
|
204
205
|
}
|
|
205
206
|
show(url, `${url}/api/local/enter?k=${accessKey}`, options.open);
|
|
206
|
-
console.log(
|
|
207
|
+
console.log(dim(" To stop it, press Ctrl-C."));
|
|
207
208
|
console.log("");
|
|
208
209
|
const code = await ended;
|
|
209
210
|
if (code !== RESTART_EXIT) {
|
|
@@ -211,7 +212,7 @@ export async function start(paths, options) {
|
|
|
211
212
|
}
|
|
212
213
|
// Updated or `wizards restart`: the command as it is on disk now starts it again, in this
|
|
213
214
|
// terminal or under the login item, which keeps waiting on this process.
|
|
214
|
-
console.log(
|
|
215
|
+
console.log(dim(" Restarting…"));
|
|
215
216
|
current = spawnCommand(paths, ["start", "--no-open"], { stdio: "inherit" });
|
|
216
217
|
return new Promise((done) => {
|
|
217
218
|
current.on("error", () => done(1));
|
|
@@ -233,7 +234,7 @@ export async function open(paths, print) {
|
|
|
233
234
|
const { dataDir } = settings(paths);
|
|
234
235
|
const running = await runningRuntime(dataDir);
|
|
235
236
|
if (!running) {
|
|
236
|
-
console.error(`engenty wizards
|
|
237
|
+
console.error(`engenty wizards isn’t running. To start it: ${cmd("start")}`);
|
|
237
238
|
return 1;
|
|
238
239
|
}
|
|
239
240
|
const entry = entryUrl(running, dataDir);
|
|
@@ -5,7 +5,7 @@ import { autostartState, setAutostart } from "./autostart.js";
|
|
|
5
5
|
import { installedByScript, isCheckout, packageRoot, packageVersion } from "./home.js";
|
|
6
6
|
import { detectClients, findChrome, findFfmpeg, nodeIsCurrent } from "./machine.js";
|
|
7
7
|
import { entryUrl, runningRuntime, settings, startInBackground } from "./start.js";
|
|
8
|
-
import { bad, badge, cyan, dim, no, ok, tilde } from "./ui.js";
|
|
8
|
+
import { bad, badge, cmd, cyan, dim, no, ok, tilde } from "./ui.js";
|
|
9
9
|
/**
|
|
10
10
|
* What is installed and what runs. With `checks` (`doctor`) it also says what is wrong and
|
|
11
11
|
* returns 1 when something is.
|
|
@@ -28,24 +28,24 @@ export async function status(paths, checks) {
|
|
|
28
28
|
row("Data", tilde(dataDir));
|
|
29
29
|
row("Node", `${process.version} ${dim(tilde(process.execPath))}`);
|
|
30
30
|
row("Running", running
|
|
31
|
-
? `${ok} ${cyan(running.url)} ${dim(`pid ${running.pid}, since ${running.startedAt}`)}`
|
|
31
|
+
? `${ok} ${cyan(running.url)} ${dim(`pid ${running.pid}, since ${new Date(running.startedAt).toLocaleString()}`)}`
|
|
32
32
|
: `${no} not running`);
|
|
33
33
|
if (!("unavailable" in atLogin)) {
|
|
34
|
-
row("At login", atLogin.on ? `${ok} starts ${dim(`(${atLogin.how})`)}` : `${no}
|
|
34
|
+
row("At login", atLogin.on ? `${ok} starts ${dim(`(${atLogin.how})`)}` : `${no} doesn’t start`);
|
|
35
35
|
}
|
|
36
36
|
row("Account", `${account.kind === "linked" ? ok : no} ${describeAccount(account)}`);
|
|
37
37
|
for (const { client, path, version } of clients) {
|
|
38
38
|
row(client.name.split(" ")[0], path ? `${ok} ${version} ${dim(tilde(path))}` : `${no} not installed`);
|
|
39
39
|
}
|
|
40
|
-
row("Browser", chrome ? `${ok} ${dim(tilde(chrome))}` : `${no}
|
|
41
|
-
row("ffmpeg", ffmpeg.path ? `${ok} ${ffmpeg.version ?? ""}` : `${no}
|
|
40
|
+
row("Browser", chrome ? `${ok} ${dim(tilde(chrome))}` : `${no} not found (needed for PDF and PNG)`);
|
|
41
|
+
row("ffmpeg", ffmpeg.path ? `${ok} ${ffmpeg.version ?? ""}` : `${no} not found (needed for MP4)`);
|
|
42
42
|
console.log("");
|
|
43
43
|
if (!checks) {
|
|
44
44
|
return 0;
|
|
45
45
|
}
|
|
46
46
|
const problems = [];
|
|
47
47
|
if (!nodeIsCurrent()) {
|
|
48
|
-
problems.push(`Node ${process.version} is too old
|
|
48
|
+
problems.push(`Node ${process.version} is too old. engenty wizards needs 24.11 or newer.`);
|
|
49
49
|
}
|
|
50
50
|
for (const part of ["apps/runtime/dist/index.js", "apps/web/dist/index.html", "plugin"]) {
|
|
51
51
|
if (!existsSync(join(packageRoot, part))) {
|
|
@@ -57,16 +57,16 @@ export async function status(paths, checks) {
|
|
|
57
57
|
accessSync(paths.home, constants.W_OK);
|
|
58
58
|
}
|
|
59
59
|
catch {
|
|
60
|
-
problems.push(`${tilde(paths.home)}
|
|
60
|
+
problems.push(`${tilde(paths.home)} can’t be written to.`);
|
|
61
61
|
}
|
|
62
62
|
if (!clients.some((state) => state.path)) {
|
|
63
|
-
console.log(` ${no} No AI client
|
|
63
|
+
console.log(` ${no} No AI client. The studio needs an API key, Ollama or Apple Intelligence (Mac only) instead. ${dim(`To install one: ${cmd("setup")}`)}`);
|
|
64
64
|
}
|
|
65
65
|
for (const problem of problems) {
|
|
66
66
|
console.log(` ${bad} ${problem}`);
|
|
67
67
|
}
|
|
68
68
|
if (!problems.length) {
|
|
69
|
-
console.log(` ${ok}
|
|
69
|
+
console.log(` ${ok} No problems found.`);
|
|
70
70
|
}
|
|
71
71
|
console.log("");
|
|
72
72
|
return problems.length ? 1 : 0;
|
|
@@ -89,7 +89,7 @@ export async function stop(paths) {
|
|
|
89
89
|
const { dataDir } = settings(paths);
|
|
90
90
|
const running = await runningRuntime(dataDir);
|
|
91
91
|
if (!running) {
|
|
92
|
-
console.log("engenty wizards
|
|
92
|
+
console.log("engenty wizards isn’t running.");
|
|
93
93
|
return 0;
|
|
94
94
|
}
|
|
95
95
|
process.kill(running.pid, "SIGTERM");
|
|
@@ -97,7 +97,7 @@ export async function stop(paths) {
|
|
|
97
97
|
console.log(`Stopped (pid ${running.pid}). Your data is kept.`);
|
|
98
98
|
return 0;
|
|
99
99
|
}
|
|
100
|
-
console.error(`
|
|
100
|
+
console.error(`engenty wizards (pid ${running.pid}) didn’t stop within 8 seconds.`);
|
|
101
101
|
return 1;
|
|
102
102
|
}
|
|
103
103
|
/**
|
|
@@ -118,31 +118,31 @@ export async function restart(paths) {
|
|
|
118
118
|
return 0;
|
|
119
119
|
}
|
|
120
120
|
}
|
|
121
|
-
console.error("engenty wizards
|
|
121
|
+
console.error("engenty wizards didn’t restart within a minute.");
|
|
122
122
|
return 1;
|
|
123
123
|
}
|
|
124
124
|
if (running) {
|
|
125
125
|
process.kill(running.pid, "SIGTERM");
|
|
126
126
|
if (!(await ended(running.pid, 8000))) {
|
|
127
|
-
console.error(`
|
|
127
|
+
console.error(`engenty wizards (pid ${running.pid}) didn’t stop within 8 seconds.`);
|
|
128
128
|
return 1;
|
|
129
129
|
}
|
|
130
130
|
}
|
|
131
131
|
const started = await startInBackground(paths);
|
|
132
132
|
if (!started) {
|
|
133
|
-
console.error(`engenty wizards
|
|
133
|
+
console.error(`engenty wizards didn’t start. Its log is in ${tilde(join(paths.logs, "runtime.log"))}.`);
|
|
134
134
|
return 1;
|
|
135
135
|
}
|
|
136
136
|
console.log(`${ok} ${running ? "Restarted" : "Started"}: ${cyan(started.url)} ${dim(`pid ${started.pid}, in the background`)}`);
|
|
137
137
|
if (!running) {
|
|
138
|
-
console.log(` Open the studio: ${entryUrl(started, dataDir)}`);
|
|
138
|
+
console.log(` Open the studio: ${cyan(entryUrl(started, dataDir))}`);
|
|
139
139
|
}
|
|
140
140
|
return 0;
|
|
141
141
|
}
|
|
142
142
|
/** `autostart [on|off]`: whether it starts at login, and the switch. */
|
|
143
143
|
export async function autostart(paths, value) {
|
|
144
144
|
if (value && value !== "on" && value !== "off") {
|
|
145
|
-
console.error("autostart
|
|
145
|
+
console.error(`Use ${cmd("autostart on")} or ${cmd("autostart off")}.`);
|
|
146
146
|
return 2;
|
|
147
147
|
}
|
|
148
148
|
let state = await autostartState(paths);
|
|
@@ -151,19 +151,19 @@ export async function autostart(paths, value) {
|
|
|
151
151
|
state = await setAutostart(paths, value === "on");
|
|
152
152
|
}
|
|
153
153
|
catch (error) {
|
|
154
|
-
console.error(`
|
|
154
|
+
console.error(`Couldn’t turn start at login ${value}: ${error.message}`);
|
|
155
155
|
return 1;
|
|
156
156
|
}
|
|
157
157
|
}
|
|
158
158
|
if ("unavailable" in state) {
|
|
159
|
-
console.error(`
|
|
159
|
+
console.error(`Start at login isn’t available here: ${state.unavailable}.`);
|
|
160
160
|
return value ? 1 : 0;
|
|
161
161
|
}
|
|
162
162
|
console.log(state.on
|
|
163
163
|
? `${ok} engenty wizards starts at login: ${state.how}.`
|
|
164
|
-
: `${no} engenty wizards
|
|
164
|
+
: `${no} engenty wizards doesn’t start at login. ${dim(`To turn it on: ${cmd("autostart on")}`)}`);
|
|
165
165
|
if (state.on && process.platform === "linux") {
|
|
166
|
-
console.log(dim(
|
|
166
|
+
console.log(dim(` To start it even before anyone logs in: ${cyan("loginctl enable-linger")}`));
|
|
167
167
|
}
|
|
168
168
|
return value && state.on !== (value === "on") ? 1 : 0;
|
|
169
169
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { homedir } from "node:os";
|
|
2
2
|
import { styleText } from "node:util";
|
|
3
3
|
import * as p from "@clack/prompts";
|
|
4
|
+
import { command } from "./home.js";
|
|
4
5
|
const colours = Boolean(process.stdout.isTTY) && !process.env.NO_COLOR;
|
|
5
6
|
/** The name on engenty's orange. */
|
|
6
7
|
export const badge = (text) => colours ? `\x1b[48;2;224;83;27m\x1b[97m\x1b[1m ${text} \x1b[0m` : text;
|
|
@@ -10,15 +11,21 @@ export const cyan = (text) => styleText("cyan", text);
|
|
|
10
11
|
export const ok = styleText("green", "✓");
|
|
11
12
|
export const no = styleText("yellow", "–");
|
|
12
13
|
export const bad = styleText("red", "✗");
|
|
14
|
+
export const live = styleText("green", "●");
|
|
13
15
|
/** A path as the person would write it. */
|
|
14
16
|
export const tilde = (path) => path.startsWith(homedir()) ? `~${path.slice(homedir().length)}` : path;
|
|
15
|
-
/** A
|
|
17
|
+
/** A command as the person types it, with this install's prefix: `cmd("stop")` → wizards stop. */
|
|
18
|
+
export const cmd = (args = "") => cyan(args ? `${command()} ${args}` : command());
|
|
19
|
+
/**
|
|
20
|
+
* A spinner on a terminal; where nobody watches, only what came of it. The message ends in "…"
|
|
21
|
+
* ("Checking status…"); clack animates its own dots in its place.
|
|
22
|
+
*/
|
|
16
23
|
export function busy(message) {
|
|
17
24
|
if (!process.stdout.isTTY) {
|
|
18
25
|
return { stop: (text) => p.log.step(text), fail: (text) => p.log.warn(text) };
|
|
19
26
|
}
|
|
20
27
|
const spinner = p.spinner();
|
|
21
|
-
spinner.start(message);
|
|
28
|
+
spinner.start(message.replace(/…$/, ""));
|
|
22
29
|
return {
|
|
23
30
|
stop: (text) => spinner.stop(text),
|
|
24
31
|
fail: (text) => spinner.error(text),
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { spawn } from "node:child_process";
|
|
2
2
|
import { mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
3
3
|
import { join } from "node:path";
|
|
4
|
-
import {
|
|
4
|
+
import { installedByScript, isCheckout } from "./home.js";
|
|
5
5
|
import { runningRuntime, settings } from "./start.js";
|
|
6
6
|
import { restart } from "./status.js";
|
|
7
|
-
import { cyan } from "./ui.js";
|
|
7
|
+
import { cmd, cyan } from "./ui.js";
|
|
8
8
|
/** The installer this install was made with; it also updates one. */
|
|
9
9
|
const INSTALLER = "https://engenty.ai/install.sh";
|
|
10
10
|
async function installer(into) {
|
|
@@ -16,7 +16,7 @@ async function installer(into) {
|
|
|
16
16
|
const text = response.ok ? await response.text() : "";
|
|
17
17
|
// The address answers with the studio's page while a server has no installer yet.
|
|
18
18
|
if (!text.startsWith("#!")) {
|
|
19
|
-
throw new Error(`${source}
|
|
19
|
+
throw new Error(`${source} didn’t return the installer.`);
|
|
20
20
|
}
|
|
21
21
|
const file = join(into, "install.sh");
|
|
22
22
|
writeFileSync(file, text, { mode: 0o700 });
|
|
@@ -30,8 +30,8 @@ async function installer(into) {
|
|
|
30
30
|
export async function update(paths, options = {}) {
|
|
31
31
|
if (!installedByScript(paths)) {
|
|
32
32
|
console.log(isCheckout()
|
|
33
|
-
? `This
|
|
34
|
-
: `This copy runs from npm.
|
|
33
|
+
? `This is a source checkout. To update: ${cyan("git pull && pnpm install && pnpm build")}`
|
|
34
|
+
: `This copy runs from npm. To update: ${cyan("npx wizards@latest")}`);
|
|
35
35
|
return 0;
|
|
36
36
|
}
|
|
37
37
|
const tmp = mkdtempSync(join(paths.home, "update-"));
|
|
@@ -57,7 +57,7 @@ export async function update(paths, options = {}) {
|
|
|
57
57
|
if (options.restart) {
|
|
58
58
|
return restart(paths);
|
|
59
59
|
}
|
|
60
|
-
console.log(`
|
|
60
|
+
console.log(` Installed. Restart engenty wizards to use the new version: ${cmd("restart")}`);
|
|
61
61
|
}
|
|
62
62
|
return 0;
|
|
63
63
|
}
|
|
@@ -51,7 +51,7 @@ export function validatePath(path) {
|
|
|
51
51
|
}
|
|
52
52
|
export function validateCommand(paths, asJson) {
|
|
53
53
|
if (!paths.length) {
|
|
54
|
-
console.error("
|
|
54
|
+
console.error("Give a path: a .wizard file, an unpacked package or a wizard JSON file.");
|
|
55
55
|
return 2;
|
|
56
56
|
}
|
|
57
57
|
const results = paths.map(validatePath);
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { bilingual } from "@engenty-wizards/shared/run";
|
|
1
2
|
import { and, asc, eq } from "drizzle-orm";
|
|
2
3
|
import { z } from "zod";
|
|
3
4
|
import { db, schema } from "../db/client.js";
|
|
@@ -274,7 +275,7 @@ export async function importConnector(userId, projectId, input) {
|
|
|
274
275
|
await requireWritableProject(projectId);
|
|
275
276
|
await requireAdmin();
|
|
276
277
|
if (await load(projectId, input.id)) {
|
|
277
|
-
throw new ServiceError("invalid", `Connector
|
|
278
|
+
throw new ServiceError("invalid", bilingual(`Den Connector „${input.id}“ gibt es in diesem Space schon.`, `The connector “${input.id}” already exists in this space.`));
|
|
278
279
|
}
|
|
279
280
|
try {
|
|
280
281
|
const { discover, surface, prepared } = await prepare(input);
|
|
@@ -351,7 +352,7 @@ export async function refreshConnector(projectId, id, accessToken) {
|
|
|
351
352
|
await requireWritableProject(projectId);
|
|
352
353
|
const record = await load(projectId, id);
|
|
353
354
|
if (!record) {
|
|
354
|
-
throw new ServiceError("not_found", "
|
|
355
|
+
throw new ServiceError("not_found", bilingual("Diesen Connector gibt es nicht.", "This connector doesn’t exist."));
|
|
355
356
|
}
|
|
356
357
|
try {
|
|
357
358
|
const { surface } = record.registry_surface_slug
|
|
@@ -170,7 +170,7 @@ export function oauthStateRun(rawState) {
|
|
|
170
170
|
export async function finishOAuth(answer, rawState) {
|
|
171
171
|
const state = unseal(rawState);
|
|
172
172
|
if (!state || state.exp < Date.now()) {
|
|
173
|
-
throw new Error("The sign-in has expired.
|
|
173
|
+
throw new Error("The sign-in has expired. Connect again.");
|
|
174
174
|
}
|
|
175
175
|
const run = await db.query.run.findFirst({ where: eq(schema.run.id, state.runId) });
|
|
176
176
|
const connection = run?.definition.connections?.find((c) => c.id === state.connectionId);
|
|
@@ -244,16 +244,16 @@ function connectFailure(err) {
|
|
|
244
244
|
const host = e.imapHost ? ` (${e.imapHost})` : "";
|
|
245
245
|
if (e.authenticationFailed) {
|
|
246
246
|
const answer = e.responseText?.slice(0, 160);
|
|
247
|
-
return bilingual(`Anmeldung abgelehnt${host}. Stimmen Adresse und (App-)Passwort?
|
|
247
|
+
return bilingual(`Anmeldung abgelehnt${host}. Stimmen Adresse und (App-)Passwort? Gmail und Google Workspace brauchen ein App-Passwort und eingeschaltetes IMAP.${answer ? ` Antwort des Servers: ${answer}` : ""}`, `The sign-in was refused${host}. Are the address and (app) password right? Gmail and Google Workspace need an app password and IMAP turned on.${answer ? ` The server said: ${answer}` : ""}`);
|
|
248
248
|
}
|
|
249
249
|
if (e.code === "ENOTFOUND") {
|
|
250
|
-
return bilingual(`Den Mail-Server${host} gibt es nicht.
|
|
250
|
+
return bilingual(`Den Mail-Server${host} gibt es nicht. Trag den IMAP-Server ein, bei Gmail und Google Workspace imap.gmail.com.`, `The mail server${host} doesn’t exist. Enter the IMAP server. For Gmail and Google Workspace, it’s imap.gmail.com.`);
|
|
251
251
|
}
|
|
252
252
|
if (e.code === "ETIMEDOUT" || e.code === "ETIMEOUT" || e.code === "ECONNREFUSED") {
|
|
253
|
-
return bilingual(`Der Mail-Server${host} antwortet nicht.
|
|
253
|
+
return bilingual(`Der Mail-Server${host} antwortet nicht. Prüf IMAP-Server und Port.`, `The mail server${host} isn’t responding. Check the IMAP server and port.`);
|
|
254
254
|
}
|
|
255
255
|
const detail = String(e.message ?? err).slice(0, 200);
|
|
256
|
-
return bilingual(`Verbinden hat nicht geklappt${host}: ${detail}`, `Connecting
|
|
256
|
+
return bilingual(`Verbinden hat nicht geklappt${host}: ${detail}`, `Connecting didn’t work${host}: ${detail}`);
|
|
257
257
|
}
|
|
258
258
|
export function disconnect(scope, connectionId) {
|
|
259
259
|
return deleteSecret(scope, slot(connectionId));
|
|
@@ -37,7 +37,7 @@ async function spaceExists(space) {
|
|
|
37
37
|
columns: { id: true },
|
|
38
38
|
});
|
|
39
39
|
if (!project) {
|
|
40
|
-
throw new Error(`There
|
|
40
|
+
throw new Error(`There’s no space “${space}”.`);
|
|
41
41
|
}
|
|
42
42
|
}
|
|
43
43
|
/** Keeps a connection: the same account for the same space again replaces the first one. */
|
|
@@ -101,7 +101,7 @@ export function pluginStateTenant(rawState) {
|
|
|
101
101
|
export async function finishPluginOAuth(answer, rawState) {
|
|
102
102
|
const state = unseal(rawState);
|
|
103
103
|
if (!state?.plugin || state.exp < Date.now()) {
|
|
104
|
-
throw new Error("The sign-in has expired.
|
|
104
|
+
throw new Error("The sign-in has expired. Connect again.");
|
|
105
105
|
}
|
|
106
106
|
const connector = oauthConnector(state.connectorId);
|
|
107
107
|
if (connector.auth.kind !== "oauth2") {
|