@agent-native/core 0.182.1 → 0.182.2-nightly-20260917210345

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 (66) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/templates/clips/app/root.tsx +59 -10
  3. package/corpus/templates/clips/changelog/2026-09-17-desktop-popover-closes-when-clicking-away.md +6 -0
  4. package/corpus/templates/clips/changelog/2026-09-17-self-hosted-extension-sign-in.md +6 -0
  5. package/corpus/templates/clips/chrome-extension/src/background.ts +45 -25
  6. package/corpus/templates/clips/chrome-extension/src/content-script.ts +43 -0
  7. package/corpus/templates/clips/desktop/src-tauri/src/lib.rs +55 -6
  8. package/corpus/templates/design/.generated/bridge/editor-chrome.generated.ts +1 -0
  9. package/corpus/templates/design/actions/add-localhost-screens.ts +54 -22
  10. package/corpus/templates/design/actions/apply-visual-edit.ts +1 -0
  11. package/corpus/templates/design/actions/create-design-from-template.ts +50 -35
  12. package/corpus/templates/design/actions/create-design-version.ts +21 -0
  13. package/corpus/templates/design/actions/create-file.ts +35 -33
  14. package/corpus/templates/design/actions/delete-design.ts +29 -28
  15. package/corpus/templates/design/actions/delete-file.ts +154 -23
  16. package/corpus/templates/design/actions/generate-design.ts +28 -16
  17. package/corpus/templates/design/actions/get-component-details.ts +187 -33
  18. package/corpus/templates/design/actions/get-design-version.ts +9 -1
  19. package/corpus/templates/design/actions/go-to-main-component.ts +37 -35
  20. package/corpus/templates/design/actions/index-components.ts +241 -126
  21. package/corpus/templates/design/actions/migrate-board-objects-to-file.ts +12 -9
  22. package/corpus/templates/design/actions/present-design-variants.ts +68 -72
  23. package/corpus/templates/design/actions/rename-component.ts +294 -0
  24. package/corpus/templates/design/actions/rename-screen.ts +10 -10
  25. package/corpus/templates/design/actions/update-file.ts +327 -330
  26. package/corpus/templates/design/actions/update-screen-source.ts +2 -43
  27. package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +1 -0
  28. package/corpus/templates/design/app/components/design/code-workbench/CodeWorkbench.tsx +8 -1
  29. package/corpus/templates/design/app/components/design/code-workbench/explorer/FileTree.tsx +55 -33
  30. package/corpus/templates/design/app/components/design/code-workbench/workspace/create-providers.ts +2 -0
  31. package/corpus/templates/design/app/components/design/code-workbench/workspace/inline-provider.ts +4 -2
  32. package/corpus/templates/design/app/components/design/edit-panel/element-classification.ts +5 -1
  33. package/corpus/templates/design/app/components/design/inspector/AutoLayoutMatrix.tsx +57 -9
  34. package/corpus/templates/design/app/components/design/types.ts +1 -0
  35. package/corpus/templates/design/app/hooks/use-design-versions.ts +3 -2
  36. package/corpus/templates/design/app/i18n-breakpoints.ts +0 -110
  37. package/corpus/templates/design/app/i18n-data.ts +0 -10
  38. package/corpus/templates/design/app/pages/DesignEditor.tsx +250 -107
  39. package/corpus/templates/design/app/pages/design-editor/commands/apply-file-content-update.ts +2 -0
  40. package/corpus/templates/design/app/pages/design-editor/commands/delete-files.ts +69 -47
  41. package/corpus/templates/design/app/pages/design-editor/commands/redo.ts +8 -1
  42. package/corpus/templates/design/app/pages/design-editor/commands/save-file-content.ts +107 -2
  43. package/corpus/templates/design/app/pages/design-editor/commands/undo.ts +26 -1
  44. package/corpus/templates/design/app/pages/design-editor/editor-state.ts +63 -2
  45. package/corpus/templates/design/app/pages/design-editor/nudge-intent.ts +74 -22
  46. package/corpus/templates/design/app/pages/design-editor/source-publication.ts +14 -2
  47. package/corpus/templates/design/changelog/2026-09-16-design-components-retain-linked-identities-when-edited-and-d.md +6 -0
  48. package/corpus/templates/design/changelog/2026-09-17-screen-deletion-is-immediate-and-undoable-with-history-that-.md +6 -0
  49. package/corpus/templates/design/e2e/fixtures/design-component-react/index.html +98 -0
  50. package/corpus/templates/design/e2e/fixtures/design-component-react/inline-component.html +65 -0
  51. package/corpus/templates/design/server/lib/design-data-mutation.ts +9 -5
  52. package/corpus/templates/design/server/lib/design-snapshot.ts +28 -16
  53. package/corpus/templates/design/server/lib/design-versions.ts +208 -130
  54. package/corpus/templates/design/server/lib/fusion-screens.ts +46 -20
  55. package/corpus/templates/design/server/lib/import-design-files.ts +5 -1
  56. package/corpus/templates/design/server/lib/localhost-connection.ts +54 -0
  57. package/corpus/templates/design/server/source-workspace.ts +412 -356
  58. package/corpus/templates/design/shared/component-library.ts +36 -6
  59. package/corpus/templates/design/shared/component-model.ts +8 -2
  60. package/dist/automation/index.d.ts +1 -1
  61. package/dist/client/chat/agentkit-protocol.js +148 -34
  62. package/dist/collab/struct-routes.d.ts +1 -1
  63. package/dist/progress/routes.d.ts +1 -1
  64. package/dist/server/core-routes-plugin.d.ts +1 -1
  65. package/package.json +4 -4
  66. package/corpus/templates/design/app/components/design/editor/PendingScreenDeletionDialog.tsx +0 -66
