@jxsuite/studio 0.34.0 → 0.36.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/dist/iframe-entry.js +9 -1
  2. package/dist/iframe-entry.js.map +3 -3
  3. package/dist/studio.js +18382 -3686
  4. package/dist/studio.js.map +265 -26
  5. package/package.json +9 -6
  6. package/src/files/files.ts +3 -0
  7. package/src/new-project/design-fields.ts +260 -0
  8. package/src/new-project/import-tab.ts +322 -0
  9. package/src/new-project/new-project-modal.ts +472 -89
  10. package/src/new-project/templates.ts +61 -0
  11. package/src/packages/ensure-deps.ts +6 -0
  12. package/src/packages/pull-package-sync.ts +339 -0
  13. package/src/panels/ai-chat/attached-context.ts +49 -0
  14. package/src/panels/ai-chat/chat-markdown.ts +38 -0
  15. package/src/panels/ai-chat/chat-view.ts +250 -0
  16. package/src/panels/ai-chat/composer.ts +315 -0
  17. package/src/panels/ai-chat/sessions-view.ts +98 -0
  18. package/src/panels/ai-panel.ts +214 -458
  19. package/src/panels/drag-ghost.ts +1 -1
  20. package/src/panels/git-panel.ts +16 -1
  21. package/src/panels/right-panel.ts +21 -5
  22. package/src/panels/toolbar.ts +2 -0
  23. package/src/panels/welcome-screen.ts +26 -0
  24. package/src/platforms/cloud.ts +774 -0
  25. package/src/platforms/devserver.ts +100 -1
  26. package/src/project-list.ts +38 -0
  27. package/src/publish/pages-service.ts +186 -0
  28. package/src/publish/publish-panel.ts +360 -0
  29. package/src/services/agent-seed.ts +91 -0
  30. package/src/services/ai-models.ts +93 -0
  31. package/src/services/ai-session-store.ts +250 -0
  32. package/src/services/ai-settings.ts +5 -0
  33. package/src/services/automation.ts +140 -0
  34. package/src/services/cf-settings.ts +58 -0
  35. package/src/services/document-assistant.ts +98 -38
  36. package/src/services/import-client.ts +134 -0
  37. package/src/services/settings-store.ts +99 -0
  38. package/src/studio.ts +33 -0
  39. package/src/types.ts +130 -133
  40. package/src/ui/ai-credentials-form.ts +205 -0
  41. package/src/ui/spectrum.ts +8 -0
