@agent-native/core 0.92.7 → 0.92.8
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/corpus/README.md +1 -1
- package/corpus/core/CHANGELOG.md +12 -0
- package/corpus/core/docs/content/a2a-protocol.mdx +12 -0
- package/corpus/core/docs/content/locales/ar-SA/a2a-protocol.mdx +12 -0
- package/corpus/core/docs/content/locales/ar-SA/pr-visual-recap.mdx +3 -3
- package/corpus/core/docs/content/locales/ar-SA/pure-agent-apps.mdx +4 -0
- package/corpus/core/docs/content/locales/de-DE/a2a-protocol.mdx +12 -0
- package/corpus/core/docs/content/locales/de-DE/pr-visual-recap.mdx +3 -3
- package/corpus/core/docs/content/locales/de-DE/pure-agent-apps.mdx +4 -0
- package/corpus/core/docs/content/locales/es-ES/a2a-protocol.mdx +12 -0
- package/corpus/core/docs/content/locales/es-ES/pr-visual-recap.mdx +3 -3
- package/corpus/core/docs/content/locales/es-ES/pure-agent-apps.mdx +4 -0
- package/corpus/core/docs/content/locales/fr-FR/a2a-protocol.mdx +12 -0
- package/corpus/core/docs/content/locales/fr-FR/pr-visual-recap.mdx +3 -3
- package/corpus/core/docs/content/locales/fr-FR/pure-agent-apps.mdx +4 -0
- package/corpus/core/docs/content/locales/hi-IN/a2a-protocol.mdx +12 -0
- package/corpus/core/docs/content/locales/hi-IN/pr-visual-recap.mdx +3 -3
- package/corpus/core/docs/content/locales/hi-IN/pure-agent-apps.mdx +4 -0
- package/corpus/core/docs/content/locales/ja-JP/a2a-protocol.mdx +12 -0
- package/corpus/core/docs/content/locales/ja-JP/pr-visual-recap.mdx +3 -3
- package/corpus/core/docs/content/locales/ja-JP/pure-agent-apps.mdx +4 -0
- package/corpus/core/docs/content/locales/ko-KR/a2a-protocol.mdx +12 -0
- package/corpus/core/docs/content/locales/ko-KR/pr-visual-recap.mdx +3 -3
- package/corpus/core/docs/content/locales/ko-KR/pure-agent-apps.mdx +4 -0
- package/corpus/core/docs/content/locales/pt-BR/a2a-protocol.mdx +12 -0
- package/corpus/core/docs/content/locales/pt-BR/pr-visual-recap.mdx +3 -3
- package/corpus/core/docs/content/locales/pt-BR/pure-agent-apps.mdx +4 -0
- package/corpus/core/docs/content/locales/zh-CN/a2a-protocol.mdx +12 -0
- package/corpus/core/docs/content/locales/zh-CN/pr-visual-recap.mdx +3 -3
- package/corpus/core/docs/content/locales/zh-CN/pure-agent-apps.mdx +4 -0
- package/corpus/core/docs/content/locales/zh-TW/a2a-protocol.mdx +12 -0
- package/corpus/core/docs/content/locales/zh-TW/pr-visual-recap.mdx +3 -3
- package/corpus/core/docs/content/locales/zh-TW/pure-agent-apps.mdx +4 -0
- package/corpus/core/docs/content/pr-visual-recap.mdx +3 -3
- package/corpus/core/docs/content/pure-agent-apps.mdx +22 -0
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/agent/engine/builtin.ts +1 -1
- package/corpus/core/src/agent/model-config.ts +30 -30
- package/corpus/core/src/agent/production-agent.ts +129 -7
- package/corpus/core/src/cli/design-connect.ts +438 -83
- package/corpus/core/src/cli/recap.ts +2 -2
- package/corpus/core/src/client/AgentPanel.tsx +8 -1
- package/corpus/core/src/client/agent-chat-adapter.ts +12 -7
- package/corpus/core/src/client/composer/TiptapComposer.tsx +1 -1
- package/corpus/core/src/client/index.ts +4 -0
- package/corpus/core/src/client/org/TeamPage.tsx +41 -26
- package/corpus/core/src/client/use-action.ts +113 -1
- package/corpus/core/src/db/client.ts +12 -2
- package/corpus/core/src/db/create-get-db.ts +4 -1
- package/corpus/core/src/scripts/agent-engines/manage-agent-engine.ts +1 -1
- package/corpus/core/src/scripts/agent-engines/set-agent-engine.ts +1 -1
- package/corpus/core/src/server/transcribe-voice.ts +1 -1
- package/corpus/core/src/usage/store.ts +13 -4
- package/corpus/core/src/vite/client.ts +38 -1
- package/corpus/templates/analytics/AGENTS.md +3 -0
- package/corpus/templates/analytics/actions/get-data-program.ts +78 -0
- package/corpus/templates/analytics/actions/list-data-programs.ts +49 -0
- package/corpus/templates/analytics/app/global.css +11 -0
- package/corpus/templates/analytics/app/hooks/use-dashboard-chat-context.ts +163 -17
- package/corpus/templates/analytics/app/i18n/zh-TW.ts +2 -0
- package/corpus/templates/analytics/app/i18n-data.ts +20 -0
- package/corpus/templates/analytics/app/pages/adhoc/explorer-dashboard/ChartCard.tsx +96 -3
- package/corpus/templates/analytics/app/pages/adhoc/explorer-dashboard/index.tsx +3 -1
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/SqlChartCard.tsx +61 -4
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +40 -2
- package/corpus/templates/analytics/changelog/2026-07-09-analytics-no-longer-forgets-successful-data-queries-when-a-l.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-09-dashboard-charts-keep-consistent-spacing-when-they-stack-ver.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-09-dashboard-charts-tables-and-extensions-can-be-selected-and-d.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-09-long-running-analytics-requests-now-recover-automatically-wh.md +6 -0
- package/corpus/templates/analytics/server/db/index.ts +6 -0
- package/corpus/templates/clips/desktop/src/hooks/useMeetingTranscription.ts +1 -7
- package/corpus/templates/content/app/components/editor/DocumentProperties.tsx +102 -15
- package/corpus/templates/content/app/hooks/use-content-database.ts +52 -0
- package/corpus/templates/content/app/hooks/use-document-properties.ts +50 -6
- package/corpus/templates/content/app/i18n/zh-TW.ts +2 -0
- package/corpus/templates/content/app/i18n-data.ts +28 -0
- package/corpus/templates/content/changelog/2026-07-09-notion-conflict-warnings-no-longer-flash-during-normal-synce.md +6 -0
- package/corpus/templates/content/changelog/2026-07-09-property-menus-and-delete-confirmations-now-open-visibly-and.md +6 -0
- package/corpus/templates/content/server/lib/notion-sync.ts +130 -28
- package/corpus/templates/design/actions/add-breakpoint.ts +48 -68
- package/corpus/templates/design/actions/add-localhost-screens.ts +496 -61
- package/corpus/templates/design/actions/apply-component-prop-edit.ts +2 -18
- package/corpus/templates/design/actions/apply-design-token-edit.ts +51 -82
- package/corpus/templates/design/actions/apply-tweaks.ts +63 -41
- package/corpus/templates/design/actions/capture-design-state.ts +2 -2
- package/corpus/templates/design/actions/connect-localhost.ts +58 -12
- package/corpus/templates/design/actions/create-component.ts +2 -18
- package/corpus/templates/design/actions/create-design-branch.ts +38 -18
- package/corpus/templates/design/actions/create-fusion-app.ts +15 -11
- package/corpus/templates/design/actions/delete-file.ts +19 -34
- package/corpus/templates/design/actions/deploy-design-preview.ts +59 -27
- package/corpus/templates/design/actions/deploy-fusion-app.ts +22 -15
- package/corpus/templates/design/actions/export-pdf.ts +2 -1
- package/corpus/templates/design/actions/export-zip.ts +9 -3
- package/corpus/templates/design/actions/generate-design.ts +107 -70
- package/corpus/templates/design/actions/get-component-details.ts +2 -18
- package/corpus/templates/design/actions/get-design-branch-diff.ts +2 -3
- package/corpus/templates/design/actions/get-design-surface-index.ts +2 -18
- package/corpus/templates/design/actions/get-design.ts +2 -1
- package/corpus/templates/design/actions/grant-localhost-write-consent.ts +7 -1
- package/corpus/templates/design/actions/import-design-tokens.ts +114 -76
- package/corpus/templates/design/actions/index-components.ts +2 -18
- package/corpus/templates/design/actions/list-design-source-capabilities.ts +23 -28
- package/corpus/templates/design/actions/list-local-files.ts +9 -2
- package/corpus/templates/design/actions/migrate-board-objects-to-file.ts +82 -98
- package/corpus/templates/design/actions/open-component-source.ts +2 -18
- package/corpus/templates/design/actions/open-visual-edit.ts +19 -1
- package/corpus/templates/design/actions/present-design-variants.ts +70 -70
- package/corpus/templates/design/actions/preview-component-prop-edit.ts +4 -14
- package/corpus/templates/design/actions/read-local-file.ts +9 -2
- package/corpus/templates/design/actions/remove-breakpoint.ts +40 -61
- package/corpus/templates/design/actions/rename-screen.ts +425 -0
- package/corpus/templates/design/actions/request-localhost-write-consent.ts +12 -2
- package/corpus/templates/design/actions/revoke-localhost-write-consent.ts +9 -2
- package/corpus/templates/design/actions/sync-fusion-app.ts +56 -39
- package/corpus/templates/design/actions/update-design.ts +376 -61
- package/corpus/templates/design/actions/update-file.ts +455 -188
- package/corpus/templates/design/actions/write-local-file.ts +10 -2
- package/corpus/templates/design/app/components/design/DesignCanvas.tsx +685 -608
- package/corpus/templates/design/app/components/design/LayersPanel.tsx +43 -15
- package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +576 -2015
- package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +62 -14
- package/corpus/templates/design/app/components/design/bridge/embedded-wheel.bridge.ts +263 -25
- package/corpus/templates/design/app/components/design/design-canvas/annotation-submit.ts +34 -0
- package/corpus/templates/design/app/components/design/design-canvas/coordinate-transforms.ts +40 -0
- package/corpus/templates/design/app/components/design/design-canvas/creation.ts +47 -0
- package/corpus/templates/design/app/components/design/design-canvas/element-payload.ts +27 -0
- package/corpus/templates/design/app/components/design/design-canvas/embedded-frame.ts +62 -0
- package/corpus/templates/design/app/components/design/design-canvas/external-preview.ts +137 -0
- package/corpus/templates/design/app/components/design/design-canvas/file-drop.ts +10 -0
- package/corpus/templates/design/app/components/design/design-canvas/hit-test.ts +23 -0
- package/corpus/templates/design/app/components/design/design-canvas/iframe-events.ts +23 -0
- package/corpus/templates/design/app/components/design/design-canvas/iframe-pan.ts +177 -0
- package/corpus/templates/design/app/components/design/design-canvas/motion-types.ts +7 -0
- package/corpus/templates/design/app/components/design/design-canvas/pending-text-edit.ts +62 -0
- package/corpus/templates/design/app/components/design/index.ts +2 -2
- package/corpus/templates/design/app/components/design/multi-screen/canvas-tools.ts +100 -0
- package/corpus/templates/design/app/components/design/multi-screen/coordinate-transforms.ts +81 -0
- package/corpus/templates/design/app/components/design/multi-screen/cross-screen-drop.ts +23 -13
- package/corpus/templates/design/app/components/design/multi-screen/culling.ts +238 -19
- package/corpus/templates/design/app/components/design/multi-screen/draft-primitives.ts +424 -0
- package/corpus/templates/design/app/components/design/multi-screen/frame-geometry.ts +341 -0
- package/corpus/templates/design/app/components/design/multi-screen/iframe-targeting.ts +52 -0
- package/corpus/templates/design/app/components/design/multi-screen/overview-layout.ts +62 -0
- package/corpus/templates/design/app/components/design/multi-screen/primitive-drop-target.ts +283 -0
- package/corpus/templates/design/app/components/design/multi-screen/screen-content-cache.ts +272 -0
- package/corpus/templates/design/app/components/design/multi-screen/types.ts +5 -1
- package/corpus/templates/design/app/components/design/multi-screen/wheel-gesture-state.ts +12 -0
- package/corpus/templates/design/app/components/visual-editor/DrawOverlay.tsx +325 -84
- package/corpus/templates/design/app/hooks/use-navigation-state.ts +15 -1
- package/corpus/templates/design/app/hooks/useDesignHotkeys.ts +119 -47
- package/corpus/templates/design/app/i18n/zh-TW.ts +9 -0
- package/corpus/templates/design/app/i18n-data.ts +223 -0
- package/corpus/templates/design/app/lib/design-save-outbox.ts +379 -0
- package/corpus/templates/design/app/lib/png-clipboard.ts +113 -0
- package/corpus/templates/design/app/pages/design-editor/canvas-primitives.ts +229 -0
- package/corpus/templates/design/app/pages/design-editor/code-layer-state.ts +918 -0
- package/corpus/templates/design/app/pages/design-editor/collab-sync.ts +43 -0
- package/corpus/templates/design/app/pages/design-editor/cross-screen-text-color.ts +336 -0
- package/corpus/templates/design/app/pages/design-editor/data-operations.ts +270 -0
- package/corpus/templates/design/app/pages/design-editor/dom-guards.ts +24 -0
- package/corpus/templates/design/app/pages/design-editor/dom-utils.ts +11 -0
- package/corpus/templates/design/app/pages/design-editor/editor-session.ts +20 -0
- package/corpus/templates/design/app/pages/design-editor/editor-state.ts +408 -0
- package/corpus/templates/design/app/pages/design-editor/export-capture.ts +115 -0
- package/corpus/templates/design/app/pages/design-editor/geometry-persistence.ts +93 -0
- package/corpus/templates/design/app/pages/design-editor/history.ts +169 -0
- package/corpus/templates/design/app/pages/design-editor/layout-operations.ts +185 -0
- package/corpus/templates/design/app/pages/design-editor/motion-state.ts +309 -0
- package/corpus/templates/design/app/pages/design-editor/overview-camera.ts +438 -0
- package/corpus/templates/design/app/pages/design-editor/pending-edits.ts +510 -0
- package/corpus/templates/design/app/pages/design-editor/portable-style.ts +115 -0
- package/corpus/templates/design/app/pages/design-editor/selection-state.ts +337 -0
- package/corpus/templates/design/app/pages/design-editor/style-utils.ts +5 -0
- package/corpus/templates/design/app/pages/design-editor/tool-state.ts +92 -0
- package/corpus/templates/design/app/pages/design-editor/tweak-save.ts +87 -0
- package/corpus/templates/design/app/pages/design-editor/types.ts +36 -0
- package/corpus/templates/design/app/routes/design.$id.tsx +11 -1
- package/corpus/templates/design/changelog/2026-07-09-design-edits-canvas-positions-tools-and-tab-context-now-pers.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-figma-style-shortcuts-drawing-annotations-and-cross-screen-d.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-hand-and-scale-tools-now-keep-their-active-toolbar-identity-.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-large-multi-screen-designs-now-stay-responsive-during-long-c.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-layer-drags-now-land-exactly-where-the-insertion-indicator-s.md +6 -0
- package/corpus/templates/design/server/db/index.ts +2 -52
- package/corpus/templates/design/server/db/schema.ts +16 -0
- package/corpus/templates/design/server/lib/design-data-access.ts +70 -0
- package/corpus/templates/design/server/lib/design-data-mutation.ts +249 -0
- package/corpus/templates/design/server/lib/fusion-screens.ts +89 -76
- package/corpus/templates/design/server/lib/import-design-files.ts +76 -35
- package/corpus/templates/design/server/lib/verify-write-grant.ts +7 -2
- package/corpus/templates/design/server/plugins/db.ts +19 -0
- package/corpus/templates/design/server/source-workspace.ts +12 -13
- package/corpus/templates/design/shared/resolve-tweaks.ts +15 -0
- package/corpus/templates/design/shared/screen-rename.ts +42 -0
- package/corpus/templates/design/shared/source-mode.ts +84 -4
- package/dist/agent/engine/builder-engine.d.ts +1 -1
- package/dist/agent/engine/builder-engine.d.ts.map +1 -1
- package/dist/agent/engine/builtin.js +1 -1
- package/dist/agent/engine/builtin.js.map +1 -1
- package/dist/agent/model-config.d.ts +9 -9
- package/dist/agent/model-config.d.ts.map +1 -1
- package/dist/agent/model-config.js +30 -30
- package/dist/agent/model-config.js.map +1 -1
- package/dist/agent/production-agent.d.ts +60 -1
- package/dist/agent/production-agent.d.ts.map +1 -1
- package/dist/agent/production-agent.js +106 -7
- package/dist/agent/production-agent.js.map +1 -1
- package/dist/cli/design-connect.d.ts +30 -1
- package/dist/cli/design-connect.d.ts.map +1 -1
- package/dist/cli/design-connect.js +359 -75
- package/dist/cli/design-connect.js.map +1 -1
- package/dist/cli/recap.js +2 -2
- package/dist/cli/recap.js.map +1 -1
- package/dist/client/AgentPanel.d.ts.map +1 -1
- package/dist/client/AgentPanel.js +6 -1
- package/dist/client/AgentPanel.js.map +1 -1
- package/dist/client/agent-chat-adapter.d.ts.map +1 -1
- package/dist/client/agent-chat-adapter.js +10 -5
- package/dist/client/agent-chat-adapter.js.map +1 -1
- package/dist/client/composer/TiptapComposer.js +1 -1
- package/dist/client/composer/TiptapComposer.js.map +1 -1
- package/dist/client/index.d.ts +1 -1
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +1 -1
- package/dist/client/index.js.map +1 -1
- package/dist/client/org/TeamPage.d.ts.map +1 -1
- package/dist/client/org/TeamPage.js +6 -5
- package/dist/client/org/TeamPage.js.map +1 -1
- package/dist/client/use-action.d.ts +32 -0
- package/dist/client/use-action.d.ts.map +1 -1
- package/dist/client/use-action.js +68 -1
- package/dist/client/use-action.js.map +1 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/db/client.d.ts +3 -0
- package/dist/db/client.d.ts.map +1 -1
- package/dist/db/client.js +7 -2
- package/dist/db/client.js.map +1 -1
- package/dist/db/create-get-db.d.ts.map +1 -1
- package/dist/db/create-get-db.js +2 -2
- package/dist/db/create-get-db.js.map +1 -1
- package/dist/notifications/routes.d.ts +3 -3
- package/dist/resources/handlers.d.ts +2 -2
- package/dist/scripts/agent-engines/manage-agent-engine.js +1 -1
- package/dist/scripts/agent-engines/manage-agent-engine.js.map +1 -1
- package/dist/scripts/agent-engines/set-agent-engine.js +1 -1
- package/dist/scripts/agent-engines/set-agent-engine.js.map +1 -1
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/transcribe-voice.js +1 -1
- package/dist/server/transcribe-voice.js.map +1 -1
- package/dist/usage/store.d.ts.map +1 -1
- package/dist/usage/store.js +13 -4
- package/dist/usage/store.js.map +1 -1
- package/dist/vite/client.d.ts.map +1 -1
- package/dist/vite/client.js +36 -1
- package/dist/vite/client.js.map +1 -1
- package/docs/content/a2a-protocol.mdx +12 -0
- package/docs/content/locales/ar-SA/a2a-protocol.mdx +12 -0
- package/docs/content/locales/ar-SA/pr-visual-recap.mdx +3 -3
- package/docs/content/locales/ar-SA/pure-agent-apps.mdx +4 -0
- package/docs/content/locales/de-DE/a2a-protocol.mdx +12 -0
- package/docs/content/locales/de-DE/pr-visual-recap.mdx +3 -3
- package/docs/content/locales/de-DE/pure-agent-apps.mdx +4 -0
- package/docs/content/locales/es-ES/a2a-protocol.mdx +12 -0
- package/docs/content/locales/es-ES/pr-visual-recap.mdx +3 -3
- package/docs/content/locales/es-ES/pure-agent-apps.mdx +4 -0
- package/docs/content/locales/fr-FR/a2a-protocol.mdx +12 -0
- package/docs/content/locales/fr-FR/pr-visual-recap.mdx +3 -3
- package/docs/content/locales/fr-FR/pure-agent-apps.mdx +4 -0
- package/docs/content/locales/hi-IN/a2a-protocol.mdx +12 -0
- package/docs/content/locales/hi-IN/pr-visual-recap.mdx +3 -3
- package/docs/content/locales/hi-IN/pure-agent-apps.mdx +4 -0
- package/docs/content/locales/ja-JP/a2a-protocol.mdx +12 -0
- package/docs/content/locales/ja-JP/pr-visual-recap.mdx +3 -3
- package/docs/content/locales/ja-JP/pure-agent-apps.mdx +4 -0
- package/docs/content/locales/ko-KR/a2a-protocol.mdx +12 -0
- package/docs/content/locales/ko-KR/pr-visual-recap.mdx +3 -3
- package/docs/content/locales/ko-KR/pure-agent-apps.mdx +4 -0
- package/docs/content/locales/pt-BR/a2a-protocol.mdx +12 -0
- package/docs/content/locales/pt-BR/pr-visual-recap.mdx +3 -3
- package/docs/content/locales/pt-BR/pure-agent-apps.mdx +4 -0
- package/docs/content/locales/zh-CN/a2a-protocol.mdx +12 -0
- package/docs/content/locales/zh-CN/pr-visual-recap.mdx +3 -3
- package/docs/content/locales/zh-CN/pure-agent-apps.mdx +4 -0
- package/docs/content/locales/zh-TW/a2a-protocol.mdx +12 -0
- package/docs/content/locales/zh-TW/pr-visual-recap.mdx +3 -3
- package/docs/content/locales/zh-TW/pure-agent-apps.mdx +4 -0
- package/docs/content/pr-visual-recap.mdx +3 -3
- package/docs/content/pure-agent-apps.mdx +22 -0
- package/package.json +2 -2
|
@@ -57,7 +57,7 @@ import {
|
|
|
57
57
|
componentNodeIdMatches,
|
|
58
58
|
} from "../shared/component-model.js";
|
|
59
59
|
import { hasCapability } from "../shared/design-source-capabilities.js";
|
|
60
|
-
import {
|
|
60
|
+
import { designSourceTypeFromData } from "../shared/source-mode.js";
|
|
61
61
|
import { sourceContentHash } from "../shared/source-workspace.js";
|
|
62
62
|
|
|
63
63
|
// ─── Helpers ──────────────────────────────────────────────────────────────────
|
|
@@ -241,24 +241,8 @@ export default defineAction({
|
|
|
241
241
|
if (!access) throw new Error("Design not found");
|
|
242
242
|
|
|
243
243
|
// ── Source type + capability gate ────────────────────────────────────────
|
|
244
|
-
let rawSourceType: unknown = "inline";
|
|
245
244
|
const rawData = (access.resource as { data?: unknown }).data;
|
|
246
|
-
|
|
247
|
-
try {
|
|
248
|
-
const parsed: unknown = JSON.parse(rawData);
|
|
249
|
-
if (
|
|
250
|
-
parsed !== null &&
|
|
251
|
-
typeof parsed === "object" &&
|
|
252
|
-
"sourceType" in (parsed as object)
|
|
253
|
-
) {
|
|
254
|
-
rawSourceType = (parsed as { sourceType: unknown }).sourceType;
|
|
255
|
-
}
|
|
256
|
-
} catch {
|
|
257
|
-
// Default to inline.
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
const sourceType = normalizeDesignSourceType(rawSourceType) ?? "inline";
|
|
245
|
+
const sourceType = designSourceTypeFromData(rawData);
|
|
262
246
|
const caps = resolveSourceCapabilities(sourceType);
|
|
263
247
|
|
|
264
248
|
// Real-app sources gate on `applyEdit` (bridge write hardening).
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { defineAction } from "@agent-native/core";
|
|
2
2
|
import { buildDeepLink } from "@agent-native/core/server";
|
|
3
3
|
import { assertAccess } from "@agent-native/core/sharing";
|
|
4
|
-
import { eq } from "drizzle-orm";
|
|
5
4
|
import { z } from "zod";
|
|
6
5
|
|
|
7
|
-
import { getDb, schema } from "../server/db/index.js";
|
|
8
6
|
import "../server/db/index.js"; // ensure registerShareableResource runs
|
|
7
|
+
import {
|
|
8
|
+
mutateDesignData,
|
|
9
|
+
type DesignDataRecord,
|
|
10
|
+
} from "../server/lib/design-data-mutation.js";
|
|
9
11
|
import {
|
|
10
12
|
INLINE_DEFAULT_CAPABILITIES,
|
|
11
13
|
hasCapability,
|
|
@@ -53,6 +55,25 @@ function designDeepLink(designId: string): string {
|
|
|
53
55
|
});
|
|
54
56
|
}
|
|
55
57
|
|
|
58
|
+
type TweakDef = Parameters<typeof resolveTweaksToCssVars>[0][number];
|
|
59
|
+
type TweakSelections = Record<string, string | number | boolean>;
|
|
60
|
+
|
|
61
|
+
function readTweaks(data: DesignDataRecord): TweakDef[] {
|
|
62
|
+
return Array.isArray(data.tweaks) ? (data.tweaks as TweakDef[]) : [];
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function readSelections(data: DesignDataRecord): TweakSelections {
|
|
66
|
+
return data.tweakSelections &&
|
|
67
|
+
typeof data.tweakSelections === "object" &&
|
|
68
|
+
!Array.isArray(data.tweakSelections)
|
|
69
|
+
? (data.tweakSelections as TweakSelections)
|
|
70
|
+
: {};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function selectionKeyForCssVar(tweaks: TweakDef[], cssVar: string): string {
|
|
74
|
+
return tweaks.find((tweak) => tweak.cssVar === cssVar)?.id ?? cssVar;
|
|
75
|
+
}
|
|
76
|
+
|
|
56
77
|
// ---------------------------------------------------------------------------
|
|
57
78
|
// Action — persist token edit through the Tweaks loop (Tier-A)
|
|
58
79
|
// ---------------------------------------------------------------------------
|
|
@@ -93,87 +114,35 @@ export default defineAction({
|
|
|
93
114
|
// sourceRef will be used once real write-back is implemented
|
|
94
115
|
void sourceRef;
|
|
95
116
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
let prevData: Record<string, unknown> = {};
|
|
108
|
-
if (existingDesign?.data) {
|
|
109
|
-
try {
|
|
110
|
-
const parsed = JSON.parse(existingDesign.data);
|
|
111
|
-
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
112
|
-
prevData = parsed;
|
|
117
|
+
// Merge against the latest designs.data revision. Each retry re-resolves
|
|
118
|
+
// cssVar -> tweak id so a concurrent tweak-definition change cannot leave
|
|
119
|
+
// the value under a stale key.
|
|
120
|
+
const { data: persistedData } = await mutateDesignData({
|
|
121
|
+
designId,
|
|
122
|
+
mutate: (prevData, { updatedAt }) => {
|
|
123
|
+
const tweaks = readTweaks(prevData);
|
|
124
|
+
const newSelections = { ...readSelections(prevData) };
|
|
125
|
+
for (const { cssVar, value } of edits) {
|
|
126
|
+
newSelections[selectionKeyForCssVar(tweaks, cssVar)] = value;
|
|
113
127
|
}
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
const
|
|
131
|
-
|
|
132
|
-
typeof prevData.tweakSelections === "object" &&
|
|
133
|
-
!Array.isArray(prevData.tweakSelections)
|
|
134
|
-
? (prevData.tweakSelections as Record<
|
|
135
|
-
string,
|
|
136
|
-
string | number | boolean
|
|
137
|
-
>)
|
|
138
|
-
: {};
|
|
139
|
-
|
|
140
|
-
// ------------------------------------------------------------------
|
|
141
|
-
// Merge edits into tweakSelections
|
|
142
|
-
// ------------------------------------------------------------------
|
|
143
|
-
// For each edit:
|
|
144
|
-
// - If the cssVar maps to a known tweak, persist by tweakId (the standard
|
|
145
|
-
// Tweaks loop key) so apply-tweaks, get-design-snapshot, and the bridge
|
|
146
|
-
// script all pick it up consistently.
|
|
147
|
-
// - If the cssVar does NOT map to a known tweak, we synthesise a minimal
|
|
148
|
-
// tweak entry and persist via the raw cssVar key so the bridge script
|
|
149
|
-
// (`TWEAK_BRIDGE_SCRIPT`) still applies it.
|
|
150
|
-
const newSelections = { ...prevSelections };
|
|
151
|
-
|
|
152
|
-
for (const { cssVar, value } of edits) {
|
|
153
|
-
const tweakId = cssVarToTweakId.get(cssVar);
|
|
154
|
-
if (tweakId) {
|
|
155
|
-
newSelections[tweakId] = value;
|
|
156
|
-
} else {
|
|
157
|
-
// Fallback: persist using the cssVar as the key — the bridge script
|
|
158
|
-
// calls documentElement.style.setProperty with the key directly, so
|
|
159
|
-
// any key starting with "--" is applied as-is.
|
|
160
|
-
newSelections[cssVar] = value;
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
// ------------------------------------------------------------------
|
|
165
|
-
// Persist — same atomic write as apply-tweaks
|
|
166
|
-
// ------------------------------------------------------------------
|
|
167
|
-
const mergedData: Record<string, unknown> = {
|
|
168
|
-
...prevData,
|
|
169
|
-
tweakSelections: newSelections,
|
|
170
|
-
tweaksAppliedAt: now,
|
|
171
|
-
};
|
|
172
|
-
|
|
173
|
-
await db
|
|
174
|
-
.update(schema.designs)
|
|
175
|
-
.set({ data: JSON.stringify(mergedData), updatedAt: now })
|
|
176
|
-
.where(eq(schema.designs.id, designId));
|
|
128
|
+
return {
|
|
129
|
+
...prevData,
|
|
130
|
+
tweakSelections: newSelections,
|
|
131
|
+
tweaksAppliedAt: updatedAt,
|
|
132
|
+
};
|
|
133
|
+
},
|
|
134
|
+
isApplied: (data) => {
|
|
135
|
+
const tweaks = readTweaks(data);
|
|
136
|
+
const selections = readSelections(data);
|
|
137
|
+
return edits.every(
|
|
138
|
+
({ cssVar, value }) =>
|
|
139
|
+
selections[selectionKeyForCssVar(tweaks, cssVar)] === value,
|
|
140
|
+
);
|
|
141
|
+
},
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
const tweaks = readTweaks(persistedData);
|
|
145
|
+
const newSelections = readSelections(persistedData);
|
|
177
146
|
|
|
178
147
|
// Resolve to full CSS var map for the response (so the caller can send a
|
|
179
148
|
// tweak-values postMessage without a separate round-trip)
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import { defineAction } from "@agent-native/core";
|
|
2
2
|
import { buildDeepLink } from "@agent-native/core/server";
|
|
3
3
|
import { assertAccess } from "@agent-native/core/sharing";
|
|
4
|
-
import { eq } from "drizzle-orm";
|
|
5
4
|
import { z } from "zod";
|
|
6
5
|
|
|
7
|
-
import { getDb, schema } from "../server/db/index.js";
|
|
8
6
|
import "../server/db/index.js"; // ensure registerShareableResource runs
|
|
7
|
+
import {
|
|
8
|
+
mutateDesignData,
|
|
9
|
+
type DesignDataRecord,
|
|
10
|
+
} from "../server/lib/design-data-mutation.js";
|
|
11
|
+
import { tweakSelectionsHash } from "../shared/resolve-tweaks.js";
|
|
9
12
|
|
|
10
13
|
/** Editor deep link so external agents can surface "Open design". */
|
|
11
14
|
function designDeepLink(designId: string): string {
|
|
@@ -16,6 +19,17 @@ function designDeepLink(designId: string): string {
|
|
|
16
19
|
});
|
|
17
20
|
}
|
|
18
21
|
|
|
22
|
+
export class TweakSelectionsConflictError extends Error {
|
|
23
|
+
readonly statusCode = 409;
|
|
24
|
+
|
|
25
|
+
constructor() {
|
|
26
|
+
super(
|
|
27
|
+
"Tweak values changed elsewhere before this edit could be saved. Refresh the design and try again.",
|
|
28
|
+
);
|
|
29
|
+
this.name = "TweakSelectionsConflictError";
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
19
33
|
export default defineAction({
|
|
20
34
|
description:
|
|
21
35
|
"Persist the user's live tweak knob values (accent color, density, " +
|
|
@@ -35,53 +49,61 @@ export default defineAction({
|
|
|
35
49
|
"e.g. { 'theme-accent': '#0EA5E9', 'border-radius': 12, " +
|
|
36
50
|
"'dark-mode': true }",
|
|
37
51
|
),
|
|
52
|
+
expectedSelectionsHash: z
|
|
53
|
+
.string()
|
|
54
|
+
.min(1)
|
|
55
|
+
.max(128)
|
|
56
|
+
.optional()
|
|
57
|
+
.describe(
|
|
58
|
+
"Optimistic-concurrency hash of the persisted tweak selection map this full snapshot was based on.",
|
|
59
|
+
),
|
|
38
60
|
}),
|
|
39
|
-
run: async ({ designId, selections }) => {
|
|
61
|
+
run: async ({ designId, selections, expectedSelectionsHash }) => {
|
|
40
62
|
await assertAccess("design", designId, "editor");
|
|
41
63
|
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
const [existingDesign] = await db
|
|
48
|
-
.select({ data: schema.designs.data })
|
|
49
|
-
.from(schema.designs)
|
|
50
|
-
.where(eq(schema.designs.id, designId));
|
|
51
|
-
|
|
52
|
-
let prevData: Record<string, unknown> = {};
|
|
53
|
-
if (existingDesign?.data) {
|
|
54
|
-
try {
|
|
55
|
-
const parsed = JSON.parse(existingDesign.data);
|
|
56
|
-
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
57
|
-
prevData = parsed;
|
|
58
|
-
}
|
|
59
|
-
} catch {
|
|
60
|
-
// Stale/invalid JSON — start fresh but never drop the column.
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
const prevSelections =
|
|
65
|
-
prevData.tweakSelections &&
|
|
66
|
-
typeof prevData.tweakSelections === "object" &&
|
|
67
|
-
!Array.isArray(prevData.tweakSelections)
|
|
68
|
-
? (prevData.tweakSelections as Record<string, unknown>)
|
|
64
|
+
const readSelections = (data: DesignDataRecord) =>
|
|
65
|
+
data.tweakSelections &&
|
|
66
|
+
typeof data.tweakSelections === "object" &&
|
|
67
|
+
!Array.isArray(data.tweakSelections)
|
|
68
|
+
? (data.tweakSelections as Record<string, unknown>)
|
|
69
69
|
: {};
|
|
70
|
+
const selectionsAreApplied = (persisted: Record<string, unknown>) =>
|
|
71
|
+
Object.entries(selections).every(
|
|
72
|
+
([key, value]) => persisted[key] === value,
|
|
73
|
+
);
|
|
70
74
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
75
|
+
// Transactional CAS merge: keep every sibling key in designs.data and
|
|
76
|
+
// retry against the newest revision if another editor/action writes while
|
|
77
|
+
// this request is in flight.
|
|
78
|
+
const { data: persistedData } = await mutateDesignData({
|
|
79
|
+
designId,
|
|
80
|
+
mutate: (prevData, { updatedAt }) => {
|
|
81
|
+
const persistedSelections = readSelections(prevData);
|
|
82
|
+
const alreadyApplied = selectionsAreApplied(persistedSelections);
|
|
83
|
+
if (
|
|
84
|
+
expectedSelectionsHash !== undefined &&
|
|
85
|
+
tweakSelectionsHash(persistedSelections) !== expectedSelectionsHash &&
|
|
86
|
+
!alreadyApplied
|
|
87
|
+
) {
|
|
88
|
+
throw new TweakSelectionsConflictError();
|
|
89
|
+
}
|
|
90
|
+
if (alreadyApplied) return prevData;
|
|
91
|
+
return {
|
|
92
|
+
...prevData,
|
|
93
|
+
tweakSelections: { ...persistedSelections, ...selections },
|
|
94
|
+
tweaksAppliedAt: updatedAt,
|
|
95
|
+
};
|
|
96
|
+
},
|
|
97
|
+
isApplied: (data) => {
|
|
98
|
+
const persistedSelections = readSelections(data);
|
|
99
|
+
return selectionsAreApplied(persistedSelections);
|
|
100
|
+
},
|
|
101
|
+
});
|
|
81
102
|
|
|
82
103
|
return {
|
|
83
104
|
designId,
|
|
84
|
-
appliedTweaks:
|
|
105
|
+
appliedTweaks: readSelections(persistedData),
|
|
106
|
+
selectionsHash: tweakSelectionsHash(readSelections(persistedData)),
|
|
85
107
|
deepLink: designDeepLink(designId),
|
|
86
108
|
};
|
|
87
109
|
},
|
|
@@ -13,7 +13,7 @@ import "../server/db/index.js"; // ensure registerShareableResource runs
|
|
|
13
13
|
import { hasCapability } from "../shared/design-source-capabilities.js";
|
|
14
14
|
import type { DesignSourceCapabilities } from "../shared/design-source-capabilities.js";
|
|
15
15
|
import {
|
|
16
|
-
|
|
16
|
+
designSourceTypeFromData,
|
|
17
17
|
resolveDescriptorCapabilities,
|
|
18
18
|
type DesignSourceDescriptor,
|
|
19
19
|
} from "../shared/source-mode.js";
|
|
@@ -34,7 +34,7 @@ function resolveCapabilities(
|
|
|
34
34
|
if (parsed.capabilities && typeof parsed.capabilities === "object") {
|
|
35
35
|
return parsed.capabilities as DesignSourceCapabilities;
|
|
36
36
|
}
|
|
37
|
-
const sourceType =
|
|
37
|
+
const sourceType = designSourceTypeFromData(parsed);
|
|
38
38
|
const descriptor: DesignSourceDescriptor =
|
|
39
39
|
sourceType === "fusion"
|
|
40
40
|
? { sourceType, connected: parsed.connected === true }
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
getRequestOrgId,
|
|
6
6
|
getRequestUserEmail,
|
|
7
7
|
} from "@agent-native/core/server/request-context";
|
|
8
|
-
import { and, eq, sql } from "drizzle-orm";
|
|
8
|
+
import { and, eq, isNull, sql } from "drizzle-orm";
|
|
9
9
|
import { z } from "zod";
|
|
10
10
|
|
|
11
11
|
import { getDb, schema } from "../server/db/index.js";
|
|
@@ -91,6 +91,17 @@ function stableConnectionId(
|
|
|
91
91
|
return `localhost_${hash}`;
|
|
92
92
|
}
|
|
93
93
|
|
|
94
|
+
const PREVIEW_TOKEN_DOMAIN = "agent-native-design-preview-v1\0";
|
|
95
|
+
|
|
96
|
+
/** One-way compatibility derivation shared with the core design-connect CLI. */
|
|
97
|
+
export function derivePreviewToken(bridgeToken: string): string {
|
|
98
|
+
return crypto
|
|
99
|
+
.createHash("sha256")
|
|
100
|
+
.update(PREVIEW_TOKEN_DOMAIN)
|
|
101
|
+
.update(bridgeToken)
|
|
102
|
+
.digest("hex");
|
|
103
|
+
}
|
|
104
|
+
|
|
94
105
|
export default defineAction({
|
|
95
106
|
description:
|
|
96
107
|
"Register or refresh a localhost Design source connection produced by `agent-native design connect`. Stores the dev server URL, bridge URL, route manifest, and operation capabilities so the UI can later list local-code artboards.",
|
|
@@ -133,6 +144,12 @@ export default defineAction({
|
|
|
133
144
|
.describe(
|
|
134
145
|
"The bridge's real auth token minted at bridge start. Stored on the connection so grant-localhost-write-consent can read it without minting its own.",
|
|
135
146
|
),
|
|
147
|
+
previewToken: z
|
|
148
|
+
.string()
|
|
149
|
+
.optional()
|
|
150
|
+
.describe(
|
|
151
|
+
"Distinct read-only token for browser preview, snapshots, and live-edit bridge registration. Omit when passing bridgeToken to derive the compatible token automatically.",
|
|
152
|
+
),
|
|
136
153
|
status: z
|
|
137
154
|
.enum(["connected", "detected", "manual", "error"])
|
|
138
155
|
.optional()
|
|
@@ -181,6 +198,12 @@ export default defineAction({
|
|
|
181
198
|
operation,
|
|
182
199
|
status: "available" as const,
|
|
183
200
|
}));
|
|
201
|
+
const ownerOrgScope = and(
|
|
202
|
+
eq(schema.designLocalhostConnections.ownerEmail, ownerEmail),
|
|
203
|
+
orgId
|
|
204
|
+
? eq(schema.designLocalhostConnections.orgId, orgId)
|
|
205
|
+
: isNull(schema.designLocalhostConnections.orgId),
|
|
206
|
+
);
|
|
184
207
|
|
|
185
208
|
// The id may already be taken by a DIFFERENT user (legacy ids were derived
|
|
186
209
|
// from devServerUrl + rootPath without user scoping, so two users on the
|
|
@@ -189,15 +212,21 @@ export default defineAction({
|
|
|
189
212
|
const existing = await db
|
|
190
213
|
.select({
|
|
191
214
|
ownerEmail: schema.designLocalhostConnections.ownerEmail,
|
|
215
|
+
orgId: schema.designLocalhostConnections.orgId,
|
|
216
|
+
previewToken: schema.designLocalhostConnections.previewToken,
|
|
192
217
|
bridgeToken: schema.designLocalhostConnections.bridgeToken,
|
|
193
218
|
})
|
|
194
219
|
.from(schema.designLocalhostConnections)
|
|
195
220
|
.where(eq(schema.designLocalhostConnections.id, id))
|
|
196
221
|
.limit(1);
|
|
197
222
|
|
|
198
|
-
if (
|
|
223
|
+
if (
|
|
224
|
+
existing[0] &&
|
|
225
|
+
(existing[0].ownerEmail !== ownerEmail ||
|
|
226
|
+
(existing[0].orgId ?? null) !== orgId)
|
|
227
|
+
) {
|
|
199
228
|
throw new Error(
|
|
200
|
-
`Connection id "${id}" already belongs to another user. ` +
|
|
229
|
+
`Connection id "${id}" already belongs to another user or organization. ` +
|
|
201
230
|
"Omit id so a per-user connection id is derived instead.",
|
|
202
231
|
);
|
|
203
232
|
}
|
|
@@ -209,6 +238,13 @@ export default defineAction({
|
|
|
209
238
|
explicitToken ||
|
|
210
239
|
existing[0]?.bridgeToken ||
|
|
211
240
|
crypto.randomBytes(32).toString("hex");
|
|
241
|
+
const explicitPreviewToken =
|
|
242
|
+
args.previewToken?.trim() ||
|
|
243
|
+
(explicitToken ? derivePreviewToken(nextBridgeToken) : undefined);
|
|
244
|
+
const nextPreviewToken =
|
|
245
|
+
explicitPreviewToken ||
|
|
246
|
+
existing[0]?.previewToken ||
|
|
247
|
+
derivePreviewToken(nextBridgeToken);
|
|
212
248
|
const baseValues = {
|
|
213
249
|
id,
|
|
214
250
|
name: args.name ?? new URL(devServerUrl).host,
|
|
@@ -232,7 +268,12 @@ export default defineAction({
|
|
|
232
268
|
// conflict a no-op.
|
|
233
269
|
await db
|
|
234
270
|
.insert(schema.designLocalhostConnections)
|
|
235
|
-
.values({
|
|
271
|
+
.values({
|
|
272
|
+
...baseValues,
|
|
273
|
+
previewToken: nextPreviewToken,
|
|
274
|
+
bridgeToken: nextBridgeToken,
|
|
275
|
+
createdAt: now,
|
|
276
|
+
})
|
|
236
277
|
.onConflictDoUpdate({
|
|
237
278
|
target: schema.designLocalhostConnections.id,
|
|
238
279
|
set: {
|
|
@@ -240,24 +281,27 @@ export default defineAction({
|
|
|
240
281
|
bridgeToken: explicitToken
|
|
241
282
|
? nextBridgeToken
|
|
242
283
|
: sql`coalesce(${schema.designLocalhostConnections.bridgeToken}, excluded.bridge_token)`,
|
|
284
|
+
previewToken: explicitPreviewToken
|
|
285
|
+
? nextPreviewToken
|
|
286
|
+
: sql`coalesce(${schema.designLocalhostConnections.previewToken}, excluded.preview_token)`,
|
|
243
287
|
},
|
|
244
|
-
setWhere:
|
|
288
|
+
setWhere: ownerOrgScope,
|
|
245
289
|
});
|
|
246
290
|
|
|
247
291
|
// Return the token the row actually holds (owner-scoped, so a cross-user
|
|
248
292
|
// no-op never leaks another user's token), not the one we minted — so
|
|
249
293
|
// concurrent callers converge on the winner (no 401 on a lost race).
|
|
250
294
|
const [stored] = await db
|
|
251
|
-
.select({
|
|
295
|
+
.select({
|
|
296
|
+
bridgeToken: schema.designLocalhostConnections.bridgeToken,
|
|
297
|
+
previewToken: schema.designLocalhostConnections.previewToken,
|
|
298
|
+
})
|
|
252
299
|
.from(schema.designLocalhostConnections)
|
|
253
|
-
.where(
|
|
254
|
-
and(
|
|
255
|
-
eq(schema.designLocalhostConnections.id, id),
|
|
256
|
-
eq(schema.designLocalhostConnections.ownerEmail, ownerEmail),
|
|
257
|
-
),
|
|
258
|
-
)
|
|
300
|
+
.where(and(eq(schema.designLocalhostConnections.id, id), ownerOrgScope))
|
|
259
301
|
.limit(1);
|
|
260
302
|
const effectiveBridgeToken = stored?.bridgeToken ?? nextBridgeToken;
|
|
303
|
+
const effectivePreviewToken =
|
|
304
|
+
stored?.previewToken ?? derivePreviewToken(effectiveBridgeToken);
|
|
261
305
|
|
|
262
306
|
return {
|
|
263
307
|
id,
|
|
@@ -271,6 +315,8 @@ export default defineAction({
|
|
|
271
315
|
capabilities,
|
|
272
316
|
status: args.status,
|
|
273
317
|
lastSeenAt: now,
|
|
318
|
+
// Safe for Design browser previews. It cannot authorize filesystem calls.
|
|
319
|
+
previewToken: effectivePreviewToken,
|
|
274
320
|
// Returned so the caller can start the bridge with
|
|
275
321
|
// `design connect --bridge-token <this>`, matching this row.
|
|
276
322
|
bridgeToken: effectiveBridgeToken,
|
|
@@ -53,7 +53,7 @@ import {
|
|
|
53
53
|
COMPONENT_PROP_PREFIX,
|
|
54
54
|
} from "../shared/component-model.js";
|
|
55
55
|
import { hasCapability } from "../shared/design-source-capabilities.js";
|
|
56
|
-
import {
|
|
56
|
+
import { designSourceTypeFromData } from "../shared/source-mode.js";
|
|
57
57
|
|
|
58
58
|
// ─── Pure helpers ─────────────────────────────────────────────────────────────
|
|
59
59
|
|
|
@@ -259,24 +259,8 @@ export default defineAction({
|
|
|
259
259
|
if (!access) throw new Error("Design not found");
|
|
260
260
|
|
|
261
261
|
// ── Source type + capability gate ────────────────────────────────────────
|
|
262
|
-
let rawSourceType: unknown = "inline";
|
|
263
262
|
const rawData = (access.resource as { data?: unknown }).data;
|
|
264
|
-
|
|
265
|
-
try {
|
|
266
|
-
const parsed: unknown = JSON.parse(rawData);
|
|
267
|
-
if (
|
|
268
|
-
parsed !== null &&
|
|
269
|
-
typeof parsed === "object" &&
|
|
270
|
-
"sourceType" in (parsed as object)
|
|
271
|
-
) {
|
|
272
|
-
rawSourceType = (parsed as { sourceType: unknown }).sourceType;
|
|
273
|
-
}
|
|
274
|
-
} catch {
|
|
275
|
-
// Default to inline.
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
const sourceType = normalizeDesignSourceType(rawSourceType) ?? "inline";
|
|
263
|
+
const sourceType = designSourceTypeFromData(rawData);
|
|
280
264
|
const caps = resolveSourceCapabilities(sourceType);
|
|
281
265
|
|
|
282
266
|
// Real-app sources gate on `applyEdit` (bridge write hardening).
|
|
@@ -36,12 +36,13 @@ import { z } from "zod";
|
|
|
36
36
|
|
|
37
37
|
import { getDb, schema } from "../server/db/index.js";
|
|
38
38
|
import "../server/db/index.js"; // ensure registerShareableResource runs
|
|
39
|
+
import { mutateDesignData } from "../server/lib/design-data-mutation.js";
|
|
39
40
|
import {
|
|
40
41
|
resolveSourceCapabilities,
|
|
41
42
|
resolveFusionCapabilities,
|
|
42
43
|
} from "../shared/capability-resolver.js";
|
|
43
44
|
import { hasCapability } from "../shared/design-source-capabilities.js";
|
|
44
|
-
import {
|
|
45
|
+
import { designSourceTypeFromData } from "../shared/source-mode.js";
|
|
45
46
|
|
|
46
47
|
// ─── Helpers ──────────────────────────────────────────────────────────────────
|
|
47
48
|
|
|
@@ -127,8 +128,7 @@ export default defineAction({
|
|
|
127
128
|
|
|
128
129
|
// ── Source type + capability check ──────────────────────────────────────
|
|
129
130
|
const designData = parseDesignData(resource.data);
|
|
130
|
-
const sourceType =
|
|
131
|
-
normalizeDesignSourceType(designData["sourceType"]) ?? "inline";
|
|
131
|
+
const sourceType = designSourceTypeFromData(designData);
|
|
132
132
|
|
|
133
133
|
// For fusion sources, resolve the Builder connection status first so that
|
|
134
134
|
// resolveFusionCapabilities returns the CONNECTED map (with branch/deploy
|
|
@@ -219,10 +219,6 @@ export default defineAction({
|
|
|
219
219
|
});
|
|
220
220
|
|
|
221
221
|
// ── Persist branch metadata into the design's data blob ─────────────────
|
|
222
|
-
const existingBranches = Array.isArray(designData["branches"])
|
|
223
|
-
? (designData["branches"] as unknown[])
|
|
224
|
-
: [];
|
|
225
|
-
|
|
226
222
|
const branchEntry = {
|
|
227
223
|
branchName: builderResult.branchName,
|
|
228
224
|
projectId: builderResult.projectId,
|
|
@@ -233,19 +229,43 @@ export default defineAction({
|
|
|
233
229
|
createdAt: now,
|
|
234
230
|
};
|
|
235
231
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
232
|
+
await mutateDesignData({
|
|
233
|
+
designId,
|
|
234
|
+
mutate: (current) => {
|
|
235
|
+
const existingBranches = Array.isArray(current.branches)
|
|
236
|
+
? current.branches
|
|
237
|
+
: [];
|
|
238
|
+
const alreadyAppended = existingBranches.some(
|
|
239
|
+
(candidate) =>
|
|
240
|
+
candidate !== null &&
|
|
241
|
+
typeof candidate === "object" &&
|
|
242
|
+
!Array.isArray(candidate) &&
|
|
243
|
+
(candidate as Record<string, unknown>).preSnapshotVersionId ===
|
|
244
|
+
versionId,
|
|
245
|
+
);
|
|
246
|
+
return {
|
|
247
|
+
...current,
|
|
248
|
+
branches: alreadyAppended
|
|
249
|
+
? existingBranches
|
|
250
|
+
: [...existingBranches, branchEntry],
|
|
251
|
+
// Upgrade the source type to fusion once a Builder branch is
|
|
252
|
+
// provisioned so the capability matrix reflects the real-app tier.
|
|
253
|
+
sourceType: "fusion",
|
|
254
|
+
};
|
|
255
|
+
},
|
|
256
|
+
isApplied: (current) =>
|
|
257
|
+
current.sourceType === "fusion" &&
|
|
258
|
+
Array.isArray(current.branches) &&
|
|
259
|
+
current.branches.some(
|
|
260
|
+
(candidate) =>
|
|
261
|
+
candidate !== null &&
|
|
262
|
+
typeof candidate === "object" &&
|
|
263
|
+
!Array.isArray(candidate) &&
|
|
264
|
+
(candidate as Record<string, unknown>).preSnapshotVersionId ===
|
|
265
|
+
versionId,
|
|
266
|
+
),
|
|
242
267
|
});
|
|
243
268
|
|
|
244
|
-
await db
|
|
245
|
-
.update(schema.designs)
|
|
246
|
-
.set({ data: updatedData, updatedAt: now })
|
|
247
|
-
.where(eq(schema.designs.id, designId));
|
|
248
|
-
|
|
249
269
|
return {
|
|
250
270
|
designId,
|
|
251
271
|
sourceType: "fusion" as const,
|
|
@@ -20,15 +20,14 @@ import {
|
|
|
20
20
|
} from "@agent-native/core/server";
|
|
21
21
|
import { getRequestUserEmail } from "@agent-native/core/server/request-context";
|
|
22
22
|
import { assertAccess } from "@agent-native/core/sharing";
|
|
23
|
-
import { eq } from "drizzle-orm";
|
|
24
23
|
import { z } from "zod";
|
|
25
24
|
|
|
26
|
-
import {
|
|
25
|
+
import { schema } from "../server/db/index.js";
|
|
27
26
|
import "../server/db/index.js"; // ensure registerShareableResource runs
|
|
27
|
+
import { mutateDesignData } from "../server/lib/design-data-mutation.js";
|
|
28
28
|
import { resolveBuilderStatus } from "../shared/builder-app.js";
|
|
29
29
|
import {
|
|
30
30
|
FULL_APP_BUILDING_ENABLED,
|
|
31
|
-
parseDesignDataBlob,
|
|
32
31
|
readFusionApp,
|
|
33
32
|
writeFusionApp,
|
|
34
33
|
} from "../shared/full-app.js";
|
|
@@ -170,23 +169,28 @@ export default defineAction({
|
|
|
170
169
|
});
|
|
171
170
|
|
|
172
171
|
const now = new Date().toISOString();
|
|
173
|
-
const
|
|
174
|
-
const nextData = writeFusionApp(parseDesignDataBlob(design.data), {
|
|
172
|
+
const nextFusionApp = {
|
|
175
173
|
projectId: result.projectId,
|
|
176
174
|
branchName: result.branchName,
|
|
177
175
|
editorUrl: result.url,
|
|
178
|
-
status: "building",
|
|
176
|
+
status: "building" as const,
|
|
179
177
|
statusMessage:
|
|
180
178
|
"App is being generated. Call sync-fusion-app to check progress.",
|
|
181
179
|
createdAt: now,
|
|
182
180
|
updatedAt: now,
|
|
181
|
+
};
|
|
182
|
+
await mutateDesignData({
|
|
183
|
+
designId,
|
|
184
|
+
mutate: (current) => writeFusionApp(current, nextFusionApp),
|
|
185
|
+
isApplied: (current) => {
|
|
186
|
+
const persisted = readFusionApp(current);
|
|
187
|
+
return (
|
|
188
|
+
persisted?.projectId === result.projectId &&
|
|
189
|
+
persisted.branchName === result.branchName
|
|
190
|
+
);
|
|
191
|
+
},
|
|
183
192
|
});
|
|
184
193
|
|
|
185
|
-
await db
|
|
186
|
-
.update(schema.designs)
|
|
187
|
-
.set({ data: JSON.stringify(nextData), updatedAt: now })
|
|
188
|
-
.where(eq(schema.designs.id, designId));
|
|
189
|
-
|
|
190
194
|
return {
|
|
191
195
|
status: "building" as const,
|
|
192
196
|
designId,
|