@@ -102,9 +102,21 @@ export function resolveSourceBaseForPublication(args: {
102
102
  persistedContent?: string | null;
103
103
  beforeContent: string;
104
104
  }): string {
105
+ const pendingContent = args.pending?.content;
106
+ const migrationSource = args.pending?.identityMigrationSourceContent;
107
+ // Identity repair is a real full-document save. Keep its raw CAS base while
108
+ // that save is still in flight, but switch to the canonical pending bytes as
109
+ // soon as the collab or persisted mirror has acknowledged them.
110
+ if (
111
+ pendingContent !== undefined &&
112
+ migrationSource !== undefined &&
113
+ args.collabContent !== pendingContent &&
114
+ args.persistedContent !== pendingContent
115
+ ) {
116
+ return migrationSource;
117
+ }
105
118
  const raw =
106
- args.pending?.identityMigrationSourceContent ??
107
- args.pending?.content ??
119
+ pendingContent ??
108
120
  args.collabContent ??
109
121
  args.persistedContent ??
110
122
  args.beforeContent;
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: improved
3
+ date: 2026-09-16
4
+ ---
5
+
6
+ Design components retain linked identities when edited and duplicated
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-09-17
4
+ ---
5
+
6
+ Screen deletion is immediate and undoable, with history that survives reloads.
@@ -0,0 +1,98 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <title>Design component React fixture</title>
6
+ <style>
7
+ body {
8
+ margin: 0;
9
+ min-height: 700px;
10
+ background: #111827;
11
+ color: white;
12
+ font: 16px system-ui;
13
+ }
14
+ main {
15
+ padding: 40px;
16
+ }
17
+ .card {
18
+ display: grid;
19
+ gap: 8px;
20
+ width: 260px;
21
+ padding: 20px;
22
+ border-radius: 14px;
23
+ background: #1f2937;
24
+ }
25
+ .card button {
26
+ padding: 10px 14px;
27
+ border: 0;
28
+ border-radius: 8px;
29
+ background: #6366f1;
30
+ color: white;
31
+ }
32
+ [data-agent-native-component-ref] {
33
+ outline: 1px dashed #f59e0b;
34
+ }
35
+ </style>
36
+ </head>
37
+ <body>
38
+ <main
39
+ data-agent-native-node-id="react-screen"
40
+ data-agent-native-layer-name="React Component Screen"
41
+ data-agent-native-source-kind="react"
42
+ data-agent-native-source-path="src/App.tsx"
43
+ data-agent-native-source-file="src/App.tsx"
44
+ data-agent-native-source-line="1"
45
+ data-agent-native-source-column="1"
46
+ >
47
+ <div
48
+ data-agent-native-node-id="promotion-target"
49
+ data-agent-native-layer-name="Promotion target"
50
+ >
51
+ Promote me
52
+ </div>
53
+ <section
54
+ class="card"
55
+ data-agent-native-node-id="card-main"
56
+ data-agent-native-layer-name="Card Main"
57
+ data-agent-native-component="ReusableCard"
58
+ data-agent-native-component-id="cmp-reusable-card"
59
+ data-agent-native-source-file="src/App.tsx"
60
+ data-agent-native-source-line="3"
61
+ data-agent-native-source-column="1"
62
+ data-source-framework="react"
63
+ data-source-file="src/App.tsx"
64
+ data-source-line="3"
65
+ data-source-column="1"
66
+ data-component-name="ReusableCard"
67
+ >
68
+ <strong data-agent-native-node-id="card-title">Canonical card</strong>
69
+ <button
70
+ data-agent-native-node-id="card-button"
71
+ data-agent-native-prop-label="Open"
72
+ >
73
+ Open
74
+ </button>
75
+ </section>
76
+ <section
77
+ class="card"
78
+ data-agent-native-node-id="card-instance"
79
+ data-agent-native-layer-name="Card Instance"
80
+ data-agent-native-component="ReusableCard"
81
+ data-agent-native-component-ref="cmp-reusable-card"
82
+ data-agent-native-component-overrides="%7B%22card-title%22%3A%7B%22textContent%22%3A%22Instance%20override%22%7D%7D"
83
+ >
84
+ <strong
85
+ data-agent-native-node-id="card-instance-title"
86
+ data-agent-native-component-source-node-id="card-title"
87
+ >Instance override</strong
88
+ >
89
+ <button
90
+ data-agent-native-node-id="card-instance-button"
91
+ data-agent-native-component-source-node-id="card-button"
92
+ >
93
+ Open
94
+ </button>
95
+ </section>
96
+ </main>
97
+ </body>
98
+ </html>
@@ -0,0 +1,65 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <title>Inline component fixture</title>
6
+ </head>
7
+ <body style="margin: 0; position: relative; min-height: 900px">
8
+ <aside
9
+ data-agent-native-node-id="legacy-copy"
10
+ data-agent-native-layer-name="Legacy same-name copy"
11
+ data-agent-native-component="ReusableCard"
12
+ style="
13
+ position: absolute;
14
+ left: 40px;
15
+ top: 40px;
16
+ width: 180px;
17
+ height: 80px;
18
+ background: #ddd;
19
+ "
20
+ >
21
+ Legacy
22
+ </aside>
23
+ <section
24
+ data-agent-native-node-id="card-main"
25
+ data-agent-native-layer-name="Card Main"
26
+ style="
27
+ position: absolute;
28
+ left: 300px;
29
+ top: 40px;
30
+ width: 420px;
31
+ height: 360px;
32
+ padding: 20px;
33
+ background: #1f2937;
34
+ color: white;
35
+ "
36
+ >
37
+ <div
38
+ data-agent-native-node-id="card-body"
39
+ data-agent-native-layer-name="Card Body"
40
+ style="display: grid; gap: 8px"
41
+ >
42
+ <strong data-agent-native-node-id="card-title"
43
+ ><span data-agent-native-node-id="card-title-text"
44
+ >Canonical card</span
45
+ ></strong
46
+ >
47
+ <button
48
+ data-agent-native-node-id="card-button"
49
+ data-agent-native-layer-name="Card Action"
50
+ data-agent-native-prop-label="Open"
51
+ style="width: 120px; padding: 10px; background: #6366f1; color: white"
52
+ >
53
+ Open
54
+ </button>
55
+ </div>
56
+ <div
57
+ data-agent-native-node-id="card-slot"
58
+ data-agent-native-layer-name="Card Slot"
59
+ style="min-height: 70px; padding: 10px; background: #374151"
60
+ >
61
+ Reparent target
62
+ </div>
63
+ </section>
64
+ </body>
65
+ </html>
@@ -2,6 +2,10 @@ import { assertAccess } from "@agent-native/core/sharing";
2
2
  import { and, eq, isNull, sql } from "drizzle-orm";
3
3
 
4
4
  import { getDb, schema } from "../db/index.js";
5
+ import {
6
+ designSourceMutationLockKey,
7
+ lockDesignFilesTable,
8
+ } from "../source-workspace.js";
5
9
 
6
10
  const DEFAULT_MAX_ATTEMPTS = 8;
7
11
  const CONFLICT_BACKOFF_MS = 8;
@@ -199,11 +203,10 @@ async function mutateDesignDataUnlocked({
199
203
  // Keep the design-data CAS and HTML rewrites in one transaction.
200
204
  // ponytail: reuse the existing design-file lock; split by design only
201
205
  // if breakpoint edits become a measurable multi-tenant bottleneck.
202
- await (
203
- tx as unknown as {
204
- execute: (query: unknown) => Promise<unknown>;
205
- }
206
- ).execute(sql`LOCK TABLE design_files IN SHARE ROW EXCLUSIVE MODE`);
206
+ await tx.execute(
207
+ sql`SELECT pg_advisory_xact_lock(hashtextextended(${designSourceMutationLockKey(designId)}, 0::bigint))`,
208
+ );
209
+ await lockDesignFilesTable(tx);
207
210
  }
208
211
 
209
212
  const [currentRow] = await tx
@@ -233,6 +236,7 @@ async function mutateDesignDataUnlocked({
233
236
  })
234
237
  .from(schema.designFiles)
235
238
  .where(eq(schema.designFiles.designId, designId))
239
+ .for("update")
236
240
  : [];
237
241
  const revisionConditions = [
238
242
  eq(schema.designs.id, designId),
@@ -43,6 +43,13 @@ export interface DesignSnapshot {
43
43
  resolvedCssVars: Record<string, string>;
44
44
  }
45
45
 
46
+ export interface BuildDesignSnapshotOptions {
47
+ /** Read the persisted SQL rows even when a live collaboration document exists. */
48
+ preferStoredFileContent?: boolean;
49
+ }
50
+
51
+ type SnapshotDatabase = Pick<ReturnType<typeof getDb>, "select">;
52
+
46
53
  function parseDesignData(data?: string | null): Record<string, unknown> {
47
54
  if (!data) return {};
48
55
  try {
@@ -62,8 +69,10 @@ function parseDesignData(data?: string | null): Record<string, unknown> {
62
69
  export async function buildDesignSnapshot(
63
70
  designId: string,
64
71
  designData?: string | null,
72
+ options: BuildDesignSnapshotOptions = {},
73
+ database?: SnapshotDatabase,
65
74
  ): Promise<DesignSnapshot> {
66
- const db = getDb();
75
+ const db = database ?? getDb();
67
76
 
68
77
  const rows = await db
69
78
  .select()
@@ -76,23 +85,26 @@ export async function buildDesignSnapshot(
76
85
  let source: "collab" | "stored" = "stored";
77
86
  // Prefer live collab text when an editing session exists for this file so
78
87
  // an external agent sees in-flight edits, not the last persisted snapshot.
79
- try {
80
- if (await hasCollabState(f.id)) {
81
- const live = await getText(f.id, "content");
82
- if (
83
- typeof live === "string" &&
84
- shouldUseLiveFileContent({
85
- liveContent: live,
86
- storedContent: f.content,
87
- fileType: f.fileType,
88
- })
89
- ) {
90
- content = live;
91
- source = "collab";
88
+ if (!options.preferStoredFileContent) {
89
+ try {
90
+ if (await hasCollabState(f.id)) {
91
+ const live = await getText(f.id, "content");
92
+ if (
93
+ typeof live === "string" &&
94
+ shouldUseLiveFileContent({
95
+ liveContent: live,
96
+ storedContent: f.content,
97
+ fileType: f.fileType,
98
+ })
99
+ ) {
100
+ content = live;
101
+ source = "collab";
102
+ }
92
103
  }
104
+ } catch {
105
+ // coercion-ok: live collaboration is optional; stored content remains explicitly tagged.
106
+ // Collab read is best-effort; fall back to stored content.
93
107
  }
94
- } catch {
95
- // Collab read is best-effort; fall back to stored content.
96
108
  }
97
109
  files.push({
98
110
  id: f.id,