@agent-native/core 0.80.9 → 0.80.11

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 (148) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/core/CHANGELOG.md +13 -0
  3. package/corpus/core/package.json +1 -1
  4. package/corpus/core/src/agent/production-agent.ts +108 -15
  5. package/corpus/core/src/cli/design-connect.ts +28 -2
  6. package/corpus/core/src/cli/skills.ts +45 -24
  7. package/corpus/core/src/client/AssistantChat.tsx +123 -26
  8. package/corpus/core/src/client/sse-event-processor.ts +9 -0
  9. package/corpus/templates/assets/.agents/skills/image-generation/SKILL.md +9 -2
  10. package/corpus/templates/assets/AGENTS.md +4 -0
  11. package/corpus/templates/assets/actions/_tool-activity.ts +46 -0
  12. package/corpus/templates/assets/actions/generate-image-batch.ts +26 -5
  13. package/corpus/templates/assets/actions/generate-image.ts +118 -67
  14. package/corpus/templates/assets/actions/list-draft-assets.ts +50 -0
  15. package/corpus/templates/assets/actions/rerun-generation-run.ts +52 -31
  16. package/corpus/templates/assets/app/components/create/RecentDraftsSection.tsx +100 -0
  17. package/corpus/templates/assets/app/i18n/zh-TW.ts +7 -0
  18. package/corpus/templates/assets/app/i18n-data.ts +61 -0
  19. package/corpus/templates/assets/app/routes/_index.tsx +4 -0
  20. package/corpus/templates/assets/app/routes/library.tsx +145 -38
  21. package/corpus/templates/assets/changelog/2026-06-29-image-generation-can-now-render-requested-text-and-respect-b.md +6 -0
  22. package/corpus/templates/assets/changelog/2026-06-30-image-generation-no-longer-looks-stuck-while-the-provider-is-still-working.md +6 -0
  23. package/corpus/templates/assets/changelog/2026-06-30-tagged-presets-now-control-the-image-aspect-ratio.md +6 -0
  24. package/corpus/templates/assets/server/lib/generation.ts +135 -11
  25. package/corpus/templates/assets/shared/api.ts +4 -0
  26. package/corpus/templates/clips/actions/list-ai-requests.ts +60 -0
  27. package/corpus/templates/clips/app/hooks/use-auto-title.ts +24 -25
  28. package/corpus/templates/design/DESIGN-STUDIO-PLAN.md +717 -0
  29. package/corpus/templates/design/actions/add-breakpoint.ts +143 -0
  30. package/corpus/templates/design/actions/add-localhost-screens.ts +5 -0
  31. package/corpus/templates/design/actions/apply-a11y-fix.ts +317 -0
  32. package/corpus/templates/design/actions/apply-component-prop-edit.ts +441 -0
  33. package/corpus/templates/design/actions/apply-design-state.ts +213 -0
  34. package/corpus/templates/design/actions/apply-design-token-edit.ts +202 -0
  35. package/corpus/templates/design/actions/apply-motion-edit.ts +413 -0
  36. package/corpus/templates/design/actions/apply-shader-fill.ts +404 -0
  37. package/corpus/templates/design/actions/apply-visual-edit.ts +191 -5
  38. package/corpus/templates/design/actions/capture-design-state.ts +224 -0
  39. package/corpus/templates/design/actions/connect-builder-app.ts +162 -0
  40. package/corpus/templates/design/actions/create-component.ts +447 -0
  41. package/corpus/templates/design/actions/create-design-branch.ts +263 -0
  42. package/corpus/templates/design/actions/create-design-state.ts +162 -0
  43. package/corpus/templates/design/actions/delete-design-state.ts +55 -0
  44. package/corpus/templates/design/actions/delete-design.ts +20 -0
  45. package/corpus/templates/design/actions/deploy-design-preview.ts +275 -0
  46. package/corpus/templates/design/actions/get-component-details.ts +251 -0
  47. package/corpus/templates/design/actions/get-design-branch-diff.ts +362 -0
  48. package/corpus/templates/design/actions/get-design-review.ts +314 -0
  49. package/corpus/templates/design/actions/get-design-surface-index.ts +582 -0
  50. package/corpus/templates/design/actions/get-motion-timeline.ts +99 -0
  51. package/corpus/templates/design/actions/index-components.ts +258 -0
  52. package/corpus/templates/design/actions/index-design-tokens.ts +277 -0
  53. package/corpus/templates/design/actions/list-design-extensions.ts +309 -0
  54. package/corpus/templates/design/actions/list-design-source-capabilities.ts +153 -0
  55. package/corpus/templates/design/actions/list-design-states.ts +90 -0
  56. package/corpus/templates/design/actions/migrate-inline-design-to-app.ts +298 -0
  57. package/corpus/templates/design/actions/open-component-source.ts +242 -0
  58. package/corpus/templates/design/actions/preview-component-prop-edit.ts +260 -0
  59. package/corpus/templates/design/actions/preview-design-token-edit.ts +113 -0
  60. package/corpus/templates/design/actions/preview-shader-fill.ts +187 -0
  61. package/corpus/templates/design/actions/remove-breakpoint.ts +103 -0
  62. package/corpus/templates/design/actions/remove-motion-timeline.ts +196 -0
  63. package/corpus/templates/design/actions/run-design-audit.ts +436 -0
  64. package/corpus/templates/design/actions/run-design-extension-action.ts +284 -0
  65. package/corpus/templates/design/actions/set-active-breakpoint.ts +39 -0
  66. package/corpus/templates/design/app/components/design/DesignCanvas.tsx +1550 -82
  67. package/corpus/templates/design/app/components/design/DesignExtensionsPanel.tsx +649 -43
  68. package/corpus/templates/design/app/components/design/DrawOverlay.tsx +1 -1
  69. package/corpus/templates/design/app/components/design/EditPanel.tsx +1788 -52
  70. package/corpus/templates/design/app/components/design/LayersPanel.tsx +114 -33
  71. package/corpus/templates/design/app/components/design/LocalSourceEditBanner.tsx +157 -0
  72. package/corpus/templates/design/app/components/design/MotionDock.tsx +1071 -0
  73. package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +1053 -99
  74. package/corpus/templates/design/app/components/design/ReviewPanel.tsx +766 -0
  75. package/corpus/templates/design/app/components/design/StatesPanel.tsx +581 -0
  76. package/corpus/templates/design/app/components/design/TokensPanel.tsx +578 -0
  77. package/corpus/templates/design/app/components/design/canvas-primitive-style.ts +241 -0
  78. package/corpus/templates/design/app/components/design/index.ts +16 -0
  79. package/corpus/templates/design/app/components/design/inspector/AutoLayoutMatrix.tsx +15 -6
  80. package/corpus/templates/design/app/components/design/inspector/DesignColorPicker.tsx +66 -3
  81. package/corpus/templates/design/app/components/design/inspector/InspectorAiActions.tsx +145 -0
  82. package/corpus/templates/design/app/components/design/inspector/SHADER_INTEGRATION.md +42 -12
  83. package/corpus/templates/design/app/components/visual-editor/DrawOverlay.tsx +1 -1
  84. package/corpus/templates/design/app/hooks/useAgentEditRequest.ts +131 -0
  85. package/corpus/templates/design/app/hooks/useDesignHotkeys.ts +3 -1
  86. package/corpus/templates/design/app/i18n/zh-TW.ts +32 -0
  87. package/corpus/templates/design/app/i18n-data.ts +280 -0
  88. package/corpus/templates/design/app/pages/DesignEditor.tsx +3087 -490
  89. package/corpus/templates/design/changelog/2026-06-29-added-a-review-panel-in-the-design-editor-s-inspector-with-a.md +6 -0
  90. package/corpus/templates/design/changelog/2026-06-29-copying-and-pasting-layers-no-longer-shows-success-notificat.md +6 -0
  91. package/corpus/templates/design/changelog/2026-06-29-device-presets-in-all-screens-view-resize-the-selected-previ.md +6 -0
  92. package/corpus/templates/design/changelog/2026-06-29-layer-and-canvas-drags-keep-the-layer-list-stable-while-chan.md +6 -0
  93. package/corpus/templates/design/changelog/2026-06-29-layer-moves-can-be-undone-and-redone-without-flashing-the-ca.md +6 -0
  94. package/corpus/templates/design/changelog/2026-06-29-screen-previews-use-a-single-blue-hover-border-in-all-screen.md +6 -0
  95. package/corpus/templates/design/changelog/2026-06-29-selected-containers-show-draggable-padding-and-gap-guides-on.md +6 -0
  96. package/corpus/templates/design/changelog/2026-06-29-the-design-editor-adds-a-studio-layer-with-tokens-respon.md +6 -0
  97. package/corpus/templates/design/changelog/2026-06-30-accessibility-findings-now-offer-a-one-click-fix.md +6 -0
  98. package/corpus/templates/design/changelog/2026-06-30-component-instances-now-have-editable-props-in-the-inspe.md +6 -0
  99. package/corpus/templates/design/changelog/2026-06-30-design-token-edits-now-stay-visible-in-previews-and-token-li.md +6 -0
  100. package/corpus/templates/design/changelog/2026-06-30-inspect-code-now-shows-the-elements-opening-tag-at-a-gla.md +6 -0
  101. package/corpus/templates/design/changelog/2026-06-30-shader-fill-presets-can-now-be-applied-to-an-element.md +6 -0
  102. package/corpus/templates/design/changelog/2026-06-30-the-motion-timeline-can-now-add-a-track-to-any-element-a.md +6 -0
  103. package/corpus/templates/design/changelog/2026-06-30-visual-editor-selection-layer-paint-and-drawing-controls-are-more-reliable.md +6 -0
  104. package/corpus/templates/design/e2e/global-setup.ts +94 -2
  105. package/corpus/templates/design/e2e/helpers.ts +10 -4
  106. package/corpus/templates/design/server/db/schema.ts +123 -0
  107. package/corpus/templates/design/server/plugins/db.ts +90 -0
  108. package/corpus/templates/design/shared/builder-app.ts +297 -0
  109. package/corpus/templates/design/shared/capability-resolver.ts +123 -0
  110. package/corpus/templates/design/shared/capture-sanitize.ts +70 -0
  111. package/corpus/templates/design/shared/code-layer.ts +1016 -71
  112. package/corpus/templates/design/shared/component-model.ts +274 -0
  113. package/corpus/templates/design/shared/design-review.ts +275 -0
  114. package/corpus/templates/design/shared/design-source-capabilities.ts +286 -0
  115. package/corpus/templates/design/shared/design-state.ts +112 -0
  116. package/corpus/templates/design/shared/design-surface-index.ts +258 -0
  117. package/corpus/templates/design/shared/motion-compiler.ts +349 -0
  118. package/corpus/templates/design/shared/motion-timeline.ts +193 -0
  119. package/corpus/templates/design/shared/resolve-tweaks.ts +32 -9
  120. package/corpus/templates/design/shared/responsive-classes.ts +452 -0
  121. package/corpus/templates/design/shared/shader-fill.ts +323 -0
  122. package/corpus/templates/design/shared/source-mode.ts +245 -0
  123. package/corpus/templates/plan/app/components/plan/CanvasArea.tsx +6 -2
  124. package/corpus/templates/plan/changelog/2026-06-29-plan-canvases-open-without-an-initial-pan-and-zoom-flicker.md +6 -0
  125. package/dist/agent/production-agent.d.ts.map +1 -1
  126. package/dist/agent/production-agent.js +94 -10
  127. package/dist/agent/production-agent.js.map +1 -1
  128. package/dist/cli/design-connect.d.ts.map +1 -1
  129. package/dist/cli/design-connect.js +28 -2
  130. package/dist/cli/design-connect.js.map +1 -1
  131. package/dist/cli/skills.d.ts.map +1 -1
  132. package/dist/cli/skills.js +37 -21
  133. package/dist/cli/skills.js.map +1 -1
  134. package/dist/client/AssistantChat.d.ts +14 -0
  135. package/dist/client/AssistantChat.d.ts.map +1 -1
  136. package/dist/client/AssistantChat.js +115 -22
  137. package/dist/client/AssistantChat.js.map +1 -1
  138. package/dist/client/sse-event-processor.d.ts.map +1 -1
  139. package/dist/client/sse-event-processor.js +10 -0
  140. package/dist/client/sse-event-processor.js.map +1 -1
  141. package/dist/collab/routes.d.ts +1 -1
  142. package/dist/file-upload/actions/upload-image.d.ts +2 -2
  143. package/dist/notifications/routes.d.ts +2 -2
  144. package/dist/observability/routes.d.ts +8 -8
  145. package/dist/resources/handlers.d.ts +2 -2
  146. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  147. package/dist/server/transcribe-voice.d.ts +1 -1
  148. package/package.json +1 -1
