@jxsuite/studio 1.2.0 → 1.3.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/dist/studio.js +81298 -81211
- package/dist/studio.js.map +330 -330
- package/package.json +1 -1
- package/src/panels/ai-panel.ts +53 -1
- package/src/platforms/cloud.ts +3 -1
- package/src/project-list.ts +5 -0
- package/src/publish/publish-panel.ts +17 -0
- package/src/services/automation.ts +67 -1
- package/src/settings/settings-modal.ts +2 -2
- package/src/studio.ts +10 -1
- package/src/ui/formula-catalog.ts +4 -1
package/package.json
CHANGED
package/src/panels/ai-panel.ts
CHANGED
|
@@ -21,7 +21,7 @@ import type { TemplateResult } from "lit-html";
|
|
|
21
21
|
import { getPlatform } from "../platform";
|
|
22
22
|
import { effect, effectScope } from "../reactivity";
|
|
23
23
|
import { createDocumentAssistant } from "../services/document-assistant";
|
|
24
|
-
import { hasOpenAiKey } from "../services/ai-settings";
|
|
24
|
+
import { hasOpenAiKey, setOpenAiKey } from "../services/ai-settings";
|
|
25
25
|
import { fetchAvailableModels, isManagedProxy, isProxyConfigured } from "../services/ai-models";
|
|
26
26
|
import { createAiCredentialsForm } from "../ui/ai-credentials-form";
|
|
27
27
|
import { clearMarkdownCache } from "./ai-chat/chat-markdown";
|
|
@@ -263,6 +263,58 @@ export async function seedAssistantPrompt(text: string): Promise<void> {
|
|
|
263
263
|
await handleAssistantSend(text);
|
|
264
264
|
}
|
|
265
265
|
|
|
266
|
+
// ─── Automation seeding (screenshot runner) ─────────────────────────────────
|
|
267
|
+
|
|
268
|
+
/** A canned tool-call chip for {@link seedAssistantMessages}. */
|
|
269
|
+
export interface SeededToolCall {
|
|
270
|
+
name: string;
|
|
271
|
+
/** JSON-encoded arguments, e.g. `{"path":["children",0],"text":"…"}`. */
|
|
272
|
+
arguments: string;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/** A canned transcript entry for {@link seedAssistantMessages}. */
|
|
276
|
+
export interface SeededAssistantMessage {
|
|
277
|
+
role: "user" | "assistant";
|
|
278
|
+
content: string;
|
|
279
|
+
toolCalls?: SeededToolCall[];
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
let seededCount = 0;
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* Automation-only seam (scripts/screenshots): stage a canned conversation without ever invoking a
|
|
286
|
+
* model. Stores an inert demo key so the key gate opens (localStorage-only on the dev server — no
|
|
287
|
+
* request fires), switches to the chat view, and pushes fully-formed messages straight into the
|
|
288
|
+
* reactive chat state — the same path session restore uses — so the panel repaints through its
|
|
289
|
+
* normal watcher.
|
|
290
|
+
*/
|
|
291
|
+
export function seedAssistantMessages(messages: SeededAssistantMessage[]): void {
|
|
292
|
+
setOpenAiKey("sk-demo");
|
|
293
|
+
keyEditing = false;
|
|
294
|
+
view = "chat";
|
|
295
|
+
stickToBottom = true;
|
|
296
|
+
for (const msg of messages) {
|
|
297
|
+
seededCount += 1;
|
|
298
|
+
const seq = seededCount;
|
|
299
|
+
assistant.chatState.messages.push({
|
|
300
|
+
content: msg.content,
|
|
301
|
+
id: `seeded_${seq}`,
|
|
302
|
+
role: msg.role,
|
|
303
|
+
timestamp: seq,
|
|
304
|
+
...(msg.toolCalls
|
|
305
|
+
? {
|
|
306
|
+
toolCalls: msg.toolCalls.map((tc, i) => ({
|
|
307
|
+
arguments: tc.arguments,
|
|
308
|
+
id: `seeded_${seq}_tc${i}`,
|
|
309
|
+
name: tc.name,
|
|
310
|
+
})),
|
|
311
|
+
}
|
|
312
|
+
: {}),
|
|
313
|
+
});
|
|
314
|
+
}
|
|
315
|
+
scheduleAiRender();
|
|
316
|
+
}
|
|
317
|
+
|
|
266
318
|
// ─── Controls ─────────────────────────────────────────────────────────────────
|
|
267
319
|
|
|
268
320
|
function stop() {
|
package/src/platforms/cloud.ts
CHANGED
|
@@ -334,7 +334,9 @@ export function createCloudPlatform(project: CloudProject | null): StudioPlatfor
|
|
|
334
334
|
* {kind:"git"} notices this handler ignores.
|
|
335
335
|
*/
|
|
336
336
|
subscribeFileEvents(handler: (events: FsEvent[]) => void) {
|
|
337
|
-
|
|
337
|
+
// No project means an empty base, so the bare `/events` URL hits no gateway route.
|
|
338
|
+
// That fails in a reconnect loop; mirror `collab`'s guard and degrade to no-op on the hub.
|
|
339
|
+
if (!project || typeof WebSocket === "undefined" || typeof location === "undefined") {
|
|
338
340
|
return () => {};
|
|
339
341
|
}
|
|
340
342
|
let socket: WebSocket | null = null;
|
package/src/project-list.ts
CHANGED
|
@@ -36,3 +36,8 @@ export function getProjectList(): ProjectListEntry[] {
|
|
|
36
36
|
export function resetProjectList(): void {
|
|
37
37
|
cache = [];
|
|
38
38
|
}
|
|
39
|
+
|
|
40
|
+
/** Seed seam for tests and the screenshot automation hook (staged catalogues). */
|
|
41
|
+
export function seedProjectList(entries: ProjectListEntry[]): void {
|
|
42
|
+
cache = entries;
|
|
43
|
+
}
|
|
@@ -339,6 +339,23 @@ function render(): void {
|
|
|
339
339
|
}
|
|
340
340
|
}
|
|
341
341
|
|
|
342
|
+
/**
|
|
343
|
+
* Automation-only seam (scripts/screenshots): open the modal directly in its connected state with a
|
|
344
|
+
* canned deployment, bypassing {@link loadConnection} so no Cloudflare request ever fires. The
|
|
345
|
+
* active project's `build.deploy` block still supplies the connected project/URL line.
|
|
346
|
+
*/
|
|
347
|
+
export function seedPublishConnected(options: {
|
|
348
|
+
accountId?: string;
|
|
349
|
+
deployment: PagesDeploymentInfo;
|
|
350
|
+
}): void {
|
|
351
|
+
_connection = { accountId: options.accountId ?? "demo-account", connected: true };
|
|
352
|
+
_accounts = [];
|
|
353
|
+
_deployment = options.deployment;
|
|
354
|
+
_error = "";
|
|
355
|
+
_busy = false;
|
|
356
|
+
render();
|
|
357
|
+
}
|
|
358
|
+
|
|
342
359
|
/** Open the publish modal for the active project. */
|
|
343
360
|
export function openPublishPanel(): void {
|
|
344
361
|
const config = currentConfig();
|
|
@@ -10,18 +10,30 @@
|
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
import { renderOnly, updateUi } from "../store";
|
|
13
|
-
import {
|
|
13
|
+
import { setProjectState } from "../state";
|
|
14
|
+
import { seedProjectList } from "../project-list";
|
|
15
|
+
import { activeTab, closeAllTabs, workspace } from "../workspace/workspace";
|
|
16
|
+
import type { ProjectListEntry } from "../types";
|
|
14
17
|
import { applyPanelCollapse, view } from "../view";
|
|
15
18
|
import { setEditZoom as applyEditZoomLevel } from "../canvas/canvas-utils";
|
|
19
|
+
import { collabState } from "../collab/collab-state";
|
|
20
|
+
import type { PeerPresence } from "../collab/collab-state";
|
|
21
|
+
import type { SeededAssistantMessage } from "../panels/ai-panel";
|
|
22
|
+
import type { PagesDeploymentInfo } from "../publish/pages-service";
|
|
16
23
|
import type { JxPath } from "../state";
|
|
17
24
|
|
|
18
25
|
/** Callbacks injected from studio.ts (module-local helpers or imports kept out of this module). */
|
|
19
26
|
export interface AutomationDeps {
|
|
20
27
|
getCanvasMode: () => string;
|
|
21
28
|
openBrowseModal: () => void;
|
|
29
|
+
openConnectorGrid: (connection: string | undefined, table: string) => void;
|
|
22
30
|
openNewProjectModal: () => void;
|
|
31
|
+
openQuickSearchPalette: () => void;
|
|
32
|
+
openSettingsModal: (section?: string) => void;
|
|
23
33
|
render: () => void;
|
|
24
34
|
renderActivityBar: () => void;
|
|
35
|
+
seedAssistantMessages: (messages: SeededAssistantMessage[]) => void;
|
|
36
|
+
seedPublishConnected: (options: { accountId?: string; deployment: PagesDeploymentInfo }) => void;
|
|
25
37
|
setCanvasMode: (mode: string) => void;
|
|
26
38
|
statusMessage: (text: string) => void;
|
|
27
39
|
}
|
|
@@ -30,7 +42,14 @@ export interface AutomationApi {
|
|
|
30
42
|
editDef: (defName: string) => void;
|
|
31
43
|
editFunction: (path: JxPath, eventKey: string) => void;
|
|
32
44
|
openBrowse: () => void;
|
|
45
|
+
openDataGrid: (options: { connection?: string; table: string }) => void;
|
|
33
46
|
openNewProject: () => void;
|
|
47
|
+
openQuickSearch: () => void;
|
|
48
|
+
openSettings: (section?: string) => void;
|
|
49
|
+
seedAssistant: (options: { messages: SeededAssistantMessage[] }) => void;
|
|
50
|
+
seedCollab: (options: { peers: PeerPresence[] }) => void;
|
|
51
|
+
seedPublish: (options: { accountId?: string; deployment: PagesDeploymentInfo }) => void;
|
|
52
|
+
showWelcome: (options?: { projects?: ProjectListEntry[] }) => void;
|
|
34
53
|
getState: () => {
|
|
35
54
|
activeTabId: string | null;
|
|
36
55
|
canvasMode: string;
|
|
@@ -66,9 +85,56 @@ export function createAutomationApi(deps: AutomationDeps): AutomationApi {
|
|
|
66
85
|
openBrowse() {
|
|
67
86
|
deps.openBrowseModal();
|
|
68
87
|
},
|
|
88
|
+
openDataGrid(options: { connection?: string; table: string }) {
|
|
89
|
+
deps.openConnectorGrid(options.connection, options.table);
|
|
90
|
+
},
|
|
69
91
|
openNewProject() {
|
|
70
92
|
deps.openNewProjectModal();
|
|
71
93
|
},
|
|
94
|
+
openQuickSearch() {
|
|
95
|
+
deps.openQuickSearchPalette();
|
|
96
|
+
},
|
|
97
|
+
openSettings(section?: string) {
|
|
98
|
+
deps.openSettingsModal(section);
|
|
99
|
+
},
|
|
100
|
+
seedAssistant(options: { messages: SeededAssistantMessage[] }) {
|
|
101
|
+
deps.seedAssistantMessages(options.messages);
|
|
102
|
+
},
|
|
103
|
+
seedCollab(options: { peers: PeerPresence[] }) {
|
|
104
|
+
// Stage a live co-editing session on the active tab: the toolbar's presence chips and the
|
|
105
|
+
// Canvas peer-selection boxes both read this same reactive store.
|
|
106
|
+
const tab = activeTab.value;
|
|
107
|
+
if (!tab) {
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
const state = collabState(tab);
|
|
111
|
+
state.status = "synced";
|
|
112
|
+
state.active = true;
|
|
113
|
+
state.peers = options.peers.map((peer) => ({
|
|
114
|
+
...peer,
|
|
115
|
+
state: {
|
|
116
|
+
...peer.state,
|
|
117
|
+
focusedPath: peer.state.focusedPath ?? tab.documentPath,
|
|
118
|
+
},
|
|
119
|
+
}));
|
|
120
|
+
deps.render();
|
|
121
|
+
},
|
|
122
|
+
seedPublish(options: { accountId?: string; deployment: PagesDeploymentInfo }) {
|
|
123
|
+
deps.seedPublishConnected(options);
|
|
124
|
+
},
|
|
125
|
+
showWelcome(options?: { projects?: ProjectListEntry[] }) {
|
|
126
|
+
// The devserver platform auto-opens the repo-root project on boot; the welcome
|
|
127
|
+
// Screen only renders with no project and no tabs, so stage that state directly.
|
|
128
|
+
// A staged catalogue replaces the real one (screenshots must not leak local paths).
|
|
129
|
+
closeAllTabs();
|
|
130
|
+
setProjectState(null);
|
|
131
|
+
if (options?.projects) {
|
|
132
|
+
seedProjectList(options.projects);
|
|
133
|
+
}
|
|
134
|
+
view.chatPanelCollapsed = true;
|
|
135
|
+
applyPanelCollapse();
|
|
136
|
+
deps.render();
|
|
137
|
+
},
|
|
72
138
|
getState() {
|
|
73
139
|
return {
|
|
74
140
|
activeTabId: workspace.activeTabId,
|
|
@@ -106,11 +106,11 @@ let _activeSection = "general";
|
|
|
106
106
|
|
|
107
107
|
let _contentEl: HTMLElement | null = null;
|
|
108
108
|
|
|
109
|
-
export function openSettingsModal() {
|
|
109
|
+
export function openSettingsModal(section?: string) {
|
|
110
110
|
if (_handle) {
|
|
111
111
|
return;
|
|
112
112
|
}
|
|
113
|
-
_activeSection = "general";
|
|
113
|
+
_activeSection = section ?? "general";
|
|
114
114
|
renderModal();
|
|
115
115
|
// Refresh descriptor-contributed sections (cached payloads make this cheap) and rerender the
|
|
116
116
|
// Nav once they land. Lazy import breaks the settings-modal ↔ extension-sections module cycle.
|
package/src/studio.ts
CHANGED
|
@@ -96,6 +96,9 @@ import { renderHeadTemplate } from "./panels/head-panel";
|
|
|
96
96
|
import { exportCemManifest as _exportCemManifest } from "./services/cem-export";
|
|
97
97
|
import { installAutomationHook } from "./services/automation";
|
|
98
98
|
import { openBrowseModal } from "./browse/browse-modal";
|
|
99
|
+
import { seedAssistantMessages } from "./panels/ai-panel";
|
|
100
|
+
import { seedPublishConnected } from "./publish/publish-panel";
|
|
101
|
+
import { openConnectorGrid } from "./grid/grid-open";
|
|
99
102
|
|
|
100
103
|
import { getPlatform, hasPlatform, registerPlatform } from "./platform";
|
|
101
104
|
import { parseMediaEntries } from "./utils/canvas-media";
|
|
@@ -145,7 +148,8 @@ import {
|
|
|
145
148
|
renderBlockActionBar,
|
|
146
149
|
} from "./panels/block-action-bar";
|
|
147
150
|
import { initCssData } from "./panels/style-utils";
|
|
148
|
-
import { initQuickSearch } from "./panels/quick-search";
|
|
151
|
+
import { initQuickSearch, openQuickSearch } from "./panels/quick-search";
|
|
152
|
+
import { openSettingsModal } from "./settings/settings-modal";
|
|
149
153
|
import { hydrateAccountStatus } from "./account-status";
|
|
150
154
|
import { hydrateProjectList } from "./project-list";
|
|
151
155
|
import { addRecentProject, hydrateRecentProjects, removeRecentProject } from "./recent-projects";
|
|
@@ -391,9 +395,14 @@ if (!hasPlatform()) {
|
|
|
391
395
|
installAutomationHook({
|
|
392
396
|
getCanvasMode,
|
|
393
397
|
openBrowseModal,
|
|
398
|
+
openConnectorGrid,
|
|
394
399
|
openNewProjectModal,
|
|
400
|
+
openQuickSearchPalette: openQuickSearch,
|
|
401
|
+
openSettingsModal,
|
|
395
402
|
render,
|
|
396
403
|
renderActivityBar,
|
|
404
|
+
seedAssistantMessages,
|
|
405
|
+
seedPublishConnected,
|
|
397
406
|
setCanvasMode,
|
|
398
407
|
statusMessage,
|
|
399
408
|
});
|
|
@@ -293,7 +293,10 @@ const OPERATOR_META: Record<string, OperatorMeta> = {
|
|
|
293
293
|
export function operatorEntries(): FormulaCatalogEntry[] {
|
|
294
294
|
const out: FormulaCatalogEntry[] = [];
|
|
295
295
|
for (const op of BLESSED_OPERATORS) {
|
|
296
|
-
|
|
296
|
+
// Own-property lookup only: a bare index would resolve inherited Object.prototype members for
|
|
297
|
+
// Ops like "toLocaleString", yielding a bogus meta whose undefined group/description breaks
|
|
298
|
+
// The palette's substring filter.
|
|
299
|
+
const meta = Object.hasOwn(OPERATOR_META, op) ? OPERATOR_META[op] : undefined;
|
|
297
300
|
if (meta) {
|
|
298
301
|
out.push({
|
|
299
302
|
description: meta.description,
|