@jxsuite/studio 5.5.0 → 5.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/dist/chunks/{2020-g8mwpbkq.js → 2020-zvax9fmb.js} +3 -3
- package/dist/chunks/adapter-6zhjbpmd.js +4 -0
- package/dist/chunks/cf-account-picker-zfycs4k2.js +4 -0
- package/dist/chunks/cf-settings-fpa485q3.js +4 -0
- package/dist/chunks/components-b0vh4sq8.js +4 -0
- package/dist/chunks/content-source-z5t0d0h9.js +4 -0
- package/dist/chunks/convert-to-repeater-x19jr6c7.js +4 -0
- package/dist/chunks/editor-7e23n4a8.js +4 -0
- package/dist/chunks/entry-commands-5cm6aba2.js +4 -0
- package/dist/chunks/extension-sections-y90sa0n4.js +4 -0
- package/dist/chunks/file-ops-hv7gf757.js +4 -0
- package/dist/chunks/files-kb0epdxf.js +4 -0
- package/dist/chunks/format-host-eg1wy2bp.js +4 -0
- package/dist/chunks/fs-events-ky3vxfmh.js +4 -0
- package/dist/chunks/git-panel-yyg3bzp2.js +4 -0
- package/dist/chunks/grid-view-5mqv1cbd.css +1 -0
- package/dist/chunks/grid-view-d9mybhn0.js +51 -0
- package/dist/chunks/iframe-host-9wdf0hes.js +4 -0
- package/dist/chunks/index-2tf0m2ne.js +4 -0
- package/dist/chunks/{index-arg188jq.js → index-vnwy9d44.js} +3 -3
- package/dist/chunks/{javascript-zcdmye2k.js → javascript-f0nrbdjb.js} +2 -2
- package/dist/chunks/{jsonMode-6x5e1nbf.js → jsonMode-nfa90dtf.js} +5 -5
- package/dist/chunks/jx-validate-7w11db9v.js +4 -0
- package/dist/chunks/layers-7zasrpse.js +4 -0
- package/dist/chunks/layers-panel-9nzc4fdq.js +4 -0
- package/dist/chunks/lit-html-5qr7nbng.js +4 -0
- package/dist/chunks/media-picker-maevn9d4.js +4 -0
- package/dist/chunks/menu-wq6q0v3y.js +4 -0
- package/dist/chunks/{monaco-binding-4az2kh5p.js → monaco-binding-antn79jf.js} +3 -3
- package/dist/chunks/monaco-buffer-9ry2rn5x.js +4 -0
- package/dist/chunks/{monaco-setup-d7mwkcx3.js → monaco-setup-k8s40vwg.js} +3 -3
- package/dist/chunks/notify-g91gjd6w.js +4 -0
- package/dist/chunks/platform-jdwjp2vt.js +4 -0
- package/dist/chunks/publish-panel-8yym447p.js +4 -0
- package/dist/chunks/quick-search-9bzm9kh3.js +4 -0
- package/dist/chunks/references-znssfqvq.js +4 -0
- package/dist/chunks/right-panel-czbzktm8.js +4 -0
- package/dist/chunks/section-registry-0rtq73qs.js +4 -0
- package/dist/chunks/studio-011em5cf.js +5 -0
- package/dist/chunks/studio-02y9cb4h.js +6 -0
- package/dist/chunks/{studio-7gqyhjns.js → studio-09n3fyy0.js} +4 -4
- package/dist/chunks/{studio-xcng8nx7.js → studio-0c3fpdqj.js} +5 -5
- package/dist/chunks/studio-0mm38y62.js +5 -0
- package/dist/chunks/studio-0nm2skex.js +4 -0
- package/dist/chunks/{studio-73czgk6a.js → studio-153mwkyq.js} +4 -4
- package/dist/chunks/{studio-f8jyp45j.js → studio-1pxvgx1t.js} +4 -4
- package/dist/chunks/studio-27tc8q0h.js +5 -0
- package/dist/chunks/studio-28pz4s1k.js +5 -0
- package/dist/chunks/{studio-x5esgzct.js → studio-36s6qjgq.js} +4 -4
- package/dist/chunks/studio-4yztve2t.js +5 -0
- package/dist/chunks/{studio-x9sagq2d.js → studio-5fc0728f.js} +7 -7
- package/dist/chunks/{studio-7jazdy6y.js → studio-654fxcr0.js} +4 -4
- package/dist/chunks/studio-6exg5z4x.js +4 -0
- package/dist/chunks/studio-6k1eswp9.js +5 -0
- package/dist/chunks/{studio-5wfrgee9.js → studio-6zyt56ek.js} +4 -4
- package/dist/chunks/studio-7djymzt2.js +5 -0
- package/dist/chunks/{studio-b4epb26c.js → studio-7w04zw8h.js} +7 -7
- package/dist/chunks/studio-805fwp9k.js +5 -0
- package/dist/chunks/{studio-k1eaqyzm.js → studio-81twpmzj.js} +4 -4
- package/dist/chunks/studio-891t1tv9.js +5 -0
- package/dist/chunks/{studio-5n1km79v.js → studio-9n2j9nqk.js} +4 -4
- package/dist/chunks/{studio-he2fhrgp.js → studio-9tkaykt5.js} +4 -4
- package/dist/chunks/studio-ant1zbp3.js +5 -0
- package/dist/chunks/studio-b29h7g7s.js +5 -0
- package/dist/chunks/studio-b5rxwkj2.js +5 -0
- package/dist/chunks/studio-d007j0z3.js +7 -0
- package/dist/chunks/studio-dknr8m7b.js +14 -0
- package/dist/chunks/{studio-eq27rrr0.js → studio-dmymvk2j.js} +3 -3
- package/dist/chunks/studio-dtmdjmqb.js +5 -0
- package/dist/chunks/studio-eb5sty2k.js +5 -0
- package/dist/chunks/{studio-hc9q4j24.js → studio-ebt49j3c.js} +5 -5
- package/dist/chunks/studio-eegyf5vg.js +5 -0
- package/dist/chunks/studio-frv7vjhw.js +5 -0
- package/dist/chunks/studio-ft8pfpp0.js +5 -0
- package/dist/chunks/{studio-mhhc9btt.js → studio-gj4j9e7k.js} +4 -4
- package/dist/chunks/{studio-hf4qdjc8.js → studio-gxna6yta.js} +4 -4
- package/dist/chunks/studio-je15p5v8.js +6 -0
- package/dist/chunks/{studio-21enxdr8.js → studio-jsr14n1s.js} +4 -4
- package/dist/chunks/studio-k9pwvmz8.js +5 -0
- package/dist/chunks/{studio-p1eggxcf.js → studio-ks0ecgjx.js} +3 -3
- package/dist/chunks/studio-mb8jhtr4.js +64 -0
- package/dist/chunks/studio-mf41717j.js +5 -0
- package/dist/chunks/{studio-625ezz59.js → studio-mm8x32gg.js} +4 -4
- package/dist/chunks/{studio-pkkw32j0.js → studio-n2e133d6.js} +4 -4
- package/dist/chunks/{studio-c4pnt1c6.js → studio-njmg0e73.js} +5 -5
- package/dist/chunks/studio-nvykrgbj.js +4 -0
- package/dist/chunks/studio-nw4q9sdn.js +5 -0
- package/dist/chunks/studio-p6avneaq.js +5 -0
- package/dist/chunks/studio-pvj970st.js +5 -0
- package/dist/chunks/studio-r7yeeqc4.js +5 -0
- package/dist/chunks/studio-s85vah66.js +6 -0
- package/dist/chunks/studio-sadckcpp.js +7 -0
- package/dist/chunks/studio-sgzss898.js +9 -0
- package/dist/chunks/{studio-7by9a93k.js → studio-t0v47dpc.js} +4 -4
- package/dist/chunks/{studio-jnb285we.js → studio-tj28pxa1.js} +4 -4
- package/dist/chunks/{studio-6j2jn55a.js → studio-tzs6njnb.js} +8 -8
- package/dist/chunks/studio-vz7b43ng.js +5 -0
- package/dist/chunks/studio-w8w9frjy.js +16 -0
- package/dist/chunks/{studio-xc8ebsts.js → studio-wr0pq67n.js} +4 -4
- package/dist/chunks/{studio-8r4y2x0z.js → studio-y164brht.js} +4 -4
- package/dist/chunks/studio-y17505ge.js +928 -0
- package/dist/chunks/studio-ymsjnvp9.js +5 -0
- package/dist/chunks/studio-z1vdxq0e.js +5 -0
- package/dist/chunks/studio-z47mm077.js +10 -0
- package/dist/chunks/studio-zkkdbbvd.js +9 -0
- package/dist/chunks/{studio-awqghqxv.js → studio-zkvyd3ev.js} +4 -4
- package/dist/chunks/{tsMode-rtwt7w1a.js → tsMode-eq26t9gs.js} +5 -5
- package/dist/chunks/workspace-emt8454d.js +4 -0
- package/dist/chunks/ws-client-3gxqp06s.js +4 -0
- package/dist/iframe-entry.js +14 -14
- package/dist/manifest.json +62 -59
- package/dist/studio.css +1 -1
- package/dist/studio.js +115 -117
- package/package.json +5 -5
- package/src/account/action-flow.ts +294 -0
- package/src/account/action-required.ts +68 -0
- package/src/account-status.ts +29 -1
- package/src/browse/library-model.ts +3 -1
- package/src/browse/library-preview.ts +6 -2
- package/src/canvas/asset-refs.ts +3 -1
- package/src/canvas/asset-resolve.ts +79 -1
- package/src/canvas/iframe-entry.ts +38 -1
- package/src/canvas/iframe-host.ts +85 -0
- package/src/canvas/iframe-protocol.ts +13 -0
- package/src/files/asset-versions.ts +294 -0
- package/src/files/files.ts +61 -9
- package/src/files/fs-events.ts +279 -28
- package/src/files/media-meta.ts +2 -1
- package/src/files/media-paths.ts +5 -2
- package/src/files/media-upload.ts +5 -1
- package/src/new-project/add-repo-modal.ts +12 -1
- package/src/new-project/new-project-modal.ts +12 -1
- package/src/panels/git-panel.ts +25 -2
- package/src/platform-errors.ts +61 -1
- package/src/platforms/cloud.ts +389 -50
- package/src/platforms/devserver.ts +17 -1
- package/src/publish/pages-service.ts +17 -7
- package/src/services/ai-models.ts +30 -6
- package/src/services/ai-system-prompt.ts +81 -51
- package/src/settings/preferences-accounts.ts +42 -3
- package/src/settings/preferences-dialog.ts +8 -1
- package/src/studio.ts +18 -1
- package/src/surfaces/dialog.ts +5 -0
- package/src/surfaces/welcome.json +86 -1
- package/src/surfaces/welcome.ts +61 -2
- package/src/types.ts +84 -2
- package/src/ui/ai-managed-connect.ts +41 -4
- package/src/ui/media-picker.ts +2 -1
- package/dist/chunks/adapter-bsbs78x9.js +0 -4
- package/dist/chunks/cf-account-picker-gnm7xeqb.js +0 -4
- package/dist/chunks/cf-settings-9y6jyscp.js +0 -4
- package/dist/chunks/components-s51h3b7c.js +0 -4
- package/dist/chunks/content-source-ty3be0qg.js +0 -4
- package/dist/chunks/convert-to-repeater-c3e7q61z.js +0 -4
- package/dist/chunks/editor-t002b41m.js +0 -4
- package/dist/chunks/entry-commands-sb72e9gy.js +0 -4
- package/dist/chunks/extension-sections-ktn2ntnj.js +0 -4
- package/dist/chunks/file-ops-78zeytkm.js +0 -4
- package/dist/chunks/files-gatzrz8v.js +0 -4
- package/dist/chunks/format-host-r59b1651.js +0 -4
- package/dist/chunks/fs-events-f8h91ndt.js +0 -4
- package/dist/chunks/git-panel-y12zf7nj.js +0 -4
- package/dist/chunks/grid-view-rfd8b2pg.js +0 -51
- package/dist/chunks/grid-view-tafenfm2.css +0 -1
- package/dist/chunks/iframe-host-vsrsj20g.js +0 -4
- package/dist/chunks/index-5aghyrfh.js +0 -4
- package/dist/chunks/jx-validate-653krkrf.js +0 -4
- package/dist/chunks/layers-32p8gtae.js +0 -4
- package/dist/chunks/layers-panel-rs58m105.js +0 -4
- package/dist/chunks/lit-html-54bmkwz3.js +0 -4
- package/dist/chunks/media-picker-5bb04wct.js +0 -4
- package/dist/chunks/menu-cbha7w2e.js +0 -4
- package/dist/chunks/monaco-buffer-9vbbyfr1.js +0 -4
- package/dist/chunks/notify-dc1nz5ar.js +0 -4
- package/dist/chunks/platform-2m49s1zf.js +0 -4
- package/dist/chunks/publish-panel-nx3ycmma.js +0 -4
- package/dist/chunks/quick-search-yzrzh9x3.js +0 -4
- package/dist/chunks/references-vx7mbj9f.js +0 -4
- package/dist/chunks/right-panel-7jzpbxja.js +0 -4
- package/dist/chunks/section-registry-gjryse41.js +0 -4
- package/dist/chunks/studio-3znfhcxg.js +0 -5
- package/dist/chunks/studio-58qam27v.js +0 -4
- package/dist/chunks/studio-6j59fwaw.js +0 -5
- package/dist/chunks/studio-7z69g1gx.js +0 -5
- package/dist/chunks/studio-93j3v6zx.js +0 -5
- package/dist/chunks/studio-9gf6v8zy.js +0 -5
- package/dist/chunks/studio-9rhmettf.js +0 -4
- package/dist/chunks/studio-ac5aq677.js +0 -10
- package/dist/chunks/studio-as65vbns.js +0 -5
- package/dist/chunks/studio-bkv0sga4.js +0 -6
- package/dist/chunks/studio-bttmqef4.js +0 -5
- package/dist/chunks/studio-c3y9d41k.js +0 -5
- package/dist/chunks/studio-ccegp7gz.js +0 -9
- package/dist/chunks/studio-chxabn98.js +0 -6
- package/dist/chunks/studio-cktcdsxz.js +0 -16
- package/dist/chunks/studio-cnspfke5.js +0 -5
- package/dist/chunks/studio-de3p1ktm.js +0 -5
- package/dist/chunks/studio-fsbcn530.js +0 -928
- package/dist/chunks/studio-gftga7a3.js +0 -64
- package/dist/chunks/studio-hf1rpcq0.js +0 -4
- package/dist/chunks/studio-hz02hq70.js +0 -5
- package/dist/chunks/studio-jsv3s3s1.js +0 -5
- package/dist/chunks/studio-ks7cksh0.js +0 -5
- package/dist/chunks/studio-nptx0dbs.js +0 -5
- package/dist/chunks/studio-pg0z7k98.js +0 -5
- package/dist/chunks/studio-pve0b2f2.js +0 -5
- package/dist/chunks/studio-q7zmjv3b.js +0 -6
- package/dist/chunks/studio-rpmvw7kj.js +0 -5
- package/dist/chunks/studio-rwhss52s.js +0 -5
- package/dist/chunks/studio-sbg3g3h0.js +0 -5
- package/dist/chunks/studio-sq1bn60g.js +0 -14
- package/dist/chunks/studio-vwz7rma2.js +0 -5
- package/dist/chunks/studio-wa55e8gf.js +0 -5
- package/dist/chunks/studio-x0mzdha2.js +0 -5
- package/dist/chunks/studio-xrgpakvc.js +0 -9
- package/dist/chunks/studio-xt3djk1w.js +0 -7
- package/dist/chunks/studio-yh3nggx1.js +0 -7
- package/dist/chunks/studio-zmecp6hq.js +0 -5
- package/dist/chunks/workspace-g6dvaete.js +0 -4
- package/dist/chunks/ws-client-shf41j5p.js +0 -4
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
/// <reference lib="dom" />
|
|
2
2
|
/**
|
|
3
|
-
* Pages-service — Cloudflare Pages publish domain logic over the PAL's
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* tell whether the publish workflow already exists.
|
|
3
|
+
* Pages-service — Cloudflare Pages publish domain logic over the PAL's `cfApi` passthrough. Works
|
|
4
|
+
* identically on every platform that provides it: the dev server / desktop (user API token via
|
|
5
|
+
* cf-settings → /__studio/cf/proxy) and the cloud platform (hosted OAuth). Publish state is written
|
|
6
|
+
* to project.json `build.deploy` — it travels with the repo, so any Studio can tell whether the
|
|
7
|
+
* publish workflow already exists.
|
|
9
8
|
*
|
|
10
9
|
* @license MIT
|
|
11
10
|
*/
|
|
@@ -13,6 +12,7 @@
|
|
|
13
12
|
import { updateWranglerConfig } from "@jxsuite/create/scaffold";
|
|
14
13
|
import type { DeployConfig, ProjectConfig } from "@jxsuite/schema/types";
|
|
15
14
|
import { getPlatform } from "../platform";
|
|
15
|
+
import { actIfRequired } from "../account/action-flow";
|
|
16
16
|
import { updateSiteConfig } from "../site-context";
|
|
17
17
|
|
|
18
18
|
export interface CfAccount {
|
|
@@ -52,12 +52,22 @@ export function platformSupportsPublish(): boolean {
|
|
|
52
52
|
}
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
+
/**
|
|
56
|
+
* One Cloudflare call. A refusal that offers an action (desktop.md §10.4) is offered here, once for
|
|
57
|
+
* every publish step, and still thrown: the step that asked failed, and its caller reports that in
|
|
58
|
+
* its own words while the offer says how to fix it.
|
|
59
|
+
*/
|
|
55
60
|
async function cfApi<T>(path: string, init?: { method?: string; body?: unknown }): Promise<T> {
|
|
56
61
|
const api = getPlatform().cfApi;
|
|
57
62
|
if (!api) {
|
|
58
63
|
throw new Error("This platform cannot reach the Cloudflare API");
|
|
59
64
|
}
|
|
60
|
-
|
|
65
|
+
try {
|
|
66
|
+
return (await api(path, init)) as T;
|
|
67
|
+
} catch (error) {
|
|
68
|
+
void actIfRequired(error);
|
|
69
|
+
throw error;
|
|
70
|
+
}
|
|
61
71
|
}
|
|
62
72
|
|
|
63
73
|
export async function listAccounts(): Promise<CfAccount[]> {
|
|
@@ -2,17 +2,17 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* Ai-models.js — available-model listing from the studio AI proxy.
|
|
4
4
|
*
|
|
5
|
-
* Fetches the proxy's /models endpoint (the chat endpoint's sibling), forwarding the
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* after credentials change).
|
|
5
|
+
* Fetches the proxy's /models endpoint (the chat endpoint's sibling), forwarding the stored API key
|
|
6
|
+
* as X-Api-Key and the endpoint override as X-Api-Base-URL so the proxy lists models from the
|
|
7
|
+
* user's chosen provider. Shared by the credentials form and the chat composer's model picker;
|
|
8
|
+
* results are cached module-wide until invalidated (e.g. after credentials change).
|
|
10
9
|
*
|
|
11
10
|
* @license MIT
|
|
12
11
|
*/
|
|
13
12
|
|
|
14
|
-
import type { AiModelsResponse } from "@jxsuite/protocol";
|
|
13
|
+
import type { AiModelsResponse, OfferedAction } from "@jxsuite/protocol";
|
|
15
14
|
import { getPlatform } from "../platform";
|
|
15
|
+
import { offeredActions } from "../platform-errors";
|
|
16
16
|
import { getBaseUrl, getOpenAiKey, hasOpenAiKey, storedModel } from "./ai-settings";
|
|
17
17
|
import { SETTINGS } from "./settings/definitions";
|
|
18
18
|
import { onSettingsChanged } from "./settings/kernel";
|
|
@@ -76,6 +76,14 @@ let proxyManaged = false;
|
|
|
76
76
|
let proxyDefaultModel = "";
|
|
77
77
|
let proxyCode: AiModelsResponse["code"];
|
|
78
78
|
let proxyModelsError = "";
|
|
79
|
+
/** What an `action_required` probe offered; null for every other answer. */
|
|
80
|
+
let proxyAction: ProxyActionOffer | null = null;
|
|
81
|
+
|
|
82
|
+
/** What a managed backend says the assistant needs first, in the backend's own words. */
|
|
83
|
+
export interface ProxyActionOffer {
|
|
84
|
+
detail?: string;
|
|
85
|
+
actions: OfferedAction[];
|
|
86
|
+
}
|
|
79
87
|
|
|
80
88
|
/**
|
|
81
89
|
* One-shot capability probe shared by every credentials gate, plus the hosts to repaint when it
|
|
@@ -118,6 +126,7 @@ export function resetModelCache() {
|
|
|
118
126
|
proxyDefaultModel = "";
|
|
119
127
|
proxyCode = undefined;
|
|
120
128
|
proxyModelsError = "";
|
|
129
|
+
proxyAction = null;
|
|
121
130
|
/* The probe's result IS the flags above. Clearing them while keeping the settled promise
|
|
122
131
|
would strand every gate on a permanent "unconfigured, unmanaged" reading — ensureProxyProbe
|
|
123
132
|
would no-op forever and the managed option would vanish until a full reload. */
|
|
@@ -278,6 +287,14 @@ export function proxyModelsErrorMessage(): string {
|
|
|
278
287
|
return proxyModelsError;
|
|
279
288
|
}
|
|
280
289
|
|
|
290
|
+
/**
|
|
291
|
+
* The offer the last probe carried — set only when the backend answered `action_required` (ai.md
|
|
292
|
+
* §2.1), and null for every other answer, so no gate can offer an action the backend did not name.
|
|
293
|
+
*/
|
|
294
|
+
export function proxyActionOffer(): ProxyActionOffer | null {
|
|
295
|
+
return proxyAction;
|
|
296
|
+
}
|
|
297
|
+
|
|
281
298
|
/** The proxy's preferred model id ("" when it does not declare one). */
|
|
282
299
|
export function getProxyDefaultModel(): string {
|
|
283
300
|
return proxyDefaultModel;
|
|
@@ -369,6 +386,13 @@ export async function fetchAvailableModels(
|
|
|
369
386
|
proxyDefaultModel = data.defaultModel ?? "";
|
|
370
387
|
proxyCode = data.code;
|
|
371
388
|
proxyModelsError = data.upstreamError !== undefined ? (data.upstreamMessage ?? "") : "";
|
|
389
|
+
proxyAction =
|
|
390
|
+
data.code === "action_required"
|
|
391
|
+
? {
|
|
392
|
+
actions: offeredActions(data.actions),
|
|
393
|
+
...(typeof data.detail === "string" && data.detail ? { detail: data.detail } : {}),
|
|
394
|
+
}
|
|
395
|
+
: null;
|
|
372
396
|
/* Capabilities are kept, not dropped. The backend has reported `toolSupport` all along and the
|
|
373
397
|
ingest mapped `{id, name}` only, so a Workers AI model that cannot call tools looked exactly
|
|
374
398
|
like one that can — the agent loop ran, called nothing, and answered as if that were normal.
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Ai-system-prompt.js — Dynamic system prompt builder for the Jx AI assistant
|
|
3
3
|
*
|
|
4
|
-
* Constructs the system prompt based on the current project context, open document,
|
|
5
|
-
*
|
|
4
|
+
* Constructs the system prompt based on the current project context, open document, and available
|
|
5
|
+
* components. The quality of AI output depends critically on this file.
|
|
6
6
|
*
|
|
7
7
|
* @license MIT
|
|
8
8
|
*/
|
|
@@ -656,6 +656,75 @@ When asked to build a site with multiple pages:
|
|
|
656
656
|
|
|
657
657
|
// ─── System prompt builder ───────────────────────────────────────────────────
|
|
658
658
|
|
|
659
|
+
const ROLE = `You are an expert Jx builder assistant embedded in Jx Studio. You help users build websites, components, pages, and layouts using the Jx JSON schema. The live jxsuite.com marketing site is built entirely with Jx — you can produce production-quality Jx code.`;
|
|
660
|
+
|
|
661
|
+
/**
|
|
662
|
+
* What to do when a tool call fails. Static: it names tools and validation messages, never the
|
|
663
|
+
* state, so it belongs to the cacheable prefix rather than after the dynamic sections.
|
|
664
|
+
*/
|
|
665
|
+
const ERROR_RECOVERY = `## Error Recovery
|
|
666
|
+
|
|
667
|
+
If a tool call fails (returns { success: false }):
|
|
668
|
+
1. Read the error message carefully — it includes a "→ Fix:" hint telling you exactly how to correct the error.
|
|
669
|
+
2. Each error points to a specific path in the document and a specific rule violation.
|
|
670
|
+
3. Apply the suggested fix using set_property, delete_node, or add_child as appropriate.
|
|
671
|
+
4. Do NOT re-issue the exact same tool call with the same arguments — you must CHANGE something.
|
|
672
|
+
5. If you see the SAME error after 2 attempts, try a completely different approach (e.g., remove and re-add the node instead of patching it).
|
|
673
|
+
|
|
674
|
+
### Common validation errors and their fixes:
|
|
675
|
+
|
|
676
|
+
| Error pattern | What happened | How to fix |
|
|
677
|
+
|---|---|---|
|
|
678
|
+
| "must NOT have additional property" in style | You used a non-camelCase CSS property (e.g. "background-color") or put an HTML attribute directly on the element. | Use camelCase: "backgroundColor". Put aria-*, data-*, role, and other non-IDL attributes inside the "attributes" object: { "attributes": { "aria-label": "..." } } |
|
|
679
|
+
| "must match pattern" on tagName | A custom element tag name doesn't contain a hyphen. | Add a hyphen: "newsletter-form" not "newsletter". Standard HTML elements use their exact name ("div", "p", "input"). |
|
|
680
|
+
| "must be string" | A value is an unquoted number, boolean, or bare word. | Wrap the value in quotes: "10px" not 10px. All CSS values and text must be strings. |
|
|
681
|
+
| "must be number" / "must be integer" | A numeric field (like index, tabIndex) is wrapped in quotes. | Remove the quotes: use 0 not "0". |
|
|
682
|
+
| "must have required property" | A required field is missing from the node. | Add the missing property. Every element must have "tagName". |
|
|
683
|
+
| "must be object" | A field that expects an object (like style or attributes) received a string or other type. | Use {} not a string. |
|
|
684
|
+
| "No node exists at path" | The path you provided doesn't point to an existing node. | Call read_document first to see the current structure and valid paths, then use the correct path. |
|
|
685
|
+
|
|
686
|
+
### If you keep getting errors:
|
|
687
|
+
- Call read_document again — the document may have changed since you last read it.
|
|
688
|
+
- Remove the problematic node entirely with delete_node, then re-create it correctly with add_child.
|
|
689
|
+
- If the error message points to a different path than you expected, the node might have moved due to previous edits.`;
|
|
690
|
+
|
|
691
|
+
/** What every section of the prompt is joined with. */
|
|
692
|
+
const SECTION_SEPARATOR = "\n\n---\n\n";
|
|
693
|
+
|
|
694
|
+
/**
|
|
695
|
+
* The part of every system prompt that does not depend on the state, byte for byte: the role, the
|
|
696
|
+
* Jx reference sections, and the error-recovery guidance, each followed by the section separator.
|
|
697
|
+
*
|
|
698
|
+
* It exists for providers' prompt caches. A cache matches on a PREFIX of the request, and the
|
|
699
|
+
* system prompt is the request's first message, so the reference material (most of the prompt's
|
|
700
|
+
* tokens) only hits when nothing that changes between rounds comes before it. The prompt used to
|
|
701
|
+
* open with the role, the workflow for the current state and its tool list, so opening a document
|
|
702
|
+
* or registering one more command tool moved the first changed byte to the second paragraph and
|
|
703
|
+
* every request after it paid for the whole reference again. Everything dynamic — the mode, the
|
|
704
|
+
* tool list, the document, project and file summaries — now follows this prefix, and the closing
|
|
705
|
+
* instructions stay last. {@link buildSystemPrompt} always starts with it, and its tests hold that
|
|
706
|
+
* for every combination of the state flags.
|
|
707
|
+
*/
|
|
708
|
+
export const SYSTEM_PROMPT_STATIC_PREFIX =
|
|
709
|
+
[
|
|
710
|
+
// 1. Role
|
|
711
|
+
ROLE,
|
|
712
|
+
// 2. Jx schema reference — kept in ALL modes (pre-project the model plans starter content)
|
|
713
|
+
JX_SCHEMA_REFERENCE,
|
|
714
|
+
// 2a. State shape decision tree
|
|
715
|
+
STATE_SHAPE_DECISION_TREE,
|
|
716
|
+
// 2b. Real-world patterns
|
|
717
|
+
REAL_WORLD_PATTERNS,
|
|
718
|
+
// 2c. Design principles — spacing, type, color, layout, restraint
|
|
719
|
+
DESIGN_PRINCIPLES,
|
|
720
|
+
// 2d. Control flow & reactivity — signals, list rendering ($map), conditionals ($switch)
|
|
721
|
+
CONTROL_FLOW_PATTERNS,
|
|
722
|
+
// 2e. Multi-page site building — layouts, file-based routing, navigation
|
|
723
|
+
MULTI_PAGE_PATTERNS,
|
|
724
|
+
// 3. Error recovery guidance
|
|
725
|
+
ERROR_RECOVERY,
|
|
726
|
+
].join(SECTION_SEPARATOR) + SECTION_SEPARATOR;
|
|
727
|
+
|
|
659
728
|
/**
|
|
660
729
|
* Build a dynamic system prompt for the AI assistant.
|
|
661
730
|
*
|
|
@@ -681,7 +750,7 @@ export function buildSystemPrompt({
|
|
|
681
750
|
}: BuildSystemPromptOptions = {}) {
|
|
682
751
|
const hasDocument = Boolean(document);
|
|
683
752
|
|
|
684
|
-
//
|
|
753
|
+
// The state-appropriate workflow and the tool list for the current state.
|
|
685
754
|
// The list the model is TOLD about and the list the gate will honour are the same filter, so a
|
|
686
755
|
// Refusal is never a surprise to it. The command-projected tools arrive already filtered by
|
|
687
756
|
// Their records' own gates, for the same reason — one function answers both the prompt and the
|
|
@@ -695,8 +764,6 @@ export function buildSystemPrompt({
|
|
|
695
764
|
.map((blurb) => `- ${blurb}`)
|
|
696
765
|
.join("\n");
|
|
697
766
|
|
|
698
|
-
const role = `You are an expert Jx builder assistant embedded in Jx Studio. You help users build websites, components, pages, and layouts using the Jx JSON schema. The live jxsuite.com marketing site is built entirely with Jx — you can produce production-quality Jx code.`;
|
|
699
|
-
|
|
700
767
|
let workflow: string;
|
|
701
768
|
if (!hasProject && !hasDocument) {
|
|
702
769
|
workflow = `No project is open yet. Your first job is to bootstrap one:
|
|
@@ -734,23 +801,10 @@ ${ASKING_THE_USER}
|
|
|
734
801
|
|
|
735
802
|
Be concise. Don't explain what Jx is unless asked. Just build.`;
|
|
736
803
|
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
sections
|
|
741
|
-
// 2. Jx schema reference — kept in ALL modes (pre-project the model plans starter content)
|
|
742
|
-
JX_SCHEMA_REFERENCE,
|
|
743
|
-
// 3. State shape decision tree
|
|
744
|
-
STATE_SHAPE_DECISION_TREE,
|
|
745
|
-
// 4. Real-world patterns
|
|
746
|
-
REAL_WORLD_PATTERNS,
|
|
747
|
-
// 4a. Design principles — spacing, type, color, layout, restraint
|
|
748
|
-
DESIGN_PRINCIPLES,
|
|
749
|
-
// 4b. Control flow & reactivity — signals, list rendering ($map), conditionals ($switch)
|
|
750
|
-
CONTROL_FLOW_PATTERNS,
|
|
751
|
-
// 4c. Multi-page site building — layouts, file-based routing, navigation
|
|
752
|
-
MULTI_PAGE_PATTERNS,
|
|
753
|
-
);
|
|
804
|
+
/* 4. The mode. Everything from here on is a function of what is open right now, so it all follows
|
|
805
|
+
SYSTEM_PROMPT_STATIC_PREFIX: a provider's prompt cache matches on a prefix, and the first byte
|
|
806
|
+
that differs between two requests ends the match. */
|
|
807
|
+
const sections = [`## Current Mode\n\n${workflow}`];
|
|
754
808
|
|
|
755
809
|
// 5. Current document context
|
|
756
810
|
if (document) {
|
|
@@ -758,7 +812,7 @@ Be concise. Don't explain what Jx is unless asked. Just build.`;
|
|
|
758
812
|
sections.push(`## Current Document\n\n${summary}`);
|
|
759
813
|
}
|
|
760
814
|
|
|
761
|
-
//
|
|
815
|
+
// 5a. Project context
|
|
762
816
|
if (hasProject && (projectConfig || components || projectRoot)) {
|
|
763
817
|
const projectSummary = buildProjectSummary({
|
|
764
818
|
components,
|
|
@@ -771,7 +825,7 @@ Be concise. Don't explain what Jx is unless asked. Just build.`;
|
|
|
771
825
|
}
|
|
772
826
|
}
|
|
773
827
|
|
|
774
|
-
//
|
|
828
|
+
// 5b. File inventory — a compact map of the project for cross-file work
|
|
775
829
|
if (hasProject && fileInventory && fileInventory.length > 0) {
|
|
776
830
|
const capped = fileInventory.slice(0, FILE_INVENTORY_CAP);
|
|
777
831
|
const more =
|
|
@@ -781,34 +835,10 @@ Be concise. Don't explain what Jx is unless asked. Just build.`;
|
|
|
781
835
|
sections.push(`## Project Files\n\n${capped.join("\n")}${more}`);
|
|
782
836
|
}
|
|
783
837
|
|
|
784
|
-
//
|
|
785
|
-
sections.push(
|
|
786
|
-
|
|
787
|
-
If a tool call fails (returns { success: false }):
|
|
788
|
-
1. Read the error message carefully — it includes a "→ Fix:" hint telling you exactly how to correct the error.
|
|
789
|
-
2. Each error points to a specific path in the document and a specific rule violation.
|
|
790
|
-
3. Apply the suggested fix using set_property, delete_node, or add_child as appropriate.
|
|
791
|
-
4. Do NOT re-issue the exact same tool call with the same arguments — you must CHANGE something.
|
|
792
|
-
5. If you see the SAME error after 2 attempts, try a completely different approach (e.g., remove and re-add the node instead of patching it).
|
|
793
|
-
|
|
794
|
-
### Common validation errors and their fixes:
|
|
795
|
-
|
|
796
|
-
| Error pattern | What happened | How to fix |
|
|
797
|
-
|---|---|---|
|
|
798
|
-
| "must NOT have additional property" in style | You used a non-camelCase CSS property (e.g. "background-color") or put an HTML attribute directly on the element. | Use camelCase: "backgroundColor". Put aria-*, data-*, role, and other non-IDL attributes inside the "attributes" object: { "attributes": { "aria-label": "..." } } |
|
|
799
|
-
| "must match pattern" on tagName | A custom element tag name doesn't contain a hyphen. | Add a hyphen: "newsletter-form" not "newsletter". Standard HTML elements use their exact name ("div", "p", "input"). |
|
|
800
|
-
| "must be string" | A value is an unquoted number, boolean, or bare word. | Wrap the value in quotes: "10px" not 10px. All CSS values and text must be strings. |
|
|
801
|
-
| "must be number" / "must be integer" | A numeric field (like index, tabIndex) is wrapped in quotes. | Remove the quotes: use 0 not "0". |
|
|
802
|
-
| "must have required property" | A required field is missing from the node. | Add the missing property. Every element must have "tagName". |
|
|
803
|
-
| "must be object" | A field that expects an object (like style or attributes) received a string or other type. | Use {} not a string. |
|
|
804
|
-
| "No node exists at path" | The path you provided doesn't point to an existing node. | Call read_document first to see the current structure and valid paths, then use the correct path. |
|
|
805
|
-
|
|
806
|
-
### If you keep getting errors:
|
|
807
|
-
- Call read_document again — the document may have changed since you last read it.
|
|
808
|
-
- Remove the problematic node entirely with delete_node, then re-create it correctly with add_child.
|
|
809
|
-
- If the error message points to a different path than you expected, the node might have moved due to previous edits.`);
|
|
838
|
+
// 6. Closing — last, where a long prompt's final instructions carry the most weight.
|
|
839
|
+
sections.push(closing);
|
|
810
840
|
|
|
811
|
-
return sections.join(
|
|
841
|
+
return SYSTEM_PROMPT_STATIC_PREFIX + sections.join(SECTION_SEPARATOR);
|
|
812
842
|
}
|
|
813
843
|
|
|
814
844
|
// ─── Helpers ─────────────────────────────────────────────────────────────────
|
|
@@ -30,7 +30,9 @@ import { clearCfConnection, getCfAccountId, getCfToken } from "../services/cf-se
|
|
|
30
30
|
import { clearAiProvider, getBaseUrl, hasOpenAiKey } from "../services/ai-settings";
|
|
31
31
|
import { preferredModel, resetModelCache } from "../services/ai-models";
|
|
32
32
|
import { getPlatform, hasPlatform } from "../platform";
|
|
33
|
-
import
|
|
33
|
+
import { getAccountEntries } from "../account-status";
|
|
34
|
+
import { runOfferedAction } from "../account/action-flow";
|
|
35
|
+
import type { AccountEntry, CfConnection, OfferedAction } from "../types";
|
|
34
36
|
|
|
35
37
|
/** One thing a row can do besides existing. */
|
|
36
38
|
export interface AccountAction {
|
|
@@ -228,11 +230,47 @@ function localCloudflareRecord(): AccountRecord {
|
|
|
228
230
|
};
|
|
229
231
|
}
|
|
230
232
|
|
|
233
|
+
// ─── The platform's own rows ─────────────────────────────────────────────────
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* One row the platform adds (desktop.md §10.4) — a membership, a role, a plan; Studio does not know
|
|
237
|
+
* which, and draws it in the platform's words.
|
|
238
|
+
*
|
|
239
|
+
* Its id is namespaced so no platform can shadow one of Studio's own rows by naming it `github`.
|
|
240
|
+
* `revoke` does nothing: whatever the row describes is not a credential this app holds, so there is
|
|
241
|
+
* nothing here to forget, and its verbs are the actions the platform offers with it.
|
|
242
|
+
*/
|
|
243
|
+
function platformAction(action: OfferedAction): AccountAction {
|
|
244
|
+
const verb: AccountAction = {
|
|
245
|
+
id: action.id,
|
|
246
|
+
label: action.label,
|
|
247
|
+
run: async () => {
|
|
248
|
+
await runOfferedAction(action);
|
|
249
|
+
},
|
|
250
|
+
};
|
|
251
|
+
if (action.primary) {
|
|
252
|
+
verb.variant = "accent";
|
|
253
|
+
}
|
|
254
|
+
return verb;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
function platformRecord(entry: AccountEntry): AccountRecord {
|
|
258
|
+
return {
|
|
259
|
+
actions: (entry.actions ?? []).map((action) => platformAction(action)),
|
|
260
|
+
connected: entry.connected ?? false,
|
|
261
|
+
detail: entry.detail,
|
|
262
|
+
id: `platform:${entry.id}`,
|
|
263
|
+
label: entry.label,
|
|
264
|
+
revoke: () => {},
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
|
|
231
268
|
/**
|
|
232
|
-
* The three accounts, always all three.
|
|
269
|
+
* The three accounts, always all three — then any rows the platform adds.
|
|
233
270
|
*
|
|
234
271
|
* A disconnected account still gets a row: "you are not signed in to GitHub" is information, and a
|
|
235
|
-
* list that hides what is absent cannot answer the question the section exists to answer.
|
|
272
|
+
* list that hides what is absent cannot answer the question the section exists to answer. The
|
|
273
|
+
* platform's rows are the platform's to include or leave out; Studio adds none of its own.
|
|
236
274
|
*/
|
|
237
275
|
export function listAccounts(): AccountRecord[] {
|
|
238
276
|
const githubToken = githubTokenStored();
|
|
@@ -260,6 +298,7 @@ export function listAccounts(): AccountRecord[] {
|
|
|
260
298
|
revoke: clearAiProvider,
|
|
261
299
|
},
|
|
262
300
|
platformBrokersCf() ? brokeredCloudflareRecord() : localCloudflareRecord(),
|
|
301
|
+
...getAccountEntries().map((entry) => platformRecord(entry)),
|
|
263
302
|
];
|
|
264
303
|
}
|
|
265
304
|
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
* this, `clearGithubToken()` had zero callers: signing out of GitHub was not expressible.
|
|
20
20
|
* - **Keyboard** — GENERATED from `commands/reference.ts`'s `shortcutReference()`, the same
|
|
21
21
|
* projection `docs/studio/interface/shortcuts.md` is built from. The registry is the one place a
|
|
22
|
-
* chord is declared, so the sheet cannot drift from the app or from the docs. Per
|
|
22
|
+
* chord is declared, so the sheet cannot drift from the app or from the docs. Per AGENTS.md's
|
|
23
23
|
* Screenshot Policy there is deliberately no screenshot of it — photographing generated content
|
|
24
24
|
* is a bug. It is searchable two ways, because there are two questions ("what is the shortcut for
|
|
25
25
|
* X" and "what did I just press"), and rebindable — as a LAYER over the registry
|
|
@@ -44,6 +44,8 @@
|
|
|
44
44
|
|
|
45
45
|
import { CHROME_THEMES, setChromeTheme, shell } from "../shell";
|
|
46
46
|
import { layerHost } from "../ui/layers";
|
|
47
|
+
import { hydrateAccountStatus } from "../account-status";
|
|
48
|
+
import { getPlatform, hasPlatform } from "../platform";
|
|
47
49
|
import { createAiCredentialsForm } from "../ui/ai-credentials-form";
|
|
48
50
|
import { createManagedConnect } from "../ui/ai-managed-connect";
|
|
49
51
|
import { activeRegistry } from "../commands/active-registry";
|
|
@@ -563,6 +565,11 @@ export function openPreferences(section?: string): Promise<null> {
|
|
|
563
565
|
grant can lapse between visits, and a row that repaints the previous answer first is stating
|
|
564
566
|
something it has no reason to believe. */
|
|
565
567
|
resetCfConnectionCache();
|
|
568
|
+
/* And the platform's own account rows, for the same reason: whatever they report can change
|
|
569
|
+
between visits. They repaint when the answer lands; until then they show the last one. */
|
|
570
|
+
if (hasPlatform() && getPlatform().getAccountStatus) {
|
|
571
|
+
void hydrateAccountStatus().then(repaint);
|
|
572
|
+
}
|
|
566
573
|
_section = section !== undefined && isPreferencesSection(section) ? section : _section;
|
|
567
574
|
if (_surface) {
|
|
568
575
|
repaint();
|
package/src/studio.ts
CHANGED
|
@@ -126,8 +126,10 @@ import {
|
|
|
126
126
|
openLastSessionOrHome,
|
|
127
127
|
registerFileTreeDnD,
|
|
128
128
|
reloadCleanTab,
|
|
129
|
+
reloadTabsIfChanged,
|
|
129
130
|
} from "./files/files";
|
|
130
131
|
import { resetIgnoreCache } from "./files/gitignore";
|
|
132
|
+
import { resetAssetVersions } from "./files/asset-versions";
|
|
131
133
|
import { startFsSync } from "./files/fs-events";
|
|
132
134
|
import { invalidateParamValues } from "./page-params";
|
|
133
135
|
import {
|
|
@@ -221,6 +223,8 @@ import {
|
|
|
221
223
|
import { initCssData } from "./panels/style-utils";
|
|
222
224
|
import { initQuickSearch } from "./panels/quick-search";
|
|
223
225
|
import { hydrateAccountStatus } from "./account-status";
|
|
226
|
+
import { showToastNotices, wireActionReports } from "./account/action-flow";
|
|
227
|
+
import { isActionRequired } from "./platform-errors";
|
|
224
228
|
import { hydrateProjectList } from "./project-list";
|
|
225
229
|
import { addRecentProject, hydrateRecentProjects, removeRecentProject } from "./recent-projects";
|
|
226
230
|
import {
|
|
@@ -507,6 +511,9 @@ toolbarPanel.mount(toolbarEl, {
|
|
|
507
511
|
});
|
|
508
512
|
|
|
509
513
|
initLayers();
|
|
514
|
+
/* Before anything reaches the backend: an `action-required` refusal (desktop.md §10.4) can be the
|
|
515
|
+
answer to the very first request, and the dialog that offers its actions needs the layers above. */
|
|
516
|
+
wireActionReports();
|
|
510
517
|
initQuickSearch({ openRecentProject: (root: string) => openRecentProject(root) });
|
|
511
518
|
|
|
512
519
|
/* The pane's four surfaces come from its CELL, not from `document.querySelector`.
|
|
@@ -959,6 +966,9 @@ function ensureFsSync() {
|
|
|
959
966
|
paneContext.resetParamValues();
|
|
960
967
|
},
|
|
961
968
|
onContentChange: reloadCleanTab,
|
|
969
|
+
/* A reconnect re-reads the clean, non-collab tabs, and leaves every one whose content did not
|
|
970
|
+
change untouched: most reconnects changed nothing, and a reload is a repaint per tab. */
|
|
971
|
+
onResyncContent: reloadTabsIfChanged,
|
|
962
972
|
renderLeftPanel,
|
|
963
973
|
});
|
|
964
974
|
}
|
|
@@ -979,7 +989,10 @@ if (!_projectParam) {
|
|
|
979
989
|
// No project is bound yet, so this call only warms the canvasUrl; a backend that refuses it
|
|
980
990
|
// Still gets the render below rather than an unhandled rejection.
|
|
981
991
|
?.catch((error: unknown) => {
|
|
982
|
-
|
|
992
|
+
// A refusal that offers an action is the action flow's to explain; it is not a fault.
|
|
993
|
+
if (!isActionRequired(error)) {
|
|
994
|
+
console.error("Boot activation failed:", error);
|
|
995
|
+
}
|
|
983
996
|
})
|
|
984
997
|
.then(() => {
|
|
985
998
|
render();
|
|
@@ -1022,6 +1035,7 @@ if (_projectParam) {
|
|
|
1022
1035
|
}
|
|
1023
1036
|
|
|
1024
1037
|
resetIgnoreCache();
|
|
1038
|
+
resetAssetVersions();
|
|
1025
1039
|
setProjectState({
|
|
1026
1040
|
dirs: new Map(),
|
|
1027
1041
|
expanded: new Set(),
|
|
@@ -1188,6 +1202,8 @@ void hydrateProjectList().then(() => {
|
|
|
1188
1202
|
// The welcome screen's install prompt. No-op on platforms without getAccountStatus.
|
|
1189
1203
|
// oxlint-disable-next-line unicorn/prefer-top-level-await -- deliberate fire-and-forget: hydration must not block initial render
|
|
1190
1204
|
void hydrateAccountStatus().then(() => {
|
|
1205
|
+
// After the status: the platform's one-time notices ride on it (desktop.md §10.4).
|
|
1206
|
+
showToastNotices();
|
|
1191
1207
|
render();
|
|
1192
1208
|
});
|
|
1193
1209
|
|
|
@@ -1355,6 +1371,7 @@ async function openRecentProject(root: string) {
|
|
|
1355
1371
|
|
|
1356
1372
|
closeAllTabs();
|
|
1357
1373
|
resetIgnoreCache();
|
|
1374
|
+
resetAssetVersions();
|
|
1358
1375
|
|
|
1359
1376
|
setProjectState({
|
|
1360
1377
|
...projectState,
|
package/src/surfaces/dialog.ts
CHANGED
|
@@ -96,6 +96,8 @@ export interface DialogSurfacePatch {
|
|
|
96
96
|
*/
|
|
97
97
|
confirmLabel?: string;
|
|
98
98
|
cancelLabel?: string;
|
|
99
|
+
/** The secondary button's text; the empty string takes the button away. */
|
|
100
|
+
secondaryLabel?: string;
|
|
99
101
|
/** The sentence under the headline. Cleared by the empty string. */
|
|
100
102
|
message?: string;
|
|
101
103
|
value?: string;
|
|
@@ -298,6 +300,9 @@ export function openDialogSurface(options: DialogSurfaceOptions): DialogSurfaceH
|
|
|
298
300
|
if (patch.cancelLabel !== undefined) {
|
|
299
301
|
scope.cancelLabel = patch.cancelLabel;
|
|
300
302
|
}
|
|
303
|
+
if (patch.secondaryLabel !== undefined) {
|
|
304
|
+
scope.secondaryLabel = patch.secondaryLabel;
|
|
305
|
+
}
|
|
301
306
|
if (patch.message !== undefined) {
|
|
302
307
|
scope.message = patch.message;
|
|
303
308
|
scope.hasMessage = patch.message !== "";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://jxsuite.com/schema/v1",
|
|
3
3
|
"$id": "StudioWelcome",
|
|
4
|
-
"$description": "The Start pane, shown when no project is loaded and no document is open. The adapter hands in the start actions, whether the GitHub App still needs installing, the recent projects with their distinguishing folders and last-opened labels, and the platform's catalogue; the document draws them in the order a first run needs them.",
|
|
4
|
+
"$description": "The Start pane, shown when no project is loaded and no document is open. The adapter hands in the start actions, whether the GitHub App still needs installing, the platform's own notices with the actions each offers, the recent projects with their distinguishing folders and last-opened labels, and the platform's catalogue; the document draws them in the order a first run needs them.",
|
|
5
5
|
"tagName": "div",
|
|
6
6
|
"attributes": {
|
|
7
7
|
"part": "screen"
|
|
@@ -311,6 +311,91 @@
|
|
|
311
311
|
}
|
|
312
312
|
}
|
|
313
313
|
},
|
|
314
|
+
{
|
|
315
|
+
"$prototype": "Array",
|
|
316
|
+
"items": {
|
|
317
|
+
"$ref": "#/state/notices"
|
|
318
|
+
},
|
|
319
|
+
"key": {
|
|
320
|
+
"$ref": "$map/item/id"
|
|
321
|
+
},
|
|
322
|
+
"map": {
|
|
323
|
+
"tagName": "section",
|
|
324
|
+
"attributes": {
|
|
325
|
+
"part": "section",
|
|
326
|
+
"data-section": "notice",
|
|
327
|
+
"data-notice": "${$map.item.id}",
|
|
328
|
+
"data-level": "${$map.item.level}"
|
|
329
|
+
},
|
|
330
|
+
"children": [
|
|
331
|
+
{
|
|
332
|
+
"tagName": "h2",
|
|
333
|
+
"attributes": {
|
|
334
|
+
"part": "section-title"
|
|
335
|
+
},
|
|
336
|
+
"textContent": "${$map.item.title}"
|
|
337
|
+
},
|
|
338
|
+
{
|
|
339
|
+
"tagName": "p",
|
|
340
|
+
"attributes": {
|
|
341
|
+
"part": "note"
|
|
342
|
+
},
|
|
343
|
+
"textContent": "${$map.item.message}"
|
|
344
|
+
},
|
|
345
|
+
{
|
|
346
|
+
"tagName": "div",
|
|
347
|
+
"attributes": {
|
|
348
|
+
"part": "actions"
|
|
349
|
+
},
|
|
350
|
+
"children": [
|
|
351
|
+
{
|
|
352
|
+
"$prototype": "Array",
|
|
353
|
+
"items": {
|
|
354
|
+
"$ref": "$map/item/actions"
|
|
355
|
+
},
|
|
356
|
+
"key": {
|
|
357
|
+
"$ref": "$map/item/key"
|
|
358
|
+
},
|
|
359
|
+
"map": {
|
|
360
|
+
"tagName": "jx-button",
|
|
361
|
+
"$props": {
|
|
362
|
+
"variant": {
|
|
363
|
+
"$ref": "$map/item/variant"
|
|
364
|
+
}
|
|
365
|
+
},
|
|
366
|
+
"attributes": {
|
|
367
|
+
"part": "notice-action",
|
|
368
|
+
"data-action": "${$map.item.key}"
|
|
369
|
+
},
|
|
370
|
+
"onclick": {
|
|
371
|
+
"$prototype": "Function",
|
|
372
|
+
"body": [
|
|
373
|
+
{
|
|
374
|
+
"operator": "call",
|
|
375
|
+
"target": {
|
|
376
|
+
"$ref": "#/state/noticeRun"
|
|
377
|
+
},
|
|
378
|
+
"value": [
|
|
379
|
+
{
|
|
380
|
+
"$ref": "$map/item/key"
|
|
381
|
+
}
|
|
382
|
+
]
|
|
383
|
+
}
|
|
384
|
+
]
|
|
385
|
+
},
|
|
386
|
+
"children": [
|
|
387
|
+
{
|
|
388
|
+
"tagName": "span",
|
|
389
|
+
"textContent": "${$map.item.label}"
|
|
390
|
+
}
|
|
391
|
+
]
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
]
|
|
395
|
+
}
|
|
396
|
+
]
|
|
397
|
+
}
|
|
398
|
+
},
|
|
314
399
|
{
|
|
315
400
|
"tagName": "div",
|
|
316
401
|
"attributes": {
|