@@ -26,7 +26,7 @@ function ensureGhost(doc: Document): HTMLElement {
26
26
  el.style.cssText =
27
27
  "position:fixed;left:0;top:0;z-index:9999;pointer-events:none;display:none;" +
28
28
  "padding:2px 8px;border-radius:4px;font-size:12px;line-height:1.4;white-space:nowrap;" +
29
- "background:var(--accent,#3b82f6);color:#fff;box-shadow:0 2px 8px rgba(0,0,0,0.25);" +
29
+ "background:var(--accent,#3b82f6);color:var(--accent-fg,#fff);box-shadow:0 2px 8px rgba(0,0,0,0.25);" +
30
30
  "transform:translate(8px,8px)";
31
31
  doc.body.append(el);
32
32
  ghostEl = el;
@@ -23,6 +23,7 @@ import { view } from "../view";
23
23
  import { showConfirmDialog, showDialog } from "../ui/layers";
24
24
  import { statusMessage } from "./statusbar";
25
25
  import { publishToGithub } from "../github/github-publish";
26
+ import { pullWithPackageSync } from "../packages/pull-package-sync";
26
27
 
27
28
  interface GitLogEntry {
28
29
  hash: string;
@@ -141,6 +142,20 @@ async function gitAction(action: string, body?: unknown) {
141
142
  }
142
143
  }
143
144
 
145
+ /** Pull via the package-aware orchestrator; same loading/error contract as gitAction. */
146
+ async function doPull() {
147
+ updateUi("gitLoading", true);
148
+ updateUi("gitError", null);
149
+ try {
150
+ await pullWithPackageSync();
151
+ await refreshGitStatus();
152
+ } catch (error) {
153
+ updateUi("gitError", errorMessage(error));
154
+ updateUi("gitLoading", false);
155
+ renderOnly("leftPanel");
156
+ }
157
+ }
158
+
144
159
  let _pollTimer = null as ReturnType<typeof setInterval> | null;
145
160
  let _lastUpdated = null as Date | null;
146
161
  let _gitSubTab = "changes";
@@ -315,7 +330,7 @@ export function renderGitPanel(
315
330
  </sp-action-button>
316
331
  <sp-action-button
317
332
  title="Pull${status?.behind ? ` (${status.behind} behind)` : ""}"
318
- @click=${() => gitAction("gitPull")}
333
+ @click=${() => void doPull()}
319
334
  ?disabled=${loading}
320
335
  >
321
336
  <sp-icon-arrow-down slot="icon" size="xs"></sp-icon-arrow-down>
@@ -10,7 +10,8 @@ import { rightPanel, updateUi } from "../store";
10
10
  import { effect, effectScope } from "../reactivity";
11
11
  import { createPanelScheduler } from "./panel-scheduler";
12
12
  import type { PanelScheduler } from "./panel-scheduler";
13
- import { activeTab } from "../workspace/workspace";
13
+ import { activeTab, workspace } from "../workspace/workspace";
14
+ import { consumePendingAgentPrompt, hasPendingAgentPrompt } from "../services/agent-seed";
14
15
  import { tabIcon } from "./activity-bar";
15
16
  import { eventsSidebarTemplate } from "./events-panel";
16
17
  import { isCustomElementDoc } from "./signals-panel";
@@ -22,9 +23,9 @@ import { renderPropertiesPanelTemplate } from "./properties-panel";
22
23
  import type { EffectScope } from "@vue/reactivity";
23
24
  import {
24
25
  renderAiPanelTemplate,
26
+ bindAiPanelHost,
25
27
  mountAiPanel,
26
- mountQuikChat,
27
- registerRightPanelRender,
28
+ seedAssistantPrompt,
28
29
  } from "./ai-panel";
29
30
 
30
31
  interface RightPanelCtx {
@@ -47,7 +48,6 @@ let _scheduler: PanelScheduler | null = null;
47
48
  export function mount(ctx: RightPanelCtx) {
48
49
  _ctx = ctx;
49
50
  mountAiPanel();
50
- registerRightPanelRender(render);
51
51
  _scheduler = createPanelScheduler({
52
52
  blockWhile: isColorPopoverOpen,
53
53
  render: _doRender,
@@ -116,6 +116,9 @@ function _ensureContainers() {
116
116
  _assistantContainer = document.createElement("div");
117
117
  _assistantContainer.className = "panel-body";
118
118
  _assistantContainer.style.cssText = "display:flex;flex-direction:column;overflow:hidden";
119
+ // The AI panel owns a focus-guard-free rAF render loop into this container so
120
+ // Streaming repaints while the composer is focused (see ai-panel.ts).
121
+ bindAiPanelHost(_assistantContainer);
119
122
  }
120
123
 
121
124
  function _doRender() {
@@ -135,6 +138,12 @@ function _doRender() {
135
138
  selection: aTab.session.selection,
136
139
  ui: aTab.session.ui,
137
140
  };
141
+ // A pending agent prompt (stored by the New Project flow, possibly from another window)
142
+ // Forces the Assistant tab open — same updateUi mechanism the automation hook uses.
143
+ const root = workspace.projectRoot;
144
+ if (root && S.ui.rightTab !== "assistant" && hasPendingAgentPrompt(root)) {
145
+ updateUi("rightTab", "assistant");
146
+ }
138
147
  const tab = S.ui.rightTab;
139
148
 
140
149
  // Render tabs header
@@ -217,9 +226,16 @@ function _doRender() {
217
226
  }
218
227
  } else if (tab === "assistant") {
219
228
  litRender(renderAiPanelTemplate(), _assistantContainer!);
229
+ if (root) {
230
+ // Consume-on-read keeps repeated renders idempotent; seed after the panel template
231
+ // Has rendered so the assistant machinery is in place.
232
+ const prompt = consumePendingAgentPrompt(root);
233
+ if (prompt) {
234
+ requestAnimationFrame(() => void seedAssistantPrompt(prompt));
235
+ }
236
+ }
220
237
  }
221
238
  } catch (error) {
222
239
  console.error("right-panel render error:", error);
223
240
  }
224
- requestAnimationFrame(() => mountQuikChat());
225
241
  }
@@ -5,6 +5,7 @@
5
5
  */
6
6
 
7
7
  import { html, render as litRender, nothing } from "lit-html";
8
+ import { openPublishPanel } from "../publish/publish-panel";
8
9
  import { updateSession } from "../store";
9
10
  import { redo as tabRedo, undo as tabUndo } from "../tabs/transact";
10
11
  import { effect, effectScope } from "../reactivity";
@@ -472,6 +473,7 @@ function toolbarTemplate() {
472
473
  ${recentProjectsTpl}
473
474
  </div>
474
475
  ${tbBtnTpl("Manage", openBrowseModal, "sp-icon-view-list")}
476
+ ${tbBtnTpl("Publish", openPublishPanel)}
475
477
  <sp-action-button size="s" title="Save" ?disabled=${!canSave} @click=${ctx.saveFile}>
476
478
  ${toolbarIconMap["sp-icon-save-floppy"]}<span class="tb-label">Save</span>
477
479
  </sp-action-button>
@@ -5,6 +5,7 @@
5
5
  */
6
6
 
7
7
  import { html, render as litRender, nothing } from "lit-html";
8
+ import { getProjectList } from "../project-list";
8
9
  import { clearRecentProjects, getRecentProjects, removeRecentProject } from "../recent-projects";
9
10
  import { renderOnly } from "../store";
10
11
  import { platformSupportsClone } from "./git-panel";
@@ -27,6 +28,8 @@ export function initWelcome(ctx: WelcomeCtx) {
27
28
  export function renderWelcome(host: HTMLElement) {
28
29
  const ctx = _ctx as WelcomeCtx;
29
30
  const recent = getRecentProjects();
31
+ // Catalogue entries already in Recent stay in that section only.
32
+ const catalogue = getProjectList().filter((p) => !recent.some((r) => r.root === p.root));
30
33
  const showClone = platformSupportsClone();
31
34
 
32
35
  litRender(
@@ -84,6 +87,29 @@ export function renderWelcome(host: HTMLElement) {
84
87
  : nothing}
85
88
  </div>
86
89
 
90
+ ${catalogue.length > 0
91
+ ? html`
92
+ <div class="welcome-section">
93
+ <h2 class="welcome-section-title">Projects</h2>
94
+ ${catalogue.map(
95
+ (p) => html`
96
+ <div class="welcome-recent-row">
97
+ <button
98
+ class="welcome-recent welcome-catalogue"
99
+ @click=${() => ctx.openRecentProject(p.root)}
100
+ title=${p.root}
101
+ >
102
+ <span class="welcome-recent-name">${p.name}</span>
103
+ <span class="welcome-recent-path">
104
+ ${p.description ?? shortenPath(p.root)}
105
+ </span>
106
+ </button>
107
+ </div>
108
+ `,
109
+ )}
110
+ </div>
111
+ `
112
+ : nothing}
87
113
  ${recent.length > 0
88
114
  ? html`
89
115
  <div class="welcome-section">