@@ -0,0 +1,309 @@
1
+ /**
2
+ * list-design-extensions — read action.
3
+ *
4
+ * Returns the first-party Design Studio extensions with their capability and
5
+ * availability status. The four built-in extensions are:
6
+ *
7
+ * 1. Asset Library — selection-aware asset insertion (ships now).
8
+ * 2. Shader Fills — GPU shader fill previews (preview-only now; apply gated).
9
+ * 3. Token Auditor — reads token usage across the design and flags clashes.
10
+ * 4. Motion Presets — one-click motion preset application.
11
+ *
12
+ * These are FIRST-PARTY extensions described as static metadata — they do not
13
+ * live in the extensions SQL table (they are capabilities of the design app,
14
+ * not user-created Alpine mini-apps). The UI surfaces them in the
15
+ * `design.editor.inspector` slot alongside user-installed extensions.
16
+ *
17
+ * The action also returns which actions power each extension, so the agent
18
+ * can invoke them directly without going through the extension iframe sandbox.
19
+ *
20
+ * Plan reference: DESIGN-STUDIO-PLAN.md §6.7 + §7 (`list-design-extensions`).
21
+ */
22
+
23
+ import { defineAction } from "@agent-native/core";
24
+ import { z } from "zod";
25
+
26
+ // ─── First-party extension catalog ───────────────────────────────────────────
27
+
28
+ export type DesignExtensionAvailability =
29
+ | "available" // ships now; can be used immediately
30
+ | "preview-only" // read / preview possible; write/apply is gated
31
+ | "planned"; // exists in the plan; not yet implemented
32
+
33
+ export interface DesignExtensionCapabilityEntry {
34
+ id: string;
35
+ label: string;
36
+ status: DesignExtensionAvailability;
37
+ reason?: string;
38
+ }
39
+
40
+ export interface FirstPartyDesignExtension {
41
+ /** Stable machine identifier — used by run-design-extension-action. */
42
+ id: string;
43
+ name: string;
44
+ description: string;
45
+ /** Tabler icon name (without the `Icon` prefix). */
46
+ icon: string;
47
+ /**
48
+ * Overall availability of this extension.
49
+ * Individual capabilities may be more restrictive.
50
+ */
51
+ availability: DesignExtensionAvailability;
52
+ /** Human-readable availability note shown in the UI. */
53
+ availabilityNote: string;
54
+ /** Fine-grained capability breakdown. */
55
+ capabilities: DesignExtensionCapabilityEntry[];
56
+ /** Design Studio actions that power this extension. */
57
+ actions: string[];
58
+ /**
59
+ * Whether this extension is registered in the `design.editor.inspector`
60
+ * extension slot as an installable first-party item.
61
+ */
62
+ slotId: "design.editor.inspector";
63
+ }
64
+
65
+ const FIRST_PARTY_EXTENSIONS: FirstPartyDesignExtension[] = [
66
+ // ── 1. Asset Library ─────────────────────────────────────────────────────
67
+ {
68
+ id: "design.asset-library",
69
+ name: "Asset Library",
70
+ description:
71
+ "Browse and insert generated or uploaded assets into the active design screen. " +
72
+ "Selection-aware: inserts near the selected element when one is active.",
73
+ icon: "Photo",
74
+ availability: "available",
75
+ availabilityNote: "Fully available — call insert-asset with an asset URL.",
76
+ capabilities: [
77
+ {
78
+ id: "browse",
79
+ label: "Browse asset library",
80
+ status: "available",
81
+ },
82
+ {
83
+ id: "insert",
84
+ label: "Insert asset into design",
85
+ status: "available",
86
+ reason:
87
+ "Uses insert-asset; selection-aware insertion lands immediately.",
88
+ },
89
+ {
90
+ id: "generate",
91
+ label: "Generate new asset via Assets app",
92
+ status: "available",
93
+ reason:
94
+ "Delegate to the Assets app via call-agent or the Assets MCP tool.",
95
+ },
96
+ ],
97
+ actions: ["insert-asset", "get-design-snapshot"],
98
+ slotId: "design.editor.inspector",
99
+ },
100
+
101
+ // ── 2. Shader Fills ──────────────────────────────────────────────────────
102
+ {
103
+ id: "design.shader-fills",
104
+ name: "Shader Fills",
105
+ description:
106
+ "GPU-accelerated shader fill presets (MeshGradient, GrainGradient, Voronoi, " +
107
+ "Metaballs, Warp, GodRays, Dithering, PaperTexture). Preview as CSS gradient " +
108
+ "without writing anything; full apply is gated until runtime rendering + " +
109
+ "source-write + fallback + diff proof are all in place.",
110
+ icon: "Sparkles",
111
+ availability: "preview-only",
112
+ availabilityNote:
113
+ "Preview-only. Call preview-shader-fill for a live CSS preview or " +
114
+ "apply-shader for a manual-edit code snippet. apply-shader-fill is " +
115
+ "gated and will return NOT_YET_AVAILABLE until safety conditions are met.",
116
+ capabilities: [
117
+ {
118
+ id: "catalog",
119
+ label: "Browse shader preset catalog",
120
+ status: "available",
121
+ reason: "Call get-shader to see all 8 presets.",
122
+ },
123
+ {
124
+ id: "preview",
125
+ label: "Preview shader fill as CSS gradient",
126
+ status: "available",
127
+ reason:
128
+ "Call preview-shader-fill — returns previewCss + bridgeMessage; no writes.",
129
+ },
130
+ {
131
+ id: "code-snippet",
132
+ label: "Generate code snippet for manual edit",
133
+ status: "available",
134
+ reason:
135
+ "Call apply-shader — returns JSX import + snippet or HTML bridge mount.",
136
+ },
137
+ {
138
+ id: "apply",
139
+ label: "Apply shader fill (persist to design)",
140
+ status: "preview-only",
141
+ reason:
142
+ "apply-shader-fill is GATED until: (1) runtime WebGL rendering verified via " +
143
+ "captureSnapshot, (2) source-write bridge available, (3) CSS fallback embedded " +
144
+ "alongside canvas, (4) before/after diff produced. Today it returns gated:true.",
145
+ },
146
+ ],
147
+ actions: [
148
+ "get-shader",
149
+ "preview-shader-fill",
150
+ "apply-shader",
151
+ "apply-shader-fill",
152
+ ],
153
+ slotId: "design.editor.inspector",
154
+ },
155
+
156
+ // ── 3. Token Auditor ─────────────────────────────────────────────────────
157
+ {
158
+ id: "design.token-auditor",
159
+ name: "Token Auditor",
160
+ description:
161
+ "Reads CSS custom property (token) usage across the active design, surfaces " +
162
+ "clashes (e.g. hard-coded colours that should be tokens, unused tokens), and " +
163
+ "guides token-first editing via the Tweaks loop.",
164
+ icon: "Palette",
165
+ availability: "available",
166
+ availabilityNote:
167
+ "Token reads are available for all source types. Token write-back " +
168
+ "to real source files (globals.css / tailwind.config) is gated on bridge " +
169
+ "hardening and requires a real-app source type.",
170
+ capabilities: [
171
+ {
172
+ id: "index",
173
+ label: "Index tokens from design",
174
+ status: "available",
175
+ reason: "Call index-design-tokens to parse CSS vars from the design.",
176
+ },
177
+ {
178
+ id: "preview-edit",
179
+ label: "Preview token edit",
180
+ status: "available",
181
+ reason: "Call preview-design-token-edit for a live CSS-var preview.",
182
+ },
183
+ {
184
+ id: "apply-edit",
185
+ label: "Apply token edit (persist)",
186
+ status: "available",
187
+ reason:
188
+ "Call apply-design-token-edit — persists via the Tweaks loop for inline designs.",
189
+ },
190
+ {
191
+ id: "write-source",
192
+ label: "Write token back to source file",
193
+ status: "preview-only",
194
+ reason:
195
+ "Source write-back (globals.css / tailwind.config) requires a real-app " +
196
+ "source type and bridge hardening. Currently planned.",
197
+ },
198
+ ],
199
+ actions: [
200
+ "index-design-tokens",
201
+ "preview-design-token-edit",
202
+ "apply-design-token-edit",
203
+ "get-design-surface-index",
204
+ ],
205
+ slotId: "design.editor.inspector",
206
+ },
207
+
208
+ // ── 4. Motion Presets ────────────────────────────────────────────────────
209
+ {
210
+ id: "design.motion-presets",
211
+ name: "Motion Presets",
212
+ description:
213
+ "One-click animation presets (fade-in, slide-up, pulse, bounce, spin) that " +
214
+ "apply to the selected node via the motion timeline. Preview is live; " +
215
+ "Write to CSS commits the keyframes atomically.",
216
+ icon: "PlayerPlay",
217
+ availability: "available",
218
+ availabilityNote:
219
+ "Motion preview is available for all source types. Write to CSS (apply-motion-edit) " +
220
+ "is atomic and available for inline + localhost. Source write-back to real CSS " +
221
+ "modules remains planned for the fusion tier.",
222
+ capabilities: [
223
+ {
224
+ id: "preview",
225
+ label: "Preview motion preset (scrub, no write)",
226
+ status: "available",
227
+ reason:
228
+ "Preview sends a motion-preview bridge message — no DB / collab write.",
229
+ },
230
+ {
231
+ id: "apply",
232
+ label: "Write keyframes to CSS (apply-motion-edit)",
233
+ status: "available",
234
+ reason:
235
+ "apply-motion-edit is atomic: persists timeline row + compiled CSS + " +
236
+ "Yjs/collab update + diff proof in one call.",
237
+ },
238
+ {
239
+ id: "write-source",
240
+ label: "Write to real CSS module / motion-react",
241
+ status: "preview-only",
242
+ reason:
243
+ "Real-source CSS module write-back is planned for fusion tier after bridge hardening.",
244
+ },
245
+ ],
246
+ actions: [
247
+ "get-motion-timeline",
248
+ "apply-motion-edit",
249
+ "remove-motion-timeline",
250
+ ],
251
+ slotId: "design.editor.inspector",
252
+ },
253
+ ];
254
+
255
+ // ─── Action ──────────────────────────────────────────────────────────────────
256
+
257
+ export default defineAction({
258
+ description: `
259
+ List the first-party Design Studio extensions with their capability and availability status.
260
+
261
+ Returns the four built-in extensions:
262
+ 1. Asset Library — selection-aware asset insertion (available now).
263
+ 2. Shader Fills — GPU shader fill previews (preview-only; apply is gated).
264
+ 3. Token Auditor — token usage reads + edits (available; source write-back planned).
265
+ 4. Motion Presets — one-click animation presets (available; source write-back planned).
266
+
267
+ Each entry includes the actions that power it so the agent can call them directly.
268
+ Use run-design-extension-action to dispatch an action through the extension surface.
269
+ `.trim(),
270
+ schema: z.object({
271
+ filter: z
272
+ .object({
273
+ availability: z
274
+ .enum(["available", "preview-only", "planned", "all"])
275
+ .optional()
276
+ .default("all")
277
+ .describe("Return only extensions with this availability status."),
278
+ extensionId: z
279
+ .string()
280
+ .optional()
281
+ .describe("Return only the extension with this id."),
282
+ })
283
+ .optional(),
284
+ }),
285
+ readOnly: true,
286
+ run: async ({ filter }) => {
287
+ let extensions = FIRST_PARTY_EXTENSIONS;
288
+
289
+ if (filter?.extensionId) {
290
+ extensions = extensions.filter((e) => e.id === filter.extensionId);
291
+ }
292
+
293
+ if (filter?.availability && filter.availability !== "all") {
294
+ extensions = extensions.filter(
295
+ (e) => e.availability === filter.availability,
296
+ );
297
+ }
298
+
299
+ return {
300
+ extensions,
301
+ count: extensions.length,
302
+ slotId: "design.editor.inspector",
303
+ note:
304
+ "These are first-party Design Studio extensions. User-created extensions " +
305
+ "live in the `design.editor.inspector` slot and can be listed via the core " +
306
+ "`list-extensions` action with a search filter for the slot id.",
307
+ };
308
+ },
309
+ });
@@ -0,0 +1,153 @@
1
+ import { defineAction } from "@agent-native/core";
2
+ import { resolveAccess } from "@agent-native/core/sharing";
3
+ import { eq } from "drizzle-orm";
4
+ import { z } from "zod";
5
+
6
+ import { getDb, schema } from "../server/db/index.js";
7
+ import { resolveSourceCapabilities } from "../shared/capability-resolver.js";
8
+ import { DESIGN_CAPABILITY_NAMES } from "../shared/design-source-capabilities.js";
9
+ import "../server/db/index.js"; // ensure registerShareableResource runs
10
+ import { normalizeDesignSourceType } from "../shared/source-mode.js";
11
+
12
+ export default defineAction({
13
+ description:
14
+ "Return the capability matrix for a design's current source. " +
15
+ "The matrix maps each capability name (readFile, writeFile, applyEdit, " +
16
+ "resolveNodeToFile, previewPatch, diffPatch, captureSnapshot, captureState, " +
17
+ "indexComponents, indexTokens, writeTokens, previewMotion, writeMotion, " +
18
+ "branch, deployPreview, deploy) to its status (available | planned | " +
19
+ "unavailable) plus an optional human-readable reason. " +
20
+ "UI controls and agent actions must gate on this matrix — never on sourceType alone.",
21
+ schema: z.object({
22
+ designId: z
23
+ .string()
24
+ .describe("Design project ID to fetch source capabilities for"),
25
+ }),
26
+ readOnly: true,
27
+ http: { method: "GET" },
28
+ run: async ({ designId }) => {
29
+ const access = await resolveAccess("design", designId);
30
+ if (!access) {
31
+ throw new Error("Design not found");
32
+ }
33
+
34
+ const db = getDb();
35
+
36
+ // Resolve source type from the design's data blob. The `sourceType`
37
+ // field lives inside `designs.data` as a JSON key (set by connect-localhost
38
+ // and the fusion upgrade flow), falling back to "inline" when absent.
39
+ let rawSourceType: unknown = "inline";
40
+ const rawData = (access.resource as { data?: unknown }).data;
41
+ if (typeof rawData === "string") {
42
+ try {
43
+ const parsed: unknown = JSON.parse(rawData);
44
+ if (
45
+ parsed !== null &&
46
+ typeof parsed === "object" &&
47
+ !Array.isArray(parsed) &&
48
+ "sourceType" in (parsed as object)
49
+ ) {
50
+ rawSourceType = (parsed as { sourceType: unknown }).sourceType;
51
+ }
52
+ } catch {
53
+ // Stale/invalid JSON — default to "inline".
54
+ }
55
+ }
56
+
57
+ const sourceType = normalizeDesignSourceType(rawSourceType) ?? "inline";
58
+ const capabilities = resolveSourceCapabilities(sourceType);
59
+
60
+ // Collect active localhost capabilities from the design's stored connection,
61
+ // if any, so that a bridge handshake that has already proven readFile
62
+ // is reflected here too.
63
+ let connectionCapabilities: Record<string, { status: string }> = {};
64
+ if (sourceType === "localhost") {
65
+ try {
66
+ const rawDesignData =
67
+ typeof rawData === "string" ? JSON.parse(rawData) : {};
68
+ const connectionId =
69
+ typeof rawDesignData === "object" &&
70
+ rawDesignData !== null &&
71
+ "connectionId" in rawDesignData
72
+ ? String(rawDesignData.connectionId)
73
+ : undefined;
74
+
75
+ if (connectionId) {
76
+ const [conn] = await db
77
+ .select({
78
+ capabilities: schema.designLocalhostConnections.capabilities,
79
+ })
80
+ .from(schema.designLocalhostConnections)
81
+ .where(eq(schema.designLocalhostConnections.id, connectionId))
82
+ .limit(1);
83
+
84
+ if (conn?.capabilities) {
85
+ try {
86
+ const parsed: unknown = JSON.parse(conn.capabilities);
87
+ if (Array.isArray(parsed)) {
88
+ // Bridge capabilities are DesignBridgeCapability[] with operation + status.
89
+ for (const entry of parsed) {
90
+ if (
91
+ entry !== null &&
92
+ typeof entry === "object" &&
93
+ "operation" in entry &&
94
+ "status" in entry
95
+ ) {
96
+ const op = String(
97
+ (entry as { operation: unknown }).operation,
98
+ );
99
+ const st = String((entry as { status: unknown }).status);
100
+ connectionCapabilities[op] = { status: st };
101
+ }
102
+ }
103
+ }
104
+ } catch {
105
+ // Ignore stale/invalid capability JSON.
106
+ }
107
+ }
108
+ }
109
+ } catch {
110
+ // Non-fatal: fall back to the defaults.
111
+ }
112
+ }
113
+
114
+ // Merge proven bridge capabilities (only for capabilities that exist in
115
+ // DESIGN_CAPABILITY_NAMES and only when the bridge reports "available").
116
+ const merged = { ...capabilities };
117
+ for (const capName of DESIGN_CAPABILITY_NAMES) {
118
+ const bridgeEntry = connectionCapabilities[capName];
119
+ if (bridgeEntry?.status === "available") {
120
+ merged[capName] = { status: "available" };
121
+ }
122
+ }
123
+
124
+ // Flatten to a list for easy agent consumption.
125
+ const capabilityList = DESIGN_CAPABILITY_NAMES.map((name) => ({
126
+ name,
127
+ ...merged[name],
128
+ }));
129
+
130
+ const availableNames = capabilityList
131
+ .filter((c) => c.status === "available")
132
+ .map((c) => c.name);
133
+
134
+ return {
135
+ designId,
136
+ sourceType,
137
+ capabilities: capabilityList,
138
+ availableCapabilities: availableNames,
139
+ summary: {
140
+ canWrite:
141
+ merged.applyEdit.status === "available" ||
142
+ merged.writeFile.status === "available",
143
+ canIndexComponents: merged.indexComponents.status === "available",
144
+ canWriteTokens: merged.writeTokens.status === "available",
145
+ canMotion:
146
+ merged.previewMotion.status === "available" ||
147
+ merged.writeMotion.status === "available",
148
+ canBranch: merged.branch.status === "available",
149
+ canDeploy: merged.deploy.status === "available",
150
+ },
151
+ };
152
+ },
153
+ });
@@ -0,0 +1,90 @@
1
+ import { defineAction } from "@agent-native/core";
2
+ import { accessFilter } from "@agent-native/core/sharing";
3
+ import { and, desc, eq } from "drizzle-orm";
4
+ import { z } from "zod";
5
+
6
+ import { getDb, schema } from "../server/db/index.js";
7
+ import "../server/db/index.js"; // ensure registerShareableResource runs
8
+
9
+ function parseJsonRecord(raw: string | null): Record<string, unknown> | null {
10
+ if (!raw) return null;
11
+ try {
12
+ const parsed = JSON.parse(raw) as unknown;
13
+ return parsed && typeof parsed === "object" && !Array.isArray(parsed)
14
+ ? (parsed as Record<string, unknown>)
15
+ : null;
16
+ } catch {
17
+ return null;
18
+ }
19
+ }
20
+
21
+ export default defineAction({
22
+ description:
23
+ "List all design states, fixtures, and captures for a design. " +
24
+ "States are alternate DOM/Alpine snapshots (Default, Loading, Empty, Error). " +
25
+ "Fixtures hold static data payloads for real-app preview. " +
26
+ "Captures are live snapshots of a running app's route + props taken via the bridge.",
27
+ schema: z.object({
28
+ designId: z.string().describe("Design project ID"),
29
+ kind: z
30
+ .enum(["state", "fixture", "capture"])
31
+ .optional()
32
+ .describe("Filter to a specific kind. Omit to return all kinds."),
33
+ sourceRef: z
34
+ .string()
35
+ .optional()
36
+ .describe(
37
+ "Filter to a specific source ref (file id for inline, route id for localhost/fusion). Omit to return all.",
38
+ ),
39
+ }),
40
+ readOnly: true,
41
+ http: { method: "GET" },
42
+ run: async ({ designId, kind, sourceRef }) => {
43
+ const db = getDb();
44
+
45
+ // Access is checked via the parent designs row (design_state has no own shares table).
46
+ const conditions = [
47
+ accessFilter(schema.designs, schema.designShares),
48
+ eq(schema.designState.designId, designId),
49
+ ];
50
+
51
+ if (kind) {
52
+ conditions.push(eq(schema.designState.kind, kind));
53
+ }
54
+ if (sourceRef) {
55
+ conditions.push(eq(schema.designState.sourceRef, sourceRef));
56
+ }
57
+
58
+ const rows = await db
59
+ .select({
60
+ id: schema.designState.id,
61
+ designId: schema.designState.designId,
62
+ sourceRef: schema.designState.sourceRef,
63
+ name: schema.designState.name,
64
+ kind: schema.designState.kind,
65
+ breakpoint: schema.designState.breakpoint,
66
+ route: schema.designState.route,
67
+ fixtureData: schema.designState.fixtureData,
68
+ captureData: schema.designState.captureData,
69
+ previewRef: schema.designState.previewRef,
70
+ createdAt: schema.designState.createdAt,
71
+ updatedAt: schema.designState.updatedAt,
72
+ })
73
+ .from(schema.designState)
74
+ .innerJoin(
75
+ schema.designs,
76
+ eq(schema.designState.designId, schema.designs.id),
77
+ )
78
+ .where(and(...conditions))
79
+ .orderBy(desc(schema.designState.updatedAt));
80
+
81
+ return {
82
+ count: rows.length,
83
+ states: rows.map((row) => ({
84
+ ...row,
85
+ fixtureData: parseJsonRecord(row.fixtureData),
86
+ captureData: parseJsonRecord(row.captureData),
87
+ })),
88
+ };
89
+ },
90
+ });